diff options
279 files changed, 32433 insertions, 1903 deletions
diff --git a/.github/workflows/linux_builds.yml b/.github/workflows/linux_builds.yml index eeca57a22e..bb3416743b 100644 --- a/.github/workflows/linux_builds.yml +++ b/.github/workflows/linux_builds.yml @@ -23,7 +23,7 @@ jobs: target: release_debug tools: true tests: false # Disabled due freeze caused by mix Mono build and CI - sconsflags: module_mono_enabled=yes mono_glue=no + sconsflags: module_mono_enabled=yes mono_static=yes mono_glue=no doc-test: true bin: "./bin/godot.linuxbsd.opt.tools.64.mono" build-mono: true @@ -47,7 +47,7 @@ jobs: target: release tools: false tests: false - sconsflags: module_mono_enabled=yes mono_glue=no debug_symbols=no + sconsflags: module_mono_enabled=yes mono_static=yes mono_glue=no debug_symbols=no build-mono: false artifact: true diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt index 368e321a2d..df1ab0c849 100644 --- a/COPYRIGHT.txt +++ b/COPYRIGHT.txt @@ -361,12 +361,16 @@ Comment: Multi-channel signed distance field generator Copyright: 2016, Viktor Chlumsky License: MIT - Files: ./thirdparty/oidn/ Comment: Intel Open Image Denoise Copyright: 2009-2019, Intel Corporation License: Apache-2.0 +Files: ./thirdparty/openxr/ +Comment: OpenXR Loader +Copyright: 2020-2022, The Khronos Group Inc. +License: Apache-2.0 + Files: ./thirdparty/pcre2/ Comment: PCRE2 Copyright: 1997-2021, University of Cambridge diff --git a/SConstruct b/SConstruct index a27e5490a5..233a79f635 100644 --- a/SConstruct +++ b/SConstruct @@ -173,6 +173,7 @@ opts.Add(BoolVariable("minizip", "Enable ZIP archive support using minizip", Tru opts.Add(BoolVariable("xaudio2", "Enable the XAudio2 audio driver", False)) opts.Add(BoolVariable("vulkan", "Enable the vulkan video driver", True)) opts.Add(BoolVariable("opengl3", "Enable the OpenGL/GLES3 video driver", True)) +opts.Add(BoolVariable("openxr", "Enable the OpenXR driver", True)) opts.Add("custom_modules", "A list of comma-separated directory paths containing custom modules to build.", "") opts.Add(BoolVariable("custom_modules_recursive", "Detect custom modules recursively for each specified path.", True)) opts.Add(BoolVariable("use_volk", "Use the volk library to load the Vulkan loader dynamically", True)) diff --git a/core/extension/native_extension.cpp b/core/extension/native_extension.cpp index 1512852234..e1db99fe5d 100644 --- a/core/extension/native_extension.cpp +++ b/core/extension/native_extension.cpp @@ -295,9 +295,10 @@ NativeExtension::InitializationLevel NativeExtension::get_minimum_library_initia ERR_FAIL_COND_V(library == nullptr, INITIALIZATION_LEVEL_CORE); return InitializationLevel(initialization.minimum_initialization_level); } + void NativeExtension::initialize_library(InitializationLevel p_level) { ERR_FAIL_COND(library == nullptr); - ERR_FAIL_COND(p_level <= int32_t(level_initialized)); + ERR_FAIL_COND_MSG(p_level <= int32_t(level_initialized), vformat("Level '%d' must be higher than the current level '%d'", p_level, level_initialized)); level_initialized = int32_t(p_level); diff --git a/core/extension/native_extension_manager.cpp b/core/extension/native_extension_manager.cpp index 87737858a8..509405494b 100644 --- a/core/extension/native_extension_manager.cpp +++ b/core/extension/native_extension_manager.cpp @@ -40,14 +40,14 @@ NativeExtensionManager::LoadStatus NativeExtensionManager::load_extension(const return LOAD_STATUS_FAILED; } - if (level >= 0) { //already initialized up to some level + if (level >= 0) { // Already initialized up to some level. int32_t minimum_level = extension->get_minimum_library_initialization_level(); if (minimum_level < MIN(level, NativeExtension::INITIALIZATION_LEVEL_SCENE)) { return LOAD_STATUS_NEEDS_RESTART; } - //initialize up to current level - for (int32_t i = minimum_level; i < level; i++) { - extension->initialize_library(NativeExtension::InitializationLevel(level)); + // Initialize up to current level. + for (int32_t i = minimum_level; i <= level; i++) { + extension->initialize_library(NativeExtension::InitializationLevel(i)); } } native_extension_map[p_path] = extension; @@ -64,14 +64,14 @@ NativeExtensionManager::LoadStatus NativeExtensionManager::unload_extension(cons Ref<NativeExtension> extension = native_extension_map[p_path]; - if (level >= 0) { //already initialized up to some level + if (level >= 0) { // Already initialized up to some level. int32_t minimum_level = extension->get_minimum_library_initialization_level(); if (minimum_level < MIN(level, NativeExtension::INITIALIZATION_LEVEL_SCENE)) { return LOAD_STATUS_NEEDS_RESTART; } - //initialize up to current level + // Deinitialize down to current level. for (int32_t i = level; i >= minimum_level; i--) { - extension->deinitialize_library(NativeExtension::InitializationLevel(level)); + extension->deinitialize_library(NativeExtension::InitializationLevel(i)); } } native_extension_map.erase(p_path); diff --git a/core/input/gamecontrollerdb.txt b/core/input/gamecontrollerdb.txt index 58014e976e..f2cbaa3698 100644 --- a/core/input/gamecontrollerdb.txt +++ b/core/input/gamecontrollerdb.txt @@ -2,12 +2,14 @@ # Source: https://github.com/gabomdq/SDL_GameControllerDB # Windows -03000000fa2d00000100000000000000,3DRUDDER,leftx:a0,lefty:a1,rightx:a5,righty:a2,platform:Windows, -03000000d0160000040d000000000000,4Play,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows, -03000000d0160000050d000000000000,4Play,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows, -03000000d0160000060d000000000000,4Play,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows, -03000000d0160000070d000000000000,4Play,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows, -03000000d0160000600a000000000000,4Play,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows, +03000000fa2d00000100000000000000,3dRudder Foot Motion Controller,leftx:a0,lefty:a1,rightx:a5,righty:a2,platform:Windows, +03000000d0160000040d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows, +03000000d0160000050d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows, +03000000d0160000060d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows, +03000000d0160000070d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows, +03000000d0160000600a000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows, +03000000c82d00000031000000000000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00000531000000000000,8BitDo Adapter 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 03000000c82d00000951000000000000,8BitDo Dogbone Modkit,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Windows, 03000000008000000210000000000000,8BitDo F30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, 030000003512000011ab000000000000,8BitDo F30 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, @@ -16,9 +18,9 @@ 03000000801000000900000000000000,8BitDo F30 Arcade Stick,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, 03000000c82d00001038000000000000,8BitDo F30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000090000000000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, -03000000c82d00000650000000000000,8BitDo M30,a:b0,b:b1,back:b10,guide:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows, -03000000c82d00005106000000000000,8BitDo M30 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b11,x:b4,y:b3,platform:Windows, -03000000c82d00000151000000000000,8BitDo M30 ModKit,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00000650000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00005106000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,guide:b2,leftshoulder:b8,lefttrigger:b9,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00000151000000000000,8BitDo M30 Modkit,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows, 03000000c82d00000310000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows, 03000000c82d00002028000000000000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00008010000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows, @@ -35,13 +37,15 @@ 03000000c82d00002038000000000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000751000000000000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b11,x:b3,y:b4,platform:Windows, 03000000c82d00000360000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000361000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000660000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00002867000000000000,8BitDo S30 Modkit,a:b0,b:b1,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b8,lefttrigger:b9,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows, 03000000c82d00000130000000000000,8BitDo SF30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000060000000000000,8Bitdo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000061000000000000,8Bitdo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, +03000000102800000900000000000000,8Bitdo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d000021ab000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, -03000000102800000900000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, -03000000c82d00003028000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00003028000000000000,8Bitdo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000030000000000000,8BitDo SN30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00001290000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d000020ab000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, @@ -54,15 +58,14 @@ 03000000c82d00000121000000000000,8BitDo SN30 Pro for Android,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 03000000c82d00000260000000000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000261000000000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, -03000000c82d00000031000000000000,8BitDo Wireless Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000a00500003232000000000000,8Bitdo Zero,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows, 03000000c82d00001890000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00003032000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, -03000000a00500003232000000000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows, 03000000d81d00000e00000000000000,AC02,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,rightx:a2,righty:a5,start:b8,x:b4,y:b5,platform:Windows, 030000008f0e00001200000000000000,Acme GA02,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows, 03000000c01100000355000000000000,Acrux,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000fa190000f0ff000000000000,Acteck AGJ 3200,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, -030000006d0400000bc2000000000000,Action Pad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b8,lefttrigger:a5~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:a2~,start:b8,x:b3,y:b4,platform:Windows, +030000006d0400000bc2000000000000,Action,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b8,lefttrigger:a5~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:a2~,start:b8,x:b3,y:b4,platform:Windows, 03000000d1180000402c000000000000,ADT1,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a3,rightx:a2,righty:a5,x:b3,y:b4,platform:Windows, 030000006f0e00001301000000000000,Afterglow,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 030000006f0e00001302000000000000,Afterglow,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, @@ -78,17 +81,20 @@ 030000006f0e00001402000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000006f0e00001901000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000006f0e00001a01000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000100000008200000000000000,Akishop Customs PS360,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000007c1800000006000000000000,Alienware Dual Compatible PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows, 03000000491900001904000000000000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows, 03000000710100001904000000000000,Amazon Luna Controller,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b8,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b4,rightstick:b7,rightx:a3,righty:a4,start:b6,x:b3,y:b2,platform:Windows, 03000000830500000160000000000000,Arcade,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b3,x:b4,y:b4,platform:Windows, 03000000120c0000100e000000000000,Armor 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000490b00004406000000000000,ASCII Seamic Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, 03000000869800002500000000000000,Astro C40 TR PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000a30c00002700000000000000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows, 03000000a30c00002800000000000000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows, 03000000ef0500000300000000000000,AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows, 03000000fd0500000230000000000000,AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a5,start:b11,x:b0,y:b1,platform:Windows, -03000000d6200000e557000000000000,Batarang,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000e4150000103f000000000000,Batarang,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000d6200000e557000000000000,Batarang PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000c01100001352000000000000,Battalife Joystick,a:b6,b:b7,back:b2,leftshoulder:b0,leftx:a0,lefty:a1,rightshoulder:b1,start:b3,x:b4,y:b5,platform:Windows, 030000006f0e00003201000000000000,Battlefield 4 PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000ad1b000001f9000000000000,BB 070,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, @@ -96,7 +102,7 @@ 03000000bc2000005250000000000000,Beitong G3,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:b9,rightx:a3,righty:a4,start:b15,x:b3,y:b4,platform:Windows, 030000000d0500000208000000000000,Belkin Nostromo N40,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows, 03000000bc2000006012000000000000,Betop 2126F,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, -03000000bc2000000055000000000000,Betop BFM Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000bc2000000055000000000000,Betop BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 03000000bc2000006312000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 03000000bc2000006321000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 03000000bc2000006412000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, @@ -109,11 +115,9 @@ 030000006b1400000209000000000000,Bigben,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000006b1400000055000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, 030000006b1400000103000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows, -03000000380700008232000000000000,Brawlpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000120c0000200e000000000000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000120c0000210e000000000000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, -0300000066f700000500000000000000,BrutalLegendTest,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows, -03000000d81d00000b00000000000000,BUFFALO BSGP1601 Series,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Windows, +03000000d81d00000b00000000000000,Buffalo BSGP1601 Series,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Windows, 030000006d04000042c2000000000000,ChillStream,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000e82000006058000000000000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 03000000457500000401000000000000,Cobra,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, @@ -123,29 +127,28 @@ 03000000d8140000cefa000000000000,Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000260900008888000000000000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a4,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Windows, 030000003807000002cb000000000000,Cyborg,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, -03000000a306000022f6000000000000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000a306000022f6000000000000,Cyborg V.3 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows, 03000000f806000000a3000000000000,DA Leader,a:b7,b:b6,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b0,leftstick:b8,lefttrigger:b1,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:b3,rightx:a2,righty:a3,start:b12,x:b4,y:b5,platform:Windows, 030000001a1c00000001000000000000,Datel,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000451300000830000000000000,Defender Game Racer X7,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, 030000007d0400000840000000000000,Destroyer Tiltpad,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,x:b0,y:b3,platform:Windows, -03000000c0160000e105000000000000,Dual,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, -03000000791d00000103000000000000,Dual Box WII,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, -030000007c1800000006000000000000,Dual Compat,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows, +03000000791d00000103000000000000,Dual Box Wii,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000c0160000e105000000000000,Dual Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, 030000004f040000070f000000000000,Dual Power,a:b8,b:b9,back:b4,dpdown:b1,dpleft:b2,dpright:b3,dpup:b0,leftshoulder:b13,leftstick:b6,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b12,rightstick:b7,righttrigger:b15,start:b5,x:b10,y:b11,platform:Windows, 030000004f04000012b3000000000000,Dual Power 3,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows, 030000004f04000020b3000000000000,Dual Trigger,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows, -03000000bd12000002e0000000000000,Dual USB Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows, +03000000bd12000002e0000000000000,Dual Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows, 03000000ff1100003133000000000000,DualForce,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b1,platform:Windows, 030000008f0e00000910000000000000,DualShock 2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows, 03000000317300000100000000000000,DualShock 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, 030000006f0e00003001000000000000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000fc0400000250000000000000,Easy Grip,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, -030000006e0500000a20000000000000,Elecom DUX60 MMO Gamepad,a:b2,b:b3,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b14,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b15,righttrigger:b13,rightx:a3,righty:a4,start:b20,x:b0,y:b1,platform:Windows, +030000006e0500000a20000000000000,Elecom DUX60 MMO,a:b2,b:b3,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b14,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b15,righttrigger:b13,rightx:a3,righty:a4,start:b20,x:b0,y:b1,platform:Windows, 03000000b80500000410000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows, 03000000b80500000610000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows, -030000006e0500000520000000000000,Elecom P301U,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows, +030000006e0500000520000000000000,Elecom P301U PlayStation Controller Adapter,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows, 03000000411200004450000000000000,Elecom U1012,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows, -030000006e0500000320000000000000,Elecom U3613M (DInput),a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows, +030000006e0500000320000000000000,Elecom U3613M,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows, 030000006e0500000e20000000000000,Elecom U3912T,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows, 030000006e0500000f20000000000000,Elecom U4013S,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows, 030000006e0500001320000000000000,Elecom U4113,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, @@ -156,52 +159,42 @@ 03000000242f000000b7000000000000,ESM 9110,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Windows, 03000000101c0000181c000000000000,Essential,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b4,leftx:a1,lefty:a0,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, 030000008f0e00000f31000000000000,EXEQ,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows, -03000000341a00000108000000000000,EXEQ RF USB Gamepad 8206,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000341a00000108000000000000,EXEQ RF Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, 03000000790000003018000000000000,F300,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, 03000000242f00003900000000000000,F300 Elite,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, -030000006f0e00008401000000000000,Faceoff Deluxe Audio Wired Controller for Nintendo Switch,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, -030000006f0e00008001000000000000,Faceoff Wired Pro Controller for Nintendo Switch,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00008401000000000000,Faceoff Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00008001000000000000,Faceoff Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000021000000090000000000000,FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, 0300000011040000c600000000000000,FC801,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows, -030000004f04000008d0000000000000,Ferrari 150,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000852100000201000000000000,FF GP1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, -030000000d0f00008500000000000000,Fighting Commander 2016 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, -030000000d0f00008400000000000000,Fighting Commander 5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, -030000000d0f00008700000000000000,Fighting Stick mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, -030000000d0f00008800000000000000,Fighting Stick mini 4,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows, -030000000d0f00002700000000000000,FIGHTING STICK V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, -03000000380700002847000000000000,FightPad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000380700002847000000000000,Fightpad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000ad1b000028f0000000000000,Fightpad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000ad1b00002ef0000000000000,Fightpad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000ad1b000038f0000000000000,Fightpad TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows, -03000000380700001847000000000000,FightStick,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows, -03000000380700008031000000000000,FightStick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, -03000000380700008731000000000000,FightStick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, -030000003807000038b7000000000000,FightStick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows, -78696e70757403000000000000000000,Fightstick TES,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Windows, +03000000380700001847000000000000,Fightstick,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows, +03000000380700008031000000000000,Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000f806000001a3000000000000,Firestorm,a:b9,b:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b0,leftstick:b10,lefttrigger:b1,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,start:b12,x:b8,y:b4,platform:Windows, 03000000b50700000399000000000000,Firestorm 2,a:b2,b:b4,back:b10,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,righttrigger:b9,start:b11,x:b3,y:b5,platform:Windows, 03000000b50700001302000000000000,Firestorm D3,a:b0,b:b2,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,x:b1,y:b3,platform:Windows, 03000000b40400001024000000000000,Flydigi Apex,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, 03000000151900004000000000000000,Flydigi Vader 2,a:b11,b:b10,back:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,leftstick:b1,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b0,righttrigger:b4,rightx:a3,righty:a4,start:b2,x:b9,y:b8,platform:Windows, 03000000b40400001124000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b4,paddle2:b5,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b2,y:b3,platform:Windows, +03000000b40400001224000000000000,Flydigi Vader 2 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,paddle3:b17,paddle4:b18,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows, 030000008305000000a0000000000000,G08XU,a:b0,b:b1,back:b4,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b5,x:b2,y:b3,platform:Windows, 03000000ac0500002d02000000000000,G2U,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, -03000000790000002201000000000000,Game Controller for PC,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 0300000066f700000100000000000000,Game VIB Joystick,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows, -03000000341a000005f7000000000000,GameCube,a:b2,b:b3,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b1,y:b0,platform:Windows, -03000000430b00000500000000000000,GameCube,a:b0,b:b2,dpdown:b10,dpleft:b8,dpright:b9,dpup:b11,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a3,rightx:a5,righty:a2,start:b7,x:b1,y:b3,platform:Windows, -03000000790000004718000000000000,GameCube,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows, -03000000260900002625000000000000,Gamecube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,lefttrigger:a4,leftx:a0,lefty:a1,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Windows, +03000000260900002625000000000000,GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,lefttrigger:a4,leftx:a0,lefty:a1,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Windows, +03000000341a000005f7000000000000,GameCube Controller,a:b2,b:b3,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b1,y:b0,platform:Windows, +03000000430b00000500000000000000,GameCube Controller,a:b0,b:b2,dpdown:b10,dpleft:b8,dpright:b9,dpup:b11,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a3,rightx:a5,righty:a2,start:b7,x:b1,y:b3,platform:Windows, +03000000790000004718000000000000,GameCube Controller,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows, 03000000790000004618000000000000,GameCube Controller Adapter,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows, 030000008f0e00000d31000000000000,Gamepad 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, -03000000280400000140000000000000,GamePad Pro USB,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +03000000280400000140000000000000,GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, 03000000ac0500003d03000000000000,GameSir,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 03000000ac0500004d04000000000000,GameSir,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 030000004c0e00001035000000000000,Gamester,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, -030000000d0f00001110000000000000,GameStick Bluetooth Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +030000000d0f00001110000000000000,GameStick Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, 0300000047530000616d000000000000,GameStop,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, -03000000ffff00000000000000000000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, 03000000c01100000140000000000000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000b62500000100000000000000,Gametel GT004 01,a:b3,b:b0,dpdown:b10,dpleft:b9,dpright:b8,dpup:b11,leftshoulder:b4,rightshoulder:b5,start:b7,x:b1,y:b2,platform:Windows, 030000008f0e00001411000000000000,Gamo2 Divaller PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, @@ -211,15 +204,15 @@ 030000008305000031b0000000000000,Genius Maxfire Blaze 3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, 03000000451300000010000000000000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, 030000005c1a00003330000000000000,Genius MaxFire Grandias 12V,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows, -03000000300f00000b01000000000000,GGE909 Recoil Pad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, -03000000f0250000c283000000000000,Gioteck,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000300f00000b01000000000000,GGE909 Recoil,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000f0250000c283000000000000,Gioteck PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 03000000f025000021c1000000000000,Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, -03000000f0250000c383000000000000,Gioteck VX2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, -03000000f0250000c483000000000000,Gioteck VX2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000f0250000c383000000000000,Gioteck VX2 PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000f0250000c483000000000000,Gioteck VX2 PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 030000004f04000026b3000000000000,GP XID,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 0300000079000000d418000000000000,GPD Win,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000c6240000025b000000000000,GPX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, -030000007d0400000540000000000000,Gravis Eliminator GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000007d0400000540000000000000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, 030000007d0400000340000000000000,Gravis G44011 Xterminator,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a2,start:b9,x:b3,y:b4,platform:Windows, 030000008f0e00000610000000000000,GreenAsia,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a5,righty:a2,start:b11,x:b3,y:b0,platform:Windows, 03000000ac0500006b05000000000000,GT2a,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, @@ -227,33 +220,40 @@ 03000000fd0500003902000000000000,Hammerhead,a:b3,b:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b2,lefttrigger:b8,rightshoulder:b7,rightstick:b5,righttrigger:b9,start:b10,x:b0,y:b1,platform:Windows, 03000000fd0500002a26000000000000,Hammerhead FX,a:b3,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b0,y:b1,platform:Windows, 03000000fd0500002f26000000000000,Hammerhead FX,a:b4,b:b5,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b1,y:b2,platform:Windows, -030000000d0f00004900000000000000,Hatsune Miku Sho Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00004900000000000000,Hatsune Miku Sho PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000001008000001e1000000000000,Havit HV G60,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b0,platform:Windows, 030000000d0f00000c00000000000000,HEXT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000d81400000862000000000000,HitBox Edition Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows, 03000000632500002605000000000000,HJD X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 030000000d0f00000a00000000000000,Hori DOA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000000d0f00005100000000000000,Hori Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 030000000d0f00008600000000000000,Hori Fighting Commander,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 030000000d0f0000ba00000000000000,Hori Fighting Commander,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000000d0f00008500000000000000,Hori Fighting Commander 2016 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00002500000000000000,Hori Fighting Commander 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, 030000000d0f00002d00000000000000,Hori Fighting Commander 3 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000000d0f00005f00000000000000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000000d0f00005e00000000000000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, -030000000d0f00005100000000000000,Hori Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, -030000000d0f00001000000000000000,Hori Fighting Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, -030000000f0d00000010000000000000,Hori Fighting Stick 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, -030000000d0f00003200000000000000,Hori Fighting Stick 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, -030000000d0f0000c000000000000000,Hori Fighting Stick 4,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, -030000000d0f00000d00000000000000,Hori Fighting Stick EX2,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, -030000000d0f00003701000000000000,Hori Fighting Stick Mini,a:b1,b:b0,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Windows, -030000000d0f00004000000000000000,Hori Fighting Stick Mini 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows, -030000000d0f00002100000000000000,Hori Fighting Stick V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00008400000000000000,Hori Fighting Commander 5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00001000000000000000,Hori Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000f0d00000010000000000000,Hori Fightstick 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00003200000000000000,Hori Fightstick 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f0000c000000000000000,Hori Fightstick 4,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000000d0f00000d00000000000000,Hori Fightstick EX2,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, +030000000d0f00003701000000000000,Hori Fightstick Mini,a:b1,b:b0,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Windows, +030000000d0f00004000000000000000,Hori Fightstick Mini 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00008700000000000000,Hori Fightstick mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00008800000000000000,Hori Fightstick mini 4,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows, +030000000d0f00002100000000000000,Hori Fightstick V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00002700000000000000,Hori Fightstick V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, 030000000d0f0000a000000000000000,Hori Grip TAC4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b13,x:b0,y:b3,platform:Windows, 030000000d0f00000101000000000000,Hori Mini Hatsune Miku FT,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000000d0f00005400000000000000,Hori Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000000d0f00000900000000000000,Hori Pad 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000000d0f00004d00000000000000,Hori Pad A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000000d0f00003801000000000000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Windows, -030000000d0f00009200000000000000,Hori Pokken Tournament DX Pro Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00009200000000000000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00002301000000000000,Hori PS4 Controller Light,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, 030000000d0f00001100000000000000,Hori Real Arcade Pro 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, 030000000d0f00002600000000000000,Hori Real Arcade Pro 3P,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 030000000d0f00004b00000000000000,Hori Real Arcade Pro 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, @@ -276,7 +276,6 @@ 03000000ad1b000002f5000000000000,Hori Real Arcade Pro VX,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b07,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b08,righttrigger:b11,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Windows, 030000000d0f00009c00000000000000,Hori TAC Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 030000000d0f0000c900000000000000,Hori Taiko Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, -030000000d0f00002301000000000000,Hori Wired PS4 Controller Light,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, 030000000d0f0000c100000000000000,Horipad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000000d0f00006400000000000000,Horipad 3TP,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 030000000d0f00001300000000000000,Horipad 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, @@ -290,24 +289,25 @@ 030000000d0f00006700000000000000,Horipad One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 030000000d0f0000dc00000000000000,Horipad Switch,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 030000008f0e00001330000000000000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,platform:Windows, -03000000d81d00000f00000000000000,iBUFFALO BSGP1204 Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, -03000000d81d00001000000000000000,iBUFFALO BSGP1204P Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000790000004e95000000000000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,platform:Windows, +03000000d81d00000f00000000000000,iBuffalo BSGP1204 Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000d81d00001000000000000000,iBuffalo BSGP1204P Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 030000005c0a00000285000000000000,iDroidCon,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b6,platform:Windows, -03000000696400006964000000000000,iDroidCon Bluetooth Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000696400006964000000000000,iDroidCon Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000b50700001403000000000000,Impact Black,a:b2,b:b3,back:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, -030000006f0e00002401000000000000,Injustice FightStick PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00002401000000000000,Injustice Fightstick PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, 03000000830500005130000000000000,InterAct ActionPad,a:b0,b:b1,back:b8,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, 03000000fd0500005302000000000000,InterAct ProPad,a:b3,b:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,platform:Windows, 03000000ac0500002c02000000000000,Ipega Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 03000000491900000204000000000000,Ipega PG9023,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, -03000000491900000304000000000000,Ipega PG9087 - Bluetooth Gamepad,+righty:+a5,-righty:-a4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,start:b11,x:b3,y:b4,platform:Windows, +03000000491900000304000000000000,Ipega PG9087,+righty:+a5,-righty:-a4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,start:b11,x:b3,y:b4,platform:Windows, 030000007e0500000620000000000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Windows, 030000007e0500000720000000000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows, 03000000bd12000003c0000000000000,Joypad Alpha Shock,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, -03000000250900000017000000000000,Joypad to USB Adapter,a:b2,b:b1,back:b9,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b8,x:b3,y:b0,platform:Windows, +03000000250900000017000000000000,Joypad to Adapter,a:b2,b:b1,back:b9,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b8,x:b3,y:b0,platform:Windows, 03000000ff1100004033000000000000,JPD FFB,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a2,start:b15,x:b3,y:b0,platform:Windows, -03000000242f00002d00000000000000,JYS Wireless Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, -03000000242f00008a00000000000000,JYS Wireless Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows, +03000000242f00002d00000000000000,JYS Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000242f00008a00000000000000,JYS Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows, 03000000c4100000c082000000000000,KADE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000828200000180000000000000,Keio,a:b4,b:b5,back:b8,leftshoulder:b2,lefttrigger:b3,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b9,x:b0,y:b1,platform:Windows, 03000000790000000200000000000000,King PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows, @@ -320,11 +320,11 @@ 030000006d04000011c2000000000000,Logitech Cordless Wingman,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b2,righttrigger:b7,rightx:a3,righty:a4,x:b4,platform:Windows, 030000006d04000016c2000000000000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000006d0400001dc2000000000000,Logitech F310,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000006d04000018c2000000000000,Logitech F510,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000006d0400001ec2000000000000,Logitech F510,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, -030000006d04000018c2000000000000,Logitech F510 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006d04000019c2000000000000,Logitech F710,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000006d0400001fc2000000000000,Logitech F710,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, -030000006d04000019c2000000000000,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, -030000006d0400001ac2000000000000,Logitech Precision Gamepad,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000006d0400001ac2000000000000,Logitech Precision,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, 030000006d04000009c2000000000000,Logitech WingMan,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows, 030000006d0400000ac2000000000000,Logitech WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Windows, 03000000380700005645000000000000,Lynx,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, @@ -333,15 +333,20 @@ 03000000380700008532000000000000,Mad Catz Arcade Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000380700006352000000000000,Mad Catz CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000380700006652000000000000,Mad Catz CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, -03000000380700005032000000000000,Mad Catz FightPad Pro PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, -03000000380700005082000000000000,Mad Catz FightPad PRO PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, -03000000380700008433000000000000,Mad Catz FightStick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, -03000000380700008483000000000000,Mad Catz FightStick TE S PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, -03000000380700008134000000000000,Mad Catz FightStick TE2 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, -03000000380700008184000000000000,Mad Catz FightStick TE2 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,leftstick:b10,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000380700005032000000000000,Mad Catz Fightpad Pro PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700005082000000000000,Mad Catz Fightpad Pro PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000003807000038b7000000000000,Mad Catz Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows, +03000000380700008433000000000000,Mad Catz Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008483000000000000,Mad Catz Fightstick TE S PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008134000000000000,Mad Catz Fightstick TE2 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008184000000000000,Mad Catz Fightstick TE2 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,leftstick:b10,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +78696e70757403000000000000000000,Mad Catz Fightstick TES,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Windows, 03000000380700006252000000000000,Mad Catz Micro CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, -03000000380700001888000000000000,Mad Catz SFIV FightStick PS3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, -03000000380700008081000000000000,Mad Catz SFV Arcade FightStick Alpha PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008232000000000000,Mad Catz PlayStation Brawlpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008731000000000000,Mad Catz PlayStation Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000003807000056a8000000000000,Mad Catz PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700001888000000000000,Mad Catz SFIV Fightstick PS3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000380700008081000000000000,Mad Catz SFV Arcade Fightstick Alpha PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000380700008034000000000000,Mad Catz TE2 PS3 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000380700008084000000000000,Mad Catz TE2 PS4 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 030000002a0600001024000000000000,Matricom,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows, @@ -352,12 +357,13 @@ 03000000242f00007300000000000000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows, 0300000079000000d218000000000000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 03000000d620000010a7000000000000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, -030000008f0e00001030000000000000,Mayflash USB Adapter for original Sega Saturn controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,rightshoulder:b2,righttrigger:b7,start:b9,x:b3,y:b4,platform:Windows, +030000008f0e00001030000000000000,Mayflash Sega Saturn Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,rightshoulder:b2,righttrigger:b7,start:b9,x:b3,y:b4,platform:Windows, 0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows, -03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, -03000000790000002418000000000000,Mega Drive,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b2,start:b9,x:b3,y:b4,platform:Windows, -0300000079000000ae18000000000000,Mega Drive,a:b0,b:b1,back:b7,dpdown:b14,dpleft:b15,dpright:b13,dpup:b2,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, -03000000c0160000990a000000000000,Mega Drive,a:b0,b:b1,leftx:a0,lefty:a1,righttrigger:b2,start:b3,platform:Windows, +03000000790000000018000000000000,Mayflash WiiU Pro Adapter,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000790000002418000000000000,Mega Drive Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b2,start:b9,x:b3,y:b4,platform:Windows, +0300000079000000ae18000000000000,Mega Drive Controller,a:b0,b:b1,back:b7,dpdown:b14,dpleft:b15,dpright:b13,dpup:b2,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, +03000000c0160000990a000000000000,Mega Drive Controller,a:b0,b:b1,leftx:a0,lefty:a1,righttrigger:b2,start:b3,platform:Windows, +030000005e0400002800000000000000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Windows, 030000005e0400000300000000000000,Microsoft SideWinder,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows, 030000005e0400000700000000000000,Microsoft SideWinder,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, 030000005e0400000e00000000000000,Microsoft SideWinder Freestyle Pro,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b8,x:b3,y:b4,platform:Windows, @@ -365,8 +371,9 @@ 03000000280d00000202000000000000,Miller Lite Cantroller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b5,x:b2,y:b3,platform:Windows, 030000005b1c00002500000000000000,Mini,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows, 03000000ad1b000023f0000000000000,MLG,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a6,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, -03000000ad1b00003ef0000000000000,MLG FightStick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows, -03000000380700006382000000000000,MLG GamePad PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000ad1b00003ef0000000000000,MLG Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows, +03000000380700006382000000000000,MLG PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000ffff00000000000000000000,Mocute M053,a:b3,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b11,leftstick:b7,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b6,righttrigger:b4,rightx:a3,righty:a4,start:b8,x:b1,y:b0,platform:Windows, 03000000d6200000e589000000000000,Moga 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows, 03000000d62000007162000000000000,Moga Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows, 03000000d6200000ad0d000000000000,Moga Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, @@ -382,7 +389,8 @@ 030000006b140000100d000000000000,Nacon Revolution Infinity PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000006b140000080d000000000000,Nacon Revolution Unlimited Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000bd12000001c0000000000000,Nebular,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b0,platform:Windows, -03000000eb0300000000000000000000,NeGcon USB Adapter,a:a2,b:b13,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,lefttrigger:a4,leftx:a1,righttrigger:b11,start:b3,x:a3,y:b12,platform:Windows, +03000000eb0300000000000000000000,NeGcon Adapter,a:a2,b:b13,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,lefttrigger:a4,leftx:a1,righttrigger:b11,start:b3,x:a3,y:b12,platform:Windows, +0300000092120000474e000000000000,NeoGeo X Arcade Stick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b3,y:b2,platform:Windows, 0300000038070000efbe000000000000,NEO SE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000921200004b46000000000000,NES 2 port Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Windows, 03000000000f00000100000000000000,NES Controller,a:b1,b:b0,back:b2,leftx:a0,lefty:a1,start:b3,platform:Windows, @@ -392,48 +400,51 @@ 030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Windows, 03000000050b00000045000000000000,Nexus,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Windows, 03000000152000000182000000000000,NGDS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows, -030000007e0500001920000000000000,Nintendo Switch N64 Controller,+rightx:b8,+righty:b2,-rightx:b3,-righty:b7,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b10,start:b9,platform:Windows, +030000007e0500001920000000000000,Nintendo Switch N64 Controller,+rightx:b8,+righty:b2,-rightx:b3,-righty:b7,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Windows, 030000007e0500001720000000000000,Nintendo Switch Online Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Windows, 030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, 030000000d0500000308000000000000,Nostromo N45,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Windows, -03000000d620000013a7000000000000,NSW wired controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, -03000000550900001472000000000000,NVIDIA Controller v01.04,a:b11,b:b10,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b5,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b4,righttrigger:a5,rightx:a3,righty:a6,start:b3,x:b9,y:b8,platform:Windows, +03000000550900001472000000000000,NVIDIA Controller,a:b11,b:b10,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b5,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b4,righttrigger:a5,rightx:a3,righty:a6,start:b3,x:b9,y:b8,platform:Windows, 03000000550900001072000000000000,NVIDIA Shield,a:b9,b:b8,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b3,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b2,righttrigger:a4,rightx:a2,righty:a5,start:b0,x:b7,y:b6,platform:Windows, -030000005509000000b4000000000000,NVIDIA Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005509000000b4000000000000,NVIDIA Virtual,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000120c00000288000000000000,Nyko Air Flo Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, 030000004b120000014d000000000000,Nyko Airflo,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a3,leftstick:a0,lefttrigger:b6,rightshoulder:b5,rightstick:a2,righttrigger:b7,start:b9,x:b2,y:b3,platform:Windows, 03000000d62000001d57000000000000,Nyko Airflo PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, -03000000782300000a10000000000000,Onlive Wireless Controller,a:b15,b:b14,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b11,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b13,y:b12,platform:Windows, +03000000791d00000900000000000000,Nyko Playpad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000782300000a10000000000000,Onlive Controller,a:b15,b:b14,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b11,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b13,y:b12,platform:Windows, 030000000d0f00000401000000000000,Onyx,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 030000008916000001fd000000000000,Onza CE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a3,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 030000008916000000fd000000000000,Onza TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000d62000006d57000000000000,OPP PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000006b14000001a1000000000000,Orange Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows, -03000000362800000100000000000000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows, -03000000120c0000f60e000000000000,P4 Wired Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows, +03000000362800000100000000000000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows, +03000000120c0000f60e000000000000,P4 Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows, +03000000790000002201000000000000,PC Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 030000006f0e00008501000000000000,PDP Fightpad Pro,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b0,platform:Windows, -030000006f0e00000901000000000000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00000901000000000000,PDP Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +03000000e30500009605000000000000,PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, 030000004c050000da0c000000000000,PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows, -03000000d9040000160f000000000000,Playstation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000632500002306000000000000,PlayStation Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows, +03000000f0250000c183000000000000,PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000d9040000160f000000000000,PlayStation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, 030000004c0500003713000000000000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, 03000000d62000006dca000000000000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000d620000013a7000000000000,PowerA Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000006d04000084ca000000000000,Precision,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, 03000000d62000009557000000000000,Pro Elite PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000c62400001a53000000000000,Pro Ex Mini,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000d62000009f31000000000000,Pro Ex mini PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000d6200000c757000000000000,Pro Ex mini PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000120c0000110e000000000000,Pro5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, -03000000632500002306000000000000,PS Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows, -03000000e30500009605000000000000,PS to USB convert cable,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, 03000000100800000100000000000000,PS1 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, 030000008f0e00007530000000000000,PS1 Controller,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b1,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000100800000300000000000000,PS2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000250900000088000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +03000000250900006888000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b6,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, 03000000250900008888000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, 03000000666600006706000000000000,PS2 Controller,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Windows, 030000006b1400000303000000000000,PS2 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, 030000009d0d00001330000000000000,PS2 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, -03000000250900000088000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, -03000000250900006888000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b6,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, 03000000120a00000100000000000000,PS3 Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, 03000000120c00001307000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000120c00001cf1000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, @@ -449,8 +460,6 @@ 030000008f0e00000300000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows, 030000008f0e00001431000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000ba2200002010000000000000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b2,platform:Windows, -030000003807000056a8000000000000,PS3 RF pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, -03000000100000008200000000000000,PS360 v1.66,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:h0.4,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, 03000000120c00000807000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000120c0000111e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000120c0000121e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, @@ -474,8 +483,7 @@ 030000004c050000a00b000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, 030000004c050000cc09000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, -030000004c050000e60c000000000000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, -03000000ff000000cb01000000000000,PSP,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows, +030000004c050000e60c000000000000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, 03000000830500005020000000000000,PSX,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,platform:Windows, 03000000300f00000111000000000000,Qanba 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000300f00000211000000000000,Qanba 2P,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, @@ -489,23 +497,23 @@ 03000000222c00000023000000000000,Qanba Obsidian Arcade Stick PS4,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 030000008a2400006682000000000000,R1 Mobile Controller,a:b3,b:b1,back:b7,leftx:a0,lefty:a1,start:b6,x:b4,y:b0,platform:Windows, 03000000086700006626000000000000,RadioShack,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows, -030000009b2800002300000000000000,Raphnet Technologies 3DO USB Adapter,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b2,start:b3,platform:Windows, -030000009b2800006900000000000000,Raphnet Technologies 3DO USB Adapter,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b2,start:b3,platform:Windows, -030000009b2800000800000000000000,Raphnet Technologies Dreamcast USB Adapter,a:b2,b:b1,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,lefttrigger:a2,leftx:a0,righttrigger:a3,righty:a1,start:b3,x:b10,y:b9,platform:Windows, -030000009b2800003200000000000000,Raphnet Technologies GC/N64 to USB v3.4,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows, -030000009b2800006000000000000000,Raphnet Technologies GC/N64 to USB v3.6,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows, -030000009b2800001800000000000000,Raphnet Technologies Jaguar USB Adapter,a:b2,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b10,start:b3,x:b11,y:b12,platform:Windows, -030000009b2800000200000000000000,Raphnet Technologies NES USB Adapter,a:b7,b:b6,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b4,platform:Windows, -030000009b2800004300000000000000,Raphnet Technologies Saturn,a:b0,b:b1,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows, -030000009b2800000500000000000000,Raphnet Technologies Saturn Adapter 2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows, -030000009b2800000300000000000000,Raphnet Technologies SNES USB Adapter,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows, -030000009b2800005600000000000000,Raphnet Technologies SNES USB Adapter,a:b1,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows, -030000009b2800005700000000000000,Raphnet Technologies SNES USB Adapter,a:b1,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows, -030000009b2800001e00000000000000,Raphnet Technologies Vectrex USB Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a1,lefty:a2,x:b2,y:b3,platform:Windows, -030000009b2800002b00000000000000,Raphnet Technologies Wii Classic USB Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows, -030000009b2800002c00000000000000,Raphnet Technologies Wii Classic USB Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows, +030000009b2800002300000000000000,Raphnet 3DO Adapter,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b2,start:b3,platform:Windows, +030000009b2800006900000000000000,Raphnet 3DO Adapter,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b2,start:b3,platform:Windows, +030000009b2800000800000000000000,Raphnet Dreamcast Adapter,a:b2,b:b1,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,lefttrigger:a2,leftx:a0,righttrigger:a3,righty:a1,start:b3,x:b10,y:b9,platform:Windows, +030000009b2800003200000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows, +030000009b2800006000000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows, +030000009b2800001800000000000000,Raphnet Jaguar Adapter,a:b2,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b10,start:b3,x:b11,y:b12,platform:Windows, +030000009b2800000200000000000000,Raphnet NES Adapter,a:b7,b:b6,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b4,platform:Windows, +030000009b2800004300000000000000,Raphnet Saturn,a:b0,b:b1,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows, +030000009b2800000500000000000000,Raphnet Saturn Adapter 2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows, +030000009b2800000300000000000000,Raphnet SNES Adapter,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows, +030000009b2800005600000000000000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows, +030000009b2800005700000000000000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows, +030000009b2800001e00000000000000,Raphnet Vectrex Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a1,lefty:a2,x:b2,y:b3,platform:Windows, +030000009b2800002b00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows, +030000009b2800002c00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows, 03000000321500000003000000000000,Razer Hydra,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, -03000000321500000204000000000000,Razer Panthera PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000321500000204000000000000,Razer Panthera PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000321500000104000000000000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000321500000010000000000000,Razer Raiju,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000321500000507000000000000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, @@ -514,14 +522,14 @@ 03000000321500000a10000000000000,Razer Raiju TE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000321500000410000000000000,Razer Raiju UE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000321500000910000000000000,Razer Raiju UE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, -03000000321500000011000000000000,Razer Raion Fightpad for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000321500000011000000000000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000321500000009000000000000,Razer Serval,+lefty:+a2,-lefty:-a1,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,leftx:a0,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows, 03000000830500006020000000000000,Retro Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b8,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows, -03000000bd12000013d0000000000000,Retrolink USB Sega Saturn Classic,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,lefttrigger:b6,rightshoulder:b2,righttrigger:b7,start:b8,x:b3,y:b4,platform:Windows, -03000000bd12000015d0000000000000,Retrolink USB Super SNES Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows, -0300000000f000000300000000000000,RetroUSB.com RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows, -0300000000f00000f100000000000000,RetroUSB.com Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows, +03000000bd12000013d0000000000000,Retrolink Sega Saturn Classic Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,lefttrigger:b6,rightshoulder:b2,righttrigger:b7,start:b8,x:b3,y:b4,platform:Windows, +03000000bd12000015d0000000000000,Retrolink Super SNES Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows, +0300000000f000000300000000000000,RetroUSB RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows, +0300000000f00000f100000000000000,RetroUSB Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows, 03000000830500000960000000000000,Revenger,a:b0,b:b1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b3,x:b4,y:b5,platform:Windows, 030000006b140000010d000000000000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 030000006b140000020d000000000000,Revolution Pro Controller 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, @@ -533,25 +541,23 @@ 030000006f0e00002801000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000006f0e00002f01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000004f04000001d0000000000000,Rumble Force,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows, -030000004f04000003d0000000000000,Run N Drive,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:a3,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:a4,rightstick:b11,righttrigger:b5,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, -030000004f04000009d0000000000000,Run N Drive,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000008916000000fe000000000000,Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000c6240000045d000000000000,Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000a30600001af5000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, -03000000a306000023f6000000000000,Saitek Cyborg V.1 Game pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows, -03000000300f00001201000000000000,Saitek Dual Analog Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, +03000000a306000023f6000000000000,Saitek Cyborg V.1 Game,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000300f00001201000000000000,Saitek Dual Analog,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, 03000000a30600000701000000000000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Windows, -03000000a30600000cff000000000000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b0,y:b1,platform:Windows, +03000000a30600000cff000000000000,Saitek P2500 Force Rumble,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b0,y:b1,platform:Windows, 03000000a30600000d5f000000000000,Saitek P2600,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Windows, 03000000a30600000dff000000000000,Saitek P2600,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b8,x:b0,y:b3,platform:Windows, 03000000a30600000c04000000000000,Saitek P2900,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows, 03000000a306000018f5000000000000,Saitek P3200,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, -03000000300f00001001000000000000,Saitek P480 Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, +03000000300f00001001000000000000,Saitek P480 Rumble,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, 03000000a30600000901000000000000,Saitek P880,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b8,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b5,rightx:a3,righty:a2,x:b0,y:b1,platform:Windows, 03000000a30600000b04000000000000,Saitek P990,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows, -03000000a30600002106000000000000,Saitek PS1000,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows, -03000000a306000020f6000000000000,Saitek PS2700,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows, -03000000300f00001101000000000000,Saitek Rumble Pad,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, +03000000a30600002106000000000000,Saitek PS1000 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000a306000020f6000000000000,Saitek PS2700 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000300f00001101000000000000,Saitek Rumble,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, 03000000e804000000a0000000000000,Samsung EIGP20,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 03000000c01100000252000000000000,Sanwa Easy Grip,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, 03000000c01100004350000000000000,Sanwa Micro Grip P3,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,x:b3,y:b2,platform:Windows, @@ -560,25 +566,27 @@ 03000000c01100004450000000000000,Sanwa Online Grip,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b11,righttrigger:b9,rightx:a3,righty:a2,start:b14,x:b3,y:b4,platform:Windows, 03000000730700000401000000000000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Windows, 03000000830500006120000000000000,Sanwa Smart Grip II,a:b0,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,x:b1,y:b3,platform:Windows, -03000000c01100000051000000000000,Satechi Bluetooth Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000c01100000051000000000000,Satechi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, 030000004f04000028b3000000000000,Score A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000952e00002577000000000000,Scuf PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000a30c00002500000000000000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Windows, 03000000a30c00002400000000000000,Sega Mega Drive Mini 6B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows, -0300000000050000289b000000000000,Sega Saturn Adapter 2,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows, +0300000000050000289b000000000000,Sega Saturn Adapter,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows, 0300000000f000000800000000000000,Sega Saturn Controller,a:b1,b:b2,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b3,start:b0,x:b5,y:b6,platform:Windows, 03000000730700000601000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, 03000000b40400000a01000000000000,Sega Saturn Controller,a:b0,b:b1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows, 030000003b07000004a1000000000000,SFX,a:b0,b:b2,back:b7,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Windows, -03000000120c00001c1e000000000000,SnakeByte GamePad 4S PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000120c00001c1e000000000000,SnakeByte 4S PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 0300000003040000c197000000000000,SNES Controller,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows, 03000000571d00002000000000000000,SNES Controller,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows, 0300000081170000960a000000000000,SNES Controller,a:b4,b:b0,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b5,y:b1,platform:Windows, 03000000811700009d0a000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows, 030000008b2800000300000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows, 03000000921200004653000000000000,SNES Controller,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows, +03000000ff000000cb01000000000000,Sony PlayStation Portable,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows, 03000000341a00000208000000000000,Speedlink 6555,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:-a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a3,righty:a2,start:b7,x:b2,y:b3,platform:Windows, 03000000341a00000908000000000000,Speedlink 6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000380700001722000000000000,Speedlink Competition Pro,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,x:b2,y:b3,platform:Windows, 030000008f0e00000800000000000000,Speedlink Strike FX,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 03000000c01100000591000000000000,Speedlink Torid,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 03000000d11800000094000000000000,Stadia Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b11,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows, @@ -592,11 +600,11 @@ 03000000790000001c18000000000000,STK 7024X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 03000000381000003014000000000000,Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000381000003114000000000000,Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, -03000000380700003847000000000000,Street Fighter Fighting Stick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,start:b7,x:b2,y:b3,platform:Windows, +03000000380700003847000000000000,Street Fighter Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,start:b7,x:b2,y:b3,platform:Windows, 030000001f08000001e4000000000000,Super Famicom Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows, 03000000790000000418000000000000,Super Famicom Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b33,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows, -03000000d620000011a7000000000000,Switch,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, -030000000d0f0000f600000000000000,Switch Hori Pad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000d620000011a7000000000000,Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f0000f600000000000000,Switch Hori,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, 03000000457500002211000000000000,Szmy Power PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000004f0400000ab1000000000000,T16000M,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b10,x:b2,y:b3,platform:Windows, 030000000d0f00007b00000000000000,TAC GEAR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, @@ -607,45 +615,46 @@ 03000000c61100001000000000000000,Tencent Xianyou Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,x:b3,y:b4,platform:Windows, 03000000790000002601000000000000,TGZ,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows, 030000004f04000015b3000000000000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows, -030000004f04000023b3000000000000,Thrustmaster Dual Trigger 3 in 1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, -030000004f0400000ed0000000000000,ThrustMaster eSwap PRO Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000004f04000023b3000000000000,Thrustmaster Dual Trigger PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000004f0400000ed0000000000000,ThrustMaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000004f04000008d0000000000000,ThrustMaster Ferrari 150 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Windows, 030000004f04000004b3000000000000,Thrustmaster Firestorm Dual Power 3,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows, +030000004f04000003d0000000000000,ThrustMaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:a3,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:a4,rightstick:b11,righttrigger:b5,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000004f04000009d0000000000000,ThrustMaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000006d04000088ca000000000000,Thunderpad,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, -03000000666600000488000000000000,TigerGame PS/PS2 Game Controller Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, -030000004f04000007d0000000000000,TMini Wireless,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000666600000488000000000000,TigerGame PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +030000004f04000007d0000000000000,TMini,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000d62000006000000000000000,Tournament PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000c01100000055000000000000,Tronsmart,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 030000005f140000c501000000000000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 03000000b80500000210000000000000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 030000004f04000087b6000000000000,TWCS Throttle,dpdown:b8,dpleft:b9,dpright:b7,dpup:b6,leftstick:b5,lefttrigger:-a5,leftx:a0,lefty:a1,righttrigger:+a5,platform:Windows, 03000000411200000450000000000000,Twin Shock,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a4,start:b11,x:b3,y:b0,platform:Windows, -03000000d90400000200000000000000,TwinShock PS2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000d90400000200000000000000,TwinShock PS2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, 03000000101c0000171c000000000000,uRage Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, -030000000b0400003065000000000000,USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows, -03000000242f00006e00000000000000,USB Game Controller,a:b1,b:b4,back:b10,leftshoulder:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b7,rightx:a2,righty:a5,start:b11,x:b0,y:b3,platform:Windows, -03000000300f00000701000000000000,USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, -03000000341a00002308000000000000,USB Game Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, -03000000666600000188000000000000,USB Game Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, -03000000666600000288000000000000,USB Game Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, -030000006b1400000203000000000000,USB Game Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, -03000000790000000a00000000000000,USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows, -03000000b404000081c6000000000000,USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows, -03000000b50700001503000000000000,USB Game Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b0,y:b1,platform:Windows, -03000000bd12000012d0000000000000,USB Game Controller,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows, -03000000f0250000c183000000000000,USB Game Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, -03000000ff1100004133000000000000,USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +030000000b0400003065000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows, +03000000242f00006e00000000000000,USB Controller,a:b1,b:b4,back:b10,leftshoulder:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b7,rightx:a2,righty:a5,start:b11,x:b0,y:b3,platform:Windows, +03000000300f00000701000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000341a00002308000000000000,USB Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000666600000188000000000000,USB Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +03000000666600000288000000000000,USB Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +030000006b1400000203000000000000,USB Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000790000000a00000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows, +03000000b404000081c6000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows, +03000000b50700001503000000000000,USB Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b0,y:b1,platform:Windows, +03000000bd12000012d0000000000000,USB Controller,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows, +03000000ff1100004133000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows, 03000000632500002305000000000000,USB Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 03000000790000001a18000000000000,Venom,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000790000001b18000000000000,Venom Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, -030000006f0e00000302000000000000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, -030000006f0e00000702000000000000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00000302000000000000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00000702000000000000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, 0300000034120000adbe000000000000,vJoy Device,a:b0,b:b1,back:b15,dpdown:b6,dpleft:b7,dpright:b8,dpup:b5,guide:b16,leftshoulder:b9,leftstick:b13,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b14,righttrigger:b12,rightx:a3,righty:a4,start:b4,x:b2,y:b3,platform:Windows, 03000000120c0000ab57000000000000,Warrior Joypad JS083,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 030000007e0500003003000000000000,WiiU Pro,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,leftshoulder:b6,leftstick:b11,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b12,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows, 0300000032150000030a000000000000,Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 030000005e040000ff02000000000000,Wired Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, -030000005e040000ea02000000000000,Wireless Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 0300000032150000140a000000000000,Wolverine,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 030000002e160000efbe000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,rightshoulder:b5,righttrigger:b11,start:b7,x:b2,y:b3,platform:Windows, 03000000380700001647000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, @@ -683,47 +692,51 @@ 030000005e040000dd02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 030000005e040000e002000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 030000005e040000e302000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 030000005e040000fd02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 030000006f0e0000a802000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 030000006f0e0000c802000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000c62400003a54000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 030000005e040000130b000000000000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000341a00000608000000000000,Xeox,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, -03000000450c00002043000000000000,Xeox Gamepad SL6556BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000450c00002043000000000000,Xeox SL6556BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, 030000006f0e00000300000000000000,XGear,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a5,righty:a2,start:b9,x:b3,y:b0,platform:Windows, 03000000ac0500005b05000000000000,Xiaoji Gamesir G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, -03000000172700004431000000000000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a7,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000172700004431000000000000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a7,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, 03000000786901006e70000000000000,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000790000004f18000000000000,ZDT Android Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, -03000000120c0000101e000000000000,Zeroplus P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000120c0000101e000000000000,Zeroplus P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, # Mac OS X -030000008f0e00000300000009010000,2In1 USB Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +030000008f0e00000300000009010000,2In1 Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000c82d00000031000001000000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00000531000000020000,8BitDo Adapter 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000c82d00000090000001000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000c82d00000650000001000000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Mac OS X, -03000000c82d00005106000000010000,8BitDo M30 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00005106000000010000,8BitDo M30,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000c82d00001590000001000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +030000003512000012ab000001000000,8BitDo NES30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000c82d000012ab000001000000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000c82d00002028000000010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X, -030000003512000012ab000001000000,8BitDo NES30 Gamepad,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000022000000090000001000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000203800000900000000010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000c82d00000190000001000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, -03000000102800000900000000000000,8Bitdo SFC30 GamePad Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, -03000000c82d00001290000001000000,8BitDo SN30 Gamepad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, -03000000c82d00004028000000010000,8Bitdo SN30 GamePad,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000660000000020000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000102800000900000000000000,8Bitdo SFC30 Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00001290000001000000,8BitDo SN30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00004028000000010000,8Bitdo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000c82d00000160000001000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000c82d00000260000001000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000c82d00000261000000010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, -03000000c82d00000031000001000000,8BitDo Wireless Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000a00500003232000008010000,8Bitdo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000a00500003232000009010000,8Bitdo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000c82d00001890000001000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a31,start:b11,x:b4,y:b3,platform:Mac OS X, -03000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X, -03000000a00500003232000009010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000491900001904000001010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Mac OS X, 03000000710100001904000000010000,Amazon Luna Controller,a:b0,b:b1,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X, 03000000a30c00002700000003030000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X, @@ -738,7 +751,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000008305000031b0000000000000,Cideko AK08b,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000d8140000cecf000000000000,Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Mac OS X, -03000000a306000022f6000001030000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000a306000022f6000001030000,Cyborg V3 Rumble Pad PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X, 030000000d0f00008400000000010000,Fighting Commander,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, 030000000d0f00008500000000010000,Fighting Commander,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000151900004000000001000000,Flydigi Vader 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, @@ -747,17 +760,17 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000ad1b000001f9000000000000,Gamestop BB070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, 03000000c01100000140000000010000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, -030000006f0e00000102000000000000,GameStop Xbox 360 Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, -030000007d0400000540000001010000,Gravis Eliminator GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006f0e00000102000000000000,GameStop Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000007d0400000540000001010000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000280400000140000000020000,Gravis Gamepad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, -030000008f0e00000300000007010000,GreenAsia USB Joystick,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Mac OS X, +030000008f0e00000300000007010000,GreenAsia Joystick,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Mac OS X, 030000000d0f00002d00000000100000,Hori Fighting Commander 3 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 030000000d0f00005f00000000000000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 030000000d0f00005f00000000010000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 030000000d0f00005e00000000000000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 030000000d0f00005e00000000010000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, 030000000d0f00004d00000000000000,Hori Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, -030000000d0f00009200000000010000,Hori Pokken Tournament DX Pro Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00009200000000010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, 030000000d0f00006e00000000010000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 030000000d0f00006600000000010000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, 030000000d0f00006600000000000000,Horipad FPS Plus 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, @@ -766,20 +779,20 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000830500006020000000000000,iBuffalo Gamepad,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X, 030000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Mac OS X, 030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Mac OS X, -03000000242f00002d00000007010000,JYS Wireless Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000242f00002d00000007010000,JYS Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +030000006d04000019c2000000000000,Logitech Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 030000006d04000016c2000000020000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 030000006d04000016c2000000030000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 030000006d04000016c2000014040000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, -030000006d04000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, -030000006d04000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, -030000006d04000019c2000005030000,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, -030000006d0400001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, -030000006d04000018c2000000010000,Logitech RumblePad 2 USB,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3~,start:b9,x:b0,y:b3,platform:Mac OS X, -030000006d04000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, -03000000380700005032000000010000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, -03000000380700005082000000010000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, -03000000380700008433000000010000,Mad Catz FightStick TE S+ (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, -03000000380700008483000000010000,Mad Catz FightStick TE S+ (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d04000016c2000000000000,Logitech F310,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d04000018c2000000000000,Logitech F510,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d04000019c2000005030000,Logitech F710,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d0400001fc2000000000000,Logitech F710,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000006d04000018c2000000010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3~,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000380700005032000000010000,Mad Catz PS3 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000380700008433000000010000,Mad Catz PS3 Fightstick TE S+,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000380700005082000000010000,Mad Catz PS4 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000380700008483000000010000,Mad Catz PS4 Fightstick TE S+,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000790000000600000007010000,Marvo GT-004,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, 03000000790000004418000000010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000242f00007300000000020000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Mac OS X, @@ -787,22 +800,23 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000d620000010a7000003010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Mac OS X, 03000000790000000018000000010000,Mayflash Wii U Pro Controller Adapter,a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X, -03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X, +03000000790000000018000000000000,Mayflash WiiU Pro Adapter,a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X, +030000005e0400002800000002010000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Mac OS X, 030000005e0400002700000001010000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,platform:Mac OS X, -03000000d62000007162000001000000,Moga Pro 2 HID,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X, +03000000d62000007162000001000000,Moga Pro 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X, 03000000c62400002a89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000c62400002b89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, -03000000632500007505000000020000,NEOGEO mini PAD Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,platform:Mac OS X, +03000000632500007505000000020000,NeoGeo mini PAD Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,platform:Mac OS X, 03000000921200004b46000003020000,NES 2-port Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Mac OS X, 030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Mac OS X, -03000000d620000011a7000000020000,Nintendo Switch Core Plus Wired Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, -03000000d620000011a7000010050000,Nintendo Switch PowerA Wired Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000d620000011a7000000020000,Nintendo Switch Core Plus Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000d620000011a7000010050000,Nintendo Switch PowerA Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, 030000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, -03000000550900001472000025050000,NVIDIA Controller v01.04,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Mac OS X, -030000006f0e00000901000002010000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000550900001472000025050000,NVIDIA Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Mac OS X, +030000006f0e00000901000002010000,PDP Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, 030000008f0e00000300000000000000,Piranha Xtreme PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Mac OS X, -030000004c050000da0c000000010000,Playstation Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X, +030000004c050000da0c000000010000,PlayStation Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X, 030000004c0500003713000000010000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000d62000006dca000000010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000100800000300000006010000,PS2 Adapter,a:b2,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, @@ -812,13 +826,13 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, 030000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, 030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, -050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, 030000008916000000fd000000000000,Razer Onza TE,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, -03000000321500000204000000010000,Razer Panthera PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000321500000204000000010000,Razer Panthera PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000321500000104000000010000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000321500000010000000010000,Razer Raiju,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000321500000507000001010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, -03000000321500000011000000010000,Razer Raion Fightpad for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000321500000011000000010000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000321500000009000000020000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X, 030000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X, 0300000032150000030a000000000000,Razer Wildcat,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, @@ -828,15 +842,15 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000790000001100000006010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X, 030000006b140000010d000000010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, 030000006b140000130d000000010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, -03000000c6240000fefa000000000000,Rock Candy Gamepad for PS3,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000c6240000fefa000000000000,Rock Candy PS3,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 03000000730700000401000000010000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Mac OS X, 03000000811700007e05000000000000,Sega Saturn,a:b2,b:b4,dpdown:b16,dpleft:b15,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,leftx:a0,lefty:a2,rightshoulder:b9,righttrigger:a4,start:b13,x:b0,y:b6,platform:Mac OS X, -03000000b40400000a01000000000000,Sega Saturn USB Gamepad,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X, +03000000b40400000a01000000000000,Sega Saturn,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X, 030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, 0300000000f00000f100000000000000,SNES RetroPort,a:b2,b:b3,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,rightshoulder:b7,start:b6,x:b0,y:b1,platform:Mac OS X, 030000004c050000e60c000000010000,Sony DualSense,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000004c050000a00b000000000000,Sony DualShock 4 Adapter,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, 030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, -030000004c050000a00b000000000000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000d11800000094000000010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X, 030000005e0400008e02000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 03000000110100002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,platform:Mac OS X, @@ -844,46 +858,51 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000381000002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X, 05000000484944204465766963650000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X, 050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X, +050000004e696d6275732b008b000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X, 05000000556e6b6e6f776e2048494400,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X, 03000000110100001714000000000000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X, 03000000110100001714000020010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X, 03000000457500002211000000010000,SZMY Power PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 030000004f04000015b3000000000000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Mac OS X, -030000004f0400000ed0000000020000,ThrustMaster eSwap PRO Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000004f0400000ed0000000020000,ThrustMaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, 030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Mac OS X, -03000000bd12000015d0000000000000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X, 03000000bd12000015d0000000010000,Tomee Retro Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000bd12000015d0000000000000,Tomee SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X, 03000000100800000100000000000000,Twin USB Joystick,a:b4,b:b2,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b12,leftstick:b20,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b14,rightstick:b22,righttrigger:b10,rightx:a6,righty:a4,start:b18,x:b6,y:b0,platform:Mac OS X, -030000006f0e00000302000025040000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, -030000006f0e00000702000003060000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006f0e00000302000025040000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006f0e00000702000003060000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000791d00000103000009010000,Wii Classic Controller,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, 050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,back:b7,dpdown:b3,dpleft:b0,dpright:b1,dpup:b2,guide:b8,leftshoulder:b11,lefttrigger:b12,leftx:a0,lefty:a1,start:b6,x:b10,y:b9,platform:Mac OS X, 050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b8,leftshoulder:b19,leftstick:b23,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b24,righttrigger:b22,rightx:a2,righty:a3,start:b6,x:b18,y:b17,platform:Mac OS X, 030000005e0400008e02000000000000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, -030000006f0e00000104000000000000,Xbox 360 Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, -03000000c6240000045d000000000000,Xbox 360 Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000006f0e00000104000000000000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000c6240000045d000000000000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 030000005e0400000a0b000000000000,Xbox Adaptive Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, -030000005e040000050b000003090000,Xbox Elite Wireless Controller Series 2,a:b0,b:b1,back:b31,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b53,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, -03000000c62400003a54000000000000,Xbox One PowerA Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, -030000005e040000d102000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, -030000005e040000dd02000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, -030000005e040000e302000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e040000050b000003090000,Xbox Elite Controller Series 2,a:b0,b:b1,back:b31,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b53,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000130b000011050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000200b000011050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000d102000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e040000dd02000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e040000e002000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X, +030000005e040000e002000003090000,Xbox One Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000e302000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e040000fd02000003090000,Xbox One Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c62400003a54000000000000,Xbox One PowerA Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 030000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 030000005e040000130b000009050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, -030000005e040000200b000011050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, -030000005e040000e002000000000000,Xbox Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X, -030000005e040000e002000003090000,Xbox Wireless Controller,a:b0,b:b1,x:b3,y:b4,back:b16,guide:b15,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Mac OS X, -030000005e040000ea02000000000000,Xbox Wireless Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, -030000005e040000fd02000003090000,Xbox Wireless Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, -03000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Mac OS X, -03000000120c0000100e000000010000,Zeroplus P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, -03000000120c0000101e000000010000,Zeroplus P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000120c0000100e000000010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000120c0000101e000000010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, # Linux +030000005e0400008e02000020010000,8BitDo Adapter,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c82d00000031000011010000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 03000000021000000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, 03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, 05000000c82d00001038000000010000,8Bitdo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000650000011010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b11,x:b3,y:b4,platform:Linux, 05000000c82d00005106000000010000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Linux, 03000000c82d00001590000011010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, 05000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, @@ -894,13 +913,15 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000c82d00000190000011010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, 05000000203800000900000000010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, 05000000c82d00002038000000010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000660000011010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, 05000000c82d00000060000000010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, 05000000c82d00000061000000010000,8Bitdo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +030000003512000012ab000010010000,8Bitdo SFC30,a:b2,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Linux, 030000003512000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, 03000000c82d000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, -030000003512000012ab000010010000,8Bitdo SFC30 GamePad,a:b2,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Linux, -05000000102800000900000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, -05000000c82d00003028000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, +05000000102800000900000000010000,8Bitdo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00003028000000010000,8Bitdo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, 03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux, 03000000c82d00000160000011010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, 03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux, @@ -909,22 +930,20 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 05000000c82d00006228000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, 03000000c82d00000260000011010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, 05000000c82d00000261000000010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, -05000000202800000900000000010000,8BitDo SNES30 Gamepad,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, -03000000c82d00000031000011010000,8BitDo Wireless Adapter (DInput),a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, -030000005e0400008e02000020010000,8BitDo Wireless Adapter (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +05000000202800000900000000010000,8BitDo SNES30,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, +05000000a00500003232000001000000,8Bitdo Zero,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux, +05000000a00500003232000008010000,8Bitdo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux, 03000000c82d00001890000011010000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, +050000005e040000e002000030110000,8BitDo Zero 2,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux, 05000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, -050000005e040000e002000030110000,8BitDo Zero 2 (XInput),a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux, -05000000a00500003232000001000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux, -05000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux, 03000000c01100000355000011010000,Acrux Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, -030000006f0e00001302000000010000,Afterglow,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000006f0e00003901000020060000,Afterglow Controller for Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006f0e00003901000000430000,Afterglow Prismatic Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000006f0e00003901000013020000,Afterglow Prismatic Wired Controller 048-007-NA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -03000000100000008200000011010000,Akishop Customs PS360 v1.66,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, -030000007c1800000006000010010000,Alienware Dual Compatible Game Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Linux, -05000000491900000204000021000000,Amazon Fire Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b17,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +030000006f0e00003901000013020000,Afterglow Prismatic Controller 048-007-NA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00001302000000010000,Afterglow Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00003901000020060000,Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000100000008200000011010000,Akishop Customs PS360,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000007c1800000006000010010000,Alienware Dual Compatible Game PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Linux, +05000000491900000204000021000000,Amazon Fire Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b17,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 03000000491900001904000011010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Linux, 05000000710100001904000000010000,Amazon Luna Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux, 03000000790000003018000011010000,Arcade Fightstick F300,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, @@ -933,17 +952,24 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 05000000050b00000045000031000000,Asus Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux, 05000000050b00000045000040000000,Asus Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux, 03000000503200000110000000000000,Atari Classic Controller,a:b0,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,x:b1,platform:Linux, +03000000503200000110000011010000,Atari Classic Controller,a:b0,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,x:b1,platform:Linux, 05000000503200000110000000000000,Atari Classic Controller,a:b0,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,x:b1,platform:Linux, -03000000503200000210000000000000,Atari Game Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Linux, -05000000503200000210000000000000,Atari Game Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux, +05000000503200000110000044010000,Atari Classic Controller,a:b0,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,x:b1,platform:Linux, +05000000503200000110000046010000,Atari Classic Controller,a:b0,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,x:b1,platform:Linux, +03000000503200000210000000000000,Atari Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Linux, +03000000503200000210000011010000,Atari Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux, +05000000503200000210000000000000,Atari Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux, +05000000503200000210000045010000,Atari Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux, +05000000503200000210000046010000,Atari Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux, 03000000120c00000500000010010000,AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux, 03000000ef0500000300000000010000,AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux, 03000000c62400001b89000011010000,BDA MOGA XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 03000000d62000002a79000011010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, 03000000c21100000791000011010000,Be1 GC101 Controller 1.03,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, -03000000c31100000791000011010000,Be1 GC101 GAMEPAD 1.03,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000c31100000791000011010000,Be1 GC101 Controller 1.03,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 030000005e0400008e02000003030000,Be1 GC101 Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 05000000bc2000000055000001000000,BETOP AX1 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000bc2000006412000011010000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b30,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, 030000006b1400000209000011010000,Bigben,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000666600006706000000010000,Boom PSX to PC Converter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Linux, 03000000120c0000200e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, @@ -952,11 +978,12 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, 030000000b0400003365000000010000,Competition Pro,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Linux, 03000000260900008888000000010000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Linux, -03000000a306000022f6000011010000,Cyborg V3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux, +03000000a306000022f6000011010000,Cyborg V3 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux, 030000004f04000004b3000010010000,Dual Power 2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux, 030000006f0e00003001000001010000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000c11100000191000011010000,EasySMX,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, 030000006e0500000320000010010000,Elecom U3613M,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Linux, +030000006e0500000720000010010000,Elecom W01U,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Linux, 03000000430b00000300000000010000,EMS Production PS2 Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a5,righty:a2,start:b9,x:b3,y:b0,platform:Linux, 03000000b40400001124000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 05000000151900004000000001000000,Flydigi Vader 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, @@ -969,26 +996,29 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000451300000010000010010000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 03000000f0250000c183000010010000,Goodbetterbest Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 0300000079000000d418000000010000,GPD Win 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000007d0400000540000000010000,Gravis Eliminator GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, -03000000280400000140000000010000,Gravis GamePad Pro USB,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000007d0400000540000000010000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +03000000280400000140000000010000,Gravis Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, 030000008f0e00000610000000010000,GreenAsia Electronics Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Linux, -030000008f0e00001200000010010000,GreenAsia USB Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux, +030000008f0e00001200000010010000,GreenAsia Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux, 0500000047532067616d657061640000,GS gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 03000000f0250000c383000010010000,GT VX2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, -06000000adde0000efbe000002010000,Hidromancer Game Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +06000000adde0000efbe000002010000,Hidromancer Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000d81400000862000011010000,HitBox PS3 PC Analog Mode,a:b1,b:b2,back:b8,guide:b9,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,y:b3,platform:Linux, -03000000c9110000f055000011010000,HJC Game Gamepqd,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +03000000c9110000f055000011010000,HJC Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 03000000632500002605000010010000,HJDX,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 030000000d0f00000d00000000010000,Hori,a:b0,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,rightshoulder:b7,start:b9,x:b1,y:b2,platform:Linux, +030000000d0f00006d00000020010000,Hori EDGE 301,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:+a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000000d0f00008500000010010000,Hori Fighting Commander,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000000d0f00008600000002010000,Hori Fighting Commander,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 030000000d0f00005f00000011010000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000000d0f00005e00000011010000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, -030000000d0f00005001000009040000,Hori Fighting Commander OCTA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000000d0f00001000000011010000,Hori Fighting Stick 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00005001000009040000,Hori Fighting Commander OCTA Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000000d0f00001000000011010000,Hori Fightstick 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +03000000ad1b000003f5000033050000,Hori Fightstick VX,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b8,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux, +030000000d0f00004d00000011010000,HORI Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000000d0f00003801000011010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Linux, -030000000d0f00009200000011010000,Hori Pokken Tournament DX Pro Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00009200000011010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, 030000000d0f0000aa00000011010000,Hori Real Arcade Pro,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, 030000000d0f00002200000011010000,Hori Real Arcade Pro 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, 030000000d0f00006a00000011010000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, @@ -999,53 +1029,56 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000000d0f0000ee00000011010000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, 030000000d0f00006700000001010000,Horipad One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000000d0f0000c100000011010000,Horipad S,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, -03000000341a000005f7000010010000,HuiJia GameCube Controller Adpater,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux, +050000000d0f0000f600000001000000,HORIPAD Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +03000000341a000005f7000010010000,HuiJia GameCube Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux, 030000008f0e00001330000010010000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,platform:Linux, 03000000242e00008816000001010000,Hyperkin X91,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 050000006964726f69643a636f6e0000,idroidcon Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000b50700001503000010010000,Impact,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux, -03000000d80400008200000003000000,IMS PCU0 Gamepad,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b5,x:b3,y:b2,platform:Linux, +03000000d80400008200000003000000,IMS PCU0,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b5,x:b3,y:b2,platform:Linux, 03000000fd0500000030000000010000,InterAct GoPad I73000,a:b3,b:b4,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b7,x:b0,y:b1,platform:Linux, -0500000049190000020400001b010000,Ipega PG 9069 Bluetooth Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b161,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, -03000000632500007505000011010000,Ipega PG 9099 Bluetooth Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000fd0500002a26000000010000,InterAct HammerHead FX,a:b3,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b2,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Linux, +0500000049190000020400001b010000,Ipega PG 9069,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b161,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000632500007505000011010000,Ipega PG 9099,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, 0500000049190000030400001b010000,Ipega PG9099,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 05000000491900000204000000000000,Ipega PG9118,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, -03000000300f00001001000010010000,Jess Tech Dual Analog Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux, -03000000300f00000b01000010010000,Jess Tech GGE909 PC Recoil Pad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, -03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +03000000300f00001001000010010000,Jess Tech Dual Analog Rumble,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux, +03000000300f00000b01000010010000,Jess Tech GGE909 PC Recoil,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +03000000ba2200002010000001010000,Jess Technology Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, 030000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Linux, 050000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Linux, 030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Linux, 050000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Linux, 03000000bd12000003c0000010010000,Joypad Alpha Shock,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, -03000000242f00002d00000011010000,JYS Wireless Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, -03000000242f00008a00000011010000,JYS Wireless Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux, +03000000242f00002d00000011010000,JYS Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000242f00008a00000011010000,JYS Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux, 030000006f0e00000103000000020000,Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006d040000d1ca000000000000,Logitech Chillstream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000006d04000016c2000010010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000006d04000016c2000011010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, -030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000006d0400001ec2000019200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, -030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d0400001dc2000014400000,Logitech F310,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d0400001ec2000019200000,Logitech F510,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d0400001ec2000020200000,Logitech F510,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d04000019c2000011010000,Logitech F710,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d0400001fc2000005030000,Logitech F710,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006d04000018c2000010010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b10,rightx:a3,righty:a4,start:b8,x:b3,y:b4,platform:Linux, 030000006d0400000ac2000010010000,Logitech WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Linux, 05000000380700006652000025010000,Mad Catz CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, -03000000380700005032000011010000,Mad Catz FightPad PRO PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, -03000000380700005082000011010000,Mad Catz FightPad PRO PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000380700008532000010010000,Mad Catz Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +03000000380700005032000011010000,Mad Catz Fightpad Pro PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700005082000011010000,Mad Catz Fightpad Pro PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, 03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux, -03000000380700008034000011010000,Mad Catz fightstick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, -03000000380700008084000011010000,Mad Catz fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, -03000000380700008433000011010000,Mad Catz FightStick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, -03000000380700008483000011010000,Mad Catz FightStick TE S PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, -03000000380700001647000010040000,Mad Catz Wired Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -03000000380700003847000090040000,Mad Catz Wired Xbox 360 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +03000000380700008034000011010000,Mad Catz Fightstick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700008084000011010000,Mad Catz Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000380700008433000011010000,Mad Catz Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700008483000011010000,Mad Catz Fightstick TE S PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000380700001888000010010000,Mad Catz Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700003888000010010000,Mad Catz Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:a0,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700001647000010040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000380700003847000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -03000000380700001888000010010000,MadCatz PC USB Wired Stick 8818,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, -03000000380700003888000010010000,MadCatz PC USB Wired Stick 8838,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:a0,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000120c00000500000000010000,Manta Dualshock 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux, 03000000790000004418000010010000,Mayflash GameCube Controller,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux, 03000000790000004318000010010000,Mayflash GameCube Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux, @@ -1054,52 +1087,59 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000d620000010a7000011010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000242f0000f700000001010000,Mayflash Magic S Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 0300000025090000e803000001010000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:a5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux, -03000000780000000600000010010000,Microntek USB Joystick,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, +03000000780000000600000010010000,Microntek Joystick,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, +030000005e0400002800000000010000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Linux, 030000005e0400000e00000000010000,Microsoft SideWinder,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Linux, -030000005e0400000700000000010000,Microsoft SideWinder Game Pad USB,a:b0,b:b1,back:b8,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Linux, +030000005e0400000700000000010000,Microsoft SideWinder Gamepad,a:b0,b:b1,back:b8,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Linux, 030000005e0400002700000000010000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,platform:Linux, -030000005e0400008e02000056210000,Microsoft X-Box 360 pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000005e0400008e02000004010000,Microsoft Xbox 360 pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000005e0400008e02000062230000,Microsoft Xbox 360 pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000005e040000000b000008040000,Microsoft Xbox One Elite 2 pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -050000005e040000050b000003090000,Microsoft Xbox One Elite 2 pad,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, -030000005e040000e302000003020000,Microsoft Xbox One Elite pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000005e040000d102000001010000,Microsoft Xbox One pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000005e040000dd02000003020000,Microsoft Xbox One pad 2015,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000005e040000d102000003020000,Microsoft Xbox One pad v2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000005e040000ea02000008040000,Microsoft Xbox One S pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000005e0400008502000000010000,Microsoft Xbox pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux, +030000005e0400008502000000010000,Microsoft Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux, +030000005e0400008e02000001000000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.1,dpleft:h0.2,dpright:h0.8,dpup:h0.4,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000004010000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000056210000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000062230000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000d102000001010000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000d102000003020000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000dd02000003020000,Microsoft Xbox One 2015,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000e302000003020000,Microsoft Xbox One Elite,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000000b000008040000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000005e040000050b000003090000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +030000005e040000ea02000008040000,Microsoft Xbox One S,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e0400008902000021010000,Microsoft Xbox pad v2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux, 03000000030000000300000002000000,Miroof,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux, 050000004d4f435554452d3035335800,Mocute 053X,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 050000004d4f435554452d3035305800,Mocute 054X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, -05000000d6200000e589000001000000,Moga 2 HID,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux, +05000000d6200000e589000001000000,Moga 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux, 05000000d6200000ad0d000001000000,Moga Pro,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux, -05000000d62000007162000001000000,Moga Pro 2 HID,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux, +05000000d62000007162000001000000,Moga Pro 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux, 03000000c62400002b89000011010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 05000000c62400002a89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b22,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 05000000c62400001a89000000010000,MOGA XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 03000000250900006688000000010000,MP8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux, 030000006b140000010c000010010000,Nacon GC 400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 030000000d0f00000900000010010000,Natec Genesis P44,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, -030000004f1f00000800000011010000,Neogeo PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000004f1f00000800000011010000,NeoGeo PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +0300000092120000474e000000010000,NeoGeo X Arcade Stick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b3,y:b2,platform:Linux, 03000000790000004518000010010000,Nexilux GameCube Controller Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux, 030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Linux, +050000004e696d6275732b0000000000,Nimbus Plus,a:b0,b:b1,back:b10,guide:b11,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,platform:Linux, 060000007e0500003713000000000000,Nintendo 3DS,a:b0,b:b1,back:b8,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux, -060000007e0500000820000000000000,Nintendo Combined Joy-Cons (joycond),a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, 030000007e0500003703000000016800,Nintendo GameCube Controller,a:b0,b:b2,dpdown:b6,dpleft:b4,dpright:b5,dpup:b7,lefttrigger:a4,leftx:a0,lefty:a1~,rightshoulder:b9,righttrigger:a5,rightx:a2,righty:a3~,start:b8,x:b1,y:b3,platform:Linux, 03000000790000004618000010010000,Nintendo GameCube Controller Adapter,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a5~,righty:a2~,start:b9,x:b2,y:b3,platform:Linux, +060000007e0500000620000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, +060000007e0500000820000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, 050000004c69632050726f20436f6e00,Nintendo Switch Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, -050000007e0500000620000001800000,Nintendo Switch Left Joy-Con,a:b9,b:b8,back:b5,leftshoulder:b2,leftstick:b6,leftx:a1,lefty:a0~,rightshoulder:b4,start:b0,x:b7,y:b10,platform:Linux, -03000000d620000013a7000011010000,Nintendo Switch PowerA Wired Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +050000007e0500000620000001800000,Nintendo Switch Left Joy-Con,a:b16,b:b15,back:b4,leftshoulder:b6,leftstick:b12,leftx:a1,lefty:a0~,rightshoulder:b8,start:b9,x:b14,y:b17,platform:Linux, +050000007e0500001920000001000000,Nintendo Switch N64 Controller,+rightx:b8,+righty:b2,-rightx:b3,-righty:b7,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Linux, +050000007e0500001720000001000000,Nintendo Switch Online Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, +03000000d620000013a7000011010000,Nintendo Switch PowerA Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000d620000011a7000011010000,Nintendo Switch PowerA Core Plus Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000007e0500000920000011810000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, 050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 050000007e0500000920000001800000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, -050000007e0500000720000001800000,Nintendo Switch Right Joy-Con,a:b1,b:b2,back:b9,leftshoulder:b4,leftstick:b10,leftx:a1~,lefty:a0~,rightshoulder:b6,start:b8,x:b0,y:b3,platform:Linux, -050000007e0500001720000001000000,Nintendo Switch SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Linux, +050000007e0500000720000001800000,Nintendo Switch Right Joy-Con,a:b1,b:b2,back:b9,leftshoulder:b4,leftstick:b10,leftx:a1~,lefty:a0,rightshoulder:b6,start:b8,x:b0,y:b3,platform:Linux, 050000007e0500003003000001000000,Nintendo Wii Remote Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux, 05000000010000000100000003000000,Nintendo Wiimote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, -030000000d0500000308000010010000,Nostromo n45 Dual Analog Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux, +030000000d0500000308000010010000,Nostromo n45 Dual Analog,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux, 03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, 03000000550900001472000011010000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux, 05000000550900001472000001000000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux, @@ -1107,33 +1147,35 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 19000000010000000100000001010000,odroidgo2 joypad,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux, 19000000010000000200000011000000,odroidgo2 joypad v11,a:b1,b:b0,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b12,leftshoulder:b4,leftstick:b14,lefttrigger:b13,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b16,start:b17,x:b2,y:b3,platform:Linux, 03000000c0160000dc27000001010000,OnyxSoft Dual JoyDivision,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,platform:Linux, -05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux, -05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux, -03000000830500005020000010010000,Padix Co. Ltd. Rockfire PSX/USB Bridge,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,platform:Linux, -03000000790000001c18000011010000,PC Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, -03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, -030000006f0e0000b802000001010000,PDP Afterglow Wired Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000006f0e0000b802000013020000,PDP Afterglow Wired Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +05000000362800000100000002010000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux, +05000000362800000100000003010000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux, +05000000362800000100000004010000,OUYA Controller,a:b0,b:b3,back:b14,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,leftshoulder:b4,leftstick:b6,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,start:b16,x:b1,y:b2,platform:Linux, +03000000830500005020000010010000,Padix Rockfire PlayStation Bridge,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,platform:Linux, +03000000790000001c18000011010000,PC Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000ff1100003133000010010000,PC Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000006f0e0000b802000001010000,PDP Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e0000b802000013020000,PDP Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006f0e00006401000001010000,PDP Battlefield One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006f0e00003101000000010000,PDP EA Sports Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000006f0e00008001000011010000,PDP Faceoff Wired Pro Controller for Nintendo Switch,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e00008001000011010000,PDP Faceoff Nintendo Switch Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000006f0e0000c802000012010000,PDP Kingdom Hearts Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000006f0e00008701000011010000,PDP Rock Candy Wired Controller for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, -030000006f0e00000901000011010000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, -030000006f0e0000a802000023020000,PDP Wired Controller for Xbox One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, -030000006f0e00008501000011010000,PDP Wired Fight Pad Pro for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000006f0e00008501000011010000,PDP Nintendo Switch Fightpad Pro,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000006f0e00002801000011010000,PDP PS3 Rock Candy Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e00008701000011010000,PDP Rock Nintendo Switch Candy Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000006f0e00000901000011010000,PDP Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e0000a802000023020000,PDP Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 030000006f0e0000a702000023020000,PDP Xbox One Raven Black,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000004c050000da0c000011010000,Playstation Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, -03000000d9040000160f000000010000,Playstation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +030000004c050000da0c000011010000,PlayStation Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, +03000000d9040000160f000000010000,PlayStation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, 030000004c0500003713000011010000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux, 03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000c62400003a54000001010000,PowerA 1428124-01,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000c62400001a53000000010000,PowerA Mini Pro Ex,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000d62000006dca000011010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, -03000000d62000000228000001010000,PowerA Wired Controller for Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -03000000d62000000220000001010000,PowerA Wired Controller for Xbox One and Xbox Series S and X,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux, 03000000c62400001a58000001010000,PowerA Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -03000000c62400001a54000001010000,PowerA Xbox One Mini Wired Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d62000000220000001010000,PowerA Xbox One Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux, +03000000d62000000228000001010000,PowerA Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c62400001a54000001010000,PowerA Xbox One Mini Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006d040000d2ca000011010000,Precision Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, 03000000341a00003608000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, @@ -1141,6 +1183,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000004c0500006802000010810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, 030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, 030000004c0500006802000011810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +030000005f1400003102000010010000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, 030000006f0e00001402000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000008f0e00000300000010010000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, 050000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, @@ -1163,25 +1206,23 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 050000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, 050000004c050000cc09000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, 050000004c050000cc09000001800000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, -030000004c050000e60c000011010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, -050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, -03000000ff000000cb01000010010000,PSP,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux, +030000004c050000e60c000011010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, 03000000300f00001211000011010000,Qanba Arcade Joystick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,platform:Linux, 03000000300f00001210000010010000,Qanba Joystick Plus,a:b0,b:b1,back:b8,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,start:b9,x:b2,y:b3,platform:Linux, -030000009b2800004200000001010000,Raphnet Technologies Dual NES to USB v2.0,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Linux, -030000009b2800003200000001010000,Raphnet Technologies GC/N64 to USB v3.4,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux, -030000009b2800006000000001010000,Raphnet Technologies GC/N64 to USB v3.6,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux, -030000009b2800000300000001010000,raphnet.net 4nes4snes v1.5,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux, +030000009b2800000300000001010000,Raphnet 4nes4snes,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux, +030000009b2800004200000001010000,Raphnet Dual NES Adapter,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Linux, +030000009b2800003200000001010000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux, +030000009b2800006000000001010000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux, 030000008916000001fd000024010000,Razer Onza Classic Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000008916000000fd000024010000,Razer Onza Tournament Edition,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -03000000321500000810000011010000,Razer Panthera Evo Arcade Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, 03000000321500000204000011010000,Razer Panthera PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000321500000104000011010000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000321500000810000011010000,Razer Panthera PS4 Evo Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000321500000010000011010000,Razer Raiju,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, 03000000321500000507000000010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, -05000000321500000a10000001000000,Razer Raiju Tournament Edition,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, -03000000321500000710000000010000,Razer Raiju Tournament Edition Wired,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, -03000000321500000010000011010000,Razer Rainu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, -03000000321500000011000011010000,Razer Raion Fightpad for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +05000000321500000a10000001000000,Razer Raiju Tournament Edition,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000321500000011000011010000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, 030000008916000000fe000024010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000c6240000045d000024010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000c6240000045d000025010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, @@ -1191,42 +1232,48 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000790000001100000010010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Linux, 0300000081170000990a000001010000,Retronic Adapter,a:b0,leftx:a0,lefty:a1,platform:Linux, 0300000000f000000300000000010000,RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux, +00000000526574726f53746f6e653200,RetroStone 2 Controller,a:b1,b:b0,back:b10,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,righttrigger:b9,start:b11,x:b4,y:b3,platform:Linux, 030000006b140000010d000011010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, 030000006b140000130d000011010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, 030000006f0e00001f01000000010000,Rock Candy,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006f0e00001e01000011010000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000c6240000fefa000000010000,Rock Candy Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006f0e00004601000001010000,Rock Candy Xbox One Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux, +03000000a306000023f6000011010000,Saitek Cyborg V1 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux, 03000000a30600001005000000010000,Saitek P150,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b2,righttrigger:b5,x:b3,y:b4,platform:Linux, 03000000a30600000701000000010000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Linux, -03000000a30600000cff000010010000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b0,y:b1,platform:Linux, -03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b12,x:b0,y:b3,platform:Linux, -03000000a306000018f5000010010000,Saitek P3200 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux, +03000000a30600000cff000010010000,Saitek P2500 Force Rumble,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b0,y:b1,platform:Linux, +03000000a30600000c04000011010000,Saitek P2900,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b12,x:b0,y:b3,platform:Linux, +03000000a306000018f5000010010000,Saitek P3200 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux, 03000000300f00001201000010010000,Saitek P380,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux, 03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,platform:Linux, -03000000a30600000b04000000010000,Saitek P990 Dual Analog Pad,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Linux, -03000000a306000020f6000011010000,Saitek PS2700 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux, +03000000a30600000b04000000010000,Saitek P990 Dual Analog,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Linux, +03000000a306000020f6000011010000,Saitek PS2700 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux, 03000000d81d00000e00000010010000,Savior,a:b0,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,start:b9,x:b4,y:b5,platform:Linux, -03000000a30c00002500000011010000,Sega Genesis Mini 3B controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Linux, +03000000a30c00002500000011010000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Linux, +03000000790000001100000011010000,Sega Saturn,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Linux, +03000000790000002201000011010000,Sega Saturn,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux, +03000000b40400000a01000000010000,Sega Saturn,a:b0,b:b1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Linux, 030000001f08000001e4000010010000,SFC Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux, -03000000f025000021c1000010010000,Shanwan Gioteck PS3 Wired Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, -03000000632500007505000010010000,Shanwan PS3 PC Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, -03000000bc2000000055000010010000,Shanwan PS3 PC Wired GamePad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, -030000005f140000c501000010010000,Shanwan Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, -03000000632500002305000010010000,ShanWan USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000632500002305000010010000,ShanWan Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000f025000021c1000010010000,Shanwan Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000632500007505000010010000,Shanwan PS3 PC,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000bc2000000055000010010000,Shanwan PS3 PC ,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +030000005f140000c501000010010000,Shanwan Trust,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, 03000000341a00000908000010010000,SL6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 030000004c050000e60c000011810000,Sony DualSense,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, 050000004c050000e60c000000810000,Sony DualSense,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, -03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux, -030000005e0400008e02000073050000,Speedlink Torid Wireless Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000005e0400008e02000020200000,SpeedLink Xeox Pro Analog Gamepad pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000004c050000cc09000001000000,Sony DualShock 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000ff000000cb01000010010000,Sony PlayStation Portable,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux, +03000000250900000500000000010000,Sony PS2 pad with SmartJoy Adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux, +030000005e0400008e02000073050000,Speedlink Torid,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000020200000,SpeedLink Xeox Pro Analog,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000d11800000094000011010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, 03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, 03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, -03000000de2800000211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux, +03000000de2800000211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b16,paddle2:b15,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux, 03000000de2800004211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, -03000000de2800004211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux, +03000000de2800004211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b16,paddle2:b15,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux, 03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, 05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, @@ -1236,118 +1283,128 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000381000003114000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 0500000011010000311400001b010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b32,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 05000000110100001914000009010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, -03000000ad1b000038f0000090040000,Street Fighter IV FightStick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000003b07000004a1000000010000,Suncom SFX Plus for USB,a:b0,b:b2,back:b7,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Linux, +03000000ad1b000038f0000090040000,Street Fighter IV Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000003b07000004a1000000010000,Suncom SFX Plus,a:b0,b:b2,back:b7,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Linux, 03000000666600000488000000010000,Super Joy Box 5 Pro,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux, 0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux, 030000008f0e00000d31000010010000,SZMY Power 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000457500002211000010010000,SZMY Power Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, -030000008f0e00001431000010010000,SZMY Power PS3 gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000008f0e00001431000010010000,SZMY Power PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000ba2200000701000001010000,Technology Innovation PS2 Adapter,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b2,platform:Linux, -030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux, 030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux, -030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3 in 1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, -030000004f0400000ed0000011010000,Thrustmaster eSwap PRO Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000004f04000020b3000010010000,Thrustmaster Dual Trigger,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux, +030000004f04000023b3000000010000,Thrustmaster Dual Trigger PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000004f0400000ed0000011010000,Thrustmaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, 03000000b50700000399000000010000,Thrustmaster Firestorm Digital 2,a:b2,b:b4,back:b11,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b0,righttrigger:b9,start:b1,x:b3,y:b5,platform:Linux, 030000004f04000003b3000010010000,Thrustmaster Firestorm Dual Analog 2,a:b0,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b9,rightx:a2,righty:a3,x:b1,y:b3,platform:Linux, 030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Linux, -030000004f04000026b3000002040000,Thrustmaster Gamepad GP XID,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -03000000c6240000025b000002020000,Thrustmaster GPX Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, -030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, -030000004f04000007d0000000010000,Thrustmaster T Mini Wireless,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, -030000004f04000012b3000010010000,Thrustmaster vibrating gamepad,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux, -03000000bd12000015d0000010010000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux, +030000004f04000026b3000002040000,Thrustmaster GP XID,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c6240000025b000002020000,Thrustmaster GPX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000004f04000008d0000000010000,Thrustmaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000004f04000009d0000000010000,Thrustmaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000004f04000007d0000000010000,Thrustmaster T Mini,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000004f04000012b3000010010000,Thrustmaster vibrating,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux, +03000000571d00002000000010010000,Tomee SNES Adapter,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux, +03000000bd12000015d0000010010000,Tomee SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux, 03000000d814000007cd000011010000,Toodles 2008 Chimp PC PS3,a:b0,b:b1,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux, 030000005e0400008e02000070050000,Torid,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000c01100000591000011010000,Torid,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, -03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +03000000100800000100000010010000,Twin PS2 Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, 03000000100800000300000010010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, 03000000790000000600000007010000,USB gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Linux, -03000000790000001100000000010000,USB Gamepad1,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,platform:Linux, -03000000790000001100000011010000,USB Saturn Controller,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Linux, -03000000790000002201000011010000,USB Saturn Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux, -03000000b40400000a01000000010000,USB Saturn Pad,a:b0,b:b1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Linux, -030000006f0e00000302000011010000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, -030000006f0e00000702000011010000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +03000000790000001100000000010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,platform:Linux, +030000006f0e00000302000011010000,Victrix Pro Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e00000702000011010000,Victrix Pro Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, 05000000ac0500003232000001000000,VR Box Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux, 03000000791d00000103000010010000,Wii Classic Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, -050000000d0f0000f600000001000000,Wireless HORIPAD Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +0000000058626f782033363020576900,Xbox 360 Controller,a:b0,b:b1,back:b14,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b7,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux, +030000005e0400001907000000010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e0400008e02000010010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e0400008e02000014010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -0000000058626f782033363020576900,Xbox 360 Wireless Controller,a:b0,b:b1,back:b14,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b7,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux, -030000005e0400001907000000010000,Xbox 360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000005e0400009102000007010000,Xbox 360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000005e040000a102000000010000,Xbox 360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000005e040000a102000007010000,Xbox 360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000005e0400008e02000000010000,Xbox 360 Wireless EasySMX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000005e040000a102000014010000,Xbox 360 Wireless Receiver,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400009102000007010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000a102000000010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000a102000007010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000000010000,Xbox 360 EasySMX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000a102000014010000,Xbox 360 Receiver,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400000202000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux, 030000006f0e00001304000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000ffff0000ffff000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux, 0000000058626f782047616d65706100,Xbox Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, 030000005e0400000a0b000005040000,Xbox One Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux, +030000005e040000120b000009050000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e040000d102000002010000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000ea02000001030000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000005e040000e002000003090000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000005e040000fd02000003090000,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 050000005e040000fd02000030110000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +060000005e040000120b000007050000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 050000005e040000e302000002090000,Xbox One Elite,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 050000005e040000050b000002090000,Xbox One Elite Series 2,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, -030000005e040000ea02000000000000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -050000005e040000e002000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -050000005e040000fd02000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, -030000005e040000ea02000001030000,Xbox One Wireless Controller (Model 1708),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -060000005e040000120b000007050000,Xbox One Wireless Controller (Model 1914),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000005e0400000202000000010000,Xbox pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux, +060000005e040000ea0200000b050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e040000120b000001050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e040000120b000005050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 050000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 050000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, -03000000450c00002043000010010000,XEOX Gamepad SL6556 BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +050000005e040000130b000009050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +060000005e040000120b00000b050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000005e040000130b000011050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000450c00002043000010010000,XEOX SL6556 BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 03000000ac0500005b05000010010000,Xiaoji Gamesir G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, -05000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux, +05000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux, 03000000c0160000e105000001010000,XinMo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux, xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -03000000120c0000100e000011010000,Zeroplus P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, -03000000120c0000101e000011010000,Zeroplus P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000120c0000100e000011010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000120c0000101e000011010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, # Android +38426974446f2038426974446f205072,8BitDo 8BitDo Pro 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +38426974446f2050726f203200000000,8BitDo 8BitDo Pro 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, 38653964633230666463343334313533,8BitDo Adapter,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +36666264316630653965636634386234,8BitDo Adapter 2,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 34343439373236623466343934376233,8BitDo FC30 Pro,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b28,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b29,righttrigger:b7,start:b5,x:b30,y:b2,platform:Android, +05000000c82d000006500000ffff3f00,8BitDo M30,a:b1,b:b0,back:b4,guide:b17,leftshoulder:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a4,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000051060000ffff3f00,8BitDo M30,a:b1,b:b0,back:b4,guide:b17,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,start:b6,x:b3,y:b2,platform:Android, 33656266353630643966653238646264,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:a5,start:b10,x:b19,y:b2,platform:Android, 39366630663062373237616566353437,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,start:b6,x:b2,y:b3,platform:Android, 64653533313537373934323436343563,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,start:b6,x:b2,y:b3,platform:Android, 66356438346136366337386437653934,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,start:b18,x:b19,y:b2,platform:Android, 66393064393162303732356665666366,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,start:b6,x:b2,y:b3,platform:Android, -05000000c82d000006500000ffff3f00,8BitDo M30 Gamepad,a:b1,b:b0,back:b4,guide:b17,leftshoulder:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a4,start:b6,x:b3,y:b2,platform:Android, -05000000c82d000051060000ffff3f00,8BitDo M30 Gamepad,a:b1,b:b0,back:b4,guide:b17,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,start:b6,x:b3,y:b2,platform:Android, 05000000c82d000015900000ffff3f00,8BitDo N30 Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, 05000000c82d000065280000ffff3f00,8BitDo N30 Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, 050000000220000000900000ffff3f00,8BitDo NES30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, 050000002038000009000000ffff3f00,8BitDo NES30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +35376664343164386333616535333434,8BitDo Pro 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,start:b10,x:b19,y:b2,platform:Android, +62373739366537363166326238653463,8BitDo Pro 2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b3,y:b2,platform:Android, 05000000c82d000000600000ffff3f00,8BitDo SF30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, 05000000c82d000000610000ffff3f00,8BitDo SF30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, 38426974646f20534633302050726f00,8BitDo SF30 Pro,a:b1,b:b0,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b17,platform:Android, 61623334636338643233383735326439,8BitDo SFC30,a:b0,b:b1,back:b4,leftshoulder:b3,leftx:a0,lefty:a1,rightshoulder:b31,start:b5,x:b30,y:b2,platform:Android, -05000000c82d000012900000ffff3f00,8BitDo SN30 Gamepad,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, -05000000c82d000062280000ffff3f00,8BitDo SN30 Gamepad,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000012900000ffff3f00,8BitDo SN30,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000062280000ffff3f00,8BitDo SN30,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, 35383531346263653330306238353131,8BitDo SN30 PP,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 05000000c82d000001600000ffff3f00,8BitDo SN30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, 36653638656632326235346264663661,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android, 38303232393133383836366330346462,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android, 38346630346135363335366265656666,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +38426974446f20534e33302050726f2b,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +536f6e7920436f6d707574657220456e,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 66306331643531333230306437353936,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, 05000000c82d000002600000ffff0f00,8BitDo SN30 Pro+,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, -050000002028000009000000ffff3f00,8BitDo SNES30 Gamepad,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, -050000003512000020ab000000780f00,8BitDo SNES30 Gamepad,a:b21,b:b20,back:b30,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b26,rightshoulder:b27,start:b31,x:b24,y:b23,platform:Android, +050000002028000009000000ffff3f00,8BitDo SNES30,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +050000003512000020ab000000780f00,8BitDo SNES30,a:b21,b:b20,back:b30,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b26,rightshoulder:b27,start:b31,x:b24,y:b23,platform:Android, 33666663316164653937326237613331,8BitDo Zero,a:b0,b:b1,back:b15,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android, +38426974646f205a65726f2047616d65,8BitDo Zero,a:b0,b:b1,back:b15,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android, 05000000c82d000018900000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, 05000000c82d000030320000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, 33663434393362303033616630346337,8BitDo Zero 2,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftx:a0,lefty:a1,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android, 34656330626361666438323266633963,8BitDo Zero 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b20,start:b10,x:b19,y:b2,platform:Android, 63396666386564393334393236386630,8BitDo Zero 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, 63633435623263373466343461646430,8BitDo Zero 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android, -32333634613735616163326165323731,Amazon Luna Game Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android, +32333634613735616163326165323731,Amazon Luna Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android, +417374726f2063697479206d696e6920,Astro City Mini,a:b23,b:b22,back:b29,leftx:a0,lefty:a1,rightshoulder:b25,righttrigger:b26,start:b30,x:b24,y:b21,platform:Android, 38383337343564366131323064613561,Brook Mars PS4 Controller,a:b1,b:b19,back:b17,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, -33323763323132376537376266393366,Dual Strike,a:b24,b:b23,back:b25,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b27,lefttrigger:b29,rightshoulder:b78,rightx:a0,righty:a1~,start:b26,x:b22,y:b21,platform:Android, 30363230653635633863366338623265,Evo VR,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,x:b2,y:b3,platform:Android, 05000000b404000011240000dfff3f00,Flydigi Vader 2,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 05000000bc20000000550000ffff3f00,GameSir G3w,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, @@ -1357,20 +1414,29 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 0500000031366332860c44aadfff0f00,GS Gamepad,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 66633030656131663837396562323935,Hori Battle,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android, 35623466343433653739346434636330,Hori Fighting Commander 3 Pro,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, +484f524920434f2e2c4c54442e203130,Hori Fighting Commander 3 Pro,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b20,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b9,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, +484f524920434f2e2c4c544420205041,Hori Gem Pad 3,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b0,y:b2,platform:Android, 65656436646661313232656661616130,Hori PC Engine Mini Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b18,platform:Android, 31303433326562636431653534636633,Hori Real Arcade Pro 3,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, +30306539356238653637313730656134,HORIPAD Switch Pro Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android, 0500000083050000602000000ffe0000,iBuffalo SNES Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b15,rightshoulder:b16,start:b10,x:b2,y:b3,platform:Android, 64306137363261396266353433303531,InterAct GoPad,a:b24,b:b25,leftshoulder:b23,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,x:b21,y:b22,platform:Android, +532e542e442e20496e74657261637420,InterAct HammerHead FX,a:b23,b:b24,back:b30,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,leftstick:b22,lefttrigger:b28,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b25,righttrigger:b29,rightx:a2,righty:a3,start:b31,x:b20,y:b21,platform:Android, 65346535636333663931613264643164,Joy Con,a:b21,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b23,y:b24,platform:Android, 33346566643039343630376565326335,Joy Con (L),a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android, 35313531613435623366313835326238,Joy Con (L),a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android, 38383665633039363066383334653465,Joy Con (R),a:b0,b:b1,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android, 39363561613936303237333537383931,Joy Con (R),a:b0,b:b1,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android, +4a6f792d436f6e20284c290000000000,Joy-Con (L),a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android, +4a6f792d436f6e202852290000000000,Joy-Con (R),a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android, 39656136363638323036303865326464,JYS Aapter,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, 63316564383539663166353034616434,JYS Adapter,a:b1,b:b3,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b0,y:b2,platform:Android, 64623163333561643339623235373232,Logitech F310,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 35623364393661626231343866613337,Logitech F710,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +4c6f6769746563682047616d65706164,Logitech F710,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 64396331333230326333313330336533,Logitech F710,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +416d617a6f6e2047616d6520436f6e74,Luna Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android, +4c756e612047616d6570616400000000,Luna Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 30363066623539323534363639323363,Magic NS,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, 31353762393935386662336365626334,Magic NS,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, 39623565346366623931666633323530,Magic NS,a:b1,b:b3,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b0,y:b2,platform:Android, @@ -1378,36 +1444,34 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 31323564663862633234646330373138,Mega Drive,a:b23,b:b22,leftx:a0,lefty:a1,rightshoulder:b25,righttrigger:b26,start:b30,x:b24,y:b21,platform:Android, 37333564393261653735306132613061,Mega Drive,a:b21,b:b22,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,lefttrigger:b28,rightshoulder:b27,righttrigger:b23,start:b30,x:b24,y:b25,platform:Android, 64363363336633363736393038313464,Mega Drive,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,platform:Android, +33323763323132376537376266393366,Microsoft Dual Strike,a:b24,b:b23,back:b25,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b27,lefttrigger:b29,rightshoulder:b78,rightx:a0,righty:a1~,start:b26,x:b22,y:b21,platform:Android, 30306461613834333439303734316539,Microsoft SideWinder Pro,a:b0,b:b1,leftshoulder:b20,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b19,righttrigger:b10,start:b17,x:b2,y:b3,platform:Android, -64633436313965656664373634323364,Microsoft X-Box 360 pad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android, +64633436313965656664373634323364,Microsoft Xbox 360,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android, 32386235353630393033393135613831,Microsoft Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +4d4f435554452d303533582d4d35312d,Mocute 053X,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 33343361376163623438613466616531,Mocute M053,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 39306635663061636563316166303966,Mocute M053,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 7573622067616d657061642020202020,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Android, 050000007e05000009200000ffff0f00,Nintendo Switch Pro Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b17,y:b2,platform:Android, 34323437396534643531326161633738,Nintendo Switch Pro Controller,a:b0,b:b1,back:b15,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,misc1:b5,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +50726f20436f6e74726f6c6c65720000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b2,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b10,rightx:a2,righty:a3,start:b18,y:b3,platform:Android, +050000005509000003720000cf7f3f00,NVIDIA Controller,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005509000010720000ffff3f00,NVIDIA Controller,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005509000014720000df7f3f00,NVIDIA Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android, 37336435666338653565313731303834,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 61363931656135336130663561616264,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, -050000005509000003720000cf7f3f00,NVIDIA Controller v01.01,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, -050000005509000010720000ffff3f00,NVIDIA Controller v01.03,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, -050000005509000014720000df7f3f00,NVIDIA Controller v01.04,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android, +39383335313438623439373538343266,OUYA Controller,a:b0,b:b2,dpdown:b18,dpleft:b15,dpright:b16,dpup:b17,leftshoulder:b3,leftstick:b9,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,x:b1,y:b19,platform:Android, +4f5559412047616d6520436f6e74726f,OUYA Controller,a:b0,b:b2,dpdown:b18,dpleft:b15,dpright:b6,dpup:b17,leftshoulder:b3,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b19,platform:Android, +506572666f726d616e63652044657369,PDP PS3 Rock Candy Controller,a:b1,b:b17,back:h0.2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b0,y:b2,platform:Android, +62653335326261303663356263626339,PlayStation Classic Controller,a:b19,b:b1,back:b17,leftshoulder:b9,lefttrigger:b3,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b20,start:b18,x:b2,y:b0,platform:Android, 61653962353232366130326530363061,Pokken,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,rightshoulder:b20,righttrigger:b10,start:b18,x:b0,y:b2,platform:Android, 32666633663735353234363064386132,PS2,a:b23,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a3,righty:a2,start:b30,x:b24,y:b21,platform:Android, -61363034663839376638653463633865,PS3,a:b0,b:b1,back:b15,dpdown:a14,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, -66366539656564653432353139356536,PS3,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, -66383132326164626636313737373037,PS3,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 050000004c05000068020000dfff3f00,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, -30303839663330346632363232623138,PS4,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android, -31326235383662333266633463653332,PS4,a:b1,b:b16,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b17,x:b0,y:b2,platform:Android, -31663838336334393132303338353963,PS4,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, -34613139376634626133336530386430,PS4,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, -37626233336235343937333961353732,PS4,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, -38393161636261653636653532386639,PS4,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, -63313733393535663339656564343962,PS4,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, -63393662363836383439353064663939,PS4,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, -65366465656364636137653363376531,PS4,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, -66613532303965383534396638613230,PS4,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android, +536f6e7920504c415953544154494f4e,PS3 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +61363034663839376638653463633865,PS3 Controller,a:b0,b:b1,back:b15,dpdown:a14,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +66366539656564653432353139356536,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +66383132326164626636313737373037,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 050000004c050000c405000000783f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 050000004c050000c4050000fffe3f00,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android, 050000004c050000c4050000ffff3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, @@ -1415,16 +1479,29 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 050000004c050000cc090000ffff3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 31373231336561636235613666323035,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 35643031303033326130316330353564,PS4 Controller,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android, +536f6e7920496e746572616374697665,PS4 Controller,a:b0,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +576972656c65737320436f6e74726f6c,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +31663838336334393132303338353963,PS4 Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +34613139376634626133336530386430,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +37626233336235343937333961353732,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +38393161636261653636653532386639,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +63313733393535663339656564343962,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +63393662363836383439353064663939,PS4 Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +30303839663330346632363232623138,PS4 Controller,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android, +31326235383662333266633463653332,PS4 Controller,a:b1,b:b16,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b17,x:b0,y:b2,platform:Android, +65366465656364636137653363376531,PS4 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, +66613532303965383534396638613230,PS4 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android, 050000004c050000e60c0000fffe3f00,PS5 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android, -62653335326261303663356263626339,PSX,a:b19,b:b1,back:b17,leftshoulder:b9,lefttrigger:b3,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b20,start:b18,x:b2,y:b0,platform:Android, 64336263393933626535303339616332,Qanba 4RAF,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b20,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b9,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android, 36626666353861663864336130363137,Razer Junglecat,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 62653861643333663663383332396665,Razer Kishi,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 050000003215000005070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 050000003215000007070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 050000003215000000090000bf7f3f00,Razer Serval,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android, +5a6869587520526574726f2042697420,Retro Bit Saturn Controller,a:b21,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,lefttrigger:b26,rightshoulder:b27,righttrigger:b28,start:b30,x:b23,y:b24,platform:Android, +526574726f466c616720576972656420,Retro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b17,rightshoulder:b18,start:b10,x:b2,y:b3,platform:Android, 61343739353764363165343237303336,Retro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b17,lefttrigger:b18,leftx:a0,lefty:a1,start:b10,x:b2,y:b3,platform:Android, -38653130373365613538333235303036,Retroid Pocket 2,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +38653130373365613538333235303036,Retroid Pocket 2,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 64363363336633363736393038313463,Retrolink,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b6,platform:Android, 33373336396634316434323337666361,RumblePad 2,a:b22,b:b23,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b24,platform:Android, 66386565396238363534313863353065,Sanwa Mobile,a:b21,b:b22,leftshoulder:b23,leftx:a0,lefty:a1,rightshoulder:b24,platform:Android, @@ -1437,40 +1514,48 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 66633132393363353531373465633064,SG H510,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android, 62653761636366393366613135366338,SN30 PP,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, 38376662666661636265313264613039,SNES,a:b0,b:b1,back:b9,leftshoulder:b3,leftx:a0,lefty:a1,rightshoulder:b20,start:b10,x:b19,y:b2,platform:Android, +5346432f555342205061640000000000,SNES Adapter,a:b0,b:b1,back:b9,leftshoulder:b3,leftx:a0,lefty:a1,rightshoulder:b20,start:b10,x:b19,y:b2,platform:Android, +5553422047616d657061642000000000,SNES Controller,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, 32633532643734376632656664383733,Sony DualSense,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android, 61303162353165316365336436343139,Sony DualSense,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android, 63303964303462366136616266653561,Sony PSP,a:b21,b:b22,back:b27,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,leftx:a0,lefty:a1,rightshoulder:b26,start:b28,x:b23,y:b24,platform:Android, 63376637643462343766333462383235,Sony Vita,a:b1,b:b19,back:b17,leftshoulder:b3,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a3,righty:a4,start:b18,x:b0,y:b2,platform:Android, +476f6f676c65204c4c43205374616469,Stadia Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android, 05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android, 0500000011010000201400000f7e0f00,SteelSeries Nimbus,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,x:b19,y:b2,platform:Android, -050000004f0400000ed00000fffe3f00,ThrustMaster eSwap PRO Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, -5477696e20555342204a6f7973746963,Twin USB Joystick,a:b22,b:b21,back:b28,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,leftstick:b30,lefttrigger:b24,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b31,righttrigger:b25,rightx:a3,righty:a2,start:b29,x:b23,y:b20,platform:Android, -30623739343039643830333266346439,Valve Steam Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,paddle1:b23,paddle2:b24,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, -31643365666432386133346639383937,Valve Steam Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,paddle1:b23,paddle2:b24,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, -30386438313564306161393537333663,Wii Classic,a:b23,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,platform:Android, -33333034646336346339646538643633,Wii Classic,a:b23,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,platform:Android, -30306539356238653637313730656134,Wireless HORIPAD Switch Pro Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android, -30396232393162346330326334636566,Xbox 360,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, -38313038323730383864666463383533,Xbox 360,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, -65353331386662343338643939643636,Xbox 360,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, -65613532386633373963616462363038,Xbox 360,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +35306436396437373135383665646464,SteelSeries Nimbus Plus,a:b0,b:b1,leftshoulder:b3,leftstick:b17,lefttrigger:b9,leftx:a0,rightshoulder:b20,rightstick:b18,righttrigger:b10,rightx:a2,x:b19,y:b2,platform:Android, +050000004f0400000ed00000fffe3f00,ThrustMaster eSwap Pro Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +5477696e20555342204a6f7973746963,Twin Joystick,a:b22,b:b21,back:b28,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,leftstick:b30,lefttrigger:b24,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b31,righttrigger:b25,rightx:a3,righty:a2,start:b29,x:b23,y:b20,platform:Android, +30623739343039643830333266346439,Valve Steam Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,paddle1:b24,paddle2:b23,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +31643365666432386133346639383937,Valve Steam Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,paddle1:b24,paddle2:b23,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +30386438313564306161393537333663,Wii Classic Controller,a:b23,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,platform:Android, +33333034646336346339646538643633,Wii Classic Controller,a:b23,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,platform:Android, 050000005e0400008e02000000783f00,Xbox 360 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +30396232393162346330326334636566,Xbox 360 Controller,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +38313038323730383864666463383533,Xbox 360 Controller,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +58626f782033363020576972656c6573,Xbox 360 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +65353331386662343338643939643636,Xbox 360 Controller,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +65613532386633373963616462363038,Xbox 360 Controller,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +47656e6572696320582d426f78207061,Xbox Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +4d6963726f736f667420582d426f7820,Xbox Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005e04000091020000ff073f00,Xbox One Controller,a:b0,b:b1,back:b4,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android, +050000005e040000e00200000ffe3f00,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b17,y:b2,platform:Android, +050000005e040000e0020000ffff3f00,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b4,leftshoulder:b3,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b17,y:b2,platform:Android, +050000005e040000fd020000ffff3f00,Xbox One Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 33356661323266333733373865656366,Xbox One Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +34356136633366613530316338376136,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,x:b17,y:b2,platform:Android, 35623965373264386238353433656138,Xbox One Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +36616131643361333337396261666433,Xbox One Controller,a:b0,b:b1,back:b15,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +58626f7820576972656c65737320436f,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 050000005e040000000b000000783f00,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android, 050000005e040000e002000000783f00,Xbox One S Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 050000005e040000ea02000000783f00,Xbox One S Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 050000005e040000fd020000ff7f3f00,Xbox One S Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, -050000005e040000e00200000ffe3f00,Xbox One Wireless Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b17,y:b2,platform:Android, -050000005e040000fd020000ffff3f00,Xbox One Wireless Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 050000005e040000120b000000783f00,Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android, -050000005e040000130b0000ffff3f00,Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005e040000130b0000ffff3f00,Xbox Series Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 65633038363832353634653836396239,Xbox Series Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, -050000005e04000091020000ff073f00,Xbox Wireless Controller,a:b0,b:b1,back:b4,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android, -34356136633366613530316338376136,Xbox Wireless Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,x:b17,y:b2,platform:Android, -36616131643361333337396261666433,Xbox Wireless Controller,a:b0,b:b1,back:b15,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, -050000001727000044310000ffff3f00,XiaoMi Game Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a6,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android, +050000001727000044310000ffff3f00,XiaoMi Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a6,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android, # iOS 05000000ac0500000100000000006d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,platform:iOS, @@ -1493,9 +1578,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 05000000ac0500000300000043006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,platform:iOS, 05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS, 05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS, -050000005e040000050b0000df070001,Xbox Elite Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b10,paddle2:b12,paddle3:b11,paddle4:b13,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, -050000005e040000050b0000ff070001,Xbox Elite Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, +050000005e040000050b0000df070001,Xbox Elite Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b10,paddle2:b12,paddle3:b11,paddle4:b13,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, +050000005e040000050b0000ff070001,Xbox Elite Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, +050000005e040000e0020000df070000,Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, +050000005e040000e0020000ff070000,Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, 050000005e040000130b0000df870001,Xbox Series X Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b10,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, 050000005e040000130b0000ff870001,Xbox Series X Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, -050000005e040000e0020000df070000,Xbox Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, -050000005e040000e0020000ff070000,Xbox Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, +050000005e040000130b000007050000,Xbox Wireless Controller,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b12,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Linux, diff --git a/core/input/godotcontrollerdb.txt b/core/input/godotcontrollerdb.txt index 5985b121c9..7f3570729a 100644 --- a/core/input/godotcontrollerdb.txt +++ b/core/input/godotcontrollerdb.txt @@ -1,4 +1,4 @@ -# Game Controller DB for Godot in SDL 2.0.10 format +# Game Controller DB for Godot in SDL 2.0.16 format # Source: https://github.com/godotengine/godot # Windows @@ -31,6 +31,7 @@ MacOSX0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoul Linux046dc216,046d-c216-Logitech Logitech Dual Action,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:-a5,dpleft:-a4,dpdown:+a5,dpright:+a4,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Javascript Linux20d6a713,Bensussen Deutsch & Associates Inc.(BDA) NSW Wired controller,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:-a5,dpleft:-a4,dpdown:+a5,dpright:+a4,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Javascript Linux054c05c4,Sony Computer Entertainment Wireless Controller,a:b0,b:b1,y:b2,x:b3,start:b9,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript +Linux18d19400,18d1-9400-Google LLC Stadia Controller rev. A,a:b0,b:b1,y:b3,x:b2,start:b7,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Javascript # UWP __UWP_GAMEPAD__,Xbox Controller,a:b2,b:b3,x:b4,y:b5,start:b0,back:b1,leftstick:b12,rightstick:b13,leftshoulder:b10,rightshoulder:b11,dpup:b6,dpdown:b7,dpleft:b8,dpright:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:UWP, diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp index 526952b14f..85faf04315 100644 --- a/core/io/file_access_compressed.cpp +++ b/core/io/file_access_compressed.cpp @@ -88,11 +88,11 @@ Error FileAccessCompressed::open_after_magic(FileAccess *p_base) { read_block_count = bc; read_block_size = read_blocks.size() == 1 ? read_total : block_size; - Compression::decompress(buffer.ptrw(), read_block_size, comp_buffer.ptr(), read_blocks[0].csize, cmode); + int ret = Compression::decompress(buffer.ptrw(), read_block_size, comp_buffer.ptr(), read_blocks[0].csize, cmode); read_block = 0; read_pos = 0; - return OK; + return ret == -1 ? ERR_FILE_CORRUPT : OK; } Error FileAccessCompressed::_open(const String &p_path, int p_mode_flags) { @@ -125,10 +125,11 @@ Error FileAccessCompressed::_open(const String &p_path, int p_mode_flags) { char rmagic[5]; f->get_buffer((uint8_t *)rmagic, 4); rmagic[4] = 0; - if (magic != rmagic || open_after_magic(f) != OK) { + err = ERR_FILE_UNRECOGNIZED; + if (magic != rmagic || (err = open_after_magic(f)) != OK) { memdelete(f); f = nullptr; - return ERR_FILE_UNRECOGNIZED; + return err; } } @@ -210,7 +211,8 @@ void FileAccessCompressed::seek(uint64_t p_position) { read_block = block_idx; f->seek(read_blocks[read_block].offset); f->get_buffer(comp_buffer.ptrw(), read_blocks[read_block].csize); - Compression::decompress(buffer.ptrw(), read_blocks.size() == 1 ? read_total : block_size, comp_buffer.ptr(), read_blocks[read_block].csize, cmode); + int ret = Compression::decompress(buffer.ptrw(), read_blocks.size() == 1 ? read_total : block_size, comp_buffer.ptr(), read_blocks[read_block].csize, cmode); + ERR_FAIL_COND_MSG(ret == -1, "Compressed file is corrupt."); read_block_size = read_block == read_block_count - 1 ? read_total % block_size : block_size; } @@ -273,7 +275,8 @@ uint8_t FileAccessCompressed::get_8() const { if (read_block < read_block_count) { //read another block of compressed data f->get_buffer(comp_buffer.ptrw(), read_blocks[read_block].csize); - Compression::decompress(buffer.ptrw(), read_blocks.size() == 1 ? read_total : block_size, comp_buffer.ptr(), read_blocks[read_block].csize, cmode); + int total = Compression::decompress(buffer.ptrw(), read_blocks.size() == 1 ? read_total : block_size, comp_buffer.ptr(), read_blocks[read_block].csize, cmode); + ERR_FAIL_COND_V_MSG(total == -1, 0, "Compressed file is corrupt."); read_block_size = read_block == read_block_count - 1 ? read_total % block_size : block_size; read_pos = 0; @@ -305,7 +308,8 @@ uint64_t FileAccessCompressed::get_buffer(uint8_t *p_dst, uint64_t p_length) con if (read_block < read_block_count) { //read another block of compressed data f->get_buffer(comp_buffer.ptrw(), read_blocks[read_block].csize); - Compression::decompress(buffer.ptrw(), read_blocks.size() == 1 ? read_total : block_size, comp_buffer.ptr(), read_blocks[read_block].csize, cmode); + int ret = Compression::decompress(buffer.ptrw(), read_blocks.size() == 1 ? read_total : block_size, comp_buffer.ptr(), read_blocks[read_block].csize, cmode); + ERR_FAIL_COND_V_MSG(ret == -1, -1, "Compressed file is corrupt."); read_block_size = read_block == read_block_count - 1 ? read_total % block_size : block_size; read_pos = 0; diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp index 12de2f582e..d0bc05566e 100644 --- a/core/io/marshalls.cpp +++ b/core/io/marshalls.cpp @@ -1068,6 +1068,21 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo flags |= ENCODE_FLAG_OBJECT_AS_ID; } } break; +#ifdef REAL_T_IS_DOUBLE + case Variant::VECTOR2: + case Variant::VECTOR3: + case Variant::PACKED_VECTOR2_ARRAY: + case Variant::PACKED_VECTOR3_ARRAY: + case Variant::TRANSFORM2D: + case Variant::TRANSFORM3D: + case Variant::QUATERNION: + case Variant::PLANE: + case Variant::BASIS: + case Variant::RECT2: + case Variant::AABB: { + flags |= ENCODE_FLAG_64; + } break; +#endif // REAL_T_IS_DOUBLE default: { } // nothing to do at this stage } diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index 611f371229..ee59a916f1 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -901,6 +901,7 @@ void ResourceLoaderBinary::open(FileAccess *p_f, bool p_no_resources, bool p_kee if (flags & ResourceFormatSaverBinaryInstance::FORMAT_FLAG_UIDS) { using_uids = true; } + f->real_is_double = (flags & ResourceFormatSaverBinaryInstance::FORMAT_FLAG_REAL_T_IS_DOUBLE) != 0; if (using_uids) { uid = f->get_64(); @@ -1897,7 +1898,13 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p save_unicode_string(f, p_resource->get_class()); f->store_64(0); //offset to import metadata - f->store_32(FORMAT_FLAG_NAMED_SCENE_IDS | FORMAT_FLAG_UIDS); + { + uint32_t format_flags = FORMAT_FLAG_NAMED_SCENE_IDS | FORMAT_FLAG_UIDS; +#ifdef REAL_T_IS_DOUBLE + format_flags |= FORMAT_FLAG_REAL_T_IS_DOUBLE; +#endif + f->store_32(format_flags); + } ResourceUID::ID uid = ResourceSaver::get_resource_id_for_path(p_path, true); f->store_64(uid); for (int i = 0; i < ResourceFormatSaverBinaryInstance::RESERVED_FIELDS; i++) { diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h index ecc3e95f6b..c80c9b0ac9 100644 --- a/core/io/resource_format_binary.h +++ b/core/io/resource_format_binary.h @@ -164,6 +164,8 @@ public: enum { FORMAT_FLAG_NAMED_SCENE_IDS = 1, FORMAT_FLAG_UIDS = 2, + FORMAT_FLAG_REAL_T_IS_DOUBLE = 4, + // Amount of reserved 32-bit fields in resource header RESERVED_FIELDS = 11 }; diff --git a/core/math/camera_matrix.h b/core/math/camera_matrix.h index 285d2ae384..f1aea5e4e8 100644 --- a/core/math/camera_matrix.h +++ b/core/math/camera_matrix.h @@ -33,6 +33,7 @@ #include "core/math/math_defs.h" #include "core/math/vector3.h" +#include "core/templates/vector.h" struct AABB; struct Plane; diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp index 998c437a22..9b3902346e 100644 --- a/core/math/vector3.cpp +++ b/core/math/vector3.cpp @@ -31,6 +31,9 @@ #include "vector3.h" #include "core/math/basis.h" +#include "core/math/vector2.h" +#include "core/math/vector3i.h" +#include "core/string/ustring.h" void Vector3::rotate(const Vector3 &p_axis, const real_t p_phi) { *this = Basis(p_axis, p_phi).xform(*this); @@ -97,6 +100,31 @@ Vector3 Vector3::move_toward(const Vector3 &p_to, const real_t p_delta) const { return len <= p_delta || len < CMP_EPSILON ? p_to : v + vd / len * p_delta; } +Vector2 Vector3::octahedron_encode() const { + Vector3 n = *this; + n /= Math::abs(n.x) + Math::abs(n.y) + Math::abs(n.z); + Vector2 o; + if (n.z >= 0.0f) { + o.x = n.x; + o.y = n.y; + } else { + o.x = (1.0f - Math::abs(n.y)) * (n.x >= 0.0f ? 1.0f : -1.0f); + o.y = (1.0f - Math::abs(n.x)) * (n.y >= 0.0f ? 1.0f : -1.0f); + } + o.x = o.x * 0.5f + 0.5f; + o.y = o.y * 0.5f + 0.5f; + return o; +} + +Vector3 Vector3::octahedron_decode(const Vector2 &p_oct) { + Vector2 f(p_oct.x * 2.0f - 1.0f, p_oct.y * 2.0f - 1.0f); + Vector3 n(f.x, f.y, 1.0f - Math::abs(f.x) - Math::abs(f.y)); + float t = CLAMP(-n.z, 0.0f, 1.0f); + n.x += n.x >= 0 ? -t : t; + n.y += n.y >= 0 ? -t : t; + return n.normalized(); +} + Basis Vector3::outer(const Vector3 &p_with) const { Vector3 row0(x * p_with.x, x * p_with.y, x * p_with.z); Vector3 row1(y * p_with.x, y * p_with.y, y * p_with.z); @@ -112,3 +140,7 @@ bool Vector3::is_equal_approx(const Vector3 &p_v) const { Vector3::operator String() const { return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ")"; } + +Vector3::operator Vector3i() const { + return Vector3i(x, y, z); +} diff --git a/core/math/vector3.h b/core/math/vector3.h index c1da159e00..89b0095741 100644 --- a/core/math/vector3.h +++ b/core/math/vector3.h @@ -31,12 +31,13 @@ #ifndef VECTOR3_H #define VECTOR3_H +#include "core/error/error_macros.h" #include "core/math/math_funcs.h" -#include "core/math/vector2.h" -#include "core/math/vector3i.h" -#include "core/string/ustring.h" +class String; struct Basis; +struct Vector2; +struct Vector3i; struct _NO_DISCARD_ Vector3 { static const int AXIS_COUNT = 3; @@ -104,30 +105,8 @@ struct _NO_DISCARD_ Vector3 { Vector3 cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight) const; Vector3 move_toward(const Vector3 &p_to, const real_t p_delta) const; - _FORCE_INLINE_ Vector2 octahedron_encode() const { - Vector3 n = *this; - n /= Math::abs(n.x) + Math::abs(n.y) + Math::abs(n.z); - Vector2 o; - if (n.z >= 0.0f) { - o.x = n.x; - o.y = n.y; - } else { - o.x = (1.0f - Math::abs(n.y)) * (n.x >= 0.0f ? 1.0f : -1.0f); - o.y = (1.0f - Math::abs(n.x)) * (n.y >= 0.0f ? 1.0f : -1.0f); - } - o.x = o.x * 0.5f + 0.5f; - o.y = o.y * 0.5f + 0.5f; - return o; - } - - static _FORCE_INLINE_ Vector3 octahedron_decode(const Vector2 &p_oct) { - Vector2 f(p_oct.x * 2.0f - 1.0f, p_oct.y * 2.0f - 1.0f); - Vector3 n(f.x, f.y, 1.0f - Math::abs(f.x) - Math::abs(f.y)); - float t = CLAMP(-n.z, 0.0f, 1.0f); - n.x += n.x >= 0 ? -t : t; - n.y += n.y >= 0 ? -t : t; - return n.normalized(); - } + Vector2 octahedron_encode() const; + static Vector3 octahedron_decode(const Vector2 &p_oct); _FORCE_INLINE_ Vector3 cross(const Vector3 &p_with) const; _FORCE_INLINE_ real_t dot(const Vector3 &p_with) const; @@ -183,16 +162,9 @@ struct _NO_DISCARD_ Vector3 { _FORCE_INLINE_ bool operator>=(const Vector3 &p_v) const; operator String() const; - _FORCE_INLINE_ operator Vector3i() const { - return Vector3i(x, y, z); - } + operator Vector3i() const; _FORCE_INLINE_ Vector3() {} - _FORCE_INLINE_ Vector3(const Vector3i &p_ivec) { - x = p_ivec.x; - y = p_ivec.y; - z = p_ivec.z; - } _FORCE_INLINE_ Vector3(const real_t p_x, const real_t p_y, const real_t p_z) { x = p_x; y = p_y; @@ -344,7 +316,7 @@ Vector3 &Vector3::operator*=(const real_t p_scalar) { } // Multiplication operators required to workaround issues with LLVM using implicit conversion -// to Vector2i instead for integers where it should not. +// to Vector3i instead for integers where it should not. _FORCE_INLINE_ Vector3 operator*(const float p_scalar, const Vector3 &p_vec) { return p_vec * p_scalar; diff --git a/core/math/vector3i.cpp b/core/math/vector3i.cpp index ac79b3c7ea..b8e74ea6d2 100644 --- a/core/math/vector3i.cpp +++ b/core/math/vector3i.cpp @@ -30,6 +30,9 @@ #include "vector3i.h" +#include "core/math/vector3.h" +#include "core/string/ustring.h" + void Vector3i::set_axis(const int p_axis, const int32_t p_value) { ERR_FAIL_INDEX(p_axis, 3); coord[p_axis] = p_value; @@ -58,3 +61,7 @@ Vector3i Vector3i::clamp(const Vector3i &p_min, const Vector3i &p_max) const { Vector3i::operator String() const { return "(" + itos(x) + ", " + itos(y) + ", " + itos(z) + ")"; } + +Vector3i::operator Vector3() const { + return Vector3(x, y, z); +} diff --git a/core/math/vector3i.h b/core/math/vector3i.h index d166de80aa..2a4c7e2e97 100644 --- a/core/math/vector3i.h +++ b/core/math/vector3i.h @@ -32,8 +32,9 @@ #define VECTOR3I_H #include "core/math/math_funcs.h" -#include "core/string/ustring.h" -#include "core/typedefs.h" + +class String; +struct Vector3; struct _NO_DISCARD_ Vector3i { enum Axis { @@ -105,6 +106,7 @@ struct _NO_DISCARD_ Vector3i { _FORCE_INLINE_ bool operator>=(const Vector3i &p_v) const; operator String() const; + operator Vector3() const; _FORCE_INLINE_ Vector3i() {} _FORCE_INLINE_ Vector3i(const int32_t p_x, const int32_t p_y, const int32_t p_z) { diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index a4b6a589f3..63aa8050c4 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -108,6 +108,8 @@ extern void unregister_global_constants(); static ResourceUID *resource_uid = nullptr; +static bool _is_core_extensions_registered = false; + void register_core_types() { //consistency check static_assert(sizeof(Callable) <= 16); @@ -314,11 +316,16 @@ void register_core_extensions() { NativeExtension::initialize_native_extensions(); native_extension_manager->load_extensions(); native_extension_manager->initialize_extensions(NativeExtension::INITIALIZATION_LEVEL_CORE); + _is_core_extensions_registered = true; } -void unregister_core_types() { - native_extension_manager->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_CORE); +void unregister_core_extensions() { + if (_is_core_extensions_registered) { + native_extension_manager->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_CORE); + } +} +void unregister_core_types() { memdelete(native_extension_manager); memdelete(resource_uid); diff --git a/core/register_core_types.h b/core/register_core_types.h index 0fd4e73c40..dfb2d8ac80 100644 --- a/core/register_core_types.h +++ b/core/register_core_types.h @@ -36,5 +36,6 @@ void register_core_settings(); void register_core_extensions(); void register_core_singletons(); void unregister_core_types(); +void unregister_core_extensions(); #endif // REGISTER_CORE_TYPES_H diff --git a/core/string/translation.cpp b/core/string/translation.cpp index 811ae95e9f..c41828de05 100644 --- a/core/string/translation.cpp +++ b/core/string/translation.cpp @@ -685,8 +685,12 @@ Ref<Translation> TranslationServer::get_tool_translation() const { String TranslationServer::get_tool_locale() { #ifdef TOOLS_ENABLED - if (TranslationServer::get_singleton()->get_tool_translation().is_valid() && (Engine::get_singleton()->is_editor_hint() || Engine::get_singleton()->is_project_manager_hint())) { - return tool_translation->get_locale(); + if (Engine::get_singleton()->is_editor_hint() || Engine::get_singleton()->is_project_manager_hint()) { + if (TranslationServer::get_singleton()->get_tool_translation().is_valid()) { + return tool_translation->get_locale(); + } else { + return "en"; + } } else { #else { diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index e9fae91ddb..17cb50d1a4 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -2405,7 +2405,7 @@ Hints that an integer, float or string property is an enumerated value to pick in a list specified via a hint string such as [code]"Hello,Something,Else"[/code]. </constant> <constant name="PROPERTY_HINT_ENUM_SUGGESTION" value="3" enum="PropertyHint"> - Hints that a string property is can be an enumerated value to pick in a list specified via a hint string such as [code]"Hello,Something,Else"[/code]. + Hints that a string property can be an enumerated value to pick in a list specified via a hint string such as [code]"Hello,Something,Else"[/code]. Unlike [constant PROPERTY_HINT_ENUM] a property with this hint still accepts arbitrary values and can be empty. The list of values serves to suggest possible values. </constant> <constant name="PROPERTY_HINT_EXP_EASING" value="4" enum="PropertyHint"> diff --git a/doc/classes/AnimationNode.xml b/doc/classes/AnimationNode.xml index f06bef4b74..99d21706ee 100644 --- a/doc/classes/AnimationNode.xml +++ b/doc/classes/AnimationNode.xml @@ -46,7 +46,7 @@ <method name="_has_filter" qualifiers="virtual const"> <return type="bool" /> <description> - Returns [code]true[/code] whether you want the blend tree editor to display filter editing on this node. + Returns whether you want the blend tree editor to display filter editing on this node. </description> </method> <method name="_process" qualifiers="virtual const"> @@ -127,7 +127,7 @@ <return type="bool" /> <argument index="0" name="path" type="NodePath" /> <description> - Returns [code]true[/code] whether a given path is filtered. + Returns whether the given path is filtered. </description> </method> <method name="remove_input"> @@ -150,7 +150,7 @@ <argument index="0" name="name" type="StringName" /> <argument index="1" name="value" type="Variant" /> <description> - Sets a custom parameter. These are used as local storage, because resources can be reused across the tree or scenes. + Sets a custom parameter. These are used as local memory, because resources can be reused across the tree or scenes. </description> </method> </methods> @@ -162,7 +162,7 @@ <signals> <signal name="removed_from_graph"> <description> - Called when the node was removed from the graph. + Emitted when the node was removed from the graph. </description> </signal> <signal name="tree_changed"> diff --git a/doc/classes/AudioServer.xml b/doc/classes/AudioServer.xml index d878d8bb65..1e076654fb 100644 --- a/doc/classes/AudioServer.xml +++ b/doc/classes/AudioServer.xml @@ -29,25 +29,12 @@ Adds an [AudioEffect] effect to the bus [code]bus_idx[/code] at [code]at_position[/code]. </description> </method> - <method name="capture_get_device"> - <return type="String" /> - <description> - Name of the current device for audio input (see [method capture_get_device_list]). The value [code]"Default"[/code] means that the system-wide default audio input is currently used. - </description> - </method> <method name="capture_get_device_list"> <return type="Array" /> <description> Returns the names of all audio input devices detected on the system. </description> </method> - <method name="capture_set_device"> - <return type="void" /> - <argument index="0" name="name" type="String" /> - <description> - Sets which audio input device is used for audio capture. On systems with multiple audio inputs (such as analog and USB), this can be used to select the audio input device. Setting the value [code]"Default"[/code] will record audio from the system-wide default audio input. If an invalid device name is set, the value will be reverted back to [code]"Default"[/code]. - </description> - </method> <method name="generate_bus_layout" qualifiers="const"> <return type="AudioBusLayout" /> <description> @@ -308,6 +295,9 @@ <member name="bus_count" type="int" setter="set_bus_count" getter="get_bus_count" default="1"> Number of available audio buses. </member> + <member name="capture_device" type="String" setter="capture_set_device" getter="capture_get_device" default=""Default""> + Name of the current device for audio input (see [method get_device_list]). On systems with multiple audio inputs (such as analog, USB and HDMI audio), this can be used to select the audio input device. The value [code]"Default"[/code] will record audio on the system-wide default audio input. If an invalid device name is set, the value will be reverted back to [code]"Default"[/code]. + </member> <member name="device" type="String" setter="set_device" getter="get_device" default=""Default""> Name of the current device for audio output (see [method get_device_list]). On systems with multiple audio outputs (such as analog, USB and HDMI audio), this can be used to select the audio output device. The value [code]"Default"[/code] will play audio on the system-wide default audio output. If an invalid device name is set, the value will be reverted back to [code]"Default"[/code]. </member> diff --git a/doc/classes/AudioStream.xml b/doc/classes/AudioStream.xml index 1e6f700c7c..6343da6eed 100644 --- a/doc/classes/AudioStream.xml +++ b/doc/classes/AudioStream.xml @@ -39,6 +39,12 @@ Returns the length of the audio stream in seconds. </description> </method> + <method name="instance_playback"> + <return type="AudioStreamPlayback" /> + <description> + Returns an AudioStreamPlayback. Useful for when you want to extend `_instance_playback` but call `instance_playback` from an internally held AudioStream subresource. An example of this can be found in the source files for `AudioStreamRandomPitch::instance_playback`. + </description> + </method> <method name="is_monophonic" qualifiers="const"> <return type="bool" /> <description> diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml index 9abdddfa5e..ae7b0afaa7 100644 --- a/doc/classes/BaseMaterial3D.xml +++ b/doc/classes/BaseMaterial3D.xml @@ -132,8 +132,8 @@ If [code]true[/code], clearcoat rendering is enabled. Adds a secondary transparent pass to the lighting calculation resulting in an added specular blob. This makes materials appear as if they have a clear layer on them that can be either glossy or rough. [b]Note:[/b] Clearcoat rendering is not visible if the material's [member shading_mode] is [constant SHADING_MODE_UNSHADED]. </member> - <member name="clearcoat_gloss" type="float" setter="set_clearcoat_gloss" getter="get_clearcoat_gloss" default="0.5"> - Sets the roughness of the clearcoat pass. A higher value results in a smoother clearcoat while a lower value results in a rougher clearcoat. + <member name="clearcoat_roughness" type="float" setter="set_clearcoat_roughness" getter="get_clearcoat_roughness" default="0.5"> + Sets the roughness of the clearcoat pass. A higher value results in a rougher clearcoat while a lower value results in a smoother clearcoat. </member> <member name="clearcoat_texture" type="Texture2D" setter="set_texture" getter="get_texture"> Texture that defines the strength of the clearcoat effect and the glossiness of the clearcoat. Strength is specified in the red channel while glossiness is specified in the green channel. @@ -319,6 +319,7 @@ </member> <member name="specular_mode" type="int" setter="set_specular_mode" getter="get_specular_mode" enum="BaseMaterial3D.SpecularMode" default="0"> The method for rendering the specular blob. See [enum SpecularMode]. + [b]Note:[/b] Only applies to the specular blob. Does not affect specular reflections from the Sky, SSR, or ReflectionProbes. </member> <member name="subsurf_scatter_enabled" type="bool" setter="set_feature" getter="get_feature" default="false"> If [code]true[/code], subsurface scattering is enabled. Emulates light that penetrates an object's surface, is scattered, and then emerges. @@ -664,16 +665,10 @@ <constant name="SPECULAR_SCHLICK_GGX" value="0" enum="SpecularMode"> Default specular blob. </constant> - <constant name="SPECULAR_BLINN" value="1" enum="SpecularMode"> - Older specular algorithm, included for compatibility. - </constant> - <constant name="SPECULAR_PHONG" value="2" enum="SpecularMode"> - Older specular algorithm, included for compatibility. - </constant> - <constant name="SPECULAR_TOON" value="3" enum="SpecularMode"> + <constant name="SPECULAR_TOON" value="1" enum="SpecularMode"> Toon blob which changes size based on roughness. </constant> - <constant name="SPECULAR_DISABLED" value="4" enum="SpecularMode"> + <constant name="SPECULAR_DISABLED" value="2" enum="SpecularMode"> No specular blob. </constant> <constant name="BILLBOARD_DISABLED" value="0" enum="BillboardMode"> diff --git a/doc/classes/CharacterBody2D.xml b/doc/classes/CharacterBody2D.xml index 75237f8df0..28060f6579 100644 --- a/doc/classes/CharacterBody2D.xml +++ b/doc/classes/CharacterBody2D.xml @@ -55,7 +55,7 @@ <method name="get_real_velocity" qualifiers="const"> <return type="Vector2" /> <description> - Returns the current real velocity since the last call to [method move_and_slide]. For example, when you climb a slope, you will move diagonally even though the velocity is horizontal. This method returns the diagonal movement, as opposed to [member motion_velocity] which returns the requested velocity. + Returns the current real velocity since the last call to [method move_and_slide]. For example, when you climb a slope, you will move diagonally even though the velocity is horizontal. This method returns the diagonal movement, as opposed to [member velocity] which returns the requested velocity. </description> </method> <method name="get_slide_collision"> @@ -131,9 +131,8 @@ <method name="move_and_slide"> <return type="bool" /> <description> - Moves the body based on [member motion_velocity]. If the body collides with another, it will slide along the other body (by default only on floor) rather than stop immediately. If the other body is a [CharacterBody2D] or [RigidDynamicBody2D], it will also be affected by the motion of the other body. You can use this to make moving and rotating platforms, or to make nodes push other nodes. - This method should be used in [method Node._physics_process] (or in a method called by [method Node._physics_process]), as it uses the physics step's [code]delta[/code] value automatically in calculations. Otherwise, the simulation will run at an incorrect speed. - Modifies [member motion_velocity] if a slide collision occurred. To get the latest collision call [method get_last_slide_collision], for detailed information about collisions that occurred, use [method get_slide_collision]. + Moves the body based on [member velocity]. If the body collides with another, it will slide along the other body (by default only on floor) rather than stop immediately. If the other body is a [CharacterBody2D] or [RigidDynamicBody2D], it will also be affected by the motion of the other body. You can use this to make moving and rotating platforms, or to make nodes push other nodes. + Modifies [member velocity] if a slide collision occurred. To get the latest collision call [method get_last_slide_collision], for detailed information about collisions that occurred, use [method get_slide_collision]. When the body touches a moving platform, the platform's velocity is automatically added to the body motion. If a collision occurs due to the platform's motion, it will always be first in the slide collisions. The general behavior and available properties change according to the [member motion_mode]. Returns [code]true[/code] if the body collided, otherwise, returns [code]false[/code]. @@ -163,7 +162,7 @@ </member> <member name="floor_stop_on_slope" type="bool" setter="set_floor_stop_on_slope_enabled" getter="is_floor_stop_on_slope_enabled" default="true"> If [code]true[/code], the body will not slide on slopes when calling [method move_and_slide] when the body is standing still. - If [code]false[/code], the body will slide on floor's slopes when [member motion_velocity] applies a downward force. + If [code]false[/code], the body will slide on floor's slopes when [member velocity] applies a downward force. </member> <member name="max_slides" type="int" setter="set_max_slides" getter="get_max_slides" default="4"> Maximum number of times the body can change direction before it stops when calling [method move_and_slide]. @@ -171,9 +170,6 @@ <member name="motion_mode" type="int" setter="set_motion_mode" getter="get_motion_mode" enum="CharacterBody2D.MotionMode" default="0"> Sets the motion mode which defines the behavior of [method move_and_slide]. See [enum MotionMode] constants for available modes. </member> - <member name="motion_velocity" type="Vector2" setter="set_motion_velocity" getter="get_motion_velocity" default="Vector2(0, 0)"> - Current velocity vector in pixels per second, used and modified during calls to [method move_and_slide]. - </member> <member name="moving_platform_apply_velocity_on_leave" type="int" setter="set_moving_platform_apply_velocity_on_leave" getter="get_moving_platform_apply_velocity_on_leave" enum="CharacterBody2D.MovingPlatformApplyVelocityOnLeave" default="0"> Sets the behavior to apply when you leave a moving platform. By default, to be physically accurate, when you leave the last platform velocity is applied. See [enum MovingPlatformApplyVelocityOnLeave] constants for available behavior. </member> @@ -189,6 +185,9 @@ <member name="up_direction" type="Vector2" setter="set_up_direction" getter="get_up_direction" default="Vector2(0, -1)"> Direction vector used to determine what is a wall and what is a floor (or a ceiling), rather than a wall, when calling [method move_and_slide]. Defaults to [code]Vector2.UP[/code]. If set to [code]Vector2(0, 0)[/code], everything is considered a wall. This is useful for topdown games. </member> + <member name="velocity" type="Vector2" setter="set_velocity" getter="get_velocity" default="Vector2(0, 0)"> + Current velocity vector in pixels per second, used and modified during calls to [method move_and_slide]. + </member> <member name="wall_min_slide_angle" type="float" setter="set_wall_min_slide_angle" getter="get_wall_min_slide_angle" default="0.261799"> Minimum angle (in radians) where the body is allowed to slide when it encounters a slope. The default value equals 15 degrees. This property only affects movement when [member motion_mode] is [constant MOTION_MODE_FLOATING]. </member> @@ -201,10 +200,10 @@ Apply when there is no notion of floor or ceiling. All collisions will be reported as [code]on_wall[/code]. In this mode, when you slide, the speed will always be constant. This mode is suitable for top-down games. </constant> <constant name="PLATFORM_VEL_ON_LEAVE_ALWAYS" value="0" enum="MovingPlatformApplyVelocityOnLeave"> - Add the last platform velocity to the [member motion_velocity] when you leave a moving platform. + Add the last platform velocity to the [member velocity] when you leave a moving platform. </constant> <constant name="PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY" value="1" enum="MovingPlatformApplyVelocityOnLeave"> - Add the last platform velocity to the [member motion_velocity] when you leave a moving platform, but any downward motion is ignored. It's useful to keep full jump height even when the platform is moving down. + Add the last platform velocity to the [member velocity] when you leave a moving platform, but any downward motion is ignored. It's useful to keep full jump height even when the platform is moving down. </constant> <constant name="PLATFORM_VEL_ON_LEAVE_NEVER" value="2" enum="MovingPlatformApplyVelocityOnLeave"> Do nothing when leaving a platform. diff --git a/doc/classes/CharacterBody3D.xml b/doc/classes/CharacterBody3D.xml index 2d18a18eac..4895e2cff7 100644 --- a/doc/classes/CharacterBody3D.xml +++ b/doc/classes/CharacterBody3D.xml @@ -56,7 +56,7 @@ <method name="get_real_velocity" qualifiers="const"> <return type="Vector3" /> <description> - Returns the current real velocity since the last call to [method move_and_slide]. For example, when you climb a slope, you will move diagonally even though the velocity is horizontal. This method returns the diagonal movement, as opposed to [member motion_velocity] which returns the requested velocity. + Returns the current real velocity since the last call to [method move_and_slide]. For example, when you climb a slope, you will move diagonally even though the velocity is horizontal. This method returns the diagonal movement, as opposed to [member velocity] which returns the requested velocity. </description> </method> <method name="get_slide_collision"> @@ -117,9 +117,8 @@ <method name="move_and_slide"> <return type="bool" /> <description> - Moves the body based on [member motion_velocity]. If the body collides with another, it will slide along the other body rather than stop immediately. If the other body is a [CharacterBody3D] or [RigidDynamicBody3D], it will also be affected by the motion of the other body. You can use this to make moving and rotating platforms, or to make nodes push other nodes. - This method should be used in [method Node._physics_process] (or in a method called by [method Node._physics_process]), as it uses the physics step's [code]delta[/code] value automatically in calculations. Otherwise, the simulation will run at an incorrect speed. - Modifies [member motion_velocity] if a slide collision occurred. To get the latest collision call [method get_last_slide_collision], for more detailed information about collisions that occurred, use [method get_slide_collision]. + Moves the body based on [member velocity]. If the body collides with another, it will slide along the other body rather than stop immediately. If the other body is a [CharacterBody3D] or [RigidDynamicBody3D], it will also be affected by the motion of the other body. You can use this to make moving and rotating platforms, or to make nodes push other nodes. + Modifies [member velocity] if a slide collision occurred. To get the latest collision call [method get_last_slide_collision], for more detailed information about collisions that occurred, use [method get_slide_collision]. When the body touches a moving platform, the platform's velocity is automatically added to the body motion. If a collision occurs due to the platform's motion, it will always be first in the slide collisions. Returns [code]true[/code] if the body collided, otherwise, returns [code]false[/code]. </description> @@ -148,7 +147,7 @@ </member> <member name="floor_stop_on_slope" type="bool" setter="set_floor_stop_on_slope_enabled" getter="is_floor_stop_on_slope_enabled" default="true"> If [code]true[/code], the body will not slide on slopes when calling [method move_and_slide] when the body is standing still. - If [code]false[/code], the body will slide on floor's slopes when [member motion_velocity] applies a downward force. + If [code]false[/code], the body will slide on floor's slopes when [member velocity] applies a downward force. </member> <member name="max_slides" type="int" setter="set_max_slides" getter="get_max_slides" default="6"> Maximum number of times the body can change direction before it stops when calling [method move_and_slide]. @@ -156,9 +155,6 @@ <member name="motion_mode" type="int" setter="set_motion_mode" getter="get_motion_mode" enum="CharacterBody3D.MotionMode" default="0"> Sets the motion mode which defines the behavior of [method move_and_slide]. See [enum MotionMode] constants for available modes. </member> - <member name="motion_velocity" type="Vector3" setter="set_motion_velocity" getter="get_motion_velocity" default="Vector3(0, 0, 0)"> - Current velocity vector (typically meters per second), used and modified during calls to [method move_and_slide]. - </member> <member name="moving_platform_apply_velocity_on_leave" type="int" setter="set_moving_platform_apply_velocity_on_leave" getter="get_moving_platform_apply_velocity_on_leave" enum="CharacterBody3D.MovingPlatformApplyVelocityOnLeave" default="0"> Sets the behavior to apply when you leave a moving platform. By default, to be physically accurate, when you leave the last platform velocity is applied. See [enum MovingPlatformApplyVelocityOnLeave] constants for available behavior. </member> @@ -174,6 +170,9 @@ <member name="up_direction" type="Vector3" setter="set_up_direction" getter="get_up_direction" default="Vector3(0, 1, 0)"> Direction vector used to determine what is a wall and what is a floor (or a ceiling), rather than a wall, when calling [method move_and_slide]. Defaults to [code]Vector3.UP[/code]. If set to [code]Vector3(0, 0, 0)[/code], everything is considered a wall. This is useful for topdown games. </member> + <member name="velocity" type="Vector3" setter="set_velocity" getter="get_velocity" default="Vector3(0, 0, 0)"> + Current velocity vector (typically meters per second), used and modified during calls to [method move_and_slide]. + </member> <member name="wall_min_slide_angle" type="float" setter="set_wall_min_slide_angle" getter="get_wall_min_slide_angle" default="0.261799"> Minimum angle (in radians) where the body is allowed to slide when it encounters a slope. The default value equals 15 degrees. When [member motion_mode] is [constant MOTION_MODE_GROUNDED], it only affects movement if [member floor_block_on_wall] is [code]true[/code]. </member> @@ -186,10 +185,10 @@ Apply when there is no notion of floor or ceiling. All collisions will be reported as [code]on_wall[/code]. In this mode, when you slide, the speed will always be constant. This mode is suitable for games without ground like space games. </constant> <constant name="PLATFORM_VEL_ON_LEAVE_ALWAYS" value="0" enum="MovingPlatformApplyVelocityOnLeave"> - Add the last platform velocity to the [member motion_velocity] when you leave a moving platform. + Add the last platform velocity to the [member velocity] when you leave a moving platform. </constant> <constant name="PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY" value="1" enum="MovingPlatformApplyVelocityOnLeave"> - Add the last platform velocity to the [member motion_velocity] when you leave a moving platform, but any downward motion is ignored. It's useful to keep full jump height even when the platform is moving down. + Add the last platform velocity to the [member velocity] when you leave a moving platform, but any downward motion is ignored. It's useful to keep full jump height even when the platform is moving down. </constant> <constant name="PLATFORM_VEL_ON_LEAVE_NEVER" value="2" enum="MovingPlatformApplyVelocityOnLeave"> Do nothing when leaving a platform. diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index 8e9bedc831..be8811d629 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -515,7 +515,7 @@ <method name="virtual_keyboard_show"> <return type="void" /> <argument index="0" name="existing_text" type="String" /> - <argument index="1" name="position" type="Rect2" default="Rect2i(0, 0, 0, 0)" /> + <argument index="1" name="position" type="Rect2" default="Rect2(0, 0, 0, 0)" /> <argument index="2" name="multiline" type="bool" default="false" /> <argument index="3" name="max_length" type="int" default="-1" /> <argument index="4" name="cursor_start" type="int" default="-1" /> diff --git a/doc/classes/Geometry2D.xml b/doc/classes/Geometry2D.xml index 446a90463d..cbd83e8d7d 100644 --- a/doc/classes/Geometry2D.xml +++ b/doc/classes/Geometry2D.xml @@ -209,7 +209,7 @@ <return type="PackedInt32Array" /> <argument index="0" name="polygon" type="PackedVector2Array" /> <description> - Triangulates the polygon specified by the points in [code]polygon[/code]. Returns a [PackedInt32Array] where each triangle consists of three consecutive point indices into [code]polygon[/code] (i.e. the returned array will have [code]n * 3[/code] elements, with [code]n[/code] being the number of found triangles). If the triangulation did not succeed, an empty [PackedInt32Array] is returned. + Triangulates the polygon specified by the points in [code]polygon[/code]. Returns a [PackedInt32Array] where each triangle consists of three consecutive point indices into [code]polygon[/code] (i.e. the returned array will have [code]n * 3[/code] elements, with [code]n[/code] being the number of found triangles). Output triangles will always be counter clockwise, and the contour will be flipped if it's clockwise. If the triangulation did not succeed, an empty [PackedInt32Array] is returned. </description> </method> </methods> diff --git a/doc/classes/Line2D.xml b/doc/classes/Line2D.xml index 41c9ea5df5..88574c0028 100644 --- a/doc/classes/Line2D.xml +++ b/doc/classes/Line2D.xml @@ -79,7 +79,8 @@ The points that form the lines. The line is drawn between every point set in this array. Points are interpreted as local vectors. </member> <member name="round_precision" type="int" setter="set_round_precision" getter="get_round_precision" default="8"> - The smoothness of the rounded joints and caps. This is only used if a cap or joint is set as round. + The smoothness of the rounded joints and caps. Higher values result in smoother corners, but are more demanding to render and update. This is only used if a cap or joint is set as round. + [b]Note:[/b] The default value is tuned for lines with the default [member width]. For thin lines, this value should be reduced to a number between [code]2[/code] and [code]4[/code] to improve performance. </member> <member name="sharp_limit" type="float" setter="set_sharp_limit" getter="get_sharp_limit" default="2.0"> The direction difference in radians between vector points. This value is only used if [member joint_mode] is set to [constant LINE_JOINT_SHARP]. diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index 5ae50f86d4..5291ecab08 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -181,16 +181,19 @@ [b]Note:[/b] It will not work properly if the node contains a script with constructor arguments (i.e. needs to supply arguments to [method Object._init] method). In that case, the node will be duplicated without a script. </description> </method> - <method name="find_node" qualifiers="const"> - <return type="Node" /> + <method name="find_nodes" qualifiers="const"> + <return type="Node[]" /> <argument index="0" name="mask" type="String" /> - <argument index="1" name="recursive" type="bool" default="true" /> - <argument index="2" name="owned" type="bool" default="true" /> + <argument index="1" name="type" type="String" default="""" /> + <argument index="2" name="recursive" type="bool" default="true" /> + <argument index="3" name="owned" type="bool" default="true" /> <description> - Finds a descendant of this node whose name matches [code]mask[/code] as in [method String.match] (i.e. case-sensitive, but [code]"*"[/code] matches zero or more characters and [code]"?"[/code] matches any single character except [code]"."[/code]). Returns [code]null[/code] if no matching [Node] is found. - [b]Note:[/b] It does not match against the full path, just against individual node names. + Finds descendants of this node whose, name matches [code]mask[/code] as in [method String.match], and/or type matches [code]type[/code] as in [method Object.is_class]. + [code]mask[/code] does not match against the full path, just against individual node names. It is case-sensitive, with [code]"*"[/code] matching zero or more characters and [code]"?"[/code] matching any single character except [code]"."[/code]). + [code]type[/code] will check equality or inheritance. It is case-sensitive, [code]"Object"[/code] will match a node whose type is [code]"Node"[/code] but not the other way around. If [code]owned[/code] is [code]true[/code], this method only finds nodes whose owner is this node. This is especially important for scenes instantiated through a script, because those scenes don't have an owner. - [b]Note:[/b] As this method walks through all the descendants of the node, it is the slowest way to get a reference to another node. Whenever possible, consider using [method get_node] instead. To avoid using [method find_node] too often, consider caching the node reference into a variable. + Returns an empty array, if no matching nodes are found. + [b]Note:[/b] As this method walks through all the descendants of the node, it is the slowest way to get references to other nodes. To avoid using [method find_nodes] too often, consider caching the node references into variables. </description> </method> <method name="find_parent" qualifiers="const"> @@ -853,6 +856,14 @@ </constant> <constant name="NOTIFICATION_WM_SIZE_CHANGED" value="1008"> </constant> + <constant name="NOTIFICATION_WM_DPI_CHANGE" value="1009"> + </constant> + <constant name="NOTIFICATION_VP_MOUSE_ENTER" value="1010"> + Notification received when the mouse enters the viewport. + </constant> + <constant name="NOTIFICATION_VP_MOUSE_EXIT" value="1011"> + Notification received when the mouse leaves the viewport. + </constant> <constant name="NOTIFICATION_OS_MEMORY_WARNING" value="2009"> Notification received from the OS when the application is exceeding its allocated memory. Specific to the iOS platform. diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 805f897b63..a3810bb575 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -1776,10 +1776,10 @@ <member name="rendering/reflections/sky_reflections/fast_filter_high_quality" type="bool" setter="" getter="" default="false"> Use a higher quality variant of the fast filtering algorithm. Significantly slower than using default quality, but results in smoother reflections. Should only be used when the scene is especially detailed. </member> - <member name="rendering/reflections/sky_reflections/ggx_samples" type="int" setter="" getter="" default="1024"> + <member name="rendering/reflections/sky_reflections/ggx_samples" type="int" setter="" getter="" default="32"> Sets the number of samples to take when using importance sampling for [Sky]s and [ReflectionProbe]s. A higher value will result in smoother, higher quality reflections, but increases time to calculate radiance maps. In general, fewer samples are needed for simpler, low dynamic range environments while more samples are needed for HDR environments and environments with a high level of detail. </member> - <member name="rendering/reflections/sky_reflections/ggx_samples.mobile" type="int" setter="" getter="" default="128"> + <member name="rendering/reflections/sky_reflections/ggx_samples.mobile" type="int" setter="" getter="" default="16"> Lower-end override for [member rendering/reflections/sky_reflections/ggx_samples] on mobile devices, due to performance concerns or driver support. </member> <member name="rendering/reflections/sky_reflections/roughness_layers" type="int" setter="" getter="" default="8"> @@ -1813,12 +1813,6 @@ </member> <member name="rendering/shader_compiler/shader_cache/use_zstd_compression" type="bool" setter="" getter="" default="true"> </member> - <member name="rendering/shading/overrides/force_blinn_over_ggx" type="bool" setter="" getter="" default="false"> - If [code]true[/code], uses faster but lower-quality Blinn model to generate blurred reflections instead of the GGX model. - </member> - <member name="rendering/shading/overrides/force_blinn_over_ggx.mobile" type="bool" setter="" getter="" default="true"> - Lower-end override for [member rendering/shading/overrides/force_blinn_over_ggx] on mobile devices, due to performance concerns or driver support. - </member> <member name="rendering/shading/overrides/force_lambert_over_burley" type="bool" setter="" getter="" default="false"> If [code]true[/code], uses faster but lower-quality Lambert material lighting model instead of Burley. </member> @@ -1921,8 +1915,23 @@ </member> <member name="rendering/vulkan/staging_buffer/texture_upload_region_size_px" type="int" setter="" getter="" default="64"> </member> - <member name="rendering/xr/enabled" type="bool" setter="" getter="" default="false"> - If [code]true[/code], XR support is enabled in Godot, this ensures required shaders are compiled. + <member name="xr/openxr/default_action_map" type="String" setter="" getter="" default=""res://default_action_map.tres""> + Action map configuration to load by default. + </member> + <member name="xr/openxr/enabled" type="bool" setter="" getter="" default="false"> + If [code]true[/code] Godot will setup and initialise OpenXR on startup. + </member> + <member name="xr/openxr/form_factor" type="int" setter="" getter="" default=""0""> + Specify whether OpenXR should be configured for an HMD or a hand held device. + </member> + <member name="xr/openxr/reference_space" type="int" setter="" getter="" default=""1""> + Specify the default reference space. + </member> + <member name="xr/openxr/view_configuration" type="int" setter="" getter="" default=""1""> + Specify the view configuration with which to configure OpenXR settting up either Mono or Stereo rendering. + </member> + <member name="xr/shaders/enabled" type="bool" setter="" getter="" default="false"> + If [code]true[/code], Godot will compile shaders required for XR. </member> </members> </class> diff --git a/doc/classes/Sky.xml b/doc/classes/Sky.xml index 20e3896b17..e14e57a1c4 100644 --- a/doc/classes/Sky.xml +++ b/doc/classes/Sky.xml @@ -9,7 +9,7 @@ <tutorials> </tutorials> <members> - <member name="process_mode" type="int" setter="set_process_mode" getter="get_process_mode" enum="Sky.ProcessMode" default="3"> + <member name="process_mode" type="int" setter="set_process_mode" getter="get_process_mode" enum="Sky.ProcessMode" default="0"> Sets the method for generating the radiance map from the sky. The radiance map is a cubemap with increasingly blurry versions of the sky corresponding to different levels of roughness. Radiance maps can be expensive to calculate. See [enum ProcessMode] for options. </member> <member name="radiance_size" type="int" setter="set_radiance_size" getter="get_radiance_size" enum="Sky.RadianceSize" default="3"> diff --git a/doc/classes/SpriteBase3D.xml b/doc/classes/SpriteBase3D.xml index 298f5bc8c2..405fff0ce8 100644 --- a/doc/classes/SpriteBase3D.xml +++ b/doc/classes/SpriteBase3D.xml @@ -61,7 +61,7 @@ </member> <member name="modulate" type="Color" setter="set_modulate" getter="get_modulate" default="Color(1, 1, 1, 1)"> A color value used to [i]multiply[/i] the texture's colors. Can be used for mood-coloring or to simulate the color of light. - [b]Note:[/b] If a [member GeometryInstance3D.material_override] is defined on the [SpriteBase3D], the material override must be configured to take vertex colors into account for albedo. Otherwise, the color defined in [member modulate] will be ignored. For a [BaseMaterial3D], [member BaseMaterial3D.vertex_color_use_as_albedo] must be [code]true[/code]. For a [ShaderMaterial], [code]ALBEDO *= COLOR.rgb;[/color] must be inserted in the shader's [code]fragment()[/code] function. + [b]Note:[/b] If a [member GeometryInstance3D.material_override] is defined on the [SpriteBase3D], the material override must be configured to take vertex colors into account for albedo. Otherwise, the color defined in [member modulate] will be ignored. For a [BaseMaterial3D], [member BaseMaterial3D.vertex_color_use_as_albedo] must be [code]true[/code]. For a [ShaderMaterial], [code]ALBEDO *= COLOR.rgb;[/code] must be inserted in the shader's [code]fragment()[/code] function. </member> <member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2(0, 0)"> The texture's drawing offset. diff --git a/doc/classes/String.xml b/doc/classes/String.xml index c1a7a2edda..5f133169f2 100644 --- a/doc/classes/String.xml +++ b/doc/classes/String.xml @@ -265,6 +265,8 @@ <return type="String" /> <argument index="0" name="size" type="int" /> <description> + Converts an integer representing a number of bytes into a human-readable form. + Note that this output is in [url=https://en.wikipedia.org/wiki/Binary_prefix#IEC_prefixes]IEC prefix format[/url], and includes [code]B[/code], [code]KiB[/code], [code]MiB[/code], [code]GiB[/code], [code]TiB[/code], [code]PiB[/code], and [code]EiB[/code]. </description> </method> <method name="indent" qualifiers="const"> @@ -420,14 +422,14 @@ <return type="bool" /> <argument index="0" name="expr" type="String" /> <description> - Does a simple case-sensitive expression match, where [code]"*"[/code] matches zero or more arbitrary characters and [code]"?"[/code] matches any single character except a period ([code]"."[/code]). + Does a simple case-sensitive expression match, where [code]"*"[/code] matches zero or more arbitrary characters and [code]"?"[/code] matches any single character except a period ([code]"."[/code]). An empty string or empty expression always evaluates to [code]false[/code]. </description> </method> <method name="matchn" qualifiers="const"> <return type="bool" /> <argument index="0" name="expr" type="String" /> <description> - Does a simple case-insensitive expression match, where [code]"*"[/code] matches zero or more arbitrary characters and [code]"?"[/code] matches any single character except a period ([code]"."[/code]). + Does a simple case-insensitive expression match, where [code]"*"[/code] matches zero or more arbitrary characters and [code]"?"[/code] matches any single character except a period ([code]"."[/code]). An empty string or empty expression always evaluates to [code]false[/code]. </description> </method> <method name="md5_buffer" qualifiers="const"> diff --git a/doc/classes/SubViewportContainer.xml b/doc/classes/SubViewportContainer.xml index bd48f2b6db..050186a883 100644 --- a/doc/classes/SubViewportContainer.xml +++ b/doc/classes/SubViewportContainer.xml @@ -6,6 +6,7 @@ <description> A [Container] node that holds a [SubViewport], automatically setting its size. [b]Note:[/b] Changing a SubViewportContainer's [member Control.rect_scale] will cause its contents to appear distorted. To change its visual size without causing distortion, adjust the node's margins instead (if it's not already in a container). + [b]Note:[/b] The SubViewportContainer forwards mouse-enter and mouse-exit notifications to its sub-viewports. </description> <tutorials> </tutorials> diff --git a/doc/classes/SurfaceTool.xml b/doc/classes/SurfaceTool.xml index 9d0962f337..43d34d3890 100644 --- a/doc/classes/SurfaceTool.xml +++ b/doc/classes/SurfaceTool.xml @@ -11,14 +11,14 @@ st.begin(Mesh.PRIMITIVE_TRIANGLES) st.set_color(Color(1, 0, 0)) st.set_uv(Vector2(0, 0)) - st.set_vertex(Vector3(0, 0, 0)) + st.add_vertex(Vector3(0, 0, 0)) [/gdscript] [csharp] var st = new SurfaceTool(); st.Begin(Mesh.PrimitiveType.Triangles); st.SetColor(new Color(1, 0, 0)); st.SetUv(new Vector2(0, 0)); - st.SetVertex(new Vector3(0, 0, 0)); + st.AddVertex(new Vector3(0, 0, 0)); [/csharp] [/codeblocks] The above [SurfaceTool] now contains one vertex of a triangle which has a UV coordinate and a specified [Color]. If another vertex were added without calling [method set_uv] or [method set_color], then the last values would be used. diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml index b6a2909ce7..c909a35ab5 100644 --- a/doc/classes/TreeItem.xml +++ b/doc/classes/TreeItem.xml @@ -18,7 +18,7 @@ <argument index="3" name="disabled" type="bool" default="false" /> <argument index="4" name="tooltip" type="String" default="""" /> <description> - Adds a button with [Texture2D] [code]button[/code] at column [code]column[/code]. The [code]id[/code] is used to identify the button. If not specified, the next available index is used, which may be retrieved by calling [method get_button_count] immediately after this method. Optionally, the button can be [code]disabled[/code] and have a [code]tooltip[/code]. + Adds a button with [Texture2D] [code]button[/code] at column [code]column[/code]. The [code]id[/code] is used to identify the button. If not specified, the next available index is used, which may be retrieved by calling [method get_button_count] immediately before this method. Optionally, the button can be [code]disabled[/code] and have a [code]tooltip[/code]. </description> </method> <method name="call_recursive" qualifiers="vararg"> @@ -92,7 +92,7 @@ <return type="int" /> <argument index="0" name="column" type="int" /> <description> - Returns the number of buttons in column [code]column[/code]. May be used to get the most recently added button's index, if no index was specified. + Returns the number of buttons in column [code]column[/code]. </description> </method> <method name="get_button_id" qualifiers="const"> diff --git a/doc/classes/VoxelGI.xml b/doc/classes/VoxelGI.xml index 788b4e1f17..55ba1c4934 100644 --- a/doc/classes/VoxelGI.xml +++ b/doc/classes/VoxelGI.xml @@ -21,6 +21,7 @@ <description> Bakes the effect from all [GeometryInstance3D]s marked with [constant GeometryInstance3D.GI_MODE_STATIC] and [Light3D]s marked with either [constant Light3D.BAKE_STATIC] or [constant Light3D.BAKE_DYNAMIC]. If [code]create_visual_debug[/code] is [code]true[/code], after baking the light, this will generate a [MultiMesh] that has a cube representing each solid cell with each cube colored to the cell's albedo color. This can be used to visualize the [VoxelGI]'s data and debug any issues that may be occurring. [b]Note:[/b] [method bake] works from the editor and in exported projects. This makes it suitable for procedurally generated or user-built levels. Baking a [VoxelGI] node generally takes from 5 to 20 seconds in most scenes. Reducing [member subdiv] can speed up baking. + [b]Note:[/b] [GeometryInstance3D]s and [Light3D]s must be fully ready before [method bake] is called. If you are procedurally creating those and some meshes or lights are missing from your baked [VoxelGI], use [code]call_deferred("bake")[/code] instead of calling [method bake] directly. </description> </method> <method name="debug_bake"> diff --git a/doc/classes/XRController3D.xml b/doc/classes/XRController3D.xml index a77f8cf9ca..deea888b8f 100644 --- a/doc/classes/XRController3D.xml +++ b/doc/classes/XRController3D.xml @@ -41,12 +41,6 @@ </description> </method> </methods> - <members> - <member name="rumble" type="float" setter="set_rumble" getter="get_rumble" default="0.0"> - The degree to which the controller vibrates. Ranges from [code]0.0[/code] to [code]1.0[/code] with precision [code].01[/code]. If changed, updates [member XRPositionalTracker.rumble] accordingly. - This is a useful property to animate if you want the controller to vibrate for a limited duration. - </member> - </members> <signals> <signal name="button_pressed"> <argument index="0" name="name" type="String" /> diff --git a/doc/classes/XRPositionalTracker.xml b/doc/classes/XRPositionalTracker.xml index c544ef3cfa..da378759d8 100644 --- a/doc/classes/XRPositionalTracker.xml +++ b/doc/classes/XRPositionalTracker.xml @@ -72,9 +72,6 @@ - [code]left_hand[/code] identifies the controller held in the players left hand - [code]right_hand[/code] identifies the controller held in the players right hand </member> - <member name="rumble" type="float" setter="set_rumble" getter="get_rumble" default="0.0"> - The degree to which the tracker rumbles. Ranges from [code]0.0[/code] to [code]1.0[/code] with precision [code].01[/code]. - </member> <member name="type" type="int" setter="set_tracker_type" getter="get_tracker_type" enum="XRServer.TrackerType" default="128"> The type of tracker. </member> diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 98c92a1d99..2d504cd052 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -1107,7 +1107,7 @@ void light_compute( float rim, float rim_tint, float clearcoat, - float clearcoat_gloss, + float clearcoat_roughness, float anisotropy, inout vec3 diffuse_light, inout vec3 specular_light, @@ -1298,7 +1298,7 @@ LIGHT_SHADER_CODE #if !defined(SPECULAR_SCHLICK_GGX) float cLdotH5 = SchlickFresnel(cLdotH); #endif - float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_gloss)); + float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_roughness)); float Fr = mix(.04, 1.0, cLdotH5); //float Gr = G_GGX_2cos(cNdotL, .25) * G_GGX_2cos(cNdotV, .25); float Gr = V_GGX(cNdotL, cNdotV, 0.25); @@ -1427,7 +1427,7 @@ void main() { float rim = 0.0; float rim_tint = 0.0; float clearcoat = 0.0; - float clearcoat_gloss = 0.0; + float clearcoat_roughness = 0.0; float anisotropy = 0.0; vec2 anisotropy_flow = vec2(1.0, 0.0); float sss_strength = 0.0; //unused @@ -2028,7 +2028,7 @@ FRAGMENT_SHADER_CODE rim, rim_tint, clearcoat, - clearcoat_gloss, + clearcoat_roughness, anisotropy, diffuse_light, specular_light, diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 247961b358..cda8871f3e 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -2118,6 +2118,124 @@ RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID return id; } +RID RenderingDeviceVulkan::texture_create_from_extension(TextureType p_type, DataFormat p_format, TextureSamples p_samples, uint64_t p_flags, uint64_t p_image, uint64_t p_width, uint64_t p_height, uint64_t p_depth, uint64_t p_layers) { + _THREAD_SAFE_METHOD_ + // This method creates a texture object using a VkImage created by an extension, module or other external source (OpenXR uses this). + VkImage image = (VkImage)p_image; + + Texture texture; + texture.image = image; + // if we leave texture.allocation as a nullptr, would that be enough to detect we don't "own" the image? + // also leave texture.allocation_info alone + // we'll set texture.view later on + texture.type = p_type; + texture.format = p_format; + texture.samples = p_samples; + texture.width = p_width; + texture.height = p_height; + texture.depth = p_depth; + texture.layers = p_layers; + texture.mipmaps = 0; // maybe make this settable too? + texture.usage_flags = p_flags; + texture.base_mipmap = 0; + texture.base_layer = 0; + texture.allowed_shared_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_UNORM); + texture.allowed_shared_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_SRGB); + + // Do we need to do something with texture.layout ? + + if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + texture.read_aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT; + texture.barrier_aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT; + + // if (format_has_stencil(p_format.format)) { + // texture.barrier_aspect_mask |= VK_IMAGE_ASPECT_STENCIL_BIT; + // } + } else { + texture.read_aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT; + texture.barrier_aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT; + } + + // Create a view for us to use + + VkImageViewCreateInfo image_view_create_info; + image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + image_view_create_info.pNext = nullptr; + image_view_create_info.flags = 0; + image_view_create_info.image = texture.image; + + static const VkImageViewType view_types[TEXTURE_TYPE_MAX] = { + VK_IMAGE_VIEW_TYPE_1D, + VK_IMAGE_VIEW_TYPE_2D, + VK_IMAGE_VIEW_TYPE_3D, + VK_IMAGE_VIEW_TYPE_CUBE, + VK_IMAGE_VIEW_TYPE_1D_ARRAY, + VK_IMAGE_VIEW_TYPE_2D_ARRAY, + VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, + }; + + image_view_create_info.viewType = view_types[texture.type]; + image_view_create_info.format = vulkan_formats[texture.format]; + + static const VkComponentSwizzle component_swizzles[TEXTURE_SWIZZLE_MAX] = { + VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_ZERO, + VK_COMPONENT_SWIZZLE_ONE, + VK_COMPONENT_SWIZZLE_R, + VK_COMPONENT_SWIZZLE_G, + VK_COMPONENT_SWIZZLE_B, + VK_COMPONENT_SWIZZLE_A + }; + + // hardcode for now, maybe make this settable from outside.. + image_view_create_info.components.r = component_swizzles[TEXTURE_SWIZZLE_R]; + image_view_create_info.components.g = component_swizzles[TEXTURE_SWIZZLE_G]; + image_view_create_info.components.b = component_swizzles[TEXTURE_SWIZZLE_B]; + image_view_create_info.components.a = component_swizzles[TEXTURE_SWIZZLE_A]; + + image_view_create_info.subresourceRange.baseMipLevel = 0; + image_view_create_info.subresourceRange.levelCount = texture.mipmaps; + image_view_create_info.subresourceRange.baseArrayLayer = 0; + image_view_create_info.subresourceRange.layerCount = texture.layers; + if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + } else { + image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + } + + VkResult err = vkCreateImageView(device, &image_view_create_info, nullptr, &texture.view); + + if (err) { + // vmaDestroyImage(allocator, texture.image, texture.allocation); + ERR_FAIL_V_MSG(RID(), "vkCreateImageView failed with error " + itos(err) + "."); + } + + //barrier to set layout + { + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = nullptr; + image_memory_barrier.srcAccessMask = 0; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + image_memory_barrier.newLayout = texture.layout; + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = texture.image; + image_memory_barrier.subresourceRange.aspectMask = texture.barrier_aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = 0; + image_memory_barrier.subresourceRange.levelCount = texture.mipmaps; + image_memory_barrier.subresourceRange.baseArrayLayer = 0; + image_memory_barrier.subresourceRange.layerCount = texture.layers; + + vkCmdPipelineBarrier(frames[frame].setup_command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); + } + + RID id = texture_owner.make_rid(texture); + + return id; +} + RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, uint32_t p_mipmaps, TextureSliceType p_slice_type) { _THREAD_SAFE_METHOD_ @@ -6652,6 +6770,10 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin_for_screen(Di VkCommandBuffer command_buffer = frames[frame].draw_command_buffer; + if (!context->window_is_valid_swapchain(p_screen)) { + return INVALID_ID; + } + Size2i size = Size2i(context->window_get_width(p_screen), context->window_get_height(p_screen)); _draw_list_allocate(Rect2i(Vector2i(), size), 0, 0); diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h index 6510893196..3e4327667b 100644 --- a/drivers/vulkan/rendering_device_vulkan.h +++ b/drivers/vulkan/rendering_device_vulkan.h @@ -1037,6 +1037,7 @@ class RenderingDeviceVulkan : public RenderingDevice { public: virtual RID texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<Vector<uint8_t>> &p_data = Vector<Vector<uint8_t>>()); virtual RID texture_create_shared(const TextureView &p_view, RID p_with_texture); + virtual RID texture_create_from_extension(TextureType p_type, DataFormat p_format, TextureSamples p_samples, uint64_t p_flags, uint64_t p_image, uint64_t p_width, uint64_t p_height, uint64_t p_depth, uint64_t p_layers); virtual RID texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, uint32_t p_mipmaps = 1, TextureSliceType p_slice_type = TEXTURE_SLICE_2D); virtual Error texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL); diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp index 1aa1bfddc8..3551b5d6c4 100644 --- a/drivers/vulkan/vulkan_context.cpp +++ b/drivers/vulkan/vulkan_context.cpp @@ -46,6 +46,8 @@ #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) #define APP_SHORT_NAME "GodotEngine" +VulkanHooks *VulkanContext::vulkan_hooks = nullptr; + VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_debug_messenger_callback( VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, @@ -514,45 +516,62 @@ Error VulkanContext::_check_capabilities() { subgroup_capabilities.supportedStages = 0; subgroup_capabilities.supportedOperations = 0; subgroup_capabilities.quadOperationsInAllStages = false; + shader_capabilities.shader_float16_is_supported = false; + shader_capabilities.shader_int8_is_supported = false; + storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported = false; + storage_buffer_capabilities.uniform_and_storage_buffer_16_bit_access_is_supported = false; + storage_buffer_capabilities.storage_push_constant_16_is_supported = false; + storage_buffer_capabilities.storage_input_output_16 = false; // check for extended features - PFN_vkGetPhysicalDeviceFeatures2 device_features_func = (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceFeatures2"); - if (device_features_func == nullptr) { + PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2_func = (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceFeatures2"); + if (vkGetPhysicalDeviceFeatures2_func == nullptr) { // In Vulkan 1.0 might be accessible under its original extension name - device_features_func = (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceFeatures2KHR"); + vkGetPhysicalDeviceFeatures2_func = (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceFeatures2KHR"); } - if (device_features_func != nullptr) { + if (vkGetPhysicalDeviceFeatures2_func != nullptr) { // check our extended features - VkPhysicalDeviceMultiviewFeatures multiview_features; - multiview_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES; - multiview_features.pNext = nullptr; + VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader_features = { + /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR, + /*pNext*/ nullptr, + /*shaderFloat16*/ false, + /*shaderInt8*/ false, + }; + + VkPhysicalDevice16BitStorageFeaturesKHR storage_feature = { + /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR, + /*pNext*/ &shader_features, + /*storageBuffer16BitAccess*/ false, + /*uniformAndStorageBuffer16BitAccess*/ false, + /*storagePushConstant16*/ false, + /*storageInputOutput16*/ false, + }; + + VkPhysicalDeviceMultiviewFeatures multiview_features = { + /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES, + /*pNext*/ &storage_feature, + /*multiview*/ false, + /*multiviewGeometryShader*/ false, + /*multiviewTessellationShader*/ false, + }; VkPhysicalDeviceFeatures2 device_features; device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; device_features.pNext = &multiview_features; - device_features_func(gpu, &device_features); + vkGetPhysicalDeviceFeatures2_func(gpu, &device_features); + multiview_capabilities.is_supported = multiview_features.multiview; multiview_capabilities.geometry_shader_is_supported = multiview_features.multiviewGeometryShader; multiview_capabilities.tessellation_shader_is_supported = multiview_features.multiviewTessellationShader; - VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader_features; - shader_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR; - shader_features.pNext = nullptr; - - device_features.pNext = &shader_features; - - device_features_func(gpu, &device_features); shader_capabilities.shader_float16_is_supported = shader_features.shaderFloat16; + shader_capabilities.shader_int8_is_supported = shader_features.shaderInt8; - VkPhysicalDevice16BitStorageFeaturesKHR storage_feature; - storage_feature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR; - storage_feature.pNext = nullptr; - - device_features.pNext = &storage_feature; - - device_features_func(gpu, &device_features); storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported = storage_feature.storageBuffer16BitAccess; + storage_buffer_capabilities.uniform_and_storage_buffer_16_bit_access_is_supported = storage_feature.uniformAndStorageBuffer16BitAccess; + storage_buffer_capabilities.storage_push_constant_16_is_supported = storage_feature.storagePushConstant16; + storage_buffer_capabilities.storage_input_output_16 = storage_feature.storageInputOutput16; } // check extended properties @@ -678,19 +697,27 @@ Error VulkanContext::_create_instance() { inst_info.pNext = &dbg_report_callback_create_info; } - VkResult err = vkCreateInstance(&inst_info, nullptr, &inst); - ERR_FAIL_COND_V_MSG(err == VK_ERROR_INCOMPATIBLE_DRIVER, ERR_CANT_CREATE, - "Cannot find a compatible Vulkan installable client driver (ICD).\n\n" - "vkCreateInstance Failure"); - ERR_FAIL_COND_V_MSG(err == VK_ERROR_EXTENSION_NOT_PRESENT, ERR_CANT_CREATE, - "Cannot find a specified extension library.\n" - "Make sure your layers path is set appropriately.\n" - "vkCreateInstance Failure"); - ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, - "vkCreateInstance failed.\n\n" - "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" - "Please look at the Getting Started guide for additional information.\n" - "vkCreateInstance Failure"); + VkResult err; + + if (vulkan_hooks) { + if (!vulkan_hooks->create_vulkan_instance(&inst_info, &inst)) { + return ERR_CANT_CREATE; + } + } else { + err = vkCreateInstance(&inst_info, nullptr, &inst); + ERR_FAIL_COND_V_MSG(err == VK_ERROR_INCOMPATIBLE_DRIVER, ERR_CANT_CREATE, + "Cannot find a compatible Vulkan installable client driver (ICD).\n\n" + "vkCreateInstance Failure"); + ERR_FAIL_COND_V_MSG(err == VK_ERROR_EXTENSION_NOT_PRESENT, ERR_CANT_CREATE, + "Cannot find a specified extension library.\n" + "Make sure your layers path is set appropriately.\n" + "vkCreateInstance Failure"); + ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, + "vkCreateInstance failed.\n\n" + "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" + "Please look at the Getting Started guide for additional information.\n" + "vkCreateInstance Failure"); + } inst_initialized = true; @@ -803,107 +830,122 @@ Error VulkanContext::_create_physical_device(VkSurfaceKHR p_surface) { { 0, nullptr }, }; - // TODO: At least on Linux Laptops integrated GPUs fail with Vulkan in many instances. - // The device should really be a preference, but for now choosing a discrete GPU over the - // integrated one is better than the default. - int32_t device_index = -1; - int type_selected = -1; - print_verbose("Vulkan devices:"); - for (uint32_t i = 0; i < gpu_count; ++i) { - VkPhysicalDeviceProperties props; - vkGetPhysicalDeviceProperties(physical_devices[i], &props); - - bool present_supported = false; - - uint32_t device_queue_family_count = 0; - vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &device_queue_family_count, nullptr); - VkQueueFamilyProperties *device_queue_props = (VkQueueFamilyProperties *)malloc(device_queue_family_count * sizeof(VkQueueFamilyProperties)); - vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &device_queue_family_count, device_queue_props); - for (uint32_t j = 0; j < device_queue_family_count; j++) { - VkBool32 supports; - vkGetPhysicalDeviceSurfaceSupportKHR(physical_devices[i], j, p_surface, &supports); - if (supports && ((device_queue_props[j].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0)) { - present_supported = true; - } else { - continue; - } + if (vulkan_hooks) { + if (!vulkan_hooks->get_physical_device(&gpu)) { + return ERR_CANT_CREATE; } - String name = props.deviceName; - String vendor = "Unknown"; - String dev_type; - switch (props.deviceType) { - case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: { - dev_type = "Discrete"; - } break; - case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: { - dev_type = "Integrated"; - } break; - case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: { - dev_type = "Virtual"; - } break; - case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_CPU: { - dev_type = "CPU"; - } break; - default: { - dev_type = "Other"; - } break; - } - uint32_t vendor_idx = 0; - while (vendor_names[vendor_idx].name != nullptr) { - if (props.vendorID == vendor_names[vendor_idx].id) { - vendor = vendor_names[vendor_idx].name; + + // not really needed but nice to print the correct entry + for (uint32_t i = 0; i < gpu_count; ++i) { + if (physical_devices[i] == gpu) { + device_index = i; break; } - vendor_idx++; } - free(device_queue_props); - print_verbose(" #" + itos(i) + ": " + vendor + " " + name + " - " + (present_supported ? "Supported" : "Unsupported") + ", " + dev_type); - - if (present_supported) { // Select first supported device of preferred type: Discrete > Integrated > Virtual > CPU > Other. + } else { + // TODO: At least on Linux Laptops integrated GPUs fail with Vulkan in many instances. + // The device should really be a preference, but for now choosing a discrete GPU over the + // integrated one is better than the default. + + int type_selected = -1; + print_verbose("Vulkan devices:"); + for (uint32_t i = 0; i < gpu_count; ++i) { + VkPhysicalDeviceProperties props; + vkGetPhysicalDeviceProperties(physical_devices[i], &props); + + bool present_supported = false; + + uint32_t device_queue_family_count = 0; + vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &device_queue_family_count, nullptr); + VkQueueFamilyProperties *device_queue_props = (VkQueueFamilyProperties *)malloc(device_queue_family_count * sizeof(VkQueueFamilyProperties)); + vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &device_queue_family_count, device_queue_props); + for (uint32_t j = 0; j < device_queue_family_count; j++) { + VkBool32 supports; + vkGetPhysicalDeviceSurfaceSupportKHR(physical_devices[i], j, p_surface, &supports); + if (supports && ((device_queue_props[j].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0)) { + present_supported = true; + } else { + continue; + } + } + String name = props.deviceName; + String vendor = "Unknown"; + String dev_type; switch (props.deviceType) { case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: { - if (type_selected < 4) { - type_selected = 4; - device_index = i; - } + dev_type = "Discrete"; } break; case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: { - if (type_selected < 3) { - type_selected = 3; - device_index = i; - } + dev_type = "Integrated"; } break; case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: { - if (type_selected < 2) { - type_selected = 2; - device_index = i; - } + dev_type = "Virtual"; } break; case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_CPU: { - if (type_selected < 1) { - type_selected = 1; - device_index = i; - } + dev_type = "CPU"; } break; default: { - if (type_selected < 0) { - type_selected = 0; - device_index = i; - } + dev_type = "Other"; } break; } + uint32_t vendor_idx = 0; + while (vendor_names[vendor_idx].name != nullptr) { + if (props.vendorID == vendor_names[vendor_idx].id) { + vendor = vendor_names[vendor_idx].name; + break; + } + vendor_idx++; + } + free(device_queue_props); + print_verbose(" #" + itos(i) + ": " + vendor + " " + name + " - " + (present_supported ? "Supported" : "Unsupported") + ", " + dev_type); + + if (present_supported) { // Select first supported device of preffered type: Discrete > Integrated > Virtual > CPU > Other. + switch (props.deviceType) { + case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: { + if (type_selected < 4) { + type_selected = 4; + device_index = i; + } + } break; + case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: { + if (type_selected < 3) { + type_selected = 3; + device_index = i; + } + } break; + case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: { + if (type_selected < 2) { + type_selected = 2; + device_index = i; + } + } break; + case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_CPU: { + if (type_selected < 1) { + type_selected = 1; + device_index = i; + } + } break; + default: { + if (type_selected < 0) { + type_selected = 0; + device_index = i; + } + } break; + } + } } - } - int32_t user_device_index = Engine::get_singleton()->get_gpu_index(); // Force user selected GPU. - if (user_device_index >= 0 && user_device_index < (int32_t)gpu_count) { - device_index = user_device_index; - } + int32_t user_device_index = Engine::get_singleton()->get_gpu_index(); // Force user selected GPU. + if (user_device_index >= 0 && user_device_index < (int32_t)gpu_count) { + device_index = user_device_index; + } + + ERR_FAIL_COND_V_MSG(device_index == -1, ERR_CANT_CREATE, "None of Vulkan devices supports both graphics and present queues."); - ERR_FAIL_COND_V_MSG(device_index == -1, ERR_CANT_CREATE, "None of Vulkan devices supports both graphics and present queues."); + gpu = physical_devices[device_index]; + } - gpu = physical_devices[device_index]; free(physical_devices); /* Look for device extensions */ @@ -1057,9 +1099,61 @@ Error VulkanContext::_create_device() { queues[0].pQueuePriorities = queue_priorities; queues[0].flags = 0; + // Before we retrieved what is supported, here we tell Vulkan we want to enable these features using the same structs. + void *nextptr = nullptr; + + VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader_features = { + /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR, + /*pNext*/ nextptr, + /*shaderFloat16*/ shader_capabilities.shader_float16_is_supported, + /*shaderInt8*/ shader_capabilities.shader_int8_is_supported, + }; + nextptr = &shader_features; + + VkPhysicalDeviceVulkan11Features vulkan11features; + VkPhysicalDevice16BitStorageFeaturesKHR storage_feature; + VkPhysicalDeviceMultiviewFeatures multiview_features; + if (vulkan_major > 1 || vulkan_minor >= 2) { + // In Vulkan 1.2 and newer we use a newer struct to enable various features + + vulkan11features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; + vulkan11features.pNext = nextptr; + vulkan11features.storageBuffer16BitAccess = storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported; + vulkan11features.uniformAndStorageBuffer16BitAccess = storage_buffer_capabilities.uniform_and_storage_buffer_16_bit_access_is_supported; + vulkan11features.storagePushConstant16 = storage_buffer_capabilities.storage_push_constant_16_is_supported; + vulkan11features.storageInputOutput16 = storage_buffer_capabilities.storage_input_output_16; + vulkan11features.multiview = multiview_capabilities.is_supported; + vulkan11features.multiviewGeometryShader = multiview_capabilities.geometry_shader_is_supported; + vulkan11features.multiviewTessellationShader = multiview_capabilities.tessellation_shader_is_supported; + vulkan11features.variablePointersStorageBuffer = 0; + vulkan11features.variablePointers = 0; + vulkan11features.protectedMemory = 0; + vulkan11features.samplerYcbcrConversion = 0; + vulkan11features.shaderDrawParameters = 0; + nextptr = &vulkan11features; + } else { + // On Vulkan 1.0 and 1.1 we use our older structs to initialise these features + storage_feature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR; + storage_feature.pNext = nextptr; + storage_feature.storageBuffer16BitAccess = storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported; + storage_feature.uniformAndStorageBuffer16BitAccess = storage_buffer_capabilities.uniform_and_storage_buffer_16_bit_access_is_supported; + storage_feature.storagePushConstant16 = storage_buffer_capabilities.storage_push_constant_16_is_supported; + storage_feature.storageInputOutput16 = storage_buffer_capabilities.storage_input_output_16; + nextptr = &storage_feature; + + if (vulkan_major == 1 && vulkan_minor == 1) { + multiview_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES; + multiview_features.pNext = nextptr; + multiview_features.multiview = multiview_capabilities.is_supported; + multiview_features.multiviewGeometryShader = multiview_capabilities.geometry_shader_is_supported; + multiview_features.multiviewTessellationShader = multiview_capabilities.tessellation_shader_is_supported; + nextptr = &multiview_features; + } + } + VkDeviceCreateInfo sdevice = { /*sType*/ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, - /*pNext*/ nullptr, + /*pNext*/ nextptr, /*flags*/ 0, /*queueCreateInfoCount*/ 1, /*pQueueCreateInfos*/ queues, @@ -1068,7 +1162,6 @@ Error VulkanContext::_create_device() { /*enabledExtensionCount*/ enabled_extension_count, /*ppEnabledExtensionNames*/ (const char *const *)extension_names, /*pEnabledFeatures*/ &physical_device_features, // If specific features are required, pass them in here - }; if (separate_present_queue) { queues[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; @@ -1080,39 +1173,15 @@ Error VulkanContext::_create_device() { sdevice.queueCreateInfoCount = 2; } - VkPhysicalDeviceVulkan11Features vulkan11features; - VkPhysicalDeviceMultiviewFeatures multiview_features; - if (vulkan_major > 1 || vulkan_minor >= 2) { - vulkan11features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; - vulkan11features.pNext = nullptr; - // !BAS! Need to figure out which ones of these we want enabled... - vulkan11features.storageBuffer16BitAccess = 0; - vulkan11features.uniformAndStorageBuffer16BitAccess = 0; - vulkan11features.storagePushConstant16 = 0; - vulkan11features.storageInputOutput16 = 0; - vulkan11features.multiview = multiview_capabilities.is_supported; - vulkan11features.multiviewGeometryShader = multiview_capabilities.geometry_shader_is_supported; - vulkan11features.multiviewTessellationShader = multiview_capabilities.tessellation_shader_is_supported; - vulkan11features.variablePointersStorageBuffer = 0; - vulkan11features.variablePointers = 0; - vulkan11features.protectedMemory = 0; - vulkan11features.samplerYcbcrConversion = 0; - vulkan11features.shaderDrawParameters = 0; - - sdevice.pNext = &vulkan11features; - } else if (vulkan_major == 1 && vulkan_minor == 1) { - multiview_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES; - multiview_features.pNext = nullptr; - multiview_features.multiview = multiview_capabilities.is_supported; - multiview_features.multiviewGeometryShader = multiview_capabilities.geometry_shader_is_supported; - multiview_features.multiviewTessellationShader = multiview_capabilities.tessellation_shader_is_supported; - - sdevice.pNext = &multiview_features; + if (vulkan_hooks) { + if (!vulkan_hooks->create_vulkan_device(&sdevice, &device)) { + return ERR_CANT_CREATE; + } + } else { + err = vkCreateDevice(gpu, &sdevice, nullptr, &device); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); } - err = vkCreateDevice(gpu, &sdevice, nullptr, &device); - ERR_FAIL_COND_V(err, ERR_CANT_CREATE); - return OK; } @@ -1348,6 +1417,12 @@ int VulkanContext::window_get_height(DisplayServer::WindowID p_window) { return windows[p_window].height; } +bool VulkanContext::window_is_valid_swapchain(DisplayServer::WindowID p_window) { + ERR_FAIL_COND_V(!windows.has(p_window), false); + Window *w = &windows[p_window]; + return w->swapchain_image_resources != VK_NULL_HANDLE; +} + VkRenderPass VulkanContext::window_get_render_pass(DisplayServer::WindowID p_window) { ERR_FAIL_COND_V(!windows.has(p_window), VK_NULL_HANDLE); Window *w = &windows[p_window]; @@ -1360,7 +1435,11 @@ VkFramebuffer VulkanContext::window_get_framebuffer(DisplayServer::WindowID p_wi ERR_FAIL_COND_V(!buffers_prepared, VK_NULL_HANDLE); Window *w = &windows[p_window]; //vulkan use of currentbuffer - return w->swapchain_image_resources[w->current_buffer].framebuffer; + if (w->swapchain_image_resources != VK_NULL_HANDLE) { + return w->swapchain_image_resources[w->current_buffer].framebuffer; + } else { + return VK_NULL_HANDLE; + } } void VulkanContext::window_destroy(DisplayServer::WindowID p_window_id) { @@ -1930,24 +2009,25 @@ Error VulkanContext::swap_buffers() { } VkSemaphore *semaphores_to_acquire = (VkSemaphore *)alloca(windows.size() * sizeof(VkSemaphore)); + VkPipelineStageFlags *pipe_stage_flags = (VkPipelineStageFlags *)alloca(windows.size() * sizeof(VkPipelineStageFlags)); uint32_t semaphores_to_acquire_count = 0; for (KeyValue<int, Window> &E : windows) { Window *w = &E.value; if (w->semaphore_acquired) { - semaphores_to_acquire[semaphores_to_acquire_count++] = w->image_acquired_semaphores[frame_index]; + semaphores_to_acquire[semaphores_to_acquire_count] = w->image_acquired_semaphores[frame_index]; + pipe_stage_flags[semaphores_to_acquire_count] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + semaphores_to_acquire_count++; } } - VkPipelineStageFlags pipe_stage_flags; VkSubmitInfo submit_info; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.pNext = nullptr; - submit_info.pWaitDstStageMask = &pipe_stage_flags; - pipe_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; submit_info.waitSemaphoreCount = semaphores_to_acquire_count; submit_info.pWaitSemaphores = semaphores_to_acquire; + submit_info.pWaitDstStageMask = pipe_stage_flags; submit_info.commandBufferCount = commands_to_submit; submit_info.pCommandBuffers = commands_ptr; submit_info.signalSemaphoreCount = 1; @@ -1963,7 +2043,7 @@ Error VulkanContext::swap_buffers() { // present queue before presenting, waiting for the draw complete // semaphore and signalling the ownership released semaphore when finished VkFence nullFence = VK_NULL_HANDLE; - pipe_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + pipe_stage_flags[0] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; submit_info.waitSemaphoreCount = 1; submit_info.pWaitSemaphores = &draw_complete_semaphores[frame_index]; submit_info.commandBufferCount = 0; diff --git a/drivers/vulkan/vulkan_context.h b/drivers/vulkan/vulkan_context.h index 67a675f6c6..8c0111714c 100644 --- a/drivers/vulkan/vulkan_context.h +++ b/drivers/vulkan/vulkan_context.h @@ -45,6 +45,8 @@ #include <vulkan/vulkan.h> #endif +#include "vulkan_hooks.h" + class VulkanContext { public: struct SubgroupCapabilities { @@ -69,10 +71,14 @@ public: struct ShaderCapabilities { bool shader_float16_is_supported; + bool shader_int8_is_supported; }; struct StorageBufferCapabilities { bool storage_buffer_16_bit_access_is_supported; + bool uniform_and_storage_buffer_16_bit_access_is_supported; + bool storage_push_constant_16_is_supported; + bool storage_input_output_16; }; private: @@ -82,6 +88,7 @@ private: FRAME_LAG = 2 }; + static VulkanHooks *vulkan_hooks; VkInstance inst = VK_NULL_HANDLE; VkPhysicalDevice gpu = VK_NULL_HANDLE; VkPhysicalDeviceProperties gpu_props; @@ -263,9 +270,12 @@ public: VkQueue get_graphics_queue() const; uint32_t get_graphics_queue_family_index() const; + static void set_vulkan_hooks(VulkanHooks *p_vulkan_hooks) { vulkan_hooks = p_vulkan_hooks; }; + void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height); int window_get_width(DisplayServer::WindowID p_window = 0); int window_get_height(DisplayServer::WindowID p_window = 0); + bool window_is_valid_swapchain(DisplayServer::WindowID p_window = 0); void window_destroy(DisplayServer::WindowID p_window_id); VkFramebuffer window_get_framebuffer(DisplayServer::WindowID p_window = 0); VkRenderPass window_get_render_pass(DisplayServer::WindowID p_window = 0); diff --git a/drivers/vulkan/vulkan_hooks.h b/drivers/vulkan/vulkan_hooks.h new file mode 100644 index 0000000000..3f244b4d45 --- /dev/null +++ b/drivers/vulkan/vulkan_hooks.h @@ -0,0 +1,48 @@ +/*************************************************************************/ +/* vulkan_hooks.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef VULKAN_HOOKS_H +#define VULKAN_HOOKS_H + +#ifdef USE_VOLK +#include <volk.h> +#else +#include <vulkan/vulkan.h> +#endif + +class VulkanHooks { +public: + virtual bool create_vulkan_instance(const VkInstanceCreateInfo *p_vulkan_create_info, VkInstance *r_instance) { return false; }; + virtual bool get_physical_device(VkPhysicalDevice *r_device) { return false; }; + virtual bool create_vulkan_device(const VkDeviceCreateInfo *p_device_create_info, VkDevice *r_device) { return false; }; + virtual ~VulkanHooks(){}; +}; + +#endif diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index 081f0ac868..7e59fc31c4 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -235,19 +235,19 @@ void CreateDialog::_add_type(const String &p_type, const TypeCategory p_type_cat } } else { if (ScriptServer::is_global_class(p_type)) { - inherits = EditorNode::get_editor_data().script_class_get_base(p_type); - if (inherits.is_empty()) { - Ref<Script> script = EditorNode::get_editor_data().script_class_load_script(p_type); - ERR_FAIL_COND(script.is_null()); + Ref<Script> script = EditorNode::get_editor_data().script_class_load_script(p_type); + ERR_FAIL_COND(script.is_null()); - Ref<Script> base = script->get_base_script(); - if (base.is_null()) { - String extends; - script->get_language()->get_global_class_name(script->get_path(), &extends); + Ref<Script> base = script->get_base_script(); + if (base.is_null()) { + String extends; + script->get_language()->get_global_class_name(script->get_path(), &extends); - inherits = extends; - inherited_type = TypeCategory::CPP_TYPE; - } else { + inherits = extends; + inherited_type = TypeCategory::CPP_TYPE; + } else { + inherits = script->get_language()->get_global_class_name(base->get_path()); + if (inherits.is_empty()) { inherits = base->get_path(); inherited_type = TypeCategory::PATH_TYPE; } diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp index 36ae19cb23..a9d18e9dcc 100644 --- a/editor/doc_tools.cpp +++ b/editor/doc_tools.cpp @@ -1375,7 +1375,7 @@ Error DocTools::save_classes(const String &p_default_path, const Map<String, Str _write_string(f, 1, "<tutorials>"); for (int i = 0; i < c.tutorials.size(); i++) { DocData::TutorialDoc tutorial = c.tutorials.get(i); - String title_attribute = (!tutorial.title.is_empty()) ? " title=\"" + tutorial.title.xml_escape() + "\"" : ""; + String title_attribute = (!tutorial.title.is_empty()) ? " title=\"" + _translate_doc_string(tutorial.title).xml_escape() + "\"" : ""; _write_string(f, 2, "<link" + title_attribute + ">" + tutorial.link.xml_escape() + "</link>"); } _write_string(f, 1, "</tutorials>"); @@ -1468,7 +1468,8 @@ Error DocTools::save_classes(const String &p_default_path, const Map<String, Str Error DocTools::load_compressed(const uint8_t *p_data, int p_compressed_size, int p_uncompressed_size) { Vector<uint8_t> data; data.resize(p_uncompressed_size); - Compression::decompress(data.ptrw(), p_uncompressed_size, p_data, p_compressed_size, Compression::MODE_DEFLATE); + int ret = Compression::decompress(data.ptrw(), p_uncompressed_size, p_data, p_compressed_size, Compression::MODE_DEFLATE); + ERR_FAIL_COND_V_MSG(ret == -1, ERR_FILE_CORRUPT, "Compressed file is corrupt."); class_list.clear(); Ref<XMLParser> parser = memnew(XMLParser); diff --git a/editor/editor_atlas_packer.cpp b/editor/editor_atlas_packer.cpp index aad32968de..9c6bcd769a 100644 --- a/editor/editor_atlas_packer.cpp +++ b/editor/editor_atlas_packer.cpp @@ -30,60 +30,10 @@ #include "editor_atlas_packer.h" +#include "core/math/geometry_2d.h" #include "core/math/vector2.h" #include "core/math/vector2i.h" -void EditorAtlasPacker::_plot_triangle(Ref<BitMap> p_bitmap, Vector2i *vertices) { - int width = p_bitmap->get_size().width; - int height = p_bitmap->get_size().height; - int x[3]; - int y[3]; - - for (int j = 0; j < 3; j++) { - x[j] = vertices[j].x; - y[j] = vertices[j].y; - } - - // sort the points vertically - if (y[1] > y[2]) { - SWAP(x[1], x[2]); - SWAP(y[1], y[2]); - } - if (y[0] > y[1]) { - SWAP(x[0], x[1]); - SWAP(y[0], y[1]); - } - if (y[1] > y[2]) { - SWAP(x[1], x[2]); - SWAP(y[1], y[2]); - } - - double dx_far = double(x[2] - x[0]) / (y[2] - y[0] + 1); - double dx_upper = double(x[1] - x[0]) / (y[1] - y[0] + 1); - double dx_low = double(x[2] - x[1]) / (y[2] - y[1] + 1); - double xf = x[0]; - double xt = x[0] + dx_upper; // if y[0] == y[1], special case - for (int yi = y[0]; yi <= (y[2] > height - 1 ? height - 1 : y[2]); yi++) { - if (yi >= 0) { - for (int xi = (xf > 0 ? int(xf) : 0); xi <= (xt < width ? xt : width - 1); xi++) { - //pixels[int(x + y * width)] = color; - - p_bitmap->set_bit(Point2(xi, yi), true); - } - - for (int xi = (xf < width ? int(xf) : width - 1); xi >= (xt > 0 ? xt : 0); xi--) { - p_bitmap->set_bit(Point2(xi, yi), true); - } - } - xf += dx_far; - if (yi < y[1]) { - xt += dx_upper; - } else { - xt += dx_low; - } - } -} - void EditorAtlasPacker::chart_pack(Vector<Chart> &charts, int &r_width, int &r_height, int p_atlas_max_size, int p_cell_resolution) { int divide_by = MIN(64, p_cell_resolution); Vector<PlottedBitmap> bitmaps; @@ -122,10 +72,18 @@ void EditorAtlasPacker::chart_pack(Vector<Chart> &charts, int &r_width, int &r_h Vector2 vtx = chart.vertices[chart.faces[j].vertex[k]]; vtx -= aabb.position; vtx /= divide_by; + vtx.x = MIN(vtx.x, w - 1); + vtx.y = MIN(vtx.y, h - 1); v[k] = vtx; } - _plot_triangle(src_bitmap, v); + for (int k = 0; k < 3; k++) { + int l = k == 0 ? 2 : k - 1; + Vector<Point2i> points = Geometry2D::bresenham_line(v[k], v[l]); + for (Point2i point : points) { + src_bitmap->set_bit(point, true); + } + } } //src_bitmap->convert_to_image()->save_png("bitmap" + itos(i) + ".png"); diff --git a/editor/editor_atlas_packer.h b/editor/editor_atlas_packer.h index 169a6bead8..7b7692011f 100644 --- a/editor/editor_atlas_packer.h +++ b/editor/editor_atlas_packer.h @@ -67,8 +67,6 @@ private: } }; - static void _plot_triangle(Ref<BitMap> p_bitmap, Vector2i *vertices); - public: static void chart_pack(Vector<Chart> &charts, int &r_width, int &r_height, int p_atlas_max_size = 2048, int p_cell_resolution = 4); }; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index a10eecbca1..cda5e6b537 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -2908,7 +2908,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { command_palette->open_popup(); } break; case HELP_DOCS: { - OS::get_singleton()->shell_open("https://docs.godotengine.org/"); + OS::get_singleton()->shell_open(VERSION_DOCS_URL "/"); } break; case HELP_QA: { OS::get_singleton()->shell_open("https://godotengine.org/qa/"); diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp index 6a5ab91ba0..18324f9971 100644 --- a/editor/editor_settings_dialog.cpp +++ b/editor/editor_settings_dialog.cpp @@ -369,6 +369,11 @@ void EditorSettingsDialog::_update_shortcuts() { Array events; // Need to get the list of events into an array so it can be set as metadata on the item. Vector<String> event_strings; + // Skip non-builtin actions. + if (!InputMap::get_singleton()->get_builtins_with_feature_overrides_applied().has(action_name)) { + continue; + } + List<Ref<InputEvent>> all_default_events = InputMap::get_singleton()->get_builtins_with_feature_overrides_applied().find(action_name).value(); List<Ref<InputEventKey>> key_default_events; // Remove all non-key events from the defaults. Only check keys, since we are in the editor. diff --git a/editor/editor_translation.cpp b/editor/editor_translation.cpp index 98248f3a87..f64adcf0a1 100644 --- a/editor/editor_translation.cpp +++ b/editor/editor_translation.cpp @@ -56,7 +56,8 @@ void load_editor_translations(const String &p_locale) { if (etl->lang == p_locale) { Vector<uint8_t> data; data.resize(etl->uncomp_size); - Compression::decompress(data.ptrw(), etl->uncomp_size, etl->data, etl->comp_size, Compression::MODE_DEFLATE); + int ret = Compression::decompress(data.ptrw(), etl->uncomp_size, etl->data, etl->comp_size, Compression::MODE_DEFLATE); + ERR_FAIL_COND_MSG(ret == -1, "Compressed file is corrupt."); FileAccessMemory *fa = memnew(FileAccessMemory); fa->open_custom(data.ptr(), data.size()); @@ -80,7 +81,8 @@ void load_doc_translations(const String &p_locale) { if (dtl->lang == p_locale) { Vector<uint8_t> data; data.resize(dtl->uncomp_size); - Compression::decompress(data.ptrw(), dtl->uncomp_size, dtl->data, dtl->comp_size, Compression::MODE_DEFLATE); + int ret = Compression::decompress(data.ptrw(), dtl->uncomp_size, dtl->data, dtl->comp_size, Compression::MODE_DEFLATE); + ERR_FAIL_COND_MSG(ret == -1, "Compressed file is corrupt."); FileAccessMemory *fa = memnew(FileAccessMemory); fa->open_custom(data.ptr(), data.size()); diff --git a/editor/import/dynamic_font_import_settings.cpp b/editor/import/dynamic_font_import_settings.cpp index 8486d170a7..ebfb0b32fb 100644 --- a/editor/import/dynamic_font_import_settings.cpp +++ b/editor/import/dynamic_font_import_settings.cpp @@ -560,7 +560,7 @@ void DynamicFontImportSettings::_variation_changed(const String &p_edited_proper void DynamicFontImportSettings::_variations_validate() { String warn; if (!vars_list_root->get_first_child()) { - warn = TTR("Warinig: There are no configurations specified, no glyphs will be pre-rendered."); + warn = TTR("Warning: There are no configurations specified, no glyphs will be pre-rendered."); } for (TreeItem *vars_item_a = vars_list_root->get_first_child(); vars_item_a; vars_item_a = vars_item_a->get_next()) { Ref<DynamicFontImportSettingsData> import_variation_data_a = vars_item_a->get_metadata(0); @@ -575,7 +575,7 @@ void DynamicFontImportSettings::_variations_validate() { match = match && (import_variation_data_b->settings[E->key()] == E->get()); } if (match) { - warn = TTR("Warinig: Multiple configurations have identical settings. Duplicates will be ignored."); + warn = TTR("Warning: Multiple configurations have identical settings. Duplicates will be ignored."); break; } } diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp index c1ae5be0bb..3b5a82b2c3 100644 --- a/editor/import/editor_import_collada.cpp +++ b/editor/import/editor_import_collada.cpp @@ -1535,7 +1535,7 @@ void ColladaImport::create_animation(int p_clip, bool p_import_value_tracks) { bool has_rotation = false; bool has_scale = false; - for (int i = 0; cn->xform_list.size(); i++) { + for (int i = 0; i < cn->xform_list.size(); i++) { switch (cn->xform_list[i].op) { case Collada::Node::XForm::OP_ROTATE: { has_rotation = true; diff --git a/editor/import/resource_importer_texture_atlas.cpp b/editor/import/resource_importer_texture_atlas.cpp index d2a9fe2538..cd481e009e 100644 --- a/editor/import/resource_importer_texture_atlas.cpp +++ b/editor/import/resource_importer_texture_atlas.cpp @@ -75,6 +75,7 @@ void ResourceImporterTextureAtlas::get_import_options(const String &p_path, List r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "atlas_file", PROPERTY_HINT_SAVE_FILE, "*.png"), "")); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "import_mode", PROPERTY_HINT_ENUM, "Region,Mesh2D"), 0)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "crop_to_region"), false)); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "trim_alpha_border_from_region"), true)); } String ResourceImporterTextureAtlas::get_option_group_file() const { @@ -210,14 +211,18 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file pack_data.is_cropped = options["crop_to_region"]; int mode = options["import_mode"]; + bool trim_alpha_border_from_region = options["trim_alpha_border_from_region"]; if (mode == IMPORT_MODE_REGION) { pack_data.is_mesh = false; EditorAtlasPacker::Chart chart; - //clip a region from the image - Rect2 used_rect = image->get_used_rect(); + Rect2 used_rect = Rect2(Vector2(), image->get_size()); + if (trim_alpha_border_from_region) { + // Clip a region from the image. + used_rect = image->get_used_rect(); + } pack_data.region = used_rect; chart.vertices.push_back(used_rect.position); diff --git a/editor/import/scene_import_settings.cpp b/editor/import/scene_import_settings.cpp index 488bd02de4..4e06253041 100644 --- a/editor/import/scene_import_settings.cpp +++ b/editor/import/scene_import_settings.cpp @@ -377,9 +377,10 @@ void SceneImportSettings::_update_view_gizmos() { continue; } - MeshInstance3D *collider_view = static_cast<MeshInstance3D *>(mesh_node->find_node("collider_view")); - CRASH_COND_MSG(collider_view == nullptr, "This is unreachable, since the collider view is always created even when the collision is not used! If this is triggered there is a bug on the function `_fill_scene`."); + TypedArray<Node> descendants = mesh_node->find_nodes("collider_view", "MeshInstance3D"); + CRASH_COND_MSG(descendants.is_empty(), "This is unreachable, since the collider view is always created even when the collision is not used! If this is triggered there is a bug on the function `_fill_scene`."); + MeshInstance3D *collider_view = static_cast<MeshInstance3D *>(descendants[0].operator Object *()); collider_view->set_visible(generate_collider); if (generate_collider) { // This collider_view doesn't have a mesh so we need to generate a new one. diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 76558eb946..85ac258c9c 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -3510,7 +3510,7 @@ void CanvasItemEditor::_draw_invisible_nodes_positions(Node *p_node, const Trans return; } CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node); - if (canvas_item && !canvas_item->is_visible()) { + if (canvas_item && !canvas_item->is_visible_in_tree()) { return; } @@ -5500,16 +5500,18 @@ bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, cons editor_data->get_undo_redo().add_do_method(ed, "live_debug_instance_node", edited_scene->get_path_to(parent), path, new_name); editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)) + "/" + new_name)); - CanvasItem *parent_ci = Object::cast_to<CanvasItem>(parent); - if (parent_ci) { + CanvasItem *instance_ci = Object::cast_to<CanvasItem>(instantiated_scene); + if (instance_ci) { Vector2 target_pos = canvas_item_editor->get_canvas_transform().affine_inverse().xform(p_point); target_pos = canvas_item_editor->snap_point(target_pos); - target_pos = parent_ci->get_global_transform_with_canvas().affine_inverse().xform(target_pos); - // Preserve instance position of the original scene. - CanvasItem *instance_ci = Object::cast_to<CanvasItem>(instantiated_scene); - if (instance_ci) { - target_pos += instance_ci->_edit_get_position(); + + CanvasItem *parent_ci = Object::cast_to<CanvasItem>(parent); + if (parent_ci) { + target_pos = parent_ci->get_global_transform_with_canvas().affine_inverse().xform(target_pos); } + // Preserve instance position of the original scene. + target_pos += instance_ci->_edit_get_position(); + editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_position", target_pos); } diff --git a/editor/plugins/control_editor_plugin.cpp b/editor/plugins/control_editor_plugin.cpp index e6f267673c..7b85fea1e9 100644 --- a/editor/plugins/control_editor_plugin.cpp +++ b/editor/plugins/control_editor_plugin.cpp @@ -358,8 +358,12 @@ void EditorPropertySizeFlags::setup(const Vector<String> &p_options, bool p_vert Control *gui_base = EditorNode::get_singleton()->get_gui_base(); String wide_preset_icon = SNAME("ControlAlignHCenterWide"); + String begin_preset_icon = SNAME("ControlAlignCenterLeft"); + String end_preset_icon = SNAME("ControlAlignCenterRight"); if (vertical) { wide_preset_icon = SNAME("ControlAlignVCenterWide"); + begin_preset_icon = SNAME("ControlAlignCenterTop"); + end_preset_icon = SNAME("ControlAlignCenterBottom"); } flag_presets->clear(); @@ -367,12 +371,12 @@ void EditorPropertySizeFlags::setup(const Vector<String> &p_options, bool p_vert flag_presets->add_icon_item(gui_base->get_theme_icon(wide_preset_icon, SNAME("EditorIcons")), TTR("Fill"), SIZE_FLAGS_PRESET_FILL); } // Shrink Begin is the same as no flags at all, as such it cannot be disabled. - flag_presets->add_icon_item(gui_base->get_theme_icon(SNAME("ControlAlignCenterLeft"), SNAME("EditorIcons")), TTR("Shrink Begin"), SIZE_FLAGS_PRESET_SHRINK_BEGIN); + flag_presets->add_icon_item(gui_base->get_theme_icon(begin_preset_icon, SNAME("EditorIcons")), TTR("Shrink Begin"), SIZE_FLAGS_PRESET_SHRINK_BEGIN); if (flags.has(SIZE_SHRINK_CENTER)) { flag_presets->add_icon_item(gui_base->get_theme_icon(SNAME("ControlAlignCenter"), SNAME("EditorIcons")), TTR("Shrink Center"), SIZE_FLAGS_PRESET_SHRINK_CENTER); } if (flags.has(SIZE_SHRINK_END)) { - flag_presets->add_icon_item(gui_base->get_theme_icon(SNAME("ControlAlignCenterRight"), SNAME("EditorIcons")), TTR("Shrink End"), SIZE_FLAGS_PRESET_SHRINK_END); + flag_presets->add_icon_item(gui_base->get_theme_icon(end_preset_icon, SNAME("EditorIcons")), TTR("Shrink End"), SIZE_FLAGS_PRESET_SHRINK_END); } flag_presets->add_separator(); flag_presets->add_item(TTR("Custom"), SIZE_FLAGS_PRESET_CUSTOM); diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp index 46b33f62fe..23f3087553 100644 --- a/editor/plugins/node_3d_editor_gizmos.cpp +++ b/editor/plugins/node_3d_editor_gizmos.cpp @@ -3669,13 +3669,8 @@ void VoxelGIGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { continue; } - Vector2 dir; - dir[j] = 1.0; - Vector2 ta, tb; int j_n1 = (j + 1) % 3; int j_n2 = (j + 2) % 3; - ta[j_n1] = 1.0; - tb[j_n2] = 1.0; for (int k = 0; k < 4; k++) { Vector3 from = aabb.position, to = aabb.position; diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 3d3738ad47..002c879cdc 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -32,6 +32,7 @@ #include "core/config/project_settings.h" #include "core/input/input.h" +#include "core/input/input_map.h" #include "core/math/camera_matrix.h" #include "core/math/math_funcs.h" #include "core/os/keyboard.h" @@ -2291,26 +2292,6 @@ Point2i Node3DEditorViewport::_get_warped_mouse_motion(const Ref<InputEventMouse return relative; } -static bool is_shortcut_pressed(const String &p_path) { - Ref<Shortcut> shortcut = ED_GET_SHORTCUT(p_path); - if (shortcut.is_null()) { - return false; - } - - const Array shortcuts = shortcut->get_events(); - Ref<InputEventKey> k; - if (shortcuts.size() > 0) { - k = shortcuts.front(); - } - - if (k.is_null()) { - return false; - } - const Input &input = *Input::get_singleton(); - Key keycode = k->get_keycode(); - return input.is_key_pressed(keycode); -} - void Node3DEditorViewport::_update_freelook(real_t delta) { if (!is_freelook_active()) { return; @@ -2340,31 +2321,34 @@ void Node3DEditorViewport::_update_freelook(real_t delta) { Vector3 direction; - if (is_shortcut_pressed("spatial_editor/freelook_left")) { + // Use actions from the inputmap, as this is the only way to reliably detect input in this method. + // See #54469 for more discussion and explanation. + Input *inp = Input::get_singleton(); + if (inp->is_action_pressed("spatial_editor/freelook_left")) { direction -= right; } - if (is_shortcut_pressed("spatial_editor/freelook_right")) { + if (inp->is_action_pressed("spatial_editor/freelook_right")) { direction += right; } - if (is_shortcut_pressed("spatial_editor/freelook_forward")) { + if (inp->is_action_pressed("spatial_editor/freelook_forward")) { direction += forward; } - if (is_shortcut_pressed("spatial_editor/freelook_backwards")) { + if (inp->is_action_pressed("spatial_editor/freelook_backwards")) { direction -= forward; } - if (is_shortcut_pressed("spatial_editor/freelook_up")) { + if (inp->is_action_pressed("spatial_editor/freelook_up")) { direction += up; } - if (is_shortcut_pressed("spatial_editor/freelook_down")) { + if (inp->is_action_pressed("spatial_editor/freelook_down")) { direction -= up; } real_t speed = freelook_speed; - if (is_shortcut_pressed("spatial_editor/freelook_speed_modifier")) { + if (inp->is_action_pressed("spatial_editor/freelook_speed_modifier")) { speed *= 3.0; } - if (is_shortcut_pressed("spatial_editor/freelook_slow_modifier")) { + if (inp->is_action_pressed("spatial_editor/freelook_slow_modifier")) { speed *= 0.333333; } @@ -4427,6 +4411,28 @@ void Node3DEditorViewport::finish_transform() { surface->update(); } +// Register a shortcut and also add it as an input action with the same events. +void Node3DEditorViewport::register_shortcut_action(const String &p_path, const String &p_name, Key p_keycode) { + Ref<Shortcut> sc = ED_SHORTCUT(p_path, p_name, p_keycode); + shortcut_changed_callback(sc, p_path); + // Connect to the change event on the shortcut so the input binding can be updated. + sc->connect("changed", callable_mp(this, &Node3DEditorViewport::shortcut_changed_callback), varray(sc, p_path)); +} + +// Update the action in the InputMap to the provided shortcut events. +void Node3DEditorViewport::shortcut_changed_callback(const Ref<Shortcut> p_shortcut, const String &p_shortcut_path) { + InputMap *im = InputMap::get_singleton(); + if (im->has_action(p_shortcut_path)) { + im->action_erase_events(p_shortcut_path); + } else { + im->add_action(p_shortcut_path); + } + + for (int i = 0; i < p_shortcut->get_events().size(); i++) { + im->action_add_event(p_shortcut_path, p_shortcut->get_events()[i]); + } +} + Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p_index) { cpu_time_history_index = 0; gpu_time_history_index = 0; @@ -4586,14 +4592,15 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p view_menu->get_popup()->set_item_tooltip(shadeless_idx, unsupported_tooltip); } - ED_SHORTCUT("spatial_editor/freelook_left", TTR("Freelook Left"), Key::A); - ED_SHORTCUT("spatial_editor/freelook_right", TTR("Freelook Right"), Key::D); - ED_SHORTCUT("spatial_editor/freelook_forward", TTR("Freelook Forward"), Key::W); - ED_SHORTCUT("spatial_editor/freelook_backwards", TTR("Freelook Backwards"), Key::S); - ED_SHORTCUT("spatial_editor/freelook_up", TTR("Freelook Up"), Key::E); - ED_SHORTCUT("spatial_editor/freelook_down", TTR("Freelook Down"), Key::Q); - ED_SHORTCUT("spatial_editor/freelook_speed_modifier", TTR("Freelook Speed Modifier"), Key::SHIFT); - ED_SHORTCUT("spatial_editor/freelook_slow_modifier", TTR("Freelook Slow Modifier"), Key::ALT); + register_shortcut_action("spatial_editor/freelook_left", TTR("Freelook Left"), Key::A); + register_shortcut_action("spatial_editor/freelook_right", TTR("Freelook Right"), Key::D); + register_shortcut_action("spatial_editor/freelook_forward", TTR("Freelook Forward"), Key::W); + register_shortcut_action("spatial_editor/freelook_backwards", TTR("Freelook Backwards"), Key::S); + register_shortcut_action("spatial_editor/freelook_up", TTR("Freelook Up"), Key::E); + register_shortcut_action("spatial_editor/freelook_down", TTR("Freelook Down"), Key::Q); + register_shortcut_action("spatial_editor/freelook_speed_modifier", TTR("Freelook Speed Modifier"), Key::SHIFT); + register_shortcut_action("spatial_editor/freelook_slow_modifier", TTR("Freelook Slow Modifier"), Key::ALT); + ED_SHORTCUT("spatial_editor/lock_transform_x", TTR("Lock Transformation to X axis"), Key::X); ED_SHORTCUT("spatial_editor/lock_transform_y", TTR("Lock Transformation to Y axis"), Key::Y); ED_SHORTCUT("spatial_editor/lock_transform_z", TTR("Lock Transformation to Z axis"), Key::Z); diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index 9e92a1e9b3..48423d1c83 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -415,6 +415,9 @@ private: void update_transform(Point2 p_mousepos, bool p_shift); void finish_transform(); + void register_shortcut_action(const String &p_path, const String &p_name, Key p_keycode); + void shortcut_changed_callback(const Ref<Shortcut> p_shortcut, const String &p_shortcut_path); + protected: void _notification(int p_what); static void _bind_methods(); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 205464daee..bd4064708b 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -36,6 +36,7 @@ #include "core/io/resource_loader.h" #include "core/os/keyboard.h" #include "core/os/os.h" +#include "core/version.h" #include "editor/debugger/editor_debugger_node.h" #include "editor/debugger/script_editor_debugger.h" #include "editor/editor_file_dialog.h" @@ -1281,7 +1282,7 @@ void ScriptEditor::_menu_option(int p_option) { help_search_dialog->popup_dialog(); } break; case SEARCH_WEBSITE: { - OS::get_singleton()->shell_open("https://docs.godotengine.org/"); + OS::get_singleton()->shell_open(VERSION_DOCS_URL "/"); } break; case WINDOW_NEXT: { _history_forward(); diff --git a/editor/plugins/shader_file_editor_plugin.cpp b/editor/plugins/shader_file_editor_plugin.cpp index 6d761729b0..4458555de2 100644 --- a/editor/plugins/shader_file_editor_plugin.cpp +++ b/editor/plugins/shader_file_editor_plugin.cpp @@ -200,10 +200,12 @@ void ShaderFileEditor::_update_options() { } void ShaderFileEditor::_notification(int p_what) { - if (p_what == NOTIFICATION_WM_WINDOW_FOCUS_IN) { - if (is_visible_in_tree() && shader_file.is_valid()) { - _update_options(); - } + switch (p_what) { + case NOTIFICATION_WM_WINDOW_FOCUS_IN: { + if (is_visible_in_tree() && shader_file.is_valid()) { + _update_options(); + } + } break; } } diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp index 761a0cdfbd..282ee9a5b7 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -103,8 +103,7 @@ void BoneTransformEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { create_editors(); - break; - } + } break; } } diff --git a/editor/plugins/text_control_editor_plugin.cpp b/editor/plugins/text_control_editor_plugin.cpp index ab3d6dcca9..4290888e94 100644 --- a/editor/plugins/text_control_editor_plugin.cpp +++ b/editor/plugins/text_control_editor_plugin.cpp @@ -34,8 +34,8 @@ #include "editor/editor_scale.h" #include "editor/multi_node_edit.h" -void TextControlEditor::_notification(int p_notification) { - switch (p_notification) { +void TextControlEditor::_notification(int p_what) { + switch (p_what) { case NOTIFICATION_ENTER_TREE: { if (!EditorFileSystem::get_singleton()->is_connected("filesystem_changed", callable_mp(this, &TextControlEditor::_reload_fonts))) { EditorFileSystem::get_singleton()->connect("filesystem_changed", callable_mp(this, &TextControlEditor::_reload_fonts), make_binds("")); @@ -45,13 +45,12 @@ void TextControlEditor::_notification(int p_notification) { case NOTIFICATION_THEME_CHANGED: { clear_formatting->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))); } break; + case NOTIFICATION_EXIT_TREE: { if (EditorFileSystem::get_singleton()->is_connected("filesystem_changed", callable_mp(this, &TextControlEditor::_reload_fonts))) { EditorFileSystem::get_singleton()->disconnect("filesystem_changed", callable_mp(this, &TextControlEditor::_reload_fonts)); } } break; - default: - break; } } diff --git a/editor/plugins/text_control_editor_plugin.h b/editor/plugins/text_control_editor_plugin.h index 1d65073c98..1349003a9c 100644 --- a/editor/plugins/text_control_editor_plugin.h +++ b/editor/plugins/text_control_editor_plugin.h @@ -66,7 +66,7 @@ class TextControlEditor : public HBoxContainer { Ref<Font> custom_font; protected: - void _notification(int p_notification); + void _notification(int p_what); static void _bind_methods(); void _find_resources(EditorFileSystemDirectory *p_dir); diff --git a/editor/plugins/texture_3d_editor_plugin.cpp b/editor/plugins/texture_3d_editor_plugin.cpp index 880cbeffba..0fc7079a24 100644 --- a/editor/plugins/texture_3d_editor_plugin.cpp +++ b/editor/plugins/texture_3d_editor_plugin.cpp @@ -35,18 +35,17 @@ void Texture3DEditor::_texture_rect_draw() { } void Texture3DEditor::_notification(int p_what) { - if (p_what == NOTIFICATION_READY) { - //get_scene()->connect("node_removed",this,"_node_removed"); - } - if (p_what == NOTIFICATION_RESIZED) { - _texture_rect_update_area(); - } + switch (p_what) { + case NOTIFICATION_RESIZED: { + _texture_rect_update_area(); + } break; - if (p_what == NOTIFICATION_DRAW) { - Ref<Texture2D> checkerboard = get_theme_icon(SNAME("Checkerboard"), SNAME("EditorIcons")); - Size2 size = get_size(); + case NOTIFICATION_DRAW: { + Ref<Texture2D> checkerboard = get_theme_icon(SNAME("Checkerboard"), SNAME("EditorIcons")); + Size2 size = get_size(); - draw_texture_rect(checkerboard, Rect2(Point2(), size), true); + draw_texture_rect(checkerboard, Rect2(Point2(), size), true); + } break; } } diff --git a/editor/plugins/texture_layered_editor_plugin.cpp b/editor/plugins/texture_layered_editor_plugin.cpp index 22f4cebf2e..cb146fd342 100644 --- a/editor/plugins/texture_layered_editor_plugin.cpp +++ b/editor/plugins/texture_layered_editor_plugin.cpp @@ -46,18 +46,17 @@ void TextureLayeredEditor::_texture_rect_draw() { } void TextureLayeredEditor::_notification(int p_what) { - if (p_what == NOTIFICATION_READY) { - //get_scene()->connect("node_removed",this,"_node_removed"); - } - if (p_what == NOTIFICATION_RESIZED) { - _texture_rect_update_area(); - } + switch (p_what) { + case NOTIFICATION_RESIZED: { + _texture_rect_update_area(); + } break; - if (p_what == NOTIFICATION_DRAW) { - Ref<Texture2D> checkerboard = get_theme_icon(SNAME("Checkerboard"), SNAME("EditorIcons")); - Size2 size = get_size(); + case NOTIFICATION_DRAW: { + Ref<Texture2D> checkerboard = get_theme_icon(SNAME("Checkerboard"), SNAME("EditorIcons")); + Size2 size = get_size(); - draw_texture_rect(checkerboard, Rect2(Point2(), size), true); + draw_texture_rect(checkerboard, Rect2(Point2(), size), true); + } break; } } diff --git a/editor/plugins/theme_editor_preview.cpp b/editor/plugins/theme_editor_preview.cpp index c3e4e66fd4..252a19a7db 100644 --- a/editor/plugins/theme_editor_preview.cpp +++ b/editor/plugins/theme_editor_preview.cpp @@ -203,6 +203,7 @@ void ThemeEditorPreview::_notification(int p_what) { theme_cache.preview_picker_font = get_theme_font(SNAME("status_source"), SNAME("EditorFonts")); theme_cache.font_size = get_theme_font_size(SNAME("font_size"), SNAME("EditorFonts")); } break; + case NOTIFICATION_PROCESS: { time_left -= get_process_delta_time(); if (time_left < 0) { diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp index d685c634bd..71947ae185 100644 --- a/editor/plugins/tiles/tile_atlas_view.cpp +++ b/editor/plugins/tiles/tile_atlas_view.cpp @@ -524,13 +524,13 @@ void TileAtlasView::update() { void TileAtlasView::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: - case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning"))); - break; + } break; - case NOTIFICATION_READY: + case NOTIFICATION_READY: { button_center_view->set_icon(get_theme_icon(SNAME("CenterView"), SNAME("EditorIcons"))); - break; + } break; } } diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp index a4d2dfc9d9..6c12573cc4 100644 --- a/editor/plugins/tiles/tile_data_editors.cpp +++ b/editor/plugins/tiles/tile_data_editors.cpp @@ -1160,13 +1160,11 @@ void TileDataDefaultEditor::setup_property_editor(Variant::Type p_type, String p void TileDataDefaultEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: - case NOTIFICATION_THEME_CHANGED: + case NOTIFICATION_THEME_CHANGED: { picker_button->set_icon(get_theme_icon(SNAME("ColorPick"), SNAME("EditorIcons"))); tile_bool_checked = get_theme_icon(SNAME("TileChecked"), SNAME("EditorIcons")); tile_bool_unchecked = get_theme_icon(SNAME("TileUnchecked"), SNAME("EditorIcons")); - break; - default: - break; + } break; } } @@ -1315,11 +1313,9 @@ void TileDataOcclusionShapeEditor::_tile_set_changed() { void TileDataOcclusionShapeEditor::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_ENTER_TREE: { polygon_editor->set_polygons_color(get_tree()->get_debug_collisions_color()); - break; - default: - break; + } break; } } @@ -1514,11 +1510,9 @@ void TileDataCollisionEditor::_tile_set_changed() { void TileDataCollisionEditor::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_ENTER_TREE: { polygon_editor->set_polygons_color(get_tree()->get_debug_collisions_color()); - break; - default: - break; + } break; } } @@ -2487,11 +2481,9 @@ void TileDataTerrainsEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform void TileDataTerrainsEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: - case NOTIFICATION_THEME_CHANGED: + case NOTIFICATION_THEME_CHANGED: { picker_button->set_icon(get_theme_icon(SNAME("ColorPick"), SNAME("EditorIcons"))); - break; - default: - break; + } break; } } @@ -2593,11 +2585,9 @@ void TileDataNavigationEditor::_tile_set_changed() { void TileDataNavigationEditor::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_ENTER_TREE: { polygon_editor->set_polygons_color(get_tree()->get_debug_navigation_color()); - break; - default: - break; + } break; } } diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp index 1cd9a17cd1..95cd5683a6 100644 --- a/editor/plugins/tiles/tile_map_editor.cpp +++ b/editor/plugins/tiles/tile_map_editor.cpp @@ -3374,15 +3374,16 @@ TileMapEditorTerrainsPlugin::~TileMapEditorTerrainsPlugin() { void TileMapEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: - case NOTIFICATION_THEME_CHANGED: + case NOTIFICATION_THEME_CHANGED: { missing_tile_texture = get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons")); warning_pattern_texture = get_theme_icon(SNAME("WarningPattern"), SNAME("EditorIcons")); advanced_menu_button->set_icon(get_theme_icon(SNAME("Tools"), SNAME("EditorIcons"))); toggle_grid_button->set_icon(get_theme_icon(SNAME("Grid"), SNAME("EditorIcons"))); toggle_grid_button->set_pressed(EditorSettings::get_singleton()->get("editors/tiles_editor/display_grid")); toogle_highlight_selected_layer_button->set_icon(get_theme_icon(SNAME("TileMapHighlightSelected"), SNAME("EditorIcons"))); - break; - case NOTIFICATION_INTERNAL_PROCESS: + } break; + + case NOTIFICATION_INTERNAL_PROCESS: { if (is_visible_in_tree() && tileset_changed_needs_update) { _update_bottom_panel(); _update_layers_selection(); @@ -3390,11 +3391,13 @@ void TileMapEditor::_notification(int p_what) { CanvasItemEditor::get_singleton()->update_viewport(); tileset_changed_needs_update = false; } - break; - case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: + } break; + + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { toggle_grid_button->set_pressed(EditorSettings::get_singleton()->get("editors/tiles_editor/display_grid")); - break; - case NOTIFICATION_VISIBILITY_CHANGED: + } break; + + case NOTIFICATION_VISIBILITY_CHANGED: { TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); if (tile_map) { if (is_visible_in_tree()) { @@ -3403,7 +3406,7 @@ void TileMapEditor::_notification(int p_what) { tile_map->set_selected_layer(-1); } } - break; + } break; } } diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp index 9a16e3d682..ade591cde6 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp @@ -2270,7 +2270,7 @@ void TileSetAtlasSourceEditor::_auto_remove_tiles() { void TileSetAtlasSourceEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: - case NOTIFICATION_THEME_CHANGED: + case NOTIFICATION_THEME_CHANGED: { tool_setup_atlas_source_button->set_icon(get_theme_icon(SNAME("Tools"), SNAME("EditorIcons"))); tool_select_button->set_icon(get_theme_icon(SNAME("ToolSelect"), SNAME("EditorIcons"))); tool_paint_button->set_icon(get_theme_icon(SNAME("CanvasItem"), SNAME("EditorIcons"))); @@ -2281,8 +2281,9 @@ void TileSetAtlasSourceEditor::_notification(int p_what) { resize_handle = get_theme_icon(SNAME("EditorHandle"), SNAME("EditorIcons")); resize_handle_disabled = get_theme_icon(SNAME("EditorHandleDisabled"), SNAME("EditorIcons")); - break; - case NOTIFICATION_INTERNAL_PROCESS: + } break; + + case NOTIFICATION_INTERNAL_PROCESS: { if (tile_set_changed_needs_update) { // Update everything. _update_source_inspector(); @@ -2298,9 +2299,7 @@ void TileSetAtlasSourceEditor::_notification(int p_what) { tile_set_changed_needs_update = false; } - break; - default: - break; + } break; } } diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp index 97b342c6a7..49e589c9ef 100644 --- a/editor/plugins/tiles/tile_set_editor.cpp +++ b/editor/plugins/tiles/tile_set_editor.cpp @@ -333,14 +333,15 @@ void TileSetEditor::_set_source_sort(int p_sort) { void TileSetEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: - case NOTIFICATION_THEME_CHANGED: + case NOTIFICATION_THEME_CHANGED: { sources_delete_button->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))); sources_add_button->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); source_sort_button->set_icon(get_theme_icon(SNAME("Sort"), SNAME("EditorIcons"))); sources_advanced_menu_button->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons"))); missing_texture_texture = get_theme_icon(SNAME("TileSet"), SNAME("EditorIcons")); - break; - case NOTIFICATION_INTERNAL_PROCESS: + } break; + + case NOTIFICATION_INTERNAL_PROCESS: { if (tile_set_changed_needs_update) { if (tile_set.is_valid()) { tile_set->set_edited(true); @@ -349,9 +350,7 @@ void TileSetEditor::_notification(int p_what) { _update_patterns_list(); tile_set_changed_needs_update = false; } - break; - default: - break; + } break; } } diff --git a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp index acb6ffc77b..21ebcbd655 100644 --- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp @@ -330,12 +330,13 @@ void TileSetScenesCollectionSourceEditor::_update_scenes_list() { void TileSetScenesCollectionSourceEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: - case NOTIFICATION_THEME_CHANGED: + case NOTIFICATION_THEME_CHANGED: { scene_tile_add_button->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); scene_tile_delete_button->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))); _update_scenes_list(); - break; - case NOTIFICATION_INTERNAL_PROCESS: + } break; + + case NOTIFICATION_INTERNAL_PROCESS: { if (tile_set_scenes_collection_source_changed_needs_update) { // Update everything. _update_source_inspector(); @@ -344,14 +345,13 @@ void TileSetScenesCollectionSourceEditor::_notification(int p_what) { _update_tile_inspector(); tile_set_scenes_collection_source_changed_needs_update = false; } - break; - case NOTIFICATION_VISIBILITY_CHANGED: + } break; + + case NOTIFICATION_VISIBILITY_CHANGED: { // Update things just in case. _update_scenes_list(); _update_action_buttons(); - break; - default: - break; + } break; } } diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 5d43813572..446ad12104 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -3373,91 +3373,98 @@ void VisualShaderEditor::_sbox_input(const Ref<InputEvent> &p_ie) { } void VisualShaderEditor::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - node_filter->set_clear_button_enabled(true); - - // collapse tree by default - - TreeItem *category = members->get_root()->get_first_child(); - while (category) { - category->set_collapsed(true); - TreeItem *sub_category = category->get_first_child(); - while (sub_category) { - sub_category->set_collapsed(true); - sub_category = sub_category->get_next(); - } - category = category->get_next(); - } - } + switch (p_what) { + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { + graph->get_panner()->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning"))); + graph->set_warped_panning(bool(EditorSettings::get_singleton()->get("editors/panning/warped_mouse_panning"))); + } break; - if (p_what == NOTIFICATION_ENTER_TREE || p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { - graph->get_panner()->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning"))); - graph->set_warped_panning(bool(EditorSettings::get_singleton()->get("editors/panning/warped_mouse_panning"))); - } + case NOTIFICATION_ENTER_TREE: { + node_filter->set_clear_button_enabled(true); - if (p_what == NOTIFICATION_DRAG_BEGIN) { - Dictionary dd = get_viewport()->gui_get_drag_data(); - if (members->is_visible_in_tree() && dd.has("id")) { - members->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM); - } - } else if (p_what == NOTIFICATION_DRAG_END) { - members->set_drop_mode_flags(0); - } + // collapse tree by default + + TreeItem *category = members->get_root()->get_first_child(); + while (category) { + category->set_collapsed(true); + TreeItem *sub_category = category->get_first_child(); + while (sub_category) { + sub_category->set_collapsed(true); + sub_category = sub_category->get_next(); + } + category = category->get_next(); + } - if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { - highend_label->set_modulate(get_theme_color(SNAME("vulkan_color"), SNAME("Editor"))); + graph->get_panner()->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning"))); + graph->set_warped_panning(bool(EditorSettings::get_singleton()->get("editors/panning/warped_mouse_panning"))); + [[fallthrough]]; + } + case NOTIFICATION_THEME_CHANGED: { + highend_label->set_modulate(get_theme_color(SNAME("vulkan_color"), SNAME("Editor"))); - node_filter->set_right_icon(Control::get_theme_icon(SNAME("Search"), SNAME("EditorIcons"))); + node_filter->set_right_icon(Control::get_theme_icon(SNAME("Search"), SNAME("EditorIcons"))); - preview_shader->set_icon(Control::get_theme_icon(SNAME("Shader"), SNAME("EditorIcons"))); + preview_shader->set_icon(Control::get_theme_icon(SNAME("Shader"), SNAME("EditorIcons"))); - { - Color background_color = EDITOR_GET("text_editor/theme/highlighting/background_color"); - Color text_color = EDITOR_GET("text_editor/theme/highlighting/text_color"); - Color keyword_color = EDITOR_GET("text_editor/theme/highlighting/keyword_color"); - Color control_flow_keyword_color = EDITOR_GET("text_editor/theme/highlighting/control_flow_keyword_color"); - Color comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color"); - Color symbol_color = EDITOR_GET("text_editor/theme/highlighting/symbol_color"); - Color function_color = EDITOR_GET("text_editor/theme/highlighting/function_color"); - Color number_color = EDITOR_GET("text_editor/theme/highlighting/number_color"); - Color members_color = EDITOR_GET("text_editor/theme/highlighting/member_variable_color"); + { + Color background_color = EDITOR_GET("text_editor/theme/highlighting/background_color"); + Color text_color = EDITOR_GET("text_editor/theme/highlighting/text_color"); + Color keyword_color = EDITOR_GET("text_editor/theme/highlighting/keyword_color"); + Color control_flow_keyword_color = EDITOR_GET("text_editor/theme/highlighting/control_flow_keyword_color"); + Color comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color"); + Color symbol_color = EDITOR_GET("text_editor/theme/highlighting/symbol_color"); + Color function_color = EDITOR_GET("text_editor/theme/highlighting/function_color"); + Color number_color = EDITOR_GET("text_editor/theme/highlighting/number_color"); + Color members_color = EDITOR_GET("text_editor/theme/highlighting/member_variable_color"); - preview_text->add_theme_color_override("background_color", background_color); + preview_text->add_theme_color_override("background_color", background_color); - for (const String &E : keyword_list) { - if (ShaderLanguage::is_control_flow_keyword(E)) { - syntax_highlighter->add_keyword_color(E, control_flow_keyword_color); - } else { - syntax_highlighter->add_keyword_color(E, keyword_color); + for (const String &E : keyword_list) { + if (ShaderLanguage::is_control_flow_keyword(E)) { + syntax_highlighter->add_keyword_color(E, control_flow_keyword_color); + } else { + syntax_highlighter->add_keyword_color(E, keyword_color); + } } - } - preview_text->add_theme_font_override("font", get_theme_font(SNAME("expression"), SNAME("EditorFonts"))); - preview_text->add_theme_font_size_override("font_size", get_theme_font_size(SNAME("expression_size"), SNAME("EditorFonts"))); - preview_text->add_theme_color_override("font_color", text_color); - syntax_highlighter->set_number_color(number_color); - syntax_highlighter->set_symbol_color(symbol_color); - syntax_highlighter->set_function_color(function_color); - syntax_highlighter->set_member_variable_color(members_color); - syntax_highlighter->clear_color_regions(); - syntax_highlighter->add_color_region("/*", "*/", comment_color, false); - syntax_highlighter->add_color_region("//", "", comment_color, true); + preview_text->add_theme_font_override("font", get_theme_font(SNAME("expression"), SNAME("EditorFonts"))); + preview_text->add_theme_font_size_override("font_size", get_theme_font_size(SNAME("expression_size"), SNAME("EditorFonts"))); + preview_text->add_theme_color_override("font_color", text_color); + syntax_highlighter->set_number_color(number_color); + syntax_highlighter->set_symbol_color(symbol_color); + syntax_highlighter->set_function_color(function_color); + syntax_highlighter->set_member_variable_color(members_color); + syntax_highlighter->clear_color_regions(); + syntax_highlighter->add_color_region("/*", "*/", comment_color, false); + syntax_highlighter->add_color_region("//", "", comment_color, true); + + preview_text->clear_comment_delimiters(); + preview_text->add_comment_delimiter("/*", "*/", false); + preview_text->add_comment_delimiter("//", "", true); + + error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Panel"))); + error_label->add_theme_font_override("font", get_theme_font(SNAME("status_source"), SNAME("EditorFonts"))); + error_label->add_theme_font_size_override("font_size", get_theme_font_size(SNAME("status_source_size"), SNAME("EditorFonts"))); + error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor"))); + } - preview_text->clear_comment_delimiters(); - preview_text->add_comment_delimiter("/*", "*/", false); - preview_text->add_comment_delimiter("//", "", true); + tools->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Tools"), SNAME("EditorIcons"))); - error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Panel"))); - error_label->add_theme_font_override("font", get_theme_font(SNAME("status_source"), SNAME("EditorFonts"))); - error_label->add_theme_font_size_override("font_size", get_theme_font_size(SNAME("status_source_size"), SNAME("EditorFonts"))); - error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor"))); - } + if (p_what == NOTIFICATION_THEME_CHANGED && is_visible_in_tree()) { + _update_graph(); + } + } break; - tools->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Tools"), SNAME("EditorIcons"))); + case NOTIFICATION_DRAG_BEGIN: { + Dictionary dd = get_viewport()->gui_get_drag_data(); + if (members->is_visible_in_tree() && dd.has("id")) { + members->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM); + } + } break; - if (p_what == NOTIFICATION_THEME_CHANGED && is_visible_in_tree()) { - _update_graph(); - } + case NOTIFICATION_DRAG_END: { + members->set_drop_mode_flags(0); + } break; } } @@ -5052,8 +5059,10 @@ class VisualShaderNodePluginInputEditor : public OptionButton { public: void _notification(int p_what) { - if (p_what == NOTIFICATION_READY) { - connect("item_selected", callable_mp(this, &VisualShaderNodePluginInputEditor::_item_selected)); + switch (p_what) { + case NOTIFICATION_READY: { + connect("item_selected", callable_mp(this, &VisualShaderNodePluginInputEditor::_item_selected)); + } break; } } @@ -5100,8 +5109,10 @@ class VisualShaderNodePluginUniformRefEditor : public OptionButton { public: void _notification(int p_what) { - if (p_what == NOTIFICATION_READY) { - connect("item_selected", callable_mp(this, &VisualShaderNodePluginUniformRefEditor::_item_selected)); + switch (p_what) { + case NOTIFICATION_READY: { + connect("item_selected", callable_mp(this, &VisualShaderNodePluginUniformRefEditor::_item_selected)); + } break; } } @@ -5514,29 +5525,31 @@ Size2 VisualShaderNodePortPreview::get_minimum_size() const { } void VisualShaderNodePortPreview::_notification(int p_what) { - if (p_what == NOTIFICATION_DRAW) { - Vector<Vector2> points = { - Vector2(), - Vector2(get_size().width, 0), - get_size(), - Vector2(0, get_size().height) - }; - - Vector<Vector2> uvs = { - Vector2(0, 0), - Vector2(1, 0), - Vector2(1, 1), - Vector2(0, 1) - }; - - Vector<Color> colors = { - Color(1, 1, 1, 1), - Color(1, 1, 1, 1), - Color(1, 1, 1, 1), - Color(1, 1, 1, 1) - }; - - draw_primitive(points, colors, uvs); + switch (p_what) { + case NOTIFICATION_DRAW: { + Vector<Vector2> points = { + Vector2(), + Vector2(get_size().width, 0), + get_size(), + Vector2(0, get_size().height) + }; + + Vector<Vector2> uvs = { + Vector2(0, 0), + Vector2(1, 0), + Vector2(1, 1), + Vector2(0, 1) + }; + + Vector<Color> colors = { + Color(1, 1, 1, 1), + Color(1, 1, 1, 1), + Color(1, 1, 1, 1), + Color(1, 1, 1, 1) + }; + + draw_primitive(points, colors, uvs); + } break; } } diff --git a/editor/plugins/voxel_gi_editor_plugin.cpp b/editor/plugins/voxel_gi_editor_plugin.cpp index 9ecdb56e50..6fc6c1ad39 100644 --- a/editor/plugins/voxel_gi_editor_plugin.cpp +++ b/editor/plugins/voxel_gi_editor_plugin.cpp @@ -65,41 +65,43 @@ bool VoxelGIEditorPlugin::handles(Object *p_object) const { } void VoxelGIEditorPlugin::_notification(int p_what) { - if (p_what == NOTIFICATION_PROCESS) { - if (!voxel_gi) { - return; - } + switch (p_what) { + case NOTIFICATION_PROCESS: { + if (!voxel_gi) { + return; + } - // Set information tooltip on the Bake button. This information is useful - // to optimize performance (video RAM size) and reduce light leaking (individual cell size). + // Set information tooltip on the Bake button. This information is useful + // to optimize performance (video RAM size) and reduce light leaking (individual cell size). - const Vector3i size = voxel_gi->get_estimated_cell_size(); + const Vector3i size = voxel_gi->get_estimated_cell_size(); - const Vector3 extents = voxel_gi->get_extents(); + const Vector3 extents = voxel_gi->get_extents(); - const int data_size = 4; - const double size_mb = size.x * size.y * size.z * data_size / (1024.0 * 1024.0); - // Add a qualitative measurement to help the user assess whether a VoxelGI node is using a lot of VRAM. - String size_quality; - if (size_mb < 16.0) { - size_quality = TTR("Low"); - } else if (size_mb < 64.0) { - size_quality = TTR("Moderate"); - } else { - size_quality = TTR("High"); - } + const int data_size = 4; + const double size_mb = size.x * size.y * size.z * data_size / (1024.0 * 1024.0); + // Add a qualitative measurement to help the user assess whether a VoxelGI node is using a lot of VRAM. + String size_quality; + if (size_mb < 16.0) { + size_quality = TTR("Low"); + } else if (size_mb < 64.0) { + size_quality = TTR("Moderate"); + } else { + size_quality = TTR("High"); + } - String text; - text += vformat(TTR("Subdivisions: %s"), vformat(String::utf8("%d × %d × %d"), size.x, size.y, size.z)) + "\n"; - text += vformat(TTR("Cell size: %s"), vformat(String::utf8("%.3f × %.3f × %.3f"), extents.x / size.x, extents.y / size.y, extents.z / size.z)) + "\n"; - text += vformat(TTR("Video RAM size: %s MB (%s)"), String::num(size_mb, 2), size_quality); + String text; + text += vformat(TTR("Subdivisions: %s"), vformat(String::utf8("%d × %d × %d"), size.x, size.y, size.z)) + "\n"; + text += vformat(TTR("Cell size: %s"), vformat(String::utf8("%.3f × %.3f × %.3f"), extents.x / size.x, extents.y / size.y, extents.z / size.z)) + "\n"; + text += vformat(TTR("Video RAM size: %s MB (%s)"), String::num(size_mb, 2), size_quality); - // Only update the tooltip when needed to avoid constant redrawing. - if (bake->get_tooltip(Point2()) == text) { - return; - } + // Only update the tooltip when needed to avoid constant redrawing. + if (bake->get_tooltip(Point2()) == text) { + return; + } - bake->set_tooltip(text); + bake->set_tooltip(text); + } break; } } diff --git a/editor/project_export.cpp b/editor/project_export.cpp index 21163531d8..55a4dc2c67 100644 --- a/editor/project_export.cpp +++ b/editor/project_export.cpp @@ -61,6 +61,7 @@ void ProjectExportDialog::_notification(int p_what) { EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "export", Rect2(get_position(), get_size())); } } break; + case NOTIFICATION_READY: { duplicate_preset->set_icon(presets->get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons"))); delete_preset->set_icon(presets->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 2a9f699ee6..87d008d144 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -647,8 +647,10 @@ private: } void _notification(int p_what) { - if (p_what == NOTIFICATION_WM_CLOSE_REQUEST) { - _remove_created_folder(); + switch (p_what) { + case NOTIFICATION_WM_CLOSE_REQUEST: { + _remove_created_folder(); + } break; } } @@ -978,10 +980,12 @@ public: hover = true; update(); } break; + case NOTIFICATION_MOUSE_EXIT: { hover = false; update(); } break; + case NOTIFICATION_DRAW: { if (hover) { draw_style_box(get_theme_stylebox(SNAME("hover"), SNAME("Tree")), Rect2(Point2(), get_size())); @@ -1143,18 +1147,20 @@ void ProjectList::update_icons_async() { } void ProjectList::_notification(int p_what) { - if (p_what == NOTIFICATION_PROCESS) { - // Load icons as a coroutine to speed up launch when you have hundreds of projects - if (_icon_load_index < _projects.size()) { - Item &item = _projects.write[_icon_load_index]; - if (item.control->icon_needs_reload) { - load_project_icon(_icon_load_index); - } - _icon_load_index++; + switch (p_what) { + case NOTIFICATION_PROCESS: { + // Load icons as a coroutine to speed up launch when you have hundreds of projects + if (_icon_load_index < _projects.size()) { + Item &item = _projects.write[_icon_load_index]; + if (item.control->icon_needs_reload) { + load_project_icon(_icon_load_index); + } + _icon_load_index++; - } else { - set_process(false); - } + } else { + set_process(false); + } + } break; } } @@ -1872,17 +1878,20 @@ void ProjectManager::_notification(int p_what) { settings_hb->set_anchors_and_offsets_preset(Control::PRESET_TOP_RIGHT); update(); } break; + case NOTIFICATION_ENTER_TREE: { search_box->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons"))); search_box->set_clear_button_enabled(true); Engine::get_singleton()->set_editor_hint(false); } break; + case NOTIFICATION_RESIZED: { if (open_templates->is_visible()) { open_templates->popup_centered(); } } break; + case NOTIFICATION_READY: { int default_sorting = (int)EditorSettings::get_singleton()->get("project_manager/sorting_order"); filter_option->select(default_sorting); @@ -1898,12 +1907,15 @@ void ProjectManager::_notification(int p_what) { search_box->grab_focus(); } } break; + case NOTIFICATION_VISIBILITY_CHANGED: { set_process_unhandled_key_input(is_visible_in_tree()); } break; + case NOTIFICATION_WM_CLOSE_REQUEST: { _dim_window(); } break; + case NOTIFICATION_WM_ABOUT: { _show_about(); } break; diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index c0ff1d72ee..03179733d5 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -531,11 +531,13 @@ void ProjectSettingsEditor::_notification(int p_what) { EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "project_settings", Rect2(get_position(), get_size())); } } break; + case NOTIFICATION_ENTER_TREE: { general_settings_inspector->edit(ps); _update_action_map_editor(); _update_theme(); } break; + case NOTIFICATION_THEME_CHANGED: { _update_theme(); } break; diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp index 40f7b86ffc..cd65ee7ae6 100644 --- a/editor/property_editor.cpp +++ b/editor/property_editor.cpp @@ -94,8 +94,10 @@ Ref<Resource> EditorResourceConversionPlugin::convert(const Ref<Resource> &p_res } void CustomPropertyEditor::_notification(int p_what) { - if (p_what == NOTIFICATION_WM_CLOSE_REQUEST) { - hide(); + switch (p_what) { + case NOTIFICATION_WM_CLOSE_REQUEST: { + hide(); + } break; } } diff --git a/editor/property_selector.cpp b/editor/property_selector.cpp index 825802d852..453ecb6b24 100644 --- a/editor/property_selector.cpp +++ b/editor/property_selector.cpp @@ -421,10 +421,14 @@ void PropertySelector::_hide_requested() { } void PropertySelector::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - connect("confirmed", callable_mp(this, &PropertySelector::_confirmed)); - } else if (p_what == NOTIFICATION_EXIT_TREE) { - disconnect("confirmed", callable_mp(this, &PropertySelector::_confirmed)); + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + connect("confirmed", callable_mp(this, &PropertySelector::_confirmed)); + } break; + + case NOTIFICATION_EXIT_TREE: { + disconnect("confirmed", callable_mp(this, &PropertySelector::_confirmed)); + } break; } } diff --git a/editor/quick_open.cpp b/editor/quick_open.cpp index 2a8ca67fe6..4e64aba1db 100644 --- a/editor/quick_open.cpp +++ b/editor/quick_open.cpp @@ -229,6 +229,7 @@ void EditorQuickOpen::_notification(int p_what) { search_box->set_clear_button_enabled(true); } break; + case NOTIFICATION_EXIT_TREE: { disconnect("confirmed", callable_mp(this, &EditorQuickOpen::_confirmed)); } break; diff --git a/editor/reparent_dialog.cpp b/editor/reparent_dialog.cpp index 1a83a61534..8879085d86 100644 --- a/editor/reparent_dialog.cpp +++ b/editor/reparent_dialog.cpp @@ -35,12 +35,14 @@ #include "scene/gui/label.h" void ReparentDialog::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - connect("confirmed", callable_mp(this, &ReparentDialog::_reparent)); - } - - if (p_what == NOTIFICATION_EXIT_TREE) { - disconnect("confirmed", callable_mp(this, &ReparentDialog::_reparent)); + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + connect("confirmed", callable_mp(this, &ReparentDialog::_reparent)); + } break; + + case NOTIFICATION_EXIT_TREE: { + disconnect("confirmed", callable_mp(this, &ReparentDialog::_reparent)); + } break; } } diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index db78546fd3..628e7880a1 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -1270,6 +1270,7 @@ void SceneTreeDock::_notification(int p_what) { case NOTIFICATION_EXIT_TREE: { clear_inherit_confirm->disconnect("confirmed", callable_mp(this, &SceneTreeDock::_tool_selected)); } break; + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { scene_tree->set_auto_expand_selected(EditorSettings::get_singleton()->get("docks/scene_tree/auto_expand_to_selected"), false); button_add->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); @@ -1286,6 +1287,7 @@ void SceneTreeDock::_notification(int p_what) { filter->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons"))); filter->set_clear_button_enabled(true); } break; + case NOTIFICATION_PROCESS: { bool show_create_root = bool(EDITOR_GET("interface/editors/show_scene_tree_root_selection")) && get_tree()->get_edited_scene_root() == nullptr; @@ -1298,7 +1300,6 @@ void SceneTreeDock::_notification(int p_what) { scene_tree->show(); } } - } break; } } diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index c10dd2e2de..ba65828ac1 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -700,6 +700,7 @@ void SceneTreeEditor::_notification(int p_what) { _update_tree(); } break; + case NOTIFICATION_EXIT_TREE: { get_tree()->disconnect("tree_changed", callable_mp(this, &SceneTreeEditor::_tree_changed)); get_tree()->disconnect("tree_process_mode_changed", callable_mp(this, &SceneTreeEditor::_tree_process_mode_changed)); @@ -708,6 +709,7 @@ void SceneTreeEditor::_notification(int p_what) { tree->disconnect("item_collapsed", callable_mp(this, &SceneTreeEditor::_cell_collapsed)); get_tree()->disconnect("node_configuration_warning_changed", callable_mp(this, &SceneTreeEditor::_warning_changed)); } break; + case NOTIFICATION_THEME_CHANGED: { _update_tree(); } break; @@ -1283,13 +1285,16 @@ void SceneTreeDialog::_notification(int p_what) { tree->update_tree(); } } break; + case NOTIFICATION_ENTER_TREE: { connect("confirmed", callable_mp(this, &SceneTreeDialog::_select)); _update_theme(); } break; + case NOTIFICATION_THEME_CHANGED: { _update_theme(); } break; + case NOTIFICATION_EXIT_TREE: { disconnect("confirmed", callable_mp(this, &SceneTreeDialog::_select)); } break; diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index c60c253a65..bf43e11cdb 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -37,9 +37,73 @@ #include "editor/create_dialog.h" #include "editor/editor_file_dialog.h" #include "editor/editor_file_system.h" +#include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +static String _get_parent_class_of_script(String p_path) { + if (!ResourceLoader::exists(p_path, "Script")) { + return "Object"; // A script eventually inherits from Object. + } + + Ref<Script> script = ResourceLoader::load(p_path, "Script"); + ERR_FAIL_COND_V(script.is_null(), "Object"); + + String class_name; + Ref<Script> base = script->get_base_script(); + + // Inherits from a built-in class. + if (base.is_null()) { + script->get_language()->get_global_class_name(script->get_path(), &class_name); + return class_name; + } + + // Inherits from a script that has class_name. + class_name = script->get_language()->get_global_class_name(base->get_path()); + if (!class_name.is_empty()) { + return class_name; + } + + // Inherits from a plain script. + return _get_parent_class_of_script(base->get_path()); +} + +static Vector<String> _get_hierarchy(String p_class_name) { + Vector<String> hierarchy; + + String class_name = p_class_name; + while (true) { + // A registered class. + if (ClassDB::class_exists(class_name)) { + hierarchy.push_back(class_name); + + class_name = ClassDB::get_parent_class(class_name); + continue; + } + + // A class defined in script with class_name. + if (ScriptServer::is_global_class(class_name)) { + hierarchy.push_back(class_name); + + Ref<Script> script = EditorNode::get_editor_data().script_class_load_script(class_name); + ERR_BREAK(script.is_null()); + class_name = _get_parent_class_of_script(script->get_path()); + continue; + } + + break; + } + + if (hierarchy.is_empty()) { + if (p_class_name.is_valid_identifier()) { + hierarchy.push_back(p_class_name); + } + hierarchy.push_back("Object"); + } + + return hierarchy; +} + void ScriptCreateDialog::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: @@ -353,18 +417,6 @@ void ScriptCreateDialog::_load_exist() { hide(); } -Vector<String> ScriptCreateDialog::get_hierarchy(String p_object) const { - Vector<String> hierarchy; - hierarchy.append(p_object); - - String parent_class = ClassDB::get_parent_class(p_object); - while (parent_class.is_valid_identifier()) { - hierarchy.append(parent_class); - parent_class = ClassDB::get_parent_class(parent_class); - } - return hierarchy; -} - void ScriptCreateDialog::_language_changed(int l) { language = ScriptServer::get_language(l); @@ -553,14 +605,14 @@ void ScriptCreateDialog::_update_template_menu() { } String inherits_base_type = parent_name->get_text(); - // If it inherits from a script, select Object instead. + // If it inherits from a script, get its parent class first. if (inherits_base_type[0] == '"') { - inherits_base_type = "Object"; + inherits_base_type = _get_parent_class_of_script(inherits_base_type.unquote()); } // Get all ancestor node for selected base node. // There templates will also fit the base node. - Vector<String> hierarchy = get_hierarchy(inherits_base_type); + Vector<String> hierarchy = _get_hierarchy(inherits_base_type); int last_used_template = -1; int preselected_template = -1; int previous_ancestor_level = -1; @@ -1038,6 +1090,7 @@ ScriptCreateDialog::ScriptCreateDialog() { internal_name = memnew(LineEdit); internal_name->set_h_size_flags(Control::SIZE_EXPAND_FILL); + internal_name->connect("text_submitted", callable_mp(this, &ScriptCreateDialog::_path_submitted)); label = memnew(Label(TTR("Name:"))); gc->add_child(label); gc->add_child(internal_name); diff --git a/editor/script_create_dialog.h b/editor/script_create_dialog.h index aea9649abc..5c0f51812f 100644 --- a/editor/script_create_dialog.h +++ b/editor/script_create_dialog.h @@ -115,7 +115,6 @@ class ScriptCreateDialog : public ConfirmationDialog { virtual void ok_pressed() override; void _create_new(); void _load_exist(); - Vector<String> get_hierarchy(String p_object) const; void _msg_script_valid(bool valid, const String &p_msg = String()); void _msg_path_valid(bool valid, const String &p_msg = String()); void _update_template_menu(); diff --git a/editor/shader_create_dialog.cpp b/editor/shader_create_dialog.cpp index 3c807548ab..dbc78e846c 100644 --- a/editor/shader_create_dialog.cpp +++ b/editor/shader_create_dialog.cpp @@ -57,6 +57,7 @@ void ShaderCreateDialog::_notification(int p_what) { current_mode = EditorSettings::get_singleton()->get_project_metadata("shader_setup", "last_selected_mode", 0); mode_menu->select(current_mode); } break; + case NOTIFICATION_THEME_CHANGED: { _update_theme(); } break; diff --git a/editor/shader_globals_editor.cpp b/editor/shader_globals_editor.cpp index 034f6d4857..70a43d24ba 100644 --- a/editor/shader_globals_editor.cpp +++ b/editor/shader_globals_editor.cpp @@ -438,13 +438,16 @@ void ShaderGlobalsEditor::_bind_methods() { } void ShaderGlobalsEditor::_notification(int p_what) { - if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { - if (is_visible_in_tree()) { - inspector->edit(interface); - } - } - if (p_what == NOTIFICATION_PREDELETE) { - inspector->edit(nullptr); + switch (p_what) { + case NOTIFICATION_VISIBILITY_CHANGED: { + if (is_visible_in_tree()) { + inspector->edit(interface); + } + } break; + + case NOTIFICATION_PREDELETE: { + inspector->edit(nullptr); + } break; } } diff --git a/main/main.cpp b/main/main.cpp index 21199fe227..246a26025c 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -487,6 +487,7 @@ void Main::test_cleanup() { } unregister_core_driver_types(); + unregister_core_extensions(); unregister_core_types(); OS::get_singleton()->finalize_core(); @@ -634,7 +635,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph continue; } #endif - List<String>::Element *N = I->next(); if (I->get() == "-h" || I->get() == "--help" || I->get() == "/?") { // display help @@ -1157,6 +1157,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph // Initialize user data dir. OS::get_singleton()->ensure_user_data_dir(); + register_core_extensions(); // core extensions must be registered after globals setup and before display + ResourceUID::get_singleton()->load_from_cache(); // load UUIDs from cache. GLOBAL_DEF("memory/limits/multithreaded_server/rid_pool_prealloc", 60); @@ -1272,7 +1274,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph OS::get_singleton()->set_cmdline(execpath, main_args); - register_core_extensions(); //before display // possibly be worth changing the default from vulkan to something lower spec, // for the project manager, depending on how smooth the fallback is. GLOBAL_DEF_RST("rendering/driver/driver_name", "vulkan"); @@ -1529,6 +1530,7 @@ error: } unregister_core_driver_types(); + unregister_core_extensions(); unregister_core_types(); OS::get_singleton()->_cmdline.clear(); @@ -1961,6 +1963,10 @@ Error Main::setup2(Thread::ID p_main_tid_override) { return OK; } +String Main::get_rendering_driver_name() { + return rendering_driver; +} + // everything the main loop needs to know about frame timings static MainTimerSync main_timer_sync; @@ -2888,6 +2894,7 @@ void Main::cleanup(bool p_force) { memdelete(message_queue); unregister_core_driver_types(); + unregister_core_extensions(); unregister_core_types(); OS::get_singleton()->finalize_core(); diff --git a/main/main.h b/main/main.h index cec31545c7..14a8fb4147 100644 --- a/main/main.h +++ b/main/main.h @@ -49,6 +49,7 @@ public: static int test_entrypoint(int argc, char *argv[], bool &tests_need_run); static Error setup(const char *execpath, int argc, char *argv[], bool p_second_phase = true); static Error setup2(Thread::ID p_main_tid_override = 0); + static String get_rendering_driver_name(); #ifdef TESTS_ENABLED static Error test_setup(); static void test_cleanup(); diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index fbddedbe55..39e4751be3 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -491,61 +491,63 @@ Vector<Face3> CSGShape3D::get_faces(uint32_t p_usage_flags) const { } void CSGShape3D::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - Node *parentn = get_parent(); - if (parentn) { - parent = Object::cast_to<CSGShape3D>(parentn); - if (parent) { - set_base(RID()); - root_mesh.unref(); + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + Node *parentn = get_parent(); + if (parentn) { + parent = Object::cast_to<CSGShape3D>(parentn); + if (parent) { + set_base(RID()); + root_mesh.unref(); + } } - } - if (use_collision && is_root_shape()) { - root_collision_shape.instantiate(); - root_collision_instance = PhysicsServer3D::get_singleton()->body_create(); - PhysicsServer3D::get_singleton()->body_set_mode(root_collision_instance, PhysicsServer3D::BODY_MODE_STATIC); - PhysicsServer3D::get_singleton()->body_set_state(root_collision_instance, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform()); - PhysicsServer3D::get_singleton()->body_add_shape(root_collision_instance, root_collision_shape->get_rid()); - PhysicsServer3D::get_singleton()->body_set_space(root_collision_instance, get_world_3d()->get_space()); - PhysicsServer3D::get_singleton()->body_attach_object_instance_id(root_collision_instance, get_instance_id()); - set_collision_layer(collision_layer); - set_collision_mask(collision_mask); - } + if (use_collision && is_root_shape()) { + root_collision_shape.instantiate(); + root_collision_instance = PhysicsServer3D::get_singleton()->body_create(); + PhysicsServer3D::get_singleton()->body_set_mode(root_collision_instance, PhysicsServer3D::BODY_MODE_STATIC); + PhysicsServer3D::get_singleton()->body_set_state(root_collision_instance, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform()); + PhysicsServer3D::get_singleton()->body_add_shape(root_collision_instance, root_collision_shape->get_rid()); + PhysicsServer3D::get_singleton()->body_set_space(root_collision_instance, get_world_3d()->get_space()); + PhysicsServer3D::get_singleton()->body_attach_object_instance_id(root_collision_instance, get_instance_id()); + set_collision_layer(collision_layer); + set_collision_mask(collision_mask); + } - _make_dirty(); - } + _make_dirty(); + } break; - if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { - if (use_collision && is_root_shape() && root_collision_instance.is_valid()) { - PhysicsServer3D::get_singleton()->body_set_state(root_collision_instance, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform()); - } - } + case NOTIFICATION_TRANSFORM_CHANGED: { + if (use_collision && is_root_shape() && root_collision_instance.is_valid()) { + PhysicsServer3D::get_singleton()->body_set_state(root_collision_instance, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform()); + } + } break; - if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) { - if (parent) { - parent->_make_dirty(); - } - } + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { + if (parent) { + parent->_make_dirty(); + } + } break; - if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { - if (parent) { - parent->_make_dirty(); - } - } + case NOTIFICATION_VISIBILITY_CHANGED: { + if (parent) { + parent->_make_dirty(); + } + } break; - if (p_what == NOTIFICATION_EXIT_TREE) { - if (parent) { - parent->_make_dirty(); - } - parent = nullptr; + case NOTIFICATION_EXIT_TREE: { + if (parent) { + parent->_make_dirty(); + } + parent = nullptr; - if (use_collision && is_root_shape() && root_collision_instance.is_valid()) { - PhysicsServer3D::get_singleton()->free(root_collision_instance); - root_collision_instance = RID(); - root_collision_shape.unref(); - } - _make_dirty(); + if (use_collision && is_root_shape() && root_collision_instance.is_valid()) { + PhysicsServer3D::get_singleton()->free(root_collision_instance); + root_collision_instance = RID(); + root_collision_shape.unref(); + } + _make_dirty(); + } break; } } diff --git a/modules/fbx/data/fbx_material.cpp b/modules/fbx/data/fbx_material.cpp index bc638244d8..36e20df3a9 100644 --- a/modules/fbx/data/fbx_material.cpp +++ b/modules/fbx/data/fbx_material.cpp @@ -426,7 +426,7 @@ Ref<StandardMaterial3D> FBXMaterial::import_material(ImportState &state) { // meaning is that approx equal to zero is disabled not actually zero. ;) if (real_value && Math::is_zero_approx(real_value->Value())) { print_verbose("clearcoat real value: " + rtos(real_value->Value())); - spatial_material->set_clearcoat_gloss(1.0 - real_value->Value()); + spatial_material->set_clearcoat_roughness(real_value->Value()); } else { print_error("unsupported value type for clearcoat gloss"); } diff --git a/modules/gdnative/gdnative/aabb.cpp b/modules/gdnative/gdnative/aabb.cpp index 82aa7215b2..b8909433cc 100644 --- a/modules/gdnative/gdnative/aabb.cpp +++ b/modules/gdnative/gdnative/aabb.cpp @@ -31,6 +31,7 @@ #include "gdnative/aabb.h" #include "core/math/aabb.h" +#include "core/os/memory.h" static_assert(sizeof(godot_aabb) == sizeof(AABB), "AABB size mismatch"); diff --git a/modules/gdnative/gdnative/plane.cpp b/modules/gdnative/gdnative/plane.cpp index 9ac5cfb3b7..41fa0da5db 100644 --- a/modules/gdnative/gdnative/plane.cpp +++ b/modules/gdnative/gdnative/plane.cpp @@ -31,6 +31,7 @@ #include "gdnative/plane.h" #include "core/math/plane.h" +#include "core/os/memory.h" static_assert(sizeof(godot_plane) == sizeof(Plane), "Plane size mismatch"); diff --git a/modules/gdnative/gdnative/vector3.cpp b/modules/gdnative/gdnative/vector3.cpp index 26e94d7e5c..37c88c3cca 100644 --- a/modules/gdnative/gdnative/vector3.cpp +++ b/modules/gdnative/gdnative/vector3.cpp @@ -31,6 +31,8 @@ #include "gdnative/vector3.h" #include "core/math/vector3.h" +#include "core/math/vector3i.h" +#include "core/os/memory.h" static_assert(sizeof(godot_vector3) == sizeof(Vector3), "Vector3 size mismatch"); static_assert(sizeof(godot_vector3i) == sizeof(Vector3i), "Vector3i size mismatch"); diff --git a/modules/gdnative/gdnative_library_singleton_editor.cpp b/modules/gdnative/gdnative_library_singleton_editor.cpp index e0079f93ee..ce1f41bdf1 100644 --- a/modules/gdnative/gdnative_library_singleton_editor.cpp +++ b/modules/gdnative/gdnative_library_singleton_editor.cpp @@ -183,10 +183,12 @@ void GDNativeLibrarySingletonEditor::_item_edited() { } void GDNativeLibrarySingletonEditor::_notification(int p_what) { - if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { - if (is_visible_in_tree()) { - _update_libraries(); - } + switch (p_what) { + case NOTIFICATION_VISIBILITY_CHANGED: { + if (is_visible_in_tree()) { + _update_libraries(); + } + } break; } } diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp index 5d5414c694..95976a8827 100644 --- a/modules/gdnative/nativescript/nativescript.cpp +++ b/modules/gdnative/nativescript/nativescript.cpp @@ -763,17 +763,19 @@ Variant NativeScriptInstance::call(const StringName &p_method, const Variant **p return Variant(); } -void NativeScriptInstance::notification(int p_notification) { +void NativeScriptInstance::notification(int p_what) { #ifdef DEBUG_ENABLED - if (p_notification == MainLoop::NOTIFICATION_CRASH) { - if (current_method_call != StringName()) { - ERR_PRINT("NativeScriptInstance detected crash on method: " + current_method_call); - current_method_call = ""; - } + switch (p_what) { + case MainLoop::NOTIFICATION_CRASH: { + if (current_method_call != StringName()) { + ERR_PRINT("NativeScriptInstance detected crash on method: " + current_method_call); + current_method_call = ""; + } + } break; } #endif - Variant value = p_notification; + Variant value = p_what; const Variant *args[1] = { &value }; Callable::CallError error; call("_notification", args, 1, error); @@ -1639,7 +1641,6 @@ void NativeReloadNode::_bind_methods() { void NativeReloadNode::_notification(int p_what) { #ifdef TOOLS_ENABLED - switch (p_what) { case NOTIFICATION_APPLICATION_FOCUS_OUT: { if (unloaded) { @@ -1672,7 +1673,6 @@ void NativeReloadNode::_notification(int p_what) { } unloaded = true; - } break; case NOTIFICATION_APPLICATION_FOCUS_IN: { @@ -1736,10 +1736,7 @@ void NativeReloadNode::_notification(int p_what) { for (Set<StringName>::Element *R = libs_to_remove.front(); R; R = R->next()) { NSL->library_gdnatives.erase(R->get()); } - } break; - default: { - }; } #endif } diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h index 6c47d35abc..2d01de5832 100644 --- a/modules/gdnative/nativescript/nativescript.h +++ b/modules/gdnative/nativescript/nativescript.h @@ -209,7 +209,7 @@ public: virtual void get_method_list(List<MethodInfo> *p_list) const; virtual bool has_method(const StringName &p_method) const; virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); - virtual void notification(int p_notification); + virtual void notification(int p_what); String to_string(bool *r_valid); virtual Ref<Script> get_script() const; diff --git a/modules/gdscript/editor_templates/CharacterBody2D/basic_movement.gd b/modules/gdscript/editor_templates/CharacterBody2D/basic_movement.gd index edaccae018..34b5ba45b7 100644 --- a/modules/gdscript/editor_templates/CharacterBody2D/basic_movement.gd +++ b/modules/gdscript/editor_templates/CharacterBody2D/basic_movement.gd @@ -12,18 +12,18 @@ var gravity: int = ProjectSettings.get_setting("physics/2d/default_gravity") func _physics_process(delta: float) -> void: # Add the gravity. if not is_on_floor(): - motion_velocity.y += gravity * delta + velocity.y += gravity * delta # Handle Jump. if Input.is_action_just_pressed("ui_accept") and is_on_floor(): - motion_velocity.y = JUMP_VELOCITY + velocity.y = JUMP_VELOCITY # Get the input direction and handle the movement/deceleration. # As good practice, you should replace UI actions with custom gameplay actions. var direction := Input.get_axis("ui_left", "ui_right") if direction: - motion_velocity.x = direction * SPEED + velocity.x = direction * SPEED else: - motion_velocity.x = move_toward(motion_velocity.x, 0, SPEED) + velocity.x = move_toward(velocity.x, 0, SPEED) move_and_slide() diff --git a/modules/gdscript/editor_templates/CharacterBody3D/basic_movement.gd b/modules/gdscript/editor_templates/CharacterBody3D/basic_movement.gd index e191e5451a..cbc9cf1064 100644 --- a/modules/gdscript/editor_templates/CharacterBody3D/basic_movement.gd +++ b/modules/gdscript/editor_templates/CharacterBody3D/basic_movement.gd @@ -12,21 +12,21 @@ var gravity: float = ProjectSettings.get_setting("physics/3d/default_gravity") func _physics_process(delta: float) -> void: # Add the gravity. if not is_on_floor(): - motion_velocity.y -= gravity * delta + velocity.y -= gravity * delta # Handle Jump. if Input.is_action_just_pressed("ui_accept") and is_on_floor(): - motion_velocity.y = JUMP_VELOCITY + velocity.y = JUMP_VELOCITY # Get the input direction and handle the movement/deceleration. # As good practice, you should replace UI actions with custom gameplay actions. var input_dir := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down") var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized() if direction: - motion_velocity.x = direction.x * SPEED - motion_velocity.z = direction.z * SPEED + velocity.x = direction.x * SPEED + velocity.z = direction.z * SPEED else: - motion_velocity.x = move_toward(motion_velocity.x, 0, SPEED) - motion_velocity.z = move_toward(motion_velocity.z, 0, SPEED) + velocity.x = move_toward(velocity.x, 0, SPEED) + velocity.z = move_toward(velocity.z, 0, SPEED) move_and_slide() diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 94daba4bf6..9a79f3d016 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -646,41 +646,51 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas } } - if (member.variable->datatype_specifier != nullptr) { - datatype = specified_type; + // Check if initalizer is an unset identifier (ie: a variable within scope, but declared below) + if (member.variable->initializer && !member.variable->initializer->get_datatype().is_set()) { + if (member.variable->initializer->type == GDScriptParser::Node::IDENTIFIER) { + GDScriptParser::IdentifierNode *initializer_identifier = static_cast<GDScriptParser::IdentifierNode *>(member.variable->initializer); + push_error(vformat(R"(Identifier "%s" must be declared above current variable.)", initializer_identifier->name), member.variable->initializer); + } else { + ERR_PRINT("Parser bug (please report): tried to assign unset node without an identifier."); + } + } else { + if (member.variable->datatype_specifier != nullptr) { + datatype = specified_type; - if (member.variable->initializer != nullptr) { - if (!is_type_compatible(datatype, member.variable->initializer->get_datatype(), true, member.variable->initializer)) { - // Try reverse test since it can be a masked subtype. - if (!is_type_compatible(member.variable->initializer->get_datatype(), datatype, true, member.variable->initializer)) { - push_error(vformat(R"(Value of type "%s" cannot be assigned to a variable of type "%s".)", member.variable->initializer->get_datatype().to_string(), datatype.to_string()), member.variable->initializer); - } else { - // TODO: Add warning. + if (member.variable->initializer != nullptr) { + if (!is_type_compatible(datatype, member.variable->initializer->get_datatype(), true, member.variable->initializer)) { + // Try reverse test since it can be a masked subtype. + if (!is_type_compatible(member.variable->initializer->get_datatype(), datatype, true, member.variable->initializer)) { + push_error(vformat(R"(Value of type "%s" cannot be assigned to a variable of type "%s".)", member.variable->initializer->get_datatype().to_string(), datatype.to_string()), member.variable->initializer); + } else { + // TODO: Add warning. + mark_node_unsafe(member.variable->initializer); + member.variable->use_conversion_assign = true; + } + } else if (datatype.builtin_type == Variant::INT && member.variable->initializer->get_datatype().builtin_type == Variant::FLOAT) { +#ifdef DEBUG_ENABLED + parser->push_warning(member.variable->initializer, GDScriptWarning::NARROWING_CONVERSION); +#endif + } + if (member.variable->initializer->get_datatype().is_variant()) { + // TODO: Warn unsafe assign. mark_node_unsafe(member.variable->initializer); member.variable->use_conversion_assign = true; } - } else if (datatype.builtin_type == Variant::INT && member.variable->initializer->get_datatype().builtin_type == Variant::FLOAT) { -#ifdef DEBUG_ENABLED - parser->push_warning(member.variable->initializer, GDScriptWarning::NARROWING_CONVERSION); -#endif } - if (member.variable->initializer->get_datatype().is_variant()) { - // TODO: Warn unsafe assign. - mark_node_unsafe(member.variable->initializer); - member.variable->use_conversion_assign = true; + } else if (member.variable->infer_datatype) { + if (member.variable->initializer == nullptr) { + push_error(vformat(R"(Cannot infer the type of "%s" variable because there's no default value.)", member.variable->identifier->name), member.variable->identifier); + } else if (!datatype.is_set() || datatype.has_no_type()) { + push_error(vformat(R"(Cannot infer the type of "%s" variable because the initial value doesn't have a set type.)", member.variable->identifier->name), member.variable->initializer); + } else if (datatype.is_variant()) { + push_error(vformat(R"(Cannot infer the type of "%s" variable because the initial value is Variant. Use explicit "Variant" type if this is intended.)", member.variable->identifier->name), member.variable->initializer); + } else if (datatype.builtin_type == Variant::NIL) { + push_error(vformat(R"(Cannot infer the type of "%s" variable because the initial value is "null".)", member.variable->identifier->name), member.variable->initializer); } + datatype.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED; } - } else if (member.variable->infer_datatype) { - if (member.variable->initializer == nullptr) { - push_error(vformat(R"(Cannot infer the type of "%s" variable because there's no default value.)", member.variable->identifier->name), member.variable->identifier); - } else if (!datatype.is_set() || datatype.has_no_type()) { - push_error(vformat(R"(Cannot infer the type of "%s" variable because the initial value doesn't have a set type.)", member.variable->identifier->name), member.variable->initializer); - } else if (datatype.is_variant()) { - push_error(vformat(R"(Cannot infer the type of "%s" variable because the initial value is Variant. Use explicit "Variant" type if this is intended.)", member.variable->identifier->name), member.variable->initializer); - } else if (datatype.builtin_type == Variant::NIL) { - push_error(vformat(R"(Cannot infer the type of "%s" variable because the initial value is "null".)", member.variable->identifier->name), member.variable->initializer); - } - datatype.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED; } datatype.is_constant = false; diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index f0dc830ed8..6fb95d32ca 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -1198,6 +1198,27 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, static bool _guess_identifier_type_from_base(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type); static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, GDScriptCompletionIdentifier &r_type); +static bool _is_expression_named_identifier(const GDScriptParser::ExpressionNode *p_expression, const StringName &p_name) { + if (p_expression) { + switch (p_expression->type) { + case GDScriptParser::Node::IDENTIFIER: { + const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(p_expression); + if (id->name == p_name) { + return true; + } + } break; + case GDScriptParser::Node::CAST: { + const GDScriptParser::CastNode *cn = static_cast<const GDScriptParser::CastNode *>(p_expression); + return _is_expression_named_identifier(cn->operand, p_name); + } break; + default: + break; + } + } + + return false; +} + static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, const GDScriptParser::ExpressionNode *p_expression, GDScriptCompletionIdentifier &r_type) { bool found = false; @@ -1904,6 +1925,14 @@ static bool _guess_identifier_type_from_base(GDScriptParser::CompletionContext & return true; } else if (init->start_line == p_context.current_line) { return false; + // Detects if variable is assigned to itself + } else if (_is_expression_named_identifier(init, member.variable->identifier->name)) { + if (member.variable->initializer->get_datatype().is_set()) { + r_type.type = member.variable->initializer->get_datatype(); + } else if (member.variable->get_datatype().is_set() && !member.variable->get_datatype().is_variant()) { + r_type.type = member.variable->get_datatype(); + } + return true; } else if (_guess_expression_type(p_context, init, r_type)) { return true; } else if (init->get_datatype().is_set() && !init->get_datatype().is_variant()) { diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 8e4e457ec1..725b62f6d6 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -2692,12 +2692,13 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_attribute(ExpressionNode * } } - attribute->is_attribute = true; attribute->base = p_previous_operand; if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected identifier after "." for attribute access.)")) { return attribute; } + + attribute->is_attribute = true; attribute->attribute = parse_identifier(); return attribute; diff --git a/modules/gdscript/language_server/gdscript_language_server.cpp b/modules/gdscript/language_server/gdscript_language_server.cpp index 33c1c834f1..14337e87da 100644 --- a/modules/gdscript/language_server/gdscript_language_server.cpp +++ b/modules/gdscript/language_server/gdscript_language_server.cpp @@ -45,17 +45,20 @@ GDScriptLanguageServer::GDScriptLanguageServer() { void GDScriptLanguageServer::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_ENTER_TREE: { start(); - break; - case NOTIFICATION_EXIT_TREE: + } break; + + case NOTIFICATION_EXIT_TREE: { stop(); - break; + } break; + case NOTIFICATION_INTERNAL_PROCESS: { if (started && !use_thread) { protocol.poll(); } } break; + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { String host = String(_EDITOR_GET("network/language_server/remote_host")); int port = (int)_EDITOR_GET("network/language_server/remote_port"); diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index f555c8912d..2c42879bd3 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -84,6 +84,41 @@ #include <cstdint> #include <limits> +static Ref<ImporterMesh> _mesh_to_importer_mesh(Ref<Mesh> p_mesh) { + Ref<ImporterMesh> importer_mesh; + importer_mesh.instantiate(); + if (p_mesh.is_null()) { + return importer_mesh; + } + + Ref<ArrayMesh> array_mesh = p_mesh; + if (p_mesh->get_blend_shape_count()) { + ArrayMesh::BlendShapeMode shape_mode = ArrayMesh::BLEND_SHAPE_MODE_NORMALIZED; + if (array_mesh.is_valid()) { + shape_mode = array_mesh->get_blend_shape_mode(); + } + importer_mesh->set_blend_shape_mode(shape_mode); + for (int morph_i = 0; morph_i < p_mesh->get_blend_shape_count(); morph_i++) { + importer_mesh->add_blend_shape(p_mesh->get_blend_shape_name(morph_i)); + } + } + for (int32_t surface_i = 0; surface_i < p_mesh->get_surface_count(); surface_i++) { + Array array = p_mesh->surface_get_arrays(surface_i); + Ref<Material> mat = p_mesh->surface_get_material(surface_i); + String mat_name; + if (mat.is_valid()) { + mat_name = mat->get_name(); + } else { + // Assign default material when no material is assigned. + mat = Ref<StandardMaterial3D>(memnew(StandardMaterial3D)); + } + importer_mesh->add_surface(p_mesh->surface_get_primitive_type(surface_i), + array, p_mesh->surface_get_blend_shape_arrays(surface_i), p_mesh->surface_get_lods(surface_i), mat, + mat_name, p_mesh->surface_get_format(surface_i)); + } + return importer_mesh; +} + Error GLTFDocument::_serialize(Ref<GLTFState> state, const String &p_path) { if (!state->buffers.size()) { state->buffers.push_back(Vector<uint8_t>()); @@ -5038,39 +5073,16 @@ GLTFMeshIndex GLTFDocument::_convert_mesh_to_gltf(Ref<GLTFState> state, MeshInst if (p_mesh_instance->get_mesh().is_null()) { return -1; } - Ref<ImporterMesh> current_mesh; - current_mesh.instantiate(); + + Ref<Mesh> import_mesh = p_mesh_instance->get_mesh(); + Ref<ImporterMesh> current_mesh = _mesh_to_importer_mesh(import_mesh); Vector<float> blend_weights; - { - Ref<Mesh> import_mesh = p_mesh_instance->get_mesh(); - Ref<ArrayMesh> import_array_mesh = p_mesh_instance->get_mesh(); - if (import_mesh->get_blend_shape_count()) { - ArrayMesh::BlendShapeMode shape_mode = ArrayMesh::BLEND_SHAPE_MODE_NORMALIZED; - if (import_array_mesh.is_valid()) { - shape_mode = import_array_mesh->get_blend_shape_mode(); - } - current_mesh->set_blend_shape_mode(shape_mode); - for (int morph_i = 0; morph_i < import_mesh->get_blend_shape_count(); morph_i++) { - current_mesh->add_blend_shape(import_mesh->get_blend_shape_name(morph_i)); - } - } - for (int32_t surface_i = 0; surface_i < import_mesh->get_surface_count(); surface_i++) { - Array array = import_mesh->surface_get_arrays(surface_i); - Ref<Material> mat = import_mesh->surface_get_material(surface_i); - String mat_name; - if (mat.is_valid()) { - mat_name = mat->get_name(); - } - current_mesh->add_surface(import_mesh->surface_get_primitive_type(surface_i), - array, import_mesh->surface_get_blend_shape_arrays(surface_i), import_mesh->surface_get_lods(surface_i), mat, - mat_name, import_mesh->surface_get_format(surface_i)); - } - int32_t blend_count = import_mesh->get_blend_shape_count(); - blend_weights.resize(blend_count); - for (int32_t blend_i = 0; blend_i < blend_count; blend_i++) { - blend_weights.write[blend_i] = 0.0f; - } + int32_t blend_count = import_mesh->get_blend_shape_count(); + blend_weights.resize(blend_count); + for (int32_t blend_i = 0; blend_i < blend_count; blend_i++) { + blend_weights.write[blend_i] = 0.0f; } + Ref<GLTFMesh> gltf_mesh; gltf_mesh.instantiate(); Array instance_materials; @@ -5412,8 +5424,6 @@ void GLTFDocument::_convert_grid_map_to_gltf(GridMap *p_grid_map, GLTFNodeIndex Vector3 cell_location = cells[k]; int32_t cell = p_grid_map->get_cell_item( Vector3(cell_location.x, cell_location.y, cell_location.z)); - ImporterMeshInstance3D *import_mesh_node = memnew(ImporterMeshInstance3D); - import_mesh_node->set_mesh(p_grid_map->get_mesh_library()->get_item_mesh(cell)); Transform3D cell_xform; cell_xform.basis.set_orthogonal_index( p_grid_map->get_cell_item_orientation( @@ -5425,7 +5435,7 @@ void GLTFDocument::_convert_grid_map_to_gltf(GridMap *p_grid_map, GLTFNodeIndex Vector3(cell_location.x, cell_location.y, cell_location.z))); Ref<GLTFMesh> gltf_mesh; gltf_mesh.instantiate(); - gltf_mesh = import_mesh_node; + gltf_mesh->set_mesh(_mesh_to_importer_mesh(p_grid_map->get_mesh_library()->get_item_mesh(cell))); new_gltf_node->mesh = state->meshes.size(); state->meshes.push_back(gltf_mesh); new_gltf_node->xform = cell_xform * p_grid_map->get_transform(); diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index 4b72c71a5a..7c4d33ff17 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -703,8 +703,8 @@ void GridMap::_notification(int p_what) { RS::get_singleton()->instance_set_scenario(baked_meshes[i].instance, get_world_3d()->get_scenario()); RS::get_singleton()->instance_set_transform(baked_meshes[i].instance, get_global_transform()); } - } break; + case NOTIFICATION_TRANSFORM_CHANGED: { Transform3D new_xform = get_global_transform(); if (new_xform == last_transform) { @@ -721,6 +721,7 @@ void GridMap::_notification(int p_what) { RS::get_singleton()->instance_set_transform(baked_meshes[i].instance, get_global_transform()); } } break; + case NOTIFICATION_EXIT_WORLD: { for (const KeyValue<OctantKey, Octant *> &E : octant_map) { _octant_exit_world(E.key); @@ -732,8 +733,8 @@ void GridMap::_notification(int p_what) { for (int i = 0; i < baked_meshes.size(); i++) { RS::get_singleton()->instance_set_scenario(baked_meshes[i].instance, RID()); } - } break; + case NOTIFICATION_VISIBILITY_CHANGED: { _update_visibility(); } break; diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp index a7f93a6ce9..80856d37c2 100644 --- a/modules/gridmap/grid_map_editor_plugin.cpp +++ b/modules/gridmap/grid_map_editor_plugin.cpp @@ -1456,15 +1456,17 @@ GridMapEditor::~GridMapEditor() { } void GridMapEditorPlugin::_notification(int p_what) { - if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { - switch ((int)EditorSettings::get_singleton()->get("editors/grid_map/editor_side")) { - case 0: { // Left. - Node3DEditor::get_singleton()->move_control_to_left_panel(grid_map_editor); - } break; - case 1: { // Right. - Node3DEditor::get_singleton()->move_control_to_right_panel(grid_map_editor); - } break; - } + switch (p_what) { + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { + switch ((int)EditorSettings::get_singleton()->get("editors/grid_map/editor_side")) { + case 0: { // Left. + Node3DEditor::get_singleton()->move_control_to_left_panel(grid_map_editor); + } break; + case 1: { // Right. + Node3DEditor::get_singleton()->move_control_to_right_panel(grid_map_editor); + } break; + } + } break; } } diff --git a/modules/mono/editor_templates/CharacterBody2D/basic_movement.cs b/modules/mono/editor_templates/CharacterBody2D/basic_movement.cs index b0ded3133f..2ca81ab7cd 100644 --- a/modules/mono/editor_templates/CharacterBody2D/basic_movement.cs +++ b/modules/mono/editor_templates/CharacterBody2D/basic_movement.cs @@ -13,29 +13,29 @@ public partial class _CLASS_ : _BASE_ public override void _PhysicsProcess(float delta) { - Vector2 motionVelocity = MotionVelocity; + Vector2 velocity = Velocity; // Add the gravity. if (!IsOnFloor()) - motionVelocity.y += gravity * delta; + velocity.y += gravity * delta; // Handle Jump. if (Input.IsActionJustPressed("ui_accept") && IsOnFloor()) - motionVelocity.y = JumpVelocity; + velocity.y = JumpVelocity; // Get the input direction and handle the movement/deceleration. // As good practice, you should replace UI actions with custom gameplay actions. Vector2 direction = Input.GetVector("ui_left", "ui_right", "ui_up", "ui_down"); if (direction != Vector2.Zero) { - motionVelocity.x = direction.x * Speed; + velocity.x = direction.x * Speed; } else { - motionVelocity.x = Mathf.MoveToward(MotionVelocity.x, 0, Speed); + velocity.x = Mathf.MoveToward(Velocity.x, 0, Speed); } - MotionVelocity = motionVelocity; + Velocity = velocity; MoveAndSlide(); } } diff --git a/modules/mono/editor_templates/CharacterBody3D/basic_movement.cs b/modules/mono/editor_templates/CharacterBody3D/basic_movement.cs index d8c2f67ac8..a6935fe497 100644 --- a/modules/mono/editor_templates/CharacterBody3D/basic_movement.cs +++ b/modules/mono/editor_templates/CharacterBody3D/basic_movement.cs @@ -13,15 +13,15 @@ public partial class _CLASS_ : _BASE_ public override void _PhysicsProcess(float delta) { - Vector3 motionVelocity = MotionVelocity; + Vector3 velocity = Velocity; // Add the gravity. if (!IsOnFloor()) - motionVelocity.y -= gravity * delta; + velocity.y -= gravity * delta; // Handle Jump. if (Input.IsActionJustPressed("ui_accept") && IsOnFloor()) - motionVelocity.y = JumpVelocity; + velocity.y = JumpVelocity; // Get the input direction and handle the movement/deceleration. // As good practice, you should replace UI actions with custom gameplay actions. @@ -29,16 +29,16 @@ public partial class _CLASS_ : _BASE_ Vector3 direction = Transform.basis.Xform(new Vector3(inputDir.x, 0, inputDir.y)).Normalized(); if (direction != Vector3.Zero) { - motionVelocity.x = direction.x * Speed; - motionVelocity.z = direction.z * Speed; + velocity.x = direction.x * Speed; + velocity.z = direction.z * Speed; } else { - motionVelocity.x = Mathf.MoveToward(MotionVelocity.x, 0, Speed); - motionVelocity.z = Mathf.MoveToward(MotionVelocity.z, 0, Speed); + velocity.x = Mathf.MoveToward(Velocity.x, 0, Speed); + velocity.z = Mathf.MoveToward(Velocity.z, 0, Speed); } - MotionVelocity = motionVelocity; + Velocity = velocity; MoveAndSlide(); } } diff --git a/modules/navigation/nav_utils.h b/modules/navigation/nav_utils.h index 30930ed6ae..0c02885b10 100644 --- a/modules/navigation/nav_utils.h +++ b/modules/navigation/nav_utils.h @@ -32,6 +32,7 @@ #define NAV_UTILS_H #include "core/math/vector3.h" +#include "core/templates/vector.h" #include <vector> diff --git a/modules/navigation/navigation_mesh_editor_plugin.cpp b/modules/navigation/navigation_mesh_editor_plugin.cpp index 04eca5fb0b..511490ba07 100644 --- a/modules/navigation/navigation_mesh_editor_plugin.cpp +++ b/modules/navigation/navigation_mesh_editor_plugin.cpp @@ -46,10 +46,12 @@ void NavigationMeshEditor::_node_removed(Node *p_node) { } } -void NavigationMeshEditor::_notification(int p_option) { - if (p_option == NOTIFICATION_ENTER_TREE) { - button_bake->set_icon(get_theme_icon(SNAME("Bake"), SNAME("EditorIcons"))); - button_reset->set_icon(get_theme_icon(SNAME("Reload"), SNAME("EditorIcons"))); +void NavigationMeshEditor::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + button_bake->set_icon(get_theme_icon(SNAME("Bake"), SNAME("EditorIcons"))); + button_reset->set_icon(get_theme_icon(SNAME("Reload"), SNAME("EditorIcons"))); + } break; } } diff --git a/modules/navigation/navigation_mesh_editor_plugin.h b/modules/navigation/navigation_mesh_editor_plugin.h index 0e4175eca0..d581b453b3 100644 --- a/modules/navigation/navigation_mesh_editor_plugin.h +++ b/modules/navigation/navigation_mesh_editor_plugin.h @@ -57,7 +57,7 @@ class NavigationMeshEditor : public Control { protected: void _node_removed(Node *p_node); static void _bind_methods(); - void _notification(int p_option); + void _notification(int p_what); public: void edit(NavigationRegion3D *p_nav_region); diff --git a/modules/ogg/ogg_packet_sequence.cpp b/modules/ogg/ogg_packet_sequence.cpp index 65058f088e..da52ecfdd5 100644 --- a/modules/ogg/ogg_packet_sequence.cpp +++ b/modules/ogg/ogg_packet_sequence.cpp @@ -162,6 +162,7 @@ bool OGGPacketSequencePlayback::next_ogg_packet(ogg_packet **p_packet) const { } uint32_t OGGPacketSequencePlayback::seek_page_internal(int64_t granule, uint32_t after_page_inclusive, uint32_t before_page_inclusive) { + // FIXME: This function needs better corner case handling. if (before_page_inclusive == after_page_inclusive) { return before_page_inclusive; } @@ -169,7 +170,8 @@ uint32_t OGGPacketSequencePlayback::seek_page_internal(int64_t granule, uint32_t // Complicating the bisection search algorithm, the middle page might not have a packet that ends on it, // which means it might not have a correct granule position. Find a nearby page that does have a packet ending on it. uint32_t bisection_page = -1; - for (uint32_t test_page = actual_middle_page; test_page <= before_page_inclusive; test_page++) { + // Don't include before_page_inclusive because that always succeeds and will cause infinite recursion later. + for (uint32_t test_page = actual_middle_page; test_page < before_page_inclusive; test_page++) { if (ogg_packet_sequence->page_data[test_page].size() > 0) { bisection_page = test_page; break; diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub new file mode 100644 index 0000000000..37a8f3909a --- /dev/null +++ b/modules/openxr/SCsub @@ -0,0 +1,87 @@ +#!/usr/bin/env python + +Import("env") +Import("env_modules") + +env_openxr = env_modules.Clone() + +################################################# +# Add in our Khronos OpenXR loader + +thirdparty_obj = [] +thirdparty_dir = "#thirdparty/openxr" + +env_openxr.Prepend( + CPPPATH=[ + thirdparty_dir, + thirdparty_dir + "/include", + thirdparty_dir + "/src", + thirdparty_dir + "/src/common", + thirdparty_dir + "/src/external/jsoncpp/include", + thirdparty_dir + "/src/loader", + ] +) + +# may need to check and set: +# - XR_USE_TIMESPEC + +env_thirdparty = env_openxr.Clone() +env_thirdparty.disable_warnings() +env_thirdparty.AppendUnique(CPPDEFINES=["DISABLE_STD_FILESYSTEM"]) + +if env["platform"] == "android": + # may need to set OPENXR_ANDROID_VERSION_SUFFIX + env_thirdparty.AppendUnique(CPPDEFINES=["XR_OS_ANDROID", "XR_USE_PLATFORM_ANDROID"]) + + # may need to include java parts of the openxr loader +elif env["platform"] == "linuxbsd": + env_thirdparty.AppendUnique(CPPDEFINES=["XR_OS_LINUX", "XR_USE_PLATFORM_XLIB"]) + # FIXME: Review what needs to be set for Android and macOS. + env_thirdparty.AppendUnique(CPPDEFINES=["HAVE_SECURE_GETENV"]) +elif env["platform"] == "windows": + env_thirdparty.AppendUnique(CPPDEFINES=["XR_OS_WINDOWS", "NOMINMAX", "XR_USE_PLATFORM_WIN32"]) + +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/xr_generated_dispatch_table.c") + +# add in common files (hope these don't clash with us) +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/common/filesystem_utils.cpp") +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/common/object_info.cpp") + +# add in external jsoncpp dependency +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/external/jsoncpp/src/lib_json/json_reader.cpp") +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/external/jsoncpp/src/lib_json/json_value.cpp") +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/external/jsoncpp/src/lib_json/json_writer.cpp") + +# add in load +if env["platform"] == "android": + env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/android_utilities.cpp") + +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/api_layer_interface.cpp") +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/loader_core.cpp") +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/loader_instance.cpp") +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/loader_logger_recorders.cpp") +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/loader_logger.cpp") +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/manifest_file.cpp") +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/runtime_interface.cpp") +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/xr_generated_loader.cpp") + +env.modules_sources += thirdparty_obj + +################################################# +# And include our module source + +module_obj = [] + +env_openxr.add_source_files(module_obj, "*.cpp") +env_openxr.add_source_files(module_obj, "action_map/*.cpp") + +# We're a little more targetted with our extensions +if env["platform"] == "android": + env_openxr.add_source_files(module_obj, "extensions/openxr_android_extension.cpp") +if env["vulkan"]: + env_openxr.add_source_files(module_obj, "extensions/openxr_vulkan_extension.cpp") + +env.modules_sources += module_obj + +# Needed to force rebuilding the module files when the thirdparty library is updated. +env.Depends(module_obj, thirdparty_obj) diff --git a/modules/openxr/action_map/openxr_action.cpp b/modules/openxr/action_map/openxr_action.cpp new file mode 100644 index 0000000000..59ee3f4292 --- /dev/null +++ b/modules/openxr/action_map/openxr_action.cpp @@ -0,0 +1,91 @@ +/*************************************************************************/ +/* openxr_action.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "openxr_action.h" + +void OpenXRAction::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_localized_name", "localized_name"), &OpenXRAction::set_localized_name); + ClassDB::bind_method(D_METHOD("get_localized_name"), &OpenXRAction::get_localized_name); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "localized_name"), "set_localized_name", "get_localized_name"); + + ClassDB::bind_method(D_METHOD("set_action_type", "action_type"), &OpenXRAction::set_action_type); + ClassDB::bind_method(D_METHOD("get_action_type"), &OpenXRAction::get_action_type); + ADD_PROPERTY(PropertyInfo(Variant::INT, "action_type", PROPERTY_HINT_ENUM, "bool,float,vector2,pose"), "set_action_type", "get_action_type"); + + ClassDB::bind_method(D_METHOD("set_toplevel_paths", "toplevel_paths"), &OpenXRAction::set_toplevel_paths); + ClassDB::bind_method(D_METHOD("get_toplevel_paths"), &OpenXRAction::get_toplevel_paths); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "toplevel_paths", PROPERTY_HINT_ARRAY_TYPE, "STRING"), "set_toplevel_paths", "get_toplevel_paths"); + + BIND_ENUM_CONSTANT(OPENXR_ACTION_BOOL); + BIND_ENUM_CONSTANT(OPENXR_ACTION_FLOAT); + BIND_ENUM_CONSTANT(OPENXR_ACTION_VECTOR2); + BIND_ENUM_CONSTANT(OPENXR_ACTION_POSE); +} + +Ref<OpenXRAction> OpenXRAction::new_action(const char *p_name, const char *p_localized_name, const ActionType p_action_type, const char *p_toplevel_paths) { + // This is a helper function to help build our default action sets + + Ref<OpenXRAction> action; + action.instantiate(); + action->set_name(String(p_name)); + action->set_localized_name(String(p_localized_name)); + action->set_action_type(p_action_type); + action->parse_toplevel_paths(String(p_toplevel_paths)); + + return action; +} + +void OpenXRAction::set_localized_name(const String p_localized_name) { + localized_name = p_localized_name; +} + +String OpenXRAction::get_localized_name() const { + return localized_name; +} + +void OpenXRAction::set_action_type(const OpenXRAction::ActionType p_action_type) { + action_type = p_action_type; +} + +OpenXRAction::ActionType OpenXRAction::get_action_type() const { + return action_type; +} + +void OpenXRAction::set_toplevel_paths(const PackedStringArray p_toplevel_paths) { + toplevel_paths = p_toplevel_paths; +} + +PackedStringArray OpenXRAction::get_toplevel_paths() const { + return toplevel_paths; +} + +void OpenXRAction::parse_toplevel_paths(const String p_toplevel_paths) { + toplevel_paths = p_toplevel_paths.split(",", false); +} diff --git a/modules/openxr/action_map/openxr_action.h b/modules/openxr/action_map/openxr_action.h new file mode 100644 index 0000000000..e2cfe79e64 --- /dev/null +++ b/modules/openxr/action_map/openxr_action.h @@ -0,0 +1,74 @@ +/*************************************************************************/ +/* openxr_action.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef OPENXR_ACTION_H +#define OPENXR_ACTION_H + +#include "core/io/resource.h" + +class OpenXRAction : public Resource { + GDCLASS(OpenXRAction, Resource); + +public: + enum ActionType { + OPENXR_ACTION_BOOL, + OPENXR_ACTION_FLOAT, + OPENXR_ACTION_VECTOR2, + OPENXR_ACTION_POSE, + OPENXR_ACTION_HAPTIC, + }; + +private: + String localized_name; + ActionType action_type = OPENXR_ACTION_FLOAT; + + PackedStringArray toplevel_paths; + +protected: + static void _bind_methods(); + +public: + static Ref<OpenXRAction> new_action(const char *p_name, const char *p_localized_name, const ActionType p_action_type, const char *p_toplevel_paths); + + void set_localized_name(const String p_localized_name); + String get_localized_name() const; + + void set_action_type(const ActionType p_action_type); + ActionType get_action_type() const; + + void set_toplevel_paths(const PackedStringArray p_toplevel_paths); + PackedStringArray get_toplevel_paths() const; + + void parse_toplevel_paths(const String p_toplevel_paths); +}; + +VARIANT_ENUM_CAST(OpenXRAction::ActionType); + +#endif // !OPENXR_ACTION_H diff --git a/modules/openxr/action_map/openxr_action_map.cpp b/modules/openxr/action_map/openxr_action_map.cpp new file mode 100644 index 0000000000..5391f9569a --- /dev/null +++ b/modules/openxr/action_map/openxr_action_map.cpp @@ -0,0 +1,261 @@ +/*************************************************************************/ +/* openxr_action_map.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "openxr_action_map.h" + +void OpenXRActionMap::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_action_sets", "action_sets"), &OpenXRActionMap::set_action_sets); + ClassDB::bind_method(D_METHOD("get_action_sets"), &OpenXRActionMap::get_action_sets); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "action_sets", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRActionSet", PROPERTY_USAGE_NO_EDITOR), "set_action_sets", "get_action_sets"); + + ClassDB::bind_method(D_METHOD("add_action_set", "action_set"), &OpenXRActionMap::add_action_set); + ClassDB::bind_method(D_METHOD("remove_action_set", "action_set"), &OpenXRActionMap::remove_action_set); + + ClassDB::bind_method(D_METHOD("set_interaction_profiles", "interaction_profiles"), &OpenXRActionMap::set_interaction_profiles); + ClassDB::bind_method(D_METHOD("get_interaction_profiles"), &OpenXRActionMap::get_interaction_profiles); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "interaction_profiles", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRInteractionProfile", PROPERTY_USAGE_NO_EDITOR), "set_interaction_profiles", "get_interaction_profiles"); + + ClassDB::bind_method(D_METHOD("add_interaction_profile", "interaction_profile"), &OpenXRActionMap::add_interaction_profile); + ClassDB::bind_method(D_METHOD("remove_interaction_profile", "interaction_profile"), &OpenXRActionMap::remove_interaction_profile); + + ClassDB::bind_method(D_METHOD("create_default_action_sets"), &OpenXRActionMap::create_default_action_sets); +} + +void OpenXRActionMap::set_action_sets(Array p_action_sets) { + action_sets = p_action_sets; +} + +Array OpenXRActionMap::get_action_sets() const { + return action_sets; +} + +void OpenXRActionMap::add_action_set(Ref<OpenXRActionSet> p_action_set) { + ERR_FAIL_COND(p_action_set.is_null()); + + if (action_sets.find(p_action_set) == -1) { + action_sets.push_back(p_action_set); + } +} + +void OpenXRActionMap::remove_action_set(Ref<OpenXRActionSet> p_action_set) { + int idx = action_sets.find(p_action_set); + if (idx != -1) { + action_sets.remove_at(idx); + } +} + +void OpenXRActionMap::set_interaction_profiles(Array p_interaction_profiles) { + interaction_profiles = p_interaction_profiles; +} + +Array OpenXRActionMap::get_interaction_profiles() const { + return interaction_profiles; +} + +void OpenXRActionMap::add_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile) { + ERR_FAIL_COND(p_interaction_profile.is_null()); + + if (interaction_profiles.find(p_interaction_profile) == -1) { + interaction_profiles.push_back(p_interaction_profile); + } +} + +void OpenXRActionMap::remove_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile) { + int idx = interaction_profiles.find(p_interaction_profile); + if (idx != -1) { + interaction_profiles.remove_at(idx); + } +} + +void OpenXRActionMap::create_default_action_sets() { + // Note, if you make changes here make sure to delete your default_action_map.tres file of it will load an old version. + + // Create our Godot action set + Ref<OpenXRActionSet> action_set = OpenXRActionSet::new_action_set("godot", "Godot action set"); + add_action_set(action_set); + + // Create our actions + Ref<OpenXRAction> trigger = action_set->add_new_action("trigger", "Trigger", OpenXRAction::OPENXR_ACTION_FLOAT, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> trigger_click = action_set->add_new_action("trigger_click", "Trigger click", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> trigger_touch = action_set->add_new_action("trigger_touch", "Trigger touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> grip = action_set->add_new_action("grip", "Grip", OpenXRAction::OPENXR_ACTION_FLOAT, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> grip_click = action_set->add_new_action("grip_click", "Grip click", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> grip_touch = action_set->add_new_action("grip_touch", "Grip touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> primary = action_set->add_new_action("primary", "Primary joystick/thumbstick/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> primary_click = action_set->add_new_action("primary_click", "Primary joystick/thumbstick/trackpad click", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> primary_touch = action_set->add_new_action("primary_touch", "Primary joystick/thumbstick/trackpad touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> secondary = action_set->add_new_action("secondary", "Secondary joystick/thumbstick/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> secondary_click = action_set->add_new_action("secondary_click", "Secondary joystick/thumbstick/trackpad click", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> secondary_touch = action_set->add_new_action("secondary_touch", "Secondary joystick/thumbstick/trackpad touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> menu_button = action_set->add_new_action("menu_button", "Menu button", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> select_button = action_set->add_new_action("select_button", "Select button", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> ax_button = action_set->add_new_action("ax_button", "A/X button", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> ax_touch = action_set->add_new_action("ax_touch", "A/X touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> by_button = action_set->add_new_action("by_button", "B/Y button", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> by_touch = action_set->add_new_action("by_touch", "B/Y touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> default_pose = action_set->add_new_action("default_pose", "Default pose", OpenXRAction::OPENXR_ACTION_POSE, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> aim_pose = action_set->add_new_action("aim_pose", "Aim pose", OpenXRAction::OPENXR_ACTION_POSE, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> grip_pose = action_set->add_new_action("grip_pose", "Grip pose", OpenXRAction::OPENXR_ACTION_POSE, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> haptic = action_set->add_new_action("haptic", "Haptic", OpenXRAction::OPENXR_ACTION_HAPTIC, "/user/hand/left,/user/hand/right"); + + // Create our interaction profiles + Ref<OpenXRInteractionProfile> profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/khr/simple_controller"); + profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click"); + profile->add_new_binding(select_button, "/user/hand/left/input/select/click,/user/hand/right/input/select/click"); + // generic has no support for triggers, grip, A/B buttons, nor joystick/trackpad inputs + profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); + add_interaction_profile(profile); + + // Create our Vive controller profile + profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_controller"); + profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click"); + profile->add_new_binding(select_button, "/user/hand/left/input/system/click,/user/hand/right/input/system/click"); + // wmr controller has no a/b/x/y buttons + profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click"); + profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); // OpenXR will convert bool to float + profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); + // primary on our vive controller is our trackpad + profile->add_new_binding(primary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad"); + profile->add_new_binding(primary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click"); + profile->add_new_binding(primary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch"); + // vive controllers have no secondary input + profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); + add_interaction_profile(profile); + + // Create our WMR controller profile + profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/microsoft/motion_controller"); + profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + // wmr controllers have no select button we can use + profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click"); + // wmr controller has no a/b/x/y buttons + profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); // OpenXR will conver float to bool + profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); // OpenXR will convert bool to float + profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); + // primary on our wmr controller is our thumbstick, no touch + profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); + profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); + // secondary on our wmr controller is our trackpad + profile->add_new_binding(secondary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad"); + profile->add_new_binding(secondary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click"); + profile->add_new_binding(secondary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch"); + profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); + add_interaction_profile(profile); + + // Create our HP MR controller profile + profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/hp/mixed_reality_controller"); + profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + // hpmr controllers have no select button we can use + profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click"); + // hpmr controllers only register click, not touch, on our a/b/x/y buttons + profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand + profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand + profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); + profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); + // primary on our hpmr controller is our thumbstick + profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); + profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); + // No secondary on our hpmr controller + profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); + add_interaction_profile(profile); + + // Create our Meta touch controller profile + profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/oculus/touch_controller"); + profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + // touch controllers have no select button we can use + profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/system/click"); // right hand system click may not be available + profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand + profile->add_new_binding(ax_touch, "/user/hand/left/input/x/touch,/user/hand/right/input/a/touch"); + profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand + profile->add_new_binding(by_touch, "/user/hand/left/input/y/touch,/user/hand/right/input/b/touch"); + profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); // should be converted to boolean + profile->add_new_binding(trigger_touch, "/user/hand/left/input/trigger/touch,/user/hand/right/input/trigger/touch"); + profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); // should be converted to boolean + profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); + // primary on our touch controller is our thumbstick + profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); + profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); + profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch"); + // touch controller has no secondary input + profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); + add_interaction_profile(profile); + + // Create our Valve index controller profile + profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/valve/index_controller"); + profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + // index controllers have no select button we can use + profile->add_new_binding(menu_button, "/user/hand/left/input/system/click,/user/hand/right/input/system/click"); + profile->add_new_binding(ax_button, "/user/hand/left/input/a/click,/user/hand/right/input/a/click"); // a on both controllers + profile->add_new_binding(ax_touch, "/user/hand/left/input/a/touch,/user/hand/right/input/a/touch"); + profile->add_new_binding(by_button, "/user/hand/left/input/b/click,/user/hand/right/input/b/click"); // b on both controllers + profile->add_new_binding(by_touch, "/user/hand/left/input/b/touch,/user/hand/right/input/b/touch"); + profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click"); + profile->add_new_binding(trigger_touch, "/user/hand/left/input/trigger/touch,/user/hand/right/input/trigger/touch"); + profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); + profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); // this should do a float to bool conversion + // primary on our index controller is our thumbstick + profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); + profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); + profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch"); + // secondary on our index controller is our trackpad + profile->add_new_binding(secondary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad"); + profile->add_new_binding(secondary_click, "/user/hand/left/input/trackpad/force,/user/hand/right/input/trackpad/force"); // not sure if this will work but doesn't seem to support click... + profile->add_new_binding(secondary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch"); + profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); + add_interaction_profile(profile); +} + +void OpenXRActionMap::create_editor_action_sets() { + // TODO implement +} + +OpenXRActionMap::~OpenXRActionMap() { + action_sets.clear(); + interaction_profiles.clear(); +} diff --git a/modules/openxr/action_map/openxr_action_map.h b/modules/openxr/action_map/openxr_action_map.h new file mode 100644 index 0000000000..866e170468 --- /dev/null +++ b/modules/openxr/action_map/openxr_action_map.h @@ -0,0 +1,68 @@ +/*************************************************************************/ +/* openxr_action_map.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef OPENXR_ACTION_SETS_H +#define OPENXR_ACTION_SETS_H + +#include "core/io/resource.h" + +#include "openxr_action_set.h" +#include "openxr_interaction_profile.h" + +class OpenXRActionMap : public Resource { + GDCLASS(OpenXRActionMap, Resource); + +private: + Array action_sets; + Array interaction_profiles; + +protected: + static void _bind_methods(); + +public: + void set_action_sets(Array p_action_sets); + Array get_action_sets() const; + + void add_action_set(Ref<OpenXRActionSet> p_action_set); + void remove_action_set(Ref<OpenXRActionSet> p_action_set); + + void set_interaction_profiles(Array p_interaction_profiles); + Array get_interaction_profiles() const; + + void add_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile); + void remove_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile); + + void create_default_action_sets(); + void create_editor_action_sets(); + + ~OpenXRActionMap(); +}; + +#endif // !OPENXR_ACTION_SETS_H diff --git a/modules/openxr/action_map/openxr_action_set.cpp b/modules/openxr/action_map/openxr_action_set.cpp new file mode 100644 index 0000000000..465a709b60 --- /dev/null +++ b/modules/openxr/action_map/openxr_action_set.cpp @@ -0,0 +1,111 @@ +/*************************************************************************/ +/* openxr_action_set.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "openxr_action_set.h" + +void OpenXRActionSet::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_localized_name", "localized_name"), &OpenXRActionSet::set_localized_name); + ClassDB::bind_method(D_METHOD("get_localized_name"), &OpenXRActionSet::get_localized_name); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "localized_name"), "set_localized_name", "get_localized_name"); + + ClassDB::bind_method(D_METHOD("set_priority", "priority"), &OpenXRActionSet::set_priority); + ClassDB::bind_method(D_METHOD("get_priority"), &OpenXRActionSet::get_priority); + ADD_PROPERTY(PropertyInfo(Variant::INT, "priority"), "set_priority", "get_priority"); + + ClassDB::bind_method(D_METHOD("set_actions", "actions"), &OpenXRActionSet::set_actions); + ClassDB::bind_method(D_METHOD("get_actions"), &OpenXRActionSet::get_actions); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "actions", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRAction", PROPERTY_USAGE_NO_EDITOR), "set_actions", "get_actions"); + + ClassDB::bind_method(D_METHOD("add_action", "action"), &OpenXRActionSet::add_action); + ClassDB::bind_method(D_METHOD("remove_action", "action"), &OpenXRActionSet::remove_action); +} + +Ref<OpenXRActionSet> OpenXRActionSet::new_action_set(const char *p_name, const char *p_localized_name, const int p_priority) { + // This is a helper function to help build our default action sets + + Ref<OpenXRActionSet> action_set; + action_set.instantiate(); + action_set->set_name(String(p_name)); + action_set->set_localized_name(p_localized_name); + action_set->set_priority(p_priority); + + return action_set; +} + +void OpenXRActionSet::set_localized_name(const String p_localized_name) { + localized_name = p_localized_name; +} + +String OpenXRActionSet::get_localized_name() const { + return localized_name; +} + +void OpenXRActionSet::set_priority(const int p_priority) { + priority = p_priority; +} + +int OpenXRActionSet::get_priority() const { + return priority; +} + +void OpenXRActionSet::set_actions(Array p_actions) { + actions = p_actions; +} + +Array OpenXRActionSet::get_actions() const { + return actions; +} + +void OpenXRActionSet::add_action(Ref<OpenXRAction> p_action) { + ERR_FAIL_COND(p_action.is_null()); + + if (actions.find(p_action) == -1) { + actions.push_back(p_action); + } +} + +void OpenXRActionSet::remove_action(Ref<OpenXRAction> p_action) { + int idx = actions.find(p_action); + if (idx != -1) { + actions.remove_at(idx); + } +} + +Ref<OpenXRAction> OpenXRActionSet::add_new_action(const char *p_name, const char *p_localized_name, const OpenXRAction::ActionType p_action_type, const char *p_toplevel_paths) { + // This is a helper function to help build our default action sets + + Ref<OpenXRAction> new_action = OpenXRAction::new_action(p_name, p_localized_name, p_action_type, p_toplevel_paths); + add_action(new_action); + return new_action; +} + +OpenXRActionSet::~OpenXRActionSet() { + actions.clear(); +} diff --git a/modules/openxr/action_map/openxr_action_set.h b/modules/openxr/action_map/openxr_action_set.h new file mode 100644 index 0000000000..012a088b1c --- /dev/null +++ b/modules/openxr/action_map/openxr_action_set.h @@ -0,0 +1,70 @@ +/*************************************************************************/ +/* openxr_action_set.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef OPENXR_ACTION_SET_H +#define OPENXR_ACTION_SET_H + +#include "core/io/resource.h" + +#include "openxr_action.h" + +class OpenXRActionSet : public Resource { + GDCLASS(OpenXRActionSet, Resource); + +private: + String localized_name; + int priority = 0; + + Array actions; + +protected: + static void _bind_methods(); + +public: + static Ref<OpenXRActionSet> new_action_set(const char *p_name, const char *p_localized_name, const int p_priority = 0); + + void set_localized_name(const String p_localized_name); + String get_localized_name() const; + + void set_priority(const int p_priority); + int get_priority() const; + + void set_actions(Array p_actions); + Array get_actions() const; + + void add_action(Ref<OpenXRAction> p_action); + void remove_action(Ref<OpenXRAction> p_action); + + Ref<OpenXRAction> add_new_action(const char *p_name, const char *p_localized_name, const OpenXRAction::ActionType p_action_type, const char *p_toplevel_paths); + + ~OpenXRActionSet(); +}; + +#endif // !OPENXR_ACTION_SET_H diff --git a/modules/openxr/action_map/openxr_interaction_profile.cpp b/modules/openxr/action_map/openxr_interaction_profile.cpp new file mode 100644 index 0000000000..bc33814f17 --- /dev/null +++ b/modules/openxr/action_map/openxr_interaction_profile.cpp @@ -0,0 +1,136 @@ +/*************************************************************************/ +/* openxr_interaction_profile.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "openxr_interaction_profile.h" + +void OpenXRIPBinding::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_action", "action"), &OpenXRIPBinding::set_action); + ClassDB::bind_method(D_METHOD("get_action"), &OpenXRIPBinding::get_action); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "action", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRAction"), "set_action", "get_action"); + + ClassDB::bind_method(D_METHOD("set_paths", "paths"), &OpenXRIPBinding::set_paths); + ClassDB::bind_method(D_METHOD("get_paths"), &OpenXRIPBinding::get_paths); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "paths", PROPERTY_HINT_ARRAY_TYPE, "STRING"), "set_paths", "get_paths"); +} + +Ref<OpenXRIPBinding> OpenXRIPBinding::new_binding(const Ref<OpenXRAction> p_action, const char *p_paths) { + // This is a helper function to help build our default action sets + + Ref<OpenXRIPBinding> binding; + binding.instantiate(); + binding->set_action(p_action); + binding->parse_paths(String(p_paths)); + + return binding; +} + +void OpenXRIPBinding::set_action(const Ref<OpenXRAction> p_action) { + action = p_action; +} + +Ref<OpenXRAction> OpenXRIPBinding::get_action() const { + return action; +} + +void OpenXRIPBinding::set_paths(const PackedStringArray p_paths) { + paths = p_paths; +} + +PackedStringArray OpenXRIPBinding::get_paths() const { + return paths; +} + +void OpenXRIPBinding::parse_paths(const String p_paths) { + paths = p_paths.split(",", false); +} + +OpenXRIPBinding::~OpenXRIPBinding() { + action.unref(); +} + +void OpenXRInteractionProfile::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_interaction_profile_path", "interaction_profile_path"), &OpenXRInteractionProfile::set_interaction_profile_path); + ClassDB::bind_method(D_METHOD("get_interaction_profile_path"), &OpenXRInteractionProfile::get_interaction_profile_path); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "interaction_profile_path"), "set_interaction_profile_path", "get_interaction_profile_path"); + + ClassDB::bind_method(D_METHOD("set_bindings", "bindings"), &OpenXRInteractionProfile::set_bindings); + ClassDB::bind_method(D_METHOD("get_bindings"), &OpenXRInteractionProfile::get_bindings); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "bindings", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRIPBinding", PROPERTY_USAGE_NO_EDITOR), "set_bindings", "get_bindings"); +} + +Ref<OpenXRInteractionProfile> OpenXRInteractionProfile::new_profile(const char *p_input_profile_path) { + Ref<OpenXRInteractionProfile> profile; + profile.instantiate(); + profile->set_interaction_profile_path(String(p_input_profile_path)); + + return profile; +} + +void OpenXRInteractionProfile::set_interaction_profile_path(const String p_input_profile_path) { + interaction_profile_path = p_input_profile_path; +} + +String OpenXRInteractionProfile::get_interaction_profile_path() const { + return interaction_profile_path; +} + +void OpenXRInteractionProfile::set_bindings(Array p_bindings) { + bindings = p_bindings; +} + +Array OpenXRInteractionProfile::get_bindings() const { + return bindings; +} + +void OpenXRInteractionProfile::add_binding(Ref<OpenXRIPBinding> p_binding) { + ERR_FAIL_COND(p_binding.is_null()); + + if (bindings.find(p_binding) == -1) { + bindings.push_back(p_binding); + } +} + +void OpenXRInteractionProfile::remove_binding(Ref<OpenXRIPBinding> p_binding) { + int idx = bindings.find(p_binding); + if (idx != -1) { + bindings.remove_at(idx); + } +} + +void OpenXRInteractionProfile::add_new_binding(const Ref<OpenXRAction> p_action, const char *p_paths) { + // This is a helper function to help build our default action sets + + Ref<OpenXRIPBinding> binding = OpenXRIPBinding::new_binding(p_action, p_paths); + add_binding(binding); +} + +OpenXRInteractionProfile::~OpenXRInteractionProfile() { + bindings.clear(); +} diff --git a/modules/openxr/action_map/openxr_interaction_profile.h b/modules/openxr/action_map/openxr_interaction_profile.h new file mode 100644 index 0000000000..abbc429e7d --- /dev/null +++ b/modules/openxr/action_map/openxr_interaction_profile.h @@ -0,0 +1,89 @@ +/*************************************************************************/ +/* openxr_interaction_profile.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef OPENXR_INTERACTION_PROFILE_H +#define OPENXR_INTERACTION_PROFILE_H + +#include "core/io/resource.h" + +#include "openxr_action.h" + +class OpenXRIPBinding : public Resource { + GDCLASS(OpenXRIPBinding, Resource); + +private: + Ref<OpenXRAction> action; + PackedStringArray paths; + +protected: + static void _bind_methods(); + +public: + static Ref<OpenXRIPBinding> new_binding(const Ref<OpenXRAction> p_action, const char *p_paths); + + void set_action(const Ref<OpenXRAction> p_action); + Ref<OpenXRAction> get_action() const; + + void set_paths(const PackedStringArray p_paths); + PackedStringArray get_paths() const; + + void parse_paths(const String p_paths); + + ~OpenXRIPBinding(); +}; + +class OpenXRInteractionProfile : public Resource { + GDCLASS(OpenXRInteractionProfile, Resource); + +private: + String interaction_profile_path; + Array bindings; + +protected: + static void _bind_methods(); + +public: + static Ref<OpenXRInteractionProfile> new_profile(const char *p_input_profile_path); + + void set_interaction_profile_path(const String p_input_profile_path); + String get_interaction_profile_path() const; + + void set_bindings(Array p_bindings); + Array get_bindings() const; + + void add_binding(Ref<OpenXRIPBinding> p_binding); + void remove_binding(Ref<OpenXRIPBinding> p_binding); + + void add_new_binding(const Ref<OpenXRAction> p_action, const char *p_paths); + + ~OpenXRInteractionProfile(); +}; + +#endif // !OPENXR_INTERACTION_PROFILE_H diff --git a/modules/openxr/config.py b/modules/openxr/config.py new file mode 100644 index 0000000000..f91cb1359f --- /dev/null +++ b/modules/openxr/config.py @@ -0,0 +1,27 @@ +def can_build(env, platform): + if ( + platform == "linuxbsd" or platform == "windows" + ): # or platform == "android" -- temporarily disabled android support + return env["openxr"] + else: + # not supported on these platforms + return False + + +def configure(env): + pass + + +def get_doc_classes(): + return [ + "OpenXRInterface", + "OpenXRAction", + "OpenXRActionSet", + "OpenXRActionMap", + "OpenXRInteractionProfile", + "OpenXRIPBinding", + ] + + +def get_doc_path(): + return "doc_classes" diff --git a/modules/openxr/doc_classes/OpenXRAction.xml b/modules/openxr/doc_classes/OpenXRAction.xml new file mode 100644 index 0000000000..6ff8c1ad26 --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRAction.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="OpenXRAction" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> + <brief_description> + An OpenXR action. + </brief_description> + <description> + This resource defines an OpenXR action. Actions can be used both for inputs (buttons/joystick/trigger/etc) and outputs (haptics). + OpenXR performs automatic conversion between action type and input type whenever possible. An analogue trigger bound to a boolean action will thus return [code]false[/core] if the trigger is depressed and [code]true[/code] if pressed fully. + Actions are not directly bound to specific devices, instead OpenXR recognises a limited number of top level paths that identify devices by usage. We can restrict which devices an action can be bound to by these top level paths. For instance an action that should only be used for hand held controllers can have the top level paths "/user/hand/left" and "/user/hand/right" associated with them. See the [url=https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#semantic-path-reserved]reserved path section in the OpenXR specification[/url] for more info on the top level paths. + Note that the name of the resource is used to register the action with. + </description> + <tutorials> + </tutorials> + <members> + <member name="action_type" type="int" setter="set_action_type" getter="get_action_type" enum="OpenXRAction.ActionType" default="1"> + The type of action. + </member> + <member name="localized_name" type="String" setter="set_localized_name" getter="get_localized_name" default=""""> + The localised description of this action. + </member> + <member name="toplevel_paths" type="PackedStringArray" setter="set_toplevel_paths" getter="get_toplevel_paths" default="PackedStringArray()"> + A collections of toplevel paths to which this action can be bound. + </member> + </members> + <constants> + <constant name="OPENXR_ACTION_BOOL" value="0" enum="ActionType"> + This action provides a boolean value. + </constant> + <constant name="OPENXR_ACTION_FLOAT" value="1" enum="ActionType"> + This action provides a float value between [code]0.0[/code] and [code]1.0[/code] for any analogue input such as triggers. + </constant> + <constant name="OPENXR_ACTION_VECTOR2" value="2" enum="ActionType"> + This action provides a vector2 value and can be bound to embedded trackpads and joysticks + </constant> + <constant name="OPENXR_ACTION_POSE" value="3" enum="ActionType"> + </constant> + </constants> +</class> diff --git a/modules/openxr/doc_classes/OpenXRActionMap.xml b/modules/openxr/doc_classes/OpenXRActionMap.xml new file mode 100644 index 0000000000..f1def8aad8 --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRActionMap.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="OpenXRActionMap" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> + <brief_description> + Collection of [OpenXRActionSet] and [OpenXRInteractionProfile] resources for the OpenXR module. + </brief_description> + <description> + OpenXR uses an action system similar to Godots Input map system to bind inputs and outputs on various types of XR controllers to named actions. OpenXR specifies more detail on these inputs and outputs than Godot supports. + Another important distinction is that OpenXR offers no control over these bindings. The bindings we register are suggestions, it is up to the XR runtime to offer users the ability to change these bindings. This allows the XR runtime to fill in the gaps if new hardware becomes available. + The action map therefor needs to be loaded at startup and can't be changed afterwards. This resource is a container for the entire action map. + </description> + <tutorials> + </tutorials> + <methods> + <method name="add_action_set"> + <return type="void" /> + <argument index="0" name="action_set" type="OpenXRActionSet" /> + <description> + Add an action set. + </description> + </method> + <method name="add_interaction_profile"> + <return type="void" /> + <argument index="0" name="interaction_profile" type="OpenXRInteractionProfile" /> + <description> + Add an interaction profile. + </description> + </method> + <method name="create_default_action_sets"> + <return type="void" /> + <description> + Setup this action set with our default actions. + </description> + </method> + <method name="remove_action_set"> + <return type="void" /> + <argument index="0" name="action_set" type="OpenXRActionSet" /> + <description> + Remove an action set. + </description> + </method> + <method name="remove_interaction_profile"> + <return type="void" /> + <argument index="0" name="interaction_profile" type="OpenXRInteractionProfile" /> + <description> + Remove an interaction profile. + </description> + </method> + </methods> + <members> + <member name="action_sets" type="Array" setter="set_action_sets" getter="get_action_sets" default="[]"> + </member> + <member name="interaction_profiles" type="Array" setter="set_interaction_profiles" getter="get_interaction_profiles" default="[]"> + </member> + </members> +</class> diff --git a/modules/openxr/doc_classes/OpenXRActionSet.xml b/modules/openxr/doc_classes/OpenXRActionSet.xml new file mode 100644 index 0000000000..5a87de463e --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRActionSet.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="OpenXRActionSet" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> + <brief_description> + Collection of [OpenXRAction] resources that make up an action set. + </brief_description> + <description> + Action sets in OpenXR define a collection of actions that can be activated in unison. This allows games to easily change between different states that require different inputs or need to reinterpret inputs. For instance we could have an action set that is active when a menu is open, an action set that is active when the player is freely walking around and an action set that is active when the player is controlling a vehicle. + Action sets can contain the same actions, or actions with the same name, if such action sets are active at the same time the action set with the highest priority defines which binding is active. + Note that the name of the resource is used to identify the action set within OpenXR. + </description> + <tutorials> + </tutorials> + <methods> + <method name="add_action"> + <return type="void" /> + <argument index="0" name="action" type="OpenXRAction" /> + <description> + Add an action to this action set. + </description> + </method> + <method name="remove_action"> + <return type="void" /> + <argument index="0" name="action" type="OpenXRAction" /> + <description> + Remove an action from this action set. + </description> + </method> + </methods> + <members> + <member name="actions" type="Array" setter="set_actions" getter="get_actions" default="[]"> + Collection of actions for this action set. + </member> + <member name="localized_name" type="String" setter="set_localized_name" getter="get_localized_name" default=""""> + The localised name of this action set. + </member> + <member name="priority" type="int" setter="set_priority" getter="get_priority" default="0"> + The priority for this action set. + </member> + </members> +</class> diff --git a/modules/openxr/doc_classes/OpenXRIPBinding.xml b/modules/openxr/doc_classes/OpenXRIPBinding.xml new file mode 100644 index 0000000000..3fdcde5eb5 --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRIPBinding.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="OpenXRIPBinding" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> + <brief_description> + Defines a binding between an [OpenXRAction] and an XR input or output. + </brief_description> + <description> + This binding resource binds an OpenXR action to inputs or outputs. As most controllers have left hand and right versions that are handled by the same interaction profile we can specify multiple bindings. For instance an action "Fire" could be bound to both "/user/hand/left/input/trigger" and "/user/hand/right/input/trigger". + </description> + <tutorials> + </tutorials> + <members> + <member name="action" type="OpenXRAction" setter="set_action" getter="get_action"> + Action that is bound to these paths. + </member> + <member name="paths" type="PackedStringArray" setter="set_paths" getter="get_paths" default="PackedStringArray()"> + Paths that define the inputs or outputs bound on the device. + </member> + </members> +</class> diff --git a/modules/openxr/doc_classes/OpenXRInteractionProfile.xml b/modules/openxr/doc_classes/OpenXRInteractionProfile.xml new file mode 100644 index 0000000000..a8629caae4 --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRInteractionProfile.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="OpenXRInteractionProfile" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> + <brief_description> + Suggested bindings object for OpenXR. + </brief_description> + <description> + This object stores suggested bindings for an interaction profile. Interaction profiles define the meta data for a tracked XR device such as an XR controller. + For more information see the [url=https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#semantic-path-interaction-profiles]interaction profiles info in the OpenXR specification[/url]. + </description> + <tutorials> + </tutorials> + <members> + <member name="bindings" type="Array" setter="set_bindings" getter="get_bindings" default="[]"> + Action bindings for this interaction profile. + </member> + <member name="interaction_profile_path" type="String" setter="set_interaction_profile_path" getter="get_interaction_profile_path" default=""""> + The interaction profile path identifying the XR device. + </member> + </members> +</class> diff --git a/modules/openxr/doc_classes/OpenXRInterface.xml b/modules/openxr/doc_classes/OpenXRInterface.xml new file mode 100644 index 0000000000..1160061e04 --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRInterface.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="OpenXRInterface" inherits="XRInterface" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> + <brief_description> + Our OpenXR interface. + </brief_description> + <description> + The OpenXR interface allows Godot to interact with OpenXR runtimes and make it possible to create XR experiences and games. + Due to the needs of OpenXR this interface works slightly different then other plugin based XR interfaces. It needs to be initialised when Godot starts. You need to enable OpenXR, settings for this can be found in your games project settings under the XR heading. You do need to mark a viewport for use with XR in order for Godot to know which render result should be output to the headset. + </description> + <tutorials> + <link title="OpenXR documentation">$DOCS_URL/tutorials/vr/openxr/index.html</link> + </tutorials> +</class> diff --git a/modules/openxr/extensions/openxr_android_extension.cpp b/modules/openxr/extensions/openxr_android_extension.cpp new file mode 100644 index 0000000000..3bd4db169c --- /dev/null +++ b/modules/openxr/extensions/openxr_android_extension.cpp @@ -0,0 +1,71 @@ +/*************************************************************************/ +/* openxr_android_extension.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "openxr_android_extension.h" + +#include <openxr/openxr.h> +#include <openxr/openxr_platform.h> + +OpenXRAndroidExtension *OpenXRAndroidExtension::singleton = nullptr; + +OpenXRAndroidExtension *OpenXRAndroidExtension::get_singleton() { + return singleton; +} + +OpenXRAndroidExtension::OpenXRAndroidExtension(OpenXRAPI *p_openxr_api) : + OpenXRExtensionWrapper(p_openxr_api) { + singleton = this; + + request_extensions[XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME] = nullptr; // must be available + + // Initialize the loader + PFN_xrInitializeLoaderKHR xrInitializeLoaderKHR; + result = xrGetInstanceProcAddr(XR_NULL_HANDLE, "xrInitializeLoaderKHR", (PFN_xrVoidFunction *)(&xrInitializeLoaderKHR)); + ERR_FAIL_COND_MSG(XR_FAILED(result), "Failed to retrieve pointer to xrInitializeLoaderKHR"); + + // TODO fix this code, this is still code from GDNative! + JNIEnv *env = android_api->godot_android_get_env(); + JavaVM *vm; + env->GetJavaVM(&vm); + jobject activity_object = env->NewGlobalRef(android_api->godot_android_get_activity()); + + XrLoaderInitInfoAndroidKHR loader_init_info_android = { + .type = XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR, + .next = nullptr, + .applicationVM = vm, + .applicationContext = activity_object + }; + xrInitializeLoaderKHR((const XrLoaderInitInfoBaseHeaderKHR *)&loader_init_info_android); + ERR_FAIL_COND_MSG(XR_FAILED(result), "Failed to call xrInitializeLoaderKHR"); +} + +OpenXRAndroidExtension::~OpenXRAndroidExtension() { + singleton = nullptr; +} diff --git a/modules/openxr/extensions/openxr_android_extension.h b/modules/openxr/extensions/openxr_android_extension.h new file mode 100644 index 0000000000..e102197a55 --- /dev/null +++ b/modules/openxr/extensions/openxr_android_extension.h @@ -0,0 +1,47 @@ +/*************************************************************************/ +/* openxr_android_extension.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef OPENXR_ANDROID_EXTENSION_H +#define OPENXR_ANDROID_EXTENSION_H + +#include "openxr_extension_wrapper.h" + +class OpenXRAndroidExtension : public OpenXRExtensionWrapper { +public: + static OpenXRAndroidExtension *get_singleton(); + + OpenXRAndroidExtension(OpenXRAPI *p_openxr_api); + virtual ~OpenXRAndroidExtension() override; + +private: + static OpenXRAndroidExtension *singleton; +}; + +#endif // !OPENXR_ANDROID_EXTENSION_H diff --git a/modules/openxr/extensions/openxr_composition_layer_provider.h b/modules/openxr/extensions/openxr_composition_layer_provider.h new file mode 100644 index 0000000000..019dffa2a8 --- /dev/null +++ b/modules/openxr/extensions/openxr_composition_layer_provider.h @@ -0,0 +1,45 @@ +/*************************************************************************/ +/* openxr_composition_layer_provider.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef OPENXR_COMPOSITION_LAYER_PROVIDER_H +#define OPENXR_COMPOSITION_LAYER_PROVIDER_H + +#include <openxr/openxr.h> + +// Interface for OpenXR extensions that provide a composition layer. +class OpenXRCompositionLayerProvider { +public: + // TODO changed to normal method definition for now + // CI complains until we implement this, haven't ported it yet from plugin + // virtual XrCompositionLayerBaseHeader *get_composition_layer() = 0; + XrCompositionLayerBaseHeader *get_composition_layer() { return nullptr; }; +}; + +#endif // OPENXR_COMPOSITION_LAYER_PROVIDER_H diff --git a/modules/openxr/extensions/openxr_extension_wrapper.h b/modules/openxr/extensions/openxr_extension_wrapper.h new file mode 100644 index 0000000000..5242ee6063 --- /dev/null +++ b/modules/openxr/extensions/openxr_extension_wrapper.h @@ -0,0 +1,106 @@ +/*************************************************************************/ +/* openxr_extension_wrapper.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef OPENXR_EXTENSION_WRAPPER_H +#define OPENXR_EXTENSION_WRAPPER_H + +#include "core/error/error_macros.h" +#include "core/math/camera_matrix.h" +#include "core/templates/map.h" +#include "core/templates/rid.h" + +#include "thirdparty/openxr/src/common/xr_linear.h" +#include <openxr/openxr.h> + +class OpenXRAPI; + +class OpenXRExtensionWrapper { +protected: + OpenXRAPI *openxr_api; + + // Store extension we require. + // If bool pointer is a nullptr this means this extension is mandatory and initialisation will fail if it is not available + // If bool pointer is set, value will be set to true or false depending on whether extension is available + Map<const char *, bool *> request_extensions; + +public: + virtual Map<const char *, bool *> get_request_extensions() { + return request_extensions; + } + + // These functions allow an extension to add entries to a struct chain. + // `p_next_pointer` points to the last struct that was created for this chain + // and should be used as the value for the `pNext` pointer in the first struct you add. + // You should return the pointer to the last struct you define as your result. + // If you are not adding any structs, just return `p_next_pointer`. + // See existing extensions for examples of this implementation. + virtual void *set_system_properties_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } + virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } + virtual void *set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } + + virtual void on_instance_created(const XrInstance p_instance) {} + virtual void on_instance_destroyed() {} + virtual void on_session_created(const XrSession p_instance) {} + virtual void on_process() {} + virtual void on_pre_render() {} + virtual void on_session_destroyed() {} + + virtual void on_state_idle() {} + virtual void on_state_ready() {} + virtual void on_state_synchronized() {} + virtual void on_state_visible() {} + virtual void on_state_focused() {} + virtual void on_state_stopping() {} + virtual void on_state_loss_pending() {} + virtual void on_state_exiting() {} + + // Returns true if the event was handled, false otherwise. + virtual bool on_event_polled(const XrEventDataBuffer &event) { + return false; + } + + OpenXRExtensionWrapper(OpenXRAPI *p_openxr_api) { openxr_api = p_openxr_api; }; + virtual ~OpenXRExtensionWrapper() = default; +}; + +class OpenXRGraphicsExtensionWrapper : public OpenXRExtensionWrapper { +public: + virtual void get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) = 0; + virtual String get_swapchain_format_name(int64_t p_swapchain_format) const = 0; + virtual bool get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) = 0; + virtual void cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) = 0; + virtual bool create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, CameraMatrix &r_camera_matrix) = 0; + virtual bool copy_render_target_to_image(RID p_from_render_target, void *p_swapchain_graphics_data, int p_image_index) = 0; + + OpenXRGraphicsExtensionWrapper(OpenXRAPI *p_openxr_api) : + OpenXRExtensionWrapper(p_openxr_api){}; +}; + +#endif // ~OPENXR_EXTENSION_WRAPPER_H diff --git a/modules/openxr/extensions/openxr_vulkan_extension.cpp b/modules/openxr/extensions/openxr_vulkan_extension.cpp new file mode 100644 index 0000000000..ba790500f9 --- /dev/null +++ b/modules/openxr/extensions/openxr_vulkan_extension.cpp @@ -0,0 +1,695 @@ +/*************************************************************************/ +/* openxr_vulkan_extension.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "core/string/print_string.h" + +#include "modules/openxr/extensions/openxr_vulkan_extension.h" +#include "modules/openxr/openxr_api.h" +#include "modules/openxr/openxr_util.h" +#include "servers/rendering/renderer_rd/renderer_storage_rd.h" +#include "servers/rendering/rendering_server_globals.h" +#include "servers/rendering_server.h" + +// need to include Vulkan so we know of type definitions +#define XR_USE_GRAPHICS_API_VULKAN + +#ifdef WINDOWS_ENABLED +// Including windows.h here is absolutely evil, we shouldn't be doing this outside of platform +// however due to the way the openxr headers are put together, we have no choice. +#include <windows.h> +#endif + +// include platform dependent structs +#include <openxr/openxr_platform.h> + +PFN_xrGetVulkanGraphicsRequirements2KHR xrGetVulkanGraphicsRequirements2KHR_ptr = nullptr; +PFN_xrCreateVulkanInstanceKHR xrCreateVulkanInstanceKHR_ptr = nullptr; +PFN_xrGetVulkanGraphicsDevice2KHR xrGetVulkanGraphicsDevice2KHR_ptr = nullptr; +PFN_xrCreateVulkanDeviceKHR xrCreateVulkanDeviceKHR_ptr = nullptr; + +OpenXRVulkanExtension::OpenXRVulkanExtension(OpenXRAPI *p_openxr_api) : + OpenXRGraphicsExtensionWrapper(p_openxr_api) { + VulkanContext::set_vulkan_hooks(this); + + request_extensions[XR_KHR_VULKAN_ENABLE2_EXTENSION_NAME] = nullptr; // must be available + + ERR_FAIL_NULL(openxr_api); +} + +OpenXRVulkanExtension::~OpenXRVulkanExtension() { + VulkanContext::set_vulkan_hooks(nullptr); +} + +void OpenXRVulkanExtension::on_instance_created(const XrInstance p_instance) { + XrResult result; + + ERR_FAIL_NULL(openxr_api); + + // Obtain pointers to functions we're accessing here, they are (not yet) part of core. + result = xrGetInstanceProcAddr(p_instance, "xrGetVulkanGraphicsRequirements2KHR", (PFN_xrVoidFunction *)&xrGetVulkanGraphicsRequirements2KHR_ptr); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to xrGetVulkanGraphicsRequirements2KHR entry point [", openxr_api->get_error_string(result), "]"); + } + + result = xrGetInstanceProcAddr(p_instance, "xrCreateVulkanInstanceKHR", (PFN_xrVoidFunction *)&xrCreateVulkanInstanceKHR_ptr); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to xrCreateVulkanInstanceKHR entry point [", openxr_api->get_error_string(result), "]"); + } + + result = xrGetInstanceProcAddr(p_instance, "xrGetVulkanGraphicsDevice2KHR", (PFN_xrVoidFunction *)&xrGetVulkanGraphicsDevice2KHR_ptr); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to xrGetVulkanGraphicsDevice2KHR entry point [", openxr_api->get_error_string(result), "]"); + } + + result = xrGetInstanceProcAddr(p_instance, "xrCreateVulkanDeviceKHR", (PFN_xrVoidFunction *)&xrCreateVulkanDeviceKHR_ptr); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to xrCreateVulkanDeviceKHR entry point [", openxr_api->get_error_string(result), "]"); + } +} + +XrResult OpenXRVulkanExtension::xrGetVulkanGraphicsRequirements2KHR(XrInstance p_instance, XrSystemId p_system_id, XrGraphicsRequirementsVulkanKHR *p_graphics_requirements) { + ERR_FAIL_NULL_V(xrGetVulkanGraphicsRequirements2KHR_ptr, XR_ERROR_HANDLE_INVALID); + + return (*xrGetVulkanGraphicsRequirements2KHR_ptr)(p_instance, p_system_id, p_graphics_requirements); +} + +bool OpenXRVulkanExtension::check_graphics_api_support(XrVersion p_desired_version) { + ERR_FAIL_NULL_V(openxr_api, false); + + XrGraphicsRequirementsVulkan2KHR vulkan_requirements = { + XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN2_KHR, // type + nullptr, // next + 0, // minApiVersionSupported + 0 // maxApiVersionSupported + }; + + XrResult result = xrGetVulkanGraphicsRequirements2KHR(openxr_api->get_instance(), openxr_api->get_system_id(), &vulkan_requirements); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to get vulkan graphics requirements [", openxr_api->get_error_string(result), "]"); + return false; + } + + // #ifdef DEBUG + print_line("OpenXR: XrGraphicsRequirementsVulkan2KHR:"); + print_line(" - minApiVersionSupported: ", OpenXRUtil::make_xr_version_string(vulkan_requirements.minApiVersionSupported)); + print_line(" - maxApiVersionSupported: ", OpenXRUtil::make_xr_version_string(vulkan_requirements.maxApiVersionSupported)); + // #endif + + if (p_desired_version < vulkan_requirements.minApiVersionSupported) { + print_line("OpenXR: Requested Vulkan version does not meet the minimum version this runtime supports."); + print_line("- desired_version ", OpenXRUtil::make_xr_version_string(p_desired_version)); + print_line("- minApiVersionSupported ", OpenXRUtil::make_xr_version_string(vulkan_requirements.minApiVersionSupported)); + print_line("- maxApiVersionSupported ", OpenXRUtil::make_xr_version_string(vulkan_requirements.maxApiVersionSupported)); + return false; + } + + if (p_desired_version > vulkan_requirements.maxApiVersionSupported) { + print_line("OpenXR: Requested Vulkan version exceeds the maximum version this runtime has been tested on and is known to support."); + print_line("- desired_version ", OpenXRUtil::make_xr_version_string(p_desired_version)); + print_line("- minApiVersionSupported ", OpenXRUtil::make_xr_version_string(vulkan_requirements.minApiVersionSupported)); + print_line("- maxApiVersionSupported ", OpenXRUtil::make_xr_version_string(vulkan_requirements.maxApiVersionSupported)); + } + + return true; +} + +XrResult OpenXRVulkanExtension::xrCreateVulkanInstanceKHR(XrInstance p_instance, const XrVulkanInstanceCreateInfoKHR *p_create_info, VkInstance *r_vulkan_instance, VkResult *r_vulkan_result) { + ERR_FAIL_NULL_V(xrCreateVulkanInstanceKHR_ptr, XR_ERROR_HANDLE_INVALID); + + return (*xrCreateVulkanInstanceKHR_ptr)(p_instance, p_create_info, r_vulkan_instance, r_vulkan_result); +} + +bool OpenXRVulkanExtension::create_vulkan_instance(const VkInstanceCreateInfo *p_vulkan_create_info, VkInstance *r_instance) { + // get the vulkan version we are creating + uint32_t vulkan_version = p_vulkan_create_info->pApplicationInfo->apiVersion; + uint32_t major_version = VK_VERSION_MAJOR(vulkan_version); + uint32_t minor_version = VK_VERSION_MINOR(vulkan_version); + uint32_t patch_version = VK_VERSION_PATCH(vulkan_version); + XrVersion desired_version = XR_MAKE_VERSION(major_version, minor_version, patch_version); + + // check if this is supported + if (!check_graphics_api_support(desired_version)) { + return false; + } + + XrVulkanInstanceCreateInfoKHR xr_vulkan_instance_info = { + XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR, // type + nullptr, // next + openxr_api->get_system_id(), // systemId + 0, // createFlags + vkGetInstanceProcAddr, // pfnGetInstanceProcAddr + p_vulkan_create_info, // vulkanCreateInfo + nullptr, // vulkanAllocator + }; + + VkResult vk_result = VK_SUCCESS; + XrResult result = xrCreateVulkanInstanceKHR(openxr_api->get_instance(), &xr_vulkan_instance_info, &vulkan_instance, &vk_result); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to create vulkan instance [", openxr_api->get_error_string(result), "]"); + return false; + } + + ERR_FAIL_COND_V_MSG(vk_result == VK_ERROR_INCOMPATIBLE_DRIVER, false, + "Cannot find a compatible Vulkan installable client driver (ICD).\n\n" + "vkCreateInstance Failure"); + ERR_FAIL_COND_V_MSG(vk_result == VK_ERROR_EXTENSION_NOT_PRESENT, false, + "Cannot find a specified extension library.\n" + "Make sure your layers path is set appropriately.\n" + "vkCreateInstance Failure"); + ERR_FAIL_COND_V_MSG(vk_result, false, + "vkCreateInstance failed.\n\n" + "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" + "Please look at the Getting Started guide for additional information.\n" + "vkCreateInstance Failure"); + + *r_instance = vulkan_instance; + + return true; +} + +XrResult OpenXRVulkanExtension::xrGetVulkanGraphicsDevice2KHR(XrInstance p_instance, const XrVulkanGraphicsDeviceGetInfoKHR *p_get_info, VkPhysicalDevice *r_vulkan_physical_device) { + ERR_FAIL_NULL_V(xrGetVulkanGraphicsDevice2KHR_ptr, XR_ERROR_HANDLE_INVALID); + + return (*xrGetVulkanGraphicsDevice2KHR_ptr)(p_instance, p_get_info, r_vulkan_physical_device); +} + +bool OpenXRVulkanExtension::get_physical_device(VkPhysicalDevice *r_device) { + ERR_FAIL_NULL_V(openxr_api, false); + + XrVulkanGraphicsDeviceGetInfoKHR get_info = { + XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR, // type + nullptr, // next + openxr_api->get_system_id(), // systemId + vulkan_instance, // vulkanInstance + }; + + XrResult result = xrGetVulkanGraphicsDevice2KHR(openxr_api->get_instance(), &get_info, &vulkan_physical_device); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to obtain vulkan physical device [", openxr_api->get_error_string(result), "]"); + return false; + } + + *r_device = vulkan_physical_device; + + return true; +} + +XrResult OpenXRVulkanExtension::xrCreateVulkanDeviceKHR(XrInstance p_instance, const XrVulkanDeviceCreateInfoKHR *p_create_info, VkDevice *r_device, VkResult *r_result) { + ERR_FAIL_NULL_V(xrCreateVulkanDeviceKHR_ptr, XR_ERROR_HANDLE_INVALID); + + return (*xrCreateVulkanDeviceKHR_ptr)(p_instance, p_create_info, r_device, r_result); +} + +bool OpenXRVulkanExtension::create_vulkan_device(const VkDeviceCreateInfo *p_device_create_info, VkDevice *r_device) { + ERR_FAIL_NULL_V(openxr_api, false); + + // the first entry in our queue list should be the one we need to remember... + vulkan_queue_family_index = p_device_create_info->pQueueCreateInfos[0].queueFamilyIndex; + vulkan_queue_index = 0; // ?? + + XrVulkanDeviceCreateInfoKHR create_info = { + XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR, // type + nullptr, // next + openxr_api->get_system_id(), // systemId + 0, // createFlags + vkGetInstanceProcAddr, // pfnGetInstanceProcAddr + vulkan_physical_device, // vulkanPhysicalDevice + p_device_create_info, // vulkanCreateInfo + nullptr // vulkanAllocator + }; + + VkResult vk_result = VK_SUCCESS; + XrResult result = xrCreateVulkanDeviceKHR(openxr_api->get_instance(), &create_info, &vulkan_device, &vk_result); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to create vulkan device [", openxr_api->get_error_string(result), "]"); + return false; + } + + if (vk_result != VK_SUCCESS) { + print_line("OpenXR: Failed to create vulkan device [vulkan error", vk_result, "]"); + } + + *r_device = vulkan_device; + + return true; +} + +XrGraphicsBindingVulkanKHR OpenXRVulkanExtension::graphics_binding_vulkan; + +void *OpenXRVulkanExtension::set_session_create_and_get_next_pointer(void *p_next_pointer) { + graphics_binding_vulkan.type = XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR; + graphics_binding_vulkan.next = p_next_pointer; + graphics_binding_vulkan.instance = vulkan_instance; + graphics_binding_vulkan.physicalDevice = vulkan_physical_device; + graphics_binding_vulkan.device = vulkan_device; + graphics_binding_vulkan.queueFamilyIndex = vulkan_queue_family_index; + graphics_binding_vulkan.queueIndex = vulkan_queue_index; + + return &graphics_binding_vulkan; +} + +void OpenXRVulkanExtension::get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) { + // We might want to do more here especially if we keep things in linear color space + // Possibly add in R10G10B10A2 as an option if we're using the mobile renderer. + p_usable_swap_chains.push_back(VK_FORMAT_R8G8B8A8_SRGB); + p_usable_swap_chains.push_back(VK_FORMAT_B8G8R8A8_SRGB); + p_usable_swap_chains.push_back(VK_FORMAT_R8G8B8A8_UINT); + p_usable_swap_chains.push_back(VK_FORMAT_B8G8R8A8_UINT); +} + +bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) { + XrSwapchainImageVulkanKHR *images = nullptr; + + RenderingServer *rendering_server = RenderingServer::get_singleton(); + ERR_FAIL_NULL_V(rendering_server, false); + RenderingDevice *rendering_device = rendering_server->get_rendering_device(); + ERR_FAIL_NULL_V(rendering_device, false); + + uint32_t swapchain_length; + XrResult result = xrEnumerateSwapchainImages(p_swapchain, 0, &swapchain_length, nullptr); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to get swapchaim image count [", openxr_api->get_error_string(result), "]"); + return false; + } + + images = (XrSwapchainImageVulkanKHR *)memalloc(sizeof(XrSwapchainImageVulkanKHR) * swapchain_length); + ERR_FAIL_NULL_V_MSG(images, false, "OpenXR Couldn't allocate memory for swap chain image"); + + for (uint64_t i = 0; i < swapchain_length; i++) { + images[i].type = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR; + images[i].next = nullptr; + images[i].image = nullptr; + } + + result = xrEnumerateSwapchainImages(p_swapchain, swapchain_length, &swapchain_length, (XrSwapchainImageBaseHeader *)images); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to get swapchaim images [", openxr_api->get_error_string(result), "]"); + memfree(images); + return false; + } + + // SwapchainGraphicsData *data = (SwapchainGraphicsData *)memalloc(sizeof(SwapchainGraphicsData)); + SwapchainGraphicsData *data = memnew(SwapchainGraphicsData); + if (data == nullptr) { + print_line("OpenXR: Failed to allocate memory for swapchain data"); + memfree(images); + return false; + } + *r_swapchain_graphics_data = data; + data->is_multiview = (p_array_size > 1); + + RenderingDevice::DataFormat format = RenderingDevice::DATA_FORMAT_R8G8B8A8_SRGB; // TODO set this based on p_swapchain_format + RenderingDevice::TextureSamples samples = RenderingDevice::TEXTURE_SAMPLES_1; // TODO set this based on p_sample_count + uint64_t usage_flags = RenderingDevice::TEXTURE_USAGE_SAMPLING_BIT | RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + + Vector<RID> image_rids; + Vector<RID> framebuffers; + + // create Godot texture objects for each entry in our swapchain + for (uint64_t i = 0; i < swapchain_length; i++) { + RID image_rid = rendering_device->texture_create_from_extension( + p_array_size == 1 ? RenderingDevice::TEXTURE_TYPE_2D : RenderingDevice::TEXTURE_TYPE_2D_ARRAY, + format, + samples, + usage_flags, + (uint64_t)images[i].image, + p_width, + p_height, + 1, + p_array_size); + + image_rids.push_back(image_rid); + + { + Vector<RID> fb; + fb.push_back(image_rid); + + RID fb_rid = rendering_device->framebuffer_create(fb, RenderingDevice::INVALID_ID, p_array_size); + framebuffers.push_back(fb_rid); + } + } + + data->image_rids = image_rids; + data->framebuffers = framebuffers; + + memfree(images); + + return true; +} + +bool OpenXRVulkanExtension::create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, CameraMatrix &r_camera_matrix) { + // Even though this is a Vulkan renderer we're using OpenGL coordinate systems + XrMatrix4x4f matrix; + XrMatrix4x4f_CreateProjectionFov(&matrix, GRAPHICS_OPENGL, p_fov, (float)p_z_near, (float)p_z_far); + + for (int j = 0; j < 4; j++) { + for (int i = 0; i < 4; i++) { + r_camera_matrix.matrix[j][i] = matrix.m[j * 4 + i]; + } + } + + return true; +} + +bool OpenXRVulkanExtension::copy_render_target_to_image(RID p_from_render_target, void *p_swapchain_graphics_data, int p_image_index) { + SwapchainGraphicsData *data = (SwapchainGraphicsData *)p_swapchain_graphics_data; + ERR_FAIL_NULL_V(data, false); + ERR_FAIL_COND_V(p_from_render_target.is_null(), false); + ERR_FAIL_NULL_V(RendererStorageRD::base_singleton, false); + + RID source_image = RendererStorageRD::base_singleton->render_target_get_rd_texture(p_from_render_target); + ERR_FAIL_COND_V(source_image.is_null(), false); + + RID depth_image; // TODO implement + + ERR_FAIL_INDEX_V(p_image_index, data->framebuffers.size(), false); + RID fb = data->framebuffers[p_image_index]; + ERR_FAIL_COND_V(fb.is_null(), false); + + // Our vulkan extension can only be used in conjunction with our vulkan renderer. + // We need access to the effects object in order to have access to our copy logic. + // Breaking all the rules but there is no nice way to do this. + EffectsRD *effects = RendererStorageRD::base_singleton->get_effects(); + ERR_FAIL_NULL_V(effects, false); + effects->copy_to_fb_rect(source_image, fb, Rect2i(), false, false, false, false, depth_image, data->is_multiview); + + return true; +} + +void OpenXRVulkanExtension::cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) { + if (*p_swapchain_graphics_data == nullptr) { + return; + } + + SwapchainGraphicsData *data = (SwapchainGraphicsData *)*p_swapchain_graphics_data; + + RenderingServer *rendering_server = RenderingServer::get_singleton(); + ERR_FAIL_NULL(rendering_server); + RenderingDevice *rendering_device = rendering_server->get_rendering_device(); + ERR_FAIL_NULL(rendering_device); + + for (int i = 0; i < data->image_rids.size(); i++) { + // This should clean up our RIDs and associated texture objects but shouldn't destroy the images, they are owned by our XrSwapchain + rendering_device->free(data->image_rids[i]); + } + data->image_rids.clear(); + + for (int i = 0; i < data->framebuffers.size(); i++) { + // This should clean up our RIDs and associated texture objects but shouldn't destroy the images, they are owned by our XrSwapchain + rendering_device->free(data->framebuffers[i]); + } + data->framebuffers.clear(); + + memdelete(data); + *p_swapchain_graphics_data = nullptr; +} + +#define ENUM_TO_STRING_CASE(e) \ + case e: { \ + return String(#e); \ + } break; + +String OpenXRVulkanExtension::get_swapchain_format_name(int64_t p_swapchain_format) const { + // This really should be in vulkan_context... + VkFormat format = VkFormat(p_swapchain_format); + switch (format) { + ENUM_TO_STRING_CASE(VK_FORMAT_UNDEFINED) + ENUM_TO_STRING_CASE(VK_FORMAT_R4G4_UNORM_PACK8) + ENUM_TO_STRING_CASE(VK_FORMAT_R4G4B4A4_UNORM_PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_B4G4R4A4_UNORM_PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_R5G6B5_UNORM_PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_B5G6R5_UNORM_PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_R5G5B5A1_UNORM_PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_B5G5R5A1_UNORM_PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_A1R5G5B5_UNORM_PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_R8_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R8_SNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R8_USCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R8_SSCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R8_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R8_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R8_SRGB) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8_SNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8_USCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8_SSCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8_SRGB) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8_SNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8_USCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8_SSCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8_SRGB) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8_SNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8_USCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8_SSCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8_SRGB) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8A8_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8A8_SNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8A8_USCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8A8_SSCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8A8_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8A8_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8A8_SRGB) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8A8_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8A8_SNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8A8_USCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8A8_SSCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8A8_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8A8_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8A8_SRGB) + ENUM_TO_STRING_CASE(VK_FORMAT_A8B8G8R8_UNORM_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A8B8G8R8_SNORM_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A8B8G8R8_USCALED_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A8B8G8R8_SSCALED_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A8B8G8R8_UINT_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A8B8G8R8_SINT_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A8B8G8R8_SRGB_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A2R10G10B10_UNORM_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A2R10G10B10_SNORM_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A2R10G10B10_USCALED_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A2R10G10B10_SSCALED_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A2R10G10B10_UINT_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A2R10G10B10_SINT_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A2B10G10R10_UNORM_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A2B10G10R10_SNORM_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A2B10G10R10_USCALED_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A2B10G10R10_SSCALED_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A2B10G10R10_UINT_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A2B10G10R10_SINT_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_R16_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R16_SNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R16_USCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R16_SSCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R16_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R16_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R16_SFLOAT) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16_SNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16_USCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16_SSCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16_SFLOAT) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16_SNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16_USCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16_SSCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16_SFLOAT) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16A16_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16A16_SNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16A16_USCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16A16_SSCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16A16_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16A16_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16A16_SFLOAT) + ENUM_TO_STRING_CASE(VK_FORMAT_R32_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R32_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R32_SFLOAT) + ENUM_TO_STRING_CASE(VK_FORMAT_R32G32_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R32G32_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R32G32_SFLOAT) + ENUM_TO_STRING_CASE(VK_FORMAT_R32G32B32_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R32G32B32_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R32G32B32_SFLOAT) + ENUM_TO_STRING_CASE(VK_FORMAT_R32G32B32A32_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R32G32B32A32_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R32G32B32A32_SFLOAT) + ENUM_TO_STRING_CASE(VK_FORMAT_R64_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R64_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R64_SFLOAT) + ENUM_TO_STRING_CASE(VK_FORMAT_R64G64_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R64G64_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R64G64_SFLOAT) + ENUM_TO_STRING_CASE(VK_FORMAT_R64G64B64_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R64G64B64_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R64G64B64_SFLOAT) + ENUM_TO_STRING_CASE(VK_FORMAT_R64G64B64A64_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R64G64B64A64_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R64G64B64A64_SFLOAT) + ENUM_TO_STRING_CASE(VK_FORMAT_B10G11R11_UFLOAT_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_E5B9G9R9_UFLOAT_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_D16_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_X8_D24_UNORM_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_D32_SFLOAT) + ENUM_TO_STRING_CASE(VK_FORMAT_S8_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_D16_UNORM_S8_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_D24_UNORM_S8_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_D32_SFLOAT_S8_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_BC1_RGB_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC1_RGB_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC1_RGBA_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC1_RGBA_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC2_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC2_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC3_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC3_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC4_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC4_SNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC5_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC5_SNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC6H_UFLOAT_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC6H_SFLOAT_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC7_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC7_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_EAC_R11_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_EAC_R11_SNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_EAC_R11G11_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_EAC_R11G11_SNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_4x4_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_4x4_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_5x4_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_5x4_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_5x5_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_5x5_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_6x5_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_6x5_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_6x6_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_6x6_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_8x5_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_8x5_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_8x6_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_8x6_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_8x8_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_8x8_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x5_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x5_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x6_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x6_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x8_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x8_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x10_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x10_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_12x10_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_12x10_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_12x12_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_12x12_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_G8B8G8R8_422_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8G8_422_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_G8_B8R8_2PLANE_420_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_G8_B8R8_2PLANE_422_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R10X6_UNORM_PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_R10X6G10X6_UNORM_2PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_R12X4_UNORM_PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_R12X4G12X4_UNORM_2PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_G16B16G16R16_422_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_B16G16R16G16_422_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_G16_B16R16_2PLANE_420_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_G16_B16R16_2PLANE_422_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG) + ENUM_TO_STRING_CASE(VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG) + ENUM_TO_STRING_CASE(VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG) + ENUM_TO_STRING_CASE(VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG) + ENUM_TO_STRING_CASE(VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG) + ENUM_TO_STRING_CASE(VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG) + ENUM_TO_STRING_CASE(VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG) + ENUM_TO_STRING_CASE(VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_MAX_ENUM) + default: { + return String("Swapchain format ") + String::num_int64(int64_t(p_swapchain_format)); + } break; + } +} diff --git a/modules/openxr/extensions/openxr_vulkan_extension.h b/modules/openxr/extensions/openxr_vulkan_extension.h new file mode 100644 index 0000000000..c04ea2c1dd --- /dev/null +++ b/modules/openxr/extensions/openxr_vulkan_extension.h @@ -0,0 +1,93 @@ +/*************************************************************************/ +/* openxr_vulkan_extension.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef OPENXR_VULKAN_EXTENSION_H +#define OPENXR_VULKAN_EXTENSION_H + +#include "core/templates/vector.h" +#include "openxr_extension_wrapper.h" + +#include "drivers/vulkan/vulkan_context.h" + +// Forward declare these so we don't need OpenXR headers where-ever this is included +// Including OpenXR at this point gives loads and loads of compile issues especially +// on Windows because windows.h is EVIL and really shouldn't be included outside of platform +// but we really don't have a choice in the matter + +struct XrGraphicsRequirementsVulkanKHR; +struct XrVulkanInstanceCreateInfoKHR; +struct XrVulkanGraphicsDeviceGetInfoKHR; +struct XrVulkanDeviceCreateInfoKHR; +struct XrGraphicsBindingVulkanKHR; + +class OpenXRVulkanExtension : public OpenXRGraphicsExtensionWrapper, VulkanHooks { +public: + OpenXRVulkanExtension(OpenXRAPI *p_openxr_api); + virtual ~OpenXRVulkanExtension() override; + + virtual void on_instance_created(const XrInstance p_instance) override; + virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) override; + + virtual bool create_vulkan_instance(const VkInstanceCreateInfo *p_vulkan_create_info, VkInstance *r_instance); + virtual bool get_physical_device(VkPhysicalDevice *r_device); + virtual bool create_vulkan_device(const VkDeviceCreateInfo *p_device_create_info, VkDevice *r_device); + + virtual void get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) override; + virtual String get_swapchain_format_name(int64_t p_swapchain_format) const override; + virtual bool get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) override; + virtual void cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) override; + virtual bool create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, CameraMatrix &r_camera_matrix) override; + virtual bool copy_render_target_to_image(RID p_from_render_target, void *p_swapchain_graphics_data, int p_image_index) override; + +private: + static OpenXRVulkanExtension *singleton; + static XrGraphicsBindingVulkanKHR graphics_binding_vulkan; // declaring this as static so we don't need to know its size and we only need it once when creating our session + + struct SwapchainGraphicsData { + bool is_multiview; + Vector<RID> image_rids; + Vector<RID> framebuffers; + }; + + bool check_graphics_api_support(XrVersion p_desired_version); + + VkInstance vulkan_instance; + VkPhysicalDevice vulkan_physical_device; + VkDevice vulkan_device; + uint32_t vulkan_queue_family_index; + uint32_t vulkan_queue_index; + + XrResult xrGetVulkanGraphicsRequirements2KHR(XrInstance p_instance, XrSystemId p_system_id, XrGraphicsRequirementsVulkanKHR *p_graphics_requirements); + XrResult xrCreateVulkanInstanceKHR(XrInstance p_instance, const XrVulkanInstanceCreateInfoKHR *p_create_info, VkInstance *r_vulkan_instance, VkResult *r_vulkan_result); + XrResult xrGetVulkanGraphicsDevice2KHR(XrInstance p_instance, const XrVulkanGraphicsDeviceGetInfoKHR *p_get_info, VkPhysicalDevice *r_vulkan_physical_device); + XrResult xrCreateVulkanDeviceKHR(XrInstance p_instance, const XrVulkanDeviceCreateInfoKHR *p_create_info, VkDevice *r_device, VkResult *r_result); +}; + +#endif // !OPENXR_VULKAN_EXTENSION_H diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp new file mode 100644 index 0000000000..23fd0404d5 --- /dev/null +++ b/modules/openxr/openxr_api.cpp @@ -0,0 +1,2171 @@ +/*************************************************************************/ +/* openxr_api.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "openxr_api.h" +#include "openxr_util.h" + +#include "core/config/engine.h" +#include "core/config/project_settings.h" +#include "core/os/memory.h" +#include "core/version.h" + +#ifdef TOOLS_ENABLED +#include "editor/editor_settings.h" +#endif + +#ifdef ANDROID_ENABLED +#include "extensions/openxr_android_extension.h" +#endif + +#ifdef VULKAN_ENABLED +#include "extensions/openxr_vulkan_extension.h" +#endif + +OpenXRAPI *OpenXRAPI::singleton = nullptr; + +void OpenXRAPI::setup_global_defs() { + // As OpenXRAPI is not constructed if OpenXR is not enabled, we register our project and editor settings here + + // Project settings + GLOBAL_DEF_BASIC("xr/openxr/enabled", false); + GLOBAL_DEF_BASIC("xr/openxr/default_action_map", "res://default_action_map.tres"); + ProjectSettings::get_singleton()->set_custom_property_info("xr/openxr/default_action_map", PropertyInfo(Variant::STRING, "xr/openxr/default_action_map", PROPERTY_HINT_FILE, "*.tres")); + + GLOBAL_DEF_BASIC("xr/openxr/form_factor", "0"); + ProjectSettings::get_singleton()->set_custom_property_info("xr/openxr/form_factor", PropertyInfo(Variant::INT, "xr/openxr/form_factor", PROPERTY_HINT_ENUM, "Head mounted,Handheld")); + + GLOBAL_DEF_BASIC("xr/openxr/view_configuration", "1"); + ProjectSettings::get_singleton()->set_custom_property_info("xr/openxr/view_configuration", PropertyInfo(Variant::INT, "xr/openxr/view_configuration", PROPERTY_HINT_ENUM, "Mono,Stereo")); // "Mono,Stereo,Quad,Observer" + + GLOBAL_DEF_BASIC("xr/openxr/reference_space", "1"); + ProjectSettings::get_singleton()->set_custom_property_info("xr/openxr/reference_space", PropertyInfo(Variant::INT, "xr/openxr/reference_space", PROPERTY_HINT_ENUM, "Local,Stage")); + +#ifdef TOOLS_ENABLED + // Disabled for now, using XR inside of the editor we'll be working on during the coming months. + + // editor settings (it seems we're too early in the process when setting up rendering, to access editor settings...) + // EDITOR_DEF_RST("xr/openxr/in_editor", false); + // GLOBAL_DEF("xr/openxr/in_editor", false); +#endif +} + +bool OpenXRAPI::openxr_is_enabled() { + // @TODO we need an overrule switch so we can force enable openxr, i.e run "godot --openxr_enabled" + + if (Engine::get_singleton()->is_editor_hint()) { +#ifdef TOOLS_ENABLED + // Disabled for now, using XR inside of the editor we'll be working on during the coming months. + return false; + + // bool enabled = GLOBAL_GET("xr/openxr/in_editor"); // EDITOR_GET("xr/openxr/in_editor"); + // return enabled; +#else + // we should never get here, editor hint won't be true if the editor isn't compiled in. + return false; +#endif + } else { + bool enabled = GLOBAL_GET("xr/openxr/enabled"); + return enabled; + } +} + +OpenXRAPI *OpenXRAPI::get_singleton() { + if (singleton != nullptr) { + // already constructed, return our singleton + return singleton; + } else if (openxr_is_enabled()) { + // construct our singleton and return it + singleton = memnew(OpenXRAPI); + return singleton; + } else { + // not enabled, don't instantiate, return nullptr + return nullptr; + } +} + +String OpenXRAPI::get_default_action_map_resource_name() { + String name = GLOBAL_GET("xr/openxr/default_action_map"); + + return name; +} + +String OpenXRAPI::get_error_string(XrResult result) { + if (XR_SUCCEEDED(result)) { + return String("Succeeded"); + } + + if (instance == XR_NULL_HANDLE) { + Array args; + args.push_back(Variant(result)); + return String("Error code {0}").format(args); + } + + char resultString[XR_MAX_RESULT_STRING_SIZE]; + xrResultToString(instance, result, resultString); + + return String(resultString); +} + +String OpenXRAPI::get_swapchain_format_name(int64_t p_swapchain_format) const { + // This is rendering engine dependend... + if (graphics_extension) { + return graphics_extension->get_swapchain_format_name(p_swapchain_format); + } + + return String("Swapchain format ") + String::num_int64(int64_t(p_swapchain_format)); +} + +bool OpenXRAPI::load_layer_properties() { + // This queries additional layers that are available and can be initialised when we create our OpenXR instance + if (layer_properties != nullptr) { + // already retrieved this + return true; + } + + // Note, instance is not yet setup so we can't use get_error_string to retrieve our error + XrResult result = xrEnumerateApiLayerProperties(0, &num_layer_properties, nullptr); + ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate number of api layer properties"); + + layer_properties = (XrApiLayerProperties *)memalloc(sizeof(XrApiLayerProperties) * num_layer_properties); + ERR_FAIL_NULL_V(layer_properties, false); + for (uint32_t i = 0; i < num_layer_properties; i++) { + layer_properties[i].type = XR_TYPE_API_LAYER_PROPERTIES; + layer_properties[i].next = nullptr; + } + + result = xrEnumerateApiLayerProperties(num_layer_properties, &num_layer_properties, layer_properties); + ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate api layer properties"); + +#ifdef DEBUG + for (uint32_t i = 0; i < num_layer_properties; i++) { + print_line("OpenXR: Found OpenXR layer ", layer_properties[i].layerName); + } +#endif + + return true; +} + +bool OpenXRAPI::load_supported_extensions() { + // This queries supported extensions that are available and can be initialised when we create our OpenXR instance + + if (supported_extensions != nullptr) { + // already retrieved this + return true; + } + + // Note, instance is not yet setup so we can't use get_error_string to retrieve our error + XrResult result = xrEnumerateInstanceExtensionProperties(nullptr, 0, &num_supported_extensions, nullptr); + ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate number of extension properties"); + + supported_extensions = (XrExtensionProperties *)memalloc(sizeof(XrExtensionProperties) * num_supported_extensions); + ERR_FAIL_NULL_V(supported_extensions, false); + + // set our types + for (uint32_t i = 0; i < num_supported_extensions; i++) { + supported_extensions[i].type = XR_TYPE_EXTENSION_PROPERTIES; + supported_extensions[i].next = nullptr; + } + result = xrEnumerateInstanceExtensionProperties(nullptr, num_supported_extensions, &num_supported_extensions, supported_extensions); + ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate extension properties"); + +#ifdef DEBUG + for (uint32_t i = 0; i < num_supported_extensions; i++) { + print_line("OpenXR: Found OpenXR extension ", supported_extensions[i].extensionName); + } +#endif + + return true; +} + +bool OpenXRAPI::is_extension_supported(const char *p_extension) const { + for (uint32_t i = 0; i < num_supported_extensions; i++) { + if (strcmp(supported_extensions[i].extensionName, p_extension)) { + return true; + } + } + + return false; +} + +void OpenXRAPI::copy_string_to_char_buffer(const String p_string, char *p_buffer, int p_buffer_len) { + CharString char_string = p_string.utf8(); + int len = char_string.length(); + if (len < p_buffer_len - 1) { + // was having weird CI issues with strcpy so.... + memcpy(p_buffer, char_string.get_data(), len); + p_buffer[len] = '\0'; + } else { + memcpy(p_buffer, char_string.get_data(), p_buffer_len - 1); + p_buffer[p_buffer_len - 1] = '\0'; + } +} + +bool OpenXRAPI::create_instance() { + // Create our OpenXR instance, this will query any registered extension wrappers for extensions we need to enable. + + // Append the extensions requested by the registered extension wrappers. + Map<const char *, bool *> requested_extensions; + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + Map<const char *, bool *> wrapper_request_extensions = wrapper->get_request_extensions(); + + // requested_extensions.insert(wrapper_request_extensions.begin(), wrapper_request_extensions.end()); + for (auto &requested_extension : wrapper_request_extensions) { + requested_extensions[requested_extension.key] = requested_extension.value; + } + } + + // Check which extensions are supported + enabled_extensions.clear(); + for (auto &requested_extension : requested_extensions) { + if (!is_extension_supported(requested_extension.key)) { + if (requested_extension.value == nullptr) { + // nullptr means this is a manditory extension so we fail + ERR_FAIL_V_MSG(false, "OpenXR: OpenXR Runtime does not support OpenGL extension!"); + } else { + // set this extension as not supported + *requested_extension.value = false; + } + } else if (requested_extension.value != nullptr) { + // set this extension as supported + *requested_extension.value = true; + + // and record that we want to enable it + enabled_extensions.push_back(requested_extension.key); + } else { + // record that we want to enable this + enabled_extensions.push_back(requested_extension.key); + } + } + + // Get our project name + String project_name = GLOBAL_GET("application/config/name"); + + // Create our OpenXR instance + XrApplicationInfo application_info{ + "", // applicationName, we'll set this down below + 1, // applicationVersion, we don't currently have this + "Godot Game Engine", // engineName + VERSION_MAJOR * 10000 + VERSION_MINOR * 100 + VERSION_PATCH, // engineVersion 4.0 -> 40000, 4.0.1 -> 40001, 4.1 -> 40100, etc. + XR_CURRENT_API_VERSION // apiVersion + }; + + XrInstanceCreateInfo instance_create_info = { + XR_TYPE_INSTANCE_CREATE_INFO, // type + nullptr, // next + 0, // createFlags + application_info, // applicationInfo + 0, // enabledApiLayerCount, need to find out if we need support for this? + nullptr, // enabledApiLayerNames + uint32_t(enabled_extensions.size()), // enabledExtensionCount + enabled_extensions.ptr() // enabledExtensionNames + }; + + copy_string_to_char_buffer(project_name, instance_create_info.applicationInfo.applicationName, XR_MAX_APPLICATION_NAME_SIZE); + + XrResult result = xrCreateInstance(&instance_create_info, &instance); + ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "Failed to create XR instance."); + + // from this point on we can use get_error_string to get more info about our errors... + + XrInstanceProperties instanceProps = { + XR_TYPE_INSTANCE_PROPERTIES, // type; + nullptr, // next + 0, // runtimeVersion, from here will be set by our get call + "" // runtimeName + }; + result = xrGetInstanceProperties(instance, &instanceProps); + if (XR_FAILED(result)) { + // not fatal probably + print_line("OpenXR: Failed to get XR instance properties [", get_error_string(result), "]"); + } else { + print_line("OpenXR: Running on OpenXR runtime: ", instanceProps.runtimeName, " ", OpenXRUtil::make_xr_version_string(instanceProps.runtimeVersion)); + } + + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_instance_created(instance); + } + + return true; +} + +bool OpenXRAPI::get_system_info() { + // Retrieve basic OpenXR system info based on the form factor we desire + + // Retrieve the system for our form factor, fails if form factor is not available + XrSystemGetInfo system_get_info = { + XR_TYPE_SYSTEM_GET_INFO, // type; + nullptr, // next + form_factor // formFactor + }; + + XrResult result = xrGetSystem(instance, &system_get_info, &system_id); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to get system for our form factor [", get_error_string(result), "]"); + return false; + } + + // obtain info about our system, writing this out completely to make CI on Linux happy.. + void *next_pointer = nullptr; + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + void *np = wrapper->set_system_properties_and_get_next_pointer(next_pointer); + if (np != nullptr) { + next_pointer = np; + } + } + + XrSystemProperties system_properties = { + XR_TYPE_SYSTEM_PROPERTIES, // type + next_pointer, // next + 0, // systemId, from here will be set by our get call + 0, // vendorId + "", // systemName + { + 0, // maxSwapchainImageHeight + 0, // maxSwapchainImageWidth + 0, // maxLayerCount + }, // graphicsProperties + { + false, // orientationTracking + false // positionTracking + } // trackingProperties + }; + + result = xrGetSystemProperties(instance, system_id, &system_properties); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to get System properties [", get_error_string(result), "]"); + return false; + } + + // remember this state, we'll use it later + system_name = String(system_properties.systemName); + vendor_id = system_properties.vendorId; + graphics_properties = system_properties.graphicsProperties; + tracking_properties = system_properties.trackingProperties; + + return true; +} + +bool OpenXRAPI::load_supported_view_configuration_types() { + // This queries the supported configuration types, likely there will only be one chosing between Mono (phone AR) and Stereo (HMDs) + + ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false); + + if (supported_view_configuration_types != nullptr) { + // free previous results + memfree(supported_view_configuration_types); + supported_view_configuration_types = nullptr; + } + + XrResult result = xrEnumerateViewConfigurations(instance, system_id, 0, &num_view_configuration_types, nullptr); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to get view configuration count [", get_error_string(result), "]"); + return false; + } + + supported_view_configuration_types = (XrViewConfigurationType *)memalloc(sizeof(XrViewConfigurationType) * num_view_configuration_types); + ERR_FAIL_NULL_V(supported_view_configuration_types, false); + + result = xrEnumerateViewConfigurations(instance, system_id, num_view_configuration_types, &num_view_configuration_types, supported_view_configuration_types); + ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerateview configurations"); + +#ifdef DEBUG + for (uint32_t i = 0; i < num_view_configuration_types; i++) { + print_line("OpenXR: Found supported view configuration ", OpenXRUtil::get_view_configuration_name(supported_view_configuration_types[i])); + } +#endif + + return true; +} + +bool OpenXRAPI::is_view_configuration_supported(XrViewConfigurationType p_configuration_type) const { + ERR_FAIL_NULL_V(supported_view_configuration_types, false); + + for (uint32_t i = 0; i < num_view_configuration_types; i++) { + if (supported_view_configuration_types[i] == p_configuration_type) { + return true; + } + } + + return false; +} + +bool OpenXRAPI::load_supported_view_configuration_views(XrViewConfigurationType p_configuration_type) { + // This loads our view configuration for each view so for a stereo HMD, we'll get two entries (that are likely identical) + // The returned data supplies us with the recommended render target size + + if (!is_view_configuration_supported(p_configuration_type)) { + print_line("OpenXR: View configuration ", OpenXRUtil::get_view_configuration_name(view_configuration), " is not supported."); + return false; + } + + if (view_configuration_views != nullptr) { + // free previous results + memfree(view_configuration_views); + view_configuration_views = nullptr; + } + + XrResult result = xrEnumerateViewConfigurationViews(instance, system_id, p_configuration_type, 0, &view_count, nullptr); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to get view configuration count [", get_error_string(result), "]"); + return false; + } + + view_configuration_views = (XrViewConfigurationView *)memalloc(sizeof(XrViewConfigurationView) * view_count); + ERR_FAIL_NULL_V(view_configuration_views, false); + + for (uint32_t i = 0; i < view_count; i++) { + view_configuration_views[i].type = XR_TYPE_VIEW_CONFIGURATION_VIEW; + view_configuration_views[i].next = NULL; + } + + result = xrEnumerateViewConfigurationViews(instance, system_id, p_configuration_type, view_count, &view_count, view_configuration_views); + ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate view configurations"); + +#ifdef DEBUG + for (uint32_t i = 0; i < view_count; i++) { + print_line("OpenXR: Found supported view configuration view"); + print_line(" - width: ", view_configuration_views[i].maxImageRectWidth); + print_line(" - height: ", view_configuration_views[i].maxImageRectHeight); + print_line(" - sample count: ", view_configuration_views[i].maxSwapchainSampleCount); + print_line(" - recommended render width: ", view_configuration_views[i].recommendedImageRectWidth); + print_line(" - recommended render height: ", view_configuration_views[i].recommendedImageRectHeight); + print_line(" - recommended render sample count: ", view_configuration_views[i].recommendedSwapchainSampleCount); + } +#endif + + return true; +} + +void OpenXRAPI::destroy_instance() { + if (view_configuration_views != nullptr) { + memfree(view_configuration_views); + view_configuration_views = nullptr; + } + + if (supported_view_configuration_types != nullptr) { + memfree(supported_view_configuration_types); + supported_view_configuration_types = nullptr; + } + + if (instance != XR_NULL_HANDLE) { + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_instance_destroyed(); + } + + xrDestroyInstance(instance); + instance = XR_NULL_HANDLE; + } + enabled_extensions.clear(); +} + +bool OpenXRAPI::create_session() { + ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false); + ERR_FAIL_COND_V(session != XR_NULL_HANDLE, false); + + void *next_pointer = nullptr; + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + void *np = wrapper->set_session_create_and_get_next_pointer(next_pointer); + if (np != nullptr) { + next_pointer = np; + } + } + + XrSessionCreateInfo session_create_info = { + XR_TYPE_SESSION_CREATE_INFO, // type + next_pointer, // next + 0, // createFlags + system_id // systemId + }; + + XrResult result = xrCreateSession(instance, &session_create_info, &session); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to create session [", get_error_string(result), "]"); + return false; + } + + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_session_created(session); + } + + return true; +} + +bool OpenXRAPI::load_supported_reference_spaces() { + // loads the supported reference spaces for our OpenXR session + + ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false); + + if (supported_reference_spaces != nullptr) { + // free previous results + memfree(supported_reference_spaces); + supported_reference_spaces = nullptr; + } + + XrResult result = xrEnumerateReferenceSpaces(session, 0, &num_reference_spaces, nullptr); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to get reference space count [", get_error_string(result), "]"); + return false; + } + + supported_reference_spaces = (XrReferenceSpaceType *)memalloc(sizeof(XrReferenceSpaceType) * num_reference_spaces); + ERR_FAIL_NULL_V(supported_reference_spaces, false); + + result = xrEnumerateReferenceSpaces(session, num_reference_spaces, &num_reference_spaces, supported_reference_spaces); + ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate reference spaces"); + + // #ifdef DEBUG + for (uint32_t i = 0; i < num_reference_spaces; i++) { + print_line("OpenXR: Found supported reference space ", OpenXRUtil::get_reference_space_name(supported_reference_spaces[i])); + } + // #endif + + return true; +} + +bool OpenXRAPI::is_reference_space_supported(XrReferenceSpaceType p_reference_space) { + ERR_FAIL_NULL_V(supported_reference_spaces, false); + + for (uint32_t i = 0; i < num_reference_spaces; i++) { + if (supported_reference_spaces[i] == p_reference_space) { + return true; + } + } + + return false; +} + +bool OpenXRAPI::setup_spaces() { + XrResult result; + + XrPosef identityPose = { + { 0.0, 0.0, 0.0, 1.0 }, + { 0.0, 0.0, 0.0 } + }; + + ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false); + + // create play space + { + if (!is_reference_space_supported(reference_space)) { + print_line("OpenXR: reference space ", OpenXRUtil::get_reference_space_name(reference_space), " is not supported."); + return false; + } + + XrReferenceSpaceCreateInfo play_space_create_info = { + XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type + nullptr, // next + reference_space, // referenceSpaceType + identityPose // poseInReferenceSpace + }; + + result = xrCreateReferenceSpace(session, &play_space_create_info, &play_space); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to create play space [", get_error_string(result), "]"); + return false; + } + } + + // create view space + { + if (!is_reference_space_supported(XR_REFERENCE_SPACE_TYPE_VIEW)) { + print_line("OpenXR: reference space XR_REFERENCE_SPACE_TYPE_VIEW is not supported."); + return false; + } + + XrReferenceSpaceCreateInfo view_space_create_info = { + XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type + nullptr, // next + XR_REFERENCE_SPACE_TYPE_VIEW, // referenceSpaceType + identityPose // poseInReferenceSpace + }; + + result = xrCreateReferenceSpace(session, &view_space_create_info, &view_space); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to create view space [", get_error_string(result), "]"); + return false; + } + } + + return true; +} + +bool OpenXRAPI::load_supported_swapchain_formats() { + ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false); + + if (supported_swapchain_formats != nullptr) { + // free previous results + memfree(supported_swapchain_formats); + supported_swapchain_formats = nullptr; + } + + XrResult result = xrEnumerateSwapchainFormats(session, 0, &num_swapchain_formats, nullptr); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to get swapchain format count [", get_error_string(result), "]"); + return false; + } + + supported_swapchain_formats = (int64_t *)memalloc(sizeof(int64_t) * num_swapchain_formats); + ERR_FAIL_NULL_V(supported_swapchain_formats, false); + + result = xrEnumerateSwapchainFormats(session, num_swapchain_formats, &num_swapchain_formats, supported_swapchain_formats); + ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate swapchain formats"); + + // #ifdef DEBUG + for (uint32_t i = 0; i < num_swapchain_formats; i++) { + print_line("OpenXR: Found supported swapchain format ", get_swapchain_format_name(supported_swapchain_formats[i])); + } + // #endif + + return true; +} + +bool OpenXRAPI::is_swapchain_format_supported(int64_t p_swapchain_format) { + ERR_FAIL_NULL_V(supported_swapchain_formats, false); + + for (uint32_t i = 0; i < num_swapchain_formats; i++) { + if (supported_swapchain_formats[i] == p_swapchain_format) { + return true; + } + } + + return false; +} + +bool OpenXRAPI::create_main_swapchain() { + ERR_FAIL_NULL_V(graphics_extension, false); + ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false); + + /* + TODO: We need to improve on this, for now we're taking our old approach of creating our main swapchains and substituting + those for the ones Godot normally creates. + This however means we can only use swapchains for our main XR view. + + It would have been nicer if we could override the swapchain creation in Godot with ours but we have a timing issue here. + We can't create XR swapchains until after our XR session is fully instantiated, yet Godot creates its swapchain much earlier. + + Also Godot only creates a swapchain for the main output. + OpenXR will require us to create swapchains as the render target for additional viewports if we want to use the layer system + to optimise text rendering and background rendering as OpenXR may choose to re-use the results for reprojection while we're + already rendering the next frame. + + Finally an area we need to expand upon is that Foveated rendering is only enabled for the swap chain we create, + as we render 3D content into internal buffers that are copied into the swapchain, we don't get any of the performance gains + until such time as we implement VRS. + */ + + // Build a vector with swapchain formats we want to use, from best fit to worst + Vector<int64_t> usable_swapchain_formats; + int64_t swapchain_format_to_use = 0; + + graphics_extension->get_usable_swapchain_formats(usable_swapchain_formats); + + // now find out which one is supported + for (int i = 0; i < usable_swapchain_formats.size() && swapchain_format_to_use == 0; i++) { + if (is_swapchain_format_supported(usable_swapchain_formats[i])) { + swapchain_format_to_use = usable_swapchain_formats[i]; + } + } + + if (swapchain_format_to_use == 0) { + swapchain_format_to_use = usable_swapchain_formats[0]; // just use the first one and hope for the best... + print_line("Couldn't find usable swap chain format, using", get_swapchain_format_name(swapchain_format_to_use), "instead."); + } else { + print_line("Using swap chain format:", get_swapchain_format_name(swapchain_format_to_use)); + } + + Size2 recommended_size = get_recommended_target_size(); + + if (!create_swapchain(swapchain_format_to_use, recommended_size.width, recommended_size.height, view_configuration_views[0].recommendedSwapchainSampleCount, view_count, swapchain, &swapchain_graphics_data)) { + return false; + } + + views = (XrView *)memalloc(sizeof(XrView) * view_count); + ERR_FAIL_NULL_V_MSG(views, false, "OpenXR Couldn't allocate memory for views"); + + projection_views = (XrCompositionLayerProjectionView *)memalloc(sizeof(XrCompositionLayerProjectionView) * view_count); + ERR_FAIL_NULL_V_MSG(projection_views, false, "OpenXR Couldn't allocate memory for projection views"); + + for (uint32_t i = 0; i < view_count; i++) { + views[i].type = XR_TYPE_VIEW; + views[i].next = NULL; + + projection_views[i].type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW; + projection_views[i].next = NULL; + projection_views[i].subImage.swapchain = swapchain; + projection_views[i].subImage.imageArrayIndex = i; + projection_views[i].subImage.imageRect.offset.x = 0; + projection_views[i].subImage.imageRect.offset.y = 0; + projection_views[i].subImage.imageRect.extent.width = recommended_size.width; + projection_views[i].subImage.imageRect.extent.height = recommended_size.height; + }; + + return true; +}; + +void OpenXRAPI::destroy_session() { + if (running && session != XR_NULL_HANDLE) { + xrEndSession(session); + } + + if (graphics_extension) { + graphics_extension->cleanup_swapchain_graphics_data(&swapchain_graphics_data); + } + + if (views != nullptr) { + memfree(views); + views = nullptr; + } + + if (projection_views != nullptr) { + memfree(projection_views); + projection_views = nullptr; + } + + if (swapchain != XR_NULL_HANDLE) { + xrDestroySwapchain(swapchain); + swapchain = XR_NULL_HANDLE; + } + + if (supported_swapchain_formats != nullptr) { + memfree(supported_swapchain_formats); + supported_swapchain_formats = nullptr; + } + + // destroy our spaces + if (play_space != XR_NULL_HANDLE) { + xrDestroySpace(play_space); + play_space = XR_NULL_HANDLE; + } + if (view_space != XR_NULL_HANDLE) { + xrDestroySpace(view_space); + view_space = XR_NULL_HANDLE; + } + + if (supported_reference_spaces != nullptr) { + // free previous results + memfree(supported_reference_spaces); + supported_reference_spaces = nullptr; + } + + if (session != XR_NULL_HANDLE) { + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_session_destroyed(); + } + + xrDestroySession(session); + session = XR_NULL_HANDLE; + } +} + +bool OpenXRAPI::create_swapchain(int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, XrSwapchain &r_swapchain, void **r_swapchain_graphics_data) { + ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false); + ERR_FAIL_NULL_V(graphics_extension, false); + + XrResult result; + + void *next_pointer = nullptr; + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + void *np = wrapper->set_swapchain_create_info_and_get_next_pointer(next_pointer); + if (np != nullptr) { + next_pointer = np; + } + } + + XrSwapchainCreateInfo swapchain_create_info = { + XR_TYPE_SWAPCHAIN_CREATE_INFO, // type + next_pointer, // next + 0, // createFlags + XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT, // usageFlags + p_swapchain_format, // format + p_sample_count, // sampleCount + p_width, // width + p_height, // height + 1, // faceCount + p_array_size, // arraySize + 1 // mipCount + }; + + XrSwapchain new_swapchain; + result = xrCreateSwapchain(session, &swapchain_create_info, &new_swapchain); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to get swapchain [", get_error_string(result), "]"); + return false; + } + + if (!graphics_extension->get_swapchain_image_data(new_swapchain, p_swapchain_format, p_width, p_height, p_array_size, p_array_size, r_swapchain_graphics_data)) { + xrDestroySwapchain(new_swapchain); + return false; + } + + r_swapchain = new_swapchain; + + return true; +} + +bool OpenXRAPI::on_state_idle() { +#ifdef DEBUG + print_line("On state idle"); +#endif + + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_state_idle(); + } + + return true; +} + +bool OpenXRAPI::on_state_ready() { +#ifdef DEBUG + print_line("On state ready"); +#endif + + // begin session + XrSessionBeginInfo session_begin_info = { + XR_TYPE_SESSION_BEGIN_INFO, // type + nullptr, // next + view_configuration // primaryViewConfigurationType + }; + + XrResult result = xrBeginSession(session, &session_begin_info); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to begin session [", get_error_string(result), "]"); + return false; + } + + // This is when we create our swapchain, this can be a "long" time after Godot finishes, we can deal with this for now + // but once we want to provide Viewports for additional layers where OpenXR requires us to create further swapchains, + // we'll be creating those viewport WAY before we reach this point. + // We may need to implement a wait in our init in main.cpp polling our events until the session is ready. + // That will be very very ugly + // The other possibility is to create a separate OpenXRViewport type specifically for this goal as part of our OpenXR module + + if (!create_main_swapchain()) { + return false; + } + + // we're running + running = true; + + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_state_ready(); + } + + // TODO emit signal + + // TODO Tell android + + return true; +} + +bool OpenXRAPI::on_state_synchronized() { +#ifdef DEBUG + print_line("On state synchronized"); +#endif + + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_state_synchronized(); + } + + return true; +} + +bool OpenXRAPI::on_state_visible() { +#ifdef DEBUG + print_line("On state visible"); +#endif + + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_state_visible(); + } + + // TODO emit signal + + return true; +} + +bool OpenXRAPI::on_state_focused() { +#ifdef DEBUG + print_line("On state focused"); +#endif + + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_state_focused(); + } + + // TODO emit signal + + return true; +} + +bool OpenXRAPI::on_state_stopping() { +#ifdef DEBUG + print_line("On state stopping"); +#endif + + // TODO emit signal + + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_state_stopping(); + } + + if (running) { + XrResult result = xrEndSession(session); + if (XR_FAILED(result)) { + // we only report this.. + print_line("OpenXR: Failed to end session [", get_error_string(result), "]"); + } + + running = false; + } + + // TODO further cleanup + + return true; +} + +bool OpenXRAPI::on_state_loss_pending() { +#ifdef DEBUG + print_line("On state loss pending"); +#endif + + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_state_loss_pending(); + } + + // TODO need to look into the correct action here, read up on the spec but we may need to signal Godot to exit (if it's not already exiting) + + return true; +} + +bool OpenXRAPI::on_state_exiting() { +#ifdef DEBUG + print_line("On state existing"); +#endif + + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_state_exiting(); + } + + // TODO need to look into the correct action here, read up on the spec but we may need to signal Godot to exit (if it's not already exiting) + + return true; +} + +bool OpenXRAPI::is_initialized() { + return (instance != XR_NULL_HANDLE); +} + +bool OpenXRAPI::is_running() { + if (instance == XR_NULL_HANDLE) { + return false; + } + if (session == XR_NULL_HANDLE) { + return false; + } + + return running; +} + +bool OpenXRAPI::initialise(const String &p_rendering_driver) { + ERR_FAIL_COND_V_MSG(instance != XR_NULL_HANDLE, false, "OpenXR instance was already created"); + + if (p_rendering_driver == "vulkan") { +#ifdef VULKAN_ENABLED + graphics_extension = memnew(OpenXRVulkanExtension(this)); + register_extension_wrapper(graphics_extension); +#else + // shouldn't be possible... + ERR_FAIL_V(false); +#endif + } else if (p_rendering_driver == "opengl3") { +#ifdef OPENGL3_ENABLED + // graphics_extension = memnew(OpenXROpenGLExtension(this)); + // register_extension_wrapper(graphics_extension); + ERR_FAIL_V_MSG(false, "OpenXR: OpenGL is not supported at this time."); +#else + // shouldn't be possible... + ERR_FAIL_V(false); +#endif + } else { + ERR_FAIL_V_MSG(false, "OpenXR: Unsupported rendering device."); + } + + // initialise + if (!load_layer_properties()) { + destroy_instance(); + return false; + } + + if (!load_supported_extensions()) { + destroy_instance(); + return false; + } + + if (!create_instance()) { + destroy_instance(); + return false; + } + + if (!get_system_info()) { + destroy_instance(); + return false; + } + + if (!load_supported_view_configuration_types()) { + destroy_instance(); + return false; + } + + if (!load_supported_view_configuration_views(view_configuration)) { + destroy_instance(); + return false; + } + + return true; +} + +bool OpenXRAPI::initialise_session() { + if (!create_session()) { + destroy_session(); + return false; + } + + if (!load_supported_reference_spaces()) { + destroy_session(); + return false; + } + + if (!setup_spaces()) { + destroy_session(); + return false; + } + + if (!load_supported_swapchain_formats()) { + destroy_session(); + return false; + } + + return true; +} + +void OpenXRAPI::finish() { + destroy_session(); + + destroy_instance(); +} + +void OpenXRAPI::register_extension_wrapper(OpenXRExtensionWrapper *p_extension_wrapper) { + registered_extension_wrappers.push_back(p_extension_wrapper); +} + +Size2 OpenXRAPI::get_recommended_target_size() { + ERR_FAIL_NULL_V(view_configuration_views, Size2()); + + Size2 target_size; + + target_size.width = view_configuration_views[0].recommendedImageRectWidth; + target_size.height = view_configuration_views[0].recommendedImageRectHeight; + + return target_size; +} + +XRPose::TrackingConfidence OpenXRAPI::get_head_center(Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity) { + XrResult result; + + ERR_FAIL_COND_V(!running, XRPose::XR_TRACKING_CONFIDENCE_NONE); + + // xrWaitFrame not run yet + if (frame_state.predictedDisplayTime == 0) { + return XRPose::XR_TRACKING_CONFIDENCE_NONE; + } + + // Get timing for the next frame, as that is the current frame we're processing + XrTime display_time = get_next_frame_time(); + + XrSpaceVelocity velocity = { + XR_TYPE_SPACE_VELOCITY, // type + nullptr, // next + 0, // velocityFlags + { 0.0, 0.0, 0.0 }, // linearVelocity + { 0.0, 0.0, 0.0 } // angularVelocity + }; + + XrSpaceLocation location = { + XR_TYPE_SPACE_LOCATION, // type + &velocity, // next + 0, // locationFlags + { + { 0.0, 0.0, 0.0, 0.0 }, // orientation + { 0.0, 0.0, 0.0 } // position + } // pose + }; + + result = xrLocateSpace(view_space, play_space, display_time, &location); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to locate view space in play space [", get_error_string(result), "]"); + return XRPose::XR_TRACKING_CONFIDENCE_NONE; + } + + XRPose::TrackingConfidence confidence = transform_from_location(location, r_transform); + parse_velocities(velocity, r_linear_velocity, r_angular_velocity); + + if (head_pose_confidence != confidence) { + // prevent error spam + head_pose_confidence = confidence; + if (head_pose_confidence == XRPose::XR_TRACKING_CONFIDENCE_NONE) { + print_line("OpenXR head space location not valid (check tracking?)"); +#ifdef DEBUG + } else if (head_pose_confidence == XRPose::XR_TRACKING_CONFIDENCE_LOW) { + print_line("OpenVR Head pose now tracking with low confidence"); + } else { + print_line("OpenVR Head pose now tracking with high confidence"); +#endif + } + } + + return confidence; +} + +bool OpenXRAPI::get_view_transform(uint32_t p_view, Transform3D &r_transform) { + ERR_FAIL_COND_V(!running, false); + + // xrWaitFrame not run yet + if (frame_state.predictedDisplayTime == 0) { + return false; + } + + // we don't have valid view info + if (views == NULL || !view_pose_valid) { + return false; + } + + // Note, the timing of this is set right before rendering, which is what we need here. + r_transform = transform_from_pose(views[p_view].pose); + + return true; +} + +bool OpenXRAPI::get_view_projection(uint32_t p_view, double p_z_near, double p_z_far, CameraMatrix &p_camera_matrix) { + ERR_FAIL_COND_V(!running, false); + ERR_FAIL_NULL_V(graphics_extension, false); + + // xrWaitFrame not run yet + if (frame_state.predictedDisplayTime == 0) { + return false; + } + + // we don't have valid view info + if (views == NULL || !view_pose_valid) { + return false; + } + + return graphics_extension->create_projection_fov(views[p_view].fov, p_z_near, p_z_far, p_camera_matrix); +} + +bool OpenXRAPI::poll_events() { + ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false); + + XrEventDataBuffer runtimeEvent; + runtimeEvent.type = XR_TYPE_EVENT_DATA_BUFFER; + runtimeEvent.next = nullptr; + // runtimeEvent.varying = ... + + XrResult pollResult = xrPollEvent(instance, &runtimeEvent); + while (pollResult == XR_SUCCESS) { + bool handled = false; + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + handled |= wrapper->on_event_polled(runtimeEvent); + } + switch (runtimeEvent.type) { + // case XR_TYPE_EVENT_DATA_EVENTS_LOST: { + // } break; + // case XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR: { + // } break; + // case XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING: { + // } break; + case XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED: { + XrEventDataSessionStateChanged *event = (XrEventDataSessionStateChanged *)&runtimeEvent; + + session_state = event->state; + if (session_state >= XR_SESSION_STATE_MAX_ENUM) { + print_line("OpenXR EVENT: session state changed to UNKNOWN -", session_state); + } else { + print_line("OpenXR EVENT: session state changed to", OpenXRUtil::get_session_state_name(session_state)); + + switch (session_state) { + case XR_SESSION_STATE_IDLE: + on_state_idle(); + break; + case XR_SESSION_STATE_READY: + on_state_ready(); + break; + case XR_SESSION_STATE_SYNCHRONIZED: + on_state_synchronized(); + break; + case XR_SESSION_STATE_VISIBLE: + on_state_visible(); + break; + case XR_SESSION_STATE_FOCUSED: + on_state_focused(); + break; + case XR_SESSION_STATE_STOPPING: + on_state_stopping(); + break; + case XR_SESSION_STATE_LOSS_PENDING: + on_state_loss_pending(); + break; + case XR_SESSION_STATE_EXITING: + on_state_exiting(); + break; + default: + break; + } + } + } break; + // case XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING: { + // } break; + // case XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED: { + // } break; + default: + if (!handled) { + print_line("OpenXR Unhandled event type", OpenXRUtil::get_structure_type_name(runtimeEvent.type)); + } + break; + } + + runtimeEvent.type = XR_TYPE_EVENT_DATA_BUFFER; + pollResult = xrPollEvent(instance, &runtimeEvent); + } + + if (pollResult == XR_EVENT_UNAVAILABLE) { + // processed all events in the queue + return true; + } else { + ERR_FAIL_V_MSG(false, "OpenXR: Failed to poll events!"); + } +} + +bool OpenXRAPI::process() { + ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false); + + if (!poll_events()) { + return false; + } + + if (!running) { + return false; + } + + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_process(); + } + + return true; +} + +bool OpenXRAPI::acquire_image(XrSwapchain p_swapchain, uint32_t &r_image_index) { + ERR_FAIL_COND_V(image_acquired, true); // this was not released when it should be, error out and re-use... + + XrResult result; + XrSwapchainImageAcquireInfo swapchain_image_acquire_info = { + XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO, // type + nullptr // next + }; + result = xrAcquireSwapchainImage(p_swapchain, &swapchain_image_acquire_info, &r_image_index); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to acquire swapchain image [", get_error_string(result), "]"); + return false; + } + + XrSwapchainImageWaitInfo swapchain_image_wait_info = { + XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO, // type + nullptr, // next + 17000000 // timeout in nanoseconds + }; + + result = xrWaitSwapchainImage(p_swapchain, &swapchain_image_wait_info); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to wait for swapchain image [", get_error_string(result), "]"); + return false; + } + + return true; +} + +bool OpenXRAPI::release_image(XrSwapchain p_swapchain) { + XrSwapchainImageReleaseInfo swapchain_image_release_info = { + XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO, // type + nullptr // next + }; + XrResult result = xrReleaseSwapchainImage(swapchain, &swapchain_image_release_info); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to release swapchain image! [", get_error_string(result), "]"); + return false; + } + + return true; +} + +void OpenXRAPI::pre_render() { + ERR_FAIL_COND(instance == XR_NULL_HANDLE); + + if (!running) { + return; + } + + // Waitframe does 2 important things in our process: + // 1) It provides us with predictive timing, telling us when OpenXR expects to display the frame we're about to commit + // 2) It will use the previous timing to pause our thread so that rendering starts as close to displaying as possible + // This must thus be called as close to when we start rendering as possible + XrFrameWaitInfo frame_wait_info = { XR_TYPE_FRAME_WAIT_INFO, nullptr }; + XrResult result = xrWaitFrame(session, &frame_wait_info, &frame_state); + if (XR_FAILED(result)) { + print_line("OpenXR: xrWaitFrame() was not successful [", get_error_string(result), "]"); + return; + } + + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_pre_render(); + } + + // Get our view info for the frame we're about to render, note from the OpenXR manual: + // "Repeatedly calling xrLocateViews with the same time may not necessarily return the same result. Instead the prediction gets increasingly accurate as the function is called closer to the given time for which a prediction is made" + + // We're calling this "relatively" early, the positioning we're obtaining here will be used to do our frustum culling, + // occlusion culling, etc. There is however a technique that we can investigate in the future where after our entire + // Vulkan command buffer is build, but right before vkSubmitQueue is called, we call xrLocateViews one more time and + // update the view and projection matrix once more with a slightly more accurate predication and then submit the + // command queues. + + // That is not possible yet but worth investigating in the future. + + XrViewLocateInfo view_locate_info = { + XR_TYPE_VIEW_LOCATE_INFO, // type + nullptr, // next + view_configuration, // viewConfigurationType + frame_state.predictedDisplayTime, // displayTime + play_space // space + }; + XrViewState view_state = { + XR_TYPE_VIEW_STATE, // type + nullptr, // next + 0 // viewStateFlags + }; + uint32_t view_count_output; + result = xrLocateViews(session, &view_locate_info, &view_state, view_count, &view_count_output, views); + if (XR_FAILED(result)) { + print_line("OpenXR: Couldn't locate views [", get_error_string(result), "]"); + return; + } + + bool pose_valid = true; + for (uint64_t i = 0; i < view_count_output; i++) { + if ((view_state.viewStateFlags & XR_VIEW_STATE_ORIENTATION_VALID_BIT) == 0 || + (view_state.viewStateFlags & XR_VIEW_STATE_POSITION_VALID_BIT) == 0) { + pose_valid = false; + } + } + if (view_pose_valid != pose_valid) { + view_pose_valid = pose_valid; +#ifdef DEBUG + if (!view_pose_valid) { + print_line("OpenXR View pose became invalid"); + } else { + print_line("OpenXR View pose became valid"); + } +#endif + } + + // let's start our frame.. + XrFrameBeginInfo frame_begin_info = { + XR_TYPE_FRAME_BEGIN_INFO, // type + nullptr // next + }; + result = xrBeginFrame(session, &frame_begin_info); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to being frame [", get_error_string(result), "]"); + return; + } +} + +bool OpenXRAPI::pre_draw_viewport(RID p_render_target) { + if (!can_render()) { + return false; + } + + // TODO: at some point in time we may support multiple viewports in which case we need to handle that... + + return true; +} + +void OpenXRAPI::post_draw_viewport(RID p_render_target) { + if (!can_render()) { + return; + } + + // TODO: at some point in time we may support multiple viewports in which case we need to handle that... + + // TODO: if we can get PR 51179 to work properly we can change away from this approach and move this into get_external_texture or something + if (!image_acquired) { + if (!acquire_image(swapchain, image_index)) { + return; + } + image_acquired = true; + + // print_line("OpenXR: acquired image " + itos(image_index) + ", copying..."); + + // Copy our buffer into our swap chain (remove once PR 51179 is done) + graphics_extension->copy_render_target_to_image(p_render_target, swapchain_graphics_data, image_index); + } +}; + +void OpenXRAPI::end_frame() { + XrResult result; + + ERR_FAIL_COND(instance == XR_NULL_HANDLE); + + if (!running) { + return; + } + + if (frame_state.shouldRender && view_pose_valid && !image_acquired) { + print_line("OpenXR: No viewport was marked with use_xr, there is no rendered output!"); + } + + // must have: + // - shouldRender set to true + // - a valid view pose for projection_views[eye].pose to submit layer + // - an image to render + if (!frame_state.shouldRender || !view_pose_valid || !image_acquired) { + // submit 0 layers when we shouldn't render + XrFrameEndInfo frame_end_info = { + XR_TYPE_FRAME_END_INFO, // type + nullptr, // next + frame_state.predictedDisplayTime, // displayTime + XR_ENVIRONMENT_BLEND_MODE_OPAQUE, // environmentBlendMode + 0, // layerCount + nullptr // layers + }; + result = xrEndFrame(session, &frame_end_info); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to end frame! [", get_error_string(result), "]"); + return; + } + + // neither eye is rendered + return; + } + + // release our swapchain image if we acquired it + if (image_acquired) { + image_acquired = false; // whether we succeed or not, consider this released. + + release_image(swapchain); + } + + for (uint32_t eye = 0; eye < view_count; eye++) { + projection_views[eye].fov = views[eye].fov; + projection_views[eye].pose = views[eye].pose; + } + + Vector<const XrCompositionLayerBaseHeader *> layers_list; + + // Add composition layers from providers + for (OpenXRCompositionLayerProvider *provider : composition_layer_providers) { + XrCompositionLayerBaseHeader *layer = provider->get_composition_layer(); + if (layer) { + layers_list.push_back(layer); + } + } + + XrCompositionLayerProjection projection_layer = { + XR_TYPE_COMPOSITION_LAYER_PROJECTION, // type + nullptr, // next + layers_list.size() > 1 ? XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT | XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT : XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT, // layerFlags + play_space, // space + view_count, // viewCount + projection_views, // views + }; + layers_list.push_back((const XrCompositionLayerBaseHeader *)&projection_layer); + + XrFrameEndInfo frame_end_info = { + XR_TYPE_FRAME_END_INFO, // type + nullptr, // next + frame_state.predictedDisplayTime, // displayTime + XR_ENVIRONMENT_BLEND_MODE_OPAQUE, // environmentBlendMode + static_cast<uint32_t>(layers_list.size()), // layerCount + layers_list.ptr() // layers + }; + result = xrEndFrame(session, &frame_end_info); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to end frame! [", get_error_string(result), "]"); + return; + } +} + +OpenXRAPI::OpenXRAPI() { + // OpenXRAPI is only constructed if OpenXR is enabled. + // It will be constructed when the rendering device first accesses OpenXR (be it the Vulkan or OpenGL rendering system) + + if (Engine::get_singleton()->is_editor_hint()) { + // Enabled OpenXR in the editor? Adjust our settings for the editor + + } else { + // Load settings from project settings + int ff = GLOBAL_GET("xr/openxr/form_factor"); + switch (ff) { + case 0: { + form_factor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY; + } break; + case 1: { + form_factor = XR_FORM_FACTOR_HANDHELD_DISPLAY; + } break; + default: + break; + } + + int vc = GLOBAL_GET("xr/openxr/view_configuration"); + switch (vc) { + case 0: { + view_configuration = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO; + } break; + case 1: { + view_configuration = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO; + } break; + /* we don't support quad and observer configurations (yet) + case 2: { + view_configuration = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_QUAD_VARJO; + } break; + case 3: { + view_configuration = XR_VIEW_CONFIGURATION_TYPE_SECONDARY_MONO_FIRST_PERSON_OBSERVER_MSFT; + } break; + */ + default: + break; + } + + int rs = GLOBAL_GET("xr/openxr/reference_space"); + switch (rs) { + case 0: { + reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL; + } break; + case 1: { + reference_space = XR_REFERENCE_SPACE_TYPE_STAGE; + } break; + default: + break; + } + } + + // reset a few things that can't be done in our class definition + frame_state.predictedDisplayTime = 0; + frame_state.predictedDisplayPeriod = 0; + +#ifdef ANDROID_ENABLED + // our android wrapper will initialise our android loader at this point + register_extension_wrapper(memnew(OpenXRAndroidExtension(this))); +#endif +} + +OpenXRAPI::~OpenXRAPI() { + // cleanup our composition layer providers + for (OpenXRCompositionLayerProvider *provider : composition_layer_providers) { + memdelete(provider); + } + composition_layer_providers.clear(); + + // cleanup our extension wrappers + for (OpenXRExtensionWrapper *extension_wrapper : registered_extension_wrappers) { + memdelete(extension_wrapper); + } + registered_extension_wrappers.clear(); + + if (supported_extensions != nullptr) { + memfree(supported_extensions); + supported_extensions = nullptr; + } + + if (layer_properties != nullptr) { + memfree(layer_properties); + layer_properties = nullptr; + } +} + +Transform3D OpenXRAPI::transform_from_pose(const XrPosef &p_pose) { + Quaternion q(p_pose.orientation.x, p_pose.orientation.y, p_pose.orientation.z, p_pose.orientation.w); + Basis basis(q); + Vector3 origin(p_pose.position.x, p_pose.position.y, p_pose.position.z); + + return Transform3D(basis, origin); +} + +template <typename T> +XRPose::TrackingConfidence _transform_from_location(const T &p_location, Transform3D &r_transform) { + Basis basis; + Vector3 origin; + XRPose::TrackingConfidence confidence = XRPose::XR_TRACKING_CONFIDENCE_NONE; + const auto &pose = p_location.pose; + + // Check orientation + if (p_location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) { + Quaternion q(pose.orientation.x, pose.orientation.y, pose.orientation.z, pose.orientation.w); + r_transform.basis = Basis(q); + + if (p_location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT) { + // Fully valid orientation, so either 3DOF or 6DOF tracking with high confidence so default to HIGH_TRACKING + confidence = XRPose::XR_TRACKING_CONFIDENCE_HIGH; + } else { + // Orientation is being tracked but we're using old/predicted data, so low tracking confidence + confidence = XRPose::XR_TRACKING_CONFIDENCE_LOW; + } + } else { + r_transform.basis = Basis(); + } + + // Check location + if (p_location.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) { + r_transform.origin = Vector3(pose.position.x, pose.position.y, pose.position.z); + + if (!(p_location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT)) { + // Location is being tracked but we're using old/predicted data, so low tracking confidence + confidence = XRPose::XR_TRACKING_CONFIDENCE_LOW; + } else if (confidence == XRPose::XR_TRACKING_CONFIDENCE_NONE) { + // Position tracking without orientation tracking? + confidence = XRPose::XR_TRACKING_CONFIDENCE_HIGH; + } + } else { + // No tracking or 3DOF I guess.. + r_transform.origin = Vector3(); + } + + return confidence; +} + +XRPose::TrackingConfidence OpenXRAPI::transform_from_location(const XrSpaceLocation &p_location, Transform3D &r_transform) { + return _transform_from_location(p_location, r_transform); +} + +XRPose::TrackingConfidence OpenXRAPI::transform_from_location(const XrHandJointLocationEXT &p_location, Transform3D &r_transform) { + return _transform_from_location(p_location, r_transform); +} + +void OpenXRAPI::parse_velocities(const XrSpaceVelocity &p_velocity, Vector3 &r_linear_velocity, Vector3 r_angular_velocity) { + if (p_velocity.velocityFlags & XR_SPACE_VELOCITY_LINEAR_VALID_BIT) { + XrVector3f linear_velocity = p_velocity.linearVelocity; + r_linear_velocity = Vector3(linear_velocity.x, linear_velocity.y, linear_velocity.z); + } else { + r_linear_velocity = Vector3(); + } + if (p_velocity.velocityFlags & XR_SPACE_VELOCITY_ANGULAR_VALID_BIT) { + XrVector3f angular_velocity = p_velocity.angularVelocity; + r_angular_velocity = Vector3(angular_velocity.x, angular_velocity.y, angular_velocity.z); + } else { + r_angular_velocity = Vector3(); + } +} + +RID OpenXRAPI::path_create(const String p_name) { + ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, RID()); + + // Encoding our path as a RID is probably overkill but it does future proof this + // Note that we only do this for XrPaths that we access from outside of this class! + + Path new_path; + + print_line("Parsing path ", p_name); + + XrResult result = xrStringToPath(instance, p_name.utf8().get_data(), &new_path.path); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to get path for ", p_name, "! [", get_error_string(result), "]"); + return RID(); + } + + return xr_path_owner.make_rid(new_path); +} + +void OpenXRAPI::path_free(RID p_path) { + Path *path = xr_path_owner.get_or_null(p_path); + ERR_FAIL_NULL(path); + + // there is nothing to free here + + xr_path_owner.free(p_path); +} + +RID OpenXRAPI::action_set_create(const String p_name, const String p_localized_name, const int p_priority) { + ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, RID()); + ActionSet action_set; + + action_set.is_attached = false; + + // create our action set... + XrActionSetCreateInfo action_set_info = { + XR_TYPE_ACTION_SET_CREATE_INFO, // type + nullptr, // next + "", // actionSetName + "", // localizedActionSetName + uint32_t(p_priority) // priority + }; + + copy_string_to_char_buffer(p_name, action_set_info.actionSetName, XR_MAX_ACTION_SET_NAME_SIZE); + copy_string_to_char_buffer(p_localized_name, action_set_info.localizedActionSetName, XR_MAX_LOCALIZED_ACTION_SET_NAME_SIZE); + + print_line("Creating action set ", action_set_info.actionSetName, " - ", action_set_info.localizedActionSetName, " (", itos(action_set_info.priority), ")"); + + XrResult result = xrCreateActionSet(instance, &action_set_info, &action_set.handle); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to create action set ", p_name, "! [", get_error_string(result), "]"); + return RID(); + } + + return action_set_owner.make_rid(action_set); +} + +bool OpenXRAPI::action_set_attach(RID p_action_set) { + ActionSet *action_set = action_set_owner.get_or_null(p_action_set); + ERR_FAIL_NULL_V(action_set, false); + + if (action_set->is_attached) { + // already attached + return true; + } + + ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false); + + // So according to the docs, once we attach our action set to our session it becomes read only.. + // https://www.khronos.org/registry/OpenXR/specs/1.0/man/html/xrAttachSessionActionSets.html + XrSessionActionSetsAttachInfo attach_info = { + XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO, // type + nullptr, // next + 1, // countActionSets, + &action_set->handle // actionSets + }; + + XrResult result = xrAttachSessionActionSets(session, &attach_info); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to attach action set! [", get_error_string(result), "]"); + return false; + } + + action_set->is_attached = true; + + return true; +} + +void OpenXRAPI::action_set_free(RID p_action_set) { + ActionSet *action_set = action_set_owner.get_or_null(p_action_set); + ERR_FAIL_NULL(action_set); + + if (action_set->handle != XR_NULL_HANDLE) { + xrDestroyActionSet(action_set->handle); + } + + action_set_owner.free(p_action_set); +} + +RID OpenXRAPI::action_create(RID p_action_set, const String p_name, const String p_localized_name, OpenXRAction::ActionType p_action_type, const Vector<RID> &p_toplevel_paths) { + ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, RID()); + + Action action; + + ActionSet *action_set = action_set_owner.get_or_null(p_action_set); + ERR_FAIL_NULL_V(action_set, RID()); + ERR_FAIL_COND_V(action_set->handle == XR_NULL_HANDLE, RID()); + + switch (p_action_type) { + case OpenXRAction::OPENXR_ACTION_BOOL: + action.action_type = XR_ACTION_TYPE_BOOLEAN_INPUT; + break; + case OpenXRAction::OPENXR_ACTION_FLOAT: + action.action_type = XR_ACTION_TYPE_FLOAT_INPUT; + break; + case OpenXRAction::OPENXR_ACTION_VECTOR2: + action.action_type = XR_ACTION_TYPE_VECTOR2F_INPUT; + break; + case OpenXRAction::OPENXR_ACTION_POSE: + action.action_type = XR_ACTION_TYPE_POSE_INPUT; + break; + case OpenXRAction::OPENXR_ACTION_HAPTIC: + action.action_type = XR_ACTION_TYPE_VIBRATION_OUTPUT; + break; + default: + ERR_FAIL_V(RID()); + break; + } + + Vector<XrPath> toplevel_paths; + for (int i = 0; i < p_toplevel_paths.size(); i++) { + Path *xr_path = xr_path_owner.get_or_null(p_toplevel_paths[i]); + if (xr_path != nullptr && xr_path->path != XR_NULL_PATH) { + PathWithSpace path_with_space = { + xr_path->path, // toplevel_path + XR_NULL_HANDLE, // space + false // was_location_valid + }; + action.toplevel_paths.push_back(path_with_space); + + toplevel_paths.push_back(xr_path->path); + } + } + + XrActionCreateInfo action_info = { + XR_TYPE_ACTION_CREATE_INFO, // type + nullptr, // next + "", // actionName + action.action_type, // actionType + uint32_t(toplevel_paths.size()), // countSubactionPaths + toplevel_paths.ptr(), // subactionPaths + "" // localizedActionName + }; + + copy_string_to_char_buffer(p_name, action_info.actionName, XR_MAX_ACTION_NAME_SIZE); + copy_string_to_char_buffer(p_localized_name, action_info.localizedActionName, XR_MAX_LOCALIZED_ACTION_NAME_SIZE); + + print_line("Creating action ", action_info.actionName, action_info.localizedActionName, action_info.countSubactionPaths); + + XrResult result = xrCreateAction(action_set->handle, &action_info, &action.handle); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to create action ", p_name, "! [", get_error_string(result), "]"); + return RID(); + } + + return action_owner.make_rid(action); +} + +void OpenXRAPI::action_free(RID p_action) { + Action *action = action_owner.get_or_null(p_action); + ERR_FAIL_NULL(action); + + if (action->handle != XR_NULL_HANDLE) { + xrDestroyAction(action->handle); + } + + action_owner.free(p_action); +} + +bool OpenXRAPI::suggest_bindings(const String p_interaction_profile, const Vector<Binding> p_bindings) { + ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false); + + XrPath interaction_profile; + Vector<XrActionSuggestedBinding> bindings; + + XrResult result = xrStringToPath(instance, p_interaction_profile.utf8().get_data(), &interaction_profile); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to get path for ", p_interaction_profile, "! [", get_error_string(result), "]"); + return false; + } + + for (int i = 0; i < p_bindings.size(); i++) { + XrActionSuggestedBinding binding; + + Action *action = action_owner.get_or_null(p_bindings[i].action); + if (action == nullptr || action->handle == XR_NULL_HANDLE) { + // just skip it + continue; + } + + binding.action = action->handle; + + result = xrStringToPath(instance, p_bindings[i].path.utf8().get_data(), &binding.binding); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to get path for ", p_bindings[i].path, "! [", get_error_string(result), "]"); + continue; + } + + bindings.push_back(binding); + } + + const XrInteractionProfileSuggestedBinding suggested_bindings = { + XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING, // type + nullptr, // next + interaction_profile, // interactionProfile + uint32_t(bindings.size()), // countSuggestedBindings + bindings.ptr() // suggestedBindings + }; + + result = xrSuggestInteractionProfileBindings(instance, &suggested_bindings); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to suggest bindings for ", p_interaction_profile, "! [", get_error_string(result), "]"); + // reporting is enough... + } + + return true; +} + +bool OpenXRAPI::sync_action_sets(const Vector<RID> p_active_sets) { + ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false); + + if (!running) { + return false; + } + + Vector<XrActiveActionSet> active_sets; + for (int i = 0; i < p_active_sets.size(); i++) { + ActionSet *action_set = action_set_owner.get_or_null(p_active_sets[i]); + if (action_set && action_set->handle != XR_NULL_HANDLE) { + XrActiveActionSet aset; + aset.actionSet = action_set->handle; + aset.subactionPath = XR_NULL_PATH; + active_sets.push_back(aset); + } + } + + ERR_FAIL_COND_V(active_sets.size() == 0, false); + + XrActionsSyncInfo sync_info = { + XR_TYPE_ACTIONS_SYNC_INFO, // type + nullptr, // next + uint32_t(active_sets.size()), // countActiveActionSets + active_sets.ptr() // activeActionSets + }; + + XrResult result = xrSyncActions(session, &sync_info); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to sync active action sets! [", get_error_string(result), "]"); + return false; + } + + return true; +} + +bool OpenXRAPI::get_action_bool(RID p_action, RID p_path) { + ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false); + Action *action = action_owner.get_or_null(p_action); + ERR_FAIL_NULL_V(action, false); + Path *path = xr_path_owner.get_or_null(p_path); + ERR_FAIL_NULL_V(path, false); + + if (!running) { + return false; + } + + ERR_FAIL_COND_V(action->action_type != XR_ACTION_TYPE_BOOLEAN_INPUT, false); + + XrActionStateGetInfo get_info = { + XR_TYPE_ACTION_STATE_GET_INFO, // type + nullptr, // next + action->handle, // action + path->path // subactionPath + }; + + XrActionStateBoolean result_state; + result_state.type = XR_TYPE_ACTION_STATE_BOOLEAN, + result_state.next = nullptr; + XrResult result = xrGetActionStateBoolean(session, &get_info, &result_state); + if (XR_FAILED(result)) { + print_line("OpenXR: couldn't get action boolean! [", get_error_string(result), "]"); + return false; + } + + return result_state.isActive && result_state.currentState; +} + +float OpenXRAPI::get_action_float(RID p_action, RID p_path) { + ERR_FAIL_COND_V(session == XR_NULL_HANDLE, 0.0); + Action *action = action_owner.get_or_null(p_action); + ERR_FAIL_NULL_V(action, 0.0); + Path *path = xr_path_owner.get_or_null(p_path); + ERR_FAIL_NULL_V(path, 0.0); + + if (!running) { + return 0.0; + } + + ERR_FAIL_COND_V(action->action_type != XR_ACTION_TYPE_FLOAT_INPUT, 0.0); + + XrActionStateGetInfo get_info = { + XR_TYPE_ACTION_STATE_GET_INFO, // type + nullptr, // next + action->handle, // action + path->path // subactionPath + }; + + XrActionStateFloat result_state; + result_state.type = XR_TYPE_ACTION_STATE_FLOAT, + result_state.next = nullptr; + XrResult result = xrGetActionStateFloat(session, &get_info, &result_state); + if (XR_FAILED(result)) { + print_line("OpenXR: couldn't get action float! [", get_error_string(result), "]"); + return 0.0; + } + + return result_state.isActive ? result_state.currentState : 0.0; +} + +Vector2 OpenXRAPI::get_action_vector2(RID p_action, RID p_path) { + ERR_FAIL_COND_V(session == XR_NULL_HANDLE, Vector2()); + Action *action = action_owner.get_or_null(p_action); + ERR_FAIL_NULL_V(action, Vector2()); + Path *path = xr_path_owner.get_or_null(p_path); + ERR_FAIL_NULL_V(path, Vector2()); + + if (!running) { + return Vector2(); + } + + ERR_FAIL_COND_V(action->action_type != XR_ACTION_TYPE_VECTOR2F_INPUT, Vector2()); + + XrActionStateGetInfo get_info = { + XR_TYPE_ACTION_STATE_GET_INFO, // type + nullptr, // next + action->handle, // action + path->path // subactionPath + }; + + XrActionStateVector2f result_state; + result_state.type = XR_TYPE_ACTION_STATE_VECTOR2F, + result_state.next = nullptr; + XrResult result = xrGetActionStateVector2f(session, &get_info, &result_state); + if (XR_FAILED(result)) { + print_line("OpenXR: couldn't get action vector2! [", get_error_string(result), "]"); + return Vector2(); + } + + return result_state.isActive ? Vector2(result_state.currentState.x, result_state.currentState.y) : Vector2(); +} + +XRPose::TrackingConfidence OpenXRAPI::get_action_pose(RID p_action, RID p_path, Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity) { + ERR_FAIL_COND_V(session == XR_NULL_HANDLE, XRPose::XR_TRACKING_CONFIDENCE_NONE); + Action *action = action_owner.get_or_null(p_action); + ERR_FAIL_NULL_V(action, XRPose::XR_TRACKING_CONFIDENCE_NONE); + Path *path = xr_path_owner.get_or_null(p_path); + ERR_FAIL_NULL_V(path, XRPose::XR_TRACKING_CONFIDENCE_NONE); + + if (!running) { + return XRPose::XR_TRACKING_CONFIDENCE_NONE; + } + + ERR_FAIL_COND_V(action->action_type != XR_ACTION_TYPE_POSE_INPUT, XRPose::XR_TRACKING_CONFIDENCE_NONE); + + uint64_t index = 0xFFFFFFFF; + uint64_t size = uint64_t(action->toplevel_paths.size()); + for (uint64_t i = 0; i < size && index == 0xFFFFFFFF; i++) { + if (action->toplevel_paths[i].toplevel_path == path->path) { + index = i; + } + } + + if (index == 0xFFFFFFFF) { + // couldn't find it? + return XRPose::XR_TRACKING_CONFIDENCE_NONE; + } + + if (action->toplevel_paths[index].space == XR_NULL_HANDLE) { + // if this is a pose we need to define spaces + + XrActionSpaceCreateInfo action_space_info = { + XR_TYPE_ACTION_SPACE_CREATE_INFO, // type + nullptr, // next + action->handle, // action + action->toplevel_paths[index].toplevel_path, // subactionPath + { + { 0.0, 0.0, 0.0, 1.0 }, // orientation + { 0.0, 0.0, 0.0 } // position + } // poseInActionSpace + }; + + XrSpace space; + XrResult result = xrCreateActionSpace(session, &action_space_info, &space); + if (XR_FAILED(result)) { + print_line("OpenXR: couldn't create action space! [", get_error_string(result), "]"); + return XRPose::XR_TRACKING_CONFIDENCE_NONE; + } + + action->toplevel_paths.ptrw()[index].space = space; + } + + XrTime display_time = get_next_frame_time(); + + XrSpaceVelocity velocity = { + XR_TYPE_SPACE_VELOCITY, // type + nullptr, // next + 0, // velocityFlags + { 0.0, 0.0, 0.0 }, // linearVelocity + { 0.0, 0.0, 0.0 } // angularVelocity + }; + + XrSpaceLocation location = { + XR_TYPE_SPACE_LOCATION, // type + &velocity, // next + 0, // locationFlags + { + { 0.0, 0.0, 0.0, 0.0 }, // orientation + { 0.0, 0.0, 0.0 } // position + } // pose + }; + + XrResult result = xrLocateSpace(action->toplevel_paths[index].space, play_space, display_time, &location); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to locate space! [", get_error_string(result), "]"); + return XRPose::XR_TRACKING_CONFIDENCE_NONE; + } + + XRPose::TrackingConfidence confidence = transform_from_location(location, r_transform); + parse_velocities(velocity, r_linear_velocity, r_angular_velocity); + + return confidence; +} + +bool OpenXRAPI::trigger_haptic_pulse(RID p_action, RID p_path, float p_frequency, float p_amplitude, XrDuration p_duration_ns) { + ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false); + Action *action = action_owner.get_or_null(p_action); + ERR_FAIL_NULL_V(action, false); + Path *path = xr_path_owner.get_or_null(p_path); + ERR_FAIL_NULL_V(path, false); + + if (!running) { + return false; + } + + ERR_FAIL_COND_V(action->action_type != XR_ACTION_TYPE_VIBRATION_OUTPUT, false); + + XrHapticActionInfo action_info = { + XR_TYPE_HAPTIC_ACTION_INFO, // type + nullptr, // next + action->handle, // action + path->path // subactionPath + }; + + XrHapticVibration vibration = { + XR_TYPE_HAPTIC_VIBRATION, // type + nullptr, // next + p_duration_ns, // duration + p_frequency, // frequency + p_amplitude, // amplitude + }; + + XrResult result = xrApplyHapticFeedback(session, &action_info, (const XrHapticBaseHeader *)&vibration); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to apply haptic feedback! [", get_error_string(result), "]"); + return false; + } + + return true; +} diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h new file mode 100644 index 0000000000..33b503543a --- /dev/null +++ b/modules/openxr/openxr_api.h @@ -0,0 +1,261 @@ +/*************************************************************************/ +/* openxr_api.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef OPENXR_DRIVER_H +#define OPENXR_DRIVER_H + +#include "core/error/error_macros.h" +#include "core/math/camera_matrix.h" +#include "core/math/transform_3d.h" +#include "core/math/vector2.h" +#include "core/os/memory.h" +#include "core/string/ustring.h" +#include "core/templates/map.h" +#include "core/templates/rid_owner.h" +#include "core/templates/vector.h" +#include "servers/xr/xr_pose.h" + +#include "thirdparty/openxr/src/common/xr_linear.h" +#include <openxr/openxr.h> + +#include "action_map/openxr_action.h" + +#include "extensions/openxr_composition_layer_provider.h" +#include "extensions/openxr_extension_wrapper.h" + +// Note, OpenXR code that we wrote for our plugin makes use of C++20 notation for initialising structs which ensures zeroing out unspecified members. +// Godot is currently restricted to C++17 which doesn't allow this notation. Make sure critical fields are set. + +// forward declarations, we don't want to include these fully +class OpenXRVulkanExtension; + +class OpenXRAPI { +private: + // our singleton + static OpenXRAPI *singleton; + + // layers + uint32_t num_layer_properties = 0; + XrApiLayerProperties *layer_properties = nullptr; + + // extensions + uint32_t num_supported_extensions = 0; + XrExtensionProperties *supported_extensions = nullptr; + Vector<OpenXRExtensionWrapper *> registered_extension_wrappers; + Vector<const char *> enabled_extensions; + + // composition layer providers + Vector<OpenXRCompositionLayerProvider *> composition_layer_providers; + + // view configuration + uint32_t num_view_configuration_types = 0; + XrViewConfigurationType *supported_view_configuration_types = nullptr; + + // reference spaces + uint32_t num_reference_spaces = 0; + XrReferenceSpaceType *supported_reference_spaces = nullptr; + + // swapchains (note these are platform dependent) + uint32_t num_swapchain_formats = 0; + int64_t *supported_swapchain_formats = nullptr; + + // configuration + XrFormFactor form_factor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY; + XrViewConfigurationType view_configuration = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO; + XrReferenceSpaceType reference_space = XR_REFERENCE_SPACE_TYPE_STAGE; + XrEnvironmentBlendMode environment_blend_mode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE; + + // state + XrInstance instance = XR_NULL_HANDLE; + XrSystemId system_id; + String system_name; + uint32_t vendor_id; + XrSystemTrackingProperties tracking_properties; + XrSession session = XR_NULL_HANDLE; + XrSessionState session_state = XR_SESSION_STATE_UNKNOWN; + bool running = false; + XrFrameState frame_state = { XR_TYPE_FRAME_STATE, NULL, 0, 0, false }; + + OpenXRGraphicsExtensionWrapper *graphics_extension = nullptr; + XrSystemGraphicsProperties graphics_properties; + void *swapchain_graphics_data = nullptr; + uint32_t image_index = 0; + bool image_acquired = false; + + uint32_t view_count = 0; + XrViewConfigurationView *view_configuration_views = nullptr; + XrView *views = nullptr; + XrCompositionLayerProjectionView *projection_views = nullptr; + XrSwapchain swapchain = XR_NULL_HANDLE; + + XrSpace play_space = XR_NULL_HANDLE; + XrSpace view_space = XR_NULL_HANDLE; + bool view_pose_valid = false; + XRPose::TrackingConfidence head_pose_confidence = XRPose::XR_TRACKING_CONFIDENCE_NONE; + + bool load_layer_properties(); + bool load_supported_extensions(); + bool is_extension_supported(const char *p_extension) const; + + // instance + bool create_instance(); + bool get_system_info(); + bool load_supported_view_configuration_types(); + bool is_view_configuration_supported(XrViewConfigurationType p_configuration_type) const; + bool load_supported_view_configuration_views(XrViewConfigurationType p_configuration_type); + void destroy_instance(); + + // session + bool create_session(); + bool load_supported_reference_spaces(); + bool is_reference_space_supported(XrReferenceSpaceType p_reference_space); + bool setup_spaces(); + bool load_supported_swapchain_formats(); + bool is_swapchain_format_supported(int64_t p_swapchain_format); + bool create_main_swapchain(); + void destroy_session(); + + // swapchains + bool create_swapchain(int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, XrSwapchain &r_swapchain, void **r_swapchain_graphics_data); + bool acquire_image(XrSwapchain p_swapchain, uint32_t &r_image_index); + bool release_image(XrSwapchain p_swapchain); + + // action map + struct Path { + XrPath path; + }; + RID_Owner<Path, true> xr_path_owner; + + struct ActionSet { + bool is_attached; + XrActionSet handle; + }; + RID_Owner<ActionSet, true> action_set_owner; + + struct PathWithSpace { + XrPath toplevel_path; + XrSpace space; + bool was_location_valid; + }; + + struct Action { + XrActionType action_type; + Vector<PathWithSpace> toplevel_paths; + XrAction handle; + }; + RID_Owner<Action, true> action_owner; + + // state changes + bool poll_events(); + bool on_state_idle(); + bool on_state_ready(); + bool on_state_synchronized(); + bool on_state_visible(); + bool on_state_focused(); + bool on_state_stopping(); + bool on_state_loss_pending(); + bool on_state_exiting(); + + // convencience + void copy_string_to_char_buffer(const String p_string, char *p_buffer, int p_buffer_len); + +protected: + friend class OpenXRVulkanExtension; + + XrInstance get_instance() const { return instance; }; + XrSystemId get_system_id() const { return system_id; }; + XrSession get_session() const { return session; }; + + // helper method to convert an XrPosef to a Transform3D + Transform3D transform_from_pose(const XrPosef &p_pose); + + // helper method to get a valid Transform3D from an openxr space location + XRPose::TrackingConfidence transform_from_location(const XrSpaceLocation &p_location, Transform3D &r_transform); + XRPose::TrackingConfidence transform_from_location(const XrHandJointLocationEXT &p_location, Transform3D &r_transform); + void parse_velocities(const XrSpaceVelocity &p_velocity, Vector3 &r_linear_velocity, Vector3 r_angular_velocity); + +public: + static void setup_global_defs(); + static bool openxr_is_enabled(); + static OpenXRAPI *get_singleton(); + + String get_error_string(XrResult result); + String get_swapchain_format_name(int64_t p_swapchain_format) const; + + void register_extension_wrapper(OpenXRExtensionWrapper *p_extension_wrapper); + + bool is_initialized(); + bool is_running(); + bool initialise(const String &p_rendering_driver); + bool initialise_session(); + void finish(); + + XrTime get_next_frame_time() { return frame_state.predictedDisplayTime + frame_state.predictedDisplayPeriod; }; + bool can_render() { return instance != XR_NULL_HANDLE && session != XR_NULL_HANDLE && running && view_pose_valid && frame_state.shouldRender; }; + + Size2 get_recommended_target_size(); + XRPose::TrackingConfidence get_head_center(Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity); + bool get_view_transform(uint32_t p_view, Transform3D &r_transform); + bool get_view_projection(uint32_t p_view, double p_z_near, double p_z_far, CameraMatrix &p_camera_matrix); + bool process(); + + void pre_render(); + bool pre_draw_viewport(RID p_render_target); + void post_draw_viewport(RID p_render_target); + void end_frame(); + + // action map + String get_default_action_map_resource_name(); + RID path_create(const String p_name); + void path_free(RID p_path); + RID action_set_create(const String p_name, const String p_localized_name, const int p_priority); + bool action_set_attach(RID p_action_set); + void action_set_free(RID p_action_set); + RID action_create(RID p_action_set, const String p_name, const String p_localized_name, OpenXRAction::ActionType p_action_type, const Vector<RID> &p_toplevel_paths); + void action_free(RID p_action); + + struct Binding { + RID action; + String path; + }; + bool suggest_bindings(const String p_interaction_profile, const Vector<Binding> p_bindings); + + bool sync_action_sets(const Vector<RID> p_active_sets); + bool get_action_bool(RID p_action, RID p_path); + float get_action_float(RID p_action, RID p_path); + Vector2 get_action_vector2(RID p_action, RID p_path); + XRPose::TrackingConfidence get_action_pose(RID p_action, RID p_path, Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity); + bool trigger_haptic_pulse(RID p_action, RID p_path, float p_frequency, float p_amplitude, XrDuration p_duration_ns); + + OpenXRAPI(); + ~OpenXRAPI(); +}; + +#endif // !OPENXR_DRIVER_H diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp new file mode 100644 index 0000000000..394f634687 --- /dev/null +++ b/modules/openxr/openxr_interface.cpp @@ -0,0 +1,663 @@ +/*************************************************************************/ +/* openxr_interface.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "openxr_interface.h" + +#include "core/io/resource_loader.h" +#include "core/io/resource_saver.h" +#include "servers/rendering/rendering_server_globals.h" + +void OpenXRInterface::_bind_methods() { + // todo +} + +StringName OpenXRInterface::get_name() const { + return StringName("OpenXR"); +}; + +uint32_t OpenXRInterface::get_capabilities() const { + return XRInterface::XR_VR + XRInterface::XR_STEREO; +}; + +XRInterface::TrackingStatus OpenXRInterface::get_tracking_status() const { + return tracking_state; +} + +void OpenXRInterface::_load_action_map() { + ERR_FAIL_NULL(openxr_api); + + // This may seem a bit duplicitous to a little bit of background info here. + // OpenXRActionMap (with all its sub resource classes) is a class that allows us to configure and store an action map in. + // This gives the user the ability to edit the action map in a UI and customise the actions. + // OpenXR however requires us to submit an action map and it takes over from that point and we can no longer change it. + // This system does that push and we store the info needed to then work with this action map going forward. + + // Within our openxr device we maintain a number of classes that wrap the relevant OpenXR objects for this. + // Within OpenXRInterface we have a few internal classes that keep track of what we've created. + // This allow us to process the relevant actions each frame. + + // just in case clean up + free_action_sets(); + free_trackers(); + + Ref<OpenXRActionMap> action_map; + if (Engine::get_singleton()->is_editor_hint()) { +#ifdef TOOLS_ENABLED + action_map.instantiate(); + action_map->create_editor_action_sets(); +#endif + } else { + String default_tres_name = openxr_api->get_default_action_map_resource_name(); + + // Check if we can load our default + if (ResourceLoader::exists(default_tres_name)) { + action_map = ResourceLoader::load(default_tres_name); + } + + // Check if we need to create default action set + if (action_map.is_null()) { + action_map.instantiate(); + action_map->create_default_action_sets(); +#ifdef TOOLS_ENABLED + // Save our action sets so our user can + action_map->set_path(default_tres_name, true); + ResourceSaver::save(default_tres_name, action_map); +#endif + } + } + + // process our action map + if (action_map.is_valid()) { + Map<Ref<OpenXRAction>, RID> action_rids; + + Array action_sets = action_map->get_action_sets(); + for (int i = 0; i < action_sets.size(); i++) { + // Create our action set + Ref<OpenXRActionSet> xr_action_set = action_sets[i]; + ActionSet *action_set = create_action_set(xr_action_set->get_name(), xr_action_set->get_localized_name(), xr_action_set->get_priority()); + if (!action_set) { + continue; + } + + // Now create our actions for these + Array actions = xr_action_set->get_actions(); + for (int j = 0; j < actions.size(); j++) { + Ref<OpenXRAction> xr_action = actions[j]; + + PackedStringArray toplevel_paths = xr_action->get_toplevel_paths(); + Vector<RID> toplevel_rids; + Vector<Tracker *> trackers; + + for (int k = 0; k < toplevel_paths.size(); k++) { + Tracker *tracker = get_tracker(toplevel_paths[k]); + if (tracker) { + toplevel_rids.push_back(tracker->path_rid); + trackers.push_back(tracker); + } + } + + Action *action = create_action(action_set, xr_action->get_name(), xr_action->get_localized_name(), xr_action->get_action_type(), toplevel_rids); + if (action) { + // we link our actions back to our trackers so we know which actions to check when we're processing our trackers + for (int t = 0; t < trackers.size(); t++) { + link_action_to_tracker(trackers[t], action); + } + + // add this to our map for creating our interaction profiles + action_rids[xr_action] = action->action_rid; + } + } + } + + // now do our suggestions + Array interaction_profiles = action_map->get_interaction_profiles(); + for (int i = 0; i < interaction_profiles.size(); i++) { + Vector<OpenXRAPI::Binding> bindings; + Ref<OpenXRInteractionProfile> xr_interaction_profile = interaction_profiles[i]; + + Array xr_bindings = xr_interaction_profile->get_bindings(); + for (int j = 0; j < xr_bindings.size(); j++) { + Ref<OpenXRIPBinding> xr_binding = xr_bindings[j]; + Ref<OpenXRAction> xr_action = xr_binding->get_action(); + OpenXRAPI::Binding binding; + + if (action_rids.has(xr_action)) { + binding.action = action_rids[xr_action]; + } else { + print_line("Action ", xr_action->get_name(), " isn't part of an action set!"); + continue; + } + + PackedStringArray xr_paths = xr_binding->get_paths(); + for (int k = 0; k < xr_paths.size(); k++) { + binding.path = xr_paths[k]; + bindings.push_back(binding); + } + } + + openxr_api->suggest_bindings(xr_interaction_profile->get_interaction_profile_path(), bindings); + } + } +} + +OpenXRInterface::ActionSet *OpenXRInterface::create_action_set(const String &p_action_set_name, const String &p_localized_name, const int p_priority) { + ERR_FAIL_NULL_V(openxr_api, nullptr); + + // find if it already exists + for (int i = 0; i < action_sets.size(); i++) { + if (action_sets[i]->action_set_name == p_action_set_name) { + // already exists in this set + return nullptr; + } + } + + ActionSet *action_set = memnew(ActionSet); + action_set->action_set_name = p_action_set_name; + action_set->is_active = true; + action_set->action_set_rid = openxr_api->action_set_create(p_action_set_name, p_localized_name, p_priority); + action_sets.push_back(action_set); + + return action_set; +} + +void OpenXRInterface::free_action_sets() { + ERR_FAIL_NULL(openxr_api); + + for (int i = 0; i < action_sets.size(); i++) { + ActionSet *action_set = action_sets[i]; + + openxr_api->path_free(action_set->action_set_rid); + free_actions(action_set); + + memfree(action_set); + } + action_sets.clear(); +} + +OpenXRInterface::Action *OpenXRInterface::create_action(ActionSet *p_action_set, const String &p_action_name, const String &p_localized_name, OpenXRAction::ActionType p_action_type, const Vector<RID> p_toplevel_paths) { + ERR_FAIL_NULL_V(openxr_api, nullptr); + + for (int i = 0; i < p_action_set->actions.size(); i++) { + if (p_action_set->actions[i]->action_name == p_action_name) { + // already exists in this set + return nullptr; + } + } + + Action *action = memnew(Action); + action->action_name = p_action_name; + action->action_type = p_action_type; + action->action_rid = openxr_api->action_create(p_action_set->action_set_rid, p_action_name, p_localized_name, p_action_type, p_toplevel_paths); + p_action_set->actions.push_back(action); + + return action; +} + +OpenXRInterface::Action *OpenXRInterface::find_action(const String &p_action_name) { + // We just find the first action by this name + + for (int i = 0; i < action_sets.size(); i++) { + for (int j = 0; j < action_sets[i]->actions.size(); j++) { + if (action_sets[i]->actions[j]->action_name == p_action_name) { + return action_sets[i]->actions[j]; + } + } + } + + // not found + return nullptr; +} + +void OpenXRInterface::free_actions(ActionSet *p_action_set) { + ERR_FAIL_NULL(openxr_api); + + for (int i = 0; i < p_action_set->actions.size(); i++) { + Action *action = p_action_set->actions[i]; + + openxr_api->action_free(action->action_rid); + + memdelete(action); + } + p_action_set->actions.clear(); +} + +OpenXRInterface::Tracker *OpenXRInterface::get_tracker(const String &p_path_name) { + XRServer *xr_server = XRServer::get_singleton(); + ERR_FAIL_NULL_V(xr_server, nullptr); + ERR_FAIL_NULL_V(openxr_api, nullptr); + + Tracker *tracker = nullptr; + for (int i = 0; i < trackers.size(); i++) { + tracker = trackers[i]; + if (tracker->path_name == p_path_name) { + return tracker; + } + } + + // create our positional tracker + Ref<XRPositionalTracker> positional_tracker; + positional_tracker.instantiate(); + + // We have standardised some names to make things nicer to the user so lets recognise the toplevel paths related to these. + if (p_path_name == "/user/hand/left") { + positional_tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER); + positional_tracker->set_tracker_name("left_hand"); + positional_tracker->set_tracker_desc("Left hand controller"); + positional_tracker->set_tracker_hand(XRPositionalTracker::TRACKER_HAND_LEFT); + } else if (p_path_name == "/user/hand/right") { + positional_tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER); + positional_tracker->set_tracker_name("right_hand"); + positional_tracker->set_tracker_desc("Right hand controller"); + positional_tracker->set_tracker_hand(XRPositionalTracker::TRACKER_HAND_RIGHT); + } else { + positional_tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER); + positional_tracker->set_tracker_name(p_path_name); + positional_tracker->set_tracker_desc(p_path_name); + } + xr_server->add_tracker(positional_tracker); + + // create a new entry + tracker = memnew(Tracker); + tracker->path_name = p_path_name; + tracker->path_rid = openxr_api->path_create(p_path_name); + tracker->positional_tracker = positional_tracker; + trackers.push_back(tracker); + + return tracker; +} + +OpenXRInterface::Tracker *OpenXRInterface::find_tracker(const String &p_positional_tracker_name) { + for (int i = 0; i < trackers.size(); i++) { + Tracker *tracker = trackers[i]; + if (tracker->positional_tracker.is_valid() && tracker->positional_tracker->get_tracker_name() == p_positional_tracker_name) { + return tracker; + } + } + + return nullptr; +} + +void OpenXRInterface::link_action_to_tracker(Tracker *p_tracker, Action *p_action) { + if (p_tracker->actions.find(p_action) == -1) { + p_tracker->actions.push_back(p_action); + } +} + +void OpenXRInterface::handle_tracker(Tracker *p_tracker) { + ERR_FAIL_NULL(openxr_api); + ERR_FAIL_COND(p_tracker->positional_tracker.is_null()); + + // handle all the actions + for (int i = 0; i < p_tracker->actions.size(); i++) { + Action *action = p_tracker->actions[i]; + switch (action->action_type) { + case OpenXRAction::OPENXR_ACTION_BOOL: { + bool pressed = openxr_api->get_action_bool(action->action_rid, p_tracker->path_rid); + p_tracker->positional_tracker->set_input(action->action_name, Variant(pressed)); + } break; + case OpenXRAction::OPENXR_ACTION_FLOAT: { + real_t value = openxr_api->get_action_float(action->action_rid, p_tracker->path_rid); + p_tracker->positional_tracker->set_input(action->action_name, Variant(value)); + } break; + case OpenXRAction::OPENXR_ACTION_VECTOR2: { + Vector2 value = openxr_api->get_action_vector2(action->action_rid, p_tracker->path_rid); + p_tracker->positional_tracker->set_input(action->action_name, Variant(value)); + } break; + case OpenXRAction::OPENXR_ACTION_POSE: { + Transform3D transform; + Vector3 linear, angular; + XRPose::TrackingConfidence confidence = openxr_api->get_action_pose(action->action_rid, p_tracker->path_rid, transform, linear, angular); + if (confidence != XRPose::XR_TRACKING_CONFIDENCE_NONE) { + String name; + // We can't have dual action names in OpenXR hence we added _pose, but default, aim and grip and default pose action names in Godot so rename them on the tracker. + // NOTE need to decide on whether we should keep the naming convention or rename it on Godots side + if (action->action_name == "default_pose") { + name = "default"; + } else if (action->action_name == "aim_pose") { + name = "aim"; + } else if (action->action_name == "grip_pose") { + name = "grip"; + } else { + name = action->action_name; + } + p_tracker->positional_tracker->set_pose(name, transform, linear, angular, confidence); + } + } break; + default: { + // not yet supported + } break; + } + } +} + +void OpenXRInterface::trigger_haptic_pulse(const String &p_action_name, const StringName &p_tracker_name, double p_frequency, double p_amplitude, double p_duration_sec, double p_delay_sec) { + ERR_FAIL_NULL(openxr_api); + Action *action = find_action(p_action_name); + ERR_FAIL_NULL(action); + Tracker *tracker = find_tracker(p_tracker_name); + ERR_FAIL_NULL(tracker); + + // TODO OpenXR does not support delay, so we may need to add support for that somehow... + + XrDuration duration = XrDuration(p_duration_sec * 1000000000.0); // seconds -> nanoseconds + + openxr_api->trigger_haptic_pulse(action->action_rid, tracker->path_rid, p_frequency, p_amplitude, duration); +} + +void OpenXRInterface::free_trackers() { + XRServer *xr_server = XRServer::get_singleton(); + ERR_FAIL_NULL(xr_server); + ERR_FAIL_NULL(openxr_api); + + for (int i = 0; i < trackers.size(); i++) { + Tracker *tracker = trackers[i]; + + openxr_api->path_free(tracker->path_rid); + xr_server->remove_tracker(tracker->positional_tracker); + tracker->positional_tracker.unref(); + + memdelete(tracker); + } + trackers.clear(); +} + +bool OpenXRInterface::initialise_on_startup() const { + if (openxr_api == nullptr) { + return false; + } else if (!openxr_api->is_initialized()) { + return false; + } else { + return true; + } +} + +bool OpenXRInterface::is_initialized() const { + return initialized; +}; + +bool OpenXRInterface::initialize() { + XRServer *xr_server = XRServer::get_singleton(); + ERR_FAIL_NULL_V(xr_server, false); + + if (openxr_api == nullptr) { + return false; + } else if (!openxr_api->is_initialized()) { + return false; + } else if (initialized) { + return true; + } + + // load up our action sets before setting up our session, note that our profiles are suggestions, OpenXR takes ownership of (re)binding + _load_action_map(); + + if (!openxr_api->initialise_session()) { + return false; + } + + // we must create a tracker for our head + head.instantiate(); + head->set_tracker_type(XRServer::TRACKER_HEAD); + head->set_tracker_name("head"); + head->set_tracker_desc("Players head"); + xr_server->add_tracker(head); + + // attach action sets + for (int i = 0; i < action_sets.size(); i++) { + openxr_api->action_set_attach(action_sets[i]->action_set_rid); + } + + // make this our primary interface + xr_server->set_primary_interface(this); + + initialized = true; + + return initialized; +} + +void OpenXRInterface::uninitialize() { + // Our OpenXR driver will clean itself up properly when Godot exits, so we just do some basic stuff here + + // end the session if we need to? + + // cleanup stuff + free_action_sets(); + free_trackers(); + + XRServer *xr_server = XRServer::get_singleton(); + if (xr_server) { + if (head.is_valid()) { + xr_server->remove_tracker(head); + + head.unref(); + } + } + + initialized = false; +} + +bool OpenXRInterface::supports_play_area_mode(XRInterface::PlayAreaMode p_mode) { + return false; +} + +XRInterface::PlayAreaMode OpenXRInterface::get_play_area_mode() const { + return XRInterface::XR_PLAY_AREA_UNKNOWN; +} + +bool OpenXRInterface::set_play_area_mode(XRInterface::PlayAreaMode p_mode) { + return false; +} + +Size2 OpenXRInterface::get_render_target_size() { + if (openxr_api == nullptr) { + return Size2(); + } else { + return openxr_api->get_recommended_target_size(); + } +} + +uint32_t OpenXRInterface::get_view_count() { + // TODO set this based on our configuration + return 2; +} + +void OpenXRInterface::_set_default_pos(Transform3D &p_transform, double p_world_scale, uint64_t p_eye) { + p_transform = Transform3D(); + + // if we're not tracking, don't put our head on the floor... + p_transform.origin.y = 1.5 * p_world_scale; + + // overkill but.. + if (p_eye == 1) { + p_transform.origin.x = 0.03 * p_world_scale; + } else if (p_eye == 2) { + p_transform.origin.x = -0.03 * p_world_scale; + } +} + +Transform3D OpenXRInterface::get_camera_transform() { + XRServer *xr_server = XRServer::get_singleton(); + ERR_FAIL_NULL_V(xr_server, Transform3D()); + + Transform3D hmd_transform; + double world_scale = xr_server->get_world_scale(); + + // head_transform should be updated in process + + hmd_transform.basis = head_transform.basis; + hmd_transform.origin = head_transform.origin * world_scale; + + return hmd_transform; +} + +Transform3D OpenXRInterface::get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) { + XRServer *xr_server = XRServer::get_singleton(); + ERR_FAIL_NULL_V(xr_server, Transform3D()); + + Transform3D t; + if (openxr_api && openxr_api->get_view_transform(p_view, t)) { + // update our cached value if we have a valid transform + transform_for_view[p_view] = t; + } else { + // reuse cached value + t = transform_for_view[p_view]; + } + + // Apply our world scale + double world_scale = xr_server->get_world_scale(); + t.origin *= world_scale; + + return p_cam_transform * xr_server->get_reference_frame() * t; +} + +CameraMatrix OpenXRInterface::get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) { + CameraMatrix cm; + + if (openxr_api) { + if (openxr_api->get_view_projection(p_view, p_z_near, p_z_far, cm)) { + return cm; + } + } + + // Failed to get from our OpenXR device? Default to some sort of sensible camera matrix.. + cm.set_for_hmd(p_view + 1, 1.0, 6.0, 14.5, 4.0, 1.5, p_z_near, p_z_far); + + return cm; +} + +void OpenXRInterface::process() { + if (openxr_api) { + // do our normal process + if (openxr_api->process()) { + Transform3D t; + Vector3 linear_velocity; + Vector3 angular_velocity; + XRPose::TrackingConfidence confidence = openxr_api->get_head_center(t, linear_velocity, angular_velocity); + if (confidence != XRPose::XR_TRACKING_CONFIDENCE_NONE) { + // Only update our transform if we have one to update it with + // note that poses are stored without world scale and reference frame applied! + head_transform = t; + head_linear_velocity = linear_velocity; + head_angular_velocity = angular_velocity; + } + } + + // handle our action sets.... + Vector<RID> active_sets; + for (int i = 0; i < action_sets.size(); i++) { + if (action_sets[i]->is_active) { + active_sets.push_back(action_sets[i]->action_set_rid); + } + } + + if (openxr_api->sync_action_sets(active_sets)) { + for (int i = 0; i < trackers.size(); i++) { + handle_tracker(trackers[i]); + } + } + } + + if (head.is_valid()) { + // TODO figure out how to get our velocities + + head->set_pose("default", head_transform, head_linear_velocity, head_angular_velocity); + + // TODO set confidence on pose once we support tracking this.. + } +} + +void OpenXRInterface::pre_render() { + if (openxr_api) { + openxr_api->pre_render(); + } +} + +bool OpenXRInterface::pre_draw_viewport(RID p_render_target) { + if (openxr_api) { + return openxr_api->pre_draw_viewport(p_render_target); + } else { + // don't render + return false; + } +} + +Vector<BlitToScreen> OpenXRInterface::post_draw_viewport(RID p_render_target, const Rect2 &p_screen_rect) { + Vector<BlitToScreen> blit_to_screen; + + // If separate HMD we should output one eye to screen + if (p_screen_rect != Rect2()) { + BlitToScreen blit; + + blit.render_target = p_render_target; + blit.multi_view.use_layer = true; + blit.multi_view.layer = 0; + blit.lens_distortion.apply = false; + + Size2 render_size = get_render_target_size(); + Rect2 dst_rect = p_screen_rect; + float new_height = dst_rect.size.x * (render_size.y / render_size.x); + if (new_height > dst_rect.size.y) { + dst_rect.position.y = (0.5 * dst_rect.size.y) - (0.5 * new_height); + dst_rect.size.y = new_height; + } else { + float new_width = dst_rect.size.y * (render_size.x / render_size.y); + + dst_rect.position.x = (0.5 * dst_rect.size.x) - (0.5 * new_width); + dst_rect.size.x = new_width; + } + + blit.dst_rect = dst_rect; + blit_to_screen.push_back(blit); + } + + if (openxr_api) { + openxr_api->post_draw_viewport(p_render_target); + } + + return blit_to_screen; +} + +void OpenXRInterface::end_frame() { + if (openxr_api) { + openxr_api->end_frame(); + } +} + +OpenXRInterface::OpenXRInterface() { + openxr_api = OpenXRAPI::get_singleton(); + + // while we don't have head tracking, don't put the headset on the floor... + _set_default_pos(head_transform, 1.0, 0); + _set_default_pos(transform_for_view[0], 1.0, 1); + _set_default_pos(transform_for_view[1], 1.0, 2); +} + +OpenXRInterface::~OpenXRInterface() { + openxr_api = nullptr; +} diff --git a/modules/openxr/openxr_interface.h b/modules/openxr/openxr_interface.h new file mode 100644 index 0000000000..ede7d481d2 --- /dev/null +++ b/modules/openxr/openxr_interface.h @@ -0,0 +1,129 @@ +/*************************************************************************/ +/* openxr_interface.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef OPENXR_INTERFACE_H +#define OPENXR_INTERFACE_H + +#include "servers/xr/xr_interface.h" +#include "servers/xr/xr_positional_tracker.h" + +#include "action_map/openxr_action_map.h" +#include "openxr_api.h" + +class OpenXRInterface : public XRInterface { + GDCLASS(OpenXRInterface, XRInterface); + +private: + OpenXRAPI *openxr_api = nullptr; + bool initialized = false; + XRInterface::TrackingStatus tracking_state; + + // At a minimum we need a tracker for our head + Ref<XRPositionalTracker> head; + Transform3D head_transform; + Vector3 head_linear_velocity; + Vector3 head_angular_velocity; + Transform3D transform_for_view[2]; // We currently assume 2, but could be 4 for VARJO which we do not support yet + + void _load_action_map(); + + struct Action { + String action_name; + OpenXRAction::ActionType action_type; + RID action_rid; + }; + struct ActionSet { + String action_set_name; + bool is_active; + RID action_set_rid; + Vector<Action *> actions; + }; + struct Tracker { + String path_name; + RID path_rid; + Ref<XRPositionalTracker> positional_tracker; + Vector<Action *> actions; + }; + + Vector<ActionSet *> action_sets; + Vector<Tracker *> trackers; + + ActionSet *create_action_set(const String &p_action_set_name, const String &p_localized_name, const int p_priority); + void free_action_sets(); + + Action *create_action(ActionSet *p_action_set, const String &p_action_name, const String &p_localized_name, OpenXRAction::ActionType p_action_type, const Vector<RID> p_toplevel_paths); + Action *find_action(const String &p_action_name); + void free_actions(ActionSet *p_action_set); + + Tracker *get_tracker(const String &p_path_name); + Tracker *find_tracker(const String &p_positional_tracker_name); + void link_action_to_tracker(Tracker *p_tracker, Action *p_action); + void handle_tracker(Tracker *p_tracker); + void free_trackers(); + + void _set_default_pos(Transform3D &p_transform, double p_world_scale, uint64_t p_eye); + +protected: + static void _bind_methods(); + +public: + virtual StringName get_name() const override; + virtual uint32_t get_capabilities() const override; + + virtual TrackingStatus get_tracking_status() const override; + + bool initialise_on_startup() const; + virtual bool is_initialized() const override; + virtual bool initialize() override; + virtual void uninitialize() override; + + virtual void trigger_haptic_pulse(const String &p_action_name, const StringName &p_tracker_name, double p_frequency, double p_amplitude, double p_duration_sec, double p_delay_sec = 0) override; + + virtual bool supports_play_area_mode(XRInterface::PlayAreaMode p_mode) override; + virtual XRInterface::PlayAreaMode get_play_area_mode() const override; + virtual bool set_play_area_mode(XRInterface::PlayAreaMode p_mode) override; + + virtual Size2 get_render_target_size() override; + virtual uint32_t get_view_count() override; + virtual Transform3D get_camera_transform() override; + virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) override; + virtual CameraMatrix get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) override; + + virtual void process() override; + virtual void pre_render() override; + bool pre_draw_viewport(RID p_render_target) override; + virtual Vector<BlitToScreen> post_draw_viewport(RID p_render_target, const Rect2 &p_screen_rect) override; + virtual void end_frame() override; + + OpenXRInterface(); + ~OpenXRInterface(); +}; + +#endif // !OPENXR_INTERFACE_H diff --git a/modules/openxr/openxr_util.cpp b/modules/openxr/openxr_util.cpp new file mode 100644 index 0000000000..e515336daa --- /dev/null +++ b/modules/openxr/openxr_util.cpp @@ -0,0 +1,291 @@ +/*************************************************************************/ +/* openxr_util.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "openxr_util.h" + +#define ENUM_TO_STRING_CASE(e) \ + case e: { \ + return String(#e); \ + } break; + +// TODO see if we can generate this code further using the xml file with meta data supplied by OpenXR + +String OpenXRUtil::get_view_configuration_name(XrViewConfigurationType p_view_configuration) { + switch (p_view_configuration) { + ENUM_TO_STRING_CASE(XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO) + ENUM_TO_STRING_CASE(XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO) + ENUM_TO_STRING_CASE(XR_VIEW_CONFIGURATION_TYPE_PRIMARY_QUAD_VARJO) + ENUM_TO_STRING_CASE(XR_VIEW_CONFIGURATION_TYPE_SECONDARY_MONO_FIRST_PERSON_OBSERVER_MSFT) + ENUM_TO_STRING_CASE(XR_VIEW_CONFIGURATION_TYPE_MAX_ENUM) + default: { + return String("View Configuration ") + String::num_int64(int64_t(p_view_configuration)); + } break; + } +} + +String OpenXRUtil::get_reference_space_name(XrReferenceSpaceType p_reference_space) { + switch (p_reference_space) { + ENUM_TO_STRING_CASE(XR_REFERENCE_SPACE_TYPE_VIEW) + ENUM_TO_STRING_CASE(XR_REFERENCE_SPACE_TYPE_LOCAL) + ENUM_TO_STRING_CASE(XR_REFERENCE_SPACE_TYPE_STAGE) + ENUM_TO_STRING_CASE(XR_REFERENCE_SPACE_TYPE_UNBOUNDED_MSFT) + ENUM_TO_STRING_CASE(XR_REFERENCE_SPACE_TYPE_COMBINED_EYE_VARJO) + ENUM_TO_STRING_CASE(XR_REFERENCE_SPACE_TYPE_MAX_ENUM) + default: { + return String("Reference space ") + String::num_int64(int64_t(p_reference_space)); + } break; + } +} + +String OpenXRUtil::get_structure_type_name(XrStructureType p_structure_type) { + switch (p_structure_type) { + ENUM_TO_STRING_CASE(XR_TYPE_UNKNOWN) + ENUM_TO_STRING_CASE(XR_TYPE_API_LAYER_PROPERTIES) + ENUM_TO_STRING_CASE(XR_TYPE_EXTENSION_PROPERTIES) + ENUM_TO_STRING_CASE(XR_TYPE_INSTANCE_CREATE_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_GET_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_PROPERTIES) + ENUM_TO_STRING_CASE(XR_TYPE_VIEW_LOCATE_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_VIEW) + ENUM_TO_STRING_CASE(XR_TYPE_SESSION_CREATE_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_CREATE_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_SESSION_BEGIN_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_VIEW_STATE) + ENUM_TO_STRING_CASE(XR_TYPE_FRAME_END_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_HAPTIC_VIBRATION) + ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_BUFFER) + ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING) + ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED) + ENUM_TO_STRING_CASE(XR_TYPE_ACTION_STATE_BOOLEAN) + ENUM_TO_STRING_CASE(XR_TYPE_ACTION_STATE_FLOAT) + ENUM_TO_STRING_CASE(XR_TYPE_ACTION_STATE_VECTOR2F) + ENUM_TO_STRING_CASE(XR_TYPE_ACTION_STATE_POSE) + ENUM_TO_STRING_CASE(XR_TYPE_ACTION_SET_CREATE_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_ACTION_CREATE_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_INSTANCE_PROPERTIES) + ENUM_TO_STRING_CASE(XR_TYPE_FRAME_WAIT_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_PROJECTION) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_QUAD) + ENUM_TO_STRING_CASE(XR_TYPE_REFERENCE_SPACE_CREATE_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_ACTION_SPACE_CREATE_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING) + ENUM_TO_STRING_CASE(XR_TYPE_VIEW_CONFIGURATION_VIEW) + ENUM_TO_STRING_CASE(XR_TYPE_SPACE_LOCATION) + ENUM_TO_STRING_CASE(XR_TYPE_SPACE_VELOCITY) + ENUM_TO_STRING_CASE(XR_TYPE_FRAME_STATE) + ENUM_TO_STRING_CASE(XR_TYPE_VIEW_CONFIGURATION_PROPERTIES) + ENUM_TO_STRING_CASE(XR_TYPE_FRAME_BEGIN_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW) + ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_EVENTS_LOST) + ENUM_TO_STRING_CASE(XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING) + ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED) + ENUM_TO_STRING_CASE(XR_TYPE_INTERACTION_PROFILE_STATE) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_ACTION_STATE_GET_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_HAPTIC_ACTION_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_ACTIONS_SYNC_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_CUBE_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_VULKAN_SWAPCHAIN_FORMAT_LIST_CREATE_INFO_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_PERF_SETTINGS_EXT) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT) + ENUM_TO_STRING_CASE(XR_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT) + ENUM_TO_STRING_CASE(XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) + ENUM_TO_STRING_CASE(XR_TYPE_DEBUG_UTILS_LABEL_EXT) + ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_BINDING_OPENGL_XCB_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_BINDING_OPENGL_WAYLAND_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_BINDING_D3D11_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_BINDING_D3D12_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_IMAGE_D3D12_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_REQUIREMENTS_D3D12_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_EYE_GAZE_INTERACTION_PROPERTIES_EXT) + ENUM_TO_STRING_CASE(XR_TYPE_EYE_GAZE_SAMPLE_TIME_EXT) + ENUM_TO_STRING_CASE(XR_TYPE_VISIBILITY_MASK_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_SESSION_CREATE_INFO_OVERLAY_EXTX) + ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_MAIN_SESSION_VISIBILITY_CHANGED_EXTX) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_COLOR_SCALE_BIAS_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SPATIAL_ANCHOR_SPACE_CREATE_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_IMAGE_LAYOUT_FB) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_ALPHA_BLEND_FB) + ENUM_TO_STRING_CASE(XR_TYPE_VIEW_CONFIGURATION_DEPTH_RANGE_EXT) + ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_BINDING_EGL_MNDX) + ENUM_TO_STRING_CASE(XR_TYPE_SPATIAL_GRAPH_NODE_SPACE_CREATE_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT) + ENUM_TO_STRING_CASE(XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT) + ENUM_TO_STRING_CASE(XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT) + ENUM_TO_STRING_CASE(XR_TYPE_HAND_JOINT_LOCATIONS_EXT) + ENUM_TO_STRING_CASE(XR_TYPE_HAND_JOINT_VELOCITIES_EXT) + ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_HAND_TRACKING_MESH_PROPERTIES_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_HAND_MESH_SPACE_CREATE_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_HAND_MESH_UPDATE_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_HAND_MESH_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_HAND_POSE_TYPE_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SESSION_BEGIN_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_STATE_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_STATE_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_END_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_LAYER_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SWAPCHAIN_CREATE_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_CONTROLLER_MODEL_KEY_STATE_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_CONTROLLER_MODEL_NODE_PROPERTIES_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_CONTROLLER_MODEL_PROPERTIES_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_CONTROLLER_MODEL_NODE_STATE_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_CONTROLLER_MODEL_STATE_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_VIEW_CONFIGURATION_VIEW_FOV_EPIC) + ENUM_TO_STRING_CASE(XR_TYPE_HOLOGRAPHIC_WINDOW_ATTACHMENT_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_REPROJECTION_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_REPROJECTION_PLANE_OVERRIDE_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_ANDROID_SURFACE_SWAPCHAIN_CREATE_INFO_FB) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_SECURE_CONTENT_FB) + ENUM_TO_STRING_CASE(XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE) + ENUM_TO_STRING_CASE(XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT) + ENUM_TO_STRING_CASE(XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_OBSERVER_CREATE_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_CREATE_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_NEW_SCENE_COMPUTE_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_VISUAL_MESH_COMPUTE_LOD_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_COMPONENTS_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_COMPONENTS_GET_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_COMPONENT_LOCATIONS_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_COMPONENTS_LOCATE_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_OBJECTS_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_COMPONENT_PARENT_FILTER_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_OBJECT_TYPES_FILTER_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_PLANES_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_PLANE_ALIGNMENT_FILTER_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_MESHES_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_MESH_BUFFERS_GET_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_MESH_BUFFERS_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_MESH_VERTEX_BUFFER_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_MESH_INDICES_UINT32_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_MESH_INDICES_UINT16_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SERIALIZED_SCENE_FRAGMENT_DATA_GET_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_DESERIALIZE_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB) + ENUM_TO_STRING_CASE(XR_TYPE_VIVE_TRACKER_PATHS_HTCX) + ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_VIVE_TRACKER_CONNECTED_HTCX) + ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_COLOR_SPACE_PROPERTIES_FB) + ENUM_TO_STRING_CASE(XR_TYPE_HAND_TRACKING_MESH_FB) + ENUM_TO_STRING_CASE(XR_TYPE_HAND_TRACKING_SCALE_FB) + ENUM_TO_STRING_CASE(XR_TYPE_HAND_TRACKING_AIM_STATE_FB) + ENUM_TO_STRING_CASE(XR_TYPE_HAND_TRACKING_CAPSULES_STATE_FB) + ENUM_TO_STRING_CASE(XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB) + ENUM_TO_STRING_CASE(XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB) + ENUM_TO_STRING_CASE(XR_TYPE_TRIANGLE_MESH_CREATE_INFO_FB) + ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES_FB) + ENUM_TO_STRING_CASE(XR_TYPE_PASSTHROUGH_CREATE_INFO_FB) + ENUM_TO_STRING_CASE(XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB) + ENUM_TO_STRING_CASE(XR_TYPE_GEOMETRY_INSTANCE_CREATE_INFO_FB) + ENUM_TO_STRING_CASE(XR_TYPE_GEOMETRY_INSTANCE_TRANSFORM_FB) + ENUM_TO_STRING_CASE(XR_TYPE_PASSTHROUGH_STYLE_FB) + ENUM_TO_STRING_CASE(XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_RGBA_FB) + ENUM_TO_STRING_CASE(XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_MONO_FB) + ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_PASSTHROUGH_STATE_CHANGED_FB) + ENUM_TO_STRING_CASE(XR_TYPE_BINDING_MODIFICATIONS_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_VIEW_LOCATE_FOVEATED_RENDERING_VARJO) + ENUM_TO_STRING_CASE(XR_TYPE_FOVEATED_VIEW_CONFIGURATION_VIEW_VARJO) + ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_FOVEATED_RENDERING_PROPERTIES_VARJO) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_VARJO) + ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_MARKER_TRACKING_PROPERTIES_VARJO) + ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO) + ENUM_TO_STRING_CASE(XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO) + ENUM_TO_STRING_CASE(XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_IMAGE_FOVEATION_VULKAN_FB) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_SPACE_WARP_INFO_FB) + ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_SPACE_WARP_PROPERTIES_FB) + ENUM_TO_STRING_CASE(XR_STRUCTURE_TYPE_MAX_ENUM) + default: { + return String("Structure type ") + String::num_int64(int64_t(p_structure_type)); + } break; + } +} + +String OpenXRUtil::get_session_state_name(XrSessionState p_session_state) { + switch (p_session_state) { + ENUM_TO_STRING_CASE(XR_SESSION_STATE_UNKNOWN) + ENUM_TO_STRING_CASE(XR_SESSION_STATE_IDLE) + ENUM_TO_STRING_CASE(XR_SESSION_STATE_READY) + ENUM_TO_STRING_CASE(XR_SESSION_STATE_SYNCHRONIZED) + ENUM_TO_STRING_CASE(XR_SESSION_STATE_VISIBLE) + ENUM_TO_STRING_CASE(XR_SESSION_STATE_FOCUSED) + ENUM_TO_STRING_CASE(XR_SESSION_STATE_STOPPING) + ENUM_TO_STRING_CASE(XR_SESSION_STATE_LOSS_PENDING) + ENUM_TO_STRING_CASE(XR_SESSION_STATE_EXITING) + ENUM_TO_STRING_CASE(XR_SESSION_STATE_MAX_ENUM) + default: { + return String("Session state ") + String::num_int64(int64_t(p_session_state)); + } break; + } +} + +String OpenXRUtil::make_xr_version_string(XrVersion p_version) { + String version; + + version += String::num_int64(XR_VERSION_MAJOR(p_version)); + version += String("."); + version += String::num_int64(XR_VERSION_MINOR(p_version)); + version += String("."); + version += String::num_int64(XR_VERSION_PATCH(p_version)); + + return version; +} diff --git a/modules/openxr/openxr_util.h b/modules/openxr/openxr_util.h new file mode 100644 index 0000000000..1261268376 --- /dev/null +++ b/modules/openxr/openxr_util.h @@ -0,0 +1,46 @@ +/*************************************************************************/ +/* openxr_util.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef OPENXR_UTIL_H +#define OPENXR_UTIL_H + +#include "core/string/ustring.h" +#include <openxr/openxr.h> + +class OpenXRUtil { +public: + static String get_view_configuration_name(XrViewConfigurationType p_view_configuration); + static String get_reference_space_name(XrReferenceSpaceType p_reference_space); + static String get_structure_type_name(XrStructureType p_structure_type); + static String get_session_state_name(XrSessionState p_session_state); + static String make_xr_version_string(XrVersion p_version); +}; + +#endif // !OPENXR_UTIL_H diff --git a/modules/openxr/register_types.cpp b/modules/openxr/register_types.cpp new file mode 100644 index 0000000000..86ff368619 --- /dev/null +++ b/modules/openxr/register_types.cpp @@ -0,0 +1,91 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "register_types.h" +#include "main/main.h" + +#include "openxr_interface.h" + +#include "action_map/openxr_action.h" +#include "action_map/openxr_action_map.h" +#include "action_map/openxr_action_set.h" +#include "action_map/openxr_interaction_profile.h" + +OpenXRAPI *openxr_api = nullptr; +Ref<OpenXRInterface> openxr_interface; + +void preregister_openxr_types() { + // For now we create our openxr device here. If we merge it with openxr_interface we'll create that here soon. + + OpenXRAPI::setup_global_defs(); + openxr_api = OpenXRAPI::get_singleton(); + if (openxr_api) { + if (!openxr_api->initialise(Main::get_rendering_driver_name())) { + return; + } + } +} + +void register_openxr_types() { + GDREGISTER_CLASS(OpenXRInterface); + + GDREGISTER_CLASS(OpenXRAction); + GDREGISTER_CLASS(OpenXRActionSet); + GDREGISTER_CLASS(OpenXRActionMap); + GDREGISTER_CLASS(OpenXRIPBinding); + GDREGISTER_CLASS(OpenXRInteractionProfile); + + XRServer *xr_server = XRServer::get_singleton(); + if (xr_server) { + openxr_interface.instantiate(); + xr_server->add_interface(openxr_interface); + + if (openxr_interface->initialise_on_startup()) { + openxr_interface->initialize(); + } + } +} + +void unregister_openxr_types() { + if (openxr_interface.is_valid()) { + // unregister our interface from the XR server + if (XRServer::get_singleton()) { + XRServer::get_singleton()->remove_interface(openxr_interface); + } + + // and release + openxr_interface.unref(); + } + + if (openxr_api) { + openxr_api->finish(); + memdelete(openxr_api); + } +} diff --git a/modules/openxr/register_types.h b/modules/openxr/register_types.h new file mode 100644 index 0000000000..fb42770750 --- /dev/null +++ b/modules/openxr/register_types.h @@ -0,0 +1,40 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef OPENXR_REGISTER_TYPES_H +#define OPENXR_REGISTER_TYPES_H + +#define MODULE_OPENXR_HAS_PREREGISTER + +void preregister_openxr_types(); +void register_openxr_types(); +void unregister_openxr_types(); + +#endif // OPENXR_REGISTER_TYPES_H diff --git a/modules/visual_script/editor/visual_script_editor.cpp b/modules/visual_script/editor/visual_script_editor.cpp index f1b6aef559..ff4b6a1f4b 100644 --- a/modules/visual_script/editor/visual_script_editor.cpp +++ b/modules/visual_script/editor/visual_script_editor.cpp @@ -3535,7 +3535,7 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri print_error("Category not handled: " + p_category.quote()); } - if (Object::cast_to<VisualScriptFunctionCall>(vnode.ptr()) && p_category != "Class") { + if (Object::cast_to<VisualScriptFunctionCall>(vnode.ptr()) && p_category != "Class" && p_category != "VisualScriptNode") { Vector<String> property_path = p_text.split(":"); String class_of_method = property_path[0]; String method_name = property_path[1]; @@ -3981,6 +3981,7 @@ void VisualScriptEditor::_notification(int p_what) { _update_graph(); } } break; + case NOTIFICATION_VISIBILITY_CHANGED: { update_toggle_scripts_button(); members_section->set_visible(is_visible_in_tree()); diff --git a/modules/visual_script/editor/visual_script_property_selector.cpp b/modules/visual_script/editor/visual_script_property_selector.cpp index 563c12eec4..31406a2a6f 100644 --- a/modules/visual_script/editor/visual_script_property_selector.cpp +++ b/modules/visual_script/editor/visual_script_property_selector.cpp @@ -118,9 +118,11 @@ void VisualScriptPropertySelector::_notification(int p_what) { case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { _update_icons(); } break; + case NOTIFICATION_ENTER_TREE: { connect("confirmed", callable_mp(this, &VisualScriptPropertySelector::_confirmed)); } break; + case NOTIFICATION_PROCESS: { // Update background search. if (search_runner.is_valid()) { diff --git a/platform/iphone/godot_view_gesture_recognizer.mm b/platform/iphone/godot_view_gesture_recognizer.mm index 18939f7108..c8137f35ff 100644 --- a/platform/iphone/godot_view_gesture_recognizer.mm +++ b/platform/iphone/godot_view_gesture_recognizer.mm @@ -149,7 +149,7 @@ const CGFloat kGLGestureMovementDistance = 0.5; return; } - [self.godotView touchesMoved:cleared withEvent:event]; + [self.godotView godotTouchesMoved:cleared withEvent:event]; [super touchesMoved:touches withEvent:event]; } diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 2f0b3b4490..6b4b342389 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -1037,9 +1037,7 @@ void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscre r_style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU; } } - if (!p_borderless) { - r_style |= WS_VISIBLE; - } + r_style |= WS_VISIBLE; if (p_no_activate_focus) { r_style_ex |= WS_EX_TOPMOST | WS_EX_NOACTIVATE; @@ -2778,13 +2776,14 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA window.width = window_client_rect.size.width; window.height = window_client_rect.size.height; -#if defined(VULKAN_ENABLED) - if (context_vulkan && window_created) { - context_vulkan->window_resize(window_id, window.width, window.height); - } -#endif rect_changed = true; } +#if defined(VULKAN_ENABLED) + if (context_vulkan && window_created) { + // Note: Trigger resize event to update swapchains when window is minimized/restored, even if size is not changed. + context_vulkan->window_resize(window_id, window.width, window.height); + } +#endif } if (!window.minimized && (!(window_pos_params->flags & SWP_NOMOVE) || window_pos_params->flags & SWP_FRAMECHANGED)) { diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp index 312ba0272e..2716bb2e25 100644 --- a/scene/2d/line_2d.cpp +++ b/scene/2d/line_2d.cpp @@ -247,10 +247,7 @@ float Line2D::get_sharp_limit() const { } void Line2D::set_round_precision(int p_precision) { - if (p_precision < 1) { - p_precision = 1; - } - _round_precision = p_precision; + _round_precision = MAX(1, p_precision); update(); } @@ -409,7 +406,7 @@ void Line2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "end_cap_mode", PROPERTY_HINT_ENUM, "None,Box,Round"), "set_end_cap_mode", "get_end_cap_mode"); ADD_GROUP("Border", ""); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sharp_limit"), "set_sharp_limit", "get_sharp_limit"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "round_precision"), "set_round_precision", "get_round_precision"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "round_precision", PROPERTY_HINT_RANGE, "1,32,1"), "set_round_precision", "get_round_precision"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "antialiased"), "set_antialiased", "get_antialiased"); BIND_ENUM_CONSTANT(LINE_JOINT_SHARP); diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index a4ad0a8d99..eb4d9d6445 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -1168,7 +1168,7 @@ bool CharacterBody2D::move_and_slide() { if (moving_platform_apply_velocity_on_leave == PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY && current_platform_velocity.dot(up_direction) < 0) { current_platform_velocity = current_platform_velocity.slide(up_direction); } - motion_velocity += current_platform_velocity; + velocity += current_platform_velocity; } } @@ -1176,7 +1176,7 @@ bool CharacterBody2D::move_and_slide() { } void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_floor) { - Vector2 motion = motion_velocity * p_delta; + Vector2 motion = velocity * p_delta; Vector2 motion_slide_up = motion.slide(up_direction); Vector2 prev_floor_normal = floor_normal; @@ -1194,7 +1194,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo // If the platform's ceiling push down the body. bool apply_ceiling_velocity = false; bool first_slide = true; - bool vel_dir_facing_up = motion_velocity.dot(up_direction) > 0; + bool vel_dir_facing_up = velocity.dot(up_direction) > 0; Vector2 last_travel; for (int iteration = 0; iteration < max_slides; ++iteration) { @@ -1211,26 +1211,26 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo motion_results.push_back(result); _set_collision_direction(result); - // If we hit a ceiling platform, we set the vertical motion_velocity to at least the platform one. + // If we hit a ceiling platform, we set the vertical velocity to at least the platform one. if (on_ceiling && result.collider_velocity != Vector2() && result.collider_velocity.dot(up_direction) < 0) { // If ceiling sliding is on, only apply when the ceiling is flat or when the motion is upward. if (!slide_on_ceiling || motion.dot(up_direction) < 0 || (result.collision_normal + up_direction).length() < 0.01) { apply_ceiling_velocity = true; Vector2 ceiling_vertical_velocity = up_direction * up_direction.dot(result.collider_velocity); - Vector2 motion_vertical_velocity = up_direction * up_direction.dot(motion_velocity); + Vector2 motion_vertical_velocity = up_direction * up_direction.dot(velocity); if (motion_vertical_velocity.dot(up_direction) > 0 || ceiling_vertical_velocity.length_squared() > motion_vertical_velocity.length_squared()) { - motion_velocity = ceiling_vertical_velocity + motion_velocity.slide(up_direction); + velocity = ceiling_vertical_velocity + velocity.slide(up_direction); } } } - if (on_floor && floor_stop_on_slope && (motion_velocity.normalized() + up_direction).length() < 0.01) { + if (on_floor && floor_stop_on_slope && (velocity.normalized() + up_direction).length() < 0.01) { Transform2D gt = get_global_transform(); if (result.travel.length() <= margin + CMP_EPSILON) { gt.elements[2] -= result.travel; } set_global_transform(gt); - motion_velocity = Vector2(); + velocity = Vector2(); last_motion = Vector2(); motion = Vector2(); break; @@ -1254,7 +1254,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo } // Determines if you are on the ground. _snap_on_floor(true, false); - motion_velocity = Vector2(); + velocity = Vector2(); last_motion = Vector2(); motion = Vector2(); break; @@ -1276,7 +1276,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo // Regular sliding, the last part of the test handle the case when you don't want to slide on the ceiling. else if ((sliding_enabled || !on_floor) && (!on_ceiling || slide_on_ceiling || !vel_dir_facing_up) && !apply_ceiling_velocity) { Vector2 slide_motion = result.remainder.slide(result.collision_normal); - if (slide_motion.dot(motion_velocity) > 0.0) { + if (slide_motion.dot(velocity) > 0.0) { motion = slide_motion; } else { motion = Vector2(); @@ -1284,10 +1284,10 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo if (slide_on_ceiling && on_ceiling) { // Apply slide only in the direction of the input motion, otherwise just stop to avoid jittering when moving against a wall. if (vel_dir_facing_up) { - motion_velocity = motion_velocity.slide(result.collision_normal); + velocity = velocity.slide(result.collision_normal); } else { // Avoid acceleration in slope when falling. - motion_velocity = up_direction * up_direction.dot(motion_velocity); + velocity = up_direction * up_direction.dot(velocity); } } } @@ -1295,7 +1295,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo else { motion = result.remainder; if (on_ceiling && !slide_on_ceiling && vel_dir_facing_up) { - motion_velocity = motion_velocity.slide(up_direction); + velocity = velocity.slide(up_direction); motion = motion.slide(up_direction); } } @@ -1329,23 +1329,23 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo // Scales the horizontal velocity according to the wall slope. if (is_on_wall_only() && motion_slide_up.dot(motion_results.get(0).collision_normal) < 0) { - Vector2 slide_motion = motion_velocity.slide(motion_results.get(0).collision_normal); + Vector2 slide_motion = velocity.slide(motion_results.get(0).collision_normal); if (motion_slide_up.dot(slide_motion) < 0) { - motion_velocity = up_direction * up_direction.dot(motion_velocity); + velocity = up_direction * up_direction.dot(velocity); } else { - // Keeps the vertical motion from motion_velocity and add the horizontal motion of the projection. - motion_velocity = up_direction * up_direction.dot(motion_velocity) + slide_motion.slide(up_direction); + // Keeps the vertical motion from velocity and add the horizontal motion of the projection. + velocity = up_direction * up_direction.dot(velocity) + slide_motion.slide(up_direction); } } // Reset the gravity accumulation when touching the ground. if (on_floor && !vel_dir_facing_up) { - motion_velocity = motion_velocity.slide(up_direction); + velocity = velocity.slide(up_direction); } } void CharacterBody2D::_move_and_slide_floating(double p_delta) { - Vector2 motion = motion_velocity * p_delta; + Vector2 motion = velocity * p_delta; platform_rid = RID(); platform_object_id = ObjectID(); @@ -1370,7 +1370,7 @@ void CharacterBody2D::_move_and_slide_floating(double p_delta) { break; } - if (wall_min_slide_angle != 0 && result.get_angle(-motion_velocity.normalized()) < wall_min_slide_angle + FLOOR_ANGLE_THRESHOLD) { + if (wall_min_slide_angle != 0 && result.get_angle(-velocity.normalized()) < wall_min_slide_angle + FLOOR_ANGLE_THRESHOLD) { motion = Vector2(); } else if (first_slide) { Vector2 motion_slide_norm = result.remainder.slide(result.collision_normal).normalized(); @@ -1379,7 +1379,7 @@ void CharacterBody2D::_move_and_slide_floating(double p_delta) { motion = result.remainder.slide(result.collision_normal); } - if (motion.dot(motion_velocity) <= 0.0) { + if (motion.dot(velocity) <= 0.0) { motion = Vector2(); } } @@ -1471,12 +1471,12 @@ void CharacterBody2D::_set_platform_data(const PhysicsServer2D::MotionResult &p_ platform_layer = PhysicsServer2D::get_singleton()->body_get_collision_layer(platform_rid); } -const Vector2 &CharacterBody2D::get_motion_velocity() const { - return motion_velocity; +const Vector2 &CharacterBody2D::get_velocity() const { + return velocity; } -void CharacterBody2D::set_motion_velocity(const Vector2 &p_velocity) { - motion_velocity = p_velocity; +void CharacterBody2D::set_velocity(const Vector2 &p_velocity) { + velocity = p_velocity; } bool CharacterBody2D::is_on_floor() const { @@ -1697,8 +1697,8 @@ void CharacterBody2D::_notification(int p_what) { void CharacterBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("move_and_slide"), &CharacterBody2D::move_and_slide); - ClassDB::bind_method(D_METHOD("set_motion_velocity", "motion_velocity"), &CharacterBody2D::set_motion_velocity); - ClassDB::bind_method(D_METHOD("get_motion_velocity"), &CharacterBody2D::get_motion_velocity); + ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &CharacterBody2D::set_velocity); + ClassDB::bind_method(D_METHOD("get_velocity"), &CharacterBody2D::get_velocity); ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &CharacterBody2D::set_safe_margin); ClassDB::bind_method(D_METHOD("get_safe_margin"), &CharacterBody2D::get_safe_margin); @@ -1750,7 +1750,7 @@ void CharacterBody2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "motion_mode", PROPERTY_HINT_ENUM, "Grounded,Floating", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_motion_mode", "get_motion_mode"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "up_direction"), "set_up_direction", "get_up_direction"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion_velocity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_motion_velocity", "get_motion_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "velocity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_velocity", "get_velocity"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slide_on_ceiling"), "set_slide_on_ceiling_enabled", "is_slide_on_ceiling_enabled"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_max_slides", "get_max_slides"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wall_min_slide_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians", PROPERTY_USAGE_DEFAULT), "set_wall_min_slide_angle", "get_wall_min_slide_angle"); diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index cfaa2570fb..8d9e31d4dd 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -337,8 +337,8 @@ public: }; bool move_and_slide(); - const Vector2 &get_motion_velocity() const; - void set_motion_velocity(const Vector2 &p_velocity); + const Vector2 &get_velocity() const; + void set_velocity(const Vector2 &p_velocity); bool is_on_floor() const; bool is_on_floor_only() const; @@ -378,7 +378,7 @@ private: Vector2 up_direction = Vector2(0.0, -1.0); uint32_t moving_platform_floor_layers = UINT32_MAX; uint32_t moving_platform_wall_layers = 0; - Vector2 motion_velocity; + Vector2 velocity; Vector2 floor_normal; Vector2 platform_velocity; diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp index c6d7e1df86..25411e54c0 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -1169,7 +1169,7 @@ bool CharacterBody3D::move_and_slide() { for (int i = 0; i < 3; i++) { if (locked_axis & (1 << i)) { - motion_velocity[i] = 0.0; + velocity[i] = 0.0; } } @@ -1239,7 +1239,7 @@ bool CharacterBody3D::move_and_slide() { if (moving_platform_apply_velocity_on_leave == PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY && current_platform_velocity.dot(up_direction) < 0) { current_platform_velocity = current_platform_velocity.slide(up_direction); } - motion_velocity += current_platform_velocity; + velocity += current_platform_velocity; } } @@ -1247,7 +1247,7 @@ bool CharacterBody3D::move_and_slide() { } void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_floor) { - Vector3 motion = motion_velocity * p_delta; + Vector3 motion = velocity * p_delta; Vector3 motion_slide_up = motion.slide(up_direction); Vector3 prev_floor_normal = floor_normal; @@ -1267,7 +1267,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo // If the platform's ceiling push down the body. bool apply_ceiling_velocity = false; bool first_slide = true; - bool vel_dir_facing_up = motion_velocity.dot(up_direction) > 0; + bool vel_dir_facing_up = velocity.dot(up_direction) > 0; Vector3 total_travel; for (int iteration = 0; iteration < max_slides; ++iteration) { @@ -1287,26 +1287,26 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo CollisionState result_state; _set_collision_direction(result, result_state); - // If we hit a ceiling platform, we set the vertical motion_velocity to at least the platform one. + // If we hit a ceiling platform, we set the vertical velocity to at least the platform one. if (collision_state.ceiling && platform_ceiling_velocity != Vector3() && platform_ceiling_velocity.dot(up_direction) < 0) { // If ceiling sliding is on, only apply when the ceiling is flat or when the motion is upward. if (!slide_on_ceiling || motion.dot(up_direction) < 0 || (ceiling_normal + up_direction).length() < 0.01) { apply_ceiling_velocity = true; Vector3 ceiling_vertical_velocity = up_direction * up_direction.dot(platform_ceiling_velocity); - Vector3 motion_vertical_velocity = up_direction * up_direction.dot(motion_velocity); + Vector3 motion_vertical_velocity = up_direction * up_direction.dot(velocity); if (motion_vertical_velocity.dot(up_direction) > 0 || ceiling_vertical_velocity.length_squared() > motion_vertical_velocity.length_squared()) { - motion_velocity = ceiling_vertical_velocity + motion_velocity.slide(up_direction); + velocity = ceiling_vertical_velocity + velocity.slide(up_direction); } } } - if (collision_state.floor && floor_stop_on_slope && (motion_velocity.normalized() + up_direction).length() < 0.01) { + if (collision_state.floor && floor_stop_on_slope && (velocity.normalized() + up_direction).length() < 0.01) { Transform3D gt = get_global_transform(); if (result.travel.length() <= margin + CMP_EPSILON) { gt.origin -= result.travel; } set_global_transform(gt); - motion_velocity = Vector3(); + velocity = Vector3(); motion = Vector3(); last_motion = Vector3(); break; @@ -1367,11 +1367,11 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo // Scales the horizontal velocity according to the wall slope. if (vel_dir_facing_up) { - Vector3 slide_motion = motion_velocity.slide(result.collisions[0].normal); - // Keeps the vertical motion from motion_velocity and add the horizontal motion of the projection. - motion_velocity = up_direction * up_direction.dot(motion_velocity) + slide_motion.slide(up_direction); + Vector3 slide_motion = velocity.slide(result.collisions[0].normal); + // Keeps the vertical motion from velocity and add the horizontal motion of the projection. + velocity = up_direction * up_direction.dot(velocity) + slide_motion.slide(up_direction); } else { - motion_velocity = motion_velocity.slide(forward); + velocity = velocity.slide(forward); } // Allow only lateral motion along previous floor when already on floor. @@ -1401,7 +1401,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo if (stop_all_motion) { motion = Vector3(); - motion_velocity = Vector3(); + velocity = Vector3(); } } } @@ -1412,7 +1412,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo real_t motion_angle = Math::abs(Math::acos(-horizontal_normal.dot(motion_slide_up.normalized()))); if (motion_angle < wall_min_slide_angle) { motion = up_direction * motion.dot(up_direction); - motion_velocity = up_direction * motion_velocity.dot(up_direction); + velocity = up_direction * velocity.dot(up_direction); apply_default_sliding = false; } @@ -1437,7 +1437,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo slide_motion *= motion_length; } - if (slide_motion.dot(motion_velocity) > 0.0) { + if (slide_motion.dot(velocity) > 0.0) { motion = slide_motion; } else { motion = Vector3(); @@ -1446,10 +1446,10 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo if (slide_on_ceiling && result_state.ceiling) { // Apply slide only in the direction of the input motion, otherwise just stop to avoid jittering when moving against a wall. if (vel_dir_facing_up) { - motion_velocity = motion_velocity.slide(collision.normal); + velocity = velocity.slide(collision.normal); } else { // Avoid acceleration in slope when falling. - motion_velocity = up_direction * up_direction.dot(motion_velocity); + velocity = up_direction * up_direction.dot(velocity); } } } @@ -1457,7 +1457,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo else { motion = result.remainder; if (result_state.ceiling && !slide_on_ceiling && vel_dir_facing_up) { - motion_velocity = motion_velocity.slide(up_direction); + velocity = velocity.slide(up_direction); motion = motion.slide(up_direction); } } @@ -1502,12 +1502,12 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo // Reset the gravity accumulation when touching the ground. if (collision_state.floor && !vel_dir_facing_up) { - motion_velocity = motion_velocity.slide(up_direction); + velocity = velocity.slide(up_direction); } } void CharacterBody3D::_move_and_slide_floating(double p_delta) { - Vector3 motion = motion_velocity * p_delta; + Vector3 motion = velocity * p_delta; platform_rid = RID(); platform_object_id = ObjectID(); @@ -1534,7 +1534,7 @@ void CharacterBody3D::_move_and_slide_floating(double p_delta) { break; } - if (wall_min_slide_angle != 0 && Math::acos(wall_normal.dot(-motion_velocity.normalized())) < wall_min_slide_angle + FLOOR_ANGLE_THRESHOLD) { + if (wall_min_slide_angle != 0 && Math::acos(wall_normal.dot(-velocity.normalized())) < wall_min_slide_angle + FLOOR_ANGLE_THRESHOLD) { motion = Vector3(); if (result.travel.length() < margin + CMP_EPSILON) { Transform3D gt = get_global_transform(); @@ -1548,7 +1548,7 @@ void CharacterBody3D::_move_and_slide_floating(double p_delta) { motion = result.remainder.slide(wall_normal); } - if (motion.dot(motion_velocity) <= 0.0) { + if (motion.dot(velocity) <= 0.0) { motion = Vector3(); } } @@ -1723,12 +1723,12 @@ real_t CharacterBody3D::get_safe_margin() const { return margin; } -const Vector3 &CharacterBody3D::get_motion_velocity() const { - return motion_velocity; +const Vector3 &CharacterBody3D::get_velocity() const { + return velocity; } -void CharacterBody3D::set_motion_velocity(const Vector3 &p_velocity) { - motion_velocity = p_velocity; +void CharacterBody3D::set_velocity(const Vector3 &p_velocity) { + velocity = p_velocity; } bool CharacterBody3D::is_on_floor() const { @@ -1943,8 +1943,8 @@ void CharacterBody3D::_notification(int p_what) { void CharacterBody3D::_bind_methods() { ClassDB::bind_method(D_METHOD("move_and_slide"), &CharacterBody3D::move_and_slide); - ClassDB::bind_method(D_METHOD("set_motion_velocity", "motion_velocity"), &CharacterBody3D::set_motion_velocity); - ClassDB::bind_method(D_METHOD("get_motion_velocity"), &CharacterBody3D::get_motion_velocity); + ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &CharacterBody3D::set_velocity); + ClassDB::bind_method(D_METHOD("get_velocity"), &CharacterBody3D::get_velocity); ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &CharacterBody3D::set_safe_margin); ClassDB::bind_method(D_METHOD("get_safe_margin"), &CharacterBody3D::get_safe_margin); @@ -1997,7 +1997,7 @@ void CharacterBody3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "motion_mode", PROPERTY_HINT_ENUM, "Grounded,Floating", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_motion_mode", "get_motion_mode"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "up_direction"), "set_up_direction", "get_up_direction"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slide_on_ceiling"), "set_slide_on_ceiling_enabled", "is_slide_on_ceiling_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "motion_velocity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_motion_velocity", "get_motion_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "velocity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_velocity", "get_velocity"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_max_slides", "get_max_slides"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wall_min_slide_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians", PROPERTY_USAGE_DEFAULT), "set_wall_min_slide_angle", "get_wall_min_slide_angle"); ADD_GROUP("Floor", "floor_"); diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h index 67dc7382c3..0f753fef76 100644 --- a/scene/3d/physics_body_3d.h +++ b/scene/3d/physics_body_3d.h @@ -354,8 +354,8 @@ public: }; bool move_and_slide(); - const Vector3 &get_motion_velocity() const; - void set_motion_velocity(const Vector3 &p_velocity); + const Vector3 &get_velocity() const; + void set_velocity(const Vector3 &p_velocity); bool is_on_floor() const; bool is_on_floor_only() const; @@ -416,7 +416,7 @@ private: real_t floor_max_angle = Math::deg2rad((real_t)45.0); real_t wall_min_slide_angle = Math::deg2rad((real_t)15.0); Vector3 up_direction = Vector3(0.0, 1.0, 0.0); - Vector3 motion_velocity; + Vector3 velocity; Vector3 floor_normal; Vector3 wall_normal; Vector3 ceiling_normal; diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp index b18819c920..efae81e048 100644 --- a/scene/3d/xr_nodes.cpp +++ b/scene/3d/xr_nodes.cpp @@ -448,11 +448,6 @@ void XRController3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_tracker_hand"), &XRController3D::get_tracker_hand); - ClassDB::bind_method(D_METHOD("get_rumble"), &XRController3D::get_rumble); - ClassDB::bind_method(D_METHOD("set_rumble", "rumble"), &XRController3D::set_rumble); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rumble", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_rumble", "get_rumble"); - ADD_PROPERTY_DEFAULT("rumble", 0.0); - ADD_SIGNAL(MethodInfo("button_pressed", PropertyInfo(Variant::STRING, "name"))); ADD_SIGNAL(MethodInfo("button_released", PropertyInfo(Variant::STRING, "name"))); ADD_SIGNAL(MethodInfo("input_value_changed", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::FLOAT, "value"))); @@ -558,20 +553,6 @@ Vector2 XRController3D::get_axis(const StringName &p_name) const { } } -real_t XRController3D::get_rumble() const { - if (!tracker.is_valid()) { - return 0.0; - } - - return tracker->get_rumble(); -} - -void XRController3D::set_rumble(real_t p_rumble) { - if (tracker.is_valid()) { - tracker->set_rumble(p_rumble); - } -} - XRPositionalTracker::TrackerHand XRController3D::get_tracker_hand() const { // get our XRServer if (!tracker.is_valid()) { @@ -612,7 +593,7 @@ TypedArray<String> XROrigin3D::get_configuration_warnings() const { } } - bool xr_enabled = GLOBAL_GET("rendering/xr/enabled"); + bool xr_enabled = GLOBAL_GET("xr/shaders/enabled"); if (!xr_enabled) { warnings.push_back(TTR("XR is not enabled in rendering project settings. Stereoscopic output is not supported unless this is enabled.")); } diff --git a/scene/3d/xr_nodes.h b/scene/3d/xr_nodes.h index 5675cbd944..3079e20dc7 100644 --- a/scene/3d/xr_nodes.h +++ b/scene/3d/xr_nodes.h @@ -139,9 +139,6 @@ public: float get_value(const StringName &p_name) const; Vector2 get_axis(const StringName &p_name) const; - real_t get_rumble() const; - void set_rumble(real_t p_rumble); - XRPositionalTracker::TrackerHand get_tracker_hand() const; XRController3D() {} diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp index ce78c286f5..c66e145bc4 100644 --- a/scene/gui/subviewport_container.cpp +++ b/scene/gui/subviewport_container.cpp @@ -148,6 +148,24 @@ void SubViewportContainer::_notification(int p_what) { } } } break; + + case NOTIFICATION_MOUSE_ENTER: { + _notify_viewports(NOTIFICATION_VP_MOUSE_ENTER); + } break; + + case NOTIFICATION_MOUSE_EXIT: { + _notify_viewports(NOTIFICATION_VP_MOUSE_EXIT); + } break; + } +} + +void SubViewportContainer::_notify_viewports(int p_notification) { + for (int i = 0; i < get_child_count(); i++) { + SubViewport *c = Object::cast_to<SubViewport>(get_child(i)); + if (!c) { + continue; + } + c->notification(p_notification); } } diff --git a/scene/gui/subviewport_container.h b/scene/gui/subviewport_container.h index 3138a6144c..f52f01e4e2 100644 --- a/scene/gui/subviewport_container.h +++ b/scene/gui/subviewport_container.h @@ -38,6 +38,7 @@ class SubViewportContainer : public Container { bool stretch = false; int shrink = 1; + void _notify_viewports(int p_notification); protected: void _notification(int p_what); diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index 9ad711c596..26b67b763c 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -56,19 +56,21 @@ Transform2D CanvasItem::_edit_get_transform() const { #endif bool CanvasItem::is_visible_in_tree() const { - return visible && visible_in_tree; + return visible && parent_visible_in_tree; } -void CanvasItem::_propagate_visibility_changed(bool p_visible, bool p_was_visible) { - if (p_visible && first_draw) { //avoid propagating it twice +void CanvasItem::_propagate_visibility_changed(bool p_visible, bool p_is_source) { + if (p_visible && first_draw) { // Avoid propagating it twice. first_draw = false; } - visible_in_tree = p_visible; + if (!p_is_source) { + parent_visible_in_tree = p_visible; + } notification(NOTIFICATION_VISIBILITY_CHANGED); if (visible && p_visible) { update(); - } else if (!p_visible && (visible || p_was_visible)) { + } else if (!p_visible && (visible || p_is_source)) { emit_signal(SceneStringNames::get_singleton()->hidden); } _block(); @@ -76,8 +78,12 @@ void CanvasItem::_propagate_visibility_changed(bool p_visible, bool p_was_visibl for (int i = 0; i < get_child_count(); i++) { CanvasItem *c = Object::cast_to<CanvasItem>(get_child(i)); - if (c && c->visible) { //should the top_levels stop propagation? i think so but.. - c->_propagate_visibility_changed(p_visible); + if (c) { // Should the top_levels stop propagation? I think so, but... + if (c->visible) { + c->_propagate_visibility_changed(p_visible); + } else { + c->parent_visible_in_tree = p_visible; + } } } @@ -92,11 +98,12 @@ void CanvasItem::set_visible(bool p_visible) { visible = p_visible; RenderingServer::get_singleton()->canvas_item_set_visible(canvas_item, p_visible); - if (!is_inside_tree()) { + if (!parent_visible_in_tree) { + notification(NOTIFICATION_VISIBILITY_CHANGED); return; } - _propagate_visibility_changed(p_visible, !p_visible); + _propagate_visibility_changed(p_visible, true); } void CanvasItem::show() { @@ -264,13 +271,13 @@ void CanvasItem::_notification(int p_what) { CanvasItem *ci = Object::cast_to<CanvasItem>(parent); if (ci) { - visible_in_tree = ci->is_visible_in_tree(); + parent_visible_in_tree = ci->is_visible_in_tree(); C = ci->children_items.push_back(this); } else { CanvasLayer *cl = Object::cast_to<CanvasLayer>(parent); if (cl) { - visible_in_tree = cl->is_visible(); + parent_visible_in_tree = cl->is_visible(); } else { // Look for a window. Viewport *viewport = nullptr; @@ -288,9 +295,9 @@ void CanvasItem::_notification(int p_what) { window = Object::cast_to<Window>(viewport); if (window) { window->connect(SceneStringNames::get_singleton()->visibility_changed, callable_mp(this, &CanvasItem::_window_visibility_changed)); - visible_in_tree = window->is_visible(); + parent_visible_in_tree = window->is_visible(); } else { - visible_in_tree = true; + parent_visible_in_tree = true; } } } @@ -333,7 +340,7 @@ void CanvasItem::_notification(int p_what) { window->disconnect(SceneStringNames::get_singleton()->visibility_changed, callable_mp(this, &CanvasItem::_window_visibility_changed)); } global_invalid = true; - visible_in_tree = false; + parent_visible_in_tree = false; } break; case NOTIFICATION_VISIBILITY_CHANGED: { diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h index 2a9e7bac3d..c0558b6be2 100644 --- a/scene/main/canvas_item.h +++ b/scene/main/canvas_item.h @@ -85,7 +85,7 @@ private: Window *window = nullptr; bool first_draw = false; bool visible = true; - bool visible_in_tree = false; + bool parent_visible_in_tree = false; bool clip_children = false; bool pending_update = false; bool top_level = false; @@ -108,7 +108,7 @@ private: void _top_level_raise_self(); - void _propagate_visibility_changed(bool p_visible, bool p_was_visible = false); + void _propagate_visibility_changed(bool p_visible, bool p_is_source = false); void _update_callback(); diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp index 6c627857fa..be24620904 100644 --- a/scene/main/canvas_layer.cpp +++ b/scene/main/canvas_layer.cpp @@ -61,7 +61,7 @@ void CanvasLayer::set_visible(bool p_visible) { if (c->is_visible()) { c->_propagate_visibility_changed(p_visible); } else { - c->notification(CanvasItem::NOTIFICATION_VISIBILITY_CHANGED); + c->parent_visible_in_tree = p_visible; } } } diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 42a2e41a08..211667ce38 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -1344,27 +1344,45 @@ bool Node::has_node(const NodePath &p_path) const { return get_node_or_null(p_path) != nullptr; } -Node *Node::find_node(const String &p_mask, bool p_recursive, bool p_owned) const { +TypedArray<Node> Node::find_nodes(const String &p_mask, const String &p_type, bool p_recursive, bool p_owned) const { + TypedArray<Node> ret; + ERR_FAIL_COND_V(p_mask.is_empty() && p_type.is_empty(), ret); + Node *const *cptr = data.children.ptr(); int ccount = data.children.size(); for (int i = 0; i < ccount; i++) { if (p_owned && !cptr[i]->data.owner) { continue; } - if (cptr[i]->data.name.operator String().match(p_mask)) { - return cptr[i]; + + if (!p_mask.is_empty()) { + if (!cptr[i]->data.name.operator String().match(p_mask)) { + continue; + } else if (p_type.is_empty()) { + ret.append(cptr[i]); + } } - if (!p_recursive) { - continue; + if (cptr[i]->is_class(p_type)) { + ret.append(cptr[i]); + } else if (cptr[i]->get_script_instance()) { + Ref<Script> script = cptr[i]->get_script_instance()->get_script(); + while (script.is_valid()) { + if ((ScriptServer::is_global_class(p_type) && ScriptServer::get_global_class_path(p_type) == script->get_path()) || p_type == script->get_path()) { + ret.append(cptr[i]); + break; + } + + script = script->get_base_script(); + } } - Node *ret = cptr[i]->find_node(p_mask, true, p_owned); - if (ret) { - return ret; + if (p_recursive) { + ret.append_array(cptr[i]->find_nodes(p_mask, p_type, true, p_owned)); } } - return nullptr; + + return ret; } Node *Node::get_parent() const { @@ -2706,7 +2724,7 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("get_node", "path"), &Node::get_node); ClassDB::bind_method(D_METHOD("get_node_or_null", "path"), &Node::get_node_or_null); ClassDB::bind_method(D_METHOD("get_parent"), &Node::get_parent); - ClassDB::bind_method(D_METHOD("find_node", "mask", "recursive", "owned"), &Node::find_node, DEFVAL(true), DEFVAL(true)); + ClassDB::bind_method(D_METHOD("find_nodes", "mask", "type", "recursive", "owned"), &Node::find_nodes, DEFVAL(""), DEFVAL(true), DEFVAL(true)); ClassDB::bind_method(D_METHOD("find_parent", "mask"), &Node::find_parent); ClassDB::bind_method(D_METHOD("has_node_and_resource", "path"), &Node::has_node_and_resource); ClassDB::bind_method(D_METHOD("get_node_and_resource", "path"), &Node::_get_node_and_resource); @@ -2845,6 +2863,9 @@ void Node::_bind_methods() { BIND_CONSTANT(NOTIFICATION_WM_CLOSE_REQUEST); BIND_CONSTANT(NOTIFICATION_WM_GO_BACK_REQUEST); BIND_CONSTANT(NOTIFICATION_WM_SIZE_CHANGED); + BIND_CONSTANT(NOTIFICATION_WM_DPI_CHANGE); + BIND_CONSTANT(NOTIFICATION_VP_MOUSE_ENTER); + BIND_CONSTANT(NOTIFICATION_VP_MOUSE_EXIT); BIND_CONSTANT(NOTIFICATION_OS_MEMORY_WARNING); BIND_CONSTANT(NOTIFICATION_TRANSLATION_CHANGED); BIND_CONSTANT(NOTIFICATION_WM_ABOUT); diff --git a/scene/main/node.h b/scene/main/node.h index f2dcdf4b43..8e49f871a7 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -268,6 +268,8 @@ public: NOTIFICATION_WM_GO_BACK_REQUEST = 1007, NOTIFICATION_WM_SIZE_CHANGED = 1008, NOTIFICATION_WM_DPI_CHANGE = 1009, + NOTIFICATION_VP_MOUSE_ENTER = 1010, + NOTIFICATION_VP_MOUSE_EXIT = 1011, NOTIFICATION_OS_MEMORY_WARNING = MainLoop::NOTIFICATION_OS_MEMORY_WARNING, NOTIFICATION_TRANSLATION_CHANGED = MainLoop::NOTIFICATION_TRANSLATION_CHANGED, @@ -299,7 +301,7 @@ public: bool has_node(const NodePath &p_path) const; Node *get_node(const NodePath &p_path) const; Node *get_node_or_null(const NodePath &p_path) const; - Node *find_node(const String &p_mask, bool p_recursive = true, bool p_owned = true) const; + TypedArray<Node> find_nodes(const String &p_mask, const String &p_type = "", bool p_recursive = true, bool p_owned = true) const; bool has_node_and_resource(const NodePath &p_path) const; Node *get_node_and_resource(const NodePath &p_path, RES &r_res, Vector<StringName> &r_leftover_subpath, bool p_last_is_property = true) const; diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 2831e76fba..ca817b17bc 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -496,17 +496,17 @@ void Viewport::_notification(int p_what) { #endif // _3D_DISABLED } break; - case NOTIFICATION_WM_MOUSE_ENTER: { - gui.mouse_in_window = true; + case NOTIFICATION_VP_MOUSE_ENTER: { + gui.mouse_in_viewport = true; } break; - case NOTIFICATION_WM_MOUSE_EXIT: { - gui.mouse_in_window = false; + case NOTIFICATION_VP_MOUSE_EXIT: { + gui.mouse_in_viewport = false; _drop_physics_mouseover(); _drop_mouse_over(); - // When the mouse exits the window, we want to end mouse_over, but + // When the mouse exits the viewport, we want to end mouse_over, but // not mouse_focus, because, for example, we want to continue - // dragging a scrollbar even if the mouse has left the window. + // dragging a scrollbar even if the mouse has left the viewport. } break; case NOTIFICATION_WM_WINDOW_FOCUS_OUT: { @@ -1683,7 +1683,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { Control *over = nullptr; if (gui.mouse_focus) { over = gui.mouse_focus; - } else if (gui.mouse_in_window) { + } else if (gui.mouse_in_viewport) { over = gui_find_control(mpos); } diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 3a71745f44..93e42f1838 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -335,7 +335,7 @@ private: // info used when this is a window bool forced_mouse_focus = false; //used for menu buttons - bool mouse_in_window = true; + bool mouse_in_viewport = true; bool key_event_accepted = false; Control *mouse_focus = nullptr; Control *last_mouse_focus = nullptr; diff --git a/scene/main/window.cpp b/scene/main/window.cpp index e7a575f40a..0ce556d36c 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -340,9 +340,11 @@ void Window::_event_callback(DisplayServer::WindowEvent p_event) { case DisplayServer::WINDOW_EVENT_MOUSE_ENTER: { _propagate_window_notification(this, NOTIFICATION_WM_MOUSE_ENTER); emit_signal(SNAME("mouse_entered")); + notification(NOTIFICATION_VP_MOUSE_ENTER); DisplayServer::get_singleton()->cursor_set_shape(DisplayServer::CURSOR_ARROW); //restore cursor shape } break; case DisplayServer::WINDOW_EVENT_MOUSE_EXIT: { + notification(NOTIFICATION_VP_MOUSE_EXIT); _propagate_window_notification(this, NOTIFICATION_WM_MOUSE_EXIT); emit_signal(SNAME("mouse_exited")); } break; diff --git a/scene/multiplayer/scene_cache_interface.cpp b/scene/multiplayer/scene_cache_interface.cpp index 2f278ed864..f05dc5a2da 100644 --- a/scene/multiplayer/scene_cache_interface.cpp +++ b/scene/multiplayer/scene_cache_interface.cpp @@ -139,74 +139,46 @@ void SceneCacheInterface::process_confirm_path(int p_from, const uint8_t *p_pack E->get() = true; } -bool SceneCacheInterface::_send_confirm_path(Node *p_node, NodePath p_path, PathSentCache *psc, int p_target) { - bool has_all_peers = true; - List<int> peers_to_add; // If one is missing, take note to add it. - - for (const Set<int>::Element *E = multiplayer->get_connected_peers().front(); E; E = E->next()) { - if (p_target < 0 && E->get() == -p_target) { - continue; // Continue, excluded. - } - - if (p_target > 0 && E->get() != p_target) { - continue; // Continue, not for this peer. - } - - Map<int, bool>::Element *F = psc->confirmed_peers.find(E->get()); - - if (!F || !F->get()) { - // Path was not cached, or was cached but is unconfirmed. - if (!F) { - // Not cached at all, take note. - peers_to_add.push_back(E->get()); - } +Error SceneCacheInterface::_send_confirm_path(Node *p_node, NodePath p_path, PathSentCache *psc, const List<int> &p_peers) { + // Encode function name. + const CharString path = String(p_path).utf8(); + const int path_len = encode_cstring(path.get_data(), nullptr); - has_all_peers = false; - } - } - - if (peers_to_add.size() > 0) { - // Those that need to be added, send a message for this. - - // Encode function name. - const CharString path = String(p_path).utf8(); - const int path_len = encode_cstring(path.get_data(), nullptr); + // Extract MD5 from rpc methods list. + const String methods_md5 = multiplayer->get_rpc_md5(p_node); + const int methods_md5_len = 33; // 32 + 1 for the `0` that is added by the encoder. - // Extract MD5 from rpc methods list. - const String methods_md5 = multiplayer->get_rpc_md5(p_node); - const int methods_md5_len = 33; // 32 + 1 for the `0` that is added by the encoder. - - Vector<uint8_t> packet; - packet.resize(1 + 4 + path_len + methods_md5_len); - int ofs = 0; + Vector<uint8_t> packet; + packet.resize(1 + 4 + path_len + methods_md5_len); + int ofs = 0; - packet.write[ofs] = MultiplayerAPI::NETWORK_COMMAND_SIMPLIFY_PATH; - ofs += 1; + packet.write[ofs] = MultiplayerAPI::NETWORK_COMMAND_SIMPLIFY_PATH; + ofs += 1; - ofs += encode_cstring(methods_md5.utf8().get_data(), &packet.write[ofs]); + ofs += encode_cstring(methods_md5.utf8().get_data(), &packet.write[ofs]); - ofs += encode_uint32(psc->id, &packet.write[ofs]); + ofs += encode_uint32(psc->id, &packet.write[ofs]); - ofs += encode_cstring(path.get_data(), &packet.write[ofs]); + ofs += encode_cstring(path.get_data(), &packet.write[ofs]); - Ref<MultiplayerPeer> multiplayer_peer = multiplayer->get_multiplayer_peer(); - ERR_FAIL_COND_V(multiplayer_peer.is_null(), false); + Ref<MultiplayerPeer> multiplayer_peer = multiplayer->get_multiplayer_peer(); + ERR_FAIL_COND_V(multiplayer_peer.is_null(), ERR_BUG); #ifdef DEBUG_ENABLED - multiplayer->profile_bandwidth("out", packet.size() * peers_to_add.size()); + multiplayer->profile_bandwidth("out", packet.size() * p_peers.size()); #endif - for (int &E : peers_to_add) { - multiplayer_peer->set_target_peer(E); // To all of you. - multiplayer_peer->set_transfer_channel(0); - multiplayer_peer->set_transfer_mode(Multiplayer::TRANSFER_MODE_RELIABLE); - multiplayer_peer->put_packet(packet.ptr(), packet.size()); - - psc->confirmed_peers.insert(E, false); // Insert into confirmed, but as false since it was not confirmed. - } + Error err = OK; + for (int peer_id : p_peers) { + multiplayer_peer->set_target_peer(peer_id); + multiplayer_peer->set_transfer_channel(0); + multiplayer_peer->set_transfer_mode(Multiplayer::TRANSFER_MODE_RELIABLE); + err = multiplayer_peer->put_packet(packet.ptr(), packet.size()); + ERR_FAIL_COND_V(err != OK, err); + // Insert into confirmed, but as false since it was not confirmed. + psc->confirmed_peers.insert(peer_id, false); } - - return has_all_peers; + return err; } bool SceneCacheInterface::is_cache_confirmed(NodePath p_path, int p_peer) { @@ -230,7 +202,43 @@ bool SceneCacheInterface::send_object_cache(Object *p_obj, NodePath p_path, int } r_id = psc->id; - return _send_confirm_path(node, p_path, psc, p_peer_id); + bool has_all_peers = true; + List<int> peers_to_add; // If one is missing, take note to add it. + + if (p_peer_id > 0) { + // Fast single peer check. + Map<int, bool>::Element *F = psc->confirmed_peers.find(p_peer_id); + if (!F) { + peers_to_add.push_back(p_peer_id); // Need to also be notified. + has_all_peers = false; + } else if (!F->get()) { + has_all_peers = false; + } + } else { + // Long and painful. + for (const Set<int>::Element *E = multiplayer->get_connected_peers().front(); E; E = E->next()) { + if (p_peer_id < 0 && E->get() == -p_peer_id) { + continue; // Continue, excluded. + } + if (p_peer_id > 0 && E->get() != p_peer_id) { + continue; // Continue, not for this peer. + } + + Map<int, bool>::Element *F = psc->confirmed_peers.find(E->get()); + if (!F) { + peers_to_add.push_back(E->get()); // Need to also be notified. + has_all_peers = false; + } else if (!F->get()) { + has_all_peers = false; + } + } + } + + if (peers_to_add.size()) { + _send_confirm_path(node, p_path, psc, peers_to_add); + } + + return has_all_peers; } Object *SceneCacheInterface::get_cached_object(int p_from, uint32_t p_cache_id) { diff --git a/scene/multiplayer/scene_cache_interface.h b/scene/multiplayer/scene_cache_interface.h index 91a53cb948..c709d26b51 100644 --- a/scene/multiplayer/scene_cache_interface.h +++ b/scene/multiplayer/scene_cache_interface.h @@ -60,7 +60,7 @@ private: int last_send_cache_id = 1; protected: - bool _send_confirm_path(Node *p_node, NodePath p_path, PathSentCache *psc, int p_target); + Error _send_confirm_path(Node *p_node, NodePath p_path, PathSentCache *psc, const List<int> &p_peers); static MultiplayerCacheInterface *_create(MultiplayerAPI *p_multiplayer); public: diff --git a/scene/multiplayer/scene_replication_interface.cpp b/scene/multiplayer/scene_replication_interface.cpp index 25a704b37e..0764f136e4 100644 --- a/scene/multiplayer/scene_replication_interface.cpp +++ b/scene/multiplayer/scene_replication_interface.cpp @@ -350,11 +350,12 @@ void SceneReplicationInterface::_send_sync(int p_peer, uint64_t p_msec) { } if (size) { uint32_t net_id = rep_state->get_net_id(oid); - if (net_id == 0) { + if (net_id == 0 || (net_id & 0x80000000)) { // First time path based ID. NodePath rel_path = multiplayer->get_root_path().rel_path_to(sync->get_path()); int path_id = 0; multiplayer->send_object_cache(sync, rel_path, p_peer, path_id); + ERR_CONTINUE_MSG(net_id && net_id != (uint32_t(path_id) | 0x80000000), "This should never happen!"); net_id = path_id; rep_state->set_net_id(oid, net_id | 0x80000000); } diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index bc533ff022..312a557602 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -2413,7 +2413,7 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, Interpol real_t c = 0.0; // prepare for all cases of interpolation - if ((loop_mode == LOOP_LINEAR || loop_mode == LOOP_PINGPONG) && p_loop_wrap) { + if (loop_mode == LOOP_LINEAR && p_loop_wrap) { // loop if (!p_backward) { // no backward @@ -2567,11 +2567,19 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, Interpol case INTERPOLATION_CUBIC: { int pre = idx - 1; if (pre < 0) { - pre = 0; + if (loop_mode == LOOP_LINEAR && p_loop_wrap) { + pre = len - 1; + } else { + pre = 0; + } } int post = next + 1; if (post >= len) { - post = next; + if (loop_mode == LOOP_LINEAR && p_loop_wrap) { + post = 0; + } else { + post = next; + } } return _cubic_interpolate(p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c); diff --git a/scene/resources/box_shape_3d.cpp b/scene/resources/box_shape_3d.cpp index a1ec9a2230..1abbf366fd 100644 --- a/scene/resources/box_shape_3d.cpp +++ b/scene/resources/box_shape_3d.cpp @@ -77,6 +77,7 @@ bool BoxShape3D::_get(const StringName &p_name, Variant &r_property) const { #endif // DISABLE_DEPRECATED void BoxShape3D::set_size(const Vector3 &p_size) { + ERR_FAIL_COND_MSG(p_size.x < 0 || p_size.y < 0 || p_size.z < 0, "BoxShape3D size cannot be negative."); size = p_size; _update_shape(); notify_change_to_owners(); diff --git a/scene/resources/capsule_shape_2d.cpp b/scene/resources/capsule_shape_2d.cpp index 4d2698d27d..a1ad487bff 100644 --- a/scene/resources/capsule_shape_2d.cpp +++ b/scene/resources/capsule_shape_2d.cpp @@ -59,6 +59,7 @@ void CapsuleShape2D::_update_shape() { } void CapsuleShape2D::set_radius(real_t p_radius) { + ERR_FAIL_COND_MSG(p_radius < 0, "CapsuleShape2D radius cannot be negative."); radius = p_radius; if (radius > height * 0.5) { height = radius * 2.0; @@ -71,6 +72,7 @@ real_t CapsuleShape2D::get_radius() const { } void CapsuleShape2D::set_height(real_t p_height) { + ERR_FAIL_COND_MSG(p_height < 0, "CapsuleShape2D height cannot be negative."); height = p_height; if (radius > height * 0.5) { radius = height * 0.5; diff --git a/scene/resources/capsule_shape_3d.cpp b/scene/resources/capsule_shape_3d.cpp index c16ddad984..2179ce82dd 100644 --- a/scene/resources/capsule_shape_3d.cpp +++ b/scene/resources/capsule_shape_3d.cpp @@ -79,6 +79,7 @@ void CapsuleShape3D::_update_shape() { } void CapsuleShape3D::set_radius(float p_radius) { + ERR_FAIL_COND_MSG(p_radius < 0, "CapsuleShape3D radius cannot be negative."); radius = p_radius; if (radius > height * 0.5) { height = radius * 2.0; @@ -92,6 +93,7 @@ float CapsuleShape3D::get_radius() const { } void CapsuleShape3D::set_height(float p_height) { + ERR_FAIL_COND_MSG(p_height < 0, "CapsuleShape3D height cannot be negative."); height = p_height; if (radius > height * 0.5) { radius = height * 0.5; diff --git a/scene/resources/circle_shape_2d.cpp b/scene/resources/circle_shape_2d.cpp index 9c16ac2eed..de931fca7e 100644 --- a/scene/resources/circle_shape_2d.cpp +++ b/scene/resources/circle_shape_2d.cpp @@ -43,6 +43,7 @@ void CircleShape2D::_update_shape() { } void CircleShape2D::set_radius(real_t p_radius) { + ERR_FAIL_COND_MSG(p_radius < 0, "CircleShape2D radius cannot be negative."); radius = p_radius; _update_shape(); } diff --git a/scene/resources/cylinder_shape_3d.cpp b/scene/resources/cylinder_shape_3d.cpp index 5eeb62d17b..c4f1cba341 100644 --- a/scene/resources/cylinder_shape_3d.cpp +++ b/scene/resources/cylinder_shape_3d.cpp @@ -72,6 +72,7 @@ void CylinderShape3D::_update_shape() { } void CylinderShape3D::set_radius(float p_radius) { + ERR_FAIL_COND_MSG(p_radius < 0, "CylinderShape3D radius cannot be negative."); radius = p_radius; _update_shape(); notify_change_to_owners(); @@ -82,6 +83,7 @@ float CylinderShape3D::get_radius() const { } void CylinderShape3D::set_height(float p_height) { + ERR_FAIL_COND_MSG(p_height < 0, "CylinderShape3D height cannot be negative."); height = p_height; _update_shape(); notify_change_to_owners(); diff --git a/scene/resources/importer_mesh.cpp b/scene/resources/importer_mesh.cpp index 92ab091b86..a27da11f8d 100644 --- a/scene/resources/importer_mesh.cpp +++ b/scene/resources/importer_mesh.cpp @@ -287,7 +287,7 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli const int *indices_ptr = indices.ptr(); if (normals.is_empty()) { - normals.resize(vertices.size()); + normals.resize(index_count); Vector3 *n_ptr = normals.ptrw(); for (unsigned int j = 0; j < index_count; j += 3) { const Vector3 &v0 = vertices_ptr[indices_ptr[j + 0]]; diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index b74f44c52f..6fb0c0468d 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -330,7 +330,7 @@ void BaseMaterial3D::init_shaders() { shader_names->rim = "rim"; shader_names->rim_tint = "rim_tint"; shader_names->clearcoat = "clearcoat"; - shader_names->clearcoat_gloss = "clearcoat_gloss"; + shader_names->clearcoat_roughness = "clearcoat_roughness"; shader_names->anisotropy = "anisotropy_ratio"; shader_names->heightmap_scale = "heightmap_scale"; shader_names->subsurface_scattering_strength = "subsurface_scattering_strength"; @@ -541,12 +541,6 @@ void BaseMaterial3D::_update_shader() { case SPECULAR_SCHLICK_GGX: code += ",specular_schlick_ggx"; break; - case SPECULAR_BLINN: - code += ",specular_blinn"; - break; - case SPECULAR_PHONG: - code += ",specular_phong"; - break; case SPECULAR_TOON: code += ",specular_toon"; break; @@ -690,7 +684,7 @@ void BaseMaterial3D::_update_shader() { } if (features[FEATURE_CLEARCOAT]) { code += "uniform float clearcoat : hint_range(0,1);\n"; - code += "uniform float clearcoat_gloss : hint_range(0,1);\n"; + code += "uniform float clearcoat_roughness : hint_range(0,1);\n"; code += "uniform sampler2D texture_clearcoat : hint_white," + texfilter_str + ";\n"; } if (features[FEATURE_ANISOTROPY]) { @@ -1166,7 +1160,7 @@ void BaseMaterial3D::_update_shader() { code += " vec2 clearcoat_tex = texture(texture_clearcoat,base_uv).xy;\n"; } code += " CLEARCOAT = clearcoat*clearcoat_tex.x;"; - code += " CLEARCOAT_GLOSS = clearcoat_gloss*clearcoat_tex.y;\n"; + code += " CLEARCOAT_ROUGHNESS = clearcoat_roughness*clearcoat_tex.y;\n"; } if (features[FEATURE_ANISOTROPY]) { @@ -1408,13 +1402,13 @@ float BaseMaterial3D::get_clearcoat() const { return clearcoat; } -void BaseMaterial3D::set_clearcoat_gloss(float p_clearcoat_gloss) { - clearcoat_gloss = p_clearcoat_gloss; - RS::get_singleton()->material_set_param(_get_material(), shader_names->clearcoat_gloss, p_clearcoat_gloss); +void BaseMaterial3D::set_clearcoat_roughness(float p_clearcoat_roughness) { + clearcoat_roughness = p_clearcoat_roughness; + RS::get_singleton()->material_set_param(_get_material(), shader_names->clearcoat_roughness, p_clearcoat_roughness); } -float BaseMaterial3D::get_clearcoat_gloss() const { - return clearcoat_gloss; +float BaseMaterial3D::get_clearcoat_roughness() const { + return clearcoat_roughness; } void BaseMaterial3D::set_anisotropy(float p_anisotropy) { @@ -2271,8 +2265,8 @@ void BaseMaterial3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_clearcoat", "clearcoat"), &BaseMaterial3D::set_clearcoat); ClassDB::bind_method(D_METHOD("get_clearcoat"), &BaseMaterial3D::get_clearcoat); - ClassDB::bind_method(D_METHOD("set_clearcoat_gloss", "clearcoat_gloss"), &BaseMaterial3D::set_clearcoat_gloss); - ClassDB::bind_method(D_METHOD("get_clearcoat_gloss"), &BaseMaterial3D::get_clearcoat_gloss); + ClassDB::bind_method(D_METHOD("set_clearcoat_roughness", "clearcoat_roughness"), &BaseMaterial3D::set_clearcoat_roughness); + ClassDB::bind_method(D_METHOD("get_clearcoat_roughness"), &BaseMaterial3D::get_clearcoat_roughness); ClassDB::bind_method(D_METHOD("set_anisotropy", "anisotropy"), &BaseMaterial3D::set_anisotropy); ClassDB::bind_method(D_METHOD("get_anisotropy"), &BaseMaterial3D::get_anisotropy); @@ -2438,7 +2432,7 @@ void BaseMaterial3D::_bind_methods() { ADD_GROUP("Shading", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "shading_mode", PROPERTY_HINT_ENUM, "Unshaded,Per-Pixel,Per-Vertex"), "set_shading_mode", "get_shading_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "diffuse_mode", PROPERTY_HINT_ENUM, "Burley,Lambert,Lambert Wrap,Toon"), "set_diffuse_mode", "get_diffuse_mode"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "specular_mode", PROPERTY_HINT_ENUM, "SchlickGGX,Blinn,Phong,Toon,Disabled"), "set_specular_mode", "get_specular_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "specular_mode", PROPERTY_HINT_ENUM, "SchlickGGX,Toon,Disabled"), "set_specular_mode", "get_specular_mode"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "disable_ambient_light"), "set_flag", "get_flag", FLAG_DISABLE_AMBIENT_LIGHT); ADD_GROUP("Vertex Color", "vertex_color"); @@ -2486,7 +2480,7 @@ void BaseMaterial3D::_bind_methods() { ADD_GROUP("Clearcoat", "clearcoat_"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "clearcoat_enabled"), "set_feature", "get_feature", FEATURE_CLEARCOAT); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "clearcoat", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_clearcoat", "get_clearcoat"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "clearcoat_gloss", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_clearcoat_gloss", "get_clearcoat_gloss"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "clearcoat_roughness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_clearcoat_roughness", "get_clearcoat_roughness"); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "clearcoat_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_CLEARCOAT); ADD_GROUP("Anisotropy", "anisotropy_"); @@ -2693,8 +2687,6 @@ void BaseMaterial3D::_bind_methods() { BIND_ENUM_CONSTANT(DIFFUSE_TOON); BIND_ENUM_CONSTANT(SPECULAR_SCHLICK_GGX); - BIND_ENUM_CONSTANT(SPECULAR_BLINN); - BIND_ENUM_CONSTANT(SPECULAR_PHONG); BIND_ENUM_CONSTANT(SPECULAR_TOON); BIND_ENUM_CONSTANT(SPECULAR_DISABLED); @@ -2732,7 +2724,7 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) : set_rim(1.0); set_rim_tint(0.5); set_clearcoat(1); - set_clearcoat_gloss(0.5); + set_clearcoat_roughness(0.5); set_anisotropy(0); set_heightmap_scale(0.05); set_subsurface_scattering_strength(0); diff --git a/scene/resources/material.h b/scene/resources/material.h index 57591bee2f..a79f072f9a 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -252,8 +252,6 @@ public: enum SpecularMode { SPECULAR_SCHLICK_GGX, - SPECULAR_BLINN, - SPECULAR_PHONG, SPECULAR_TOON, SPECULAR_DISABLED, SPECULAR_MAX @@ -387,7 +385,7 @@ private: StringName rim; StringName rim_tint; StringName clearcoat; - StringName clearcoat_gloss; + StringName clearcoat_roughness; StringName anisotropy; StringName heightmap_scale; StringName subsurface_scattering_strength; @@ -454,7 +452,7 @@ private: float rim; float rim_tint; float clearcoat; - float clearcoat_gloss; + float clearcoat_roughness; float anisotropy; float heightmap_scale; float subsurface_scattering_strength; @@ -572,8 +570,8 @@ public: void set_clearcoat(float p_clearcoat); float get_clearcoat() const; - void set_clearcoat_gloss(float p_clearcoat_gloss); - float get_clearcoat_gloss() const; + void set_clearcoat_roughness(float p_clearcoat_roughness); + float get_clearcoat_roughness() const; void set_anisotropy(float p_anisotropy); float get_anisotropy() const; diff --git a/scene/resources/rectangle_shape_2d.cpp b/scene/resources/rectangle_shape_2d.cpp index 27659f724e..5e88c9974c 100644 --- a/scene/resources/rectangle_shape_2d.cpp +++ b/scene/resources/rectangle_shape_2d.cpp @@ -58,6 +58,7 @@ bool RectangleShape2D::_get(const StringName &p_name, Variant &r_property) const #endif // DISABLE_DEPRECATED void RectangleShape2D::set_size(const Vector2 &p_size) { + ERR_FAIL_COND_MSG(p_size.x < 0 || p_size.y < 0, "RectangleShape2D size cannot be negative."); size = p_size; _update_shape(); } diff --git a/scene/resources/sky.cpp b/scene/resources/sky.cpp index 917aa40934..9cb6a16f5c 100644 --- a/scene/resources/sky.cpp +++ b/scene/resources/sky.cpp @@ -83,7 +83,7 @@ void Sky::_bind_methods() { ClassDB::bind_method(D_METHOD("get_material"), &Sky::get_material); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "sky_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,PanoramaSkyMaterial,ProceduralSkyMaterial,PhysicalSkyMaterial"), "set_material", "get_material"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Automatic,High Quality (Slow),High Quality Incremental (Average),Real-Time (Fast)"), "set_process_mode", "get_process_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Automatic,HighQuality,HighQualityIncremental,RealTime"), "set_process_mode", "get_process_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "radiance_size", PROPERTY_HINT_ENUM, "32,64,128,256,512,1024,2048"), "set_radiance_size", "get_radiance_size"); BIND_ENUM_CONSTANT(RADIANCE_SIZE_32); diff --git a/scene/resources/sky.h b/scene/resources/sky.h index 3653568ac6..5e52239032 100644 --- a/scene/resources/sky.h +++ b/scene/resources/sky.h @@ -59,7 +59,7 @@ public: private: RID sky; - ProcessMode mode = PROCESS_MODE_REALTIME; + ProcessMode mode = PROCESS_MODE_AUTOMATIC; RadianceSize radiance_size = RADIANCE_SIZE_256; Ref<Material> sky_material; diff --git a/scene/resources/sphere_shape_3d.cpp b/scene/resources/sphere_shape_3d.cpp index ee789362c9..8282992401 100644 --- a/scene/resources/sphere_shape_3d.cpp +++ b/scene/resources/sphere_shape_3d.cpp @@ -63,6 +63,7 @@ void SphereShape3D::_update_shape() { } void SphereShape3D::set_radius(float p_radius) { + ERR_FAIL_COND_MSG(p_radius < 0, "SphereShape3D radius cannot be negative."); radius = p_radius; _update_shape(); notify_change_to_owners(); diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index 1e84947b87..1174117028 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -4432,6 +4432,10 @@ void TileSetAtlasSource::_update_padded_texture() { Ref<Image> src = texture->get_image(); + if (!src.is_valid()) { + return; + } + Ref<Image> image; image.instantiate(); image->create(size.x, size.y, false, src->get_format()); diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index dae61c8609..47ca643029 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -3163,7 +3163,7 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "rim", "RIM" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "rim_tint", "RIM_TINT" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "clearcoat", "CLEARCOAT" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "clearcoat_gloss", "CLEARCOAT_GLOSS" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "clearcoat_roughness", "CLEARCOAT_ROUGHNESS" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "anisotropy", "ANISOTROPY" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "anisotropy_flow", "ANISOTROPY_FLOW" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "subsurf_scatter", "SSS_STRENGTH" }, diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index f2479199ee..a6aa6d8c49 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -2843,8 +2843,7 @@ String VisualShaderNodeColorFunc::generate_code(Shader::Mode p_mode, VisualShade code += " vec3 c = " + p_input_vars[0] + ";\n"; code += " float max1 = max(c.r, c.g);\n"; code += " float max2 = max(max1, c.b);\n"; - code += " float max3 = max(max1, max2);\n"; - code += " " + p_output_vars[0] + " = vec3(max3, max3, max3);\n"; + code += " " + p_output_vars[0] + " = vec3(max2, max2, max2);\n"; code += " }\n"; break; case FUNC_SEPIA: diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp index 39060286a4..a710658bff 100644 --- a/servers/audio/audio_stream.cpp +++ b/servers/audio/audio_stream.cpp @@ -200,6 +200,7 @@ bool AudioStream::is_monophonic() const { void AudioStream::_bind_methods() { ClassDB::bind_method(D_METHOD("get_length"), &AudioStream::get_length); ClassDB::bind_method(D_METHOD("is_monophonic"), &AudioStream::is_monophonic); + ClassDB::bind_method(D_METHOD("instance_playback"), &AudioStream::instance_playback); GDVIRTUAL_BIND(_instance_playback); GDVIRTUAL_BIND(_get_stream_name); GDVIRTUAL_BIND(_get_length); diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index f00b8077d1..9d83e5cacc 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -1731,6 +1731,10 @@ void AudioServer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "bus_count"), "set_bus_count", "get_bus_count"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "device"), "set_device", "get_device"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "capture_device"), "capture_set_device", "capture_get_device"); + // The default value may be set to an empty string by the platform-specific audio driver. + // Override for class reference generation purposes. + ADD_PROPERTY_DEFAULT("capture_device", "Default"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "playback_speed_scale"), "set_playback_speed_scale", "get_playback_speed_scale"); ADD_SIGNAL(MethodInfo("bus_layout_changed")); diff --git a/servers/display_server.cpp b/servers/display_server.cpp index 4d7e2b4d9f..58a51e3aea 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -451,7 +451,7 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("ime_get_selection"), &DisplayServer::ime_get_selection); ClassDB::bind_method(D_METHOD("ime_get_text"), &DisplayServer::ime_get_text); - ClassDB::bind_method(D_METHOD("virtual_keyboard_show", "existing_text", "position", "multiline", "max_length", "cursor_start", "cursor_end"), &DisplayServer::virtual_keyboard_show, DEFVAL(Rect2i()), DEFVAL(false), DEFVAL(-1), DEFVAL(-1), DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("virtual_keyboard_show", "existing_text", "position", "multiline", "max_length", "cursor_start", "cursor_end"), &DisplayServer::virtual_keyboard_show, DEFVAL(Rect2()), DEFVAL(false), DEFVAL(-1), DEFVAL(-1), DEFVAL(-1)); ClassDB::bind_method(D_METHOD("virtual_keyboard_hide"), &DisplayServer::virtual_keyboard_hide); ClassDB::bind_method(D_METHOD("virtual_keyboard_get_height"), &DisplayServer::virtual_keyboard_get_height); diff --git a/servers/physics_2d/godot_space_2d.cpp b/servers/physics_2d/godot_space_2d.cpp index 5c2bda340b..68dac67d21 100644 --- a/servers/physics_2d/godot_space_2d.cpp +++ b/servers/physics_2d/godot_space_2d.cpp @@ -888,6 +888,9 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D:: // Allowed depth can't be lower than motion length, in order to handle contacts at low speed. rcd.min_allowed_depth = MIN(motion_length, min_contact_depth); + body_aabb.position += p_parameters.motion * unsafe; + int amount = _cull_aabb_for_body(p_body, body_aabb); + int from_shape = best_shape != -1 ? best_shape : 0; int to_shape = best_shape != -1 ? best_shape + 1 : p_body->get_shape_count(); @@ -899,10 +902,6 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D:: Transform2D body_shape_xform = ugt * p_body->get_shape_transform(j); GodotShape2D *body_shape = p_body->get_shape(j); - body_aabb.position += p_parameters.motion * unsafe; - - int amount = _cull_aabb_for_body(p_body, body_aabb); - for (int i = 0; i < amount; i++) { const GodotCollisionObject2D *col_obj = intersection_query_results[i]; if (p_parameters.exclude_bodies.has(col_obj->get_self())) { diff --git a/servers/physics_3d/godot_space_3d.cpp b/servers/physics_3d/godot_space_3d.cpp index ed756a7f9d..2490a2f506 100644 --- a/servers/physics_3d/godot_space_3d.cpp +++ b/servers/physics_3d/godot_space_3d.cpp @@ -926,6 +926,9 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D:: // Allowed depth can't be lower than motion length, in order to handle contacts at low speed. rcd.min_allowed_depth = MIN(motion_length, min_contact_depth); + body_aabb.position += p_parameters.motion * unsafe; + int amount = _cull_aabb_for_body(p_body, body_aabb); + int from_shape = best_shape != -1 ? best_shape : 0; int to_shape = best_shape != -1 ? best_shape + 1 : p_body->get_shape_count(); @@ -937,10 +940,6 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D:: Transform3D body_shape_xform = ugt * p_body->get_shape_transform(j); GodotShape3D *body_shape = p_body->get_shape(j); - body_aabb.position += p_parameters.motion * unsafe; - - int amount = _cull_aabb_for_body(p_body, body_aabb); - for (int i = 0; i < amount; i++) { const GodotCollisionObject3D *col_obj = intersection_query_results[i]; if (p_parameters.exclude_bodies.has(col_obj->get_self())) { diff --git a/servers/rendering/renderer_compositor.cpp b/servers/rendering/renderer_compositor.cpp index 82e8bd6ef9..fa4d9c8b31 100644 --- a/servers/rendering/renderer_compositor.cpp +++ b/servers/rendering/renderer_compositor.cpp @@ -45,7 +45,7 @@ bool RendererCompositor::is_xr_enabled() const { } RendererCompositor::RendererCompositor() { - xr_enabled = GLOBAL_GET("rendering/xr/enabled"); + xr_enabled = GLOBAL_GET("xr/shaders/enabled"); } RendererCanvasRender *RendererCanvasRender::singleton = nullptr; diff --git a/servers/rendering/renderer_rd/effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp index 02a0b6f184..7883a2d816 100644 --- a/servers/rendering/renderer_rd/effects_rd.cpp +++ b/servers/rendering/renderer_rd/effects_rd.cpp @@ -332,7 +332,7 @@ void EffectsRD::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer RD::get_singleton()->draw_list_draw(draw_list, true); } -void EffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_alpha_to_zero, bool p_srgb, RID p_secondary) { +void EffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_alpha_to_zero, bool p_srgb, RID p_secondary, bool p_multiview) { memset(©_to_fb.push_constant, 0, sizeof(CopyToFbPushConstant)); if (p_flip_y) { @@ -348,10 +348,18 @@ void EffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, copy_to_fb.push_constant.srgb = true; } + CopyToFBMode mode; + if (p_multiview) { + mode = p_secondary.is_valid() ? COPY_TO_FB_MULTIVIEW_WITH_DEPTH : COPY_TO_FB_MULTIVIEW; + } else { + mode = p_secondary.is_valid() ? COPY_TO_FB_COPY2 : COPY_TO_FB_COPY; + } + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_rect); - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_to_fb.pipelines[p_secondary.is_valid() ? COPY_TO_FB_COPY2 : COPY_TO_FB_COPY].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_to_fb.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0); if (p_secondary.is_valid()) { + // TODO may need to do this differently when reading from depth buffer for multiview RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_secondary), 1); } RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); @@ -2032,7 +2040,7 @@ void EffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, u memset(&roughness.push_constant, 0, sizeof(CubemapRoughnessPushConstant)); roughness.push_constant.face_id = p_face_id > 9 ? 0 : p_face_id; - roughness.push_constant.roughness = p_roughness; + roughness.push_constant.roughness = p_roughness * p_roughness; // Shader expects roughness, not perceptual roughness, so multiply before passing in. roughness.push_constant.sample_count = p_sample_count; roughness.push_constant.use_direct_write = p_roughness == 0.0; roughness.push_constant.face_size = p_size; @@ -2040,7 +2048,7 @@ void EffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, u RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, roughness.compute_pipeline); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture, true), 0); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 1); RD::get_singleton()->compute_list_set_push_constant(compute_list, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant)); @@ -2060,7 +2068,7 @@ void EffectsRD::cubemap_roughness_raster(RID p_source_rd_texture, RID p_dest_fra memset(&roughness.push_constant, 0, sizeof(CubemapRoughnessPushConstant)); roughness.push_constant.face_id = p_face_id; - roughness.push_constant.roughness = p_roughness; + roughness.push_constant.roughness = p_roughness * p_roughness; // Shader expects roughness, not perceptual roughness, so multiply before passing in. roughness.push_constant.sample_count = p_sample_count; roughness.push_constant.use_direct_write = p_roughness == 0.0; roughness.push_constant.face_size = p_size; @@ -2367,15 +2375,26 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) { copy_modes.push_back("\n"); copy_modes.push_back("\n#define MODE_PANORAMA_TO_DP\n"); copy_modes.push_back("\n#define MODE_TWO_SOURCES\n"); + copy_modes.push_back("\n#define MULTIVIEW\n"); + copy_modes.push_back("\n#define MULTIVIEW\n#define MODE_TWO_SOURCES\n"); copy_to_fb.shader.initialize(copy_modes); + if (!RendererCompositorRD::singleton->is_xr_enabled()) { + copy_to_fb.shader.set_variant_enabled(COPY_TO_FB_MULTIVIEW, false); + copy_to_fb.shader.set_variant_enabled(COPY_TO_FB_MULTIVIEW_WITH_DEPTH, false); + } + copy_to_fb.shader_version = copy_to_fb.shader.version_create(); //use additive for (int i = 0; i < COPY_TO_FB_MAX; i++) { - copy_to_fb.pipelines[i].setup(copy_to_fb.shader.version_get_shader(copy_to_fb.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); + if (copy_to_fb.shader.is_variant_enabled(i)) { + copy_to_fb.pipelines[i].setup(copy_to_fb.shader.version_get_shader(copy_to_fb.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); + } else { + copy_to_fb.pipelines[i].clear(); + } } } diff --git a/servers/rendering/renderer_rd/effects_rd.h b/servers/rendering/renderer_rd/effects_rd.h index f5e5b1ace7..eca5e09800 100644 --- a/servers/rendering/renderer_rd/effects_rd.h +++ b/servers/rendering/renderer_rd/effects_rd.h @@ -203,6 +203,9 @@ private: COPY_TO_FB_COPY, COPY_TO_FB_COPY_PANORAMA_TO_DP, COPY_TO_FB_COPY2, + + COPY_TO_FB_MULTIVIEW, + COPY_TO_FB_MULTIVIEW_WITH_DEPTH, COPY_TO_FB_MAX, }; @@ -893,7 +896,7 @@ public: bool get_prefer_raster_effects(); void fsr_upscale(RID p_source_rd_texture, RID p_secondary_texture, RID p_destination_texture, const Size2i &p_internal_size, const Size2i &p_size, float p_fsr_upscale_sharpness); - void copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_alpha_to_zero = false, bool p_srgb = false, RID p_secondary = RID()); + void copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_alpha_to_zero = false, bool p_srgb = false, RID p_secondary = RID(), bool p_multiview = false); void copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_all_source = false, bool p_8_bit_dst = false, bool p_alpha_to_one = false); void copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array); void copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false); diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp index 7987a98b0e..24be451e78 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp @@ -557,7 +557,7 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin actions.renames["RIM"] = "rim"; actions.renames["RIM_TINT"] = "rim_tint"; actions.renames["CLEARCOAT"] = "clearcoat"; - actions.renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss"; + actions.renames["CLEARCOAT_ROUGHNESS"] = "clearcoat_roughness"; actions.renames["ANISOTROPY"] = "anisotropy"; actions.renames["ANISOTROPY_FLOW"] = "anisotropy_flow"; actions.renames["SSS_STRENGTH"] = "sss_strength"; @@ -607,7 +607,7 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin actions.usage_defines["RIM"] = "#define LIGHT_RIM_USED\n"; actions.usage_defines["RIM_TINT"] = "@RIM"; actions.usage_defines["CLEARCOAT"] = "#define LIGHT_CLEARCOAT_USED\n"; - actions.usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT"; + actions.usage_defines["CLEARCOAT_ROUGHNESS"] = "@CLEARCOAT"; actions.usage_defines["ANISOTROPY"] = "#define LIGHT_ANISOTROPY_USED\n"; actions.usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY"; actions.usage_defines["AO"] = "#define AO_USED\n"; @@ -663,20 +663,12 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin actions.render_mode_defines["sss_mode_skin"] = "#define SSS_MODE_SKIN\n"; - bool force_blinn = GLOBAL_GET("rendering/shading/overrides/force_blinn_over_ggx"); - - if (!force_blinn) { - actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; - } else { - actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n"; - } + actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; actions.custom_samplers["SCREEN_TEXTURE"] = "material_samplers[3]"; // linear filter with mipmaps actions.custom_samplers["DEPTH_TEXTURE"] = "material_samplers[3]"; actions.custom_samplers["NORMAL_ROUGHNESS_TEXTURE"] = "material_samplers[1]"; // linear filter - actions.render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n"; - actions.render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n"; actions.render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n"; actions.render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n"; actions.render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n"; diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp index 0b99948063..34b2fa9440 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp @@ -545,7 +545,7 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p actions.renames["RIM"] = "rim"; actions.renames["RIM_TINT"] = "rim_tint"; actions.renames["CLEARCOAT"] = "clearcoat"; - actions.renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss"; + actions.renames["CLEARCOAT_ROUGHNESS"] = "clearcoat_roughness"; actions.renames["ANISOTROPY"] = "anisotropy"; actions.renames["ANISOTROPY_FLOW"] = "anisotropy_flow"; actions.renames["SSS_STRENGTH"] = "sss_strength"; @@ -594,7 +594,7 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p actions.usage_defines["RIM"] = "#define LIGHT_RIM_USED\n"; actions.usage_defines["RIM_TINT"] = "@RIM"; actions.usage_defines["CLEARCOAT"] = "#define LIGHT_CLEARCOAT_USED\n"; - actions.usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT"; + actions.usage_defines["CLEARCOAT_ROUGHNESS"] = "@CLEARCOAT"; actions.usage_defines["ANISOTROPY"] = "#define LIGHT_ANISOTROPY_USED\n"; actions.usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY"; actions.usage_defines["AO"] = "#define AO_USED\n"; @@ -649,15 +649,8 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p actions.render_mode_defines["sss_mode_skin"] = "#define SSS_MODE_SKIN\n"; - bool force_blinn = GLOBAL_GET("rendering/shading/overrides/force_blinn_over_ggx"); - if (!force_blinn) { - actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; - } else { - actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n"; - } + actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; - actions.render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n"; - actions.render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n"; actions.render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n"; actions.render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n"; actions.render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n"; diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index 2f8ef696cd..606527ed24 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp @@ -39,6 +39,9 @@ void RendererCompositorRD::prepare_for_blitting_render_targets() { void RendererCompositorRD::blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) { RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin_for_screen(p_screen); + if (draw_list == RD::INVALID_ID) { + return; // Window is minimized and does not have valid swapchain, skip drawing without printing errors. + } for (int i = 0; i < p_amount; i++) { RID texture = storage->render_target_get_texture(p_render_targets[i].render_target); diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp index 354516ae87..b44ae6cf8d 100644 --- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp @@ -473,12 +473,13 @@ void RendererSceneSkyRD::ReflectionData::create_reflection_fast_filter(RendererS } RD::get_singleton()->draw_command_end_label(); // Filter radiance } else { + RD::get_singleton()->draw_command_begin_label("Downsample radiance map"); effects->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size); for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) { effects->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size); } - + RD::get_singleton()->draw_command_end_label(); // Downsample Radiance Vector<RID> views; if (p_use_arrays) { for (int i = 1; i < layers.size(); i++) { @@ -489,8 +490,9 @@ void RendererSceneSkyRD::ReflectionData::create_reflection_fast_filter(RendererS views.push_back(layers[0].views[i]); } } - + RD::get_singleton()->draw_command_begin_label("Fast filter radiance"); effects->cubemap_filter(downsampled_radiance_cubemap, views, p_use_arrays); + RD::get_singleton()->draw_command_end_label(); // Filter radiance } } @@ -500,12 +502,25 @@ void RendererSceneSkyRD::ReflectionData::create_reflection_importance_sample(Ren bool prefer_raster_effects = effects->get_prefer_raster_effects(); if (prefer_raster_effects) { - // Need to ask clayjohn but p_cube_side is set to 10, looks like in the compute shader we're doing all 6 sides in one call - // here we need to do them one by one so ignoring p_cube_side + if (p_base_layer == 1) { + RD::get_singleton()->draw_command_begin_label("Downsample radiance map"); + for (int k = 0; k < 6; k++) { + effects->cubemap_downsample_raster(radiance_base_cubemap, downsampled_layer.mipmaps[0].framebuffers[k], k, downsampled_layer.mipmaps[0].size); + } + + for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) { + for (int k = 0; k < 6; k++) { + effects->cubemap_downsample_raster(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].framebuffers[k], k, downsampled_layer.mipmaps[i].size); + } + } + RD::get_singleton()->draw_command_end_label(); // Downsample Radiance + } + + RD::get_singleton()->draw_command_begin_label("High Quality filter radiance"); if (p_use_arrays) { for (int k = 0; k < 6; k++) { effects->cubemap_roughness_raster( - radiance_base_cubemap, + downsampled_radiance_cubemap, layers[p_base_layer].mipmaps[0].framebuffers[k], k, p_sky_ggx_samples_quality, @@ -515,7 +530,7 @@ void RendererSceneSkyRD::ReflectionData::create_reflection_importance_sample(Ren } else { for (int k = 0; k < 6; k++) { effects->cubemap_roughness_raster( - layers[0].views[p_base_layer - 1], + downsampled_radiance_cubemap, layers[0].mipmaps[p_base_layer].framebuffers[k], k, p_sky_ggx_samples_quality, @@ -524,12 +539,22 @@ void RendererSceneSkyRD::ReflectionData::create_reflection_importance_sample(Ren } } } else { + if (p_base_layer == 1) { + RD::get_singleton()->draw_command_begin_label("Downsample radiance map"); + effects->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size); + + for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) { + effects->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size); + } + RD::get_singleton()->draw_command_end_label(); // Downsample Radiance + } + + RD::get_singleton()->draw_command_begin_label("High Quality filter radiance"); if (p_use_arrays) { - //render directly to the layers - effects->cubemap_roughness(radiance_base_cubemap, layers[p_base_layer].views[0], p_cube_side, p_sky_ggx_samples_quality, float(p_base_layer) / (layers.size() - 1.0), layers[p_base_layer].mipmaps[0].size.x); + effects->cubemap_roughness(downsampled_radiance_cubemap, layers[p_base_layer].views[0], p_cube_side, p_sky_ggx_samples_quality, float(p_base_layer) / (layers.size() - 1.0), layers[p_base_layer].mipmaps[0].size.x); } else { effects->cubemap_roughness( - layers[0].views[p_base_layer - 1], + downsampled_radiance_cubemap, layers[0].views[p_base_layer], p_cube_side, p_sky_ggx_samples_quality, @@ -537,6 +562,7 @@ void RendererSceneSkyRD::ReflectionData::create_reflection_importance_sample(Ren layers[0].mipmaps[p_base_layer].size.x); } } + RD::get_singleton()->draw_command_end_label(); // Filter radiance } void RendererSceneSkyRD::ReflectionData::update_reflection_mipmaps(RendererStorageRD *p_storage, int p_start, int p_end) { diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h index 7b6c813d90..13d24e2508 100644 --- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h @@ -254,7 +254,7 @@ public: int radiance_size = 256; - RS::SkyMode mode = RS::SKY_MODE_REALTIME; + RS::SkyMode mode = RS::SKY_MODE_AUTOMATIC; ReflectionData reflection; bool dirty = false; diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp index e3829eb5ed..1473a92a1a 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp @@ -5712,6 +5712,21 @@ void RendererStorageRD::update_particles() { total_amount *= particles->trail_bind_poses.size(); } + // Affect 2D only. + if (particles->use_local_coords) { + // In local mode, particle positions are calculated locally (relative to the node position) + // and they're also drawn locally. + // It works as expected, so we just pass an identity transform. + store_transform(Transform3D(), copy_push_constant.inv_emission_transform); + } else { + // In global mode, particle positions are calculated globally (relative to the canvas origin) + // but they're drawn locally. + // So, we need to pass the inverse of the emission transform to bring the + // particles to local coordinates before drawing. + Transform3D inv = particles->emission_transform.affine_inverse(); + store_transform(inv, copy_push_constant.inv_emission_transform); + } + copy_push_constant.total_particles = total_amount; copy_push_constant.frame_remainder = particles->interpolate ? particles->frame_remainder : 0.0; copy_push_constant.align_mode = particles->transform_align; diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h index ee4d18210a..33a3b8e229 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.h +++ b/servers/rendering/renderer_rd/renderer_storage_rd.h @@ -852,6 +852,8 @@ private: uint32_t lifetime_split; uint32_t lifetime_reverse; uint32_t copy_mode_2d; + + float inv_emission_transform[16]; }; enum { diff --git a/servers/rendering/renderer_rd/shaders/copy_to_fb.glsl b/servers/rendering/renderer_rd/shaders/copy_to_fb.glsl index 2f1f9c4765..9787c9879d 100644 --- a/servers/rendering/renderer_rd/shaders/copy_to_fb.glsl +++ b/servers/rendering/renderer_rd/shaders/copy_to_fb.glsl @@ -4,7 +4,20 @@ #VERSION_DEFINES +#ifdef MULTIVIEW +#ifdef has_VK_KHR_multiview +#extension GL_EXT_multiview : enable +#define ViewIndex gl_ViewIndex +#else // has_VK_KHR_multiview +#define ViewIndex 0 +#endif // has_VK_KHR_multiview +#endif //MULTIVIEW + +#ifdef MULTIVIEW +layout(location = 0) out vec3 uv_interp; +#else layout(location = 0) out vec2 uv_interp; +#endif layout(push_constant, std430) uniform Params { vec4 section; @@ -19,9 +32,11 @@ params; void main() { vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)); - uv_interp = base_arr[gl_VertexIndex]; - - vec2 vpos = uv_interp; + uv_interp.xy = base_arr[gl_VertexIndex]; +#ifdef MULTIVIEW + uv_interp.z = ViewIndex; +#endif + vec2 vpos = uv_interp.xy; if (params.use_section) { vpos = params.section.xy + vpos * params.section.zw; } @@ -39,6 +54,15 @@ void main() { #VERSION_DEFINES +#ifdef MULTIVIEW +#ifdef has_VK_KHR_multiview +#extension GL_EXT_multiview : enable +#define ViewIndex gl_ViewIndex +#else // has_VK_KHR_multiview +#define ViewIndex 0 +#endif // has_VK_KHR_multiview +#endif //MULTIVIEW + layout(push_constant, std430) uniform Params { vec4 section; vec2 pixel_size; @@ -52,12 +76,25 @@ layout(push_constant, std430) uniform Params { } params; +#ifdef MULTIVIEW +layout(location = 0) in vec3 uv_interp; +#else layout(location = 0) in vec2 uv_interp; +#endif +#ifdef MULTIVIEW +layout(set = 0, binding = 0) uniform sampler2DArray source_color; +#ifdef MODE_TWO_SOURCES +layout(set = 1, binding = 0) uniform sampler2DArray source_depth; +layout(location = 1) out float depth; +#endif /* MODE_TWO_SOURCES */ +#else layout(set = 0, binding = 0) uniform sampler2D source_color; #ifdef MODE_TWO_SOURCES layout(set = 1, binding = 0) uniform sampler2D source_color2; -#endif +#endif /* MODE_TWO_SOURCES */ +#endif /* MULTIVIEW */ + layout(location = 0) out vec4 frag_color; vec3 linear_to_srgb(vec3 color) { @@ -68,9 +105,14 @@ vec3 linear_to_srgb(vec3 color) { } void main() { +#ifdef MULTIVIEW + vec3 uv = uv_interp; +#else vec2 uv = uv_interp; +#endif #ifdef MODE_PANORAMA_TO_DP + // Note, multiview and panorama should not be mixed at this time //obtain normal from dual paraboloid uv #define M_PI 3.14159265359 @@ -98,10 +140,20 @@ void main() { uv = 1.0 - uv; } #endif + +#ifdef MULTIVIEW + vec4 color = textureLod(source_color, uv, 0.0); +#ifdef MODE_TWO_SOURCES + // In multiview our 2nd input will be our depth map + depth = textureLod(source_depth, uv, 0.0).r; +#endif /* MODE_TWO_SOURCES */ + +#else vec4 color = textureLod(source_color, uv, 0.0); #ifdef MODE_TWO_SOURCES color += textureLod(source_color2, uv, 0.0); -#endif +#endif /* MODE_TWO_SOURCES */ +#endif /* MULTIVIEW */ if (params.force_luminance) { color.rgb = vec3(max(max(color.r, color.g), color.b)); } diff --git a/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl b/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl index 28f4dc59ec..1d46f59408 100644 --- a/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl +++ b/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl @@ -21,24 +21,38 @@ void main() { vec2 uv = ((vec2(id.xy) * 2.0 + 1.0) / (params.face_size) - 1.0); vec3 N = texelCoordToVec(uv, id.z); - //vec4 color = color_interp; - if (params.use_direct_write) { imageStore(dest_cubemap, ivec3(id), vec4(texture(source_cube, N).rgb, 1.0)); } else { vec4 sum = vec4(0.0, 0.0, 0.0, 0.0); + float solid_angle_texel = 4.0 * M_PI / (6.0 * params.face_size * params.face_size); + float roughness2 = params.roughness * params.roughness; + float roughness4 = roughness2 * roughness2; + vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); + mat3 T; + T[0] = normalize(cross(UpVector, N)); + T[1] = cross(N, T[0]); + T[2] = N; + for (uint sampleNum = 0u; sampleNum < params.sample_count; sampleNum++) { vec2 xi = Hammersley(sampleNum, params.sample_count); - vec3 H = ImportanceSampleGGX(xi, params.roughness, N); - vec3 V = N; - vec3 L = (2.0 * dot(V, H) * H - V); + vec3 H = T * ImportanceSampleGGX(xi, roughness4); + float NdotH = dot(N, H); + vec3 L = (2.0 * NdotH * H - N); float ndotl = clamp(dot(N, L), 0.0, 1.0); if (ndotl > 0.0) { - sum.rgb += textureLod(source_cube, L, 0.0).rgb * ndotl; + float D = DistributionGGX(NdotH, roughness4); + float pdf = D * NdotH / (4.0 * NdotH) + 0.0001; + + float solid_angle_sample = 1.0 / (float(params.sample_count) * pdf + 0.0001); + + float mipLevel = params.roughness == 0.0 ? 0.0 : 0.5 * log2(solid_angle_sample / solid_angle_texel); + + sum.rgb += textureLod(source_cube, L, mipLevel).rgb * ndotl; sum.a += ndotl; } } diff --git a/servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl b/servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl index ce0a25e12f..1bee428a6f 100644 --- a/servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl @@ -47,12 +47,10 @@ vec3 texelCoordToVec(vec2 uv, uint faceID) { return normalize(result); } -vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) { - float a = Roughness * Roughness; // DISNEY'S ROUGHNESS [see Burley'12 siggraph] - +vec3 ImportanceSampleGGX(vec2 xi, float roughness4) { // Compute distribution direction - float Phi = 2.0 * M_PI * Xi.x; - float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a * a - 1.0) * Xi.y)); + float Phi = 2.0 * M_PI * xi.x; + float CosTheta = sqrt((1.0 - xi.y) / (1.0 + (roughness4 - 1.0) * xi.y)); float SinTheta = sqrt(1.0 - CosTheta * CosTheta); // Convert to spherical direction @@ -61,12 +59,15 @@ vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) { H.y = SinTheta * sin(Phi); H.z = CosTheta; - vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); - vec3 TangentX = normalize(cross(UpVector, N)); - vec3 TangentY = cross(N, TangentX); + return H; +} + +float DistributionGGX(float NdotH, float roughness4) { + float NdotH2 = NdotH * NdotH; + float denom = (NdotH2 * (roughness4 - 1.0) + 1.0); + denom = M_PI * denom * denom; - // Tangent to world space - return TangentX * H.x + TangentY * H.y + N * H.z; + return roughness4 / denom; } // https://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html diff --git a/servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl b/servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl index 2570308816..c29accd8a7 100644 --- a/servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl +++ b/servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl @@ -42,17 +42,33 @@ void main() { } else { vec4 sum = vec4(0.0, 0.0, 0.0, 0.0); + float solid_angle_texel = 4.0 * M_PI / (6.0 * params.face_size * params.face_size); + float roughness2 = params.roughness * params.roughness; + float roughness4 = roughness2 * roughness2; + vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); + mat3 T; + T[0] = normalize(cross(UpVector, N)); + T[1] = cross(N, T[0]); + T[2] = N; + for (uint sampleNum = 0u; sampleNum < params.sample_count; sampleNum++) { vec2 xi = Hammersley(sampleNum, params.sample_count); - vec3 H = ImportanceSampleGGX(xi, params.roughness, N); - vec3 V = N; - vec3 L = (2.0 * dot(V, H) * H - V); + vec3 H = T * ImportanceSampleGGX(xi, roughness4); + float NdotH = dot(N, H); + vec3 L = (2.0 * NdotH * H - N); float ndotl = clamp(dot(N, L), 0.0, 1.0); if (ndotl > 0.0) { - sum.rgb += textureLod(source_cube, L, 0.0).rgb * ndotl; + float D = DistributionGGX(NdotH, roughness4); + float pdf = D * NdotH / (4.0 * NdotH) + 0.0001; + + float solid_angle_sample = 1.0 / (float(params.sample_count) * pdf + 0.0001); + + float mipLevel = params.roughness == 0.0 ? 0.0 : 0.5 * log2(solid_angle_sample / solid_angle_texel); + + sum.rgb += textureLod(source_cube, L, mipLevel).rgb * ndotl; sum.a += ndotl; } } diff --git a/servers/rendering/renderer_rd/shaders/particles_copy.glsl b/servers/rendering/renderer_rd/shaders/particles_copy.glsl index b991880cd9..afbd5a9caa 100644 --- a/servers/rendering/renderer_rd/shaders/particles_copy.glsl +++ b/servers/rendering/renderer_rd/shaders/particles_copy.glsl @@ -61,6 +61,8 @@ layout(push_constant, std430) uniform Params { uint lifetime_split; bool lifetime_reverse; bool copy_mode_2d; + + mat4 inv_emission_transform; } params; @@ -199,6 +201,12 @@ void main() { txform = txform * trail_bind_poses.data[part_ofs]; } + if (params.copy_mode_2d) { + // In global mode, bring 2D particles to local coordinates + // as they will be drawn with the node position as origin. + txform = params.inv_emission_transform * txform; + } + txform = transpose(txform); } else { txform = mat4(vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0)); //zero scale, becomes invisible diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl index 5d65b00bee..a8648fc96a 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl @@ -478,8 +478,8 @@ layout(location = 0) out vec4 frag_color; #if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) -/* Make a default specular mode SPECULAR_SCHLICK_GGX. */ -#if !defined(SPECULAR_DISABLED) && !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_BLINN) && !defined(SPECULAR_PHONG) && !defined(SPECULAR_TOON) +// Default to SPECULAR_SCHLICK_GGX. +#if !defined(SPECULAR_DISABLED) && !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_TOON) #define SPECULAR_SCHLICK_GGX #endif @@ -589,7 +589,7 @@ void main() { float rim = 0.0; float rim_tint = 0.0; float clearcoat = 0.0; - float clearcoat_gloss = 0.0; + float clearcoat_roughness = 0.0; float anisotropy = 0.0; vec2 anisotropy_flow = vec2(1.0, 0.0); vec4 fog = vec4(0.0); @@ -912,7 +912,17 @@ void main() { #if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) if (scene_data.use_reflection_cubemap) { +#ifdef LIGHT_ANISOTROPY_USED + // https://google.github.io/filament/Filament.html#lighting/imagebasedlights/anisotropy + vec3 anisotropic_direction = anisotropy >= 0.0 ? binormal : tangent; + vec3 anisotropic_tangent = cross(anisotropic_direction, view); + vec3 anisotropic_normal = cross(anisotropic_tangent, anisotropic_direction); + vec3 bent_normal = normalize(mix(normal, anisotropic_normal, abs(anisotropy) * clamp(5.0 * roughness, 0.0, 1.0))); + vec3 ref_vec = reflect(-view, bent_normal); +#else vec3 ref_vec = reflect(-view, normal); +#endif + float horizon = min(1.0 + dot(ref_vec, normal), 1.0); ref_vec = scene_data.radiance_inverse_xform * ref_vec; #ifdef USE_RADIANCE_CUBEMAP_ARRAY @@ -954,6 +964,36 @@ void main() { #if defined(CUSTOM_IRRADIANCE_USED) ambient_light = mix(ambient_light, custom_irradiance.rgb, custom_irradiance.a); #endif + +#ifdef LIGHT_CLEARCOAT_USED + + if (scene_data.use_reflection_cubemap) { + vec3 n = normalize(normal_interp); // We want to use geometric normal, not normal_map + float NoV = max(dot(n, view), 0.0001); + vec3 ref_vec = reflect(-view, n); + // The clear coat layer assumes an IOR of 1.5 (4% reflectance) + float Fc = clearcoat * (0.04 + 0.96 * SchlickFresnel(NoV)); + float attenuation = 1.0 - Fc; + ambient_light *= attenuation; + specular_light *= attenuation; + + float horizon = min(1.0 + dot(ref_vec, normal), 1.0); + ref_vec = scene_data.radiance_inverse_xform * ref_vec; + float roughness_lod = mix(0.001, 0.1, clearcoat_roughness) * MAX_ROUGHNESS_LOD; +#ifdef USE_RADIANCE_CUBEMAP_ARRAY + + float lod, blend; + blend = modf(roughness_lod, lod); + vec3 clearcoat_light = texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ref_vec, lod)).rgb; + clearcoat_light = mix(clearcoat_light, texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ref_vec, lod + 1)).rgb, blend); + +#else + vec3 clearcoat_light = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ref_vec, roughness_lod).rgb; + +#endif //USE_RADIANCE_CUBEMAP_ARRAY + specular_light += clearcoat_light * horizon * horizon * Fc * scene_data.ambient_light_color_energy.a; + } +#endif #endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) //radiance @@ -1202,8 +1242,16 @@ void main() { if (!bool(reflections.data[reflection_index].mask & instances.data[instance_index].layer_mask)) { continue; //not masked } - - reflection_process(reflection_index, vertex, normal, roughness, ambient_light, specular_light, ambient_accum, reflection_accum); +#ifdef LIGHT_ANISOTROPY_USED + // https://google.github.io/filament/Filament.html#lighting/imagebasedlights/anisotropy + vec3 anisotropic_direction = anisotropy >= 0.0 ? binormal : tangent; + vec3 anisotropic_tangent = cross(anisotropic_direction, view); + vec3 anisotropic_normal = cross(anisotropic_tangent, anisotropic_direction); + vec3 bent_normal = normalize(mix(normal, anisotropic_normal, abs(anisotropy) * clamp(5.0 * roughness, 0.0, 1.0))); +#else + vec3 bent_normal = normal; +#endif + reflection_process(reflection_index, vertex, bent_normal, roughness, ambient_light, specular_light, ambient_accum, reflection_accum); } } @@ -1555,10 +1603,11 @@ void main() { rim, rim_tint, #endif #ifdef LIGHT_CLEARCOAT_USED - clearcoat, clearcoat_gloss, + clearcoat, clearcoat_roughness, normalize(normal_interp), #endif #ifdef LIGHT_ANISOTROPY_USED - binormal, tangent, anisotropy, + binormal, + tangent, anisotropy, #endif diffuse_light, specular_light); @@ -1626,7 +1675,7 @@ void main() { rim_tint, #endif #ifdef LIGHT_CLEARCOAT_USED - clearcoat, clearcoat_gloss, + clearcoat, clearcoat_roughness, normalize(normal_interp), #endif #ifdef LIGHT_ANISOTROPY_USED tangent, binormal, anisotropy, @@ -1698,10 +1747,11 @@ void main() { rim_tint, #endif #ifdef LIGHT_CLEARCOAT_USED - clearcoat, clearcoat_gloss, + clearcoat, clearcoat_roughness, normalize(normal_interp), #endif #ifdef LIGHT_ANISOTROPY_USED - tangent, binormal, anisotropy, + tangent, + binormal, anisotropy, #endif diffuse_light, specular_light); } @@ -1904,7 +1954,7 @@ void main() { frag_color = vec4(albedo, alpha); #else frag_color = vec4(emission + ambient_light + diffuse_light + specular_light, alpha); - //frag_color = vec4(1.0); +//frag_color = vec4(1.0); #endif //USE_NO_SHADING // Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky. diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl index 084e2a0673..3b110aded2 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl @@ -15,7 +15,7 @@ #include "cluster_data_inc.glsl" #include "decal_data_inc.glsl" -#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(MODE_RENDER_SDF) || defined(MODE_RENDER_NORMAL_ROUGHNESS) || defined(MODE_RENDER_VOXEL_GI) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) +#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(MODE_RENDER_SDF) || defined(MODE_RENDER_NORMAL_ROUGHNESS) || defined(MODE_RENDER_VOXEL_GI) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) #ifndef NORMAL_USED #define NORMAL_USED #endif diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl index 16f77fb91a..cf2e835b04 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl @@ -1,55 +1,29 @@ // Functions related to lighting -// This returns the G_GGX function divided by 2 cos_theta_m, where in practice cos_theta_m is either N.L or N.V. -// We're dividing this factor off because the overall term we'll end up looks like -// (see, for example, the first unnumbered equation in B. Burley, "Physically Based Shading at Disney", SIGGRAPH 2012): -// -// F(L.V) D(N.H) G(N.L) G(N.V) / (4 N.L N.V) -// -// We're basically regouping this as -// -// F(L.V) D(N.H) [G(N.L)/(2 N.L)] [G(N.V) / (2 N.V)] -// -// and thus, this function implements the [G(N.m)/(2 N.m)] part with m = L or V. -// -// The contents of the D and G (G1) functions (GGX) are taken from -// E. Heitz, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs", J. Comp. Graph. Tech. 3 (2) (2014). -// Eqns 71-72 and 85-86 (see also Eqns 43 and 80). - -float G_GGX_2cos(float cos_theta_m, float alpha) { - // Schlick's approximation - // C. Schlick, "An Inexpensive BRDF Model for Physically-based Rendering", Computer Graphics Forum. 13 (3): 233 (1994) - // Eq. (19), although see Heitz (2014) the about the problems with his derivation. - // It nevertheless approximates GGX well with k = alpha/2. - float k = 0.5 * alpha; - return 0.5 / (cos_theta_m * (1.0 - k) + k); - - // float cos2 = cos_theta_m * cos_theta_m; - // float sin2 = (1.0 - cos2); - // return 1.0 / (cos_theta_m + sqrt(cos2 + alpha * alpha * sin2)); -} - float D_GGX(float cos_theta_m, float alpha) { float alpha2 = alpha * alpha; float d = 1.0 + (alpha2 - 1.0) * cos_theta_m * cos_theta_m; return alpha2 / (M_PI * d * d); } -float G_GGX_anisotropic_2cos(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) { - float cos2 = cos_theta_m * cos_theta_m; - float sin2 = (1.0 - cos2); - float s_x = alpha_x * cos_phi; - float s_y = alpha_y * sin_phi; - return 1.0 / max(cos_theta_m + sqrt(cos2 + (s_x * s_x + s_y * s_y) * sin2), 0.001); +// From Earl Hammon, Jr. "PBR Diffuse Lighting for GGX+Smith Microsurfaces" https://www.gdcvault.com/play/1024478/PBR-Diffuse-Lighting-for-GGX +float V_GGX(float NdotL, float NdotV, float alpha) { + return 0.5 / mix(2.0 * NdotL * NdotV, NdotL + NdotV, alpha); } float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) { - float cos2 = cos_theta_m * cos_theta_m; - float sin2 = (1.0 - cos2); - float r_x = cos_phi / alpha_x; - float r_y = sin_phi / alpha_y; - float d = cos2 + sin2 * (r_x * r_x + r_y * r_y); - return 1.0 / max(M_PI * alpha_x * alpha_y * d * d, 0.001); + float alpha2 = alpha_x * alpha_y; + highp vec3 v = vec3(alpha_y * cos_phi, alpha_x * sin_phi, alpha2 * cos_theta_m); + highp float v2 = dot(v, v); + float w2 = alpha2 / v2; + float D = alpha2 * w2 * w2 * (1.0 / M_PI); + return D; +} + +float V_GGX_anisotropic(float alpha_x, float alpha_y, float TdotV, float TdotL, float BdotV, float BdotL, float NdotV, float NdotL) { + float Lambda_V = NdotL * length(vec3(alpha_x * TdotV, alpha_y * BdotV, NdotV)); + float Lambda_L = NdotV * length(vec3(alpha_x * TdotL, alpha_y * BdotL, NdotL)); + return 0.5 / (Lambda_V + Lambda_L); } float SchlickFresnel(float u) { @@ -58,14 +32,6 @@ float SchlickFresnel(float u) { return m2 * m2 * m; // pow(m,5) } -float GTR1(float NdotH, float a) { - if (a >= 1.0) - return 1.0 / M_PI; - float a2 = a * a; - float t = 1.0 + (a2 - 1.0) * NdotH * NdotH; - return (a2 - 1.0) / (M_PI * log(a2) * t); -} - vec3 F0(float metallic, float specular, vec3 albedo) { float dielectric = 0.16 * specular * specular; // use albedo * metallic as colored specular reflectance at 0 angle for metallic materials; @@ -87,7 +53,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte float rim, float rim_tint, #endif #ifdef LIGHT_CLEARCOAT_USED - float clearcoat, float clearcoat_gloss, + float clearcoat, float clearcoat_roughness, vec3 vertex_normal, #endif #ifdef LIGHT_ANISOTROPY_USED vec3 B, vec3 T, float anisotropy, @@ -115,11 +81,11 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte float NdotV = dot(N, V); float cNdotV = max(NdotV, 0.0); -#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) +#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) vec3 H = normalize(V + L); #endif -#if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) +#if defined(SPECULAR_SCHLICK_GGX) float cNdotH = clamp(A + dot(N, H), 0.0, 1.0); #endif @@ -203,26 +169,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte // D -#if defined(SPECULAR_BLINN) - - //normalized blinn - float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; - float blinn = pow(cNdotH, shininess); - blinn *= (shininess + 2.0) * (1.0 / (8.0 * M_PI)); - - specular_light += light_color * attenuation * specular_amount * blinn * f0 * orms_unpacked.w; - -#elif defined(SPECULAR_PHONG) - - vec3 R = normalize(-reflect(L, N)); - float cRdotV = clamp(A + dot(R, V), 0.0, 1.0); - float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; - float phong = pow(cRdotV, shininess); - phong *= (shininess + 1.0) * (1.0 / (8.0 * M_PI)); - - specular_light += light_color * attenuation * specular_amount * phong * f0 * orms_unpacked.w; - -#elif defined(SPECULAR_TOON) +#if defined(SPECULAR_TOON) vec3 R = normalize(-reflect(L, N)); float RdotV = dot(R, V); @@ -236,24 +183,21 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte #elif defined(SPECULAR_SCHLICK_GGX) // shlick+ggx as default - + float alpha_ggx = roughness * roughness; #if defined(LIGHT_ANISOTROPY_USED) - float alpha_ggx = roughness * roughness; float aspect = sqrt(1.0 - anisotropy * 0.9); float ax = alpha_ggx / aspect; float ay = alpha_ggx * aspect; float XdotH = dot(T, H); float YdotH = dot(B, H); float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH); - float G = G_GGX_anisotropic_2cos(cNdotL, ax, ay, XdotH, YdotH) * G_GGX_anisotropic_2cos(cNdotV, ax, ay, XdotH, YdotH); - -#else - float alpha_ggx = roughness * roughness; + float G = V_GGX_anisotropic(ax, ay, dot(T, V), dot(T, L), dot(B, V), dot(B, L), cNdotV, cNdotL); +#else // LIGHT_ANISOTROPY_USED float D = D_GGX(cNdotH, alpha_ggx); - float G = G_GGX_2cos(cNdotL, alpha_ggx) * G_GGX_2cos(cNdotV, alpha_ggx); -#endif - // F + float G = V_GGX(cNdotL, cNdotV, alpha_ggx); +#endif // LIGHT_ANISOTROPY_USED + // F float cLdotH5 = SchlickFresnel(cLdotH); vec3 F = mix(vec3(cLdotH5), vec3(1.0), f0); @@ -263,18 +207,23 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte #endif #if defined(LIGHT_CLEARCOAT_USED) + // Clearcoat ignores normal_map, use vertex normal instead + float ccNdotL = max(min(A + dot(vertex_normal, L), 1.0), 0.0); + float ccNdotH = clamp(A + dot(vertex_normal, H), 0.0, 1.0); + float ccNdotV = max(dot(vertex_normal, V), 0.0); #if !defined(SPECULAR_SCHLICK_GGX) float cLdotH5 = SchlickFresnel(cLdotH); #endif - float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_gloss)); + float Dr = D_GGX(ccNdotH, mix(0.001, 0.1, clearcoat_roughness)); + float Gr = 0.25 / (cLdotH * cLdotH); float Fr = mix(.04, 1.0, cLdotH5); - float Gr = G_GGX_2cos(cNdotL, .25) * G_GGX_2cos(cNdotV, .25); - - float clearcoat_specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL; + float clearcoat_specular_brdf_NL = clearcoat * Gr * Fr * Dr * cNdotL; specular_light += clearcoat_specular_brdf_NL * light_color * attenuation * specular_amount; -#endif + // TODO: Clearcoat adds light to the scene right now (it is non-energy conserving), both diffuse and specular need to be scaled by (1.0 - FR) + // but to do so we need to rearrange this entire function +#endif // LIGHT_CLEARCOAT_USED } #ifdef USE_SHADOW_TO_OPACITY @@ -587,7 +536,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v float rim, float rim_tint, #endif #ifdef LIGHT_CLEARCOAT_USED - float clearcoat, float clearcoat_gloss, + float clearcoat, float clearcoat_roughness, vec3 vertex_normal, #endif #ifdef LIGHT_ANISOTROPY_USED vec3 binormal, vec3 tangent, float anisotropy, @@ -711,7 +660,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v rim * omni_attenuation, rim_tint, #endif #ifdef LIGHT_CLEARCOAT_USED - clearcoat, clearcoat_gloss, + clearcoat, clearcoat_roughness, vertex_normal, #endif #ifdef LIGHT_ANISOTROPY_USED binormal, tangent, anisotropy, @@ -827,7 +776,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v float rim, float rim_tint, #endif #ifdef LIGHT_CLEARCOAT_USED - float clearcoat, float clearcoat_gloss, + float clearcoat, float clearcoat_roughness, vec3 vertex_normal, #endif #ifdef LIGHT_ANISOTROPY_USED vec3 binormal, vec3 tangent, float anisotropy, @@ -912,7 +861,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v rim * spot_attenuation, rim_tint, #endif #ifdef LIGHT_CLEARCOAT_USED - clearcoat, clearcoat_gloss, + clearcoat, clearcoat_roughness, vertex_normal, #endif #ifdef LIGHT_ANISOTROPY_USED binormal, tangent, anisotropy, diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl index 4d6a3b5864..a1cf1d3c04 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl @@ -511,8 +511,8 @@ layout(location = 0) out mediump vec4 frag_color; #if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) -/* Make a default specular mode SPECULAR_SCHLICK_GGX. */ -#if !defined(SPECULAR_DISABLED) && !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_BLINN) && !defined(SPECULAR_PHONG) && !defined(SPECULAR_TOON) +// Default to SPECULAR_SCHLICK_GGX. +#if !defined(SPECULAR_DISABLED) && !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_TOON) #define SPECULAR_SCHLICK_GGX #endif @@ -596,7 +596,7 @@ void main() { float rim = 0.0; float rim_tint = 0.0; float clearcoat = 0.0; - float clearcoat_gloss = 0.0; + float clearcoat_roughness = 0.0; float anisotropy = 0.0; vec2 anisotropy_flow = vec2(1.0, 0.0); vec4 fog = vec4(0.0); @@ -874,7 +874,16 @@ void main() { #if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) if (scene_data.use_reflection_cubemap) { +#ifdef LIGHT_ANISOTROPY_USED + // https://google.github.io/filament/Filament.html#lighting/imagebasedlights/anisotropy + vec3 anisotropic_direction = anisotropy >= 0.0 ? binormal : tangent; + vec3 anisotropic_tangent = cross(anisotropic_direction, view); + vec3 anisotropic_normal = cross(anisotropic_tangent, anisotropic_direction); + vec3 bent_normal = normalize(mix(normal, anisotropic_normal, abs(anisotropy) * clamp(5.0 * roughness, 0.0, 1.0))); + vec3 ref_vec = reflect(-view, bent_normal); +#else vec3 ref_vec = reflect(-view, normal); +#endif float horizon = min(1.0 + dot(ref_vec, normal), 1.0); ref_vec = scene_data.radiance_inverse_xform * ref_vec; #ifdef USE_RADIANCE_CUBEMAP_ARRAY @@ -917,7 +926,35 @@ void main() { #if defined(CUSTOM_IRRADIANCE_USED) ambient_light = mix(specular_light, custom_irradiance.rgb, custom_irradiance.a); #endif // CUSTOM_IRRADIANCE_USED +#ifdef LIGHT_CLEARCOAT_USED + + if (scene_data.use_reflection_cubemap) { + vec3 n = normalize(normal_interp); // We want to use geometric normal, not normal_map + float NoV = max(dot(n, view), 0.0001); + vec3 ref_vec = reflect(-view, n); + // The clear coat layer assumes an IOR of 1.5 (4% reflectance) + float Fc = clearcoat * (0.04 + 0.96 * SchlickFresnel(NoV)); + float attenuation = 1.0 - Fc; + ambient_light *= attenuation; + specular_light *= attenuation; + float horizon = min(1.0 + dot(ref_vec, normal), 1.0); + ref_vec = scene_data.radiance_inverse_xform * ref_vec; + float roughness_lod = mix(0.001, 0.1, clearcoat_roughness) * MAX_ROUGHNESS_LOD; +#ifdef USE_RADIANCE_CUBEMAP_ARRAY + + float lod, blend; + blend = modf(roughness_lod, lod); + vec3 clearcoat_light = texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ref_vec, lod)).rgb; + clearcoat_light = mix(clearcoat_light, texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ref_vec, lod + 1)).rgb, blend); + +#else + vec3 clearcoat_light = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ref_vec, roughness_lod).rgb; + +#endif //USE_RADIANCE_CUBEMAP_ARRAY + specular_light += clearcoat_light * horizon * horizon * Fc * scene_data.ambient_light_color_energy.a; + } +#endif #endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) //radiance @@ -1002,8 +1039,16 @@ void main() { if (reflection_index == 0xFF) { break; } - - reflection_process(reflection_index, vertex, normal, roughness, ambient_light, specular_light, ambient_accum, reflection_accum); +#ifdef LIGHT_ANISOTROPY_USED + // https://google.github.io/filament/Filament.html#lighting/imagebasedlights/anisotropy + vec3 anisotropic_direction = anisotropy >= 0.0 ? binormal : tangent; + vec3 anisotropic_tangent = cross(anisotropic_direction, view); + vec3 anisotropic_normal = cross(anisotropic_tangent, anisotropic_direction); + vec3 bent_normal = normalize(mix(normal, anisotropic_normal, abs(anisotropy) * clamp(5.0 * roughness, 0.0, 1.0))); +#else + vec3 bent_normal = normal; +#endif + reflection_process(reflection_index, vertex, bent_normal, roughness, ambient_light, specular_light, ambient_accum, reflection_accum); } if (reflection_accum.a > 0.0) { @@ -1368,7 +1413,7 @@ void main() { rim, rim_tint, #endif #ifdef LIGHT_CLEARCOAT_USED - clearcoat, clearcoat_gloss, + clearcoat, clearcoat_roughness, normalize(normal_interp), #endif #ifdef LIGHT_ANISOTROPY_USED binormal, tangent, anisotropy, @@ -1415,10 +1460,11 @@ void main() { rim_tint, #endif #ifdef LIGHT_CLEARCOAT_USED - clearcoat, clearcoat_gloss, + clearcoat, clearcoat_roughness, normalize(normal_interp), #endif #ifdef LIGHT_ANISOTROPY_USED - tangent, binormal, anisotropy, + tangent, + binormal, anisotropy, #endif diffuse_light, specular_light); } @@ -1459,10 +1505,11 @@ void main() { rim_tint, #endif #ifdef LIGHT_CLEARCOAT_USED - clearcoat, clearcoat_gloss, + clearcoat, clearcoat_roughness, normalize(normal_interp), #endif #ifdef LIGHT_ANISOTROPY_USED - tangent, binormal, anisotropy, + tangent, + binormal, anisotropy, #endif diffuse_light, specular_light); } diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl index 541c0b0603..7a624c3b95 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl @@ -7,7 +7,7 @@ #include "decal_data_inc.glsl" -#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) +#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) #ifndef NORMAL_USED #define NORMAL_USED #endif diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index 5a84bace2d..69c017a1c8 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -548,7 +548,6 @@ void RendererViewport::draw_viewports() { // get our xr interface in case we need it Ref<XRInterface> xr_interface; - XRServer *xr_server = XRServer::get_singleton(); if (xr_server != nullptr) { // let our XR server know we're about to render our frames so we can get our frame timing diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index 655a32a805..49d89bcadc 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -500,6 +500,7 @@ public: virtual RID texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<Vector<uint8_t>> &p_data = Vector<Vector<uint8_t>>()) = 0; virtual RID texture_create_shared(const TextureView &p_view, RID p_with_texture) = 0; + virtual RID texture_create_from_extension(TextureType p_type, DataFormat p_format, TextureSamples p_samples, uint64_t p_flags, uint64_t p_image, uint64_t p_width, uint64_t p_height, uint64_t p_depth, uint64_t p_layers) = 0; enum TextureSliceType { TEXTURE_SLICE_2D, diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp index a0b0b31a7b..812d636a0b 100644 --- a/servers/rendering/shader_compiler.cpp +++ b/servers/rendering/shader_compiler.cpp @@ -1373,148 +1373,4 @@ void ShaderCompiler::initialize(DefaultIdentifierActions p_actions) { } ShaderCompiler::ShaderCompiler() { -#if 0 - - /** SPATIAL SHADER **/ - - actions[RS::SHADER_SPATIAL].renames["WORLD_MATRIX"] = "world_transform"; - actions[RS::SHADER_SPATIAL].renames["INV_CAMERA_MATRIX"] = "camera_inverse_matrix"; - actions[RS::SHADER_SPATIAL].renames["CAMERA_MATRIX"] = "camera_matrix"; - actions[RS::SHADER_SPATIAL].renames["PROJECTION_MATRIX"] = "projection_matrix"; - actions[RS::SHADER_SPATIAL].renames["INV_PROJECTION_MATRIX"] = "inv_projection_matrix"; - actions[RS::SHADER_SPATIAL].renames["MODELVIEW_MATRIX"] = "modelview"; - - actions[RS::SHADER_SPATIAL].renames["VERTEX"] = "vertex.xyz"; - actions[RS::SHADER_SPATIAL].renames["NORMAL"] = "normal"; - actions[RS::SHADER_SPATIAL].renames["TANGENT"] = "tangent"; - actions[RS::SHADER_SPATIAL].renames["BINORMAL"] = "binormal"; - actions[RS::SHADER_SPATIAL].renames["POSITION"] = "position"; - actions[RS::SHADER_SPATIAL].renames["UV"] = "uv_interp"; - actions[RS::SHADER_SPATIAL].renames["UV2"] = "uv2_interp"; - actions[RS::SHADER_SPATIAL].renames["COLOR"] = "color_interp"; - actions[RS::SHADER_SPATIAL].renames["POINT_SIZE"] = "gl_PointSize"; - actions[RS::SHADER_SPATIAL].renames["INSTANCE_ID"] = "gl_InstanceID"; - - //builtins - - actions[RS::SHADER_SPATIAL].renames["TIME"] = "time"; - actions[RS::SHADER_SPATIAL].renames["VIEWPORT_SIZE"] = "viewport_size"; - - actions[RS::SHADER_SPATIAL].renames["FRAGCOORD"] = "gl_FragCoord"; - actions[RS::SHADER_SPATIAL].renames["FRONT_FACING"] = "gl_FrontFacing"; - actions[RS::SHADER_SPATIAL].renames["NORMAL_MAP"] = "normal_map"; - actions[RS::SHADER_SPATIAL].renames["NORMAL_MAP_DEPTH"] = "normal_map_depth"; - actions[RS::SHADER_SPATIAL].renames["ALBEDO"] = "albedo"; - actions[RS::SHADER_SPATIAL].renames["ALPHA"] = "alpha"; - actions[RS::SHADER_SPATIAL].renames["METALLIC"] = "metallic"; - actions[RS::SHADER_SPATIAL].renames["SPECULAR"] = "specular"; - actions[RS::SHADER_SPATIAL].renames["ROUGHNESS"] = "roughness"; - actions[RS::SHADER_SPATIAL].renames["RIM"] = "rim"; - actions[RS::SHADER_SPATIAL].renames["RIM_TINT"] = "rim_tint"; - actions[RS::SHADER_SPATIAL].renames["CLEARCOAT"] = "clearcoat"; - actions[RS::SHADER_SPATIAL].renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss"; - actions[RS::SHADER_SPATIAL].renames["ANISOTROPY"] = "anisotropy"; - actions[RS::SHADER_SPATIAL].renames["ANISOTROPY_FLOW"] = "anisotropy_flow"; - actions[RS::SHADER_SPATIAL].renames["SSS_STRENGTH"] = "sss_strength"; - actions[RS::SHADER_SPATIAL].renames["TRANSMISSION"] = "transmission"; - actions[RS::SHADER_SPATIAL].renames["AO"] = "ao"; - actions[RS::SHADER_SPATIAL].renames["AO_LIGHT_AFFECT"] = "ao_light_affect"; - actions[RS::SHADER_SPATIAL].renames["EMISSION"] = "emission"; - actions[RS::SHADER_SPATIAL].renames["POINT_COORD"] = "gl_PointCoord"; - actions[RS::SHADER_SPATIAL].renames["INSTANCE_CUSTOM"] = "instance_custom"; - actions[RS::SHADER_SPATIAL].renames["SCREEN_UV"] = "screen_uv"; - actions[RS::SHADER_SPATIAL].renames["SCREEN_TEXTURE"] = "screen_texture"; - actions[RS::SHADER_SPATIAL].renames["DEPTH_TEXTURE"] = "depth_buffer"; - actions[RS::SHADER_SPATIAL].renames["DEPTH"] = "gl_FragDepth"; - actions[RS::SHADER_SPATIAL].renames["ALPHA_SCISSOR"] = "alpha_scissor"; - actions[RS::SHADER_SPATIAL].renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB"; - - //for light - actions[RS::SHADER_SPATIAL].renames["VIEW"] = "view"; - actions[RS::SHADER_SPATIAL].renames["LIGHT_COLOR"] = "light_color"; - actions[RS::SHADER_SPATIAL].renames["LIGHT"] = "light"; - actions[RS::SHADER_SPATIAL].renames["ATTENUATION"] = "attenuation"; - actions[RS::SHADER_SPATIAL].renames["DIFFUSE_LIGHT"] = "diffuse_light"; - actions[RS::SHADER_SPATIAL].renames["SPECULAR_LIGHT"] = "specular_light"; - - actions[RS::SHADER_SPATIAL].usage_defines["TANGENT"] = "#define ENABLE_TANGENT_INTERP\n"; - actions[RS::SHADER_SPATIAL].usage_defines["BINORMAL"] = "@TANGENT"; - actions[RS::SHADER_SPATIAL].usage_defines["RIM"] = "#define LIGHT_USE_RIM\n"; - actions[RS::SHADER_SPATIAL].usage_defines["RIM_TINT"] = "@RIM"; - actions[RS::SHADER_SPATIAL].usage_defines["CLEARCOAT"] = "#define LIGHT_USE_CLEARCOAT\n"; - actions[RS::SHADER_SPATIAL].usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT"; - actions[RS::SHADER_SPATIAL].usage_defines["ANISOTROPY"] = "#define LIGHT_USE_ANISOTROPY\n"; - actions[RS::SHADER_SPATIAL].usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY"; - actions[RS::SHADER_SPATIAL].usage_defines["AO"] = "#define ENABLE_AO\n"; - actions[RS::SHADER_SPATIAL].usage_defines["AO_LIGHT_AFFECT"] = "#define ENABLE_AO\n"; - actions[RS::SHADER_SPATIAL].usage_defines["UV"] = "#define ENABLE_UV_INTERP\n"; - actions[RS::SHADER_SPATIAL].usage_defines["UV2"] = "#define ENABLE_UV2_INTERP\n"; - actions[RS::SHADER_SPATIAL].usage_defines["NORMAL_MAP"] = "#define ENABLE_NORMAL_MAP\n"; - actions[RS::SHADER_SPATIAL].usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP"; - actions[RS::SHADER_SPATIAL].usage_defines["COLOR"] = "#define ENABLE_COLOR_INTERP\n"; - actions[RS::SHADER_SPATIAL].usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n"; - actions[RS::SHADER_SPATIAL].usage_defines["ALPHA_SCISSOR"] = "#define ALPHA_SCISSOR_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n"; - - actions[RS::SHADER_SPATIAL].usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n"; - actions[RS::SHADER_SPATIAL].usage_defines["TRANSMISSION"] = "#define TRANSMISSION_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; - - actions[RS::SHADER_SPATIAL].usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; - actions[RS::SHADER_SPATIAL].usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; - - actions[RS::SHADER_SPATIAL].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n"; - - bool force_lambert = GLOBAL_GET("rendering/shading/overrides/force_lambert_over_burley"); - - if (!force_lambert) { - actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n"; - } - - actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n"; - - bool force_blinn = GLOBAL_GET("rendering/shading/overrides/force_blinn_over_ggx"); - - if (!force_blinn) { - actions[RS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; - } else { - actions[RS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n"; - } - - actions[RS::SHADER_SPATIAL].render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n"; - - /* PARTICLES SHADER */ - - actions[RS::SHADER_PARTICLES].renames["COLOR"] = "out_color"; - actions[RS::SHADER_PARTICLES].renames["VELOCITY"] = "out_velocity_active.xyz"; - actions[RS::SHADER_PARTICLES].renames["MASS"] = "mass"; - actions[RS::SHADER_PARTICLES].renames["ACTIVE"] = "shader_active"; - actions[RS::SHADER_PARTICLES].renames["RESTART"] = "restart"; - actions[RS::SHADER_PARTICLES].renames["CUSTOM"] = "out_custom"; - actions[RS::SHADER_PARTICLES].renames["TRANSFORM"] = "xform"; - actions[RS::SHADER_PARTICLES].renames["TIME"] = "time"; - actions[RS::SHADER_PARTICLES].renames["LIFETIME"] = "lifetime"; - actions[RS::SHADER_PARTICLES].renames["DELTA"] = "local_delta"; - actions[RS::SHADER_PARTICLES].renames["NUMBER"] = "particle_number"; - actions[RS::SHADER_PARTICLES].renames["INDEX"] = "index"; - actions[RS::SHADER_PARTICLES].renames["GRAVITY"] = "current_gravity"; - actions[RS::SHADER_PARTICLES].renames["EMISSION_TRANSFORM"] = "emission_transform"; - actions[RS::SHADER_PARTICLES].renames["RANDOM_SEED"] = "random_seed"; - - actions[RS::SHADER_PARTICLES].render_mode_defines["disable_force"] = "#define DISABLE_FORCE\n"; - actions[RS::SHADER_PARTICLES].render_mode_defines["disable_velocity"] = "#define DISABLE_VELOCITY\n"; - actions[RS::SHADER_PARTICLES].render_mode_defines["keep_data"] = "#define ENABLE_KEEP_DATA\n"; -#endif } diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp index d628cf3713..9ea98dc593 100644 --- a/servers/rendering/shader_types.cpp +++ b/servers/rendering/shader_types.cpp @@ -121,7 +121,7 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["RIM"] = ShaderLanguage::TYPE_FLOAT; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["RIM_TINT"] = ShaderLanguage::TYPE_FLOAT; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["CLEARCOAT"] = ShaderLanguage::TYPE_FLOAT; - shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["CLEARCOAT_GLOSS"] = ShaderLanguage::TYPE_FLOAT; + shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["CLEARCOAT_ROUGHNESS"] = ShaderLanguage::TYPE_FLOAT; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["ANISOTROPY"] = ShaderLanguage::TYPE_FLOAT; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["ANISOTROPY_FLOW"] = ShaderLanguage::TYPE_VEC2; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SSS_STRENGTH"] = ShaderLanguage::TYPE_FLOAT; @@ -202,7 +202,7 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "unshaded" }); shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "wireframe" }); shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "diffuse", "lambert", "lambert_wrap", "burley", "toon" }); - shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "specular", "schlick_ggx", "blinn", "phong", "toon", "disabled" }); + shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "specular", "schlick_ggx", "toon", "disabled" }); shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "skip_vertex_transform" }); shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "world_vertex_coords" }); shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "ensure_correct_normals" }); diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index a7fcbcce42..c9ac42863a 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2860,11 +2860,11 @@ RenderingServer::RenderingServer() { GLOBAL_DEF("rendering/shader_compiler/shader_cache/strip_debug", false); GLOBAL_DEF("rendering/shader_compiler/shader_cache/strip_debug.release", true); - GLOBAL_DEF("rendering/reflections/sky_reflections/roughness_layers", 8); + GLOBAL_DEF_RST("rendering/reflections/sky_reflections/roughness_layers", 8); // Assumes a 256x256 cubemap GLOBAL_DEF_RST("rendering/reflections/sky_reflections/texture_array_reflections", true); GLOBAL_DEF("rendering/reflections/sky_reflections/texture_array_reflections.mobile", false); - GLOBAL_DEF("rendering/reflections/sky_reflections/ggx_samples", 1024); - GLOBAL_DEF("rendering/reflections/sky_reflections/ggx_samples.mobile", 128); + GLOBAL_DEF_RST("rendering/reflections/sky_reflections/ggx_samples", 32); + GLOBAL_DEF("rendering/reflections/sky_reflections/ggx_samples.mobile", 16); GLOBAL_DEF("rendering/reflections/sky_reflections/fast_filter_high_quality", false); GLOBAL_DEF("rendering/reflections/reflection_atlas/reflection_size", 256); GLOBAL_DEF("rendering/reflections/reflection_atlas/reflection_size.mobile", 128); @@ -2879,8 +2879,6 @@ RenderingServer::RenderingServer() { GLOBAL_DEF("rendering/shading/overrides/force_vertex_shading.mobile", true); GLOBAL_DEF("rendering/shading/overrides/force_lambert_over_burley", false); GLOBAL_DEF("rendering/shading/overrides/force_lambert_over_burley.mobile", true); - GLOBAL_DEF("rendering/shading/overrides/force_blinn_over_ggx", false); - GLOBAL_DEF("rendering/shading/overrides/force_blinn_over_ggx.mobile", true); GLOBAL_DEF("rendering/driver/depth_prepass/enable", true); @@ -3001,7 +2999,7 @@ RenderingServer::RenderingServer() { GLOBAL_DEF("rendering/limits/cluster_builder/max_clustered_elements", 512); ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/cluster_builder/max_clustered_elements", PropertyInfo(Variant::FLOAT, "rendering/limits/cluster_builder/max_clustered_elements", PROPERTY_HINT_RANGE, "32,8192,1")); - GLOBAL_DEF_RST("rendering/xr/enabled", false); + GLOBAL_DEF_RST_BASIC("xr/shaders/enabled", false); GLOBAL_DEF_RST("rendering/2d/options/use_software_skinning", true); GLOBAL_DEF_RST("rendering/2d/options/ninepatch_mode", 1); diff --git a/servers/xr/xr_positional_tracker.cpp b/servers/xr/xr_positional_tracker.cpp index 7b21eeba04..671eb7a111 100644 --- a/servers/xr/xr_positional_tracker.cpp +++ b/servers/xr/xr_positional_tracker.cpp @@ -65,10 +65,6 @@ void XRPositionalTracker::_bind_methods() { ADD_SIGNAL(MethodInfo("button_released", PropertyInfo(Variant::STRING, "name"))); ADD_SIGNAL(MethodInfo("input_value_changed", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::FLOAT, "value"))); ADD_SIGNAL(MethodInfo("input_axis_changed", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::VECTOR2, "vector"))); - - ClassDB::bind_method(D_METHOD("get_rumble"), &XRPositionalTracker::get_rumble); - ClassDB::bind_method(D_METHOD("set_rumble", "rumble"), &XRPositionalTracker::set_rumble); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rumble"), "set_rumble", "get_rumble"); }; void XRPositionalTracker::set_tracker_type(XRServer::TrackerType p_type) { @@ -206,21 +202,8 @@ void XRPositionalTracker::set_input(const StringName &p_action_name, const Varia } } -real_t XRPositionalTracker::get_rumble() const { - return rumble; -}; - -void XRPositionalTracker::set_rumble(real_t p_rumble) { - if (p_rumble > 0.0) { - rumble = p_rumble; - } else { - rumble = 0.0; - }; -}; - XRPositionalTracker::XRPositionalTracker() { type = XRServer::TRACKER_UNKNOWN; name = "Unknown"; hand = TRACKER_HAND_UNKNOWN; - rumble = 0.0; }; diff --git a/servers/xr/xr_positional_tracker.h b/servers/xr/xr_positional_tracker.h index 2f358cbb21..ccb30bbbe6 100644 --- a/servers/xr/xr_positional_tracker.h +++ b/servers/xr/xr_positional_tracker.h @@ -62,10 +62,6 @@ private: Map<StringName, Ref<XRPose>> poses; Map<StringName, Variant> inputs; - int joy_id; // if we also have a related joystick entity, the id of the joystick - Ref<Mesh> mesh; // when available, a mesh that can be used to render this tracker - real_t rumble; // rumble strength, 0.0 is off, 1.0 is maximum, note that we only record here, xr_interface is responsible for execution - protected: static void _bind_methods(); @@ -87,10 +83,6 @@ public: Variant get_input(const StringName &p_action_name) const; void set_input(const StringName &p_action_name, const Variant &p_value); - // TODO replace by new implementation - real_t get_rumble() const; - void set_rumble(real_t p_rumble); - XRPositionalTracker(); ~XRPositionalTracker() {} }; diff --git a/servers/xr_server.cpp b/servers/xr_server.cpp index dbfe76a127..e32b41c7ae 100644 --- a/servers/xr_server.cpp +++ b/servers/xr_server.cpp @@ -348,9 +348,10 @@ PackedStringArray XRServer::get_suggested_pose_names(const StringName &p_tracker } void XRServer::_process() { - /* called from renderer_viewport.draw_viewports right before we start drawing our viewports */ + // called from our main game loop before we handle physics and game logic + // note that we can have multiple interfaces active if we have interfaces that purely handle tracking - /* process all active interfaces */ + // process all active interfaces for (int i = 0; i < interfaces.size(); i++) { if (!interfaces[i].is_valid()) { // ignore, not a valid reference diff --git a/thirdparty/README.md b/thirdparty/README.md index 7d2586b4dc..f204367b8b 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -474,6 +474,7 @@ Files extracted from the upstream source: - Files in `core/` folder. - `LICENSE.txt` and `CHANGELOG.md` + ## oidn - Upstream: https://github.com/OpenImageDenoise/oidn @@ -505,6 +506,30 @@ Patch files are provided in `oidn/patches/`. - scripts/resource_to_cpp.py (used in modules/denoise/resource_to_cpp.py) +## openxr + +- Upstream: https://github.com/KhronosGroup/OpenXR-SDK +- Version: 1.0.22 (458984d7f59d1ae6dc1b597d94b02e4f7132eaba, 2022) +- License: Apache 2.0 + +Files extracted from upstream source: + +- include/ +- src/common/ +- src/loader/ +- src/*.{c,h} +- src/external/jsoncpp/include/ +- src/external/jsoncpp/src/lib_json/ +- LICENSE and COPYING.adoc + +Exclude: + +- src/external/android-jni-wrappers and src/external/jnipp (not used yet) +- All CMake stuff: cmake/, CMakeLists.txt and *.cmake +- All Gradle stuff: *gradle*, AndroidManifest.xml +- All following files (and their .license files): *.{def,in,json,map,pom,rc} + + ## pcre2 - Upstream: http://www.pcre.org diff --git a/thirdparty/misc/patches/polypartition-godot-types.patch b/thirdparty/misc/patches/polypartition-godot-types.patch index 61737f9fd2..5d8aba3437 100644 --- a/thirdparty/misc/patches/polypartition-godot-types.patch +++ b/thirdparty/misc/patches/polypartition-godot-types.patch @@ -101,7 +101,7 @@ index 3a8a6efa83..8c5409bf24 100644 pointvisible = true; - for (iter2 = polys.begin(); iter2 != polys.end(); iter2++) { - if (iter2->IsHole()) { -+ for (iter2 = polys.front(); iter2; iter2->next()) { ++ for (iter2 = polys.front(); iter2; iter2 = iter2->next()) { + if (iter2->get().IsHole()) { continue; } diff --git a/thirdparty/misc/polypartition.cpp b/thirdparty/misc/polypartition.cpp index 8c5409bf24..df144c57a6 100644 --- a/thirdparty/misc/polypartition.cpp +++ b/thirdparty/misc/polypartition.cpp @@ -262,7 +262,7 @@ int TPPLPartition::RemoveHoles(TPPLPolyList *inpolys, TPPLPolyList *outpolys) { } } pointvisible = true; - for (iter2 = polys.front(); iter2; iter2->next()) { + for (iter2 = polys.front(); iter2; iter2 = iter2->next()) { if (iter2->get().IsHole()) { continue; } diff --git a/thirdparty/openxr/COPYING.adoc b/thirdparty/openxr/COPYING.adoc new file mode 100644 index 0000000000..3a31362acb --- /dev/null +++ b/thirdparty/openxr/COPYING.adoc @@ -0,0 +1,123 @@ += COPYING.adoc for the Khronos Group OpenXR projects + +// Copyright (c) 2020-2022, The Khronos Group Inc. +// +// SPDX-License-Identifier: CC-BY-4.0 + +This document is shared across a number of OpenXR GitHub projects, as the +set of files in those projects is partially overlapping. +(There is a single "source of truth" internal Khronos GitLab repo these +GitHub repositories interact with.) + +== Licenses + +The OpenXR GitHub projects use several licenses. +In general, we work to maintain compliance with the +https://reuse.software/spec/[REUSE 3.0 specification] with clear copyright +holders and license identifier listed for each file, preferably in each +file. +Where this is not possible, or e.g. when we are using files unmodified from +other open-source projects, license data is listed: + +* in an adjacent file of the same name, with the additional extension + "`.license`" +* in the repository-wide "`.reuse/dep5`" copyright description + https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/["DEP5" + machine-readable copyright data] file. + +The https://github.com/fsfe/reuse-tool["`reuse`" command line tool] can be +used to create a software bill of materials in SPDX format from this data. +Note that this tool will typically exclude the generated files, so if the +BOM is important to you, you may consider using the +https://github.com/KhronosGroup/OpenXR-SDK[OpenXR-SDK] repository that +contains the API headers and the loader source with all generated files +pre-generated. + +The data in/adjacent to each file is the authoritative license and copyright +data. +However, for ease of understanding, the following general practices can be +observed. +(If in doubt, or if the following summary conflicts with the per-file data, +the per-file data remains authoritative.) + +* The source files (in asciidoctor and other formats) for the OpenXR + Specification, reference pages, and supporting documentation are licensed + under the Creative Commons Attribution 4.0 International License (SPDX + license identifier "`CC-BY-4.0`"). +* Header files, scripts, programs, XML files, and other tooling used or + generated as part of the build process is licensed under the Apache + License, Version 2.0. +* For compatibility with external developers working in GPLed projects who + have requested it, the main OpenXR headers, XML registry, and loader + source are licensed under a dual license with the SPDX license identifier + "`Apache-2.0 OR MIT`" . + Relevant files include: +** "`specification/registry/xr.xml`" +** "`include/openxr/openxr_platform_defines.h`" +** The generated OpenXR headers "`openxr.h`", "`openxr_platform.h`", and + "`openxr_reflection.h`". +** Source files in "`src/loader/`", and a few files in "`src/common/`". +** Generated source files used by the loader (including pre-generated in + OpenXR-SDK): "`common_config.h`", "`xr_generated_loader.cpp`", and + "`xr_generated_loader.hpp`". +* There are a few files adopted from other open source projects. + Such files continue under their original licenses, and appropriately + annotated in accordance with REUSE. +* Some generated, transient files produced during the course of building the + specification, headers, or other targets may not have copyrights. + These are typically very short asciidoc fragments describing parts of the + OpenXR API, and are incorporated by reference into specification or + reference page builds. + +Users outside Khronos who create and post OpenXR Specifications, whether +modified or not, should use the CC-BY-4.0 license on the output documents +(HTML, PDF, etc.) they generate. + + +== Frequently Asked Questions + +Q: Why are the HTML and PDF Specifications posted on Khronos' website under +a license which is neither CC-BY-4.0 nor Apache 2.0? + +A: The Specifications posted by Khronos in the OpenXR Registry are licensed +under the proprietary Khronos Specification License. +Only these Specifications are Ratified by the Khronos Board of Promoters, +and therefore they are the only Specifications covered by the Khronos +Intellectual Property Rights Policy. + + +Q: Does Khronos allow the creation and distribution of modified versions of +the OpenXR Specification, such as translations to other languages? + +A: Yes. +Such modified Specifications, since they are not created by Khronos, should +be placed under the CC-BY-4.0 license. +If you believe your modifications are of general interest, consider +contributing them back by making a pull request (PR) on the OpenXR-Docs +project. + + +Q: Can I contribute changes to the OpenXR Specification? + +A: Yes, by opening an Issue or Pull Request (PR) on the +link:https://github.com/KhronosGroup/OpenXR-Docs/[OpenXR-Docs] GitHub +project. +You must execute a click-through Contributor License Agreement, which brings +your changes under the umbrella of the Khronos IP policy. + + +Q: Can you change the license on your files so they're compatible with my +license? + +A: We are using a dual license license on `xr.xml`, the main API headers, +and the loader source files, to make them compatible with GPL-2.0- and +LGPL-2.0/2.1-licensed projects. +This replaces earlier approaches of an MIT-like license on the XML and +Apache 2.0 on all headers, and allows use of the SPDX license identifier +"`Apache-2.0 OR MIT`" to denote the license. + +If you *require* this same compatibility for use of other Apache-2.0 +licensed files in our repository, please raise an issue identifying the +files and we will consider changing those specific files to the dual license +as well. + diff --git a/thirdparty/openxr/LICENSE b/thirdparty/openxr/LICENSE new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/thirdparty/openxr/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/thirdparty/openxr/include/openxr/openxr.h b/thirdparty/openxr/include/openxr/openxr.h new file mode 100644 index 0000000000..8798e5a6e0 --- /dev/null +++ b/thirdparty/openxr/include/openxr/openxr.h @@ -0,0 +1,3925 @@ +#ifndef OPENXR_H_ +#define OPENXR_H_ 1 + +/* +** Copyright (c) 2017-2022, The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos OpenXR XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +#define XR_VERSION_1_0 1 +#include "openxr_platform_defines.h" +#define XR_MAKE_VERSION(major, minor, patch) \ + ((((major) & 0xffffULL) << 48) | (((minor) & 0xffffULL) << 32) | ((patch) & 0xffffffffULL)) + +// OpenXR current version number. +#define XR_CURRENT_API_VERSION XR_MAKE_VERSION(1, 0, 22) + +#define XR_VERSION_MAJOR(version) (uint16_t)(((uint64_t)(version) >> 48)& 0xffffULL) +#define XR_VERSION_MINOR(version) (uint16_t)(((uint64_t)(version) >> 32) & 0xffffULL) +#define XR_VERSION_PATCH(version) (uint32_t)((uint64_t)(version) & 0xffffffffULL) + +#if !defined(XR_NULL_HANDLE) +#if (XR_PTR_SIZE == 8) && XR_CPP_NULLPTR_SUPPORTED + #define XR_NULL_HANDLE nullptr +#else + #define XR_NULL_HANDLE 0 +#endif +#endif + + + +#define XR_NULL_SYSTEM_ID 0 + + +#define XR_NULL_PATH 0 + + +#define XR_SUCCEEDED(result) ((result) >= 0) + + +#define XR_FAILED(result) ((result) < 0) + + +#define XR_UNQUALIFIED_SUCCESS(result) ((result) == 0) + + +#define XR_NO_DURATION 0 + + +#define XR_INFINITE_DURATION 0x7fffffffffffffffLL + + +#define XR_MIN_HAPTIC_DURATION -1 + + +#define XR_FREQUENCY_UNSPECIFIED 0 + + +#define XR_MAX_EVENT_DATA_SIZE sizeof(XrEventDataBuffer) + + +#if !defined(XR_MAY_ALIAS) +#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4)) +#define XR_MAY_ALIAS __attribute__((__may_alias__)) +#else +#define XR_MAY_ALIAS +#endif +#endif + + +#if !defined(XR_DEFINE_HANDLE) +#if (XR_PTR_SIZE == 8) + #define XR_DEFINE_HANDLE(object) typedef struct object##_T* object; +#else + #define XR_DEFINE_HANDLE(object) typedef uint64_t object; +#endif +#endif + + + +#if !defined(XR_DEFINE_ATOM) + #define XR_DEFINE_ATOM(object) typedef uint64_t object; +#endif + + +typedef uint64_t XrVersion; +typedef uint64_t XrFlags64; +XR_DEFINE_ATOM(XrSystemId) +typedef uint32_t XrBool32; +XR_DEFINE_ATOM(XrPath) +typedef int64_t XrTime; +typedef int64_t XrDuration; +XR_DEFINE_HANDLE(XrInstance) +XR_DEFINE_HANDLE(XrSession) +XR_DEFINE_HANDLE(XrSpace) +XR_DEFINE_HANDLE(XrAction) +XR_DEFINE_HANDLE(XrSwapchain) +XR_DEFINE_HANDLE(XrActionSet) +#define XR_TRUE 1 +#define XR_FALSE 0 +#define XR_MAX_EXTENSION_NAME_SIZE 128 +#define XR_MAX_API_LAYER_NAME_SIZE 256 +#define XR_MAX_API_LAYER_DESCRIPTION_SIZE 256 +#define XR_MAX_SYSTEM_NAME_SIZE 256 +#define XR_MAX_APPLICATION_NAME_SIZE 128 +#define XR_MAX_ENGINE_NAME_SIZE 128 +#define XR_MAX_RUNTIME_NAME_SIZE 128 +#define XR_MAX_PATH_LENGTH 256 +#define XR_MAX_STRUCTURE_NAME_SIZE 64 +#define XR_MAX_RESULT_STRING_SIZE 64 +#define XR_MIN_COMPOSITION_LAYERS_SUPPORTED 16 +#define XR_MAX_ACTION_SET_NAME_SIZE 64 +#define XR_MAX_LOCALIZED_ACTION_SET_NAME_SIZE 128 +#define XR_MAX_ACTION_NAME_SIZE 64 +#define XR_MAX_LOCALIZED_ACTION_NAME_SIZE 128 + +typedef enum XrResult { + XR_SUCCESS = 0, + XR_TIMEOUT_EXPIRED = 1, + XR_SESSION_LOSS_PENDING = 3, + XR_EVENT_UNAVAILABLE = 4, + XR_SPACE_BOUNDS_UNAVAILABLE = 7, + XR_SESSION_NOT_FOCUSED = 8, + XR_FRAME_DISCARDED = 9, + XR_ERROR_VALIDATION_FAILURE = -1, + XR_ERROR_RUNTIME_FAILURE = -2, + XR_ERROR_OUT_OF_MEMORY = -3, + XR_ERROR_API_VERSION_UNSUPPORTED = -4, + XR_ERROR_INITIALIZATION_FAILED = -6, + XR_ERROR_FUNCTION_UNSUPPORTED = -7, + XR_ERROR_FEATURE_UNSUPPORTED = -8, + XR_ERROR_EXTENSION_NOT_PRESENT = -9, + XR_ERROR_LIMIT_REACHED = -10, + XR_ERROR_SIZE_INSUFFICIENT = -11, + XR_ERROR_HANDLE_INVALID = -12, + XR_ERROR_INSTANCE_LOST = -13, + XR_ERROR_SESSION_RUNNING = -14, + XR_ERROR_SESSION_NOT_RUNNING = -16, + XR_ERROR_SESSION_LOST = -17, + XR_ERROR_SYSTEM_INVALID = -18, + XR_ERROR_PATH_INVALID = -19, + XR_ERROR_PATH_COUNT_EXCEEDED = -20, + XR_ERROR_PATH_FORMAT_INVALID = -21, + XR_ERROR_PATH_UNSUPPORTED = -22, + XR_ERROR_LAYER_INVALID = -23, + XR_ERROR_LAYER_LIMIT_EXCEEDED = -24, + XR_ERROR_SWAPCHAIN_RECT_INVALID = -25, + XR_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED = -26, + XR_ERROR_ACTION_TYPE_MISMATCH = -27, + XR_ERROR_SESSION_NOT_READY = -28, + XR_ERROR_SESSION_NOT_STOPPING = -29, + XR_ERROR_TIME_INVALID = -30, + XR_ERROR_REFERENCE_SPACE_UNSUPPORTED = -31, + XR_ERROR_FILE_ACCESS_ERROR = -32, + XR_ERROR_FILE_CONTENTS_INVALID = -33, + XR_ERROR_FORM_FACTOR_UNSUPPORTED = -34, + XR_ERROR_FORM_FACTOR_UNAVAILABLE = -35, + XR_ERROR_API_LAYER_NOT_PRESENT = -36, + XR_ERROR_CALL_ORDER_INVALID = -37, + XR_ERROR_GRAPHICS_DEVICE_INVALID = -38, + XR_ERROR_POSE_INVALID = -39, + XR_ERROR_INDEX_OUT_OF_RANGE = -40, + XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED = -41, + XR_ERROR_ENVIRONMENT_BLEND_MODE_UNSUPPORTED = -42, + XR_ERROR_NAME_DUPLICATED = -44, + XR_ERROR_NAME_INVALID = -45, + XR_ERROR_ACTIONSET_NOT_ATTACHED = -46, + XR_ERROR_ACTIONSETS_ALREADY_ATTACHED = -47, + XR_ERROR_LOCALIZED_NAME_DUPLICATED = -48, + XR_ERROR_LOCALIZED_NAME_INVALID = -49, + XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING = -50, + XR_ERROR_RUNTIME_UNAVAILABLE = -51, + XR_ERROR_ANDROID_THREAD_SETTINGS_ID_INVALID_KHR = -1000003000, + XR_ERROR_ANDROID_THREAD_SETTINGS_FAILURE_KHR = -1000003001, + XR_ERROR_CREATE_SPATIAL_ANCHOR_FAILED_MSFT = -1000039001, + XR_ERROR_SECONDARY_VIEW_CONFIGURATION_TYPE_NOT_ENABLED_MSFT = -1000053000, + XR_ERROR_CONTROLLER_MODEL_KEY_INVALID_MSFT = -1000055000, + XR_ERROR_REPROJECTION_MODE_UNSUPPORTED_MSFT = -1000066000, + XR_ERROR_COMPUTE_NEW_SCENE_NOT_COMPLETED_MSFT = -1000097000, + XR_ERROR_SCENE_COMPONENT_ID_INVALID_MSFT = -1000097001, + XR_ERROR_SCENE_COMPONENT_TYPE_MISMATCH_MSFT = -1000097002, + XR_ERROR_SCENE_MESH_BUFFER_ID_INVALID_MSFT = -1000097003, + XR_ERROR_SCENE_COMPUTE_FEATURE_INCOMPATIBLE_MSFT = -1000097004, + XR_ERROR_SCENE_COMPUTE_CONSISTENCY_MISMATCH_MSFT = -1000097005, + XR_ERROR_DISPLAY_REFRESH_RATE_UNSUPPORTED_FB = -1000101000, + XR_ERROR_COLOR_SPACE_UNSUPPORTED_FB = -1000108000, + XR_ERROR_UNEXPECTED_STATE_PASSTHROUGH_FB = -1000118000, + XR_ERROR_FEATURE_ALREADY_CREATED_PASSTHROUGH_FB = -1000118001, + XR_ERROR_FEATURE_REQUIRED_PASSTHROUGH_FB = -1000118002, + XR_ERROR_NOT_PERMITTED_PASSTHROUGH_FB = -1000118003, + XR_ERROR_INSUFFICIENT_RESOURCES_PASSTHROUGH_FB = -1000118004, + XR_ERROR_UNKNOWN_PASSTHROUGH_FB = -1000118050, + XR_ERROR_RENDER_MODEL_KEY_INVALID_FB = -1000119000, + XR_RENDER_MODEL_UNAVAILABLE_FB = 1000119020, + XR_ERROR_MARKER_NOT_TRACKED_VARJO = -1000124000, + XR_ERROR_MARKER_ID_INVALID_VARJO = -1000124001, + XR_ERROR_SPATIAL_ANCHOR_NAME_NOT_FOUND_MSFT = -1000142001, + XR_ERROR_SPATIAL_ANCHOR_NAME_INVALID_MSFT = -1000142002, + XR_RESULT_MAX_ENUM = 0x7FFFFFFF +} XrResult; + +typedef enum XrStructureType { + XR_TYPE_UNKNOWN = 0, + XR_TYPE_API_LAYER_PROPERTIES = 1, + XR_TYPE_EXTENSION_PROPERTIES = 2, + XR_TYPE_INSTANCE_CREATE_INFO = 3, + XR_TYPE_SYSTEM_GET_INFO = 4, + XR_TYPE_SYSTEM_PROPERTIES = 5, + XR_TYPE_VIEW_LOCATE_INFO = 6, + XR_TYPE_VIEW = 7, + XR_TYPE_SESSION_CREATE_INFO = 8, + XR_TYPE_SWAPCHAIN_CREATE_INFO = 9, + XR_TYPE_SESSION_BEGIN_INFO = 10, + XR_TYPE_VIEW_STATE = 11, + XR_TYPE_FRAME_END_INFO = 12, + XR_TYPE_HAPTIC_VIBRATION = 13, + XR_TYPE_EVENT_DATA_BUFFER = 16, + XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING = 17, + XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED = 18, + XR_TYPE_ACTION_STATE_BOOLEAN = 23, + XR_TYPE_ACTION_STATE_FLOAT = 24, + XR_TYPE_ACTION_STATE_VECTOR2F = 25, + XR_TYPE_ACTION_STATE_POSE = 27, + XR_TYPE_ACTION_SET_CREATE_INFO = 28, + XR_TYPE_ACTION_CREATE_INFO = 29, + XR_TYPE_INSTANCE_PROPERTIES = 32, + XR_TYPE_FRAME_WAIT_INFO = 33, + XR_TYPE_COMPOSITION_LAYER_PROJECTION = 35, + XR_TYPE_COMPOSITION_LAYER_QUAD = 36, + XR_TYPE_REFERENCE_SPACE_CREATE_INFO = 37, + XR_TYPE_ACTION_SPACE_CREATE_INFO = 38, + XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING = 40, + XR_TYPE_VIEW_CONFIGURATION_VIEW = 41, + XR_TYPE_SPACE_LOCATION = 42, + XR_TYPE_SPACE_VELOCITY = 43, + XR_TYPE_FRAME_STATE = 44, + XR_TYPE_VIEW_CONFIGURATION_PROPERTIES = 45, + XR_TYPE_FRAME_BEGIN_INFO = 46, + XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW = 48, + XR_TYPE_EVENT_DATA_EVENTS_LOST = 49, + XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING = 51, + XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED = 52, + XR_TYPE_INTERACTION_PROFILE_STATE = 53, + XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO = 55, + XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO = 56, + XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO = 57, + XR_TYPE_ACTION_STATE_GET_INFO = 58, + XR_TYPE_HAPTIC_ACTION_INFO = 59, + XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO = 60, + XR_TYPE_ACTIONS_SYNC_INFO = 61, + XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO = 62, + XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO = 63, + XR_TYPE_COMPOSITION_LAYER_CUBE_KHR = 1000006000, + XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR = 1000008000, + XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR = 1000010000, + XR_TYPE_VULKAN_SWAPCHAIN_FORMAT_LIST_CREATE_INFO_KHR = 1000014000, + XR_TYPE_EVENT_DATA_PERF_SETTINGS_EXT = 1000015000, + XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR = 1000017000, + XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR = 1000018000, + XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT = 1000019000, + XR_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT = 1000019001, + XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT = 1000019002, + XR_TYPE_DEBUG_UTILS_LABEL_EXT = 1000019003, + XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR = 1000023000, + XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR = 1000023001, + XR_TYPE_GRAPHICS_BINDING_OPENGL_XCB_KHR = 1000023002, + XR_TYPE_GRAPHICS_BINDING_OPENGL_WAYLAND_KHR = 1000023003, + XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR = 1000023004, + XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR = 1000023005, + XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR = 1000024001, + XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR = 1000024002, + XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR = 1000024003, + XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR = 1000025000, + XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR = 1000025001, + XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR = 1000025002, + XR_TYPE_GRAPHICS_BINDING_D3D11_KHR = 1000027000, + XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR = 1000027001, + XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR = 1000027002, + XR_TYPE_GRAPHICS_BINDING_D3D12_KHR = 1000028000, + XR_TYPE_SWAPCHAIN_IMAGE_D3D12_KHR = 1000028001, + XR_TYPE_GRAPHICS_REQUIREMENTS_D3D12_KHR = 1000028002, + XR_TYPE_SYSTEM_EYE_GAZE_INTERACTION_PROPERTIES_EXT = 1000030000, + XR_TYPE_EYE_GAZE_SAMPLE_TIME_EXT = 1000030001, + XR_TYPE_VISIBILITY_MASK_KHR = 1000031000, + XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR = 1000031001, + XR_TYPE_SESSION_CREATE_INFO_OVERLAY_EXTX = 1000033000, + XR_TYPE_EVENT_DATA_MAIN_SESSION_VISIBILITY_CHANGED_EXTX = 1000033003, + XR_TYPE_COMPOSITION_LAYER_COLOR_SCALE_BIAS_KHR = 1000034000, + XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_MSFT = 1000039000, + XR_TYPE_SPATIAL_ANCHOR_SPACE_CREATE_INFO_MSFT = 1000039001, + XR_TYPE_COMPOSITION_LAYER_IMAGE_LAYOUT_FB = 1000040000, + XR_TYPE_COMPOSITION_LAYER_ALPHA_BLEND_FB = 1000041001, + XR_TYPE_VIEW_CONFIGURATION_DEPTH_RANGE_EXT = 1000046000, + XR_TYPE_GRAPHICS_BINDING_EGL_MNDX = 1000048004, + XR_TYPE_SPATIAL_GRAPH_NODE_SPACE_CREATE_INFO_MSFT = 1000049000, + XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT = 1000051000, + XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT = 1000051001, + XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT = 1000051002, + XR_TYPE_HAND_JOINT_LOCATIONS_EXT = 1000051003, + XR_TYPE_HAND_JOINT_VELOCITIES_EXT = 1000051004, + XR_TYPE_SYSTEM_HAND_TRACKING_MESH_PROPERTIES_MSFT = 1000052000, + XR_TYPE_HAND_MESH_SPACE_CREATE_INFO_MSFT = 1000052001, + XR_TYPE_HAND_MESH_UPDATE_INFO_MSFT = 1000052002, + XR_TYPE_HAND_MESH_MSFT = 1000052003, + XR_TYPE_HAND_POSE_TYPE_INFO_MSFT = 1000052004, + XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SESSION_BEGIN_INFO_MSFT = 1000053000, + XR_TYPE_SECONDARY_VIEW_CONFIGURATION_STATE_MSFT = 1000053001, + XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_STATE_MSFT = 1000053002, + XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_END_INFO_MSFT = 1000053003, + XR_TYPE_SECONDARY_VIEW_CONFIGURATION_LAYER_INFO_MSFT = 1000053004, + XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SWAPCHAIN_CREATE_INFO_MSFT = 1000053005, + XR_TYPE_CONTROLLER_MODEL_KEY_STATE_MSFT = 1000055000, + XR_TYPE_CONTROLLER_MODEL_NODE_PROPERTIES_MSFT = 1000055001, + XR_TYPE_CONTROLLER_MODEL_PROPERTIES_MSFT = 1000055002, + XR_TYPE_CONTROLLER_MODEL_NODE_STATE_MSFT = 1000055003, + XR_TYPE_CONTROLLER_MODEL_STATE_MSFT = 1000055004, + XR_TYPE_VIEW_CONFIGURATION_VIEW_FOV_EPIC = 1000059000, + XR_TYPE_HOLOGRAPHIC_WINDOW_ATTACHMENT_MSFT = 1000063000, + XR_TYPE_COMPOSITION_LAYER_REPROJECTION_INFO_MSFT = 1000066000, + XR_TYPE_COMPOSITION_LAYER_REPROJECTION_PLANE_OVERRIDE_MSFT = 1000066001, + XR_TYPE_ANDROID_SURFACE_SWAPCHAIN_CREATE_INFO_FB = 1000070000, + XR_TYPE_COMPOSITION_LAYER_SECURE_CONTENT_FB = 1000072000, + XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE = 1000079000, + XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT = 1000080000, + XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR = 1000089000, + XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR = 1000090000, + XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR = 1000090001, + XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR = 1000090003, + XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR = 1000091000, + XR_TYPE_SCENE_OBSERVER_CREATE_INFO_MSFT = 1000097000, + XR_TYPE_SCENE_CREATE_INFO_MSFT = 1000097001, + XR_TYPE_NEW_SCENE_COMPUTE_INFO_MSFT = 1000097002, + XR_TYPE_VISUAL_MESH_COMPUTE_LOD_INFO_MSFT = 1000097003, + XR_TYPE_SCENE_COMPONENTS_MSFT = 1000097004, + XR_TYPE_SCENE_COMPONENTS_GET_INFO_MSFT = 1000097005, + XR_TYPE_SCENE_COMPONENT_LOCATIONS_MSFT = 1000097006, + XR_TYPE_SCENE_COMPONENTS_LOCATE_INFO_MSFT = 1000097007, + XR_TYPE_SCENE_OBJECTS_MSFT = 1000097008, + XR_TYPE_SCENE_COMPONENT_PARENT_FILTER_INFO_MSFT = 1000097009, + XR_TYPE_SCENE_OBJECT_TYPES_FILTER_INFO_MSFT = 1000097010, + XR_TYPE_SCENE_PLANES_MSFT = 1000097011, + XR_TYPE_SCENE_PLANE_ALIGNMENT_FILTER_INFO_MSFT = 1000097012, + XR_TYPE_SCENE_MESHES_MSFT = 1000097013, + XR_TYPE_SCENE_MESH_BUFFERS_GET_INFO_MSFT = 1000097014, + XR_TYPE_SCENE_MESH_BUFFERS_MSFT = 1000097015, + XR_TYPE_SCENE_MESH_VERTEX_BUFFER_MSFT = 1000097016, + XR_TYPE_SCENE_MESH_INDICES_UINT32_MSFT = 1000097017, + XR_TYPE_SCENE_MESH_INDICES_UINT16_MSFT = 1000097018, + XR_TYPE_SERIALIZED_SCENE_FRAGMENT_DATA_GET_INFO_MSFT = 1000098000, + XR_TYPE_SCENE_DESERIALIZE_INFO_MSFT = 1000098001, + XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB = 1000101000, + XR_TYPE_VIVE_TRACKER_PATHS_HTCX = 1000103000, + XR_TYPE_EVENT_DATA_VIVE_TRACKER_CONNECTED_HTCX = 1000103001, + XR_TYPE_SYSTEM_FACIAL_TRACKING_PROPERTIES_HTC = 1000104000, + XR_TYPE_FACIAL_TRACKER_CREATE_INFO_HTC = 1000104001, + XR_TYPE_FACIAL_EXPRESSIONS_HTC = 1000104002, + XR_TYPE_SYSTEM_COLOR_SPACE_PROPERTIES_FB = 1000108000, + XR_TYPE_HAND_TRACKING_MESH_FB = 1000110001, + XR_TYPE_HAND_TRACKING_SCALE_FB = 1000110003, + XR_TYPE_HAND_TRACKING_AIM_STATE_FB = 1000111001, + XR_TYPE_HAND_TRACKING_CAPSULES_STATE_FB = 1000112000, + XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB = 1000114000, + XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB = 1000114001, + XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB = 1000114002, + XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB = 1000115000, + XR_TYPE_KEYBOARD_SPACE_CREATE_INFO_FB = 1000116009, + XR_TYPE_KEYBOARD_TRACKING_QUERY_FB = 1000116004, + XR_TYPE_SYSTEM_KEYBOARD_TRACKING_PROPERTIES_FB = 1000116002, + XR_TYPE_TRIANGLE_MESH_CREATE_INFO_FB = 1000117001, + XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES_FB = 1000118000, + XR_TYPE_PASSTHROUGH_CREATE_INFO_FB = 1000118001, + XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB = 1000118002, + XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB = 1000118003, + XR_TYPE_GEOMETRY_INSTANCE_CREATE_INFO_FB = 1000118004, + XR_TYPE_GEOMETRY_INSTANCE_TRANSFORM_FB = 1000118005, + XR_TYPE_PASSTHROUGH_STYLE_FB = 1000118020, + XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_RGBA_FB = 1000118021, + XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_MONO_FB = 1000118022, + XR_TYPE_EVENT_DATA_PASSTHROUGH_STATE_CHANGED_FB = 1000118030, + XR_TYPE_RENDER_MODEL_PATH_INFO_FB = 1000119000, + XR_TYPE_RENDER_MODEL_PROPERTIES_FB = 1000119001, + XR_TYPE_RENDER_MODEL_BUFFER_FB = 1000119002, + XR_TYPE_RENDER_MODEL_LOAD_INFO_FB = 1000119003, + XR_TYPE_SYSTEM_RENDER_MODEL_PROPERTIES_FB = 1000119004, + XR_TYPE_BINDING_MODIFICATIONS_KHR = 1000120000, + XR_TYPE_VIEW_LOCATE_FOVEATED_RENDERING_VARJO = 1000121000, + XR_TYPE_FOVEATED_VIEW_CONFIGURATION_VIEW_VARJO = 1000121001, + XR_TYPE_SYSTEM_FOVEATED_RENDERING_PROPERTIES_VARJO = 1000121002, + XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_VARJO = 1000122000, + XR_TYPE_SYSTEM_MARKER_TRACKING_PROPERTIES_VARJO = 1000124000, + XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO = 1000124001, + XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO = 1000124002, + XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT = 1000142000, + XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT = 1000142001, + XR_TYPE_SWAPCHAIN_IMAGE_FOVEATION_VULKAN_FB = 1000160000, + XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB = 1000161000, + XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB = 1000162000, + XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB = 1000163000, + XR_TYPE_COMPOSITION_LAYER_SPACE_WARP_INFO_FB = 1000171000, + XR_TYPE_SYSTEM_SPACE_WARP_PROPERTIES_FB = 1000171001, + XR_TYPE_DIGITAL_LENS_CONTROL_ALMALENCE = 1000196000, + XR_TYPE_PASSTHROUGH_KEYBOARD_HANDS_INTENSITY_FB = 1000203002, + XR_TYPE_GRAPHICS_BINDING_VULKAN2_KHR = XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR, + XR_TYPE_SWAPCHAIN_IMAGE_VULKAN2_KHR = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR, + XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN2_KHR = XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR, + XR_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF +} XrStructureType; + +typedef enum XrFormFactor { + XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY = 1, + XR_FORM_FACTOR_HANDHELD_DISPLAY = 2, + XR_FORM_FACTOR_MAX_ENUM = 0x7FFFFFFF +} XrFormFactor; + +typedef enum XrViewConfigurationType { + XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO = 1, + XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO = 2, + XR_VIEW_CONFIGURATION_TYPE_PRIMARY_QUAD_VARJO = 1000037000, + XR_VIEW_CONFIGURATION_TYPE_SECONDARY_MONO_FIRST_PERSON_OBSERVER_MSFT = 1000054000, + XR_VIEW_CONFIGURATION_TYPE_MAX_ENUM = 0x7FFFFFFF +} XrViewConfigurationType; + +typedef enum XrEnvironmentBlendMode { + XR_ENVIRONMENT_BLEND_MODE_OPAQUE = 1, + XR_ENVIRONMENT_BLEND_MODE_ADDITIVE = 2, + XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND = 3, + XR_ENVIRONMENT_BLEND_MODE_MAX_ENUM = 0x7FFFFFFF +} XrEnvironmentBlendMode; + +typedef enum XrReferenceSpaceType { + XR_REFERENCE_SPACE_TYPE_VIEW = 1, + XR_REFERENCE_SPACE_TYPE_LOCAL = 2, + XR_REFERENCE_SPACE_TYPE_STAGE = 3, + XR_REFERENCE_SPACE_TYPE_UNBOUNDED_MSFT = 1000038000, + XR_REFERENCE_SPACE_TYPE_COMBINED_EYE_VARJO = 1000121000, + XR_REFERENCE_SPACE_TYPE_MAX_ENUM = 0x7FFFFFFF +} XrReferenceSpaceType; + +typedef enum XrActionType { + XR_ACTION_TYPE_BOOLEAN_INPUT = 1, + XR_ACTION_TYPE_FLOAT_INPUT = 2, + XR_ACTION_TYPE_VECTOR2F_INPUT = 3, + XR_ACTION_TYPE_POSE_INPUT = 4, + XR_ACTION_TYPE_VIBRATION_OUTPUT = 100, + XR_ACTION_TYPE_MAX_ENUM = 0x7FFFFFFF +} XrActionType; + +typedef enum XrEyeVisibility { + XR_EYE_VISIBILITY_BOTH = 0, + XR_EYE_VISIBILITY_LEFT = 1, + XR_EYE_VISIBILITY_RIGHT = 2, + XR_EYE_VISIBILITY_MAX_ENUM = 0x7FFFFFFF +} XrEyeVisibility; + +typedef enum XrSessionState { + XR_SESSION_STATE_UNKNOWN = 0, + XR_SESSION_STATE_IDLE = 1, + XR_SESSION_STATE_READY = 2, + XR_SESSION_STATE_SYNCHRONIZED = 3, + XR_SESSION_STATE_VISIBLE = 4, + XR_SESSION_STATE_FOCUSED = 5, + XR_SESSION_STATE_STOPPING = 6, + XR_SESSION_STATE_LOSS_PENDING = 7, + XR_SESSION_STATE_EXITING = 8, + XR_SESSION_STATE_MAX_ENUM = 0x7FFFFFFF +} XrSessionState; + +typedef enum XrObjectType { + XR_OBJECT_TYPE_UNKNOWN = 0, + XR_OBJECT_TYPE_INSTANCE = 1, + XR_OBJECT_TYPE_SESSION = 2, + XR_OBJECT_TYPE_SWAPCHAIN = 3, + XR_OBJECT_TYPE_SPACE = 4, + XR_OBJECT_TYPE_ACTION_SET = 5, + XR_OBJECT_TYPE_ACTION = 6, + XR_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT = 1000019000, + XR_OBJECT_TYPE_SPATIAL_ANCHOR_MSFT = 1000039000, + XR_OBJECT_TYPE_HAND_TRACKER_EXT = 1000051000, + XR_OBJECT_TYPE_SCENE_OBSERVER_MSFT = 1000097000, + XR_OBJECT_TYPE_SCENE_MSFT = 1000097001, + XR_OBJECT_TYPE_FACIAL_TRACKER_HTC = 1000104000, + XR_OBJECT_TYPE_FOVEATION_PROFILE_FB = 1000114000, + XR_OBJECT_TYPE_TRIANGLE_MESH_FB = 1000117000, + XR_OBJECT_TYPE_PASSTHROUGH_FB = 1000118000, + XR_OBJECT_TYPE_PASSTHROUGH_LAYER_FB = 1000118002, + XR_OBJECT_TYPE_GEOMETRY_INSTANCE_FB = 1000118004, + XR_OBJECT_TYPE_SPATIAL_ANCHOR_STORE_CONNECTION_MSFT = 1000142000, + XR_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF +} XrObjectType; +typedef XrFlags64 XrInstanceCreateFlags; + +// Flag bits for XrInstanceCreateFlags + +typedef XrFlags64 XrSessionCreateFlags; + +// Flag bits for XrSessionCreateFlags + +typedef XrFlags64 XrSpaceVelocityFlags; + +// Flag bits for XrSpaceVelocityFlags +static const XrSpaceVelocityFlags XR_SPACE_VELOCITY_LINEAR_VALID_BIT = 0x00000001; +static const XrSpaceVelocityFlags XR_SPACE_VELOCITY_ANGULAR_VALID_BIT = 0x00000002; + +typedef XrFlags64 XrSpaceLocationFlags; + +// Flag bits for XrSpaceLocationFlags +static const XrSpaceLocationFlags XR_SPACE_LOCATION_ORIENTATION_VALID_BIT = 0x00000001; +static const XrSpaceLocationFlags XR_SPACE_LOCATION_POSITION_VALID_BIT = 0x00000002; +static const XrSpaceLocationFlags XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT = 0x00000004; +static const XrSpaceLocationFlags XR_SPACE_LOCATION_POSITION_TRACKED_BIT = 0x00000008; + +typedef XrFlags64 XrSwapchainCreateFlags; + +// Flag bits for XrSwapchainCreateFlags +static const XrSwapchainCreateFlags XR_SWAPCHAIN_CREATE_PROTECTED_CONTENT_BIT = 0x00000001; +static const XrSwapchainCreateFlags XR_SWAPCHAIN_CREATE_STATIC_IMAGE_BIT = 0x00000002; + +typedef XrFlags64 XrSwapchainUsageFlags; + +// Flag bits for XrSwapchainUsageFlags +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT = 0x00000001; +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000002; +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_UNORDERED_ACCESS_BIT = 0x00000004; +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_TRANSFER_SRC_BIT = 0x00000008; +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_TRANSFER_DST_BIT = 0x00000010; +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_SAMPLED_BIT = 0x00000020; +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT = 0x00000040; +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_MND = 0x00000080; +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_KHR = 0x00000080; // alias of XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_MND + +typedef XrFlags64 XrCompositionLayerFlags; + +// Flag bits for XrCompositionLayerFlags +static const XrCompositionLayerFlags XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT = 0x00000001; +static const XrCompositionLayerFlags XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT = 0x00000002; +static const XrCompositionLayerFlags XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT = 0x00000004; + +typedef XrFlags64 XrViewStateFlags; + +// Flag bits for XrViewStateFlags +static const XrViewStateFlags XR_VIEW_STATE_ORIENTATION_VALID_BIT = 0x00000001; +static const XrViewStateFlags XR_VIEW_STATE_POSITION_VALID_BIT = 0x00000002; +static const XrViewStateFlags XR_VIEW_STATE_ORIENTATION_TRACKED_BIT = 0x00000004; +static const XrViewStateFlags XR_VIEW_STATE_POSITION_TRACKED_BIT = 0x00000008; + +typedef XrFlags64 XrInputSourceLocalizedNameFlags; + +// Flag bits for XrInputSourceLocalizedNameFlags +static const XrInputSourceLocalizedNameFlags XR_INPUT_SOURCE_LOCALIZED_NAME_USER_PATH_BIT = 0x00000001; +static const XrInputSourceLocalizedNameFlags XR_INPUT_SOURCE_LOCALIZED_NAME_INTERACTION_PROFILE_BIT = 0x00000002; +static const XrInputSourceLocalizedNameFlags XR_INPUT_SOURCE_LOCALIZED_NAME_COMPONENT_BIT = 0x00000004; + +typedef void (XRAPI_PTR *PFN_xrVoidFunction)(void); +typedef struct XrApiLayerProperties { + XrStructureType type; + void* XR_MAY_ALIAS next; + char layerName[XR_MAX_API_LAYER_NAME_SIZE]; + XrVersion specVersion; + uint32_t layerVersion; + char description[XR_MAX_API_LAYER_DESCRIPTION_SIZE]; +} XrApiLayerProperties; + +typedef struct XrExtensionProperties { + XrStructureType type; + void* XR_MAY_ALIAS next; + char extensionName[XR_MAX_EXTENSION_NAME_SIZE]; + uint32_t extensionVersion; +} XrExtensionProperties; + +typedef struct XrApplicationInfo { + char applicationName[XR_MAX_APPLICATION_NAME_SIZE]; + uint32_t applicationVersion; + char engineName[XR_MAX_ENGINE_NAME_SIZE]; + uint32_t engineVersion; + XrVersion apiVersion; +} XrApplicationInfo; + +typedef struct XrInstanceCreateInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrInstanceCreateFlags createFlags; + XrApplicationInfo applicationInfo; + uint32_t enabledApiLayerCount; + const char* const* enabledApiLayerNames; + uint32_t enabledExtensionCount; + const char* const* enabledExtensionNames; +} XrInstanceCreateInfo; + +typedef struct XrInstanceProperties { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrVersion runtimeVersion; + char runtimeName[XR_MAX_RUNTIME_NAME_SIZE]; +} XrInstanceProperties; + +typedef struct XrEventDataBuffer { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint8_t varying[4000]; +} XrEventDataBuffer; + +typedef struct XrSystemGetInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrFormFactor formFactor; +} XrSystemGetInfo; + +typedef struct XrSystemGraphicsProperties { + uint32_t maxSwapchainImageHeight; + uint32_t maxSwapchainImageWidth; + uint32_t maxLayerCount; +} XrSystemGraphicsProperties; + +typedef struct XrSystemTrackingProperties { + XrBool32 orientationTracking; + XrBool32 positionTracking; +} XrSystemTrackingProperties; + +typedef struct XrSystemProperties { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrSystemId systemId; + uint32_t vendorId; + char systemName[XR_MAX_SYSTEM_NAME_SIZE]; + XrSystemGraphicsProperties graphicsProperties; + XrSystemTrackingProperties trackingProperties; +} XrSystemProperties; + +typedef struct XrSessionCreateInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSessionCreateFlags createFlags; + XrSystemId systemId; +} XrSessionCreateInfo; + +typedef struct XrVector3f { + float x; + float y; + float z; +} XrVector3f; + +// XrSpaceVelocity extends XrSpaceLocation +typedef struct XrSpaceVelocity { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrSpaceVelocityFlags velocityFlags; + XrVector3f linearVelocity; + XrVector3f angularVelocity; +} XrSpaceVelocity; + +typedef struct XrQuaternionf { + float x; + float y; + float z; + float w; +} XrQuaternionf; + +typedef struct XrPosef { + XrQuaternionf orientation; + XrVector3f position; +} XrPosef; + +typedef struct XrReferenceSpaceCreateInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrReferenceSpaceType referenceSpaceType; + XrPosef poseInReferenceSpace; +} XrReferenceSpaceCreateInfo; + +typedef struct XrExtent2Df { + float width; + float height; +} XrExtent2Df; + +typedef struct XrActionSpaceCreateInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAction action; + XrPath subactionPath; + XrPosef poseInActionSpace; +} XrActionSpaceCreateInfo; + +typedef struct XrSpaceLocation { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrSpaceLocationFlags locationFlags; + XrPosef pose; +} XrSpaceLocation; + +typedef struct XrViewConfigurationProperties { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrViewConfigurationType viewConfigurationType; + XrBool32 fovMutable; +} XrViewConfigurationProperties; + +typedef struct XrViewConfigurationView { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t recommendedImageRectWidth; + uint32_t maxImageRectWidth; + uint32_t recommendedImageRectHeight; + uint32_t maxImageRectHeight; + uint32_t recommendedSwapchainSampleCount; + uint32_t maxSwapchainSampleCount; +} XrViewConfigurationView; + +typedef struct XrSwapchainCreateInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSwapchainCreateFlags createFlags; + XrSwapchainUsageFlags usageFlags; + int64_t format; + uint32_t sampleCount; + uint32_t width; + uint32_t height; + uint32_t faceCount; + uint32_t arraySize; + uint32_t mipCount; +} XrSwapchainCreateInfo; + +typedef struct XR_MAY_ALIAS XrSwapchainImageBaseHeader { + XrStructureType type; + void* XR_MAY_ALIAS next; +} XrSwapchainImageBaseHeader; + +typedef struct XrSwapchainImageAcquireInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSwapchainImageAcquireInfo; + +typedef struct XrSwapchainImageWaitInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrDuration timeout; +} XrSwapchainImageWaitInfo; + +typedef struct XrSwapchainImageReleaseInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSwapchainImageReleaseInfo; + +typedef struct XrSessionBeginInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrViewConfigurationType primaryViewConfigurationType; +} XrSessionBeginInfo; + +typedef struct XrFrameWaitInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrFrameWaitInfo; + +typedef struct XrFrameState { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrTime predictedDisplayTime; + XrDuration predictedDisplayPeriod; + XrBool32 shouldRender; +} XrFrameState; + +typedef struct XrFrameBeginInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrFrameBeginInfo; + +typedef struct XR_MAY_ALIAS XrCompositionLayerBaseHeader { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerFlags layerFlags; + XrSpace space; +} XrCompositionLayerBaseHeader; + +typedef struct XrFrameEndInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrTime displayTime; + XrEnvironmentBlendMode environmentBlendMode; + uint32_t layerCount; + const XrCompositionLayerBaseHeader* const* layers; +} XrFrameEndInfo; + +typedef struct XrViewLocateInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrViewConfigurationType viewConfigurationType; + XrTime displayTime; + XrSpace space; +} XrViewLocateInfo; + +typedef struct XrViewState { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrViewStateFlags viewStateFlags; +} XrViewState; + +typedef struct XrFovf { + float angleLeft; + float angleRight; + float angleUp; + float angleDown; +} XrFovf; + +typedef struct XrView { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrPosef pose; + XrFovf fov; +} XrView; + +typedef struct XrActionSetCreateInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + char actionSetName[XR_MAX_ACTION_SET_NAME_SIZE]; + char localizedActionSetName[XR_MAX_LOCALIZED_ACTION_SET_NAME_SIZE]; + uint32_t priority; +} XrActionSetCreateInfo; + +typedef struct XrActionCreateInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + char actionName[XR_MAX_ACTION_NAME_SIZE]; + XrActionType actionType; + uint32_t countSubactionPaths; + const XrPath* subactionPaths; + char localizedActionName[XR_MAX_LOCALIZED_ACTION_NAME_SIZE]; +} XrActionCreateInfo; + +typedef struct XrActionSuggestedBinding { + XrAction action; + XrPath binding; +} XrActionSuggestedBinding; + +typedef struct XrInteractionProfileSuggestedBinding { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPath interactionProfile; + uint32_t countSuggestedBindings; + const XrActionSuggestedBinding* suggestedBindings; +} XrInteractionProfileSuggestedBinding; + +typedef struct XrSessionActionSetsAttachInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t countActionSets; + const XrActionSet* actionSets; +} XrSessionActionSetsAttachInfo; + +typedef struct XrInteractionProfileState { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrPath interactionProfile; +} XrInteractionProfileState; + +typedef struct XrActionStateGetInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAction action; + XrPath subactionPath; +} XrActionStateGetInfo; + +typedef struct XrActionStateBoolean { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 currentState; + XrBool32 changedSinceLastSync; + XrTime lastChangeTime; + XrBool32 isActive; +} XrActionStateBoolean; + +typedef struct XrActionStateFloat { + XrStructureType type; + void* XR_MAY_ALIAS next; + float currentState; + XrBool32 changedSinceLastSync; + XrTime lastChangeTime; + XrBool32 isActive; +} XrActionStateFloat; + +typedef struct XrVector2f { + float x; + float y; +} XrVector2f; + +typedef struct XrActionStateVector2f { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrVector2f currentState; + XrBool32 changedSinceLastSync; + XrTime lastChangeTime; + XrBool32 isActive; +} XrActionStateVector2f; + +typedef struct XrActionStatePose { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 isActive; +} XrActionStatePose; + +typedef struct XrActiveActionSet { + XrActionSet actionSet; + XrPath subactionPath; +} XrActiveActionSet; + +typedef struct XrActionsSyncInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t countActiveActionSets; + const XrActiveActionSet* activeActionSets; +} XrActionsSyncInfo; + +typedef struct XrBoundSourcesForActionEnumerateInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAction action; +} XrBoundSourcesForActionEnumerateInfo; + +typedef struct XrInputSourceLocalizedNameGetInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPath sourcePath; + XrInputSourceLocalizedNameFlags whichComponents; +} XrInputSourceLocalizedNameGetInfo; + +typedef struct XrHapticActionInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAction action; + XrPath subactionPath; +} XrHapticActionInfo; + +typedef struct XR_MAY_ALIAS XrHapticBaseHeader { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrHapticBaseHeader; + +typedef struct XR_MAY_ALIAS XrBaseInStructure { + XrStructureType type; + const struct XrBaseInStructure* next; +} XrBaseInStructure; + +typedef struct XR_MAY_ALIAS XrBaseOutStructure { + XrStructureType type; + struct XrBaseOutStructure* next; +} XrBaseOutStructure; + +typedef struct XrOffset2Di { + int32_t x; + int32_t y; +} XrOffset2Di; + +typedef struct XrExtent2Di { + int32_t width; + int32_t height; +} XrExtent2Di; + +typedef struct XrRect2Di { + XrOffset2Di offset; + XrExtent2Di extent; +} XrRect2Di; + +typedef struct XrSwapchainSubImage { + XrSwapchain swapchain; + XrRect2Di imageRect; + uint32_t imageArrayIndex; +} XrSwapchainSubImage; + +typedef struct XrCompositionLayerProjectionView { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPosef pose; + XrFovf fov; + XrSwapchainSubImage subImage; +} XrCompositionLayerProjectionView; + +typedef struct XrCompositionLayerProjection { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerFlags layerFlags; + XrSpace space; + uint32_t viewCount; + const XrCompositionLayerProjectionView* views; +} XrCompositionLayerProjection; + +typedef struct XrCompositionLayerQuad { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerFlags layerFlags; + XrSpace space; + XrEyeVisibility eyeVisibility; + XrSwapchainSubImage subImage; + XrPosef pose; + XrExtent2Df size; +} XrCompositionLayerQuad; + +typedef struct XR_MAY_ALIAS XrEventDataBaseHeader { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrEventDataBaseHeader; + +typedef struct XrEventDataEventsLost { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t lostEventCount; +} XrEventDataEventsLost; + +typedef struct XrEventDataInstanceLossPending { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrTime lossTime; +} XrEventDataInstanceLossPending; + +typedef struct XrEventDataSessionStateChanged { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSession session; + XrSessionState state; + XrTime time; +} XrEventDataSessionStateChanged; + +typedef struct XrEventDataReferenceSpaceChangePending { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSession session; + XrReferenceSpaceType referenceSpaceType; + XrTime changeTime; + XrBool32 poseValid; + XrPosef poseInPreviousSpace; +} XrEventDataReferenceSpaceChangePending; + +typedef struct XrEventDataInteractionProfileChanged { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSession session; +} XrEventDataInteractionProfileChanged; + +typedef struct XrHapticVibration { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrDuration duration; + float frequency; + float amplitude; +} XrHapticVibration; + +typedef struct XrOffset2Df { + float x; + float y; +} XrOffset2Df; + +typedef struct XrRect2Df { + XrOffset2Df offset; + XrExtent2Df extent; +} XrRect2Df; + +typedef struct XrVector4f { + float x; + float y; + float z; + float w; +} XrVector4f; + +typedef struct XrColor4f { + float r; + float g; + float b; + float a; +} XrColor4f; + +typedef XrResult (XRAPI_PTR *PFN_xrGetInstanceProcAddr)(XrInstance instance, const char* name, PFN_xrVoidFunction* function); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateApiLayerProperties)(uint32_t propertyCapacityInput, uint32_t* propertyCountOutput, XrApiLayerProperties* properties); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateInstanceExtensionProperties)(const char* layerName, uint32_t propertyCapacityInput, uint32_t* propertyCountOutput, XrExtensionProperties* properties); +typedef XrResult (XRAPI_PTR *PFN_xrCreateInstance)(const XrInstanceCreateInfo* createInfo, XrInstance* instance); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyInstance)(XrInstance instance); +typedef XrResult (XRAPI_PTR *PFN_xrGetInstanceProperties)(XrInstance instance, XrInstanceProperties* instanceProperties); +typedef XrResult (XRAPI_PTR *PFN_xrPollEvent)(XrInstance instance, XrEventDataBuffer* eventData); +typedef XrResult (XRAPI_PTR *PFN_xrResultToString)(XrInstance instance, XrResult value, char buffer[XR_MAX_RESULT_STRING_SIZE]); +typedef XrResult (XRAPI_PTR *PFN_xrStructureTypeToString)(XrInstance instance, XrStructureType value, char buffer[XR_MAX_STRUCTURE_NAME_SIZE]); +typedef XrResult (XRAPI_PTR *PFN_xrGetSystem)(XrInstance instance, const XrSystemGetInfo* getInfo, XrSystemId* systemId); +typedef XrResult (XRAPI_PTR *PFN_xrGetSystemProperties)(XrInstance instance, XrSystemId systemId, XrSystemProperties* properties); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateEnvironmentBlendModes)(XrInstance instance, XrSystemId systemId, XrViewConfigurationType viewConfigurationType, uint32_t environmentBlendModeCapacityInput, uint32_t* environmentBlendModeCountOutput, XrEnvironmentBlendMode* environmentBlendModes); +typedef XrResult (XRAPI_PTR *PFN_xrCreateSession)(XrInstance instance, const XrSessionCreateInfo* createInfo, XrSession* session); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySession)(XrSession session); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateReferenceSpaces)(XrSession session, uint32_t spaceCapacityInput, uint32_t* spaceCountOutput, XrReferenceSpaceType* spaces); +typedef XrResult (XRAPI_PTR *PFN_xrCreateReferenceSpace)(XrSession session, const XrReferenceSpaceCreateInfo* createInfo, XrSpace* space); +typedef XrResult (XRAPI_PTR *PFN_xrGetReferenceSpaceBoundsRect)(XrSession session, XrReferenceSpaceType referenceSpaceType, XrExtent2Df* bounds); +typedef XrResult (XRAPI_PTR *PFN_xrCreateActionSpace)(XrSession session, const XrActionSpaceCreateInfo* createInfo, XrSpace* space); +typedef XrResult (XRAPI_PTR *PFN_xrLocateSpace)(XrSpace space, XrSpace baseSpace, XrTime time, XrSpaceLocation* location); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySpace)(XrSpace space); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateViewConfigurations)(XrInstance instance, XrSystemId systemId, uint32_t viewConfigurationTypeCapacityInput, uint32_t* viewConfigurationTypeCountOutput, XrViewConfigurationType* viewConfigurationTypes); +typedef XrResult (XRAPI_PTR *PFN_xrGetViewConfigurationProperties)(XrInstance instance, XrSystemId systemId, XrViewConfigurationType viewConfigurationType, XrViewConfigurationProperties* configurationProperties); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateViewConfigurationViews)(XrInstance instance, XrSystemId systemId, XrViewConfigurationType viewConfigurationType, uint32_t viewCapacityInput, uint32_t* viewCountOutput, XrViewConfigurationView* views); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateSwapchainFormats)(XrSession session, uint32_t formatCapacityInput, uint32_t* formatCountOutput, int64_t* formats); +typedef XrResult (XRAPI_PTR *PFN_xrCreateSwapchain)(XrSession session, const XrSwapchainCreateInfo* createInfo, XrSwapchain* swapchain); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySwapchain)(XrSwapchain swapchain); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateSwapchainImages)(XrSwapchain swapchain, uint32_t imageCapacityInput, uint32_t* imageCountOutput, XrSwapchainImageBaseHeader* images); +typedef XrResult (XRAPI_PTR *PFN_xrAcquireSwapchainImage)(XrSwapchain swapchain, const XrSwapchainImageAcquireInfo* acquireInfo, uint32_t* index); +typedef XrResult (XRAPI_PTR *PFN_xrWaitSwapchainImage)(XrSwapchain swapchain, const XrSwapchainImageWaitInfo* waitInfo); +typedef XrResult (XRAPI_PTR *PFN_xrReleaseSwapchainImage)(XrSwapchain swapchain, const XrSwapchainImageReleaseInfo* releaseInfo); +typedef XrResult (XRAPI_PTR *PFN_xrBeginSession)(XrSession session, const XrSessionBeginInfo* beginInfo); +typedef XrResult (XRAPI_PTR *PFN_xrEndSession)(XrSession session); +typedef XrResult (XRAPI_PTR *PFN_xrRequestExitSession)(XrSession session); +typedef XrResult (XRAPI_PTR *PFN_xrWaitFrame)(XrSession session, const XrFrameWaitInfo* frameWaitInfo, XrFrameState* frameState); +typedef XrResult (XRAPI_PTR *PFN_xrBeginFrame)(XrSession session, const XrFrameBeginInfo* frameBeginInfo); +typedef XrResult (XRAPI_PTR *PFN_xrEndFrame)(XrSession session, const XrFrameEndInfo* frameEndInfo); +typedef XrResult (XRAPI_PTR *PFN_xrLocateViews)(XrSession session, const XrViewLocateInfo* viewLocateInfo, XrViewState* viewState, uint32_t viewCapacityInput, uint32_t* viewCountOutput, XrView* views); +typedef XrResult (XRAPI_PTR *PFN_xrStringToPath)(XrInstance instance, const char* pathString, XrPath* path); +typedef XrResult (XRAPI_PTR *PFN_xrPathToString)(XrInstance instance, XrPath path, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer); +typedef XrResult (XRAPI_PTR *PFN_xrCreateActionSet)(XrInstance instance, const XrActionSetCreateInfo* createInfo, XrActionSet* actionSet); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyActionSet)(XrActionSet actionSet); +typedef XrResult (XRAPI_PTR *PFN_xrCreateAction)(XrActionSet actionSet, const XrActionCreateInfo* createInfo, XrAction* action); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyAction)(XrAction action); +typedef XrResult (XRAPI_PTR *PFN_xrSuggestInteractionProfileBindings)(XrInstance instance, const XrInteractionProfileSuggestedBinding* suggestedBindings); +typedef XrResult (XRAPI_PTR *PFN_xrAttachSessionActionSets)(XrSession session, const XrSessionActionSetsAttachInfo* attachInfo); +typedef XrResult (XRAPI_PTR *PFN_xrGetCurrentInteractionProfile)(XrSession session, XrPath topLevelUserPath, XrInteractionProfileState* interactionProfile); +typedef XrResult (XRAPI_PTR *PFN_xrGetActionStateBoolean)(XrSession session, const XrActionStateGetInfo* getInfo, XrActionStateBoolean* state); +typedef XrResult (XRAPI_PTR *PFN_xrGetActionStateFloat)(XrSession session, const XrActionStateGetInfo* getInfo, XrActionStateFloat* state); +typedef XrResult (XRAPI_PTR *PFN_xrGetActionStateVector2f)(XrSession session, const XrActionStateGetInfo* getInfo, XrActionStateVector2f* state); +typedef XrResult (XRAPI_PTR *PFN_xrGetActionStatePose)(XrSession session, const XrActionStateGetInfo* getInfo, XrActionStatePose* state); +typedef XrResult (XRAPI_PTR *PFN_xrSyncActions)(XrSession session, const XrActionsSyncInfo* syncInfo); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateBoundSourcesForAction)(XrSession session, const XrBoundSourcesForActionEnumerateInfo* enumerateInfo, uint32_t sourceCapacityInput, uint32_t* sourceCountOutput, XrPath* sources); +typedef XrResult (XRAPI_PTR *PFN_xrGetInputSourceLocalizedName)(XrSession session, const XrInputSourceLocalizedNameGetInfo* getInfo, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer); +typedef XrResult (XRAPI_PTR *PFN_xrApplyHapticFeedback)(XrSession session, const XrHapticActionInfo* hapticActionInfo, const XrHapticBaseHeader* hapticFeedback); +typedef XrResult (XRAPI_PTR *PFN_xrStopHapticFeedback)(XrSession session, const XrHapticActionInfo* hapticActionInfo); + +#ifndef XR_NO_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetInstanceProcAddr( + XrInstance instance, + const char* name, + PFN_xrVoidFunction* function); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateApiLayerProperties( + uint32_t propertyCapacityInput, + uint32_t* propertyCountOutput, + XrApiLayerProperties* properties); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateInstanceExtensionProperties( + const char* layerName, + uint32_t propertyCapacityInput, + uint32_t* propertyCountOutput, + XrExtensionProperties* properties); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateInstance( + const XrInstanceCreateInfo* createInfo, + XrInstance* instance); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyInstance( + XrInstance instance); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetInstanceProperties( + XrInstance instance, + XrInstanceProperties* instanceProperties); + +XRAPI_ATTR XrResult XRAPI_CALL xrPollEvent( + XrInstance instance, + XrEventDataBuffer* eventData); + +XRAPI_ATTR XrResult XRAPI_CALL xrResultToString( + XrInstance instance, + XrResult value, + char buffer[XR_MAX_RESULT_STRING_SIZE]); + +XRAPI_ATTR XrResult XRAPI_CALL xrStructureTypeToString( + XrInstance instance, + XrStructureType value, + char buffer[XR_MAX_STRUCTURE_NAME_SIZE]); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSystem( + XrInstance instance, + const XrSystemGetInfo* getInfo, + XrSystemId* systemId); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSystemProperties( + XrInstance instance, + XrSystemId systemId, + XrSystemProperties* properties); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateEnvironmentBlendModes( + XrInstance instance, + XrSystemId systemId, + XrViewConfigurationType viewConfigurationType, + uint32_t environmentBlendModeCapacityInput, + uint32_t* environmentBlendModeCountOutput, + XrEnvironmentBlendMode* environmentBlendModes); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSession( + XrInstance instance, + const XrSessionCreateInfo* createInfo, + XrSession* session); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySession( + XrSession session); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateReferenceSpaces( + XrSession session, + uint32_t spaceCapacityInput, + uint32_t* spaceCountOutput, + XrReferenceSpaceType* spaces); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateReferenceSpace( + XrSession session, + const XrReferenceSpaceCreateInfo* createInfo, + XrSpace* space); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetReferenceSpaceBoundsRect( + XrSession session, + XrReferenceSpaceType referenceSpaceType, + XrExtent2Df* bounds); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateActionSpace( + XrSession session, + const XrActionSpaceCreateInfo* createInfo, + XrSpace* space); + +XRAPI_ATTR XrResult XRAPI_CALL xrLocateSpace( + XrSpace space, + XrSpace baseSpace, + XrTime time, + XrSpaceLocation* location); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpace( + XrSpace space); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateViewConfigurations( + XrInstance instance, + XrSystemId systemId, + uint32_t viewConfigurationTypeCapacityInput, + uint32_t* viewConfigurationTypeCountOutput, + XrViewConfigurationType* viewConfigurationTypes); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetViewConfigurationProperties( + XrInstance instance, + XrSystemId systemId, + XrViewConfigurationType viewConfigurationType, + XrViewConfigurationProperties* configurationProperties); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateViewConfigurationViews( + XrInstance instance, + XrSystemId systemId, + XrViewConfigurationType viewConfigurationType, + uint32_t viewCapacityInput, + uint32_t* viewCountOutput, + XrViewConfigurationView* views); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSwapchainFormats( + XrSession session, + uint32_t formatCapacityInput, + uint32_t* formatCountOutput, + int64_t* formats); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSwapchain( + XrSession session, + const XrSwapchainCreateInfo* createInfo, + XrSwapchain* swapchain); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySwapchain( + XrSwapchain swapchain); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSwapchainImages( + XrSwapchain swapchain, + uint32_t imageCapacityInput, + uint32_t* imageCountOutput, + XrSwapchainImageBaseHeader* images); + +XRAPI_ATTR XrResult XRAPI_CALL xrAcquireSwapchainImage( + XrSwapchain swapchain, + const XrSwapchainImageAcquireInfo* acquireInfo, + uint32_t* index); + +XRAPI_ATTR XrResult XRAPI_CALL xrWaitSwapchainImage( + XrSwapchain swapchain, + const XrSwapchainImageWaitInfo* waitInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrReleaseSwapchainImage( + XrSwapchain swapchain, + const XrSwapchainImageReleaseInfo* releaseInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrBeginSession( + XrSession session, + const XrSessionBeginInfo* beginInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrEndSession( + XrSession session); + +XRAPI_ATTR XrResult XRAPI_CALL xrRequestExitSession( + XrSession session); + +XRAPI_ATTR XrResult XRAPI_CALL xrWaitFrame( + XrSession session, + const XrFrameWaitInfo* frameWaitInfo, + XrFrameState* frameState); + +XRAPI_ATTR XrResult XRAPI_CALL xrBeginFrame( + XrSession session, + const XrFrameBeginInfo* frameBeginInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrEndFrame( + XrSession session, + const XrFrameEndInfo* frameEndInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrLocateViews( + XrSession session, + const XrViewLocateInfo* viewLocateInfo, + XrViewState* viewState, + uint32_t viewCapacityInput, + uint32_t* viewCountOutput, + XrView* views); + +XRAPI_ATTR XrResult XRAPI_CALL xrStringToPath( + XrInstance instance, + const char* pathString, + XrPath* path); + +XRAPI_ATTR XrResult XRAPI_CALL xrPathToString( + XrInstance instance, + XrPath path, + uint32_t bufferCapacityInput, + uint32_t* bufferCountOutput, + char* buffer); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateActionSet( + XrInstance instance, + const XrActionSetCreateInfo* createInfo, + XrActionSet* actionSet); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyActionSet( + XrActionSet actionSet); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateAction( + XrActionSet actionSet, + const XrActionCreateInfo* createInfo, + XrAction* action); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyAction( + XrAction action); + +XRAPI_ATTR XrResult XRAPI_CALL xrSuggestInteractionProfileBindings( + XrInstance instance, + const XrInteractionProfileSuggestedBinding* suggestedBindings); + +XRAPI_ATTR XrResult XRAPI_CALL xrAttachSessionActionSets( + XrSession session, + const XrSessionActionSetsAttachInfo* attachInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetCurrentInteractionProfile( + XrSession session, + XrPath topLevelUserPath, + XrInteractionProfileState* interactionProfile); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateBoolean( + XrSession session, + const XrActionStateGetInfo* getInfo, + XrActionStateBoolean* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateFloat( + XrSession session, + const XrActionStateGetInfo* getInfo, + XrActionStateFloat* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateVector2f( + XrSession session, + const XrActionStateGetInfo* getInfo, + XrActionStateVector2f* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStatePose( + XrSession session, + const XrActionStateGetInfo* getInfo, + XrActionStatePose* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrSyncActions( + XrSession session, + const XrActionsSyncInfo* syncInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateBoundSourcesForAction( + XrSession session, + const XrBoundSourcesForActionEnumerateInfo* enumerateInfo, + uint32_t sourceCapacityInput, + uint32_t* sourceCountOutput, + XrPath* sources); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetInputSourceLocalizedName( + XrSession session, + const XrInputSourceLocalizedNameGetInfo* getInfo, + uint32_t bufferCapacityInput, + uint32_t* bufferCountOutput, + char* buffer); + +XRAPI_ATTR XrResult XRAPI_CALL xrApplyHapticFeedback( + XrSession session, + const XrHapticActionInfo* hapticActionInfo, + const XrHapticBaseHeader* hapticFeedback); + +XRAPI_ATTR XrResult XRAPI_CALL xrStopHapticFeedback( + XrSession session, + const XrHapticActionInfo* hapticActionInfo); +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_KHR_composition_layer_cube 1 +#define XR_KHR_composition_layer_cube_SPEC_VERSION 8 +#define XR_KHR_COMPOSITION_LAYER_CUBE_EXTENSION_NAME "XR_KHR_composition_layer_cube" +typedef struct XrCompositionLayerCubeKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerFlags layerFlags; + XrSpace space; + XrEyeVisibility eyeVisibility; + XrSwapchain swapchain; + uint32_t imageArrayIndex; + XrQuaternionf orientation; +} XrCompositionLayerCubeKHR; + + + +#define XR_KHR_composition_layer_depth 1 +#define XR_KHR_composition_layer_depth_SPEC_VERSION 5 +#define XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME "XR_KHR_composition_layer_depth" +// XrCompositionLayerDepthInfoKHR extends XrCompositionLayerProjectionView +typedef struct XrCompositionLayerDepthInfoKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSwapchainSubImage subImage; + float minDepth; + float maxDepth; + float nearZ; + float farZ; +} XrCompositionLayerDepthInfoKHR; + + + +#define XR_KHR_composition_layer_cylinder 1 +#define XR_KHR_composition_layer_cylinder_SPEC_VERSION 4 +#define XR_KHR_COMPOSITION_LAYER_CYLINDER_EXTENSION_NAME "XR_KHR_composition_layer_cylinder" +typedef struct XrCompositionLayerCylinderKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerFlags layerFlags; + XrSpace space; + XrEyeVisibility eyeVisibility; + XrSwapchainSubImage subImage; + XrPosef pose; + float radius; + float centralAngle; + float aspectRatio; +} XrCompositionLayerCylinderKHR; + + + +#define XR_KHR_composition_layer_equirect 1 +#define XR_KHR_composition_layer_equirect_SPEC_VERSION 3 +#define XR_KHR_COMPOSITION_LAYER_EQUIRECT_EXTENSION_NAME "XR_KHR_composition_layer_equirect" +typedef struct XrCompositionLayerEquirectKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerFlags layerFlags; + XrSpace space; + XrEyeVisibility eyeVisibility; + XrSwapchainSubImage subImage; + XrPosef pose; + float radius; + XrVector2f scale; + XrVector2f bias; +} XrCompositionLayerEquirectKHR; + + + +#define XR_KHR_visibility_mask 1 +#define XR_KHR_visibility_mask_SPEC_VERSION 2 +#define XR_KHR_VISIBILITY_MASK_EXTENSION_NAME "XR_KHR_visibility_mask" + +typedef enum XrVisibilityMaskTypeKHR { + XR_VISIBILITY_MASK_TYPE_HIDDEN_TRIANGLE_MESH_KHR = 1, + XR_VISIBILITY_MASK_TYPE_VISIBLE_TRIANGLE_MESH_KHR = 2, + XR_VISIBILITY_MASK_TYPE_LINE_LOOP_KHR = 3, + XR_VISIBILITY_MASK_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} XrVisibilityMaskTypeKHR; +typedef struct XrVisibilityMaskKHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t vertexCapacityInput; + uint32_t vertexCountOutput; + XrVector2f* vertices; + uint32_t indexCapacityInput; + uint32_t indexCountOutput; + uint32_t* indices; +} XrVisibilityMaskKHR; + +typedef struct XrEventDataVisibilityMaskChangedKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSession session; + XrViewConfigurationType viewConfigurationType; + uint32_t viewIndex; +} XrEventDataVisibilityMaskChangedKHR; + +typedef XrResult (XRAPI_PTR *PFN_xrGetVisibilityMaskKHR)(XrSession session, XrViewConfigurationType viewConfigurationType, uint32_t viewIndex, XrVisibilityMaskTypeKHR visibilityMaskType, XrVisibilityMaskKHR* visibilityMask); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetVisibilityMaskKHR( + XrSession session, + XrViewConfigurationType viewConfigurationType, + uint32_t viewIndex, + XrVisibilityMaskTypeKHR visibilityMaskType, + XrVisibilityMaskKHR* visibilityMask); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_KHR_composition_layer_color_scale_bias 1 +#define XR_KHR_composition_layer_color_scale_bias_SPEC_VERSION 5 +#define XR_KHR_COMPOSITION_LAYER_COLOR_SCALE_BIAS_EXTENSION_NAME "XR_KHR_composition_layer_color_scale_bias" +// XrCompositionLayerColorScaleBiasKHR extends XrCompositionLayerBaseHeader +typedef struct XrCompositionLayerColorScaleBiasKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrColor4f colorScale; + XrColor4f colorBias; +} XrCompositionLayerColorScaleBiasKHR; + + + +#define XR_KHR_loader_init 1 +#define XR_KHR_loader_init_SPEC_VERSION 1 +#define XR_KHR_LOADER_INIT_EXTENSION_NAME "XR_KHR_loader_init" +typedef struct XR_MAY_ALIAS XrLoaderInitInfoBaseHeaderKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrLoaderInitInfoBaseHeaderKHR; + +typedef XrResult (XRAPI_PTR *PFN_xrInitializeLoaderKHR)(const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrInitializeLoaderKHR( + const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_KHR_composition_layer_equirect2 1 +#define XR_KHR_composition_layer_equirect2_SPEC_VERSION 1 +#define XR_KHR_COMPOSITION_LAYER_EQUIRECT2_EXTENSION_NAME "XR_KHR_composition_layer_equirect2" +typedef struct XrCompositionLayerEquirect2KHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerFlags layerFlags; + XrSpace space; + XrEyeVisibility eyeVisibility; + XrSwapchainSubImage subImage; + XrPosef pose; + float radius; + float centralHorizontalAngle; + float upperVerticalAngle; + float lowerVerticalAngle; +} XrCompositionLayerEquirect2KHR; + + + +#define XR_KHR_binding_modification 1 +#define XR_KHR_binding_modification_SPEC_VERSION 1 +#define XR_KHR_BINDING_MODIFICATION_EXTENSION_NAME "XR_KHR_binding_modification" +typedef struct XR_MAY_ALIAS XrBindingModificationBaseHeaderKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrBindingModificationBaseHeaderKHR; + +// XrBindingModificationsKHR extends XrInteractionProfileSuggestedBinding +typedef struct XrBindingModificationsKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t bindingModificationCount; + const XrBindingModificationBaseHeaderKHR* const* bindingModifications; +} XrBindingModificationsKHR; + + + +#define XR_KHR_swapchain_usage_input_attachment_bit 1 +#define XR_KHR_swapchain_usage_input_attachment_bit_SPEC_VERSION 3 +#define XR_KHR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_EXTENSION_NAME "XR_KHR_swapchain_usage_input_attachment_bit" + + +#define XR_EXT_performance_settings 1 +#define XR_EXT_performance_settings_SPEC_VERSION 3 +#define XR_EXT_PERFORMANCE_SETTINGS_EXTENSION_NAME "XR_EXT_performance_settings" + +typedef enum XrPerfSettingsDomainEXT { + XR_PERF_SETTINGS_DOMAIN_CPU_EXT = 1, + XR_PERF_SETTINGS_DOMAIN_GPU_EXT = 2, + XR_PERF_SETTINGS_DOMAIN_MAX_ENUM_EXT = 0x7FFFFFFF +} XrPerfSettingsDomainEXT; + +typedef enum XrPerfSettingsSubDomainEXT { + XR_PERF_SETTINGS_SUB_DOMAIN_COMPOSITING_EXT = 1, + XR_PERF_SETTINGS_SUB_DOMAIN_RENDERING_EXT = 2, + XR_PERF_SETTINGS_SUB_DOMAIN_THERMAL_EXT = 3, + XR_PERF_SETTINGS_SUB_DOMAIN_MAX_ENUM_EXT = 0x7FFFFFFF +} XrPerfSettingsSubDomainEXT; + +typedef enum XrPerfSettingsLevelEXT { + XR_PERF_SETTINGS_LEVEL_POWER_SAVINGS_EXT = 0, + XR_PERF_SETTINGS_LEVEL_SUSTAINED_LOW_EXT = 25, + XR_PERF_SETTINGS_LEVEL_SUSTAINED_HIGH_EXT = 50, + XR_PERF_SETTINGS_LEVEL_BOOST_EXT = 75, + XR_PERF_SETTINGS_LEVEL_MAX_ENUM_EXT = 0x7FFFFFFF +} XrPerfSettingsLevelEXT; + +typedef enum XrPerfSettingsNotificationLevelEXT { + XR_PERF_SETTINGS_NOTIF_LEVEL_NORMAL_EXT = 0, + XR_PERF_SETTINGS_NOTIF_LEVEL_WARNING_EXT = 25, + XR_PERF_SETTINGS_NOTIF_LEVEL_IMPAIRED_EXT = 75, + XR_PERF_SETTINGS_NOTIFICATION_LEVEL_MAX_ENUM_EXT = 0x7FFFFFFF +} XrPerfSettingsNotificationLevelEXT; +typedef struct XrEventDataPerfSettingsEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPerfSettingsDomainEXT domain; + XrPerfSettingsSubDomainEXT subDomain; + XrPerfSettingsNotificationLevelEXT fromLevel; + XrPerfSettingsNotificationLevelEXT toLevel; +} XrEventDataPerfSettingsEXT; + +typedef XrResult (XRAPI_PTR *PFN_xrPerfSettingsSetPerformanceLevelEXT)(XrSession session, XrPerfSettingsDomainEXT domain, XrPerfSettingsLevelEXT level); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrPerfSettingsSetPerformanceLevelEXT( + XrSession session, + XrPerfSettingsDomainEXT domain, + XrPerfSettingsLevelEXT level); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_EXT_thermal_query 1 +#define XR_EXT_thermal_query_SPEC_VERSION 2 +#define XR_EXT_THERMAL_QUERY_EXTENSION_NAME "XR_EXT_thermal_query" +typedef XrResult (XRAPI_PTR *PFN_xrThermalGetTemperatureTrendEXT)(XrSession session, XrPerfSettingsDomainEXT domain, XrPerfSettingsNotificationLevelEXT* notificationLevel, float* tempHeadroom, float* tempSlope); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrThermalGetTemperatureTrendEXT( + XrSession session, + XrPerfSettingsDomainEXT domain, + XrPerfSettingsNotificationLevelEXT* notificationLevel, + float* tempHeadroom, + float* tempSlope); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_EXT_debug_utils 1 +XR_DEFINE_HANDLE(XrDebugUtilsMessengerEXT) +#define XR_EXT_debug_utils_SPEC_VERSION 4 +#define XR_EXT_DEBUG_UTILS_EXTENSION_NAME "XR_EXT_debug_utils" +typedef XrFlags64 XrDebugUtilsMessageSeverityFlagsEXT; + +// Flag bits for XrDebugUtilsMessageSeverityFlagsEXT +static const XrDebugUtilsMessageSeverityFlagsEXT XR_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT = 0x00000001; +static const XrDebugUtilsMessageSeverityFlagsEXT XR_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT = 0x00000010; +static const XrDebugUtilsMessageSeverityFlagsEXT XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT = 0x00000100; +static const XrDebugUtilsMessageSeverityFlagsEXT XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT = 0x00001000; + +typedef XrFlags64 XrDebugUtilsMessageTypeFlagsEXT; + +// Flag bits for XrDebugUtilsMessageTypeFlagsEXT +static const XrDebugUtilsMessageTypeFlagsEXT XR_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT = 0x00000001; +static const XrDebugUtilsMessageTypeFlagsEXT XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT = 0x00000002; +static const XrDebugUtilsMessageTypeFlagsEXT XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT = 0x00000004; +static const XrDebugUtilsMessageTypeFlagsEXT XR_DEBUG_UTILS_MESSAGE_TYPE_CONFORMANCE_BIT_EXT = 0x00000008; + +typedef struct XrDebugUtilsObjectNameInfoEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrObjectType objectType; + uint64_t objectHandle; + const char* objectName; +} XrDebugUtilsObjectNameInfoEXT; + +typedef struct XrDebugUtilsLabelEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + const char* labelName; +} XrDebugUtilsLabelEXT; + +typedef struct XrDebugUtilsMessengerCallbackDataEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + const char* messageId; + const char* functionName; + const char* message; + uint32_t objectCount; + XrDebugUtilsObjectNameInfoEXT* objects; + uint32_t sessionLabelCount; + XrDebugUtilsLabelEXT* sessionLabels; +} XrDebugUtilsMessengerCallbackDataEXT; + +typedef XrBool32 (XRAPI_PTR *PFN_xrDebugUtilsMessengerCallbackEXT)( + XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, + XrDebugUtilsMessageTypeFlagsEXT messageTypes, + const XrDebugUtilsMessengerCallbackDataEXT* callbackData, + void* userData); + + +// XrDebugUtilsMessengerCreateInfoEXT extends XrInstanceCreateInfo +typedef struct XrDebugUtilsMessengerCreateInfoEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrDebugUtilsMessageSeverityFlagsEXT messageSeverities; + XrDebugUtilsMessageTypeFlagsEXT messageTypes; + PFN_xrDebugUtilsMessengerCallbackEXT userCallback; + void* XR_MAY_ALIAS userData; +} XrDebugUtilsMessengerCreateInfoEXT; + +typedef XrResult (XRAPI_PTR *PFN_xrSetDebugUtilsObjectNameEXT)(XrInstance instance, const XrDebugUtilsObjectNameInfoEXT* nameInfo); +typedef XrResult (XRAPI_PTR *PFN_xrCreateDebugUtilsMessengerEXT)(XrInstance instance, const XrDebugUtilsMessengerCreateInfoEXT* createInfo, XrDebugUtilsMessengerEXT* messenger); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyDebugUtilsMessengerEXT)(XrDebugUtilsMessengerEXT messenger); +typedef XrResult (XRAPI_PTR *PFN_xrSubmitDebugUtilsMessageEXT)(XrInstance instance, XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, XrDebugUtilsMessageTypeFlagsEXT messageTypes, const XrDebugUtilsMessengerCallbackDataEXT* callbackData); +typedef XrResult (XRAPI_PTR *PFN_xrSessionBeginDebugUtilsLabelRegionEXT)(XrSession session, const XrDebugUtilsLabelEXT* labelInfo); +typedef XrResult (XRAPI_PTR *PFN_xrSessionEndDebugUtilsLabelRegionEXT)(XrSession session); +typedef XrResult (XRAPI_PTR *PFN_xrSessionInsertDebugUtilsLabelEXT)(XrSession session, const XrDebugUtilsLabelEXT* labelInfo); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetDebugUtilsObjectNameEXT( + XrInstance instance, + const XrDebugUtilsObjectNameInfoEXT* nameInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateDebugUtilsMessengerEXT( + XrInstance instance, + const XrDebugUtilsMessengerCreateInfoEXT* createInfo, + XrDebugUtilsMessengerEXT* messenger); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyDebugUtilsMessengerEXT( + XrDebugUtilsMessengerEXT messenger); + +XRAPI_ATTR XrResult XRAPI_CALL xrSubmitDebugUtilsMessageEXT( + XrInstance instance, + XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, + XrDebugUtilsMessageTypeFlagsEXT messageTypes, + const XrDebugUtilsMessengerCallbackDataEXT* callbackData); + +XRAPI_ATTR XrResult XRAPI_CALL xrSessionBeginDebugUtilsLabelRegionEXT( + XrSession session, + const XrDebugUtilsLabelEXT* labelInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrSessionEndDebugUtilsLabelRegionEXT( + XrSession session); + +XRAPI_ATTR XrResult XRAPI_CALL xrSessionInsertDebugUtilsLabelEXT( + XrSession session, + const XrDebugUtilsLabelEXT* labelInfo); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_EXT_eye_gaze_interaction 1 +#define XR_EXT_eye_gaze_interaction_SPEC_VERSION 1 +#define XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME "XR_EXT_eye_gaze_interaction" +// XrSystemEyeGazeInteractionPropertiesEXT extends XrSystemProperties +typedef struct XrSystemEyeGazeInteractionPropertiesEXT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsEyeGazeInteraction; +} XrSystemEyeGazeInteractionPropertiesEXT; + +// XrEyeGazeSampleTimeEXT extends XrSpaceLocation +typedef struct XrEyeGazeSampleTimeEXT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrTime time; +} XrEyeGazeSampleTimeEXT; + + + +#define XR_EXTX_overlay 1 +#define XR_EXTX_overlay_SPEC_VERSION 5 +#define XR_EXTX_OVERLAY_EXTENSION_NAME "XR_EXTX_overlay" +typedef XrFlags64 XrOverlaySessionCreateFlagsEXTX; + +// Flag bits for XrOverlaySessionCreateFlagsEXTX + +typedef XrFlags64 XrOverlayMainSessionFlagsEXTX; + +// Flag bits for XrOverlayMainSessionFlagsEXTX +static const XrOverlayMainSessionFlagsEXTX XR_OVERLAY_MAIN_SESSION_ENABLED_COMPOSITION_LAYER_INFO_DEPTH_BIT_EXTX = 0x00000001; + +// XrSessionCreateInfoOverlayEXTX extends XrSessionCreateInfo +typedef struct XrSessionCreateInfoOverlayEXTX { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrOverlaySessionCreateFlagsEXTX createFlags; + uint32_t sessionLayersPlacement; +} XrSessionCreateInfoOverlayEXTX; + +typedef struct XrEventDataMainSessionVisibilityChangedEXTX { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 visible; + XrOverlayMainSessionFlagsEXTX flags; +} XrEventDataMainSessionVisibilityChangedEXTX; + + + +#define XR_VARJO_quad_views 1 +#define XR_VARJO_quad_views_SPEC_VERSION 1 +#define XR_VARJO_QUAD_VIEWS_EXTENSION_NAME "XR_VARJO_quad_views" + + +#define XR_MSFT_unbounded_reference_space 1 +#define XR_MSFT_unbounded_reference_space_SPEC_VERSION 1 +#define XR_MSFT_UNBOUNDED_REFERENCE_SPACE_EXTENSION_NAME "XR_MSFT_unbounded_reference_space" + + +#define XR_MSFT_spatial_anchor 1 +XR_DEFINE_HANDLE(XrSpatialAnchorMSFT) +#define XR_MSFT_spatial_anchor_SPEC_VERSION 2 +#define XR_MSFT_SPATIAL_ANCHOR_EXTENSION_NAME "XR_MSFT_spatial_anchor" +typedef struct XrSpatialAnchorCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace space; + XrPosef pose; + XrTime time; +} XrSpatialAnchorCreateInfoMSFT; + +typedef struct XrSpatialAnchorSpaceCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpatialAnchorMSFT anchor; + XrPosef poseInAnchorSpace; +} XrSpatialAnchorSpaceCreateInfoMSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorMSFT)(XrSession session, const XrSpatialAnchorCreateInfoMSFT* createInfo, XrSpatialAnchorMSFT* anchor); +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorSpaceMSFT)(XrSession session, const XrSpatialAnchorSpaceCreateInfoMSFT* createInfo, XrSpace* space); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySpatialAnchorMSFT)(XrSpatialAnchorMSFT anchor); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorMSFT( + XrSession session, + const XrSpatialAnchorCreateInfoMSFT* createInfo, + XrSpatialAnchorMSFT* anchor); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorSpaceMSFT( + XrSession session, + const XrSpatialAnchorSpaceCreateInfoMSFT* createInfo, + XrSpace* space); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpatialAnchorMSFT( + XrSpatialAnchorMSFT anchor); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_composition_layer_image_layout 1 +#define XR_FB_composition_layer_image_layout_SPEC_VERSION 1 +#define XR_FB_COMPOSITION_LAYER_IMAGE_LAYOUT_EXTENSION_NAME "XR_FB_composition_layer_image_layout" +typedef XrFlags64 XrCompositionLayerImageLayoutFlagsFB; + +// Flag bits for XrCompositionLayerImageLayoutFlagsFB +static const XrCompositionLayerImageLayoutFlagsFB XR_COMPOSITION_LAYER_IMAGE_LAYOUT_VERTICAL_FLIP_BIT_FB = 0x00000001; + +// XrCompositionLayerImageLayoutFB extends XrCompositionLayerBaseHeader +typedef struct XrCompositionLayerImageLayoutFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrCompositionLayerImageLayoutFlagsFB flags; +} XrCompositionLayerImageLayoutFB; + + + +#define XR_FB_composition_layer_alpha_blend 1 +#define XR_FB_composition_layer_alpha_blend_SPEC_VERSION 2 +#define XR_FB_COMPOSITION_LAYER_ALPHA_BLEND_EXTENSION_NAME "XR_FB_composition_layer_alpha_blend" + +typedef enum XrBlendFactorFB { + XR_BLEND_FACTOR_ZERO_FB = 0, + XR_BLEND_FACTOR_ONE_FB = 1, + XR_BLEND_FACTOR_SRC_ALPHA_FB = 2, + XR_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA_FB = 3, + XR_BLEND_FACTOR_DST_ALPHA_FB = 4, + XR_BLEND_FACTOR_ONE_MINUS_DST_ALPHA_FB = 5, + XR_BLEND_FACTOR_MAX_ENUM_FB = 0x7FFFFFFF +} XrBlendFactorFB; +// XrCompositionLayerAlphaBlendFB extends XrCompositionLayerBaseHeader +typedef struct XrCompositionLayerAlphaBlendFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBlendFactorFB srcFactorColor; + XrBlendFactorFB dstFactorColor; + XrBlendFactorFB srcFactorAlpha; + XrBlendFactorFB dstFactorAlpha; +} XrCompositionLayerAlphaBlendFB; + + + +#define XR_MND_headless 1 +#define XR_MND_headless_SPEC_VERSION 2 +#define XR_MND_HEADLESS_EXTENSION_NAME "XR_MND_headless" + + +#define XR_OCULUS_android_session_state_enable 1 +#define XR_OCULUS_android_session_state_enable_SPEC_VERSION 1 +#define XR_OCULUS_ANDROID_SESSION_STATE_ENABLE_EXTENSION_NAME "XR_OCULUS_android_session_state_enable" + + +#define XR_EXT_view_configuration_depth_range 1 +#define XR_EXT_view_configuration_depth_range_SPEC_VERSION 1 +#define XR_EXT_VIEW_CONFIGURATION_DEPTH_RANGE_EXTENSION_NAME "XR_EXT_view_configuration_depth_range" +// XrViewConfigurationDepthRangeEXT extends XrViewConfigurationView +typedef struct XrViewConfigurationDepthRangeEXT { + XrStructureType type; + void* XR_MAY_ALIAS next; + float recommendedNearZ; + float minNearZ; + float recommendedFarZ; + float maxFarZ; +} XrViewConfigurationDepthRangeEXT; + + + +#define XR_EXT_conformance_automation 1 +#define XR_EXT_conformance_automation_SPEC_VERSION 3 +#define XR_EXT_CONFORMANCE_AUTOMATION_EXTENSION_NAME "XR_EXT_conformance_automation" +typedef XrResult (XRAPI_PTR *PFN_xrSetInputDeviceActiveEXT)(XrSession session, XrPath interactionProfile, XrPath topLevelPath, XrBool32 isActive); +typedef XrResult (XRAPI_PTR *PFN_xrSetInputDeviceStateBoolEXT)(XrSession session, XrPath topLevelPath, XrPath inputSourcePath, XrBool32 state); +typedef XrResult (XRAPI_PTR *PFN_xrSetInputDeviceStateFloatEXT)(XrSession session, XrPath topLevelPath, XrPath inputSourcePath, float state); +typedef XrResult (XRAPI_PTR *PFN_xrSetInputDeviceStateVector2fEXT)(XrSession session, XrPath topLevelPath, XrPath inputSourcePath, XrVector2f state); +typedef XrResult (XRAPI_PTR *PFN_xrSetInputDeviceLocationEXT)(XrSession session, XrPath topLevelPath, XrPath inputSourcePath, XrSpace space, XrPosef pose); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetInputDeviceActiveEXT( + XrSession session, + XrPath interactionProfile, + XrPath topLevelPath, + XrBool32 isActive); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetInputDeviceStateBoolEXT( + XrSession session, + XrPath topLevelPath, + XrPath inputSourcePath, + XrBool32 state); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetInputDeviceStateFloatEXT( + XrSession session, + XrPath topLevelPath, + XrPath inputSourcePath, + float state); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetInputDeviceStateVector2fEXT( + XrSession session, + XrPath topLevelPath, + XrPath inputSourcePath, + XrVector2f state); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetInputDeviceLocationEXT( + XrSession session, + XrPath topLevelPath, + XrPath inputSourcePath, + XrSpace space, + XrPosef pose); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_MSFT_spatial_graph_bridge 1 +#define XR_MSFT_spatial_graph_bridge_SPEC_VERSION 1 +#define XR_MSFT_SPATIAL_GRAPH_BRIDGE_EXTENSION_NAME "XR_MSFT_spatial_graph_bridge" + +typedef enum XrSpatialGraphNodeTypeMSFT { + XR_SPATIAL_GRAPH_NODE_TYPE_STATIC_MSFT = 1, + XR_SPATIAL_GRAPH_NODE_TYPE_DYNAMIC_MSFT = 2, + XR_SPATIAL_GRAPH_NODE_TYPE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrSpatialGraphNodeTypeMSFT; +typedef struct XrSpatialGraphNodeSpaceCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpatialGraphNodeTypeMSFT nodeType; + uint8_t nodeId[16]; + XrPosef pose; +} XrSpatialGraphNodeSpaceCreateInfoMSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialGraphNodeSpaceMSFT)(XrSession session, const XrSpatialGraphNodeSpaceCreateInfoMSFT* createInfo, XrSpace* space); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialGraphNodeSpaceMSFT( + XrSession session, + const XrSpatialGraphNodeSpaceCreateInfoMSFT* createInfo, + XrSpace* space); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_MSFT_hand_interaction 1 +#define XR_MSFT_hand_interaction_SPEC_VERSION 1 +#define XR_MSFT_HAND_INTERACTION_EXTENSION_NAME "XR_MSFT_hand_interaction" + + +#define XR_EXT_hand_tracking 1 + +#define XR_HAND_JOINT_COUNT_EXT 26 + +XR_DEFINE_HANDLE(XrHandTrackerEXT) +#define XR_EXT_hand_tracking_SPEC_VERSION 4 +#define XR_EXT_HAND_TRACKING_EXTENSION_NAME "XR_EXT_hand_tracking" + +typedef enum XrHandEXT { + XR_HAND_LEFT_EXT = 1, + XR_HAND_RIGHT_EXT = 2, + XR_HAND_MAX_ENUM_EXT = 0x7FFFFFFF +} XrHandEXT; + +typedef enum XrHandJointEXT { + XR_HAND_JOINT_PALM_EXT = 0, + XR_HAND_JOINT_WRIST_EXT = 1, + XR_HAND_JOINT_THUMB_METACARPAL_EXT = 2, + XR_HAND_JOINT_THUMB_PROXIMAL_EXT = 3, + XR_HAND_JOINT_THUMB_DISTAL_EXT = 4, + XR_HAND_JOINT_THUMB_TIP_EXT = 5, + XR_HAND_JOINT_INDEX_METACARPAL_EXT = 6, + XR_HAND_JOINT_INDEX_PROXIMAL_EXT = 7, + XR_HAND_JOINT_INDEX_INTERMEDIATE_EXT = 8, + XR_HAND_JOINT_INDEX_DISTAL_EXT = 9, + XR_HAND_JOINT_INDEX_TIP_EXT = 10, + XR_HAND_JOINT_MIDDLE_METACARPAL_EXT = 11, + XR_HAND_JOINT_MIDDLE_PROXIMAL_EXT = 12, + XR_HAND_JOINT_MIDDLE_INTERMEDIATE_EXT = 13, + XR_HAND_JOINT_MIDDLE_DISTAL_EXT = 14, + XR_HAND_JOINT_MIDDLE_TIP_EXT = 15, + XR_HAND_JOINT_RING_METACARPAL_EXT = 16, + XR_HAND_JOINT_RING_PROXIMAL_EXT = 17, + XR_HAND_JOINT_RING_INTERMEDIATE_EXT = 18, + XR_HAND_JOINT_RING_DISTAL_EXT = 19, + XR_HAND_JOINT_RING_TIP_EXT = 20, + XR_HAND_JOINT_LITTLE_METACARPAL_EXT = 21, + XR_HAND_JOINT_LITTLE_PROXIMAL_EXT = 22, + XR_HAND_JOINT_LITTLE_INTERMEDIATE_EXT = 23, + XR_HAND_JOINT_LITTLE_DISTAL_EXT = 24, + XR_HAND_JOINT_LITTLE_TIP_EXT = 25, + XR_HAND_JOINT_MAX_ENUM_EXT = 0x7FFFFFFF +} XrHandJointEXT; + +typedef enum XrHandJointSetEXT { + XR_HAND_JOINT_SET_DEFAULT_EXT = 0, + XR_HAND_JOINT_SET_MAX_ENUM_EXT = 0x7FFFFFFF +} XrHandJointSetEXT; +// XrSystemHandTrackingPropertiesEXT extends XrSystemProperties +typedef struct XrSystemHandTrackingPropertiesEXT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsHandTracking; +} XrSystemHandTrackingPropertiesEXT; + +typedef struct XrHandTrackerCreateInfoEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrHandEXT hand; + XrHandJointSetEXT handJointSet; +} XrHandTrackerCreateInfoEXT; + +typedef struct XrHandJointsLocateInfoEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace baseSpace; + XrTime time; +} XrHandJointsLocateInfoEXT; + +typedef struct XrHandJointLocationEXT { + XrSpaceLocationFlags locationFlags; + XrPosef pose; + float radius; +} XrHandJointLocationEXT; + +typedef struct XrHandJointVelocityEXT { + XrSpaceVelocityFlags velocityFlags; + XrVector3f linearVelocity; + XrVector3f angularVelocity; +} XrHandJointVelocityEXT; + +typedef struct XrHandJointLocationsEXT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 isActive; + uint32_t jointCount; + XrHandJointLocationEXT* jointLocations; +} XrHandJointLocationsEXT; + +// XrHandJointVelocitiesEXT extends XrHandJointLocationsEXT +typedef struct XrHandJointVelocitiesEXT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t jointCount; + XrHandJointVelocityEXT* jointVelocities; +} XrHandJointVelocitiesEXT; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateHandTrackerEXT)(XrSession session, const XrHandTrackerCreateInfoEXT* createInfo, XrHandTrackerEXT* handTracker); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyHandTrackerEXT)(XrHandTrackerEXT handTracker); +typedef XrResult (XRAPI_PTR *PFN_xrLocateHandJointsEXT)(XrHandTrackerEXT handTracker, const XrHandJointsLocateInfoEXT* locateInfo, XrHandJointLocationsEXT* locations); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateHandTrackerEXT( + XrSession session, + const XrHandTrackerCreateInfoEXT* createInfo, + XrHandTrackerEXT* handTracker); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyHandTrackerEXT( + XrHandTrackerEXT handTracker); + +XRAPI_ATTR XrResult XRAPI_CALL xrLocateHandJointsEXT( + XrHandTrackerEXT handTracker, + const XrHandJointsLocateInfoEXT* locateInfo, + XrHandJointLocationsEXT* locations); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_MSFT_hand_tracking_mesh 1 +#define XR_MSFT_hand_tracking_mesh_SPEC_VERSION 4 +#define XR_MSFT_HAND_TRACKING_MESH_EXTENSION_NAME "XR_MSFT_hand_tracking_mesh" + +typedef enum XrHandPoseTypeMSFT { + XR_HAND_POSE_TYPE_TRACKED_MSFT = 0, + XR_HAND_POSE_TYPE_REFERENCE_OPEN_PALM_MSFT = 1, + XR_HAND_POSE_TYPE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrHandPoseTypeMSFT; +// XrSystemHandTrackingMeshPropertiesMSFT extends XrSystemProperties +typedef struct XrSystemHandTrackingMeshPropertiesMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsHandTrackingMesh; + uint32_t maxHandMeshIndexCount; + uint32_t maxHandMeshVertexCount; +} XrSystemHandTrackingMeshPropertiesMSFT; + +typedef struct XrHandMeshSpaceCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrHandPoseTypeMSFT handPoseType; + XrPosef poseInHandMeshSpace; +} XrHandMeshSpaceCreateInfoMSFT; + +typedef struct XrHandMeshUpdateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrTime time; + XrHandPoseTypeMSFT handPoseType; +} XrHandMeshUpdateInfoMSFT; + +typedef struct XrHandMeshIndexBufferMSFT { + uint32_t indexBufferKey; + uint32_t indexCapacityInput; + uint32_t indexCountOutput; + uint32_t* indices; +} XrHandMeshIndexBufferMSFT; + +typedef struct XrHandMeshVertexMSFT { + XrVector3f position; + XrVector3f normal; +} XrHandMeshVertexMSFT; + +typedef struct XrHandMeshVertexBufferMSFT { + XrTime vertexUpdateTime; + uint32_t vertexCapacityInput; + uint32_t vertexCountOutput; + XrHandMeshVertexMSFT* vertices; +} XrHandMeshVertexBufferMSFT; + +typedef struct XrHandMeshMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 isActive; + XrBool32 indexBufferChanged; + XrBool32 vertexBufferChanged; + XrHandMeshIndexBufferMSFT indexBuffer; + XrHandMeshVertexBufferMSFT vertexBuffer; +} XrHandMeshMSFT; + +// XrHandPoseTypeInfoMSFT extends XrHandTrackerCreateInfoEXT +typedef struct XrHandPoseTypeInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrHandPoseTypeMSFT handPoseType; +} XrHandPoseTypeInfoMSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateHandMeshSpaceMSFT)(XrHandTrackerEXT handTracker, const XrHandMeshSpaceCreateInfoMSFT* createInfo, XrSpace* space); +typedef XrResult (XRAPI_PTR *PFN_xrUpdateHandMeshMSFT)(XrHandTrackerEXT handTracker, const XrHandMeshUpdateInfoMSFT* updateInfo, XrHandMeshMSFT* handMesh); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateHandMeshSpaceMSFT( + XrHandTrackerEXT handTracker, + const XrHandMeshSpaceCreateInfoMSFT* createInfo, + XrSpace* space); + +XRAPI_ATTR XrResult XRAPI_CALL xrUpdateHandMeshMSFT( + XrHandTrackerEXT handTracker, + const XrHandMeshUpdateInfoMSFT* updateInfo, + XrHandMeshMSFT* handMesh); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_MSFT_secondary_view_configuration 1 +#define XR_MSFT_secondary_view_configuration_SPEC_VERSION 1 +#define XR_MSFT_SECONDARY_VIEW_CONFIGURATION_EXTENSION_NAME "XR_MSFT_secondary_view_configuration" +// XrSecondaryViewConfigurationSessionBeginInfoMSFT extends XrSessionBeginInfo +typedef struct XrSecondaryViewConfigurationSessionBeginInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t viewConfigurationCount; + const XrViewConfigurationType* enabledViewConfigurationTypes; +} XrSecondaryViewConfigurationSessionBeginInfoMSFT; + +typedef struct XrSecondaryViewConfigurationStateMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrViewConfigurationType viewConfigurationType; + XrBool32 active; +} XrSecondaryViewConfigurationStateMSFT; + +// XrSecondaryViewConfigurationFrameStateMSFT extends XrFrameState +typedef struct XrSecondaryViewConfigurationFrameStateMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t viewConfigurationCount; + XrSecondaryViewConfigurationStateMSFT* viewConfigurationStates; +} XrSecondaryViewConfigurationFrameStateMSFT; + +typedef struct XrSecondaryViewConfigurationLayerInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrViewConfigurationType viewConfigurationType; + XrEnvironmentBlendMode environmentBlendMode; + uint32_t layerCount; + const XrCompositionLayerBaseHeader* const* layers; +} XrSecondaryViewConfigurationLayerInfoMSFT; + +// XrSecondaryViewConfigurationFrameEndInfoMSFT extends XrFrameEndInfo +typedef struct XrSecondaryViewConfigurationFrameEndInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t viewConfigurationCount; + const XrSecondaryViewConfigurationLayerInfoMSFT* viewConfigurationLayersInfo; +} XrSecondaryViewConfigurationFrameEndInfoMSFT; + +// XrSecondaryViewConfigurationSwapchainCreateInfoMSFT extends XrSwapchainCreateInfo +typedef struct XrSecondaryViewConfigurationSwapchainCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrViewConfigurationType viewConfigurationType; +} XrSecondaryViewConfigurationSwapchainCreateInfoMSFT; + + + +#define XR_MSFT_first_person_observer 1 +#define XR_MSFT_first_person_observer_SPEC_VERSION 1 +#define XR_MSFT_FIRST_PERSON_OBSERVER_EXTENSION_NAME "XR_MSFT_first_person_observer" + + +#define XR_MSFT_controller_model 1 + +#define XR_NULL_CONTROLLER_MODEL_KEY_MSFT 0 + +XR_DEFINE_ATOM(XrControllerModelKeyMSFT) +#define XR_MSFT_controller_model_SPEC_VERSION 2 +#define XR_MSFT_CONTROLLER_MODEL_EXTENSION_NAME "XR_MSFT_controller_model" +#define XR_MAX_CONTROLLER_MODEL_NODE_NAME_SIZE_MSFT 64 +typedef struct XrControllerModelKeyStateMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrControllerModelKeyMSFT modelKey; +} XrControllerModelKeyStateMSFT; + +typedef struct XrControllerModelNodePropertiesMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + char parentNodeName[XR_MAX_CONTROLLER_MODEL_NODE_NAME_SIZE_MSFT]; + char nodeName[XR_MAX_CONTROLLER_MODEL_NODE_NAME_SIZE_MSFT]; +} XrControllerModelNodePropertiesMSFT; + +typedef struct XrControllerModelPropertiesMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t nodeCapacityInput; + uint32_t nodeCountOutput; + XrControllerModelNodePropertiesMSFT* nodeProperties; +} XrControllerModelPropertiesMSFT; + +typedef struct XrControllerModelNodeStateMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrPosef nodePose; +} XrControllerModelNodeStateMSFT; + +typedef struct XrControllerModelStateMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t nodeCapacityInput; + uint32_t nodeCountOutput; + XrControllerModelNodeStateMSFT* nodeStates; +} XrControllerModelStateMSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrGetControllerModelKeyMSFT)(XrSession session, XrPath topLevelUserPath, XrControllerModelKeyStateMSFT* controllerModelKeyState); +typedef XrResult (XRAPI_PTR *PFN_xrLoadControllerModelMSFT)(XrSession session, XrControllerModelKeyMSFT modelKey, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, uint8_t* buffer); +typedef XrResult (XRAPI_PTR *PFN_xrGetControllerModelPropertiesMSFT)(XrSession session, XrControllerModelKeyMSFT modelKey, XrControllerModelPropertiesMSFT* properties); +typedef XrResult (XRAPI_PTR *PFN_xrGetControllerModelStateMSFT)(XrSession session, XrControllerModelKeyMSFT modelKey, XrControllerModelStateMSFT* state); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetControllerModelKeyMSFT( + XrSession session, + XrPath topLevelUserPath, + XrControllerModelKeyStateMSFT* controllerModelKeyState); + +XRAPI_ATTR XrResult XRAPI_CALL xrLoadControllerModelMSFT( + XrSession session, + XrControllerModelKeyMSFT modelKey, + uint32_t bufferCapacityInput, + uint32_t* bufferCountOutput, + uint8_t* buffer); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetControllerModelPropertiesMSFT( + XrSession session, + XrControllerModelKeyMSFT modelKey, + XrControllerModelPropertiesMSFT* properties); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetControllerModelStateMSFT( + XrSession session, + XrControllerModelKeyMSFT modelKey, + XrControllerModelStateMSFT* state); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_EXT_win32_appcontainer_compatible 1 +#define XR_EXT_win32_appcontainer_compatible_SPEC_VERSION 1 +#define XR_EXT_WIN32_APPCONTAINER_COMPATIBLE_EXTENSION_NAME "XR_EXT_win32_appcontainer_compatible" + + +#define XR_EPIC_view_configuration_fov 1 +#define XR_EPIC_view_configuration_fov_SPEC_VERSION 2 +#define XR_EPIC_VIEW_CONFIGURATION_FOV_EXTENSION_NAME "XR_EPIC_view_configuration_fov" +// XrViewConfigurationViewFovEPIC extends XrViewConfigurationView +typedef struct XrViewConfigurationViewFovEPIC { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrFovf recommendedFov; + XrFovf maxMutableFov; +} XrViewConfigurationViewFovEPIC; + + + +#define XR_MSFT_composition_layer_reprojection 1 +#define XR_MSFT_composition_layer_reprojection_SPEC_VERSION 1 +#define XR_MSFT_COMPOSITION_LAYER_REPROJECTION_EXTENSION_NAME "XR_MSFT_composition_layer_reprojection" + +typedef enum XrReprojectionModeMSFT { + XR_REPROJECTION_MODE_DEPTH_MSFT = 1, + XR_REPROJECTION_MODE_PLANAR_FROM_DEPTH_MSFT = 2, + XR_REPROJECTION_MODE_PLANAR_MANUAL_MSFT = 3, + XR_REPROJECTION_MODE_ORIENTATION_ONLY_MSFT = 4, + XR_REPROJECTION_MODE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrReprojectionModeMSFT; +// XrCompositionLayerReprojectionInfoMSFT extends XrCompositionLayerProjection +typedef struct XrCompositionLayerReprojectionInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrReprojectionModeMSFT reprojectionMode; +} XrCompositionLayerReprojectionInfoMSFT; + +// XrCompositionLayerReprojectionPlaneOverrideMSFT extends XrCompositionLayerProjection +typedef struct XrCompositionLayerReprojectionPlaneOverrideMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrVector3f position; + XrVector3f normal; + XrVector3f velocity; +} XrCompositionLayerReprojectionPlaneOverrideMSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateReprojectionModesMSFT)(XrInstance instance, XrSystemId systemId, XrViewConfigurationType viewConfigurationType, uint32_t modeCapacityInput, uint32_t* modeCountOutput, XrReprojectionModeMSFT* modes); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateReprojectionModesMSFT( + XrInstance instance, + XrSystemId systemId, + XrViewConfigurationType viewConfigurationType, + uint32_t modeCapacityInput, + uint32_t* modeCountOutput, + XrReprojectionModeMSFT* modes); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_HUAWEI_controller_interaction 1 +#define XR_HUAWEI_controller_interaction_SPEC_VERSION 1 +#define XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_HUAWEI_controller_interaction" + + +#define XR_FB_swapchain_update_state 1 +#define XR_FB_swapchain_update_state_SPEC_VERSION 3 +#define XR_FB_SWAPCHAIN_UPDATE_STATE_EXTENSION_NAME "XR_FB_swapchain_update_state" +typedef struct XR_MAY_ALIAS XrSwapchainStateBaseHeaderFB { + XrStructureType type; + void* XR_MAY_ALIAS next; +} XrSwapchainStateBaseHeaderFB; + +typedef XrResult (XRAPI_PTR *PFN_xrUpdateSwapchainFB)(XrSwapchain swapchain, const XrSwapchainStateBaseHeaderFB* state); +typedef XrResult (XRAPI_PTR *PFN_xrGetSwapchainStateFB)(XrSwapchain swapchain, XrSwapchainStateBaseHeaderFB* state); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrUpdateSwapchainFB( + XrSwapchain swapchain, + const XrSwapchainStateBaseHeaderFB* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSwapchainStateFB( + XrSwapchain swapchain, + XrSwapchainStateBaseHeaderFB* state); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_composition_layer_secure_content 1 +#define XR_FB_composition_layer_secure_content_SPEC_VERSION 1 +#define XR_FB_COMPOSITION_LAYER_SECURE_CONTENT_EXTENSION_NAME "XR_FB_composition_layer_secure_content" +typedef XrFlags64 XrCompositionLayerSecureContentFlagsFB; + +// Flag bits for XrCompositionLayerSecureContentFlagsFB +static const XrCompositionLayerSecureContentFlagsFB XR_COMPOSITION_LAYER_SECURE_CONTENT_EXCLUDE_LAYER_BIT_FB = 0x00000001; +static const XrCompositionLayerSecureContentFlagsFB XR_COMPOSITION_LAYER_SECURE_CONTENT_REPLACE_LAYER_BIT_FB = 0x00000002; + +// XrCompositionLayerSecureContentFB extends XrCompositionLayerBaseHeader +typedef struct XrCompositionLayerSecureContentFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerSecureContentFlagsFB flags; +} XrCompositionLayerSecureContentFB; + + + +#define XR_VALVE_analog_threshold 1 +#define XR_VALVE_analog_threshold_SPEC_VERSION 2 +#define XR_VALVE_ANALOG_THRESHOLD_EXTENSION_NAME "XR_VALVE_analog_threshold" +typedef struct XrInteractionProfileAnalogThresholdVALVE { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAction action; + XrPath binding; + float onThreshold; + float offThreshold; + const XrHapticBaseHeader* onHaptic; + const XrHapticBaseHeader* offHaptic; +} XrInteractionProfileAnalogThresholdVALVE; + + + +#define XR_EXT_hand_joints_motion_range 1 +#define XR_EXT_hand_joints_motion_range_SPEC_VERSION 1 +#define XR_EXT_HAND_JOINTS_MOTION_RANGE_EXTENSION_NAME "XR_EXT_hand_joints_motion_range" + +typedef enum XrHandJointsMotionRangeEXT { + XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT = 1, + XR_HAND_JOINTS_MOTION_RANGE_CONFORMING_TO_CONTROLLER_EXT = 2, + XR_HAND_JOINTS_MOTION_RANGE_MAX_ENUM_EXT = 0x7FFFFFFF +} XrHandJointsMotionRangeEXT; +// XrHandJointsMotionRangeInfoEXT extends XrHandJointsLocateInfoEXT +typedef struct XrHandJointsMotionRangeInfoEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrHandJointsMotionRangeEXT handJointsMotionRange; +} XrHandJointsMotionRangeInfoEXT; + + + +#define XR_EXT_samsung_odyssey_controller 1 +#define XR_EXT_samsung_odyssey_controller_SPEC_VERSION 1 +#define XR_EXT_SAMSUNG_ODYSSEY_CONTROLLER_EXTENSION_NAME "XR_EXT_samsung_odyssey_controller" + + +#define XR_EXT_hp_mixed_reality_controller 1 +#define XR_EXT_hp_mixed_reality_controller_SPEC_VERSION 1 +#define XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME "XR_EXT_hp_mixed_reality_controller" + + +#define XR_MND_swapchain_usage_input_attachment_bit 1 +#define XR_MND_swapchain_usage_input_attachment_bit_SPEC_VERSION 2 +#define XR_MND_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_EXTENSION_NAME "XR_MND_swapchain_usage_input_attachment_bit" + + +#define XR_MSFT_scene_understanding 1 + + XR_DEFINE_HANDLE(XrSceneObserverMSFT) + + + XR_DEFINE_HANDLE(XrSceneMSFT) + +#define XR_MSFT_scene_understanding_SPEC_VERSION 1 +#define XR_MSFT_SCENE_UNDERSTANDING_EXTENSION_NAME "XR_MSFT_scene_understanding" + +typedef enum XrSceneComputeFeatureMSFT { + XR_SCENE_COMPUTE_FEATURE_PLANE_MSFT = 1, + XR_SCENE_COMPUTE_FEATURE_PLANE_MESH_MSFT = 2, + XR_SCENE_COMPUTE_FEATURE_VISUAL_MESH_MSFT = 3, + XR_SCENE_COMPUTE_FEATURE_COLLIDER_MESH_MSFT = 4, + XR_SCENE_COMPUTE_FEATURE_SERIALIZE_SCENE_MSFT = 1000098000, + XR_SCENE_COMPUTE_FEATURE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrSceneComputeFeatureMSFT; + +typedef enum XrSceneComputeConsistencyMSFT { + XR_SCENE_COMPUTE_CONSISTENCY_SNAPSHOT_COMPLETE_MSFT = 1, + XR_SCENE_COMPUTE_CONSISTENCY_SNAPSHOT_INCOMPLETE_FAST_MSFT = 2, + XR_SCENE_COMPUTE_CONSISTENCY_OCCLUSION_OPTIMIZED_MSFT = 3, + XR_SCENE_COMPUTE_CONSISTENCY_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrSceneComputeConsistencyMSFT; + +typedef enum XrMeshComputeLodMSFT { + XR_MESH_COMPUTE_LOD_COARSE_MSFT = 1, + XR_MESH_COMPUTE_LOD_MEDIUM_MSFT = 2, + XR_MESH_COMPUTE_LOD_FINE_MSFT = 3, + XR_MESH_COMPUTE_LOD_UNLIMITED_MSFT = 4, + XR_MESH_COMPUTE_LOD_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrMeshComputeLodMSFT; + +typedef enum XrSceneComponentTypeMSFT { + XR_SCENE_COMPONENT_TYPE_INVALID_MSFT = -1, + XR_SCENE_COMPONENT_TYPE_OBJECT_MSFT = 1, + XR_SCENE_COMPONENT_TYPE_PLANE_MSFT = 2, + XR_SCENE_COMPONENT_TYPE_VISUAL_MESH_MSFT = 3, + XR_SCENE_COMPONENT_TYPE_COLLIDER_MESH_MSFT = 4, + XR_SCENE_COMPONENT_TYPE_SERIALIZED_SCENE_FRAGMENT_MSFT = 1000098000, + XR_SCENE_COMPONENT_TYPE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrSceneComponentTypeMSFT; + +typedef enum XrSceneObjectTypeMSFT { + XR_SCENE_OBJECT_TYPE_UNCATEGORIZED_MSFT = -1, + XR_SCENE_OBJECT_TYPE_BACKGROUND_MSFT = 1, + XR_SCENE_OBJECT_TYPE_WALL_MSFT = 2, + XR_SCENE_OBJECT_TYPE_FLOOR_MSFT = 3, + XR_SCENE_OBJECT_TYPE_CEILING_MSFT = 4, + XR_SCENE_OBJECT_TYPE_PLATFORM_MSFT = 5, + XR_SCENE_OBJECT_TYPE_INFERRED_MSFT = 6, + XR_SCENE_OBJECT_TYPE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrSceneObjectTypeMSFT; + +typedef enum XrScenePlaneAlignmentTypeMSFT { + XR_SCENE_PLANE_ALIGNMENT_TYPE_NON_ORTHOGONAL_MSFT = 0, + XR_SCENE_PLANE_ALIGNMENT_TYPE_HORIZONTAL_MSFT = 1, + XR_SCENE_PLANE_ALIGNMENT_TYPE_VERTICAL_MSFT = 2, + XR_SCENE_PLANE_ALIGNMENT_TYPE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrScenePlaneAlignmentTypeMSFT; + +typedef enum XrSceneComputeStateMSFT { + XR_SCENE_COMPUTE_STATE_NONE_MSFT = 0, + XR_SCENE_COMPUTE_STATE_UPDATING_MSFT = 1, + XR_SCENE_COMPUTE_STATE_COMPLETED_MSFT = 2, + XR_SCENE_COMPUTE_STATE_COMPLETED_WITH_ERROR_MSFT = 3, + XR_SCENE_COMPUTE_STATE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrSceneComputeStateMSFT; +typedef struct XrUuidMSFT { + uint8_t bytes[16]; +} XrUuidMSFT; + +typedef struct XrSceneObserverCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSceneObserverCreateInfoMSFT; + +typedef struct XrSceneCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSceneCreateInfoMSFT; + +typedef struct XrSceneSphereBoundMSFT { + XrVector3f center; + float radius; +} XrSceneSphereBoundMSFT; + +typedef struct XrSceneOrientedBoxBoundMSFT { + XrPosef pose; + XrVector3f extents; +} XrSceneOrientedBoxBoundMSFT; + +typedef struct XrSceneFrustumBoundMSFT { + XrPosef pose; + XrFovf fov; + float farDistance; +} XrSceneFrustumBoundMSFT; + +typedef struct XrSceneBoundsMSFT { + XrSpace space; + XrTime time; + uint32_t sphereCount; + const XrSceneSphereBoundMSFT* spheres; + uint32_t boxCount; + const XrSceneOrientedBoxBoundMSFT* boxes; + uint32_t frustumCount; + const XrSceneFrustumBoundMSFT* frustums; +} XrSceneBoundsMSFT; + +typedef struct XrNewSceneComputeInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t requestedFeatureCount; + const XrSceneComputeFeatureMSFT* requestedFeatures; + XrSceneComputeConsistencyMSFT consistency; + XrSceneBoundsMSFT bounds; +} XrNewSceneComputeInfoMSFT; + +// XrVisualMeshComputeLodInfoMSFT extends XrNewSceneComputeInfoMSFT +typedef struct XrVisualMeshComputeLodInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrMeshComputeLodMSFT lod; +} XrVisualMeshComputeLodInfoMSFT; + +typedef struct XrSceneComponentMSFT { + XrSceneComponentTypeMSFT componentType; + XrUuidMSFT id; + XrUuidMSFT parentId; + XrTime updateTime; +} XrSceneComponentMSFT; + +typedef struct XrSceneComponentsMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t componentCapacityInput; + uint32_t componentCountOutput; + XrSceneComponentMSFT* components; +} XrSceneComponentsMSFT; + +typedef struct XrSceneComponentsGetInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSceneComponentTypeMSFT componentType; +} XrSceneComponentsGetInfoMSFT; + +typedef struct XrSceneComponentLocationMSFT { + XrSpaceLocationFlags flags; + XrPosef pose; +} XrSceneComponentLocationMSFT; + +typedef struct XrSceneComponentLocationsMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t locationCount; + XrSceneComponentLocationMSFT* locations; +} XrSceneComponentLocationsMSFT; + +typedef struct XrSceneComponentsLocateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace baseSpace; + XrTime time; + uint32_t componentIdCount; + const XrUuidMSFT* componentIds; +} XrSceneComponentsLocateInfoMSFT; + +typedef struct XrSceneObjectMSFT { + XrSceneObjectTypeMSFT objectType; +} XrSceneObjectMSFT; + +// XrSceneObjectsMSFT extends XrSceneComponentsMSFT +typedef struct XrSceneObjectsMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t sceneObjectCount; + XrSceneObjectMSFT* sceneObjects; +} XrSceneObjectsMSFT; + +// XrSceneComponentParentFilterInfoMSFT extends XrSceneComponentsGetInfoMSFT +typedef struct XrSceneComponentParentFilterInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrUuidMSFT parentId; +} XrSceneComponentParentFilterInfoMSFT; + +// XrSceneObjectTypesFilterInfoMSFT extends XrSceneComponentsGetInfoMSFT +typedef struct XrSceneObjectTypesFilterInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t objectTypeCount; + const XrSceneObjectTypeMSFT* objectTypes; +} XrSceneObjectTypesFilterInfoMSFT; + +typedef struct XrScenePlaneMSFT { + XrScenePlaneAlignmentTypeMSFT alignment; + XrExtent2Df size; + uint64_t meshBufferId; + XrBool32 supportsIndicesUint16; +} XrScenePlaneMSFT; + +// XrScenePlanesMSFT extends XrSceneComponentsMSFT +typedef struct XrScenePlanesMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t scenePlaneCount; + XrScenePlaneMSFT* scenePlanes; +} XrScenePlanesMSFT; + +// XrScenePlaneAlignmentFilterInfoMSFT extends XrSceneComponentsGetInfoMSFT +typedef struct XrScenePlaneAlignmentFilterInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t alignmentCount; + const XrScenePlaneAlignmentTypeMSFT* alignments; +} XrScenePlaneAlignmentFilterInfoMSFT; + +typedef struct XrSceneMeshMSFT { + uint64_t meshBufferId; + XrBool32 supportsIndicesUint16; +} XrSceneMeshMSFT; + +// XrSceneMeshesMSFT extends XrSceneComponentsMSFT +typedef struct XrSceneMeshesMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t sceneMeshCount; + XrSceneMeshMSFT* sceneMeshes; +} XrSceneMeshesMSFT; + +typedef struct XrSceneMeshBuffersGetInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint64_t meshBufferId; +} XrSceneMeshBuffersGetInfoMSFT; + +typedef struct XrSceneMeshBuffersMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; +} XrSceneMeshBuffersMSFT; + +typedef struct XrSceneMeshVertexBufferMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t vertexCapacityInput; + uint32_t vertexCountOutput; + XrVector3f* vertices; +} XrSceneMeshVertexBufferMSFT; + +typedef struct XrSceneMeshIndicesUint32MSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t indexCapacityInput; + uint32_t indexCountOutput; + uint32_t* indices; +} XrSceneMeshIndicesUint32MSFT; + +typedef struct XrSceneMeshIndicesUint16MSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t indexCapacityInput; + uint32_t indexCountOutput; + uint16_t* indices; +} XrSceneMeshIndicesUint16MSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateSceneComputeFeaturesMSFT)(XrInstance instance, XrSystemId systemId, uint32_t featureCapacityInput, uint32_t* featureCountOutput, XrSceneComputeFeatureMSFT* features); +typedef XrResult (XRAPI_PTR *PFN_xrCreateSceneObserverMSFT)(XrSession session, const XrSceneObserverCreateInfoMSFT* createInfo, XrSceneObserverMSFT* sceneObserver); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySceneObserverMSFT)(XrSceneObserverMSFT sceneObserver); +typedef XrResult (XRAPI_PTR *PFN_xrCreateSceneMSFT)(XrSceneObserverMSFT sceneObserver, const XrSceneCreateInfoMSFT* createInfo, XrSceneMSFT* scene); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySceneMSFT)(XrSceneMSFT scene); +typedef XrResult (XRAPI_PTR *PFN_xrComputeNewSceneMSFT)(XrSceneObserverMSFT sceneObserver, const XrNewSceneComputeInfoMSFT* computeInfo); +typedef XrResult (XRAPI_PTR *PFN_xrGetSceneComputeStateMSFT)(XrSceneObserverMSFT sceneObserver, XrSceneComputeStateMSFT* state); +typedef XrResult (XRAPI_PTR *PFN_xrGetSceneComponentsMSFT)(XrSceneMSFT scene, const XrSceneComponentsGetInfoMSFT* getInfo, XrSceneComponentsMSFT* components); +typedef XrResult (XRAPI_PTR *PFN_xrLocateSceneComponentsMSFT)(XrSceneMSFT scene, const XrSceneComponentsLocateInfoMSFT* locateInfo, XrSceneComponentLocationsMSFT* locations); +typedef XrResult (XRAPI_PTR *PFN_xrGetSceneMeshBuffersMSFT)(XrSceneMSFT scene, const XrSceneMeshBuffersGetInfoMSFT* getInfo, XrSceneMeshBuffersMSFT* buffers); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSceneComputeFeaturesMSFT( + XrInstance instance, + XrSystemId systemId, + uint32_t featureCapacityInput, + uint32_t* featureCountOutput, + XrSceneComputeFeatureMSFT* features); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSceneObserverMSFT( + XrSession session, + const XrSceneObserverCreateInfoMSFT* createInfo, + XrSceneObserverMSFT* sceneObserver); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySceneObserverMSFT( + XrSceneObserverMSFT sceneObserver); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSceneMSFT( + XrSceneObserverMSFT sceneObserver, + const XrSceneCreateInfoMSFT* createInfo, + XrSceneMSFT* scene); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySceneMSFT( + XrSceneMSFT scene); + +XRAPI_ATTR XrResult XRAPI_CALL xrComputeNewSceneMSFT( + XrSceneObserverMSFT sceneObserver, + const XrNewSceneComputeInfoMSFT* computeInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSceneComputeStateMSFT( + XrSceneObserverMSFT sceneObserver, + XrSceneComputeStateMSFT* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSceneComponentsMSFT( + XrSceneMSFT scene, + const XrSceneComponentsGetInfoMSFT* getInfo, + XrSceneComponentsMSFT* components); + +XRAPI_ATTR XrResult XRAPI_CALL xrLocateSceneComponentsMSFT( + XrSceneMSFT scene, + const XrSceneComponentsLocateInfoMSFT* locateInfo, + XrSceneComponentLocationsMSFT* locations); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSceneMeshBuffersMSFT( + XrSceneMSFT scene, + const XrSceneMeshBuffersGetInfoMSFT* getInfo, + XrSceneMeshBuffersMSFT* buffers); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_MSFT_scene_understanding_serialization 1 +#define XR_MSFT_scene_understanding_serialization_SPEC_VERSION 1 +#define XR_MSFT_SCENE_UNDERSTANDING_SERIALIZATION_EXTENSION_NAME "XR_MSFT_scene_understanding_serialization" +typedef struct XrSerializedSceneFragmentDataGetInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrUuidMSFT sceneFragmentId; +} XrSerializedSceneFragmentDataGetInfoMSFT; + +typedef struct XrDeserializeSceneFragmentMSFT { + uint32_t bufferSize; + const uint8_t* buffer; +} XrDeserializeSceneFragmentMSFT; + +typedef struct XrSceneDeserializeInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t fragmentCount; + const XrDeserializeSceneFragmentMSFT* fragments; +} XrSceneDeserializeInfoMSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrDeserializeSceneMSFT)(XrSceneObserverMSFT sceneObserver, const XrSceneDeserializeInfoMSFT* deserializeInfo); +typedef XrResult (XRAPI_PTR *PFN_xrGetSerializedSceneFragmentDataMSFT)(XrSceneMSFT scene, const XrSerializedSceneFragmentDataGetInfoMSFT* getInfo, uint32_t countInput, uint32_t* readOutput, uint8_t* buffer); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrDeserializeSceneMSFT( + XrSceneObserverMSFT sceneObserver, + const XrSceneDeserializeInfoMSFT* deserializeInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSerializedSceneFragmentDataMSFT( + XrSceneMSFT scene, + const XrSerializedSceneFragmentDataGetInfoMSFT* getInfo, + uint32_t countInput, + uint32_t* readOutput, + uint8_t* buffer); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_display_refresh_rate 1 +#define XR_FB_display_refresh_rate_SPEC_VERSION 1 +#define XR_FB_DISPLAY_REFRESH_RATE_EXTENSION_NAME "XR_FB_display_refresh_rate" +typedef struct XrEventDataDisplayRefreshRateChangedFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + float fromDisplayRefreshRate; + float toDisplayRefreshRate; +} XrEventDataDisplayRefreshRateChangedFB; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateDisplayRefreshRatesFB)(XrSession session, uint32_t displayRefreshRateCapacityInput, uint32_t* displayRefreshRateCountOutput, float* displayRefreshRates); +typedef XrResult (XRAPI_PTR *PFN_xrGetDisplayRefreshRateFB)(XrSession session, float* displayRefreshRate); +typedef XrResult (XRAPI_PTR *PFN_xrRequestDisplayRefreshRateFB)(XrSession session, float displayRefreshRate); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateDisplayRefreshRatesFB( + XrSession session, + uint32_t displayRefreshRateCapacityInput, + uint32_t* displayRefreshRateCountOutput, + float* displayRefreshRates); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetDisplayRefreshRateFB( + XrSession session, + float* displayRefreshRate); + +XRAPI_ATTR XrResult XRAPI_CALL xrRequestDisplayRefreshRateFB( + XrSession session, + float displayRefreshRate); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_HTC_vive_cosmos_controller_interaction 1 +#define XR_HTC_vive_cosmos_controller_interaction_SPEC_VERSION 1 +#define XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_HTC_vive_cosmos_controller_interaction" + + +#define XR_HTCX_vive_tracker_interaction 1 +#define XR_HTCX_vive_tracker_interaction_SPEC_VERSION 1 +#define XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME "XR_HTCX_vive_tracker_interaction" +typedef struct XrViveTrackerPathsHTCX { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrPath persistentPath; + XrPath rolePath; +} XrViveTrackerPathsHTCX; + +typedef struct XrEventDataViveTrackerConnectedHTCX { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrViveTrackerPathsHTCX* paths; +} XrEventDataViveTrackerConnectedHTCX; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateViveTrackerPathsHTCX)(XrInstance instance, uint32_t pathCapacityInput, uint32_t* pathCountOutput, XrViveTrackerPathsHTCX* paths); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateViveTrackerPathsHTCX( + XrInstance instance, + uint32_t pathCapacityInput, + uint32_t* pathCountOutput, + XrViveTrackerPathsHTCX* paths); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_HTC_facial_tracking 1 + +#define XR_FACIAL_EXPRESSION_EYE_COUNT_HTC 14 + + +#define XR_FACIAL_EXPRESSION_LIP_COUNT_HTC 37 + +XR_DEFINE_HANDLE(XrFacialTrackerHTC) +#define XR_HTC_facial_tracking_SPEC_VERSION 1 +#define XR_HTC_FACIAL_TRACKING_EXTENSION_NAME "XR_HTC_facial_tracking" + +typedef enum XrEyeExpressionHTC { + XR_EYE_EXPRESSION_LEFT_BLINK_HTC = 0, + XR_EYE_EXPRESSION_LEFT_WIDE_HTC = 1, + XR_EYE_EXPRESSION_RIGHT_BLINK_HTC = 2, + XR_EYE_EXPRESSION_RIGHT_WIDE_HTC = 3, + XR_EYE_EXPRESSION_LEFT_SQUEEZE_HTC = 4, + XR_EYE_EXPRESSION_RIGHT_SQUEEZE_HTC = 5, + XR_EYE_EXPRESSION_LEFT_DOWN_HTC = 6, + XR_EYE_EXPRESSION_RIGHT_DOWN_HTC = 7, + XR_EYE_EXPRESSION_LEFT_OUT_HTC = 8, + XR_EYE_EXPRESSION_RIGHT_IN_HTC = 9, + XR_EYE_EXPRESSION_LEFT_IN_HTC = 10, + XR_EYE_EXPRESSION_RIGHT_OUT_HTC = 11, + XR_EYE_EXPRESSION_LEFT_UP_HTC = 12, + XR_EYE_EXPRESSION_RIGHT_UP_HTC = 13, + XR_EYE_EXPRESSION_MAX_ENUM_HTC = 0x7FFFFFFF +} XrEyeExpressionHTC; + +typedef enum XrLipExpressionHTC { + XR_LIP_EXPRESSION_JAW_RIGHT_HTC = 0, + XR_LIP_EXPRESSION_JAW_LEFT_HTC = 1, + XR_LIP_EXPRESSION_JAW_FORWARD_HTC = 2, + XR_LIP_EXPRESSION_JAW_OPEN_HTC = 3, + XR_LIP_EXPRESSION_MOUTH_APE_SHAPE_HTC = 4, + XR_LIP_EXPRESSION_MOUTH_UPPER_RIGHT_HTC = 5, + XR_LIP_EXPRESSION_MOUTH_UPPER_LEFT_HTC = 6, + XR_LIP_EXPRESSION_MOUTH_LOWER_RIGHT_HTC = 7, + XR_LIP_EXPRESSION_MOUTH_LOWER_LEFT_HTC = 8, + XR_LIP_EXPRESSION_MOUTH_UPPER_OVERTURN_HTC = 9, + XR_LIP_EXPRESSION_MOUTH_LOWER_OVERTURN_HTC = 10, + XR_LIP_EXPRESSION_MOUTH_POUT_HTC = 11, + XR_LIP_EXPRESSION_MOUTH_SMILE_RIGHT_HTC = 12, + XR_LIP_EXPRESSION_MOUTH_SMILE_LEFT_HTC = 13, + XR_LIP_EXPRESSION_MOUTH_SAD_RIGHT_HTC = 14, + XR_LIP_EXPRESSION_MOUTH_SAD_LEFT_HTC = 15, + XR_LIP_EXPRESSION_CHEEK_PUFF_RIGHT_HTC = 16, + XR_LIP_EXPRESSION_CHEEK_PUFF_LEFT_HTC = 17, + XR_LIP_EXPRESSION_CHEEK_SUCK_HTC = 18, + XR_LIP_EXPRESSION_MOUTH_UPPER_UPRIGHT_HTC = 19, + XR_LIP_EXPRESSION_MOUTH_UPPER_UPLEFT_HTC = 20, + XR_LIP_EXPRESSION_MOUTH_LOWER_DOWNRIGHT_HTC = 21, + XR_LIP_EXPRESSION_MOUTH_LOWER_DOWNLEFT_HTC = 22, + XR_LIP_EXPRESSION_MOUTH_UPPER_INSIDE_HTC = 23, + XR_LIP_EXPRESSION_MOUTH_LOWER_INSIDE_HTC = 24, + XR_LIP_EXPRESSION_MOUTH_LOWER_OVERLAY_HTC = 25, + XR_LIP_EXPRESSION_TONGUE_LONGSTEP1_HTC = 26, + XR_LIP_EXPRESSION_TONGUE_LEFT_HTC = 27, + XR_LIP_EXPRESSION_TONGUE_RIGHT_HTC = 28, + XR_LIP_EXPRESSION_TONGUE_UP_HTC = 29, + XR_LIP_EXPRESSION_TONGUE_DOWN_HTC = 30, + XR_LIP_EXPRESSION_TONGUE_ROLL_HTC = 31, + XR_LIP_EXPRESSION_TONGUE_LONGSTEP2_HTC = 32, + XR_LIP_EXPRESSION_TONGUE_UPRIGHT_MORPH_HTC = 33, + XR_LIP_EXPRESSION_TONGUE_UPLEFT_MORPH_HTC = 34, + XR_LIP_EXPRESSION_TONGUE_DOWNRIGHT_MORPH_HTC = 35, + XR_LIP_EXPRESSION_TONGUE_DOWNLEFT_MORPH_HTC = 36, + XR_LIP_EXPRESSION_MAX_ENUM_HTC = 0x7FFFFFFF +} XrLipExpressionHTC; + +typedef enum XrFacialTrackingTypeHTC { + XR_FACIAL_TRACKING_TYPE_EYE_DEFAULT_HTC = 1, + XR_FACIAL_TRACKING_TYPE_LIP_DEFAULT_HTC = 2, + XR_FACIAL_TRACKING_TYPE_MAX_ENUM_HTC = 0x7FFFFFFF +} XrFacialTrackingTypeHTC; +// XrSystemFacialTrackingPropertiesHTC extends XrSystemProperties +typedef struct XrSystemFacialTrackingPropertiesHTC { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportEyeFacialTracking; + XrBool32 supportLipFacialTracking; +} XrSystemFacialTrackingPropertiesHTC; + +typedef struct XrFacialExpressionsHTC { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 isActive; + XrTime sampleTime; + uint32_t expressionCount; + float* expressionWeightings; +} XrFacialExpressionsHTC; + +typedef struct XrFacialTrackerCreateInfoHTC { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrFacialTrackingTypeHTC facialTrackingType; +} XrFacialTrackerCreateInfoHTC; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateFacialTrackerHTC)(XrSession session, const XrFacialTrackerCreateInfoHTC* createInfo, XrFacialTrackerHTC* facialTracker); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyFacialTrackerHTC)(XrFacialTrackerHTC facialTracker); +typedef XrResult (XRAPI_PTR *PFN_xrGetFacialExpressionsHTC)(XrFacialTrackerHTC facialTracker, XrFacialExpressionsHTC* facialExpressions); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateFacialTrackerHTC( + XrSession session, + const XrFacialTrackerCreateInfoHTC* createInfo, + XrFacialTrackerHTC* facialTracker); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyFacialTrackerHTC( + XrFacialTrackerHTC facialTracker); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetFacialExpressionsHTC( + XrFacialTrackerHTC facialTracker, + XrFacialExpressionsHTC* facialExpressions); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_HTC_vive_focus3_controller_interaction 1 +#define XR_HTC_vive_focus3_controller_interaction_SPEC_VERSION 1 +#define XR_HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_HTC_vive_focus3_controller_interaction" + + +#define XR_FB_color_space 1 +#define XR_FB_color_space_SPEC_VERSION 2 +#define XR_FB_COLOR_SPACE_EXTENSION_NAME "XR_FB_color_space" + +typedef enum XrColorSpaceFB { + XR_COLOR_SPACE_UNMANAGED_FB = 0, + XR_COLOR_SPACE_REC2020_FB = 1, + XR_COLOR_SPACE_REC709_FB = 2, + XR_COLOR_SPACE_RIFT_CV1_FB = 3, + XR_COLOR_SPACE_RIFT_S_FB = 4, + XR_COLOR_SPACE_QUEST_FB = 5, + XR_COLOR_SPACE_P3_FB = 6, + XR_COLOR_SPACE_ADOBE_RGB_FB = 7, + XR_COLOR_SPACE_MAX_ENUM_FB = 0x7FFFFFFF +} XrColorSpaceFB; +// XrSystemColorSpacePropertiesFB extends XrSystemProperties +typedef struct XrSystemColorSpacePropertiesFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrColorSpaceFB colorSpace; +} XrSystemColorSpacePropertiesFB; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateColorSpacesFB)(XrSession session, uint32_t colorSpaceCapacityInput, uint32_t* colorSpaceCountOutput, XrColorSpaceFB* colorSpaces); +typedef XrResult (XRAPI_PTR *PFN_xrSetColorSpaceFB)(XrSession session, const XrColorSpaceFB colorspace); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateColorSpacesFB( + XrSession session, + uint32_t colorSpaceCapacityInput, + uint32_t* colorSpaceCountOutput, + XrColorSpaceFB* colorSpaces); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetColorSpaceFB( + XrSession session, + const XrColorSpaceFB colorspace); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_hand_tracking_mesh 1 +#define XR_FB_hand_tracking_mesh_SPEC_VERSION 1 +#define XR_FB_HAND_TRACKING_MESH_EXTENSION_NAME "XR_FB_hand_tracking_mesh" +typedef struct XrVector4sFB { + int16_t x; + int16_t y; + int16_t z; + int16_t w; +} XrVector4sFB; + +typedef struct XrHandTrackingMeshFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t jointCapacityInput; + uint32_t jointCountOutput; + XrPosef* jointBindPoses; + float* jointRadii; + XrHandJointEXT* jointParents; + uint32_t vertexCapacityInput; + uint32_t vertexCountOutput; + XrVector3f* vertexPositions; + XrVector3f* vertexNormals; + XrVector2f* vertexUVs; + XrVector4sFB* vertexBlendIndices; + XrVector4f* vertexBlendWeights; + uint32_t indexCapacityInput; + uint32_t indexCountOutput; + int16_t* indices; +} XrHandTrackingMeshFB; + +// XrHandTrackingScaleFB extends XrHandJointsLocateInfoEXT +typedef struct XrHandTrackingScaleFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + float sensorOutput; + float currentOutput; + XrBool32 overrideHandScale; + float overrideValueInput; +} XrHandTrackingScaleFB; + +typedef XrResult (XRAPI_PTR *PFN_xrGetHandMeshFB)(XrHandTrackerEXT handTracker, XrHandTrackingMeshFB* mesh); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetHandMeshFB( + XrHandTrackerEXT handTracker, + XrHandTrackingMeshFB* mesh); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_hand_tracking_aim 1 +#define XR_FB_hand_tracking_aim_SPEC_VERSION 1 +#define XR_FB_HAND_TRACKING_AIM_EXTENSION_NAME "XR_FB_hand_tracking_aim" +typedef XrFlags64 XrHandTrackingAimFlagsFB; + +// Flag bits for XrHandTrackingAimFlagsFB +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_COMPUTED_BIT_FB = 0x00000001; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_VALID_BIT_FB = 0x00000002; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_INDEX_PINCHING_BIT_FB = 0x00000004; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_MIDDLE_PINCHING_BIT_FB = 0x00000008; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_RING_PINCHING_BIT_FB = 0x00000010; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_LITTLE_PINCHING_BIT_FB = 0x00000020; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_SYSTEM_GESTURE_BIT_FB = 0x00000040; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_DOMINANT_HAND_BIT_FB = 0x00000080; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_MENU_PRESSED_BIT_FB = 0x00000100; + +// XrHandTrackingAimStateFB extends XrHandJointsLocateInfoEXT +typedef struct XrHandTrackingAimStateFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrHandTrackingAimFlagsFB status; + XrPosef aimPose; + float pinchStrengthIndex; + float pinchStrengthMiddle; + float pinchStrengthRing; + float pinchStrengthLittle; +} XrHandTrackingAimStateFB; + + + +#define XR_FB_hand_tracking_capsules 1 +#define XR_HAND_TRACKING_CAPSULE_POINT_COUNT_FB 2 +#define XR_FB_HAND_TRACKING_CAPSULE_POINT_COUNT XR_HAND_TRACKING_CAPSULE_POINT_COUNT_FB +#define XR_HAND_TRACKING_CAPSULE_COUNT_FB 19 +#define XR_FB_HAND_TRACKING_CAPSULE_COUNT XR_HAND_TRACKING_CAPSULE_COUNT_FB +#define XR_FB_hand_tracking_capsules_SPEC_VERSION 2 +#define XR_FB_HAND_TRACKING_CAPSULES_EXTENSION_NAME "XR_FB_hand_tracking_capsules" +typedef struct XrHandCapsuleFB { + XrVector3f points[XR_FB_HAND_TRACKING_CAPSULE_POINT_COUNT]; + float radius; + XrHandJointEXT joint; +} XrHandCapsuleFB; + +// XrHandTrackingCapsulesStateFB extends XrHandJointsLocateInfoEXT +typedef struct XrHandTrackingCapsulesStateFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrHandCapsuleFB capsules[XR_FB_HAND_TRACKING_CAPSULE_COUNT]; +} XrHandTrackingCapsulesStateFB; + + + +#define XR_FB_foveation 1 +XR_DEFINE_HANDLE(XrFoveationProfileFB) +#define XR_FB_foveation_SPEC_VERSION 1 +#define XR_FB_FOVEATION_EXTENSION_NAME "XR_FB_foveation" +typedef XrFlags64 XrSwapchainCreateFoveationFlagsFB; + +// Flag bits for XrSwapchainCreateFoveationFlagsFB +static const XrSwapchainCreateFoveationFlagsFB XR_SWAPCHAIN_CREATE_FOVEATION_SCALED_BIN_BIT_FB = 0x00000001; +static const XrSwapchainCreateFoveationFlagsFB XR_SWAPCHAIN_CREATE_FOVEATION_FRAGMENT_DENSITY_MAP_BIT_FB = 0x00000002; + +typedef XrFlags64 XrSwapchainStateFoveationFlagsFB; + +// Flag bits for XrSwapchainStateFoveationFlagsFB + +typedef struct XrFoveationProfileCreateInfoFB { + XrStructureType type; + void* XR_MAY_ALIAS next; +} XrFoveationProfileCreateInfoFB; + +// XrSwapchainCreateInfoFoveationFB extends XrSwapchainCreateInfo +typedef struct XrSwapchainCreateInfoFoveationFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrSwapchainCreateFoveationFlagsFB flags; +} XrSwapchainCreateInfoFoveationFB; + +typedef struct XrSwapchainStateFoveationFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrSwapchainStateFoveationFlagsFB flags; + XrFoveationProfileFB profile; +} XrSwapchainStateFoveationFB; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateFoveationProfileFB)(XrSession session, const XrFoveationProfileCreateInfoFB* createInfo, XrFoveationProfileFB* profile); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyFoveationProfileFB)(XrFoveationProfileFB profile); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateFoveationProfileFB( + XrSession session, + const XrFoveationProfileCreateInfoFB* createInfo, + XrFoveationProfileFB* profile); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyFoveationProfileFB( + XrFoveationProfileFB profile); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_foveation_configuration 1 +#define XR_FB_foveation_configuration_SPEC_VERSION 1 +#define XR_FB_FOVEATION_CONFIGURATION_EXTENSION_NAME "XR_FB_foveation_configuration" + +typedef enum XrFoveationLevelFB { + XR_FOVEATION_LEVEL_NONE_FB = 0, + XR_FOVEATION_LEVEL_LOW_FB = 1, + XR_FOVEATION_LEVEL_MEDIUM_FB = 2, + XR_FOVEATION_LEVEL_HIGH_FB = 3, + XR_FOVEATION_LEVEL_MAX_ENUM_FB = 0x7FFFFFFF +} XrFoveationLevelFB; + +typedef enum XrFoveationDynamicFB { + XR_FOVEATION_DYNAMIC_DISABLED_FB = 0, + XR_FOVEATION_DYNAMIC_LEVEL_ENABLED_FB = 1, + XR_FOVEATION_DYNAMIC_MAX_ENUM_FB = 0x7FFFFFFF +} XrFoveationDynamicFB; +// XrFoveationLevelProfileCreateInfoFB extends XrFoveationProfileCreateInfoFB +typedef struct XrFoveationLevelProfileCreateInfoFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrFoveationLevelFB level; + float verticalOffset; + XrFoveationDynamicFB dynamic; +} XrFoveationLevelProfileCreateInfoFB; + + + +#define XR_FB_keyboard_tracking 1 +#define XR_FB_keyboard_tracking_SPEC_VERSION 1 +#define XR_FB_KEYBOARD_TRACKING_EXTENSION_NAME "XR_FB_keyboard_tracking" +#define XR_MAX_KEYBOARD_TRACKING_NAME_SIZE_FB 128 +typedef XrFlags64 XrKeyboardTrackingFlagsFB; + +// Flag bits for XrKeyboardTrackingFlagsFB +static const XrKeyboardTrackingFlagsFB XR_KEYBOARD_TRACKING_EXISTS_BIT_FB = 0x00000001; +static const XrKeyboardTrackingFlagsFB XR_KEYBOARD_TRACKING_LOCAL_BIT_FB = 0x00000002; +static const XrKeyboardTrackingFlagsFB XR_KEYBOARD_TRACKING_REMOTE_BIT_FB = 0x00000004; +static const XrKeyboardTrackingFlagsFB XR_KEYBOARD_TRACKING_CONNECTED_BIT_FB = 0x00000008; + +typedef XrFlags64 XrKeyboardTrackingQueryFlagsFB; + +// Flag bits for XrKeyboardTrackingQueryFlagsFB +static const XrKeyboardTrackingQueryFlagsFB XR_KEYBOARD_TRACKING_QUERY_LOCAL_BIT_FB = 0x00000002; +static const XrKeyboardTrackingQueryFlagsFB XR_KEYBOARD_TRACKING_QUERY_REMOTE_BIT_FB = 0x00000004; + +// XrSystemKeyboardTrackingPropertiesFB extends XrSystemProperties +typedef struct XrSystemKeyboardTrackingPropertiesFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsKeyboardTracking; +} XrSystemKeyboardTrackingPropertiesFB; + +typedef struct XrKeyboardTrackingDescriptionFB { + uint64_t trackedKeyboardId; + XrVector3f size; + XrKeyboardTrackingFlagsFB flags; + char name[XR_MAX_KEYBOARD_TRACKING_NAME_SIZE_FB]; +} XrKeyboardTrackingDescriptionFB; + +typedef struct XrKeyboardSpaceCreateInfoFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint64_t trackedKeyboardId; +} XrKeyboardSpaceCreateInfoFB; + +typedef struct XrKeyboardTrackingQueryFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrKeyboardTrackingQueryFlagsFB flags; +} XrKeyboardTrackingQueryFB; + +typedef XrResult (XRAPI_PTR *PFN_xrQuerySystemTrackedKeyboardFB)(XrSession session, const XrKeyboardTrackingQueryFB* queryInfo, XrKeyboardTrackingDescriptionFB* keyboard); +typedef XrResult (XRAPI_PTR *PFN_xrCreateKeyboardSpaceFB)(XrSession session, const XrKeyboardSpaceCreateInfoFB* createInfo, XrSpace* keyboardSpace); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrQuerySystemTrackedKeyboardFB( + XrSession session, + const XrKeyboardTrackingQueryFB* queryInfo, + XrKeyboardTrackingDescriptionFB* keyboard); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateKeyboardSpaceFB( + XrSession session, + const XrKeyboardSpaceCreateInfoFB* createInfo, + XrSpace* keyboardSpace); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_triangle_mesh 1 +XR_DEFINE_HANDLE(XrTriangleMeshFB) +#define XR_FB_triangle_mesh_SPEC_VERSION 1 +#define XR_FB_TRIANGLE_MESH_EXTENSION_NAME "XR_FB_triangle_mesh" + +typedef enum XrWindingOrderFB { + XR_WINDING_ORDER_UNKNOWN_FB = 0, + XR_WINDING_ORDER_CW_FB = 1, + XR_WINDING_ORDER_CCW_FB = 2, + XR_WINDING_ORDER_MAX_ENUM_FB = 0x7FFFFFFF +} XrWindingOrderFB; +typedef XrFlags64 XrTriangleMeshFlagsFB; + +// Flag bits for XrTriangleMeshFlagsFB +static const XrTriangleMeshFlagsFB XR_TRIANGLE_MESH_MUTABLE_BIT_FB = 0x00000001; + +typedef struct XrTriangleMeshCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrTriangleMeshFlagsFB flags; + XrWindingOrderFB windingOrder; + uint32_t vertexCount; + const XrVector3f* vertexBuffer; + uint32_t triangleCount; + const uint32_t* indexBuffer; +} XrTriangleMeshCreateInfoFB; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateTriangleMeshFB)(XrSession session, const XrTriangleMeshCreateInfoFB* createInfo, XrTriangleMeshFB* outTriangleMesh); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyTriangleMeshFB)(XrTriangleMeshFB mesh); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshGetVertexBufferFB)(XrTriangleMeshFB mesh, XrVector3f** outVertexBuffer); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshGetIndexBufferFB)(XrTriangleMeshFB mesh, uint32_t** outIndexBuffer); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshBeginUpdateFB)(XrTriangleMeshFB mesh); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshEndUpdateFB)(XrTriangleMeshFB mesh, uint32_t vertexCount, uint32_t triangleCount); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshBeginVertexBufferUpdateFB)(XrTriangleMeshFB mesh, uint32_t* outVertexCount); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshEndVertexBufferUpdateFB)(XrTriangleMeshFB mesh); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateTriangleMeshFB( + XrSession session, + const XrTriangleMeshCreateInfoFB* createInfo, + XrTriangleMeshFB* outTriangleMesh); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyTriangleMeshFB( + XrTriangleMeshFB mesh); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshGetVertexBufferFB( + XrTriangleMeshFB mesh, + XrVector3f** outVertexBuffer); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshGetIndexBufferFB( + XrTriangleMeshFB mesh, + uint32_t** outIndexBuffer); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshBeginUpdateFB( + XrTriangleMeshFB mesh); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshEndUpdateFB( + XrTriangleMeshFB mesh, + uint32_t vertexCount, + uint32_t triangleCount); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshBeginVertexBufferUpdateFB( + XrTriangleMeshFB mesh, + uint32_t* outVertexCount); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshEndVertexBufferUpdateFB( + XrTriangleMeshFB mesh); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_passthrough 1 +XR_DEFINE_HANDLE(XrPassthroughFB) +XR_DEFINE_HANDLE(XrPassthroughLayerFB) +XR_DEFINE_HANDLE(XrGeometryInstanceFB) +#define XR_FB_passthrough_SPEC_VERSION 1 +#define XR_FB_PASSTHROUGH_EXTENSION_NAME "XR_FB_passthrough" +#define XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB 256 + +typedef enum XrPassthroughLayerPurposeFB { + XR_PASSTHROUGH_LAYER_PURPOSE_RECONSTRUCTION_FB = 0, + XR_PASSTHROUGH_LAYER_PURPOSE_PROJECTED_FB = 1, + XR_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_HANDS_FB = 1000203001, + XR_PASSTHROUGH_LAYER_PURPOSE_MAX_ENUM_FB = 0x7FFFFFFF +} XrPassthroughLayerPurposeFB; +typedef XrFlags64 XrPassthroughFlagsFB; + +// Flag bits for XrPassthroughFlagsFB +static const XrPassthroughFlagsFB XR_PASSTHROUGH_IS_RUNNING_AT_CREATION_BIT_FB = 0x00000001; + +typedef XrFlags64 XrPassthroughStateChangedFlagsFB; + +// Flag bits for XrPassthroughStateChangedFlagsFB +static const XrPassthroughStateChangedFlagsFB XR_PASSTHROUGH_STATE_CHANGED_REINIT_REQUIRED_BIT_FB = 0x00000001; +static const XrPassthroughStateChangedFlagsFB XR_PASSTHROUGH_STATE_CHANGED_NON_RECOVERABLE_ERROR_BIT_FB = 0x00000002; +static const XrPassthroughStateChangedFlagsFB XR_PASSTHROUGH_STATE_CHANGED_RECOVERABLE_ERROR_BIT_FB = 0x00000004; +static const XrPassthroughStateChangedFlagsFB XR_PASSTHROUGH_STATE_CHANGED_RESTORED_ERROR_BIT_FB = 0x00000008; + +// XrSystemPassthroughPropertiesFB extends XrSystemProperties +typedef struct XrSystemPassthroughPropertiesFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 supportsPassthrough; +} XrSystemPassthroughPropertiesFB; + +typedef struct XrPassthroughCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPassthroughFlagsFB flags; +} XrPassthroughCreateInfoFB; + +typedef struct XrPassthroughLayerCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPassthroughFB passthrough; + XrPassthroughFlagsFB flags; + XrPassthroughLayerPurposeFB purpose; +} XrPassthroughLayerCreateInfoFB; + +// XrCompositionLayerPassthroughFB extends XrCompositionLayerBaseHeader +typedef struct XrCompositionLayerPassthroughFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerFlags flags; + XrSpace space; + XrPassthroughLayerFB layerHandle; +} XrCompositionLayerPassthroughFB; + +typedef struct XrGeometryInstanceCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPassthroughLayerFB layer; + XrTriangleMeshFB mesh; + XrSpace baseSpace; + XrPosef pose; + XrVector3f scale; +} XrGeometryInstanceCreateInfoFB; + +typedef struct XrGeometryInstanceTransformFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace baseSpace; + XrTime time; + XrPosef pose; + XrVector3f scale; +} XrGeometryInstanceTransformFB; + +typedef struct XrPassthroughStyleFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + float textureOpacityFactor; + XrColor4f edgeColor; +} XrPassthroughStyleFB; + +typedef struct XrPassthroughColorMapMonoToRgbaFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrColor4f textureColorMap[XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB]; +} XrPassthroughColorMapMonoToRgbaFB; + +typedef struct XrPassthroughColorMapMonoToMonoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint8_t textureColorMap[XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB]; +} XrPassthroughColorMapMonoToMonoFB; + +typedef struct XrEventDataPassthroughStateChangedFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPassthroughStateChangedFlagsFB flags; +} XrEventDataPassthroughStateChangedFB; + +typedef XrResult (XRAPI_PTR *PFN_xrCreatePassthroughFB)(XrSession session, const XrPassthroughCreateInfoFB* createInfo, XrPassthroughFB* outPassthrough); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyPassthroughFB)(XrPassthroughFB passthrough); +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughStartFB)(XrPassthroughFB passthrough); +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughPauseFB)(XrPassthroughFB passthrough); +typedef XrResult (XRAPI_PTR *PFN_xrCreatePassthroughLayerFB)(XrSession session, const XrPassthroughLayerCreateInfoFB* createInfo, XrPassthroughLayerFB* outLayer); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyPassthroughLayerFB)(XrPassthroughLayerFB layer); +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughLayerPauseFB)(XrPassthroughLayerFB layer); +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughLayerResumeFB)(XrPassthroughLayerFB layer); +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughLayerSetStyleFB)(XrPassthroughLayerFB layer, const XrPassthroughStyleFB* style); +typedef XrResult (XRAPI_PTR *PFN_xrCreateGeometryInstanceFB)(XrSession session, const XrGeometryInstanceCreateInfoFB* createInfo, XrGeometryInstanceFB* outGeometryInstance); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyGeometryInstanceFB)(XrGeometryInstanceFB instance); +typedef XrResult (XRAPI_PTR *PFN_xrGeometryInstanceSetTransformFB)(XrGeometryInstanceFB instance, const XrGeometryInstanceTransformFB* transformation); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreatePassthroughFB( + XrSession session, + const XrPassthroughCreateInfoFB* createInfo, + XrPassthroughFB* outPassthrough); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyPassthroughFB( + XrPassthroughFB passthrough); + +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughStartFB( + XrPassthroughFB passthrough); + +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughPauseFB( + XrPassthroughFB passthrough); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreatePassthroughLayerFB( + XrSession session, + const XrPassthroughLayerCreateInfoFB* createInfo, + XrPassthroughLayerFB* outLayer); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyPassthroughLayerFB( + XrPassthroughLayerFB layer); + +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughLayerPauseFB( + XrPassthroughLayerFB layer); + +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughLayerResumeFB( + XrPassthroughLayerFB layer); + +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughLayerSetStyleFB( + XrPassthroughLayerFB layer, + const XrPassthroughStyleFB* style); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateGeometryInstanceFB( + XrSession session, + const XrGeometryInstanceCreateInfoFB* createInfo, + XrGeometryInstanceFB* outGeometryInstance); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyGeometryInstanceFB( + XrGeometryInstanceFB instance); + +XRAPI_ATTR XrResult XRAPI_CALL xrGeometryInstanceSetTransformFB( + XrGeometryInstanceFB instance, + const XrGeometryInstanceTransformFB* transformation); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_render_model 1 + +#define XR_NULL_RENDER_MODEL_KEY_FB 0 + +XR_DEFINE_ATOM(XrRenderModelKeyFB) +#define XR_FB_render_model_SPEC_VERSION 1 +#define XR_FB_RENDER_MODEL_EXTENSION_NAME "XR_FB_render_model" +#define XR_MAX_RENDER_MODEL_NAME_SIZE_FB 64 +typedef XrFlags64 XrRenderModelFlagsFB; + +// Flag bits for XrRenderModelFlagsFB + +typedef struct XrRenderModelPathInfoFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrPath path; +} XrRenderModelPathInfoFB; + +typedef struct XrRenderModelPropertiesFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t vendorId; + char modelName[XR_MAX_RENDER_MODEL_NAME_SIZE_FB]; + XrRenderModelKeyFB modelKey; + uint32_t modelVersion; + XrRenderModelFlagsFB flags; +} XrRenderModelPropertiesFB; + +typedef struct XrRenderModelBufferFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t bufferCapacityInput; + uint32_t bufferCountOutput; + uint8_t* buffer; +} XrRenderModelBufferFB; + +typedef struct XrRenderModelLoadInfoFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrRenderModelKeyFB modelKey; +} XrRenderModelLoadInfoFB; + +// XrSystemRenderModelPropertiesFB extends XrSystemProperties +typedef struct XrSystemRenderModelPropertiesFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsRenderModelLoading; +} XrSystemRenderModelPropertiesFB; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateRenderModelPathsFB)(XrSession session, uint32_t pathCapacityInput, uint32_t* pathCountOutput, XrRenderModelPathInfoFB* paths); +typedef XrResult (XRAPI_PTR *PFN_xrGetRenderModelPropertiesFB)(XrSession session, XrPath path, XrRenderModelPropertiesFB* properties); +typedef XrResult (XRAPI_PTR *PFN_xrLoadRenderModelFB)(XrSession session, const XrRenderModelLoadInfoFB* info, XrRenderModelBufferFB* buffer); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateRenderModelPathsFB( + XrSession session, + uint32_t pathCapacityInput, + uint32_t* pathCountOutput, + XrRenderModelPathInfoFB* paths); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetRenderModelPropertiesFB( + XrSession session, + XrPath path, + XrRenderModelPropertiesFB* properties); + +XRAPI_ATTR XrResult XRAPI_CALL xrLoadRenderModelFB( + XrSession session, + const XrRenderModelLoadInfoFB* info, + XrRenderModelBufferFB* buffer); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_VARJO_foveated_rendering 1 +#define XR_VARJO_foveated_rendering_SPEC_VERSION 2 +#define XR_VARJO_FOVEATED_RENDERING_EXTENSION_NAME "XR_VARJO_foveated_rendering" +// XrViewLocateFoveatedRenderingVARJO extends XrViewLocateInfo +typedef struct XrViewLocateFoveatedRenderingVARJO { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 foveatedRenderingActive; +} XrViewLocateFoveatedRenderingVARJO; + +// XrFoveatedViewConfigurationViewVARJO extends XrViewConfigurationView +typedef struct XrFoveatedViewConfigurationViewVARJO { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 foveatedRenderingActive; +} XrFoveatedViewConfigurationViewVARJO; + +// XrSystemFoveatedRenderingPropertiesVARJO extends XrSystemProperties +typedef struct XrSystemFoveatedRenderingPropertiesVARJO { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsFoveatedRendering; +} XrSystemFoveatedRenderingPropertiesVARJO; + + + +#define XR_VARJO_composition_layer_depth_test 1 +#define XR_VARJO_composition_layer_depth_test_SPEC_VERSION 2 +#define XR_VARJO_COMPOSITION_LAYER_DEPTH_TEST_EXTENSION_NAME "XR_VARJO_composition_layer_depth_test" +// XrCompositionLayerDepthTestVARJO extends XrCompositionLayerProjection +typedef struct XrCompositionLayerDepthTestVARJO { + XrStructureType type; + const void* XR_MAY_ALIAS next; + float depthTestRangeNearZ; + float depthTestRangeFarZ; +} XrCompositionLayerDepthTestVARJO; + + + +#define XR_VARJO_environment_depth_estimation 1 +#define XR_VARJO_environment_depth_estimation_SPEC_VERSION 1 +#define XR_VARJO_ENVIRONMENT_DEPTH_ESTIMATION_EXTENSION_NAME "XR_VARJO_environment_depth_estimation" +typedef XrResult (XRAPI_PTR *PFN_xrSetEnvironmentDepthEstimationVARJO)(XrSession session, XrBool32 enabled); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetEnvironmentDepthEstimationVARJO( + XrSession session, + XrBool32 enabled); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_VARJO_marker_tracking 1 +#define XR_VARJO_marker_tracking_SPEC_VERSION 1 +#define XR_VARJO_MARKER_TRACKING_EXTENSION_NAME "XR_VARJO_marker_tracking" +// XrSystemMarkerTrackingPropertiesVARJO extends XrSystemProperties +typedef struct XrSystemMarkerTrackingPropertiesVARJO { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsMarkerTracking; +} XrSystemMarkerTrackingPropertiesVARJO; + +typedef struct XrEventDataMarkerTrackingUpdateVARJO { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint64_t markerId; + XrBool32 isActive; + XrBool32 isPredicted; + XrTime time; +} XrEventDataMarkerTrackingUpdateVARJO; + +typedef struct XrMarkerSpaceCreateInfoVARJO { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint64_t markerId; + XrPosef poseInMarkerSpace; +} XrMarkerSpaceCreateInfoVARJO; + +typedef XrResult (XRAPI_PTR *PFN_xrSetMarkerTrackingVARJO)(XrSession session, XrBool32 enabled); +typedef XrResult (XRAPI_PTR *PFN_xrSetMarkerTrackingTimeoutVARJO)(XrSession session, uint64_t markerId, XrDuration timeout); +typedef XrResult (XRAPI_PTR *PFN_xrSetMarkerTrackingPredictionVARJO)(XrSession session, uint64_t markerId, XrBool32 enabled); +typedef XrResult (XRAPI_PTR *PFN_xrGetMarkerSizeVARJO)(XrSession session, uint64_t markerId, XrExtent2Df* size); +typedef XrResult (XRAPI_PTR *PFN_xrCreateMarkerSpaceVARJO)(XrSession session, const XrMarkerSpaceCreateInfoVARJO* createInfo, XrSpace* space); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetMarkerTrackingVARJO( + XrSession session, + XrBool32 enabled); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetMarkerTrackingTimeoutVARJO( + XrSession session, + uint64_t markerId, + XrDuration timeout); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetMarkerTrackingPredictionVARJO( + XrSession session, + uint64_t markerId, + XrBool32 enabled); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetMarkerSizeVARJO( + XrSession session, + uint64_t markerId, + XrExtent2Df* size); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateMarkerSpaceVARJO( + XrSession session, + const XrMarkerSpaceCreateInfoVARJO* createInfo, + XrSpace* space); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_MSFT_spatial_anchor_persistence 1 +XR_DEFINE_HANDLE(XrSpatialAnchorStoreConnectionMSFT) +#define XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_MSFT 256 +#define XR_MSFT_spatial_anchor_persistence_SPEC_VERSION 2 +#define XR_MSFT_SPATIAL_ANCHOR_PERSISTENCE_EXTENSION_NAME "XR_MSFT_spatial_anchor_persistence" +typedef struct XrSpatialAnchorPersistenceNameMSFT { + char name[XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_MSFT]; +} XrSpatialAnchorPersistenceNameMSFT; + +typedef struct XrSpatialAnchorPersistenceInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpatialAnchorPersistenceNameMSFT spatialAnchorPersistenceName; + XrSpatialAnchorMSFT spatialAnchor; +} XrSpatialAnchorPersistenceInfoMSFT; + +typedef struct XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore; + XrSpatialAnchorPersistenceNameMSFT spatialAnchorPersistenceName; +} XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorStoreConnectionMSFT)(XrSession session, XrSpatialAnchorStoreConnectionMSFT* spatialAnchorStore); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySpatialAnchorStoreConnectionMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore); +typedef XrResult (XRAPI_PTR *PFN_xrPersistSpatialAnchorMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, const XrSpatialAnchorPersistenceInfoMSFT* spatialAnchorPersistenceInfo); +typedef XrResult (XRAPI_PTR *PFN_xrEnumeratePersistedSpatialAnchorNamesMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, uint32_t spatialAnchorNamesCapacityInput, uint32_t* spatialAnchorNamesCountOutput, XrSpatialAnchorPersistenceNameMSFT* persistedAnchorNames); +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorFromPersistedNameMSFT)(XrSession session, const XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT* spatialAnchorCreateInfo, XrSpatialAnchorMSFT* spatialAnchor); +typedef XrResult (XRAPI_PTR *PFN_xrUnpersistSpatialAnchorMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, const XrSpatialAnchorPersistenceNameMSFT* spatialAnchorPersistenceName); +typedef XrResult (XRAPI_PTR *PFN_xrClearSpatialAnchorStoreMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorStoreConnectionMSFT( + XrSession session, + XrSpatialAnchorStoreConnectionMSFT* spatialAnchorStore); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpatialAnchorStoreConnectionMSFT( + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore); + +XRAPI_ATTR XrResult XRAPI_CALL xrPersistSpatialAnchorMSFT( + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, + const XrSpatialAnchorPersistenceInfoMSFT* spatialAnchorPersistenceInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumeratePersistedSpatialAnchorNamesMSFT( + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, + uint32_t spatialAnchorNamesCapacityInput, + uint32_t* spatialAnchorNamesCountOutput, + XrSpatialAnchorPersistenceNameMSFT* persistedAnchorNames); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorFromPersistedNameMSFT( + XrSession session, + const XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT* spatialAnchorCreateInfo, + XrSpatialAnchorMSFT* spatialAnchor); + +XRAPI_ATTR XrResult XRAPI_CALL xrUnpersistSpatialAnchorMSFT( + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, + const XrSpatialAnchorPersistenceNameMSFT* spatialAnchorPersistenceName); + +XRAPI_ATTR XrResult XRAPI_CALL xrClearSpatialAnchorStoreMSFT( + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_space_warp 1 +#define XR_FB_space_warp_SPEC_VERSION 1 +#define XR_FB_SPACE_WARP_EXTENSION_NAME "XR_FB_space_warp" +typedef XrFlags64 XrCompositionLayerSpaceWarpInfoFlagsFB; + +// Flag bits for XrCompositionLayerSpaceWarpInfoFlagsFB + +// XrCompositionLayerSpaceWarpInfoFB extends XrCompositionLayerProjectionView +typedef struct XrCompositionLayerSpaceWarpInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerSpaceWarpInfoFlagsFB layerFlags; + XrSwapchainSubImage motionVectorSubImage; + XrPosef appSpaceDeltaPose; + XrSwapchainSubImage depthSubImage; + float minDepth; + float maxDepth; + float nearZ; + float farZ; +} XrCompositionLayerSpaceWarpInfoFB; + +// XrSystemSpaceWarpPropertiesFB extends XrSystemProperties +typedef struct XrSystemSpaceWarpPropertiesFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t recommendedMotionVectorImageRectWidth; + uint32_t recommendedMotionVectorImageRectHeight; +} XrSystemSpaceWarpPropertiesFB; + + + +#define XR_ALMALENCE_digital_lens_control 1 +#define XR_ALMALENCE_digital_lens_control_SPEC_VERSION 1 +#define XR_ALMALENCE_DIGITAL_LENS_CONTROL_EXTENSION_NAME "XR_ALMALENCE_digital_lens_control" +typedef XrFlags64 XrDigitalLensControlFlagsALMALENCE; + +// Flag bits for XrDigitalLensControlFlagsALMALENCE +static const XrDigitalLensControlFlagsALMALENCE XR_DIGITAL_LENS_CONTROL_PROCESSING_DISABLE_BIT_ALMALENCE = 0x00000001; + +typedef struct XrDigitalLensControlALMALENCE { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrDigitalLensControlFlagsALMALENCE flags; +} XrDigitalLensControlALMALENCE; + +typedef XrResult (XRAPI_PTR *PFN_xrSetDigitalLensControlALMALENCE)(XrSession session, const XrDigitalLensControlALMALENCE* digitalLensControl); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetDigitalLensControlALMALENCE( + XrSession session, + const XrDigitalLensControlALMALENCE* digitalLensControl); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_passthrough_keyboard_hands 1 +#define XR_FB_passthrough_keyboard_hands_SPEC_VERSION 1 +#define XR_FB_PASSTHROUGH_KEYBOARD_HANDS_EXTENSION_NAME "XR_FB_passthrough_keyboard_hands" +typedef struct XrPassthroughKeyboardHandsIntensityFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + float leftHandIntensity; + float rightHandIntensity; +} XrPassthroughKeyboardHandsIntensityFB; + +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughLayerSetKeyboardHandsIntensityFB)(XrPassthroughLayerFB layer, const XrPassthroughKeyboardHandsIntensityFB* intensity); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughLayerSetKeyboardHandsIntensityFB( + XrPassthroughLayerFB layer, + const XrPassthroughKeyboardHandsIntensityFB* intensity); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_EXT_uuid 1 +#define XR_EXT_uuid_SPEC_VERSION 1 +#define XR_EXT_UUID_EXTENSION_NAME "XR_EXT_uuid" +#define XR_UUID_SIZE_EXT 16 +typedef struct XrUuidEXT { + uint8_t data[XR_UUID_SIZE_EXT]; +} XrUuidEXT; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/thirdparty/openxr/include/openxr/openxr_platform.h b/thirdparty/openxr/include/openxr/openxr_platform.h new file mode 100644 index 0000000000..eb5e5f8c4b --- /dev/null +++ b/thirdparty/openxr/include/openxr/openxr_platform.h @@ -0,0 +1,675 @@ +#ifndef OPENXR_PLATFORM_H_ +#define OPENXR_PLATFORM_H_ 1 + +/* +** Copyright (c) 2017-2022, The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos OpenXR XML API Registry. +** +*/ + +#include "openxr.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef XR_USE_PLATFORM_ANDROID + +#define XR_KHR_android_thread_settings 1 +#define XR_KHR_android_thread_settings_SPEC_VERSION 5 +#define XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME "XR_KHR_android_thread_settings" + +typedef enum XrAndroidThreadTypeKHR { + XR_ANDROID_THREAD_TYPE_APPLICATION_MAIN_KHR = 1, + XR_ANDROID_THREAD_TYPE_APPLICATION_WORKER_KHR = 2, + XR_ANDROID_THREAD_TYPE_RENDERER_MAIN_KHR = 3, + XR_ANDROID_THREAD_TYPE_RENDERER_WORKER_KHR = 4, + XR_ANDROID_THREAD_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} XrAndroidThreadTypeKHR; +typedef XrResult (XRAPI_PTR *PFN_xrSetAndroidApplicationThreadKHR)(XrSession session, XrAndroidThreadTypeKHR threadType, uint32_t threadId); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetAndroidApplicationThreadKHR( + XrSession session, + XrAndroidThreadTypeKHR threadType, + uint32_t threadId); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_PLATFORM_ANDROID */ + +#ifdef XR_USE_PLATFORM_ANDROID + +#define XR_KHR_android_surface_swapchain 1 +#define XR_KHR_android_surface_swapchain_SPEC_VERSION 4 +#define XR_KHR_ANDROID_SURFACE_SWAPCHAIN_EXTENSION_NAME "XR_KHR_android_surface_swapchain" +typedef XrResult (XRAPI_PTR *PFN_xrCreateSwapchainAndroidSurfaceKHR)(XrSession session, const XrSwapchainCreateInfo* info, XrSwapchain* swapchain, jobject* surface); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSwapchainAndroidSurfaceKHR( + XrSession session, + const XrSwapchainCreateInfo* info, + XrSwapchain* swapchain, + jobject* surface); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_PLATFORM_ANDROID */ + +#ifdef XR_USE_PLATFORM_ANDROID + +#define XR_KHR_android_create_instance 1 +#define XR_KHR_android_create_instance_SPEC_VERSION 3 +#define XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME "XR_KHR_android_create_instance" +// XrInstanceCreateInfoAndroidKHR extends XrInstanceCreateInfo +typedef struct XrInstanceCreateInfoAndroidKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + void* XR_MAY_ALIAS applicationVM; + void* XR_MAY_ALIAS applicationActivity; +} XrInstanceCreateInfoAndroidKHR; + +#endif /* XR_USE_PLATFORM_ANDROID */ + +#ifdef XR_USE_GRAPHICS_API_VULKAN + +#define XR_KHR_vulkan_swapchain_format_list 1 +#define XR_KHR_vulkan_swapchain_format_list_SPEC_VERSION 4 +#define XR_KHR_VULKAN_SWAPCHAIN_FORMAT_LIST_EXTENSION_NAME "XR_KHR_vulkan_swapchain_format_list" +typedef struct XrVulkanSwapchainFormatListCreateInfoKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t viewFormatCount; + const VkFormat* viewFormats; +} XrVulkanSwapchainFormatListCreateInfoKHR; + +#endif /* XR_USE_GRAPHICS_API_VULKAN */ + +#ifdef XR_USE_GRAPHICS_API_OPENGL + +#define XR_KHR_opengl_enable 1 +#define XR_KHR_opengl_enable_SPEC_VERSION 10 +#define XR_KHR_OPENGL_ENABLE_EXTENSION_NAME "XR_KHR_opengl_enable" +#ifdef XR_USE_PLATFORM_WIN32 +// XrGraphicsBindingOpenGLWin32KHR extends XrSessionCreateInfo +typedef struct XrGraphicsBindingOpenGLWin32KHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + HDC hDC; + HGLRC hGLRC; +} XrGraphicsBindingOpenGLWin32KHR; +#endif // XR_USE_PLATFORM_WIN32 + +#ifdef XR_USE_PLATFORM_XLIB +// XrGraphicsBindingOpenGLXlibKHR extends XrSessionCreateInfo +typedef struct XrGraphicsBindingOpenGLXlibKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + Display* xDisplay; + uint32_t visualid; + GLXFBConfig glxFBConfig; + GLXDrawable glxDrawable; + GLXContext glxContext; +} XrGraphicsBindingOpenGLXlibKHR; +#endif // XR_USE_PLATFORM_XLIB + +#ifdef XR_USE_PLATFORM_XCB +// XrGraphicsBindingOpenGLXcbKHR extends XrSessionCreateInfo +typedef struct XrGraphicsBindingOpenGLXcbKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + xcb_connection_t* connection; + uint32_t screenNumber; + xcb_glx_fbconfig_t fbconfigid; + xcb_visualid_t visualid; + xcb_glx_drawable_t glxDrawable; + xcb_glx_context_t glxContext; +} XrGraphicsBindingOpenGLXcbKHR; +#endif // XR_USE_PLATFORM_XCB + +#ifdef XR_USE_PLATFORM_WAYLAND +// XrGraphicsBindingOpenGLWaylandKHR extends XrSessionCreateInfo +typedef struct XrGraphicsBindingOpenGLWaylandKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + struct wl_display* display; +} XrGraphicsBindingOpenGLWaylandKHR; +#endif // XR_USE_PLATFORM_WAYLAND + +typedef struct XrSwapchainImageOpenGLKHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t image; +} XrSwapchainImageOpenGLKHR; + +typedef struct XrGraphicsRequirementsOpenGLKHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrVersion minApiVersionSupported; + XrVersion maxApiVersionSupported; +} XrGraphicsRequirementsOpenGLKHR; + +typedef XrResult (XRAPI_PTR *PFN_xrGetOpenGLGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsOpenGLKHR* graphicsRequirements); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetOpenGLGraphicsRequirementsKHR( + XrInstance instance, + XrSystemId systemId, + XrGraphicsRequirementsOpenGLKHR* graphicsRequirements); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_GRAPHICS_API_OPENGL */ + +#ifdef XR_USE_GRAPHICS_API_OPENGL_ES + +#define XR_KHR_opengl_es_enable 1 +#define XR_KHR_opengl_es_enable_SPEC_VERSION 8 +#define XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME "XR_KHR_opengl_es_enable" +#ifdef XR_USE_PLATFORM_ANDROID +// XrGraphicsBindingOpenGLESAndroidKHR extends XrSessionCreateInfo +typedef struct XrGraphicsBindingOpenGLESAndroidKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + EGLDisplay display; + EGLConfig config; + EGLContext context; +} XrGraphicsBindingOpenGLESAndroidKHR; +#endif // XR_USE_PLATFORM_ANDROID + +typedef struct XrSwapchainImageOpenGLESKHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t image; +} XrSwapchainImageOpenGLESKHR; + +typedef struct XrGraphicsRequirementsOpenGLESKHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrVersion minApiVersionSupported; + XrVersion maxApiVersionSupported; +} XrGraphicsRequirementsOpenGLESKHR; + +typedef XrResult (XRAPI_PTR *PFN_xrGetOpenGLESGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsOpenGLESKHR* graphicsRequirements); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetOpenGLESGraphicsRequirementsKHR( + XrInstance instance, + XrSystemId systemId, + XrGraphicsRequirementsOpenGLESKHR* graphicsRequirements); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_GRAPHICS_API_OPENGL_ES */ + +#ifdef XR_USE_GRAPHICS_API_VULKAN + +#define XR_KHR_vulkan_enable 1 +#define XR_KHR_vulkan_enable_SPEC_VERSION 8 +#define XR_KHR_VULKAN_ENABLE_EXTENSION_NAME "XR_KHR_vulkan_enable" +// XrGraphicsBindingVulkanKHR extends XrSessionCreateInfo +typedef struct XrGraphicsBindingVulkanKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + VkInstance instance; + VkPhysicalDevice physicalDevice; + VkDevice device; + uint32_t queueFamilyIndex; + uint32_t queueIndex; +} XrGraphicsBindingVulkanKHR; + +typedef struct XrSwapchainImageVulkanKHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + VkImage image; +} XrSwapchainImageVulkanKHR; + +typedef struct XrGraphicsRequirementsVulkanKHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrVersion minApiVersionSupported; + XrVersion maxApiVersionSupported; +} XrGraphicsRequirementsVulkanKHR; + +typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanInstanceExtensionsKHR)(XrInstance instance, XrSystemId systemId, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer); +typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanDeviceExtensionsKHR)(XrInstance instance, XrSystemId systemId, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer); +typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsDeviceKHR)(XrInstance instance, XrSystemId systemId, VkInstance vkInstance, VkPhysicalDevice* vkPhysicalDevice); +typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsVulkanKHR* graphicsRequirements); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanInstanceExtensionsKHR( + XrInstance instance, + XrSystemId systemId, + uint32_t bufferCapacityInput, + uint32_t* bufferCountOutput, + char* buffer); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanDeviceExtensionsKHR( + XrInstance instance, + XrSystemId systemId, + uint32_t bufferCapacityInput, + uint32_t* bufferCountOutput, + char* buffer); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsDeviceKHR( + XrInstance instance, + XrSystemId systemId, + VkInstance vkInstance, + VkPhysicalDevice* vkPhysicalDevice); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsRequirementsKHR( + XrInstance instance, + XrSystemId systemId, + XrGraphicsRequirementsVulkanKHR* graphicsRequirements); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_GRAPHICS_API_VULKAN */ + +#ifdef XR_USE_GRAPHICS_API_D3D11 + +#define XR_KHR_D3D11_enable 1 +#define XR_KHR_D3D11_enable_SPEC_VERSION 8 +#define XR_KHR_D3D11_ENABLE_EXTENSION_NAME "XR_KHR_D3D11_enable" +// XrGraphicsBindingD3D11KHR extends XrSessionCreateInfo +typedef struct XrGraphicsBindingD3D11KHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + ID3D11Device* device; +} XrGraphicsBindingD3D11KHR; + +typedef struct XrSwapchainImageD3D11KHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + ID3D11Texture2D* texture; +} XrSwapchainImageD3D11KHR; + +typedef struct XrGraphicsRequirementsD3D11KHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + LUID adapterLuid; + D3D_FEATURE_LEVEL minFeatureLevel; +} XrGraphicsRequirementsD3D11KHR; + +typedef XrResult (XRAPI_PTR *PFN_xrGetD3D11GraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsD3D11KHR* graphicsRequirements); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetD3D11GraphicsRequirementsKHR( + XrInstance instance, + XrSystemId systemId, + XrGraphicsRequirementsD3D11KHR* graphicsRequirements); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_GRAPHICS_API_D3D11 */ + +#ifdef XR_USE_GRAPHICS_API_D3D12 + +#define XR_KHR_D3D12_enable 1 +#define XR_KHR_D3D12_enable_SPEC_VERSION 8 +#define XR_KHR_D3D12_ENABLE_EXTENSION_NAME "XR_KHR_D3D12_enable" +// XrGraphicsBindingD3D12KHR extends XrSessionCreateInfo +typedef struct XrGraphicsBindingD3D12KHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + ID3D12Device* device; + ID3D12CommandQueue* queue; +} XrGraphicsBindingD3D12KHR; + +typedef struct XrSwapchainImageD3D12KHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + ID3D12Resource* texture; +} XrSwapchainImageD3D12KHR; + +typedef struct XrGraphicsRequirementsD3D12KHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + LUID adapterLuid; + D3D_FEATURE_LEVEL minFeatureLevel; +} XrGraphicsRequirementsD3D12KHR; + +typedef XrResult (XRAPI_PTR *PFN_xrGetD3D12GraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsD3D12KHR* graphicsRequirements); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetD3D12GraphicsRequirementsKHR( + XrInstance instance, + XrSystemId systemId, + XrGraphicsRequirementsD3D12KHR* graphicsRequirements); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_GRAPHICS_API_D3D12 */ + +#ifdef XR_USE_PLATFORM_WIN32 + +#define XR_KHR_win32_convert_performance_counter_time 1 +#define XR_KHR_win32_convert_performance_counter_time_SPEC_VERSION 1 +#define XR_KHR_WIN32_CONVERT_PERFORMANCE_COUNTER_TIME_EXTENSION_NAME "XR_KHR_win32_convert_performance_counter_time" +typedef XrResult (XRAPI_PTR *PFN_xrConvertWin32PerformanceCounterToTimeKHR)(XrInstance instance, const LARGE_INTEGER* performanceCounter, XrTime* time); +typedef XrResult (XRAPI_PTR *PFN_xrConvertTimeToWin32PerformanceCounterKHR)(XrInstance instance, XrTime time, LARGE_INTEGER* performanceCounter); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrConvertWin32PerformanceCounterToTimeKHR( + XrInstance instance, + const LARGE_INTEGER* performanceCounter, + XrTime* time); + +XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimeToWin32PerformanceCounterKHR( + XrInstance instance, + XrTime time, + LARGE_INTEGER* performanceCounter); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_PLATFORM_WIN32 */ + +#ifdef XR_USE_TIMESPEC + +#define XR_KHR_convert_timespec_time 1 +#define XR_KHR_convert_timespec_time_SPEC_VERSION 1 +#define XR_KHR_CONVERT_TIMESPEC_TIME_EXTENSION_NAME "XR_KHR_convert_timespec_time" +typedef XrResult (XRAPI_PTR *PFN_xrConvertTimespecTimeToTimeKHR)(XrInstance instance, const struct timespec* timespecTime, XrTime* time); +typedef XrResult (XRAPI_PTR *PFN_xrConvertTimeToTimespecTimeKHR)(XrInstance instance, XrTime time, struct timespec* timespecTime); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimespecTimeToTimeKHR( + XrInstance instance, + const struct timespec* timespecTime, + XrTime* time); + +XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimeToTimespecTimeKHR( + XrInstance instance, + XrTime time, + struct timespec* timespecTime); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_TIMESPEC */ + +#ifdef XR_USE_PLATFORM_ANDROID + +#define XR_KHR_loader_init_android 1 +#define XR_KHR_loader_init_android_SPEC_VERSION 1 +#define XR_KHR_LOADER_INIT_ANDROID_EXTENSION_NAME "XR_KHR_loader_init_android" +typedef struct XrLoaderInitInfoAndroidKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + void* XR_MAY_ALIAS applicationVM; + void* XR_MAY_ALIAS applicationContext; +} XrLoaderInitInfoAndroidKHR; + +#endif /* XR_USE_PLATFORM_ANDROID */ + +#ifdef XR_USE_GRAPHICS_API_VULKAN + +#define XR_KHR_vulkan_enable2 1 +#define XR_KHR_vulkan_enable2_SPEC_VERSION 2 +#define XR_KHR_VULKAN_ENABLE2_EXTENSION_NAME "XR_KHR_vulkan_enable2" +typedef XrFlags64 XrVulkanInstanceCreateFlagsKHR; + +// Flag bits for XrVulkanInstanceCreateFlagsKHR + +typedef XrFlags64 XrVulkanDeviceCreateFlagsKHR; + +// Flag bits for XrVulkanDeviceCreateFlagsKHR + +typedef struct XrVulkanInstanceCreateInfoKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSystemId systemId; + XrVulkanInstanceCreateFlagsKHR createFlags; + PFN_vkGetInstanceProcAddr pfnGetInstanceProcAddr; + const VkInstanceCreateInfo* vulkanCreateInfo; + const VkAllocationCallbacks* vulkanAllocator; +} XrVulkanInstanceCreateInfoKHR; + +typedef struct XrVulkanDeviceCreateInfoKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSystemId systemId; + XrVulkanDeviceCreateFlagsKHR createFlags; + PFN_vkGetInstanceProcAddr pfnGetInstanceProcAddr; + VkPhysicalDevice vulkanPhysicalDevice; + const VkDeviceCreateInfo* vulkanCreateInfo; + const VkAllocationCallbacks* vulkanAllocator; +} XrVulkanDeviceCreateInfoKHR; + +typedef XrGraphicsBindingVulkanKHR XrGraphicsBindingVulkan2KHR; + +typedef struct XrVulkanGraphicsDeviceGetInfoKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSystemId systemId; + VkInstance vulkanInstance; +} XrVulkanGraphicsDeviceGetInfoKHR; + +typedef XrSwapchainImageVulkanKHR XrSwapchainImageVulkan2KHR; + +typedef XrGraphicsRequirementsVulkanKHR XrGraphicsRequirementsVulkan2KHR; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateVulkanInstanceKHR)(XrInstance instance, const XrVulkanInstanceCreateInfoKHR* createInfo, VkInstance* vulkanInstance, VkResult* vulkanResult); +typedef XrResult (XRAPI_PTR *PFN_xrCreateVulkanDeviceKHR)(XrInstance instance, const XrVulkanDeviceCreateInfoKHR* createInfo, VkDevice* vulkanDevice, VkResult* vulkanResult); +typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsDevice2KHR)(XrInstance instance, const XrVulkanGraphicsDeviceGetInfoKHR* getInfo, VkPhysicalDevice* vulkanPhysicalDevice); +typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsRequirements2KHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsVulkanKHR* graphicsRequirements); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateVulkanInstanceKHR( + XrInstance instance, + const XrVulkanInstanceCreateInfoKHR* createInfo, + VkInstance* vulkanInstance, + VkResult* vulkanResult); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateVulkanDeviceKHR( + XrInstance instance, + const XrVulkanDeviceCreateInfoKHR* createInfo, + VkDevice* vulkanDevice, + VkResult* vulkanResult); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsDevice2KHR( + XrInstance instance, + const XrVulkanGraphicsDeviceGetInfoKHR* getInfo, + VkPhysicalDevice* vulkanPhysicalDevice); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsRequirements2KHR( + XrInstance instance, + XrSystemId systemId, + XrGraphicsRequirementsVulkanKHR* graphicsRequirements); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_GRAPHICS_API_VULKAN */ + +#ifdef XR_USE_PLATFORM_EGL + +#define XR_MNDX_egl_enable 1 +#define XR_MNDX_egl_enable_SPEC_VERSION 1 +#define XR_MNDX_EGL_ENABLE_EXTENSION_NAME "XR_MNDX_egl_enable" +// XrGraphicsBindingEGLMNDX extends XrSessionCreateInfo +typedef struct XrGraphicsBindingEGLMNDX { + XrStructureType type; + const void* XR_MAY_ALIAS next; + PFNEGLGETPROCADDRESSPROC getProcAddress; + EGLDisplay display; + EGLConfig config; + EGLContext context; +} XrGraphicsBindingEGLMNDX; + +#endif /* XR_USE_PLATFORM_EGL */ + +#ifdef XR_USE_PLATFORM_WIN32 + +#define XR_MSFT_perception_anchor_interop 1 +#define XR_MSFT_perception_anchor_interop_SPEC_VERSION 1 +#define XR_MSFT_PERCEPTION_ANCHOR_INTEROP_EXTENSION_NAME "XR_MSFT_perception_anchor_interop" +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorFromPerceptionAnchorMSFT)(XrSession session, IUnknown* perceptionAnchor, XrSpatialAnchorMSFT* anchor); +typedef XrResult (XRAPI_PTR *PFN_xrTryGetPerceptionAnchorFromSpatialAnchorMSFT)(XrSession session, XrSpatialAnchorMSFT anchor, IUnknown** perceptionAnchor); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorFromPerceptionAnchorMSFT( + XrSession session, + IUnknown* perceptionAnchor, + XrSpatialAnchorMSFT* anchor); + +XRAPI_ATTR XrResult XRAPI_CALL xrTryGetPerceptionAnchorFromSpatialAnchorMSFT( + XrSession session, + XrSpatialAnchorMSFT anchor, + IUnknown** perceptionAnchor); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_PLATFORM_WIN32 */ + +#ifdef XR_USE_PLATFORM_WIN32 + +#define XR_MSFT_holographic_window_attachment 1 +#define XR_MSFT_holographic_window_attachment_SPEC_VERSION 1 +#define XR_MSFT_HOLOGRAPHIC_WINDOW_ATTACHMENT_EXTENSION_NAME "XR_MSFT_holographic_window_attachment" +#ifdef XR_USE_PLATFORM_WIN32 +// XrHolographicWindowAttachmentMSFT extends XrSessionCreateInfo +typedef struct XrHolographicWindowAttachmentMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + IUnknown* holographicSpace; + IUnknown* coreWindow; +} XrHolographicWindowAttachmentMSFT; +#endif // XR_USE_PLATFORM_WIN32 + +#endif /* XR_USE_PLATFORM_WIN32 */ + +#ifdef XR_USE_PLATFORM_ANDROID + +#define XR_FB_android_surface_swapchain_create 1 +#define XR_FB_android_surface_swapchain_create_SPEC_VERSION 1 +#define XR_FB_ANDROID_SURFACE_SWAPCHAIN_CREATE_EXTENSION_NAME "XR_FB_android_surface_swapchain_create" +typedef XrFlags64 XrAndroidSurfaceSwapchainFlagsFB; + +// Flag bits for XrAndroidSurfaceSwapchainFlagsFB +static const XrAndroidSurfaceSwapchainFlagsFB XR_ANDROID_SURFACE_SWAPCHAIN_SYNCHRONOUS_BIT_FB = 0x00000001; +static const XrAndroidSurfaceSwapchainFlagsFB XR_ANDROID_SURFACE_SWAPCHAIN_USE_TIMESTAMPS_BIT_FB = 0x00000002; + +#ifdef XR_USE_PLATFORM_ANDROID +// XrAndroidSurfaceSwapchainCreateInfoFB extends XrSwapchainCreateInfo +typedef struct XrAndroidSurfaceSwapchainCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAndroidSurfaceSwapchainFlagsFB createFlags; +} XrAndroidSurfaceSwapchainCreateInfoFB; +#endif // XR_USE_PLATFORM_ANDROID + +#endif /* XR_USE_PLATFORM_ANDROID */ + +#ifdef XR_USE_PLATFORM_WIN32 + +#define XR_OCULUS_audio_device_guid 1 +#define XR_OCULUS_audio_device_guid_SPEC_VERSION 1 +#define XR_OCULUS_AUDIO_DEVICE_GUID_EXTENSION_NAME "XR_OCULUS_audio_device_guid" +#define XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS 128 +typedef XrResult (XRAPI_PTR *PFN_xrGetAudioOutputDeviceGuidOculus)(XrInstance instance, wchar_t buffer[XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS]); +typedef XrResult (XRAPI_PTR *PFN_xrGetAudioInputDeviceGuidOculus)(XrInstance instance, wchar_t buffer[XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS]); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetAudioOutputDeviceGuidOculus( + XrInstance instance, + wchar_t buffer[XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS]); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetAudioInputDeviceGuidOculus( + XrInstance instance, + wchar_t buffer[XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS]); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_PLATFORM_WIN32 */ + +#ifdef XR_USE_GRAPHICS_API_VULKAN + +#define XR_FB_foveation_vulkan 1 +#define XR_FB_foveation_vulkan_SPEC_VERSION 1 +#define XR_FB_FOVEATION_VULKAN_EXTENSION_NAME "XR_FB_foveation_vulkan" +// XrSwapchainImageFoveationVulkanFB extends XrSwapchainImageVulkanKHR +typedef struct XrSwapchainImageFoveationVulkanFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + VkImage image; + uint32_t width; + uint32_t height; +} XrSwapchainImageFoveationVulkanFB; + +#endif /* XR_USE_GRAPHICS_API_VULKAN */ + +#ifdef XR_USE_PLATFORM_ANDROID + +#define XR_FB_swapchain_update_state_android_surface 1 +#define XR_FB_swapchain_update_state_android_surface_SPEC_VERSION 1 +#define XR_FB_SWAPCHAIN_UPDATE_STATE_ANDROID_SURFACE_EXTENSION_NAME "XR_FB_swapchain_update_state_android_surface" +#ifdef XR_USE_PLATFORM_ANDROID +typedef struct XrSwapchainStateAndroidSurfaceDimensionsFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t width; + uint32_t height; +} XrSwapchainStateAndroidSurfaceDimensionsFB; +#endif // XR_USE_PLATFORM_ANDROID + +#endif /* XR_USE_PLATFORM_ANDROID */ + +#ifdef XR_USE_GRAPHICS_API_OPENGL_ES + +#define XR_FB_swapchain_update_state_opengl_es 1 +#define XR_FB_swapchain_update_state_opengl_es_SPEC_VERSION 1 +#define XR_FB_SWAPCHAIN_UPDATE_STATE_OPENGL_ES_EXTENSION_NAME "XR_FB_swapchain_update_state_opengl_es" +#ifdef XR_USE_GRAPHICS_API_OPENGL_ES +typedef struct XrSwapchainStateSamplerOpenGLESFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + EGLenum minFilter; + EGLenum magFilter; + EGLenum wrapModeS; + EGLenum wrapModeT; + EGLenum swizzleRed; + EGLenum swizzleGreen; + EGLenum swizzleBlue; + EGLenum swizzleAlpha; + float maxAnisotropy; + XrColor4f borderColor; +} XrSwapchainStateSamplerOpenGLESFB; +#endif // XR_USE_GRAPHICS_API_OPENGL_ES + +#endif /* XR_USE_GRAPHICS_API_OPENGL_ES */ + +#ifdef XR_USE_GRAPHICS_API_VULKAN + +#define XR_FB_swapchain_update_state_vulkan 1 +#define XR_FB_swapchain_update_state_vulkan_SPEC_VERSION 1 +#define XR_FB_SWAPCHAIN_UPDATE_STATE_VULKAN_EXTENSION_NAME "XR_FB_swapchain_update_state_vulkan" +#ifdef XR_USE_GRAPHICS_API_VULKAN +typedef struct XrSwapchainStateSamplerVulkanFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + VkFilter minFilter; + VkFilter magFilter; + VkSamplerMipmapMode mipmapMode; + VkSamplerAddressMode wrapModeS; + VkSamplerAddressMode wrapModeT; + VkComponentSwizzle swizzleRed; + VkComponentSwizzle swizzleGreen; + VkComponentSwizzle swizzleBlue; + VkComponentSwizzle swizzleAlpha; + float maxAnisotropy; + XrColor4f borderColor; +} XrSwapchainStateSamplerVulkanFB; +#endif // XR_USE_GRAPHICS_API_VULKAN + +#endif /* XR_USE_GRAPHICS_API_VULKAN */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/thirdparty/openxr/include/openxr/openxr_platform_defines.h b/thirdparty/openxr/include/openxr/openxr_platform_defines.h new file mode 100644 index 0000000000..31fa05a0c8 --- /dev/null +++ b/thirdparty/openxr/include/openxr/openxr_platform_defines.h @@ -0,0 +1,110 @@ +/* +** Copyright (c) 2017-2022, The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +#ifndef OPENXR_PLATFORM_DEFINES_H_ +#define OPENXR_PLATFORM_DEFINES_H_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Platform-specific calling convention macros. + * + * Platforms should define these so that OpenXR clients call OpenXR functions + * with the same calling conventions that the OpenXR implementation expects. + * + * XRAPI_ATTR - Placed before the return type in function declarations. + * Useful for C++11 and GCC/Clang-style function attribute syntax. + * XRAPI_CALL - Placed after the return type in function declarations. + * Useful for MSVC-style calling convention syntax. + * XRAPI_PTR - Placed between the '(' and '*' in function pointer types. + * + * Function declaration: XRAPI_ATTR void XRAPI_CALL xrFunction(void); + * Function pointer type: typedef void (XRAPI_PTR *PFN_xrFunction)(void); + */ +#if defined(_WIN32) +#define XRAPI_ATTR +// On Windows, functions use the stdcall convention +#define XRAPI_CALL __stdcall +#define XRAPI_PTR XRAPI_CALL +#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7 +#error "API not supported for the 'armeabi' NDK ABI" +#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE) +// On Android 32-bit ARM targets, functions use the "hardfloat" +// calling convention, i.e. float parameters are passed in registers. This +// is true even if the rest of the application passes floats on the stack, +// as it does by default when compiling for the armeabi-v7a NDK ABI. +#define XRAPI_ATTR __attribute__((pcs("aapcs-vfp"))) +#define XRAPI_CALL +#define XRAPI_PTR XRAPI_ATTR +#else +// On other platforms, use the default calling convention +#define XRAPI_ATTR +#define XRAPI_CALL +#define XRAPI_PTR +#endif + +#include <stddef.h> + +#if !defined(XR_NO_STDINT_H) +#if defined(_MSC_VER) && (_MSC_VER < 1600) +typedef signed __int8 int8_t; +typedef unsigned __int8 uint8_t; +typedef signed __int16 int16_t; +typedef unsigned __int16 uint16_t; +typedef signed __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +#include <stdint.h> +#endif +#endif // !defined( XR_NO_STDINT_H ) + +// XR_PTR_SIZE (in bytes) +#if (defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)) +#define XR_PTR_SIZE 8 +#else +#define XR_PTR_SIZE 4 +#endif + +// Needed so we can use clang __has_feature portably. +#if !defined(XR_COMPILER_HAS_FEATURE) +#if defined(__clang__) +#define XR_COMPILER_HAS_FEATURE(x) __has_feature(x) +#else +#define XR_COMPILER_HAS_FEATURE(x) 0 +#endif +#endif + +// Identifies if the current compiler has C++11 support enabled. +// Does not by itself identify if any given C++11 feature is present. +#if !defined(XR_CPP11_ENABLED) && defined(__cplusplus) +#if defined(__GNUC__) && defined(__GXX_EXPERIMENTAL_CXX0X__) +#define XR_CPP11_ENABLED 1 +#elif defined(_MSC_VER) && (_MSC_VER >= 1600) +#define XR_CPP11_ENABLED 1 +#elif (__cplusplus >= 201103L) // 201103 is the first C++11 version. +#define XR_CPP11_ENABLED 1 +#endif +#endif + +// Identifies if the current compiler supports C++11 nullptr. +#if !defined(XR_CPP_NULLPTR_SUPPORTED) +#if defined(XR_CPP11_ENABLED) && \ + ((defined(__clang__) && XR_COMPILER_HAS_FEATURE(cxx_nullptr)) || \ + (defined(__GNUC__) && (((__GNUC__ * 1000) + __GNUC_MINOR__) >= 4006)) || \ + (defined(_MSC_VER) && (_MSC_VER >= 1600)) || \ + (defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 403))) +#define XR_CPP_NULLPTR_SUPPORTED 1 +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/thirdparty/openxr/include/openxr/openxr_reflection.h b/thirdparty/openxr/include/openxr/openxr_reflection.h new file mode 100644 index 0000000000..2bc14be600 --- /dev/null +++ b/thirdparty/openxr/include/openxr/openxr_reflection.h @@ -0,0 +1,2746 @@ +#ifndef OPENXR_REFLECTION_H_ +#define OPENXR_REFLECTION_H_ 1 + +/* +** Copyright (c) 2017-2022, The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos OpenXR XML API Registry. +** +*/ + +#include "openxr.h" + +/* +This file contains expansion macros (X Macros) for OpenXR enumerations and structures. +Example of how to use expansion macros to make an enum-to-string function: + +#define XR_ENUM_CASE_STR(name, val) case name: return #name; +#define XR_ENUM_STR(enumType) \ + constexpr const char* XrEnumStr(enumType e) { \ + switch (e) { \ + XR_LIST_ENUM_##enumType(XR_ENUM_CASE_STR) \ + default: return "Unknown"; \ + } \ + } \ + +XR_ENUM_STR(XrResult); +*/ + +#define XR_LIST_ENUM_XrResult(_) \ + _(XR_SUCCESS, 0) \ + _(XR_TIMEOUT_EXPIRED, 1) \ + _(XR_SESSION_LOSS_PENDING, 3) \ + _(XR_EVENT_UNAVAILABLE, 4) \ + _(XR_SPACE_BOUNDS_UNAVAILABLE, 7) \ + _(XR_SESSION_NOT_FOCUSED, 8) \ + _(XR_FRAME_DISCARDED, 9) \ + _(XR_ERROR_VALIDATION_FAILURE, -1) \ + _(XR_ERROR_RUNTIME_FAILURE, -2) \ + _(XR_ERROR_OUT_OF_MEMORY, -3) \ + _(XR_ERROR_API_VERSION_UNSUPPORTED, -4) \ + _(XR_ERROR_INITIALIZATION_FAILED, -6) \ + _(XR_ERROR_FUNCTION_UNSUPPORTED, -7) \ + _(XR_ERROR_FEATURE_UNSUPPORTED, -8) \ + _(XR_ERROR_EXTENSION_NOT_PRESENT, -9) \ + _(XR_ERROR_LIMIT_REACHED, -10) \ + _(XR_ERROR_SIZE_INSUFFICIENT, -11) \ + _(XR_ERROR_HANDLE_INVALID, -12) \ + _(XR_ERROR_INSTANCE_LOST, -13) \ + _(XR_ERROR_SESSION_RUNNING, -14) \ + _(XR_ERROR_SESSION_NOT_RUNNING, -16) \ + _(XR_ERROR_SESSION_LOST, -17) \ + _(XR_ERROR_SYSTEM_INVALID, -18) \ + _(XR_ERROR_PATH_INVALID, -19) \ + _(XR_ERROR_PATH_COUNT_EXCEEDED, -20) \ + _(XR_ERROR_PATH_FORMAT_INVALID, -21) \ + _(XR_ERROR_PATH_UNSUPPORTED, -22) \ + _(XR_ERROR_LAYER_INVALID, -23) \ + _(XR_ERROR_LAYER_LIMIT_EXCEEDED, -24) \ + _(XR_ERROR_SWAPCHAIN_RECT_INVALID, -25) \ + _(XR_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED, -26) \ + _(XR_ERROR_ACTION_TYPE_MISMATCH, -27) \ + _(XR_ERROR_SESSION_NOT_READY, -28) \ + _(XR_ERROR_SESSION_NOT_STOPPING, -29) \ + _(XR_ERROR_TIME_INVALID, -30) \ + _(XR_ERROR_REFERENCE_SPACE_UNSUPPORTED, -31) \ + _(XR_ERROR_FILE_ACCESS_ERROR, -32) \ + _(XR_ERROR_FILE_CONTENTS_INVALID, -33) \ + _(XR_ERROR_FORM_FACTOR_UNSUPPORTED, -34) \ + _(XR_ERROR_FORM_FACTOR_UNAVAILABLE, -35) \ + _(XR_ERROR_API_LAYER_NOT_PRESENT, -36) \ + _(XR_ERROR_CALL_ORDER_INVALID, -37) \ + _(XR_ERROR_GRAPHICS_DEVICE_INVALID, -38) \ + _(XR_ERROR_POSE_INVALID, -39) \ + _(XR_ERROR_INDEX_OUT_OF_RANGE, -40) \ + _(XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED, -41) \ + _(XR_ERROR_ENVIRONMENT_BLEND_MODE_UNSUPPORTED, -42) \ + _(XR_ERROR_NAME_DUPLICATED, -44) \ + _(XR_ERROR_NAME_INVALID, -45) \ + _(XR_ERROR_ACTIONSET_NOT_ATTACHED, -46) \ + _(XR_ERROR_ACTIONSETS_ALREADY_ATTACHED, -47) \ + _(XR_ERROR_LOCALIZED_NAME_DUPLICATED, -48) \ + _(XR_ERROR_LOCALIZED_NAME_INVALID, -49) \ + _(XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING, -50) \ + _(XR_ERROR_RUNTIME_UNAVAILABLE, -51) \ + _(XR_ERROR_ANDROID_THREAD_SETTINGS_ID_INVALID_KHR, -1000003000) \ + _(XR_ERROR_ANDROID_THREAD_SETTINGS_FAILURE_KHR, -1000003001) \ + _(XR_ERROR_CREATE_SPATIAL_ANCHOR_FAILED_MSFT, -1000039001) \ + _(XR_ERROR_SECONDARY_VIEW_CONFIGURATION_TYPE_NOT_ENABLED_MSFT, -1000053000) \ + _(XR_ERROR_CONTROLLER_MODEL_KEY_INVALID_MSFT, -1000055000) \ + _(XR_ERROR_REPROJECTION_MODE_UNSUPPORTED_MSFT, -1000066000) \ + _(XR_ERROR_COMPUTE_NEW_SCENE_NOT_COMPLETED_MSFT, -1000097000) \ + _(XR_ERROR_SCENE_COMPONENT_ID_INVALID_MSFT, -1000097001) \ + _(XR_ERROR_SCENE_COMPONENT_TYPE_MISMATCH_MSFT, -1000097002) \ + _(XR_ERROR_SCENE_MESH_BUFFER_ID_INVALID_MSFT, -1000097003) \ + _(XR_ERROR_SCENE_COMPUTE_FEATURE_INCOMPATIBLE_MSFT, -1000097004) \ + _(XR_ERROR_SCENE_COMPUTE_CONSISTENCY_MISMATCH_MSFT, -1000097005) \ + _(XR_ERROR_DISPLAY_REFRESH_RATE_UNSUPPORTED_FB, -1000101000) \ + _(XR_ERROR_COLOR_SPACE_UNSUPPORTED_FB, -1000108000) \ + _(XR_ERROR_UNEXPECTED_STATE_PASSTHROUGH_FB, -1000118000) \ + _(XR_ERROR_FEATURE_ALREADY_CREATED_PASSTHROUGH_FB, -1000118001) \ + _(XR_ERROR_FEATURE_REQUIRED_PASSTHROUGH_FB, -1000118002) \ + _(XR_ERROR_NOT_PERMITTED_PASSTHROUGH_FB, -1000118003) \ + _(XR_ERROR_INSUFFICIENT_RESOURCES_PASSTHROUGH_FB, -1000118004) \ + _(XR_ERROR_UNKNOWN_PASSTHROUGH_FB, -1000118050) \ + _(XR_ERROR_RENDER_MODEL_KEY_INVALID_FB, -1000119000) \ + _(XR_RENDER_MODEL_UNAVAILABLE_FB, 1000119020) \ + _(XR_ERROR_MARKER_NOT_TRACKED_VARJO, -1000124000) \ + _(XR_ERROR_MARKER_ID_INVALID_VARJO, -1000124001) \ + _(XR_ERROR_SPATIAL_ANCHOR_NAME_NOT_FOUND_MSFT, -1000142001) \ + _(XR_ERROR_SPATIAL_ANCHOR_NAME_INVALID_MSFT, -1000142002) \ + _(XR_RESULT_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrStructureType(_) \ + _(XR_TYPE_UNKNOWN, 0) \ + _(XR_TYPE_API_LAYER_PROPERTIES, 1) \ + _(XR_TYPE_EXTENSION_PROPERTIES, 2) \ + _(XR_TYPE_INSTANCE_CREATE_INFO, 3) \ + _(XR_TYPE_SYSTEM_GET_INFO, 4) \ + _(XR_TYPE_SYSTEM_PROPERTIES, 5) \ + _(XR_TYPE_VIEW_LOCATE_INFO, 6) \ + _(XR_TYPE_VIEW, 7) \ + _(XR_TYPE_SESSION_CREATE_INFO, 8) \ + _(XR_TYPE_SWAPCHAIN_CREATE_INFO, 9) \ + _(XR_TYPE_SESSION_BEGIN_INFO, 10) \ + _(XR_TYPE_VIEW_STATE, 11) \ + _(XR_TYPE_FRAME_END_INFO, 12) \ + _(XR_TYPE_HAPTIC_VIBRATION, 13) \ + _(XR_TYPE_EVENT_DATA_BUFFER, 16) \ + _(XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING, 17) \ + _(XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED, 18) \ + _(XR_TYPE_ACTION_STATE_BOOLEAN, 23) \ + _(XR_TYPE_ACTION_STATE_FLOAT, 24) \ + _(XR_TYPE_ACTION_STATE_VECTOR2F, 25) \ + _(XR_TYPE_ACTION_STATE_POSE, 27) \ + _(XR_TYPE_ACTION_SET_CREATE_INFO, 28) \ + _(XR_TYPE_ACTION_CREATE_INFO, 29) \ + _(XR_TYPE_INSTANCE_PROPERTIES, 32) \ + _(XR_TYPE_FRAME_WAIT_INFO, 33) \ + _(XR_TYPE_COMPOSITION_LAYER_PROJECTION, 35) \ + _(XR_TYPE_COMPOSITION_LAYER_QUAD, 36) \ + _(XR_TYPE_REFERENCE_SPACE_CREATE_INFO, 37) \ + _(XR_TYPE_ACTION_SPACE_CREATE_INFO, 38) \ + _(XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING, 40) \ + _(XR_TYPE_VIEW_CONFIGURATION_VIEW, 41) \ + _(XR_TYPE_SPACE_LOCATION, 42) \ + _(XR_TYPE_SPACE_VELOCITY, 43) \ + _(XR_TYPE_FRAME_STATE, 44) \ + _(XR_TYPE_VIEW_CONFIGURATION_PROPERTIES, 45) \ + _(XR_TYPE_FRAME_BEGIN_INFO, 46) \ + _(XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW, 48) \ + _(XR_TYPE_EVENT_DATA_EVENTS_LOST, 49) \ + _(XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING, 51) \ + _(XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED, 52) \ + _(XR_TYPE_INTERACTION_PROFILE_STATE, 53) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO, 55) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO, 56) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO, 57) \ + _(XR_TYPE_ACTION_STATE_GET_INFO, 58) \ + _(XR_TYPE_HAPTIC_ACTION_INFO, 59) \ + _(XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO, 60) \ + _(XR_TYPE_ACTIONS_SYNC_INFO, 61) \ + _(XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO, 62) \ + _(XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO, 63) \ + _(XR_TYPE_COMPOSITION_LAYER_CUBE_KHR, 1000006000) \ + _(XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR, 1000008000) \ + _(XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR, 1000010000) \ + _(XR_TYPE_VULKAN_SWAPCHAIN_FORMAT_LIST_CREATE_INFO_KHR, 1000014000) \ + _(XR_TYPE_EVENT_DATA_PERF_SETTINGS_EXT, 1000015000) \ + _(XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR, 1000017000) \ + _(XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR, 1000018000) \ + _(XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, 1000019000) \ + _(XR_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT, 1000019001) \ + _(XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, 1000019002) \ + _(XR_TYPE_DEBUG_UTILS_LABEL_EXT, 1000019003) \ + _(XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR, 1000023000) \ + _(XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR, 1000023001) \ + _(XR_TYPE_GRAPHICS_BINDING_OPENGL_XCB_KHR, 1000023002) \ + _(XR_TYPE_GRAPHICS_BINDING_OPENGL_WAYLAND_KHR, 1000023003) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR, 1000023004) \ + _(XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR, 1000023005) \ + _(XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR, 1000024001) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR, 1000024002) \ + _(XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR, 1000024003) \ + _(XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR, 1000025000) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR, 1000025001) \ + _(XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR, 1000025002) \ + _(XR_TYPE_GRAPHICS_BINDING_D3D11_KHR, 1000027000) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR, 1000027001) \ + _(XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR, 1000027002) \ + _(XR_TYPE_GRAPHICS_BINDING_D3D12_KHR, 1000028000) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_D3D12_KHR, 1000028001) \ + _(XR_TYPE_GRAPHICS_REQUIREMENTS_D3D12_KHR, 1000028002) \ + _(XR_TYPE_SYSTEM_EYE_GAZE_INTERACTION_PROPERTIES_EXT, 1000030000) \ + _(XR_TYPE_EYE_GAZE_SAMPLE_TIME_EXT, 1000030001) \ + _(XR_TYPE_VISIBILITY_MASK_KHR, 1000031000) \ + _(XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR, 1000031001) \ + _(XR_TYPE_SESSION_CREATE_INFO_OVERLAY_EXTX, 1000033000) \ + _(XR_TYPE_EVENT_DATA_MAIN_SESSION_VISIBILITY_CHANGED_EXTX, 1000033003) \ + _(XR_TYPE_COMPOSITION_LAYER_COLOR_SCALE_BIAS_KHR, 1000034000) \ + _(XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_MSFT, 1000039000) \ + _(XR_TYPE_SPATIAL_ANCHOR_SPACE_CREATE_INFO_MSFT, 1000039001) \ + _(XR_TYPE_COMPOSITION_LAYER_IMAGE_LAYOUT_FB, 1000040000) \ + _(XR_TYPE_COMPOSITION_LAYER_ALPHA_BLEND_FB, 1000041001) \ + _(XR_TYPE_VIEW_CONFIGURATION_DEPTH_RANGE_EXT, 1000046000) \ + _(XR_TYPE_GRAPHICS_BINDING_EGL_MNDX, 1000048004) \ + _(XR_TYPE_SPATIAL_GRAPH_NODE_SPACE_CREATE_INFO_MSFT, 1000049000) \ + _(XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT, 1000051000) \ + _(XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT, 1000051001) \ + _(XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT, 1000051002) \ + _(XR_TYPE_HAND_JOINT_LOCATIONS_EXT, 1000051003) \ + _(XR_TYPE_HAND_JOINT_VELOCITIES_EXT, 1000051004) \ + _(XR_TYPE_SYSTEM_HAND_TRACKING_MESH_PROPERTIES_MSFT, 1000052000) \ + _(XR_TYPE_HAND_MESH_SPACE_CREATE_INFO_MSFT, 1000052001) \ + _(XR_TYPE_HAND_MESH_UPDATE_INFO_MSFT, 1000052002) \ + _(XR_TYPE_HAND_MESH_MSFT, 1000052003) \ + _(XR_TYPE_HAND_POSE_TYPE_INFO_MSFT, 1000052004) \ + _(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SESSION_BEGIN_INFO_MSFT, 1000053000) \ + _(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_STATE_MSFT, 1000053001) \ + _(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_STATE_MSFT, 1000053002) \ + _(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_END_INFO_MSFT, 1000053003) \ + _(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_LAYER_INFO_MSFT, 1000053004) \ + _(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SWAPCHAIN_CREATE_INFO_MSFT, 1000053005) \ + _(XR_TYPE_CONTROLLER_MODEL_KEY_STATE_MSFT, 1000055000) \ + _(XR_TYPE_CONTROLLER_MODEL_NODE_PROPERTIES_MSFT, 1000055001) \ + _(XR_TYPE_CONTROLLER_MODEL_PROPERTIES_MSFT, 1000055002) \ + _(XR_TYPE_CONTROLLER_MODEL_NODE_STATE_MSFT, 1000055003) \ + _(XR_TYPE_CONTROLLER_MODEL_STATE_MSFT, 1000055004) \ + _(XR_TYPE_VIEW_CONFIGURATION_VIEW_FOV_EPIC, 1000059000) \ + _(XR_TYPE_HOLOGRAPHIC_WINDOW_ATTACHMENT_MSFT, 1000063000) \ + _(XR_TYPE_COMPOSITION_LAYER_REPROJECTION_INFO_MSFT, 1000066000) \ + _(XR_TYPE_COMPOSITION_LAYER_REPROJECTION_PLANE_OVERRIDE_MSFT, 1000066001) \ + _(XR_TYPE_ANDROID_SURFACE_SWAPCHAIN_CREATE_INFO_FB, 1000070000) \ + _(XR_TYPE_COMPOSITION_LAYER_SECURE_CONTENT_FB, 1000072000) \ + _(XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE, 1000079000) \ + _(XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT, 1000080000) \ + _(XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR, 1000089000) \ + _(XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR, 1000090000) \ + _(XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR, 1000090001) \ + _(XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR, 1000090003) \ + _(XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR, 1000091000) \ + _(XR_TYPE_SCENE_OBSERVER_CREATE_INFO_MSFT, 1000097000) \ + _(XR_TYPE_SCENE_CREATE_INFO_MSFT, 1000097001) \ + _(XR_TYPE_NEW_SCENE_COMPUTE_INFO_MSFT, 1000097002) \ + _(XR_TYPE_VISUAL_MESH_COMPUTE_LOD_INFO_MSFT, 1000097003) \ + _(XR_TYPE_SCENE_COMPONENTS_MSFT, 1000097004) \ + _(XR_TYPE_SCENE_COMPONENTS_GET_INFO_MSFT, 1000097005) \ + _(XR_TYPE_SCENE_COMPONENT_LOCATIONS_MSFT, 1000097006) \ + _(XR_TYPE_SCENE_COMPONENTS_LOCATE_INFO_MSFT, 1000097007) \ + _(XR_TYPE_SCENE_OBJECTS_MSFT, 1000097008) \ + _(XR_TYPE_SCENE_COMPONENT_PARENT_FILTER_INFO_MSFT, 1000097009) \ + _(XR_TYPE_SCENE_OBJECT_TYPES_FILTER_INFO_MSFT, 1000097010) \ + _(XR_TYPE_SCENE_PLANES_MSFT, 1000097011) \ + _(XR_TYPE_SCENE_PLANE_ALIGNMENT_FILTER_INFO_MSFT, 1000097012) \ + _(XR_TYPE_SCENE_MESHES_MSFT, 1000097013) \ + _(XR_TYPE_SCENE_MESH_BUFFERS_GET_INFO_MSFT, 1000097014) \ + _(XR_TYPE_SCENE_MESH_BUFFERS_MSFT, 1000097015) \ + _(XR_TYPE_SCENE_MESH_VERTEX_BUFFER_MSFT, 1000097016) \ + _(XR_TYPE_SCENE_MESH_INDICES_UINT32_MSFT, 1000097017) \ + _(XR_TYPE_SCENE_MESH_INDICES_UINT16_MSFT, 1000097018) \ + _(XR_TYPE_SERIALIZED_SCENE_FRAGMENT_DATA_GET_INFO_MSFT, 1000098000) \ + _(XR_TYPE_SCENE_DESERIALIZE_INFO_MSFT, 1000098001) \ + _(XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB, 1000101000) \ + _(XR_TYPE_VIVE_TRACKER_PATHS_HTCX, 1000103000) \ + _(XR_TYPE_EVENT_DATA_VIVE_TRACKER_CONNECTED_HTCX, 1000103001) \ + _(XR_TYPE_SYSTEM_FACIAL_TRACKING_PROPERTIES_HTC, 1000104000) \ + _(XR_TYPE_FACIAL_TRACKER_CREATE_INFO_HTC, 1000104001) \ + _(XR_TYPE_FACIAL_EXPRESSIONS_HTC, 1000104002) \ + _(XR_TYPE_SYSTEM_COLOR_SPACE_PROPERTIES_FB, 1000108000) \ + _(XR_TYPE_HAND_TRACKING_MESH_FB, 1000110001) \ + _(XR_TYPE_HAND_TRACKING_SCALE_FB, 1000110003) \ + _(XR_TYPE_HAND_TRACKING_AIM_STATE_FB, 1000111001) \ + _(XR_TYPE_HAND_TRACKING_CAPSULES_STATE_FB, 1000112000) \ + _(XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB, 1000114000) \ + _(XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB, 1000114001) \ + _(XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB, 1000114002) \ + _(XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB, 1000115000) \ + _(XR_TYPE_KEYBOARD_SPACE_CREATE_INFO_FB, 1000116009) \ + _(XR_TYPE_KEYBOARD_TRACKING_QUERY_FB, 1000116004) \ + _(XR_TYPE_SYSTEM_KEYBOARD_TRACKING_PROPERTIES_FB, 1000116002) \ + _(XR_TYPE_TRIANGLE_MESH_CREATE_INFO_FB, 1000117001) \ + _(XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES_FB, 1000118000) \ + _(XR_TYPE_PASSTHROUGH_CREATE_INFO_FB, 1000118001) \ + _(XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB, 1000118002) \ + _(XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB, 1000118003) \ + _(XR_TYPE_GEOMETRY_INSTANCE_CREATE_INFO_FB, 1000118004) \ + _(XR_TYPE_GEOMETRY_INSTANCE_TRANSFORM_FB, 1000118005) \ + _(XR_TYPE_PASSTHROUGH_STYLE_FB, 1000118020) \ + _(XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_RGBA_FB, 1000118021) \ + _(XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_MONO_FB, 1000118022) \ + _(XR_TYPE_EVENT_DATA_PASSTHROUGH_STATE_CHANGED_FB, 1000118030) \ + _(XR_TYPE_RENDER_MODEL_PATH_INFO_FB, 1000119000) \ + _(XR_TYPE_RENDER_MODEL_PROPERTIES_FB, 1000119001) \ + _(XR_TYPE_RENDER_MODEL_BUFFER_FB, 1000119002) \ + _(XR_TYPE_RENDER_MODEL_LOAD_INFO_FB, 1000119003) \ + _(XR_TYPE_SYSTEM_RENDER_MODEL_PROPERTIES_FB, 1000119004) \ + _(XR_TYPE_BINDING_MODIFICATIONS_KHR, 1000120000) \ + _(XR_TYPE_VIEW_LOCATE_FOVEATED_RENDERING_VARJO, 1000121000) \ + _(XR_TYPE_FOVEATED_VIEW_CONFIGURATION_VIEW_VARJO, 1000121001) \ + _(XR_TYPE_SYSTEM_FOVEATED_RENDERING_PROPERTIES_VARJO, 1000121002) \ + _(XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_VARJO, 1000122000) \ + _(XR_TYPE_SYSTEM_MARKER_TRACKING_PROPERTIES_VARJO, 1000124000) \ + _(XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO, 1000124001) \ + _(XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO, 1000124002) \ + _(XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT, 1000142000) \ + _(XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT, 1000142001) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_FOVEATION_VULKAN_FB, 1000160000) \ + _(XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB, 1000161000) \ + _(XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB, 1000162000) \ + _(XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB, 1000163000) \ + _(XR_TYPE_COMPOSITION_LAYER_SPACE_WARP_INFO_FB, 1000171000) \ + _(XR_TYPE_SYSTEM_SPACE_WARP_PROPERTIES_FB, 1000171001) \ + _(XR_TYPE_DIGITAL_LENS_CONTROL_ALMALENCE, 1000196000) \ + _(XR_TYPE_PASSTHROUGH_KEYBOARD_HANDS_INTENSITY_FB, 1000203002) \ + _(XR_STRUCTURE_TYPE_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrFormFactor(_) \ + _(XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY, 1) \ + _(XR_FORM_FACTOR_HANDHELD_DISPLAY, 2) \ + _(XR_FORM_FACTOR_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrViewConfigurationType(_) \ + _(XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO, 1) \ + _(XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, 2) \ + _(XR_VIEW_CONFIGURATION_TYPE_PRIMARY_QUAD_VARJO, 1000037000) \ + _(XR_VIEW_CONFIGURATION_TYPE_SECONDARY_MONO_FIRST_PERSON_OBSERVER_MSFT, 1000054000) \ + _(XR_VIEW_CONFIGURATION_TYPE_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrEnvironmentBlendMode(_) \ + _(XR_ENVIRONMENT_BLEND_MODE_OPAQUE, 1) \ + _(XR_ENVIRONMENT_BLEND_MODE_ADDITIVE, 2) \ + _(XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND, 3) \ + _(XR_ENVIRONMENT_BLEND_MODE_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrReferenceSpaceType(_) \ + _(XR_REFERENCE_SPACE_TYPE_VIEW, 1) \ + _(XR_REFERENCE_SPACE_TYPE_LOCAL, 2) \ + _(XR_REFERENCE_SPACE_TYPE_STAGE, 3) \ + _(XR_REFERENCE_SPACE_TYPE_UNBOUNDED_MSFT, 1000038000) \ + _(XR_REFERENCE_SPACE_TYPE_COMBINED_EYE_VARJO, 1000121000) \ + _(XR_REFERENCE_SPACE_TYPE_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrActionType(_) \ + _(XR_ACTION_TYPE_BOOLEAN_INPUT, 1) \ + _(XR_ACTION_TYPE_FLOAT_INPUT, 2) \ + _(XR_ACTION_TYPE_VECTOR2F_INPUT, 3) \ + _(XR_ACTION_TYPE_POSE_INPUT, 4) \ + _(XR_ACTION_TYPE_VIBRATION_OUTPUT, 100) \ + _(XR_ACTION_TYPE_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrEyeVisibility(_) \ + _(XR_EYE_VISIBILITY_BOTH, 0) \ + _(XR_EYE_VISIBILITY_LEFT, 1) \ + _(XR_EYE_VISIBILITY_RIGHT, 2) \ + _(XR_EYE_VISIBILITY_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSessionState(_) \ + _(XR_SESSION_STATE_UNKNOWN, 0) \ + _(XR_SESSION_STATE_IDLE, 1) \ + _(XR_SESSION_STATE_READY, 2) \ + _(XR_SESSION_STATE_SYNCHRONIZED, 3) \ + _(XR_SESSION_STATE_VISIBLE, 4) \ + _(XR_SESSION_STATE_FOCUSED, 5) \ + _(XR_SESSION_STATE_STOPPING, 6) \ + _(XR_SESSION_STATE_LOSS_PENDING, 7) \ + _(XR_SESSION_STATE_EXITING, 8) \ + _(XR_SESSION_STATE_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrObjectType(_) \ + _(XR_OBJECT_TYPE_UNKNOWN, 0) \ + _(XR_OBJECT_TYPE_INSTANCE, 1) \ + _(XR_OBJECT_TYPE_SESSION, 2) \ + _(XR_OBJECT_TYPE_SWAPCHAIN, 3) \ + _(XR_OBJECT_TYPE_SPACE, 4) \ + _(XR_OBJECT_TYPE_ACTION_SET, 5) \ + _(XR_OBJECT_TYPE_ACTION, 6) \ + _(XR_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT, 1000019000) \ + _(XR_OBJECT_TYPE_SPATIAL_ANCHOR_MSFT, 1000039000) \ + _(XR_OBJECT_TYPE_HAND_TRACKER_EXT, 1000051000) \ + _(XR_OBJECT_TYPE_SCENE_OBSERVER_MSFT, 1000097000) \ + _(XR_OBJECT_TYPE_SCENE_MSFT, 1000097001) \ + _(XR_OBJECT_TYPE_FACIAL_TRACKER_HTC, 1000104000) \ + _(XR_OBJECT_TYPE_FOVEATION_PROFILE_FB, 1000114000) \ + _(XR_OBJECT_TYPE_TRIANGLE_MESH_FB, 1000117000) \ + _(XR_OBJECT_TYPE_PASSTHROUGH_FB, 1000118000) \ + _(XR_OBJECT_TYPE_PASSTHROUGH_LAYER_FB, 1000118002) \ + _(XR_OBJECT_TYPE_GEOMETRY_INSTANCE_FB, 1000118004) \ + _(XR_OBJECT_TYPE_SPATIAL_ANCHOR_STORE_CONNECTION_MSFT, 1000142000) \ + _(XR_OBJECT_TYPE_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrAndroidThreadTypeKHR(_) \ + _(XR_ANDROID_THREAD_TYPE_APPLICATION_MAIN_KHR, 1) \ + _(XR_ANDROID_THREAD_TYPE_APPLICATION_WORKER_KHR, 2) \ + _(XR_ANDROID_THREAD_TYPE_RENDERER_MAIN_KHR, 3) \ + _(XR_ANDROID_THREAD_TYPE_RENDERER_WORKER_KHR, 4) \ + _(XR_ANDROID_THREAD_TYPE_MAX_ENUM_KHR, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrVisibilityMaskTypeKHR(_) \ + _(XR_VISIBILITY_MASK_TYPE_HIDDEN_TRIANGLE_MESH_KHR, 1) \ + _(XR_VISIBILITY_MASK_TYPE_VISIBLE_TRIANGLE_MESH_KHR, 2) \ + _(XR_VISIBILITY_MASK_TYPE_LINE_LOOP_KHR, 3) \ + _(XR_VISIBILITY_MASK_TYPE_MAX_ENUM_KHR, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrPerfSettingsDomainEXT(_) \ + _(XR_PERF_SETTINGS_DOMAIN_CPU_EXT, 1) \ + _(XR_PERF_SETTINGS_DOMAIN_GPU_EXT, 2) \ + _(XR_PERF_SETTINGS_DOMAIN_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrPerfSettingsSubDomainEXT(_) \ + _(XR_PERF_SETTINGS_SUB_DOMAIN_COMPOSITING_EXT, 1) \ + _(XR_PERF_SETTINGS_SUB_DOMAIN_RENDERING_EXT, 2) \ + _(XR_PERF_SETTINGS_SUB_DOMAIN_THERMAL_EXT, 3) \ + _(XR_PERF_SETTINGS_SUB_DOMAIN_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrPerfSettingsLevelEXT(_) \ + _(XR_PERF_SETTINGS_LEVEL_POWER_SAVINGS_EXT, 0) \ + _(XR_PERF_SETTINGS_LEVEL_SUSTAINED_LOW_EXT, 25) \ + _(XR_PERF_SETTINGS_LEVEL_SUSTAINED_HIGH_EXT, 50) \ + _(XR_PERF_SETTINGS_LEVEL_BOOST_EXT, 75) \ + _(XR_PERF_SETTINGS_LEVEL_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrPerfSettingsNotificationLevelEXT(_) \ + _(XR_PERF_SETTINGS_NOTIF_LEVEL_NORMAL_EXT, 0) \ + _(XR_PERF_SETTINGS_NOTIF_LEVEL_WARNING_EXT, 25) \ + _(XR_PERF_SETTINGS_NOTIF_LEVEL_IMPAIRED_EXT, 75) \ + _(XR_PERF_SETTINGS_NOTIFICATION_LEVEL_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrBlendFactorFB(_) \ + _(XR_BLEND_FACTOR_ZERO_FB, 0) \ + _(XR_BLEND_FACTOR_ONE_FB, 1) \ + _(XR_BLEND_FACTOR_SRC_ALPHA_FB, 2) \ + _(XR_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA_FB, 3) \ + _(XR_BLEND_FACTOR_DST_ALPHA_FB, 4) \ + _(XR_BLEND_FACTOR_ONE_MINUS_DST_ALPHA_FB, 5) \ + _(XR_BLEND_FACTOR_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSpatialGraphNodeTypeMSFT(_) \ + _(XR_SPATIAL_GRAPH_NODE_TYPE_STATIC_MSFT, 1) \ + _(XR_SPATIAL_GRAPH_NODE_TYPE_DYNAMIC_MSFT, 2) \ + _(XR_SPATIAL_GRAPH_NODE_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrHandEXT(_) \ + _(XR_HAND_LEFT_EXT, 1) \ + _(XR_HAND_RIGHT_EXT, 2) \ + _(XR_HAND_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrHandJointEXT(_) \ + _(XR_HAND_JOINT_PALM_EXT, 0) \ + _(XR_HAND_JOINT_WRIST_EXT, 1) \ + _(XR_HAND_JOINT_THUMB_METACARPAL_EXT, 2) \ + _(XR_HAND_JOINT_THUMB_PROXIMAL_EXT, 3) \ + _(XR_HAND_JOINT_THUMB_DISTAL_EXT, 4) \ + _(XR_HAND_JOINT_THUMB_TIP_EXT, 5) \ + _(XR_HAND_JOINT_INDEX_METACARPAL_EXT, 6) \ + _(XR_HAND_JOINT_INDEX_PROXIMAL_EXT, 7) \ + _(XR_HAND_JOINT_INDEX_INTERMEDIATE_EXT, 8) \ + _(XR_HAND_JOINT_INDEX_DISTAL_EXT, 9) \ + _(XR_HAND_JOINT_INDEX_TIP_EXT, 10) \ + _(XR_HAND_JOINT_MIDDLE_METACARPAL_EXT, 11) \ + _(XR_HAND_JOINT_MIDDLE_PROXIMAL_EXT, 12) \ + _(XR_HAND_JOINT_MIDDLE_INTERMEDIATE_EXT, 13) \ + _(XR_HAND_JOINT_MIDDLE_DISTAL_EXT, 14) \ + _(XR_HAND_JOINT_MIDDLE_TIP_EXT, 15) \ + _(XR_HAND_JOINT_RING_METACARPAL_EXT, 16) \ + _(XR_HAND_JOINT_RING_PROXIMAL_EXT, 17) \ + _(XR_HAND_JOINT_RING_INTERMEDIATE_EXT, 18) \ + _(XR_HAND_JOINT_RING_DISTAL_EXT, 19) \ + _(XR_HAND_JOINT_RING_TIP_EXT, 20) \ + _(XR_HAND_JOINT_LITTLE_METACARPAL_EXT, 21) \ + _(XR_HAND_JOINT_LITTLE_PROXIMAL_EXT, 22) \ + _(XR_HAND_JOINT_LITTLE_INTERMEDIATE_EXT, 23) \ + _(XR_HAND_JOINT_LITTLE_DISTAL_EXT, 24) \ + _(XR_HAND_JOINT_LITTLE_TIP_EXT, 25) \ + _(XR_HAND_JOINT_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrHandJointSetEXT(_) \ + _(XR_HAND_JOINT_SET_DEFAULT_EXT, 0) \ + _(XR_HAND_JOINT_SET_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrHandPoseTypeMSFT(_) \ + _(XR_HAND_POSE_TYPE_TRACKED_MSFT, 0) \ + _(XR_HAND_POSE_TYPE_REFERENCE_OPEN_PALM_MSFT, 1) \ + _(XR_HAND_POSE_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrReprojectionModeMSFT(_) \ + _(XR_REPROJECTION_MODE_DEPTH_MSFT, 1) \ + _(XR_REPROJECTION_MODE_PLANAR_FROM_DEPTH_MSFT, 2) \ + _(XR_REPROJECTION_MODE_PLANAR_MANUAL_MSFT, 3) \ + _(XR_REPROJECTION_MODE_ORIENTATION_ONLY_MSFT, 4) \ + _(XR_REPROJECTION_MODE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrHandJointsMotionRangeEXT(_) \ + _(XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT, 1) \ + _(XR_HAND_JOINTS_MOTION_RANGE_CONFORMING_TO_CONTROLLER_EXT, 2) \ + _(XR_HAND_JOINTS_MOTION_RANGE_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSceneComputeFeatureMSFT(_) \ + _(XR_SCENE_COMPUTE_FEATURE_PLANE_MSFT, 1) \ + _(XR_SCENE_COMPUTE_FEATURE_PLANE_MESH_MSFT, 2) \ + _(XR_SCENE_COMPUTE_FEATURE_VISUAL_MESH_MSFT, 3) \ + _(XR_SCENE_COMPUTE_FEATURE_COLLIDER_MESH_MSFT, 4) \ + _(XR_SCENE_COMPUTE_FEATURE_SERIALIZE_SCENE_MSFT, 1000098000) \ + _(XR_SCENE_COMPUTE_FEATURE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSceneComputeConsistencyMSFT(_) \ + _(XR_SCENE_COMPUTE_CONSISTENCY_SNAPSHOT_COMPLETE_MSFT, 1) \ + _(XR_SCENE_COMPUTE_CONSISTENCY_SNAPSHOT_INCOMPLETE_FAST_MSFT, 2) \ + _(XR_SCENE_COMPUTE_CONSISTENCY_OCCLUSION_OPTIMIZED_MSFT, 3) \ + _(XR_SCENE_COMPUTE_CONSISTENCY_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrMeshComputeLodMSFT(_) \ + _(XR_MESH_COMPUTE_LOD_COARSE_MSFT, 1) \ + _(XR_MESH_COMPUTE_LOD_MEDIUM_MSFT, 2) \ + _(XR_MESH_COMPUTE_LOD_FINE_MSFT, 3) \ + _(XR_MESH_COMPUTE_LOD_UNLIMITED_MSFT, 4) \ + _(XR_MESH_COMPUTE_LOD_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSceneComponentTypeMSFT(_) \ + _(XR_SCENE_COMPONENT_TYPE_INVALID_MSFT, -1) \ + _(XR_SCENE_COMPONENT_TYPE_OBJECT_MSFT, 1) \ + _(XR_SCENE_COMPONENT_TYPE_PLANE_MSFT, 2) \ + _(XR_SCENE_COMPONENT_TYPE_VISUAL_MESH_MSFT, 3) \ + _(XR_SCENE_COMPONENT_TYPE_COLLIDER_MESH_MSFT, 4) \ + _(XR_SCENE_COMPONENT_TYPE_SERIALIZED_SCENE_FRAGMENT_MSFT, 1000098000) \ + _(XR_SCENE_COMPONENT_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSceneObjectTypeMSFT(_) \ + _(XR_SCENE_OBJECT_TYPE_UNCATEGORIZED_MSFT, -1) \ + _(XR_SCENE_OBJECT_TYPE_BACKGROUND_MSFT, 1) \ + _(XR_SCENE_OBJECT_TYPE_WALL_MSFT, 2) \ + _(XR_SCENE_OBJECT_TYPE_FLOOR_MSFT, 3) \ + _(XR_SCENE_OBJECT_TYPE_CEILING_MSFT, 4) \ + _(XR_SCENE_OBJECT_TYPE_PLATFORM_MSFT, 5) \ + _(XR_SCENE_OBJECT_TYPE_INFERRED_MSFT, 6) \ + _(XR_SCENE_OBJECT_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrScenePlaneAlignmentTypeMSFT(_) \ + _(XR_SCENE_PLANE_ALIGNMENT_TYPE_NON_ORTHOGONAL_MSFT, 0) \ + _(XR_SCENE_PLANE_ALIGNMENT_TYPE_HORIZONTAL_MSFT, 1) \ + _(XR_SCENE_PLANE_ALIGNMENT_TYPE_VERTICAL_MSFT, 2) \ + _(XR_SCENE_PLANE_ALIGNMENT_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSceneComputeStateMSFT(_) \ + _(XR_SCENE_COMPUTE_STATE_NONE_MSFT, 0) \ + _(XR_SCENE_COMPUTE_STATE_UPDATING_MSFT, 1) \ + _(XR_SCENE_COMPUTE_STATE_COMPLETED_MSFT, 2) \ + _(XR_SCENE_COMPUTE_STATE_COMPLETED_WITH_ERROR_MSFT, 3) \ + _(XR_SCENE_COMPUTE_STATE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrEyeExpressionHTC(_) \ + _(XR_EYE_EXPRESSION_LEFT_BLINK_HTC, 0) \ + _(XR_EYE_EXPRESSION_LEFT_WIDE_HTC, 1) \ + _(XR_EYE_EXPRESSION_RIGHT_BLINK_HTC, 2) \ + _(XR_EYE_EXPRESSION_RIGHT_WIDE_HTC, 3) \ + _(XR_EYE_EXPRESSION_LEFT_SQUEEZE_HTC, 4) \ + _(XR_EYE_EXPRESSION_RIGHT_SQUEEZE_HTC, 5) \ + _(XR_EYE_EXPRESSION_LEFT_DOWN_HTC, 6) \ + _(XR_EYE_EXPRESSION_RIGHT_DOWN_HTC, 7) \ + _(XR_EYE_EXPRESSION_LEFT_OUT_HTC, 8) \ + _(XR_EYE_EXPRESSION_RIGHT_IN_HTC, 9) \ + _(XR_EYE_EXPRESSION_LEFT_IN_HTC, 10) \ + _(XR_EYE_EXPRESSION_RIGHT_OUT_HTC, 11) \ + _(XR_EYE_EXPRESSION_LEFT_UP_HTC, 12) \ + _(XR_EYE_EXPRESSION_RIGHT_UP_HTC, 13) \ + _(XR_EYE_EXPRESSION_MAX_ENUM_HTC, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrLipExpressionHTC(_) \ + _(XR_LIP_EXPRESSION_JAW_RIGHT_HTC, 0) \ + _(XR_LIP_EXPRESSION_JAW_LEFT_HTC, 1) \ + _(XR_LIP_EXPRESSION_JAW_FORWARD_HTC, 2) \ + _(XR_LIP_EXPRESSION_JAW_OPEN_HTC, 3) \ + _(XR_LIP_EXPRESSION_MOUTH_APE_SHAPE_HTC, 4) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_RIGHT_HTC, 5) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_LEFT_HTC, 6) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_RIGHT_HTC, 7) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_LEFT_HTC, 8) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_OVERTURN_HTC, 9) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_OVERTURN_HTC, 10) \ + _(XR_LIP_EXPRESSION_MOUTH_POUT_HTC, 11) \ + _(XR_LIP_EXPRESSION_MOUTH_SMILE_RIGHT_HTC, 12) \ + _(XR_LIP_EXPRESSION_MOUTH_SMILE_LEFT_HTC, 13) \ + _(XR_LIP_EXPRESSION_MOUTH_SAD_RIGHT_HTC, 14) \ + _(XR_LIP_EXPRESSION_MOUTH_SAD_LEFT_HTC, 15) \ + _(XR_LIP_EXPRESSION_CHEEK_PUFF_RIGHT_HTC, 16) \ + _(XR_LIP_EXPRESSION_CHEEK_PUFF_LEFT_HTC, 17) \ + _(XR_LIP_EXPRESSION_CHEEK_SUCK_HTC, 18) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_UPRIGHT_HTC, 19) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_UPLEFT_HTC, 20) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_DOWNRIGHT_HTC, 21) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_DOWNLEFT_HTC, 22) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_INSIDE_HTC, 23) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_INSIDE_HTC, 24) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_OVERLAY_HTC, 25) \ + _(XR_LIP_EXPRESSION_TONGUE_LONGSTEP1_HTC, 26) \ + _(XR_LIP_EXPRESSION_TONGUE_LEFT_HTC, 27) \ + _(XR_LIP_EXPRESSION_TONGUE_RIGHT_HTC, 28) \ + _(XR_LIP_EXPRESSION_TONGUE_UP_HTC, 29) \ + _(XR_LIP_EXPRESSION_TONGUE_DOWN_HTC, 30) \ + _(XR_LIP_EXPRESSION_TONGUE_ROLL_HTC, 31) \ + _(XR_LIP_EXPRESSION_TONGUE_LONGSTEP2_HTC, 32) \ + _(XR_LIP_EXPRESSION_TONGUE_UPRIGHT_MORPH_HTC, 33) \ + _(XR_LIP_EXPRESSION_TONGUE_UPLEFT_MORPH_HTC, 34) \ + _(XR_LIP_EXPRESSION_TONGUE_DOWNRIGHT_MORPH_HTC, 35) \ + _(XR_LIP_EXPRESSION_TONGUE_DOWNLEFT_MORPH_HTC, 36) \ + _(XR_LIP_EXPRESSION_MAX_ENUM_HTC, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrFacialTrackingTypeHTC(_) \ + _(XR_FACIAL_TRACKING_TYPE_EYE_DEFAULT_HTC, 1) \ + _(XR_FACIAL_TRACKING_TYPE_LIP_DEFAULT_HTC, 2) \ + _(XR_FACIAL_TRACKING_TYPE_MAX_ENUM_HTC, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrColorSpaceFB(_) \ + _(XR_COLOR_SPACE_UNMANAGED_FB, 0) \ + _(XR_COLOR_SPACE_REC2020_FB, 1) \ + _(XR_COLOR_SPACE_REC709_FB, 2) \ + _(XR_COLOR_SPACE_RIFT_CV1_FB, 3) \ + _(XR_COLOR_SPACE_RIFT_S_FB, 4) \ + _(XR_COLOR_SPACE_QUEST_FB, 5) \ + _(XR_COLOR_SPACE_P3_FB, 6) \ + _(XR_COLOR_SPACE_ADOBE_RGB_FB, 7) \ + _(XR_COLOR_SPACE_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrFoveationLevelFB(_) \ + _(XR_FOVEATION_LEVEL_NONE_FB, 0) \ + _(XR_FOVEATION_LEVEL_LOW_FB, 1) \ + _(XR_FOVEATION_LEVEL_MEDIUM_FB, 2) \ + _(XR_FOVEATION_LEVEL_HIGH_FB, 3) \ + _(XR_FOVEATION_LEVEL_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrFoveationDynamicFB(_) \ + _(XR_FOVEATION_DYNAMIC_DISABLED_FB, 0) \ + _(XR_FOVEATION_DYNAMIC_LEVEL_ENABLED_FB, 1) \ + _(XR_FOVEATION_DYNAMIC_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrWindingOrderFB(_) \ + _(XR_WINDING_ORDER_UNKNOWN_FB, 0) \ + _(XR_WINDING_ORDER_CW_FB, 1) \ + _(XR_WINDING_ORDER_CCW_FB, 2) \ + _(XR_WINDING_ORDER_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrPassthroughLayerPurposeFB(_) \ + _(XR_PASSTHROUGH_LAYER_PURPOSE_RECONSTRUCTION_FB, 0) \ + _(XR_PASSTHROUGH_LAYER_PURPOSE_PROJECTED_FB, 1) \ + _(XR_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_HANDS_FB, 1000203001) \ + _(XR_PASSTHROUGH_LAYER_PURPOSE_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_BITS_XrInstanceCreateFlags(_) + +#define XR_LIST_BITS_XrSessionCreateFlags(_) + +#define XR_LIST_BITS_XrSpaceVelocityFlags(_) \ + _(XR_SPACE_VELOCITY_LINEAR_VALID_BIT, 0x00000001) \ + _(XR_SPACE_VELOCITY_ANGULAR_VALID_BIT, 0x00000002) \ + +#define XR_LIST_BITS_XrSpaceLocationFlags(_) \ + _(XR_SPACE_LOCATION_ORIENTATION_VALID_BIT, 0x00000001) \ + _(XR_SPACE_LOCATION_POSITION_VALID_BIT, 0x00000002) \ + _(XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT, 0x00000004) \ + _(XR_SPACE_LOCATION_POSITION_TRACKED_BIT, 0x00000008) \ + +#define XR_LIST_BITS_XrSwapchainCreateFlags(_) \ + _(XR_SWAPCHAIN_CREATE_PROTECTED_CONTENT_BIT, 0x00000001) \ + _(XR_SWAPCHAIN_CREATE_STATIC_IMAGE_BIT, 0x00000002) \ + +#define XR_LIST_BITS_XrSwapchainUsageFlags(_) \ + _(XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT, 0x00000001) \ + _(XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 0x00000002) \ + _(XR_SWAPCHAIN_USAGE_UNORDERED_ACCESS_BIT, 0x00000004) \ + _(XR_SWAPCHAIN_USAGE_TRANSFER_SRC_BIT, 0x00000008) \ + _(XR_SWAPCHAIN_USAGE_TRANSFER_DST_BIT, 0x00000010) \ + _(XR_SWAPCHAIN_USAGE_SAMPLED_BIT, 0x00000020) \ + _(XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, 0x00000040) \ + _(XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_MND, 0x00000080) \ + _(XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_KHR, XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_MND) \ + +#define XR_LIST_BITS_XrCompositionLayerFlags(_) \ + _(XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT, 0x00000001) \ + _(XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT, 0x00000002) \ + _(XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT, 0x00000004) \ + +#define XR_LIST_BITS_XrViewStateFlags(_) \ + _(XR_VIEW_STATE_ORIENTATION_VALID_BIT, 0x00000001) \ + _(XR_VIEW_STATE_POSITION_VALID_BIT, 0x00000002) \ + _(XR_VIEW_STATE_ORIENTATION_TRACKED_BIT, 0x00000004) \ + _(XR_VIEW_STATE_POSITION_TRACKED_BIT, 0x00000008) \ + +#define XR_LIST_BITS_XrInputSourceLocalizedNameFlags(_) \ + _(XR_INPUT_SOURCE_LOCALIZED_NAME_USER_PATH_BIT, 0x00000001) \ + _(XR_INPUT_SOURCE_LOCALIZED_NAME_INTERACTION_PROFILE_BIT, 0x00000002) \ + _(XR_INPUT_SOURCE_LOCALIZED_NAME_COMPONENT_BIT, 0x00000004) \ + +#define XR_LIST_BITS_XrVulkanInstanceCreateFlagsKHR(_) + +#define XR_LIST_BITS_XrVulkanDeviceCreateFlagsKHR(_) + +#define XR_LIST_BITS_XrDebugUtilsMessageSeverityFlagsEXT(_) \ + _(XR_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT, 0x00000001) \ + _(XR_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT, 0x00000010) \ + _(XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT, 0x00000100) \ + _(XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, 0x00001000) \ + +#define XR_LIST_BITS_XrDebugUtilsMessageTypeFlagsEXT(_) \ + _(XR_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, 0x00000001) \ + _(XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT, 0x00000002) \ + _(XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, 0x00000004) \ + _(XR_DEBUG_UTILS_MESSAGE_TYPE_CONFORMANCE_BIT_EXT, 0x00000008) \ + +#define XR_LIST_BITS_XrOverlaySessionCreateFlagsEXTX(_) + +#define XR_LIST_BITS_XrOverlayMainSessionFlagsEXTX(_) \ + _(XR_OVERLAY_MAIN_SESSION_ENABLED_COMPOSITION_LAYER_INFO_DEPTH_BIT_EXTX, 0x00000001) \ + +#define XR_LIST_BITS_XrCompositionLayerImageLayoutFlagsFB(_) \ + _(XR_COMPOSITION_LAYER_IMAGE_LAYOUT_VERTICAL_FLIP_BIT_FB, 0x00000001) \ + +#define XR_LIST_BITS_XrAndroidSurfaceSwapchainFlagsFB(_) \ + _(XR_ANDROID_SURFACE_SWAPCHAIN_SYNCHRONOUS_BIT_FB, 0x00000001) \ + _(XR_ANDROID_SURFACE_SWAPCHAIN_USE_TIMESTAMPS_BIT_FB, 0x00000002) \ + +#define XR_LIST_BITS_XrCompositionLayerSecureContentFlagsFB(_) \ + _(XR_COMPOSITION_LAYER_SECURE_CONTENT_EXCLUDE_LAYER_BIT_FB, 0x00000001) \ + _(XR_COMPOSITION_LAYER_SECURE_CONTENT_REPLACE_LAYER_BIT_FB, 0x00000002) \ + +#define XR_LIST_BITS_XrHandTrackingAimFlagsFB(_) \ + _(XR_HAND_TRACKING_AIM_COMPUTED_BIT_FB, 0x00000001) \ + _(XR_HAND_TRACKING_AIM_VALID_BIT_FB, 0x00000002) \ + _(XR_HAND_TRACKING_AIM_INDEX_PINCHING_BIT_FB, 0x00000004) \ + _(XR_HAND_TRACKING_AIM_MIDDLE_PINCHING_BIT_FB, 0x00000008) \ + _(XR_HAND_TRACKING_AIM_RING_PINCHING_BIT_FB, 0x00000010) \ + _(XR_HAND_TRACKING_AIM_LITTLE_PINCHING_BIT_FB, 0x00000020) \ + _(XR_HAND_TRACKING_AIM_SYSTEM_GESTURE_BIT_FB, 0x00000040) \ + _(XR_HAND_TRACKING_AIM_DOMINANT_HAND_BIT_FB, 0x00000080) \ + _(XR_HAND_TRACKING_AIM_MENU_PRESSED_BIT_FB, 0x00000100) \ + +#define XR_LIST_BITS_XrSwapchainCreateFoveationFlagsFB(_) \ + _(XR_SWAPCHAIN_CREATE_FOVEATION_SCALED_BIN_BIT_FB, 0x00000001) \ + _(XR_SWAPCHAIN_CREATE_FOVEATION_FRAGMENT_DENSITY_MAP_BIT_FB, 0x00000002) \ + +#define XR_LIST_BITS_XrSwapchainStateFoveationFlagsFB(_) + +#define XR_LIST_BITS_XrKeyboardTrackingFlagsFB(_) \ + _(XR_KEYBOARD_TRACKING_EXISTS_BIT_FB, 0x00000001) \ + _(XR_KEYBOARD_TRACKING_LOCAL_BIT_FB, 0x00000002) \ + _(XR_KEYBOARD_TRACKING_REMOTE_BIT_FB, 0x00000004) \ + _(XR_KEYBOARD_TRACKING_CONNECTED_BIT_FB, 0x00000008) \ + +#define XR_LIST_BITS_XrKeyboardTrackingQueryFlagsFB(_) \ + _(XR_KEYBOARD_TRACKING_QUERY_LOCAL_BIT_FB, 0x00000002) \ + _(XR_KEYBOARD_TRACKING_QUERY_REMOTE_BIT_FB, 0x00000004) \ + +#define XR_LIST_BITS_XrTriangleMeshFlagsFB(_) \ + _(XR_TRIANGLE_MESH_MUTABLE_BIT_FB, 0x00000001) \ + +#define XR_LIST_BITS_XrPassthroughFlagsFB(_) \ + _(XR_PASSTHROUGH_IS_RUNNING_AT_CREATION_BIT_FB, 0x00000001) \ + +#define XR_LIST_BITS_XrPassthroughStateChangedFlagsFB(_) \ + _(XR_PASSTHROUGH_STATE_CHANGED_REINIT_REQUIRED_BIT_FB, 0x00000001) \ + _(XR_PASSTHROUGH_STATE_CHANGED_NON_RECOVERABLE_ERROR_BIT_FB, 0x00000002) \ + _(XR_PASSTHROUGH_STATE_CHANGED_RECOVERABLE_ERROR_BIT_FB, 0x00000004) \ + _(XR_PASSTHROUGH_STATE_CHANGED_RESTORED_ERROR_BIT_FB, 0x00000008) \ + +#define XR_LIST_BITS_XrRenderModelFlagsFB(_) + +#define XR_LIST_BITS_XrCompositionLayerSpaceWarpInfoFlagsFB(_) + +#define XR_LIST_BITS_XrDigitalLensControlFlagsALMALENCE(_) \ + _(XR_DIGITAL_LENS_CONTROL_PROCESSING_DISABLE_BIT_ALMALENCE, 0x00000001) \ + +#define XR_LIST_STRUCT_XrApiLayerProperties(_) \ + _(type) \ + _(next) \ + _(layerName) \ + _(specVersion) \ + _(layerVersion) \ + _(description) \ + +#define XR_LIST_STRUCT_XrExtensionProperties(_) \ + _(type) \ + _(next) \ + _(extensionName) \ + _(extensionVersion) \ + +#define XR_LIST_STRUCT_XrApplicationInfo(_) \ + _(applicationName) \ + _(applicationVersion) \ + _(engineName) \ + _(engineVersion) \ + _(apiVersion) \ + +#define XR_LIST_STRUCT_XrInstanceCreateInfo(_) \ + _(type) \ + _(next) \ + _(createFlags) \ + _(applicationInfo) \ + _(enabledApiLayerCount) \ + _(enabledApiLayerNames) \ + _(enabledExtensionCount) \ + _(enabledExtensionNames) \ + +#define XR_LIST_STRUCT_XrInstanceProperties(_) \ + _(type) \ + _(next) \ + _(runtimeVersion) \ + _(runtimeName) \ + +#define XR_LIST_STRUCT_XrEventDataBuffer(_) \ + _(type) \ + _(next) \ + _(varying) \ + +#define XR_LIST_STRUCT_XrSystemGetInfo(_) \ + _(type) \ + _(next) \ + _(formFactor) \ + +#define XR_LIST_STRUCT_XrSystemGraphicsProperties(_) \ + _(maxSwapchainImageHeight) \ + _(maxSwapchainImageWidth) \ + _(maxLayerCount) \ + +#define XR_LIST_STRUCT_XrSystemTrackingProperties(_) \ + _(orientationTracking) \ + _(positionTracking) \ + +#define XR_LIST_STRUCT_XrSystemProperties(_) \ + _(type) \ + _(next) \ + _(systemId) \ + _(vendorId) \ + _(systemName) \ + _(graphicsProperties) \ + _(trackingProperties) \ + +#define XR_LIST_STRUCT_XrSessionCreateInfo(_) \ + _(type) \ + _(next) \ + _(createFlags) \ + _(systemId) \ + +#define XR_LIST_STRUCT_XrVector3f(_) \ + _(x) \ + _(y) \ + _(z) \ + +#define XR_LIST_STRUCT_XrSpaceVelocity(_) \ + _(type) \ + _(next) \ + _(velocityFlags) \ + _(linearVelocity) \ + _(angularVelocity) \ + +#define XR_LIST_STRUCT_XrQuaternionf(_) \ + _(x) \ + _(y) \ + _(z) \ + _(w) \ + +#define XR_LIST_STRUCT_XrPosef(_) \ + _(orientation) \ + _(position) \ + +#define XR_LIST_STRUCT_XrReferenceSpaceCreateInfo(_) \ + _(type) \ + _(next) \ + _(referenceSpaceType) \ + _(poseInReferenceSpace) \ + +#define XR_LIST_STRUCT_XrExtent2Df(_) \ + _(width) \ + _(height) \ + +#define XR_LIST_STRUCT_XrActionSpaceCreateInfo(_) \ + _(type) \ + _(next) \ + _(action) \ + _(subactionPath) \ + _(poseInActionSpace) \ + +#define XR_LIST_STRUCT_XrSpaceLocation(_) \ + _(type) \ + _(next) \ + _(locationFlags) \ + _(pose) \ + +#define XR_LIST_STRUCT_XrViewConfigurationProperties(_) \ + _(type) \ + _(next) \ + _(viewConfigurationType) \ + _(fovMutable) \ + +#define XR_LIST_STRUCT_XrViewConfigurationView(_) \ + _(type) \ + _(next) \ + _(recommendedImageRectWidth) \ + _(maxImageRectWidth) \ + _(recommendedImageRectHeight) \ + _(maxImageRectHeight) \ + _(recommendedSwapchainSampleCount) \ + _(maxSwapchainSampleCount) \ + +#define XR_LIST_STRUCT_XrSwapchainCreateInfo(_) \ + _(type) \ + _(next) \ + _(createFlags) \ + _(usageFlags) \ + _(format) \ + _(sampleCount) \ + _(width) \ + _(height) \ + _(faceCount) \ + _(arraySize) \ + _(mipCount) \ + +#define XR_LIST_STRUCT_XrSwapchainImageBaseHeader(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSwapchainImageAcquireInfo(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSwapchainImageWaitInfo(_) \ + _(type) \ + _(next) \ + _(timeout) \ + +#define XR_LIST_STRUCT_XrSwapchainImageReleaseInfo(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSessionBeginInfo(_) \ + _(type) \ + _(next) \ + _(primaryViewConfigurationType) \ + +#define XR_LIST_STRUCT_XrFrameWaitInfo(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrFrameState(_) \ + _(type) \ + _(next) \ + _(predictedDisplayTime) \ + _(predictedDisplayPeriod) \ + _(shouldRender) \ + +#define XR_LIST_STRUCT_XrFrameBeginInfo(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrCompositionLayerBaseHeader(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + _(space) \ + +#define XR_LIST_STRUCT_XrFrameEndInfo(_) \ + _(type) \ + _(next) \ + _(displayTime) \ + _(environmentBlendMode) \ + _(layerCount) \ + _(layers) \ + +#define XR_LIST_STRUCT_XrViewLocateInfo(_) \ + _(type) \ + _(next) \ + _(viewConfigurationType) \ + _(displayTime) \ + _(space) \ + +#define XR_LIST_STRUCT_XrViewState(_) \ + _(type) \ + _(next) \ + _(viewStateFlags) \ + +#define XR_LIST_STRUCT_XrFovf(_) \ + _(angleLeft) \ + _(angleRight) \ + _(angleUp) \ + _(angleDown) \ + +#define XR_LIST_STRUCT_XrView(_) \ + _(type) \ + _(next) \ + _(pose) \ + _(fov) \ + +#define XR_LIST_STRUCT_XrActionSetCreateInfo(_) \ + _(type) \ + _(next) \ + _(actionSetName) \ + _(localizedActionSetName) \ + _(priority) \ + +#define XR_LIST_STRUCT_XrActionCreateInfo(_) \ + _(type) \ + _(next) \ + _(actionName) \ + _(actionType) \ + _(countSubactionPaths) \ + _(subactionPaths) \ + _(localizedActionName) \ + +#define XR_LIST_STRUCT_XrActionSuggestedBinding(_) \ + _(action) \ + _(binding) \ + +#define XR_LIST_STRUCT_XrInteractionProfileSuggestedBinding(_) \ + _(type) \ + _(next) \ + _(interactionProfile) \ + _(countSuggestedBindings) \ + _(suggestedBindings) \ + +#define XR_LIST_STRUCT_XrSessionActionSetsAttachInfo(_) \ + _(type) \ + _(next) \ + _(countActionSets) \ + _(actionSets) \ + +#define XR_LIST_STRUCT_XrInteractionProfileState(_) \ + _(type) \ + _(next) \ + _(interactionProfile) \ + +#define XR_LIST_STRUCT_XrActionStateGetInfo(_) \ + _(type) \ + _(next) \ + _(action) \ + _(subactionPath) \ + +#define XR_LIST_STRUCT_XrActionStateBoolean(_) \ + _(type) \ + _(next) \ + _(currentState) \ + _(changedSinceLastSync) \ + _(lastChangeTime) \ + _(isActive) \ + +#define XR_LIST_STRUCT_XrActionStateFloat(_) \ + _(type) \ + _(next) \ + _(currentState) \ + _(changedSinceLastSync) \ + _(lastChangeTime) \ + _(isActive) \ + +#define XR_LIST_STRUCT_XrVector2f(_) \ + _(x) \ + _(y) \ + +#define XR_LIST_STRUCT_XrActionStateVector2f(_) \ + _(type) \ + _(next) \ + _(currentState) \ + _(changedSinceLastSync) \ + _(lastChangeTime) \ + _(isActive) \ + +#define XR_LIST_STRUCT_XrActionStatePose(_) \ + _(type) \ + _(next) \ + _(isActive) \ + +#define XR_LIST_STRUCT_XrActiveActionSet(_) \ + _(actionSet) \ + _(subactionPath) \ + +#define XR_LIST_STRUCT_XrActionsSyncInfo(_) \ + _(type) \ + _(next) \ + _(countActiveActionSets) \ + _(activeActionSets) \ + +#define XR_LIST_STRUCT_XrBoundSourcesForActionEnumerateInfo(_) \ + _(type) \ + _(next) \ + _(action) \ + +#define XR_LIST_STRUCT_XrInputSourceLocalizedNameGetInfo(_) \ + _(type) \ + _(next) \ + _(sourcePath) \ + _(whichComponents) \ + +#define XR_LIST_STRUCT_XrHapticActionInfo(_) \ + _(type) \ + _(next) \ + _(action) \ + _(subactionPath) \ + +#define XR_LIST_STRUCT_XrHapticBaseHeader(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrBaseInStructure(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrBaseOutStructure(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrOffset2Di(_) \ + _(x) \ + _(y) \ + +#define XR_LIST_STRUCT_XrExtent2Di(_) \ + _(width) \ + _(height) \ + +#define XR_LIST_STRUCT_XrRect2Di(_) \ + _(offset) \ + _(extent) \ + +#define XR_LIST_STRUCT_XrSwapchainSubImage(_) \ + _(swapchain) \ + _(imageRect) \ + _(imageArrayIndex) \ + +#define XR_LIST_STRUCT_XrCompositionLayerProjectionView(_) \ + _(type) \ + _(next) \ + _(pose) \ + _(fov) \ + _(subImage) \ + +#define XR_LIST_STRUCT_XrCompositionLayerProjection(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + _(space) \ + _(viewCount) \ + _(views) \ + +#define XR_LIST_STRUCT_XrCompositionLayerQuad(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + _(space) \ + _(eyeVisibility) \ + _(subImage) \ + _(pose) \ + _(size) \ + +#define XR_LIST_STRUCT_XrEventDataBaseHeader(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrEventDataEventsLost(_) \ + _(type) \ + _(next) \ + _(lostEventCount) \ + +#define XR_LIST_STRUCT_XrEventDataInstanceLossPending(_) \ + _(type) \ + _(next) \ + _(lossTime) \ + +#define XR_LIST_STRUCT_XrEventDataSessionStateChanged(_) \ + _(type) \ + _(next) \ + _(session) \ + _(state) \ + _(time) \ + +#define XR_LIST_STRUCT_XrEventDataReferenceSpaceChangePending(_) \ + _(type) \ + _(next) \ + _(session) \ + _(referenceSpaceType) \ + _(changeTime) \ + _(poseValid) \ + _(poseInPreviousSpace) \ + +#define XR_LIST_STRUCT_XrEventDataInteractionProfileChanged(_) \ + _(type) \ + _(next) \ + _(session) \ + +#define XR_LIST_STRUCT_XrHapticVibration(_) \ + _(type) \ + _(next) \ + _(duration) \ + _(frequency) \ + _(amplitude) \ + +#define XR_LIST_STRUCT_XrOffset2Df(_) \ + _(x) \ + _(y) \ + +#define XR_LIST_STRUCT_XrRect2Df(_) \ + _(offset) \ + _(extent) \ + +#define XR_LIST_STRUCT_XrVector4f(_) \ + _(x) \ + _(y) \ + _(z) \ + _(w) \ + +#define XR_LIST_STRUCT_XrColor4f(_) \ + _(r) \ + _(g) \ + _(b) \ + _(a) \ + +#define XR_LIST_STRUCT_XrCompositionLayerCubeKHR(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + _(space) \ + _(eyeVisibility) \ + _(swapchain) \ + _(imageArrayIndex) \ + _(orientation) \ + +#define XR_LIST_STRUCT_XrInstanceCreateInfoAndroidKHR(_) \ + _(type) \ + _(next) \ + _(applicationVM) \ + _(applicationActivity) \ + +#define XR_LIST_STRUCT_XrCompositionLayerDepthInfoKHR(_) \ + _(type) \ + _(next) \ + _(subImage) \ + _(minDepth) \ + _(maxDepth) \ + _(nearZ) \ + _(farZ) \ + +#define XR_LIST_STRUCT_XrVulkanSwapchainFormatListCreateInfoKHR(_) \ + _(type) \ + _(next) \ + _(viewFormatCount) \ + _(viewFormats) \ + +#define XR_LIST_STRUCT_XrCompositionLayerCylinderKHR(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + _(space) \ + _(eyeVisibility) \ + _(subImage) \ + _(pose) \ + _(radius) \ + _(centralAngle) \ + _(aspectRatio) \ + +#define XR_LIST_STRUCT_XrCompositionLayerEquirectKHR(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + _(space) \ + _(eyeVisibility) \ + _(subImage) \ + _(pose) \ + _(radius) \ + _(scale) \ + _(bias) \ + +#define XR_LIST_STRUCT_XrGraphicsBindingOpenGLWin32KHR(_) \ + _(type) \ + _(next) \ + _(hDC) \ + _(hGLRC) \ + +#define XR_LIST_STRUCT_XrGraphicsBindingOpenGLXlibKHR(_) \ + _(type) \ + _(next) \ + _(xDisplay) \ + _(visualid) \ + _(glxFBConfig) \ + _(glxDrawable) \ + _(glxContext) \ + +#define XR_LIST_STRUCT_XrGraphicsBindingOpenGLXcbKHR(_) \ + _(type) \ + _(next) \ + _(connection) \ + _(screenNumber) \ + _(fbconfigid) \ + _(visualid) \ + _(glxDrawable) \ + _(glxContext) \ + +#define XR_LIST_STRUCT_XrGraphicsBindingOpenGLWaylandKHR(_) \ + _(type) \ + _(next) \ + _(display) \ + +#define XR_LIST_STRUCT_XrSwapchainImageOpenGLKHR(_) \ + _(type) \ + _(next) \ + _(image) \ + +#define XR_LIST_STRUCT_XrGraphicsRequirementsOpenGLKHR(_) \ + _(type) \ + _(next) \ + _(minApiVersionSupported) \ + _(maxApiVersionSupported) \ + +#define XR_LIST_STRUCT_XrGraphicsBindingOpenGLESAndroidKHR(_) \ + _(type) \ + _(next) \ + _(display) \ + _(config) \ + _(context) \ + +#define XR_LIST_STRUCT_XrSwapchainImageOpenGLESKHR(_) \ + _(type) \ + _(next) \ + _(image) \ + +#define XR_LIST_STRUCT_XrGraphicsRequirementsOpenGLESKHR(_) \ + _(type) \ + _(next) \ + _(minApiVersionSupported) \ + _(maxApiVersionSupported) \ + +#define XR_LIST_STRUCT_XrGraphicsBindingVulkanKHR(_) \ + _(type) \ + _(next) \ + _(instance) \ + _(physicalDevice) \ + _(device) \ + _(queueFamilyIndex) \ + _(queueIndex) \ + +#define XR_LIST_STRUCT_XrSwapchainImageVulkanKHR(_) \ + _(type) \ + _(next) \ + _(image) \ + +#define XR_LIST_STRUCT_XrGraphicsRequirementsVulkanKHR(_) \ + _(type) \ + _(next) \ + _(minApiVersionSupported) \ + _(maxApiVersionSupported) \ + +#define XR_LIST_STRUCT_XrGraphicsBindingD3D11KHR(_) \ + _(type) \ + _(next) \ + _(device) \ + +#define XR_LIST_STRUCT_XrSwapchainImageD3D11KHR(_) \ + _(type) \ + _(next) \ + _(texture) \ + +#define XR_LIST_STRUCT_XrGraphicsRequirementsD3D11KHR(_) \ + _(type) \ + _(next) \ + _(adapterLuid) \ + _(minFeatureLevel) \ + +#define XR_LIST_STRUCT_XrGraphicsBindingD3D12KHR(_) \ + _(type) \ + _(next) \ + _(device) \ + _(queue) \ + +#define XR_LIST_STRUCT_XrSwapchainImageD3D12KHR(_) \ + _(type) \ + _(next) \ + _(texture) \ + +#define XR_LIST_STRUCT_XrGraphicsRequirementsD3D12KHR(_) \ + _(type) \ + _(next) \ + _(adapterLuid) \ + _(minFeatureLevel) \ + +#define XR_LIST_STRUCT_XrVisibilityMaskKHR(_) \ + _(type) \ + _(next) \ + _(vertexCapacityInput) \ + _(vertexCountOutput) \ + _(vertices) \ + _(indexCapacityInput) \ + _(indexCountOutput) \ + _(indices) \ + +#define XR_LIST_STRUCT_XrEventDataVisibilityMaskChangedKHR(_) \ + _(type) \ + _(next) \ + _(session) \ + _(viewConfigurationType) \ + _(viewIndex) \ + +#define XR_LIST_STRUCT_XrCompositionLayerColorScaleBiasKHR(_) \ + _(type) \ + _(next) \ + _(colorScale) \ + _(colorBias) \ + +#define XR_LIST_STRUCT_XrLoaderInitInfoBaseHeaderKHR(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrLoaderInitInfoAndroidKHR(_) \ + _(type) \ + _(next) \ + _(applicationVM) \ + _(applicationContext) \ + +#define XR_LIST_STRUCT_XrVulkanInstanceCreateInfoKHR(_) \ + _(type) \ + _(next) \ + _(systemId) \ + _(createFlags) \ + _(pfnGetInstanceProcAddr) \ + _(vulkanCreateInfo) \ + _(vulkanAllocator) \ + +#define XR_LIST_STRUCT_XrVulkanDeviceCreateInfoKHR(_) \ + _(type) \ + _(next) \ + _(systemId) \ + _(createFlags) \ + _(pfnGetInstanceProcAddr) \ + _(vulkanPhysicalDevice) \ + _(vulkanCreateInfo) \ + _(vulkanAllocator) \ + +#define XR_LIST_STRUCT_XrVulkanGraphicsDeviceGetInfoKHR(_) \ + _(type) \ + _(next) \ + _(systemId) \ + _(vulkanInstance) \ + +#define XR_LIST_STRUCT_XrCompositionLayerEquirect2KHR(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + _(space) \ + _(eyeVisibility) \ + _(subImage) \ + _(pose) \ + _(radius) \ + _(centralHorizontalAngle) \ + _(upperVerticalAngle) \ + _(lowerVerticalAngle) \ + +#define XR_LIST_STRUCT_XrBindingModificationBaseHeaderKHR(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrBindingModificationsKHR(_) \ + _(type) \ + _(next) \ + _(bindingModificationCount) \ + _(bindingModifications) \ + +#define XR_LIST_STRUCT_XrEventDataPerfSettingsEXT(_) \ + _(type) \ + _(next) \ + _(domain) \ + _(subDomain) \ + _(fromLevel) \ + _(toLevel) \ + +#define XR_LIST_STRUCT_XrDebugUtilsObjectNameInfoEXT(_) \ + _(type) \ + _(next) \ + _(objectType) \ + _(objectHandle) \ + _(objectName) \ + +#define XR_LIST_STRUCT_XrDebugUtilsLabelEXT(_) \ + _(type) \ + _(next) \ + _(labelName) \ + +#define XR_LIST_STRUCT_XrDebugUtilsMessengerCallbackDataEXT(_) \ + _(type) \ + _(next) \ + _(messageId) \ + _(functionName) \ + _(message) \ + _(objectCount) \ + _(objects) \ + _(sessionLabelCount) \ + _(sessionLabels) \ + +#define XR_LIST_STRUCT_XrDebugUtilsMessengerCreateInfoEXT(_) \ + _(type) \ + _(next) \ + _(messageSeverities) \ + _(messageTypes) \ + _(userCallback) \ + _(userData) \ + +#define XR_LIST_STRUCT_XrSystemEyeGazeInteractionPropertiesEXT(_) \ + _(type) \ + _(next) \ + _(supportsEyeGazeInteraction) \ + +#define XR_LIST_STRUCT_XrEyeGazeSampleTimeEXT(_) \ + _(type) \ + _(next) \ + _(time) \ + +#define XR_LIST_STRUCT_XrSessionCreateInfoOverlayEXTX(_) \ + _(type) \ + _(next) \ + _(createFlags) \ + _(sessionLayersPlacement) \ + +#define XR_LIST_STRUCT_XrEventDataMainSessionVisibilityChangedEXTX(_) \ + _(type) \ + _(next) \ + _(visible) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrSpatialAnchorCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(space) \ + _(pose) \ + _(time) \ + +#define XR_LIST_STRUCT_XrSpatialAnchorSpaceCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(anchor) \ + _(poseInAnchorSpace) \ + +#define XR_LIST_STRUCT_XrCompositionLayerImageLayoutFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrCompositionLayerAlphaBlendFB(_) \ + _(type) \ + _(next) \ + _(srcFactorColor) \ + _(dstFactorColor) \ + _(srcFactorAlpha) \ + _(dstFactorAlpha) \ + +#define XR_LIST_STRUCT_XrViewConfigurationDepthRangeEXT(_) \ + _(type) \ + _(next) \ + _(recommendedNearZ) \ + _(minNearZ) \ + _(recommendedFarZ) \ + _(maxFarZ) \ + +#define XR_LIST_STRUCT_XrGraphicsBindingEGLMNDX(_) \ + _(type) \ + _(next) \ + _(getProcAddress) \ + _(display) \ + _(config) \ + _(context) \ + +#define XR_LIST_STRUCT_XrSpatialGraphNodeSpaceCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(nodeType) \ + _(nodeId) \ + _(pose) \ + +#define XR_LIST_STRUCT_XrSystemHandTrackingPropertiesEXT(_) \ + _(type) \ + _(next) \ + _(supportsHandTracking) \ + +#define XR_LIST_STRUCT_XrHandTrackerCreateInfoEXT(_) \ + _(type) \ + _(next) \ + _(hand) \ + _(handJointSet) \ + +#define XR_LIST_STRUCT_XrHandJointsLocateInfoEXT(_) \ + _(type) \ + _(next) \ + _(baseSpace) \ + _(time) \ + +#define XR_LIST_STRUCT_XrHandJointLocationEXT(_) \ + _(locationFlags) \ + _(pose) \ + _(radius) \ + +#define XR_LIST_STRUCT_XrHandJointVelocityEXT(_) \ + _(velocityFlags) \ + _(linearVelocity) \ + _(angularVelocity) \ + +#define XR_LIST_STRUCT_XrHandJointLocationsEXT(_) \ + _(type) \ + _(next) \ + _(isActive) \ + _(jointCount) \ + _(jointLocations) \ + +#define XR_LIST_STRUCT_XrHandJointVelocitiesEXT(_) \ + _(type) \ + _(next) \ + _(jointCount) \ + _(jointVelocities) \ + +#define XR_LIST_STRUCT_XrSystemHandTrackingMeshPropertiesMSFT(_) \ + _(type) \ + _(next) \ + _(supportsHandTrackingMesh) \ + _(maxHandMeshIndexCount) \ + _(maxHandMeshVertexCount) \ + +#define XR_LIST_STRUCT_XrHandMeshSpaceCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(handPoseType) \ + _(poseInHandMeshSpace) \ + +#define XR_LIST_STRUCT_XrHandMeshUpdateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(time) \ + _(handPoseType) \ + +#define XR_LIST_STRUCT_XrHandMeshIndexBufferMSFT(_) \ + _(indexBufferKey) \ + _(indexCapacityInput) \ + _(indexCountOutput) \ + _(indices) \ + +#define XR_LIST_STRUCT_XrHandMeshVertexMSFT(_) \ + _(position) \ + _(normal) \ + +#define XR_LIST_STRUCT_XrHandMeshVertexBufferMSFT(_) \ + _(vertexUpdateTime) \ + _(vertexCapacityInput) \ + _(vertexCountOutput) \ + _(vertices) \ + +#define XR_LIST_STRUCT_XrHandMeshMSFT(_) \ + _(type) \ + _(next) \ + _(isActive) \ + _(indexBufferChanged) \ + _(vertexBufferChanged) \ + _(indexBuffer) \ + _(vertexBuffer) \ + +#define XR_LIST_STRUCT_XrHandPoseTypeInfoMSFT(_) \ + _(type) \ + _(next) \ + _(handPoseType) \ + +#define XR_LIST_STRUCT_XrSecondaryViewConfigurationSessionBeginInfoMSFT(_) \ + _(type) \ + _(next) \ + _(viewConfigurationCount) \ + _(enabledViewConfigurationTypes) \ + +#define XR_LIST_STRUCT_XrSecondaryViewConfigurationStateMSFT(_) \ + _(type) \ + _(next) \ + _(viewConfigurationType) \ + _(active) \ + +#define XR_LIST_STRUCT_XrSecondaryViewConfigurationFrameStateMSFT(_) \ + _(type) \ + _(next) \ + _(viewConfigurationCount) \ + _(viewConfigurationStates) \ + +#define XR_LIST_STRUCT_XrSecondaryViewConfigurationLayerInfoMSFT(_) \ + _(type) \ + _(next) \ + _(viewConfigurationType) \ + _(environmentBlendMode) \ + _(layerCount) \ + _(layers) \ + +#define XR_LIST_STRUCT_XrSecondaryViewConfigurationFrameEndInfoMSFT(_) \ + _(type) \ + _(next) \ + _(viewConfigurationCount) \ + _(viewConfigurationLayersInfo) \ + +#define XR_LIST_STRUCT_XrSecondaryViewConfigurationSwapchainCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(viewConfigurationType) \ + +#define XR_LIST_STRUCT_XrControllerModelKeyStateMSFT(_) \ + _(type) \ + _(next) \ + _(modelKey) \ + +#define XR_LIST_STRUCT_XrControllerModelNodePropertiesMSFT(_) \ + _(type) \ + _(next) \ + _(parentNodeName) \ + _(nodeName) \ + +#define XR_LIST_STRUCT_XrControllerModelPropertiesMSFT(_) \ + _(type) \ + _(next) \ + _(nodeCapacityInput) \ + _(nodeCountOutput) \ + _(nodeProperties) \ + +#define XR_LIST_STRUCT_XrControllerModelNodeStateMSFT(_) \ + _(type) \ + _(next) \ + _(nodePose) \ + +#define XR_LIST_STRUCT_XrControllerModelStateMSFT(_) \ + _(type) \ + _(next) \ + _(nodeCapacityInput) \ + _(nodeCountOutput) \ + _(nodeStates) \ + +#define XR_LIST_STRUCT_XrViewConfigurationViewFovEPIC(_) \ + _(type) \ + _(next) \ + _(recommendedFov) \ + _(maxMutableFov) \ + +#define XR_LIST_STRUCT_XrHolographicWindowAttachmentMSFT(_) \ + _(type) \ + _(next) \ + _(holographicSpace) \ + _(coreWindow) \ + +#define XR_LIST_STRUCT_XrCompositionLayerReprojectionInfoMSFT(_) \ + _(type) \ + _(next) \ + _(reprojectionMode) \ + +#define XR_LIST_STRUCT_XrCompositionLayerReprojectionPlaneOverrideMSFT(_) \ + _(type) \ + _(next) \ + _(position) \ + _(normal) \ + _(velocity) \ + +#define XR_LIST_STRUCT_XrAndroidSurfaceSwapchainCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(createFlags) \ + +#define XR_LIST_STRUCT_XrSwapchainStateBaseHeaderFB(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrCompositionLayerSecureContentFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrInteractionProfileAnalogThresholdVALVE(_) \ + _(type) \ + _(next) \ + _(action) \ + _(binding) \ + _(onThreshold) \ + _(offThreshold) \ + _(onHaptic) \ + _(offHaptic) \ + +#define XR_LIST_STRUCT_XrHandJointsMotionRangeInfoEXT(_) \ + _(type) \ + _(next) \ + _(handJointsMotionRange) \ + +#define XR_LIST_STRUCT_XrUuidMSFT(_) \ + _(bytes) \ + +#define XR_LIST_STRUCT_XrSceneObserverCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSceneCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSceneSphereBoundMSFT(_) \ + _(center) \ + _(radius) \ + +#define XR_LIST_STRUCT_XrSceneOrientedBoxBoundMSFT(_) \ + _(pose) \ + _(extents) \ + +#define XR_LIST_STRUCT_XrSceneFrustumBoundMSFT(_) \ + _(pose) \ + _(fov) \ + _(farDistance) \ + +#define XR_LIST_STRUCT_XrSceneBoundsMSFT(_) \ + _(space) \ + _(time) \ + _(sphereCount) \ + _(spheres) \ + _(boxCount) \ + _(boxes) \ + _(frustumCount) \ + _(frustums) \ + +#define XR_LIST_STRUCT_XrNewSceneComputeInfoMSFT(_) \ + _(type) \ + _(next) \ + _(requestedFeatureCount) \ + _(requestedFeatures) \ + _(consistency) \ + _(bounds) \ + +#define XR_LIST_STRUCT_XrVisualMeshComputeLodInfoMSFT(_) \ + _(type) \ + _(next) \ + _(lod) \ + +#define XR_LIST_STRUCT_XrSceneComponentMSFT(_) \ + _(componentType) \ + _(id) \ + _(parentId) \ + _(updateTime) \ + +#define XR_LIST_STRUCT_XrSceneComponentsMSFT(_) \ + _(type) \ + _(next) \ + _(componentCapacityInput) \ + _(componentCountOutput) \ + _(components) \ + +#define XR_LIST_STRUCT_XrSceneComponentsGetInfoMSFT(_) \ + _(type) \ + _(next) \ + _(componentType) \ + +#define XR_LIST_STRUCT_XrSceneComponentLocationMSFT(_) \ + _(flags) \ + _(pose) \ + +#define XR_LIST_STRUCT_XrSceneComponentLocationsMSFT(_) \ + _(type) \ + _(next) \ + _(locationCount) \ + _(locations) \ + +#define XR_LIST_STRUCT_XrSceneComponentsLocateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(baseSpace) \ + _(time) \ + _(componentIdCount) \ + _(componentIds) \ + +#define XR_LIST_STRUCT_XrSceneObjectMSFT(_) \ + _(objectType) \ + +#define XR_LIST_STRUCT_XrSceneObjectsMSFT(_) \ + _(type) \ + _(next) \ + _(sceneObjectCount) \ + _(sceneObjects) \ + +#define XR_LIST_STRUCT_XrSceneComponentParentFilterInfoMSFT(_) \ + _(type) \ + _(next) \ + _(parentId) \ + +#define XR_LIST_STRUCT_XrSceneObjectTypesFilterInfoMSFT(_) \ + _(type) \ + _(next) \ + _(objectTypeCount) \ + _(objectTypes) \ + +#define XR_LIST_STRUCT_XrScenePlaneMSFT(_) \ + _(alignment) \ + _(size) \ + _(meshBufferId) \ + _(supportsIndicesUint16) \ + +#define XR_LIST_STRUCT_XrScenePlanesMSFT(_) \ + _(type) \ + _(next) \ + _(scenePlaneCount) \ + _(scenePlanes) \ + +#define XR_LIST_STRUCT_XrScenePlaneAlignmentFilterInfoMSFT(_) \ + _(type) \ + _(next) \ + _(alignmentCount) \ + _(alignments) \ + +#define XR_LIST_STRUCT_XrSceneMeshMSFT(_) \ + _(meshBufferId) \ + _(supportsIndicesUint16) \ + +#define XR_LIST_STRUCT_XrSceneMeshesMSFT(_) \ + _(type) \ + _(next) \ + _(sceneMeshCount) \ + _(sceneMeshes) \ + +#define XR_LIST_STRUCT_XrSceneMeshBuffersGetInfoMSFT(_) \ + _(type) \ + _(next) \ + _(meshBufferId) \ + +#define XR_LIST_STRUCT_XrSceneMeshBuffersMSFT(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSceneMeshVertexBufferMSFT(_) \ + _(type) \ + _(next) \ + _(vertexCapacityInput) \ + _(vertexCountOutput) \ + _(vertices) \ + +#define XR_LIST_STRUCT_XrSceneMeshIndicesUint32MSFT(_) \ + _(type) \ + _(next) \ + _(indexCapacityInput) \ + _(indexCountOutput) \ + _(indices) \ + +#define XR_LIST_STRUCT_XrSceneMeshIndicesUint16MSFT(_) \ + _(type) \ + _(next) \ + _(indexCapacityInput) \ + _(indexCountOutput) \ + _(indices) \ + +#define XR_LIST_STRUCT_XrSerializedSceneFragmentDataGetInfoMSFT(_) \ + _(type) \ + _(next) \ + _(sceneFragmentId) \ + +#define XR_LIST_STRUCT_XrDeserializeSceneFragmentMSFT(_) \ + _(bufferSize) \ + _(buffer) \ + +#define XR_LIST_STRUCT_XrSceneDeserializeInfoMSFT(_) \ + _(type) \ + _(next) \ + _(fragmentCount) \ + _(fragments) \ + +#define XR_LIST_STRUCT_XrEventDataDisplayRefreshRateChangedFB(_) \ + _(type) \ + _(next) \ + _(fromDisplayRefreshRate) \ + _(toDisplayRefreshRate) \ + +#define XR_LIST_STRUCT_XrViveTrackerPathsHTCX(_) \ + _(type) \ + _(next) \ + _(persistentPath) \ + _(rolePath) \ + +#define XR_LIST_STRUCT_XrEventDataViveTrackerConnectedHTCX(_) \ + _(type) \ + _(next) \ + _(paths) \ + +#define XR_LIST_STRUCT_XrSystemFacialTrackingPropertiesHTC(_) \ + _(type) \ + _(next) \ + _(supportEyeFacialTracking) \ + _(supportLipFacialTracking) \ + +#define XR_LIST_STRUCT_XrFacialExpressionsHTC(_) \ + _(type) \ + _(next) \ + _(isActive) \ + _(sampleTime) \ + _(expressionCount) \ + _(expressionWeightings) \ + +#define XR_LIST_STRUCT_XrFacialTrackerCreateInfoHTC(_) \ + _(type) \ + _(next) \ + _(facialTrackingType) \ + +#define XR_LIST_STRUCT_XrSystemColorSpacePropertiesFB(_) \ + _(type) \ + _(next) \ + _(colorSpace) \ + +#define XR_LIST_STRUCT_XrVector4sFB(_) \ + _(x) \ + _(y) \ + _(z) \ + _(w) \ + +#define XR_LIST_STRUCT_XrHandTrackingMeshFB(_) \ + _(type) \ + _(next) \ + _(jointCapacityInput) \ + _(jointCountOutput) \ + _(jointBindPoses) \ + _(jointRadii) \ + _(jointParents) \ + _(vertexCapacityInput) \ + _(vertexCountOutput) \ + _(vertexPositions) \ + _(vertexNormals) \ + _(vertexUVs) \ + _(vertexBlendIndices) \ + _(vertexBlendWeights) \ + _(indexCapacityInput) \ + _(indexCountOutput) \ + _(indices) \ + +#define XR_LIST_STRUCT_XrHandTrackingScaleFB(_) \ + _(type) \ + _(next) \ + _(sensorOutput) \ + _(currentOutput) \ + _(overrideHandScale) \ + _(overrideValueInput) \ + +#define XR_LIST_STRUCT_XrHandTrackingAimStateFB(_) \ + _(type) \ + _(next) \ + _(status) \ + _(aimPose) \ + _(pinchStrengthIndex) \ + _(pinchStrengthMiddle) \ + _(pinchStrengthRing) \ + _(pinchStrengthLittle) \ + +#define XR_LIST_STRUCT_XrHandCapsuleFB(_) \ + _(points) \ + _(radius) \ + _(joint) \ + +#define XR_LIST_STRUCT_XrHandTrackingCapsulesStateFB(_) \ + _(type) \ + _(next) \ + _(capsules) \ + +#define XR_LIST_STRUCT_XrFoveationProfileCreateInfoFB(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSwapchainCreateInfoFoveationFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrSwapchainStateFoveationFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + _(profile) \ + +#define XR_LIST_STRUCT_XrFoveationLevelProfileCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(level) \ + _(verticalOffset) \ + _(dynamic) \ + +#define XR_LIST_STRUCT_XrSystemKeyboardTrackingPropertiesFB(_) \ + _(type) \ + _(next) \ + _(supportsKeyboardTracking) \ + +#define XR_LIST_STRUCT_XrKeyboardTrackingDescriptionFB(_) \ + _(trackedKeyboardId) \ + _(size) \ + _(flags) \ + _(name) \ + +#define XR_LIST_STRUCT_XrKeyboardSpaceCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(trackedKeyboardId) \ + +#define XR_LIST_STRUCT_XrKeyboardTrackingQueryFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrTriangleMeshCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + _(windingOrder) \ + _(vertexCount) \ + _(vertexBuffer) \ + _(triangleCount) \ + _(indexBuffer) \ + +#define XR_LIST_STRUCT_XrSystemPassthroughPropertiesFB(_) \ + _(type) \ + _(next) \ + _(supportsPassthrough) \ + +#define XR_LIST_STRUCT_XrPassthroughCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrPassthroughLayerCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(passthrough) \ + _(flags) \ + _(purpose) \ + +#define XR_LIST_STRUCT_XrCompositionLayerPassthroughFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + _(space) \ + _(layerHandle) \ + +#define XR_LIST_STRUCT_XrGeometryInstanceCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(layer) \ + _(mesh) \ + _(baseSpace) \ + _(pose) \ + _(scale) \ + +#define XR_LIST_STRUCT_XrGeometryInstanceTransformFB(_) \ + _(type) \ + _(next) \ + _(baseSpace) \ + _(time) \ + _(pose) \ + _(scale) \ + +#define XR_LIST_STRUCT_XrPassthroughStyleFB(_) \ + _(type) \ + _(next) \ + _(textureOpacityFactor) \ + _(edgeColor) \ + +#define XR_LIST_STRUCT_XrPassthroughColorMapMonoToRgbaFB(_) \ + _(type) \ + _(next) \ + _(textureColorMap) \ + +#define XR_LIST_STRUCT_XrPassthroughColorMapMonoToMonoFB(_) \ + _(type) \ + _(next) \ + _(textureColorMap) \ + +#define XR_LIST_STRUCT_XrEventDataPassthroughStateChangedFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrRenderModelPathInfoFB(_) \ + _(type) \ + _(next) \ + _(path) \ + +#define XR_LIST_STRUCT_XrRenderModelPropertiesFB(_) \ + _(type) \ + _(next) \ + _(vendorId) \ + _(modelName) \ + _(modelKey) \ + _(modelVersion) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrRenderModelBufferFB(_) \ + _(type) \ + _(next) \ + _(bufferCapacityInput) \ + _(bufferCountOutput) \ + _(buffer) \ + +#define XR_LIST_STRUCT_XrRenderModelLoadInfoFB(_) \ + _(type) \ + _(next) \ + _(modelKey) \ + +#define XR_LIST_STRUCT_XrSystemRenderModelPropertiesFB(_) \ + _(type) \ + _(next) \ + _(supportsRenderModelLoading) \ + +#define XR_LIST_STRUCT_XrViewLocateFoveatedRenderingVARJO(_) \ + _(type) \ + _(next) \ + _(foveatedRenderingActive) \ + +#define XR_LIST_STRUCT_XrFoveatedViewConfigurationViewVARJO(_) \ + _(type) \ + _(next) \ + _(foveatedRenderingActive) \ + +#define XR_LIST_STRUCT_XrSystemFoveatedRenderingPropertiesVARJO(_) \ + _(type) \ + _(next) \ + _(supportsFoveatedRendering) \ + +#define XR_LIST_STRUCT_XrCompositionLayerDepthTestVARJO(_) \ + _(type) \ + _(next) \ + _(depthTestRangeNearZ) \ + _(depthTestRangeFarZ) \ + +#define XR_LIST_STRUCT_XrSystemMarkerTrackingPropertiesVARJO(_) \ + _(type) \ + _(next) \ + _(supportsMarkerTracking) \ + +#define XR_LIST_STRUCT_XrEventDataMarkerTrackingUpdateVARJO(_) \ + _(type) \ + _(next) \ + _(markerId) \ + _(isActive) \ + _(isPredicted) \ + _(time) \ + +#define XR_LIST_STRUCT_XrMarkerSpaceCreateInfoVARJO(_) \ + _(type) \ + _(next) \ + _(markerId) \ + _(poseInMarkerSpace) \ + +#define XR_LIST_STRUCT_XrSpatialAnchorPersistenceNameMSFT(_) \ + _(name) \ + +#define XR_LIST_STRUCT_XrSpatialAnchorPersistenceInfoMSFT(_) \ + _(type) \ + _(next) \ + _(spatialAnchorPersistenceName) \ + _(spatialAnchor) \ + +#define XR_LIST_STRUCT_XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(spatialAnchorStore) \ + _(spatialAnchorPersistenceName) \ + +#define XR_LIST_STRUCT_XrSwapchainImageFoveationVulkanFB(_) \ + _(type) \ + _(next) \ + _(image) \ + _(width) \ + _(height) \ + +#define XR_LIST_STRUCT_XrSwapchainStateAndroidSurfaceDimensionsFB(_) \ + _(type) \ + _(next) \ + _(width) \ + _(height) \ + +#define XR_LIST_STRUCT_XrSwapchainStateSamplerOpenGLESFB(_) \ + _(type) \ + _(next) \ + _(minFilter) \ + _(magFilter) \ + _(wrapModeS) \ + _(wrapModeT) \ + _(swizzleRed) \ + _(swizzleGreen) \ + _(swizzleBlue) \ + _(swizzleAlpha) \ + _(maxAnisotropy) \ + _(borderColor) \ + +#define XR_LIST_STRUCT_XrSwapchainStateSamplerVulkanFB(_) \ + _(type) \ + _(next) \ + _(minFilter) \ + _(magFilter) \ + _(mipmapMode) \ + _(wrapModeS) \ + _(wrapModeT) \ + _(swizzleRed) \ + _(swizzleGreen) \ + _(swizzleBlue) \ + _(swizzleAlpha) \ + _(maxAnisotropy) \ + _(borderColor) \ + +#define XR_LIST_STRUCT_XrCompositionLayerSpaceWarpInfoFB(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + _(motionVectorSubImage) \ + _(appSpaceDeltaPose) \ + _(depthSubImage) \ + _(minDepth) \ + _(maxDepth) \ + _(nearZ) \ + _(farZ) \ + +#define XR_LIST_STRUCT_XrSystemSpaceWarpPropertiesFB(_) \ + _(type) \ + _(next) \ + _(recommendedMotionVectorImageRectWidth) \ + _(recommendedMotionVectorImageRectHeight) \ + +#define XR_LIST_STRUCT_XrDigitalLensControlALMALENCE(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrPassthroughKeyboardHandsIntensityFB(_) \ + _(type) \ + _(next) \ + _(leftHandIntensity) \ + _(rightHandIntensity) \ + +#define XR_LIST_STRUCT_XrUuidEXT(_) \ + _(data) \ + + + +#define XR_LIST_STRUCTURE_TYPES_CORE(_) \ + _(XrApiLayerProperties, XR_TYPE_API_LAYER_PROPERTIES) \ + _(XrExtensionProperties, XR_TYPE_EXTENSION_PROPERTIES) \ + _(XrInstanceCreateInfo, XR_TYPE_INSTANCE_CREATE_INFO) \ + _(XrInstanceProperties, XR_TYPE_INSTANCE_PROPERTIES) \ + _(XrEventDataBuffer, XR_TYPE_EVENT_DATA_BUFFER) \ + _(XrSystemGetInfo, XR_TYPE_SYSTEM_GET_INFO) \ + _(XrSystemProperties, XR_TYPE_SYSTEM_PROPERTIES) \ + _(XrSessionCreateInfo, XR_TYPE_SESSION_CREATE_INFO) \ + _(XrSpaceVelocity, XR_TYPE_SPACE_VELOCITY) \ + _(XrReferenceSpaceCreateInfo, XR_TYPE_REFERENCE_SPACE_CREATE_INFO) \ + _(XrActionSpaceCreateInfo, XR_TYPE_ACTION_SPACE_CREATE_INFO) \ + _(XrSpaceLocation, XR_TYPE_SPACE_LOCATION) \ + _(XrViewConfigurationProperties, XR_TYPE_VIEW_CONFIGURATION_PROPERTIES) \ + _(XrViewConfigurationView, XR_TYPE_VIEW_CONFIGURATION_VIEW) \ + _(XrSwapchainCreateInfo, XR_TYPE_SWAPCHAIN_CREATE_INFO) \ + _(XrSwapchainImageAcquireInfo, XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO) \ + _(XrSwapchainImageWaitInfo, XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO) \ + _(XrSwapchainImageReleaseInfo, XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO) \ + _(XrSessionBeginInfo, XR_TYPE_SESSION_BEGIN_INFO) \ + _(XrFrameWaitInfo, XR_TYPE_FRAME_WAIT_INFO) \ + _(XrFrameState, XR_TYPE_FRAME_STATE) \ + _(XrFrameBeginInfo, XR_TYPE_FRAME_BEGIN_INFO) \ + _(XrFrameEndInfo, XR_TYPE_FRAME_END_INFO) \ + _(XrViewLocateInfo, XR_TYPE_VIEW_LOCATE_INFO) \ + _(XrViewState, XR_TYPE_VIEW_STATE) \ + _(XrView, XR_TYPE_VIEW) \ + _(XrActionSetCreateInfo, XR_TYPE_ACTION_SET_CREATE_INFO) \ + _(XrActionCreateInfo, XR_TYPE_ACTION_CREATE_INFO) \ + _(XrInteractionProfileSuggestedBinding, XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING) \ + _(XrSessionActionSetsAttachInfo, XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO) \ + _(XrInteractionProfileState, XR_TYPE_INTERACTION_PROFILE_STATE) \ + _(XrActionStateGetInfo, XR_TYPE_ACTION_STATE_GET_INFO) \ + _(XrActionStateBoolean, XR_TYPE_ACTION_STATE_BOOLEAN) \ + _(XrActionStateFloat, XR_TYPE_ACTION_STATE_FLOAT) \ + _(XrActionStateVector2f, XR_TYPE_ACTION_STATE_VECTOR2F) \ + _(XrActionStatePose, XR_TYPE_ACTION_STATE_POSE) \ + _(XrActionsSyncInfo, XR_TYPE_ACTIONS_SYNC_INFO) \ + _(XrBoundSourcesForActionEnumerateInfo, XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO) \ + _(XrInputSourceLocalizedNameGetInfo, XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO) \ + _(XrHapticActionInfo, XR_TYPE_HAPTIC_ACTION_INFO) \ + _(XrCompositionLayerProjectionView, XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW) \ + _(XrCompositionLayerProjection, XR_TYPE_COMPOSITION_LAYER_PROJECTION) \ + _(XrCompositionLayerQuad, XR_TYPE_COMPOSITION_LAYER_QUAD) \ + _(XrEventDataEventsLost, XR_TYPE_EVENT_DATA_EVENTS_LOST) \ + _(XrEventDataInstanceLossPending, XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING) \ + _(XrEventDataSessionStateChanged, XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED) \ + _(XrEventDataReferenceSpaceChangePending, XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING) \ + _(XrEventDataInteractionProfileChanged, XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED) \ + _(XrHapticVibration, XR_TYPE_HAPTIC_VIBRATION) \ + _(XrCompositionLayerCubeKHR, XR_TYPE_COMPOSITION_LAYER_CUBE_KHR) \ + _(XrCompositionLayerDepthInfoKHR, XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR) \ + _(XrCompositionLayerCylinderKHR, XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR) \ + _(XrCompositionLayerEquirectKHR, XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR) \ + _(XrVisibilityMaskKHR, XR_TYPE_VISIBILITY_MASK_KHR) \ + _(XrEventDataVisibilityMaskChangedKHR, XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR) \ + _(XrCompositionLayerColorScaleBiasKHR, XR_TYPE_COMPOSITION_LAYER_COLOR_SCALE_BIAS_KHR) \ + _(XrCompositionLayerEquirect2KHR, XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR) \ + _(XrBindingModificationsKHR, XR_TYPE_BINDING_MODIFICATIONS_KHR) \ + _(XrEventDataPerfSettingsEXT, XR_TYPE_EVENT_DATA_PERF_SETTINGS_EXT) \ + _(XrDebugUtilsObjectNameInfoEXT, XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT) \ + _(XrDebugUtilsLabelEXT, XR_TYPE_DEBUG_UTILS_LABEL_EXT) \ + _(XrDebugUtilsMessengerCallbackDataEXT, XR_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT) \ + _(XrDebugUtilsMessengerCreateInfoEXT, XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) \ + _(XrSystemEyeGazeInteractionPropertiesEXT, XR_TYPE_SYSTEM_EYE_GAZE_INTERACTION_PROPERTIES_EXT) \ + _(XrEyeGazeSampleTimeEXT, XR_TYPE_EYE_GAZE_SAMPLE_TIME_EXT) \ + _(XrSessionCreateInfoOverlayEXTX, XR_TYPE_SESSION_CREATE_INFO_OVERLAY_EXTX) \ + _(XrEventDataMainSessionVisibilityChangedEXTX, XR_TYPE_EVENT_DATA_MAIN_SESSION_VISIBILITY_CHANGED_EXTX) \ + _(XrSpatialAnchorCreateInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_MSFT) \ + _(XrSpatialAnchorSpaceCreateInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_SPACE_CREATE_INFO_MSFT) \ + _(XrCompositionLayerImageLayoutFB, XR_TYPE_COMPOSITION_LAYER_IMAGE_LAYOUT_FB) \ + _(XrCompositionLayerAlphaBlendFB, XR_TYPE_COMPOSITION_LAYER_ALPHA_BLEND_FB) \ + _(XrViewConfigurationDepthRangeEXT, XR_TYPE_VIEW_CONFIGURATION_DEPTH_RANGE_EXT) \ + _(XrSpatialGraphNodeSpaceCreateInfoMSFT, XR_TYPE_SPATIAL_GRAPH_NODE_SPACE_CREATE_INFO_MSFT) \ + _(XrSystemHandTrackingPropertiesEXT, XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT) \ + _(XrHandTrackerCreateInfoEXT, XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT) \ + _(XrHandJointsLocateInfoEXT, XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT) \ + _(XrHandJointLocationsEXT, XR_TYPE_HAND_JOINT_LOCATIONS_EXT) \ + _(XrHandJointVelocitiesEXT, XR_TYPE_HAND_JOINT_VELOCITIES_EXT) \ + _(XrSystemHandTrackingMeshPropertiesMSFT, XR_TYPE_SYSTEM_HAND_TRACKING_MESH_PROPERTIES_MSFT) \ + _(XrHandMeshSpaceCreateInfoMSFT, XR_TYPE_HAND_MESH_SPACE_CREATE_INFO_MSFT) \ + _(XrHandMeshUpdateInfoMSFT, XR_TYPE_HAND_MESH_UPDATE_INFO_MSFT) \ + _(XrHandMeshMSFT, XR_TYPE_HAND_MESH_MSFT) \ + _(XrHandPoseTypeInfoMSFT, XR_TYPE_HAND_POSE_TYPE_INFO_MSFT) \ + _(XrSecondaryViewConfigurationSessionBeginInfoMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SESSION_BEGIN_INFO_MSFT) \ + _(XrSecondaryViewConfigurationStateMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_STATE_MSFT) \ + _(XrSecondaryViewConfigurationFrameStateMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_STATE_MSFT) \ + _(XrSecondaryViewConfigurationLayerInfoMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_LAYER_INFO_MSFT) \ + _(XrSecondaryViewConfigurationFrameEndInfoMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_END_INFO_MSFT) \ + _(XrSecondaryViewConfigurationSwapchainCreateInfoMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SWAPCHAIN_CREATE_INFO_MSFT) \ + _(XrControllerModelKeyStateMSFT, XR_TYPE_CONTROLLER_MODEL_KEY_STATE_MSFT) \ + _(XrControllerModelNodePropertiesMSFT, XR_TYPE_CONTROLLER_MODEL_NODE_PROPERTIES_MSFT) \ + _(XrControllerModelPropertiesMSFT, XR_TYPE_CONTROLLER_MODEL_PROPERTIES_MSFT) \ + _(XrControllerModelNodeStateMSFT, XR_TYPE_CONTROLLER_MODEL_NODE_STATE_MSFT) \ + _(XrControllerModelStateMSFT, XR_TYPE_CONTROLLER_MODEL_STATE_MSFT) \ + _(XrViewConfigurationViewFovEPIC, XR_TYPE_VIEW_CONFIGURATION_VIEW_FOV_EPIC) \ + _(XrCompositionLayerReprojectionInfoMSFT, XR_TYPE_COMPOSITION_LAYER_REPROJECTION_INFO_MSFT) \ + _(XrCompositionLayerReprojectionPlaneOverrideMSFT, XR_TYPE_COMPOSITION_LAYER_REPROJECTION_PLANE_OVERRIDE_MSFT) \ + _(XrCompositionLayerSecureContentFB, XR_TYPE_COMPOSITION_LAYER_SECURE_CONTENT_FB) \ + _(XrInteractionProfileAnalogThresholdVALVE, XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE) \ + _(XrHandJointsMotionRangeInfoEXT, XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT) \ + _(XrSceneObserverCreateInfoMSFT, XR_TYPE_SCENE_OBSERVER_CREATE_INFO_MSFT) \ + _(XrSceneCreateInfoMSFT, XR_TYPE_SCENE_CREATE_INFO_MSFT) \ + _(XrNewSceneComputeInfoMSFT, XR_TYPE_NEW_SCENE_COMPUTE_INFO_MSFT) \ + _(XrVisualMeshComputeLodInfoMSFT, XR_TYPE_VISUAL_MESH_COMPUTE_LOD_INFO_MSFT) \ + _(XrSceneComponentsMSFT, XR_TYPE_SCENE_COMPONENTS_MSFT) \ + _(XrSceneComponentsGetInfoMSFT, XR_TYPE_SCENE_COMPONENTS_GET_INFO_MSFT) \ + _(XrSceneComponentLocationsMSFT, XR_TYPE_SCENE_COMPONENT_LOCATIONS_MSFT) \ + _(XrSceneComponentsLocateInfoMSFT, XR_TYPE_SCENE_COMPONENTS_LOCATE_INFO_MSFT) \ + _(XrSceneObjectsMSFT, XR_TYPE_SCENE_OBJECTS_MSFT) \ + _(XrSceneComponentParentFilterInfoMSFT, XR_TYPE_SCENE_COMPONENT_PARENT_FILTER_INFO_MSFT) \ + _(XrSceneObjectTypesFilterInfoMSFT, XR_TYPE_SCENE_OBJECT_TYPES_FILTER_INFO_MSFT) \ + _(XrScenePlanesMSFT, XR_TYPE_SCENE_PLANES_MSFT) \ + _(XrScenePlaneAlignmentFilterInfoMSFT, XR_TYPE_SCENE_PLANE_ALIGNMENT_FILTER_INFO_MSFT) \ + _(XrSceneMeshesMSFT, XR_TYPE_SCENE_MESHES_MSFT) \ + _(XrSceneMeshBuffersGetInfoMSFT, XR_TYPE_SCENE_MESH_BUFFERS_GET_INFO_MSFT) \ + _(XrSceneMeshBuffersMSFT, XR_TYPE_SCENE_MESH_BUFFERS_MSFT) \ + _(XrSceneMeshVertexBufferMSFT, XR_TYPE_SCENE_MESH_VERTEX_BUFFER_MSFT) \ + _(XrSceneMeshIndicesUint32MSFT, XR_TYPE_SCENE_MESH_INDICES_UINT32_MSFT) \ + _(XrSceneMeshIndicesUint16MSFT, XR_TYPE_SCENE_MESH_INDICES_UINT16_MSFT) \ + _(XrSerializedSceneFragmentDataGetInfoMSFT, XR_TYPE_SERIALIZED_SCENE_FRAGMENT_DATA_GET_INFO_MSFT) \ + _(XrSceneDeserializeInfoMSFT, XR_TYPE_SCENE_DESERIALIZE_INFO_MSFT) \ + _(XrEventDataDisplayRefreshRateChangedFB, XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB) \ + _(XrViveTrackerPathsHTCX, XR_TYPE_VIVE_TRACKER_PATHS_HTCX) \ + _(XrEventDataViveTrackerConnectedHTCX, XR_TYPE_EVENT_DATA_VIVE_TRACKER_CONNECTED_HTCX) \ + _(XrSystemFacialTrackingPropertiesHTC, XR_TYPE_SYSTEM_FACIAL_TRACKING_PROPERTIES_HTC) \ + _(XrFacialExpressionsHTC, XR_TYPE_FACIAL_EXPRESSIONS_HTC) \ + _(XrFacialTrackerCreateInfoHTC, XR_TYPE_FACIAL_TRACKER_CREATE_INFO_HTC) \ + _(XrSystemColorSpacePropertiesFB, XR_TYPE_SYSTEM_COLOR_SPACE_PROPERTIES_FB) \ + _(XrHandTrackingMeshFB, XR_TYPE_HAND_TRACKING_MESH_FB) \ + _(XrHandTrackingScaleFB, XR_TYPE_HAND_TRACKING_SCALE_FB) \ + _(XrHandTrackingAimStateFB, XR_TYPE_HAND_TRACKING_AIM_STATE_FB) \ + _(XrHandTrackingCapsulesStateFB, XR_TYPE_HAND_TRACKING_CAPSULES_STATE_FB) \ + _(XrFoveationProfileCreateInfoFB, XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB) \ + _(XrSwapchainCreateInfoFoveationFB, XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB) \ + _(XrSwapchainStateFoveationFB, XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB) \ + _(XrFoveationLevelProfileCreateInfoFB, XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB) \ + _(XrSystemKeyboardTrackingPropertiesFB, XR_TYPE_SYSTEM_KEYBOARD_TRACKING_PROPERTIES_FB) \ + _(XrKeyboardSpaceCreateInfoFB, XR_TYPE_KEYBOARD_SPACE_CREATE_INFO_FB) \ + _(XrKeyboardTrackingQueryFB, XR_TYPE_KEYBOARD_TRACKING_QUERY_FB) \ + _(XrTriangleMeshCreateInfoFB, XR_TYPE_TRIANGLE_MESH_CREATE_INFO_FB) \ + _(XrSystemPassthroughPropertiesFB, XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES_FB) \ + _(XrPassthroughCreateInfoFB, XR_TYPE_PASSTHROUGH_CREATE_INFO_FB) \ + _(XrPassthroughLayerCreateInfoFB, XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB) \ + _(XrCompositionLayerPassthroughFB, XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB) \ + _(XrGeometryInstanceCreateInfoFB, XR_TYPE_GEOMETRY_INSTANCE_CREATE_INFO_FB) \ + _(XrGeometryInstanceTransformFB, XR_TYPE_GEOMETRY_INSTANCE_TRANSFORM_FB) \ + _(XrPassthroughStyleFB, XR_TYPE_PASSTHROUGH_STYLE_FB) \ + _(XrPassthroughColorMapMonoToRgbaFB, XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_RGBA_FB) \ + _(XrPassthroughColorMapMonoToMonoFB, XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_MONO_FB) \ + _(XrEventDataPassthroughStateChangedFB, XR_TYPE_EVENT_DATA_PASSTHROUGH_STATE_CHANGED_FB) \ + _(XrRenderModelPathInfoFB, XR_TYPE_RENDER_MODEL_PATH_INFO_FB) \ + _(XrRenderModelPropertiesFB, XR_TYPE_RENDER_MODEL_PROPERTIES_FB) \ + _(XrRenderModelBufferFB, XR_TYPE_RENDER_MODEL_BUFFER_FB) \ + _(XrRenderModelLoadInfoFB, XR_TYPE_RENDER_MODEL_LOAD_INFO_FB) \ + _(XrSystemRenderModelPropertiesFB, XR_TYPE_SYSTEM_RENDER_MODEL_PROPERTIES_FB) \ + _(XrViewLocateFoveatedRenderingVARJO, XR_TYPE_VIEW_LOCATE_FOVEATED_RENDERING_VARJO) \ + _(XrFoveatedViewConfigurationViewVARJO, XR_TYPE_FOVEATED_VIEW_CONFIGURATION_VIEW_VARJO) \ + _(XrSystemFoveatedRenderingPropertiesVARJO, XR_TYPE_SYSTEM_FOVEATED_RENDERING_PROPERTIES_VARJO) \ + _(XrCompositionLayerDepthTestVARJO, XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_VARJO) \ + _(XrSystemMarkerTrackingPropertiesVARJO, XR_TYPE_SYSTEM_MARKER_TRACKING_PROPERTIES_VARJO) \ + _(XrEventDataMarkerTrackingUpdateVARJO, XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO) \ + _(XrMarkerSpaceCreateInfoVARJO, XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO) \ + _(XrSpatialAnchorPersistenceInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT) \ + _(XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT) \ + _(XrCompositionLayerSpaceWarpInfoFB, XR_TYPE_COMPOSITION_LAYER_SPACE_WARP_INFO_FB) \ + _(XrSystemSpaceWarpPropertiesFB, XR_TYPE_SYSTEM_SPACE_WARP_PROPERTIES_FB) \ + _(XrDigitalLensControlALMALENCE, XR_TYPE_DIGITAL_LENS_CONTROL_ALMALENCE) \ + _(XrPassthroughKeyboardHandsIntensityFB, XR_TYPE_PASSTHROUGH_KEYBOARD_HANDS_INTENSITY_FB) \ + + + + +#if defined(XR_USE_GRAPHICS_API_D3D11) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D11(_) \ + _(XrGraphicsBindingD3D11KHR, XR_TYPE_GRAPHICS_BINDING_D3D11_KHR) \ + _(XrSwapchainImageD3D11KHR, XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR) \ + _(XrGraphicsRequirementsD3D11KHR, XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D11(_) +#endif + +#if defined(XR_USE_GRAPHICS_API_D3D12) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D12(_) \ + _(XrGraphicsBindingD3D12KHR, XR_TYPE_GRAPHICS_BINDING_D3D12_KHR) \ + _(XrSwapchainImageD3D12KHR, XR_TYPE_SWAPCHAIN_IMAGE_D3D12_KHR) \ + _(XrGraphicsRequirementsD3D12KHR, XR_TYPE_GRAPHICS_REQUIREMENTS_D3D12_KHR) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D12(_) +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL(_) \ + _(XrSwapchainImageOpenGLKHR, XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR) \ + _(XrGraphicsRequirementsOpenGLKHR, XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL(_) +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL) && defined(XR_USE_PLATFORM_WAYLAND) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WAYLAND(_) \ + _(XrGraphicsBindingOpenGLWaylandKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_WAYLAND_KHR) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WAYLAND(_) +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL) && defined(XR_USE_PLATFORM_WIN32) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WIN32(_) \ + _(XrGraphicsBindingOpenGLWin32KHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WIN32(_) +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL) && defined(XR_USE_PLATFORM_XCB) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XCB(_) \ + _(XrGraphicsBindingOpenGLXcbKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_XCB_KHR) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XCB(_) +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL) && defined(XR_USE_PLATFORM_XLIB) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XLIB(_) \ + _(XrGraphicsBindingOpenGLXlibKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XLIB(_) +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL_ES) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES(_) \ + _(XrSwapchainImageOpenGLESKHR, XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR) \ + _(XrGraphicsRequirementsOpenGLESKHR, XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR) \ + _(XrSwapchainStateSamplerOpenGLESFB, XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES(_) +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL_ES) && defined(XR_USE_PLATFORM_ANDROID) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES_XR_USE_PLATFORM_ANDROID(_) \ + _(XrGraphicsBindingOpenGLESAndroidKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES_XR_USE_PLATFORM_ANDROID(_) +#endif + +#if defined(XR_USE_GRAPHICS_API_VULKAN) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_VULKAN(_) \ + _(XrVulkanSwapchainFormatListCreateInfoKHR, XR_TYPE_VULKAN_SWAPCHAIN_FORMAT_LIST_CREATE_INFO_KHR) \ + _(XrGraphicsBindingVulkanKHR, XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR) \ + _(XrSwapchainImageVulkanKHR, XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR) \ + _(XrGraphicsRequirementsVulkanKHR, XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR) \ + _(XrVulkanInstanceCreateInfoKHR, XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR) \ + _(XrVulkanDeviceCreateInfoKHR, XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR) \ + _(XrVulkanGraphicsDeviceGetInfoKHR, XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR) \ + _(XrSwapchainImageFoveationVulkanFB, XR_TYPE_SWAPCHAIN_IMAGE_FOVEATION_VULKAN_FB) \ + _(XrSwapchainStateSamplerVulkanFB, XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_VULKAN(_) +#endif + +#if defined(XR_USE_PLATFORM_ANDROID) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID(_) \ + _(XrInstanceCreateInfoAndroidKHR, XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR) \ + _(XrLoaderInitInfoAndroidKHR, XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR) \ + _(XrAndroidSurfaceSwapchainCreateInfoFB, XR_TYPE_ANDROID_SURFACE_SWAPCHAIN_CREATE_INFO_FB) \ + _(XrSwapchainStateAndroidSurfaceDimensionsFB, XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID(_) +#endif + +#if defined(XR_USE_PLATFORM_EGL) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_EGL(_) \ + _(XrGraphicsBindingEGLMNDX, XR_TYPE_GRAPHICS_BINDING_EGL_MNDX) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_EGL(_) +#endif + +#if defined(XR_USE_PLATFORM_WIN32) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_WIN32(_) \ + _(XrHolographicWindowAttachmentMSFT, XR_TYPE_HOLOGRAPHIC_WINDOW_ATTACHMENT_MSFT) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_WIN32(_) +#endif + +#define XR_LIST_STRUCTURE_TYPES(_) \ + XR_LIST_STRUCTURE_TYPES_CORE(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D11(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D12(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WAYLAND(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WIN32(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XCB(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XLIB(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES_XR_USE_PLATFORM_ANDROID(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_VULKAN(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_EGL(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_WIN32(_) \ + + +#define XR_LIST_EXTENSIONS(_) \ + _(XR_KHR_android_thread_settings, 4) \ + _(XR_KHR_android_surface_swapchain, 5) \ + _(XR_KHR_composition_layer_cube, 7) \ + _(XR_KHR_android_create_instance, 9) \ + _(XR_KHR_composition_layer_depth, 11) \ + _(XR_KHR_vulkan_swapchain_format_list, 15) \ + _(XR_EXT_performance_settings, 16) \ + _(XR_EXT_thermal_query, 17) \ + _(XR_KHR_composition_layer_cylinder, 18) \ + _(XR_KHR_composition_layer_equirect, 19) \ + _(XR_EXT_debug_utils, 20) \ + _(XR_KHR_opengl_enable, 24) \ + _(XR_KHR_opengl_es_enable, 25) \ + _(XR_KHR_vulkan_enable, 26) \ + _(XR_KHR_D3D11_enable, 28) \ + _(XR_KHR_D3D12_enable, 29) \ + _(XR_EXT_eye_gaze_interaction, 31) \ + _(XR_KHR_visibility_mask, 32) \ + _(XR_EXTX_overlay, 34) \ + _(XR_KHR_composition_layer_color_scale_bias, 35) \ + _(XR_KHR_win32_convert_performance_counter_time, 36) \ + _(XR_KHR_convert_timespec_time, 37) \ + _(XR_VARJO_quad_views, 38) \ + _(XR_MSFT_unbounded_reference_space, 39) \ + _(XR_MSFT_spatial_anchor, 40) \ + _(XR_FB_composition_layer_image_layout, 41) \ + _(XR_FB_composition_layer_alpha_blend, 42) \ + _(XR_MND_headless, 43) \ + _(XR_OCULUS_android_session_state_enable, 45) \ + _(XR_EXT_view_configuration_depth_range, 47) \ + _(XR_EXT_conformance_automation, 48) \ + _(XR_MNDX_egl_enable, 49) \ + _(XR_MSFT_spatial_graph_bridge, 50) \ + _(XR_MSFT_hand_interaction, 51) \ + _(XR_EXT_hand_tracking, 52) \ + _(XR_MSFT_hand_tracking_mesh, 53) \ + _(XR_MSFT_secondary_view_configuration, 54) \ + _(XR_MSFT_first_person_observer, 55) \ + _(XR_MSFT_controller_model, 56) \ + _(XR_MSFT_perception_anchor_interop, 57) \ + _(XR_EXT_win32_appcontainer_compatible, 58) \ + _(XR_EPIC_view_configuration_fov, 60) \ + _(XR_MSFT_holographic_window_attachment, 64) \ + _(XR_MSFT_composition_layer_reprojection, 67) \ + _(XR_HUAWEI_controller_interaction, 70) \ + _(XR_FB_android_surface_swapchain_create, 71) \ + _(XR_FB_swapchain_update_state, 72) \ + _(XR_FB_composition_layer_secure_content, 73) \ + _(XR_VALVE_analog_threshold, 80) \ + _(XR_EXT_hand_joints_motion_range, 81) \ + _(XR_KHR_loader_init, 89) \ + _(XR_KHR_loader_init_android, 90) \ + _(XR_KHR_vulkan_enable2, 91) \ + _(XR_KHR_composition_layer_equirect2, 92) \ + _(XR_EXT_samsung_odyssey_controller, 95) \ + _(XR_EXT_hp_mixed_reality_controller, 96) \ + _(XR_MND_swapchain_usage_input_attachment_bit, 97) \ + _(XR_MSFT_scene_understanding, 98) \ + _(XR_MSFT_scene_understanding_serialization, 99) \ + _(XR_FB_display_refresh_rate, 102) \ + _(XR_HTC_vive_cosmos_controller_interaction, 103) \ + _(XR_HTCX_vive_tracker_interaction, 104) \ + _(XR_HTC_facial_tracking, 105) \ + _(XR_HTC_vive_focus3_controller_interaction, 106) \ + _(XR_FB_color_space, 109) \ + _(XR_FB_hand_tracking_mesh, 111) \ + _(XR_FB_hand_tracking_aim, 112) \ + _(XR_FB_hand_tracking_capsules, 113) \ + _(XR_FB_foveation, 115) \ + _(XR_FB_foveation_configuration, 116) \ + _(XR_FB_keyboard_tracking, 117) \ + _(XR_FB_triangle_mesh, 118) \ + _(XR_FB_passthrough, 119) \ + _(XR_FB_render_model, 120) \ + _(XR_KHR_binding_modification, 121) \ + _(XR_VARJO_foveated_rendering, 122) \ + _(XR_VARJO_composition_layer_depth_test, 123) \ + _(XR_VARJO_environment_depth_estimation, 124) \ + _(XR_VARJO_marker_tracking, 125) \ + _(XR_MSFT_spatial_anchor_persistence, 143) \ + _(XR_OCULUS_audio_device_guid, 160) \ + _(XR_FB_foveation_vulkan, 161) \ + _(XR_FB_swapchain_update_state_android_surface, 162) \ + _(XR_FB_swapchain_update_state_opengl_es, 163) \ + _(XR_FB_swapchain_update_state_vulkan, 164) \ + _(XR_KHR_swapchain_usage_input_attachment_bit, 166) \ + _(XR_FB_space_warp, 172) \ + _(XR_ALMALENCE_digital_lens_control, 197) \ + _(XR_FB_passthrough_keyboard_hands, 204) \ + _(XR_EXT_uuid, 300) \ + + +#endif + diff --git a/thirdparty/openxr/src/.clang-format b/thirdparty/openxr/src/.clang-format new file mode 100644 index 0000000000..36546cab92 --- /dev/null +++ b/thirdparty/openxr/src/.clang-format @@ -0,0 +1,10 @@ +--- +# Copyright (c) 2017-2022, The Khronos Group Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# Use defaults from the Google style with the following exceptions: +BasedOnStyle: Google +IndentWidth: 4 +ColumnLimit: 132 +SortIncludes: false +... diff --git a/thirdparty/openxr/src/common/extra_algorithms.h b/thirdparty/openxr/src/common/extra_algorithms.h new file mode 100644 index 0000000000..64af4d08ff --- /dev/null +++ b/thirdparty/openxr/src/common/extra_algorithms.h @@ -0,0 +1,47 @@ +// Copyright (c) 2017-2022, The Khronos Group Inc. +// Copyright (c) 2017-2019 Valve Corporation +// Copyright (c) 2017-2019 LunarG, Inc. +// Copyright (c) 2019 Collabora, Ltd. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Initial Author: Ryan Pavlik <ryan.pavlik@collabora.com> +// + +/*! + * @file + * + * Additional functions along the lines of the standard library algorithms. + */ + +#pragma once + +#include <algorithm> +#include <vector> + +/// Like std::remove_if, except it works on associative containers and it actually removes this. +/// +/// The iterator stuff in here is subtle - .erase() invalidates only that iterator, but it returns a non-invalidated iterator to the +/// next valid element which we can use instead of incrementing. +template <typename T, typename Pred> +static inline void map_erase_if(T &container, Pred &&predicate) { + for (auto it = container.begin(); it != container.end();) { + if (predicate(*it)) { + it = container.erase(it); + } else { + ++it; + } + } +} + +/*! + * Moves all elements matching the predicate to the end of the vector then erases them. + * + * Combines the two parts of the erase-remove idiom to simplify things and avoid accidentally using the wrong erase overload. + */ +template <typename T, typename Alloc, typename Pred> +static inline void vector_remove_if_and_erase(std::vector<T, Alloc> &vec, Pred &&predicate) { + auto b = vec.begin(); + auto e = vec.end(); + vec.erase(std::remove_if(b, e, std::forward<Pred>(predicate)), e); +} diff --git a/thirdparty/openxr/src/common/filesystem_utils.cpp b/thirdparty/openxr/src/common/filesystem_utils.cpp new file mode 100644 index 0000000000..d3d4182fb9 --- /dev/null +++ b/thirdparty/openxr/src/common/filesystem_utils.cpp @@ -0,0 +1,322 @@ +// Copyright (c) 2017 The Khronos Group Inc. +// Copyright (c) 2017 Valve Corporation +// Copyright (c) 2017 LunarG, Inc. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Initial Authors: Mark Young <marky@lunarg.com> +// Nat Brown <natb@valvesoftware.com> +// + +#include "filesystem_utils.hpp" + +#include "platform_utils.hpp" + +#include <cstring> +#include <string> + +#if defined DISABLE_STD_FILESYSTEM +#define USE_EXPERIMENTAL_FS 0 +#define USE_FINAL_FS 0 + +#else +#include "stdfs_conditions.h" +#endif + +#if USE_FINAL_FS == 1 +#include <filesystem> +#define FS_PREFIX std::filesystem +#elif USE_EXPERIMENTAL_FS == 1 +#include <experimental/filesystem> +#define FS_PREFIX std::experimental::filesystem +#elif defined(XR_USE_PLATFORM_WIN32) +// Windows fallback includes +#include <stdint.h> +#include <direct.h> +#else +// Linux/Apple fallback includes +#include <sys/stat.h> +#include <unistd.h> +#include <limits.h> +#include <stdlib.h> +#include <dirent.h> +#endif + +#if defined(XR_USE_PLATFORM_WIN32) +#define PATH_SEPARATOR ';' +#define DIRECTORY_SYMBOL '\\' +#define ALTERNATE_DIRECTORY_SYMBOL '/' +#else +#define PATH_SEPARATOR ':' +#define DIRECTORY_SYMBOL '/' +#endif + +#if (USE_FINAL_FS == 1) || (USE_EXPERIMENTAL_FS == 1) +// We can use one of the C++ filesystem packages + +bool FileSysUtilsIsRegularFile(const std::string& path) { return FS_PREFIX::is_regular_file(path); } + +bool FileSysUtilsIsDirectory(const std::string& path) { return FS_PREFIX::is_directory(path); } + +bool FileSysUtilsPathExists(const std::string& path) { return FS_PREFIX::exists(path); } + +bool FileSysUtilsIsAbsolutePath(const std::string& path) { + FS_PREFIX::path file_path(path); + return file_path.is_absolute(); +} + +bool FileSysUtilsGetCurrentPath(std::string& path) { + FS_PREFIX::path cur_path = FS_PREFIX::current_path(); + path = cur_path.string(); + return true; +} + +bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path) { + FS_PREFIX::path path_var(file_path); + parent_path = path_var.parent_path().string(); + return true; +} + +bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute) { + absolute = FS_PREFIX::absolute(path).string(); + return true; +} + +bool FileSysUtilsGetCanonicalPath(const std::string& path, std::string& canonical) { +#if defined(XR_USE_PLATFORM_WIN32) + // std::filesystem::canonical fails on UWP and must be avoided. Further, PathCchCanonicalize is not available on Windows 7 and + // PathCanonicalizeW is not available on UWP. However, symbolic links are not important on Windows since the loader uses the + // registry for indirection instead, and so this function can be a no-op on Windows. + canonical = path; +#else + canonical = FS_PREFIX::canonical(path).string(); +#endif + return true; +} + +bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined) { + FS_PREFIX::path parent_path(parent); + FS_PREFIX::path child_path(child); + FS_PREFIX::path full_path = parent_path / child_path; + combined = full_path.string(); + return true; +} + +bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths) { + std::string::size_type start = 0; + std::string::size_type location = path_list.find(PATH_SEPARATOR); + while (location != std::string::npos) { + paths.push_back(path_list.substr(start, location)); + start = location + 1; + location = path_list.find(PATH_SEPARATOR, start); + } + paths.push_back(path_list.substr(start, location)); + return true; +} + +bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files) { + for (auto& dir_iter : FS_PREFIX::directory_iterator(path)) { + files.push_back(dir_iter.path().filename().string()); + } + return true; +} + +#elif defined(XR_OS_WINDOWS) + +// For pre C++17 compiler that doesn't support experimental filesystem + +bool FileSysUtilsIsRegularFile(const std::string& path) { + const DWORD attr = GetFileAttributesW(utf8_to_wide(path).c_str()); + return attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY); +} + +bool FileSysUtilsIsDirectory(const std::string& path) { + const DWORD attr = GetFileAttributesW(utf8_to_wide(path).c_str()); + return attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY); +} + +bool FileSysUtilsPathExists(const std::string& path) { + return (GetFileAttributesW(utf8_to_wide(path).c_str()) != INVALID_FILE_ATTRIBUTES); +} + +bool FileSysUtilsIsAbsolutePath(const std::string& path) { + bool pathStartsWithDir = (path.size() >= 1) && ((path[0] == DIRECTORY_SYMBOL) || (path[0] == ALTERNATE_DIRECTORY_SYMBOL)); + + bool pathStartsWithDrive = + (path.size() >= 3) && (path[1] == ':' && (path[2] == DIRECTORY_SYMBOL || path[2] == ALTERNATE_DIRECTORY_SYMBOL)); + + return pathStartsWithDir || pathStartsWithDrive; +} + +bool FileSysUtilsGetCurrentPath(std::string& path) { + wchar_t tmp_path[MAX_PATH]; + if (nullptr != _wgetcwd(tmp_path, MAX_PATH - 1)) { + path = wide_to_utf8(tmp_path); + return true; + } + return false; +} + +bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path) { + std::string full_path; + if (FileSysUtilsGetAbsolutePath(file_path, full_path)) { + std::string::size_type lastSeparator = full_path.find_last_of(DIRECTORY_SYMBOL); + parent_path = (lastSeparator == 0) ? full_path : full_path.substr(0, lastSeparator); + return true; + } + return false; +} + +bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute) { + wchar_t tmp_path[MAX_PATH]; + if (0 != GetFullPathNameW(utf8_to_wide(path).c_str(), MAX_PATH, tmp_path, NULL)) { + absolute = wide_to_utf8(tmp_path); + return true; + } + return false; +} + +bool FileSysUtilsGetCanonicalPath(const std::string& path, std::string& absolute) { + // PathCchCanonicalize is not available on Windows 7 and PathCanonicalizeW is not available on UWP. However, symbolic links are + // not important on Windows since the loader uses the registry for indirection instead, and so this function can be a no-op on + // Windows. + absolute = path; + return true; +} + +bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined) { + std::string::size_type parent_len = parent.length(); + if (0 == parent_len || "." == parent || ".\\" == parent || "./" == parent) { + combined = child; + return true; + } + char last_char = parent[parent_len - 1]; + if ((last_char == DIRECTORY_SYMBOL) || (last_char == ALTERNATE_DIRECTORY_SYMBOL)) { + parent_len--; + } + combined = parent.substr(0, parent_len) + DIRECTORY_SYMBOL + child; + return true; +} + +bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths) { + std::string::size_type start = 0; + std::string::size_type location = path_list.find(PATH_SEPARATOR); + while (location != std::string::npos) { + paths.push_back(path_list.substr(start, location)); + start = location + 1; + location = path_list.find(PATH_SEPARATOR, start); + } + paths.push_back(path_list.substr(start, location)); + return true; +} + +bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files) { + std::string searchPath; + FileSysUtilsCombinePaths(path, "*", searchPath); + + WIN32_FIND_DATAW file_data; + HANDLE file_handle = FindFirstFileW(utf8_to_wide(searchPath).c_str(), &file_data); + if (file_handle != INVALID_HANDLE_VALUE) { + do { + if (!(file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + files.push_back(wide_to_utf8(file_data.cFileName)); + } + } while (FindNextFileW(file_handle, &file_data)); + return true; + } + return false; +} + +#else // XR_OS_LINUX/XR_OS_APPLE fallback + +// simple POSIX-compatible implementation of the <filesystem> pieces used by OpenXR + +bool FileSysUtilsIsRegularFile(const std::string& path) { + struct stat path_stat; + stat(path.c_str(), &path_stat); + return S_ISREG(path_stat.st_mode); +} + +bool FileSysUtilsIsDirectory(const std::string& path) { + struct stat path_stat; + stat(path.c_str(), &path_stat); + return S_ISDIR(path_stat.st_mode); +} + +bool FileSysUtilsPathExists(const std::string& path) { return (access(path.c_str(), F_OK) != -1); } + +bool FileSysUtilsIsAbsolutePath(const std::string& path) { return (path[0] == DIRECTORY_SYMBOL); } + +bool FileSysUtilsGetCurrentPath(std::string& path) { + char tmp_path[PATH_MAX]; + if (nullptr != getcwd(tmp_path, PATH_MAX - 1)) { + path = tmp_path; + return true; + } + return false; +} + +bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path) { + std::string full_path; + if (FileSysUtilsGetAbsolutePath(file_path, full_path)) { + std::string::size_type lastSeparator = full_path.find_last_of(DIRECTORY_SYMBOL); + parent_path = (lastSeparator == 0) ? full_path : full_path.substr(0, lastSeparator); + return true; + } + return false; +} + +bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute) { + // canonical path is absolute + return FileSysUtilsGetCanonicalPath(path, absolute); +} + +bool FileSysUtilsGetCanonicalPath(const std::string& path, std::string& canonical) { + char buf[PATH_MAX]; + if (nullptr != realpath(path.c_str(), buf)) { + canonical = buf; + return true; + } + return false; +} + +bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined) { + std::string::size_type parent_len = parent.length(); + if (0 == parent_len || "." == parent || "./" == parent) { + combined = child; + return true; + } + char last_char = parent[parent_len - 1]; + if (last_char == DIRECTORY_SYMBOL) { + parent_len--; + } + combined = parent.substr(0, parent_len) + DIRECTORY_SYMBOL + child; + return true; +} + +bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths) { + std::string::size_type start = 0; + std::string::size_type location = path_list.find(PATH_SEPARATOR); + while (location != std::string::npos) { + paths.push_back(path_list.substr(start, location)); + start = location + 1; + location = path_list.find(PATH_SEPARATOR, start); + } + paths.push_back(path_list.substr(start, location)); + return true; +} + +bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files) { + DIR* dir = opendir(path.c_str()); + if (dir == nullptr) { + return false; + } + struct dirent* entry; + while ((entry = readdir(dir)) != nullptr) { + files.emplace_back(entry->d_name); + } + closedir(dir); + return true; +} + +#endif diff --git a/thirdparty/openxr/src/common/filesystem_utils.hpp b/thirdparty/openxr/src/common/filesystem_utils.hpp new file mode 100644 index 0000000000..4a5c987e7b --- /dev/null +++ b/thirdparty/openxr/src/common/filesystem_utils.hpp @@ -0,0 +1,46 @@ +// Copyright (c) 2017 The Khronos Group Inc. +// Copyright (c) 2017 Valve Corporation +// Copyright (c) 2017 LunarG, Inc. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Initial Author: Mark Young <marky@lunarg.com> +// + +#pragma once + +#include <string> +#include <vector> + +// Determine if the path indicates a regular file (not a directory or symbolic link) +bool FileSysUtilsIsRegularFile(const std::string& path); + +// Determine if the path indicates a directory +bool FileSysUtilsIsDirectory(const std::string& path); + +// Determine if the provided path exists on the filesystem +bool FileSysUtilsPathExists(const std::string& path); + +// Get the current directory +bool FileSysUtilsGetCurrentPath(std::string& path); + +// Get the parent path of a file +bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path); + +// Determine if the provided path is an absolute path +bool FileSysUtilsIsAbsolutePath(const std::string& path); + +// Get the absolute path for a provided file +bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute); + +// Get the absolute path for a provided file +bool FileSysUtilsGetCanonicalPath(const std::string& path, std::string& canonical); + +// Combine a parent and child directory +bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined); + +// Parse out individual paths in a path list +bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths); + +// Record all the filenames for files found in the provided path. +bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files); diff --git a/thirdparty/openxr/src/common/hex_and_handles.h b/thirdparty/openxr/src/common/hex_and_handles.h new file mode 100644 index 0000000000..341013d32b --- /dev/null +++ b/thirdparty/openxr/src/common/hex_and_handles.h @@ -0,0 +1,108 @@ +// Copyright (c) 2017-2022, The Khronos Group Inc. +// Copyright (c) 2017-2019 Valve Corporation +// Copyright (c) 2017-2019 LunarG, Inc. +// Copyright (c) 2019 Collabora, Ltd. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Initial Author: Ryan Pavlik <ryan.pavlik@collabora.com> +// + +/*! + * @file + * + * Some utilities, primarily for working with OpenXR handles in a generic way. + */ + +#pragma once + +#include <openxr/openxr.h> + +#include <string> +#include <stdint.h> + +inline std::string to_hex(const uint8_t* const data, size_t bytes) { + std::string out(2 + bytes * 2, '?'); + out[0] = '0'; + out[1] = 'x'; + static const char* hex = "0123456789abcdef"; + auto ch = out.end(); + for (size_t i = 0; i < bytes; ++i) { + auto b = data[i]; + *--ch = hex[(b >> 0) & 0xf]; + *--ch = hex[(b >> 4) & 0xf]; + } + return out; +} + +template <typename T> +inline std::string to_hex(const T& data) { + return to_hex(reinterpret_cast<const uint8_t* const>(&data), sizeof(data)); +} + +#if XR_PTR_SIZE == 8 +/// Convert a handle into a same-sized integer. +template <typename T> +static inline uint64_t MakeHandleGeneric(T handle) { + return reinterpret_cast<uint64_t>(handle); +} + +/// Treat an integer as a handle +template <typename T> +static inline T& TreatIntegerAsHandle(uint64_t& handle) { + return reinterpret_cast<T&>(handle); +} + +/// @overload +template <typename T> +static inline T const& TreatIntegerAsHandle(uint64_t const& handle) { + return reinterpret_cast<T const&>(handle); +} + +/// Does a correctly-sized integer represent a null handle? +static inline bool IsIntegerNullHandle(uint64_t handle) { return XR_NULL_HANDLE == reinterpret_cast<void*>(handle); } + +#else + +/// Convert a handle into a same-sized integer: no-op on 32-bit systems +static inline uint64_t MakeHandleGeneric(uint64_t handle) { return handle; } + +/// Treat an integer as a handle: no-op on 32-bit systems +template <typename T> +static inline T& TreatIntegerAsHandle(uint64_t& handle) { + return handle; +} + +/// @overload +template <typename T> +static inline T const& TreatIntegerAsHandle(uint64_t const& handle) { + return handle; +} + +/// Does a correctly-sized integer represent a null handle? +static inline bool IsIntegerNullHandle(uint64_t handle) { return XR_NULL_HANDLE == handle; } + +#endif + +/// Turns a uint64_t into a string formatted as hex. +/// +/// The core of the HandleToHexString implementation is in here. +inline std::string Uint64ToHexString(uint64_t val) { return to_hex(val); } + +/// Turns a uint32_t into a string formatted as hex. +inline std::string Uint32ToHexString(uint32_t val) { return to_hex(val); } + +/// Turns an OpenXR handle into a string formatted as hex. +template <typename T> +inline std::string HandleToHexString(T handle) { + return to_hex(handle); +} + +/// Turns a pointer-sized integer into a string formatted as hex. +inline std::string UintptrToHexString(uintptr_t val) { return to_hex(val); } + +/// Convert a pointer to a string formatted as hex. +template <typename T> +inline std::string PointerToHexString(T const* ptr) { + return to_hex(ptr); +} diff --git a/thirdparty/openxr/src/common/loader_interfaces.h b/thirdparty/openxr/src/common/loader_interfaces.h new file mode 100644 index 0000000000..9c74ed16f3 --- /dev/null +++ b/thirdparty/openxr/src/common/loader_interfaces.h @@ -0,0 +1,114 @@ +// Copyright (c) 2017-2022, The Khronos Group Inc. +// Copyright (c) 2017 Valve Corporation +// Copyright (c) 2017 LunarG, Inc. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Initial Author: Mark Young <marky@lunarg.com> +// + +#pragma once + +#include <openxr/openxr.h> + +#ifdef __cplusplus +extern "C" { +#endif + +// Forward declare. +typedef struct XrApiLayerCreateInfo XrApiLayerCreateInfo; + +// Function pointer prototype for the xrCreateApiLayerInstance function used in place of xrCreateInstance. +// This function allows us to pass special API layer information to each layer during the process of creating an Instance. +typedef XrResult(XRAPI_PTR *PFN_xrCreateApiLayerInstance)(const XrInstanceCreateInfo *info, + const XrApiLayerCreateInfo *apiLayerInfo, XrInstance *instance); + +// Loader/API Layer Interface versions +// 1 - First version, introduces negotiation structure and functions +#define XR_CURRENT_LOADER_API_LAYER_VERSION 1 + +// Loader/Runtime Interface versions +// 1 - First version, introduces negotiation structure and functions +#define XR_CURRENT_LOADER_RUNTIME_VERSION 1 + +// Version negotiation values +typedef enum XrLoaderInterfaceStructs { + XR_LOADER_INTERFACE_STRUCT_UNINTIALIZED = 0, + XR_LOADER_INTERFACE_STRUCT_LOADER_INFO, + XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST, + XR_LOADER_INTERFACE_STRUCT_RUNTIME_REQUEST, + XR_LOADER_INTERFACE_STRUCT_API_LAYER_CREATE_INFO, + XR_LOADER_INTERFACE_STRUCT_API_LAYER_NEXT_INFO, +} XrLoaderInterfaceStructs; + +#define XR_LOADER_INFO_STRUCT_VERSION 1 +typedef struct XrNegotiateLoaderInfo { + XrLoaderInterfaceStructs structType; // XR_LOADER_INTERFACE_STRUCT_LOADER_INFO + uint32_t structVersion; // XR_LOADER_INFO_STRUCT_VERSION + size_t structSize; // sizeof(XrNegotiateLoaderInfo) + uint32_t minInterfaceVersion; + uint32_t maxInterfaceVersion; + XrVersion minApiVersion; + XrVersion maxApiVersion; +} XrNegotiateLoaderInfo; + +#define XR_API_LAYER_INFO_STRUCT_VERSION 1 +typedef struct XrNegotiateApiLayerRequest { + XrLoaderInterfaceStructs structType; // XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST + uint32_t structVersion; // XR_API_LAYER_INFO_STRUCT_VERSION + size_t structSize; // sizeof(XrNegotiateApiLayerRequest) + uint32_t layerInterfaceVersion; // CURRENT_LOADER_API_LAYER_VERSION + XrVersion layerApiVersion; + PFN_xrGetInstanceProcAddr getInstanceProcAddr; + PFN_xrCreateApiLayerInstance createApiLayerInstance; +} XrNegotiateApiLayerRequest; + +#define XR_RUNTIME_INFO_STRUCT_VERSION 1 +typedef struct XrNegotiateRuntimeRequest { + XrLoaderInterfaceStructs structType; // XR_LOADER_INTERFACE_STRUCT_RUNTIME_REQUEST + uint32_t structVersion; // XR_RUNTIME_INFO_STRUCT_VERSION + size_t structSize; // sizeof(XrNegotiateRuntimeRequest) + uint32_t runtimeInterfaceVersion; // CURRENT_LOADER_RUNTIME_VERSION + XrVersion runtimeApiVersion; + PFN_xrGetInstanceProcAddr getInstanceProcAddr; +} XrNegotiateRuntimeRequest; + +// Function used to negotiate an interface betewen the loader and an API layer. Each library exposing one or +// more API layers needs to expose at least this function. +typedef XrResult(XRAPI_PTR *PFN_xrNegotiateLoaderApiLayerInterface)(const XrNegotiateLoaderInfo *loaderInfo, + const char *apiLayerName, + XrNegotiateApiLayerRequest *apiLayerRequest); + +// Function used to negotiate an interface betewen the loader and a runtime. Each runtime should expose +// at least this function. +typedef XrResult(XRAPI_PTR *PFN_xrNegotiateLoaderRuntimeInterface)(const XrNegotiateLoaderInfo *loaderInfo, + XrNegotiateRuntimeRequest *runtimeRequest); + +// Forward declare. +typedef struct XrApiLayerNextInfo XrApiLayerNextInfo; + +#define XR_API_LAYER_NEXT_INFO_STRUCT_VERSION 1 +struct XrApiLayerNextInfo { + XrLoaderInterfaceStructs structType; // XR_LOADER_INTERFACE_STRUCT_API_LAYER_NEXT_INFO + uint32_t structVersion; // XR_API_LAYER_NEXT_INFO_STRUCT_VERSION + size_t structSize; // sizeof(XrApiLayerNextInfo) + char layerName[XR_MAX_API_LAYER_NAME_SIZE]; // Name of API layer which should receive this info + PFN_xrGetInstanceProcAddr nextGetInstanceProcAddr; // Pointer to next API layer's xrGetInstanceProcAddr + PFN_xrCreateApiLayerInstance nextCreateApiLayerInstance; // Pointer to next API layer's xrCreateApiLayerInstance + XrApiLayerNextInfo *next; // Pointer to the next API layer info in the sequence +}; + +#define XR_API_LAYER_MAX_SETTINGS_PATH_SIZE 512 +#define XR_API_LAYER_CREATE_INFO_STRUCT_VERSION 1 +typedef struct XrApiLayerCreateInfo { + XrLoaderInterfaceStructs structType; // XR_LOADER_INTERFACE_STRUCT_API_LAYER_CREATE_INFO + uint32_t structVersion; // XR_API_LAYER_CREATE_INFO_STRUCT_VERSION + size_t structSize; // sizeof(XrApiLayerCreateInfo) + void *loaderInstance; // Pointer to the LoaderInstance class + char settings_file_location[XR_API_LAYER_MAX_SETTINGS_PATH_SIZE]; // Location to the found settings file (or empty '\0') + XrApiLayerNextInfo *nextInfo; // Pointer to the next API layer's Info +} XrApiLayerCreateInfo; + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/thirdparty/openxr/src/common/object_info.cpp b/thirdparty/openxr/src/common/object_info.cpp new file mode 100644 index 0000000000..95b5aaf404 --- /dev/null +++ b/thirdparty/openxr/src/common/object_info.cpp @@ -0,0 +1,276 @@ +// Copyright (c) 2017-2022, The Khronos Group Inc. +// Copyright (c) 2017-2019 Valve Corporation +// Copyright (c) 2017-2019 LunarG, Inc. +// Copyright (c) 2019 Collabora, Ltd. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Initial Authors: Mark Young <marky@lunarg.com> +// Ryan Pavlik <ryan.pavlik@collabora.com> +// Dave Houlton <daveh@lunarg.com> +// + +#include "object_info.h" + +#include "extra_algorithms.h" +#include "hex_and_handles.h" + +#include <openxr/openxr.h> + +#include <algorithm> +#include <iterator> +#include <memory> +#include <sstream> +#include <string> +#include <vector> + +#include "memory.h" + +std::string XrSdkLogObjectInfo::ToString() const { + std::ostringstream oss; + oss << Uint64ToHexString(handle); + if (!name.empty()) { + oss << " (" << name << ")"; + } + return oss.str(); +} + +void ObjectInfoCollection::AddObjectName(uint64_t object_handle, XrObjectType object_type, const std::string& object_name) { + // If name is empty, we should erase it + if (object_name.empty()) { + RemoveObject(object_handle, object_type); + return; + } + + // Otherwise, add it or update the name + XrSdkLogObjectInfo new_obj = {object_handle, object_type}; + + // If it already exists, update the name + auto lookup_info = LookUpStoredObjectInfo(new_obj); + if (lookup_info != nullptr) { + lookup_info->name = object_name; + return; + } + + // It doesn't exist, so add a new info block + new_obj.name = object_name; + object_info_.push_back(new_obj); +} + +void ObjectInfoCollection::RemoveObject(uint64_t object_handle, XrObjectType object_type) { + vector_remove_if_and_erase( + object_info_, [=](XrSdkLogObjectInfo const& info) { return info.handle == object_handle && info.type == object_type; }); +} + +XrSdkLogObjectInfo const* ObjectInfoCollection::LookUpStoredObjectInfo(XrSdkLogObjectInfo const& info) const { + auto e = object_info_.end(); + auto it = std::find_if(object_info_.begin(), e, [&](XrSdkLogObjectInfo const& stored) { return Equivalent(stored, info); }); + if (it != e) { + return &(*it); + } + return nullptr; +} + +XrSdkLogObjectInfo* ObjectInfoCollection::LookUpStoredObjectInfo(XrSdkLogObjectInfo const& info) { + auto e = object_info_.end(); + auto it = std::find_if(object_info_.begin(), e, [&](XrSdkLogObjectInfo const& stored) { return Equivalent(stored, info); }); + if (it != e) { + return &(*it); + } + return nullptr; +} + +bool ObjectInfoCollection::LookUpObjectName(XrDebugUtilsObjectNameInfoEXT& info) const { + auto info_lookup = LookUpStoredObjectInfo(info.objectHandle, info.objectType); + if (info_lookup != nullptr) { + info.objectName = info_lookup->name.c_str(); + return true; + } + return false; +} + +bool ObjectInfoCollection::LookUpObjectName(XrSdkLogObjectInfo& info) const { + auto info_lookup = LookUpStoredObjectInfo(info); + if (info_lookup != nullptr) { + info.name = info_lookup->name; + return true; + } + return false; +} + +static std::vector<XrDebugUtilsObjectNameInfoEXT> PopulateObjectNameInfo(std::vector<XrSdkLogObjectInfo> const& obj) { + std::vector<XrDebugUtilsObjectNameInfoEXT> ret; + ret.reserve(obj.size()); + std::transform(obj.begin(), obj.end(), std::back_inserter(ret), [](XrSdkLogObjectInfo const& info) { + return XrDebugUtilsObjectNameInfoEXT{XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, nullptr, info.type, info.handle, + info.name.c_str()}; + }); + return ret; +} + +NamesAndLabels::NamesAndLabels(std::vector<XrSdkLogObjectInfo> obj, std::vector<XrDebugUtilsLabelEXT> lab) + : sdk_objects(std::move(obj)), objects(PopulateObjectNameInfo(sdk_objects)), labels(std::move(lab)) {} + +void NamesAndLabels::PopulateCallbackData(XrDebugUtilsMessengerCallbackDataEXT& callback_data) const { + callback_data.objects = objects.empty() ? nullptr : const_cast<XrDebugUtilsObjectNameInfoEXT*>(objects.data()); + callback_data.objectCount = static_cast<uint32_t>(objects.size()); + callback_data.sessionLabels = labels.empty() ? nullptr : const_cast<XrDebugUtilsLabelEXT*>(labels.data()); + callback_data.sessionLabelCount = static_cast<uint32_t>(labels.size()); +} + +void DebugUtilsData::LookUpSessionLabels(XrSession session, std::vector<XrDebugUtilsLabelEXT>& labels) const { + auto session_label_iterator = session_labels_.find(session); + if (session_label_iterator != session_labels_.end()) { + auto& XrSdkSessionLabels = *session_label_iterator->second; + // Copy the debug utils labels in reverse order in the the labels vector. + std::transform(XrSdkSessionLabels.rbegin(), XrSdkSessionLabels.rend(), std::back_inserter(labels), + [](XrSdkSessionLabelPtr const& label) { return label->debug_utils_label; }); + } +} + +XrSdkSessionLabel::XrSdkSessionLabel(const XrDebugUtilsLabelEXT& label_info, bool individual) + : label_name(label_info.labelName), debug_utils_label(label_info), is_individual_label(individual) { + // Update the c string pointer to the one we hold. + debug_utils_label.labelName = label_name.c_str(); +} + +XrSdkSessionLabelPtr XrSdkSessionLabel::make(const XrDebugUtilsLabelEXT& label_info, bool individual) { + XrSdkSessionLabelPtr ret(new XrSdkSessionLabel(label_info, individual)); + return ret; +} +void DebugUtilsData::AddObjectName(uint64_t object_handle, XrObjectType object_type, const std::string& object_name) { + object_info_.AddObjectName(object_handle, object_type, object_name); +} + +// We always want to remove the old individual label before we do anything else. +// So, do that in it's own method +void DebugUtilsData::RemoveIndividualLabel(XrSdkSessionLabelList& label_vec) { + if (!label_vec.empty() && label_vec.back()->is_individual_label) { + label_vec.pop_back(); + } +} + +XrSdkSessionLabelList* DebugUtilsData::GetSessionLabelList(XrSession session) { + auto session_label_iterator = session_labels_.find(session); + if (session_label_iterator == session_labels_.end()) { + return nullptr; + } + return session_label_iterator->second.get(); +} + +XrSdkSessionLabelList& DebugUtilsData::GetOrCreateSessionLabelList(XrSession session) { + XrSdkSessionLabelList* vec_ptr = GetSessionLabelList(session); + if (vec_ptr == nullptr) { + std::unique_ptr<XrSdkSessionLabelList> vec(new XrSdkSessionLabelList); + vec_ptr = vec.get(); + session_labels_[session] = std::move(vec); + } + return *vec_ptr; +} + +void DebugUtilsData::BeginLabelRegion(XrSession session, const XrDebugUtilsLabelEXT& label_info) { + auto& vec = GetOrCreateSessionLabelList(session); + + // Individual labels do not stay around in the transition into a new label region + RemoveIndividualLabel(vec); + + // Start the new label region + vec.emplace_back(XrSdkSessionLabel::make(label_info, false)); +} + +void DebugUtilsData::EndLabelRegion(XrSession session) { + XrSdkSessionLabelList* vec_ptr = GetSessionLabelList(session); + if (vec_ptr == nullptr) { + return; + } + + // Individual labels do not stay around in the transition out of label region + RemoveIndividualLabel(*vec_ptr); + + // Remove the last label region + if (!vec_ptr->empty()) { + vec_ptr->pop_back(); + } +} + +void DebugUtilsData::InsertLabel(XrSession session, const XrDebugUtilsLabelEXT& label_info) { + auto& vec = GetOrCreateSessionLabelList(session); + + // Remove any individual layer that might already be there + RemoveIndividualLabel(vec); + + // Insert a new individual label + vec.emplace_back(XrSdkSessionLabel::make(label_info, true)); +} + +void DebugUtilsData::DeleteObject(uint64_t object_handle, XrObjectType object_type) { + object_info_.RemoveObject(object_handle, object_type); + + if (object_type == XR_OBJECT_TYPE_SESSION) { + auto session = TreatIntegerAsHandle<XrSession>(object_handle); + XrSdkSessionLabelList* vec_ptr = GetSessionLabelList(session); + if (vec_ptr != nullptr) { + session_labels_.erase(session); + } + } +} + +void DebugUtilsData::DeleteSessionLabels(XrSession session) { session_labels_.erase(session); } + +NamesAndLabels DebugUtilsData::PopulateNamesAndLabels(std::vector<XrSdkLogObjectInfo> objects) const { + std::vector<XrDebugUtilsLabelEXT> labels; + for (auto& obj : objects) { + // Check for any names that have been associated with the objects and set them up here + object_info_.LookUpObjectName(obj); + // If this is a session, see if there are any labels associated with it for us to add + // to the callback content. + if (XR_OBJECT_TYPE_SESSION == obj.type) { + LookUpSessionLabels(obj.GetTypedHandle<XrSession>(), labels); + } + } + + return {objects, labels}; +} + +void DebugUtilsData::WrapCallbackData(AugmentedCallbackData* aug_data, + const XrDebugUtilsMessengerCallbackDataEXT* callback_data) const { + // If there's nothing to add, just return the original data as the augmented copy + aug_data->exported_data = callback_data; + if (object_info_.Empty() || callback_data->objectCount == 0) { + return; + } + + // Inspect each of the callback objects + bool name_found = false; + for (uint32_t obj = 0; obj < callback_data->objectCount; ++obj) { + auto& current_obj = callback_data->objects[obj]; + name_found |= (nullptr != object_info_.LookUpStoredObjectInfo(current_obj.objectHandle, current_obj.objectType)); + + // If this is a session, record any labels associated with it + if (XR_OBJECT_TYPE_SESSION == current_obj.objectType) { + XrSession session = TreatIntegerAsHandle<XrSession>(current_obj.objectHandle); + LookUpSessionLabels(session, aug_data->labels); + } + } + + // If we found nothing to add, return the original data + if (!name_found && aug_data->labels.empty()) { + return; + } + + // Found additional data - modify an internal copy and return that as the exported data + memcpy(&aug_data->modified_data, callback_data, sizeof(XrDebugUtilsMessengerCallbackDataEXT)); + aug_data->new_objects.assign(callback_data->objects, callback_data->objects + callback_data->objectCount); + + // Record (overwrite) the names of all incoming objects provided in our internal list + for (auto& obj : aug_data->new_objects) { + object_info_.LookUpObjectName(obj); + } + + // Update local copy & point export to it + aug_data->modified_data.objects = aug_data->new_objects.data(); + aug_data->modified_data.sessionLabelCount = static_cast<uint32_t>(aug_data->labels.size()); + aug_data->modified_data.sessionLabels = aug_data->labels.empty() ? nullptr : aug_data->labels.data(); + aug_data->exported_data = &aug_data->modified_data; + return; +} diff --git a/thirdparty/openxr/src/common/object_info.h b/thirdparty/openxr/src/common/object_info.h new file mode 100644 index 0000000000..8e9742b605 --- /dev/null +++ b/thirdparty/openxr/src/common/object_info.h @@ -0,0 +1,229 @@ +// Copyright (c) 2017-2022, The Khronos Group Inc. +// Copyright (c) 2017-2019 Valve Corporation +// Copyright (c) 2017-2019 LunarG, Inc. +// Copyright (c) 2019 Collabora, Ltd. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Initial Authors: Mark Young <marky@lunarg.com>, Ryan Pavlik <ryan.pavlik@collabora.com +// +/*! + * @file + * + * The core of an XR_EXT_debug_utils implementation, used/shared by the loader and several SDK layers. + */ + +#pragma once + +#include "hex_and_handles.h" + +#include <openxr/openxr.h> + +#include <memory> +#include <string> +#include <unordered_map> +#include <vector> + +struct XrSdkGenericObject { + //! Type-erased handle value + uint64_t handle; + + //! Kind of object this handle refers to + XrObjectType type; + /// Un-erase the type of the handle and get it properly typed again. + /// + /// Note: Does not check the type before doing it! + template <typename HandleType> + HandleType& GetTypedHandle() { + return TreatIntegerAsHandle<HandleType&>(handle); + } + + //! @overload + template <typename HandleType> + HandleType const& GetTypedHandle() const { + return TreatIntegerAsHandle<HandleType&>(handle); + } + + //! Create from a typed handle and object type + template <typename T> + XrSdkGenericObject(T h, XrObjectType t) : handle(MakeHandleGeneric(h)), type(t) {} + + //! Create from an untyped handle value (integer) and object type + XrSdkGenericObject(uint64_t h, XrObjectType t) : handle(h), type(t) {} +}; + +struct XrSdkLogObjectInfo { + //! Type-erased handle value + uint64_t handle; + + //! Kind of object this handle refers to + XrObjectType type; + + //! To be assigned by the application - not part of this object's identity + std::string name; + + /// Un-erase the type of the handle and get it properly typed again. + /// + /// Note: Does not check the type before doing it! + template <typename HandleType> + HandleType& GetTypedHandle() { + return TreatIntegerAsHandle<HandleType&>(handle); + } + + //! @overload + template <typename HandleType> + HandleType const& GetTypedHandle() const { + return TreatIntegerAsHandle<HandleType&>(handle); + } + + XrSdkLogObjectInfo() = default; + + //! Create from a typed handle and object type + template <typename T> + XrSdkLogObjectInfo(T h, XrObjectType t) : handle(MakeHandleGeneric(h)), type(t) {} + + //! Create from an untyped handle value (integer) and object type + XrSdkLogObjectInfo(uint64_t h, XrObjectType t) : handle(h), type(t) {} + //! Create from an untyped handle value (integer), object type, and name + XrSdkLogObjectInfo(uint64_t h, XrObjectType t, const char* n) : handle(h), type(t), name(n == nullptr ? "" : n) {} + + std::string ToString() const; +}; + +//! True if the two object infos have the same handle value and handle type +static inline bool Equivalent(XrSdkLogObjectInfo const& a, XrSdkLogObjectInfo const& b) { + return a.handle == b.handle && a.type == b.type; +} + +//! @overload +static inline bool Equivalent(XrDebugUtilsObjectNameInfoEXT const& a, XrSdkLogObjectInfo const& b) { + return a.objectHandle == b.handle && a.objectType == b.type; +} + +//! @overload +static inline bool Equivalent(XrSdkLogObjectInfo const& a, XrDebugUtilsObjectNameInfoEXT const& b) { return Equivalent(b, a); } + +/// Object info registered with calls to xrSetDebugUtilsObjectNameEXT +class ObjectInfoCollection { + public: + void AddObjectName(uint64_t object_handle, XrObjectType object_type, const std::string& object_name); + + void RemoveObject(uint64_t object_handle, XrObjectType object_type); + + //! Find the stored object info, if any, matching handle and type. + //! Return nullptr if not found. + XrSdkLogObjectInfo const* LookUpStoredObjectInfo(XrSdkLogObjectInfo const& info) const; + + //! Find the stored object info, if any, matching handle and type. + //! Return nullptr if not found. + XrSdkLogObjectInfo* LookUpStoredObjectInfo(XrSdkLogObjectInfo const& info); + + //! Find the stored object info, if any. + //! Return nullptr if not found. + XrSdkLogObjectInfo const* LookUpStoredObjectInfo(uint64_t handle, XrObjectType type) const { + return LookUpStoredObjectInfo({handle, type}); + } + + //! Find the object name, if any, and update debug utils info accordingly. + //! Return true if found and updated. + bool LookUpObjectName(XrDebugUtilsObjectNameInfoEXT& info) const; + + //! Find the object name, if any, and update logging info accordingly. + //! Return true if found and updated. + bool LookUpObjectName(XrSdkLogObjectInfo& info) const; + + //! Is the collection empty? + bool Empty() const { return object_info_.empty(); } + + private: + // Object names that have been set for given objects + std::vector<XrSdkLogObjectInfo> object_info_; +}; + +struct XrSdkSessionLabel; +using XrSdkSessionLabelPtr = std::unique_ptr<XrSdkSessionLabel>; +using XrSdkSessionLabelList = std::vector<XrSdkSessionLabelPtr>; + +struct XrSdkSessionLabel { + static XrSdkSessionLabelPtr make(const XrDebugUtilsLabelEXT& label_info, bool individual); + + std::string label_name; + XrDebugUtilsLabelEXT debug_utils_label; + bool is_individual_label; + + private: + XrSdkSessionLabel(const XrDebugUtilsLabelEXT& label_info, bool individual); +}; + +/// The metadata for a collection of objects. Must persist unmodified during the entire debug messenger call! +struct NamesAndLabels { + NamesAndLabels() = default; + NamesAndLabels(std::vector<XrSdkLogObjectInfo> obj, std::vector<XrDebugUtilsLabelEXT> lab); + /// C++ structure owning the data (strings) backing the objects vector. + std::vector<XrSdkLogObjectInfo> sdk_objects; + + std::vector<XrDebugUtilsObjectNameInfoEXT> objects; + std::vector<XrDebugUtilsLabelEXT> labels; + + /// Populate the debug utils callback data structure. + void PopulateCallbackData(XrDebugUtilsMessengerCallbackDataEXT& data) const; + // XrDebugUtilsMessengerCallbackDataEXT MakeCallbackData() const; +}; + +struct AugmentedCallbackData { + std::vector<XrDebugUtilsLabelEXT> labels; + std::vector<XrDebugUtilsObjectNameInfoEXT> new_objects; + XrDebugUtilsMessengerCallbackDataEXT modified_data; + const XrDebugUtilsMessengerCallbackDataEXT* exported_data; +}; + +/// Tracks all the data (handle names and session labels) required to fully augment XR_EXT_debug_utils-related calls. +class DebugUtilsData { + public: + DebugUtilsData() = default; + + DebugUtilsData(const DebugUtilsData&) = delete; + DebugUtilsData& operator=(const DebugUtilsData&) = delete; + + bool Empty() const { return object_info_.Empty() && session_labels_.empty(); } + + //! Core of implementation for xrSetDebugUtilsObjectNameEXT + void AddObjectName(uint64_t object_handle, XrObjectType object_type, const std::string& object_name); + + /// Core of implementation for xrSessionBeginDebugUtilsLabelRegionEXT + void BeginLabelRegion(XrSession session, const XrDebugUtilsLabelEXT& label_info); + + /// Core of implementation for xrSessionEndDebugUtilsLabelRegionEXT + void EndLabelRegion(XrSession session); + + /// Core of implementation for xrSessionInsertDebugUtilsLabelEXT + void InsertLabel(XrSession session, const XrDebugUtilsLabelEXT& label_info); + + /// Removes all labels associated with a session - call in xrDestroySession and xrDestroyInstance (for all child sessions) + void DeleteSessionLabels(XrSession session); + + /// Retrieve labels for the given session, if any, and push them in reverse order on the vector. + void LookUpSessionLabels(XrSession session, std::vector<XrDebugUtilsLabelEXT>& labels) const; + + /// Removes all data related to this object - including session labels if it's a session. + /// + /// Does not take care of handling child objects - you must do this yourself. + void DeleteObject(uint64_t object_handle, XrObjectType object_type); + + /// Given the collection of objects, populate their names and list of labels + NamesAndLabels PopulateNamesAndLabels(std::vector<XrSdkLogObjectInfo> objects) const; + + void WrapCallbackData(AugmentedCallbackData* aug_data, + const XrDebugUtilsMessengerCallbackDataEXT* provided_callback_data) const; + + private: + void RemoveIndividualLabel(XrSdkSessionLabelList& label_vec); + XrSdkSessionLabelList* GetSessionLabelList(XrSession session); + XrSdkSessionLabelList& GetOrCreateSessionLabelList(XrSession session); + + // Session labels: one vector of them per session. + std::unordered_map<XrSession, std::unique_ptr<XrSdkSessionLabelList>> session_labels_; + + // Names for objects. + ObjectInfoCollection object_info_; +}; diff --git a/thirdparty/openxr/src/common/platform_utils.hpp b/thirdparty/openxr/src/common/platform_utils.hpp new file mode 100644 index 0000000000..85d5cdab10 --- /dev/null +++ b/thirdparty/openxr/src/common/platform_utils.hpp @@ -0,0 +1,345 @@ +// Copyright (c) 2017-2022, The Khronos Group Inc. +// Copyright (c) 2017-2019 Valve Corporation +// Copyright (c) 2017-2019 LunarG, Inc. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Initial Authors: Mark Young <marky@lunarg.com>, Dave Houlton <daveh@lunarg.com> +// + +#pragma once + +#include "xr_dependencies.h" +#include <string> +#include <stdlib.h> + +// OpenXR paths and registry key locations +#define OPENXR_RELATIVE_PATH "openxr/" +#define OPENXR_IMPLICIT_API_LAYER_RELATIVE_PATH "/api_layers/implicit.d" +#define OPENXR_EXPLICIT_API_LAYER_RELATIVE_PATH "/api_layers/explicit.d" +#ifdef XR_OS_WINDOWS +#define OPENXR_REGISTRY_LOCATION "SOFTWARE\\Khronos\\OpenXR\\" +#define OPENXR_IMPLICIT_API_LAYER_REGISTRY_LOCATION "\\ApiLayers\\Implicit" +#define OPENXR_EXPLICIT_API_LAYER_REGISTRY_LOCATION "\\ApiLayers\\Explicit" +#endif + +// OpenXR Loader environment variables of interest +#define OPENXR_RUNTIME_JSON_ENV_VAR "XR_RUNTIME_JSON" +#define OPENXR_API_LAYER_PATH_ENV_VAR "XR_API_LAYER_PATH" + +// This is a CMake generated file with #defines for any functions/includes +// that it found present and build-time configuration. +// If you don't have this file, on non-Windows you'll need to define +// one of HAVE_SECURE_GETENV or HAVE___SECURE_GETENV depending on which +// of secure_getenv or __secure_getenv are present +#ifdef OPENXR_HAVE_COMMON_CONFIG +#include "common_config.h" +#endif // OPENXR_HAVE_COMMON_CONFIG + +// Environment variables +#if defined(XR_OS_LINUX) || defined(XR_OS_APPLE) + +#include <unistd.h> +#include <fcntl.h> +#include <iostream> + +namespace detail { + +static inline char* ImplGetEnv(const char* name) { return getenv(name); } + +static inline int ImplSetEnv(const char* name, const char* value, int overwrite) { return setenv(name, value, overwrite); } + +static inline char* ImplGetSecureEnv(const char* name) { +#ifdef HAVE_SECURE_GETENV + return secure_getenv(name); +#elif defined(HAVE___SECURE_GETENV) + return __secure_getenv(name); +#else +#pragma message( \ + "Warning: Falling back to non-secure getenv for environmental" \ + "lookups! Consider updating to a different libc.") + + return ImplGetEnv(name); +#endif +} +} // namespace detail + +#endif // defined(XR_OS_LINUX) || defined(XR_OS_APPLE) +#if defined(XR_OS_LINUX) + +static inline std::string PlatformUtilsGetEnv(const char* name) { + auto str = detail::ImplGetEnv(name); + if (str == nullptr) { + return {}; + } + return str; +} + +static inline std::string PlatformUtilsGetSecureEnv(const char* name) { + auto str = detail::ImplGetSecureEnv(name); + if (str == nullptr) { + return {}; + } + return str; +} + +static inline bool PlatformUtilsGetEnvSet(const char* name) { return detail::ImplGetEnv(name) != nullptr; } + +static inline bool PlatformUtilsSetEnv(const char* name, const char* value) { + const int shouldOverwrite = 1; + int result = detail::ImplSetEnv(name, value, shouldOverwrite); + return (result == 0); +} + +#elif defined(XR_OS_APPLE) + +static inline std::string PlatformUtilsGetEnv(const char* name) { + auto str = detail::ImplGetEnv(name); + if (str == nullptr) { + return {}; + } + return str; +} + +static inline std::string PlatformUtilsGetSecureEnv(const char* name) { + auto str = detail::ImplGetSecureEnv(name); + if (str == nullptr) { + return {}; + } + return str; +} + +static inline bool PlatformUtilsGetEnvSet(const char* name) { return detail::ImplGetEnv(name) != nullptr; } + +static inline bool PlatformUtilsSetEnv(const char* name, const char* value) { + const int shouldOverwrite = 1; + int result = detail::ImplSetEnv(name, value, shouldOverwrite); + return (result == 0); +} + +// Prefix for the Apple global runtime JSON file name +static const std::string rt_dir_prefix = "/usr/local/share/openxr/"; +static const std::string rt_filename = "/active_runtime.json"; + +static inline bool PlatformGetGlobalRuntimeFileName(uint16_t major_version, std::string& file_name) { + file_name = rt_dir_prefix; + file_name += std::to_string(major_version); + file_name += rt_filename; + return true; +} + +#elif defined(XR_OS_WINDOWS) + +#if !defined(NDEBUG) +inline void LogError(const std::string& error) { OutputDebugStringA(error.c_str()); } +#else +#define LogError(x) +#endif + +inline std::wstring utf8_to_wide(const std::string& utf8Text) { + if (utf8Text.empty()) { + return {}; + } + + std::wstring wideText; + const int wideLength = ::MultiByteToWideChar(CP_UTF8, 0, utf8Text.data(), (int)utf8Text.size(), nullptr, 0); + if (wideLength == 0) { + LogError("utf8_to_wide get size error: " + std::to_string(::GetLastError())); + return {}; + } + + // MultiByteToWideChar returns number of chars of the input buffer, regardless of null terminitor + wideText.resize(wideLength, 0); + wchar_t* wideString = const_cast<wchar_t*>(wideText.data()); // mutable data() only exists in c++17 + const int length = ::MultiByteToWideChar(CP_UTF8, 0, utf8Text.data(), (int)utf8Text.size(), wideString, wideLength); + if (length != wideLength) { + LogError("utf8_to_wide convert string error: " + std::to_string(::GetLastError())); + return {}; + } + + return wideText; +} + +inline std::string wide_to_utf8(const std::wstring& wideText) { + if (wideText.empty()) { + return {}; + } + + std::string narrowText; + int narrowLength = ::WideCharToMultiByte(CP_UTF8, 0, wideText.data(), (int)wideText.size(), nullptr, 0, nullptr, nullptr); + if (narrowLength == 0) { + LogError("wide_to_utf8 get size error: " + std::to_string(::GetLastError())); + return {}; + } + + // WideCharToMultiByte returns number of chars of the input buffer, regardless of null terminitor + narrowText.resize(narrowLength, 0); + char* narrowString = const_cast<char*>(narrowText.data()); // mutable data() only exists in c++17 + const int length = + ::WideCharToMultiByte(CP_UTF8, 0, wideText.data(), (int)wideText.size(), narrowString, narrowLength, nullptr, nullptr); + if (length != narrowLength) { + LogError("wide_to_utf8 convert string error: " + std::to_string(::GetLastError())); + return {}; + } + + return narrowText; +} + +// Returns true if the current process has an integrity level > SECURITY_MANDATORY_MEDIUM_RID. +static inline bool IsHighIntegrityLevel() { + // Execute this check once and save the value as a static bool. + static bool isHighIntegrityLevel = ([] { + HANDLE processToken; + if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_QUERY_SOURCE, &processToken)) { + // Maximum possible size of SID_AND_ATTRIBUTES is maximum size of a SID + size of attributes DWORD. + uint8_t mandatoryLabelBuffer[SECURITY_MAX_SID_SIZE + sizeof(DWORD)]{}; + DWORD bufferSize; + if (GetTokenInformation(processToken, TokenIntegrityLevel, mandatoryLabelBuffer, sizeof(mandatoryLabelBuffer), + &bufferSize) != 0) { + const auto mandatoryLabel = reinterpret_cast<const TOKEN_MANDATORY_LABEL*>(mandatoryLabelBuffer); + if (mandatoryLabel->Label.Sid != 0) { + const DWORD subAuthorityCount = *GetSidSubAuthorityCount(mandatoryLabel->Label.Sid); + const DWORD integrityLevel = *GetSidSubAuthority(mandatoryLabel->Label.Sid, subAuthorityCount - 1); + CloseHandle(processToken); + return integrityLevel > SECURITY_MANDATORY_MEDIUM_RID; + } + } + + CloseHandle(processToken); + } + + return false; + })(); + + return isHighIntegrityLevel; +} + +// Returns true if the given environment variable exists. +// The name is a case-sensitive UTF8 string. +static inline bool PlatformUtilsGetEnvSet(const char* name) { + const std::wstring wname = utf8_to_wide(name); + const DWORD valSize = ::GetEnvironmentVariableW(wname.c_str(), nullptr, 0); + // GetEnvironmentVariable returns 0 when environment variable does not exist or there is an error. + return 0 != valSize; +} + +// Returns the environment variable value for the given name. +// Returns an empty string if the environment variable doesn't exist or if it exists but is empty. +// Use PlatformUtilsGetEnvSet to tell if it exists. +// The name is a case-sensitive UTF8 string. +static inline std::string PlatformUtilsGetEnv(const char* name) { + const std::wstring wname = utf8_to_wide(name); + const DWORD valSize = ::GetEnvironmentVariableW(wname.c_str(), nullptr, 0); + // GetEnvironmentVariable returns 0 when environment variable does not exist or there is an error. + // The size includes the null-terminator, so a size of 1 is means the variable was explicitly set to empty. + if (valSize == 0 || valSize == 1) { + return {}; + } + + // GetEnvironmentVariable returns size including null terminator for "query size" call. + std::wstring wValue(valSize, 0); + wchar_t* wValueData = &wValue[0]; + + // GetEnvironmentVariable returns string length, excluding null terminator for "get value" + // call if there was enough capacity. Else it returns the required capacity (including null terminator). + const DWORD length = ::GetEnvironmentVariableW(wname.c_str(), wValueData, (DWORD)wValue.size()); + if ((length == 0) || (length >= wValue.size())) { // If error or the variable increased length between calls... + LogError("GetEnvironmentVariable get value error: " + std::to_string(::GetLastError())); + return {}; + } + + wValue.resize(length); // Strip the null terminator. + + return wide_to_utf8(wValue); +} + +// Acts the same as PlatformUtilsGetEnv except returns an empty string if IsHighIntegrityLevel. +static inline std::string PlatformUtilsGetSecureEnv(const char* name) { + // Do not allow high integrity processes to act on data that can be controlled by medium integrity processes. + if (IsHighIntegrityLevel()) { + return {}; + } + + // No secure version for Windows so the above integrity check is needed. + return PlatformUtilsGetEnv(name); +} + +// Sets an environment variable via UTF8 strings. +// The name is case-sensitive. +// Overwrites the variable if it already exists. +// Returns true if it could be set. +static inline bool PlatformUtilsSetEnv(const char* name, const char* value) { + const std::wstring wname = utf8_to_wide(name); + const std::wstring wvalue = utf8_to_wide(value); + BOOL result = ::SetEnvironmentVariableW(wname.c_str(), wvalue.c_str()); + return (result != 0); +} + +#elif defined(XR_OS_ANDROID) + +static inline bool PlatformUtilsGetEnvSet(const char* /* name */) { + // Stub func + return false; +} + +static inline std::string PlatformUtilsGetEnv(const char* /* name */) { + // Stub func + return {}; +} + +static inline std::string PlatformUtilsGetSecureEnv(const char* /* name */) { + // Stub func + return {}; +} + +static inline bool PlatformUtilsSetEnv(const char* /* name */, const char* /* value */) { + // Stub func + return false; +} + +#include <sys/stat.h> + +// Intended to be only used as a fallback on Android, with a more open, "native" technique used in most cases +static inline bool PlatformGetGlobalRuntimeFileName(uint16_t major_version, std::string& file_name) { + // Prefix for the runtime JSON file name + static const char* rt_dir_prefixes[] = {"/oem", "/vendor", "/system"}; + static const std::string rt_filename = "/active_runtime.json"; + static const std::string subdir = "/etc/openxr/"; + for (const auto prefix : rt_dir_prefixes) { + auto path = prefix + subdir + std::to_string(major_version) + rt_filename; + struct stat buf; + if (0 == stat(path.c_str(), &buf)) { + file_name = path; + return true; + } + } + return false; +} +#else // Not Linux, Apple, nor Windows + +static inline bool PlatformUtilsGetEnvSet(const char* /* name */) { + // Stub func + return false; +} + +static inline std::string PlatformUtilsGetEnv(const char* /* name */) { + // Stub func + return {}; +} + +static inline std::string PlatformUtilsGetSecureEnv(const char* /* name */) { + // Stub func + return {}; +} + +static inline bool PlatformUtilsSetEnv(const char* /* name */, const char* /* value */) { + // Stub func + return false; +} + +static inline bool PlatformGetGlobalRuntimeFileName(uint16_t /* major_version */, std::string const& /* file_name */) { + // Stub func + return false; +} + +#endif diff --git a/thirdparty/openxr/src/common/stdfs_conditions.h b/thirdparty/openxr/src/common/stdfs_conditions.h new file mode 100644 index 0000000000..6dc18cc620 --- /dev/null +++ b/thirdparty/openxr/src/common/stdfs_conditions.h @@ -0,0 +1,45 @@ +// Copyright (c) 2017-2022, The Khronos Group Inc. +// Copyright (c) 2017 Valve Corporation +// Copyright (c) 2017 LunarG, Inc. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +#ifndef _STDFS_CONDITIONS_H +#define _STDFS_CONDITIONS_H + +// If the C++ macro is set to the version containing C++17, it must support +// the final C++17 package +#if __cplusplus >= 201703L +#define USE_EXPERIMENTAL_FS 0 +#define USE_FINAL_FS 1 + +#elif defined(_MSC_VER) && _MSC_VER >= 1900 + +#if defined(_HAS_CXX17) && _HAS_CXX17 +// When MSC supports c++17 use <filesystem> package. +#define USE_EXPERIMENTAL_FS 0 +#define USE_FINAL_FS 1 +#endif // !_HAS_CXX17 + +// GCC supports the experimental filesystem items starting in GCC 6 +#elif (__GNUC__ >= 6) +#define USE_EXPERIMENTAL_FS 1 +#define USE_FINAL_FS 0 + +// If Clang, check for feature support +#elif defined(__clang__) && (__cpp_lib_filesystem || __cpp_lib_experimental_filesystem) +#if __cpp_lib_filesystem +#define USE_EXPERIMENTAL_FS 0 +#define USE_FINAL_FS 1 +#else +#define USE_EXPERIMENTAL_FS 1 +#define USE_FINAL_FS 0 +#endif + +// If all above fails, fall back to standard C++ and OS-specific items +#else +#define USE_EXPERIMENTAL_FS 0 +#define USE_FINAL_FS 0 +#endif + +#endif // !_STDFS_CONDITIONS_H diff --git a/thirdparty/openxr/src/common/xr_dependencies.h b/thirdparty/openxr/src/common/xr_dependencies.h new file mode 100644 index 0000000000..e34527abc3 --- /dev/null +++ b/thirdparty/openxr/src/common/xr_dependencies.h @@ -0,0 +1,89 @@ +// Copyright (c) 2018-2022, The Khronos Group Inc. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// This file includes headers with types which openxr.h depends on in order +// to compile when platforms, graphics apis, and the like are enabled. + +#pragma once + +#ifdef XR_USE_PLATFORM_ANDROID +#include <android/native_window.h> +#include <android/window.h> +#include <android/native_window_jni.h> +#endif // XR_USE_PLATFORM_ANDROID + +#ifdef XR_USE_PLATFORM_WIN32 + +#include <winapifamily.h> +#if !(WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)) +// Enable desktop partition APIs, such as RegOpenKeyEx, LoadLibraryEx, PathFileExists etc. +#undef WINAPI_PARTITION_DESKTOP +#define WINAPI_PARTITION_DESKTOP 1 +#endif + +#ifndef NOMINMAX +#define NOMINMAX +#endif // !NOMINMAX + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif // !WIN32_LEAN_AND_MEAN + +#include <windows.h> +#include <unknwn.h> + +#endif // XR_USE_PLATFORM_WIN32 + +#ifdef XR_USE_GRAPHICS_API_D3D11 +#include <d3d11.h> +#endif // XR_USE_GRAPHICS_API_D3D11 + +#ifdef XR_USE_GRAPHICS_API_D3D12 +#include <d3d12.h> +#endif // XR_USE_GRAPHICS_API_D3D12 + +#ifdef XR_USE_PLATFORM_XLIB +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +#ifdef Success +#undef Success +#endif // Success + +#ifdef Always +#undef Always +#endif // Always + +#ifdef None +#undef None +#endif // None +#endif // XR_USE_PLATFORM_XLIB + +#ifdef XR_USE_PLATFORM_XCB +#include <xcb/xcb.h> +#endif // XR_USE_PLATFORM_XCB + +#ifdef XR_USE_GRAPHICS_API_OPENGL +#if defined(XR_USE_PLATFORM_XLIB) || defined(XR_USE_PLATFORM_XCB) +#include <GL/glx.h> +#endif // (XR_USE_PLATFORM_XLIB || XR_USE_PLATFORM_XCB) +#ifdef XR_USE_PLATFORM_XCB +#include <xcb/glx.h> +#endif // XR_USE_PLATFORM_XCB +#ifdef XR_USE_PLATFORM_MACOS +#include <CL/cl_gl_ext.h> +#endif // XR_USE_PLATFORM_MACOS +#endif // XR_USE_GRAPHICS_API_OPENGL + +#ifdef XR_USE_GRAPHICS_API_OPENGL_ES +#include <EGL/egl.h> +#endif // XR_USE_GRAPHICS_API_OPENGL_ES + +#ifdef XR_USE_GRAPHICS_API_VULKAN +#include <vulkan/vulkan.h> +#endif // XR_USE_GRAPHICS_API_VULKAN + +#ifdef XR_USE_PLATFORM_WAYLAND +#include "wayland-client.h" +#endif // XR_USE_PLATFORM_WAYLAND diff --git a/thirdparty/openxr/src/common/xr_linear.h b/thirdparty/openxr/src/common/xr_linear.h new file mode 100644 index 0000000000..9ffb49a4b6 --- /dev/null +++ b/thirdparty/openxr/src/common/xr_linear.h @@ -0,0 +1,787 @@ +// Copyright (c) 2017 The Khronos Group Inc. +// Copyright (c) 2016 Oculus VR, LLC. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: J.M.P. van Waveren +// + +#ifndef XR_LINEAR_H_ +#define XR_LINEAR_H_ + +#if defined(OS_LINUX_XCB) || defined(OS_LINUX_XCB_GLX) || defined(OS_LINUX_WAYLAND) +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma clang diagnostic ignored "-Wunused-function" +#endif + +#include <openxr/openxr.h> + +/* +================================================================================================ + +Description : Vector, matrix and quaternion math. +Author : J.M.P. van Waveren +Date : 12/10/2016 +Language : C99 +Format : Indent 4 spaces - no tabs. +Copyright : Copyright (c) 2016 Oculus VR, LLC. All Rights reserved. + + +DESCRIPTION +=========== + +All matrices are column-major. + +INTERFACE +========= + +XrVector2f +XrVector3f +XrVector4f +XrQuaternionf +XrMatrix4x4f + +inline static void XrVector3f_Set(XrVector3f* v, const float value); +inline static void XrVector3f_Add(XrVector3f* result, const XrVector3f* a, const XrVector3f* b); +inline static void XrVector3f_Sub(XrVector3f* result, const XrVector3f* a, const XrVector3f* b); +inline static void XrVector3f_Min(XrVector3f* result, const XrVector3f* a, const XrVector3f* b); +inline static void XrVector3f_Max(XrVector3f* result, const XrVector3f* a, const XrVector3f* b); +inline static void XrVector3f_Decay(XrVector3f* result, const XrVector3f* a, const float value); +inline static void XrVector3f_Lerp(XrVector3f* result, const XrVector3f* a, const XrVector3f* b, const float fraction); +inline static void XrVector3f_Scale(XrVector3f* result, const XrVector3f* a, const float scaleFactor); +inline static void XrVector3f_Normalize(XrVector3f* v); +inline static float XrVector3f_Length(const XrVector3f* v); + +inline static void XrQuaternionf_Lerp(XrQuaternionf* result, const XrQuaternionf* a, const XrQuaternionf* b, const float fraction); +inline static void XrQuaternionf_Multiply(XrQuaternionf* result, const XrQuaternionf* a, const XrQuaternionf* b; + +inline static void XrMatrix4x4f_CreateIdentity(XrMatrix4x4f* result); +inline static void XrMatrix4x4f_CreateTranslation(XrMatrix4x4f* result, const float x, const float y, const float z); +inline static void XrMatrix4x4f_CreateRotation(XrMatrix4x4f* result, const float degreesX, const float degreesY, + const float degreesZ); +inline static void XrMatrix4x4f_CreateScale(XrMatrix4x4f* result, const float x, const float y, const float z); +inline static void XrMatrix4x4f_CreateTranslationRotationScale(XrMatrix4x4f* result, const XrVector3f* translation, + const XrQuaternionf* rotation, const XrVector3f* scale); +inline static void XrMatrix4x4f_CreateProjection(XrMatrix4x4f* result, const float tanAngleLeft, const float tanAngleRight, + const float tanAngleUp, float const tanAngleDown, const float nearZ, + const float farZ); +inline static void XrMatrix4x4f_CreateProjectionFov(XrMatrix4x4f* result, const float fovDegreesLeft, const float fovDegreesRight, + const float fovDegreeUp, const float fovDegreesDown, const float nearZ, + const float farZ); +inline static void XrMatrix4x4f_CreateFromQuaternion(XrMatrix4x4f* result, const XrQuaternionf* src); +inline static void XrMatrix4x4f_CreateOffsetScaleForBounds(XrMatrix4x4f* result, const XrMatrix4x4f* matrix, const XrVector3f* mins, + const XrVector3f* maxs); + +inline static bool XrMatrix4x4f_IsAffine(const XrMatrix4x4f* matrix, const float epsilon); +inline static bool XrMatrix4x4f_IsOrthogonal(const XrMatrix4x4f* matrix, const float epsilon); +inline static bool XrMatrix4x4f_IsOrthonormal(const XrMatrix4x4f* matrix, const float epsilon); +inline static bool XrMatrix4x4f_IsRigidBody(const XrMatrix4x4f* matrix, const float epsilon); + +inline static void XrMatrix4x4f_GetTranslation(XrVector3f* result, const XrMatrix4x4f* src); +inline static void XrMatrix4x4f_GetRotation(XrQuaternionf* result, const XrMatrix4x4f* src); +inline static void XrMatrix4x4f_GetScale(XrVector3f* result, const XrMatrix4x4f* src); + +inline static void XrMatrix4x4f_Multiply(XrMatrix4x4f* result, const XrMatrix4x4f* a, const XrMatrix4x4f* b); +inline static void XrMatrix4x4f_Transpose(XrMatrix4x4f* result, const XrMatrix4x4f* src); +inline static void XrMatrix4x4f_Invert(XrMatrix4x4f* result, const XrMatrix4x4f* src); +inline static void XrMatrix4x4f_InvertRigidBody(XrMatrix4x4f* result, const XrMatrix4x4f* src); + +inline static void XrMatrix4x4f_TransformVector3f(XrVector3f* result, const XrMatrix4x4f* m, const XrVector3f* v); +inline static void XrMatrix4x4f_TransformVector4f(XrVector4f* result, const XrMatrix4x4f* m, const XrVector4f* v); + +inline static void XrMatrix4x4f_TransformBounds(XrVector3f* resultMins, XrVector3f* resultMaxs, const XrMatrix4x4f* matrix, + const XrVector3f* mins, const XrVector3f* maxs); +inline static bool XrMatrix4x4f_CullBounds(const XrMatrix4x4f* mvp, const XrVector3f* mins, const XrVector3f* maxs); + +================================================================================================ +*/ + +#include <assert.h> +#include <math.h> +#include <stdbool.h> + +#define MATH_PI 3.14159265358979323846f + +#define DEFAULT_NEAR_Z 0.015625f // exact floating point representation +#define INFINITE_FAR_Z 0.0f + +static const XrColor4f XrColorRed = {1.0f, 0.0f, 0.0f, 1.0f}; +static const XrColor4f XrColorGreen = {0.0f, 1.0f, 0.0f, 1.0f}; +static const XrColor4f XrColorBlue = {0.0f, 0.0f, 1.0f, 1.0f}; +static const XrColor4f XrColorYellow = {1.0f, 1.0f, 0.0f, 1.0f}; +static const XrColor4f XrColorPurple = {1.0f, 0.0f, 1.0f, 1.0f}; +static const XrColor4f XrColorCyan = {0.0f, 1.0f, 1.0f, 1.0f}; +static const XrColor4f XrColorLightGrey = {0.7f, 0.7f, 0.7f, 1.0f}; +static const XrColor4f XrColorDarkGrey = {0.3f, 0.3f, 0.3f, 1.0f}; + +enum GraphicsAPI { GRAPHICS_VULKAN, GRAPHICS_OPENGL, GRAPHICS_OPENGL_ES, GRAPHICS_D3D }; + +// Column-major, pre-multiplied. This type does not exist in the OpenXR API and is provided for convenience. +struct XrMatrix4x4f { + float m[16]; +}; + +inline static float XrRcpSqrt(const float x) { + const float SMALLEST_NON_DENORMAL = 1.1754943508222875e-038f; // ( 1U << 23 ) + const float rcp = (x >= SMALLEST_NON_DENORMAL) ? 1.0f / sqrtf(x) : 1.0f; + return rcp; +} + +inline static void XrVector3f_Set(XrVector3f* v, const float value) { + v->x = value; + v->y = value; + v->z = value; +} + +inline static void XrVector3f_Add(XrVector3f* result, const XrVector3f* a, const XrVector3f* b) { + result->x = a->x + b->x; + result->y = a->y + b->y; + result->z = a->z + b->z; +} + +inline static void XrVector3f_Sub(XrVector3f* result, const XrVector3f* a, const XrVector3f* b) { + result->x = a->x - b->x; + result->y = a->y - b->y; + result->z = a->z - b->z; +} + +inline static void XrVector3f_Min(XrVector3f* result, const XrVector3f* a, const XrVector3f* b) { + result->x = (a->x < b->x) ? a->x : b->x; + result->y = (a->y < b->y) ? a->y : b->y; + result->z = (a->z < b->z) ? a->z : b->z; +} + +inline static void XrVector3f_Max(XrVector3f* result, const XrVector3f* a, const XrVector3f* b) { + result->x = (a->x > b->x) ? a->x : b->x; + result->y = (a->y > b->y) ? a->y : b->y; + result->z = (a->z > b->z) ? a->z : b->z; +} + +inline static void XrVector3f_Decay(XrVector3f* result, const XrVector3f* a, const float value) { + result->x = (fabsf(a->x) > value) ? ((a->x > 0.0f) ? (a->x - value) : (a->x + value)) : 0.0f; + result->y = (fabsf(a->y) > value) ? ((a->y > 0.0f) ? (a->y - value) : (a->y + value)) : 0.0f; + result->z = (fabsf(a->z) > value) ? ((a->z > 0.0f) ? (a->z - value) : (a->z + value)) : 0.0f; +} + +inline static void XrVector3f_Lerp(XrVector3f* result, const XrVector3f* a, const XrVector3f* b, const float fraction) { + result->x = a->x + fraction * (b->x - a->x); + result->y = a->y + fraction * (b->y - a->y); + result->z = a->z + fraction * (b->z - a->z); +} + +inline static void XrVector3f_Scale(XrVector3f* result, const XrVector3f* a, const float scaleFactor) { + result->x = a->x * scaleFactor; + result->y = a->y * scaleFactor; + result->z = a->z * scaleFactor; +} + +inline static float XrVector3f_Dot(const XrVector3f* a, const XrVector3f* b) { return a->x * b->x + a->y * b->y + a->z * b->z; } + +// Compute cross product, which generates a normal vector. +// Direction vector can be determined by right-hand rule: Pointing index finder in +// direction a and middle finger in direction b, thumb will point in Cross(a, b). +inline static void XrVector3f_Cross(XrVector3f* result, const XrVector3f* a, const XrVector3f* b) { + result->x = a->y * b->z - a->z * b->y; + result->y = a->z * b->x - a->x * b->z; + result->z = a->x * b->y - a->y * b->x; +} + +inline static void XrVector3f_Normalize(XrVector3f* v) { + const float lengthRcp = XrRcpSqrt(v->x * v->x + v->y * v->y + v->z * v->z); + v->x *= lengthRcp; + v->y *= lengthRcp; + v->z *= lengthRcp; +} + +inline static float XrVector3f_Length(const XrVector3f* v) { return sqrtf(v->x * v->x + v->y * v->y + v->z * v->z); } + +inline static void XrQuaternionf_CreateFromAxisAngle(XrQuaternionf* result, const XrVector3f* axis, const float angleInRadians) { + float s = sinf(angleInRadians / 2.0f); + float lengthRcp = XrRcpSqrt(axis->x * axis->x + axis->y * axis->y + axis->z * axis->z); + result->x = s * axis->x * lengthRcp; + result->y = s * axis->y * lengthRcp; + result->z = s * axis->z * lengthRcp; + result->w = cosf(angleInRadians / 2.0f); +} + +inline static void XrQuaternionf_Lerp(XrQuaternionf* result, const XrQuaternionf* a, const XrQuaternionf* b, const float fraction) { + const float s = a->x * b->x + a->y * b->y + a->z * b->z + a->w * b->w; + const float fa = 1.0f - fraction; + const float fb = (s < 0.0f) ? -fraction : fraction; + const float x = a->x * fa + b->x * fb; + const float y = a->y * fa + b->y * fb; + const float z = a->z * fa + b->z * fb; + const float w = a->w * fa + b->w * fb; + const float lengthRcp = XrRcpSqrt(x * x + y * y + z * z + w * w); + result->x = x * lengthRcp; + result->y = y * lengthRcp; + result->z = z * lengthRcp; + result->w = w * lengthRcp; +} + +inline static void XrQuaternionf_Multiply(XrQuaternionf* result, const XrQuaternionf* a, const XrQuaternionf* b) { + result->x = (b->w * a->x) + (b->x * a->w) + (b->y * a->z) - (b->z * a->y); + result->y = (b->w * a->y) - (b->x * a->z) + (b->y * a->w) + (b->z * a->x); + result->z = (b->w * a->z) + (b->x * a->y) - (b->y * a->x) + (b->z * a->w); + result->w = (b->w * a->w) - (b->x * a->x) - (b->y * a->y) - (b->z * a->z); +} + +// Use left-multiplication to accumulate transformations. +inline static void XrMatrix4x4f_Multiply(XrMatrix4x4f* result, const XrMatrix4x4f* a, const XrMatrix4x4f* b) { + result->m[0] = a->m[0] * b->m[0] + a->m[4] * b->m[1] + a->m[8] * b->m[2] + a->m[12] * b->m[3]; + result->m[1] = a->m[1] * b->m[0] + a->m[5] * b->m[1] + a->m[9] * b->m[2] + a->m[13] * b->m[3]; + result->m[2] = a->m[2] * b->m[0] + a->m[6] * b->m[1] + a->m[10] * b->m[2] + a->m[14] * b->m[3]; + result->m[3] = a->m[3] * b->m[0] + a->m[7] * b->m[1] + a->m[11] * b->m[2] + a->m[15] * b->m[3]; + + result->m[4] = a->m[0] * b->m[4] + a->m[4] * b->m[5] + a->m[8] * b->m[6] + a->m[12] * b->m[7]; + result->m[5] = a->m[1] * b->m[4] + a->m[5] * b->m[5] + a->m[9] * b->m[6] + a->m[13] * b->m[7]; + result->m[6] = a->m[2] * b->m[4] + a->m[6] * b->m[5] + a->m[10] * b->m[6] + a->m[14] * b->m[7]; + result->m[7] = a->m[3] * b->m[4] + a->m[7] * b->m[5] + a->m[11] * b->m[6] + a->m[15] * b->m[7]; + + result->m[8] = a->m[0] * b->m[8] + a->m[4] * b->m[9] + a->m[8] * b->m[10] + a->m[12] * b->m[11]; + result->m[9] = a->m[1] * b->m[8] + a->m[5] * b->m[9] + a->m[9] * b->m[10] + a->m[13] * b->m[11]; + result->m[10] = a->m[2] * b->m[8] + a->m[6] * b->m[9] + a->m[10] * b->m[10] + a->m[14] * b->m[11]; + result->m[11] = a->m[3] * b->m[8] + a->m[7] * b->m[9] + a->m[11] * b->m[10] + a->m[15] * b->m[11]; + + result->m[12] = a->m[0] * b->m[12] + a->m[4] * b->m[13] + a->m[8] * b->m[14] + a->m[12] * b->m[15]; + result->m[13] = a->m[1] * b->m[12] + a->m[5] * b->m[13] + a->m[9] * b->m[14] + a->m[13] * b->m[15]; + result->m[14] = a->m[2] * b->m[12] + a->m[6] * b->m[13] + a->m[10] * b->m[14] + a->m[14] * b->m[15]; + result->m[15] = a->m[3] * b->m[12] + a->m[7] * b->m[13] + a->m[11] * b->m[14] + a->m[15] * b->m[15]; +} + +// Creates the transpose of the given matrix. +inline static void XrMatrix4x4f_Transpose(XrMatrix4x4f* result, const XrMatrix4x4f* src) { + result->m[0] = src->m[0]; + result->m[1] = src->m[4]; + result->m[2] = src->m[8]; + result->m[3] = src->m[12]; + + result->m[4] = src->m[1]; + result->m[5] = src->m[5]; + result->m[6] = src->m[9]; + result->m[7] = src->m[13]; + + result->m[8] = src->m[2]; + result->m[9] = src->m[6]; + result->m[10] = src->m[10]; + result->m[11] = src->m[14]; + + result->m[12] = src->m[3]; + result->m[13] = src->m[7]; + result->m[14] = src->m[11]; + result->m[15] = src->m[15]; +} + +// Returns a 3x3 minor of a 4x4 matrix. +inline static float XrMatrix4x4f_Minor(const XrMatrix4x4f* matrix, int r0, int r1, int r2, int c0, int c1, int c2) { + return matrix->m[4 * r0 + c0] * + (matrix->m[4 * r1 + c1] * matrix->m[4 * r2 + c2] - matrix->m[4 * r2 + c1] * matrix->m[4 * r1 + c2]) - + matrix->m[4 * r0 + c1] * + (matrix->m[4 * r1 + c0] * matrix->m[4 * r2 + c2] - matrix->m[4 * r2 + c0] * matrix->m[4 * r1 + c2]) + + matrix->m[4 * r0 + c2] * + (matrix->m[4 * r1 + c0] * matrix->m[4 * r2 + c1] - matrix->m[4 * r2 + c0] * matrix->m[4 * r1 + c1]); +} + +// Calculates the inverse of a 4x4 matrix. +inline static void XrMatrix4x4f_Invert(XrMatrix4x4f* result, const XrMatrix4x4f* src) { + const float rcpDet = + 1.0f / (src->m[0] * XrMatrix4x4f_Minor(src, 1, 2, 3, 1, 2, 3) - src->m[1] * XrMatrix4x4f_Minor(src, 1, 2, 3, 0, 2, 3) + + src->m[2] * XrMatrix4x4f_Minor(src, 1, 2, 3, 0, 1, 3) - src->m[3] * XrMatrix4x4f_Minor(src, 1, 2, 3, 0, 1, 2)); + + result->m[0] = XrMatrix4x4f_Minor(src, 1, 2, 3, 1, 2, 3) * rcpDet; + result->m[1] = -XrMatrix4x4f_Minor(src, 0, 2, 3, 1, 2, 3) * rcpDet; + result->m[2] = XrMatrix4x4f_Minor(src, 0, 1, 3, 1, 2, 3) * rcpDet; + result->m[3] = -XrMatrix4x4f_Minor(src, 0, 1, 2, 1, 2, 3) * rcpDet; + result->m[4] = -XrMatrix4x4f_Minor(src, 1, 2, 3, 0, 2, 3) * rcpDet; + result->m[5] = XrMatrix4x4f_Minor(src, 0, 2, 3, 0, 2, 3) * rcpDet; + result->m[6] = -XrMatrix4x4f_Minor(src, 0, 1, 3, 0, 2, 3) * rcpDet; + result->m[7] = XrMatrix4x4f_Minor(src, 0, 1, 2, 0, 2, 3) * rcpDet; + result->m[8] = XrMatrix4x4f_Minor(src, 1, 2, 3, 0, 1, 3) * rcpDet; + result->m[9] = -XrMatrix4x4f_Minor(src, 0, 2, 3, 0, 1, 3) * rcpDet; + result->m[10] = XrMatrix4x4f_Minor(src, 0, 1, 3, 0, 1, 3) * rcpDet; + result->m[11] = -XrMatrix4x4f_Minor(src, 0, 1, 2, 0, 1, 3) * rcpDet; + result->m[12] = -XrMatrix4x4f_Minor(src, 1, 2, 3, 0, 1, 2) * rcpDet; + result->m[13] = XrMatrix4x4f_Minor(src, 0, 2, 3, 0, 1, 2) * rcpDet; + result->m[14] = -XrMatrix4x4f_Minor(src, 0, 1, 3, 0, 1, 2) * rcpDet; + result->m[15] = XrMatrix4x4f_Minor(src, 0, 1, 2, 0, 1, 2) * rcpDet; +} + +// Calculates the inverse of a rigid body transform. +inline static void XrMatrix4x4f_InvertRigidBody(XrMatrix4x4f* result, const XrMatrix4x4f* src) { + result->m[0] = src->m[0]; + result->m[1] = src->m[4]; + result->m[2] = src->m[8]; + result->m[3] = 0.0f; + result->m[4] = src->m[1]; + result->m[5] = src->m[5]; + result->m[6] = src->m[9]; + result->m[7] = 0.0f; + result->m[8] = src->m[2]; + result->m[9] = src->m[6]; + result->m[10] = src->m[10]; + result->m[11] = 0.0f; + result->m[12] = -(src->m[0] * src->m[12] + src->m[1] * src->m[13] + src->m[2] * src->m[14]); + result->m[13] = -(src->m[4] * src->m[12] + src->m[5] * src->m[13] + src->m[6] * src->m[14]); + result->m[14] = -(src->m[8] * src->m[12] + src->m[9] * src->m[13] + src->m[10] * src->m[14]); + result->m[15] = 1.0f; +} + +// Creates an identity matrix. +inline static void XrMatrix4x4f_CreateIdentity(XrMatrix4x4f* result) { + result->m[0] = 1.0f; + result->m[1] = 0.0f; + result->m[2] = 0.0f; + result->m[3] = 0.0f; + result->m[4] = 0.0f; + result->m[5] = 1.0f; + result->m[6] = 0.0f; + result->m[7] = 0.0f; + result->m[8] = 0.0f; + result->m[9] = 0.0f; + result->m[10] = 1.0f; + result->m[11] = 0.0f; + result->m[12] = 0.0f; + result->m[13] = 0.0f; + result->m[14] = 0.0f; + result->m[15] = 1.0f; +} + +// Creates a translation matrix. +inline static void XrMatrix4x4f_CreateTranslation(XrMatrix4x4f* result, const float x, const float y, const float z) { + result->m[0] = 1.0f; + result->m[1] = 0.0f; + result->m[2] = 0.0f; + result->m[3] = 0.0f; + result->m[4] = 0.0f; + result->m[5] = 1.0f; + result->m[6] = 0.0f; + result->m[7] = 0.0f; + result->m[8] = 0.0f; + result->m[9] = 0.0f; + result->m[10] = 1.0f; + result->m[11] = 0.0f; + result->m[12] = x; + result->m[13] = y; + result->m[14] = z; + result->m[15] = 1.0f; +} + +// Creates a rotation matrix. +// If -Z=forward, +Y=up, +X=right, then degreesX=pitch, degreesY=yaw, degreesZ=roll. +inline static void XrMatrix4x4f_CreateRotation(XrMatrix4x4f* result, const float degreesX, const float degreesY, + const float degreesZ) { + const float sinX = sinf(degreesX * (MATH_PI / 180.0f)); + const float cosX = cosf(degreesX * (MATH_PI / 180.0f)); + const XrMatrix4x4f rotationX = {{1, 0, 0, 0, 0, cosX, sinX, 0, 0, -sinX, cosX, 0, 0, 0, 0, 1}}; + const float sinY = sinf(degreesY * (MATH_PI / 180.0f)); + const float cosY = cosf(degreesY * (MATH_PI / 180.0f)); + const XrMatrix4x4f rotationY = {{cosY, 0, -sinY, 0, 0, 1, 0, 0, sinY, 0, cosY, 0, 0, 0, 0, 1}}; + const float sinZ = sinf(degreesZ * (MATH_PI / 180.0f)); + const float cosZ = cosf(degreesZ * (MATH_PI / 180.0f)); + const XrMatrix4x4f rotationZ = {{cosZ, sinZ, 0, 0, -sinZ, cosZ, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}}; + XrMatrix4x4f rotationXY; + XrMatrix4x4f_Multiply(&rotationXY, &rotationY, &rotationX); + XrMatrix4x4f_Multiply(result, &rotationZ, &rotationXY); +} + +// Creates a scale matrix. +inline static void XrMatrix4x4f_CreateScale(XrMatrix4x4f* result, const float x, const float y, const float z) { + result->m[0] = x; + result->m[1] = 0.0f; + result->m[2] = 0.0f; + result->m[3] = 0.0f; + result->m[4] = 0.0f; + result->m[5] = y; + result->m[6] = 0.0f; + result->m[7] = 0.0f; + result->m[8] = 0.0f; + result->m[9] = 0.0f; + result->m[10] = z; + result->m[11] = 0.0f; + result->m[12] = 0.0f; + result->m[13] = 0.0f; + result->m[14] = 0.0f; + result->m[15] = 1.0f; +} + +// Creates a matrix from a quaternion. +inline static void XrMatrix4x4f_CreateFromQuaternion(XrMatrix4x4f* result, const XrQuaternionf* quat) { + const float x2 = quat->x + quat->x; + const float y2 = quat->y + quat->y; + const float z2 = quat->z + quat->z; + + const float xx2 = quat->x * x2; + const float yy2 = quat->y * y2; + const float zz2 = quat->z * z2; + + const float yz2 = quat->y * z2; + const float wx2 = quat->w * x2; + const float xy2 = quat->x * y2; + const float wz2 = quat->w * z2; + const float xz2 = quat->x * z2; + const float wy2 = quat->w * y2; + + result->m[0] = 1.0f - yy2 - zz2; + result->m[1] = xy2 + wz2; + result->m[2] = xz2 - wy2; + result->m[3] = 0.0f; + + result->m[4] = xy2 - wz2; + result->m[5] = 1.0f - xx2 - zz2; + result->m[6] = yz2 + wx2; + result->m[7] = 0.0f; + + result->m[8] = xz2 + wy2; + result->m[9] = yz2 - wx2; + result->m[10] = 1.0f - xx2 - yy2; + result->m[11] = 0.0f; + + result->m[12] = 0.0f; + result->m[13] = 0.0f; + result->m[14] = 0.0f; + result->m[15] = 1.0f; +} + +// Creates a combined translation(rotation(scale(object))) matrix. +inline static void XrMatrix4x4f_CreateTranslationRotationScale(XrMatrix4x4f* result, const XrVector3f* translation, + const XrQuaternionf* rotation, const XrVector3f* scale) { + XrMatrix4x4f scaleMatrix; + XrMatrix4x4f_CreateScale(&scaleMatrix, scale->x, scale->y, scale->z); + + XrMatrix4x4f rotationMatrix; + XrMatrix4x4f_CreateFromQuaternion(&rotationMatrix, rotation); + + XrMatrix4x4f translationMatrix; + XrMatrix4x4f_CreateTranslation(&translationMatrix, translation->x, translation->y, translation->z); + + XrMatrix4x4f combinedMatrix; + XrMatrix4x4f_Multiply(&combinedMatrix, &rotationMatrix, &scaleMatrix); + XrMatrix4x4f_Multiply(result, &translationMatrix, &combinedMatrix); +} + +// Creates a projection matrix based on the specified dimensions. +// The projection matrix transforms -Z=forward, +Y=up, +X=right to the appropriate clip space for the graphics API. +// The far plane is placed at infinity if farZ <= nearZ. +// An infinite projection matrix is preferred for rasterization because, except for +// things *right* up against the near plane, it always provides better precision: +// "Tightening the Precision of Perspective Rendering" +// Paul Upchurch, Mathieu Desbrun +// Journal of Graphics Tools, Volume 16, Issue 1, 2012 +inline static void XrMatrix4x4f_CreateProjection(XrMatrix4x4f* result, GraphicsAPI graphicsApi, const float tanAngleLeft, + const float tanAngleRight, const float tanAngleUp, float const tanAngleDown, + const float nearZ, const float farZ) { + const float tanAngleWidth = tanAngleRight - tanAngleLeft; + + // Set to tanAngleDown - tanAngleUp for a clip space with positive Y down (Vulkan). + // Set to tanAngleUp - tanAngleDown for a clip space with positive Y up (OpenGL / D3D / Metal). + const float tanAngleHeight = graphicsApi == GRAPHICS_VULKAN ? (tanAngleDown - tanAngleUp) : (tanAngleUp - tanAngleDown); + + // Set to nearZ for a [-1,1] Z clip space (OpenGL / OpenGL ES). + // Set to zero for a [0,1] Z clip space (Vulkan / D3D / Metal). + const float offsetZ = (graphicsApi == GRAPHICS_OPENGL || graphicsApi == GRAPHICS_OPENGL_ES) ? nearZ : 0; + + if (farZ <= nearZ) { + // place the far plane at infinity + result->m[0] = 2.0f / tanAngleWidth; + result->m[4] = 0.0f; + result->m[8] = (tanAngleRight + tanAngleLeft) / tanAngleWidth; + result->m[12] = 0.0f; + + result->m[1] = 0.0f; + result->m[5] = 2.0f / tanAngleHeight; + result->m[9] = (tanAngleUp + tanAngleDown) / tanAngleHeight; + result->m[13] = 0.0f; + + result->m[2] = 0.0f; + result->m[6] = 0.0f; + result->m[10] = -1.0f; + result->m[14] = -(nearZ + offsetZ); + + result->m[3] = 0.0f; + result->m[7] = 0.0f; + result->m[11] = -1.0f; + result->m[15] = 0.0f; + } else { + // normal projection + result->m[0] = 2.0f / tanAngleWidth; + result->m[4] = 0.0f; + result->m[8] = (tanAngleRight + tanAngleLeft) / tanAngleWidth; + result->m[12] = 0.0f; + + result->m[1] = 0.0f; + result->m[5] = 2.0f / tanAngleHeight; + result->m[9] = (tanAngleUp + tanAngleDown) / tanAngleHeight; + result->m[13] = 0.0f; + + result->m[2] = 0.0f; + result->m[6] = 0.0f; + result->m[10] = -(farZ + offsetZ) / (farZ - nearZ); + result->m[14] = -(farZ * (nearZ + offsetZ)) / (farZ - nearZ); + + result->m[3] = 0.0f; + result->m[7] = 0.0f; + result->m[11] = -1.0f; + result->m[15] = 0.0f; + } +} + +// Creates a projection matrix based on the specified FOV. +inline static void XrMatrix4x4f_CreateProjectionFov(XrMatrix4x4f* result, GraphicsAPI graphicsApi, const XrFovf fov, + const float nearZ, const float farZ) { + const float tanLeft = tanf(fov.angleLeft); + const float tanRight = tanf(fov.angleRight); + + const float tanDown = tanf(fov.angleDown); + const float tanUp = tanf(fov.angleUp); + + XrMatrix4x4f_CreateProjection(result, graphicsApi, tanLeft, tanRight, tanUp, tanDown, nearZ, farZ); +} + +// Creates a matrix that transforms the -1 to 1 cube to cover the given 'mins' and 'maxs' transformed with the given 'matrix'. +inline static void XrMatrix4x4f_CreateOffsetScaleForBounds(XrMatrix4x4f* result, const XrMatrix4x4f* matrix, const XrVector3f* mins, + const XrVector3f* maxs) { + const XrVector3f offset = {(maxs->x + mins->x) * 0.5f, (maxs->y + mins->y) * 0.5f, (maxs->z + mins->z) * 0.5f}; + const XrVector3f scale = {(maxs->x - mins->x) * 0.5f, (maxs->y - mins->y) * 0.5f, (maxs->z - mins->z) * 0.5f}; + + result->m[0] = matrix->m[0] * scale.x; + result->m[1] = matrix->m[1] * scale.x; + result->m[2] = matrix->m[2] * scale.x; + result->m[3] = matrix->m[3] * scale.x; + + result->m[4] = matrix->m[4] * scale.y; + result->m[5] = matrix->m[5] * scale.y; + result->m[6] = matrix->m[6] * scale.y; + result->m[7] = matrix->m[7] * scale.y; + + result->m[8] = matrix->m[8] * scale.z; + result->m[9] = matrix->m[9] * scale.z; + result->m[10] = matrix->m[10] * scale.z; + result->m[11] = matrix->m[11] * scale.z; + + result->m[12] = matrix->m[12] + matrix->m[0] * offset.x + matrix->m[4] * offset.y + matrix->m[8] * offset.z; + result->m[13] = matrix->m[13] + matrix->m[1] * offset.x + matrix->m[5] * offset.y + matrix->m[9] * offset.z; + result->m[14] = matrix->m[14] + matrix->m[2] * offset.x + matrix->m[6] * offset.y + matrix->m[10] * offset.z; + result->m[15] = matrix->m[15] + matrix->m[3] * offset.x + matrix->m[7] * offset.y + matrix->m[11] * offset.z; +} + +// Returns true if the given matrix is affine. +inline static bool XrMatrix4x4f_IsAffine(const XrMatrix4x4f* matrix, const float epsilon) { + return fabsf(matrix->m[3]) <= epsilon && fabsf(matrix->m[7]) <= epsilon && fabsf(matrix->m[11]) <= epsilon && + fabsf(matrix->m[15] - 1.0f) <= epsilon; +} + +// Returns true if the given matrix is orthogonal. +inline static bool XrMatrix4x4f_IsOrthogonal(const XrMatrix4x4f* matrix, const float epsilon) { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (i != j) { + if (fabsf(matrix->m[4 * i + 0] * matrix->m[4 * j + 0] + matrix->m[4 * i + 1] * matrix->m[4 * j + 1] + + matrix->m[4 * i + 2] * matrix->m[4 * j + 2]) > epsilon) { + return false; + } + if (fabsf(matrix->m[4 * 0 + i] * matrix->m[4 * 0 + j] + matrix->m[4 * 1 + i] * matrix->m[4 * 1 + j] + + matrix->m[4 * 2 + i] * matrix->m[4 * 2 + j]) > epsilon) { + return false; + } + } + } + } + return true; +} + +// Returns true if the given matrix is orthonormal. +inline static bool XrMatrix4x4f_IsOrthonormal(const XrMatrix4x4f* matrix, const float epsilon) { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + const float kd = (i == j) ? 1.0f : 0.0f; // Kronecker delta + if (fabsf(kd - (matrix->m[4 * i + 0] * matrix->m[4 * j + 0] + matrix->m[4 * i + 1] * matrix->m[4 * j + 1] + + matrix->m[4 * i + 2] * matrix->m[4 * j + 2])) > epsilon) { + return false; + } + if (fabsf(kd - (matrix->m[4 * 0 + i] * matrix->m[4 * 0 + j] + matrix->m[4 * 1 + i] * matrix->m[4 * 1 + j] + + matrix->m[4 * 2 + i] * matrix->m[4 * 2 + j])) > epsilon) { + return false; + } + } + } + return true; +} + +// Returns true if the given matrix is a rigid body transform. +inline static bool XrMatrix4x4f_IsRigidBody(const XrMatrix4x4f* matrix, const float epsilon) { + return XrMatrix4x4f_IsAffine(matrix, epsilon) && XrMatrix4x4f_IsOrthonormal(matrix, epsilon); +} + +// Get the translation from a combined translation(rotation(scale(object))) matrix. +inline static void XrMatrix4x4f_GetTranslation(XrVector3f* result, const XrMatrix4x4f* src) { + assert(XrMatrix4x4f_IsAffine(src, 1e-4f)); + assert(XrMatrix4x4f_IsOrthogonal(src, 1e-4f)); + + result->x = src->m[12]; + result->y = src->m[13]; + result->z = src->m[14]; +} + +// Get the rotation from a combined translation(rotation(scale(object))) matrix. +inline static void XrMatrix4x4f_GetRotation(XrQuaternionf* result, const XrMatrix4x4f* src) { + assert(XrMatrix4x4f_IsAffine(src, 1e-4f)); + assert(XrMatrix4x4f_IsOrthogonal(src, 1e-4f)); + + const float rcpScaleX = XrRcpSqrt(src->m[0] * src->m[0] + src->m[1] * src->m[1] + src->m[2] * src->m[2]); + const float rcpScaleY = XrRcpSqrt(src->m[4] * src->m[4] + src->m[5] * src->m[5] + src->m[6] * src->m[6]); + const float rcpScaleZ = XrRcpSqrt(src->m[8] * src->m[8] + src->m[9] * src->m[9] + src->m[10] * src->m[10]); + const float m[9] = {src->m[0] * rcpScaleX, src->m[1] * rcpScaleX, src->m[2] * rcpScaleX, + src->m[4] * rcpScaleY, src->m[5] * rcpScaleY, src->m[6] * rcpScaleY, + src->m[8] * rcpScaleZ, src->m[9] * rcpScaleZ, src->m[10] * rcpScaleZ}; + if (m[0 * 3 + 0] + m[1 * 3 + 1] + m[2 * 3 + 2] > 0.0f) { + float t = +m[0 * 3 + 0] + m[1 * 3 + 1] + m[2 * 3 + 2] + 1.0f; + float s = XrRcpSqrt(t) * 0.5f; + result->w = s * t; + result->z = (m[0 * 3 + 1] - m[1 * 3 + 0]) * s; + result->y = (m[2 * 3 + 0] - m[0 * 3 + 2]) * s; + result->x = (m[1 * 3 + 2] - m[2 * 3 + 1]) * s; + } else if (m[0 * 3 + 0] > m[1 * 3 + 1] && m[0 * 3 + 0] > m[2 * 3 + 2]) { + float t = +m[0 * 3 + 0] - m[1 * 3 + 1] - m[2 * 3 + 2] + 1.0f; + float s = XrRcpSqrt(t) * 0.5f; + result->x = s * t; + result->y = (m[0 * 3 + 1] + m[1 * 3 + 0]) * s; + result->z = (m[2 * 3 + 0] + m[0 * 3 + 2]) * s; + result->w = (m[1 * 3 + 2] - m[2 * 3 + 1]) * s; + } else if (m[1 * 3 + 1] > m[2 * 3 + 2]) { + float t = -m[0 * 3 + 0] + m[1 * 3 + 1] - m[2 * 3 + 2] + 1.0f; + float s = XrRcpSqrt(t) * 0.5f; + result->y = s * t; + result->x = (m[0 * 3 + 1] + m[1 * 3 + 0]) * s; + result->w = (m[2 * 3 + 0] - m[0 * 3 + 2]) * s; + result->z = (m[1 * 3 + 2] + m[2 * 3 + 1]) * s; + } else { + float t = -m[0 * 3 + 0] - m[1 * 3 + 1] + m[2 * 3 + 2] + 1.0f; + float s = XrRcpSqrt(t) * 0.5f; + result->z = s * t; + result->w = (m[0 * 3 + 1] - m[1 * 3 + 0]) * s; + result->x = (m[2 * 3 + 0] + m[0 * 3 + 2]) * s; + result->y = (m[1 * 3 + 2] + m[2 * 3 + 1]) * s; + } +} + +// Get the scale from a combined translation(rotation(scale(object))) matrix. +inline static void XrMatrix4x4f_GetScale(XrVector3f* result, const XrMatrix4x4f* src) { + assert(XrMatrix4x4f_IsAffine(src, 1e-4f)); + assert(XrMatrix4x4f_IsOrthogonal(src, 1e-4f)); + + result->x = sqrtf(src->m[0] * src->m[0] + src->m[1] * src->m[1] + src->m[2] * src->m[2]); + result->y = sqrtf(src->m[4] * src->m[4] + src->m[5] * src->m[5] + src->m[6] * src->m[6]); + result->z = sqrtf(src->m[8] * src->m[8] + src->m[9] * src->m[9] + src->m[10] * src->m[10]); +} + +// Transforms a 3D vector. +inline static void XrMatrix4x4f_TransformVector3f(XrVector3f* result, const XrMatrix4x4f* m, const XrVector3f* v) { + const float w = m->m[3] * v->x + m->m[7] * v->y + m->m[11] * v->z + m->m[15]; + const float rcpW = 1.0f / w; + result->x = (m->m[0] * v->x + m->m[4] * v->y + m->m[8] * v->z + m->m[12]) * rcpW; + result->y = (m->m[1] * v->x + m->m[5] * v->y + m->m[9] * v->z + m->m[13]) * rcpW; + result->z = (m->m[2] * v->x + m->m[6] * v->y + m->m[10] * v->z + m->m[14]) * rcpW; +} + +// Transforms a 4D vector. +inline static void XrMatrix4x4f_TransformVector4f(XrVector4f* result, const XrMatrix4x4f* m, const XrVector4f* v) { + result->x = m->m[0] * v->x + m->m[4] * v->y + m->m[8] * v->z + m->m[12] * v->w; + result->y = m->m[1] * v->x + m->m[5] * v->y + m->m[9] * v->z + m->m[13] * v->w; + result->z = m->m[2] * v->x + m->m[6] * v->y + m->m[10] * v->z + m->m[14] * v->w; + result->w = m->m[3] * v->x + m->m[7] * v->y + m->m[11] * v->z + m->m[15] * v->w; +} + +// Transforms the 'mins' and 'maxs' bounds with the given 'matrix'. +inline static void XrMatrix4x4f_TransformBounds(XrVector3f* resultMins, XrVector3f* resultMaxs, const XrMatrix4x4f* matrix, + const XrVector3f* mins, const XrVector3f* maxs) { + assert(XrMatrix4x4f_IsAffine(matrix, 1e-4f)); + + const XrVector3f center = {(mins->x + maxs->x) * 0.5f, (mins->y + maxs->y) * 0.5f, (mins->z + maxs->z) * 0.5f}; + const XrVector3f extents = {maxs->x - center.x, maxs->y - center.y, maxs->z - center.z}; + const XrVector3f newCenter = {matrix->m[0] * center.x + matrix->m[4] * center.y + matrix->m[8] * center.z + matrix->m[12], + matrix->m[1] * center.x + matrix->m[5] * center.y + matrix->m[9] * center.z + matrix->m[13], + matrix->m[2] * center.x + matrix->m[6] * center.y + matrix->m[10] * center.z + matrix->m[14]}; + const XrVector3f newExtents = { + fabsf(extents.x * matrix->m[0]) + fabsf(extents.y * matrix->m[4]) + fabsf(extents.z * matrix->m[8]), + fabsf(extents.x * matrix->m[1]) + fabsf(extents.y * matrix->m[5]) + fabsf(extents.z * matrix->m[9]), + fabsf(extents.x * matrix->m[2]) + fabsf(extents.y * matrix->m[6]) + fabsf(extents.z * matrix->m[10])}; + XrVector3f_Sub(resultMins, &newCenter, &newExtents); + XrVector3f_Add(resultMaxs, &newCenter, &newExtents); +} + +// Returns true if the 'mins' and 'maxs' bounds is completely off to one side of the projection matrix. +inline static bool XrMatrix4x4f_CullBounds(const XrMatrix4x4f* mvp, const XrVector3f* mins, const XrVector3f* maxs) { + if (maxs->x <= mins->x && maxs->y <= mins->y && maxs->z <= mins->z) { + return false; + } + + XrVector4f c[8]; + for (int i = 0; i < 8; i++) { + const XrVector4f corner = {(i & 1) != 0 ? maxs->x : mins->x, (i & 2) != 0 ? maxs->y : mins->y, + (i & 4) != 0 ? maxs->z : mins->z, 1.0f}; + XrMatrix4x4f_TransformVector4f(&c[i], mvp, &corner); + } + + int i; + for (i = 0; i < 8; i++) { + if (c[i].x > -c[i].w) { + break; + } + } + if (i == 8) { + return true; + } + for (i = 0; i < 8; i++) { + if (c[i].x < c[i].w) { + break; + } + } + if (i == 8) { + return true; + } + + for (i = 0; i < 8; i++) { + if (c[i].y > -c[i].w) { + break; + } + } + if (i == 8) { + return true; + } + for (i = 0; i < 8; i++) { + if (c[i].y < c[i].w) { + break; + } + } + if (i == 8) { + return true; + } + for (i = 0; i < 8; i++) { + if (c[i].z > -c[i].w) { + break; + } + } + if (i == 8) { + return true; + } + for (i = 0; i < 8; i++) { + if (c[i].z < c[i].w) { + break; + } + } + return i == 8; +} + +#endif // XR_LINEAR_H_ diff --git a/thirdparty/openxr/src/external/jsoncpp/AUTHORS b/thirdparty/openxr/src/external/jsoncpp/AUTHORS new file mode 100644 index 0000000000..e1fa0fc3ad --- /dev/null +++ b/thirdparty/openxr/src/external/jsoncpp/AUTHORS @@ -0,0 +1,115 @@ +Baptiste Lepilleur <blep@users.sourceforge.net> + +Aaron Jacobs <aaronjjacobs@gmail.com> +Aaron Jacobs <jacobsa@google.com> +Adam Boseley <ABoseley@agjunction.com> +Adam Boseley <adam.boseley@gmail.com> +Aleksandr Derbenev <13alexac@gmail.com> +Alexander Gazarov <DrMetallius@users.noreply.github.com> +Alexander V. Brezgin <abrezgin@appliedtech.ru> +Alexandr Brezgin <albrezgin@mail.ru> +Alexey Kruchinin <alexey@mopals.com> +Anton Indrawan <anton.indrawan@gmail.com> +Baptiste Jonglez <git@bitsofnetworks.org> +Baptiste Lepilleur <baptiste.lepilleur@gmail.com> +Baruch Siach <baruch@tkos.co.il> +Ben Boeckel <mathstuf@gmail.com> +Benjamin Knecht <bknecht@logitech.com> +Bernd Kuhls <bernd.kuhls@t-online.de> +Billy Donahue <billydonahue@google.com> +Braden McDorman <bmcdorman@gmail.com> +Brandon Myers <bmyers1788@gmail.com> +Brendan Drew <brendan.drew@daqri.com> +chason <cxchao802@gmail.com> +chenguoping <chenguopingdota@163.com> +Chris Gilling <cgilling@iparadigms.com> +Christopher Dawes <christopher.dawes.1981@googlemail.com> +Christopher Dunn <cdunn2001@gmail.com> +Chuck Atkins <chuck.atkins@kitware.com> +Cody P Schafer <dev@codyps.com> +Connor Manning <connor@hobu.co> +Cory Quammen <cory.quammen@kitware.com> +Cristóvão B da Cruz e Silva <CrisXed@gmail.com> +Daniel Krügler <daniel.kruegler@gmail.com> +Dani-Hub <daniel.kruegler@googlemail.com> +Dan Liu <gzliudan> +datadiode <datadiode@users.noreply.github.com> +datadiode <jochen.neubeck@vodafone.de> +David Seifert <soap@gentoo.org> +David West <david-west@idexx.com> +dawesc <chris.dawes@eftlab.co.uk> +Devin Jeanpierre <jeanpierreda@google.com> +Dmitry Marakasov <amdmi3@amdmi3.ru> +dominicpezzuto <dom@dompezzuto.com> +Don Milham <dmilham@gmail.com> +drgler <daniel.kruegler@gmail.com> +ds283 <D.Seery@sussex.ac.uk> +Egor Tensin <Egor.Tensin@gmail.com> +eightnoteight <mr.eightnoteight@gmail.com> +Evince <baneyue@gmail.com> +filipjs <filipjs@users.noreply.github.com> +findblar <ft@finbarr.ca> +Florian Meier <florian.meier@koalo.de> +Gaëtan Lehmann <gaetan.lehmann@gmail.com> +Gaurav <g.gupta@samsung.com> +Gergely Nagy <ngg@ngg.hu> +Gida Pataki <gida.pataki@prezi.com> +I3ck <buckmartin@buckmartin.de> +Iñaki Baz Castillo <ibc@aliax.net> +Jacco <jacco@geul.net> +Jean-Christophe Fillion-Robin <jchris.fillionr@kitware.com> +Jonas Platte <mail@jonasplatte.de> +Jordan Bayles <bayles.jordan@gmail.com> +Jörg Krause <joerg.krause@embedded.rocks> +Keith Lea <keith@whamcitylights.com> +Kevin Grant <kbradleygrant@gmail.com> +Kirill V. Lyadvinsky <jia3ep@gmail.com> +Kirill V. Lyadvinsky <mail@codeatcpp.com> +Kobi Gurkan <kobigurk@gmail.com> +Magnus Bjerke Vik <mbvett@gmail.com> +Malay Shah <malays@users.sourceforge.net> +Mara Kim <hacker.root@gmail.com> +Marek Kotewicz <marek.kotewicz@gmail.com> +Mark Lakata <mark@lakata.org> +Mark Zeren <mzeren@vmware.com> +Martin Buck <buckmartin@buckmartin.de> +Martyn Gigg <martyn.gigg@gmail.com> +Mattes D <github@xoft.cz> +Matthias Loy <matthias.loy@hbm.com> +Merlyn Morgan-Graham <kavika@gmail.com> +Michael Shields <mshields@google.com> +Michał Górny <mgorny@gentoo.org> +Mike Naberezny <mike@naberezny.com> +mloy <matthias.loy@googlemail.com> +Motti <lanzkron@gmail.com> +nnkur <nnkur@mail.ru> +Omkar Wagh <owagh@owaghlinux.ny.tower-research.com> +paulo <paulobrizolara@users.noreply.github.com> +pavel.pimenov <pavel.pimenov@gmail.com> +Paweł Bylica <chfast@gmail.com> +Péricles Lopes Machado <pericles.raskolnikoff@gmail.com> +Peter Spiess-Knafl <psk@autistici.org> +pffang <pffang@vip.qq.com> +Rémi Verschelde <remi@verschelde.fr> +renu555 <renu.tyagi@samsung.com> +Robert Dailey <rcdailey@gmail.com> +Sam Clegg <sbc@chromium.org> +selaselah <selah@outlook.com> +Sergiy80 <sil2004@gmail.com> +sergzub <sergzub@gmail.com> +Stefan Schweter <stefan@schweter.it> +Stefano Fiorentino <stefano.fiore84@gmail.com> +Steffen Kieß <Steffen.Kiess@ipvs.uni-stuttgart.de> +Steven Hahn <hahnse@ornl.gov> +Stuart Eichert <stuart@fivemicro.com> +SuperManitu <supermanitu@gmail.com> +Techwolf <dring@g33kworld.net> +Tengiz Sharafiev <btolfa+github@gmail.com> +Tomasz Maciejewski <tmaciejewsk@gmail.com> +Vicente Olivert Riera <Vincent.Riera@imgtec.com> +xiaoyur347 <xiaoyur347@gmail.com> +ycqiu <429148848@qq.com> +yiqiju <fred_ju@selinc.com> +Yu Xiaolei <dreifachstein@gmail.com> + +Google Inc. diff --git a/thirdparty/openxr/src/external/jsoncpp/LICENSE b/thirdparty/openxr/src/external/jsoncpp/LICENSE new file mode 100644 index 0000000000..c41a1d1c77 --- /dev/null +++ b/thirdparty/openxr/src/external/jsoncpp/LICENSE @@ -0,0 +1,55 @@ +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and +The JsonCpp Authors, and is released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. diff --git a/thirdparty/openxr/src/external/jsoncpp/include/json/allocator.h b/thirdparty/openxr/src/external/jsoncpp/include/json/allocator.h new file mode 100644 index 0000000000..95ef8a5ec4 --- /dev/null +++ b/thirdparty/openxr/src/external/jsoncpp/include/json/allocator.h @@ -0,0 +1,88 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_ALLOCATOR_H_INCLUDED +#define JSON_ALLOCATOR_H_INCLUDED + +#include <cstring> +#include <memory> + +#pragma pack(push, 8) + +namespace Json { +template <typename T> class SecureAllocator { +public: + // Type definitions + using value_type = T; + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + /** + * Allocate memory for N items using the standard allocator. + */ + pointer allocate(size_type n) { + // allocate using "global operator new" + return static_cast<pointer>(::operator new(n * sizeof(T))); + } + + /** + * Release memory which was allocated for N items at pointer P. + * + * The memory block is filled with zeroes before being released. + */ + void deallocate(pointer p, size_type n) { + // memset_s is used because memset may be optimized away by the compiler + memset_s(p, n * sizeof(T), 0, n * sizeof(T)); + // free using "global operator delete" + ::operator delete(p); + } + + /** + * Construct an item in-place at pointer P. + */ + template <typename... Args> void construct(pointer p, Args&&... args) { + // construct using "placement new" and "perfect forwarding" + ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...); + } + + size_type max_size() const { return size_t(-1) / sizeof(T); } + + pointer address(reference x) const { return std::addressof(x); } + + const_pointer address(const_reference x) const { return std::addressof(x); } + + /** + * Destroy an item in-place at pointer P. + */ + void destroy(pointer p) { + // destroy using "explicit destructor" + p->~T(); + } + + // Boilerplate + SecureAllocator() {} + template <typename U> SecureAllocator(const SecureAllocator<U>&) {} + template <typename U> struct rebind { using other = SecureAllocator<U>; }; +}; + +template <typename T, typename U> +bool operator==(const SecureAllocator<T>&, const SecureAllocator<U>&) { + return true; +} + +template <typename T, typename U> +bool operator!=(const SecureAllocator<T>&, const SecureAllocator<U>&) { + return false; +} + +} // namespace Json + +#pragma pack(pop) + +#endif // JSON_ALLOCATOR_H_INCLUDED diff --git a/thirdparty/openxr/src/external/jsoncpp/include/json/assertions.h b/thirdparty/openxr/src/external/jsoncpp/include/json/assertions.h new file mode 100644 index 0000000000..666fa7f542 --- /dev/null +++ b/thirdparty/openxr/src/external/jsoncpp/include/json/assertions.h @@ -0,0 +1,61 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_ASSERTIONS_H_INCLUDED +#define JSON_ASSERTIONS_H_INCLUDED + +#include <cstdlib> +#include <sstream> + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +/** It should not be possible for a maliciously designed file to + * cause an abort() or seg-fault, so these macros are used only + * for pre-condition violations and internal logic errors. + */ +#if JSON_USE_EXCEPTION + +// @todo <= add detail about condition in exception +#define JSON_ASSERT(condition) \ + do { \ + if (!(condition)) { \ + Json::throwLogicError("assert json failed"); \ + } \ + } while (0) + +#define JSON_FAIL_MESSAGE(message) \ + do { \ + OStringStream oss; \ + oss << message; \ + Json::throwLogicError(oss.str()); \ + abort(); \ + } while (0) + +#else // JSON_USE_EXCEPTION + +#define JSON_ASSERT(condition) assert(condition) + +// The call to assert() will show the failure message in debug builds. In +// release builds we abort, for a core-dump or debugger. +#define JSON_FAIL_MESSAGE(message) \ + { \ + OStringStream oss; \ + oss << message; \ + assert(false && oss.str().c_str()); \ + abort(); \ + } + +#endif + +#define JSON_ASSERT_MESSAGE(condition, message) \ + do { \ + if (!(condition)) { \ + JSON_FAIL_MESSAGE(message); \ + } \ + } while (0) + +#endif // JSON_ASSERTIONS_H_INCLUDED diff --git a/thirdparty/openxr/src/external/jsoncpp/include/json/config.h b/thirdparty/openxr/src/external/jsoncpp/include/json/config.h new file mode 100644 index 0000000000..6359273a22 --- /dev/null +++ b/thirdparty/openxr/src/external/jsoncpp/include/json/config.h @@ -0,0 +1,150 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_CONFIG_H_INCLUDED +#define JSON_CONFIG_H_INCLUDED +#include <cstddef> +#include <cstdint> +#include <istream> +#include <memory> +#include <ostream> +#include <sstream> +#include <string> +#include <type_traits> + +// If non-zero, the library uses exceptions to report bad input instead of C +// assertion macros. The default is to use exceptions. +#ifndef JSON_USE_EXCEPTION +#define JSON_USE_EXCEPTION 1 +#endif + +// Temporary, tracked for removal with issue #982. +#ifndef JSON_USE_NULLREF +#define JSON_USE_NULLREF 1 +#endif + +/// If defined, indicates that the source file is amalgamated +/// to prevent private header inclusion. +/// Remarks: it is automatically defined in the generated amalgamated header. +// #define JSON_IS_AMALGAMATION + +// Export macros for DLL visibility +#if defined(JSON_DLL_BUILD) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllexport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#elif defined(__GNUC__) || defined(__clang__) +#define JSON_API __attribute__((visibility("default"))) +#endif // if defined(_MSC_VER) + +#elif defined(JSON_DLL) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllimport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#endif // ifdef JSON_DLL_BUILD + +#if !defined(JSON_API) +#define JSON_API +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1800 +#error \ + "ERROR: Visual Studio 12 (2013) with _MSC_VER=1800 is the oldest supported compiler with sufficient C++11 capabilities" +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1900 +// As recommended at +// https://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 +extern JSON_API int msvc_pre1900_c99_snprintf(char* outBuf, size_t size, + const char* format, ...); +#define jsoncpp_snprintf msvc_pre1900_c99_snprintf +#else +#define jsoncpp_snprintf std::snprintf +#endif + +// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for +// integer +// Storages, and 64 bits integer support is disabled. +// #define JSON_NO_INT64 1 + +// JSONCPP_OVERRIDE is maintained for backwards compatibility of external tools. +// C++11 should be used directly in JSONCPP. +#define JSONCPP_OVERRIDE override + +#ifdef __clang__ +#if __has_extension(attribute_deprecated_with_message) +#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message))) +#endif +#elif defined(__GNUC__) // not clang (gcc comes later since clang emulates gcc) +#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message))) +#elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) +#endif // GNUC version +#elif defined(_MSC_VER) // MSVC (after clang because clang on Windows emulates + // MSVC) +#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +#endif // __clang__ || __GNUC__ || _MSC_VER + +#if !defined(JSONCPP_DEPRECATED) +#define JSONCPP_DEPRECATED(message) +#endif // if !defined(JSONCPP_DEPRECATED) + +#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 6)) +#define JSON_USE_INT64_DOUBLE_CONVERSION 1 +#endif + +#if !defined(JSON_IS_AMALGAMATION) + +#include "allocator.h" +#include "version.h" + +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { +using Int = int; +using UInt = unsigned int; +#if defined(JSON_NO_INT64) +using LargestInt = int; +using LargestUInt = unsigned int; +#undef JSON_HAS_INT64 +#else // if defined(JSON_NO_INT64) +// For Microsoft Visual use specific types as long long is not supported +#if defined(_MSC_VER) // Microsoft Visual Studio +using Int64 = __int64; +using UInt64 = unsigned __int64; +#else // if defined(_MSC_VER) // Other platforms, use long long +using Int64 = int64_t; +using UInt64 = uint64_t; +#endif // if defined(_MSC_VER) +using LargestInt = Int64; +using LargestUInt = UInt64; +#define JSON_HAS_INT64 +#endif // if defined(JSON_NO_INT64) + +template <typename T> +using Allocator = + typename std::conditional<JSONCPP_USING_SECURE_MEMORY, SecureAllocator<T>, + std::allocator<T>>::type; +using String = std::basic_string<char, std::char_traits<char>, Allocator<char>>; +using IStringStream = + std::basic_istringstream<String::value_type, String::traits_type, + String::allocator_type>; +using OStringStream = + std::basic_ostringstream<String::value_type, String::traits_type, + String::allocator_type>; +using IStream = std::istream; +using OStream = std::ostream; +} // namespace Json + +// Legacy names (formerly macros). +using JSONCPP_STRING = Json::String; +using JSONCPP_ISTRINGSTREAM = Json::IStringStream; +using JSONCPP_OSTRINGSTREAM = Json::OStringStream; +using JSONCPP_ISTREAM = Json::IStream; +using JSONCPP_OSTREAM = Json::OStream; + +#endif // JSON_CONFIG_H_INCLUDED diff --git a/thirdparty/openxr/src/external/jsoncpp/include/json/forwards.h b/thirdparty/openxr/src/external/jsoncpp/include/json/forwards.h new file mode 100644 index 0000000000..affe33a7f9 --- /dev/null +++ b/thirdparty/openxr/src/external/jsoncpp/include/json/forwards.h @@ -0,0 +1,43 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_FORWARDS_H_INCLUDED +#define JSON_FORWARDS_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +// writer.h +class StreamWriter; +class StreamWriterBuilder; +class Writer; +class FastWriter; +class StyledWriter; +class StyledStreamWriter; + +// reader.h +class Reader; +class CharReader; +class CharReaderBuilder; + +// json_features.h +class Features; + +// value.h +using ArrayIndex = unsigned int; +class StaticString; +class Path; +class PathArgument; +class Value; +class ValueIteratorBase; +class ValueIterator; +class ValueConstIterator; + +} // namespace Json + +#endif // JSON_FORWARDS_H_INCLUDED diff --git a/thirdparty/openxr/src/external/jsoncpp/include/json/json.h b/thirdparty/openxr/src/external/jsoncpp/include/json/json.h new file mode 100644 index 0000000000..5c776a1609 --- /dev/null +++ b/thirdparty/openxr/src/external/jsoncpp/include/json/json.h @@ -0,0 +1,15 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_JSON_H_INCLUDED +#define JSON_JSON_H_INCLUDED + +#include "config.h" +#include "json_features.h" +#include "reader.h" +#include "value.h" +#include "writer.h" + +#endif // JSON_JSON_H_INCLUDED diff --git a/thirdparty/openxr/src/external/jsoncpp/include/json/json_features.h b/thirdparty/openxr/src/external/jsoncpp/include/json/json_features.h new file mode 100644 index 0000000000..7c7e9f5de1 --- /dev/null +++ b/thirdparty/openxr/src/external/jsoncpp/include/json/json_features.h @@ -0,0 +1,61 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_FEATURES_H_INCLUDED +#define JSON_FEATURES_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "forwards.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +#pragma pack(push, 8) + +namespace Json { + +/** \brief Configuration passed to reader and writer. + * This configuration object can be used to force the Reader or Writer + * to behave in a standard conforming way. + */ +class JSON_API Features { +public: + /** \brief A configuration that allows all features and assumes all strings + * are UTF-8. + * - C & C++ comments are allowed + * - Root object can be any JSON value + * - Assumes Value strings are encoded in UTF-8 + */ + static Features all(); + + /** \brief A configuration that is strictly compatible with the JSON + * specification. + * - Comments are forbidden. + * - Root object must be either an array or an object value. + * - Assumes Value strings are encoded in UTF-8 + */ + static Features strictMode(); + + /** \brief Initialize the configuration like JsonConfig::allFeatures; + */ + Features(); + + /// \c true if comments are allowed. Default: \c true. + bool allowComments_{true}; + + /// \c true if root must be either an array or an object value. Default: \c + /// false. + bool strictRoot_{false}; + + /// \c true if dropped null placeholders are allowed. Default: \c false. + bool allowDroppedNullPlaceholders_{false}; + + /// \c true if numeric object key are allowed. Default: \c false. + bool allowNumericKeys_{false}; +}; + +} // namespace Json + +#pragma pack(pop) + +#endif // JSON_FEATURES_H_INCLUDED diff --git a/thirdparty/openxr/src/external/jsoncpp/include/json/reader.h b/thirdparty/openxr/src/external/jsoncpp/include/json/reader.h new file mode 100644 index 0000000000..be0d7676ab --- /dev/null +++ b/thirdparty/openxr/src/external/jsoncpp/include/json/reader.h @@ -0,0 +1,405 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_READER_H_INCLUDED +#define JSON_READER_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "json_features.h" +#include "value.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include <deque> +#include <iosfwd> +#include <istream> +#include <stack> +#include <string> + +// Disable warning C4251: <data member>: <type> needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#pragma pack(push, 8) + +namespace Json { + +/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a + * Value. + * + * \deprecated Use CharReader and CharReaderBuilder. + */ + +class JSON_API Reader { +public: + using Char = char; + using Location = const Char*; + + /** \brief An error tagged with where in the JSON text it was encountered. + * + * The offsets give the [start, limit) range of bytes within the text. Note + * that this is bytes, not codepoints. + */ + struct StructuredError { + ptrdiff_t offset_start; + ptrdiff_t offset_limit; + String message; + }; + + /** \brief Constructs a Reader allowing all features for parsing. + * \deprecated Use CharReader and CharReaderBuilder. + */ + Reader(); + + /** \brief Constructs a Reader allowing the specified feature set for parsing. + * \deprecated Use CharReader and CharReaderBuilder. + */ + Reader(const Features& features); + + /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> + * document. + * + * \param document UTF-8 encoded string containing the document + * to read. + * \param[out] root Contains the root value of the document if it + * was successfully parsed. + * \param collectComments \c true to collect comment and allow writing + * them back during serialization, \c false to + * discard comments. This parameter is ignored + * if Features::allowComments_ is \c false. + * \return \c true if the document was successfully parsed, \c false if an + * error occurred. + */ + bool parse(const std::string& document, Value& root, + bool collectComments = true); + + /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> + * document. + * + * \param beginDoc Pointer on the beginning of the UTF-8 encoded + * string of the document to read. + * \param endDoc Pointer on the end of the UTF-8 encoded string + * of the document to read. Must be >= beginDoc. + * \param[out] root Contains the root value of the document if it + * was successfully parsed. + * \param collectComments \c true to collect comment and allow writing + * them back during serialization, \c false to + * discard comments. This parameter is ignored + * if Features::allowComments_ is \c false. + * \return \c true if the document was successfully parsed, \c false if an + * error occurred. + */ + bool parse(const char* beginDoc, const char* endDoc, Value& root, + bool collectComments = true); + + /// \brief Parse from input stream. + /// \see Json::operator>>(std::istream&, Json::Value&). + bool parse(IStream& is, Value& root, bool collectComments = true); + + /** \brief Returns a user friendly string that list errors in the parsed + * document. + * + * \return Formatted error message with the list of errors with their + * location in the parsed document. An empty string is returned if no error + * occurred during parsing. + * \deprecated Use getFormattedErrorMessages() instead (typo fix). + */ + JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.") + String getFormatedErrorMessages() const; + + /** \brief Returns a user friendly string that list errors in the parsed + * document. + * + * \return Formatted error message with the list of errors with their + * location in the parsed document. An empty string is returned if no error + * occurred during parsing. + */ + String getFormattedErrorMessages() const; + + /** \brief Returns a vector of structured errors encountered while parsing. + * + * \return A (possibly empty) vector of StructuredError objects. Currently + * only one error can be returned, but the caller should tolerate multiple + * errors. This can occur if the parser recovers from a non-fatal parse + * error and then encounters additional errors. + */ + std::vector<StructuredError> getStructuredErrors() const; + + /** \brief Add a semantic error message. + * + * \param value JSON Value location associated with the error + * \param message The error message. + * \return \c true if the error was successfully added, \c false if the Value + * offset exceeds the document size. + */ + bool pushError(const Value& value, const String& message); + + /** \brief Add a semantic error message with extra context. + * + * \param value JSON Value location associated with the error + * \param message The error message. + * \param extra Additional JSON Value location to contextualize the error + * \return \c true if the error was successfully added, \c false if either + * Value offset exceeds the document size. + */ + bool pushError(const Value& value, const String& message, const Value& extra); + + /** \brief Return whether there are any errors. + * + * \return \c true if there are no errors to report \c false if errors have + * occurred. + */ + bool good() const; + +private: + enum TokenType { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token { + public: + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo { + public: + Token token_; + String message_; + Location extra_; + }; + + using Errors = std::deque<ErrorInfo>; + + bool readToken(Token& token); + void skipSpaces(); + bool match(const Char* pattern, int patternLength); + bool readComment(); + bool readCStyleComment(); + bool readCppStyleComment(); + bool readString(); + void readNumber(); + bool readValue(); + bool readObject(Token& token); + bool readArray(Token& token); + bool decodeNumber(Token& token); + bool decodeNumber(Token& token, Value& decoded); + bool decodeString(Token& token); + bool decodeString(Token& token, String& decoded); + bool decodeDouble(Token& token); + bool decodeDouble(Token& token, Value& decoded); + bool decodeUnicodeCodePoint(Token& token, Location& current, Location end, + unsigned int& unicode); + bool decodeUnicodeEscapeSequence(Token& token, Location& current, + Location end, unsigned int& unicode); + bool addError(const String& message, Token& token, Location extra = nullptr); + bool recoverFromError(TokenType skipUntilToken); + bool addErrorAndRecover(const String& message, Token& token, + TokenType skipUntilToken); + void skipUntilSpace(); + Value& currentValue(); + Char getNextChar(); + void getLocationLineAndColumn(Location location, int& line, + int& column) const; + String getLocationLineAndColumn(Location location) const; + void addComment(Location begin, Location end, CommentPlacement placement); + void skipCommentTokens(Token& token); + + static bool containsNewLine(Location begin, Location end); + static String normalizeEOL(Location begin, Location end); + + using Nodes = std::stack<Value*>; + Nodes nodes_; + Errors errors_; + String document_; + Location begin_{}; + Location end_{}; + Location current_{}; + Location lastValueEnd_{}; + Value* lastValue_{}; + String commentsBefore_; + Features features_; + bool collectComments_{}; +}; // Reader + +/** Interface for reading JSON from a char array. + */ +class JSON_API CharReader { +public: + virtual ~CharReader() = default; + /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> + * document. The document must be a UTF-8 encoded string containing the + * document to read. + * + * \param beginDoc Pointer on the beginning of the UTF-8 encoded string + * of the document to read. + * \param endDoc Pointer on the end of the UTF-8 encoded string of the + * document to read. Must be >= beginDoc. + * \param[out] root Contains the root value of the document if it was + * successfully parsed. + * \param[out] errs Formatted error messages (if not NULL) a user + * friendly string that lists errors in the parsed + * document. + * \return \c true if the document was successfully parsed, \c false if an + * error occurred. + */ + virtual bool parse(char const* beginDoc, char const* endDoc, Value* root, + String* errs) = 0; + + class JSON_API Factory { + public: + virtual ~Factory() = default; + /** \brief Allocate a CharReader via operator new(). + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual CharReader* newCharReader() const = 0; + }; // Factory +}; // CharReader + +/** \brief Build a CharReader implementation. + * + * Usage: + * \code + * using namespace Json; + * CharReaderBuilder builder; + * builder["collectComments"] = false; + * Value value; + * String errs; + * bool ok = parseFromStream(builder, std::cin, &value, &errs); + * \endcode + */ +class JSON_API CharReaderBuilder : public CharReader::Factory { +public: + // Note: We use a Json::Value so that we can add data-members to this class + // without a major version bump. + /** Configuration of this builder. + * These are case-sensitive. + * Available settings (case-sensitive): + * - `"collectComments": false or true` + * - true to collect comment and allow writing them back during + * serialization, false to discard comments. This parameter is ignored + * if allowComments is false. + * - `"allowComments": false or true` + * - true if comments are allowed. + * - `"allowTrailingCommas": false or true` + * - true if trailing commas in objects and arrays are allowed. + * - `"strictRoot": false or true` + * - true if root must be either an array or an object value + * - `"allowDroppedNullPlaceholders": false or true` + * - true if dropped null placeholders are allowed. (See + * StreamWriterBuilder.) + * - `"allowNumericKeys": false or true` + * - true if numeric object keys are allowed. + * - `"allowSingleQuotes": false or true` + * - true if '' are allowed for strings (both keys and values) + * - `"stackLimit": integer` + * - Exceeding stackLimit (recursive depth of `readValue()`) will cause an + * exception. + * - This is a security issue (seg-faults caused by deeply nested JSON), so + * the default is low. + * - `"failIfExtra": false or true` + * - If true, `parse()` returns false when extra non-whitespace trails the + * JSON value in the input string. + * - `"rejectDupKeys": false or true` + * - If true, `parse()` returns false when a key is duplicated within an + * object. + * - `"allowSpecialFloats": false or true` + * - If true, special float values (NaNs and infinities) are allowed and + * their values are lossfree restorable. + * - `"skipBom": false or true` + * - If true, if the input starts with the Unicode byte order mark (BOM), + * it is skipped. + * + * You can examine 'settings_` yourself to see the defaults. You can also + * write and read them just like any JSON Value. + * \sa setDefaults() + */ + Json::Value settings_; + + CharReaderBuilder(); + ~CharReaderBuilder() override; + + CharReader* newCharReader() const override; + + /** \return true if 'settings' are legal and consistent; + * otherwise, indicate bad settings via 'invalid'. + */ + bool validate(Json::Value* invalid) const; + + /** A simple way to update a specific setting. + */ + Value& operator[](const String& key); + + /** Called by ctor, but you can use this to reset settings_. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults + */ + static void setDefaults(Json::Value* settings); + /** Same as old Features::strictMode(). + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode + */ + static void strictMode(Json::Value* settings); +}; + +/** Consume entire stream and use its begin/end. + * Someday we might have a real StreamReader, but for now this + * is convenient. + */ +bool JSON_API parseFromStream(CharReader::Factory const&, IStream&, Value* root, + String* errs); + +/** \brief Read from 'sin' into 'root'. + * + * Always keep comments from the input JSON. + * + * This can be used to read a file into a particular sub-object. + * For example: + * \code + * Json::Value root; + * cin >> root["dir"]["file"]; + * cout << root; + * \endcode + * Result: + * \verbatim + * { + * "dir": { + * "file": { + * // The input stream JSON would be nested here. + * } + * } + * } + * \endverbatim + * \throw std::exception on parse error. + * \see Json::operator<<() + */ +JSON_API IStream& operator>>(IStream&, Value&); + +} // namespace Json + +#pragma pack(pop) + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // JSON_READER_H_INCLUDED diff --git a/thirdparty/openxr/src/external/jsoncpp/include/json/value.h b/thirdparty/openxr/src/external/jsoncpp/include/json/value.h new file mode 100644 index 0000000000..0edeb050ca --- /dev/null +++ b/thirdparty/openxr/src/external/jsoncpp/include/json/value.h @@ -0,0 +1,935 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_H_INCLUDED +#define JSON_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "forwards.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +// Conditional NORETURN attribute on the throw functions would: +// a) suppress false positives from static code analysis +// b) possibly improve optimization opportunities. +#if !defined(JSONCPP_NORETURN) +#if defined(_MSC_VER) && _MSC_VER == 1800 +#define JSONCPP_NORETURN __declspec(noreturn) +#else +#define JSONCPP_NORETURN [[noreturn]] +#endif +#endif + +// Support for '= delete' with template declarations was a late addition +// to the c++11 standard and is rejected by clang 3.8 and Apple clang 8.2 +// even though these declare themselves to be c++11 compilers. +#if !defined(JSONCPP_TEMPLATE_DELETE) +#if defined(__clang__) && defined(__apple_build_version__) +#if __apple_build_version__ <= 8000042 +#define JSONCPP_TEMPLATE_DELETE +#endif +#elif defined(__clang__) +#if __clang_major__ == 3 && __clang_minor__ <= 8 +#define JSONCPP_TEMPLATE_DELETE +#endif +#endif +#if !defined(JSONCPP_TEMPLATE_DELETE) +#define JSONCPP_TEMPLATE_DELETE = delete +#endif +#endif + +#include <array> +#include <exception> +#include <map> +#include <memory> +#include <string> +#include <vector> + +// Disable warning C4251: <data member>: <type> needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251 4275) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#pragma pack(push, 8) + +/** \brief JSON (JavaScript Object Notation). + */ +namespace Json { + +#if JSON_USE_EXCEPTION +/** Base class for all exceptions we throw. + * + * We use nothing but these internally. Of course, STL can throw others. + */ +class JSON_API Exception : public std::exception { +public: + Exception(String msg); + ~Exception() noexcept override; + char const* what() const noexcept override; + +protected: + String msg_; +}; + +/** Exceptions which the user cannot easily avoid. + * + * E.g. out-of-memory (when we use malloc), stack-overflow, malicious input + * + * \remark derived from Json::Exception + */ +class JSON_API RuntimeError : public Exception { +public: + RuntimeError(String const& msg); +}; + +/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros. + * + * These are precondition-violations (user bugs) and internal errors (our bugs). + * + * \remark derived from Json::Exception + */ +class JSON_API LogicError : public Exception { +public: + LogicError(String const& msg); +}; +#endif + +/// used internally +JSONCPP_NORETURN void throwRuntimeError(String const& msg); +/// used internally +JSONCPP_NORETURN void throwLogicError(String const& msg); + +/** \brief Type of the value held by a Value object. + */ +enum ValueType { + nullValue = 0, ///< 'null' value + intValue, ///< signed integer value + uintValue, ///< unsigned integer value + realValue, ///< double value + stringValue, ///< UTF-8 string value + booleanValue, ///< bool value + arrayValue, ///< array value (ordered list) + objectValue ///< object value (collection of name/value pairs). +}; + +enum CommentPlacement { + commentBefore = 0, ///< a comment placed on the line before a value + commentAfterOnSameLine, ///< a comment just after a value on the same line + commentAfter, ///< a comment on the line after a value (only make sense for + /// root value) + numberOfCommentPlacement +}; + +/** \brief Type of precision for formatting of real values. + */ +enum PrecisionType { + significantDigits = 0, ///< we set max number of significant digits in string + decimalPlaces ///< we set max number of digits after "." in string +}; + +/** \brief Lightweight wrapper to tag static string. + * + * Value constructor and objectValue member assignment takes advantage of the + * StaticString and avoid the cost of string duplication when storing the + * string or the member name. + * + * Example of usage: + * \code + * Json::Value aValue( StaticString("some text") ); + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ +class JSON_API StaticString { +public: + explicit StaticString(const char* czstring) : c_str_(czstring) {} + + operator const char*() const { return c_str_; } + + const char* c_str() const { return c_str_; } + +private: + const char* c_str_; +}; + +/** \brief Represents a <a HREF="http://www.json.org">JSON</a> value. + * + * This class is a discriminated union wrapper that can represents a: + * - signed integer [range: Value::minInt - Value::maxInt] + * - unsigned integer (range: 0 - Value::maxUInt) + * - double + * - UTF-8 string + * - boolean + * - 'null' + * - an ordered list of Value + * - collection of name/value pairs (javascript object) + * + * The type of the held value is represented by a #ValueType and + * can be obtained using type(). + * + * Values of an #objectValue or #arrayValue can be accessed using operator[]() + * methods. + * Non-const methods will automatically create the a #nullValue element + * if it does not exist. + * The sequence of an #arrayValue will be automatically resized and initialized + * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. + * + * The get() methods can be used to obtain default value in the case the + * required element does not exist. + * + * It is possible to iterate over the list of member keys of an object using + * the getMemberNames() method. + * + * \note #Value string-length fit in size_t, but keys must be < 2^30. + * (The reason is an implementation detail.) A #CharReader will raise an + * exception if a bound is exceeded to avoid security holes in your app, + * but the Value API does *not* check bounds. That is the responsibility + * of the caller. + */ +class JSON_API Value { + friend class ValueIteratorBase; + +public: + using Members = std::vector<String>; + using iterator = ValueIterator; + using const_iterator = ValueConstIterator; + using UInt = Json::UInt; + using Int = Json::Int; +#if defined(JSON_HAS_INT64) + using UInt64 = Json::UInt64; + using Int64 = Json::Int64; +#endif // defined(JSON_HAS_INT64) + using LargestInt = Json::LargestInt; + using LargestUInt = Json::LargestUInt; + using ArrayIndex = Json::ArrayIndex; + + // Required for boost integration, e. g. BOOST_TEST + using value_type = std::string; + +#if JSON_USE_NULLREF + // Binary compatibility kludges, do not use. + static const Value& null; + static const Value& nullRef; +#endif + + // null and nullRef are deprecated, use this instead. + static Value const& nullSingleton(); + + /// Minimum signed integer value that can be stored in a Json::Value. + static constexpr LargestInt minLargestInt = + LargestInt(~(LargestUInt(-1) / 2)); + /// Maximum signed integer value that can be stored in a Json::Value. + static constexpr LargestInt maxLargestInt = LargestInt(LargestUInt(-1) / 2); + /// Maximum unsigned integer value that can be stored in a Json::Value. + static constexpr LargestUInt maxLargestUInt = LargestUInt(-1); + + /// Minimum signed int value that can be stored in a Json::Value. + static constexpr Int minInt = Int(~(UInt(-1) / 2)); + /// Maximum signed int value that can be stored in a Json::Value. + static constexpr Int maxInt = Int(UInt(-1) / 2); + /// Maximum unsigned int value that can be stored in a Json::Value. + static constexpr UInt maxUInt = UInt(-1); + +#if defined(JSON_HAS_INT64) + /// Minimum signed 64 bits int value that can be stored in a Json::Value. + static constexpr Int64 minInt64 = Int64(~(UInt64(-1) / 2)); + /// Maximum signed 64 bits int value that can be stored in a Json::Value. + static constexpr Int64 maxInt64 = Int64(UInt64(-1) / 2); + /// Maximum unsigned 64 bits int value that can be stored in a Json::Value. + static constexpr UInt64 maxUInt64 = UInt64(-1); +#endif // defined(JSON_HAS_INT64) + /// Default precision for real value for string representation. + static constexpr UInt defaultRealPrecision = 17; + // The constant is hard-coded because some compiler have trouble + // converting Value::maxUInt64 to a double correctly (AIX/xlC). + // Assumes that UInt64 is a 64 bits integer. + static constexpr double maxUInt64AsDouble = 18446744073709551615.0; +// Workaround for bug in the NVIDIAs CUDA 9.1 nvcc compiler +// when using gcc and clang backend compilers. CZString +// cannot be defined as private. See issue #486 +#ifdef __NVCC__ +public: +#else +private: +#endif +#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + class CZString { + public: + enum DuplicationPolicy { noDuplication = 0, duplicate, duplicateOnCopy }; + CZString(ArrayIndex index); + CZString(char const* str, unsigned length, DuplicationPolicy allocate); + CZString(CZString const& other); + CZString(CZString&& other) noexcept; + ~CZString(); + CZString& operator=(const CZString& other); + CZString& operator=(CZString&& other) noexcept; + + bool operator<(CZString const& other) const; + bool operator==(CZString const& other) const; + ArrayIndex index() const; + // const char* c_str() const; ///< \deprecated + char const* data() const; + unsigned length() const; + bool isStaticString() const; + + private: + void swap(CZString& other); + + struct StringStorage { + unsigned policy_ : 2; + unsigned length_ : 30; // 1GB max + }; + + char const* cstr_; // actually, a prefixed string, unless policy is noDup + union { + ArrayIndex index_; + StringStorage storage_; + }; + }; + +public: + typedef std::map<CZString, Value> ObjectValues; +#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + +public: + /** + * \brief Create a default Value of the given type. + * + * This is a very useful constructor. + * To create an empty array, pass arrayValue. + * To create an empty object, pass objectValue. + * Another Value can then be set to this one by assignment. + * This is useful since clear() and resize() will not alter types. + * + * Examples: + * \code + * Json::Value null_value; // null + * Json::Value arr_value(Json::arrayValue); // [] + * Json::Value obj_value(Json::objectValue); // {} + * \endcode + */ + Value(ValueType type = nullValue); + Value(Int value); + Value(UInt value); +#if defined(JSON_HAS_INT64) + Value(Int64 value); + Value(UInt64 value); +#endif // if defined(JSON_HAS_INT64) + Value(double value); + Value(const char* value); ///< Copy til first 0. (NULL causes to seg-fault.) + Value(const char* begin, const char* end); ///< Copy all, incl zeroes. + /** + * \brief Constructs a value from a static string. + * + * Like other value string constructor but do not duplicate the string for + * internal storage. The given string must remain alive after the call to + * this constructor. + * + * \note This works only for null-terminated strings. (We cannot change the + * size of this class, so we have nowhere to store the length, which might be + * computed later for various operations.) + * + * Example of usage: + * \code + * static StaticString foo("some text"); + * Json::Value aValue(foo); + * \endcode + */ + Value(const StaticString& value); + Value(const String& value); + Value(bool value); + Value(std::nullptr_t ptr) = delete; + Value(const Value& other); + Value(Value&& other) noexcept; + ~Value(); + + /// \note Overwrite existing comments. To preserve comments, use + /// #swapPayload(). + Value& operator=(const Value& other); + Value& operator=(Value&& other) noexcept; + + /// Swap everything. + void swap(Value& other); + /// Swap values but leave comments and source offsets in place. + void swapPayload(Value& other); + + /// copy everything. + void copy(const Value& other); + /// copy values but leave comments and source offsets in place. + void copyPayload(const Value& other); + + ValueType type() const; + + /// Compare payload only, not comments etc. + bool operator<(const Value& other) const; + bool operator<=(const Value& other) const; + bool operator>=(const Value& other) const; + bool operator>(const Value& other) const; + bool operator==(const Value& other) const; + bool operator!=(const Value& other) const; + int compare(const Value& other) const; + + const char* asCString() const; ///< Embedded zeroes could cause you trouble! +#if JSONCPP_USING_SECURE_MEMORY + unsigned getCStringLength() const; // Allows you to understand the length of + // the CString +#endif + String asString() const; ///< Embedded zeroes are possible. + /** Get raw char* of string-value. + * \return false if !string. (Seg-fault if str or end are NULL.) + */ + bool getString(char const** begin, char const** end) const; + Int asInt() const; + UInt asUInt() const; +#if defined(JSON_HAS_INT64) + Int64 asInt64() const; + UInt64 asUInt64() const; +#endif // if defined(JSON_HAS_INT64) + LargestInt asLargestInt() const; + LargestUInt asLargestUInt() const; + float asFloat() const; + double asDouble() const; + bool asBool() const; + + bool isNull() const; + bool isBool() const; + bool isInt() const; + bool isInt64() const; + bool isUInt() const; + bool isUInt64() const; + bool isIntegral() const; + bool isDouble() const; + bool isNumeric() const; + bool isString() const; + bool isArray() const; + bool isObject() const; + + /// The `as<T>` and `is<T>` member function templates and specializations. + template <typename T> T as() const JSONCPP_TEMPLATE_DELETE; + template <typename T> bool is() const JSONCPP_TEMPLATE_DELETE; + + bool isConvertibleTo(ValueType other) const; + + /// Number of values in array or object + ArrayIndex size() const; + + /// \brief Return true if empty array, empty object, or null; + /// otherwise, false. + bool empty() const; + + /// Return !isNull() + explicit operator bool() const; + + /// Remove all object members and array elements. + /// \pre type() is arrayValue, objectValue, or nullValue + /// \post type() is unchanged + void clear(); + + /// Resize the array to newSize elements. + /// New elements are initialized to null. + /// May only be called on nullValue or arrayValue. + /// \pre type() is arrayValue or nullValue + /// \post type() is arrayValue + void resize(ArrayIndex newSize); + + //@{ + /// Access an array element (zero based index). If the array contains less + /// than index element, then null value are inserted in the array so that + /// its size is index+1. + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value& operator[](ArrayIndex index); + Value& operator[](int index); + //@} + + //@{ + /// Access an array element (zero based index). + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value& operator[](ArrayIndex index) const; + const Value& operator[](int index) const; + //@} + + /// If the array contains at least index+1 elements, returns the element + /// value, otherwise returns defaultValue. + Value get(ArrayIndex index, const Value& defaultValue) const; + /// Return true if index < size(). + bool isValidIndex(ArrayIndex index) const; + /// \brief Append value to array at the end. + /// + /// Equivalent to jsonvalue[jsonvalue.size()] = value; + Value& append(const Value& value); + Value& append(Value&& value); + + /// \brief Insert value in array at specific index + bool insert(ArrayIndex index, const Value& newValue); + bool insert(ArrayIndex index, Value&& newValue); + + /// Access an object value by name, create a null member if it does not exist. + /// \note Because of our implementation, keys are limited to 2^30 -1 chars. + /// Exceeding that will cause an exception. + Value& operator[](const char* key); + /// Access an object value by name, returns null if there is no member with + /// that name. + const Value& operator[](const char* key) const; + /// Access an object value by name, create a null member if it does not exist. + /// \param key may contain embedded nulls. + Value& operator[](const String& key); + /// Access an object value by name, returns null if there is no member with + /// that name. + /// \param key may contain embedded nulls. + const Value& operator[](const String& key) const; + /** \brief Access an object value by name, create a null member if it does not + * exist. + * + * If the object has no entry for that name, then the member name used to + * store the new entry is not duplicated. + * Example of use: + * \code + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ + Value& operator[](const StaticString& key); + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + Value get(const char* key, const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \note key may contain embedded nulls. + Value get(const char* begin, const char* end, + const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \param key may contain embedded nulls. + Value get(const String& key, const Value& defaultValue) const; + /// Most general and efficient version of isMember()const, get()const, + /// and operator[]const + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + Value const* find(char const* begin, char const* end) const; + /// Most general and efficient version of object-mutators. + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue. + Value* demand(char const* begin, char const* end); + /// \brief Remove and return the named member. + /// + /// Do nothing if it did not exist. + /// \pre type() is objectValue or nullValue + /// \post type() is unchanged + void removeMember(const char* key); + /// Same as removeMember(const char*) + /// \param key may contain embedded nulls. + void removeMember(const String& key); + /// Same as removeMember(const char* begin, const char* end, Value* removed), + /// but 'key' is null-terminated. + bool removeMember(const char* key, Value* removed); + /** \brief Remove the named map member. + * + * Update 'removed' iff removed. + * \param key may contain embedded nulls. + * \return true iff removed (no exceptions) + */ + bool removeMember(String const& key, Value* removed); + /// Same as removeMember(String const& key, Value* removed) + bool removeMember(const char* begin, const char* end, Value* removed); + /** \brief Remove the indexed array element. + * + * O(n) expensive operations. + * Update 'removed' iff removed. + * \return true if removed (no exceptions) + */ + bool removeIndex(ArrayIndex index, Value* removed); + + /// Return true if the object has a member named key. + /// \note 'key' must be null-terminated. + bool isMember(const char* key) const; + /// Return true if the object has a member named key. + /// \param key may contain embedded nulls. + bool isMember(const String& key) const; + /// Same as isMember(String const& key)const + bool isMember(const char* begin, const char* end) const; + + /// \brief Return a list of the member names. + /// + /// If null, return an empty list. + /// \pre type() is objectValue or nullValue + /// \post if type() was nullValue, it remains nullValue + Members getMemberNames() const; + + /// \deprecated Always pass len. + JSONCPP_DEPRECATED("Use setComment(String const&) instead.") + void setComment(const char* comment, CommentPlacement placement) { + setComment(String(comment, strlen(comment)), placement); + } + /// Comments must be //... or /* ... */ + void setComment(const char* comment, size_t len, CommentPlacement placement) { + setComment(String(comment, len), placement); + } + /// Comments must be //... or /* ... */ + void setComment(String comment, CommentPlacement placement); + bool hasComment(CommentPlacement placement) const; + /// Include delimiters and embedded newlines. + String getComment(CommentPlacement placement) const; + + String toStyledString() const; + + const_iterator begin() const; + const_iterator end() const; + + iterator begin(); + iterator end(); + + // Accessors for the [start, limit) range of bytes within the JSON text from + // which this value was parsed, if any. + void setOffsetStart(ptrdiff_t start); + void setOffsetLimit(ptrdiff_t limit); + ptrdiff_t getOffsetStart() const; + ptrdiff_t getOffsetLimit() const; + +private: + void setType(ValueType v) { + bits_.value_type_ = static_cast<unsigned char>(v); + } + bool isAllocated() const { return bits_.allocated_; } + void setIsAllocated(bool v) { bits_.allocated_ = v; } + + void initBasic(ValueType type, bool allocated = false); + void dupPayload(const Value& other); + void releasePayload(); + void dupMeta(const Value& other); + + Value& resolveReference(const char* key); + Value& resolveReference(const char* key, const char* end); + + // struct MemberNamesTransform + //{ + // typedef const char *result_type; + // const char *operator()( const CZString &name ) const + // { + // return name.c_str(); + // } + //}; + + union ValueHolder { + LargestInt int_; + LargestUInt uint_; + double real_; + bool bool_; + char* string_; // if allocated_, ptr to { unsigned, char[] }. + ObjectValues* map_; + } value_; + + struct { + // Really a ValueType, but types should agree for bitfield packing. + unsigned int value_type_ : 8; + // Unless allocated_, string_ must be null-terminated. + unsigned int allocated_ : 1; + } bits_; + + class Comments { + public: + Comments() = default; + Comments(const Comments& that); + Comments(Comments&& that) noexcept; + Comments& operator=(const Comments& that); + Comments& operator=(Comments&& that) noexcept; + bool has(CommentPlacement slot) const; + String get(CommentPlacement slot) const; + void set(CommentPlacement slot, String comment); + + private: + using Array = std::array<String, numberOfCommentPlacement>; + std::unique_ptr<Array> ptr_; + }; + Comments comments_; + + // [start, limit) byte offsets in the source JSON text from which this Value + // was extracted. + ptrdiff_t start_; + ptrdiff_t limit_; +}; + +template <> inline bool Value::as<bool>() const { return asBool(); } +template <> inline bool Value::is<bool>() const { return isBool(); } + +template <> inline Int Value::as<Int>() const { return asInt(); } +template <> inline bool Value::is<Int>() const { return isInt(); } + +template <> inline UInt Value::as<UInt>() const { return asUInt(); } +template <> inline bool Value::is<UInt>() const { return isUInt(); } + +#if defined(JSON_HAS_INT64) +template <> inline Int64 Value::as<Int64>() const { return asInt64(); } +template <> inline bool Value::is<Int64>() const { return isInt64(); } + +template <> inline UInt64 Value::as<UInt64>() const { return asUInt64(); } +template <> inline bool Value::is<UInt64>() const { return isUInt64(); } +#endif + +template <> inline double Value::as<double>() const { return asDouble(); } +template <> inline bool Value::is<double>() const { return isDouble(); } + +template <> inline String Value::as<String>() const { return asString(); } +template <> inline bool Value::is<String>() const { return isString(); } + +/// These `as` specializations are type conversions, and do not have a +/// corresponding `is`. +template <> inline float Value::as<float>() const { return asFloat(); } +template <> inline const char* Value::as<const char*>() const { + return asCString(); +} + +/** \brief Experimental and untested: represents an element of the "path" to + * access a node. + */ +class JSON_API PathArgument { +public: + friend class Path; + + PathArgument(); + PathArgument(ArrayIndex index); + PathArgument(const char* key); + PathArgument(String key); + +private: + enum Kind { kindNone = 0, kindIndex, kindKey }; + String key_; + ArrayIndex index_{}; + Kind kind_{kindNone}; +}; + +/** \brief Experimental and untested: represents a "path" to access a node. + * + * Syntax: + * - "." => root node + * - ".[n]" => elements at index 'n' of root node (an array value) + * - ".name" => member named 'name' of root node (an object value) + * - ".name1.name2.name3" + * - ".[0][1][2].name1[3]" + * - ".%" => member name is provided as parameter + * - ".[%]" => index is provided as parameter + */ +class JSON_API Path { +public: + Path(const String& path, const PathArgument& a1 = PathArgument(), + const PathArgument& a2 = PathArgument(), + const PathArgument& a3 = PathArgument(), + const PathArgument& a4 = PathArgument(), + const PathArgument& a5 = PathArgument()); + + const Value& resolve(const Value& root) const; + Value resolve(const Value& root, const Value& defaultValue) const; + /// Creates the "path" to access the specified node and returns a reference on + /// the node. + Value& make(Value& root) const; + +private: + using InArgs = std::vector<const PathArgument*>; + using Args = std::vector<PathArgument>; + + void makePath(const String& path, const InArgs& in); + void addPathInArg(const String& path, const InArgs& in, + InArgs::const_iterator& itInArg, PathArgument::Kind kind); + static void invalidPath(const String& path, int location); + + Args args_; +}; + +/** \brief base class for Value iterators. + * + */ +class JSON_API ValueIteratorBase { +public: + using iterator_category = std::bidirectional_iterator_tag; + using size_t = unsigned int; + using difference_type = int; + using SelfType = ValueIteratorBase; + + bool operator==(const SelfType& other) const { return isEqual(other); } + + bool operator!=(const SelfType& other) const { return !isEqual(other); } + + difference_type operator-(const SelfType& other) const { + return other.computeDistance(*this); + } + + /// Return either the index or the member name of the referenced value as a + /// Value. + Value key() const; + + /// Return the index of the referenced Value, or -1 if it is not an + /// arrayValue. + UInt index() const; + + /// Return the member name of the referenced Value, or "" if it is not an + /// objectValue. + /// \note Avoid `c_str()` on result, as embedded zeroes are possible. + String name() const; + + /// Return the member name of the referenced Value. "" if it is not an + /// objectValue. + /// \deprecated This cannot be used for UTF-8 strings, since there can be + /// embedded nulls. + JSONCPP_DEPRECATED("Use `key = name();` instead.") + char const* memberName() const; + /// Return the member name of the referenced Value, or NULL if it is not an + /// objectValue. + /// \note Better version than memberName(). Allows embedded nulls. + char const* memberName(char const** end) const; + +protected: + /*! Internal utility functions to assist with implementing + * other iterator functions. The const and non-const versions + * of the "deref" protected methods expose the protected + * current_ member variable in a way that can often be + * optimized away by the compiler. + */ + const Value& deref() const; + Value& deref(); + + void increment(); + + void decrement(); + + difference_type computeDistance(const SelfType& other) const; + + bool isEqual(const SelfType& other) const; + + void copy(const SelfType& other); + +private: + Value::ObjectValues::iterator current_; + // Indicates that iterator is for a null value. + bool isNull_{true}; + +public: + // For some reason, BORLAND needs these at the end, rather + // than earlier. No idea why. + ValueIteratorBase(); + explicit ValueIteratorBase(const Value::ObjectValues::iterator& current); +}; + +/** \brief const iterator for object and array value. + * + */ +class JSON_API ValueConstIterator : public ValueIteratorBase { + friend class Value; + +public: + using value_type = const Value; + // typedef unsigned int size_t; + // typedef int difference_type; + using reference = const Value&; + using pointer = const Value*; + using SelfType = ValueConstIterator; + + ValueConstIterator(); + ValueConstIterator(ValueIterator const& other); + +private: + /*! \internal Use by Value to create an iterator. + */ + explicit ValueConstIterator(const Value::ObjectValues::iterator& current); + +public: + SelfType& operator=(const ValueIteratorBase& other); + + SelfType operator++(int) { + SelfType temp(*this); + ++*this; + return temp; + } + + SelfType operator--(int) { + SelfType temp(*this); + --*this; + return temp; + } + + SelfType& operator--() { + decrement(); + return *this; + } + + SelfType& operator++() { + increment(); + return *this; + } + + reference operator*() const { return deref(); } + + pointer operator->() const { return &deref(); } +}; + +/** \brief Iterator for object and array value. + */ +class JSON_API ValueIterator : public ValueIteratorBase { + friend class Value; + +public: + using value_type = Value; + using size_t = unsigned int; + using difference_type = int; + using reference = Value&; + using pointer = Value*; + using SelfType = ValueIterator; + + ValueIterator(); + explicit ValueIterator(const ValueConstIterator& other); + ValueIterator(const ValueIterator& other); + +private: + /*! \internal Use by Value to create an iterator. + */ + explicit ValueIterator(const Value::ObjectValues::iterator& current); + +public: + SelfType& operator=(const SelfType& other); + + SelfType operator++(int) { + SelfType temp(*this); + ++*this; + return temp; + } + + SelfType operator--(int) { + SelfType temp(*this); + --*this; + return temp; + } + + SelfType& operator--() { + decrement(); + return *this; + } + + SelfType& operator++() { + increment(); + return *this; + } + + /*! The return value of non-const iterators can be + * changed, so the these functions are not const + * because the returned references/pointers can be used + * to change state of the base class. + */ + reference operator*() const { return const_cast<reference>(deref()); } + pointer operator->() const { return const_cast<pointer>(&deref()); } +}; + +inline void swap(Value& a, Value& b) { a.swap(b); } + +} // namespace Json + +#pragma pack(pop) + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // JSON_H_INCLUDED diff --git a/thirdparty/openxr/src/external/jsoncpp/include/json/version.h b/thirdparty/openxr/src/external/jsoncpp/include/json/version.h new file mode 100644 index 0000000000..e931d0383e --- /dev/null +++ b/thirdparty/openxr/src/external/jsoncpp/include/json/version.h @@ -0,0 +1,28 @@ +#ifndef JSON_VERSION_H_INCLUDED +#define JSON_VERSION_H_INCLUDED + +// Note: version must be updated in three places when doing a release. This +// annoying process ensures that amalgamate, CMake, and meson all report the +// correct version. +// 1. /meson.build +// 2. /include/json/version.h +// 3. /CMakeLists.txt +// IMPORTANT: also update the SOVERSION!! + +#define JSONCPP_VERSION_STRING "1.9.5" +#define JSONCPP_VERSION_MAJOR 1 +#define JSONCPP_VERSION_MINOR 9 +#define JSONCPP_VERSION_PATCH 5 +#define JSONCPP_VERSION_QUALIFIER +#define JSONCPP_VERSION_HEXA \ + ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \ + (JSONCPP_VERSION_PATCH << 8)) + +#ifdef JSONCPP_USING_SECURE_MEMORY +#undef JSONCPP_USING_SECURE_MEMORY +#endif +#define JSONCPP_USING_SECURE_MEMORY 0 +// If non-zero, the library zeroes any memory that it has allocated before +// it frees its memory. + +#endif // JSON_VERSION_H_INCLUDED diff --git a/thirdparty/openxr/src/external/jsoncpp/include/json/writer.h b/thirdparty/openxr/src/external/jsoncpp/include/json/writer.h new file mode 100644 index 0000000000..88a3b12e9d --- /dev/null +++ b/thirdparty/openxr/src/external/jsoncpp/include/json/writer.h @@ -0,0 +1,369 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_WRITER_H_INCLUDED +#define JSON_WRITER_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "value.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include <ostream> +#include <string> +#include <vector> + +// Disable warning C4251: <data member>: <type> needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) && defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#pragma pack(push, 8) + +namespace Json { + +class Value; + +/** + * + * Usage: + * \code + * using namespace Json; + * void writeToStdout(StreamWriter::Factory const& factory, Value const& value) + * { std::unique_ptr<StreamWriter> const writer( factory.newStreamWriter()); + * writer->write(value, &std::cout); + * std::cout << std::endl; // add lf and flush + * } + * \endcode + */ +class JSON_API StreamWriter { +protected: + OStream* sout_; // not owned; will not delete +public: + StreamWriter(); + virtual ~StreamWriter(); + /** Write Value into document as configured in sub-class. + * Do not take ownership of sout, but maintain a reference during function. + * \pre sout != NULL + * \return zero on success (For now, we always return zero, so check the + * stream instead.) \throw std::exception possibly, depending on + * configuration + */ + virtual int write(Value const& root, OStream* sout) = 0; + + /** \brief A simple abstract factory. + */ + class JSON_API Factory { + public: + virtual ~Factory(); + /** \brief Allocate a CharReader via operator new(). + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual StreamWriter* newStreamWriter() const = 0; + }; // Factory +}; // StreamWriter + +/** \brief Write into stringstream, then return string, for convenience. + * A StreamWriter will be created from the factory, used, and then deleted. + */ +String JSON_API writeString(StreamWriter::Factory const& factory, + Value const& root); + +/** \brief Build a StreamWriter implementation. + +* Usage: +* \code +* using namespace Json; +* Value value = ...; +* StreamWriterBuilder builder; +* builder["commentStyle"] = "None"; +* builder["indentation"] = " "; // or whatever you like +* std::unique_ptr<Json::StreamWriter> writer( +* builder.newStreamWriter()); +* writer->write(value, &std::cout); +* std::cout << std::endl; // add lf and flush +* \endcode +*/ +class JSON_API StreamWriterBuilder : public StreamWriter::Factory { +public: + // Note: We use a Json::Value so that we can add data-members to this class + // without a major version bump. + /** Configuration of this builder. + * Available settings (case-sensitive): + * - "commentStyle": "None" or "All" + * - "indentation": "<anything>". + * - Setting this to an empty string also omits newline characters. + * - "enableYAMLCompatibility": false or true + * - slightly change the whitespace around colons + * - "dropNullPlaceholders": false or true + * - Drop the "null" string from the writer's output for nullValues. + * Strictly speaking, this is not valid JSON. But when the output is being + * fed to a browser's JavaScript, it makes for smaller output and the + * browser can handle the output just fine. + * - "useSpecialFloats": false or true + * - If true, outputs non-finite floating point values in the following way: + * NaN values as "NaN", positive infinity as "Infinity", and negative + * infinity as "-Infinity". + * - "precision": int + * - Number of precision digits for formatting of real values. + * - "precisionType": "significant"(default) or "decimal" + * - Type of precision for formatting of real values. + * - "emitUTF8": false or true + * - If true, outputs raw UTF8 strings instead of escaping them. + + * You can examine 'settings_` yourself + * to see the defaults. You can also write and read them just like any + * JSON Value. + * \sa setDefaults() + */ + Json::Value settings_; + + StreamWriterBuilder(); + ~StreamWriterBuilder() override; + + /** + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + StreamWriter* newStreamWriter() const override; + + /** \return true if 'settings' are legal and consistent; + * otherwise, indicate bad settings via 'invalid'. + */ + bool validate(Json::Value* invalid) const; + /** A simple way to update a specific setting. + */ + Value& operator[](const String& key); + + /** Called by ctor, but you can use this to reset settings_. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults + */ + static void setDefaults(Json::Value* settings); +}; + +/** \brief Abstract class for writers. + * \deprecated Use StreamWriter. (And really, this is an implementation detail.) + */ +class JSON_API Writer { +public: + virtual ~Writer(); + + virtual String write(const Value& root) = 0; +}; + +/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format + *without formatting (not human friendly). + * + * The JSON document is written in a single line. It is not intended for 'human' + *consumption, + * but may be useful to support feature such as RPC where bandwidth is limited. + * \sa Reader, Value + * \deprecated Use StreamWriterBuilder. + */ +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4996) // Deriving from deprecated class +#endif +class JSON_API FastWriter + : public Writer { +public: + FastWriter(); + ~FastWriter() override = default; + + void enableYAMLCompatibility(); + + /** \brief Drop the "null" string from the writer's output for nullValues. + * Strictly speaking, this is not valid JSON. But when the output is being + * fed to a browser's JavaScript, it makes for smaller output and the + * browser can handle the output just fine. + */ + void dropNullPlaceholders(); + + void omitEndingLineFeed(); + +public: // overridden from Writer + String write(const Value& root) override; + +private: + void writeValue(const Value& value); + + String document_; + bool yamlCompatibilityEnabled_{false}; + bool dropNullPlaceholders_{false}; + bool omitEndingLineFeed_{false}; +}; +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a + *human friendly way. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per + *line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value + *types, + * and all the values fit on one lines, then print the array on a single + *line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their + *#CommentPlacement. + * + * \sa Reader, Value, Value::setComment() + * \deprecated Use StreamWriterBuilder. + */ +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4996) // Deriving from deprecated class +#endif +class JSON_API + StyledWriter : public Writer { +public: + StyledWriter(); + ~StyledWriter() override = default; + +public: // overridden from Writer + /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format. + * \param root Value to serialize. + * \return String containing the JSON document that represents the root value. + */ + String write(const Value& root) override; + +private: + void writeValue(const Value& value); + void writeArrayValue(const Value& value); + bool isMultilineArray(const Value& value); + void pushValue(const String& value); + void writeIndent(); + void writeWithIndent(const String& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(const Value& root); + void writeCommentAfterValueOnSameLine(const Value& root); + static bool hasCommentForValue(const Value& value); + static String normalizeEOL(const String& text); + + using ChildValues = std::vector<String>; + + ChildValues childValues_; + String document_; + String indentString_; + unsigned int rightMargin_{74}; + unsigned int indentSize_{3}; + bool addChildValues_{false}; +}; +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a + human friendly way, + to a stream rather than to a string. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per + line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value + types, + * and all the values fit on one lines, then print the array on a single + line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their + #CommentPlacement. + * + * \sa Reader, Value, Value::setComment() + * \deprecated Use StreamWriterBuilder. + */ +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4996) // Deriving from deprecated class +#endif +class JSON_API + StyledStreamWriter { +public: + /** + * \param indentation Each level will be indented by this amount extra. + */ + StyledStreamWriter(String indentation = "\t"); + ~StyledStreamWriter() = default; + +public: + /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format. + * \param out Stream to write to. (Can be ostringstream, e.g.) + * \param root Value to serialize. + * \note There is no point in deriving from Writer, since write() should not + * return a value. + */ + void write(OStream& out, const Value& root); + +private: + void writeValue(const Value& value); + void writeArrayValue(const Value& value); + bool isMultilineArray(const Value& value); + void pushValue(const String& value); + void writeIndent(); + void writeWithIndent(const String& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(const Value& root); + void writeCommentAfterValueOnSameLine(const Value& root); + static bool hasCommentForValue(const Value& value); + static String normalizeEOL(const String& text); + + using ChildValues = std::vector<String>; + + ChildValues childValues_; + OStream* document_; + String indentString_; + unsigned int rightMargin_{74}; + String indentation_; + bool addChildValues_ : 1; + bool indented_ : 1; +}; +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#if defined(JSON_HAS_INT64) +String JSON_API valueToString(Int value); +String JSON_API valueToString(UInt value); +#endif // if defined(JSON_HAS_INT64) +String JSON_API valueToString(LargestInt value); +String JSON_API valueToString(LargestUInt value); +String JSON_API valueToString( + double value, unsigned int precision = Value::defaultRealPrecision, + PrecisionType precisionType = PrecisionType::significantDigits); +String JSON_API valueToString(bool value); +String JSON_API valueToQuotedString(const char* value); + +/// \brief Output using the StyledStreamWriter. +/// \see Json::operator>>() +JSON_API OStream& operator<<(OStream&, const Value& root); + +} // namespace Json + +#pragma pack(pop) + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // JSON_WRITER_H_INCLUDED diff --git a/thirdparty/openxr/src/external/jsoncpp/src/lib_json/json_reader.cpp b/thirdparty/openxr/src/external/jsoncpp/src/lib_json/json_reader.cpp new file mode 100644 index 0000000000..a6a3f4e30d --- /dev/null +++ b/thirdparty/openxr/src/external/jsoncpp/src/lib_json/json_reader.cpp @@ -0,0 +1,1992 @@ +// Copyright 2007-2011 Baptiste Lepilleur and The JsonCpp Authors +// Copyright (C) 2016 InfoTeCS JSC. All rights reserved. +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +#include "json_tool.h" +#include <json/assertions.h> +#include <json/reader.h> +#include <json/value.h> +#endif // if !defined(JSON_IS_AMALGAMATION) +#include <algorithm> +#include <cassert> +#include <cstring> +#include <iostream> +#include <istream> +#include <limits> +#include <memory> +#include <set> +#include <sstream> +#include <utility> + +#include <cstdio> +#if __cplusplus >= 201103L + +#if !defined(sscanf) +#define sscanf std::sscanf +#endif + +#endif //__cplusplus + +#if defined(_MSC_VER) +#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES) +#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 +#endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES +#endif //_MSC_VER + +#if defined(_MSC_VER) +// Disable warning about strdup being deprecated. +#pragma warning(disable : 4996) +#endif + +// Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile +// time to change the stack limit +#if !defined(JSONCPP_DEPRECATED_STACK_LIMIT) +#define JSONCPP_DEPRECATED_STACK_LIMIT 1000 +#endif + +static size_t const stackLimit_g = + JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue() + +namespace Json { + +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) +using CharReaderPtr = std::unique_ptr<CharReader>; +#else +using CharReaderPtr = std::auto_ptr<CharReader>; +#endif + +// Implementation of class Features +// //////////////////////////////// + +Features::Features() = default; + +Features Features::all() { return {}; } + +Features Features::strictMode() { + Features features; + features.allowComments_ = false; + features.strictRoot_ = true; + features.allowDroppedNullPlaceholders_ = false; + features.allowNumericKeys_ = false; + return features; +} + +// Implementation of class Reader +// //////////////////////////////// + +bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) { + return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; }); +} + +// Class Reader +// ////////////////////////////////////////////////////////////////// + +Reader::Reader() : features_(Features::all()) {} + +Reader::Reader(const Features& features) : features_(features) {} + +bool Reader::parse(const std::string& document, Value& root, + bool collectComments) { + document_.assign(document.begin(), document.end()); + const char* begin = document_.c_str(); + const char* end = begin + document_.length(); + return parse(begin, end, root, collectComments); +} + +bool Reader::parse(std::istream& is, Value& root, bool collectComments) { + // std::istream_iterator<char> begin(is); + // std::istream_iterator<char> end; + // Those would allow streamed input from a file, if parse() were a + // template function. + + // Since String is reference-counted, this at least does not + // create an extra copy. + String doc(std::istreambuf_iterator<char>(is), {}); + return parse(doc.data(), doc.data() + doc.size(), root, collectComments); +} + +bool Reader::parse(const char* beginDoc, const char* endDoc, Value& root, + bool collectComments) { + if (!features_.allowComments_) { + collectComments = false; + } + + begin_ = beginDoc; + end_ = endDoc; + collectComments_ = collectComments; + current_ = begin_; + lastValueEnd_ = nullptr; + lastValue_ = nullptr; + commentsBefore_.clear(); + errors_.clear(); + while (!nodes_.empty()) + nodes_.pop(); + nodes_.push(&root); + + bool successful = readValue(); + Token token; + skipCommentTokens(token); + if (collectComments_ && !commentsBefore_.empty()) + root.setComment(commentsBefore_, commentAfter); + if (features_.strictRoot_) { + if (!root.isArray() && !root.isObject()) { + // Set error location to start of doc, ideally should be first token found + // in doc + token.type_ = tokenError; + token.start_ = beginDoc; + token.end_ = endDoc; + addError( + "A valid JSON document must be either an array or an object value.", + token); + return false; + } + } + return successful; +} + +bool Reader::readValue() { + // readValue() may call itself only if it calls readObject() or ReadArray(). + // These methods execute nodes_.push() just before and nodes_.pop)() just + // after calling readValue(). parse() executes one nodes_.push(), so > instead + // of >=. + if (nodes_.size() > stackLimit_g) + throwRuntimeError("Exceeded stackLimit in readValue()."); + + Token token; + skipCommentTokens(token); + bool successful = true; + + if (collectComments_ && !commentsBefore_.empty()) { + currentValue().setComment(commentsBefore_, commentBefore); + commentsBefore_.clear(); + } + + switch (token.type_) { + case tokenObjectBegin: + successful = readObject(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenArrayBegin: + successful = readArray(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenNumber: + successful = decodeNumber(token); + break; + case tokenString: + successful = decodeString(token); + break; + case tokenTrue: { + Value v(true); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenFalse: { + Value v(false); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenNull: { + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenArraySeparator: + case tokenObjectEnd: + case tokenArrayEnd: + if (features_.allowDroppedNullPlaceholders_) { + // "Un-read" the current token and mark the current value as a null + // token. + current_--; + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(current_ - begin_ - 1); + currentValue().setOffsetLimit(current_ - begin_); + break; + } // Else, fall through... + default: + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return addError("Syntax error: value, object or array expected.", token); + } + + if (collectComments_) { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + + return successful; +} + +void Reader::skipCommentTokens(Token& token) { + if (features_.allowComments_) { + do { + readToken(token); + } while (token.type_ == tokenComment); + } else { + readToken(token); + } +} + +bool Reader::readToken(Token& token) { + skipSpaces(); + token.start_ = current_; + Char c = getNextChar(); + bool ok = true; + switch (c) { + case '{': + token.type_ = tokenObjectBegin; + break; + case '}': + token.type_ = tokenObjectEnd; + break; + case '[': + token.type_ = tokenArrayBegin; + break; + case ']': + token.type_ = tokenArrayEnd; + break; + case '"': + token.type_ = tokenString; + ok = readString(); + break; + case '/': + token.type_ = tokenComment; + ok = readComment(); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + token.type_ = tokenNumber; + readNumber(); + break; + case 't': + token.type_ = tokenTrue; + ok = match("rue", 3); + break; + case 'f': + token.type_ = tokenFalse; + ok = match("alse", 4); + break; + case 'n': + token.type_ = tokenNull; + ok = match("ull", 3); + break; + case ',': + token.type_ = tokenArraySeparator; + break; + case ':': + token.type_ = tokenMemberSeparator; + break; + case 0: + token.type_ = tokenEndOfStream; + break; + default: + ok = false; + break; + } + if (!ok) + token.type_ = tokenError; + token.end_ = current_; + return ok; +} + +void Reader::skipSpaces() { + while (current_ != end_) { + Char c = *current_; + if (c == ' ' || c == '\t' || c == '\r' || c == '\n') + ++current_; + else + break; + } +} + +bool Reader::match(const Char* pattern, int patternLength) { + if (end_ - current_ < patternLength) + return false; + int index = patternLength; + while (index--) + if (current_[index] != pattern[index]) + return false; + current_ += patternLength; + return true; +} + +bool Reader::readComment() { + Location commentBegin = current_ - 1; + Char c = getNextChar(); + bool successful = false; + if (c == '*') + successful = readCStyleComment(); + else if (c == '/') + successful = readCppStyleComment(); + if (!successful) + return false; + + if (collectComments_) { + CommentPlacement placement = commentBefore; + if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { + if (c != '*' || !containsNewLine(commentBegin, current_)) + placement = commentAfterOnSameLine; + } + + addComment(commentBegin, current_, placement); + } + return true; +} + +String Reader::normalizeEOL(Reader::Location begin, Reader::Location end) { + String normalized; + normalized.reserve(static_cast<size_t>(end - begin)); + Reader::Location current = begin; + while (current != end) { + char c = *current++; + if (c == '\r') { + if (current != end && *current == '\n') + // convert dos EOL + ++current; + // convert Mac EOL + normalized += '\n'; + } else { + normalized += c; + } + } + return normalized; +} + +void Reader::addComment(Location begin, Location end, + CommentPlacement placement) { + assert(collectComments_); + const String& normalized = normalizeEOL(begin, end); + if (placement == commentAfterOnSameLine) { + assert(lastValue_ != nullptr); + lastValue_->setComment(normalized, placement); + } else { + commentsBefore_ += normalized; + } +} + +bool Reader::readCStyleComment() { + while ((current_ + 1) < end_) { + Char c = getNextChar(); + if (c == '*' && *current_ == '/') + break; + } + return getNextChar() == '/'; +} + +bool Reader::readCppStyleComment() { + while (current_ != end_) { + Char c = getNextChar(); + if (c == '\n') + break; + if (c == '\r') { + // Consume DOS EOL. It will be normalized in addComment. + if (current_ != end_ && *current_ == '\n') + getNextChar(); + // Break on Moc OS 9 EOL. + break; + } + } + return true; +} + +void Reader::readNumber() { + Location p = current_; + char c = '0'; // stopgap for already consumed character + // integral part + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + // fractional part + if (c == '.') { + c = (current_ = p) < end_ ? *p++ : '\0'; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + } + // exponential part + if (c == 'e' || c == 'E') { + c = (current_ = p) < end_ ? *p++ : '\0'; + if (c == '+' || c == '-') + c = (current_ = p) < end_ ? *p++ : '\0'; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + } +} + +bool Reader::readString() { + Char c = '\0'; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '"') + break; + } + return c == '"'; +} + +bool Reader::readObject(Token& token) { + Token tokenName; + String name; + Value init(objectValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(token.start_ - begin_); + while (readToken(tokenName)) { + bool initialTokenOk = true; + while (tokenName.type_ == tokenComment && initialTokenOk) + initialTokenOk = readToken(tokenName); + if (!initialTokenOk) + break; + if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object + return true; + name.clear(); + if (tokenName.type_ == tokenString) { + if (!decodeString(tokenName, name)) + return recoverFromError(tokenObjectEnd); + } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { + Value numberName; + if (!decodeNumber(tokenName, numberName)) + return recoverFromError(tokenObjectEnd); + name = numberName.asString(); + } else { + break; + } + + Token colon; + if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { + return addErrorAndRecover("Missing ':' after object member name", colon, + tokenObjectEnd); + } + Value& value = currentValue()[name]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenObjectEnd); + + Token comma; + if (!readToken(comma) || + (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && + comma.type_ != tokenComment)) { + return addErrorAndRecover("Missing ',' or '}' in object declaration", + comma, tokenObjectEnd); + } + bool finalizeTokenOk = true; + while (comma.type_ == tokenComment && finalizeTokenOk) + finalizeTokenOk = readToken(comma); + if (comma.type_ == tokenObjectEnd) + return true; + } + return addErrorAndRecover("Missing '}' or object member name", tokenName, + tokenObjectEnd); +} + +bool Reader::readArray(Token& token) { + Value init(arrayValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(token.start_ - begin_); + skipSpaces(); + if (current_ != end_ && *current_ == ']') // empty array + { + Token endArray; + readToken(endArray); + return true; + } + int index = 0; + for (;;) { + Value& value = currentValue()[index++]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenArrayEnd); + + Token currentToken; + // Accept Comment after last item in the array. + ok = readToken(currentToken); + while (currentToken.type_ == tokenComment && ok) { + ok = readToken(currentToken); + } + bool badTokenType = (currentToken.type_ != tokenArraySeparator && + currentToken.type_ != tokenArrayEnd); + if (!ok || badTokenType) { + return addErrorAndRecover("Missing ',' or ']' in array declaration", + currentToken, tokenArrayEnd); + } + if (currentToken.type_ == tokenArrayEnd) + break; + } + return true; +} + +bool Reader::decodeNumber(Token& token) { + Value decoded; + if (!decodeNumber(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool Reader::decodeNumber(Token& token, Value& decoded) { + // Attempts to parse the number as an integer. If the number is + // larger than the maximum supported value of an integer then + // we decode the number as a double. + Location current = token.start_; + bool isNegative = *current == '-'; + if (isNegative) + ++current; + // TODO: Help the compiler do the div and mod at compile time or get rid of + // them. + Value::LargestUInt maxIntegerValue = + isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1 + : Value::maxLargestUInt; + Value::LargestUInt threshold = maxIntegerValue / 10; + Value::LargestUInt value = 0; + while (current < token.end_) { + Char c = *current++; + if (c < '0' || c > '9') + return decodeDouble(token, decoded); + auto digit(static_cast<Value::UInt>(c - '0')); + if (value >= threshold) { + // We've hit or exceeded the max value divided by 10 (rounded down). If + // a) we've only just touched the limit, b) this is the last digit, and + // c) it's small enough to fit in that rounding delta, we're okay. + // Otherwise treat this number as a double to avoid overflow. + if (value > threshold || current != token.end_ || + digit > maxIntegerValue % 10) { + return decodeDouble(token, decoded); + } + } + value = value * 10 + digit; + } + if (isNegative && value == maxIntegerValue) + decoded = Value::minLargestInt; + else if (isNegative) + decoded = -Value::LargestInt(value); + else if (value <= Value::LargestUInt(Value::maxInt)) + decoded = Value::LargestInt(value); + else + decoded = value; + return true; +} + +bool Reader::decodeDouble(Token& token) { + Value decoded; + if (!decodeDouble(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool Reader::decodeDouble(Token& token, Value& decoded) { + double value = 0; + String buffer(token.start_, token.end_); + IStringStream is(buffer); + if (!(is >> value)) + return addError( + "'" + String(token.start_, token.end_) + "' is not a number.", token); + decoded = value; + return true; +} + +bool Reader::decodeString(Token& token) { + String decoded_string; + if (!decodeString(token, decoded_string)) + return false; + Value decoded(decoded_string); + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool Reader::decodeString(Token& token, String& decoded) { + decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2)); + Location current = token.start_ + 1; // skip '"' + Location end = token.end_ - 1; // do not include '"' + while (current != end) { + Char c = *current++; + if (c == '"') + break; + if (c == '\\') { + if (current == end) + return addError("Empty escape sequence in string", token, current); + Char escape = *current++; + switch (escape) { + case '"': + decoded += '"'; + break; + case '/': + decoded += '/'; + break; + case '\\': + decoded += '\\'; + break; + case 'b': + decoded += '\b'; + break; + case 'f': + decoded += '\f'; + break; + case 'n': + decoded += '\n'; + break; + case 'r': + decoded += '\r'; + break; + case 't': + decoded += '\t'; + break; + case 'u': { + unsigned int unicode; + if (!decodeUnicodeCodePoint(token, current, end, unicode)) + return false; + decoded += codePointToUTF8(unicode); + } break; + default: + return addError("Bad escape sequence in string", token, current); + } + } else { + decoded += c; + } + } + return true; +} + +bool Reader::decodeUnicodeCodePoint(Token& token, Location& current, + Location end, unsigned int& unicode) { + + if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) + return false; + if (unicode >= 0xD800 && unicode <= 0xDBFF) { + // surrogate pairs + if (end - current < 6) + return addError( + "additional six characters expected to parse unicode surrogate pair.", + token, current); + if (*(current++) == '\\' && *(current++) == 'u') { + unsigned int surrogatePair; + if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { + unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); + } else + return false; + } else + return addError("expecting another \\u token to begin the second half of " + "a unicode surrogate pair", + token, current); + } + return true; +} + +bool Reader::decodeUnicodeEscapeSequence(Token& token, Location& current, + Location end, + unsigned int& ret_unicode) { + if (end - current < 4) + return addError( + "Bad unicode escape sequence in string: four digits expected.", token, + current); + int unicode = 0; + for (int index = 0; index < 4; ++index) { + Char c = *current++; + unicode *= 16; + if (c >= '0' && c <= '9') + unicode += c - '0'; + else if (c >= 'a' && c <= 'f') + unicode += c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + unicode += c - 'A' + 10; + else + return addError( + "Bad unicode escape sequence in string: hexadecimal digit expected.", + token, current); + } + ret_unicode = static_cast<unsigned int>(unicode); + return true; +} + +bool Reader::addError(const String& message, Token& token, Location extra) { + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = extra; + errors_.push_back(info); + return false; +} + +bool Reader::recoverFromError(TokenType skipUntilToken) { + size_t const errorCount = errors_.size(); + Token skip; + for (;;) { + if (!readToken(skip)) + errors_.resize(errorCount); // discard errors caused by recovery + if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) + break; + } + errors_.resize(errorCount); + return false; +} + +bool Reader::addErrorAndRecover(const String& message, Token& token, + TokenType skipUntilToken) { + addError(message, token); + return recoverFromError(skipUntilToken); +} + +Value& Reader::currentValue() { return *(nodes_.top()); } + +Reader::Char Reader::getNextChar() { + if (current_ == end_) + return 0; + return *current_++; +} + +void Reader::getLocationLineAndColumn(Location location, int& line, + int& column) const { + Location current = begin_; + Location lastLineStart = current; + line = 0; + while (current < location && current != end_) { + Char c = *current++; + if (c == '\r') { + if (*current == '\n') + ++current; + lastLineStart = current; + ++line; + } else if (c == '\n') { + lastLineStart = current; + ++line; + } + } + // column & line start at 1 + column = int(location - lastLineStart) + 1; + ++line; +} + +String Reader::getLocationLineAndColumn(Location location) const { + int line, column; + getLocationLineAndColumn(location, line, column); + char buffer[18 + 16 + 16 + 1]; + jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); + return buffer; +} + +// Deprecated. Preserved for backward compatibility +String Reader::getFormatedErrorMessages() const { + return getFormattedErrorMessages(); +} + +String Reader::getFormattedErrorMessages() const { + String formattedMessage; + for (const auto& error : errors_) { + formattedMessage += + "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; + formattedMessage += " " + error.message_ + "\n"; + if (error.extra_) + formattedMessage += + "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; + } + return formattedMessage; +} + +std::vector<Reader::StructuredError> Reader::getStructuredErrors() const { + std::vector<Reader::StructuredError> allErrors; + for (const auto& error : errors_) { + Reader::StructuredError structured; + structured.offset_start = error.token_.start_ - begin_; + structured.offset_limit = error.token_.end_ - begin_; + structured.message = error.message_; + allErrors.push_back(structured); + } + return allErrors; +} + +bool Reader::pushError(const Value& value, const String& message) { + ptrdiff_t const length = end_ - begin_; + if (value.getOffsetStart() > length || value.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = begin_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = nullptr; + errors_.push_back(info); + return true; +} + +bool Reader::pushError(const Value& value, const String& message, + const Value& extra) { + ptrdiff_t const length = end_ - begin_; + if (value.getOffsetStart() > length || value.getOffsetLimit() > length || + extra.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = begin_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = begin_ + extra.getOffsetStart(); + errors_.push_back(info); + return true; +} + +bool Reader::good() const { return errors_.empty(); } + +// Originally copied from the Features class (now deprecated), used internally +// for features implementation. +class OurFeatures { +public: + static OurFeatures all(); + bool allowComments_; + bool allowTrailingCommas_; + bool strictRoot_; + bool allowDroppedNullPlaceholders_; + bool allowNumericKeys_; + bool allowSingleQuotes_; + bool failIfExtra_; + bool rejectDupKeys_; + bool allowSpecialFloats_; + bool skipBom_; + size_t stackLimit_; +}; // OurFeatures + +OurFeatures OurFeatures::all() { return {}; } + +// Implementation of class Reader +// //////////////////////////////// + +// Originally copied from the Reader class (now deprecated), used internally +// for implementing JSON reading. +class OurReader { +public: + using Char = char; + using Location = const Char*; + struct StructuredError { + ptrdiff_t offset_start; + ptrdiff_t offset_limit; + String message; + }; + + explicit OurReader(OurFeatures const& features); + bool parse(const char* beginDoc, const char* endDoc, Value& root, + bool collectComments = true); + String getFormattedErrorMessages() const; + std::vector<StructuredError> getStructuredErrors() const; + +private: + OurReader(OurReader const&); // no impl + void operator=(OurReader const&); // no impl + + enum TokenType { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenNaN, + tokenPosInf, + tokenNegInf, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token { + public: + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo { + public: + Token token_; + String message_; + Location extra_; + }; + + using Errors = std::deque<ErrorInfo>; + + bool readToken(Token& token); + void skipSpaces(); + void skipBom(bool skipBom); + bool match(const Char* pattern, int patternLength); + bool readComment(); + bool readCStyleComment(bool* containsNewLineResult); + bool readCppStyleComment(); + bool readString(); + bool readStringSingleQuote(); + bool readNumber(bool checkInf); + bool readValue(); + bool readObject(Token& token); + bool readArray(Token& token); + bool decodeNumber(Token& token); + bool decodeNumber(Token& token, Value& decoded); + bool decodeString(Token& token); + bool decodeString(Token& token, String& decoded); + bool decodeDouble(Token& token); + bool decodeDouble(Token& token, Value& decoded); + bool decodeUnicodeCodePoint(Token& token, Location& current, Location end, + unsigned int& unicode); + bool decodeUnicodeEscapeSequence(Token& token, Location& current, + Location end, unsigned int& unicode); + bool addError(const String& message, Token& token, Location extra = nullptr); + bool recoverFromError(TokenType skipUntilToken); + bool addErrorAndRecover(const String& message, Token& token, + TokenType skipUntilToken); + void skipUntilSpace(); + Value& currentValue(); + Char getNextChar(); + void getLocationLineAndColumn(Location location, int& line, + int& column) const; + String getLocationLineAndColumn(Location location) const; + void addComment(Location begin, Location end, CommentPlacement placement); + void skipCommentTokens(Token& token); + + static String normalizeEOL(Location begin, Location end); + static bool containsNewLine(Location begin, Location end); + + using Nodes = std::stack<Value*>; + + Nodes nodes_{}; + Errors errors_{}; + String document_{}; + Location begin_ = nullptr; + Location end_ = nullptr; + Location current_ = nullptr; + Location lastValueEnd_ = nullptr; + Value* lastValue_ = nullptr; + bool lastValueHasAComment_ = false; + String commentsBefore_{}; + + OurFeatures const features_; + bool collectComments_ = false; +}; // OurReader + +// complete copy of Read impl, for OurReader + +bool OurReader::containsNewLine(OurReader::Location begin, + OurReader::Location end) { + return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; }); +} + +OurReader::OurReader(OurFeatures const& features) : features_(features) {} + +bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root, + bool collectComments) { + if (!features_.allowComments_) { + collectComments = false; + } + + begin_ = beginDoc; + end_ = endDoc; + collectComments_ = collectComments; + current_ = begin_; + lastValueEnd_ = nullptr; + lastValue_ = nullptr; + commentsBefore_.clear(); + errors_.clear(); + while (!nodes_.empty()) + nodes_.pop(); + nodes_.push(&root); + + // skip byte order mark if it exists at the beginning of the UTF-8 text. + skipBom(features_.skipBom_); + bool successful = readValue(); + nodes_.pop(); + Token token; + skipCommentTokens(token); + if (features_.failIfExtra_ && (token.type_ != tokenEndOfStream)) { + addError("Extra non-whitespace after JSON value.", token); + return false; + } + if (collectComments_ && !commentsBefore_.empty()) + root.setComment(commentsBefore_, commentAfter); + if (features_.strictRoot_) { + if (!root.isArray() && !root.isObject()) { + // Set error location to start of doc, ideally should be first token found + // in doc + token.type_ = tokenError; + token.start_ = beginDoc; + token.end_ = endDoc; + addError( + "A valid JSON document must be either an array or an object value.", + token); + return false; + } + } + return successful; +} + +bool OurReader::readValue() { + // To preserve the old behaviour we cast size_t to int. + if (nodes_.size() > features_.stackLimit_) + throwRuntimeError("Exceeded stackLimit in readValue()."); + Token token; + skipCommentTokens(token); + bool successful = true; + + if (collectComments_ && !commentsBefore_.empty()) { + currentValue().setComment(commentsBefore_, commentBefore); + commentsBefore_.clear(); + } + + switch (token.type_) { + case tokenObjectBegin: + successful = readObject(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenArrayBegin: + successful = readArray(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenNumber: + successful = decodeNumber(token); + break; + case tokenString: + successful = decodeString(token); + break; + case tokenTrue: { + Value v(true); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenFalse: { + Value v(false); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenNull: { + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenNaN: { + Value v(std::numeric_limits<double>::quiet_NaN()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenPosInf: { + Value v(std::numeric_limits<double>::infinity()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenNegInf: { + Value v(-std::numeric_limits<double>::infinity()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenArraySeparator: + case tokenObjectEnd: + case tokenArrayEnd: + if (features_.allowDroppedNullPlaceholders_) { + // "Un-read" the current token and mark the current value as a null + // token. + current_--; + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(current_ - begin_ - 1); + currentValue().setOffsetLimit(current_ - begin_); + break; + } // else, fall through ... + default: + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return addError("Syntax error: value, object or array expected.", token); + } + + if (collectComments_) { + lastValueEnd_ = current_; + lastValueHasAComment_ = false; + lastValue_ = ¤tValue(); + } + + return successful; +} + +void OurReader::skipCommentTokens(Token& token) { + if (features_.allowComments_) { + do { + readToken(token); + } while (token.type_ == tokenComment); + } else { + readToken(token); + } +} + +bool OurReader::readToken(Token& token) { + skipSpaces(); + token.start_ = current_; + Char c = getNextChar(); + bool ok = true; + switch (c) { + case '{': + token.type_ = tokenObjectBegin; + break; + case '}': + token.type_ = tokenObjectEnd; + break; + case '[': + token.type_ = tokenArrayBegin; + break; + case ']': + token.type_ = tokenArrayEnd; + break; + case '"': + token.type_ = tokenString; + ok = readString(); + break; + case '\'': + if (features_.allowSingleQuotes_) { + token.type_ = tokenString; + ok = readStringSingleQuote(); + } else { + // If we don't allow single quotes, this is a failure case. + ok = false; + } + break; + case '/': + token.type_ = tokenComment; + ok = readComment(); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + token.type_ = tokenNumber; + readNumber(false); + break; + case '-': + if (readNumber(true)) { + token.type_ = tokenNumber; + } else { + token.type_ = tokenNegInf; + ok = features_.allowSpecialFloats_ && match("nfinity", 7); + } + break; + case '+': + if (readNumber(true)) { + token.type_ = tokenNumber; + } else { + token.type_ = tokenPosInf; + ok = features_.allowSpecialFloats_ && match("nfinity", 7); + } + break; + case 't': + token.type_ = tokenTrue; + ok = match("rue", 3); + break; + case 'f': + token.type_ = tokenFalse; + ok = match("alse", 4); + break; + case 'n': + token.type_ = tokenNull; + ok = match("ull", 3); + break; + case 'N': + if (features_.allowSpecialFloats_) { + token.type_ = tokenNaN; + ok = match("aN", 2); + } else { + ok = false; + } + break; + case 'I': + if (features_.allowSpecialFloats_) { + token.type_ = tokenPosInf; + ok = match("nfinity", 7); + } else { + ok = false; + } + break; + case ',': + token.type_ = tokenArraySeparator; + break; + case ':': + token.type_ = tokenMemberSeparator; + break; + case 0: + token.type_ = tokenEndOfStream; + break; + default: + ok = false; + break; + } + if (!ok) + token.type_ = tokenError; + token.end_ = current_; + return ok; +} + +void OurReader::skipSpaces() { + while (current_ != end_) { + Char c = *current_; + if (c == ' ' || c == '\t' || c == '\r' || c == '\n') + ++current_; + else + break; + } +} + +void OurReader::skipBom(bool skipBom) { + // The default behavior is to skip BOM. + if (skipBom) { + if ((end_ - begin_) >= 3 && strncmp(begin_, "\xEF\xBB\xBF", 3) == 0) { + begin_ += 3; + current_ = begin_; + } + } +} + +bool OurReader::match(const Char* pattern, int patternLength) { + if (end_ - current_ < patternLength) + return false; + int index = patternLength; + while (index--) + if (current_[index] != pattern[index]) + return false; + current_ += patternLength; + return true; +} + +bool OurReader::readComment() { + const Location commentBegin = current_ - 1; + const Char c = getNextChar(); + bool successful = false; + bool cStyleWithEmbeddedNewline = false; + + const bool isCStyleComment = (c == '*'); + const bool isCppStyleComment = (c == '/'); + if (isCStyleComment) { + successful = readCStyleComment(&cStyleWithEmbeddedNewline); + } else if (isCppStyleComment) { + successful = readCppStyleComment(); + } + + if (!successful) + return false; + + if (collectComments_) { + CommentPlacement placement = commentBefore; + + if (!lastValueHasAComment_) { + if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { + if (isCppStyleComment || !cStyleWithEmbeddedNewline) { + placement = commentAfterOnSameLine; + lastValueHasAComment_ = true; + } + } + } + + addComment(commentBegin, current_, placement); + } + return true; +} + +String OurReader::normalizeEOL(OurReader::Location begin, + OurReader::Location end) { + String normalized; + normalized.reserve(static_cast<size_t>(end - begin)); + OurReader::Location current = begin; + while (current != end) { + char c = *current++; + if (c == '\r') { + if (current != end && *current == '\n') + // convert dos EOL + ++current; + // convert Mac EOL + normalized += '\n'; + } else { + normalized += c; + } + } + return normalized; +} + +void OurReader::addComment(Location begin, Location end, + CommentPlacement placement) { + assert(collectComments_); + const String& normalized = normalizeEOL(begin, end); + if (placement == commentAfterOnSameLine) { + assert(lastValue_ != nullptr); + lastValue_->setComment(normalized, placement); + } else { + commentsBefore_ += normalized; + } +} + +bool OurReader::readCStyleComment(bool* containsNewLineResult) { + *containsNewLineResult = false; + + while ((current_ + 1) < end_) { + Char c = getNextChar(); + if (c == '*' && *current_ == '/') + break; + if (c == '\n') + *containsNewLineResult = true; + } + + return getNextChar() == '/'; +} + +bool OurReader::readCppStyleComment() { + while (current_ != end_) { + Char c = getNextChar(); + if (c == '\n') + break; + if (c == '\r') { + // Consume DOS EOL. It will be normalized in addComment. + if (current_ != end_ && *current_ == '\n') + getNextChar(); + // Break on Moc OS 9 EOL. + break; + } + } + return true; +} + +bool OurReader::readNumber(bool checkInf) { + Location p = current_; + if (checkInf && p != end_ && *p == 'I') { + current_ = ++p; + return false; + } + char c = '0'; // stopgap for already consumed character + // integral part + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + // fractional part + if (c == '.') { + c = (current_ = p) < end_ ? *p++ : '\0'; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + } + // exponential part + if (c == 'e' || c == 'E') { + c = (current_ = p) < end_ ? *p++ : '\0'; + if (c == '+' || c == '-') + c = (current_ = p) < end_ ? *p++ : '\0'; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + } + return true; +} +bool OurReader::readString() { + Char c = 0; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '"') + break; + } + return c == '"'; +} + +bool OurReader::readStringSingleQuote() { + Char c = 0; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '\'') + break; + } + return c == '\''; +} + +bool OurReader::readObject(Token& token) { + Token tokenName; + String name; + Value init(objectValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(token.start_ - begin_); + while (readToken(tokenName)) { + bool initialTokenOk = true; + while (tokenName.type_ == tokenComment && initialTokenOk) + initialTokenOk = readToken(tokenName); + if (!initialTokenOk) + break; + if (tokenName.type_ == tokenObjectEnd && + (name.empty() || + features_.allowTrailingCommas_)) // empty object or trailing comma + return true; + name.clear(); + if (tokenName.type_ == tokenString) { + if (!decodeString(tokenName, name)) + return recoverFromError(tokenObjectEnd); + } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { + Value numberName; + if (!decodeNumber(tokenName, numberName)) + return recoverFromError(tokenObjectEnd); + name = numberName.asString(); + } else { + break; + } + if (name.length() >= (1U << 30)) + throwRuntimeError("keylength >= 2^30"); + if (features_.rejectDupKeys_ && currentValue().isMember(name)) { + String msg = "Duplicate key: '" + name + "'"; + return addErrorAndRecover(msg, tokenName, tokenObjectEnd); + } + + Token colon; + if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { + return addErrorAndRecover("Missing ':' after object member name", colon, + tokenObjectEnd); + } + Value& value = currentValue()[name]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenObjectEnd); + + Token comma; + if (!readToken(comma) || + (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && + comma.type_ != tokenComment)) { + return addErrorAndRecover("Missing ',' or '}' in object declaration", + comma, tokenObjectEnd); + } + bool finalizeTokenOk = true; + while (comma.type_ == tokenComment && finalizeTokenOk) + finalizeTokenOk = readToken(comma); + if (comma.type_ == tokenObjectEnd) + return true; + } + return addErrorAndRecover("Missing '}' or object member name", tokenName, + tokenObjectEnd); +} + +bool OurReader::readArray(Token& token) { + Value init(arrayValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(token.start_ - begin_); + int index = 0; + for (;;) { + skipSpaces(); + if (current_ != end_ && *current_ == ']' && + (index == 0 || + (features_.allowTrailingCommas_ && + !features_.allowDroppedNullPlaceholders_))) // empty array or trailing + // comma + { + Token endArray; + readToken(endArray); + return true; + } + Value& value = currentValue()[index++]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenArrayEnd); + + Token currentToken; + // Accept Comment after last item in the array. + ok = readToken(currentToken); + while (currentToken.type_ == tokenComment && ok) { + ok = readToken(currentToken); + } + bool badTokenType = (currentToken.type_ != tokenArraySeparator && + currentToken.type_ != tokenArrayEnd); + if (!ok || badTokenType) { + return addErrorAndRecover("Missing ',' or ']' in array declaration", + currentToken, tokenArrayEnd); + } + if (currentToken.type_ == tokenArrayEnd) + break; + } + return true; +} + +bool OurReader::decodeNumber(Token& token) { + Value decoded; + if (!decodeNumber(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeNumber(Token& token, Value& decoded) { + // Attempts to parse the number as an integer. If the number is + // larger than the maximum supported value of an integer then + // we decode the number as a double. + Location current = token.start_; + const bool isNegative = *current == '-'; + if (isNegative) { + ++current; + } + + // We assume we can represent the largest and smallest integer types as + // unsigned integers with separate sign. This is only true if they can fit + // into an unsigned integer. + static_assert(Value::maxLargestInt <= Value::maxLargestUInt, + "Int must be smaller than UInt"); + + // We need to convert minLargestInt into a positive number. The easiest way + // to do this conversion is to assume our "threshold" value of minLargestInt + // divided by 10 can fit in maxLargestInt when absolute valued. This should + // be a safe assumption. + static_assert(Value::minLargestInt <= -Value::maxLargestInt, + "The absolute value of minLargestInt must be greater than or " + "equal to maxLargestInt"); + static_assert(Value::minLargestInt / 10 >= -Value::maxLargestInt, + "The absolute value of minLargestInt must be only 1 magnitude " + "larger than maxLargest Int"); + + static constexpr Value::LargestUInt positive_threshold = + Value::maxLargestUInt / 10; + static constexpr Value::UInt positive_last_digit = Value::maxLargestUInt % 10; + + // For the negative values, we have to be more careful. Since typically + // -Value::minLargestInt will cause an overflow, we first divide by 10 and + // then take the inverse. This assumes that minLargestInt is only a single + // power of 10 different in magnitude, which we check above. For the last + // digit, we take the modulus before negating for the same reason. + static constexpr auto negative_threshold = + Value::LargestUInt(-(Value::minLargestInt / 10)); + static constexpr auto negative_last_digit = + Value::UInt(-(Value::minLargestInt % 10)); + + const Value::LargestUInt threshold = + isNegative ? negative_threshold : positive_threshold; + const Value::UInt max_last_digit = + isNegative ? negative_last_digit : positive_last_digit; + + Value::LargestUInt value = 0; + while (current < token.end_) { + Char c = *current++; + if (c < '0' || c > '9') + return decodeDouble(token, decoded); + + const auto digit(static_cast<Value::UInt>(c - '0')); + if (value >= threshold) { + // We've hit or exceeded the max value divided by 10 (rounded down). If + // a) we've only just touched the limit, meaing value == threshold, + // b) this is the last digit, or + // c) it's small enough to fit in that rounding delta, we're okay. + // Otherwise treat this number as a double to avoid overflow. + if (value > threshold || current != token.end_ || + digit > max_last_digit) { + return decodeDouble(token, decoded); + } + } + value = value * 10 + digit; + } + + if (isNegative) { + // We use the same magnitude assumption here, just in case. + const auto last_digit = static_cast<Value::UInt>(value % 10); + decoded = -Value::LargestInt(value / 10) * 10 - last_digit; + } else if (value <= Value::LargestUInt(Value::maxLargestInt)) { + decoded = Value::LargestInt(value); + } else { + decoded = value; + } + + return true; +} + +bool OurReader::decodeDouble(Token& token) { + Value decoded; + if (!decodeDouble(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeDouble(Token& token, Value& decoded) { + double value = 0; + const String buffer(token.start_, token.end_); + IStringStream is(buffer); + if (!(is >> value)) { + return addError( + "'" + String(token.start_, token.end_) + "' is not a number.", token); + } + decoded = value; + return true; +} + +bool OurReader::decodeString(Token& token) { + String decoded_string; + if (!decodeString(token, decoded_string)) + return false; + Value decoded(decoded_string); + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeString(Token& token, String& decoded) { + decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2)); + Location current = token.start_ + 1; // skip '"' + Location end = token.end_ - 1; // do not include '"' + while (current != end) { + Char c = *current++; + if (c == '"') + break; + if (c == '\\') { + if (current == end) + return addError("Empty escape sequence in string", token, current); + Char escape = *current++; + switch (escape) { + case '"': + decoded += '"'; + break; + case '/': + decoded += '/'; + break; + case '\\': + decoded += '\\'; + break; + case 'b': + decoded += '\b'; + break; + case 'f': + decoded += '\f'; + break; + case 'n': + decoded += '\n'; + break; + case 'r': + decoded += '\r'; + break; + case 't': + decoded += '\t'; + break; + case 'u': { + unsigned int unicode; + if (!decodeUnicodeCodePoint(token, current, end, unicode)) + return false; + decoded += codePointToUTF8(unicode); + } break; + default: + return addError("Bad escape sequence in string", token, current); + } + } else { + decoded += c; + } + } + return true; +} + +bool OurReader::decodeUnicodeCodePoint(Token& token, Location& current, + Location end, unsigned int& unicode) { + + if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) + return false; + if (unicode >= 0xD800 && unicode <= 0xDBFF) { + // surrogate pairs + if (end - current < 6) + return addError( + "additional six characters expected to parse unicode surrogate pair.", + token, current); + if (*(current++) == '\\' && *(current++) == 'u') { + unsigned int surrogatePair; + if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { + unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); + } else + return false; + } else + return addError("expecting another \\u token to begin the second half of " + "a unicode surrogate pair", + token, current); + } + return true; +} + +bool OurReader::decodeUnicodeEscapeSequence(Token& token, Location& current, + Location end, + unsigned int& ret_unicode) { + if (end - current < 4) + return addError( + "Bad unicode escape sequence in string: four digits expected.", token, + current); + int unicode = 0; + for (int index = 0; index < 4; ++index) { + Char c = *current++; + unicode *= 16; + if (c >= '0' && c <= '9') + unicode += c - '0'; + else if (c >= 'a' && c <= 'f') + unicode += c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + unicode += c - 'A' + 10; + else + return addError( + "Bad unicode escape sequence in string: hexadecimal digit expected.", + token, current); + } + ret_unicode = static_cast<unsigned int>(unicode); + return true; +} + +bool OurReader::addError(const String& message, Token& token, Location extra) { + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = extra; + errors_.push_back(info); + return false; +} + +bool OurReader::recoverFromError(TokenType skipUntilToken) { + size_t errorCount = errors_.size(); + Token skip; + for (;;) { + if (!readToken(skip)) + errors_.resize(errorCount); // discard errors caused by recovery + if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) + break; + } + errors_.resize(errorCount); + return false; +} + +bool OurReader::addErrorAndRecover(const String& message, Token& token, + TokenType skipUntilToken) { + addError(message, token); + return recoverFromError(skipUntilToken); +} + +Value& OurReader::currentValue() { return *(nodes_.top()); } + +OurReader::Char OurReader::getNextChar() { + if (current_ == end_) + return 0; + return *current_++; +} + +void OurReader::getLocationLineAndColumn(Location location, int& line, + int& column) const { + Location current = begin_; + Location lastLineStart = current; + line = 0; + while (current < location && current != end_) { + Char c = *current++; + if (c == '\r') { + if (*current == '\n') + ++current; + lastLineStart = current; + ++line; + } else if (c == '\n') { + lastLineStart = current; + ++line; + } + } + // column & line start at 1 + column = int(location - lastLineStart) + 1; + ++line; +} + +String OurReader::getLocationLineAndColumn(Location location) const { + int line, column; + getLocationLineAndColumn(location, line, column); + char buffer[18 + 16 + 16 + 1]; + jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); + return buffer; +} + +String OurReader::getFormattedErrorMessages() const { + String formattedMessage; + for (const auto& error : errors_) { + formattedMessage += + "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; + formattedMessage += " " + error.message_ + "\n"; + if (error.extra_) + formattedMessage += + "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; + } + return formattedMessage; +} + +std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const { + std::vector<OurReader::StructuredError> allErrors; + for (const auto& error : errors_) { + OurReader::StructuredError structured; + structured.offset_start = error.token_.start_ - begin_; + structured.offset_limit = error.token_.end_ - begin_; + structured.message = error.message_; + allErrors.push_back(structured); + } + return allErrors; +} + +class OurCharReader : public CharReader { + bool const collectComments_; + OurReader reader_; + +public: + OurCharReader(bool collectComments, OurFeatures const& features) + : collectComments_(collectComments), reader_(features) {} + bool parse(char const* beginDoc, char const* endDoc, Value* root, + String* errs) override { + bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_); + if (errs) { + *errs = reader_.getFormattedErrorMessages(); + } + return ok; + } +}; + +CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); } +CharReaderBuilder::~CharReaderBuilder() = default; +CharReader* CharReaderBuilder::newCharReader() const { + bool collectComments = settings_["collectComments"].asBool(); + OurFeatures features = OurFeatures::all(); + features.allowComments_ = settings_["allowComments"].asBool(); + features.allowTrailingCommas_ = settings_["allowTrailingCommas"].asBool(); + features.strictRoot_ = settings_["strictRoot"].asBool(); + features.allowDroppedNullPlaceholders_ = + settings_["allowDroppedNullPlaceholders"].asBool(); + features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool(); + features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool(); + + // Stack limit is always a size_t, so we get this as an unsigned int + // regardless of it we have 64-bit integer support enabled. + features.stackLimit_ = static_cast<size_t>(settings_["stackLimit"].asUInt()); + features.failIfExtra_ = settings_["failIfExtra"].asBool(); + features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool(); + features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool(); + features.skipBom_ = settings_["skipBom"].asBool(); + return new OurCharReader(collectComments, features); +} + +bool CharReaderBuilder::validate(Json::Value* invalid) const { + static const auto& valid_keys = *new std::set<String>{ + "collectComments", + "allowComments", + "allowTrailingCommas", + "strictRoot", + "allowDroppedNullPlaceholders", + "allowNumericKeys", + "allowSingleQuotes", + "stackLimit", + "failIfExtra", + "rejectDupKeys", + "allowSpecialFloats", + "skipBom", + }; + for (auto si = settings_.begin(); si != settings_.end(); ++si) { + auto key = si.name(); + if (valid_keys.count(key)) + continue; + if (invalid) + (*invalid)[key] = *si; + else + return false; + } + return invalid ? invalid->empty() : true; +} + +Value& CharReaderBuilder::operator[](const String& key) { + return settings_[key]; +} +// static +void CharReaderBuilder::strictMode(Json::Value* settings) { + //! [CharReaderBuilderStrictMode] + (*settings)["allowComments"] = false; + (*settings)["allowTrailingCommas"] = false; + (*settings)["strictRoot"] = true; + (*settings)["allowDroppedNullPlaceholders"] = false; + (*settings)["allowNumericKeys"] = false; + (*settings)["allowSingleQuotes"] = false; + (*settings)["stackLimit"] = 1000; + (*settings)["failIfExtra"] = true; + (*settings)["rejectDupKeys"] = true; + (*settings)["allowSpecialFloats"] = false; + (*settings)["skipBom"] = true; + //! [CharReaderBuilderStrictMode] +} +// static +void CharReaderBuilder::setDefaults(Json::Value* settings) { + //! [CharReaderBuilderDefaults] + (*settings)["collectComments"] = true; + (*settings)["allowComments"] = true; + (*settings)["allowTrailingCommas"] = true; + (*settings)["strictRoot"] = false; + (*settings)["allowDroppedNullPlaceholders"] = false; + (*settings)["allowNumericKeys"] = false; + (*settings)["allowSingleQuotes"] = false; + (*settings)["stackLimit"] = 1000; + (*settings)["failIfExtra"] = false; + (*settings)["rejectDupKeys"] = false; + (*settings)["allowSpecialFloats"] = false; + (*settings)["skipBom"] = true; + //! [CharReaderBuilderDefaults] +} + +////////////////////////////////// +// global functions + +bool parseFromStream(CharReader::Factory const& fact, IStream& sin, Value* root, + String* errs) { + OStringStream ssin; + ssin << sin.rdbuf(); + String doc = ssin.str(); + char const* begin = doc.data(); + char const* end = begin + doc.size(); + // Note that we do not actually need a null-terminator. + CharReaderPtr const reader(fact.newCharReader()); + return reader->parse(begin, end, root, errs); +} + +IStream& operator>>(IStream& sin, Value& root) { + CharReaderBuilder b; + String errs; + bool ok = parseFromStream(b, sin, &root, &errs); + if (!ok) { + throwRuntimeError(errs); + } + return sin; +} + +} // namespace Json diff --git a/thirdparty/openxr/src/external/jsoncpp/src/lib_json/json_tool.h b/thirdparty/openxr/src/external/jsoncpp/src/lib_json/json_tool.h new file mode 100644 index 0000000000..b952c19167 --- /dev/null +++ b/thirdparty/openxr/src/external/jsoncpp/src/lib_json/json_tool.h @@ -0,0 +1,138 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED +#define LIB_JSONCPP_JSON_TOOL_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include <json/config.h> +#endif + +// Also support old flag NO_LOCALE_SUPPORT +#ifdef NO_LOCALE_SUPPORT +#define JSONCPP_NO_LOCALE_SUPPORT +#endif + +#ifndef JSONCPP_NO_LOCALE_SUPPORT +#include <clocale> +#endif + +/* This header provides common string manipulation support, such as UTF-8, + * portable conversion from/to string... + * + * It is an internal header that must not be exposed. + */ + +namespace Json { +static inline char getDecimalPoint() { +#ifdef JSONCPP_NO_LOCALE_SUPPORT + return '\0'; +#else + struct lconv* lc = localeconv(); + return lc ? *(lc->decimal_point) : '\0'; +#endif +} + +/// Converts a unicode code-point to UTF-8. +static inline String codePointToUTF8(unsigned int cp) { + String result; + + // based on description from http://en.wikipedia.org/wiki/UTF-8 + + if (cp <= 0x7f) { + result.resize(1); + result[0] = static_cast<char>(cp); + } else if (cp <= 0x7FF) { + result.resize(2); + result[1] = static_cast<char>(0x80 | (0x3f & cp)); + result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6))); + } else if (cp <= 0xFFFF) { + result.resize(3); + result[2] = static_cast<char>(0x80 | (0x3f & cp)); + result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 6))); + result[0] = static_cast<char>(0xE0 | (0xf & (cp >> 12))); + } else if (cp <= 0x10FFFF) { + result.resize(4); + result[3] = static_cast<char>(0x80 | (0x3f & cp)); + result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6))); + result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12))); + result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18))); + } + + return result; +} + +enum { + /// Constant that specify the size of the buffer that must be passed to + /// uintToString. + uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1 +}; + +// Defines a char buffer for use with uintToString(). +using UIntToStringBuffer = char[uintToStringBufferSize]; + +/** Converts an unsigned integer to string. + * @param value Unsigned integer to convert to string + * @param current Input/Output string buffer. + * Must have at least uintToStringBufferSize chars free. + */ +static inline void uintToString(LargestUInt value, char*& current) { + *--current = 0; + do { + *--current = static_cast<char>(value % 10U + static_cast<unsigned>('0')); + value /= 10; + } while (value != 0); +} + +/** Change ',' to '.' everywhere in buffer. + * + * We had a sophisticated way, but it did not work in WinCE. + * @see https://github.com/open-source-parsers/jsoncpp/pull/9 + */ +template <typename Iter> Iter fixNumericLocale(Iter begin, Iter end) { + for (; begin != end; ++begin) { + if (*begin == ',') { + *begin = '.'; + } + } + return begin; +} + +template <typename Iter> void fixNumericLocaleInput(Iter begin, Iter end) { + char decimalPoint = getDecimalPoint(); + if (decimalPoint == '\0' || decimalPoint == '.') { + return; + } + for (; begin != end; ++begin) { + if (*begin == '.') { + *begin = decimalPoint; + } + } +} + +/** + * Return iterator that would be the new end of the range [begin,end), if we + * were to delete zeros in the end of string, but not the last zero before '.'. + */ +template <typename Iter> +Iter fixZerosInTheEnd(Iter begin, Iter end, unsigned int precision) { + for (; begin != end; --end) { + if (*(end - 1) != '0') { + return end; + } + // Don't delete the last zero before the decimal point. + if (begin != (end - 1) && begin != (end - 2) && *(end - 2) == '.') { + if (precision) { + return end; + } + return end - 2; + } + } + return end; +} + +} // namespace Json + +#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED diff --git a/thirdparty/openxr/src/external/jsoncpp/src/lib_json/json_value.cpp b/thirdparty/openxr/src/external/jsoncpp/src/lib_json/json_value.cpp new file mode 100644 index 0000000000..aa2b744ca8 --- /dev/null +++ b/thirdparty/openxr/src/external/jsoncpp/src/lib_json/json_value.cpp @@ -0,0 +1,1634 @@ +// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +#include <json/assertions.h> +#include <json/value.h> +#include <json/writer.h> +#endif // if !defined(JSON_IS_AMALGAMATION) +#include <algorithm> +#include <cassert> +#include <cmath> +#include <cstddef> +#include <cstring> +#include <iostream> +#include <sstream> +#include <utility> + +// Provide implementation equivalent of std::snprintf for older _MSC compilers +#if defined(_MSC_VER) && _MSC_VER < 1900 +#include <stdarg.h> +static int msvc_pre1900_c99_vsnprintf(char* outBuf, size_t size, + const char* format, va_list ap) { + int count = -1; + if (size != 0) + count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap); + if (count == -1) + count = _vscprintf(format, ap); + return count; +} + +int JSON_API msvc_pre1900_c99_snprintf(char* outBuf, size_t size, + const char* format, ...) { + va_list ap; + va_start(ap, format); + const int count = msvc_pre1900_c99_vsnprintf(outBuf, size, format, ap); + va_end(ap); + return count; +} +#endif + +// Disable warning C4702 : unreachable code +#if defined(_MSC_VER) +#pragma warning(disable : 4702) +#endif + +#define JSON_ASSERT_UNREACHABLE assert(false) + +namespace Json { +template <typename T> +static std::unique_ptr<T> cloneUnique(const std::unique_ptr<T>& p) { + std::unique_ptr<T> r; + if (p) { + r = std::unique_ptr<T>(new T(*p)); + } + return r; +} + +// This is a walkaround to avoid the static initialization of Value::null. +// kNull must be word-aligned to avoid crashing on ARM. We use an alignment of +// 8 (instead of 4) as a bit of future-proofing. +#if defined(__ARMEL__) +#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) +#else +#define ALIGNAS(byte_alignment) +#endif + +// static +Value const& Value::nullSingleton() { + static Value const nullStatic; + return nullStatic; +} + +#if JSON_USE_NULLREF +// for backwards compatibility, we'll leave these global references around, but +// DO NOT use them in JSONCPP library code any more! +// static +Value const& Value::null = Value::nullSingleton(); + +// static +Value const& Value::nullRef = Value::nullSingleton(); +#endif + +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) +template <typename T, typename U> +static inline bool InRange(double d, T min, U max) { + // The casts can lose precision, but we are looking only for + // an approximate range. Might fail on edge cases though. ~cdunn + return d >= static_cast<double>(min) && d <= static_cast<double>(max); +} +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) +static inline double integerToDouble(Json::UInt64 value) { + return static_cast<double>(Int64(value / 2)) * 2.0 + + static_cast<double>(Int64(value & 1)); +} + +template <typename T> static inline double integerToDouble(T value) { + return static_cast<double>(value); +} + +template <typename T, typename U> +static inline bool InRange(double d, T min, U max) { + return d >= integerToDouble(min) && d <= integerToDouble(max); +} +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + +/** Duplicates the specified string value. + * @param value Pointer to the string to duplicate. Must be zero-terminated if + * length is "unknown". + * @param length Length of the value. if equals to unknown, then it will be + * computed using strlen(value). + * @return Pointer on the duplicate instance of string. + */ +static inline char* duplicateStringValue(const char* value, size_t length) { + // Avoid an integer overflow in the call to malloc below by limiting length + // to a sane value. + if (length >= static_cast<size_t>(Value::maxInt)) + length = Value::maxInt - 1; + + auto newString = static_cast<char*>(malloc(length + 1)); + if (newString == nullptr) { + throwRuntimeError("in Json::Value::duplicateStringValue(): " + "Failed to allocate string value buffer"); + } + memcpy(newString, value, length); + newString[length] = 0; + return newString; +} + +/* Record the length as a prefix. + */ +static inline char* duplicateAndPrefixStringValue(const char* value, + unsigned int length) { + // Avoid an integer overflow in the call to malloc below by limiting length + // to a sane value. + JSON_ASSERT_MESSAGE(length <= static_cast<unsigned>(Value::maxInt) - + sizeof(unsigned) - 1U, + "in Json::Value::duplicateAndPrefixStringValue(): " + "length too big for prefixing"); + size_t actualLength = sizeof(length) + length + 1; + auto newString = static_cast<char*>(malloc(actualLength)); + if (newString == nullptr) { + throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): " + "Failed to allocate string value buffer"); + } + *reinterpret_cast<unsigned*>(newString) = length; + memcpy(newString + sizeof(unsigned), value, length); + newString[actualLength - 1U] = + 0; // to avoid buffer over-run accidents by users later + return newString; +} +inline static void decodePrefixedString(bool isPrefixed, char const* prefixed, + unsigned* length, char const** value) { + if (!isPrefixed) { + *length = static_cast<unsigned>(strlen(prefixed)); + *value = prefixed; + } else { + *length = *reinterpret_cast<unsigned const*>(prefixed); + *value = prefixed + sizeof(unsigned); + } +} +/** Free the string duplicated by + * duplicateStringValue()/duplicateAndPrefixStringValue(). + */ +#if JSONCPP_USING_SECURE_MEMORY +static inline void releasePrefixedStringValue(char* value) { + unsigned length = 0; + char const* valueDecoded; + decodePrefixedString(true, value, &length, &valueDecoded); + size_t const size = sizeof(unsigned) + length + 1U; + memset(value, 0, size); + free(value); +} +static inline void releaseStringValue(char* value, unsigned length) { + // length==0 => we allocated the strings memory + size_t size = (length == 0) ? strlen(value) : length; + memset(value, 0, size); + free(value); +} +#else // !JSONCPP_USING_SECURE_MEMORY +static inline void releasePrefixedStringValue(char* value) { free(value); } +static inline void releaseStringValue(char* value, unsigned) { free(value); } +#endif // JSONCPP_USING_SECURE_MEMORY + +} // namespace Json + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ValueInternals... +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +#if !defined(JSON_IS_AMALGAMATION) + +#include "json_valueiterator.inl" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +#if JSON_USE_EXCEPTION +Exception::Exception(String msg) : msg_(std::move(msg)) {} +Exception::~Exception() noexcept = default; +char const* Exception::what() const noexcept { return msg_.c_str(); } +RuntimeError::RuntimeError(String const& msg) : Exception(msg) {} +LogicError::LogicError(String const& msg) : Exception(msg) {} +JSONCPP_NORETURN void throwRuntimeError(String const& msg) { + throw RuntimeError(msg); +} +JSONCPP_NORETURN void throwLogicError(String const& msg) { + throw LogicError(msg); +} +#else // !JSON_USE_EXCEPTION +JSONCPP_NORETURN void throwRuntimeError(String const& msg) { + std::cerr << msg << std::endl; + abort(); +} +JSONCPP_NORETURN void throwLogicError(String const& msg) { + std::cerr << msg << std::endl; + abort(); +} +#endif + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CZString +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +// Notes: policy_ indicates if the string was allocated when +// a string is stored. + +Value::CZString::CZString(ArrayIndex index) : cstr_(nullptr), index_(index) {} + +Value::CZString::CZString(char const* str, unsigned length, + DuplicationPolicy allocate) + : cstr_(str) { + // allocate != duplicate + storage_.policy_ = allocate & 0x3; + storage_.length_ = length & 0x3FFFFFFF; +} + +Value::CZString::CZString(const CZString& other) { + cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != nullptr + ? duplicateStringValue(other.cstr_, other.storage_.length_) + : other.cstr_); + storage_.policy_ = + static_cast<unsigned>( + other.cstr_ + ? (static_cast<DuplicationPolicy>(other.storage_.policy_) == + noDuplication + ? noDuplication + : duplicate) + : static_cast<DuplicationPolicy>(other.storage_.policy_)) & + 3U; + storage_.length_ = other.storage_.length_; +} + +Value::CZString::CZString(CZString&& other) noexcept + : cstr_(other.cstr_), index_(other.index_) { + other.cstr_ = nullptr; +} + +Value::CZString::~CZString() { + if (cstr_ && storage_.policy_ == duplicate) { + releaseStringValue(const_cast<char*>(cstr_), + storage_.length_ + 1U); // +1 for null terminating + // character for sake of + // completeness but not actually + // necessary + } +} + +void Value::CZString::swap(CZString& other) { + std::swap(cstr_, other.cstr_); + std::swap(index_, other.index_); +} + +Value::CZString& Value::CZString::operator=(const CZString& other) { + cstr_ = other.cstr_; + index_ = other.index_; + return *this; +} + +Value::CZString& Value::CZString::operator=(CZString&& other) noexcept { + cstr_ = other.cstr_; + index_ = other.index_; + other.cstr_ = nullptr; + return *this; +} + +bool Value::CZString::operator<(const CZString& other) const { + if (!cstr_) + return index_ < other.index_; + // return strcmp(cstr_, other.cstr_) < 0; + // Assume both are strings. + unsigned this_len = this->storage_.length_; + unsigned other_len = other.storage_.length_; + unsigned min_len = std::min<unsigned>(this_len, other_len); + JSON_ASSERT(this->cstr_ && other.cstr_); + int comp = memcmp(this->cstr_, other.cstr_, min_len); + if (comp < 0) + return true; + if (comp > 0) + return false; + return (this_len < other_len); +} + +bool Value::CZString::operator==(const CZString& other) const { + if (!cstr_) + return index_ == other.index_; + // return strcmp(cstr_, other.cstr_) == 0; + // Assume both are strings. + unsigned this_len = this->storage_.length_; + unsigned other_len = other.storage_.length_; + if (this_len != other_len) + return false; + JSON_ASSERT(this->cstr_ && other.cstr_); + int comp = memcmp(this->cstr_, other.cstr_, this_len); + return comp == 0; +} + +ArrayIndex Value::CZString::index() const { return index_; } + +// const char* Value::CZString::c_str() const { return cstr_; } +const char* Value::CZString::data() const { return cstr_; } +unsigned Value::CZString::length() const { return storage_.length_; } +bool Value::CZString::isStaticString() const { + return storage_.policy_ == noDuplication; +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::Value +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +/*! \internal Default constructor initialization must be equivalent to: + * memset( this, 0, sizeof(Value) ) + * This optimization is used in ValueInternalMap fast allocator. + */ +Value::Value(ValueType type) { + static char const emptyString[] = ""; + initBasic(type); + switch (type) { + case nullValue: + break; + case intValue: + case uintValue: + value_.int_ = 0; + break; + case realValue: + value_.real_ = 0.0; + break; + case stringValue: + // allocated_ == false, so this is safe. + value_.string_ = const_cast<char*>(static_cast<char const*>(emptyString)); + break; + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(); + break; + case booleanValue: + value_.bool_ = false; + break; + default: + JSON_ASSERT_UNREACHABLE; + } +} + +Value::Value(Int value) { + initBasic(intValue); + value_.int_ = value; +} + +Value::Value(UInt value) { + initBasic(uintValue); + value_.uint_ = value; +} +#if defined(JSON_HAS_INT64) +Value::Value(Int64 value) { + initBasic(intValue); + value_.int_ = value; +} +Value::Value(UInt64 value) { + initBasic(uintValue); + value_.uint_ = value; +} +#endif // defined(JSON_HAS_INT64) + +Value::Value(double value) { + initBasic(realValue); + value_.real_ = value; +} + +Value::Value(const char* value) { + initBasic(stringValue, true); + JSON_ASSERT_MESSAGE(value != nullptr, + "Null Value Passed to Value Constructor"); + value_.string_ = duplicateAndPrefixStringValue( + value, static_cast<unsigned>(strlen(value))); +} + +Value::Value(const char* begin, const char* end) { + initBasic(stringValue, true); + value_.string_ = + duplicateAndPrefixStringValue(begin, static_cast<unsigned>(end - begin)); +} + +Value::Value(const String& value) { + initBasic(stringValue, true); + value_.string_ = duplicateAndPrefixStringValue( + value.data(), static_cast<unsigned>(value.length())); +} + +Value::Value(const StaticString& value) { + initBasic(stringValue); + value_.string_ = const_cast<char*>(value.c_str()); +} + +Value::Value(bool value) { + initBasic(booleanValue); + value_.bool_ = value; +} + +Value::Value(const Value& other) { + dupPayload(other); + dupMeta(other); +} + +Value::Value(Value&& other) noexcept { + initBasic(nullValue); + swap(other); +} + +Value::~Value() { + releasePayload(); + value_.uint_ = 0; +} + +Value& Value::operator=(const Value& other) { + Value(other).swap(*this); + return *this; +} + +Value& Value::operator=(Value&& other) noexcept { + other.swap(*this); + return *this; +} + +void Value::swapPayload(Value& other) { + std::swap(bits_, other.bits_); + std::swap(value_, other.value_); +} + +void Value::copyPayload(const Value& other) { + releasePayload(); + dupPayload(other); +} + +void Value::swap(Value& other) { + swapPayload(other); + std::swap(comments_, other.comments_); + std::swap(start_, other.start_); + std::swap(limit_, other.limit_); +} + +void Value::copy(const Value& other) { + copyPayload(other); + dupMeta(other); +} + +ValueType Value::type() const { + return static_cast<ValueType>(bits_.value_type_); +} + +int Value::compare(const Value& other) const { + if (*this < other) + return -1; + if (*this > other) + return 1; + return 0; +} + +bool Value::operator<(const Value& other) const { + int typeDelta = type() - other.type(); + if (typeDelta) + return typeDelta < 0; + switch (type()) { + case nullValue: + return false; + case intValue: + return value_.int_ < other.value_.int_; + case uintValue: + return value_.uint_ < other.value_.uint_; + case realValue: + return value_.real_ < other.value_.real_; + case booleanValue: + return value_.bool_ < other.value_.bool_; + case stringValue: { + if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) { + return other.value_.string_ != nullptr; + } + unsigned this_len; + unsigned other_len; + char const* this_str; + char const* other_str; + decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, + &this_str); + decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len, + &other_str); + unsigned min_len = std::min<unsigned>(this_len, other_len); + JSON_ASSERT(this_str && other_str); + int comp = memcmp(this_str, other_str, min_len); + if (comp < 0) + return true; + if (comp > 0) + return false; + return (this_len < other_len); + } + case arrayValue: + case objectValue: { + auto thisSize = value_.map_->size(); + auto otherSize = other.value_.map_->size(); + if (thisSize != otherSize) + return thisSize < otherSize; + return (*value_.map_) < (*other.value_.map_); + } + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable +} + +bool Value::operator<=(const Value& other) const { return !(other < *this); } + +bool Value::operator>=(const Value& other) const { return !(*this < other); } + +bool Value::operator>(const Value& other) const { return other < *this; } + +bool Value::operator==(const Value& other) const { + if (type() != other.type()) + return false; + switch (type()) { + case nullValue: + return true; + case intValue: + return value_.int_ == other.value_.int_; + case uintValue: + return value_.uint_ == other.value_.uint_; + case realValue: + return value_.real_ == other.value_.real_; + case booleanValue: + return value_.bool_ == other.value_.bool_; + case stringValue: { + if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) { + return (value_.string_ == other.value_.string_); + } + unsigned this_len; + unsigned other_len; + char const* this_str; + char const* other_str; + decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, + &this_str); + decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len, + &other_str); + if (this_len != other_len) + return false; + JSON_ASSERT(this_str && other_str); + int comp = memcmp(this_str, other_str, this_len); + return comp == 0; + } + case arrayValue: + case objectValue: + return value_.map_->size() == other.value_.map_->size() && + (*value_.map_) == (*other.value_.map_); + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable +} + +bool Value::operator!=(const Value& other) const { return !(*this == other); } + +const char* Value::asCString() const { + JSON_ASSERT_MESSAGE(type() == stringValue, + "in Json::Value::asCString(): requires stringValue"); + if (value_.string_ == nullptr) + return nullptr; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, + &this_str); + return this_str; +} + +#if JSONCPP_USING_SECURE_MEMORY +unsigned Value::getCStringLength() const { + JSON_ASSERT_MESSAGE(type() == stringValue, + "in Json::Value::asCString(): requires stringValue"); + if (value_.string_ == 0) + return 0; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, + &this_str); + return this_len; +} +#endif + +bool Value::getString(char const** begin, char const** end) const { + if (type() != stringValue) + return false; + if (value_.string_ == nullptr) + return false; + unsigned length; + decodePrefixedString(this->isAllocated(), this->value_.string_, &length, + begin); + *end = *begin + length; + return true; +} + +String Value::asString() const { + switch (type()) { + case nullValue: + return ""; + case stringValue: { + if (value_.string_ == nullptr) + return ""; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, + &this_str); + return String(this_str, this_len); + } + case booleanValue: + return value_.bool_ ? "true" : "false"; + case intValue: + return valueToString(value_.int_); + case uintValue: + return valueToString(value_.uint_); + case realValue: + return valueToString(value_.real_); + default: + JSON_FAIL_MESSAGE("Type is not convertible to string"); + } +} + +Value::Int Value::asInt() const { + switch (type()) { + case intValue: + JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range"); + return Int(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range"); + return Int(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt), + "double out of Int range"); + return Int(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to Int."); +} + +Value::UInt Value::asUInt() const { + switch (type()) { + case intValue: + JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range"); + return UInt(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range"); + return UInt(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt), + "double out of UInt range"); + return UInt(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to UInt."); +} + +#if defined(JSON_HAS_INT64) + +Value::Int64 Value::asInt64() const { + switch (type()) { + case intValue: + return Int64(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range"); + return Int64(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64), + "double out of Int64 range"); + return Int64(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to Int64."); +} + +Value::UInt64 Value::asUInt64() const { + switch (type()) { + case intValue: + JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range"); + return UInt64(value_.int_); + case uintValue: + return UInt64(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64), + "double out of UInt64 range"); + return UInt64(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to UInt64."); +} +#endif // if defined(JSON_HAS_INT64) + +LargestInt Value::asLargestInt() const { +#if defined(JSON_NO_INT64) + return asInt(); +#else + return asInt64(); +#endif +} + +LargestUInt Value::asLargestUInt() const { +#if defined(JSON_NO_INT64) + return asUInt(); +#else + return asUInt64(); +#endif +} + +double Value::asDouble() const { + switch (type()) { + case intValue: + return static_cast<double>(value_.int_); + case uintValue: +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast<double>(value_.uint_); +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return integerToDouble(value_.uint_); +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + case realValue: + return value_.real_; + case nullValue: + return 0.0; + case booleanValue: + return value_.bool_ ? 1.0 : 0.0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to double."); +} + +float Value::asFloat() const { + switch (type()) { + case intValue: + return static_cast<float>(value_.int_); + case uintValue: +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast<float>(value_.uint_); +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + // This can fail (silently?) if the value is bigger than MAX_FLOAT. + return static_cast<float>(integerToDouble(value_.uint_)); +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + case realValue: + return static_cast<float>(value_.real_); + case nullValue: + return 0.0; + case booleanValue: + return value_.bool_ ? 1.0F : 0.0F; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to float."); +} + +bool Value::asBool() const { + switch (type()) { + case booleanValue: + return value_.bool_; + case nullValue: + return false; + case intValue: + return value_.int_ != 0; + case uintValue: + return value_.uint_ != 0; + case realValue: { + // According to JavaScript language zero or NaN is regarded as false + const auto value_classification = std::fpclassify(value_.real_); + return value_classification != FP_ZERO && value_classification != FP_NAN; + } + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to bool."); +} + +bool Value::isConvertibleTo(ValueType other) const { + switch (other) { + case nullValue: + return (isNumeric() && asDouble() == 0.0) || + (type() == booleanValue && !value_.bool_) || + (type() == stringValue && asString().empty()) || + (type() == arrayValue && value_.map_->empty()) || + (type() == objectValue && value_.map_->empty()) || + type() == nullValue; + case intValue: + return isInt() || + (type() == realValue && InRange(value_.real_, minInt, maxInt)) || + type() == booleanValue || type() == nullValue; + case uintValue: + return isUInt() || + (type() == realValue && InRange(value_.real_, 0, maxUInt)) || + type() == booleanValue || type() == nullValue; + case realValue: + return isNumeric() || type() == booleanValue || type() == nullValue; + case booleanValue: + return isNumeric() || type() == booleanValue || type() == nullValue; + case stringValue: + return isNumeric() || type() == booleanValue || type() == stringValue || + type() == nullValue; + case arrayValue: + return type() == arrayValue || type() == nullValue; + case objectValue: + return type() == objectValue || type() == nullValue; + } + JSON_ASSERT_UNREACHABLE; + return false; +} + +/// Number of values in array or object +ArrayIndex Value::size() const { + switch (type()) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + case stringValue: + return 0; + case arrayValue: // size of the array is highest index + 1 + if (!value_.map_->empty()) { + ObjectValues::const_iterator itLast = value_.map_->end(); + --itLast; + return (*itLast).first.index() + 1; + } + return 0; + case objectValue: + return ArrayIndex(value_.map_->size()); + } + JSON_ASSERT_UNREACHABLE; + return 0; // unreachable; +} + +bool Value::empty() const { + if (isNull() || isArray() || isObject()) + return size() == 0U; + return false; +} + +Value::operator bool() const { return !isNull(); } + +void Value::clear() { + JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue || + type() == objectValue, + "in Json::Value::clear(): requires complex value"); + start_ = 0; + limit_ = 0; + switch (type()) { + case arrayValue: + case objectValue: + value_.map_->clear(); + break; + default: + break; + } +} + +void Value::resize(ArrayIndex newSize) { + JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue, + "in Json::Value::resize(): requires arrayValue"); + if (type() == nullValue) + *this = Value(arrayValue); + ArrayIndex oldSize = size(); + if (newSize == 0) + clear(); + else if (newSize > oldSize) + for (ArrayIndex i = oldSize; i < newSize; ++i) + (*this)[i]; + else { + for (ArrayIndex index = newSize; index < oldSize; ++index) { + value_.map_->erase(index); + } + JSON_ASSERT(size() == newSize); + } +} + +Value& Value::operator[](ArrayIndex index) { + JSON_ASSERT_MESSAGE( + type() == nullValue || type() == arrayValue, + "in Json::Value::operator[](ArrayIndex): requires arrayValue"); + if (type() == nullValue) + *this = Value(arrayValue); + CZString key(index); + auto it = value_.map_->lower_bound(key); + if (it != value_.map_->end() && (*it).first == key) + return (*it).second; + + ObjectValues::value_type defaultValue(key, nullSingleton()); + it = value_.map_->insert(it, defaultValue); + return (*it).second; +} + +Value& Value::operator[](int index) { + JSON_ASSERT_MESSAGE( + index >= 0, + "in Json::Value::operator[](int index): index cannot be negative"); + return (*this)[ArrayIndex(index)]; +} + +const Value& Value::operator[](ArrayIndex index) const { + JSON_ASSERT_MESSAGE( + type() == nullValue || type() == arrayValue, + "in Json::Value::operator[](ArrayIndex)const: requires arrayValue"); + if (type() == nullValue) + return nullSingleton(); + CZString key(index); + ObjectValues::const_iterator it = value_.map_->find(key); + if (it == value_.map_->end()) + return nullSingleton(); + return (*it).second; +} + +const Value& Value::operator[](int index) const { + JSON_ASSERT_MESSAGE( + index >= 0, + "in Json::Value::operator[](int index) const: index cannot be negative"); + return (*this)[ArrayIndex(index)]; +} + +void Value::initBasic(ValueType type, bool allocated) { + setType(type); + setIsAllocated(allocated); + comments_ = Comments{}; + start_ = 0; + limit_ = 0; +} + +void Value::dupPayload(const Value& other) { + setType(other.type()); + setIsAllocated(false); + switch (type()) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + value_ = other.value_; + break; + case stringValue: + if (other.value_.string_ && other.isAllocated()) { + unsigned len; + char const* str; + decodePrefixedString(other.isAllocated(), other.value_.string_, &len, + &str); + value_.string_ = duplicateAndPrefixStringValue(str, len); + setIsAllocated(true); + } else { + value_.string_ = other.value_.string_; + } + break; + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(*other.value_.map_); + break; + default: + JSON_ASSERT_UNREACHABLE; + } +} + +void Value::releasePayload() { + switch (type()) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + break; + case stringValue: + if (isAllocated()) + releasePrefixedStringValue(value_.string_); + break; + case arrayValue: + case objectValue: + delete value_.map_; + break; + default: + JSON_ASSERT_UNREACHABLE; + } +} + +void Value::dupMeta(const Value& other) { + comments_ = other.comments_; + start_ = other.start_; + limit_ = other.limit_; +} + +// Access an object value by name, create a null member if it does not exist. +// @pre Type of '*this' is object or null. +// @param key is null-terminated. +Value& Value::resolveReference(const char* key) { + JSON_ASSERT_MESSAGE( + type() == nullValue || type() == objectValue, + "in Json::Value::resolveReference(): requires objectValue"); + if (type() == nullValue) + *this = Value(objectValue); + CZString actualKey(key, static_cast<unsigned>(strlen(key)), + CZString::noDuplication); // NOTE! + auto it = value_.map_->lower_bound(actualKey); + if (it != value_.map_->end() && (*it).first == actualKey) + return (*it).second; + + ObjectValues::value_type defaultValue(actualKey, nullSingleton()); + it = value_.map_->insert(it, defaultValue); + Value& value = (*it).second; + return value; +} + +// @param key is not null-terminated. +Value& Value::resolveReference(char const* key, char const* end) { + JSON_ASSERT_MESSAGE( + type() == nullValue || type() == objectValue, + "in Json::Value::resolveReference(key, end): requires objectValue"); + if (type() == nullValue) + *this = Value(objectValue); + CZString actualKey(key, static_cast<unsigned>(end - key), + CZString::duplicateOnCopy); + auto it = value_.map_->lower_bound(actualKey); + if (it != value_.map_->end() && (*it).first == actualKey) + return (*it).second; + + ObjectValues::value_type defaultValue(actualKey, nullSingleton()); + it = value_.map_->insert(it, defaultValue); + Value& value = (*it).second; + return value; +} + +Value Value::get(ArrayIndex index, const Value& defaultValue) const { + const Value* value = &((*this)[index]); + return value == &nullSingleton() ? defaultValue : *value; +} + +bool Value::isValidIndex(ArrayIndex index) const { return index < size(); } + +Value const* Value::find(char const* begin, char const* end) const { + JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, + "in Json::Value::find(begin, end): requires " + "objectValue or nullValue"); + if (type() == nullValue) + return nullptr; + CZString actualKey(begin, static_cast<unsigned>(end - begin), + CZString::noDuplication); + ObjectValues::const_iterator it = value_.map_->find(actualKey); + if (it == value_.map_->end()) + return nullptr; + return &(*it).second; +} +Value* Value::demand(char const* begin, char const* end) { + JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, + "in Json::Value::demand(begin, end): requires " + "objectValue or nullValue"); + return &resolveReference(begin, end); +} +const Value& Value::operator[](const char* key) const { + Value const* found = find(key, key + strlen(key)); + if (!found) + return nullSingleton(); + return *found; +} +Value const& Value::operator[](const String& key) const { + Value const* found = find(key.data(), key.data() + key.length()); + if (!found) + return nullSingleton(); + return *found; +} + +Value& Value::operator[](const char* key) { + return resolveReference(key, key + strlen(key)); +} + +Value& Value::operator[](const String& key) { + return resolveReference(key.data(), key.data() + key.length()); +} + +Value& Value::operator[](const StaticString& key) { + return resolveReference(key.c_str()); +} + +Value& Value::append(const Value& value) { return append(Value(value)); } + +Value& Value::append(Value&& value) { + JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue, + "in Json::Value::append: requires arrayValue"); + if (type() == nullValue) { + *this = Value(arrayValue); + } + return this->value_.map_->emplace(size(), std::move(value)).first->second; +} + +bool Value::insert(ArrayIndex index, const Value& newValue) { + return insert(index, Value(newValue)); +} + +bool Value::insert(ArrayIndex index, Value&& newValue) { + JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue, + "in Json::Value::insert: requires arrayValue"); + ArrayIndex length = size(); + if (index > length) { + return false; + } + for (ArrayIndex i = length; i > index; i--) { + (*this)[i] = std::move((*this)[i - 1]); + } + (*this)[index] = std::move(newValue); + return true; +} + +Value Value::get(char const* begin, char const* end, + Value const& defaultValue) const { + Value const* found = find(begin, end); + return !found ? defaultValue : *found; +} +Value Value::get(char const* key, Value const& defaultValue) const { + return get(key, key + strlen(key), defaultValue); +} +Value Value::get(String const& key, Value const& defaultValue) const { + return get(key.data(), key.data() + key.length(), defaultValue); +} + +bool Value::removeMember(const char* begin, const char* end, Value* removed) { + if (type() != objectValue) { + return false; + } + CZString actualKey(begin, static_cast<unsigned>(end - begin), + CZString::noDuplication); + auto it = value_.map_->find(actualKey); + if (it == value_.map_->end()) + return false; + if (removed) + *removed = std::move(it->second); + value_.map_->erase(it); + return true; +} +bool Value::removeMember(const char* key, Value* removed) { + return removeMember(key, key + strlen(key), removed); +} +bool Value::removeMember(String const& key, Value* removed) { + return removeMember(key.data(), key.data() + key.length(), removed); +} +void Value::removeMember(const char* key) { + JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, + "in Json::Value::removeMember(): requires objectValue"); + if (type() == nullValue) + return; + + CZString actualKey(key, unsigned(strlen(key)), CZString::noDuplication); + value_.map_->erase(actualKey); +} +void Value::removeMember(const String& key) { removeMember(key.c_str()); } + +bool Value::removeIndex(ArrayIndex index, Value* removed) { + if (type() != arrayValue) { + return false; + } + CZString key(index); + auto it = value_.map_->find(key); + if (it == value_.map_->end()) { + return false; + } + if (removed) + *removed = it->second; + ArrayIndex oldSize = size(); + // shift left all items left, into the place of the "removed" + for (ArrayIndex i = index; i < (oldSize - 1); ++i) { + CZString keey(i); + (*value_.map_)[keey] = (*this)[i + 1]; + } + // erase the last one ("leftover") + CZString keyLast(oldSize - 1); + auto itLast = value_.map_->find(keyLast); + value_.map_->erase(itLast); + return true; +} + +bool Value::isMember(char const* begin, char const* end) const { + Value const* value = find(begin, end); + return nullptr != value; +} +bool Value::isMember(char const* key) const { + return isMember(key, key + strlen(key)); +} +bool Value::isMember(String const& key) const { + return isMember(key.data(), key.data() + key.length()); +} + +Value::Members Value::getMemberNames() const { + JSON_ASSERT_MESSAGE( + type() == nullValue || type() == objectValue, + "in Json::Value::getMemberNames(), value must be objectValue"); + if (type() == nullValue) + return Value::Members(); + Members members; + members.reserve(value_.map_->size()); + ObjectValues::const_iterator it = value_.map_->begin(); + ObjectValues::const_iterator itEnd = value_.map_->end(); + for (; it != itEnd; ++it) { + members.push_back(String((*it).first.data(), (*it).first.length())); + } + return members; +} + +static bool IsIntegral(double d) { + double integral_part; + return modf(d, &integral_part) == 0.0; +} + +bool Value::isNull() const { return type() == nullValue; } + +bool Value::isBool() const { return type() == booleanValue; } + +bool Value::isInt() const { + switch (type()) { + case intValue: +#if defined(JSON_HAS_INT64) + return value_.int_ >= minInt && value_.int_ <= maxInt; +#else + return true; +#endif + case uintValue: + return value_.uint_ <= UInt(maxInt); + case realValue: + return value_.real_ >= minInt && value_.real_ <= maxInt && + IsIntegral(value_.real_); + default: + break; + } + return false; +} + +bool Value::isUInt() const { + switch (type()) { + case intValue: +#if defined(JSON_HAS_INT64) + return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt); +#else + return value_.int_ >= 0; +#endif + case uintValue: +#if defined(JSON_HAS_INT64) + return value_.uint_ <= maxUInt; +#else + return true; +#endif + case realValue: + return value_.real_ >= 0 && value_.real_ <= maxUInt && + IsIntegral(value_.real_); + default: + break; + } + return false; +} + +bool Value::isInt64() const { +#if defined(JSON_HAS_INT64) + switch (type()) { + case intValue: + return true; + case uintValue: + return value_.uint_ <= UInt64(maxInt64); + case realValue: + // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a + // double, so double(maxInt64) will be rounded up to 2^63. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= double(minInt64) && + value_.real_ < double(maxInt64) && IsIntegral(value_.real_); + default: + break; + } +#endif // JSON_HAS_INT64 + return false; +} + +bool Value::isUInt64() const { +#if defined(JSON_HAS_INT64) + switch (type()) { + case intValue: + return value_.int_ >= 0; + case uintValue: + return true; + case realValue: + // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a + // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble && + IsIntegral(value_.real_); + default: + break; + } +#endif // JSON_HAS_INT64 + return false; +} + +bool Value::isIntegral() const { + switch (type()) { + case intValue: + case uintValue: + return true; + case realValue: +#if defined(JSON_HAS_INT64) + // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a + // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= double(minInt64) && + value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_); +#else + return value_.real_ >= minInt && value_.real_ <= maxUInt && + IsIntegral(value_.real_); +#endif // JSON_HAS_INT64 + default: + break; + } + return false; +} + +bool Value::isDouble() const { + return type() == intValue || type() == uintValue || type() == realValue; +} + +bool Value::isNumeric() const { return isDouble(); } + +bool Value::isString() const { return type() == stringValue; } + +bool Value::isArray() const { return type() == arrayValue; } + +bool Value::isObject() const { return type() == objectValue; } + +Value::Comments::Comments(const Comments& that) + : ptr_{cloneUnique(that.ptr_)} {} + +Value::Comments::Comments(Comments&& that) noexcept + : ptr_{std::move(that.ptr_)} {} + +Value::Comments& Value::Comments::operator=(const Comments& that) { + ptr_ = cloneUnique(that.ptr_); + return *this; +} + +Value::Comments& Value::Comments::operator=(Comments&& that) noexcept { + ptr_ = std::move(that.ptr_); + return *this; +} + +bool Value::Comments::has(CommentPlacement slot) const { + return ptr_ && !(*ptr_)[slot].empty(); +} + +String Value::Comments::get(CommentPlacement slot) const { + if (!ptr_) + return {}; + return (*ptr_)[slot]; +} + +void Value::Comments::set(CommentPlacement slot, String comment) { + if (slot >= CommentPlacement::numberOfCommentPlacement) + return; + if (!ptr_) + ptr_ = std::unique_ptr<Array>(new Array()); + (*ptr_)[slot] = std::move(comment); +} + +void Value::setComment(String comment, CommentPlacement placement) { + if (!comment.empty() && (comment.back() == '\n')) { + // Always discard trailing newline, to aid indentation. + comment.pop_back(); + } + JSON_ASSERT(!comment.empty()); + JSON_ASSERT_MESSAGE( + comment[0] == '\0' || comment[0] == '/', + "in Json::Value::setComment(): Comments must start with /"); + comments_.set(placement, std::move(comment)); +} + +bool Value::hasComment(CommentPlacement placement) const { + return comments_.has(placement); +} + +String Value::getComment(CommentPlacement placement) const { + return comments_.get(placement); +} + +void Value::setOffsetStart(ptrdiff_t start) { start_ = start; } + +void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; } + +ptrdiff_t Value::getOffsetStart() const { return start_; } + +ptrdiff_t Value::getOffsetLimit() const { return limit_; } + +String Value::toStyledString() const { + StreamWriterBuilder builder; + + String out = this->hasComment(commentBefore) ? "\n" : ""; + out += Json::writeString(builder, *this); + out += '\n'; + + return out; +} + +Value::const_iterator Value::begin() const { + switch (type()) { + case arrayValue: + case objectValue: + if (value_.map_) + return const_iterator(value_.map_->begin()); + break; + default: + break; + } + return {}; +} + +Value::const_iterator Value::end() const { + switch (type()) { + case arrayValue: + case objectValue: + if (value_.map_) + return const_iterator(value_.map_->end()); + break; + default: + break; + } + return {}; +} + +Value::iterator Value::begin() { + switch (type()) { + case arrayValue: + case objectValue: + if (value_.map_) + return iterator(value_.map_->begin()); + break; + default: + break; + } + return iterator(); +} + +Value::iterator Value::end() { + switch (type()) { + case arrayValue: + case objectValue: + if (value_.map_) + return iterator(value_.map_->end()); + break; + default: + break; + } + return iterator(); +} + +// class PathArgument +// ////////////////////////////////////////////////////////////////// + +PathArgument::PathArgument() = default; + +PathArgument::PathArgument(ArrayIndex index) + : index_(index), kind_(kindIndex) {} + +PathArgument::PathArgument(const char* key) : key_(key), kind_(kindKey) {} + +PathArgument::PathArgument(String key) : key_(std::move(key)), kind_(kindKey) {} + +// class Path +// ////////////////////////////////////////////////////////////////// + +Path::Path(const String& path, const PathArgument& a1, const PathArgument& a2, + const PathArgument& a3, const PathArgument& a4, + const PathArgument& a5) { + InArgs in; + in.reserve(5); + in.push_back(&a1); + in.push_back(&a2); + in.push_back(&a3); + in.push_back(&a4); + in.push_back(&a5); + makePath(path, in); +} + +void Path::makePath(const String& path, const InArgs& in) { + const char* current = path.c_str(); + const char* end = current + path.length(); + auto itInArg = in.begin(); + while (current != end) { + if (*current == '[') { + ++current; + if (*current == '%') + addPathInArg(path, in, itInArg, PathArgument::kindIndex); + else { + ArrayIndex index = 0; + for (; current != end && *current >= '0' && *current <= '9'; ++current) + index = index * 10 + ArrayIndex(*current - '0'); + args_.push_back(index); + } + if (current == end || *++current != ']') + invalidPath(path, int(current - path.c_str())); + } else if (*current == '%') { + addPathInArg(path, in, itInArg, PathArgument::kindKey); + ++current; + } else if (*current == '.' || *current == ']') { + ++current; + } else { + const char* beginName = current; + while (current != end && !strchr("[.", *current)) + ++current; + args_.push_back(String(beginName, current)); + } + } +} + +void Path::addPathInArg(const String& /*path*/, const InArgs& in, + InArgs::const_iterator& itInArg, + PathArgument::Kind kind) { + if (itInArg == in.end()) { + // Error: missing argument %d + } else if ((*itInArg)->kind_ != kind) { + // Error: bad argument type + } else { + args_.push_back(**itInArg++); + } +} + +void Path::invalidPath(const String& /*path*/, int /*location*/) { + // Error: invalid path. +} + +const Value& Path::resolve(const Value& root) const { + const Value* node = &root; + for (const auto& arg : args_) { + if (arg.kind_ == PathArgument::kindIndex) { + if (!node->isArray() || !node->isValidIndex(arg.index_)) { + // Error: unable to resolve path (array value expected at position... ) + return Value::nullSingleton(); + } + node = &((*node)[arg.index_]); + } else if (arg.kind_ == PathArgument::kindKey) { + if (!node->isObject()) { + // Error: unable to resolve path (object value expected at position...) + return Value::nullSingleton(); + } + node = &((*node)[arg.key_]); + if (node == &Value::nullSingleton()) { + // Error: unable to resolve path (object has no member named '' at + // position...) + return Value::nullSingleton(); + } + } + } + return *node; +} + +Value Path::resolve(const Value& root, const Value& defaultValue) const { + const Value* node = &root; + for (const auto& arg : args_) { + if (arg.kind_ == PathArgument::kindIndex) { + if (!node->isArray() || !node->isValidIndex(arg.index_)) + return defaultValue; + node = &((*node)[arg.index_]); + } else if (arg.kind_ == PathArgument::kindKey) { + if (!node->isObject()) + return defaultValue; + node = &((*node)[arg.key_]); + if (node == &Value::nullSingleton()) + return defaultValue; + } + } + return *node; +} + +Value& Path::make(Value& root) const { + Value* node = &root; + for (const auto& arg : args_) { + if (arg.kind_ == PathArgument::kindIndex) { + if (!node->isArray()) { + // Error: node is not an array at position ... + } + node = &((*node)[arg.index_]); + } else if (arg.kind_ == PathArgument::kindKey) { + if (!node->isObject()) { + // Error: node is not an object at position... + } + node = &((*node)[arg.key_]); + } + } + return *node; +} + +} // namespace Json diff --git a/thirdparty/openxr/src/external/jsoncpp/src/lib_json/json_valueiterator.inl b/thirdparty/openxr/src/external/jsoncpp/src/lib_json/json_valueiterator.inl new file mode 100644 index 0000000000..d6128b8edf --- /dev/null +++ b/thirdparty/openxr/src/external/jsoncpp/src/lib_json/json_valueiterator.inl @@ -0,0 +1,156 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +// included by json_value.cpp + +namespace Json { + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueIteratorBase +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueIteratorBase::ValueIteratorBase() : current_() {} + +ValueIteratorBase::ValueIteratorBase( + const Value::ObjectValues::iterator& current) + : current_(current), isNull_(false) {} + +Value& ValueIteratorBase::deref() { return current_->second; } +const Value& ValueIteratorBase::deref() const { return current_->second; } + +void ValueIteratorBase::increment() { ++current_; } + +void ValueIteratorBase::decrement() { --current_; } + +ValueIteratorBase::difference_type +ValueIteratorBase::computeDistance(const SelfType& other) const { + // Iterator for null value are initialized using the default + // constructor, which initialize current_ to the default + // std::map::iterator. As begin() and end() are two instance + // of the default std::map::iterator, they can not be compared. + // To allow this, we handle this comparison specifically. + if (isNull_ && other.isNull_) { + return 0; + } + + // Usage of std::distance is not portable (does not compile with Sun Studio 12 + // RogueWave STL, + // which is the one used by default). + // Using a portable hand-made version for non random iterator instead: + // return difference_type( std::distance( current_, other.current_ ) ); + difference_type myDistance = 0; + for (Value::ObjectValues::iterator it = current_; it != other.current_; + ++it) { + ++myDistance; + } + return myDistance; +} + +bool ValueIteratorBase::isEqual(const SelfType& other) const { + if (isNull_) { + return other.isNull_; + } + return current_ == other.current_; +} + +void ValueIteratorBase::copy(const SelfType& other) { + current_ = other.current_; + isNull_ = other.isNull_; +} + +Value ValueIteratorBase::key() const { + const Value::CZString czstring = (*current_).first; + if (czstring.data()) { + if (czstring.isStaticString()) + return Value(StaticString(czstring.data())); + return Value(czstring.data(), czstring.data() + czstring.length()); + } + return Value(czstring.index()); +} + +UInt ValueIteratorBase::index() const { + const Value::CZString czstring = (*current_).first; + if (!czstring.data()) + return czstring.index(); + return Value::UInt(-1); +} + +String ValueIteratorBase::name() const { + char const* keey; + char const* end; + keey = memberName(&end); + if (!keey) + return String(); + return String(keey, end); +} + +char const* ValueIteratorBase::memberName() const { + const char* cname = (*current_).first.data(); + return cname ? cname : ""; +} + +char const* ValueIteratorBase::memberName(char const** end) const { + const char* cname = (*current_).first.data(); + if (!cname) { + *end = nullptr; + return nullptr; + } + *end = cname + (*current_).first.length(); + return cname; +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueConstIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueConstIterator::ValueConstIterator() = default; + +ValueConstIterator::ValueConstIterator( + const Value::ObjectValues::iterator& current) + : ValueIteratorBase(current) {} + +ValueConstIterator::ValueConstIterator(ValueIterator const& other) + : ValueIteratorBase(other) {} + +ValueConstIterator& ValueConstIterator:: +operator=(const ValueIteratorBase& other) { + copy(other); + return *this; +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueIterator::ValueIterator() = default; + +ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current) + : ValueIteratorBase(current) {} + +ValueIterator::ValueIterator(const ValueConstIterator& other) + : ValueIteratorBase(other) { + throwRuntimeError("ConstIterator to Iterator should never be allowed."); +} + +ValueIterator::ValueIterator(const ValueIterator& other) = default; + +ValueIterator& ValueIterator::operator=(const SelfType& other) { + copy(other); + return *this; +} + +} // namespace Json diff --git a/thirdparty/openxr/src/external/jsoncpp/src/lib_json/json_writer.cpp b/thirdparty/openxr/src/external/jsoncpp/src/lib_json/json_writer.cpp new file mode 100644 index 0000000000..0dd160e452 --- /dev/null +++ b/thirdparty/openxr/src/external/jsoncpp/src/lib_json/json_writer.cpp @@ -0,0 +1,1259 @@ +// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +#include "json_tool.h" +#include <json/writer.h> +#endif // if !defined(JSON_IS_AMALGAMATION) +#include <algorithm> +#include <cassert> +#include <cctype> +#include <cstring> +#include <iomanip> +#include <memory> +#include <set> +#include <sstream> +#include <utility> + +#if __cplusplus >= 201103L +#include <cmath> +#include <cstdio> + +#if !defined(isnan) +#define isnan std::isnan +#endif + +#if !defined(isfinite) +#define isfinite std::isfinite +#endif + +#else +#include <cmath> +#include <cstdio> + +#if defined(_MSC_VER) +#if !defined(isnan) +#include <float.h> +#define isnan _isnan +#endif + +#if !defined(isfinite) +#include <float.h> +#define isfinite _finite +#endif + +#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES) +#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 +#endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES + +#endif //_MSC_VER + +#if defined(__sun) && defined(__SVR4) // Solaris +#if !defined(isfinite) +#include <ieeefp.h> +#define isfinite finite +#endif +#endif + +#if defined(__hpux) +#if !defined(isfinite) +#if defined(__ia64) && !defined(finite) +#define isfinite(x) \ + ((sizeof(x) == sizeof(float) ? _Isfinitef(x) : _IsFinite(x))) +#endif +#endif +#endif + +#if !defined(isnan) +// IEEE standard states that NaN values will not compare to themselves +#define isnan(x) ((x) != (x)) +#endif + +#if !defined(__APPLE__) +#if !defined(isfinite) +#define isfinite finite +#endif +#endif +#endif + +#if defined(_MSC_VER) +// Disable warning about strdup being deprecated. +#pragma warning(disable : 4996) +#endif + +namespace Json { + +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) +using StreamWriterPtr = std::unique_ptr<StreamWriter>; +#else +using StreamWriterPtr = std::auto_ptr<StreamWriter>; +#endif + +String valueToString(LargestInt value) { + UIntToStringBuffer buffer; + char* current = buffer + sizeof(buffer); + if (value == Value::minLargestInt) { + uintToString(LargestUInt(Value::maxLargestInt) + 1, current); + *--current = '-'; + } else if (value < 0) { + uintToString(LargestUInt(-value), current); + *--current = '-'; + } else { + uintToString(LargestUInt(value), current); + } + assert(current >= buffer); + return current; +} + +String valueToString(LargestUInt value) { + UIntToStringBuffer buffer; + char* current = buffer + sizeof(buffer); + uintToString(value, current); + assert(current >= buffer); + return current; +} + +#if defined(JSON_HAS_INT64) + +String valueToString(Int value) { return valueToString(LargestInt(value)); } + +String valueToString(UInt value) { return valueToString(LargestUInt(value)); } + +#endif // # if defined(JSON_HAS_INT64) + +namespace { +String valueToString(double value, bool useSpecialFloats, + unsigned int precision, PrecisionType precisionType) { + // Print into the buffer. We need not request the alternative representation + // that always has a decimal point because JSON doesn't distinguish the + // concepts of reals and integers. + if (!isfinite(value)) { + static const char* const reps[2][3] = {{"NaN", "-Infinity", "Infinity"}, + {"null", "-1e+9999", "1e+9999"}}; + return reps[useSpecialFloats ? 0 : 1] + [isnan(value) ? 0 : (value < 0) ? 1 : 2]; + } + + String buffer(size_t(36), '\0'); + while (true) { + int len = jsoncpp_snprintf( + &*buffer.begin(), buffer.size(), + (precisionType == PrecisionType::significantDigits) ? "%.*g" : "%.*f", + precision, value); + assert(len >= 0); + auto wouldPrint = static_cast<size_t>(len); + if (wouldPrint >= buffer.size()) { + buffer.resize(wouldPrint + 1); + continue; + } + buffer.resize(wouldPrint); + break; + } + + buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end()); + + // try to ensure we preserve the fact that this was given to us as a double on + // input + if (buffer.find('.') == buffer.npos && buffer.find('e') == buffer.npos) { + buffer += ".0"; + } + + // strip the zero padding from the right + if (precisionType == PrecisionType::decimalPlaces) { + buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end(), precision), + buffer.end()); + } + + return buffer; +} +} // namespace + +String valueToString(double value, unsigned int precision, + PrecisionType precisionType) { + return valueToString(value, false, precision, precisionType); +} + +String valueToString(bool value) { return value ? "true" : "false"; } + +static bool doesAnyCharRequireEscaping(char const* s, size_t n) { + assert(s || !n); + + return std::any_of(s, s + n, [](unsigned char c) { + return c == '\\' || c == '"' || c < 0x20 || c > 0x7F; + }); +} + +static unsigned int utf8ToCodepoint(const char*& s, const char* e) { + const unsigned int REPLACEMENT_CHARACTER = 0xFFFD; + + unsigned int firstByte = static_cast<unsigned char>(*s); + + if (firstByte < 0x80) + return firstByte; + + if (firstByte < 0xE0) { + if (e - s < 2) + return REPLACEMENT_CHARACTER; + + unsigned int calculated = + ((firstByte & 0x1F) << 6) | (static_cast<unsigned int>(s[1]) & 0x3F); + s += 1; + // oversized encoded characters are invalid + return calculated < 0x80 ? REPLACEMENT_CHARACTER : calculated; + } + + if (firstByte < 0xF0) { + if (e - s < 3) + return REPLACEMENT_CHARACTER; + + unsigned int calculated = ((firstByte & 0x0F) << 12) | + ((static_cast<unsigned int>(s[1]) & 0x3F) << 6) | + (static_cast<unsigned int>(s[2]) & 0x3F); + s += 2; + // surrogates aren't valid codepoints itself + // shouldn't be UTF-8 encoded + if (calculated >= 0xD800 && calculated <= 0xDFFF) + return REPLACEMENT_CHARACTER; + // oversized encoded characters are invalid + return calculated < 0x800 ? REPLACEMENT_CHARACTER : calculated; + } + + if (firstByte < 0xF8) { + if (e - s < 4) + return REPLACEMENT_CHARACTER; + + unsigned int calculated = ((firstByte & 0x07) << 18) | + ((static_cast<unsigned int>(s[1]) & 0x3F) << 12) | + ((static_cast<unsigned int>(s[2]) & 0x3F) << 6) | + (static_cast<unsigned int>(s[3]) & 0x3F); + s += 3; + // oversized encoded characters are invalid + return calculated < 0x10000 ? REPLACEMENT_CHARACTER : calculated; + } + + return REPLACEMENT_CHARACTER; +} + +static const char hex2[] = "000102030405060708090a0b0c0d0e0f" + "101112131415161718191a1b1c1d1e1f" + "202122232425262728292a2b2c2d2e2f" + "303132333435363738393a3b3c3d3e3f" + "404142434445464748494a4b4c4d4e4f" + "505152535455565758595a5b5c5d5e5f" + "606162636465666768696a6b6c6d6e6f" + "707172737475767778797a7b7c7d7e7f" + "808182838485868788898a8b8c8d8e8f" + "909192939495969798999a9b9c9d9e9f" + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf" + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; + +static String toHex16Bit(unsigned int x) { + const unsigned int hi = (x >> 8) & 0xff; + const unsigned int lo = x & 0xff; + String result(4, ' '); + result[0] = hex2[2 * hi]; + result[1] = hex2[2 * hi + 1]; + result[2] = hex2[2 * lo]; + result[3] = hex2[2 * lo + 1]; + return result; +} + +static void appendRaw(String& result, unsigned ch) { + result += static_cast<char>(ch); +} + +static void appendHex(String& result, unsigned ch) { + result.append("\\u").append(toHex16Bit(ch)); +} + +static String valueToQuotedStringN(const char* value, size_t length, + bool emitUTF8 = false) { + if (value == nullptr) + return ""; + + if (!doesAnyCharRequireEscaping(value, length)) + return String("\"") + value + "\""; + // We have to walk value and escape any special characters. + // Appending to String is not efficient, but this should be rare. + // (Note: forward slashes are *not* rare, but I am not escaping them.) + String::size_type maxsize = length * 2 + 3; // allescaped+quotes+NULL + String result; + result.reserve(maxsize); // to avoid lots of mallocs + result += "\""; + char const* end = value + length; + for (const char* c = value; c != end; ++c) { + switch (*c) { + case '\"': + result += "\\\""; + break; + case '\\': + result += "\\\\"; + break; + case '\b': + result += "\\b"; + break; + case '\f': + result += "\\f"; + break; + case '\n': + result += "\\n"; + break; + case '\r': + result += "\\r"; + break; + case '\t': + result += "\\t"; + break; + // case '/': + // Even though \/ is considered a legal escape in JSON, a bare + // slash is also legal, so I see no reason to escape it. + // (I hope I am not misunderstanding something.) + // blep notes: actually escaping \/ may be useful in javascript to avoid </ + // sequence. + // Should add a flag to allow this compatibility mode and prevent this + // sequence from occurring. + default: { + if (emitUTF8) { + unsigned codepoint = static_cast<unsigned char>(*c); + if (codepoint < 0x20) { + appendHex(result, codepoint); + } else { + appendRaw(result, codepoint); + } + } else { + unsigned codepoint = utf8ToCodepoint(c, end); // modifies `c` + if (codepoint < 0x20) { + appendHex(result, codepoint); + } else if (codepoint < 0x80) { + appendRaw(result, codepoint); + } else if (codepoint < 0x10000) { + // Basic Multilingual Plane + appendHex(result, codepoint); + } else { + // Extended Unicode. Encode 20 bits as a surrogate pair. + codepoint -= 0x10000; + appendHex(result, 0xd800 + ((codepoint >> 10) & 0x3ff)); + appendHex(result, 0xdc00 + (codepoint & 0x3ff)); + } + } + } break; + } + } + result += "\""; + return result; +} + +String valueToQuotedString(const char* value) { + return valueToQuotedStringN(value, strlen(value)); +} + +// Class Writer +// ////////////////////////////////////////////////////////////////// +Writer::~Writer() = default; + +// Class FastWriter +// ////////////////////////////////////////////////////////////////// + +FastWriter::FastWriter() + + = default; + +void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ = true; } + +void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; } + +void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; } + +String FastWriter::write(const Value& root) { + document_.clear(); + writeValue(root); + if (!omitEndingLineFeed_) + document_ += '\n'; + return document_; +} + +void FastWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + if (!dropNullPlaceholders_) + document_ += "null"; + break; + case intValue: + document_ += valueToString(value.asLargestInt()); + break; + case uintValue: + document_ += valueToString(value.asLargestUInt()); + break; + case realValue: + document_ += valueToString(value.asDouble()); + break; + case stringValue: { + // Is NULL possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) + document_ += valueToQuotedStringN(str, static_cast<size_t>(end - str)); + break; + } + case booleanValue: + document_ += valueToString(value.asBool()); + break; + case arrayValue: { + document_ += '['; + ArrayIndex size = value.size(); + for (ArrayIndex index = 0; index < size; ++index) { + if (index > 0) + document_ += ','; + writeValue(value[index]); + } + document_ += ']'; + } break; + case objectValue: { + Value::Members members(value.getMemberNames()); + document_ += '{'; + for (auto it = members.begin(); it != members.end(); ++it) { + const String& name = *it; + if (it != members.begin()) + document_ += ','; + document_ += valueToQuotedStringN(name.data(), name.length()); + document_ += yamlCompatibilityEnabled_ ? ": " : ":"; + writeValue(value[name]); + } + document_ += '}'; + } break; + } +} + +// Class StyledWriter +// ////////////////////////////////////////////////////////////////// + +StyledWriter::StyledWriter() = default; + +String StyledWriter::write(const Value& root) { + document_.clear(); + addChildValues_ = false; + indentString_.clear(); + writeCommentBeforeValue(root); + writeValue(root); + writeCommentAfterValueOnSameLine(root); + document_ += '\n'; + return document_; +} + +void StyledWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + pushValue("null"); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble())); + break; + case stringValue: { + // Is NULL possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) + pushValue(valueToQuotedStringN(str, static_cast<size_t>(end - str))); + else + pushValue(""); + break; + } + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else { + writeWithIndent("{"); + indent(); + auto it = members.begin(); + for (;;) { + const String& name = *it; + const Value& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedString(name.c_str())); + document_ += " : "; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + document_ += ','; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void StyledWriter::writeArrayValue(const Value& value) { + size_t size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isArrayMultiLine = isMultilineArray(value); + if (isArrayMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + ArrayIndex index = 0; + for (;;) { + const Value& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + writeIndent(); + writeValue(childValue); + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + document_ += ','; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + document_ += "[ "; + for (size_t index = 0; index < size; ++index) { + if (index > 0) + document_ += ", "; + document_ += childValues_[index]; + } + document_ += " ]"; + } + } +} + +bool StyledWriter::isMultilineArray(const Value& value) { + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { + const Value& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + !childValue.empty()); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast<ArrayIndex>(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void StyledWriter::pushValue(const String& value) { + if (addChildValues_) + childValues_.push_back(value); + else + document_ += value; +} + +void StyledWriter::writeIndent() { + if (!document_.empty()) { + char last = document_[document_.length() - 1]; + if (last == ' ') // already indented + return; + if (last != '\n') // Comments may add new-line + document_ += '\n'; + } + document_ += indentString_; +} + +void StyledWriter::writeWithIndent(const String& value) { + writeIndent(); + document_ += value; +} + +void StyledWriter::indent() { indentString_ += String(indentSize_, ' '); } + +void StyledWriter::unindent() { + assert(indentString_.size() >= indentSize_); + indentString_.resize(indentString_.size() - indentSize_); +} + +void StyledWriter::writeCommentBeforeValue(const Value& root) { + if (!root.hasComment(commentBefore)) + return; + + document_ += '\n'; + writeIndent(); + const String& comment = root.getComment(commentBefore); + String::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + document_ += *iter; + if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/')) + writeIndent(); + ++iter; + } + + // Comments are stripped of trailing newlines, so add one here + document_ += '\n'; +} + +void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) { + if (root.hasComment(commentAfterOnSameLine)) + document_ += " " + root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + document_ += '\n'; + document_ += root.getComment(commentAfter); + document_ += '\n'; + } +} + +bool StyledWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +// Class StyledStreamWriter +// ////////////////////////////////////////////////////////////////// + +StyledStreamWriter::StyledStreamWriter(String indentation) + : document_(nullptr), indentation_(std::move(indentation)), + addChildValues_(), indented_(false) {} + +void StyledStreamWriter::write(OStream& out, const Value& root) { + document_ = &out; + addChildValues_ = false; + indentString_.clear(); + indented_ = true; + writeCommentBeforeValue(root); + if (!indented_) + writeIndent(); + indented_ = true; + writeValue(root); + writeCommentAfterValueOnSameLine(root); + *document_ << "\n"; + document_ = nullptr; // Forget the stream, for safety. +} + +void StyledStreamWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + pushValue("null"); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble())); + break; + case stringValue: { + // Is NULL possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) + pushValue(valueToQuotedStringN(str, static_cast<size_t>(end - str))); + else + pushValue(""); + break; + } + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else { + writeWithIndent("{"); + indent(); + auto it = members.begin(); + for (;;) { + const String& name = *it; + const Value& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedString(name.c_str())); + *document_ << " : "; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void StyledStreamWriter::writeArrayValue(const Value& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isArrayMultiLine = isMultilineArray(value); + if (isArrayMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + const Value& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + if (!indented_) + writeIndent(); + indented_ = true; + writeValue(childValue); + indented_ = false; + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + *document_ << "[ "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + *document_ << ", "; + *document_ << childValues_[index]; + } + *document_ << " ]"; + } + } +} + +bool StyledStreamWriter::isMultilineArray(const Value& value) { + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { + const Value& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + !childValue.empty()); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast<ArrayIndex>(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void StyledStreamWriter::pushValue(const String& value) { + if (addChildValues_) + childValues_.push_back(value); + else + *document_ << value; +} + +void StyledStreamWriter::writeIndent() { + // blep intended this to look at the so-far-written string + // to determine whether we are already indented, but + // with a stream we cannot do that. So we rely on some saved state. + // The caller checks indented_. + *document_ << '\n' << indentString_; +} + +void StyledStreamWriter::writeWithIndent(const String& value) { + if (!indented_) + writeIndent(); + *document_ << value; + indented_ = false; +} + +void StyledStreamWriter::indent() { indentString_ += indentation_; } + +void StyledStreamWriter::unindent() { + assert(indentString_.size() >= indentation_.size()); + indentString_.resize(indentString_.size() - indentation_.size()); +} + +void StyledStreamWriter::writeCommentBeforeValue(const Value& root) { + if (!root.hasComment(commentBefore)) + return; + + if (!indented_) + writeIndent(); + const String& comment = root.getComment(commentBefore); + String::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + *document_ << *iter; + if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/')) + // writeIndent(); // would include newline + *document_ << indentString_; + ++iter; + } + indented_ = false; +} + +void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) { + if (root.hasComment(commentAfterOnSameLine)) + *document_ << ' ' << root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + writeIndent(); + *document_ << root.getComment(commentAfter); + } + indented_ = false; +} + +bool StyledStreamWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +////////////////////////// +// BuiltStyledStreamWriter + +/// Scoped enums are not available until C++11. +struct CommentStyle { + /// Decide whether to write comments. + enum Enum { + None, ///< Drop all comments. + Most, ///< Recover odd behavior of previous versions (not implemented yet). + All ///< Keep all comments. + }; +}; + +struct BuiltStyledStreamWriter : public StreamWriter { + BuiltStyledStreamWriter(String indentation, CommentStyle::Enum cs, + String colonSymbol, String nullSymbol, + String endingLineFeedSymbol, bool useSpecialFloats, + bool emitUTF8, unsigned int precision, + PrecisionType precisionType); + int write(Value const& root, OStream* sout) override; + +private: + void writeValue(Value const& value); + void writeArrayValue(Value const& value); + bool isMultilineArray(Value const& value); + void pushValue(String const& value); + void writeIndent(); + void writeWithIndent(String const& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(Value const& root); + void writeCommentAfterValueOnSameLine(Value const& root); + static bool hasCommentForValue(const Value& value); + + using ChildValues = std::vector<String>; + + ChildValues childValues_; + String indentString_; + unsigned int rightMargin_; + String indentation_; + CommentStyle::Enum cs_; + String colonSymbol_; + String nullSymbol_; + String endingLineFeedSymbol_; + bool addChildValues_ : 1; + bool indented_ : 1; + bool useSpecialFloats_ : 1; + bool emitUTF8_ : 1; + unsigned int precision_; + PrecisionType precisionType_; +}; +BuiltStyledStreamWriter::BuiltStyledStreamWriter( + String indentation, CommentStyle::Enum cs, String colonSymbol, + String nullSymbol, String endingLineFeedSymbol, bool useSpecialFloats, + bool emitUTF8, unsigned int precision, PrecisionType precisionType) + : rightMargin_(74), indentation_(std::move(indentation)), cs_(cs), + colonSymbol_(std::move(colonSymbol)), nullSymbol_(std::move(nullSymbol)), + endingLineFeedSymbol_(std::move(endingLineFeedSymbol)), + addChildValues_(false), indented_(false), + useSpecialFloats_(useSpecialFloats), emitUTF8_(emitUTF8), + precision_(precision), precisionType_(precisionType) {} +int BuiltStyledStreamWriter::write(Value const& root, OStream* sout) { + sout_ = sout; + addChildValues_ = false; + indented_ = true; + indentString_.clear(); + writeCommentBeforeValue(root); + if (!indented_) + writeIndent(); + indented_ = true; + writeValue(root); + writeCommentAfterValueOnSameLine(root); + *sout_ << endingLineFeedSymbol_; + sout_ = nullptr; + return 0; +} +void BuiltStyledStreamWriter::writeValue(Value const& value) { + switch (value.type()) { + case nullValue: + pushValue(nullSymbol_); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_, + precisionType_)); + break; + case stringValue: { + // Is NULL is possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) + pushValue( + valueToQuotedStringN(str, static_cast<size_t>(end - str), emitUTF8_)); + else + pushValue(""); + break; + } + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else { + writeWithIndent("{"); + indent(); + auto it = members.begin(); + for (;;) { + String const& name = *it; + Value const& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent( + valueToQuotedStringN(name.data(), name.length(), emitUTF8_)); + *sout_ << colonSymbol_; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *sout_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isMultiLine = (cs_ == CommentStyle::All) || isMultilineArray(value); + if (isMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + Value const& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + if (!indented_) + writeIndent(); + indented_ = true; + writeValue(childValue); + indented_ = false; + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *sout_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + *sout_ << "["; + if (!indentation_.empty()) + *sout_ << " "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + *sout_ << ((!indentation_.empty()) ? ", " : ","); + *sout_ << childValues_[index]; + } + if (!indentation_.empty()) + *sout_ << " "; + *sout_ << "]"; + } + } +} + +bool BuiltStyledStreamWriter::isMultilineArray(Value const& value) { + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { + Value const& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + !childValue.empty()); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast<ArrayIndex>(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void BuiltStyledStreamWriter::pushValue(String const& value) { + if (addChildValues_) + childValues_.push_back(value); + else + *sout_ << value; +} + +void BuiltStyledStreamWriter::writeIndent() { + // blep intended this to look at the so-far-written string + // to determine whether we are already indented, but + // with a stream we cannot do that. So we rely on some saved state. + // The caller checks indented_. + + if (!indentation_.empty()) { + // In this case, drop newlines too. + *sout_ << '\n' << indentString_; + } +} + +void BuiltStyledStreamWriter::writeWithIndent(String const& value) { + if (!indented_) + writeIndent(); + *sout_ << value; + indented_ = false; +} + +void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; } + +void BuiltStyledStreamWriter::unindent() { + assert(indentString_.size() >= indentation_.size()); + indentString_.resize(indentString_.size() - indentation_.size()); +} + +void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) { + if (cs_ == CommentStyle::None) + return; + if (!root.hasComment(commentBefore)) + return; + + if (!indented_) + writeIndent(); + const String& comment = root.getComment(commentBefore); + String::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + *sout_ << *iter; + if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/')) + // writeIndent(); // would write extra newline + *sout_ << indentString_; + ++iter; + } + indented_ = false; +} + +void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine( + Value const& root) { + if (cs_ == CommentStyle::None) + return; + if (root.hasComment(commentAfterOnSameLine)) + *sout_ << " " + root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + writeIndent(); + *sout_ << root.getComment(commentAfter); + } +} + +// static +bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +/////////////// +// StreamWriter + +StreamWriter::StreamWriter() : sout_(nullptr) {} +StreamWriter::~StreamWriter() = default; +StreamWriter::Factory::~Factory() = default; +StreamWriterBuilder::StreamWriterBuilder() { setDefaults(&settings_); } +StreamWriterBuilder::~StreamWriterBuilder() = default; +StreamWriter* StreamWriterBuilder::newStreamWriter() const { + const String indentation = settings_["indentation"].asString(); + const String cs_str = settings_["commentStyle"].asString(); + const String pt_str = settings_["precisionType"].asString(); + const bool eyc = settings_["enableYAMLCompatibility"].asBool(); + const bool dnp = settings_["dropNullPlaceholders"].asBool(); + const bool usf = settings_["useSpecialFloats"].asBool(); + const bool emitUTF8 = settings_["emitUTF8"].asBool(); + unsigned int pre = settings_["precision"].asUInt(); + CommentStyle::Enum cs = CommentStyle::All; + if (cs_str == "All") { + cs = CommentStyle::All; + } else if (cs_str == "None") { + cs = CommentStyle::None; + } else { + throwRuntimeError("commentStyle must be 'All' or 'None'"); + } + PrecisionType precisionType(significantDigits); + if (pt_str == "significant") { + precisionType = PrecisionType::significantDigits; + } else if (pt_str == "decimal") { + precisionType = PrecisionType::decimalPlaces; + } else { + throwRuntimeError("precisionType must be 'significant' or 'decimal'"); + } + String colonSymbol = " : "; + if (eyc) { + colonSymbol = ": "; + } else if (indentation.empty()) { + colonSymbol = ":"; + } + String nullSymbol = "null"; + if (dnp) { + nullSymbol.clear(); + } + if (pre > 17) + pre = 17; + String endingLineFeedSymbol; + return new BuiltStyledStreamWriter(indentation, cs, colonSymbol, nullSymbol, + endingLineFeedSymbol, usf, emitUTF8, pre, + precisionType); +} + +bool StreamWriterBuilder::validate(Json::Value* invalid) const { + static const auto& valid_keys = *new std::set<String>{ + "indentation", + "commentStyle", + "enableYAMLCompatibility", + "dropNullPlaceholders", + "useSpecialFloats", + "emitUTF8", + "precision", + "precisionType", + }; + for (auto si = settings_.begin(); si != settings_.end(); ++si) { + auto key = si.name(); + if (valid_keys.count(key)) + continue; + if (invalid) + (*invalid)[key] = *si; + else + return false; + } + return invalid ? invalid->empty() : true; +} + +Value& StreamWriterBuilder::operator[](const String& key) { + return settings_[key]; +} +// static +void StreamWriterBuilder::setDefaults(Json::Value* settings) { + //! [StreamWriterBuilderDefaults] + (*settings)["commentStyle"] = "All"; + (*settings)["indentation"] = "\t"; + (*settings)["enableYAMLCompatibility"] = false; + (*settings)["dropNullPlaceholders"] = false; + (*settings)["useSpecialFloats"] = false; + (*settings)["emitUTF8"] = false; + (*settings)["precision"] = 17; + (*settings)["precisionType"] = "significant"; + //! [StreamWriterBuilderDefaults] +} + +String writeString(StreamWriter::Factory const& factory, Value const& root) { + OStringStream sout; + StreamWriterPtr const writer(factory.newStreamWriter()); + writer->write(root, &sout); + return sout.str(); +} + +OStream& operator<<(OStream& sout, Value const& root) { + StreamWriterBuilder builder; + StreamWriterPtr const writer(builder.newStreamWriter()); + writer->write(root, &sout); + return sout; +} + +} // namespace Json diff --git a/thirdparty/openxr/src/loader/.gitignore b/thirdparty/openxr/src/loader/.gitignore new file mode 100644 index 0000000000..5e8e0ba3a4 --- /dev/null +++ b/thirdparty/openxr/src/loader/.gitignore @@ -0,0 +1,5 @@ +# Copyright (c) 2020 The Khronos Group Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +!openxr_loader_for_android.pom diff --git a/thirdparty/openxr/src/loader/android_utilities.cpp b/thirdparty/openxr/src/loader/android_utilities.cpp new file mode 100644 index 0000000000..807a775820 --- /dev/null +++ b/thirdparty/openxr/src/loader/android_utilities.cpp @@ -0,0 +1,319 @@ +// Copyright (c) 2020-2022, The Khronos Group Inc. +// Copyright (c) 2020-2021, Collabora, Ltd. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Initial Author: Ryan Pavlik <ryan.pavlik@collabora.com> + +#include "android_utilities.h" + +#ifdef __ANDROID__ +#include <wrap/android.net.h> +#include <wrap/android.content.h> +#include <wrap/android.database.h> +#include <json/value.h> + +#include <openxr/openxr.h> + +#include <sstream> +#include <vector> +#include <android/log.h> + +#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, "openxr_loader", __VA_ARGS__) +#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, "openxr_loader", __VA_ARGS__) +#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "openxr_loader", __VA_ARGS__) +#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, "openxr_loader", __VA_ARGS__) + +namespace openxr_android { +using wrap::android::content::ContentUris; +using wrap::android::content::Context; +using wrap::android::database::Cursor; +using wrap::android::net::Uri; +using wrap::android::net::Uri_Builder; + +// Code in here corresponds roughly to the Java "BrokerContract" class and subclasses. +namespace { +constexpr auto AUTHORITY = "org.khronos.openxr.runtime_broker"; +constexpr auto SYSTEM_AUTHORITY = "org.khronos.openxr.system_runtime_broker"; +constexpr auto BASE_PATH = "openxr"; +constexpr auto ABI_PATH = "abi"; +constexpr auto RUNTIMES_PATH = "runtimes"; + +constexpr const char *getBrokerAuthority(bool systemBroker) { return systemBroker ? SYSTEM_AUTHORITY : AUTHORITY; } + +struct BaseColumns { + /** + * The unique ID for a row. + */ + [[maybe_unused]] static constexpr auto ID = "_id"; +}; + +/** + * Contains details for the /openxr/[major_ver]/abi/[abi]/runtimes/active URI. + * <p> + * This URI represents a "table" containing at most one item, the currently active runtime. The + * policy of which runtime is chosen to be active (if more than one is installed) is left to the + * content provider. + * <p> + * No sort order is required to be honored by the content provider. + */ +namespace active_runtime { +/** + * Final path component to this URI. + */ +static constexpr auto TABLE_PATH = "active"; + +/** + * Create a content URI for querying the data on the active runtime for a + * given major version of OpenXR. + * + * @param systemBroker If the system runtime broker (instead of the installable one) should be queried. + * @param majorVer The major version of OpenXR. + * @param abi The Android ABI name in use. + * @return A content URI for a single item: the active runtime. + */ +static Uri makeContentUri(bool systemBroker, int majorVersion, const char *abi) { + auto builder = Uri_Builder::construct(); + builder.scheme("content") + .authority(getBrokerAuthority(systemBroker)) + .appendPath(BASE_PATH) + .appendPath(std::to_string(majorVersion)) + .appendPath(ABI_PATH) + .appendPath(abi) + .appendPath(RUNTIMES_PATH) + .appendPath(TABLE_PATH); + ContentUris::appendId(builder, 0); + return builder.build(); +} + +struct Columns : BaseColumns { + /** + * Constant for the PACKAGE_NAME column name + */ + static constexpr auto PACKAGE_NAME = "package_name"; + + /** + * Constant for the NATIVE_LIB_DIR column name + */ + static constexpr auto NATIVE_LIB_DIR = "native_lib_dir"; + + /** + * Constant for the SO_FILENAME column name + */ + static constexpr auto SO_FILENAME = "so_filename"; + + /** + * Constant for the HAS_FUNCTIONS column name. + * <p> + * If this column contains true, you should check the /functions/ URI for that runtime. + */ + static constexpr auto HAS_FUNCTIONS = "has_functions"; +}; +} // namespace active_runtime + +/** + * Contains details for the /openxr/[major_ver]/abi/[abi]/runtimes/[package]/functions URI. + * <p> + * This URI is for package-specific function name remapping. Since this is an optional field in + * the corresponding JSON manifests for OpenXR, it is optional here as well. If the active + * runtime contains "true" in its "has_functions" column, then this table must exist and be + * queryable. + * <p> + * No sort order is required to be honored by the content provider. + */ +namespace functions { +/** + * Final path component to this URI. + */ +static constexpr auto TABLE_PATH = "functions"; + +/** + * Create a content URI for querying all rows of the function remapping data for a given + * runtime package and major version of OpenXR. + * + * @param systemBroker If the system runtime broker (instead of the installable one) should be queried. + * @param majorVer The major version of OpenXR. + * @param packageName The package name of the runtime. + * @param abi The Android ABI name in use. + * @return A content URI for the entire table: the function remapping for that runtime. + */ +static Uri makeContentUri(bool systemBroker, int majorVersion, std::string const &packageName, const char *abi) { + auto builder = Uri_Builder::construct(); + builder.scheme("content") + .authority(getBrokerAuthority(systemBroker)) + .appendPath(BASE_PATH) + .appendPath(std::to_string(majorVersion)) + .appendPath(ABI_PATH) + .appendPath(abi) + .appendPath(RUNTIMES_PATH) + .appendPath(packageName) + .appendPath(TABLE_PATH); + return builder.build(); +} + +struct Columns : BaseColumns { + /** + * Constant for the FUNCTION_NAME column name + */ + static constexpr auto FUNCTION_NAME = "function_name"; + + /** + * Constant for the SYMBOL_NAME column name + */ + static constexpr auto SYMBOL_NAME = "symbol_name"; +}; +} // namespace functions + +} // namespace + +static inline jni::Array<std::string> makeArray(std::initializer_list<const char *> &&list) { + auto ret = jni::Array<std::string>{(long)list.size()}; + long i = 0; + for (auto &&elt : list) { + ret.setElement(i, elt); + ++i; + } + return ret; +} +static constexpr auto TAG = "OpenXR-Loader"; + +#if defined(__arm__) +static constexpr auto ABI = "armeabi-v7l"; +#elif defined(__aarch64__) +static constexpr auto ABI = "arm64-v8a"; +#elif defined(__i386__) +static constexpr auto ABI = "x86"; +#elif defined(__x86_64__) +static constexpr auto ABI = "x86_64"; +#else +#error "Unknown ABI!" +#endif + +/// Helper class to generate the jsoncpp object corresponding to a synthetic runtime manifest. +class JsonManifestBuilder { + public: + JsonManifestBuilder(const std::string &libraryPathParent, const std::string &libraryPath); + JsonManifestBuilder &function(const std::string &functionName, const std::string &symbolName); + + Json::Value build() const { return root_node; } + + private: + Json::Value root_node; +}; + +inline JsonManifestBuilder::JsonManifestBuilder(const std::string &libraryPathParent, const std::string &libraryPath) + : root_node(Json::objectValue) { + root_node["file_format_version"] = "1.0.0"; + root_node["instance_extensions"] = Json::Value(Json::arrayValue); + root_node["functions"] = Json::Value(Json::objectValue); + root_node[libraryPathParent] = Json::objectValue; + root_node[libraryPathParent]["library_path"] = libraryPath; +} + +inline JsonManifestBuilder &JsonManifestBuilder::function(const std::string &functionName, const std::string &symbolName) { + root_node["functions"][functionName] = symbolName; + return *this; +} + +static constexpr const char *getBrokerTypeName(bool systemBroker) { return systemBroker ? "system" : "installable"; } + +static int populateFunctions(wrap::android::content::Context const &context, bool systemBroker, const std::string &packageName, + JsonManifestBuilder &builder) { + jni::Array<std::string> projection = makeArray({functions::Columns::FUNCTION_NAME, functions::Columns::SYMBOL_NAME}); + + auto uri = functions::makeContentUri(systemBroker, XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), packageName, ABI); + ALOGI("populateFunctions: Querying URI: %s", uri.toString().c_str()); + + Cursor cursor = context.getContentResolver().query(uri, projection); + + if (cursor.isNull()) { + ALOGE("Null cursor when querying content resolver for functions."); + return -1; + } + if (cursor.getCount() < 1) { + ALOGE("Non-null but empty cursor when querying content resolver for functions."); + cursor.close(); + return -1; + } + auto functionIndex = cursor.getColumnIndex(functions::Columns::FUNCTION_NAME); + auto symbolIndex = cursor.getColumnIndex(functions::Columns::SYMBOL_NAME); + while (cursor.moveToNext()) { + builder.function(cursor.getString(functionIndex), cursor.getString(symbolIndex)); + } + + cursor.close(); + return 0; +} + +/// Get cursor for active runtime, parameterized by whether or not we use the system broker +static bool getActiveRuntimeCursor(wrap::android::content::Context const &context, jni::Array<std::string> const &projection, + bool systemBroker, Cursor &cursor) { + auto uri = active_runtime::makeContentUri(systemBroker, XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), ABI); + ALOGI("getActiveRuntimeCursor: Querying URI: %s", uri.toString().c_str()); + try { + cursor = context.getContentResolver().query(uri, projection); + } catch (const std::exception &e) { + ALOGW("Exception when querying %s content resolver: %s", getBrokerTypeName(systemBroker), e.what()); + cursor = {}; + return false; + } + + if (cursor.isNull()) { + ALOGW("Null cursor when querying %s content resolver.", getBrokerTypeName(systemBroker)); + cursor = {}; + return false; + } + if (cursor.getCount() < 1) { + ALOGW("Non-null but empty cursor when querying %s content resolver.", getBrokerTypeName(systemBroker)); + cursor.close(); + cursor = {}; + return false; + } + return true; +} + +int getActiveRuntimeVirtualManifest(wrap::android::content::Context const &context, Json::Value &virtualManifest) { + jni::Array<std::string> projection = makeArray({active_runtime::Columns::PACKAGE_NAME, active_runtime::Columns::NATIVE_LIB_DIR, + active_runtime::Columns::SO_FILENAME, active_runtime::Columns::HAS_FUNCTIONS}); + + // First, try getting the installable broker's provider + bool systemBroker = false; + Cursor cursor; + if (!getActiveRuntimeCursor(context, projection, systemBroker, cursor)) { + // OK, try the system broker as a fallback. + systemBroker = true; + getActiveRuntimeCursor(context, projection, systemBroker, cursor); + } + + if (cursor.isNull()) { + // Couldn't find either broker + ALOGE("Could access neither the installable nor system runtime broker."); + return -1; + } + + cursor.moveToFirst(); + + auto filename = cursor.getString(cursor.getColumnIndex(active_runtime::Columns::SO_FILENAME)); + auto libDir = cursor.getString(cursor.getColumnIndex(active_runtime::Columns::NATIVE_LIB_DIR)); + auto packageName = cursor.getString(cursor.getColumnIndex(active_runtime::Columns::PACKAGE_NAME)); + + auto hasFunctions = cursor.getInt(cursor.getColumnIndex(active_runtime::Columns::HAS_FUNCTIONS)) == 1; + __android_log_print(ANDROID_LOG_INFO, TAG, "Got runtime: package: %s, so filename: %s, native lib dir: %s, has functions: %s", + packageName.c_str(), libDir.c_str(), filename.c_str(), (hasFunctions ? "yes" : "no")); + + auto lib_path = libDir + "/" + filename; + cursor.close(); + + JsonManifestBuilder builder{"runtime", lib_path}; + if (hasFunctions) { + int result = populateFunctions(context, systemBroker, packageName, builder); + if (result != 0) { + return result; + } + } + virtualManifest = builder.build(); + return 0; +} +} // namespace openxr_android + +#endif // __ANDROID__ diff --git a/thirdparty/openxr/src/loader/android_utilities.h b/thirdparty/openxr/src/loader/android_utilities.h new file mode 100644 index 0000000000..adb8abaf1f --- /dev/null +++ b/thirdparty/openxr/src/loader/android_utilities.h @@ -0,0 +1,32 @@ +// Copyright (c) 2020-2022, The Khronos Group Inc. +// Copyright (c) 2020-2021, Collabora, Ltd. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Initial Author: Ryan Pavlik <ryan.pavlik@collabora.com> + +#pragma once +#ifdef __ANDROID__ + +#include "wrap/android.content.h" + +#include <string> +namespace Json { +class Value; +} // namespace Json + +namespace openxr_android { +using wrap::android::content::Context; + +/*! + * Find the single active OpenXR runtime on the system, and return a constructed JSON object representing it. + * + * @param context An Android context, preferably an Activity Context. + * @param[out] virtualManifest The Json::Value to fill with the virtual manifest. + * + * @return 0 on success, something else on failure. + */ +int getActiveRuntimeVirtualManifest(wrap::android::content::Context const &context, Json::Value &virtualManifest); +} // namespace openxr_android + +#endif // __ANDROID__ diff --git a/thirdparty/openxr/src/loader/api_layer_interface.cpp b/thirdparty/openxr/src/loader/api_layer_interface.cpp new file mode 100644 index 0000000000..c3fd5bb7f1 --- /dev/null +++ b/thirdparty/openxr/src/loader/api_layer_interface.cpp @@ -0,0 +1,399 @@ +// Copyright (c) 2017-2022, The Khronos Group Inc. +// Copyright (c) 2017-2019 Valve Corporation +// Copyright (c) 2017-2019 LunarG, Inc. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Initial Author: Mark Young <marky@lunarg.com> +// + +#include "api_layer_interface.hpp" + +#include "loader_interfaces.h" +#include "loader_logger.hpp" +#include "loader_platform.hpp" +#include "manifest_file.hpp" +#include "platform_utils.hpp" + +#include <openxr/openxr.h> + +#include <cstring> +#include <memory> +#include <sstream> +#include <string> +#include <utility> +#include <vector> + +#define OPENXR_ENABLE_LAYERS_ENV_VAR "XR_ENABLE_API_LAYERS" + +// Add any layers defined in the loader layer environment variable. +static void AddEnvironmentApiLayers(std::vector<std::string>& enabled_layers) { + std::string layers = PlatformUtilsGetEnv(OPENXR_ENABLE_LAYERS_ENV_VAR); + + std::size_t last_found = 0; + std::size_t found = layers.find_first_of(PATH_SEPARATOR); + std::string cur_search; + + // Handle any path listings in the string (separated by the appropriate path separator) + while (found != std::string::npos) { + cur_search = layers.substr(last_found, found - last_found); + enabled_layers.push_back(cur_search); + last_found = found + 1; + found = layers.find_first_of(PATH_SEPARATOR, last_found); + } + + // If there's something remaining in the string, copy it over + if (last_found < layers.size()) { + cur_search = layers.substr(last_found); + enabled_layers.push_back(cur_search); + } +} + +XrResult ApiLayerInterface::GetApiLayerProperties(const std::string& openxr_command, uint32_t incoming_count, + uint32_t* outgoing_count, XrApiLayerProperties* api_layer_properties) { + std::vector<std::unique_ptr<ApiLayerManifestFile>> manifest_files; + uint32_t manifest_count = 0; + + // Validate props struct before proceeding + if (0 < incoming_count && nullptr != api_layer_properties) { + for (uint32_t i = 0; i < incoming_count; i++) { + if (XR_TYPE_API_LAYER_PROPERTIES != api_layer_properties[i].type) { + LoaderLogger::LogErrorMessage(openxr_command, + "VUID-XrApiLayerProperties-type-type: unknown type in api_layer_properties"); + return XR_ERROR_VALIDATION_FAILURE; + } + } + } + + // "Independent of elementCapacityInput or elements parameters, elementCountOutput must be a valid pointer, + // and the function sets elementCountOutput." - 2.11 + if (nullptr == outgoing_count) { + return XR_ERROR_VALIDATION_FAILURE; + } + + // Find any implicit layers which we may need to report information for. + XrResult result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_IMPLICIT_API_LAYER, manifest_files); + if (XR_SUCCEEDED(result)) { + // Find any explicit layers which we may need to report information for. + result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_EXPLICIT_API_LAYER, manifest_files); + } + if (XR_FAILED(result)) { + LoaderLogger::LogErrorMessage(openxr_command, + "ApiLayerInterface::GetApiLayerProperties - failed searching for API layer manifest files"); + return result; + } + + manifest_count = static_cast<uint32_t>(manifest_files.size()); + if (nullptr == outgoing_count) { + LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties", + "VUID-xrEnumerateApiLayerProperties-propertyCountOutput-parameter: null propertyCountOutput"); + return XR_ERROR_VALIDATION_FAILURE; + } + + *outgoing_count = manifest_count; + if (0 == incoming_count) { + // capacity check only + return XR_SUCCESS; + } + if (nullptr == api_layer_properties) { + // incoming_count is not 0 BUT the api_layer_properties is NULL + LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties", + "VUID-xrEnumerateApiLayerProperties-properties-parameter: non-zero capacity but null array"); + return XR_ERROR_VALIDATION_FAILURE; + } + if (incoming_count < manifest_count) { + LoaderLogger::LogErrorMessage( + "xrEnumerateInstanceExtensionProperties", + "VUID-xrEnumerateApiLayerProperties-propertyCapacityInput-parameter: insufficient space in array"); + return XR_ERROR_SIZE_INSUFFICIENT; + } + + for (uint32_t prop = 0; prop < incoming_count && prop < manifest_count; ++prop) { + manifest_files[prop]->PopulateApiLayerProperties(api_layer_properties[prop]); + } + return XR_SUCCESS; +} + +XrResult ApiLayerInterface::GetInstanceExtensionProperties(const std::string& openxr_command, const char* layer_name, + std::vector<XrExtensionProperties>& extension_properties) { + std::vector<std::unique_ptr<ApiLayerManifestFile>> manifest_files; + + // If a layer name is supplied, only use the information out of that one layer + if (nullptr != layer_name && 0 != strlen(layer_name)) { + XrResult result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_IMPLICIT_API_LAYER, manifest_files); + if (XR_SUCCEEDED(result)) { + // Find any explicit layers which we may need to report information for. + result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_EXPLICIT_API_LAYER, manifest_files); + if (XR_FAILED(result)) { + LoaderLogger::LogErrorMessage( + openxr_command, + "ApiLayerInterface::GetInstanceExtensionProperties - failed searching for API layer manifest files"); + return result; + } + + bool found = false; + auto num_files = static_cast<uint32_t>(manifest_files.size()); + for (uint32_t man_file = 0; man_file < num_files; ++man_file) { + // If a layer with the provided name exists, get it's instance extension information. + if (manifest_files[man_file]->LayerName() == layer_name) { + manifest_files[man_file]->GetInstanceExtensionProperties(extension_properties); + found = true; + break; + } + } + + // If nothing found, report 0 + if (!found) { + return XR_ERROR_API_LAYER_NOT_PRESENT; + } + } + // Otherwise, we want to add only implicit API layers and explicit API layers enabled using the environment variables + } else { + XrResult result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_IMPLICIT_API_LAYER, manifest_files); + if (XR_SUCCEEDED(result)) { + // Find any environmentally enabled explicit layers. If they're present, treat them like implicit layers + // since we know that they're going to be enabled. + std::vector<std::string> env_enabled_layers; + AddEnvironmentApiLayers(env_enabled_layers); + if (!env_enabled_layers.empty()) { + std::vector<std::unique_ptr<ApiLayerManifestFile>> exp_layer_man_files = {}; + result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_EXPLICIT_API_LAYER, exp_layer_man_files); + if (XR_SUCCEEDED(result)) { + for (auto& exp_layer_man_file : exp_layer_man_files) { + for (std::string& enabled_layer : env_enabled_layers) { + // If this is an enabled layer, transfer it over to the manifest list. + if (enabled_layer == exp_layer_man_file->LayerName()) { + manifest_files.push_back(std::move(exp_layer_man_file)); + break; + } + } + } + } + } + } + + // Grab the layer instance extensions information + auto num_files = static_cast<uint32_t>(manifest_files.size()); + for (uint32_t man_file = 0; man_file < num_files; ++man_file) { + manifest_files[man_file]->GetInstanceExtensionProperties(extension_properties); + } + } + return XR_SUCCESS; +} + +XrResult ApiLayerInterface::LoadApiLayers(const std::string& openxr_command, uint32_t enabled_api_layer_count, + const char* const* enabled_api_layer_names, + std::vector<std::unique_ptr<ApiLayerInterface>>& api_layer_interfaces) { + XrResult last_error = XR_SUCCESS; + std::unordered_set<std::string> layers_already_found; + + bool any_loaded = false; + std::vector<std::unique_ptr<ApiLayerManifestFile>> enabled_layer_manifest_files_in_init_order = {}; + + // Find any implicit layers. + XrResult result = + ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_IMPLICIT_API_LAYER, enabled_layer_manifest_files_in_init_order); + + for (const auto& enabled_layer_manifest_file : enabled_layer_manifest_files_in_init_order) { + layers_already_found.insert(enabled_layer_manifest_file->LayerName()); + } + + // Find any explicit layers. + std::vector<std::unique_ptr<ApiLayerManifestFile>> explicit_layer_manifest_files = {}; + + if (XR_SUCCEEDED(result)) { + result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_EXPLICIT_API_LAYER, explicit_layer_manifest_files); + } + + bool found_all_layers = true; + + if (XR_SUCCEEDED(result)) { + // Put all explicit and then xrCreateInstance enabled layers into a string vector + + std::vector<std::string> enabled_explicit_api_layer_names = {}; + + AddEnvironmentApiLayers(enabled_explicit_api_layer_names); + + if (enabled_api_layer_count > 0) { + if (nullptr == enabled_api_layer_names) { + LoaderLogger::LogErrorMessage( + "xrCreateInstance", + "VUID-XrInstanceCreateInfo-enabledApiLayerNames-parameter: enabledApiLayerCount is non-0 but array is NULL"); + LoaderLogger::LogErrorMessage( + "xrCreateInstance", "VUID-xrCreateInstance-info-parameter: something wrong with XrInstanceCreateInfo contents"); + return XR_ERROR_VALIDATION_FAILURE; + } + + std::copy(enabled_api_layer_names, enabled_api_layer_names + enabled_api_layer_count, + std::back_inserter(enabled_explicit_api_layer_names)); + } + + // add explicit layers to list of layers to enable + for (const auto& layer_name : enabled_explicit_api_layer_names) { + bool found_this_layer = false; + + for (auto it = explicit_layer_manifest_files.begin(); it != explicit_layer_manifest_files.end();) { + bool erased_layer_manifest_file = false; + + if (layers_already_found.count(layer_name) > 0) { + found_this_layer = true; + } else if (layer_name == (*it)->LayerName()) { + found_this_layer = true; + layers_already_found.insert(layer_name); + enabled_layer_manifest_files_in_init_order.push_back(std::move(*it)); + it = explicit_layer_manifest_files.erase(it); + erased_layer_manifest_file = true; + } + + if (!erased_layer_manifest_file) { + it++; + } + } + + // If even one of the layers wasn't found, we want to return an error + if (!found_this_layer) { + found_all_layers = false; + std::string error_message = "ApiLayerInterface::LoadApiLayers - failed to find layer "; + error_message += layer_name; + LoaderLogger::LogErrorMessage(openxr_command, error_message); + } + } + } + + for (std::unique_ptr<ApiLayerManifestFile>& manifest_file : enabled_layer_manifest_files_in_init_order) { + LoaderPlatformLibraryHandle layer_library = LoaderPlatformLibraryOpen(manifest_file->LibraryPath()); + if (nullptr == layer_library) { + if (!any_loaded) { + last_error = XR_ERROR_FILE_ACCESS_ERROR; + } + std::string library_message = LoaderPlatformLibraryOpenError(manifest_file->LibraryPath()); + std::string warning_message = "ApiLayerInterface::LoadApiLayers skipping layer "; + warning_message += manifest_file->LayerName(); + warning_message += ", failed to load with message \""; + warning_message += library_message; + warning_message += "\""; + LoaderLogger::LogWarningMessage(openxr_command, warning_message); + continue; + } + + // Get and settle on an layer interface version (using any provided name if required). + std::string function_name = manifest_file->GetFunctionName("xrNegotiateLoaderApiLayerInterface"); + auto negotiate = reinterpret_cast<PFN_xrNegotiateLoaderApiLayerInterface>( + LoaderPlatformLibraryGetProcAddr(layer_library, function_name)); + + if (nullptr == negotiate) { + std::ostringstream oss; + oss << "ApiLayerInterface::LoadApiLayers skipping layer " << manifest_file->LayerName() + << " because negotiation function " << function_name << " was not found"; + LoaderLogger::LogErrorMessage(openxr_command, oss.str()); + LoaderPlatformLibraryClose(layer_library); + last_error = XR_ERROR_API_LAYER_NOT_PRESENT; + continue; + } + + // Loader info for negotiation + XrNegotiateLoaderInfo loader_info = {}; + loader_info.structType = XR_LOADER_INTERFACE_STRUCT_LOADER_INFO; + loader_info.structVersion = XR_LOADER_INFO_STRUCT_VERSION; + loader_info.structSize = sizeof(XrNegotiateLoaderInfo); + loader_info.minInterfaceVersion = 1; + loader_info.maxInterfaceVersion = XR_CURRENT_LOADER_API_LAYER_VERSION; + loader_info.minApiVersion = XR_MAKE_VERSION(1, 0, 0); + loader_info.maxApiVersion = XR_MAKE_VERSION(1, 0x3ff, 0xfff); // Maximum allowed version for this major version. + + // Set up the layer return structure + XrNegotiateApiLayerRequest api_layer_info = {}; + api_layer_info.structType = XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST; + api_layer_info.structVersion = XR_API_LAYER_INFO_STRUCT_VERSION; + api_layer_info.structSize = sizeof(XrNegotiateApiLayerRequest); + + XrResult res = negotiate(&loader_info, manifest_file->LayerName().c_str(), &api_layer_info); + // If we supposedly succeeded, but got a nullptr for getInstanceProcAddr + // then something still went wrong, so return with an error. + if (XR_SUCCEEDED(res) && nullptr == api_layer_info.getInstanceProcAddr) { + std::string warning_message = "ApiLayerInterface::LoadApiLayers skipping layer "; + warning_message += manifest_file->LayerName(); + warning_message += ", negotiation did not return a valid getInstanceProcAddr"; + LoaderLogger::LogWarningMessage(openxr_command, warning_message); + res = XR_ERROR_FILE_CONTENTS_INVALID; + } + if (XR_FAILED(res)) { + if (!any_loaded) { + last_error = res; + } + std::ostringstream oss; + oss << "ApiLayerInterface::LoadApiLayers skipping layer " << manifest_file->LayerName() + << " due to failed negotiation with error " << res; + LoaderLogger::LogWarningMessage(openxr_command, oss.str()); + LoaderPlatformLibraryClose(layer_library); + continue; + } + + { + std::ostringstream oss; + oss << "ApiLayerInterface::LoadApiLayers succeeded loading layer " << manifest_file->LayerName() + << " using interface version " << api_layer_info.layerInterfaceVersion << " and OpenXR API version " + << XR_VERSION_MAJOR(api_layer_info.layerApiVersion) << "." << XR_VERSION_MINOR(api_layer_info.layerApiVersion); + LoaderLogger::LogInfoMessage(openxr_command, oss.str()); + } + + // Grab the list of extensions this layer supports for easy filtering after the + // xrCreateInstance call + std::vector<std::string> supported_extensions; + std::vector<XrExtensionProperties> extension_properties; + manifest_file->GetInstanceExtensionProperties(extension_properties); + supported_extensions.reserve(extension_properties.size()); + for (XrExtensionProperties& ext_prop : extension_properties) { + supported_extensions.emplace_back(ext_prop.extensionName); + } + + // Add this API layer to the vector + api_layer_interfaces.emplace_back(new ApiLayerInterface(manifest_file->LayerName(), layer_library, supported_extensions, + api_layer_info.getInstanceProcAddr, + api_layer_info.createApiLayerInstance)); + + // If we load one, clear all errors. + any_loaded = true; + last_error = XR_SUCCESS; + } + + // Set error here to preserve prior error behavior + if (!found_all_layers) { + last_error = XR_ERROR_API_LAYER_NOT_PRESENT; + } + + // If we failed catastrophically for some reason, clean up everything. + if (XR_FAILED(last_error)) { + api_layer_interfaces.clear(); + } + + return last_error; +} + +ApiLayerInterface::ApiLayerInterface(const std::string& layer_name, LoaderPlatformLibraryHandle layer_library, + std::vector<std::string>& supported_extensions, + PFN_xrGetInstanceProcAddr get_instance_proc_addr, + PFN_xrCreateApiLayerInstance create_api_layer_instance) + : _layer_name(layer_name), + _layer_library(layer_library), + _get_instance_proc_addr(get_instance_proc_addr), + _create_api_layer_instance(create_api_layer_instance), + _supported_extensions(supported_extensions) {} + +ApiLayerInterface::~ApiLayerInterface() { + std::string info_message = "ApiLayerInterface being destroyed for layer "; + info_message += _layer_name; + LoaderLogger::LogInfoMessage("", info_message); + LoaderPlatformLibraryClose(_layer_library); +} + +bool ApiLayerInterface::SupportsExtension(const std::string& extension_name) const { + bool found_prop = false; + for (const std::string& supported_extension : _supported_extensions) { + if (supported_extension == extension_name) { + found_prop = true; + break; + } + } + return found_prop; +} diff --git a/thirdparty/openxr/src/loader/api_layer_interface.hpp b/thirdparty/openxr/src/loader/api_layer_interface.hpp new file mode 100644 index 0000000000..b93e44584e --- /dev/null +++ b/thirdparty/openxr/src/loader/api_layer_interface.hpp @@ -0,0 +1,54 @@ +// Copyright (c) 2017-2022, The Khronos Group Inc. +// Copyright (c) 2017-2019 Valve Corporation +// Copyright (c) 2017-2019 LunarG, Inc. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Initial Author: Mark Young <marky@lunarg.com> +// + +#pragma once + +#include <string> +#include <vector> +#include <memory> + +#include <openxr/openxr.h> + +#include "loader_platform.hpp" +#include "loader_interfaces.h" + +struct XrGeneratedDispatchTable; + +class ApiLayerInterface { + public: + // Factory method + static XrResult LoadApiLayers(const std::string& openxr_command, uint32_t enabled_api_layer_count, + const char* const* enabled_api_layer_names, + std::vector<std::unique_ptr<ApiLayerInterface>>& api_layer_interfaces); + // Static queries + static XrResult GetApiLayerProperties(const std::string& openxr_command, uint32_t incoming_count, uint32_t* outgoing_count, + XrApiLayerProperties* api_layer_properties); + static XrResult GetInstanceExtensionProperties(const std::string& openxr_command, const char* layer_name, + std::vector<XrExtensionProperties>& extension_properties); + + ApiLayerInterface(const std::string& layer_name, LoaderPlatformLibraryHandle layer_library, + std::vector<std::string>& supported_extensions, PFN_xrGetInstanceProcAddr get_instance_proc_addr, + PFN_xrCreateApiLayerInstance create_api_layer_instance); + virtual ~ApiLayerInterface(); + + PFN_xrGetInstanceProcAddr GetInstanceProcAddrFuncPointer() { return _get_instance_proc_addr; } + PFN_xrCreateApiLayerInstance GetCreateApiLayerInstanceFuncPointer() { return _create_api_layer_instance; } + + std::string LayerName() { return _layer_name; } + + // Generated methods + bool SupportsExtension(const std::string& extension_name) const; + + private: + std::string _layer_name; + LoaderPlatformLibraryHandle _layer_library; + PFN_xrGetInstanceProcAddr _get_instance_proc_addr; + PFN_xrCreateApiLayerInstance _create_api_layer_instance; + std::vector<std::string> _supported_extensions; +}; diff --git a/thirdparty/openxr/src/loader/exception_handling.hpp b/thirdparty/openxr/src/loader/exception_handling.hpp new file mode 100644 index 0000000000..428dd00279 --- /dev/null +++ b/thirdparty/openxr/src/loader/exception_handling.hpp @@ -0,0 +1,40 @@ +// Copyright (c) 2019-2022, The Khronos Group Inc. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Initial Author: Ryan Pavlik <ryan.pavlik@collabora.com> +// +// Provides protection for C ABI functions if standard library functions may throw. + +#pragma once + +#ifdef OPENXR_HAVE_COMMON_CONFIG +#include "common_config.h" +#endif // OPENXR_HAVE_COMMON_CONFIG + +#ifdef XRLOADER_DISABLE_EXCEPTION_HANDLING + +#define XRLOADER_ABI_TRY +#define XRLOADER_ABI_CATCH_BAD_ALLOC_OOM +#define XRLOADER_ABI_CATCH_FALLBACK + +#else + +#include <stdexcept> +#define XRLOADER_ABI_TRY try +#define XRLOADER_ABI_CATCH_BAD_ALLOC_OOM \ + catch (const std::bad_alloc&) { \ + LoaderLogger::LogErrorMessage("", "failed allocating memory"); \ + return XR_ERROR_OUT_OF_MEMORY; \ + } +#define XRLOADER_ABI_CATCH_FALLBACK \ + catch (const std::exception& e) { \ + LoaderLogger::LogErrorMessage("", "Unknown failure: " + std::string(e.what())); \ + return XR_ERROR_RUNTIME_FAILURE; \ + } \ + catch (...) { \ + LoaderLogger::LogErrorMessage("", "Unknown failure"); \ + return XR_ERROR_RUNTIME_FAILURE; \ + } + +#endif diff --git a/thirdparty/openxr/src/loader/loader_core.cpp b/thirdparty/openxr/src/loader/loader_core.cpp new file mode 100644 index 0000000000..375f1c93ba --- /dev/null +++ b/thirdparty/openxr/src/loader/loader_core.cpp @@ -0,0 +1,847 @@ +// Copyright (c) 2017-2022, The Khronos Group Inc. +// Copyright (c) 2017-2019 Valve Corporation +// Copyright (c) 2017-2019 LunarG, Inc. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Initial Authors: Mark Young <marky@lunarg.com>, Dave Houlton <daveh@lunarg.com> +// + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif // defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) + +#include "api_layer_interface.hpp" +#include "exception_handling.hpp" +#include "hex_and_handles.h" +#include "loader_instance.hpp" +#include "loader_logger_recorders.hpp" +#include "loader_logger.hpp" +#include "loader_platform.hpp" +#include "runtime_interface.hpp" +#include "xr_generated_dispatch_table.h" +#include "xr_generated_loader.hpp" + +#include <openxr/openxr.h> + +#include <cstring> +#include <memory> +#include <mutex> +#include <sstream> +#include <string> +#include <utility> +#include <vector> + +// Global loader lock to: +// 1. Ensure ActiveLoaderInstance get and set operations are done atomically. +// 2. Ensure RuntimeInterface isn't used to unload the runtime while the runtime is in use. +std::mutex &GetGlobalLoaderMutex() { + static std::mutex loader_mutex; + return loader_mutex; +} + +// Prototypes for the debug utils calls used internally. +static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineCreateDebugUtilsMessengerEXT( + XrInstance instance, const XrDebugUtilsMessengerCreateInfoEXT *createInfo, XrDebugUtilsMessengerEXT *messenger); +static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger); + +// Terminal functions needed by xrCreateInstance. +static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermGetInstanceProcAddr(XrInstance, const char *, PFN_xrVoidFunction *); +static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateInstance(const XrInstanceCreateInfo *, XrInstance *); +static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateApiLayerInstance(const XrInstanceCreateInfo *, + const struct XrApiLayerCreateInfo *, XrInstance *); +static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermSetDebugUtilsObjectNameEXT(XrInstance, const XrDebugUtilsObjectNameInfoEXT *); +static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateDebugUtilsMessengerEXT(XrInstance, + const XrDebugUtilsMessengerCreateInfoEXT *, + XrDebugUtilsMessengerEXT *); +static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT); +static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermSubmitDebugUtilsMessageEXT( + XrInstance instance, XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, XrDebugUtilsMessageTypeFlagsEXT messageTypes, + const XrDebugUtilsMessengerCallbackDataEXT *callbackData); + +// Utility template function meant to validate if a fixed size string contains +// a null-terminator. +template <size_t max_length> +inline bool IsMissingNullTerminator(const char (&str)[max_length]) { + for (size_t index = 0; index < max_length; ++index) { + if (str[index] == '\0') { + return false; + } + } + return true; +} + +// ---- Core 1.0 manual loader trampoline functions +#ifdef XR_KHR_LOADER_INIT_SUPPORT // platforms that support XR_KHR_loader_init. +XRAPI_ATTR XrResult XRAPI_CALL LoaderXrInitializeLoaderKHR(const XrLoaderInitInfoBaseHeaderKHR *loaderInitInfo) XRLOADER_ABI_TRY { + LoaderLogger::LogVerboseMessage("xrInitializeLoaderKHR", "Entering loader trampoline"); + return InitializeLoader(loaderInitInfo); +} +XRLOADER_ABI_CATCH_FALLBACK +#endif + +static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrEnumerateApiLayerProperties(uint32_t propertyCapacityInput, + uint32_t *propertyCountOutput, + XrApiLayerProperties *properties) XRLOADER_ABI_TRY { + LoaderLogger::LogVerboseMessage("xrEnumerateApiLayerProperties", "Entering loader trampoline"); + + // Make sure only one thread is attempting to read the JSON files at a time. + std::unique_lock<std::mutex> loader_lock(GetGlobalLoaderMutex()); + + XrResult result = ApiLayerInterface::GetApiLayerProperties("xrEnumerateApiLayerProperties", propertyCapacityInput, + propertyCountOutput, properties); + if (XR_FAILED(result)) { + LoaderLogger::LogErrorMessage("xrEnumerateApiLayerProperties", "Failed ApiLayerInterface::GetApiLayerProperties"); + } + + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +static XRAPI_ATTR XrResult XRAPI_CALL +LoaderXrEnumerateInstanceExtensionProperties(const char *layerName, uint32_t propertyCapacityInput, uint32_t *propertyCountOutput, + XrExtensionProperties *properties) XRLOADER_ABI_TRY { + bool just_layer_properties = false; + LoaderLogger::LogVerboseMessage("xrEnumerateInstanceExtensionProperties", "Entering loader trampoline"); + + // "Independent of elementCapacityInput or elements parameters, elementCountOutput must be a valid pointer, + // and the function sets elementCountOutput." - 2.11 + if (nullptr == propertyCountOutput) { + return XR_ERROR_VALIDATION_FAILURE; + } + + if (nullptr != layerName && 0 != strlen(layerName)) { + // Application is only interested in layer's properties, not all of them. + just_layer_properties = true; + } + + std::vector<XrExtensionProperties> extension_properties = {}; + XrResult result; + + { + // Make sure the runtime isn't unloaded while this call is in progress. + std::unique_lock<std::mutex> loader_lock(GetGlobalLoaderMutex()); + + // Get the layer extension properties + result = ApiLayerInterface::GetInstanceExtensionProperties("xrEnumerateInstanceExtensionProperties", layerName, + extension_properties); + if (XR_SUCCEEDED(result) && !just_layer_properties) { + // If not specific to a layer, get the runtime extension properties + result = RuntimeInterface::LoadRuntime("xrEnumerateInstanceExtensionProperties"); + if (XR_SUCCEEDED(result)) { + RuntimeInterface::GetRuntime().GetInstanceExtensionProperties(extension_properties); + } else { + LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties", + "Failed to find default runtime with RuntimeInterface::LoadRuntime()"); + } + } + } + + if (XR_FAILED(result)) { + LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties", "Failed querying extension properties"); + return result; + } + + // If this is not in reference to a specific layer, then add the loader-specific extension properties as well. + // These are extensions that the loader directly supports. + if (!just_layer_properties) { + for (const XrExtensionProperties &loader_prop : LoaderInstance::LoaderSpecificExtensions()) { + bool found_prop = false; + for (XrExtensionProperties &existing_prop : extension_properties) { + if (0 == strcmp(existing_prop.extensionName, loader_prop.extensionName)) { + found_prop = true; + // Use the loader version if it is newer + if (existing_prop.extensionVersion < loader_prop.extensionVersion) { + existing_prop.extensionVersion = loader_prop.extensionVersion; + } + break; + } + } + // Only add extensions not supported by the loader + if (!found_prop) { + extension_properties.push_back(loader_prop); + } + } + } + + auto num_extension_properties = static_cast<uint32_t>(extension_properties.size()); + if (propertyCapacityInput == 0) { + *propertyCountOutput = num_extension_properties; + } else if (nullptr != properties) { + if (propertyCapacityInput < num_extension_properties) { + *propertyCountOutput = num_extension_properties; + LoaderLogger::LogValidationErrorMessage("VUID-xrEnumerateInstanceExtensionProperties-propertyCountOutput-parameter", + "xrEnumerateInstanceExtensionProperties", "insufficient space in array"); + return XR_ERROR_SIZE_INSUFFICIENT; + } + + uint32_t num_to_copy = num_extension_properties; + // Determine how many extension properties we can copy over + if (propertyCapacityInput < num_to_copy) { + num_to_copy = propertyCapacityInput; + } + bool properties_valid = true; + for (uint32_t prop = 0; prop < propertyCapacityInput && prop < extension_properties.size(); ++prop) { + if (XR_TYPE_EXTENSION_PROPERTIES != properties[prop].type) { + properties_valid = false; + LoaderLogger::LogValidationErrorMessage("VUID-XrExtensionProperties-type-type", + "xrEnumerateInstanceExtensionProperties", "unknown type in properties"); + } + if (properties_valid) { + properties[prop] = extension_properties[prop]; + } + } + if (!properties_valid) { + LoaderLogger::LogValidationErrorMessage("VUID-xrEnumerateInstanceExtensionProperties-properties-parameter", + "xrEnumerateInstanceExtensionProperties", "invalid properties"); + return XR_ERROR_VALIDATION_FAILURE; + } + if (nullptr != propertyCountOutput) { + *propertyCountOutput = num_to_copy; + } + } else { + // incoming_count is not 0 BUT the properties is NULL + return XR_ERROR_VALIDATION_FAILURE; + } + LoaderLogger::LogVerboseMessage("xrEnumerateInstanceExtensionProperties", "Completed loader trampoline"); + return XR_SUCCESS; +} +XRLOADER_ABI_CATCH_FALLBACK + +static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrCreateInstance(const XrInstanceCreateInfo *info, + XrInstance *instance) XRLOADER_ABI_TRY { + LoaderLogger::LogVerboseMessage("xrCreateInstance", "Entering loader trampoline"); + if (nullptr == info) { + LoaderLogger::LogValidationErrorMessage("VUID-xrCreateInstance-info-parameter", "xrCreateInstance", "must be non-NULL"); + return XR_ERROR_VALIDATION_FAILURE; + } + // If application requested OpenXR API version is higher than the loader version, then we need to throw + // an error. + uint16_t app_major = XR_VERSION_MAJOR(info->applicationInfo.apiVersion); // NOLINT + uint16_t app_minor = XR_VERSION_MINOR(info->applicationInfo.apiVersion); // NOLINT + uint16_t loader_major = XR_VERSION_MAJOR(XR_CURRENT_API_VERSION); // NOLINT + uint16_t loader_minor = XR_VERSION_MINOR(XR_CURRENT_API_VERSION); // NOLINT + if (app_major > loader_major || (app_major == loader_major && app_minor > loader_minor)) { + std::ostringstream oss; + oss << "xrCreateInstance called with invalid API version " << app_major << "." << app_minor + << ". Max supported version is " << loader_major << "." << loader_minor; + LoaderLogger::LogErrorMessage("xrCreateInstance", oss.str()); + return XR_ERROR_API_VERSION_UNSUPPORTED; + } + + if (nullptr == instance) { + LoaderLogger::LogValidationErrorMessage("VUID-xrCreateInstance-instance-parameter", "xrCreateInstance", "must be non-NULL"); + return XR_ERROR_VALIDATION_FAILURE; + } + + // Make sure the ActiveLoaderInstance::IsAvailable check is done atomically with RuntimeInterface::LoadRuntime. + std::unique_lock<std::mutex> instance_lock(GetGlobalLoaderMutex()); + + // Check if there is already an XrInstance that is alive. If so, another instance cannot be created. + // The loader does not support multiple simultaneous instances because the loader is intended to be + // usable by apps using future OpenXR APIs (through xrGetInstanceProcAddr). Because the loader would + // not be aware of new handle types, it would not be able to look up the appropriate dispatch table + // in some cases. + if (ActiveLoaderInstance::IsAvailable()) { // If there is an XrInstance already alive. + LoaderLogger::LogErrorMessage("xrCreateInstance", "Loader does not support simultaneous XrInstances"); + return XR_ERROR_LIMIT_REACHED; + } + + std::vector<std::unique_ptr<ApiLayerInterface>> api_layer_interfaces; + XrResult result; + + // Make sure only one thread is attempting to read the JSON files and use the instance. + { + // Load the available runtime + result = RuntimeInterface::LoadRuntime("xrCreateInstance"); + if (XR_FAILED(result)) { + LoaderLogger::LogErrorMessage("xrCreateInstance", "Failed loading runtime information"); + } else { + // Load the appropriate layers + result = ApiLayerInterface::LoadApiLayers("xrCreateInstance", info->enabledApiLayerCount, info->enabledApiLayerNames, + api_layer_interfaces); + if (XR_FAILED(result)) { + LoaderLogger::LogErrorMessage("xrCreateInstance", "Failed loading layer information"); + } + } + } + + // Create the loader instance (only send down first runtime interface) + LoaderInstance *loader_instance = nullptr; + if (XR_SUCCEEDED(result)) { + std::unique_ptr<LoaderInstance> owned_loader_instance; + result = LoaderInstance::CreateInstance(LoaderXrTermGetInstanceProcAddr, LoaderXrTermCreateInstance, + LoaderXrTermCreateApiLayerInstance, std::move(api_layer_interfaces), info, + &owned_loader_instance); + if (XR_SUCCEEDED(result)) { + loader_instance = owned_loader_instance.get(); + result = ActiveLoaderInstance::Set(std::move(owned_loader_instance), "xrCreateInstance"); + } + } + + if (XR_SUCCEEDED(result)) { + // Create a debug utils messenger if the create structure is in the "next" chain + const auto *next_header = reinterpret_cast<const XrBaseInStructure *>(info->next); + const XrDebugUtilsMessengerCreateInfoEXT *dbg_utils_create_info = nullptr; + while (next_header != nullptr) { + if (next_header->type == XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) { + LoaderLogger::LogInfoMessage("xrCreateInstance", "Found XrDebugUtilsMessengerCreateInfoEXT in \'next\' chain."); + dbg_utils_create_info = reinterpret_cast<const XrDebugUtilsMessengerCreateInfoEXT *>(next_header); + XrDebugUtilsMessengerEXT messenger; + result = LoaderTrampolineCreateDebugUtilsMessengerEXT(loader_instance->GetInstanceHandle(), dbg_utils_create_info, + &messenger); + if (XR_FAILED(result)) { + return XR_ERROR_VALIDATION_FAILURE; + } + loader_instance->SetDefaultDebugUtilsMessenger(messenger); + break; + } + next_header = reinterpret_cast<const XrBaseInStructure *>(next_header->next); + } + } + + if (XR_FAILED(result)) { + // Ensure the global loader instance and runtime are destroyed if something went wrong. + ActiveLoaderInstance::Remove(); + RuntimeInterface::UnloadRuntime("xrCreateInstance"); + LoaderLogger::LogErrorMessage("xrCreateInstance", "xrCreateInstance failed"); + } else { + *instance = loader_instance->GetInstanceHandle(); + LoaderLogger::LogVerboseMessage("xrCreateInstance", "Completed loader trampoline"); + } + + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrDestroyInstance(XrInstance instance) XRLOADER_ABI_TRY { + LoaderLogger::LogVerboseMessage("xrDestroyInstance", "Entering loader trampoline"); + // Runtimes may detect XR_NULL_HANDLE provided as a required handle parameter and return XR_ERROR_HANDLE_INVALID. - 2.9 + if (XR_NULL_HANDLE == instance) { + LoaderLogger::LogErrorMessage("xrDestroyInstance", "Instance handle is XR_NULL_HANDLE."); + return XR_ERROR_HANDLE_INVALID; + } + + // Make sure the runtime isn't unloaded while it is being used by xrEnumerateInstanceExtensionProperties. + std::unique_lock<std::mutex> loader_lock(GetGlobalLoaderMutex()); + + LoaderInstance *loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrDestroyInstance"); + if (XR_FAILED(result)) { + return result; + } + + const std::unique_ptr<XrGeneratedDispatchTable> &dispatch_table = loader_instance->DispatchTable(); + + // If we allocated a default debug utils messenger, free it + XrDebugUtilsMessengerEXT messenger = loader_instance->DefaultDebugUtilsMessenger(); + if (messenger != XR_NULL_HANDLE) { + LoaderTrampolineDestroyDebugUtilsMessengerEXT(messenger); + } + + // Now destroy the instance + if (XR_FAILED(dispatch_table->DestroyInstance(instance))) { + LoaderLogger::LogErrorMessage("xrDestroyInstance", "Unknown error occurred calling down chain"); + } + + // Get rid of the loader instance. This will make it possible to create another instance in the future. + ActiveLoaderInstance::Remove(); + + // Lock the instance create/destroy mutex + LoaderLogger::LogVerboseMessage("xrDestroyInstance", "Completed loader trampoline"); + + // Finally, unload the runtime if necessary + RuntimeInterface::UnloadRuntime("xrDestroyInstance"); + + return XR_SUCCESS; +} +XRLOADER_ABI_CATCH_FALLBACK + +// ---- Core 1.0 manual loader terminator functions + +// Validate that the applicationInfo structure in the XrInstanceCreateInfo is valid. +static XrResult ValidateApplicationInfo(const XrApplicationInfo &info) { + if (IsMissingNullTerminator<XR_MAX_APPLICATION_NAME_SIZE>(info.applicationName)) { + LoaderLogger::LogValidationErrorMessage("VUID-XrApplicationInfo-applicationName-parameter", "xrCreateInstance", + "application name missing NULL terminator."); + return XR_ERROR_NAME_INVALID; + } + if (IsMissingNullTerminator<XR_MAX_ENGINE_NAME_SIZE>(info.engineName)) { + LoaderLogger::LogValidationErrorMessage("VUID-XrApplicationInfo-engineName-parameter", "xrCreateInstance", + "engine name missing NULL terminator."); + return XR_ERROR_NAME_INVALID; + } + if (strlen(info.applicationName) == 0) { + LoaderLogger::LogErrorMessage("xrCreateInstance", + "VUID-XrApplicationInfo-engineName-parameter: application name can not be empty."); + return XR_ERROR_NAME_INVALID; + } + return XR_SUCCESS; +} + +// Validate that the XrInstanceCreateInfo is valid +static XrResult ValidateInstanceCreateInfo(const XrInstanceCreateInfo *info) { + // Should have a valid 'type' + if (XR_TYPE_INSTANCE_CREATE_INFO != info->type) { + LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-type-type", "xrCreateInstance", + "expected XR_TYPE_INSTANCE_CREATE_INFO."); + return XR_ERROR_VALIDATION_FAILURE; + } + // Flags must be 0 + if (0 != info->createFlags) { + LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-createFlags-zerobitmask", "xrCreateInstance", + "flags must be 0."); + return XR_ERROR_VALIDATION_FAILURE; + } + // ApplicationInfo struct must be valid + XrResult result = ValidateApplicationInfo(info->applicationInfo); + if (XR_FAILED(result)) { + LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-applicationInfo-parameter", "xrCreateInstance", + "info->applicationInfo is not valid."); + return result; + } + // VUID-XrInstanceCreateInfo-enabledApiLayerNames-parameter already tested in LoadApiLayers() + if ((info->enabledExtensionCount != 0u) && nullptr == info->enabledExtensionNames) { + LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-enabledExtensionNames-parameter", "xrCreateInstance", + "enabledExtensionCount is non-0 but array is NULL"); + return XR_ERROR_VALIDATION_FAILURE; + } + return XR_SUCCESS; +} + +static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateInstance(const XrInstanceCreateInfo *createInfo, + XrInstance *instance) XRLOADER_ABI_TRY { + LoaderLogger::LogVerboseMessage("xrCreateInstance", "Entering loader terminator"); + XrResult result = ValidateInstanceCreateInfo(createInfo); + if (XR_FAILED(result)) { + LoaderLogger::LogValidationErrorMessage("VUID-xrCreateInstance-info-parameter", "xrCreateInstance", + "something wrong with XrInstanceCreateInfo contents"); + return result; + } + result = RuntimeInterface::GetRuntime().CreateInstance(createInfo, instance); + LoaderLogger::LogVerboseMessage("xrCreateInstance", "Completed loader terminator"); + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateApiLayerInstance(const XrInstanceCreateInfo *info, + const struct XrApiLayerCreateInfo * /*apiLayerInfo*/, + XrInstance *instance) { + return LoaderXrTermCreateInstance(info, instance); +} + +static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermDestroyInstance(XrInstance instance) XRLOADER_ABI_TRY { + LoaderLogger::LogVerboseMessage("xrDestroyInstance", "Entering loader terminator"); + LoaderLogger::GetInstance().RemoveLogRecordersForXrInstance(instance); + XrResult result = RuntimeInterface::GetRuntime().DestroyInstance(instance); + LoaderLogger::LogVerboseMessage("xrDestroyInstance", "Completed loader terminator"); + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermGetInstanceProcAddr(XrInstance instance, const char *name, + PFN_xrVoidFunction *function) XRLOADER_ABI_TRY { + // A few instance commands need to go through a loader terminator. + // Otherwise, go directly to the runtime version of the command if it exists. + // But first set the function pointer to NULL so that the fall-through below actually works. + *function = nullptr; + + // NOTE: ActiveLoaderInstance cannot be used in this function because it is called before an instance is made active. + + if (0 == strcmp(name, "xrGetInstanceProcAddr")) { + *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermGetInstanceProcAddr); + } else if (0 == strcmp(name, "xrCreateInstance")) { + *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermCreateInstance); + } else if (0 == strcmp(name, "xrDestroyInstance")) { + *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermDestroyInstance); + } else if (0 == strcmp(name, "xrSetDebugUtilsObjectNameEXT")) { + *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermSetDebugUtilsObjectNameEXT); + } else if (0 == strcmp(name, "xrCreateDebugUtilsMessengerEXT")) { + *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermCreateDebugUtilsMessengerEXT); + } else if (0 == strcmp(name, "xrDestroyDebugUtilsMessengerEXT")) { + *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermDestroyDebugUtilsMessengerEXT); + } else if (0 == strcmp(name, "xrSubmitDebugUtilsMessageEXT")) { + *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermSubmitDebugUtilsMessageEXT); + } else if (0 == strcmp(name, "xrCreateApiLayerInstance")) { + // Special layer version of xrCreateInstance terminator. If we get called this by a layer, + // we simply re-direct the information back into the standard xrCreateInstance terminator. + *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermCreateApiLayerInstance); + } + + if (nullptr != *function) { + return XR_SUCCESS; + } + + return RuntimeInterface::GetInstanceProcAddr(instance, name, function); +} +XRLOADER_ABI_CATCH_FALLBACK + +// ---- Extension manual loader trampoline functions + +static XRAPI_ATTR XrResult XRAPI_CALL +LoaderTrampolineCreateDebugUtilsMessengerEXT(XrInstance instance, const XrDebugUtilsMessengerCreateInfoEXT *createInfo, + XrDebugUtilsMessengerEXT *messenger) XRLOADER_ABI_TRY { + LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT", "Entering loader trampoline"); + + if (instance == XR_NULL_HANDLE) { + LoaderLogger::LogErrorMessage("xrCreateDebugUtilsMessengerEXT", "Instance handle is XR_NULL_HANDLE."); + return XR_ERROR_HANDLE_INVALID; + } + + LoaderInstance *loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrCreateDebugUtilsMessengerEXT"); + if (XR_FAILED(result)) { + return result; + } + + result = loader_instance->DispatchTable()->CreateDebugUtilsMessengerEXT(instance, createInfo, messenger); + LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT", "Completed loader trampoline"); + return result; +} +XRLOADER_ABI_CATCH_BAD_ALLOC_OOM XRLOADER_ABI_CATCH_FALLBACK + + static XRAPI_ATTR XrResult XRAPI_CALL + LoaderTrampolineDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger) XRLOADER_ABI_TRY { + // TODO: get instance from messenger in loader + // Also, is the loader really doing all this every call? + LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT", "Entering loader trampoline"); + + if (messenger == XR_NULL_HANDLE) { + LoaderLogger::LogErrorMessage("xrDestroyDebugUtilsMessengerEXT", "Messenger handle is XR_NULL_HANDLE."); + return XR_ERROR_HANDLE_INVALID; + } + + LoaderInstance *loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrDestroyDebugUtilsMessengerEXT"); + if (XR_FAILED(result)) { + return result; + } + + result = loader_instance->DispatchTable()->DestroyDebugUtilsMessengerEXT(messenger); + LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT", "Completed loader trampoline"); + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +static XRAPI_ATTR XrResult XRAPI_CALL +LoaderTrampolineSessionBeginDebugUtilsLabelRegionEXT(XrSession session, const XrDebugUtilsLabelEXT *labelInfo) XRLOADER_ABI_TRY { + if (session == XR_NULL_HANDLE) { + LoaderLogger::LogErrorMessage("xrSessionBeginDebugUtilsLabelRegionEXT", "Session handle is XR_NULL_HANDLE."); + return XR_ERROR_HANDLE_INVALID; + } + + if (nullptr == labelInfo) { + LoaderLogger::LogValidationErrorMessage("VUID-xrSessionBeginDebugUtilsLabelRegionEXT-labelInfo-parameter", + "xrSessionBeginDebugUtilsLabelRegionEXT", "labelInfo must be non-NULL", + {XrSdkLogObjectInfo{session, XR_OBJECT_TYPE_SESSION}}); + return XR_ERROR_VALIDATION_FAILURE; + } + + LoaderInstance *loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSessionBeginDebugUtilsLabelRegionEXT"); + if (XR_FAILED(result)) { + return result; + } + LoaderLogger::GetInstance().BeginLabelRegion(session, labelInfo); + const std::unique_ptr<XrGeneratedDispatchTable> &dispatch_table = loader_instance->DispatchTable(); + if (nullptr != dispatch_table->SessionBeginDebugUtilsLabelRegionEXT) { + return dispatch_table->SessionBeginDebugUtilsLabelRegionEXT(session, labelInfo); + } + return XR_SUCCESS; +} +XRLOADER_ABI_CATCH_FALLBACK + +static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineSessionEndDebugUtilsLabelRegionEXT(XrSession session) XRLOADER_ABI_TRY { + if (session == XR_NULL_HANDLE) { + LoaderLogger::LogErrorMessage("xrSessionEndDebugUtilsLabelRegionEXT", "Session handle is XR_NULL_HANDLE."); + return XR_ERROR_HANDLE_INVALID; + } + + LoaderInstance *loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSessionEndDebugUtilsLabelRegionEXT"); + if (XR_FAILED(result)) { + return result; + } + + LoaderLogger::GetInstance().EndLabelRegion(session); + const std::unique_ptr<XrGeneratedDispatchTable> &dispatch_table = loader_instance->DispatchTable(); + if (nullptr != dispatch_table->SessionEndDebugUtilsLabelRegionEXT) { + return dispatch_table->SessionEndDebugUtilsLabelRegionEXT(session); + } + return XR_SUCCESS; +} +XRLOADER_ABI_CATCH_FALLBACK + +static XRAPI_ATTR XrResult XRAPI_CALL +LoaderTrampolineSessionInsertDebugUtilsLabelEXT(XrSession session, const XrDebugUtilsLabelEXT *labelInfo) XRLOADER_ABI_TRY { + if (session == XR_NULL_HANDLE) { + LoaderLogger::LogErrorMessage("xrSessionInsertDebugUtilsLabelEXT", "Session handle is XR_NULL_HANDLE."); + return XR_ERROR_HANDLE_INVALID; + } + + LoaderInstance *loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSessionInsertDebugUtilsLabelEXT"); + if (XR_FAILED(result)) { + return result; + } + + if (nullptr == labelInfo) { + LoaderLogger::LogValidationErrorMessage("VUID-xrSessionInsertDebugUtilsLabelEXT-labelInfo-parameter", + "xrSessionInsertDebugUtilsLabelEXT", "labelInfo must be non-NULL", + {XrSdkLogObjectInfo{session, XR_OBJECT_TYPE_SESSION}}); + return XR_ERROR_VALIDATION_FAILURE; + } + + LoaderLogger::GetInstance().InsertLabel(session, labelInfo); + + const std::unique_ptr<XrGeneratedDispatchTable> &dispatch_table = loader_instance->DispatchTable(); + if (nullptr != dispatch_table->SessionInsertDebugUtilsLabelEXT) { + return dispatch_table->SessionInsertDebugUtilsLabelEXT(session, labelInfo); + } + + return XR_SUCCESS; +} +XRLOADER_ABI_CATCH_FALLBACK + +// No-op trampoline needed for xrGetInstanceProcAddr. Work done in terminator. +static XRAPI_ATTR XrResult XRAPI_CALL +LoaderTrampolineSetDebugUtilsObjectNameEXT(XrInstance instance, const XrDebugUtilsObjectNameInfoEXT *nameInfo) XRLOADER_ABI_TRY { + LoaderInstance *loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSetDebugUtilsObjectNameEXT"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->SetDebugUtilsObjectNameEXT(instance, nameInfo); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +// No-op trampoline needed for xrGetInstanceProcAddr. Work done in terminator. +static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineSubmitDebugUtilsMessageEXT( + XrInstance instance, XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, XrDebugUtilsMessageTypeFlagsEXT messageTypes, + const XrDebugUtilsMessengerCallbackDataEXT *callbackData) XRLOADER_ABI_TRY { + LoaderInstance *loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSubmitDebugUtilsMessageEXT"); + if (XR_SUCCEEDED(result)) { + result = + loader_instance->DispatchTable()->SubmitDebugUtilsMessageEXT(instance, messageSeverity, messageTypes, callbackData); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +// ---- Extension manual loader terminator functions + +XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateDebugUtilsMessengerEXT(XrInstance instance, + const XrDebugUtilsMessengerCreateInfoEXT *createInfo, + XrDebugUtilsMessengerEXT *messenger) XRLOADER_ABI_TRY { + LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT", "Entering loader terminator"); + if (nullptr == messenger) { + LoaderLogger::LogValidationErrorMessage("VUID-xrCreateDebugUtilsMessengerEXT-messenger-parameter", + "xrCreateDebugUtilsMessengerEXT", "invalid messenger pointer"); + return XR_ERROR_VALIDATION_FAILURE; + } + const XrGeneratedDispatchTable *dispatch_table = RuntimeInterface::GetDispatchTable(instance); + XrResult result = XR_SUCCESS; + // This extension is supported entirely by the loader which means the runtime may or may not support it. + if (nullptr != dispatch_table->CreateDebugUtilsMessengerEXT) { + result = dispatch_table->CreateDebugUtilsMessengerEXT(instance, createInfo, messenger); + } else { + // Just allocate a character so we have a unique value + char *temp_mess_ptr = new char; + *messenger = reinterpret_cast<XrDebugUtilsMessengerEXT>(temp_mess_ptr); + } + if (XR_SUCCEEDED(result)) { + LoaderLogger::GetInstance().AddLogRecorderForXrInstance(instance, MakeDebugUtilsLoaderLogRecorder(createInfo, *messenger)); + RuntimeInterface::GetRuntime().TrackDebugMessenger(instance, *messenger); + } + LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT", "Completed loader terminator"); + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger) XRLOADER_ABI_TRY { + LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT", "Entering loader terminator"); + const XrGeneratedDispatchTable *dispatch_table = RuntimeInterface::GetDebugUtilsMessengerDispatchTable(messenger); + XrResult result = XR_SUCCESS; + LoaderLogger::GetInstance().RemoveLogRecorder(MakeHandleGeneric(messenger)); + RuntimeInterface::GetRuntime().ForgetDebugMessenger(messenger); + // This extension is supported entirely by the loader which means the runtime may or may not support it. + if (nullptr != dispatch_table->DestroyDebugUtilsMessengerEXT) { + result = dispatch_table->DestroyDebugUtilsMessengerEXT(messenger); + } else { + // Delete the character we would've created + delete (reinterpret_cast<char *>(MakeHandleGeneric(messenger))); + } + LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT", "Completed loader terminator"); + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermSubmitDebugUtilsMessageEXT( + XrInstance instance, XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, XrDebugUtilsMessageTypeFlagsEXT messageTypes, + const XrDebugUtilsMessengerCallbackDataEXT *callbackData) XRLOADER_ABI_TRY { + LoaderLogger::LogVerboseMessage("xrSubmitDebugUtilsMessageEXT", "Entering loader terminator"); + const XrGeneratedDispatchTable *dispatch_table = RuntimeInterface::GetDispatchTable(instance); + XrResult result = XR_SUCCESS; + if (nullptr != dispatch_table->SubmitDebugUtilsMessageEXT) { + result = dispatch_table->SubmitDebugUtilsMessageEXT(instance, messageSeverity, messageTypes, callbackData); + } else { + // Only log the message from the loader if the runtime doesn't support this extension. If we did, + // then the user would receive multiple instances of the same message. + LoaderLogger::GetInstance().LogDebugUtilsMessage(messageSeverity, messageTypes, callbackData); + } + LoaderLogger::LogVerboseMessage("xrSubmitDebugUtilsMessageEXT", "Completed loader terminator"); + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +XRAPI_ATTR XrResult XRAPI_CALL +LoaderXrTermSetDebugUtilsObjectNameEXT(XrInstance instance, const XrDebugUtilsObjectNameInfoEXT *nameInfo) XRLOADER_ABI_TRY { + LoaderLogger::LogVerboseMessage("xrSetDebugUtilsObjectNameEXT", "Entering loader terminator"); + const XrGeneratedDispatchTable *dispatch_table = RuntimeInterface::GetDispatchTable(instance); + XrResult result = XR_SUCCESS; + if (nullptr != dispatch_table->SetDebugUtilsObjectNameEXT) { + result = dispatch_table->SetDebugUtilsObjectNameEXT(instance, nameInfo); + } + LoaderLogger::GetInstance().AddObjectName(nameInfo->objectHandle, nameInfo->objectType, nameInfo->objectName); + LoaderLogger::LogVerboseMessage("xrSetDebugUtilsObjectNameEXT", "Completed loader terminator"); + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +XRAPI_ATTR XrResult XRAPI_CALL LoaderXrGetInstanceProcAddr(XrInstance instance, const char *name, + PFN_xrVoidFunction *function) XRLOADER_ABI_TRY { + // Initialize the function to nullptr in case it does not get caught in a known case + *function = nullptr; + + if (nullptr == function) { + LoaderLogger::LogValidationErrorMessage("VUID-xrGetInstanceProcAddr-function-parameter", "xrGetInstanceProcAddr", + "Invalid Function pointer"); + return XR_ERROR_VALIDATION_FAILURE; + } + + if (nullptr == name) { + LoaderLogger::LogValidationErrorMessage("VUID-xrGetInstanceProcAddr-function-parameter", "xrGetInstanceProcAddr", + "Invalid Name pointer"); + return XR_ERROR_VALIDATION_FAILURE; + } + + LoaderInstance *loader_instance = nullptr; + if (instance == XR_NULL_HANDLE) { + // Null instance is allowed for a few specific API entry points, otherwise return error + if (strcmp(name, "xrCreateInstance") != 0 && strcmp(name, "xrEnumerateApiLayerProperties") != 0 && + strcmp(name, "xrEnumerateInstanceExtensionProperties") != 0 && strcmp(name, "xrInitializeLoaderKHR") != 0) { + // TODO why is xrGetInstanceProcAddr not listed in here? + std::string error_str = "XR_NULL_HANDLE for instance but query for "; + error_str += name; + error_str += " requires a valid instance"; + LoaderLogger::LogValidationErrorMessage("VUID-xrGetInstanceProcAddr-instance-parameter", "xrGetInstanceProcAddr", + error_str); + return XR_ERROR_HANDLE_INVALID; + } + } else { + // non null instance passed in, it should be our current instance + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetInstanceProcAddr"); + if (XR_FAILED(result)) { + return result; + } + if (loader_instance->GetInstanceHandle() != instance) { + return XR_ERROR_HANDLE_INVALID; + } + } + + // These functions must always go through the loader's implementation (trampoline). + if (strcmp(name, "xrGetInstanceProcAddr") == 0) { + *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrGetInstanceProcAddr); + return XR_SUCCESS; + } else if (strcmp(name, "xrInitializeLoaderKHR") == 0) { +#ifdef XR_KHR_LOADER_INIT_SUPPORT + *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrInitializeLoaderKHR); + return XR_SUCCESS; +#else + return XR_ERROR_FUNCTION_UNSUPPORTED; +#endif + } else if (strcmp(name, "xrEnumerateApiLayerProperties") == 0) { + *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrEnumerateApiLayerProperties); + return XR_SUCCESS; + } else if (strcmp(name, "xrEnumerateInstanceExtensionProperties") == 0) { + *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrEnumerateInstanceExtensionProperties); + return XR_SUCCESS; + } else if (strcmp(name, "xrCreateInstance") == 0) { + *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrCreateInstance); + return XR_SUCCESS; + } else if (strcmp(name, "xrDestroyInstance") == 0) { + *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrDestroyInstance); + return XR_SUCCESS; + } + + // XR_EXT_debug_utils is built into the loader and handled partly through the xrGetInstanceProcAddress terminator, + // but the check to see if the extension is enabled must be done here where ActiveLoaderInstance is safe to use. + if (*function == nullptr) { + if (strcmp(name, "xrCreateDebugUtilsMessengerEXT") == 0) { + *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineCreateDebugUtilsMessengerEXT); + } else if (strcmp(name, "xrDestroyDebugUtilsMessengerEXT") == 0) { + *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineDestroyDebugUtilsMessengerEXT); + } else if (strcmp(name, "xrSessionBeginDebugUtilsLabelRegionEXT") == 0) { + *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSessionBeginDebugUtilsLabelRegionEXT); + } else if (strcmp(name, "xrSessionEndDebugUtilsLabelRegionEXT") == 0) { + *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSessionEndDebugUtilsLabelRegionEXT); + } else if (strcmp(name, "xrSessionInsertDebugUtilsLabelEXT") == 0) { + *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSessionInsertDebugUtilsLabelEXT); + } else if (strcmp(name, "xrSetDebugUtilsObjectNameEXT") == 0) { + *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSetDebugUtilsObjectNameEXT); + } else if (strcmp(name, "xrSubmitDebugUtilsMessageEXT") == 0) { + *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSubmitDebugUtilsMessageEXT); + } + + if (*function != nullptr && !loader_instance->ExtensionIsEnabled("XR_EXT_debug_utils")) { + // The function matches one of the XR_EXT_debug_utils functions but the extension is not enabled. + *function = nullptr; + return XR_ERROR_FUNCTION_UNSUPPORTED; + } + } + + if (*function != nullptr) { + // The loader has a trampoline or implementation of this function. + return XR_SUCCESS; + } + + // If the function is not supported by the loader, call down to the next layer. + return loader_instance->GetInstanceProcAddr(name, function); +} +XRLOADER_ABI_CATCH_FALLBACK + +// Exported loader functions +// +// The application might override these by exporting the same symbols and so we can't use these +// symbols anywhere in the loader code, and instead the internal non exported functions that these +// stubs call should be used internally. +LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateApiLayerProperties(uint32_t propertyCapacityInput, + uint32_t *propertyCountOutput, + XrApiLayerProperties *properties) { + return LoaderXrEnumerateApiLayerProperties(propertyCapacityInput, propertyCountOutput, properties); +} + +LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateInstanceExtensionProperties(const char *layerName, + uint32_t propertyCapacityInput, + uint32_t *propertyCountOutput, + XrExtensionProperties *properties) { + return LoaderXrEnumerateInstanceExtensionProperties(layerName, propertyCapacityInput, propertyCountOutput, properties); +} + +LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateInstance(const XrInstanceCreateInfo *info, XrInstance *instance) { + return LoaderXrCreateInstance(info, instance); +} + +LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroyInstance(XrInstance instance) { return LoaderXrDestroyInstance(instance); } + +LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetInstanceProcAddr(XrInstance instance, const char *name, + PFN_xrVoidFunction *function) { + return LoaderXrGetInstanceProcAddr(instance, name, function); +} + +#ifdef XR_KHR_LOADER_INIT_SUPPORT +LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrInitializeLoaderKHR(const XrLoaderInitInfoBaseHeaderKHR *loaderInitInfo) { + return LoaderXrInitializeLoaderKHR(loaderInitInfo); +} +#endif diff --git a/thirdparty/openxr/src/loader/loader_instance.cpp b/thirdparty/openxr/src/loader/loader_instance.cpp new file mode 100644 index 0000000000..b24c8de53b --- /dev/null +++ b/thirdparty/openxr/src/loader/loader_instance.cpp @@ -0,0 +1,303 @@ +// Copyright (c) 2017-2022, The Khronos Group Inc. +// Copyright (c) 2017-2019 Valve Corporation +// Copyright (c) 2017-2019 LunarG, Inc. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Initial Author: Mark Young <marky@lunarg.com> +// + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif // defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) + +#include "loader_instance.hpp" + +#include "api_layer_interface.hpp" +#include "hex_and_handles.h" +#include "loader_interfaces.h" +#include "loader_logger.hpp" +#include "runtime_interface.hpp" +#include "xr_generated_dispatch_table.h" +#include "xr_generated_loader.hpp" + +#include <openxr/openxr.h> + +#include <cstring> +#include <memory> +#include <sstream> +#include <string> +#include <utility> +#include <vector> + +namespace { +std::unique_ptr<LoaderInstance>& GetSetCurrentLoaderInstance() { + static std::unique_ptr<LoaderInstance> current_loader_instance; + return current_loader_instance; +} +} // namespace + +namespace ActiveLoaderInstance { +XrResult Set(std::unique_ptr<LoaderInstance> loader_instance, const char* log_function_name) { + if (GetSetCurrentLoaderInstance() != nullptr) { + LoaderLogger::LogErrorMessage(log_function_name, "Active XrInstance handle already exists"); + return XR_ERROR_LIMIT_REACHED; + } + + GetSetCurrentLoaderInstance() = std::move(loader_instance); + return XR_SUCCESS; +} + +XrResult Get(LoaderInstance** loader_instance, const char* log_function_name) { + *loader_instance = GetSetCurrentLoaderInstance().get(); + if (*loader_instance == nullptr) { + LoaderLogger::LogErrorMessage(log_function_name, "No active XrInstance handle."); + return XR_ERROR_HANDLE_INVALID; + } + + return XR_SUCCESS; +} + +bool IsAvailable() { return GetSetCurrentLoaderInstance() != nullptr; } + +void Remove() { GetSetCurrentLoaderInstance().release(); } +} // namespace ActiveLoaderInstance + +// Extensions that are supported by the loader, but may not be supported +// the the runtime. +const std::array<XrExtensionProperties, 1>& LoaderInstance::LoaderSpecificExtensions() { + static const std::array<XrExtensionProperties, 1> extensions = {XrExtensionProperties{ + XR_TYPE_EXTENSION_PROPERTIES, nullptr, XR_EXT_DEBUG_UTILS_EXTENSION_NAME, XR_EXT_debug_utils_SPEC_VERSION}}; + return extensions; +} + +namespace { +class InstanceCreateInfoManager { + public: + explicit InstanceCreateInfoManager(const XrInstanceCreateInfo* info) : original_create_info(info), modified_create_info(*info) { + Reset(); + } + + // Reset the "modified" state to match the original state. + void Reset() { + enabled_extensions_cstr.clear(); + enabled_extensions_cstr.reserve(original_create_info->enabledExtensionCount); + + for (uint32_t i = 0; i < original_create_info->enabledExtensionCount; ++i) { + enabled_extensions_cstr.push_back(original_create_info->enabledExtensionNames[i]); + } + Update(); + } + + // Remove extensions named in the parameter and return a pointer to the current state. + const XrInstanceCreateInfo* FilterOutExtensions(const std::vector<const char*>& extensions_to_skip) { + if (enabled_extensions_cstr.empty()) { + return Get(); + } + if (extensions_to_skip.empty()) { + return Get(); + } + for (auto& ext : extensions_to_skip) { + FilterOutExtension(ext); + } + return Update(); + } + // Remove the extension named in the parameter and return a pointer to the current state. + const XrInstanceCreateInfo* FilterOutExtension(const char* extension_to_skip) { + if (enabled_extensions_cstr.empty()) { + return &modified_create_info; + } + auto b = enabled_extensions_cstr.begin(); + auto e = enabled_extensions_cstr.end(); + auto it = std::find_if(b, e, [&](const char* extension) { return strcmp(extension_to_skip, extension) == 0; }); + if (it != e) { + // Just that one element goes away + enabled_extensions_cstr.erase(it); + } + return Update(); + } + + // Get the current modified XrInstanceCreateInfo + const XrInstanceCreateInfo* Get() const { return &modified_create_info; } + + private: + const XrInstanceCreateInfo* Update() { + modified_create_info.enabledExtensionCount = static_cast<uint32_t>(enabled_extensions_cstr.size()); + modified_create_info.enabledExtensionNames = enabled_extensions_cstr.empty() ? nullptr : enabled_extensions_cstr.data(); + return &modified_create_info; + } + const XrInstanceCreateInfo* original_create_info; + + XrInstanceCreateInfo modified_create_info; + std::vector<const char*> enabled_extensions_cstr; +}; +} // namespace + +// Factory method +XrResult LoaderInstance::CreateInstance(PFN_xrGetInstanceProcAddr get_instance_proc_addr_term, + PFN_xrCreateInstance create_instance_term, + PFN_xrCreateApiLayerInstance create_api_layer_instance_term, + std::vector<std::unique_ptr<ApiLayerInterface>> api_layer_interfaces, + const XrInstanceCreateInfo* info, std::unique_ptr<LoaderInstance>* loader_instance) { + LoaderLogger::LogVerboseMessage("xrCreateInstance", "Entering LoaderInstance::CreateInstance"); + + // Check the list of enabled extensions to make sure something supports them, and, if we do, + // add it to the list of enabled extensions + XrResult last_error = XR_SUCCESS; + for (uint32_t ext = 0; ext < info->enabledExtensionCount; ++ext) { + bool found = false; + // First check the runtime + if (RuntimeInterface::GetRuntime().SupportsExtension(info->enabledExtensionNames[ext])) { + found = true; + } + // Next check the loader + if (!found) { + for (auto& loader_extension : LoaderInstance::LoaderSpecificExtensions()) { + if (strcmp(loader_extension.extensionName, info->enabledExtensionNames[ext]) == 0) { + found = true; + break; + } + } + } + // Finally, check the enabled layers + if (!found) { + for (auto& layer_interface : api_layer_interfaces) { + if (layer_interface->SupportsExtension(info->enabledExtensionNames[ext])) { + found = true; + break; + } + } + } + if (!found) { + std::string msg = "LoaderInstance::CreateInstance, no support found for requested extension: "; + msg += info->enabledExtensionNames[ext]; + LoaderLogger::LogErrorMessage("xrCreateInstance", msg); + last_error = XR_ERROR_EXTENSION_NOT_PRESENT; + break; + } + } + + // Topmost means "closest to the application" + PFN_xrGetInstanceProcAddr topmost_gipa = get_instance_proc_addr_term; + XrInstance instance{XR_NULL_HANDLE}; + + if (XR_SUCCEEDED(last_error)) { + // Remove the loader-supported-extensions (debug utils), if it's in the list of enabled extensions but not supported by + // the runtime. + InstanceCreateInfoManager create_info_manager{info}; + const XrInstanceCreateInfo* modified_create_info = info; + if (info->enabledExtensionCount > 0) { + std::vector<const char*> extensions_to_skip; + for (const auto& ext : LoaderInstance::LoaderSpecificExtensions()) { + if (!RuntimeInterface::GetRuntime().SupportsExtension(ext.extensionName)) { + extensions_to_skip.emplace_back(ext.extensionName); + } + } + modified_create_info = create_info_manager.FilterOutExtensions(extensions_to_skip); + } + + // Only start the xrCreateApiLayerInstance stack if we have layers. + if (!api_layer_interfaces.empty()) { + // Initialize an array of ApiLayerNextInfo structs + std::unique_ptr<XrApiLayerNextInfo[]> next_info_list(new XrApiLayerNextInfo[api_layer_interfaces.size()]); + auto ni_index = static_cast<uint32_t>(api_layer_interfaces.size() - 1); + for (uint32_t i = 0; i <= ni_index; i++) { + next_info_list[i].structType = XR_LOADER_INTERFACE_STRUCT_API_LAYER_NEXT_INFO; + next_info_list[i].structVersion = XR_API_LAYER_NEXT_INFO_STRUCT_VERSION; + next_info_list[i].structSize = sizeof(XrApiLayerNextInfo); + } + + // Go through all layers, and override the instance pointers with the layer version. However, + // go backwards through the layer list so we replace in reverse order so the layers can call their next function + // appropriately. + PFN_xrCreateApiLayerInstance topmost_cali_fp = create_api_layer_instance_term; + XrApiLayerNextInfo* topmost_nextinfo = nullptr; + for (auto layer_interface = api_layer_interfaces.rbegin(); layer_interface != api_layer_interfaces.rend(); + ++layer_interface) { + // Collect current layer's function pointers + PFN_xrGetInstanceProcAddr cur_gipa_fp = (*layer_interface)->GetInstanceProcAddrFuncPointer(); + PFN_xrCreateApiLayerInstance cur_cali_fp = (*layer_interface)->GetCreateApiLayerInstanceFuncPointer(); + + // Fill in layer info and link previous (lower) layer fxn pointers + strncpy(next_info_list[ni_index].layerName, (*layer_interface)->LayerName().c_str(), + XR_MAX_API_LAYER_NAME_SIZE - 1); + next_info_list[ni_index].layerName[XR_MAX_API_LAYER_NAME_SIZE - 1] = '\0'; + next_info_list[ni_index].next = topmost_nextinfo; + next_info_list[ni_index].nextGetInstanceProcAddr = topmost_gipa; + next_info_list[ni_index].nextCreateApiLayerInstance = topmost_cali_fp; + + // Update saved pointers for next iteration + topmost_nextinfo = &next_info_list[ni_index]; + topmost_gipa = cur_gipa_fp; + topmost_cali_fp = cur_cali_fp; + ni_index--; + } + + // Populate the ApiLayerCreateInfo struct and pass to topmost CreateApiLayerInstance() + XrApiLayerCreateInfo api_layer_ci = {}; + api_layer_ci.structType = XR_LOADER_INTERFACE_STRUCT_API_LAYER_CREATE_INFO; + api_layer_ci.structVersion = XR_API_LAYER_CREATE_INFO_STRUCT_VERSION; + api_layer_ci.structSize = sizeof(XrApiLayerCreateInfo); + api_layer_ci.loaderInstance = nullptr; // Not used. + api_layer_ci.settings_file_location[0] = '\0'; + api_layer_ci.nextInfo = next_info_list.get(); + //! @todo do we filter our create info extension list here? + //! Think that actually each layer might need to filter... + last_error = topmost_cali_fp(modified_create_info, &api_layer_ci, &instance); + + } else { + // The loader's terminator is the topmost CreateInstance if there are no layers. + last_error = create_instance_term(modified_create_info, &instance); + } + + if (XR_FAILED(last_error)) { + LoaderLogger::LogErrorMessage("xrCreateInstance", "LoaderInstance::CreateInstance chained CreateInstance call failed"); + } + } + + if (XR_SUCCEEDED(last_error)) { + loader_instance->reset(new LoaderInstance(instance, info, topmost_gipa, std::move(api_layer_interfaces))); + + std::ostringstream oss; + oss << "LoaderInstance::CreateInstance succeeded with "; + oss << (*loader_instance)->LayerInterfaces().size(); + oss << " layers enabled and runtime interface - created instance = "; + oss << HandleToHexString((*loader_instance)->GetInstanceHandle()); + LoaderLogger::LogInfoMessage("xrCreateInstance", oss.str()); + } + + return last_error; +} + +XrResult LoaderInstance::GetInstanceProcAddr(const char* name, PFN_xrVoidFunction* function) { + return _topmost_gipa(_runtime_instance, name, function); +} + +LoaderInstance::LoaderInstance(XrInstance instance, const XrInstanceCreateInfo* create_info, PFN_xrGetInstanceProcAddr topmost_gipa, + std::vector<std::unique_ptr<ApiLayerInterface>> api_layer_interfaces) + : _runtime_instance(instance), + _topmost_gipa(topmost_gipa), + _api_layer_interfaces(std::move(api_layer_interfaces)), + _dispatch_table(new XrGeneratedDispatchTable{}) { + for (uint32_t ext = 0; ext < create_info->enabledExtensionCount; ++ext) { + _enabled_extensions.push_back(create_info->enabledExtensionNames[ext]); + } + + GeneratedXrPopulateDispatchTable(_dispatch_table.get(), instance, topmost_gipa); +} + +LoaderInstance::~LoaderInstance() { + std::ostringstream oss; + oss << "Destroying LoaderInstance = "; + oss << PointerToHexString(this); + LoaderLogger::LogInfoMessage("xrDestroyInstance", oss.str()); +} + +bool LoaderInstance::ExtensionIsEnabled(const std::string& extension) { + for (std::string& cur_enabled : _enabled_extensions) { + if (cur_enabled == extension) { + return true; + } + } + return false; +} diff --git a/thirdparty/openxr/src/loader/loader_instance.hpp b/thirdparty/openxr/src/loader/loader_instance.hpp new file mode 100644 index 0000000000..1d43ed758d --- /dev/null +++ b/thirdparty/openxr/src/loader/loader_instance.hpp @@ -0,0 +1,77 @@ +// Copyright (c) 2017-2022, The Khronos Group Inc. +// Copyright (c) 2017-2019 Valve Corporation +// Copyright (c) 2017-2019 LunarG, Inc. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Initial Author: Mark Young <marky@lunarg.com> +// + +#pragma once + +#include "extra_algorithms.h" +#include "loader_interfaces.h" + +#include <openxr/openxr.h> + +#include <array> +#include <cmath> +#include <memory> +#include <mutex> +#include <string> +#include <unordered_map> +#include <vector> + +class ApiLayerInterface; +struct XrGeneratedDispatchTable; +class LoaderInstance; + +// Manage the single loader instance that is available. +namespace ActiveLoaderInstance { +// Set the active loader instance. This will fail if there is already an active loader instance. +XrResult Set(std::unique_ptr<LoaderInstance> loader_instance, const char* log_function_name); + +// Returns true if there is an active loader instance. +bool IsAvailable(); + +// Get the active LoaderInstance. +XrResult Get(LoaderInstance** loader_instance, const char* log_function_name); + +// Destroy the currently active LoaderInstance if there is one. This will make the loader able to create a new XrInstance if needed. +void Remove(); +}; // namespace ActiveLoaderInstance + +// Manages information needed by the loader for an XrInstance, such as what extensions are available and the dispatch table. +class LoaderInstance { + public: + // Factory method + static XrResult CreateInstance(PFN_xrGetInstanceProcAddr get_instance_proc_addr_term, PFN_xrCreateInstance create_instance_term, + PFN_xrCreateApiLayerInstance create_api_layer_instance_term, + std::vector<std::unique_ptr<ApiLayerInterface>> layer_interfaces, + const XrInstanceCreateInfo* createInfo, std::unique_ptr<LoaderInstance>* loader_instance); + static const std::array<XrExtensionProperties, 1>& LoaderSpecificExtensions(); + + virtual ~LoaderInstance(); + + XrInstance GetInstanceHandle() { return _runtime_instance; } + const std::unique_ptr<XrGeneratedDispatchTable>& DispatchTable() { return _dispatch_table; } + std::vector<std::unique_ptr<ApiLayerInterface>>& LayerInterfaces() { return _api_layer_interfaces; } + bool ExtensionIsEnabled(const std::string& extension); + XrDebugUtilsMessengerEXT DefaultDebugUtilsMessenger() { return _messenger; } + void SetDefaultDebugUtilsMessenger(XrDebugUtilsMessengerEXT messenger) { _messenger = messenger; } + XrResult GetInstanceProcAddr(const char* name, PFN_xrVoidFunction* function); + + private: + LoaderInstance(XrInstance instance, const XrInstanceCreateInfo* createInfo, PFN_xrGetInstanceProcAddr topmost_gipa, + std::vector<std::unique_ptr<ApiLayerInterface>> api_layer_interfaces); + + private: + XrInstance _runtime_instance{XR_NULL_HANDLE}; + PFN_xrGetInstanceProcAddr _topmost_gipa{nullptr}; + std::vector<std::string> _enabled_extensions; + std::vector<std::unique_ptr<ApiLayerInterface>> _api_layer_interfaces; + + std::unique_ptr<XrGeneratedDispatchTable> _dispatch_table; + // Internal debug messenger created during xrCreateInstance + XrDebugUtilsMessengerEXT _messenger{XR_NULL_HANDLE}; +}; diff --git a/thirdparty/openxr/src/loader/loader_logger.cpp b/thirdparty/openxr/src/loader/loader_logger.cpp new file mode 100644 index 0000000000..dba46aa92d --- /dev/null +++ b/thirdparty/openxr/src/loader/loader_logger.cpp @@ -0,0 +1,239 @@ +// Copyright (c) 2017-2022, The Khronos Group Inc. +// Copyright (c) 2017-2019 Valve Corporation +// Copyright (c) 2017-2019 LunarG, Inc. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Initial Author: Mark Young <marky@lunarg.com> +// + +#include "loader_logger.hpp" + +#include "extra_algorithms.h" +#include "hex_and_handles.h" +#include "loader_logger_recorders.hpp" +#include "platform_utils.hpp" + +#include <openxr/openxr.h> + +#include <algorithm> +#include <iterator> +#include <memory> +#include <mutex> +#include <sstream> +#include <string> +#include <unordered_map> +#include <utility> +#include <vector> + +bool LoaderLogRecorder::LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT /*message_severity*/, + XrDebugUtilsMessageTypeFlagsEXT /*message_type*/, + const XrDebugUtilsMessengerCallbackDataEXT* /*callback_data*/) { + return false; +} + +// Utility functions for converting to/from XR_EXT_debug_utils values + +XrLoaderLogMessageSeverityFlags DebugUtilsSeveritiesToLoaderLogMessageSeverities( + XrDebugUtilsMessageSeverityFlagsEXT utils_severities) { + XrLoaderLogMessageSeverityFlags log_severities = 0UL; + if ((utils_severities & XR_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) != 0u) { + log_severities |= XR_LOADER_LOG_MESSAGE_SEVERITY_VERBOSE_BIT; + } + if ((utils_severities & XR_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) != 0u) { + log_severities |= XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT; + } + if ((utils_severities & XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) != 0u) { + log_severities |= XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT; + } + if ((utils_severities & XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0u) { + log_severities |= XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT; + } + return log_severities; +} + +XrDebugUtilsMessageSeverityFlagsEXT LoaderLogMessageSeveritiesToDebugUtilsMessageSeverities( + XrLoaderLogMessageSeverityFlags log_severities) { + XrDebugUtilsMessageSeverityFlagsEXT utils_severities = 0UL; + if ((log_severities & XR_LOADER_LOG_MESSAGE_SEVERITY_VERBOSE_BIT) != 0u) { + utils_severities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT; + } + if ((log_severities & XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT) != 0u) { + utils_severities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; + } + if ((log_severities & XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT) != 0u) { + utils_severities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; + } + if ((log_severities & XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT) != 0u) { + utils_severities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + } + return utils_severities; +} + +XrLoaderLogMessageTypeFlagBits DebugUtilsMessageTypesToLoaderLogMessageTypes(XrDebugUtilsMessageTypeFlagsEXT utils_types) { + XrLoaderLogMessageTypeFlagBits log_types = 0UL; + if ((utils_types & XR_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) != 0u) { + log_types |= XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT; + } + if ((utils_types & XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) != 0u) { + log_types |= XR_LOADER_LOG_MESSAGE_TYPE_SPECIFICATION_BIT; + } + if ((utils_types & XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) != 0u) { + log_types |= XR_LOADER_LOG_MESSAGE_TYPE_PERFORMANCE_BIT; + } + return log_types; +} + +XrDebugUtilsMessageTypeFlagsEXT LoaderLogMessageTypesToDebugUtilsMessageTypes(XrLoaderLogMessageTypeFlagBits log_types) { + XrDebugUtilsMessageTypeFlagsEXT utils_types = 0UL; + if ((log_types & XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT) != 0u) { + utils_types |= XR_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT; + } + if ((log_types & XR_LOADER_LOG_MESSAGE_TYPE_SPECIFICATION_BIT) != 0u) { + utils_types |= XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; + } + if ((log_types & XR_LOADER_LOG_MESSAGE_TYPE_PERFORMANCE_BIT) != 0u) { + utils_types |= XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + } + return utils_types; +} + +LoaderLogger::LoaderLogger() { + std::string debug_string = PlatformUtilsGetEnv("XR_LOADER_DEBUG"); + + // Add an error logger by default so that we at least get errors out to std::cerr. + // Normally we enable stderr output. But if the XR_LOADER_DEBUG environment variable is + // present as "none" then we don't. + if (debug_string != "none") { + AddLogRecorder(MakeStdErrLoaderLogRecorder(nullptr)); +#ifdef __ANDROID__ + // Add a logcat logger by default. + AddLogRecorder(MakeLogcatLoaderLogRecorder()); +#endif // __ANDROID__ + } + +#ifdef _WIN32 + // Add an debugger logger by default so that we at least get errors out to the debugger. + AddLogRecorder(MakeDebuggerLoaderLogRecorder(nullptr)); +#endif + + // If the environment variable to enable loader debugging is set, then enable the + // appropriate logging out to std::cout. + if (!debug_string.empty()) { + XrLoaderLogMessageSeverityFlags debug_flags = {}; + if (debug_string == "error") { + debug_flags = XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT; + } else if (debug_string == "warn") { + debug_flags = XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT | XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT; + } else if (debug_string == "info") { + debug_flags = XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT | XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT | + XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT; + } else if (debug_string == "all" || debug_string == "verbose") { + debug_flags = XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT | XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT | + XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT | XR_LOADER_LOG_MESSAGE_SEVERITY_VERBOSE_BIT; + } + AddLogRecorder(MakeStdOutLoaderLogRecorder(nullptr, debug_flags)); + } +} + +void LoaderLogger::AddLogRecorder(std::unique_ptr<LoaderLogRecorder>&& recorder) { + std::unique_lock<std::shared_timed_mutex> lock(_mutex); + _recorders.push_back(std::move(recorder)); +} + +void LoaderLogger::AddLogRecorderForXrInstance(XrInstance instance, std::unique_ptr<LoaderLogRecorder>&& recorder) { + std::unique_lock<std::shared_timed_mutex> lock(_mutex); + _recordersByInstance[instance].insert(recorder->UniqueId()); + _recorders.emplace_back(std::move(recorder)); +} + +void LoaderLogger::RemoveLogRecorder(uint64_t unique_id) { + std::unique_lock<std::shared_timed_mutex> lock(_mutex); + vector_remove_if_and_erase( + _recorders, [=](std::unique_ptr<LoaderLogRecorder> const& recorder) { return recorder->UniqueId() == unique_id; }); + for (auto& recorders : _recordersByInstance) { + auto& messengersForInstance = recorders.second; + if (messengersForInstance.count(unique_id) > 0) { + messengersForInstance.erase(unique_id); + } + } +} + +void LoaderLogger::RemoveLogRecordersForXrInstance(XrInstance instance) { + std::unique_lock<std::shared_timed_mutex> lock(_mutex); + if (_recordersByInstance.find(instance) != _recordersByInstance.end()) { + auto recorders = _recordersByInstance[instance]; + vector_remove_if_and_erase(_recorders, [=](std::unique_ptr<LoaderLogRecorder> const& recorder) { + return recorders.find(recorder->UniqueId()) != recorders.end(); + }); + _recordersByInstance.erase(instance); + } +} + +bool LoaderLogger::LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, XrLoaderLogMessageTypeFlags message_type, + const std::string& message_id, const std::string& command_name, const std::string& message, + const std::vector<XrSdkLogObjectInfo>& objects) { + XrLoaderLogMessengerCallbackData callback_data = {}; + callback_data.message_id = message_id.c_str(); + callback_data.command_name = command_name.c_str(); + callback_data.message = message.c_str(); + + auto names_and_labels = data_.PopulateNamesAndLabels(objects); + callback_data.objects = names_and_labels.sdk_objects.empty() ? nullptr : names_and_labels.sdk_objects.data(); + callback_data.object_count = static_cast<uint8_t>(names_and_labels.objects.size()); + + callback_data.session_labels = names_and_labels.labels.empty() ? nullptr : names_and_labels.labels.data(); + callback_data.session_labels_count = static_cast<uint8_t>(names_and_labels.labels.size()); + + std::shared_lock<std::shared_timed_mutex> lock(_mutex); + bool exit_app = false; + for (std::unique_ptr<LoaderLogRecorder>& recorder : _recorders) { + if ((recorder->MessageSeverities() & message_severity) == message_severity && + (recorder->MessageTypes() & message_type) == message_type) { + exit_app |= recorder->LogMessage(message_severity, message_type, &callback_data); + } + } + return exit_app; +} + +// Extension-specific logging functions +bool LoaderLogger::LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT message_severity, + XrDebugUtilsMessageTypeFlagsEXT message_type, + const XrDebugUtilsMessengerCallbackDataEXT* callback_data) { + bool exit_app = false; + XrLoaderLogMessageSeverityFlags log_message_severity = DebugUtilsSeveritiesToLoaderLogMessageSeverities(message_severity); + XrLoaderLogMessageTypeFlags log_message_type = DebugUtilsMessageTypesToLoaderLogMessageTypes(message_type); + + AugmentedCallbackData augmented_data; + data_.WrapCallbackData(&augmented_data, callback_data); + + // Loop through the recorders + std::shared_lock<std::shared_timed_mutex> lock(_mutex); + for (std::unique_ptr<LoaderLogRecorder>& recorder : _recorders) { + // Only send the message if it's a debug utils recorder and of the type the recorder cares about. + if (recorder->Type() != XR_LOADER_LOG_DEBUG_UTILS || + (recorder->MessageSeverities() & log_message_severity) != log_message_severity || + (recorder->MessageTypes() & log_message_type) != log_message_type) { + continue; + } + + exit_app |= recorder->LogDebugUtilsMessage(message_severity, message_type, augmented_data.exported_data); + } + return exit_app; +} + +void LoaderLogger::AddObjectName(uint64_t object_handle, XrObjectType object_type, const std::string& object_name) { + data_.AddObjectName(object_handle, object_type, object_name); +} + +void LoaderLogger::BeginLabelRegion(XrSession session, const XrDebugUtilsLabelEXT* label_info) { + data_.BeginLabelRegion(session, *label_info); +} + +void LoaderLogger::EndLabelRegion(XrSession session) { data_.EndLabelRegion(session); } + +void LoaderLogger::InsertLabel(XrSession session, const XrDebugUtilsLabelEXT* label_info) { + data_.InsertLabel(session, *label_info); +} + +void LoaderLogger::DeleteSessionLabels(XrSession session) { data_.DeleteSessionLabels(session); } diff --git a/thirdparty/openxr/src/loader/loader_logger.hpp b/thirdparty/openxr/src/loader/loader_logger.hpp new file mode 100644 index 0000000000..260ebe354a --- /dev/null +++ b/thirdparty/openxr/src/loader/loader_logger.hpp @@ -0,0 +1,194 @@ +// Copyright (c) 2017-2022, The Khronos Group Inc. +// Copyright (c) 2017-2019 Valve Corporation +// Copyright (c) 2017-2019 LunarG, Inc. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Initial Author: Mark Young <marky@lunarg.com> +// + +#pragma once + +#include <memory> +#include <mutex> +#include <string> +#include <unordered_map> +#include <unordered_set> +#include <vector> +#include <set> +#include <map> +#include <shared_mutex> + +#include <openxr/openxr.h> + +#include "hex_and_handles.h" +#include "object_info.h" + +// Use internal versions of flags similar to XR_EXT_debug_utils so that +// we're not tightly coupled to that extension. This way, if the extension +// changes or gets replaced, we can be flexible in the loader. +#define XR_LOADER_LOG_MESSAGE_SEVERITY_VERBOSE_BIT 0x00000001 +#define XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT 0x00000010 +#define XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT 0x00000100 +#define XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT 0x00001000 +#define XR_LOADER_LOG_MESSAGE_SEVERITY_DEFAULT_BITS 0x00000000 +typedef XrFlags64 XrLoaderLogMessageSeverityFlagBits; +typedef XrFlags64 XrLoaderLogMessageSeverityFlags; + +#define XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT 0x00000001 +#define XR_LOADER_LOG_MESSAGE_TYPE_SPECIFICATION_BIT 0x00000002 +#define XR_LOADER_LOG_MESSAGE_TYPE_PERFORMANCE_BIT 0x00000004 +#define XR_LOADER_LOG_MESSAGE_TYPE_DEFAULT_BITS 0xffffffff +typedef XrFlags64 XrLoaderLogMessageTypeFlagBits; +typedef XrFlags64 XrLoaderLogMessageTypeFlags; + +struct XrLoaderLogMessengerCallbackData { + const char* message_id; + const char* command_name; + const char* message; + uint8_t object_count; + XrSdkLogObjectInfo* objects; + uint8_t session_labels_count; + XrDebugUtilsLabelEXT* session_labels; +}; + +enum XrLoaderLogType { + XR_LOADER_LOG_UNKNOWN = 0, + XR_LOADER_LOG_STDERR, + XR_LOADER_LOG_STDOUT, + XR_LOADER_LOG_DEBUG_UTILS, + XR_LOADER_LOG_DEBUGGER, + XR_LOADER_LOG_LOGCAT, +}; + +class LoaderLogRecorder { + public: + LoaderLogRecorder(XrLoaderLogType type, void* user_data, XrLoaderLogMessageSeverityFlags message_severities, + XrLoaderLogMessageTypeFlags message_types) { + _active = false; + _user_data = user_data; + _type = type; + _unique_id = 0; + _message_severities = message_severities; + _message_types = message_types; + } + virtual ~LoaderLogRecorder() = default; + + XrLoaderLogType Type() { return _type; } + + uint64_t UniqueId() { return _unique_id; } + + XrLoaderLogMessageSeverityFlags MessageSeverities() { return _message_severities; } + + XrLoaderLogMessageTypeFlags MessageTypes() { return _message_types; } + + virtual void Start() { _active = true; } + + bool IsPaused() { return _active; } + + virtual void Pause() { _active = false; } + + virtual void Resume() { _active = true; } + + virtual void Stop() { _active = false; } + + virtual bool LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, XrLoaderLogMessageTypeFlags message_type, + const XrLoaderLogMessengerCallbackData* callback_data) = 0; + + // Extension-specific logging functions - defaults to do nothing. + virtual bool LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT message_severity, + XrDebugUtilsMessageTypeFlagsEXT message_type, + const XrDebugUtilsMessengerCallbackDataEXT* callback_data); + + protected: + bool _active; + XrLoaderLogType _type; + uint64_t _unique_id; + void* _user_data; + XrLoaderLogMessageSeverityFlags _message_severities; + XrLoaderLogMessageTypeFlags _message_types; +}; + +class LoaderLogger { + public: + static LoaderLogger& GetInstance() { + static LoaderLogger instance; + return instance; + } + + void AddLogRecorder(std::unique_ptr<LoaderLogRecorder>&& recorder); + void RemoveLogRecorder(uint64_t unique_id); + + void AddLogRecorderForXrInstance(XrInstance instance, std::unique_ptr<LoaderLogRecorder>&& recorder); + void RemoveLogRecordersForXrInstance(XrInstance instance); + + //! Called from LoaderXrTermSetDebugUtilsObjectNameEXT - an empty name means remove + void AddObjectName(uint64_t object_handle, XrObjectType object_type, const std::string& object_name); + void BeginLabelRegion(XrSession session, const XrDebugUtilsLabelEXT* label_info); + void EndLabelRegion(XrSession session); + void InsertLabel(XrSession session, const XrDebugUtilsLabelEXT* label_info); + void DeleteSessionLabels(XrSession session); + + bool LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, XrLoaderLogMessageTypeFlags message_type, + const std::string& message_id, const std::string& command_name, const std::string& message, + const std::vector<XrSdkLogObjectInfo>& objects = {}); + static bool LogErrorMessage(const std::string& command_name, const std::string& message, + const std::vector<XrSdkLogObjectInfo>& objects = {}) { + return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT, XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT, + "OpenXR-Loader", command_name, message, objects); + } + static bool LogWarningMessage(const std::string& command_name, const std::string& message, + const std::vector<XrSdkLogObjectInfo>& objects = {}) { + return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT, XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT, + "OpenXR-Loader", command_name, message, objects); + } + static bool LogInfoMessage(const std::string& command_name, const std::string& message, + const std::vector<XrSdkLogObjectInfo>& objects = {}) { + return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT, XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT, + "OpenXR-Loader", command_name, message, objects); + } + static bool LogVerboseMessage(const std::string& command_name, const std::string& message, + const std::vector<XrSdkLogObjectInfo>& objects = {}) { + return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_VERBOSE_BIT, XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT, + "OpenXR-Loader", command_name, message, objects); + } + static bool LogValidationErrorMessage(const std::string& vuid, const std::string& command_name, const std::string& message, + const std::vector<XrSdkLogObjectInfo>& objects = {}) { + return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT, XR_LOADER_LOG_MESSAGE_TYPE_SPECIFICATION_BIT, + vuid, command_name, message, objects); + } + static bool LogValidationWarningMessage(const std::string& vuid, const std::string& command_name, const std::string& message, + const std::vector<XrSdkLogObjectInfo>& objects = {}) { + return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT, XR_LOADER_LOG_MESSAGE_TYPE_SPECIFICATION_BIT, + vuid, command_name, message, objects); + } + + // Extension-specific logging functions + bool LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT message_severity, XrDebugUtilsMessageTypeFlagsEXT message_type, + const XrDebugUtilsMessengerCallbackDataEXT* callback_data); + + // Non-copyable + LoaderLogger(const LoaderLogger&) = delete; + LoaderLogger& operator=(const LoaderLogger&) = delete; + + private: + LoaderLogger(); + + std::shared_timed_mutex _mutex; + + // List of *all* available recorder objects (including created specifically for an Instance) + std::vector<std::unique_ptr<LoaderLogRecorder>> _recorders; + + // List of recorder objects only created specifically for an XrInstance + std::unordered_map<XrInstance, std::unordered_set<uint64_t>> _recordersByInstance; + + DebugUtilsData data_; +}; + +// Utility functions for converting to/from XR_EXT_debug_utils values +XrLoaderLogMessageSeverityFlags DebugUtilsSeveritiesToLoaderLogMessageSeverities( + XrDebugUtilsMessageSeverityFlagsEXT utils_severities); +XrDebugUtilsMessageSeverityFlagsEXT LoaderLogMessageSeveritiesToDebugUtilsMessageSeverities( + XrLoaderLogMessageSeverityFlags log_severities); +XrLoaderLogMessageTypeFlagBits DebugUtilsMessageTypesToLoaderLogMessageTypes(XrDebugUtilsMessageTypeFlagsEXT utils_types); +XrDebugUtilsMessageTypeFlagsEXT LoaderLogMessageTypesToDebugUtilsMessageTypes(XrLoaderLogMessageTypeFlagBits log_types); diff --git a/thirdparty/openxr/src/loader/loader_logger_recorders.cpp b/thirdparty/openxr/src/loader/loader_logger_recorders.cpp new file mode 100644 index 0000000000..7673678c60 --- /dev/null +++ b/thirdparty/openxr/src/loader/loader_logger_recorders.cpp @@ -0,0 +1,291 @@ +// Copyright (c) 2017-2022, The Khronos Group Inc. +// Copyright (c) 2017-2019 Valve Corporation +// Copyright (c) 2017-2019 LunarG, Inc. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Initial Author: Mark Young <marky@lunarg.com> +// + +#include "loader_logger_recorders.hpp" + +#include "hex_and_handles.h" +#include "loader_logger.hpp" + +#include <openxr/openxr.h> + +#include <memory> +#include <string> +#include <vector> +#include <iostream> +#include <sstream> + +#ifdef __ANDROID__ +#include "android/log.h" +#endif + +#ifdef _WIN32 +#include <windows.h> +#endif + +// Anonymous namespace to keep these types private +namespace { +void OutputMessageToStream(std::ostream& os, XrLoaderLogMessageSeverityFlagBits message_severity, + XrLoaderLogMessageTypeFlags message_type, const XrLoaderLogMessengerCallbackData* callback_data) { + if (XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT > message_severity) { + os << "Verbose ["; + } else if (XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT > message_severity) { + os << "Info ["; + } else if (XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT > message_severity) { + os << "Warning ["; + } else { + os << "Error ["; + } + switch (message_type) { + case XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT: + os << "GENERAL"; + break; + case XR_LOADER_LOG_MESSAGE_TYPE_SPECIFICATION_BIT: + os << "SPEC"; + break; + case XR_LOADER_LOG_MESSAGE_TYPE_PERFORMANCE_BIT: + os << "PERF"; + break; + default: + os << "UNKNOWN"; + break; + } + os << " | " << callback_data->command_name << " | " << callback_data->message_id << "] : " << callback_data->message + << std::endl; + + for (uint32_t obj = 0; obj < callback_data->object_count; ++obj) { + os << " Object[" << obj << "] = " << callback_data->objects[obj].ToString(); + os << std::endl; + } + for (uint32_t label = 0; label < callback_data->session_labels_count; ++label) { + os << " SessionLabel[" << std::to_string(label) << "] = " << callback_data->session_labels[label].labelName; + os << std::endl; + } +} + +// With std::cerr: Standard Error logger, always on for now +// With std::cout: Standard Output logger used with XR_LOADER_DEBUG +class OstreamLoaderLogRecorder : public LoaderLogRecorder { + public: + OstreamLoaderLogRecorder(std::ostream& os, void* user_data, XrLoaderLogMessageSeverityFlags flags); + + bool LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, XrLoaderLogMessageTypeFlags message_type, + const XrLoaderLogMessengerCallbackData* callback_data) override; + + private: + std::ostream& os_; +}; + +// Debug Utils logger used with XR_EXT_debug_utils +class DebugUtilsLogRecorder : public LoaderLogRecorder { + public: + DebugUtilsLogRecorder(const XrDebugUtilsMessengerCreateInfoEXT* create_info, XrDebugUtilsMessengerEXT debug_messenger); + + bool LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, XrLoaderLogMessageTypeFlags message_type, + const XrLoaderLogMessengerCallbackData* callback_data) override; + + // Extension-specific logging functions + bool LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT message_severity, XrDebugUtilsMessageTypeFlagsEXT message_type, + const XrDebugUtilsMessengerCallbackDataEXT* callback_data) override; + + private: + PFN_xrDebugUtilsMessengerCallbackEXT _user_callback; +}; +#ifdef __ANDROID__ + +class LogcatLoaderLogRecorder : public LoaderLogRecorder { + public: + LogcatLoaderLogRecorder(); + + bool LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, XrLoaderLogMessageTypeFlags message_type, + const XrLoaderLogMessengerCallbackData* callback_data) override; +}; +#endif + +#ifdef _WIN32 +// Output to debugger +class DebuggerLoaderLogRecorder : public LoaderLogRecorder { + public: + DebuggerLoaderLogRecorder(void* user_data, XrLoaderLogMessageSeverityFlags flags); + + bool LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, XrLoaderLogMessageTypeFlags message_type, + const XrLoaderLogMessengerCallbackData* callback_data) override; +}; +#endif + +// Unified stdout/stderr logger +OstreamLoaderLogRecorder::OstreamLoaderLogRecorder(std::ostream& os, void* user_data, XrLoaderLogMessageSeverityFlags flags) + : LoaderLogRecorder(XR_LOADER_LOG_STDOUT, user_data, flags, 0xFFFFFFFFUL), os_(os) { + // Automatically start + Start(); +} + +bool OstreamLoaderLogRecorder::LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, + XrLoaderLogMessageTypeFlags message_type, + const XrLoaderLogMessengerCallbackData* callback_data) { + if (_active && 0 != (_message_severities & message_severity) && 0 != (_message_types & message_type)) { + OutputMessageToStream(os_, message_severity, message_type, callback_data); + } + + // Return of "true" means that we should exit the application after the logged message. We + // don't want to do that for our internal logging. Only let a user return true. + return false; +} + +// A logger associated with the XR_EXT_debug_utils extension + +DebugUtilsLogRecorder::DebugUtilsLogRecorder(const XrDebugUtilsMessengerCreateInfoEXT* create_info, + XrDebugUtilsMessengerEXT debug_messenger) + : LoaderLogRecorder(XR_LOADER_LOG_DEBUG_UTILS, static_cast<void*>(create_info->userData), + DebugUtilsSeveritiesToLoaderLogMessageSeverities(create_info->messageSeverities), + DebugUtilsMessageTypesToLoaderLogMessageTypes(create_info->messageTypes)), + _user_callback(create_info->userCallback) { + // Use the debug messenger value to uniquely identify this logger with that messenger + _unique_id = MakeHandleGeneric(debug_messenger); + Start(); +} + +// Extension-specific logging functions +bool DebugUtilsLogRecorder::LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, + XrLoaderLogMessageTypeFlags message_type, + const XrLoaderLogMessengerCallbackData* callback_data) { + bool should_exit = false; + if (_active && 0 != (_message_severities & message_severity) && 0 != (_message_types & message_type)) { + XrDebugUtilsMessageSeverityFlagsEXT utils_severity = DebugUtilsSeveritiesToLoaderLogMessageSeverities(message_severity); + XrDebugUtilsMessageTypeFlagsEXT utils_type = LoaderLogMessageTypesToDebugUtilsMessageTypes(message_type); + + // Convert the loader log message into the debug utils log message information + XrDebugUtilsMessengerCallbackDataEXT utils_callback_data = {}; + utils_callback_data.type = XR_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT; + utils_callback_data.messageId = callback_data->message_id; + utils_callback_data.functionName = callback_data->command_name; + utils_callback_data.message = callback_data->message; + std::vector<XrDebugUtilsObjectNameInfoEXT> utils_objects; + utils_objects.resize(callback_data->object_count); + for (uint8_t object = 0; object < callback_data->object_count; ++object) { + utils_objects[object].type = XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; + utils_objects[object].next = nullptr; + utils_objects[object].objectHandle = callback_data->objects[object].handle; + utils_objects[object].objectType = callback_data->objects[object].type; + utils_objects[object].objectName = callback_data->objects[object].name.c_str(); + } + utils_callback_data.objectCount = callback_data->object_count; + utils_callback_data.objects = utils_objects.data(); + utils_callback_data.sessionLabelCount = callback_data->session_labels_count; + utils_callback_data.sessionLabels = callback_data->session_labels; + + // Call the user callback with the appropriate info + // Return of "true" means that we should exit the application after the logged message. + should_exit = (_user_callback(utils_severity, utils_type, &utils_callback_data, _user_data) == XR_TRUE); + } + + return should_exit; +} + +bool DebugUtilsLogRecorder::LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT message_severity, + XrDebugUtilsMessageTypeFlagsEXT message_type, + const XrDebugUtilsMessengerCallbackDataEXT* callback_data) { + // Call the user callback with the appropriate info + // Return of "true" means that we should exit the application after the logged message. + return (_user_callback(message_severity, message_type, callback_data, _user_data) == XR_TRUE); +} + +#ifdef __ANDROID__ + +static inline android_LogPriority LoaderToAndroidLogPriority(XrLoaderLogMessageSeverityFlags message_severity) { + if (0 != (message_severity & XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT)) { + return ANDROID_LOG_ERROR; + } + if (0 != (message_severity & XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT)) { + return ANDROID_LOG_WARN; + } + if (0 != (message_severity & XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT)) { + return ANDROID_LOG_INFO; + } + return ANDROID_LOG_VERBOSE; +} + +LogcatLoaderLogRecorder::LogcatLoaderLogRecorder() + : LoaderLogRecorder(XR_LOADER_LOG_LOGCAT, nullptr, + XR_LOADER_LOG_MESSAGE_SEVERITY_VERBOSE_BIT | XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT | + XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT | XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT, + 0xFFFFFFFFUL) { + // Automatically start + Start(); +} + +bool LogcatLoaderLogRecorder::LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, + XrLoaderLogMessageTypeFlags message_type, + const XrLoaderLogMessengerCallbackData* callback_data) { + if (_active && 0 != (_message_severities & message_severity) && 0 != (_message_types & message_type)) { + std::stringstream ss; + OutputMessageToStream(ss, message_severity, message_type, callback_data); + __android_log_write(LoaderToAndroidLogPriority(message_severity), "OpenXR-Loader", ss.str().c_str()); + } + + // Return of "true" means that we should exit the application after the logged message. We + // don't want to do that for our internal logging. Only let a user return true. + return false; +} +#endif // __ANDROID__ + +#ifdef _WIN32 +// Unified stdout/stderr logger +DebuggerLoaderLogRecorder::DebuggerLoaderLogRecorder(void* user_data, XrLoaderLogMessageSeverityFlags flags) + : LoaderLogRecorder(XR_LOADER_LOG_DEBUGGER, user_data, flags, 0xFFFFFFFFUL) { + // Automatically start + Start(); +} + +bool DebuggerLoaderLogRecorder::LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, + XrLoaderLogMessageTypeFlags message_type, + const XrLoaderLogMessengerCallbackData* callback_data) { + if (_active && 0 != (_message_severities & message_severity) && 0 != (_message_types & message_type)) { + std::stringstream ss; + OutputMessageToStream(ss, message_severity, message_type, callback_data); + + OutputDebugStringA(ss.str().c_str()); + } + + // Return of "true" means that we should exit the application after the logged message. We + // don't want to do that for our internal logging. Only let a user return true. + return false; +} +#endif +} // namespace + +std::unique_ptr<LoaderLogRecorder> MakeStdOutLoaderLogRecorder(void* user_data, XrLoaderLogMessageSeverityFlags flags) { + std::unique_ptr<LoaderLogRecorder> recorder(new OstreamLoaderLogRecorder(std::cout, user_data, flags)); + return recorder; +} + +std::unique_ptr<LoaderLogRecorder> MakeStdErrLoaderLogRecorder(void* user_data) { + std::unique_ptr<LoaderLogRecorder> recorder( + new OstreamLoaderLogRecorder(std::cerr, user_data, XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT)); + return recorder; +} + +std::unique_ptr<LoaderLogRecorder> MakeDebugUtilsLoaderLogRecorder(const XrDebugUtilsMessengerCreateInfoEXT* create_info, + XrDebugUtilsMessengerEXT debug_messenger) { + std::unique_ptr<LoaderLogRecorder> recorder(new DebugUtilsLogRecorder(create_info, debug_messenger)); + return recorder; +} + +#ifdef __ANDROID__ +std::unique_ptr<LoaderLogRecorder> MakeLogcatLoaderLogRecorder() { + std::unique_ptr<LoaderLogRecorder> recorder(new LogcatLoaderLogRecorder()); + return recorder; +} +#endif + +#ifdef _WIN32 +std::unique_ptr<LoaderLogRecorder> MakeDebuggerLoaderLogRecorder(void* user_data) { + std::unique_ptr<LoaderLogRecorder> recorder(new DebuggerLoaderLogRecorder(user_data, XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT)); + return recorder; +} +#endif diff --git a/thirdparty/openxr/src/loader/loader_logger_recorders.hpp b/thirdparty/openxr/src/loader/loader_logger_recorders.hpp new file mode 100644 index 0000000000..31e5243c45 --- /dev/null +++ b/thirdparty/openxr/src/loader/loader_logger_recorders.hpp @@ -0,0 +1,40 @@ +// Copyright (c) 2017-2022, The Khronos Group Inc. +// Copyright (c) 2017-2019 Valve Corporation +// Copyright (c) 2017-2019 LunarG, Inc. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Initial Author: Ryan Pavlik <ryan.pavlik@collabora.com> +// + +#pragma once + +#include "loader_logger.hpp" + +#include <openxr/openxr.h> + +#include <memory> + +//! Standard Error logger, on by default. Disabled with environment variable XR_LOADER_DEBUG = "none". +std::unique_ptr<LoaderLogRecorder> MakeStdErrLoaderLogRecorder(void* user_data); + +//! Standard Output logger used with XR_LOADER_DEBUG environment variable. +std::unique_ptr<LoaderLogRecorder> MakeStdOutLoaderLogRecorder(void* user_data, XrLoaderLogMessageSeverityFlags flags); + +#ifdef __ANDROID__ +//! Android liblog ("logcat") logger +std::unique_ptr<LoaderLogRecorder> MakeLogcatLoaderLogRecorder(); +#endif + +// Debug Utils logger used with XR_EXT_debug_utils +std::unique_ptr<LoaderLogRecorder> MakeDebugUtilsLoaderLogRecorder(const XrDebugUtilsMessengerCreateInfoEXT* create_info, + XrDebugUtilsMessengerEXT debug_messenger); + +#ifdef _WIN32 +//! Win32 debugger output +std::unique_ptr<LoaderLogRecorder> MakeDebuggerLoaderLogRecorder(void* user_data); +#endif + +// TODO: Add other Derived classes: +// - FileLoaderLogRecorder - During/after xrCreateInstance +// - PipeLoaderLogRecorder? - During/after xrCreateInstance diff --git a/thirdparty/openxr/src/loader/loader_platform.hpp b/thirdparty/openxr/src/loader/loader_platform.hpp new file mode 100644 index 0000000000..e2757fffb9 --- /dev/null +++ b/thirdparty/openxr/src/loader/loader_platform.hpp @@ -0,0 +1,204 @@ +// Copyright (c) 2017-2022, The Khronos Group Inc. +// Copyright (c) 2017-2019 Valve Corporation +// Copyright (c) 2017-2019 LunarG, Inc. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Initial Authors: Mark Young <marky@lunarg.com>, Dave Houlton <daveh@lunarg.com> +// + +#pragma once + +#include <cassert> +#include <sstream> +#include <string> + +#include "xr_dependencies.h" +#include "platform_utils.hpp" + +#if defined(__GNUC__) && __GNUC__ >= 4 +#define LOADER_EXPORT __attribute__((visibility("default"))) +#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590) +#define LOADER_EXPORT __attribute__((visibility("default"))) +#else +#define LOADER_EXPORT +#endif + +// Environment variables +#if defined(XR_OS_LINUX) || defined(XR_OS_APPLE) || defined(XR_OS_ANDROID) + +#include <sys/types.h> +#include <sys/stat.h> +#include <dlfcn.h> +#include <unistd.h> +#include <stdlib.h> +#include <dirent.h> + +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif + +#define PATH_SEPARATOR ':' +#define DIRECTORY_SYMBOL '/' + +// Dynamic Loading of libraries: +typedef void *LoaderPlatformLibraryHandle; +static inline LoaderPlatformLibraryHandle LoaderPlatformLibraryOpen(const std::string &path) { + // When loading the library, we use RTLD_LAZY so that not all symbols have to be + // resolved at this time (which improves performance). Note that if not all symbols + // can be resolved, this could cause crashes later. + // For experimenting/debugging: Define the LD_BIND_NOW environment variable to force all + // symbols to be resolved here. + return dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL); +} + +static inline const char *LoaderPlatformLibraryOpenError(const std::string &path) { + (void)path; + return dlerror(); +} + +static inline void LoaderPlatformLibraryClose(LoaderPlatformLibraryHandle library) { dlclose(library); } + +static inline void *LoaderPlatformLibraryGetProcAddr(LoaderPlatformLibraryHandle library, const std::string &name) { + assert(library); + assert(!name.empty()); + return dlsym(library, name.c_str()); +} + +static inline const char *LoaderPlatformLibraryGetProcAddrError(const std::string &name) { + (void)name; + return dlerror(); +} + +#elif defined(XR_OS_WINDOWS) + +#define PATH_SEPARATOR ';' +#define DIRECTORY_SYMBOL '\\' + +// Workaround for MS VS 2010/2013 missing snprintf and vsnprintf +#if defined(_MSC_VER) && _MSC_VER < 1900 +#include <stdint.h> + +static inline int32_t xr_vsnprintf(char *result_buffer, size_t buffer_size, const char *print_format, va_list varying_list) { + int32_t copy_count = -1; + if (buffer_size != 0) { + copy_count = _vsnprintf_s(result_buffer, buffer_size, _TRUNCATE, print_format, varying_list); + } + if (copy_count == -1) { + copy_count = _vscprintf(print_format, varying_list); + } + return copy_count; +} + +static inline int32_t xr_snprintf(char *result_buffer, size_t buffer_size, const char *print_format, ...) { + va_list varying_list; + va_start(varying_list, print_format); + int32_t copy_count = xr_vsnprintf(result_buffer, buffer_size, print_format, varying_list); + va_end(varying_list); + return copy_count; +} + +#define snprintf xr_snprintf +#define vsnprintf xr_vsnprintf + +#endif + +static inline std::string DescribeError(uint32_t code, bool prefixErrorCode = true) { + std::string str; + + if (prefixErrorCode) { + char prefixBuffer[64]; + snprintf(prefixBuffer, sizeof(prefixBuffer), "0x%llx (%lld): ", (uint64_t)code, (int64_t)code); + str = prefixBuffer; + } + + // Could use FORMAT_MESSAGE_FROM_HMODULE to specify an error source. + WCHAR errorBufferW[1024]{}; + const DWORD errorBufferWCapacity = sizeof(errorBufferW) / sizeof(errorBufferW[0]); + const DWORD length = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, (DWORD)code, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), errorBufferW, errorBufferWCapacity, nullptr); + + if (length) { // If errorBufferW contains what we are looking for... + str += wide_to_utf8(errorBufferW); + } else { + str = "(unknown)"; + } + + return str; +} + +// Dynamic Loading: +typedef HMODULE LoaderPlatformLibraryHandle; +static inline LoaderPlatformLibraryHandle LoaderPlatformLibraryOpen(const std::string &path) { + const std::wstring pathW = utf8_to_wide(path); + + // Try loading the library the original way first. + LoaderPlatformLibraryHandle handle = LoadLibraryW(pathW.c_str()); + + if (handle == NULL && GetLastError() == ERROR_MOD_NOT_FOUND) { + const DWORD dwAttrib = GetFileAttributesW(pathW.c_str()); + const bool fileExists = (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); + if (fileExists) { + // If that failed, then try loading it with broader search folders. + handle = LoadLibraryExW(pathW.c_str(), NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR); + } + } + + return handle; +} + +static inline std::string LoaderPlatformLibraryOpenError(const std::string &path) { + std::stringstream ss; + const DWORD dwLastError = GetLastError(); + const std::string strError = DescribeError(dwLastError); + ss << "Failed to open dynamic library " << path << " with error " << dwLastError << ": " << strError; + return ss.str(); +} + +static inline void LoaderPlatformLibraryClose(LoaderPlatformLibraryHandle library) { FreeLibrary(library); } + +static inline void *LoaderPlatformLibraryGetProcAddr(LoaderPlatformLibraryHandle library, const std::string &name) { + assert(library); + assert(name.size() > 0); + return reinterpret_cast<void *>(GetProcAddress(library, name.c_str())); +} + +static inline std::string LoaderPlatformLibraryGetProcAddrAddrError(const std::string &name) { + std::stringstream ss; + ss << "Failed to find function " << name << " in dynamic library"; + return ss.str(); +} + +#else // Not Linux or Windows + +#define PATH_SEPARATOR ':' +#define DIRECTORY_SYMBOL '/' + +static inline LoaderPlatformLibraryHandle LoaderPlatformLibraryOpen(const std::string &path) { +// Stub func +#error("Unknown platform, undefined dynamic library routines resulting"); + (void)path; +} + +static inline const char *LoaderPlatformLibraryOpenError(const std::string &path) { + // Stub func + (void)path; +} + +static inline void LoaderPlatformLibraryClose(LoaderPlatformLibraryHandle library) { + // Stub func + (void)library; +} + +static inline void *LoaderPlatformLibraryGetProcAddr(LoaderPlatformLibraryHandle library, const std::string &name) { + // Stub func + void(library); + void(name); +} + +static inline const char *LoaderPlatformLibraryGetProcAddrError(const std::string &name) { + // Stub func + (void)name; +} + +#endif diff --git a/thirdparty/openxr/src/loader/manifest_file.cpp b/thirdparty/openxr/src/loader/manifest_file.cpp new file mode 100644 index 0000000000..e4eab3949e --- /dev/null +++ b/thirdparty/openxr/src/loader/manifest_file.cpp @@ -0,0 +1,845 @@ +// Copyright (c) 2017-2022, The Khronos Group Inc. +// Copyright (c) 2017-2019 Valve Corporation +// Copyright (c) 2017-2019 LunarG, Inc. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Initial Authors: Mark Young <marky@lunarg.com>, Dave Houlton <daveh@lunarg.com> +// + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif // defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) + +#include "manifest_file.hpp" + +#ifdef OPENXR_HAVE_COMMON_CONFIG +#include "common_config.h" +#endif // OPENXR_HAVE_COMMON_CONFIG + +#include "filesystem_utils.hpp" +#include "loader_platform.hpp" +#include "platform_utils.hpp" +#include "loader_logger.hpp" + +#include <json/json.h> +#include <openxr/openxr.h> + +#include <algorithm> +#include <cstring> +#include <fstream> +#include <memory> +#include <sstream> +#include <stdexcept> +#include <stdio.h> +#include <stdlib.h> +#include <string> +#include <unordered_map> +#include <utility> +#include <vector> + +#ifndef FALLBACK_CONFIG_DIRS +#define FALLBACK_CONFIG_DIRS "/etc/xdg" +#endif // !FALLBACK_CONFIG_DIRS + +#ifndef FALLBACK_DATA_DIRS +#define FALLBACK_DATA_DIRS "/usr/local/share:/usr/share" +#endif // !FALLBACK_DATA_DIRS + +#ifndef SYSCONFDIR +#define SYSCONFDIR "/etc" +#endif // !SYSCONFDIR + +#ifdef XRLOADER_DISABLE_EXCEPTION_HANDLING +#if JSON_USE_EXCEPTIONS +#error \ + "Loader is configured to not catch exceptions, but jsoncpp was built with exception-throwing enabled, which could violate the C ABI. One of those two things needs to change." +#endif // JSON_USE_EXCEPTIONS +#endif // !XRLOADER_DISABLE_EXCEPTION_HANDLING + +#include "runtime_interface.hpp" + +// Utility functions for finding files in the appropriate paths + +static inline bool StringEndsWith(const std::string &value, const std::string &ending) { + if (ending.size() > value.size()) { + return false; + } + return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); +} + +// If the file found is a manifest file name, add it to the out_files manifest list. +static void AddIfJson(const std::string &full_file, std::vector<std::string> &manifest_files) { + if (full_file.empty() || !StringEndsWith(full_file, ".json")) { + return; + } + manifest_files.push_back(full_file); +} + +// Check the current path for any manifest files. If the provided search_path is a directory, look for +// all included JSON files in that directory. Otherwise, just check the provided search_path which should +// be a single filename. +static void CheckAllFilesInThePath(const std::string &search_path, bool is_directory_list, + std::vector<std::string> &manifest_files) { + if (FileSysUtilsPathExists(search_path)) { + std::string absolute_path; + if (!is_directory_list) { + // If the file exists, try to add it + if (FileSysUtilsIsRegularFile(search_path)) { + FileSysUtilsGetAbsolutePath(search_path, absolute_path); + AddIfJson(absolute_path, manifest_files); + } + } else { + std::vector<std::string> files; + if (FileSysUtilsFindFilesInPath(search_path, files)) { + for (std::string &cur_file : files) { + std::string relative_path; + FileSysUtilsCombinePaths(search_path, cur_file, relative_path); + if (!FileSysUtilsGetAbsolutePath(relative_path, absolute_path)) { + continue; + } + AddIfJson(absolute_path, manifest_files); + } + } + } + } +} + +// Add all manifest files in the provided paths to the manifest_files list. If search_path +// is made up of directory listings (versus direct manifest file names) search each path for +// any manifest files. +static void AddFilesInPath(const std::string &search_path, bool is_directory_list, std::vector<std::string> &manifest_files) { + std::size_t last_found = 0; + std::size_t found = search_path.find_first_of(PATH_SEPARATOR); + std::string cur_search; + + // Handle any path listings in the string (separated by the appropriate path separator) + while (found != std::string::npos) { + // substr takes a start index and length. + std::size_t length = found - last_found; + cur_search = search_path.substr(last_found, length); + + CheckAllFilesInThePath(cur_search, is_directory_list, manifest_files); + + // This works around issue if multiple path separator follow each other directly. + last_found = found; + while (found == last_found) { + last_found = found + 1; + found = search_path.find_first_of(PATH_SEPARATOR, last_found); + } + } + + // If there's something remaining in the string, copy it over + if (last_found < search_path.size()) { + cur_search = search_path.substr(last_found); + CheckAllFilesInThePath(cur_search, is_directory_list, manifest_files); + } +} + +// Copy all paths listed in the cur_path string into output_path and append the appropriate relative_path onto the end of each. +static void CopyIncludedPaths(bool is_directory_list, const std::string &cur_path, const std::string &relative_path, + std::string &output_path) { + if (!cur_path.empty()) { + std::size_t last_found = 0; + std::size_t found = cur_path.find_first_of(PATH_SEPARATOR); + + // Handle any path listings in the string (separated by the appropriate path separator) + while (found != std::string::npos) { + std::size_t length = found - last_found; + output_path += cur_path.substr(last_found, length); + if (is_directory_list && (cur_path[found - 1] != '\\' && cur_path[found - 1] != '/')) { + output_path += DIRECTORY_SYMBOL; + } + output_path += relative_path; + output_path += PATH_SEPARATOR; + + last_found = found; + found = cur_path.find_first_of(PATH_SEPARATOR, found + 1); + } + + // If there's something remaining in the string, copy it over + size_t last_char = cur_path.size() - 1; + if (last_found != last_char) { + output_path += cur_path.substr(last_found); + if (is_directory_list && (cur_path[last_char] != '\\' && cur_path[last_char] != '/')) { + output_path += DIRECTORY_SYMBOL; + } + output_path += relative_path; + output_path += PATH_SEPARATOR; + } + } +} + +// Look for data files in the provided paths, but first check the environment override to determine if we should use that instead. +static void ReadDataFilesInSearchPaths(const std::string &override_env_var, const std::string &relative_path, bool &override_active, + std::vector<std::string> &manifest_files) { + std::string override_path; + std::string search_path; + + if (!override_env_var.empty()) { + bool permit_override = true; +#ifndef XR_OS_WINDOWS + if (geteuid() != getuid() || getegid() != getgid()) { + // Don't allow setuid apps to use the env var + permit_override = false; + } +#endif + if (permit_override) { + override_path = PlatformUtilsGetSecureEnv(override_env_var.c_str()); + } + } + + if (!override_path.empty()) { + CopyIncludedPaths(true, override_path, "", search_path); + override_active = true; + } else { + override_active = false; +#if !defined(XR_OS_WINDOWS) && !defined(XR_OS_ANDROID) + const char home_additional[] = ".local/share/"; + + // Determine how much space is needed to generate the full search path + // for the current manifest files. + std::string xdg_conf_dirs = PlatformUtilsGetSecureEnv("XDG_CONFIG_DIRS"); + std::string xdg_data_dirs = PlatformUtilsGetSecureEnv("XDG_DATA_DIRS"); + std::string xdg_data_home = PlatformUtilsGetSecureEnv("XDG_DATA_HOME"); + std::string home = PlatformUtilsGetSecureEnv("HOME"); + + if (xdg_conf_dirs.empty()) { + CopyIncludedPaths(true, FALLBACK_CONFIG_DIRS, relative_path, search_path); + } else { + CopyIncludedPaths(true, xdg_conf_dirs, relative_path, search_path); + } + + CopyIncludedPaths(true, SYSCONFDIR, relative_path, search_path); +#if defined(EXTRASYSCONFDIR) + CopyIncludedPaths(true, EXTRASYSCONFDIR, relative_path, search_path); +#endif + + if (xdg_data_dirs.empty()) { + CopyIncludedPaths(true, FALLBACK_DATA_DIRS, relative_path, search_path); + } else { + CopyIncludedPaths(true, xdg_data_dirs, relative_path, search_path); + } + + if (!xdg_data_home.empty()) { + CopyIncludedPaths(true, xdg_data_home, relative_path, search_path); + } else if (!home.empty()) { + std::string relative_home_path = home_additional; + relative_home_path += relative_path; + CopyIncludedPaths(true, home, relative_home_path, search_path); + } +#else + (void)relative_path; +#endif + } + + // Now, parse the paths and add any manifest files found in them. + AddFilesInPath(search_path, true, manifest_files); +} + +#ifdef XR_OS_LINUX + +// Get an XDG environment variable with a $HOME-relative default +static std::string GetXDGEnvHome(const char *name, const char *fallback_path) { + std::string result = PlatformUtilsGetSecureEnv(name); + if (!result.empty()) { + return result; + } + result = PlatformUtilsGetSecureEnv("HOME"); + if (result.empty()) { + return result; + } + result += "/"; + result += fallback_path; + return result; +} + +// Get an XDG environment variable with absolute defaults +static std::string GetXDGEnvAbsolute(const char *name, const char *fallback_paths) { + std::string result = PlatformUtilsGetSecureEnv(name); + if (!result.empty()) { + return result; + } + return fallback_paths; +} + +// Return the first instance of relative_path occurring in an XDG config dir according to standard +// precedence order. +static bool FindXDGConfigFile(const std::string &relative_path, std::string &out) { + out = GetXDGEnvHome("XDG_CONFIG_HOME", ".config"); + if (!out.empty()) { + out += "/"; + out += relative_path; + + LoaderLogger::LogInfoMessage("", "Looking for " + relative_path + " in XDG_CONFIG_HOME: " + out); + if (FileSysUtilsPathExists(out)) { + return true; + } + } + + std::istringstream iss(GetXDGEnvAbsolute("XDG_CONFIG_DIRS", FALLBACK_CONFIG_DIRS)); + std::string path; + while (std::getline(iss, path, PATH_SEPARATOR)) { + if (path.empty()) { + continue; + } + out = path; + out += "/"; + out += relative_path; + LoaderLogger::LogInfoMessage("", "Looking for " + relative_path + " in an entry of XDG_CONFIG_DIRS: " + out); + if (FileSysUtilsPathExists(out)) { + return true; + } + } + + out = SYSCONFDIR; + out += "/"; + out += relative_path; + LoaderLogger::LogInfoMessage("", "Looking for " + relative_path + " in compiled-in SYSCONFDIR: " + out); + if (FileSysUtilsPathExists(out)) { + return true; + } + +#if defined(EXTRASYSCONFDIR) + out = EXTRASYSCONFDIR; + out += "/"; + out += relative_path; + LoaderLogger::LogInfoMessage("", "Looking for " + relative_path + " in compiled-in EXTRASYSCONFDIR: " + out); + if (FileSysUtilsPathExists(out)) { + return true; + } +#endif + + out.clear(); + return false; +} + +#endif + +#ifdef XR_OS_WINDOWS + +// Look for runtime data files in the provided paths, but first check the environment override to determine +// if we should use that instead. +static void ReadRuntimeDataFilesInRegistry(const std::string &runtime_registry_location, + const std::string &default_runtime_value_name, + std::vector<std::string> &manifest_files) { + HKEY hkey; + DWORD access_flags; + wchar_t value_w[1024]; + DWORD value_size_w = sizeof(value_w); // byte size of the buffer. + + // Generate the full registry location for the registry information + std::string full_registry_location = OPENXR_REGISTRY_LOCATION; + full_registry_location += std::to_string(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION)); + full_registry_location += runtime_registry_location; + + const std::wstring full_registry_location_w = utf8_to_wide(full_registry_location); + const std::wstring default_runtime_value_name_w = utf8_to_wide(default_runtime_value_name); + + // Use 64 bit regkey for 64bit application, and use 32 bit regkey in WOW for 32bit application. + access_flags = KEY_QUERY_VALUE; + LONG open_value = RegOpenKeyExW(HKEY_LOCAL_MACHINE, full_registry_location_w.c_str(), 0, access_flags, &hkey); + + if (ERROR_SUCCESS != open_value) { + LoaderLogger::LogWarningMessage("", + "ReadRuntimeDataFilesInRegistry - failed to open registry key " + full_registry_location); + } else if (ERROR_SUCCESS != RegGetValueW(hkey, nullptr, default_runtime_value_name_w.c_str(), + RRF_RT_REG_SZ | REG_EXPAND_SZ | RRF_ZEROONFAILURE, NULL, + reinterpret_cast<LPBYTE>(&value_w), &value_size_w)) { + LoaderLogger::LogWarningMessage( + "", "ReadRuntimeDataFilesInRegistry - failed to read registry value " + default_runtime_value_name); + } else { + AddFilesInPath(wide_to_utf8(value_w), false, manifest_files); + } +} + +// Look for layer data files in the provided paths, but first check the environment override to determine +// if we should use that instead. +static void ReadLayerDataFilesInRegistry(const std::string ®istry_location, std::vector<std::string> &manifest_files) { + const std::wstring full_registry_location_w = + utf8_to_wide(OPENXR_REGISTRY_LOCATION + std::to_string(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION)) + registry_location); + + auto ReadLayerDataFilesInHive = [&](HKEY hive) { + HKEY hkey; + LONG open_value = RegOpenKeyExW(hive, full_registry_location_w.c_str(), 0, KEY_QUERY_VALUE, &hkey); + if (ERROR_SUCCESS != open_value) { + return false; + } + + wchar_t name_w[1024]{}; + LONG rtn_value; + DWORD name_size = 1023; + DWORD value; + DWORD value_size = sizeof(value); + DWORD key_index = 0; + while (ERROR_SUCCESS == + (rtn_value = RegEnumValueW(hkey, key_index++, name_w, &name_size, NULL, NULL, (LPBYTE)&value, &value_size))) { + if (value_size == sizeof(value) && value == 0) { + const std::string filename = wide_to_utf8(name_w); + AddFilesInPath(filename, false, manifest_files); + } + // Reset some items for the next loop + name_size = 1023; + } + + RegCloseKey(hkey); + + return true; + }; + + // Do not allow high integrity processes to act on data that can be controlled by medium integrity processes. + const bool readFromCurrentUser = !IsHighIntegrityLevel(); + + bool found = ReadLayerDataFilesInHive(HKEY_LOCAL_MACHINE); + if (readFromCurrentUser) { + found |= ReadLayerDataFilesInHive(HKEY_CURRENT_USER); + } + + if (!found) { + std::string warning_message = "ReadLayerDataFilesInRegistry - failed to read registry location "; + warning_message += registry_location; + warning_message += (readFromCurrentUser ? " in either HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER" : " in HKEY_LOCAL_MACHINE"); + LoaderLogger::LogWarningMessage("", warning_message); + } +} + +#endif // XR_OS_WINDOWS + +ManifestFile::ManifestFile(ManifestFileType type, const std::string &filename, const std::string &library_path) + : _filename(filename), _type(type), _library_path(library_path) {} + +bool ManifestFile::IsValidJson(const Json::Value &root_node, JsonVersion &version) { + if (root_node["file_format_version"].isNull() || !root_node["file_format_version"].isString()) { + LoaderLogger::LogErrorMessage("", "ManifestFile::IsValidJson - JSON file missing \"file_format_version\""); + return false; + } + std::string file_format = root_node["file_format_version"].asString(); + const int num_fields = sscanf(file_format.c_str(), "%u.%u.%u", &version.major, &version.minor, &version.patch); + + // Only version 1.0.0 is defined currently. Eventually we may have more version, but + // some of the versions may only be valid for layers or runtimes specifically. + if (num_fields != 3 || version.major != 1 || version.minor != 0 || version.patch != 0) { + std::ostringstream error_ss; + error_ss << "ManifestFile::IsValidJson - JSON \"file_format_version\" " << version.major << "." << version.minor << "." + << version.patch << " is not supported"; + LoaderLogger::LogErrorMessage("", error_ss.str()); + return false; + } + + return true; +} + +static void GetExtensionProperties(const std::vector<ExtensionListing> &extensions, std::vector<XrExtensionProperties> &props) { + for (const auto &ext : extensions) { + auto it = + std::find_if(props.begin(), props.end(), [&](XrExtensionProperties &prop) { return prop.extensionName == ext.name; }); + if (it != props.end()) { + it->extensionVersion = std::max(it->extensionVersion, ext.extension_version); + } else { + XrExtensionProperties prop = {}; + prop.type = XR_TYPE_EXTENSION_PROPERTIES; + prop.next = nullptr; + strncpy(prop.extensionName, ext.name.c_str(), XR_MAX_EXTENSION_NAME_SIZE - 1); + prop.extensionName[XR_MAX_EXTENSION_NAME_SIZE - 1] = '\0'; + prop.extensionVersion = ext.extension_version; + props.push_back(prop); + } + } +} + +// Return any instance extensions found in the manifest files in the proper form for +// OpenXR (XrExtensionProperties). +void ManifestFile::GetInstanceExtensionProperties(std::vector<XrExtensionProperties> &props) { + GetExtensionProperties(_instance_extensions, props); +} + +const std::string &ManifestFile::GetFunctionName(const std::string &func_name) const { + if (!_functions_renamed.empty()) { + auto found = _functions_renamed.find(func_name); + if (found != _functions_renamed.end()) { + return found->second; + } + } + return func_name; +} + +RuntimeManifestFile::RuntimeManifestFile(const std::string &filename, const std::string &library_path) + : ManifestFile(MANIFEST_TYPE_RUNTIME, filename, library_path) {} + +static void ParseExtension(Json::Value const &ext, std::vector<ExtensionListing> &extensions) { + Json::Value ext_name = ext["name"]; + Json::Value ext_version = ext["extension_version"]; + + // Allow "extension_version" as a String or a UInt to maintain backwards compatibility, even though it should be a String. + // Internal Issue 1411: https://gitlab.khronos.org/openxr/openxr/-/issues/1411 + // Internal MR !1867: https://gitlab.khronos.org/openxr/openxr/-/merge_requests/1867 + if (ext_name.isString() && (ext_version.isString() || ext_version.isUInt())) { + ExtensionListing ext_listing = {}; + ext_listing.name = ext_name.asString(); + if (ext_version.isUInt()) { + ext_listing.extension_version = ext_version.asUInt(); + } else { + ext_listing.extension_version = atoi(ext_version.asString().c_str()); + } + extensions.push_back(ext_listing); + } +} + +void ManifestFile::ParseCommon(Json::Value const &root_node) { + const Json::Value &inst_exts = root_node["instance_extensions"]; + if (!inst_exts.isNull() && inst_exts.isArray()) { + for (const auto &ext : inst_exts) { + ParseExtension(ext, _instance_extensions); + } + } + const Json::Value &funcs_renamed = root_node["functions"]; + if (!funcs_renamed.isNull() && !funcs_renamed.empty()) { + for (Json::ValueConstIterator func_it = funcs_renamed.begin(); func_it != funcs_renamed.end(); ++func_it) { + if (!(*func_it).isString()) { + LoaderLogger::LogWarningMessage( + "", "ManifestFile::ParseCommon " + _filename + " \"functions\" section contains non-string values."); + continue; + } + std::string original_name = func_it.key().asString(); + std::string new_name = (*func_it).asString(); + _functions_renamed.emplace(original_name, new_name); + } + } +} + +void RuntimeManifestFile::CreateIfValid(std::string const &filename, + std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files) { + std::ifstream json_stream(filename, std::ifstream::in); + + LoaderLogger::LogInfoMessage("", "RuntimeManifestFile::CreateIfValid - attempting to load " + filename); + std::ostringstream error_ss("RuntimeManifestFile::CreateIfValid "); + if (!json_stream.is_open()) { + error_ss << "failed to open " << filename << ". Does it exist?"; + LoaderLogger::LogErrorMessage("", error_ss.str()); + return; + } + Json::CharReaderBuilder builder; + std::string errors; + Json::Value root_node = Json::nullValue; + if (!Json::parseFromStream(builder, json_stream, &root_node, &errors) || !root_node.isObject()) { + error_ss << "failed to parse " << filename << "."; + if (!errors.empty()) { + error_ss << " (Error message: " << errors << ")"; + } + error_ss << " Is it a valid runtime manifest file?"; + LoaderLogger::LogErrorMessage("", error_ss.str()); + return; + } + + CreateIfValid(root_node, filename, manifest_files); +} + +void RuntimeManifestFile::CreateIfValid(const Json::Value &root_node, const std::string &filename, + std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files) { + std::ostringstream error_ss("RuntimeManifestFile::CreateIfValid "); + JsonVersion file_version = {}; + if (!ManifestFile::IsValidJson(root_node, file_version)) { + error_ss << "isValidJson indicates " << filename << " is not a valid manifest file."; + LoaderLogger::LogErrorMessage("", error_ss.str()); + return; + } + const Json::Value &runtime_root_node = root_node["runtime"]; + // The Runtime manifest file needs the "runtime" root as well as a sub-node for "library_path". If any of those aren't there, + // fail. + if (runtime_root_node.isNull() || runtime_root_node["library_path"].isNull() || !runtime_root_node["library_path"].isString()) { + error_ss << filename << " is missing required fields. Verify all proper fields exist."; + LoaderLogger::LogErrorMessage("", error_ss.str()); + return; + } + + std::string lib_path = runtime_root_node["library_path"].asString(); + + // If the library_path variable has no directory symbol, it's just a file name and should be accessible on the + // global library path. + if (lib_path.find('\\') != std::string::npos || lib_path.find('/') != std::string::npos) { + // If the library_path is an absolute path, just use that if it exists + if (FileSysUtilsIsAbsolutePath(lib_path)) { + if (!FileSysUtilsPathExists(lib_path)) { + error_ss << filename << " library " << lib_path << " does not appear to exist"; + LoaderLogger::LogErrorMessage("", error_ss.str()); + return; + } + } else { + // Otherwise, treat the library path as a relative path based on the JSON file. + std::string canonical_path; + std::string combined_path; + std::string file_parent; + // Search relative to the real manifest file, not relative to the symlink + if (!FileSysUtilsGetCanonicalPath(filename, canonical_path)) { + // Give relative to the non-canonical path a chance + canonical_path = filename; + } + if (!FileSysUtilsGetParentPath(canonical_path, file_parent) || + !FileSysUtilsCombinePaths(file_parent, lib_path, combined_path) || !FileSysUtilsPathExists(combined_path)) { + error_ss << filename << " library " << combined_path << " does not appear to exist"; + LoaderLogger::LogErrorMessage("", error_ss.str()); + return; + } + lib_path = combined_path; + } + } + + // Add this runtime manifest file + manifest_files.emplace_back(new RuntimeManifestFile(filename, lib_path)); + + // Add any extensions to it after the fact. + // Handle any renamed functions + manifest_files.back()->ParseCommon(runtime_root_node); +} + +// Find all manifest files in the appropriate search paths/registries for the given type. +XrResult RuntimeManifestFile::FindManifestFiles(std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files) { + XrResult result = XR_SUCCESS; + std::string filename = PlatformUtilsGetSecureEnv(OPENXR_RUNTIME_JSON_ENV_VAR); + if (!filename.empty()) { + LoaderLogger::LogInfoMessage( + "", "RuntimeManifestFile::FindManifestFiles - using environment variable override runtime file " + filename); + } else { +#ifdef XR_OS_WINDOWS + std::vector<std::string> filenames; + ReadRuntimeDataFilesInRegistry("", "ActiveRuntime", filenames); + if (filenames.size() == 0) { + LoaderLogger::LogErrorMessage( + "", "RuntimeManifestFile::FindManifestFiles - failed to find active runtime file in registry"); + return XR_ERROR_RUNTIME_UNAVAILABLE; + } + if (filenames.size() > 1) { + LoaderLogger::LogWarningMessage( + "", "RuntimeManifestFile::FindManifestFiles - found too many default runtime files in registry"); + } + filename = filenames[0]; + LoaderLogger::LogInfoMessage("", + "RuntimeManifestFile::FindManifestFiles - using registry-specified runtime file " + filename); +#elif defined(XR_OS_LINUX) + const std::string relative_path = + "openxr/" + std::to_string(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION)) + "/active_runtime.json"; + if (!FindXDGConfigFile(relative_path, filename)) { + LoaderLogger::LogErrorMessage( + "", "RuntimeManifestFile::FindManifestFiles - failed to determine active runtime file path for this environment"); + return XR_ERROR_RUNTIME_UNAVAILABLE; + } +#else + +#if defined(XR_KHR_LOADER_INIT_SUPPORT) + Json::Value virtualManifest; + result = GetPlatformRuntimeVirtualManifest(virtualManifest); + if (XR_SUCCESS == result) { + RuntimeManifestFile::CreateIfValid(virtualManifest, "", manifest_files); + return result; + } +#endif // defined(XR_KHR_LOADER_INIT_SUPPORT) + if (!PlatformGetGlobalRuntimeFileName(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), filename)) { + LoaderLogger::LogErrorMessage( + "", "RuntimeManifestFile::FindManifestFiles - failed to determine active runtime file path for this environment"); + return XR_ERROR_RUNTIME_UNAVAILABLE; + } + result = XR_SUCCESS; + LoaderLogger::LogInfoMessage("", "RuntimeManifestFile::FindManifestFiles - using global runtime file " + filename); +#endif + } + RuntimeManifestFile::CreateIfValid(filename, manifest_files); + + return result; +} + +ApiLayerManifestFile::ApiLayerManifestFile(ManifestFileType type, const std::string &filename, const std::string &layer_name, + const std::string &description, const JsonVersion &api_version, + const uint32_t &implementation_version, const std::string &library_path) + : ManifestFile(type, filename, library_path), + _api_version(api_version), + _layer_name(layer_name), + _description(description), + _implementation_version(implementation_version) {} + +void ApiLayerManifestFile::CreateIfValid(ManifestFileType type, const std::string &filename, + std::vector<std::unique_ptr<ApiLayerManifestFile>> &manifest_files) { + std::ifstream json_stream(filename, std::ifstream::in); + + std::ostringstream error_ss("ApiLayerManifestFile::CreateIfValid "); + if (!json_stream.is_open()) { + error_ss << "failed to open " << filename << ". Does it exist?"; + LoaderLogger::LogErrorMessage("", error_ss.str()); + return; + } + + Json::CharReaderBuilder builder; + std::string errors; + Json::Value root_node = Json::nullValue; + if (!Json::parseFromStream(builder, json_stream, &root_node, &errors) || !root_node.isObject()) { + error_ss << "failed to parse " << filename << "."; + if (!errors.empty()) { + error_ss << " (Error message: " << errors << ")"; + } + error_ss << " Is it a valid layer manifest file?"; + LoaderLogger::LogErrorMessage("", error_ss.str()); + return; + } + JsonVersion file_version = {}; + if (!ManifestFile::IsValidJson(root_node, file_version)) { + error_ss << "isValidJson indicates " << filename << " is not a valid manifest file."; + LoaderLogger::LogErrorMessage("", error_ss.str()); + return; + } + + Json::Value layer_root_node = root_node["api_layer"]; + + // The API Layer manifest file needs the "api_layer" root as well as other sub-nodes. + // If any of those aren't there, fail. + if (layer_root_node.isNull() || layer_root_node["name"].isNull() || !layer_root_node["name"].isString() || + layer_root_node["api_version"].isNull() || !layer_root_node["api_version"].isString() || + layer_root_node["library_path"].isNull() || !layer_root_node["library_path"].isString() || + layer_root_node["implementation_version"].isNull() || !layer_root_node["implementation_version"].isString()) { + error_ss << filename << " is missing required fields. Verify all proper fields exist."; + LoaderLogger::LogErrorMessage("", error_ss.str()); + return; + } + if (MANIFEST_TYPE_IMPLICIT_API_LAYER == type) { + bool enabled = true; + // Implicit layers require the disable environment variable. + if (layer_root_node["disable_environment"].isNull() || !layer_root_node["disable_environment"].isString()) { + error_ss << "Implicit layer " << filename << " is missing \"disable_environment\""; + LoaderLogger::LogErrorMessage("", error_ss.str()); + return; + } + // Check if there's an enable environment variable provided + if (!layer_root_node["enable_environment"].isNull() && layer_root_node["enable_environment"].isString()) { + std::string env_var = layer_root_node["enable_environment"].asString(); + // If it's not set in the environment, disable the layer + if (!PlatformUtilsGetEnvSet(env_var.c_str())) { + enabled = false; + } + } + // Check for the disable environment variable, which must be provided in the JSON + std::string env_var = layer_root_node["disable_environment"].asString(); + // If the env var is set, disable the layer. Disable env var overrides enable above + if (PlatformUtilsGetEnvSet(env_var.c_str())) { + enabled = false; + } + + // Not enabled, so pretend like it isn't even there. + if (!enabled) { + error_ss << "Implicit layer " << filename << " is disabled"; + LoaderLogger::LogInfoMessage("", error_ss.str()); + return; + } + } + std::string layer_name = layer_root_node["name"].asString(); + std::string api_version_string = layer_root_node["api_version"].asString(); + JsonVersion api_version = {}; + const int num_fields = sscanf(api_version_string.c_str(), "%u.%u", &api_version.major, &api_version.minor); + api_version.patch = 0; + + if ((num_fields != 2) || (api_version.major == 0 && api_version.minor == 0) || + api_version.major > XR_VERSION_MAJOR(XR_CURRENT_API_VERSION)) { + error_ss << "layer " << filename << " has invalid API Version. Skipping layer."; + LoaderLogger::LogWarningMessage("", error_ss.str()); + return; + } + + uint32_t implementation_version = atoi(layer_root_node["implementation_version"].asString().c_str()); + std::string library_path = layer_root_node["library_path"].asString(); + + // If the library_path variable has no directory symbol, it's just a file name and should be accessible on the + // global library path. + if (library_path.find('\\') != std::string::npos || library_path.find('/') != std::string::npos) { + // If the library_path is an absolute path, just use that if it exists + if (FileSysUtilsIsAbsolutePath(library_path)) { + if (!FileSysUtilsPathExists(library_path)) { + error_ss << filename << " library " << library_path << " does not appear to exist"; + LoaderLogger::LogErrorMessage("", error_ss.str()); + return; + } + } else { + // Otherwise, treat the library path as a relative path based on the JSON file. + std::string combined_path; + std::string file_parent; + if (!FileSysUtilsGetParentPath(filename, file_parent) || + !FileSysUtilsCombinePaths(file_parent, library_path, combined_path) || !FileSysUtilsPathExists(combined_path)) { + error_ss << filename << " library " << combined_path << " does not appear to exist"; + LoaderLogger::LogErrorMessage("", error_ss.str()); + return; + } + library_path = combined_path; + } + } + + std::string description; + if (!layer_root_node["description"].isNull() && layer_root_node["description"].isString()) { + description = layer_root_node["description"].asString(); + } + + // Add this layer manifest file + manifest_files.emplace_back( + new ApiLayerManifestFile(type, filename, layer_name, description, api_version, implementation_version, library_path)); + + // Add any extensions to it after the fact. + manifest_files.back()->ParseCommon(layer_root_node); +} + +void ApiLayerManifestFile::PopulateApiLayerProperties(XrApiLayerProperties &props) const { + props.layerVersion = _implementation_version; + props.specVersion = XR_MAKE_VERSION(_api_version.major, _api_version.minor, _api_version.patch); + strncpy(props.layerName, _layer_name.c_str(), XR_MAX_API_LAYER_NAME_SIZE - 1); + if (_layer_name.size() >= XR_MAX_API_LAYER_NAME_SIZE - 1) { + props.layerName[XR_MAX_API_LAYER_NAME_SIZE - 1] = '\0'; + } + strncpy(props.description, _description.c_str(), XR_MAX_API_LAYER_DESCRIPTION_SIZE - 1); + if (_description.size() >= XR_MAX_API_LAYER_DESCRIPTION_SIZE - 1) { + props.description[XR_MAX_API_LAYER_DESCRIPTION_SIZE - 1] = '\0'; + } +} + +// Find all layer manifest files in the appropriate search paths/registries for the given type. +XrResult ApiLayerManifestFile::FindManifestFiles(ManifestFileType type, + std::vector<std::unique_ptr<ApiLayerManifestFile>> &manifest_files) { + std::string relative_path; + std::string override_env_var; + std::string registry_location; + + // Add the appropriate top-level folders for the relative path. These should be + // the string "openxr/" followed by the API major version as a string. + relative_path = OPENXR_RELATIVE_PATH; + relative_path += std::to_string(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION)); + + switch (type) { + case MANIFEST_TYPE_IMPLICIT_API_LAYER: + relative_path += OPENXR_IMPLICIT_API_LAYER_RELATIVE_PATH; + override_env_var = ""; +#ifdef XR_OS_WINDOWS + registry_location = OPENXR_IMPLICIT_API_LAYER_REGISTRY_LOCATION; +#endif + break; + case MANIFEST_TYPE_EXPLICIT_API_LAYER: + relative_path += OPENXR_EXPLICIT_API_LAYER_RELATIVE_PATH; + override_env_var = OPENXR_API_LAYER_PATH_ENV_VAR; +#ifdef XR_OS_WINDOWS + registry_location = OPENXR_EXPLICIT_API_LAYER_REGISTRY_LOCATION; +#endif + break; + default: + LoaderLogger::LogErrorMessage("", "ApiLayerManifestFile::FindManifestFiles - unknown manifest file requested"); + return XR_ERROR_FILE_ACCESS_ERROR; + } + + bool override_active = false; + std::vector<std::string> filenames; + ReadDataFilesInSearchPaths(override_env_var, relative_path, override_active, filenames); + +#ifdef XR_OS_WINDOWS + // Read the registry if the override wasn't active. + if (!override_active) { + ReadLayerDataFilesInRegistry(registry_location, filenames); + } +#endif + + for (std::string &cur_file : filenames) { + ApiLayerManifestFile::CreateIfValid(type, cur_file, manifest_files); + } + + return XR_SUCCESS; +} diff --git a/thirdparty/openxr/src/loader/manifest_file.hpp b/thirdparty/openxr/src/loader/manifest_file.hpp new file mode 100644 index 0000000000..0d04886d84 --- /dev/null +++ b/thirdparty/openxr/src/loader/manifest_file.hpp @@ -0,0 +1,103 @@ +// Copyright (c) 2017 The Khronos Group Inc. +// Copyright (c) 2017 Valve Corporation +// Copyright (c) 2017 LunarG, Inc. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Initial Author: Mark Young <marky@lunarg.com> +// + +#pragma once + +#include <openxr/openxr.h> + +#include <memory> +#include <string> +#include <vector> +#include <unordered_map> + +namespace Json { +class Value; +} + +enum ManifestFileType { + MANIFEST_TYPE_UNDEFINED = 0, + MANIFEST_TYPE_RUNTIME, + MANIFEST_TYPE_IMPLICIT_API_LAYER, + MANIFEST_TYPE_EXPLICIT_API_LAYER, +}; + +struct JsonVersion { + uint32_t major; + uint32_t minor; + uint32_t patch; +}; + +struct ExtensionListing { + std::string name; + uint32_t extension_version; +}; + +// ManifestFile class - +// Base class responsible for finding and parsing manifest files. +class ManifestFile { + public: + // Non-copyable + ManifestFile(const ManifestFile &) = delete; + ManifestFile &operator=(const ManifestFile &) = delete; + + ManifestFileType Type() const { return _type; } + const std::string &Filename() const { return _filename; } + const std::string &LibraryPath() const { return _library_path; } + void GetInstanceExtensionProperties(std::vector<XrExtensionProperties> &props); + const std::string &GetFunctionName(const std::string &func_name) const; + + protected: + ManifestFile(ManifestFileType type, const std::string &filename, const std::string &library_path); + void ParseCommon(Json::Value const &root_node); + static bool IsValidJson(const Json::Value &root, JsonVersion &version); + + private: + std::string _filename; + ManifestFileType _type; + std::string _library_path; + std::vector<ExtensionListing> _instance_extensions; + std::unordered_map<std::string, std::string> _functions_renamed; +}; + +// RuntimeManifestFile class - +// Responsible for finding and parsing Runtime-specific manifest files. +class RuntimeManifestFile : public ManifestFile { + public: + // Factory method + static XrResult FindManifestFiles(std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files); + + private: + RuntimeManifestFile(const std::string &filename, const std::string &library_path); + static void CreateIfValid(const std::string &filename, std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files); + static void CreateIfValid(const Json::Value &root_node, const std::string &filename, + std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files); +}; + +// ApiLayerManifestFile class - +// Responsible for finding and parsing API Layer-specific manifest files. +class ApiLayerManifestFile : public ManifestFile { + public: + // Factory method + static XrResult FindManifestFiles(ManifestFileType type, std::vector<std::unique_ptr<ApiLayerManifestFile>> &manifest_files); + + const std::string &LayerName() const { return _layer_name; } + void PopulateApiLayerProperties(XrApiLayerProperties &props) const; + + private: + ApiLayerManifestFile(ManifestFileType type, const std::string &filename, const std::string &layer_name, + const std::string &description, const JsonVersion &api_version, const uint32_t &implementation_version, + const std::string &library_path); + static void CreateIfValid(ManifestFileType type, const std::string &filename, + std::vector<std::unique_ptr<ApiLayerManifestFile>> &manifest_files); + + JsonVersion _api_version; + std::string _layer_name; + std::string _description; + uint32_t _implementation_version; +}; diff --git a/thirdparty/openxr/src/loader/runtime_interface.cpp b/thirdparty/openxr/src/loader/runtime_interface.cpp new file mode 100644 index 0000000000..1a35ba013a --- /dev/null +++ b/thirdparty/openxr/src/loader/runtime_interface.cpp @@ -0,0 +1,493 @@ +// Copyright (c) 2017-2022, The Khronos Group Inc. +// Copyright (c) 2017-2019 Valve Corporation +// Copyright (c) 2017-2019 LunarG, Inc. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Initial Author: Mark Young <marky@lunarg.com> +// + +#include "runtime_interface.hpp" + +#include "manifest_file.hpp" +#include "loader_interfaces.h" +#include "loader_logger.hpp" +#include "loader_platform.hpp" +#include "xr_generated_dispatch_table.h" + +#include <openxr/openxr.h> + +#include <cstring> +#include <memory> +#include <mutex> +#include <string> +#include <unordered_map> +#include <utility> +#include <vector> + +#ifdef XR_USE_PLATFORM_ANDROID +#include "android_utilities.h" +#include <json/value.h> +#endif // XR_USE_PLATFORM_ANDROID + +#ifdef XR_KHR_LOADER_INIT_SUPPORT +namespace { +/*! + * Stores a copy of the data passed to the xrInitializeLoaderKHR function in a singleton. + */ +class LoaderInitData { + public: + /*! + * Singleton accessor. + */ + static LoaderInitData& instance() { + static LoaderInitData obj; + return obj; + } + +#ifdef XR_USE_PLATFORM_ANDROID + /*! + * Type alias for the platform-specific structure type. + */ + using StructType = XrLoaderInitInfoAndroidKHR; +#endif + + /*! + * Get our copy of the data, casted to pass to the runtime's matching method. + */ + const XrLoaderInitInfoBaseHeaderKHR* getParam() const { return reinterpret_cast<const XrLoaderInitInfoBaseHeaderKHR*>(&_data); } + + /*! + * Get the data via its real structure type. + */ + const StructType& getData() const { return _data; } + + /*! + * Has this been correctly initialized? + */ + bool initialized() const noexcept { return _initialized; } + + /*! + * Initialize loader data - called by InitializeLoader() and thus ultimately by the loader's xrInitializeLoaderKHR + * implementation. Each platform that needs this extension will provide an implementation of this. + */ + XrResult initialize(const XrLoaderInitInfoBaseHeaderKHR* info); + + private: + //! Private constructor, forces use of singleton accessor. + LoaderInitData() = default; + //! Platform-specific init data + StructType _data = {}; + //! Flag for indicating whether _data is valid. + bool _initialized = false; +}; + +#ifdef XR_USE_PLATFORM_ANDROID +// Check and copy the Android-specific init data. +XrResult LoaderInitData::initialize(const XrLoaderInitInfoBaseHeaderKHR* info) { + if (info->type != XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR) { + return XR_ERROR_VALIDATION_FAILURE; + } + auto cast_info = reinterpret_cast<XrLoaderInitInfoAndroidKHR const*>(info); + + if (cast_info->applicationVM == nullptr) { + return XR_ERROR_VALIDATION_FAILURE; + } + if (cast_info->applicationContext == nullptr) { + return XR_ERROR_VALIDATION_FAILURE; + } + _data = *cast_info; + jni::init((jni::JavaVM*)_data.applicationVM); + _data.next = nullptr; + _initialized = true; + return XR_SUCCESS; +} +#endif // XR_USE_PLATFORM_ANDROID +} // namespace + +XrResult InitializeLoader(const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo) { + return LoaderInitData::instance().initialize(loaderInitInfo); +} + +#endif // XR_KHR_LOADER_INIT_SUPPORT + +#ifdef XR_USE_PLATFORM_ANDROID +XrResult GetPlatformRuntimeVirtualManifest(Json::Value& out_manifest) { + using wrap::android::content::Context; + auto& initData = LoaderInitData::instance(); + if (!initData.initialized()) { + return XR_ERROR_INITIALIZATION_FAILED; + } + auto context = Context(reinterpret_cast<jobject>(initData.getData().applicationContext)); + if (context.isNull()) { + return XR_ERROR_INITIALIZATION_FAILED; + } + Json::Value virtualManifest; + if (0 != openxr_android::getActiveRuntimeVirtualManifest(context, virtualManifest)) { + return XR_ERROR_INITIALIZATION_FAILED; + } + out_manifest = virtualManifest; + return XR_SUCCESS; +} +#endif // XR_USE_PLATFORM_ANDROID + +XrResult RuntimeInterface::TryLoadingSingleRuntime(const std::string& openxr_command, + std::unique_ptr<RuntimeManifestFile>& manifest_file) { + LoaderPlatformLibraryHandle runtime_library = LoaderPlatformLibraryOpen(manifest_file->LibraryPath()); + if (nullptr == runtime_library) { + std::string library_message = LoaderPlatformLibraryOpenError(manifest_file->LibraryPath()); + std::string warning_message = "RuntimeInterface::LoadRuntime skipping manifest file "; + warning_message += manifest_file->Filename(); + warning_message += ", failed to load with message \""; + warning_message += library_message; + warning_message += "\""; + LoaderLogger::LogErrorMessage(openxr_command, warning_message); + return XR_ERROR_FILE_ACCESS_ERROR; + } +#ifdef XR_KHR_LOADER_INIT_SUPPORT + if (!LoaderInitData::instance().initialized()) { + LoaderLogger::LogErrorMessage(openxr_command, "RuntimeInterface::LoadRuntime skipping manifest file " + + manifest_file->Filename() + + " because xrInitializeLoaderKHR was not yet called."); + + LoaderPlatformLibraryClose(runtime_library); + return XR_ERROR_VALIDATION_FAILURE; + } + bool forwardedInitLoader = false; + { + // If we have xrInitializeLoaderKHR exposed as an export, forward call to it. + const auto function_name = manifest_file->GetFunctionName("xrInitializeLoaderKHR"); + auto initLoader = + reinterpret_cast<PFN_xrInitializeLoaderKHR>(LoaderPlatformLibraryGetProcAddr(runtime_library, function_name)); + if (initLoader != nullptr) { + // we found the entry point one way or another. + LoaderLogger::LogInfoMessage(openxr_command, + "RuntimeInterface::LoadRuntime forwarding xrInitializeLoaderKHR call to runtime before " + "calling xrNegotiateLoaderRuntimeInterface."); + XrResult res = initLoader(LoaderInitData::instance().getParam()); + if (!XR_SUCCEEDED(res)) { + LoaderLogger::LogErrorMessage(openxr_command, + "RuntimeInterface::LoadRuntime forwarded call to xrInitializeLoaderKHR failed."); + + LoaderPlatformLibraryClose(runtime_library); + return res; + } + forwardedInitLoader = true; + } + } +#endif + + // Get and settle on an runtime interface version (using any provided name if required). + std::string function_name = manifest_file->GetFunctionName("xrNegotiateLoaderRuntimeInterface"); + auto negotiate = + reinterpret_cast<PFN_xrNegotiateLoaderRuntimeInterface>(LoaderPlatformLibraryGetProcAddr(runtime_library, function_name)); + + // Loader info for negotiation + XrNegotiateLoaderInfo loader_info = {}; + loader_info.structType = XR_LOADER_INTERFACE_STRUCT_LOADER_INFO; + loader_info.structVersion = XR_LOADER_INFO_STRUCT_VERSION; + loader_info.structSize = sizeof(XrNegotiateLoaderInfo); + loader_info.minInterfaceVersion = 1; + loader_info.maxInterfaceVersion = XR_CURRENT_LOADER_RUNTIME_VERSION; + loader_info.minApiVersion = XR_MAKE_VERSION(1, 0, 0); + loader_info.maxApiVersion = XR_MAKE_VERSION(1, 0x3ff, 0xfff); // Maximum allowed version for this major version. + + // Set up the runtime return structure + XrNegotiateRuntimeRequest runtime_info = {}; + runtime_info.structType = XR_LOADER_INTERFACE_STRUCT_RUNTIME_REQUEST; + runtime_info.structVersion = XR_RUNTIME_INFO_STRUCT_VERSION; + runtime_info.structSize = sizeof(XrNegotiateRuntimeRequest); + + // Skip calling the negotiate function and fail if the function pointer + // could not get loaded + XrResult res = XR_ERROR_RUNTIME_FAILURE; + if (nullptr != negotiate) { + res = negotiate(&loader_info, &runtime_info); + } + // If we supposedly succeeded, but got a nullptr for GetInstanceProcAddr + // then something still went wrong, so return with an error. + if (XR_SUCCEEDED(res)) { + uint32_t runtime_major = XR_VERSION_MAJOR(runtime_info.runtimeApiVersion); + uint32_t runtime_minor = XR_VERSION_MINOR(runtime_info.runtimeApiVersion); + uint32_t loader_major = XR_VERSION_MAJOR(XR_CURRENT_API_VERSION); + if (nullptr == runtime_info.getInstanceProcAddr) { + std::string error_message = "RuntimeInterface::LoadRuntime skipping manifest file "; + error_message += manifest_file->Filename(); + error_message += ", negotiation succeeded but returned NULL getInstanceProcAddr"; + LoaderLogger::LogErrorMessage(openxr_command, error_message); + res = XR_ERROR_FILE_CONTENTS_INVALID; + } else if (0 >= runtime_info.runtimeInterfaceVersion || + XR_CURRENT_LOADER_RUNTIME_VERSION < runtime_info.runtimeInterfaceVersion) { + std::string error_message = "RuntimeInterface::LoadRuntime skipping manifest file "; + error_message += manifest_file->Filename(); + error_message += ", negotiation succeeded but returned invalid interface version"; + LoaderLogger::LogErrorMessage(openxr_command, error_message); + res = XR_ERROR_FILE_CONTENTS_INVALID; + } else if (runtime_major != loader_major || (runtime_major == 0 && runtime_minor == 0)) { + std::string error_message = "RuntimeInterface::LoadRuntime skipping manifest file "; + error_message += manifest_file->Filename(); + error_message += ", OpenXR version returned not compatible with this loader"; + LoaderLogger::LogErrorMessage(openxr_command, error_message); + res = XR_ERROR_FILE_CONTENTS_INVALID; + } + } +#ifdef XR_KHR_LOADER_INIT_SUPPORT + if (XR_SUCCEEDED(res) && !forwardedInitLoader) { + // Forward initialize loader call, where possible and if we did not do so before. + PFN_xrVoidFunction initializeVoid = nullptr; + PFN_xrInitializeLoaderKHR initialize = nullptr; + + // Now we may try asking xrGetInstanceProcAddr + if (XR_SUCCEEDED(runtime_info.getInstanceProcAddr(XR_NULL_HANDLE, "xrInitializeLoaderKHR", &initializeVoid))) { + if (initializeVoid == nullptr) { + LoaderLogger::LogErrorMessage(openxr_command, + "RuntimeInterface::LoadRuntime got success from xrGetInstanceProcAddr " + "for xrInitializeLoaderKHR, but output a null pointer."); + res = XR_ERROR_RUNTIME_FAILURE; + } else { + initialize = reinterpret_cast<PFN_xrInitializeLoaderKHR>(initializeVoid); + } + } + if (initialize != nullptr) { + // we found the entry point one way or another. + LoaderLogger::LogInfoMessage(openxr_command, + "RuntimeInterface::LoadRuntime forwarding xrInitializeLoaderKHR call to runtime after " + "calling xrNegotiateLoaderRuntimeInterface."); + res = initialize(LoaderInitData::instance().getParam()); + if (!XR_SUCCEEDED(res)) { + LoaderLogger::LogErrorMessage(openxr_command, + "RuntimeInterface::LoadRuntime forwarded call to xrInitializeLoaderKHR failed."); + } + } + } +#endif + if (XR_FAILED(res)) { + std::string warning_message = "RuntimeInterface::LoadRuntime skipping manifest file "; + warning_message += manifest_file->Filename(); + warning_message += ", negotiation failed with error "; + warning_message += std::to_string(res); + LoaderLogger::LogErrorMessage(openxr_command, warning_message); + LoaderPlatformLibraryClose(runtime_library); + return res; + } + + std::string info_message = "RuntimeInterface::LoadRuntime succeeded loading runtime defined in manifest file "; + info_message += manifest_file->Filename(); + info_message += " using interface version "; + info_message += std::to_string(runtime_info.runtimeInterfaceVersion); + info_message += " and OpenXR API version "; + info_message += std::to_string(XR_VERSION_MAJOR(runtime_info.runtimeApiVersion)); + info_message += "."; + info_message += std::to_string(XR_VERSION_MINOR(runtime_info.runtimeApiVersion)); + LoaderLogger::LogInfoMessage(openxr_command, info_message); + + // Use this runtime + GetInstance().reset(new RuntimeInterface(runtime_library, runtime_info.getInstanceProcAddr)); + + // Grab the list of extensions this runtime supports for easy filtering after the + // xrCreateInstance call + std::vector<std::string> supported_extensions; + std::vector<XrExtensionProperties> extension_properties; + GetInstance()->GetInstanceExtensionProperties(extension_properties); + supported_extensions.reserve(extension_properties.size()); + for (XrExtensionProperties ext_prop : extension_properties) { + supported_extensions.emplace_back(ext_prop.extensionName); + } + GetInstance()->SetSupportedExtensions(supported_extensions); + + return XR_SUCCESS; +} + +XrResult RuntimeInterface::LoadRuntime(const std::string& openxr_command) { + // If something's already loaded, we're done here. + if (GetInstance() != nullptr) { + return XR_SUCCESS; + } +#ifdef XR_KHR_LOADER_INIT_SUPPORT + + if (!LoaderInitData::instance().initialized()) { + LoaderLogger::LogErrorMessage( + openxr_command, "RuntimeInterface::LoadRuntime cannot run because xrInitializeLoaderKHR was not successfully called."); + return XR_ERROR_INITIALIZATION_FAILED; + } +#endif // XR_KHR_LOADER_INIT_SUPPORT + + std::vector<std::unique_ptr<RuntimeManifestFile>> runtime_manifest_files = {}; + + // Find the available runtimes which we may need to report information for. + XrResult last_error = RuntimeManifestFile::FindManifestFiles(runtime_manifest_files); + if (XR_FAILED(last_error)) { + LoaderLogger::LogErrorMessage(openxr_command, "RuntimeInterface::LoadRuntimes - unknown error"); + } else { + last_error = XR_ERROR_RUNTIME_UNAVAILABLE; + for (std::unique_ptr<RuntimeManifestFile>& manifest_file : runtime_manifest_files) { + last_error = RuntimeInterface::TryLoadingSingleRuntime(openxr_command, manifest_file); + if (XR_SUCCEEDED(last_error)) { + break; + } + } + } + + // Unsuccessful in loading any runtime, throw the runtime unavailable message. + if (XR_FAILED(last_error)) { + LoaderLogger::LogErrorMessage(openxr_command, "RuntimeInterface::LoadRuntimes - failed to load a runtime"); + last_error = XR_ERROR_RUNTIME_UNAVAILABLE; + } + + return last_error; +} + +void RuntimeInterface::UnloadRuntime(const std::string& openxr_command) { + if (GetInstance()) { + LoaderLogger::LogInfoMessage(openxr_command, "RuntimeInterface::UnloadRuntime - Unloading RuntimeInterface"); + GetInstance().reset(); + } +} + +XrResult RuntimeInterface::GetInstanceProcAddr(XrInstance instance, const char* name, PFN_xrVoidFunction* function) { + return GetInstance()->_get_instance_proc_addr(instance, name, function); +} + +const XrGeneratedDispatchTable* RuntimeInterface::GetDispatchTable(XrInstance instance) { + XrGeneratedDispatchTable* table = nullptr; + std::lock_guard<std::mutex> mlock(GetInstance()->_dispatch_table_mutex); + auto it = GetInstance()->_dispatch_table_map.find(instance); + if (it != GetInstance()->_dispatch_table_map.end()) { + table = it->second.get(); + } + return table; +} + +const XrGeneratedDispatchTable* RuntimeInterface::GetDebugUtilsMessengerDispatchTable(XrDebugUtilsMessengerEXT messenger) { + XrInstance runtime_instance = XR_NULL_HANDLE; + { + std::lock_guard<std::mutex> mlock(GetInstance()->_messenger_to_instance_mutex); + auto it = GetInstance()->_messenger_to_instance_map.find(messenger); + if (it != GetInstance()->_messenger_to_instance_map.end()) { + runtime_instance = it->second; + } + } + return GetDispatchTable(runtime_instance); +} + +RuntimeInterface::RuntimeInterface(LoaderPlatformLibraryHandle runtime_library, PFN_xrGetInstanceProcAddr get_instance_proc_addr) + : _runtime_library(runtime_library), _get_instance_proc_addr(get_instance_proc_addr) {} + +RuntimeInterface::~RuntimeInterface() { + std::string info_message = "RuntimeInterface being destroyed."; + LoaderLogger::LogInfoMessage("", info_message); + { + std::lock_guard<std::mutex> mlock(_dispatch_table_mutex); + _dispatch_table_map.clear(); + } + LoaderPlatformLibraryClose(_runtime_library); +} + +void RuntimeInterface::GetInstanceExtensionProperties(std::vector<XrExtensionProperties>& extension_properties) { + std::vector<XrExtensionProperties> runtime_extension_properties; + PFN_xrEnumerateInstanceExtensionProperties rt_xrEnumerateInstanceExtensionProperties; + _get_instance_proc_addr(XR_NULL_HANDLE, "xrEnumerateInstanceExtensionProperties", + reinterpret_cast<PFN_xrVoidFunction*>(&rt_xrEnumerateInstanceExtensionProperties)); + uint32_t count = 0; + uint32_t count_output = 0; + // Get the count from the runtime + rt_xrEnumerateInstanceExtensionProperties(nullptr, count, &count_output, nullptr); + if (count_output > 0) { + runtime_extension_properties.resize(count_output); + count = count_output; + for (XrExtensionProperties& ext_prop : runtime_extension_properties) { + ext_prop.type = XR_TYPE_EXTENSION_PROPERTIES; + ext_prop.next = nullptr; + } + rt_xrEnumerateInstanceExtensionProperties(nullptr, count, &count_output, runtime_extension_properties.data()); + } + size_t ext_count = runtime_extension_properties.size(); + size_t props_count = extension_properties.size(); + for (size_t ext = 0; ext < ext_count; ++ext) { + bool found = false; + for (size_t prop = 0; prop < props_count; ++prop) { + // If we find it, then make sure the spec version matches that of the runtime instead of the + // layer. + if (strcmp(extension_properties[prop].extensionName, runtime_extension_properties[ext].extensionName) == 0) { + // Make sure the spec version used is the runtime's + extension_properties[prop].extensionVersion = runtime_extension_properties[ext].extensionVersion; + found = true; + break; + } + } + if (!found) { + extension_properties.push_back(runtime_extension_properties[ext]); + } + } +} + +XrResult RuntimeInterface::CreateInstance(const XrInstanceCreateInfo* info, XrInstance* instance) { + XrResult res = XR_SUCCESS; + bool create_succeeded = false; + PFN_xrCreateInstance rt_xrCreateInstance; + _get_instance_proc_addr(XR_NULL_HANDLE, "xrCreateInstance", reinterpret_cast<PFN_xrVoidFunction*>(&rt_xrCreateInstance)); + res = rt_xrCreateInstance(info, instance); + if (XR_SUCCEEDED(res)) { + create_succeeded = true; + std::unique_ptr<XrGeneratedDispatchTable> dispatch_table(new XrGeneratedDispatchTable()); + GeneratedXrPopulateDispatchTable(dispatch_table.get(), *instance, _get_instance_proc_addr); + std::lock_guard<std::mutex> mlock(_dispatch_table_mutex); + _dispatch_table_map[*instance] = std::move(dispatch_table); + } + + // If the failure occurred during the populate, clean up the instance we had picked up from the runtime + if (XR_FAILED(res) && create_succeeded) { + PFN_xrDestroyInstance rt_xrDestroyInstance; + _get_instance_proc_addr(*instance, "xrDestroyInstance", reinterpret_cast<PFN_xrVoidFunction*>(&rt_xrDestroyInstance)); + rt_xrDestroyInstance(*instance); + *instance = XR_NULL_HANDLE; + } + + return res; +} + +XrResult RuntimeInterface::DestroyInstance(XrInstance instance) { + if (XR_NULL_HANDLE != instance) { + // Destroy the dispatch table for this instance first + { + std::lock_guard<std::mutex> mlock(_dispatch_table_mutex); + auto map_iter = _dispatch_table_map.find(instance); + if (map_iter != _dispatch_table_map.end()) { + _dispatch_table_map.erase(map_iter); + } + } + // Now delete the instance + PFN_xrDestroyInstance rt_xrDestroyInstance; + _get_instance_proc_addr(instance, "xrDestroyInstance", reinterpret_cast<PFN_xrVoidFunction*>(&rt_xrDestroyInstance)); + rt_xrDestroyInstance(instance); + } + return XR_SUCCESS; +} + +bool RuntimeInterface::TrackDebugMessenger(XrInstance instance, XrDebugUtilsMessengerEXT messenger) { + std::lock_guard<std::mutex> mlock(_messenger_to_instance_mutex); + _messenger_to_instance_map[messenger] = instance; + return true; +} + +void RuntimeInterface::ForgetDebugMessenger(XrDebugUtilsMessengerEXT messenger) { + if (XR_NULL_HANDLE != messenger) { + std::lock_guard<std::mutex> mlock(_messenger_to_instance_mutex); + _messenger_to_instance_map.erase(messenger); + } +} + +void RuntimeInterface::SetSupportedExtensions(std::vector<std::string>& supported_extensions) { + _supported_extensions = supported_extensions; +} + +bool RuntimeInterface::SupportsExtension(const std::string& extension_name) { + bool found_prop = false; + for (const std::string& supported_extension : _supported_extensions) { + if (supported_extension == extension_name) { + found_prop = true; + break; + } + } + return found_prop; +} diff --git a/thirdparty/openxr/src/loader/runtime_interface.hpp b/thirdparty/openxr/src/loader/runtime_interface.hpp new file mode 100644 index 0000000000..5f49b28abe --- /dev/null +++ b/thirdparty/openxr/src/loader/runtime_interface.hpp @@ -0,0 +1,84 @@ +// Copyright (c) 2017-2022, The Khronos Group Inc. +// Copyright (c) 2017-2019 Valve Corporation +// Copyright (c) 2017-2019 LunarG, Inc. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Initial Author: Mark Young <marky@lunarg.com> +// + +#pragma once + +#include "loader_platform.hpp" + +#include <openxr/openxr.h> + +#include <string> +#include <vector> +#include <unordered_map> +#include <mutex> +#include <memory> + +#ifdef XR_USE_PLATFORM_ANDROID +#define XR_KHR_LOADER_INIT_SUPPORT +#endif + +namespace Json { +class Value; +} + +#ifdef XR_KHR_LOADER_INIT_SUPPORT +//! Initialize loader, where required. +XrResult InitializeLoader(const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo); +XrResult GetPlatformRuntimeVirtualManifest(Json::Value& out_manifest); +#endif + +class RuntimeManifestFile; +struct XrGeneratedDispatchTable; + +class RuntimeInterface { + public: + virtual ~RuntimeInterface(); + + // Helper functions for loading and unloading the runtime (but only when necessary) + static XrResult LoadRuntime(const std::string& openxr_command); + static void UnloadRuntime(const std::string& openxr_command); + static RuntimeInterface& GetRuntime() { return *(GetInstance().get()); } + static XrResult GetInstanceProcAddr(XrInstance instance, const char* name, PFN_xrVoidFunction* function); + + // Get the direct dispatch table to this runtime, without API layers or loader terminators. + static const XrGeneratedDispatchTable* GetDispatchTable(XrInstance instance); + static const XrGeneratedDispatchTable* GetDebugUtilsMessengerDispatchTable(XrDebugUtilsMessengerEXT messenger); + + void GetInstanceExtensionProperties(std::vector<XrExtensionProperties>& extension_properties); + bool SupportsExtension(const std::string& extension_name); + XrResult CreateInstance(const XrInstanceCreateInfo* info, XrInstance* instance); + XrResult DestroyInstance(XrInstance instance); + bool TrackDebugMessenger(XrInstance instance, XrDebugUtilsMessengerEXT messenger); + void ForgetDebugMessenger(XrDebugUtilsMessengerEXT messenger); + + // No default construction + RuntimeInterface() = delete; + + // Non-copyable + RuntimeInterface(const RuntimeInterface&) = delete; + RuntimeInterface& operator=(const RuntimeInterface&) = delete; + + private: + RuntimeInterface(LoaderPlatformLibraryHandle runtime_library, PFN_xrGetInstanceProcAddr get_instance_proc_addr); + void SetSupportedExtensions(std::vector<std::string>& supported_extensions); + static XrResult TryLoadingSingleRuntime(const std::string& openxr_command, std::unique_ptr<RuntimeManifestFile>& manifest_file); + + static std::unique_ptr<RuntimeInterface>& GetInstance() { + static std::unique_ptr<RuntimeInterface> instance; + return instance; + } + + LoaderPlatformLibraryHandle _runtime_library; + PFN_xrGetInstanceProcAddr _get_instance_proc_addr; + std::unordered_map<XrInstance, std::unique_ptr<XrGeneratedDispatchTable>> _dispatch_table_map; + std::mutex _dispatch_table_mutex; + std::unordered_map<XrDebugUtilsMessengerEXT, XrInstance> _messenger_to_instance_map; + std::mutex _messenger_to_instance_mutex; + std::vector<std::string> _supported_extensions; +}; diff --git a/thirdparty/openxr/src/loader/xr_generated_loader.cpp b/thirdparty/openxr/src/loader/xr_generated_loader.cpp new file mode 100644 index 0000000000..2ce323e51f --- /dev/null +++ b/thirdparty/openxr/src/loader/xr_generated_loader.cpp @@ -0,0 +1,700 @@ +// Copyright (c) 2017-2022, The Khronos Group Inc. +// Copyright (c) 2017-2019 Valve Corporation +// Copyright (c) 2017-2019 LunarG, Inc. +// SPDX-License-Identifier: Apache-2.0 OR MIT +// *********** THIS FILE IS GENERATED - DO NOT EDIT *********** +// See loader_source_generator.py for modifications +// ************************************************************ + +// Copyright (c) 2017-2022, The Khronos Group Inc. +// Copyright (c) 2017-2019 Valve Corporation +// Copyright (c) 2017-2019 LunarG, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Mark Young <marky@lunarg.com> +// + +#include "xr_generated_loader.hpp" + +#include "api_layer_interface.hpp" +#include "exception_handling.hpp" +#include "hex_and_handles.h" +#include "loader_instance.hpp" +#include "loader_logger.hpp" +#include "loader_platform.hpp" +#include "runtime_interface.hpp" +#include "xr_generated_dispatch_table.h" + +#include "xr_dependencies.h" +#include <openxr/openxr.h> +#include <openxr/openxr_platform.h> + +#include <cstring> +#include <memory> +#include <new> +#include <string> +#include <unordered_map> + + +// Automatically generated instance trampolines and terminators +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetInstanceProperties( + XrInstance instance, + XrInstanceProperties* instanceProperties) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetInstanceProperties"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->GetInstanceProperties(instance, instanceProperties); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrPollEvent( + XrInstance instance, + XrEventDataBuffer* eventData) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrPollEvent"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->PollEvent(instance, eventData); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrResultToString( + XrInstance instance, + XrResult value, + char buffer[XR_MAX_RESULT_STRING_SIZE]) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrResultToString"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->ResultToString(instance, value, buffer); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrStructureTypeToString( + XrInstance instance, + XrStructureType value, + char buffer[XR_MAX_STRUCTURE_NAME_SIZE]) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrStructureTypeToString"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->StructureTypeToString(instance, value, buffer); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetSystem( + XrInstance instance, + const XrSystemGetInfo* getInfo, + XrSystemId* systemId) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetSystem"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->GetSystem(instance, getInfo, systemId); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetSystemProperties( + XrInstance instance, + XrSystemId systemId, + XrSystemProperties* properties) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetSystemProperties"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->GetSystemProperties(instance, systemId, properties); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateEnvironmentBlendModes( + XrInstance instance, + XrSystemId systemId, + XrViewConfigurationType viewConfigurationType, + uint32_t environmentBlendModeCapacityInput, + uint32_t* environmentBlendModeCountOutput, + XrEnvironmentBlendMode* environmentBlendModes) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrEnumerateEnvironmentBlendModes"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->EnumerateEnvironmentBlendModes(instance, systemId, viewConfigurationType, environmentBlendModeCapacityInput, environmentBlendModeCountOutput, environmentBlendModes); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateSession( + XrInstance instance, + const XrSessionCreateInfo* createInfo, + XrSession* session) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrCreateSession"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->CreateSession(instance, createInfo, session); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroySession( + XrSession session) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrDestroySession"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->DestroySession(session); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateReferenceSpaces( + XrSession session, + uint32_t spaceCapacityInput, + uint32_t* spaceCountOutput, + XrReferenceSpaceType* spaces) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrEnumerateReferenceSpaces"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->EnumerateReferenceSpaces(session, spaceCapacityInput, spaceCountOutput, spaces); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateReferenceSpace( + XrSession session, + const XrReferenceSpaceCreateInfo* createInfo, + XrSpace* space) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrCreateReferenceSpace"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->CreateReferenceSpace(session, createInfo, space); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetReferenceSpaceBoundsRect( + XrSession session, + XrReferenceSpaceType referenceSpaceType, + XrExtent2Df* bounds) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetReferenceSpaceBoundsRect"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->GetReferenceSpaceBoundsRect(session, referenceSpaceType, bounds); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateActionSpace( + XrSession session, + const XrActionSpaceCreateInfo* createInfo, + XrSpace* space) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrCreateActionSpace"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->CreateActionSpace(session, createInfo, space); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrLocateSpace( + XrSpace space, + XrSpace baseSpace, + XrTime time, + XrSpaceLocation* location) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrLocateSpace"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->LocateSpace(space, baseSpace, time, location); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpace( + XrSpace space) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrDestroySpace"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->DestroySpace(space); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateViewConfigurations( + XrInstance instance, + XrSystemId systemId, + uint32_t viewConfigurationTypeCapacityInput, + uint32_t* viewConfigurationTypeCountOutput, + XrViewConfigurationType* viewConfigurationTypes) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrEnumerateViewConfigurations"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->EnumerateViewConfigurations(instance, systemId, viewConfigurationTypeCapacityInput, viewConfigurationTypeCountOutput, viewConfigurationTypes); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetViewConfigurationProperties( + XrInstance instance, + XrSystemId systemId, + XrViewConfigurationType viewConfigurationType, + XrViewConfigurationProperties* configurationProperties) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetViewConfigurationProperties"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->GetViewConfigurationProperties(instance, systemId, viewConfigurationType, configurationProperties); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateViewConfigurationViews( + XrInstance instance, + XrSystemId systemId, + XrViewConfigurationType viewConfigurationType, + uint32_t viewCapacityInput, + uint32_t* viewCountOutput, + XrViewConfigurationView* views) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrEnumerateViewConfigurationViews"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->EnumerateViewConfigurationViews(instance, systemId, viewConfigurationType, viewCapacityInput, viewCountOutput, views); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSwapchainFormats( + XrSession session, + uint32_t formatCapacityInput, + uint32_t* formatCountOutput, + int64_t* formats) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrEnumerateSwapchainFormats"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->EnumerateSwapchainFormats(session, formatCapacityInput, formatCountOutput, formats); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateSwapchain( + XrSession session, + const XrSwapchainCreateInfo* createInfo, + XrSwapchain* swapchain) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrCreateSwapchain"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->CreateSwapchain(session, createInfo, swapchain); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroySwapchain( + XrSwapchain swapchain) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrDestroySwapchain"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->DestroySwapchain(swapchain); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSwapchainImages( + XrSwapchain swapchain, + uint32_t imageCapacityInput, + uint32_t* imageCountOutput, + XrSwapchainImageBaseHeader* images) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrEnumerateSwapchainImages"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->EnumerateSwapchainImages(swapchain, imageCapacityInput, imageCountOutput, images); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrAcquireSwapchainImage( + XrSwapchain swapchain, + const XrSwapchainImageAcquireInfo* acquireInfo, + uint32_t* index) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrAcquireSwapchainImage"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->AcquireSwapchainImage(swapchain, acquireInfo, index); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrWaitSwapchainImage( + XrSwapchain swapchain, + const XrSwapchainImageWaitInfo* waitInfo) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrWaitSwapchainImage"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->WaitSwapchainImage(swapchain, waitInfo); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrReleaseSwapchainImage( + XrSwapchain swapchain, + const XrSwapchainImageReleaseInfo* releaseInfo) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrReleaseSwapchainImage"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->ReleaseSwapchainImage(swapchain, releaseInfo); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrBeginSession( + XrSession session, + const XrSessionBeginInfo* beginInfo) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrBeginSession"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->BeginSession(session, beginInfo); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEndSession( + XrSession session) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrEndSession"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->EndSession(session); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrRequestExitSession( + XrSession session) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrRequestExitSession"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->RequestExitSession(session); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrWaitFrame( + XrSession session, + const XrFrameWaitInfo* frameWaitInfo, + XrFrameState* frameState) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrWaitFrame"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->WaitFrame(session, frameWaitInfo, frameState); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrBeginFrame( + XrSession session, + const XrFrameBeginInfo* frameBeginInfo) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrBeginFrame"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->BeginFrame(session, frameBeginInfo); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEndFrame( + XrSession session, + const XrFrameEndInfo* frameEndInfo) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrEndFrame"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->EndFrame(session, frameEndInfo); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrLocateViews( + XrSession session, + const XrViewLocateInfo* viewLocateInfo, + XrViewState* viewState, + uint32_t viewCapacityInput, + uint32_t* viewCountOutput, + XrView* views) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrLocateViews"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->LocateViews(session, viewLocateInfo, viewState, viewCapacityInput, viewCountOutput, views); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrStringToPath( + XrInstance instance, + const char* pathString, + XrPath* path) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrStringToPath"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->StringToPath(instance, pathString, path); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrPathToString( + XrInstance instance, + XrPath path, + uint32_t bufferCapacityInput, + uint32_t* bufferCountOutput, + char* buffer) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrPathToString"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->PathToString(instance, path, bufferCapacityInput, bufferCountOutput, buffer); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateActionSet( + XrInstance instance, + const XrActionSetCreateInfo* createInfo, + XrActionSet* actionSet) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrCreateActionSet"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->CreateActionSet(instance, createInfo, actionSet); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroyActionSet( + XrActionSet actionSet) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrDestroyActionSet"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->DestroyActionSet(actionSet); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateAction( + XrActionSet actionSet, + const XrActionCreateInfo* createInfo, + XrAction* action) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrCreateAction"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->CreateAction(actionSet, createInfo, action); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroyAction( + XrAction action) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrDestroyAction"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->DestroyAction(action); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrSuggestInteractionProfileBindings( + XrInstance instance, + const XrInteractionProfileSuggestedBinding* suggestedBindings) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSuggestInteractionProfileBindings"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->SuggestInteractionProfileBindings(instance, suggestedBindings); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrAttachSessionActionSets( + XrSession session, + const XrSessionActionSetsAttachInfo* attachInfo) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrAttachSessionActionSets"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->AttachSessionActionSets(session, attachInfo); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetCurrentInteractionProfile( + XrSession session, + XrPath topLevelUserPath, + XrInteractionProfileState* interactionProfile) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetCurrentInteractionProfile"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->GetCurrentInteractionProfile(session, topLevelUserPath, interactionProfile); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateBoolean( + XrSession session, + const XrActionStateGetInfo* getInfo, + XrActionStateBoolean* state) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetActionStateBoolean"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->GetActionStateBoolean(session, getInfo, state); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateFloat( + XrSession session, + const XrActionStateGetInfo* getInfo, + XrActionStateFloat* state) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetActionStateFloat"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->GetActionStateFloat(session, getInfo, state); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateVector2f( + XrSession session, + const XrActionStateGetInfo* getInfo, + XrActionStateVector2f* state) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetActionStateVector2f"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->GetActionStateVector2f(session, getInfo, state); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStatePose( + XrSession session, + const XrActionStateGetInfo* getInfo, + XrActionStatePose* state) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetActionStatePose"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->GetActionStatePose(session, getInfo, state); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrSyncActions( + XrSession session, + const XrActionsSyncInfo* syncInfo) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSyncActions"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->SyncActions(session, syncInfo); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateBoundSourcesForAction( + XrSession session, + const XrBoundSourcesForActionEnumerateInfo* enumerateInfo, + uint32_t sourceCapacityInput, + uint32_t* sourceCountOutput, + XrPath* sources) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrEnumerateBoundSourcesForAction"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->EnumerateBoundSourcesForAction(session, enumerateInfo, sourceCapacityInput, sourceCountOutput, sources); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetInputSourceLocalizedName( + XrSession session, + const XrInputSourceLocalizedNameGetInfo* getInfo, + uint32_t bufferCapacityInput, + uint32_t* bufferCountOutput, + char* buffer) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetInputSourceLocalizedName"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->GetInputSourceLocalizedName(session, getInfo, bufferCapacityInput, bufferCountOutput, buffer); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrApplyHapticFeedback( + XrSession session, + const XrHapticActionInfo* hapticActionInfo, + const XrHapticBaseHeader* hapticFeedback) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrApplyHapticFeedback"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->ApplyHapticFeedback(session, hapticActionInfo, hapticFeedback); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrStopHapticFeedback( + XrSession session, + const XrHapticActionInfo* hapticActionInfo) XRLOADER_ABI_TRY { + LoaderInstance* loader_instance; + XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrStopHapticFeedback"); + if (XR_SUCCEEDED(result)) { + result = loader_instance->DispatchTable()->StopHapticFeedback(session, hapticActionInfo); + } + return result; +} +XRLOADER_ABI_CATCH_FALLBACK + + diff --git a/thirdparty/openxr/src/loader/xr_generated_loader.hpp b/thirdparty/openxr/src/loader/xr_generated_loader.hpp new file mode 100644 index 0000000000..482cf1e83e --- /dev/null +++ b/thirdparty/openxr/src/loader/xr_generated_loader.hpp @@ -0,0 +1,252 @@ +// Copyright (c) 2017-2022, The Khronos Group Inc. +// Copyright (c) 2017-2019 Valve Corporation +// Copyright (c) 2017-2019 LunarG, Inc. +// SPDX-License-Identifier: Apache-2.0 OR MIT +// *********** THIS FILE IS GENERATED - DO NOT EDIT *********** +// See loader_source_generator.py for modifications +// ************************************************************ + +// Copyright (c) 2017-2022, The Khronos Group Inc. +// Copyright (c) 2017-2019 Valve Corporation +// Copyright (c) 2017-2019 LunarG, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Mark Young <marky@lunarg.com> +// + +#pragma once +#include <unordered_map> +#include <thread> +#include <mutex> + +#include "xr_dependencies.h" +#include "openxr/openxr.h" +#include "openxr/openxr_platform.h" + +#include "loader_interfaces.h" + +#include "loader_instance.hpp" + +#include "loader_platform.hpp" + + +#ifdef __cplusplus +extern "C" { +#endif + +// Loader manually generated function prototypes + +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetInstanceProperties( + XrInstance instance, + XrInstanceProperties* instanceProperties); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrPollEvent( + XrInstance instance, + XrEventDataBuffer* eventData); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrResultToString( + XrInstance instance, + XrResult value, + char buffer[XR_MAX_RESULT_STRING_SIZE]); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrStructureTypeToString( + XrInstance instance, + XrStructureType value, + char buffer[XR_MAX_STRUCTURE_NAME_SIZE]); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetSystem( + XrInstance instance, + const XrSystemGetInfo* getInfo, + XrSystemId* systemId); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetSystemProperties( + XrInstance instance, + XrSystemId systemId, + XrSystemProperties* properties); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateEnvironmentBlendModes( + XrInstance instance, + XrSystemId systemId, + XrViewConfigurationType viewConfigurationType, + uint32_t environmentBlendModeCapacityInput, + uint32_t* environmentBlendModeCountOutput, + XrEnvironmentBlendMode* environmentBlendModes); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateSession( + XrInstance instance, + const XrSessionCreateInfo* createInfo, + XrSession* session); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroySession( + XrSession session); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateReferenceSpaces( + XrSession session, + uint32_t spaceCapacityInput, + uint32_t* spaceCountOutput, + XrReferenceSpaceType* spaces); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateReferenceSpace( + XrSession session, + const XrReferenceSpaceCreateInfo* createInfo, + XrSpace* space); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetReferenceSpaceBoundsRect( + XrSession session, + XrReferenceSpaceType referenceSpaceType, + XrExtent2Df* bounds); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateActionSpace( + XrSession session, + const XrActionSpaceCreateInfo* createInfo, + XrSpace* space); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrLocateSpace( + XrSpace space, + XrSpace baseSpace, + XrTime time, + XrSpaceLocation* location); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpace( + XrSpace space); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateViewConfigurations( + XrInstance instance, + XrSystemId systemId, + uint32_t viewConfigurationTypeCapacityInput, + uint32_t* viewConfigurationTypeCountOutput, + XrViewConfigurationType* viewConfigurationTypes); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetViewConfigurationProperties( + XrInstance instance, + XrSystemId systemId, + XrViewConfigurationType viewConfigurationType, + XrViewConfigurationProperties* configurationProperties); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateViewConfigurationViews( + XrInstance instance, + XrSystemId systemId, + XrViewConfigurationType viewConfigurationType, + uint32_t viewCapacityInput, + uint32_t* viewCountOutput, + XrViewConfigurationView* views); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSwapchainFormats( + XrSession session, + uint32_t formatCapacityInput, + uint32_t* formatCountOutput, + int64_t* formats); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateSwapchain( + XrSession session, + const XrSwapchainCreateInfo* createInfo, + XrSwapchain* swapchain); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroySwapchain( + XrSwapchain swapchain); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSwapchainImages( + XrSwapchain swapchain, + uint32_t imageCapacityInput, + uint32_t* imageCountOutput, + XrSwapchainImageBaseHeader* images); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrAcquireSwapchainImage( + XrSwapchain swapchain, + const XrSwapchainImageAcquireInfo* acquireInfo, + uint32_t* index); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrWaitSwapchainImage( + XrSwapchain swapchain, + const XrSwapchainImageWaitInfo* waitInfo); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrReleaseSwapchainImage( + XrSwapchain swapchain, + const XrSwapchainImageReleaseInfo* releaseInfo); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrBeginSession( + XrSession session, + const XrSessionBeginInfo* beginInfo); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEndSession( + XrSession session); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrRequestExitSession( + XrSession session); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrWaitFrame( + XrSession session, + const XrFrameWaitInfo* frameWaitInfo, + XrFrameState* frameState); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrBeginFrame( + XrSession session, + const XrFrameBeginInfo* frameBeginInfo); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEndFrame( + XrSession session, + const XrFrameEndInfo* frameEndInfo); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrLocateViews( + XrSession session, + const XrViewLocateInfo* viewLocateInfo, + XrViewState* viewState, + uint32_t viewCapacityInput, + uint32_t* viewCountOutput, + XrView* views); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrStringToPath( + XrInstance instance, + const char* pathString, + XrPath* path); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrPathToString( + XrInstance instance, + XrPath path, + uint32_t bufferCapacityInput, + uint32_t* bufferCountOutput, + char* buffer); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateActionSet( + XrInstance instance, + const XrActionSetCreateInfo* createInfo, + XrActionSet* actionSet); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroyActionSet( + XrActionSet actionSet); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateAction( + XrActionSet actionSet, + const XrActionCreateInfo* createInfo, + XrAction* action); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroyAction( + XrAction action); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrSuggestInteractionProfileBindings( + XrInstance instance, + const XrInteractionProfileSuggestedBinding* suggestedBindings); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrAttachSessionActionSets( + XrSession session, + const XrSessionActionSetsAttachInfo* attachInfo); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetCurrentInteractionProfile( + XrSession session, + XrPath topLevelUserPath, + XrInteractionProfileState* interactionProfile); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateBoolean( + XrSession session, + const XrActionStateGetInfo* getInfo, + XrActionStateBoolean* state); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateFloat( + XrSession session, + const XrActionStateGetInfo* getInfo, + XrActionStateFloat* state); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateVector2f( + XrSession session, + const XrActionStateGetInfo* getInfo, + XrActionStateVector2f* state); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStatePose( + XrSession session, + const XrActionStateGetInfo* getInfo, + XrActionStatePose* state); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrSyncActions( + XrSession session, + const XrActionsSyncInfo* syncInfo); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateBoundSourcesForAction( + XrSession session, + const XrBoundSourcesForActionEnumerateInfo* enumerateInfo, + uint32_t sourceCapacityInput, + uint32_t* sourceCountOutput, + XrPath* sources); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetInputSourceLocalizedName( + XrSession session, + const XrInputSourceLocalizedNameGetInfo* getInfo, + uint32_t bufferCapacityInput, + uint32_t* bufferCountOutput, + char* buffer); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrApplyHapticFeedback( + XrSession session, + const XrHapticActionInfo* hapticActionInfo, + const XrHapticBaseHeader* hapticFeedback); +extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrStopHapticFeedback( + XrSession session, + const XrHapticActionInfo* hapticActionInfo); +#ifdef __cplusplus +} // extern "C" +#endif + diff --git a/thirdparty/openxr/src/xr_generated_dispatch_table.c b/thirdparty/openxr/src/xr_generated_dispatch_table.c new file mode 100644 index 0000000000..79fbefc52a --- /dev/null +++ b/thirdparty/openxr/src/xr_generated_dispatch_table.c @@ -0,0 +1,347 @@ +// Copyright (c) 2017-2022, The Khronos Group Inc. +// Copyright (c) 2017-2019 Valve Corporation +// Copyright (c) 2017-2019 LunarG, Inc. +// SPDX-License-Identifier: Apache-2.0 OR MIT +// *********** THIS FILE IS GENERATED - DO NOT EDIT *********** +// See utility_source_generator.py for modifications +// ************************************************************ + +// Copyright (c) 2017-2022, The Khronos Group Inc. +// Copyright (c) 2017-2019 Valve Corporation +// Copyright (c) 2017-2019 LunarG, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Mark Young <marky@lunarg.com> +// + +#include "xr_generated_dispatch_table.h" +#include "xr_dependencies.h" +#include <openxr/openxr.h> +#include <openxr/openxr_platform.h> + + +#ifdef __cplusplus +extern "C" { +#endif +// Helper function to populate an instance dispatch table +void GeneratedXrPopulateDispatchTable(struct XrGeneratedDispatchTable *table, + XrInstance instance, + PFN_xrGetInstanceProcAddr get_inst_proc_addr) { + + // ---- Core 1.0 commands + table->GetInstanceProcAddr = get_inst_proc_addr; + (get_inst_proc_addr(instance, "xrCreateInstance", (PFN_xrVoidFunction*)&table->CreateInstance)); + (get_inst_proc_addr(instance, "xrDestroyInstance", (PFN_xrVoidFunction*)&table->DestroyInstance)); + (get_inst_proc_addr(instance, "xrGetInstanceProperties", (PFN_xrVoidFunction*)&table->GetInstanceProperties)); + (get_inst_proc_addr(instance, "xrPollEvent", (PFN_xrVoidFunction*)&table->PollEvent)); + (get_inst_proc_addr(instance, "xrResultToString", (PFN_xrVoidFunction*)&table->ResultToString)); + (get_inst_proc_addr(instance, "xrStructureTypeToString", (PFN_xrVoidFunction*)&table->StructureTypeToString)); + (get_inst_proc_addr(instance, "xrGetSystem", (PFN_xrVoidFunction*)&table->GetSystem)); + (get_inst_proc_addr(instance, "xrGetSystemProperties", (PFN_xrVoidFunction*)&table->GetSystemProperties)); + (get_inst_proc_addr(instance, "xrEnumerateEnvironmentBlendModes", (PFN_xrVoidFunction*)&table->EnumerateEnvironmentBlendModes)); + (get_inst_proc_addr(instance, "xrCreateSession", (PFN_xrVoidFunction*)&table->CreateSession)); + (get_inst_proc_addr(instance, "xrDestroySession", (PFN_xrVoidFunction*)&table->DestroySession)); + (get_inst_proc_addr(instance, "xrEnumerateReferenceSpaces", (PFN_xrVoidFunction*)&table->EnumerateReferenceSpaces)); + (get_inst_proc_addr(instance, "xrCreateReferenceSpace", (PFN_xrVoidFunction*)&table->CreateReferenceSpace)); + (get_inst_proc_addr(instance, "xrGetReferenceSpaceBoundsRect", (PFN_xrVoidFunction*)&table->GetReferenceSpaceBoundsRect)); + (get_inst_proc_addr(instance, "xrCreateActionSpace", (PFN_xrVoidFunction*)&table->CreateActionSpace)); + (get_inst_proc_addr(instance, "xrLocateSpace", (PFN_xrVoidFunction*)&table->LocateSpace)); + (get_inst_proc_addr(instance, "xrDestroySpace", (PFN_xrVoidFunction*)&table->DestroySpace)); + (get_inst_proc_addr(instance, "xrEnumerateViewConfigurations", (PFN_xrVoidFunction*)&table->EnumerateViewConfigurations)); + (get_inst_proc_addr(instance, "xrGetViewConfigurationProperties", (PFN_xrVoidFunction*)&table->GetViewConfigurationProperties)); + (get_inst_proc_addr(instance, "xrEnumerateViewConfigurationViews", (PFN_xrVoidFunction*)&table->EnumerateViewConfigurationViews)); + (get_inst_proc_addr(instance, "xrEnumerateSwapchainFormats", (PFN_xrVoidFunction*)&table->EnumerateSwapchainFormats)); + (get_inst_proc_addr(instance, "xrCreateSwapchain", (PFN_xrVoidFunction*)&table->CreateSwapchain)); + (get_inst_proc_addr(instance, "xrDestroySwapchain", (PFN_xrVoidFunction*)&table->DestroySwapchain)); + (get_inst_proc_addr(instance, "xrEnumerateSwapchainImages", (PFN_xrVoidFunction*)&table->EnumerateSwapchainImages)); + (get_inst_proc_addr(instance, "xrAcquireSwapchainImage", (PFN_xrVoidFunction*)&table->AcquireSwapchainImage)); + (get_inst_proc_addr(instance, "xrWaitSwapchainImage", (PFN_xrVoidFunction*)&table->WaitSwapchainImage)); + (get_inst_proc_addr(instance, "xrReleaseSwapchainImage", (PFN_xrVoidFunction*)&table->ReleaseSwapchainImage)); + (get_inst_proc_addr(instance, "xrBeginSession", (PFN_xrVoidFunction*)&table->BeginSession)); + (get_inst_proc_addr(instance, "xrEndSession", (PFN_xrVoidFunction*)&table->EndSession)); + (get_inst_proc_addr(instance, "xrRequestExitSession", (PFN_xrVoidFunction*)&table->RequestExitSession)); + (get_inst_proc_addr(instance, "xrWaitFrame", (PFN_xrVoidFunction*)&table->WaitFrame)); + (get_inst_proc_addr(instance, "xrBeginFrame", (PFN_xrVoidFunction*)&table->BeginFrame)); + (get_inst_proc_addr(instance, "xrEndFrame", (PFN_xrVoidFunction*)&table->EndFrame)); + (get_inst_proc_addr(instance, "xrLocateViews", (PFN_xrVoidFunction*)&table->LocateViews)); + (get_inst_proc_addr(instance, "xrStringToPath", (PFN_xrVoidFunction*)&table->StringToPath)); + (get_inst_proc_addr(instance, "xrPathToString", (PFN_xrVoidFunction*)&table->PathToString)); + (get_inst_proc_addr(instance, "xrCreateActionSet", (PFN_xrVoidFunction*)&table->CreateActionSet)); + (get_inst_proc_addr(instance, "xrDestroyActionSet", (PFN_xrVoidFunction*)&table->DestroyActionSet)); + (get_inst_proc_addr(instance, "xrCreateAction", (PFN_xrVoidFunction*)&table->CreateAction)); + (get_inst_proc_addr(instance, "xrDestroyAction", (PFN_xrVoidFunction*)&table->DestroyAction)); + (get_inst_proc_addr(instance, "xrSuggestInteractionProfileBindings", (PFN_xrVoidFunction*)&table->SuggestInteractionProfileBindings)); + (get_inst_proc_addr(instance, "xrAttachSessionActionSets", (PFN_xrVoidFunction*)&table->AttachSessionActionSets)); + (get_inst_proc_addr(instance, "xrGetCurrentInteractionProfile", (PFN_xrVoidFunction*)&table->GetCurrentInteractionProfile)); + (get_inst_proc_addr(instance, "xrGetActionStateBoolean", (PFN_xrVoidFunction*)&table->GetActionStateBoolean)); + (get_inst_proc_addr(instance, "xrGetActionStateFloat", (PFN_xrVoidFunction*)&table->GetActionStateFloat)); + (get_inst_proc_addr(instance, "xrGetActionStateVector2f", (PFN_xrVoidFunction*)&table->GetActionStateVector2f)); + (get_inst_proc_addr(instance, "xrGetActionStatePose", (PFN_xrVoidFunction*)&table->GetActionStatePose)); + (get_inst_proc_addr(instance, "xrSyncActions", (PFN_xrVoidFunction*)&table->SyncActions)); + (get_inst_proc_addr(instance, "xrEnumerateBoundSourcesForAction", (PFN_xrVoidFunction*)&table->EnumerateBoundSourcesForAction)); + (get_inst_proc_addr(instance, "xrGetInputSourceLocalizedName", (PFN_xrVoidFunction*)&table->GetInputSourceLocalizedName)); + (get_inst_proc_addr(instance, "xrApplyHapticFeedback", (PFN_xrVoidFunction*)&table->ApplyHapticFeedback)); + (get_inst_proc_addr(instance, "xrStopHapticFeedback", (PFN_xrVoidFunction*)&table->StopHapticFeedback)); + + // ---- XR_KHR_android_thread_settings extension commands +#if defined(XR_USE_PLATFORM_ANDROID) + (get_inst_proc_addr(instance, "xrSetAndroidApplicationThreadKHR", (PFN_xrVoidFunction*)&table->SetAndroidApplicationThreadKHR)); +#endif // defined(XR_USE_PLATFORM_ANDROID) + + // ---- XR_KHR_android_surface_swapchain extension commands +#if defined(XR_USE_PLATFORM_ANDROID) + (get_inst_proc_addr(instance, "xrCreateSwapchainAndroidSurfaceKHR", (PFN_xrVoidFunction*)&table->CreateSwapchainAndroidSurfaceKHR)); +#endif // defined(XR_USE_PLATFORM_ANDROID) + + // ---- XR_KHR_opengl_enable extension commands +#if defined(XR_USE_GRAPHICS_API_OPENGL) + (get_inst_proc_addr(instance, "xrGetOpenGLGraphicsRequirementsKHR", (PFN_xrVoidFunction*)&table->GetOpenGLGraphicsRequirementsKHR)); +#endif // defined(XR_USE_GRAPHICS_API_OPENGL) + + // ---- XR_KHR_opengl_es_enable extension commands +#if defined(XR_USE_GRAPHICS_API_OPENGL_ES) + (get_inst_proc_addr(instance, "xrGetOpenGLESGraphicsRequirementsKHR", (PFN_xrVoidFunction*)&table->GetOpenGLESGraphicsRequirementsKHR)); +#endif // defined(XR_USE_GRAPHICS_API_OPENGL_ES) + + // ---- XR_KHR_vulkan_enable extension commands +#if defined(XR_USE_GRAPHICS_API_VULKAN) + (get_inst_proc_addr(instance, "xrGetVulkanInstanceExtensionsKHR", (PFN_xrVoidFunction*)&table->GetVulkanInstanceExtensionsKHR)); +#endif // defined(XR_USE_GRAPHICS_API_VULKAN) +#if defined(XR_USE_GRAPHICS_API_VULKAN) + (get_inst_proc_addr(instance, "xrGetVulkanDeviceExtensionsKHR", (PFN_xrVoidFunction*)&table->GetVulkanDeviceExtensionsKHR)); +#endif // defined(XR_USE_GRAPHICS_API_VULKAN) +#if defined(XR_USE_GRAPHICS_API_VULKAN) + (get_inst_proc_addr(instance, "xrGetVulkanGraphicsDeviceKHR", (PFN_xrVoidFunction*)&table->GetVulkanGraphicsDeviceKHR)); +#endif // defined(XR_USE_GRAPHICS_API_VULKAN) +#if defined(XR_USE_GRAPHICS_API_VULKAN) + (get_inst_proc_addr(instance, "xrGetVulkanGraphicsRequirementsKHR", (PFN_xrVoidFunction*)&table->GetVulkanGraphicsRequirementsKHR)); +#endif // defined(XR_USE_GRAPHICS_API_VULKAN) + + // ---- XR_KHR_D3D11_enable extension commands +#if defined(XR_USE_GRAPHICS_API_D3D11) + (get_inst_proc_addr(instance, "xrGetD3D11GraphicsRequirementsKHR", (PFN_xrVoidFunction*)&table->GetD3D11GraphicsRequirementsKHR)); +#endif // defined(XR_USE_GRAPHICS_API_D3D11) + + // ---- XR_KHR_D3D12_enable extension commands +#if defined(XR_USE_GRAPHICS_API_D3D12) + (get_inst_proc_addr(instance, "xrGetD3D12GraphicsRequirementsKHR", (PFN_xrVoidFunction*)&table->GetD3D12GraphicsRequirementsKHR)); +#endif // defined(XR_USE_GRAPHICS_API_D3D12) + + // ---- XR_KHR_visibility_mask extension commands + (get_inst_proc_addr(instance, "xrGetVisibilityMaskKHR", (PFN_xrVoidFunction*)&table->GetVisibilityMaskKHR)); + + // ---- XR_KHR_win32_convert_performance_counter_time extension commands +#if defined(XR_USE_PLATFORM_WIN32) + (get_inst_proc_addr(instance, "xrConvertWin32PerformanceCounterToTimeKHR", (PFN_xrVoidFunction*)&table->ConvertWin32PerformanceCounterToTimeKHR)); +#endif // defined(XR_USE_PLATFORM_WIN32) +#if defined(XR_USE_PLATFORM_WIN32) + (get_inst_proc_addr(instance, "xrConvertTimeToWin32PerformanceCounterKHR", (PFN_xrVoidFunction*)&table->ConvertTimeToWin32PerformanceCounterKHR)); +#endif // defined(XR_USE_PLATFORM_WIN32) + + // ---- XR_KHR_convert_timespec_time extension commands +#if defined(XR_USE_TIMESPEC) + (get_inst_proc_addr(instance, "xrConvertTimespecTimeToTimeKHR", (PFN_xrVoidFunction*)&table->ConvertTimespecTimeToTimeKHR)); +#endif // defined(XR_USE_TIMESPEC) +#if defined(XR_USE_TIMESPEC) + (get_inst_proc_addr(instance, "xrConvertTimeToTimespecTimeKHR", (PFN_xrVoidFunction*)&table->ConvertTimeToTimespecTimeKHR)); +#endif // defined(XR_USE_TIMESPEC) + + // ---- XR_KHR_vulkan_enable2 extension commands +#if defined(XR_USE_GRAPHICS_API_VULKAN) + (get_inst_proc_addr(instance, "xrCreateVulkanInstanceKHR", (PFN_xrVoidFunction*)&table->CreateVulkanInstanceKHR)); +#endif // defined(XR_USE_GRAPHICS_API_VULKAN) +#if defined(XR_USE_GRAPHICS_API_VULKAN) + (get_inst_proc_addr(instance, "xrCreateVulkanDeviceKHR", (PFN_xrVoidFunction*)&table->CreateVulkanDeviceKHR)); +#endif // defined(XR_USE_GRAPHICS_API_VULKAN) +#if defined(XR_USE_GRAPHICS_API_VULKAN) + (get_inst_proc_addr(instance, "xrGetVulkanGraphicsDevice2KHR", (PFN_xrVoidFunction*)&table->GetVulkanGraphicsDevice2KHR)); +#endif // defined(XR_USE_GRAPHICS_API_VULKAN) +#if defined(XR_USE_GRAPHICS_API_VULKAN) + (get_inst_proc_addr(instance, "xrGetVulkanGraphicsRequirements2KHR", (PFN_xrVoidFunction*)&table->GetVulkanGraphicsRequirements2KHR)); +#endif // defined(XR_USE_GRAPHICS_API_VULKAN) + + // ---- XR_EXT_performance_settings extension commands + (get_inst_proc_addr(instance, "xrPerfSettingsSetPerformanceLevelEXT", (PFN_xrVoidFunction*)&table->PerfSettingsSetPerformanceLevelEXT)); + + // ---- XR_EXT_thermal_query extension commands + (get_inst_proc_addr(instance, "xrThermalGetTemperatureTrendEXT", (PFN_xrVoidFunction*)&table->ThermalGetTemperatureTrendEXT)); + + // ---- XR_EXT_debug_utils extension commands + (get_inst_proc_addr(instance, "xrSetDebugUtilsObjectNameEXT", (PFN_xrVoidFunction*)&table->SetDebugUtilsObjectNameEXT)); + (get_inst_proc_addr(instance, "xrCreateDebugUtilsMessengerEXT", (PFN_xrVoidFunction*)&table->CreateDebugUtilsMessengerEXT)); + (get_inst_proc_addr(instance, "xrDestroyDebugUtilsMessengerEXT", (PFN_xrVoidFunction*)&table->DestroyDebugUtilsMessengerEXT)); + (get_inst_proc_addr(instance, "xrSubmitDebugUtilsMessageEXT", (PFN_xrVoidFunction*)&table->SubmitDebugUtilsMessageEXT)); + (get_inst_proc_addr(instance, "xrSessionBeginDebugUtilsLabelRegionEXT", (PFN_xrVoidFunction*)&table->SessionBeginDebugUtilsLabelRegionEXT)); + (get_inst_proc_addr(instance, "xrSessionEndDebugUtilsLabelRegionEXT", (PFN_xrVoidFunction*)&table->SessionEndDebugUtilsLabelRegionEXT)); + (get_inst_proc_addr(instance, "xrSessionInsertDebugUtilsLabelEXT", (PFN_xrVoidFunction*)&table->SessionInsertDebugUtilsLabelEXT)); + + // ---- XR_MSFT_spatial_anchor extension commands + (get_inst_proc_addr(instance, "xrCreateSpatialAnchorMSFT", (PFN_xrVoidFunction*)&table->CreateSpatialAnchorMSFT)); + (get_inst_proc_addr(instance, "xrCreateSpatialAnchorSpaceMSFT", (PFN_xrVoidFunction*)&table->CreateSpatialAnchorSpaceMSFT)); + (get_inst_proc_addr(instance, "xrDestroySpatialAnchorMSFT", (PFN_xrVoidFunction*)&table->DestroySpatialAnchorMSFT)); + + // ---- XR_EXT_conformance_automation extension commands + (get_inst_proc_addr(instance, "xrSetInputDeviceActiveEXT", (PFN_xrVoidFunction*)&table->SetInputDeviceActiveEXT)); + (get_inst_proc_addr(instance, "xrSetInputDeviceStateBoolEXT", (PFN_xrVoidFunction*)&table->SetInputDeviceStateBoolEXT)); + (get_inst_proc_addr(instance, "xrSetInputDeviceStateFloatEXT", (PFN_xrVoidFunction*)&table->SetInputDeviceStateFloatEXT)); + (get_inst_proc_addr(instance, "xrSetInputDeviceStateVector2fEXT", (PFN_xrVoidFunction*)&table->SetInputDeviceStateVector2fEXT)); + (get_inst_proc_addr(instance, "xrSetInputDeviceLocationEXT", (PFN_xrVoidFunction*)&table->SetInputDeviceLocationEXT)); + + // ---- XR_MSFT_spatial_graph_bridge extension commands + (get_inst_proc_addr(instance, "xrCreateSpatialGraphNodeSpaceMSFT", (PFN_xrVoidFunction*)&table->CreateSpatialGraphNodeSpaceMSFT)); + + // ---- XR_EXT_hand_tracking extension commands + (get_inst_proc_addr(instance, "xrCreateHandTrackerEXT", (PFN_xrVoidFunction*)&table->CreateHandTrackerEXT)); + (get_inst_proc_addr(instance, "xrDestroyHandTrackerEXT", (PFN_xrVoidFunction*)&table->DestroyHandTrackerEXT)); + (get_inst_proc_addr(instance, "xrLocateHandJointsEXT", (PFN_xrVoidFunction*)&table->LocateHandJointsEXT)); + + // ---- XR_MSFT_hand_tracking_mesh extension commands + (get_inst_proc_addr(instance, "xrCreateHandMeshSpaceMSFT", (PFN_xrVoidFunction*)&table->CreateHandMeshSpaceMSFT)); + (get_inst_proc_addr(instance, "xrUpdateHandMeshMSFT", (PFN_xrVoidFunction*)&table->UpdateHandMeshMSFT)); + + // ---- XR_MSFT_controller_model extension commands + (get_inst_proc_addr(instance, "xrGetControllerModelKeyMSFT", (PFN_xrVoidFunction*)&table->GetControllerModelKeyMSFT)); + (get_inst_proc_addr(instance, "xrLoadControllerModelMSFT", (PFN_xrVoidFunction*)&table->LoadControllerModelMSFT)); + (get_inst_proc_addr(instance, "xrGetControllerModelPropertiesMSFT", (PFN_xrVoidFunction*)&table->GetControllerModelPropertiesMSFT)); + (get_inst_proc_addr(instance, "xrGetControllerModelStateMSFT", (PFN_xrVoidFunction*)&table->GetControllerModelStateMSFT)); + + // ---- XR_MSFT_perception_anchor_interop extension commands +#if defined(XR_USE_PLATFORM_WIN32) + (get_inst_proc_addr(instance, "xrCreateSpatialAnchorFromPerceptionAnchorMSFT", (PFN_xrVoidFunction*)&table->CreateSpatialAnchorFromPerceptionAnchorMSFT)); +#endif // defined(XR_USE_PLATFORM_WIN32) +#if defined(XR_USE_PLATFORM_WIN32) + (get_inst_proc_addr(instance, "xrTryGetPerceptionAnchorFromSpatialAnchorMSFT", (PFN_xrVoidFunction*)&table->TryGetPerceptionAnchorFromSpatialAnchorMSFT)); +#endif // defined(XR_USE_PLATFORM_WIN32) + + // ---- XR_MSFT_composition_layer_reprojection extension commands + (get_inst_proc_addr(instance, "xrEnumerateReprojectionModesMSFT", (PFN_xrVoidFunction*)&table->EnumerateReprojectionModesMSFT)); + + // ---- XR_FB_swapchain_update_state extension commands + (get_inst_proc_addr(instance, "xrUpdateSwapchainFB", (PFN_xrVoidFunction*)&table->UpdateSwapchainFB)); + (get_inst_proc_addr(instance, "xrGetSwapchainStateFB", (PFN_xrVoidFunction*)&table->GetSwapchainStateFB)); + + // ---- XR_MSFT_scene_understanding extension commands + (get_inst_proc_addr(instance, "xrEnumerateSceneComputeFeaturesMSFT", (PFN_xrVoidFunction*)&table->EnumerateSceneComputeFeaturesMSFT)); + (get_inst_proc_addr(instance, "xrCreateSceneObserverMSFT", (PFN_xrVoidFunction*)&table->CreateSceneObserverMSFT)); + (get_inst_proc_addr(instance, "xrDestroySceneObserverMSFT", (PFN_xrVoidFunction*)&table->DestroySceneObserverMSFT)); + (get_inst_proc_addr(instance, "xrCreateSceneMSFT", (PFN_xrVoidFunction*)&table->CreateSceneMSFT)); + (get_inst_proc_addr(instance, "xrDestroySceneMSFT", (PFN_xrVoidFunction*)&table->DestroySceneMSFT)); + (get_inst_proc_addr(instance, "xrComputeNewSceneMSFT", (PFN_xrVoidFunction*)&table->ComputeNewSceneMSFT)); + (get_inst_proc_addr(instance, "xrGetSceneComputeStateMSFT", (PFN_xrVoidFunction*)&table->GetSceneComputeStateMSFT)); + (get_inst_proc_addr(instance, "xrGetSceneComponentsMSFT", (PFN_xrVoidFunction*)&table->GetSceneComponentsMSFT)); + (get_inst_proc_addr(instance, "xrLocateSceneComponentsMSFT", (PFN_xrVoidFunction*)&table->LocateSceneComponentsMSFT)); + (get_inst_proc_addr(instance, "xrGetSceneMeshBuffersMSFT", (PFN_xrVoidFunction*)&table->GetSceneMeshBuffersMSFT)); + + // ---- XR_MSFT_scene_understanding_serialization extension commands + (get_inst_proc_addr(instance, "xrDeserializeSceneMSFT", (PFN_xrVoidFunction*)&table->DeserializeSceneMSFT)); + (get_inst_proc_addr(instance, "xrGetSerializedSceneFragmentDataMSFT", (PFN_xrVoidFunction*)&table->GetSerializedSceneFragmentDataMSFT)); + + // ---- XR_FB_display_refresh_rate extension commands + (get_inst_proc_addr(instance, "xrEnumerateDisplayRefreshRatesFB", (PFN_xrVoidFunction*)&table->EnumerateDisplayRefreshRatesFB)); + (get_inst_proc_addr(instance, "xrGetDisplayRefreshRateFB", (PFN_xrVoidFunction*)&table->GetDisplayRefreshRateFB)); + (get_inst_proc_addr(instance, "xrRequestDisplayRefreshRateFB", (PFN_xrVoidFunction*)&table->RequestDisplayRefreshRateFB)); + + // ---- XR_HTCX_vive_tracker_interaction extension commands + (get_inst_proc_addr(instance, "xrEnumerateViveTrackerPathsHTCX", (PFN_xrVoidFunction*)&table->EnumerateViveTrackerPathsHTCX)); + + // ---- XR_HTC_facial_tracking extension commands + (get_inst_proc_addr(instance, "xrCreateFacialTrackerHTC", (PFN_xrVoidFunction*)&table->CreateFacialTrackerHTC)); + (get_inst_proc_addr(instance, "xrDestroyFacialTrackerHTC", (PFN_xrVoidFunction*)&table->DestroyFacialTrackerHTC)); + (get_inst_proc_addr(instance, "xrGetFacialExpressionsHTC", (PFN_xrVoidFunction*)&table->GetFacialExpressionsHTC)); + + // ---- XR_FB_color_space extension commands + (get_inst_proc_addr(instance, "xrEnumerateColorSpacesFB", (PFN_xrVoidFunction*)&table->EnumerateColorSpacesFB)); + (get_inst_proc_addr(instance, "xrSetColorSpaceFB", (PFN_xrVoidFunction*)&table->SetColorSpaceFB)); + + // ---- XR_FB_hand_tracking_mesh extension commands + (get_inst_proc_addr(instance, "xrGetHandMeshFB", (PFN_xrVoidFunction*)&table->GetHandMeshFB)); + + // ---- XR_FB_foveation extension commands + (get_inst_proc_addr(instance, "xrCreateFoveationProfileFB", (PFN_xrVoidFunction*)&table->CreateFoveationProfileFB)); + (get_inst_proc_addr(instance, "xrDestroyFoveationProfileFB", (PFN_xrVoidFunction*)&table->DestroyFoveationProfileFB)); + + // ---- XR_FB_keyboard_tracking extension commands + (get_inst_proc_addr(instance, "xrQuerySystemTrackedKeyboardFB", (PFN_xrVoidFunction*)&table->QuerySystemTrackedKeyboardFB)); + (get_inst_proc_addr(instance, "xrCreateKeyboardSpaceFB", (PFN_xrVoidFunction*)&table->CreateKeyboardSpaceFB)); + + // ---- XR_FB_triangle_mesh extension commands + (get_inst_proc_addr(instance, "xrCreateTriangleMeshFB", (PFN_xrVoidFunction*)&table->CreateTriangleMeshFB)); + (get_inst_proc_addr(instance, "xrDestroyTriangleMeshFB", (PFN_xrVoidFunction*)&table->DestroyTriangleMeshFB)); + (get_inst_proc_addr(instance, "xrTriangleMeshGetVertexBufferFB", (PFN_xrVoidFunction*)&table->TriangleMeshGetVertexBufferFB)); + (get_inst_proc_addr(instance, "xrTriangleMeshGetIndexBufferFB", (PFN_xrVoidFunction*)&table->TriangleMeshGetIndexBufferFB)); + (get_inst_proc_addr(instance, "xrTriangleMeshBeginUpdateFB", (PFN_xrVoidFunction*)&table->TriangleMeshBeginUpdateFB)); + (get_inst_proc_addr(instance, "xrTriangleMeshEndUpdateFB", (PFN_xrVoidFunction*)&table->TriangleMeshEndUpdateFB)); + (get_inst_proc_addr(instance, "xrTriangleMeshBeginVertexBufferUpdateFB", (PFN_xrVoidFunction*)&table->TriangleMeshBeginVertexBufferUpdateFB)); + (get_inst_proc_addr(instance, "xrTriangleMeshEndVertexBufferUpdateFB", (PFN_xrVoidFunction*)&table->TriangleMeshEndVertexBufferUpdateFB)); + + // ---- XR_FB_passthrough extension commands + (get_inst_proc_addr(instance, "xrCreatePassthroughFB", (PFN_xrVoidFunction*)&table->CreatePassthroughFB)); + (get_inst_proc_addr(instance, "xrDestroyPassthroughFB", (PFN_xrVoidFunction*)&table->DestroyPassthroughFB)); + (get_inst_proc_addr(instance, "xrPassthroughStartFB", (PFN_xrVoidFunction*)&table->PassthroughStartFB)); + (get_inst_proc_addr(instance, "xrPassthroughPauseFB", (PFN_xrVoidFunction*)&table->PassthroughPauseFB)); + (get_inst_proc_addr(instance, "xrCreatePassthroughLayerFB", (PFN_xrVoidFunction*)&table->CreatePassthroughLayerFB)); + (get_inst_proc_addr(instance, "xrDestroyPassthroughLayerFB", (PFN_xrVoidFunction*)&table->DestroyPassthroughLayerFB)); + (get_inst_proc_addr(instance, "xrPassthroughLayerPauseFB", (PFN_xrVoidFunction*)&table->PassthroughLayerPauseFB)); + (get_inst_proc_addr(instance, "xrPassthroughLayerResumeFB", (PFN_xrVoidFunction*)&table->PassthroughLayerResumeFB)); + (get_inst_proc_addr(instance, "xrPassthroughLayerSetStyleFB", (PFN_xrVoidFunction*)&table->PassthroughLayerSetStyleFB)); + (get_inst_proc_addr(instance, "xrCreateGeometryInstanceFB", (PFN_xrVoidFunction*)&table->CreateGeometryInstanceFB)); + (get_inst_proc_addr(instance, "xrDestroyGeometryInstanceFB", (PFN_xrVoidFunction*)&table->DestroyGeometryInstanceFB)); + (get_inst_proc_addr(instance, "xrGeometryInstanceSetTransformFB", (PFN_xrVoidFunction*)&table->GeometryInstanceSetTransformFB)); + + // ---- XR_FB_render_model extension commands + (get_inst_proc_addr(instance, "xrEnumerateRenderModelPathsFB", (PFN_xrVoidFunction*)&table->EnumerateRenderModelPathsFB)); + (get_inst_proc_addr(instance, "xrGetRenderModelPropertiesFB", (PFN_xrVoidFunction*)&table->GetRenderModelPropertiesFB)); + (get_inst_proc_addr(instance, "xrLoadRenderModelFB", (PFN_xrVoidFunction*)&table->LoadRenderModelFB)); + + // ---- XR_VARJO_environment_depth_estimation extension commands + (get_inst_proc_addr(instance, "xrSetEnvironmentDepthEstimationVARJO", (PFN_xrVoidFunction*)&table->SetEnvironmentDepthEstimationVARJO)); + + // ---- XR_VARJO_marker_tracking extension commands + (get_inst_proc_addr(instance, "xrSetMarkerTrackingVARJO", (PFN_xrVoidFunction*)&table->SetMarkerTrackingVARJO)); + (get_inst_proc_addr(instance, "xrSetMarkerTrackingTimeoutVARJO", (PFN_xrVoidFunction*)&table->SetMarkerTrackingTimeoutVARJO)); + (get_inst_proc_addr(instance, "xrSetMarkerTrackingPredictionVARJO", (PFN_xrVoidFunction*)&table->SetMarkerTrackingPredictionVARJO)); + (get_inst_proc_addr(instance, "xrGetMarkerSizeVARJO", (PFN_xrVoidFunction*)&table->GetMarkerSizeVARJO)); + (get_inst_proc_addr(instance, "xrCreateMarkerSpaceVARJO", (PFN_xrVoidFunction*)&table->CreateMarkerSpaceVARJO)); + + // ---- XR_MSFT_spatial_anchor_persistence extension commands + (get_inst_proc_addr(instance, "xrCreateSpatialAnchorStoreConnectionMSFT", (PFN_xrVoidFunction*)&table->CreateSpatialAnchorStoreConnectionMSFT)); + (get_inst_proc_addr(instance, "xrDestroySpatialAnchorStoreConnectionMSFT", (PFN_xrVoidFunction*)&table->DestroySpatialAnchorStoreConnectionMSFT)); + (get_inst_proc_addr(instance, "xrPersistSpatialAnchorMSFT", (PFN_xrVoidFunction*)&table->PersistSpatialAnchorMSFT)); + (get_inst_proc_addr(instance, "xrEnumeratePersistedSpatialAnchorNamesMSFT", (PFN_xrVoidFunction*)&table->EnumeratePersistedSpatialAnchorNamesMSFT)); + (get_inst_proc_addr(instance, "xrCreateSpatialAnchorFromPersistedNameMSFT", (PFN_xrVoidFunction*)&table->CreateSpatialAnchorFromPersistedNameMSFT)); + (get_inst_proc_addr(instance, "xrUnpersistSpatialAnchorMSFT", (PFN_xrVoidFunction*)&table->UnpersistSpatialAnchorMSFT)); + (get_inst_proc_addr(instance, "xrClearSpatialAnchorStoreMSFT", (PFN_xrVoidFunction*)&table->ClearSpatialAnchorStoreMSFT)); + + // ---- XR_OCULUS_audio_device_guid extension commands +#if defined(XR_USE_PLATFORM_WIN32) + (get_inst_proc_addr(instance, "xrGetAudioOutputDeviceGuidOculus", (PFN_xrVoidFunction*)&table->GetAudioOutputDeviceGuidOculus)); +#endif // defined(XR_USE_PLATFORM_WIN32) +#if defined(XR_USE_PLATFORM_WIN32) + (get_inst_proc_addr(instance, "xrGetAudioInputDeviceGuidOculus", (PFN_xrVoidFunction*)&table->GetAudioInputDeviceGuidOculus)); +#endif // defined(XR_USE_PLATFORM_WIN32) + + // ---- XR_ALMALENCE_digital_lens_control extension commands + (get_inst_proc_addr(instance, "xrSetDigitalLensControlALMALENCE", (PFN_xrVoidFunction*)&table->SetDigitalLensControlALMALENCE)); + + // ---- XR_FB_passthrough_keyboard_hands extension commands + (get_inst_proc_addr(instance, "xrPassthroughLayerSetKeyboardHandsIntensityFB", (PFN_xrVoidFunction*)&table->PassthroughLayerSetKeyboardHandsIntensityFB)); +} + + +#ifdef __cplusplus +} // extern "C" +#endif + diff --git a/thirdparty/openxr/src/xr_generated_dispatch_table.h b/thirdparty/openxr/src/xr_generated_dispatch_table.h new file mode 100644 index 0000000000..34e0de93f5 --- /dev/null +++ b/thirdparty/openxr/src/xr_generated_dispatch_table.h @@ -0,0 +1,355 @@ +// Copyright (c) 2017-2022, The Khronos Group Inc. +// Copyright (c) 2017-2019 Valve Corporation +// Copyright (c) 2017-2019 LunarG, Inc. +// SPDX-License-Identifier: Apache-2.0 OR MIT +// *********** THIS FILE IS GENERATED - DO NOT EDIT *********** +// See utility_source_generator.py for modifications +// ************************************************************ + +// Copyright (c) 2017-2022, The Khronos Group Inc. +// Copyright (c) 2017-2019 Valve Corporation +// Copyright (c) 2017-2019 LunarG, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Mark Young <marky@lunarg.com> +// + +#pragma once +#include "xr_dependencies.h" +#include <openxr/openxr.h> +#include <openxr/openxr_platform.h> + + +#ifdef __cplusplus +extern "C" { +#endif +// Generated dispatch table +struct XrGeneratedDispatchTable { + + // ---- Core 1.0 commands + PFN_xrGetInstanceProcAddr GetInstanceProcAddr; + PFN_xrEnumerateApiLayerProperties EnumerateApiLayerProperties; + PFN_xrEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties; + PFN_xrCreateInstance CreateInstance; + PFN_xrDestroyInstance DestroyInstance; + PFN_xrGetInstanceProperties GetInstanceProperties; + PFN_xrPollEvent PollEvent; + PFN_xrResultToString ResultToString; + PFN_xrStructureTypeToString StructureTypeToString; + PFN_xrGetSystem GetSystem; + PFN_xrGetSystemProperties GetSystemProperties; + PFN_xrEnumerateEnvironmentBlendModes EnumerateEnvironmentBlendModes; + PFN_xrCreateSession CreateSession; + PFN_xrDestroySession DestroySession; + PFN_xrEnumerateReferenceSpaces EnumerateReferenceSpaces; + PFN_xrCreateReferenceSpace CreateReferenceSpace; + PFN_xrGetReferenceSpaceBoundsRect GetReferenceSpaceBoundsRect; + PFN_xrCreateActionSpace CreateActionSpace; + PFN_xrLocateSpace LocateSpace; + PFN_xrDestroySpace DestroySpace; + PFN_xrEnumerateViewConfigurations EnumerateViewConfigurations; + PFN_xrGetViewConfigurationProperties GetViewConfigurationProperties; + PFN_xrEnumerateViewConfigurationViews EnumerateViewConfigurationViews; + PFN_xrEnumerateSwapchainFormats EnumerateSwapchainFormats; + PFN_xrCreateSwapchain CreateSwapchain; + PFN_xrDestroySwapchain DestroySwapchain; + PFN_xrEnumerateSwapchainImages EnumerateSwapchainImages; + PFN_xrAcquireSwapchainImage AcquireSwapchainImage; + PFN_xrWaitSwapchainImage WaitSwapchainImage; + PFN_xrReleaseSwapchainImage ReleaseSwapchainImage; + PFN_xrBeginSession BeginSession; + PFN_xrEndSession EndSession; + PFN_xrRequestExitSession RequestExitSession; + PFN_xrWaitFrame WaitFrame; + PFN_xrBeginFrame BeginFrame; + PFN_xrEndFrame EndFrame; + PFN_xrLocateViews LocateViews; + PFN_xrStringToPath StringToPath; + PFN_xrPathToString PathToString; + PFN_xrCreateActionSet CreateActionSet; + PFN_xrDestroyActionSet DestroyActionSet; + PFN_xrCreateAction CreateAction; + PFN_xrDestroyAction DestroyAction; + PFN_xrSuggestInteractionProfileBindings SuggestInteractionProfileBindings; + PFN_xrAttachSessionActionSets AttachSessionActionSets; + PFN_xrGetCurrentInteractionProfile GetCurrentInteractionProfile; + PFN_xrGetActionStateBoolean GetActionStateBoolean; + PFN_xrGetActionStateFloat GetActionStateFloat; + PFN_xrGetActionStateVector2f GetActionStateVector2f; + PFN_xrGetActionStatePose GetActionStatePose; + PFN_xrSyncActions SyncActions; + PFN_xrEnumerateBoundSourcesForAction EnumerateBoundSourcesForAction; + PFN_xrGetInputSourceLocalizedName GetInputSourceLocalizedName; + PFN_xrApplyHapticFeedback ApplyHapticFeedback; + PFN_xrStopHapticFeedback StopHapticFeedback; + + // ---- XR_KHR_android_thread_settings extension commands +#if defined(XR_USE_PLATFORM_ANDROID) + PFN_xrSetAndroidApplicationThreadKHR SetAndroidApplicationThreadKHR; +#endif // defined(XR_USE_PLATFORM_ANDROID) + + // ---- XR_KHR_android_surface_swapchain extension commands +#if defined(XR_USE_PLATFORM_ANDROID) + PFN_xrCreateSwapchainAndroidSurfaceKHR CreateSwapchainAndroidSurfaceKHR; +#endif // defined(XR_USE_PLATFORM_ANDROID) + + // ---- XR_KHR_opengl_enable extension commands +#if defined(XR_USE_GRAPHICS_API_OPENGL) + PFN_xrGetOpenGLGraphicsRequirementsKHR GetOpenGLGraphicsRequirementsKHR; +#endif // defined(XR_USE_GRAPHICS_API_OPENGL) + + // ---- XR_KHR_opengl_es_enable extension commands +#if defined(XR_USE_GRAPHICS_API_OPENGL_ES) + PFN_xrGetOpenGLESGraphicsRequirementsKHR GetOpenGLESGraphicsRequirementsKHR; +#endif // defined(XR_USE_GRAPHICS_API_OPENGL_ES) + + // ---- XR_KHR_vulkan_enable extension commands +#if defined(XR_USE_GRAPHICS_API_VULKAN) + PFN_xrGetVulkanInstanceExtensionsKHR GetVulkanInstanceExtensionsKHR; +#endif // defined(XR_USE_GRAPHICS_API_VULKAN) +#if defined(XR_USE_GRAPHICS_API_VULKAN) + PFN_xrGetVulkanDeviceExtensionsKHR GetVulkanDeviceExtensionsKHR; +#endif // defined(XR_USE_GRAPHICS_API_VULKAN) +#if defined(XR_USE_GRAPHICS_API_VULKAN) + PFN_xrGetVulkanGraphicsDeviceKHR GetVulkanGraphicsDeviceKHR; +#endif // defined(XR_USE_GRAPHICS_API_VULKAN) +#if defined(XR_USE_GRAPHICS_API_VULKAN) + PFN_xrGetVulkanGraphicsRequirementsKHR GetVulkanGraphicsRequirementsKHR; +#endif // defined(XR_USE_GRAPHICS_API_VULKAN) + + // ---- XR_KHR_D3D11_enable extension commands +#if defined(XR_USE_GRAPHICS_API_D3D11) + PFN_xrGetD3D11GraphicsRequirementsKHR GetD3D11GraphicsRequirementsKHR; +#endif // defined(XR_USE_GRAPHICS_API_D3D11) + + // ---- XR_KHR_D3D12_enable extension commands +#if defined(XR_USE_GRAPHICS_API_D3D12) + PFN_xrGetD3D12GraphicsRequirementsKHR GetD3D12GraphicsRequirementsKHR; +#endif // defined(XR_USE_GRAPHICS_API_D3D12) + + // ---- XR_KHR_visibility_mask extension commands + PFN_xrGetVisibilityMaskKHR GetVisibilityMaskKHR; + + // ---- XR_KHR_win32_convert_performance_counter_time extension commands +#if defined(XR_USE_PLATFORM_WIN32) + PFN_xrConvertWin32PerformanceCounterToTimeKHR ConvertWin32PerformanceCounterToTimeKHR; +#endif // defined(XR_USE_PLATFORM_WIN32) +#if defined(XR_USE_PLATFORM_WIN32) + PFN_xrConvertTimeToWin32PerformanceCounterKHR ConvertTimeToWin32PerformanceCounterKHR; +#endif // defined(XR_USE_PLATFORM_WIN32) + + // ---- XR_KHR_convert_timespec_time extension commands +#if defined(XR_USE_TIMESPEC) + PFN_xrConvertTimespecTimeToTimeKHR ConvertTimespecTimeToTimeKHR; +#endif // defined(XR_USE_TIMESPEC) +#if defined(XR_USE_TIMESPEC) + PFN_xrConvertTimeToTimespecTimeKHR ConvertTimeToTimespecTimeKHR; +#endif // defined(XR_USE_TIMESPEC) + + // ---- XR_KHR_loader_init extension commands + PFN_xrInitializeLoaderKHR InitializeLoaderKHR; + + // ---- XR_KHR_vulkan_enable2 extension commands +#if defined(XR_USE_GRAPHICS_API_VULKAN) + PFN_xrCreateVulkanInstanceKHR CreateVulkanInstanceKHR; +#endif // defined(XR_USE_GRAPHICS_API_VULKAN) +#if defined(XR_USE_GRAPHICS_API_VULKAN) + PFN_xrCreateVulkanDeviceKHR CreateVulkanDeviceKHR; +#endif // defined(XR_USE_GRAPHICS_API_VULKAN) +#if defined(XR_USE_GRAPHICS_API_VULKAN) + PFN_xrGetVulkanGraphicsDevice2KHR GetVulkanGraphicsDevice2KHR; +#endif // defined(XR_USE_GRAPHICS_API_VULKAN) +#if defined(XR_USE_GRAPHICS_API_VULKAN) + PFN_xrGetVulkanGraphicsRequirements2KHR GetVulkanGraphicsRequirements2KHR; +#endif // defined(XR_USE_GRAPHICS_API_VULKAN) + + // ---- XR_EXT_performance_settings extension commands + PFN_xrPerfSettingsSetPerformanceLevelEXT PerfSettingsSetPerformanceLevelEXT; + + // ---- XR_EXT_thermal_query extension commands + PFN_xrThermalGetTemperatureTrendEXT ThermalGetTemperatureTrendEXT; + + // ---- XR_EXT_debug_utils extension commands + PFN_xrSetDebugUtilsObjectNameEXT SetDebugUtilsObjectNameEXT; + PFN_xrCreateDebugUtilsMessengerEXT CreateDebugUtilsMessengerEXT; + PFN_xrDestroyDebugUtilsMessengerEXT DestroyDebugUtilsMessengerEXT; + PFN_xrSubmitDebugUtilsMessageEXT SubmitDebugUtilsMessageEXT; + PFN_xrSessionBeginDebugUtilsLabelRegionEXT SessionBeginDebugUtilsLabelRegionEXT; + PFN_xrSessionEndDebugUtilsLabelRegionEXT SessionEndDebugUtilsLabelRegionEXT; + PFN_xrSessionInsertDebugUtilsLabelEXT SessionInsertDebugUtilsLabelEXT; + + // ---- XR_MSFT_spatial_anchor extension commands + PFN_xrCreateSpatialAnchorMSFT CreateSpatialAnchorMSFT; + PFN_xrCreateSpatialAnchorSpaceMSFT CreateSpatialAnchorSpaceMSFT; + PFN_xrDestroySpatialAnchorMSFT DestroySpatialAnchorMSFT; + + // ---- XR_EXT_conformance_automation extension commands + PFN_xrSetInputDeviceActiveEXT SetInputDeviceActiveEXT; + PFN_xrSetInputDeviceStateBoolEXT SetInputDeviceStateBoolEXT; + PFN_xrSetInputDeviceStateFloatEXT SetInputDeviceStateFloatEXT; + PFN_xrSetInputDeviceStateVector2fEXT SetInputDeviceStateVector2fEXT; + PFN_xrSetInputDeviceLocationEXT SetInputDeviceLocationEXT; + + // ---- XR_MSFT_spatial_graph_bridge extension commands + PFN_xrCreateSpatialGraphNodeSpaceMSFT CreateSpatialGraphNodeSpaceMSFT; + + // ---- XR_EXT_hand_tracking extension commands + PFN_xrCreateHandTrackerEXT CreateHandTrackerEXT; + PFN_xrDestroyHandTrackerEXT DestroyHandTrackerEXT; + PFN_xrLocateHandJointsEXT LocateHandJointsEXT; + + // ---- XR_MSFT_hand_tracking_mesh extension commands + PFN_xrCreateHandMeshSpaceMSFT CreateHandMeshSpaceMSFT; + PFN_xrUpdateHandMeshMSFT UpdateHandMeshMSFT; + + // ---- XR_MSFT_controller_model extension commands + PFN_xrGetControllerModelKeyMSFT GetControllerModelKeyMSFT; + PFN_xrLoadControllerModelMSFT LoadControllerModelMSFT; + PFN_xrGetControllerModelPropertiesMSFT GetControllerModelPropertiesMSFT; + PFN_xrGetControllerModelStateMSFT GetControllerModelStateMSFT; + + // ---- XR_MSFT_perception_anchor_interop extension commands +#if defined(XR_USE_PLATFORM_WIN32) + PFN_xrCreateSpatialAnchorFromPerceptionAnchorMSFT CreateSpatialAnchorFromPerceptionAnchorMSFT; +#endif // defined(XR_USE_PLATFORM_WIN32) +#if defined(XR_USE_PLATFORM_WIN32) + PFN_xrTryGetPerceptionAnchorFromSpatialAnchorMSFT TryGetPerceptionAnchorFromSpatialAnchorMSFT; +#endif // defined(XR_USE_PLATFORM_WIN32) + + // ---- XR_MSFT_composition_layer_reprojection extension commands + PFN_xrEnumerateReprojectionModesMSFT EnumerateReprojectionModesMSFT; + + // ---- XR_FB_swapchain_update_state extension commands + PFN_xrUpdateSwapchainFB UpdateSwapchainFB; + PFN_xrGetSwapchainStateFB GetSwapchainStateFB; + + // ---- XR_MSFT_scene_understanding extension commands + PFN_xrEnumerateSceneComputeFeaturesMSFT EnumerateSceneComputeFeaturesMSFT; + PFN_xrCreateSceneObserverMSFT CreateSceneObserverMSFT; + PFN_xrDestroySceneObserverMSFT DestroySceneObserverMSFT; + PFN_xrCreateSceneMSFT CreateSceneMSFT; + PFN_xrDestroySceneMSFT DestroySceneMSFT; + PFN_xrComputeNewSceneMSFT ComputeNewSceneMSFT; + PFN_xrGetSceneComputeStateMSFT GetSceneComputeStateMSFT; + PFN_xrGetSceneComponentsMSFT GetSceneComponentsMSFT; + PFN_xrLocateSceneComponentsMSFT LocateSceneComponentsMSFT; + PFN_xrGetSceneMeshBuffersMSFT GetSceneMeshBuffersMSFT; + + // ---- XR_MSFT_scene_understanding_serialization extension commands + PFN_xrDeserializeSceneMSFT DeserializeSceneMSFT; + PFN_xrGetSerializedSceneFragmentDataMSFT GetSerializedSceneFragmentDataMSFT; + + // ---- XR_FB_display_refresh_rate extension commands + PFN_xrEnumerateDisplayRefreshRatesFB EnumerateDisplayRefreshRatesFB; + PFN_xrGetDisplayRefreshRateFB GetDisplayRefreshRateFB; + PFN_xrRequestDisplayRefreshRateFB RequestDisplayRefreshRateFB; + + // ---- XR_HTCX_vive_tracker_interaction extension commands + PFN_xrEnumerateViveTrackerPathsHTCX EnumerateViveTrackerPathsHTCX; + + // ---- XR_HTC_facial_tracking extension commands + PFN_xrCreateFacialTrackerHTC CreateFacialTrackerHTC; + PFN_xrDestroyFacialTrackerHTC DestroyFacialTrackerHTC; + PFN_xrGetFacialExpressionsHTC GetFacialExpressionsHTC; + + // ---- XR_FB_color_space extension commands + PFN_xrEnumerateColorSpacesFB EnumerateColorSpacesFB; + PFN_xrSetColorSpaceFB SetColorSpaceFB; + + // ---- XR_FB_hand_tracking_mesh extension commands + PFN_xrGetHandMeshFB GetHandMeshFB; + + // ---- XR_FB_foveation extension commands + PFN_xrCreateFoveationProfileFB CreateFoveationProfileFB; + PFN_xrDestroyFoveationProfileFB DestroyFoveationProfileFB; + + // ---- XR_FB_keyboard_tracking extension commands + PFN_xrQuerySystemTrackedKeyboardFB QuerySystemTrackedKeyboardFB; + PFN_xrCreateKeyboardSpaceFB CreateKeyboardSpaceFB; + + // ---- XR_FB_triangle_mesh extension commands + PFN_xrCreateTriangleMeshFB CreateTriangleMeshFB; + PFN_xrDestroyTriangleMeshFB DestroyTriangleMeshFB; + PFN_xrTriangleMeshGetVertexBufferFB TriangleMeshGetVertexBufferFB; + PFN_xrTriangleMeshGetIndexBufferFB TriangleMeshGetIndexBufferFB; + PFN_xrTriangleMeshBeginUpdateFB TriangleMeshBeginUpdateFB; + PFN_xrTriangleMeshEndUpdateFB TriangleMeshEndUpdateFB; + PFN_xrTriangleMeshBeginVertexBufferUpdateFB TriangleMeshBeginVertexBufferUpdateFB; + PFN_xrTriangleMeshEndVertexBufferUpdateFB TriangleMeshEndVertexBufferUpdateFB; + + // ---- XR_FB_passthrough extension commands + PFN_xrCreatePassthroughFB CreatePassthroughFB; + PFN_xrDestroyPassthroughFB DestroyPassthroughFB; + PFN_xrPassthroughStartFB PassthroughStartFB; + PFN_xrPassthroughPauseFB PassthroughPauseFB; + PFN_xrCreatePassthroughLayerFB CreatePassthroughLayerFB; + PFN_xrDestroyPassthroughLayerFB DestroyPassthroughLayerFB; + PFN_xrPassthroughLayerPauseFB PassthroughLayerPauseFB; + PFN_xrPassthroughLayerResumeFB PassthroughLayerResumeFB; + PFN_xrPassthroughLayerSetStyleFB PassthroughLayerSetStyleFB; + PFN_xrCreateGeometryInstanceFB CreateGeometryInstanceFB; + PFN_xrDestroyGeometryInstanceFB DestroyGeometryInstanceFB; + PFN_xrGeometryInstanceSetTransformFB GeometryInstanceSetTransformFB; + + // ---- XR_FB_render_model extension commands + PFN_xrEnumerateRenderModelPathsFB EnumerateRenderModelPathsFB; + PFN_xrGetRenderModelPropertiesFB GetRenderModelPropertiesFB; + PFN_xrLoadRenderModelFB LoadRenderModelFB; + + // ---- XR_VARJO_environment_depth_estimation extension commands + PFN_xrSetEnvironmentDepthEstimationVARJO SetEnvironmentDepthEstimationVARJO; + + // ---- XR_VARJO_marker_tracking extension commands + PFN_xrSetMarkerTrackingVARJO SetMarkerTrackingVARJO; + PFN_xrSetMarkerTrackingTimeoutVARJO SetMarkerTrackingTimeoutVARJO; + PFN_xrSetMarkerTrackingPredictionVARJO SetMarkerTrackingPredictionVARJO; + PFN_xrGetMarkerSizeVARJO GetMarkerSizeVARJO; + PFN_xrCreateMarkerSpaceVARJO CreateMarkerSpaceVARJO; + + // ---- XR_MSFT_spatial_anchor_persistence extension commands + PFN_xrCreateSpatialAnchorStoreConnectionMSFT CreateSpatialAnchorStoreConnectionMSFT; + PFN_xrDestroySpatialAnchorStoreConnectionMSFT DestroySpatialAnchorStoreConnectionMSFT; + PFN_xrPersistSpatialAnchorMSFT PersistSpatialAnchorMSFT; + PFN_xrEnumeratePersistedSpatialAnchorNamesMSFT EnumeratePersistedSpatialAnchorNamesMSFT; + PFN_xrCreateSpatialAnchorFromPersistedNameMSFT CreateSpatialAnchorFromPersistedNameMSFT; + PFN_xrUnpersistSpatialAnchorMSFT UnpersistSpatialAnchorMSFT; + PFN_xrClearSpatialAnchorStoreMSFT ClearSpatialAnchorStoreMSFT; + + // ---- XR_OCULUS_audio_device_guid extension commands +#if defined(XR_USE_PLATFORM_WIN32) + PFN_xrGetAudioOutputDeviceGuidOculus GetAudioOutputDeviceGuidOculus; +#endif // defined(XR_USE_PLATFORM_WIN32) +#if defined(XR_USE_PLATFORM_WIN32) + PFN_xrGetAudioInputDeviceGuidOculus GetAudioInputDeviceGuidOculus; +#endif // defined(XR_USE_PLATFORM_WIN32) + + // ---- XR_ALMALENCE_digital_lens_control extension commands + PFN_xrSetDigitalLensControlALMALENCE SetDigitalLensControlALMALENCE; + + // ---- XR_FB_passthrough_keyboard_hands extension commands + PFN_xrPassthroughLayerSetKeyboardHandsIntensityFB PassthroughLayerSetKeyboardHandsIntensityFB; +}; + + +// Prototype for dispatch table helper function +void GeneratedXrPopulateDispatchTable(struct XrGeneratedDispatchTable *table, + XrInstance instance, + PFN_xrGetInstanceProcAddr get_inst_proc_addr); + +#ifdef __cplusplus +} // extern "C" +#endif + |