From 2129833c7e4284ea0fd39f94b82cd180addb7226 Mon Sep 17 00:00:00 2001 From: Bastiaan Olij Date: Wed, 18 Sep 2024 10:14:21 +1000 Subject: [PATCH] OpenXR: Add support for binding modifiers --- doc/classes/ProjectSettings.xml | 6 + editor/icons/Modifiers.svg | 1 + main/main.cpp | 6 +- .../openxr/action_map/openxr_action_map.cpp | 35 +- modules/openxr/action_map/openxr_action_map.h | 1 + .../action_map/openxr_binding_modifier.cpp | 34 ++ .../action_map/openxr_binding_modifier.h | 66 ++++ .../action_map/openxr_haptic_feedback.cpp | 93 +++++ .../action_map/openxr_haptic_feedback.h | 72 ++++ .../action_map/openxr_interaction_profile.cpp | 153 ++++++++ .../action_map/openxr_interaction_profile.h | 35 ++ .../openxr_interaction_profile_metadata.cpp | 335 +++++++++--------- modules/openxr/config.py | 8 + .../OpenXRAnalogThresholdModifier.xml | 26 ++ .../doc_classes/OpenXRBindingModifier.xml | 11 + .../OpenXRBindingModifierEditor.xml | 38 ++ .../doc_classes/OpenXRDpadBindingModifier.xml | 43 +++ .../openxr/doc_classes/OpenXRHapticBase.xml | 11 + .../doc_classes/OpenXRHapticVibration.xml | 22 ++ .../openxr/doc_classes/OpenXRIPBinding.xml | 16 + .../doc_classes/OpenXRInteractionProfile.xml | 16 + .../OpenXRInteractionProfileEditor.xml | 11 + .../OpenXRInteractionProfileEditorBase.xml | 25 ++ modules/openxr/editor/SCsub | 7 +- .../editor/openxr_action_map_editor.cpp | 56 ++- .../openxr/editor/openxr_action_map_editor.h | 8 + .../editor/openxr_binding_modifier_editor.cpp | 279 +++++++++++++++ .../editor/openxr_binding_modifier_editor.h | 114 ++++++ .../openxr_binding_modifiers_dialog.cpp | 266 ++++++++++++++ .../editor/openxr_binding_modifiers_dialog.h | 81 +++++ .../openxr/editor/openxr_editor_plugin.cpp | 3 + modules/openxr/editor/openxr_editor_plugin.h | 2 + .../openxr_interaction_profile_editor.cpp | 131 +++++-- .../openxr_interaction_profile_editor.h | 38 +- ...enxr_select_interaction_profile_dialog.cpp | 13 +- .../openxr_dpad_binding_extension.cpp | 274 ++++++++++++++ .../openxr_dpad_binding_extension.h | 110 ++++++ .../openxr_htc_controller_extension.cpp | 176 +++++---- .../openxr_htc_vive_tracker_extension.cpp | 167 ++------- .../openxr_huawei_controller_extension.cpp | 52 ++- .../openxr_meta_controller_extension.cpp | 235 ++++++------ .../openxr_ml2_controller_extension.cpp | 7 +- .../openxr_pico_controller_extension.cpp | 156 ++++---- ...penxr_valve_analog_threshold_extension.cpp | 193 ++++++++++ .../openxr_valve_analog_threshold_extension.h | 88 +++++ .../openxr_wmr_controller_extension.cpp | 167 +++++---- modules/openxr/openxr_api.cpp | 145 +++++++- modules/openxr/openxr_api.h | 12 +- modules/openxr/openxr_interface.cpp | 20 +- modules/openxr/register_types.cpp | 26 ++ 50 files changed, 3095 insertions(+), 795 deletions(-) create mode 100644 editor/icons/Modifiers.svg create mode 100644 modules/openxr/action_map/openxr_binding_modifier.cpp create mode 100644 modules/openxr/action_map/openxr_binding_modifier.h create mode 100644 modules/openxr/action_map/openxr_haptic_feedback.cpp create mode 100644 modules/openxr/action_map/openxr_haptic_feedback.h create mode 100644 modules/openxr/doc_classes/OpenXRAnalogThresholdModifier.xml create mode 100644 modules/openxr/doc_classes/OpenXRBindingModifier.xml create mode 100644 modules/openxr/doc_classes/OpenXRBindingModifierEditor.xml create mode 100644 modules/openxr/doc_classes/OpenXRDpadBindingModifier.xml create mode 100644 modules/openxr/doc_classes/OpenXRHapticBase.xml create mode 100644 modules/openxr/doc_classes/OpenXRHapticVibration.xml create mode 100644 modules/openxr/doc_classes/OpenXRInteractionProfileEditor.xml create mode 100644 modules/openxr/doc_classes/OpenXRInteractionProfileEditorBase.xml create mode 100644 modules/openxr/editor/openxr_binding_modifier_editor.cpp create mode 100644 modules/openxr/editor/openxr_binding_modifier_editor.h create mode 100644 modules/openxr/editor/openxr_binding_modifiers_dialog.cpp create mode 100644 modules/openxr/editor/openxr_binding_modifiers_dialog.h create mode 100644 modules/openxr/extensions/openxr_dpad_binding_extension.cpp create mode 100644 modules/openxr/extensions/openxr_dpad_binding_extension.h create mode 100644 modules/openxr/extensions/openxr_valve_analog_threshold_extension.cpp create mode 100644 modules/openxr/extensions/openxr_valve_analog_threshold_extension.h diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 1684edb9b88e..74f22d7fbac4 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -2956,6 +2956,12 @@ Maximum number of threads to be used by [WorkerThreadPool]. Value of [code]-1[/code] means no limit. + + Enables the analog threshold binding modifier if supported by the XR runtime. + + + Enabled the dpad binding modifier if supported by the XR runtime. + Action map configuration to load by default. diff --git a/editor/icons/Modifiers.svg b/editor/icons/Modifiers.svg new file mode 100644 index 000000000000..1b25d620278d --- /dev/null +++ b/editor/icons/Modifiers.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/main/main.cpp b/main/main.cpp index 5206e9b84c57..be550b4585e8 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -2602,7 +2602,11 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph GLOBAL_DEF_BASIC("xr/openxr/extensions/hand_tracking_unobstructed_data_source", false); // XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT GLOBAL_DEF_BASIC("xr/openxr/extensions/hand_tracking_controller_data_source", false); // XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT GLOBAL_DEF_RST_BASIC("xr/openxr/extensions/hand_interaction_profile", false); - GLOBAL_DEF_BASIC("xr/openxr/extensions/eye_gaze_interaction", false); + GLOBAL_DEF_RST_BASIC("xr/openxr/extensions/eye_gaze_interaction", false); + + // OpenXR Binding modifier settings + GLOBAL_DEF_BASIC("xr/openxr/binding_modifiers/analog_threshold", false); + GLOBAL_DEF_RST_BASIC("xr/openxr/binding_modifiers/dpad_binding", false); #ifdef TOOLS_ENABLED // Disabled for now, using XR inside of the editor we'll be working on during the coming months. diff --git a/modules/openxr/action_map/openxr_action_map.cpp b/modules/openxr/action_map/openxr_action_map.cpp index f924386ecf15..1979f09e0293 100644 --- a/modules/openxr/action_map/openxr_action_map.cpp +++ b/modules/openxr/action_map/openxr_action_map.cpp @@ -107,14 +107,26 @@ void OpenXRActionMap::remove_action_set(Ref p_action_set) { } } -void OpenXRActionMap::set_interaction_profiles(Array p_interaction_profiles) { +void OpenXRActionMap::clear_interaction_profiles() { + // Interaction profiles held within our action map set should be released and destroyed but just in case they are still used some where else + if (interaction_profiles.size() == 0) { + return; + } + + for (int i = 0; i < interaction_profiles.size(); i++) { + Ref interaction_profile = interaction_profiles[i]; + interaction_profile->action_map = nullptr; + } interaction_profiles.clear(); + emit_changed(); +} + +void OpenXRActionMap::set_interaction_profiles(Array p_interaction_profiles) { + clear_interaction_profiles(); for (int i = 0; i < p_interaction_profiles.size(); i++) { - Ref interaction_profile = p_interaction_profiles[i]; - if (interaction_profile.is_valid() && !interaction_profiles.has(interaction_profile)) { - interaction_profiles.push_back(interaction_profile); - } + // add them anew so we verify our interaction profile pointer + add_interaction_profile(p_interaction_profiles[i]); } } @@ -147,6 +159,13 @@ void OpenXRActionMap::add_interaction_profile(Ref p_in ERR_FAIL_COND(p_interaction_profile.is_null()); if (!interaction_profiles.has(p_interaction_profile)) { + if (p_interaction_profile->action_map && p_interaction_profile->action_map != this) { + // interaction profiles should only relate to our action map + p_interaction_profile->action_map->remove_interaction_profile(p_interaction_profile); + } + + p_interaction_profile->action_map = this; + interaction_profiles.push_back(p_interaction_profile); emit_changed(); } @@ -156,6 +175,10 @@ void OpenXRActionMap::remove_interaction_profile(Ref p int idx = interaction_profiles.find(p_interaction_profile); if (idx != -1) { interaction_profiles.remove_at(idx); + + ERR_FAIL_COND_MSG(p_interaction_profile->action_map != this, "Removing interaction profile that belongs to this action map but had incorrect action map pointer."); // this should never happen! + p_interaction_profile->action_map = nullptr; + emit_changed(); } } @@ -598,5 +621,5 @@ PackedStringArray OpenXRActionMap::get_top_level_paths(const Ref p OpenXRActionMap::~OpenXRActionMap() { action_sets.clear(); - interaction_profiles.clear(); + clear_interaction_profiles(); } diff --git a/modules/openxr/action_map/openxr_action_map.h b/modules/openxr/action_map/openxr_action_map.h index 678b3d7fbc57..7239a8534c9f 100644 --- a/modules/openxr/action_map/openxr_action_map.h +++ b/modules/openxr/action_map/openxr_action_map.h @@ -57,6 +57,7 @@ class OpenXRActionMap : public Resource { void add_action_set(Ref p_action_set); // Add an action set to our action map void remove_action_set(Ref p_action_set); // Remove an action set from our action map + void clear_interaction_profiles(); // Remove all our interaction profiles void set_interaction_profiles(Array p_interaction_profiles); // Set our interaction profiles by providing an array (for loading from resource) Array get_interaction_profiles() const; // Get our interaction profiles as an array (for saving to resource) diff --git a/modules/openxr/action_map/openxr_binding_modifier.cpp b/modules/openxr/action_map/openxr_binding_modifier.cpp new file mode 100644 index 000000000000..29ed90104fcf --- /dev/null +++ b/modules/openxr/action_map/openxr_binding_modifier.cpp @@ -0,0 +1,34 @@ +/**************************************************************************/ +/* openxr_binding_modifier.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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_binding_modifier.h" + +void OpenXRBindingModifier::_bind_methods() { +} diff --git a/modules/openxr/action_map/openxr_binding_modifier.h b/modules/openxr/action_map/openxr_binding_modifier.h new file mode 100644 index 000000000000..295ec9b807ea --- /dev/null +++ b/modules/openxr/action_map/openxr_binding_modifier.h @@ -0,0 +1,66 @@ +/**************************************************************************/ +/* openxr_binding_modifier.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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_BINDING_MODIFIER_H +#define OPENXR_BINDING_MODIFIER_H + +#include "../action_map/openxr_action.h" +#include "core/io/resource.h" + +// Part of implementation for: +// https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#XR_KHR_binding_modification + +class OpenXRInteractionProfile; +class OpenXRIPBinding; + +class OpenXRBindingModifier : public Resource { + GDCLASS(OpenXRBindingModifier, Resource); + +private: +protected: + friend class OpenXRInteractionProfile; + friend class OpenXRIPBinding; + + static void _bind_methods(); + + OpenXRInteractionProfile *interaction_profile = nullptr; // action belongs to this interaction profile (should only be set if record_on_binding() == false). + OpenXRIPBinding *ip_binding = nullptr; // action belongs to this binding (should only be set if record_on_binding() == true). + +public: + OpenXRInteractionProfile *get_interaction_profile() const { return interaction_profile; } + OpenXRIPBinding *get_ip_binding() const { return ip_binding; } + + virtual bool record_on_binding() const { return true; } // If true, this binding modifier is recorded on a specific binding. If false, this binding modifier is recorded on the interaction profile. + + virtual String get_description() const = 0; // Returns the description shown in the editor + virtual PackedByteArray get_ip_modification() = 0; // Return the XrBindingModificationsKHR binding modifier struct data used when calling xrSuggestInteractionProfileBindings +}; + +#endif // OPENXR_BINDING_MODIFIER_H diff --git a/modules/openxr/action_map/openxr_haptic_feedback.cpp b/modules/openxr/action_map/openxr_haptic_feedback.cpp new file mode 100644 index 000000000000..583e4d4fe307 --- /dev/null +++ b/modules/openxr/action_map/openxr_haptic_feedback.cpp @@ -0,0 +1,93 @@ +/**************************************************************************/ +/* openxr_haptic_feedback.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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_haptic_feedback.h" + +//////////////////////////////////////////////////////////////////////////// +// OpenXRHapticBase + +void OpenXRHapticBase::_bind_methods() { +} + +//////////////////////////////////////////////////////////////////////////// +// OpenXRHapticVibration + +void OpenXRHapticVibration::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_duration", "duration"), &OpenXRHapticVibration::set_duration); + ClassDB::bind_method(D_METHOD("get_duration"), &OpenXRHapticVibration::get_duration); + ADD_PROPERTY(PropertyInfo(Variant::INT, "duration"), "set_duration", "get_duration"); + + ClassDB::bind_method(D_METHOD("set_frequency", "frequency"), &OpenXRHapticVibration::set_frequency); + ClassDB::bind_method(D_METHOD("get_frequency"), &OpenXRHapticVibration::get_frequency); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frequency"), "set_frequency", "get_frequency"); + + ClassDB::bind_method(D_METHOD("set_amplitude", "amplitude"), &OpenXRHapticVibration::set_amplitude); + ClassDB::bind_method(D_METHOD("get_amplitude"), &OpenXRHapticVibration::get_amplitude); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "amplitude", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_amplitude", "get_amplitude"); +} + +void OpenXRHapticVibration::set_duration(int64_t p_duration) { + haptic_vibration.duration = p_duration; + emit_changed(); +} + +int64_t OpenXRHapticVibration::get_duration() const { + return haptic_vibration.duration; +} + +void OpenXRHapticVibration::set_frequency(float p_frequency) { + haptic_vibration.frequency = p_frequency; + emit_changed(); +} + +float OpenXRHapticVibration::get_frequency() const { + return haptic_vibration.frequency; +} + +void OpenXRHapticVibration::set_amplitude(float p_amplitude) { + haptic_vibration.amplitude = p_amplitude; + emit_changed(); +} + +float OpenXRHapticVibration::get_amplitude() const { + return haptic_vibration.amplitude; +} + +const XrHapticBaseHeader *OpenXRHapticVibration::get_xr_structure() { + return (XrHapticBaseHeader *)&haptic_vibration; +} + +OpenXRHapticVibration::OpenXRHapticVibration() { + haptic_vibration.type = XR_TYPE_HAPTIC_VIBRATION; + haptic_vibration.next = nullptr; + haptic_vibration.duration = -1; + haptic_vibration.frequency = 0.0; + haptic_vibration.amplitude = 1.0; +} diff --git a/modules/openxr/action_map/openxr_haptic_feedback.h b/modules/openxr/action_map/openxr_haptic_feedback.h new file mode 100644 index 000000000000..d16f1ab1694d --- /dev/null +++ b/modules/openxr/action_map/openxr_haptic_feedback.h @@ -0,0 +1,72 @@ +/**************************************************************************/ +/* openxr_haptic_feedback.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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_HAPTIC_FEEDBACK_H +#define OPENXR_HAPTIC_FEEDBACK_H + +#include "core/io/resource.h" +#include + +class OpenXRHapticBase : public Resource { + GDCLASS(OpenXRHapticBase, Resource); + +private: +protected: + static void _bind_methods(); + +public: + virtual const XrHapticBaseHeader *get_xr_structure() = 0; +}; + +class OpenXRHapticVibration : public OpenXRHapticBase { + GDCLASS(OpenXRHapticVibration, OpenXRHapticBase); + +private: + XrHapticVibration haptic_vibration; + +protected: + static void _bind_methods(); + +public: + void set_duration(int64_t p_duration); + int64_t get_duration() const; + + void set_frequency(float p_frequency); + float get_frequency() const; + + void set_amplitude(float p_amplitude); + float get_amplitude() const; + + virtual const XrHapticBaseHeader *get_xr_structure() override; + + OpenXRHapticVibration(); +}; + +#endif // OPENXR_HAPTIC_FEEDBACK_H diff --git a/modules/openxr/action_map/openxr_interaction_profile.cpp b/modules/openxr/action_map/openxr_interaction_profile.cpp index 2aab55f6ec2f..7c98252b9e78 100644 --- a/modules/openxr/action_map/openxr_interaction_profile.cpp +++ b/modules/openxr/action_map/openxr_interaction_profile.cpp @@ -39,6 +39,12 @@ void OpenXRIPBinding::_bind_methods() { ClassDB::bind_method(D_METHOD("get_binding_path"), &OpenXRIPBinding::get_binding_path); ADD_PROPERTY(PropertyInfo(Variant::STRING, "binding_path"), "set_binding_path", "get_binding_path"); + ClassDB::bind_method(D_METHOD("get_binding_modifier_count"), &OpenXRIPBinding::get_binding_modifier_count); + ClassDB::bind_method(D_METHOD("get_binding_modifier", "index"), &OpenXRIPBinding::get_binding_modifier); + ClassDB::bind_method(D_METHOD("set_binding_modifiers", "binding_modifiers"), &OpenXRIPBinding::set_binding_modifiers); + ClassDB::bind_method(D_METHOD("get_binding_modifiers"), &OpenXRIPBinding::get_binding_modifiers); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "binding_modifiers", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRBindingModifier", PROPERTY_USAGE_NO_EDITOR), "set_binding_modifiers", "get_binding_modifiers"); + // Deprecated #ifndef DISABLE_DEPRECATED ClassDB::bind_method(D_METHOD("set_paths", "paths"), &OpenXRIPBinding::set_paths); @@ -81,6 +87,76 @@ String OpenXRIPBinding::get_binding_path() const { return binding_path; } +int OpenXRIPBinding::get_binding_modifier_count() const { + return binding_modifiers.size(); +} + +Ref OpenXRIPBinding::get_binding_modifier(int p_index) const { + ERR_FAIL_INDEX_V(p_index, binding_modifiers.size(), nullptr); + + return binding_modifiers[p_index]; +} + +void OpenXRIPBinding::clear_binding_modifiers() { + // Binding modifiers held within our interaction profile set should be released and destroyed but just in case they are still used some where else + if (binding_modifiers.size() == 0) { + return; + } + + for (int i = 0; i < binding_modifiers.size(); i++) { + Ref binding_modifier = binding_modifiers[i]; + binding_modifier->ip_binding = nullptr; + } + binding_modifiers.clear(); + emit_changed(); +} + +void OpenXRIPBinding::set_binding_modifiers(Array p_binding_modifiers) { + // Any binding modifier not retained in p_binding_modifiers should be freed automatically, those held within our Array will have be relinked to our interaction profile. + clear_binding_modifiers(); + + for (int i = 0; i < p_binding_modifiers.size(); i++) { + // add them anew so we verify our binding modifier pointer + add_binding_modifier(p_binding_modifiers[i]); + } +} + +Array OpenXRIPBinding::get_binding_modifiers() const { + Array ret; + for (const Ref &binding_modifier : binding_modifiers) { + ret.push_back(binding_modifier); + } + return ret; +} + +void OpenXRIPBinding::add_binding_modifier(Ref p_binding_modifier) { + ERR_FAIL_COND(p_binding_modifier.is_null()); + ERR_FAIL_COND_MSG(!p_binding_modifier->record_on_binding(), "This binding modifier must be added to an interaction profile."); + + if (!binding_modifiers.has(p_binding_modifier)) { + if (p_binding_modifier->ip_binding && p_binding_modifier->ip_binding != this) { + // binding modifier should only relate to our binding + p_binding_modifier->ip_binding->remove_binding_modifier(p_binding_modifier); + } + + p_binding_modifier->ip_binding = this; + binding_modifiers.push_back(p_binding_modifier); + emit_changed(); + } +} + +void OpenXRIPBinding::remove_binding_modifier(Ref p_binding_modifier) { + int idx = binding_modifiers.find(p_binding_modifier); + if (idx != -1) { + binding_modifiers.remove_at(idx); + + ERR_FAIL_COND_MSG(p_binding_modifier->ip_binding != this, "Removing binding modifier that belongs to this binding but had incorrect binding pointer."); // this should never happen! + p_binding_modifier->ip_binding = nullptr; + + emit_changed(); + } +} + #ifndef DISABLE_DEPRECATED void OpenXRIPBinding::set_paths(const PackedStringArray p_paths) { // Deprecated, but needed for loading old action maps. @@ -148,6 +224,12 @@ void OpenXRInteractionProfile::_bind_methods() { 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"); + + ClassDB::bind_method(D_METHOD("get_binding_modifier_count"), &OpenXRInteractionProfile::get_binding_modifier_count); + ClassDB::bind_method(D_METHOD("get_binding_modifier", "index"), &OpenXRInteractionProfile::get_binding_modifier); + ClassDB::bind_method(D_METHOD("set_binding_modifiers", "binding_modifiers"), &OpenXRInteractionProfile::set_binding_modifiers); + ClassDB::bind_method(D_METHOD("get_binding_modifiers"), &OpenXRInteractionProfile::get_binding_modifiers); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "binding_modifiers", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRBindingModifier", PROPERTY_USAGE_NO_EDITOR), "set_binding_modifiers", "get_binding_modifiers"); } Ref OpenXRInteractionProfile::new_profile(const char *p_input_profile_path) { @@ -275,6 +357,77 @@ bool OpenXRInteractionProfile::has_binding_for_action(const Ref p_ return false; } +int OpenXRInteractionProfile::get_binding_modifier_count() const { + return binding_modifiers.size(); +} + +Ref OpenXRInteractionProfile::get_binding_modifier(int p_index) const { + ERR_FAIL_INDEX_V(p_index, binding_modifiers.size(), nullptr); + + return binding_modifiers[p_index]; +} + +void OpenXRInteractionProfile::clear_binding_modifiers() { + // Binding modifiers held within our interaction profile set should be released and destroyed but just in case they are still used some where else + if (binding_modifiers.size() == 0) { + return; + } + + for (int i = 0; i < binding_modifiers.size(); i++) { + Ref binding_modifier = binding_modifiers[i]; + binding_modifier->interaction_profile = nullptr; + } + binding_modifiers.clear(); + emit_changed(); +} + +void OpenXRInteractionProfile::set_binding_modifiers(Array p_binding_modifiers) { + // Any binding modifier not retained in p_binding_modifiers should be freed automatically, those held within our Array will have be relinked to our interaction profile. + clear_binding_modifiers(); + + for (int i = 0; i < p_binding_modifiers.size(); i++) { + // add them anew so we verify our binding modifier pointer + add_binding_modifier(p_binding_modifiers[i]); + } +} + +Array OpenXRInteractionProfile::get_binding_modifiers() const { + Array ret; + for (const Ref &binding_modifier : binding_modifiers) { + ret.push_back(binding_modifier); + } + return ret; +} + +void OpenXRInteractionProfile::add_binding_modifier(Ref p_binding_modifier) { + ERR_FAIL_COND(p_binding_modifier.is_null()); + ERR_FAIL_COND_MSG(p_binding_modifier->record_on_binding(), "This binding modifier must be added to a binding."); + + if (!binding_modifiers.has(p_binding_modifier)) { + if (p_binding_modifier->interaction_profile && p_binding_modifier->interaction_profile != this) { + // binding modifier should only relate to our interaction profile + p_binding_modifier->interaction_profile->remove_binding_modifier(p_binding_modifier); + } + + p_binding_modifier->interaction_profile = this; + binding_modifiers.push_back(p_binding_modifier); + emit_changed(); + } +} + +void OpenXRInteractionProfile::remove_binding_modifier(Ref p_binding_modifier) { + int idx = binding_modifiers.find(p_binding_modifier); + if (idx != -1) { + binding_modifiers.remove_at(idx); + + ERR_FAIL_COND_MSG(p_binding_modifier->interaction_profile != this, "Removing binding modifier that belongs to this interaction profile but had incorrect interaction profile pointer."); // this should never happen! + p_binding_modifier->interaction_profile = nullptr; + + emit_changed(); + } +} + OpenXRInteractionProfile::~OpenXRInteractionProfile() { bindings.clear(); + clear_binding_modifiers(); } diff --git a/modules/openxr/action_map/openxr_interaction_profile.h b/modules/openxr/action_map/openxr_interaction_profile.h index 952f87a09d06..832bbc455b1a 100644 --- a/modules/openxr/action_map/openxr_interaction_profile.h +++ b/modules/openxr/action_map/openxr_interaction_profile.h @@ -32,29 +32,48 @@ #define OPENXR_INTERACTION_PROFILE_H #include "openxr_action.h" +#include "openxr_binding_modifier.h" #include "openxr_interaction_profile_metadata.h" #include "core/io/resource.h" +class OpenXRActionMap; + class OpenXRIPBinding : public Resource { GDCLASS(OpenXRIPBinding, Resource); private: Ref action; String binding_path; + Vector> binding_modifiers; protected: + friend class OpenXRActionMap; + + OpenXRActionMap *action_map = nullptr; + static void _bind_methods(); public: static Ref new_binding(const Ref p_action, const String &p_binding_path); // Helper function for adding a new binding. + OpenXRActionMap *get_action_map() { return action_map; } // Return the action map we're a part of. + void set_action(const Ref p_action); // Set the action for this binding. Ref get_action() const; // Get the action for this binding. void set_binding_path(const String &path); String get_binding_path() const; + int get_binding_modifier_count() const; // Retrieve the number of binding modifiers in this profile path + Ref get_binding_modifier(int p_index) const; + void clear_binding_modifiers(); // Remove all binding modifiers + void set_binding_modifiers(Array p_bindings); // Set the binding modifiers (for loading from a resource) + Array get_binding_modifiers() const; // Get the binding modifiers (for saving to a resource) + + void add_binding_modifier(Ref p_binding_modifier); // Add a binding modifier object + void remove_binding_modifier(Ref p_binding_modifier); // Remove a binding modifier object + // Deprecated. #ifndef DISABLE_DEPRECATED void set_paths(const PackedStringArray p_paths); // Set our paths (for loading from resource), needed for loading old action maps. @@ -76,13 +95,20 @@ class OpenXRInteractionProfile : public Resource { private: String interaction_profile_path; Array bindings; + Vector> binding_modifiers; protected: + friend class OpenXRActionMap; + + OpenXRActionMap *action_map = nullptr; + static void _bind_methods(); public: static Ref new_profile(const char *p_input_profile_path); // Helper function to create a new interaction profile + OpenXRActionMap *get_action_map() { return action_map; } + void set_interaction_profile_path(const String p_input_profile_path); // Set our input profile path String get_interaction_profile_path() const; // get our input profile path @@ -100,6 +126,15 @@ class OpenXRInteractionProfile : public Resource { void remove_binding_for_action(const Ref p_action); // Remove all bindings for this action bool has_binding_for_action(const Ref p_action); // Returns true if we have a binding for this action + int get_binding_modifier_count() const; // Retrieve the number of binding modifiers in this profile path + Ref get_binding_modifier(int p_index) const; + void clear_binding_modifiers(); // Remove all binding modifiers + void set_binding_modifiers(Array p_bindings); // Set the binding modifiers (for loading from a resource) + Array get_binding_modifiers() const; // Get the binding modifiers (for saving to a resource) + + void add_binding_modifier(Ref p_binding_modifier); // Add a binding modifier object + void remove_binding_modifier(Ref p_binding_modifier); // Remove a binding modifier object + ~OpenXRInteractionProfile(); }; diff --git a/modules/openxr/action_map/openxr_interaction_profile_metadata.cpp b/modules/openxr/action_map/openxr_interaction_profile_metadata.cpp index 6315c95a03d7..8cddaee666a1 100644 --- a/modules/openxr/action_map/openxr_interaction_profile_metadata.cpp +++ b/modules/openxr/action_map/openxr_interaction_profile_metadata.cpp @@ -225,179 +225,164 @@ void OpenXRInteractionProfileMetadata::_register_core_metadata() { register_top_level_path("Gamepad", "/user/gamepad", ""); register_top_level_path("Treadmill", "/user/treadmill", ""); - // Fallback Khronos simple controller - register_interaction_profile("Simple controller", "/interaction_profiles/khr/simple_controller", ""); - register_io_path("/interaction_profiles/khr/simple_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/khr/simple_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/khr/simple_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/khr/simple_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/khr/simple_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/khr/simple_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - - register_io_path("/interaction_profiles/khr/simple_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/khr/simple_controller", "Menu click", "/user/hand/right", "/user/hand/right/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/khr/simple_controller", "Select click", "/user/hand/left", "/user/hand/left/input/select/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/khr/simple_controller", "Select click", "/user/hand/right", "/user/hand/right/input/select/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/khr/simple_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - register_io_path("/interaction_profiles/khr/simple_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - - // Original HTC Vive wands - register_interaction_profile("HTC Vive wand", "/interaction_profiles/htc/vive_controller", ""); - register_io_path("/interaction_profiles/htc/vive_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/htc/vive_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/htc/vive_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/htc/vive_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/htc/vive_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/htc/vive_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - - register_io_path("/interaction_profiles/htc/vive_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_controller", "Menu click", "/user/hand/right", "/user/hand/right/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_controller", "System click", "/user/hand/left", "/user/hand/left/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_controller", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/htc/vive_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/htc/vive_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/htc/vive_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/htc/vive_controller", "Squeeze click", "/user/hand/left", "/user/hand/left/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_controller", "Squeeze click", "/user/hand/right", "/user/hand/right/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/htc/vive_controller", "Trackpad", "/user/hand/left", "/user/hand/left/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/htc/vive_controller", "Trackpad click", "/user/hand/left", "/user/hand/left/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_controller", "Trackpad touch", "/user/hand/left", "/user/hand/left/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_controller", "Trackpad", "/user/hand/right", "/user/hand/right/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/htc/vive_controller", "Trackpad click", "/user/hand/right", "/user/hand/right/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_controller", "Trackpad touch", "/user/hand/right", "/user/hand/right/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/htc/vive_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - register_io_path("/interaction_profiles/htc/vive_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - - // Microsoft motion controller (original WMR controllers) - register_interaction_profile("MS Motion controller", "/interaction_profiles/microsoft/motion_controller", ""); - register_io_path("/interaction_profiles/microsoft/motion_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/microsoft/motion_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/microsoft/motion_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/microsoft/motion_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/microsoft/motion_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/microsoft/motion_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - - register_io_path("/interaction_profiles/microsoft/motion_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/microsoft/motion_controller", "Menu click", "/user/hand/right", "/user/hand/right/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/microsoft/motion_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/microsoft/motion_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/microsoft/motion_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/microsoft/motion_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/microsoft/motion_controller", "Squeeze click", "/user/hand/left", "/user/hand/left/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/microsoft/motion_controller", "Squeeze click", "/user/hand/right", "/user/hand/right/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/microsoft/motion_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/microsoft/motion_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/microsoft/motion_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/microsoft/motion_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/microsoft/motion_controller", "Trackpad", "/user/hand/left", "/user/hand/left/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/microsoft/motion_controller", "Trackpad click", "/user/hand/left", "/user/hand/left/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/microsoft/motion_controller", "Trackpad touch", "/user/hand/left", "/user/hand/left/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/microsoft/motion_controller", "Trackpad", "/user/hand/right", "/user/hand/right/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/microsoft/motion_controller", "Trackpad click", "/user/hand/right", "/user/hand/right/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/microsoft/motion_controller", "Trackpad touch", "/user/hand/right", "/user/hand/right/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/microsoft/motion_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - register_io_path("/interaction_profiles/microsoft/motion_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - - // Meta touch controller (original touch controllers, Quest 1 and Quest 2 controllers) - register_interaction_profile("Touch controller", "/interaction_profiles/oculus/touch_controller", ""); - register_io_path("/interaction_profiles/oculus/touch_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/oculus/touch_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/oculus/touch_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/oculus/touch_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/oculus/touch_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/oculus/touch_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - - register_io_path("/interaction_profiles/oculus/touch_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/oculus/touch_controller", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/oculus/touch_controller", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/oculus/touch_controller", "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/oculus/touch_controller", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/oculus/touch_controller", "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/oculus/touch_controller", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/oculus/touch_controller", "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/oculus/touch_controller", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/oculus/touch_controller", "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/oculus/touch_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/oculus/touch_controller", "Trigger touch", "/user/hand/left", "/user/hand/left/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/oculus/touch_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/oculus/touch_controller", "Trigger touch", "/user/hand/right", "/user/hand/right/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/oculus/touch_controller", "Squeeze", "/user/hand/left", "/user/hand/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/oculus/touch_controller", "Squeeze", "/user/hand/right", "/user/hand/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - - register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbrest touch", "/user/hand/left", "/user/hand/left/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbrest touch", "/user/hand/right", "/user/hand/right/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/oculus/touch_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - register_io_path("/interaction_profiles/oculus/touch_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - - // Valve Index controller - register_interaction_profile("Index controller", "/interaction_profiles/valve/index_controller", ""); - register_io_path("/interaction_profiles/valve/index_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/valve/index_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/valve/index_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/valve/index_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/valve/index_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/valve/index_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - - register_io_path("/interaction_profiles/valve/index_controller", "System click", "/user/hand/left", "/user/hand/left/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/valve/index_controller", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/valve/index_controller", "A click", "/user/hand/left", "/user/hand/left/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/valve/index_controller", "A touch", "/user/hand/left", "/user/hand/left/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/valve/index_controller", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/valve/index_controller", "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/valve/index_controller", "B click", "/user/hand/left", "/user/hand/left/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/valve/index_controller", "B touch", "/user/hand/left", "/user/hand/left/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/valve/index_controller", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/valve/index_controller", "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/valve/index_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/valve/index_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/valve/index_controller", "Trigger touch", "/user/hand/left", "/user/hand/left/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/valve/index_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/valve/index_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/valve/index_controller", "Trigger touch", "/user/hand/right", "/user/hand/right/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/valve/index_controller", "Squeeze", "/user/hand/left", "/user/hand/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/valve/index_controller", "Squeeze force", "/user/hand/left", "/user/hand/left/input/squeeze/force", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/valve/index_controller", "Squeeze", "/user/hand/right", "/user/hand/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/valve/index_controller", "Squeeze force", "/user/hand/right", "/user/hand/right/input/squeeze/force", "", OpenXRAction::OPENXR_ACTION_FLOAT); - - register_io_path("/interaction_profiles/valve/index_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/valve/index_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/valve/index_controller", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/valve/index_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/valve/index_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/valve/index_controller", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/valve/index_controller", "Trackpad", "/user/hand/left", "/user/hand/left/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/valve/index_controller", "Trackpad force", "/user/hand/left", "/user/hand/left/input/trackpad/force", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/valve/index_controller", "Trackpad touch", "/user/hand/left", "/user/hand/left/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/valve/index_controller", "Trackpad", "/user/hand/right", "/user/hand/right/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/valve/index_controller", "Trackpad force", "/user/hand/right", "/user/hand/right/input/trackpad/force", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/valve/index_controller", "Trackpad touch", "/user/hand/right", "/user/hand/right/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/valve/index_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - register_io_path("/interaction_profiles/valve/index_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + { // Fallback Khronos simple controller + const String profile_path = "/interaction_profiles/khr/simple_controller"; + register_interaction_profile("Simple controller", profile_path, ""); + for (const String user_path : { "/user/hand/left", "/user/hand/right" }) { + register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + + register_io_path(profile_path, "Menu click", user_path, user_path + "/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Select click", user_path, user_path + "/input/select/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + } + } + + { // Original HTC Vive wands + const String profile_path = "/interaction_profiles/htc/vive_controller"; + register_interaction_profile("HTC Vive wand", profile_path, ""); + for (const String user_path : { "/user/hand/left", "/user/hand/right" }) { + register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + + register_io_path(profile_path, "Menu click", user_path, user_path + "/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "System click", user_path, user_path + "/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + register_io_path(profile_path, "Trigger click", user_path, user_path + "/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + register_io_path(profile_path, "Squeeze click", user_path, user_path + "/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + register_io_path(profile_path, "Trackpad", user_path, user_path + "/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + register_io_path(profile_path, "Trackpad click", user_path, user_path + "/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Trackpad touch", user_path, user_path + "/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Trackpad Dpad Up", user_path, user_path + "/input/trackpad/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Trackpad Dpad Down", user_path, user_path + "/input/trackpad/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Trackpad Dpad Left", user_path, user_path + "/input/trackpad/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Trackpad Dpad Right", user_path, user_path + "/input/trackpad/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Trackpad Dpad Center", user_path, user_path + "/input/trackpad/dpad_center", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + + register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + } + } + + { // Microsoft motion controller (original WMR controllers) + const String profile_path = "/interaction_profiles/microsoft/motion_controller"; + register_interaction_profile("MS Motion controller", profile_path, ""); + for (const String user_path : { "/user/hand/left", "/user/hand/right" }) { + register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + + register_io_path(profile_path, "Menu click", user_path, user_path + "/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + register_io_path(profile_path, "Trigger click", user_path, user_path + "/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + register_io_path(profile_path, "Squeeze click", user_path, user_path + "/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + + register_io_path(profile_path, "Trackpad", user_path, user_path + "/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + register_io_path(profile_path, "Trackpad click", user_path, user_path + "/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Trackpad touch", user_path, user_path + "/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Trackpad Dpad Up", user_path, user_path + "/input/trackpad/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Trackpad Dpad Down", user_path, user_path + "/input/trackpad/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Trackpad Dpad Left", user_path, user_path + "/input/trackpad/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Trackpad Dpad Right", user_path, user_path + "/input/trackpad/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Trackpad Dpad Center", user_path, user_path + "/input/trackpad/dpad_center", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + + register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + } + } + + { // Meta touch controller (original touch controllers, Quest 1 and Quest 2 controllers) + const String profile_path = "/interaction_profiles/oculus/touch_controller"; + register_interaction_profile("Touch controller", profile_path, ""); + for (const String user_path : { "/user/hand/left", "/user/hand/right" }) { + register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + + register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + register_io_path(profile_path, "Trigger touch", user_path, user_path + "/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + + register_io_path(profile_path, "Squeeze", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + + register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Thumbstick touch", user_path, user_path + "/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + + register_io_path(profile_path, "Thumbrest touch", user_path, user_path + "/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + + register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + } + + register_io_path(profile_path, "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + register_io_path(profile_path, "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + } + + { // Valve Index controller + const String profile_path = "/interaction_profiles/valve/index_controller"; + register_interaction_profile("Index controller", profile_path, ""); + for (const String user_path : { "/user/hand/left", "/user/hand/right" }) { + register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + + register_io_path(profile_path, "System click", user_path, user_path + "/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + register_io_path(profile_path, "A click", user_path, user_path + "/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "A touch", user_path, user_path + "/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "B click", user_path, user_path + "/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "B touch", user_path, user_path + "/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + + register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + register_io_path(profile_path, "Trigger click", user_path, user_path + "/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Trigger touch", user_path, user_path + "/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + + register_io_path(profile_path, "Squeeze", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + register_io_path(profile_path, "Squeeze force", user_path, user_path + "/input/squeeze/force", "", OpenXRAction::OPENXR_ACTION_FLOAT); + + register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Thumbstick touch", user_path, user_path + "/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + + register_io_path(profile_path, "Trackpad", user_path, user_path + "/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + register_io_path(profile_path, "Trackpad force", user_path, user_path + "/input/trackpad/force", "", OpenXRAction::OPENXR_ACTION_FLOAT); + register_io_path(profile_path, "Trackpad touch", user_path, user_path + "/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Trackpad Dpad Up", user_path, user_path + "/input/trackpad/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Trackpad Dpad Down", user_path, user_path + "/input/trackpad/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Trackpad Dpad Left", user_path, user_path + "/input/trackpad/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Trackpad Dpad Right", user_path, user_path + "/input/trackpad/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path(profile_path, "Trackpad Dpad Center", user_path, user_path + "/input/trackpad/dpad_center", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + + register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + } + } } diff --git a/modules/openxr/config.py b/modules/openxr/config.py index 559aa2acf69c..ee84457b7523 100644 --- a/modules/openxr/config.py +++ b/modules/openxr/config.py @@ -27,6 +27,14 @@ def get_doc_classes(): "OpenXRCompositionLayerQuad", "OpenXRCompositionLayerCylinder", "OpenXRCompositionLayerEquirect", + "OpenXRBindingModifier", + "OpenXRAnalogThresholdModifier", + "OpenXRDpadBindingModifier", + "OpenXRInteractionProfileEditorBase", + "OpenXRInteractionProfileEditor", + "OpenXRBindingModifierEditor", + "OpenXRHapticBase", + "OpenXRHapticVibration", ] diff --git a/modules/openxr/doc_classes/OpenXRAnalogThresholdModifier.xml b/modules/openxr/doc_classes/OpenXRAnalogThresholdModifier.xml new file mode 100644 index 000000000000..577b91d6ad77 --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRAnalogThresholdModifier.xml @@ -0,0 +1,26 @@ + + + + The analog threshold binding modifier can modify a float input to a boolean input with specified thresholds. + + + The analog threshold binding modifier can modify a float input to a boolean input with specified thresholds. + See [url=https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#XR_VALVE_analog_threshold]XR_VALVE_analog_threshold[/url] for indepth details. + + + + + + Haptic pulse to emit when the user releases the input. + + + When our input value falls below this, our output becomes false. + + + Haptic pulse to emit when the user presses the input. + + + When our input value is equal or larger than this value, our output becomes true. It stays true until it falls under the [member off_threshold] value. + + + diff --git a/modules/openxr/doc_classes/OpenXRBindingModifier.xml b/modules/openxr/doc_classes/OpenXRBindingModifier.xml new file mode 100644 index 000000000000..12af05ed9d74 --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRBindingModifier.xml @@ -0,0 +1,11 @@ + + + + Binding modifier base class. + + + Binding modifier base class. Subclasses implement various modifiers that alter how an OpenXR runtime processes inputs. + + + + diff --git a/modules/openxr/doc_classes/OpenXRBindingModifierEditor.xml b/modules/openxr/doc_classes/OpenXRBindingModifierEditor.xml new file mode 100644 index 000000000000..706688a5ad7d --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRBindingModifierEditor.xml @@ -0,0 +1,38 @@ + + + + Binding modifier editor. + + + This is the default binding modifier editor used in the OpenXR action map. + + + + + + + + Returns the [OpenXRBindingModifier] currently being edited. + + + + + + + + Setup this editor for the provided [param action_map] and [param binding_modifier]. + + + + + + + + + + + Signal emitted when the user presses the delete binding modifier button for this modifier. + + + + diff --git a/modules/openxr/doc_classes/OpenXRDpadBindingModifier.xml b/modules/openxr/doc_classes/OpenXRDpadBindingModifier.xml new file mode 100644 index 000000000000..63fa2ac517d4 --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRDpadBindingModifier.xml @@ -0,0 +1,43 @@ + + + + The DPad binding modifier converts an axis input to a dpad output. + + + The DPad binding modifier converts an axis input to a dpad output, emulating a DPad. New input paths for each dpad direction will be added to the interaction profile. When bound to actions the DPad emulation will be activated. You should [b]not[/b] combine dpad inputs with normal inputs in the same action set for the same control, this will result in an error being returned when suggested bindings are submitted to OpenXR. + See [url=https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#XR_EXT_dpad_binding]XR_EXT_dpad_binding[/url] for indepth details. + [b]Note:[/b] If the DPad binding modifier extension is enabled, all dpad binding paths will be available in the action map. Adding the modifier to an interaction profile allows you to further customize the behavior. + + + + + + Action set for which this dpad binding modifier is active. + + + Center region in which our center position of our dpad return [code]true[/code]. + + + Input path for this dpad binding modifier. + + + If [code]false[/code], when the joystick enters a new dpad zone this becomes true. + If [code]true[/code], when the joystick remains in active dpad zone, this remains true even if we overlap with another zone. + + + Haptic pulse to emit when the user releases the input. + + + Haptic pulse to emit when the user presses the input. + + + When our input value is equal or larger than this value, our dpad in that direction becomes true. It stays true until it falls under the [member threshold_released] value. + + + When our input value falls below this, our output becomes false. + + + The angle of each wedge that identifies the 4 directions of the emulated dpad. + + + diff --git a/modules/openxr/doc_classes/OpenXRHapticBase.xml b/modules/openxr/doc_classes/OpenXRHapticBase.xml new file mode 100644 index 000000000000..c23d86587ca9 --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRHapticBase.xml @@ -0,0 +1,11 @@ + + + + OpenXR Haptic feedback base class. + + + This is a base class for haptic feedback resources. + + + + diff --git a/modules/openxr/doc_classes/OpenXRHapticVibration.xml b/modules/openxr/doc_classes/OpenXRHapticVibration.xml new file mode 100644 index 000000000000..f147abb1021f --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRHapticVibration.xml @@ -0,0 +1,22 @@ + + + + Vibration haptic feedback. + + + This haptic feedback resource makes it possible to define a vibration based haptic feedback pulse that can be triggered through actions in the OpenXR action map. + + + + + + The amplitude of the pulse between [code]0.0[/code] and [code]1.0[/code]. + + + The duration of the pulse in nanoseconds. Use [code]-1[/code] for a minimum duration pulse for the current XR runtime. + + + The frequency of the pulse in Hz. [code]0.0[/code] will let the XR runtime chose an optimal frequency for the device used. + + + diff --git a/modules/openxr/doc_classes/OpenXRIPBinding.xml b/modules/openxr/doc_classes/OpenXRIPBinding.xml index 5bcade2589b1..f293a14bac19 100644 --- a/modules/openxr/doc_classes/OpenXRIPBinding.xml +++ b/modules/openxr/doc_classes/OpenXRIPBinding.xml @@ -16,6 +16,19 @@ Add an input/output path to this binding. + + + + + Get the [OpenXRBindingModifier] at this index. + + + + + + Get the number of binding modifiers for this binding. + + @@ -41,6 +54,9 @@ [OpenXRAction] that is bound to [member binding_path]. + + Binding modifiers for this binding. + Binding path that defines the input or output bound to [member action]. [b]Node:[/b] Binding paths are suggestions, an XR runtime may choose to bind the action to a different input or output emulating this input or output. diff --git a/modules/openxr/doc_classes/OpenXRInteractionProfile.xml b/modules/openxr/doc_classes/OpenXRInteractionProfile.xml index ed5113f83c9d..f6fddd0b69e7 100644 --- a/modules/openxr/doc_classes/OpenXRInteractionProfile.xml +++ b/modules/openxr/doc_classes/OpenXRInteractionProfile.xml @@ -23,8 +23,24 @@ Get the number of bindings in this interaction profile. + + + + + Get the [OpenXRBindingModifier] at this index. + + + + + + Get the number of binding modifiers in this interaction profile. + + + + Binding modifiers for this interaction profile. + Action bindings for this interaction profile. diff --git a/modules/openxr/doc_classes/OpenXRInteractionProfileEditor.xml b/modules/openxr/doc_classes/OpenXRInteractionProfileEditor.xml new file mode 100644 index 000000000000..0155d74bc814 --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRInteractionProfileEditor.xml @@ -0,0 +1,11 @@ + + + + Default OpenXR interaction profile editor. + + + This is the default OpenXR interaction profile editor that provides a generic interface for editing any interaction profile for which no custom editor has been defined. + + + + diff --git a/modules/openxr/doc_classes/OpenXRInteractionProfileEditorBase.xml b/modules/openxr/doc_classes/OpenXRInteractionProfileEditorBase.xml new file mode 100644 index 000000000000..49298c68b847 --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRInteractionProfileEditorBase.xml @@ -0,0 +1,25 @@ + + + + Base class for editing interaction profiles. + + + This is a base class for interaction profile editors used by the OpenXR action map editor. It can be used to create bespoke editors for specific interaction profiles. + + + + + + + + + + Setup this editor for the provided [param action_map] and [param interaction_profile]. + + + + + + + + diff --git a/modules/openxr/editor/SCsub b/modules/openxr/editor/SCsub index 39eb469978ed..d659be1d99bd 100644 --- a/modules/openxr/editor/SCsub +++ b/modules/openxr/editor/SCsub @@ -2,5 +2,10 @@ from misc.utility.scons_hints import * Import("env") +Import("env_openxr") -env.add_source_files(env.modules_sources, "*.cpp") +module_obj = [] + +env_openxr.add_source_files(module_obj, "*.cpp") + +env.modules_sources += module_obj diff --git a/modules/openxr/editor/openxr_action_map_editor.cpp b/modules/openxr/editor/openxr_action_map_editor.cpp index a353073f215b..96b2f6d806e1 100644 --- a/modules/openxr/editor/openxr_action_map_editor.cpp +++ b/modules/openxr/editor/openxr_action_map_editor.cpp @@ -37,7 +37,8 @@ #include "editor/gui/editor_file_dialog.h" #include "editor/themes/editor_scale.h" -// TODO implement redo/undo system +HashMap OpenXRActionMapEditor::interaction_profile_editors; +HashMap OpenXRActionMapEditor::binding_modifier_editors; void OpenXRActionMapEditor::_bind_methods() { ClassDB::bind_method("_add_action_set_editor", &OpenXRActionMapEditor::_add_action_set_editor); @@ -50,6 +51,9 @@ void OpenXRActionMapEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_do_remove_action_set_editor", "action_set_editor"), &OpenXRActionMapEditor::_do_remove_action_set_editor); ClassDB::bind_method(D_METHOD("_do_add_interaction_profile_editor", "interaction_profile_editor"), &OpenXRActionMapEditor::_do_add_interaction_profile_editor); ClassDB::bind_method(D_METHOD("_do_remove_interaction_profile_editor", "interaction_profile_editor"), &OpenXRActionMapEditor::_do_remove_interaction_profile_editor); + + ClassDB::bind_static_method("OpenXRActionMapEditor", D_METHOD("register_interaction_profile_editor", "interaction_profile_path", "editor_class"), &OpenXRActionMapEditor::register_interaction_profile_editor); + ClassDB::bind_static_method("OpenXRActionMapEditor", D_METHOD("register_binding_modifier_editor", "binding_modifier_class", "editor_class"), &OpenXRActionMapEditor::register_binding_modifier_editor); } void OpenXRActionMapEditor::_notification(int p_what) { @@ -100,19 +104,32 @@ OpenXRInteractionProfileEditorBase *OpenXRActionMapEditor::_add_interaction_prof // need to instance the correct editor for our profile OpenXRInteractionProfileEditorBase *new_profile_editor = nullptr; - if (profile_path == "placeholder_text") { - // instance specific editor for this type - } else { + if (interaction_profile_editors.has(profile_path)) { + Object *new_editor = ClassDB::instantiate(interaction_profile_editors[profile_path]); + if (new_editor) { + new_profile_editor = Object::cast_to(new_editor); + if (!new_profile_editor) { + WARN_PRINT("Interaction profile editor type mismatch for " + profile_path); + memfree(new_editor); + } + } + } + if (!new_profile_editor) { // instance generic editor - new_profile_editor = memnew(OpenXRInteractionProfileEditor(action_map, p_interaction_profile)); + new_profile_editor = memnew(OpenXRInteractionProfileEditor); } // now add it in.. ERR_FAIL_NULL_V(new_profile_editor, nullptr); + new_profile_editor->setup(action_map, p_interaction_profile); tabs->add_child(new_profile_editor); new_profile_editor->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree"))); tabs->set_tab_button_icon(tabs->get_tab_count() - 1, get_theme_icon(SNAME("close"), SNAME("TabBar"))); + if (!new_profile_editor->tooltip.is_empty()) { + tabs->set_tab_tooltip(tabs->get_tab_count() - 1, new_profile_editor->tooltip); + } + return new_profile_editor; } @@ -195,8 +212,19 @@ void OpenXRActionMapEditor::_on_remove_action_set(Object *p_action_set_editor) { Ref action_set = action_set_editor->get_action_set(); ERR_FAIL_COND(action_set.is_null()); + // Remove all actions first. action_set_editor->remove_all_actions(); + // Make sure we update our interaction profiles. + for (int i = 0; i < tabs->get_tab_count(); i++) { + // First tab won't be an interaction profile editor, but being thorough.. + OpenXRInteractionProfileEditorBase *interaction_profile_editor = Object::cast_to(tabs->get_tab_control(i)); + if (interaction_profile_editor) { + interaction_profile_editor->remove_all_for_action_set(action_set); + } + } + + // And now we can remove our action set. undo_redo->create_action(TTR("Remove action set")); undo_redo->add_do_method(this, "_do_remove_action_set_editor", action_set_editor); undo_redo->add_undo_method(this, "_do_add_action_set_editor", action_set_editor); @@ -210,7 +238,7 @@ void OpenXRActionMapEditor::_on_action_removed(Ref p_action) { // First tab won't be an interaction profile editor, but being thorough.. OpenXRInteractionProfileEditorBase *interaction_profile_editor = Object::cast_to(tabs->get_tab_control(i)); if (interaction_profile_editor) { - interaction_profile_editor->remove_all_bindings_for_action(p_action); + interaction_profile_editor->remove_all_for_action(p_action); } } } @@ -387,6 +415,22 @@ void OpenXRActionMapEditor::_clear_action_map() { } } +void OpenXRActionMapEditor::register_interaction_profile_editor(const String &p_for_path, const String &p_editor_class) { + interaction_profile_editors[p_for_path] = p_editor_class; +} + +void OpenXRActionMapEditor::register_binding_modifier_editor(const String &p_binding_modifier_class, const String &p_editor_class) { + binding_modifier_editors[p_binding_modifier_class] = p_editor_class; +} + +String OpenXRActionMapEditor::get_binding_modifier_editor_class(const String &p_binding_modifier_class) { + if (binding_modifier_editors.has(p_binding_modifier_class)) { + return binding_modifier_editors[p_binding_modifier_class]; + } + + return "OpenXRBindingModifierEditor"; +} + OpenXRActionMapEditor::OpenXRActionMapEditor() { undo_redo = EditorUndoRedoManager::get_singleton(); set_custom_minimum_size(Size2(0.0, 300.0)); diff --git a/modules/openxr/editor/openxr_action_map_editor.h b/modules/openxr/editor/openxr_action_map_editor.h index cfe5fed0955e..088bf0c613d0 100644 --- a/modules/openxr/editor/openxr_action_map_editor.h +++ b/modules/openxr/editor/openxr_action_map_editor.h @@ -36,6 +36,7 @@ #include "openxr_interaction_profile_editor.h" #include "openxr_select_interaction_profile_dialog.h" +#include "core/templates/hash_map.h" #include "editor/editor_undo_redo_manager.h" #include "editor/plugins/editor_plugin.h" #include "scene/gui/box_container.h" @@ -48,6 +49,9 @@ class OpenXRActionMapEditor : public VBoxContainer { GDCLASS(OpenXRActionMapEditor, VBoxContainer); private: + static HashMap interaction_profile_editors; // interaction profile path, interaction profile editor + static HashMap binding_modifier_editors; // binding modifier class, binding modifiers editor + EditorUndoRedoManager *undo_redo; String edited_path; Ref action_map; @@ -100,6 +104,10 @@ class OpenXRActionMapEditor : public VBoxContainer { void _do_remove_interaction_profile_editor(OpenXRInteractionProfileEditorBase *p_interaction_profile_editor); public: + static void register_interaction_profile_editor(const String &p_for_path, const String &p_editor_class); + static void register_binding_modifier_editor(const String &p_binding_modifier_class, const String &p_editor_class); + static String get_binding_modifier_editor_class(const String &p_binding_modifier_class); + void open_action_map(String p_path); OpenXRActionMapEditor(); diff --git a/modules/openxr/editor/openxr_binding_modifier_editor.cpp b/modules/openxr/editor/openxr_binding_modifier_editor.cpp new file mode 100644 index 000000000000..e46516189158 --- /dev/null +++ b/modules/openxr/editor/openxr_binding_modifier_editor.cpp @@ -0,0 +1,279 @@ +/**************************************************************************/ +/* openxr_binding_modifier_editor.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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_binding_modifier_editor.h" + +#include "editor/editor_string_names.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// EditorPropertyActionSet + +void EditorPropertyActionSet::_set_read_only(bool p_read_only) { + options->set_disabled(p_read_only); +} + +void EditorPropertyActionSet::_option_selected(int p_which) { + Ref val = options->get_item_metadata(p_which); + emit_changed(get_edited_property(), val); +} + +void EditorPropertyActionSet::update_property() { + Variant current = get_edited_property_value(); + if (current.get_type() == Variant::NIL) { + options->select(-1); + return; + } + + Ref which = current; + for (int i = 0; i < options->get_item_count(); i++) { + if (which == (Ref)options->get_item_metadata(i)) { + options->select(i); + return; + } + } + + // Couldn't find it? deselect.. + options->select(-1); +} + +void EditorPropertyActionSet::setup(const Ref &p_action_map) { + options->clear(); + + Array action_sets = p_action_map->get_action_sets(); + for (Ref action_set : action_sets) { + options->add_item(action_set->get_localized_name()); + options->set_item_metadata(-1, action_set); + } +} + +void EditorPropertyActionSet::set_option_button_clip(bool p_enable) { + options->set_clip_text(p_enable); +} + +EditorPropertyActionSet::EditorPropertyActionSet() { + options = memnew(OptionButton); + options->set_clip_text(true); + options->set_flat(true); + options->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); + add_child(options); + add_focusable(options); + options->connect(SceneStringName(item_selected), callable_mp(this, &EditorPropertyActionSet::_option_selected)); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// EditorPropertyBindingPath + +void EditorPropertyBindingPath::_set_read_only(bool p_read_only) { + options->set_disabled(p_read_only); +} + +void EditorPropertyBindingPath::_option_selected(int p_which) { + String val = options->get_item_metadata(p_which); + emit_changed(get_edited_property(), val); +} + +void EditorPropertyBindingPath::update_property() { + Variant current = get_edited_property_value(); + if (current.get_type() == Variant::NIL) { + options->select(-1); + return; + } + + String which = current; + for (int i = 0; i < options->get_item_count(); i++) { + if (which == (String)options->get_item_metadata(i)) { + options->select(i); + return; + } + } + + // Couldn't find it? deselect.. + options->select(-1); +} + +void EditorPropertyBindingPath::setup(const String &p_interaction_profile_path, Vector p_include_action_types) { + options->clear(); + + const OpenXRInteractionProfileMetadata::InteractionProfile *profile_def = OpenXRInteractionProfileMetadata::get_singleton()->get_profile(p_interaction_profile_path); + + // Determine toplevel paths + Vector top_level_paths; + for (const OpenXRInteractionProfileMetadata::IOPath &io_path : profile_def->io_paths) { + if (!top_level_paths.has(io_path.top_level_path)) { + top_level_paths.push_back(io_path.top_level_path); + } + } + + for (const String &top_level_path : top_level_paths) { + String top_level_name = OpenXRInteractionProfileMetadata::get_singleton()->get_top_level_name(top_level_path); + + for (const OpenXRInteractionProfileMetadata::IOPath &io_path : profile_def->io_paths) { + if (io_path.top_level_path == top_level_path && p_include_action_types.has(io_path.action_type)) { + options->add_item(top_level_name + "/" + io_path.display_name); + options->set_item_metadata(-1, io_path.openxr_path); + } + } + } +} + +void EditorPropertyBindingPath::set_option_button_clip(bool p_enable) { + options->set_clip_text(p_enable); +} + +EditorPropertyBindingPath::EditorPropertyBindingPath() { + options = memnew(OptionButton); + options->set_clip_text(true); + options->set_flat(true); + options->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); + add_child(options); + add_focusable(options); + options->connect(SceneStringName(item_selected), callable_mp(this, &EditorPropertyBindingPath::_option_selected)); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// OpenXRBindingModifierEditor + +bool EditorInspectorPluginBindingModifier::can_handle(Object *p_object) { + Ref binding_modifier(Object::cast_to(p_object)); + return binding_modifier.is_valid(); +} + +bool EditorInspectorPluginBindingModifier::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField p_usage, const bool p_wide) { + Ref binding_modifier(Object::cast_to(p_object)); + ERR_FAIL_COND_V(binding_modifier.is_null(), false); + + if (p_type == Variant::OBJECT && p_hint == PROPERTY_HINT_RESOURCE_TYPE && p_hint_text == "OpenXRActionSet") { + OpenXRActionMap *action_map = nullptr; + + OpenXRInteractionProfile *interaction_profile = binding_modifier->get_interaction_profile(); + if (interaction_profile == nullptr) { + OpenXRIPBinding *ip_binding = binding_modifier->get_ip_binding(); + ERR_FAIL_NULL_V(ip_binding, false); + + action_map = ip_binding->get_action_map(); + } else { + action_map = interaction_profile->get_action_map(); + } + + ERR_FAIL_NULL_V(action_map, false); + + EditorPropertyActionSet *action_set_property = memnew(EditorPropertyActionSet); + action_set_property->setup(action_map); + add_property_editor(p_path, action_set_property); + return true; + } + + if (p_type == Variant::STRING && p_hint == PROPERTY_HINT_TYPE_STRING && p_hint_text == "binding_path") { + EditorPropertyBindingPath *binding_path_property = memnew(EditorPropertyBindingPath); + + OpenXRInteractionProfile *interaction_profile = binding_modifier->get_interaction_profile(); + if (interaction_profile) { + Vector action_types; + action_types.push_back(OpenXRAction::OPENXR_ACTION_VECTOR2); + binding_path_property->setup(interaction_profile->get_interaction_profile_path(), action_types); + } + + add_property_editor(p_path, binding_path_property); + return true; + } + + return false; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// OpenXRBindingModifierEditor + +void OpenXRBindingModifierEditor::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_binding_modifier"), &OpenXRBindingModifierEditor::get_binding_modifier); + ClassDB::bind_method(D_METHOD("setup", "action_map", "binding_modifier"), &OpenXRBindingModifierEditor::setup); + + ClassDB::bind_method("_on_remove_binding_modifier", &OpenXRBindingModifierEditor::_on_remove_binding_modifier); + + ADD_SIGNAL(MethodInfo("remove", PropertyInfo(Variant::OBJECT, "binding_modifier_editor"))); +} + +void OpenXRBindingModifierEditor::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: { + rem_binding_modifier_btn->set_icon(get_theme_icon(SNAME("Remove"), EditorStringName(EditorIcons))); + } break; + } +} + +void OpenXRBindingModifierEditor::_on_remove_binding_modifier() { + // Tell parent to remove us + emit_signal("remove", this); +} + +OpenXRBindingModifierEditor::OpenXRBindingModifierEditor() { + undo_redo = EditorUndoRedoManager::get_singleton(); + + set_h_size_flags(Control::SIZE_EXPAND_FILL); + + main_vb = memnew(VBoxContainer); + main_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + add_child(main_vb); + + header_hb = memnew(HBoxContainer); + header_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + main_vb->add_child(header_hb); + + binding_modifier_title = memnew(Label); + binding_modifier_title->set_h_size_flags(Control::SIZE_EXPAND_FILL); + header_hb->add_child(binding_modifier_title); + + rem_binding_modifier_btn = memnew(Button); + rem_binding_modifier_btn->set_tooltip_text(TTR("Remove binding modifier.")); + rem_binding_modifier_btn->connect(SceneStringName(pressed), callable_mp(this, &OpenXRBindingModifierEditor::_on_remove_binding_modifier)); + rem_binding_modifier_btn->set_flat(true); + header_hb->add_child(rem_binding_modifier_btn); + + editor_inspector = memnew(EditorInspector); + editor_inspector->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED); + editor_inspector->set_vertical_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED); + editor_inspector->set_h_size_flags(Control::SIZE_EXPAND_FILL); + main_vb->add_child(editor_inspector); +} + +void OpenXRBindingModifierEditor::setup(Ref p_action_map, Ref p_binding_modifier) { + ERR_FAIL_NULL(binding_modifier_title); + ERR_FAIL_NULL(editor_inspector); + + action_map = p_action_map; + binding_modifier = p_binding_modifier; + + if (p_binding_modifier.is_valid()) { + binding_modifier_title->set_text(p_binding_modifier->get_description()); + + editor_inspector->set_object_class(p_binding_modifier->get_class()); + editor_inspector->edit(p_binding_modifier.ptr()); + } +} diff --git a/modules/openxr/editor/openxr_binding_modifier_editor.h b/modules/openxr/editor/openxr_binding_modifier_editor.h new file mode 100644 index 000000000000..89f5610f7e85 --- /dev/null +++ b/modules/openxr/editor/openxr_binding_modifier_editor.h @@ -0,0 +1,114 @@ +/**************************************************************************/ +/* openxr_binding_modifier_editor.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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_BINDING_MODIFIER_EDITOR_H +#define OPENXR_BINDING_MODIFIER_EDITOR_H + +#include "../action_map/openxr_action_map.h" +#include "../action_map/openxr_action_set.h" +#include "../action_map/openxr_binding_modifier.h" +#include "editor/editor_inspector.h" +// #include "editor/editor_properties.h" +#include "editor/editor_undo_redo_manager.h" +#include "scene/gui/box_container.h" +#include "scene/gui/button.h" +#include "scene/gui/label.h" +#include "scene/gui/panel_container.h" + +class EditorPropertyActionSet : public EditorProperty { + GDCLASS(EditorPropertyActionSet, EditorProperty); + OptionButton *options = nullptr; + + void _option_selected(int p_which); + +protected: + virtual void _set_read_only(bool p_read_only) override; + +public: + void setup(const Ref &p_action_map); + virtual void update_property() override; + void set_option_button_clip(bool p_enable); + EditorPropertyActionSet(); +}; + +class EditorPropertyBindingPath : public EditorProperty { + GDCLASS(EditorPropertyBindingPath, EditorProperty); + OptionButton *options = nullptr; + + void _option_selected(int p_which); + +protected: + virtual void _set_read_only(bool p_read_only) override; + +public: + void setup(const String &p_interaction_profile_path, Vector p_include_action_types); + virtual void update_property() override; + void set_option_button_clip(bool p_enable); + EditorPropertyBindingPath(); +}; + +class EditorInspectorPluginBindingModifier : public EditorInspectorPlugin { + GDCLASS(EditorInspectorPluginBindingModifier, EditorInspectorPlugin); + +public: + virtual bool can_handle(Object *p_object) override; + virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField p_usage, const bool p_wide) override; +}; + +class OpenXRBindingModifierEditor : public PanelContainer { + GDCLASS(OpenXRBindingModifierEditor, PanelContainer); + +private: + HBoxContainer *header_hb = nullptr; + Label *binding_modifier_title = nullptr; + Button *rem_binding_modifier_btn = nullptr; + EditorInspector *editor_inspector = nullptr; + +protected: + VBoxContainer *main_vb = nullptr; + + EditorUndoRedoManager *undo_redo; + Ref binding_modifier; + Ref action_map; + + static void _bind_methods(); + void _notification(int p_what); + + void _on_remove_binding_modifier(); + +public: + Ref get_binding_modifier() const { return binding_modifier; } + + virtual void setup(Ref p_action_map, Ref p_binding_modifier); + + OpenXRBindingModifierEditor(); +}; + +#endif // OPENXR_BINDING_MODIFIER_EDITOR_H diff --git a/modules/openxr/editor/openxr_binding_modifiers_dialog.cpp b/modules/openxr/editor/openxr_binding_modifiers_dialog.cpp new file mode 100644 index 000000000000..f8af34a49b73 --- /dev/null +++ b/modules/openxr/editor/openxr_binding_modifiers_dialog.cpp @@ -0,0 +1,266 @@ +/**************************************************************************/ +/* openxr_binding_modifiers_dialog.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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_binding_modifiers_dialog.h" +#include "../action_map/openxr_interaction_profile_metadata.h" +#include "editor/editor_string_names.h" +#include "openxr_action_map_editor.h" + +void OpenXRBindingModifiersDialog::_bind_methods() { + ClassDB::bind_method(D_METHOD("_on_add_binding_modifier"), &OpenXRBindingModifiersDialog::_on_add_binding_modifier); + ClassDB::bind_method(D_METHOD("_on_dialog_created"), &OpenXRBindingModifiersDialog::_on_dialog_created); + + ClassDB::bind_method(D_METHOD("_do_add_binding_modifier_editor", "binding_modifier_editor"), &OpenXRBindingModifiersDialog::_do_add_binding_modifier_editor); + ClassDB::bind_method(D_METHOD("_do_remove_binding_modifier_editor", "binding_modifier_editor"), &OpenXRBindingModifiersDialog::_do_remove_binding_modifier_editor); +} + +void OpenXRBindingModifiersDialog::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_READY: { + _create_binding_modifiers(); + } break; + + case NOTIFICATION_THEME_CHANGED: { + if (binding_modifier_sc) { + binding_modifier_sc->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree"))); + } + } break; + } +} + +OpenXRBindingModifierEditor *OpenXRBindingModifiersDialog::_add_binding_modifier_editor(Ref p_binding_modifier) { + ERR_FAIL_COND_V(p_binding_modifier.is_null(), nullptr); + + String class_name = p_binding_modifier->get_class(); + ERR_FAIL_COND_V(class_name.is_empty(), nullptr); + String editor_class = OpenXRActionMapEditor::get_binding_modifier_editor_class(class_name); + ERR_FAIL_COND_V(editor_class.is_empty(), nullptr); + + OpenXRBindingModifierEditor *new_editor = nullptr; + + Object *obj = ClassDB::instantiate(editor_class); + if (obj) { + new_editor = Object::cast_to(obj); + if (!new_editor) { + // Not of correct type?? Free it. + memfree(obj); + } + } + ERR_FAIL_NULL_V(new_editor, nullptr); + + new_editor->setup(action_map, p_binding_modifier); + new_editor->connect("remove", callable_mp(this, &OpenXRBindingModifiersDialog::_on_remove_binding_modifier)); + + binding_modifiers_vb->add_child(new_editor); + new_editor->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree"))); + + return new_editor; +} + +void OpenXRBindingModifiersDialog::_create_binding_modifiers() { + Array new_binding_modifiers; + + if (ip_binding.is_valid()) { + new_binding_modifiers = ip_binding->get_binding_modifiers(); + } else if (interaction_profile.is_valid()) { + new_binding_modifiers = interaction_profile->get_binding_modifiers(); + } else { + ERR_FAIL_MSG("No binding nor interaction profile specified."); + } + + for (int i = 0; i < new_binding_modifiers.size(); i++) { + Ref binding_modifier = new_binding_modifiers[i]; + _add_binding_modifier_editor(binding_modifier); + } +} + +void OpenXRBindingModifiersDialog::_on_add_binding_modifier() { + create_dialog->popup_create(false); +} + +void OpenXRBindingModifiersDialog::_on_remove_binding_modifier(Object *p_binding_modifier_editor) { + if (ip_binding.is_valid()) { + ip_binding->set_edited(true); + } else if (interaction_profile.is_valid()) { + interaction_profile->set_edited(true); + } else { + ERR_FAIL_MSG("No binding nor interaction profile specified."); + } + + OpenXRBindingModifierEditor *binding_modifier_editor = Object::cast_to(p_binding_modifier_editor); + ERR_FAIL_NULL(binding_modifier_editor); + ERR_FAIL_COND(binding_modifier_editor->get_parent() != binding_modifiers_vb); + + undo_redo->create_action(TTR("Remove binding modifier")); + undo_redo->add_do_method(this, "_do_remove_binding_modifier_editor", binding_modifier_editor); + undo_redo->add_undo_method(this, "_do_add_binding_modifier_editor", binding_modifier_editor); + undo_redo->commit_action(true); +} + +void OpenXRBindingModifiersDialog::_on_dialog_created() { + // Instance new binding modifier object + Variant obj = create_dialog->instantiate_selected(); + ERR_FAIL_COND(obj.get_type() != Variant::OBJECT); + + Ref new_binding_modifier = obj; + ERR_FAIL_COND(new_binding_modifier.is_null()); + + if (ip_binding.is_valid()) { + // TODO these should be filtered out, and if we can't make this a nicer error... + ERR_FAIL_COND(!new_binding_modifier->record_on_binding()); + + // Add it to our binding. + ip_binding->add_binding_modifier(new_binding_modifier); + ip_binding->set_edited(true); + } else if (interaction_profile.is_valid()) { + // TODO these should be filtered out, and if we can't make this a nicer error... + ERR_FAIL_COND(new_binding_modifier->record_on_binding()); + + // Add it to our interaction profile. + interaction_profile->add_binding_modifier(new_binding_modifier); + interaction_profile->set_edited(true); + } else { + ERR_FAIL_MSG("No binding nor interaction profile specified."); + } + + // Create our editor for this. + OpenXRBindingModifierEditor *binding_modifier_editor = _add_binding_modifier_editor(new_binding_modifier); + ERR_FAIL_NULL(binding_modifier_editor); + + // Add undo/redo. + undo_redo->create_action(TTR("Add binding modifier")); + undo_redo->add_do_method(this, "_do_add_binding_modifier_editor", binding_modifier_editor); + undo_redo->add_undo_method(this, "_do_remove_binding_modifier_editor", binding_modifier_editor); + undo_redo->commit_action(false); +} + +void OpenXRBindingModifiersDialog::_do_add_binding_modifier_editor(OpenXRBindingModifierEditor *p_binding_modifier_editor) { + Ref binding_modifier = p_binding_modifier_editor->get_binding_modifier(); + ERR_FAIL_COND(binding_modifier.is_null()); + + if (ip_binding.is_valid()) { + // Add it to our binding + ip_binding->add_binding_modifier(binding_modifier); + } else if (interaction_profile.is_valid()) { + // Add it to our interaction profile + interaction_profile->add_binding_modifier(binding_modifier); + } else { + ERR_FAIL_MSG("No binding nor interaction profile specified."); + } + + binding_modifiers_vb->add_child(p_binding_modifier_editor); +} + +void OpenXRBindingModifiersDialog::_do_remove_binding_modifier_editor(OpenXRBindingModifierEditor *p_binding_modifier_editor) { + Ref binding_modifier = p_binding_modifier_editor->get_binding_modifier(); + ERR_FAIL_COND(binding_modifier.is_null()); + + if (ip_binding.is_valid()) { + // Remove it from our binding. + ip_binding->remove_binding_modifier(binding_modifier); + } else if (interaction_profile.is_valid()) { + // Removed it to from interaction profile. + interaction_profile->remove_binding_modifier(binding_modifier); + } else { + ERR_FAIL_MSG("No binding nor interaction profile specified."); + } + + binding_modifiers_vb->remove_child(p_binding_modifier_editor); +} + +OpenXRBindingModifiersDialog::OpenXRBindingModifiersDialog() { + undo_redo = EditorUndoRedoManager::get_singleton(); + + set_transient(true); + + binding_modifier_sc = memnew(ScrollContainer); + binding_modifier_sc->set_custom_minimum_size(Size2(350.0, 0.0)); + binding_modifier_sc->set_h_size_flags(Control::SIZE_EXPAND_FILL); + binding_modifier_sc->set_v_size_flags(Control::SIZE_EXPAND_FILL); + binding_modifier_sc->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED); + add_child(binding_modifier_sc); + + binding_modifiers_vb = memnew(VBoxContainer); + binding_modifiers_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + binding_modifier_sc->add_child(binding_modifiers_vb); + + binding_warning_label = memnew(Label); + binding_warning_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD); + binding_warning_label->set_text(TTR("Note: modifiers will only be applied if supported on the host system.")); + binding_modifiers_vb->add_child(binding_warning_label); + + add_binding_modifier_btn = memnew(Button); + add_binding_modifier_btn->set_text(TTR("Add binding modifier")); + add_binding_modifier_btn->connect("pressed", callable_mp(this, &OpenXRBindingModifiersDialog::_on_add_binding_modifier)); + binding_modifiers_vb->add_child(add_binding_modifier_btn); + + // TODO may need to create our own dialog for this that can filter on binding modifiers recorded on interaction profiles or on individual bindings. + + create_dialog = memnew(CreateDialog); + create_dialog->set_transient(true); + create_dialog->set_base_type("OpenXRBindingModifier"); + create_dialog->connect("create", callable_mp(this, &OpenXRBindingModifiersDialog::_on_dialog_created)); + add_child(create_dialog); +} + +void OpenXRBindingModifiersDialog::setup(Ref p_action_map, Ref p_interaction_profile, Ref p_ip_binding) { + OpenXRInteractionProfileMetadata *meta_data = OpenXRInteractionProfileMetadata::get_singleton(); + action_map = p_action_map; + interaction_profile = p_interaction_profile; + ip_binding = p_ip_binding; + + String profile_path = interaction_profile->get_interaction_profile_path(); + + if (ip_binding.is_valid()) { + String action_name = "unset"; + String path_name = "unset"; + + Ref action = p_ip_binding->get_action(); + if (action.is_valid()) { + action_name = action->get_name_with_set(); + } + + const OpenXRInteractionProfileMetadata::IOPath *io_path = meta_data->get_io_path(profile_path, p_ip_binding->get_binding_path()); + if (io_path != nullptr) { + path_name = io_path->display_name; + } + + set_title(TTR("Binding modifiers for:") + " " + action_name + ": " + path_name); + } else if (interaction_profile.is_valid()) { + String profile_name = profile_path; + + const OpenXRInteractionProfileMetadata::InteractionProfile *profile_def = meta_data->get_profile(profile_path); + if (profile_def != nullptr) { + profile_name = profile_def->display_name; + } + + set_title(TTR("Binding modifiers for:") + " " + profile_name); + } +} diff --git a/modules/openxr/editor/openxr_binding_modifiers_dialog.h b/modules/openxr/editor/openxr_binding_modifiers_dialog.h new file mode 100644 index 000000000000..c60a3760b38e --- /dev/null +++ b/modules/openxr/editor/openxr_binding_modifiers_dialog.h @@ -0,0 +1,81 @@ +/**************************************************************************/ +/* openxr_binding_modifiers_dialog.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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_BINDING_MODIFIERS_DIALOG_H +#define OPENXR_BINDING_MODIFIERS_DIALOG_H + +#include "../action_map/openxr_action_map.h" +#include "../action_map/openxr_interaction_profile.h" +#include "../editor/openxr_binding_modifier_editor.h" +#include "editor/create_dialog.h" +#include "editor/editor_undo_redo_manager.h" +#include "scene/gui/box_container.h" +#include "scene/gui/button.h" +#include "scene/gui/dialogs.h" +#include "scene/gui/label.h" +#include "scene/gui/scroll_container.h" + +class OpenXRBindingModifiersDialog : public AcceptDialog { + GDCLASS(OpenXRBindingModifiersDialog, AcceptDialog); + +private: + ScrollContainer *binding_modifier_sc = nullptr; + VBoxContainer *binding_modifiers_vb = nullptr; + Label *binding_warning_label = nullptr; + Button *add_binding_modifier_btn = nullptr; + CreateDialog *create_dialog = nullptr; + + OpenXRBindingModifierEditor *_add_binding_modifier_editor(Ref p_binding_modifier); + void _create_binding_modifiers(); + + void _on_add_binding_modifier(); + void _on_remove_binding_modifier(Object *p_binding_modifier_editor); + void _on_dialog_created(); + +protected: + EditorUndoRedoManager *undo_redo; + Ref action_map; + Ref interaction_profile; + Ref ip_binding; + + static void _bind_methods(); + void _notification(int p_what); + + // used for undo/redo + void _do_add_binding_modifier_editor(OpenXRBindingModifierEditor *p_binding_modifier_editor); + void _do_remove_binding_modifier_editor(OpenXRBindingModifierEditor *p_binding_modifier_editor); + +public: + OpenXRBindingModifiersDialog(); + + void setup(Ref p_action_map, Ref p_interaction_profile, Ref p_ip_binding = Ref()); +}; + +#endif // OPENXR_BINDING_MODIFIERS_DIALOG_H diff --git a/modules/openxr/editor/openxr_editor_plugin.cpp b/modules/openxr/editor/openxr_editor_plugin.cpp index f6b7f2dd0c30..ecd1d8451f65 100644 --- a/modules/openxr/editor/openxr_editor_plugin.cpp +++ b/modules/openxr/editor/openxr_editor_plugin.cpp @@ -56,6 +56,9 @@ OpenXREditorPlugin::OpenXREditorPlugin() { action_map_editor = memnew(OpenXRActionMapEditor); EditorNode::get_bottom_panel()->add_item(TTR("OpenXR Action Map"), action_map_editor, ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_openxr_action_map_bottom_panel", TTR("Toggle OpenXR Action Map Bottom Panel"))); + binding_modifier_inspector_plugin = Ref(memnew(EditorInspectorPluginBindingModifier)); + EditorInspector::add_inspector_plugin(binding_modifier_inspector_plugin); + #ifndef ANDROID_ENABLED select_runtime = memnew(OpenXRSelectRuntime); add_control_to_container(CONTAINER_TOOLBAR, select_runtime); diff --git a/modules/openxr/editor/openxr_editor_plugin.h b/modules/openxr/editor/openxr_editor_plugin.h index 672df0de28a6..18c82b24ac65 100644 --- a/modules/openxr/editor/openxr_editor_plugin.h +++ b/modules/openxr/editor/openxr_editor_plugin.h @@ -32,6 +32,7 @@ #define OPENXR_EDITOR_PLUGIN_H #include "openxr_action_map_editor.h" +#include "openxr_binding_modifier_editor.h" #include "openxr_select_runtime.h" #include "editor/plugins/editor_plugin.h" @@ -40,6 +41,7 @@ class OpenXREditorPlugin : public EditorPlugin { GDCLASS(OpenXREditorPlugin, EditorPlugin); OpenXRActionMapEditor *action_map_editor = nullptr; + Ref binding_modifier_inspector_plugin = nullptr; #ifndef ANDROID_ENABLED OpenXRSelectRuntime *select_runtime = nullptr; #endif diff --git a/modules/openxr/editor/openxr_interaction_profile_editor.cpp b/modules/openxr/editor/openxr_interaction_profile_editor.cpp index 09a9a990ed9f..867212389577 100644 --- a/modules/openxr/editor/openxr_interaction_profile_editor.cpp +++ b/modules/openxr/editor/openxr_interaction_profile_editor.cpp @@ -29,20 +29,16 @@ /**************************************************************************/ #include "openxr_interaction_profile_editor.h" - +#include "../openxr_api.h" #include "editor/editor_string_names.h" -#include "scene/gui/box_container.h" -#include "scene/gui/button.h" -#include "scene/gui/label.h" -#include "scene/gui/line_edit.h" -#include "scene/gui/panel_container.h" -#include "scene/gui/separator.h" -#include "scene/gui/text_edit.h" +#include "openxr_action_map_editor.h" /////////////////////////////////////////////////////////////////////////// // Interaction profile editor base void OpenXRInteractionProfileEditorBase::_bind_methods() { + ClassDB::bind_method(D_METHOD("setup", "action_map", "interaction_profile"), &OpenXRInteractionProfileEditorBase::setup); + ClassDB::bind_method(D_METHOD("_add_binding", "action", "path"), &OpenXRInteractionProfileEditorBase::_add_binding); ClassDB::bind_method(D_METHOD("_remove_binding", "action", "path"), &OpenXRInteractionProfileEditorBase::_remove_binding); } @@ -112,12 +108,36 @@ void OpenXRInteractionProfileEditorBase::_remove_binding(const String p_action, } } -void OpenXRInteractionProfileEditorBase::remove_all_bindings_for_action(Ref p_action) { +void OpenXRInteractionProfileEditorBase::_update_interaction_profile() { + if (!is_dirty) { + // no need to update + return; + } + + // Nothing to do here for now.. + + // and we've updated it... + is_dirty = false; +} + +void OpenXRInteractionProfileEditorBase::_theme_changed() { + if (binding_modifiers_btn) { + binding_modifiers_btn->set_icon(get_theme_icon(SNAME("Modifiers"), EditorStringName(EditorIcons))); + } +} + +void OpenXRInteractionProfileEditorBase::remove_all_for_action_set(Ref p_action_set) { + // Note, don't need to remove bindings themselves as remove_all_for_action will be called for each before this is called. + + // TODO update binding modifiers +} + +void OpenXRInteractionProfileEditorBase::remove_all_for_action(Ref p_action) { Vector> bindings = interaction_profile->get_bindings_for_action(p_action); if (bindings.size() > 0) { String action_name = p_action->get_name_with_set(); - // for our undo/redo we process all paths + // For our undo/redo we process all paths undo_redo->create_action(TTR("Remove action from interaction profile")); for (const Ref &binding : bindings) { undo_redo->add_do_method(this, "_remove_binding", action_name, binding->get_binding_path()); @@ -125,7 +145,7 @@ void OpenXRInteractionProfileEditorBase::remove_all_bindings_for_action(Refcommit_action(false); - // but we take a shortcut here :) + // But remove them all in one go so we're more efficient in updating our UI. for (const Ref &binding : bindings) { interaction_profile->remove_binding(binding); } @@ -137,10 +157,39 @@ void OpenXRInteractionProfileEditorBase::remove_all_bindings_for_action(Refpopup_centered(Size2i(500, 400)); +} -OpenXRInteractionProfileEditorBase::OpenXRInteractionProfileEditorBase(Ref p_action_map, Ref p_interaction_profile) { +OpenXRInteractionProfileEditorBase::OpenXRInteractionProfileEditorBase() { undo_redo = EditorUndoRedoManager::get_singleton(); + set_h_size_flags(SIZE_EXPAND_FILL); + set_v_size_flags(SIZE_EXPAND_FILL); + + interaction_profile_sc = memnew(ScrollContainer); + interaction_profile_sc->set_h_size_flags(SIZE_EXPAND_FILL); + interaction_profile_sc->set_v_size_flags(SIZE_EXPAND_FILL); + add_child(interaction_profile_sc); + + binding_modifiers_dialog = memnew(OpenXRBindingModifiersDialog); + add_child(binding_modifiers_dialog); + + toolbar_vb = memnew(VBoxContainer); + toolbar_vb->set_v_size_flags(SIZE_EXPAND_FILL); + add_child(toolbar_vb); + + binding_modifiers_btn = memnew(Button); + binding_modifiers_btn->set_tooltip_text(TTR("Edit binding modifiers")); + binding_modifiers_btn->connect("pressed", callable_mp(this, &OpenXRInteractionProfileEditorBase::_on_open_binding_modifiers)); + // TODO show visual difference if there are binding modifiers for this interaction profile + toolbar_vb->add_child(binding_modifiers_btn); +} + +void OpenXRInteractionProfileEditorBase::setup(Ref p_action_map, Ref p_interaction_profile) { + ERR_FAIL_NULL(binding_modifiers_dialog); + binding_modifiers_dialog->setup(p_action_map, p_interaction_profile); + action_map = p_action_map; interaction_profile = p_interaction_profile; String profile_path = interaction_profile->get_interaction_profile_path(); @@ -149,11 +198,15 @@ OpenXRInteractionProfileEditorBase::OpenXRInteractionProfileEditorBase(Refget_profile(profile_path); if (profile_def != nullptr) { profile_name = profile_def->display_name; + + if (!profile_def->openxr_extension_name.is_empty()) { + profile_name += "*"; + + tooltip = vformat(TTR("Note: This interaction profile requires extension %s support."), profile_def->openxr_extension_name); + } } set_name(profile_name); - set_h_size_flags(SIZE_EXPAND_FILL); - set_v_size_flags(SIZE_EXPAND_FILL); // Make sure it is updated when it enters the tree... is_dirty = true; @@ -189,7 +242,12 @@ void OpenXRInteractionProfileEditor::_add_io_path(VBoxContainer *p_container, co p_container->add_child(path_hb); Label *path_label = memnew(Label); - path_label->set_text(p_io_path->display_name); + if (p_io_path->openxr_extension_name.is_empty()) { + path_label->set_text(p_io_path->display_name); + } else { + path_label->set_text(p_io_path->display_name + "*"); + p_container->set_tooltip_text(vformat(TTR("Note: This binding path requires extension %s support."), p_io_path->openxr_extension_name)); + } path_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); path_hb->add_child(path_label); @@ -243,6 +301,17 @@ void OpenXRInteractionProfileEditor::_add_io_path(VBoxContainer *p_container, co action_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); action_hb->add_child(action_label); + OpenXRBindingModifiersDialog *action_binding_modifiers_dialog = memnew(OpenXRBindingModifiersDialog); + action_binding_modifiers_dialog->setup(action_map, interaction_profile, binding); + action_hb->add_child(action_binding_modifiers_dialog); + + Button *action_binding_modifiers_btn = memnew(Button); + action_binding_modifiers_btn->set_flat(true); + action_binding_modifiers_btn->set_icon(get_theme_icon(SNAME("Modifiers"), EditorStringName(EditorIcons))); + action_binding_modifiers_btn->connect(SceneStringName(pressed), callable_mp((Window *)action_binding_modifiers_dialog, &Window::popup_centered).bind(Size2i(500, 400))); + // TODO change style of button if there are binding modifiers + action_hb->add_child(action_binding_modifiers_btn); + Button *action_rem = memnew(Button); action_rem->set_flat(true); action_rem->set_icon(get_theme_icon(SNAME("Remove"), EditorStringName(EditorIcons))); @@ -261,9 +330,11 @@ void OpenXRInteractionProfileEditor::_update_interaction_profile() { return; } + PackedStringArray requested_extensions = OpenXRAPI::get_all_requested_extensions(); + // out with the old... - while (main_hb->get_child_count() > 0) { - memdelete(main_hb->get_child(0)); + while (interaction_profile_hb->get_child_count() > 0) { + memdelete(interaction_profile_hb->get_child(0)); } // in with the new... @@ -281,7 +352,7 @@ void OpenXRInteractionProfileEditor::_update_interaction_profile() { for (int i = 0; i < top_level_paths.size(); i++) { PanelContainer *panel = memnew(PanelContainer); panel->set_v_size_flags(Control::SIZE_EXPAND_FILL); - main_hb->add_child(panel); + interaction_profile_hb->add_child(panel); panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("TabContainer"))); VBoxContainer *container = memnew(VBoxContainer); @@ -293,29 +364,35 @@ void OpenXRInteractionProfileEditor::_update_interaction_profile() { for (int j = 0; j < profile_def->io_paths.size(); j++) { const OpenXRInteractionProfileMetadata::IOPath *io_path = &profile_def->io_paths[j]; - if (io_path->top_level_path == top_level_paths[i]) { + if (io_path->top_level_path == top_level_paths[i] && (io_path->openxr_extension_name.is_empty() || requested_extensions.has(io_path->openxr_extension_name))) { _add_io_path(container, io_path); } } } - // and we've updated it... - is_dirty = false; + OpenXRInteractionProfileEditorBase::_update_interaction_profile(); } void OpenXRInteractionProfileEditor::_theme_changed() { - for (int i = 0; i < main_hb->get_child_count(); i++) { - Control *panel = Object::cast_to(main_hb->get_child(i)); + OpenXRInteractionProfileEditorBase::_theme_changed(); + + interaction_profile_sc->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree"))); + + for (int i = 0; i < interaction_profile_hb->get_child_count(); i++) { + Control *panel = Object::cast_to(interaction_profile_hb->get_child(i)); if (panel) { panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("TabContainer"))); } } } -OpenXRInteractionProfileEditor::OpenXRInteractionProfileEditor(Ref p_action_map, Ref p_interaction_profile) : - OpenXRInteractionProfileEditorBase(p_action_map, p_interaction_profile) { - main_hb = memnew(HBoxContainer); - add_child(main_hb); +OpenXRInteractionProfileEditor::OpenXRInteractionProfileEditor() { + interaction_profile_hb = memnew(HBoxContainer); + interaction_profile_sc->add_child(interaction_profile_hb); +} + +void OpenXRInteractionProfileEditor::setup(Ref p_action_map, Ref p_interaction_profile) { + OpenXRInteractionProfileEditorBase::setup(p_action_map, p_interaction_profile); select_action_dialog = memnew(OpenXRSelectActionDialog(p_action_map)); select_action_dialog->connect("action_selected", callable_mp(this, &OpenXRInteractionProfileEditor::action_selected)); diff --git a/modules/openxr/editor/openxr_interaction_profile_editor.h b/modules/openxr/editor/openxr_interaction_profile_editor.h index 2ec72127cfcf..a5df9dd784b5 100644 --- a/modules/openxr/editor/openxr_interaction_profile_editor.h +++ b/modules/openxr/editor/openxr_interaction_profile_editor.h @@ -34,19 +34,29 @@ #include "../action_map/openxr_action_map.h" #include "../action_map/openxr_interaction_profile.h" #include "../action_map/openxr_interaction_profile_metadata.h" +#include "../editor/openxr_binding_modifiers_dialog.h" +#include "editor/editor_undo_redo_manager.h" #include "openxr_select_action_dialog.h" +#include "scene/gui/box_container.h" +#include "scene/gui/button.h" -#include "editor/editor_undo_redo_manager.h" -#include "scene/gui/scroll_container.h" +class OpenXRInteractionProfileEditorBase : public HBoxContainer { + GDCLASS(OpenXRInteractionProfileEditorBase, HBoxContainer); -class OpenXRInteractionProfileEditorBase : public ScrollContainer { - GDCLASS(OpenXRInteractionProfileEditorBase, ScrollContainer); +private: + OpenXRBindingModifiersDialog *binding_modifiers_dialog = nullptr; + VBoxContainer *toolbar_vb = nullptr; + Button *binding_modifiers_btn = nullptr; + + void _on_open_binding_modifiers(); protected: EditorUndoRedoManager *undo_redo; Ref interaction_profile; Ref action_map; + ScrollContainer *interaction_profile_sc = nullptr; + bool is_dirty = false; static void _bind_methods(); @@ -55,18 +65,23 @@ class OpenXRInteractionProfileEditorBase : public ScrollContainer { const OpenXRInteractionProfileMetadata::InteractionProfile *profile_def = nullptr; public: + String tooltip; // Tooltip text to show on tab + Ref get_interaction_profile() { return interaction_profile; } - virtual void _update_interaction_profile() {} - virtual void _theme_changed() {} + virtual void _update_interaction_profile(); + virtual void _theme_changed(); void _do_update_interaction_profile(); void _add_binding(const String p_action, const String p_path); void _remove_binding(const String p_action, const String p_path); - void remove_all_bindings_for_action(Ref p_action); + void remove_all_for_action_set(Ref p_action_set); + void remove_all_for_action(Ref p_action); + + virtual void setup(Ref p_action_map, Ref p_interaction_profile); - OpenXRInteractionProfileEditorBase(Ref p_action_map, Ref p_interaction_profile); + OpenXRInteractionProfileEditorBase(); }; class OpenXRInteractionProfileEditor : public OpenXRInteractionProfileEditorBase { @@ -74,7 +89,8 @@ class OpenXRInteractionProfileEditor : public OpenXRInteractionProfileEditorBase private: String selecting_for_io_path; - HBoxContainer *main_hb = nullptr; + HBoxContainer *interaction_profile_hb = nullptr; + OpenXRSelectActionDialog *select_action_dialog = nullptr; void _add_io_path(VBoxContainer *p_container, const OpenXRInteractionProfileMetadata::IOPath *p_io_path); @@ -86,7 +102,9 @@ class OpenXRInteractionProfileEditor : public OpenXRInteractionProfileEditorBase virtual void _update_interaction_profile() override; virtual void _theme_changed() override; - OpenXRInteractionProfileEditor(Ref p_action_map, Ref p_interaction_profile); + virtual void setup(Ref p_action_map, Ref p_interaction_profile) override; + + OpenXRInteractionProfileEditor(); }; #endif // OPENXR_INTERACTION_PROFILE_EDITOR_H diff --git a/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp b/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp index ee8940f30baf..4481fc7c5d8e 100644 --- a/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp +++ b/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp @@ -29,6 +29,7 @@ /**************************************************************************/ #include "openxr_select_interaction_profile_dialog.h" +#include "../openxr_api.h" void OpenXRSelectInteractionProfileDialog::_bind_methods() { ADD_SIGNAL(MethodInfo("interaction_profile_selected", PropertyInfo(Variant::STRING, "interaction_profile"))); @@ -66,22 +67,28 @@ void OpenXRSelectInteractionProfileDialog::_on_select_interaction_profile(const void OpenXRSelectInteractionProfileDialog::open(PackedStringArray p_do_not_include) { int available_count = 0; + OpenXRInteractionProfileMetadata *meta_data = OpenXRInteractionProfileMetadata::get_singleton(); + ERR_FAIL_NULL(meta_data); + // Out with the old. while (main_vb->get_child_count() > 1) { memdelete(main_vb->get_child(1)); } + PackedStringArray requested_extensions = OpenXRAPI::get_all_requested_extensions(); + selected_interaction_profile = ""; ip_buttons.clear(); // In with the new. - PackedStringArray interaction_profiles = OpenXRInteractionProfileMetadata::get_singleton()->get_interaction_profile_paths(); + PackedStringArray interaction_profiles = meta_data->get_interaction_profile_paths(); for (int i = 0; i < interaction_profiles.size(); i++) { const String &path = interaction_profiles[i]; - if (!p_do_not_include.has(path)) { + const String extension = meta_data->get_interaction_profile_extension(path); + if (!p_do_not_include.has(path) && (extension.is_empty() || requested_extensions.has(extension))) { Button *ip_button = memnew(Button); ip_button->set_flat(true); - ip_button->set_text(OpenXRInteractionProfileMetadata::get_singleton()->get_profile(path)->display_name); + ip_button->set_text(meta_data->get_profile(path)->display_name); ip_button->set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT); ip_button->connect(SceneStringName(pressed), callable_mp(this, &OpenXRSelectInteractionProfileDialog::_on_select_interaction_profile).bind(path)); main_vb->add_child(ip_button); diff --git a/modules/openxr/extensions/openxr_dpad_binding_extension.cpp b/modules/openxr/extensions/openxr_dpad_binding_extension.cpp new file mode 100644 index 000000000000..e2967d816b0c --- /dev/null +++ b/modules/openxr/extensions/openxr_dpad_binding_extension.cpp @@ -0,0 +1,274 @@ +/**************************************************************************/ +/* openxr_dpad_binding_extension.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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_dpad_binding_extension.h" +#include "../action_map/openxr_interaction_profile_metadata.h" +#include "../openxr_api.h" +#include "core/math/math_funcs.h" + +// Implementation for: +// https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#XR_EXT_dpad_binding + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// OpenXRDPadBindingExtension + +OpenXRDPadBindingExtension *OpenXRDPadBindingExtension::singleton = nullptr; + +OpenXRDPadBindingExtension *OpenXRDPadBindingExtension::get_singleton() { + return singleton; +} + +OpenXRDPadBindingExtension::OpenXRDPadBindingExtension() { + singleton = this; +} + +OpenXRDPadBindingExtension::~OpenXRDPadBindingExtension() { + singleton = nullptr; +} + +HashMap OpenXRDPadBindingExtension::get_requested_extensions() { + HashMap request_extensions; + + // Note, we're dependent on the binding modifier extension, this may be requested by multiple extension wrappers. + request_extensions[XR_KHR_BINDING_MODIFICATION_EXTENSION_NAME] = &binding_modifier_ext; + request_extensions[XR_EXT_DPAD_BINDING_EXTENSION_NAME] = &dpad_binding_ext; + + return request_extensions; +} + +bool OpenXRDPadBindingExtension::is_available() { + return binding_modifier_ext && dpad_binding_ext; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// OpenXRDpadBindingModifier + +void OpenXRDpadBindingModifier::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_action_set", "action_set"), &OpenXRDpadBindingModifier::set_action_set); + ClassDB::bind_method(D_METHOD("get_action_set"), &OpenXRDpadBindingModifier::get_action_set); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "action_set", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRActionSet"), "set_action_set", "get_action_set"); + + ClassDB::bind_method(D_METHOD("set_input_path", "input_path"), &OpenXRDpadBindingModifier::set_input_path); + ClassDB::bind_method(D_METHOD("get_input_path"), &OpenXRDpadBindingModifier::get_input_path); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "input_path", PROPERTY_HINT_TYPE_STRING, "binding_path"), "set_input_path", "get_input_path"); + + ClassDB::bind_method(D_METHOD("set_threshold", "threshold"), &OpenXRDpadBindingModifier::set_threshold); + ClassDB::bind_method(D_METHOD("get_threshold"), &OpenXRDpadBindingModifier::get_threshold); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "threshold", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_threshold", "get_threshold"); + + ClassDB::bind_method(D_METHOD("set_threshold_released", "threshold_released"), &OpenXRDpadBindingModifier::set_threshold_released); + ClassDB::bind_method(D_METHOD("get_threshold_released"), &OpenXRDpadBindingModifier::get_threshold_released); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "threshold_released", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_threshold_released", "get_threshold_released"); + + ClassDB::bind_method(D_METHOD("set_center_region", "center_region"), &OpenXRDpadBindingModifier::set_center_region); + ClassDB::bind_method(D_METHOD("get_center_region"), &OpenXRDpadBindingModifier::get_center_region); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "center_region", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_center_region", "get_center_region"); + + ClassDB::bind_method(D_METHOD("set_wedge_angle", "wedge_angle"), &OpenXRDpadBindingModifier::set_wedge_angle); + ClassDB::bind_method(D_METHOD("get_wedge_angle"), &OpenXRDpadBindingModifier::get_wedge_angle); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wedge_angle"), "set_wedge_angle", "get_wedge_angle"); + + ClassDB::bind_method(D_METHOD("set_is_sticky", "is_sticky"), &OpenXRDpadBindingModifier::set_is_sticky); + ClassDB::bind_method(D_METHOD("get_is_sticky"), &OpenXRDpadBindingModifier::get_is_sticky); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "is_sticky"), "set_is_sticky", "get_is_sticky"); + + ClassDB::bind_method(D_METHOD("set_on_haptic", "haptic"), &OpenXRDpadBindingModifier::set_on_haptic); + ClassDB::bind_method(D_METHOD("get_on_haptic"), &OpenXRDpadBindingModifier::get_on_haptic); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "on_haptic", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRHapticBase"), "set_on_haptic", "get_on_haptic"); + + ClassDB::bind_method(D_METHOD("set_off_haptic", "haptic"), &OpenXRDpadBindingModifier::set_off_haptic); + ClassDB::bind_method(D_METHOD("get_off_haptic"), &OpenXRDpadBindingModifier::get_off_haptic); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "off_haptic", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRHapticBase"), "set_off_haptic", "get_off_haptic"); +} + +OpenXRDpadBindingModifier::OpenXRDpadBindingModifier() { + ERR_FAIL_COND(dpad_bindings_data.resize_zeroed(sizeof(XrInteractionProfileDpadBindingEXT)) != OK); + dpad_bindings = (XrInteractionProfileDpadBindingEXT *)dpad_bindings_data.ptrw(); + + dpad_bindings->type = XR_TYPE_INTERACTION_PROFILE_DPAD_BINDING_EXT; + dpad_bindings->next = nullptr; + + dpad_bindings->forceThreshold = 0.6; + dpad_bindings->forceThresholdReleased = 0.4; + dpad_bindings->centerRegion = 0.1; + dpad_bindings->wedgeAngle = Math::deg_to_rad(90.0); + dpad_bindings->isSticky = false; +} + +void OpenXRDpadBindingModifier::set_action_set(const Ref p_action_set) { + action_set = p_action_set; +} + +Ref OpenXRDpadBindingModifier::get_action_set() const { + return action_set; +} + +void OpenXRDpadBindingModifier::set_input_path(const String &p_input_path) { + input_path = p_input_path; + emit_changed(); +} + +String OpenXRDpadBindingModifier::get_input_path() const { + return input_path; +} + +void OpenXRDpadBindingModifier::set_threshold(float p_threshold) { + ERR_FAIL_NULL(dpad_bindings); + ERR_FAIL_COND(p_threshold < 0.0 || p_threshold > 1.0); + + dpad_bindings->forceThreshold = p_threshold; + emit_changed(); +} + +float OpenXRDpadBindingModifier::get_threshold() const { + ERR_FAIL_NULL_V(dpad_bindings, 0.0); + return dpad_bindings->forceThreshold; +} + +void OpenXRDpadBindingModifier::set_threshold_released(float p_threshold) { + ERR_FAIL_NULL(dpad_bindings); + ERR_FAIL_COND(p_threshold < 0.0 || p_threshold > 1.0); + + dpad_bindings->forceThresholdReleased = p_threshold; + emit_changed(); +} + +float OpenXRDpadBindingModifier::get_threshold_released() const { + ERR_FAIL_NULL_V(dpad_bindings, 0.0); + return dpad_bindings->forceThresholdReleased; +} + +void OpenXRDpadBindingModifier::set_center_region(float p_center_region) { + ERR_FAIL_NULL(dpad_bindings); + ERR_FAIL_COND(p_center_region < 0.0 || p_center_region > 1.0); + + dpad_bindings->centerRegion = p_center_region; + emit_changed(); +} + +float OpenXRDpadBindingModifier::get_center_region() const { + ERR_FAIL_NULL_V(dpad_bindings, 0.0); + return dpad_bindings->centerRegion; +} + +void OpenXRDpadBindingModifier::set_wedge_angle(float p_wedge_angle) { + ERR_FAIL_NULL(dpad_bindings); + dpad_bindings->wedgeAngle = p_wedge_angle; + emit_changed(); +} + +float OpenXRDpadBindingModifier::get_wedge_angle() const { + ERR_FAIL_NULL_V(dpad_bindings, 0.0); + return dpad_bindings->wedgeAngle; +} + +void OpenXRDpadBindingModifier::set_wedge_angle_deg(float p_wedge_angle) { + ERR_FAIL_NULL(dpad_bindings); + dpad_bindings->wedgeAngle = Math::deg_to_rad(p_wedge_angle); + emit_changed(); +} + +float OpenXRDpadBindingModifier::get_wedge_angle_deg() const { + ERR_FAIL_NULL_V(dpad_bindings, 0.0); + return Math::rad_to_deg(dpad_bindings->wedgeAngle); +} + +void OpenXRDpadBindingModifier::set_is_sticky(bool p_sticky) { + ERR_FAIL_NULL(dpad_bindings); + dpad_bindings->isSticky = p_sticky; + emit_changed(); +} + +bool OpenXRDpadBindingModifier::get_is_sticky() const { + ERR_FAIL_NULL_V(dpad_bindings, false); + return dpad_bindings->isSticky; +} + +void OpenXRDpadBindingModifier::set_on_haptic(const Ref p_haptic) { + on_haptic = p_haptic; + emit_changed(); +} + +Ref OpenXRDpadBindingModifier::get_on_haptic() const { + return on_haptic; +} + +void OpenXRDpadBindingModifier::set_off_haptic(const Ref p_haptic) { + off_haptic = p_haptic; + emit_changed(); +} + +Ref OpenXRDpadBindingModifier::get_off_haptic() const { + return off_haptic; +} + +PackedByteArray OpenXRDpadBindingModifier::get_ip_modification() { + ERR_FAIL_NULL_V(dpad_bindings, PackedByteArray()); + + OpenXRAPI *openxr_api = OpenXRAPI::get_singleton(); + ERR_FAIL_NULL_V(openxr_api, PackedByteArray()); + + OpenXRDPadBindingExtension *dpad_binding_ext = OpenXRDPadBindingExtension::get_singleton(); + if (!dpad_binding_ext || !dpad_binding_ext->is_available()) { + // Extension not enabled! + WARN_PRINT("DPad binding extension is not enabled or available."); + return PackedByteArray(); + } + + dpad_bindings->binding = openxr_api->get_xr_path(input_path); + ERR_FAIL_COND_V(dpad_bindings->binding == XR_NULL_PATH, PackedByteArray()); + + // Get our action set + ERR_FAIL_COND_V(!action_set.is_valid(), PackedByteArray()); + RID action_set_rid = openxr_api->find_action_set(action_set->get_name()); + ERR_FAIL_COND_V(!action_set_rid.is_valid(), PackedByteArray()); + dpad_bindings->actionSet = openxr_api->action_set_get_handle(action_set_rid); + + // These are set already: + // - forceThreshold + // - forceThresholdReleased + // - centerRegion + // - wedgeAngle + // - isSticky + + if (on_haptic.is_valid()) { + dpad_bindings->onHaptic = on_haptic->get_xr_structure(); + } else { + dpad_bindings->onHaptic = nullptr; + } + + if (off_haptic.is_valid()) { + dpad_bindings->offHaptic = off_haptic->get_xr_structure(); + } else { + dpad_bindings->offHaptic = nullptr; + } + + return dpad_bindings_data; +} diff --git a/modules/openxr/extensions/openxr_dpad_binding_extension.h b/modules/openxr/extensions/openxr_dpad_binding_extension.h new file mode 100644 index 000000000000..357445b4e12d --- /dev/null +++ b/modules/openxr/extensions/openxr_dpad_binding_extension.h @@ -0,0 +1,110 @@ +/**************************************************************************/ +/* openxr_dpad_binding_extension.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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_DPAD_BINDING_EXTENSION_H +#define OPENXR_DPAD_BINDING_EXTENSION_H + +#include "../action_map/openxr_action_set.h" +#include "../action_map/openxr_binding_modifier.h" +#include "../action_map/openxr_haptic_feedback.h" +#include "../util.h" +#include "openxr_extension_wrapper.h" + +class OpenXRDPadBindingExtension : public OpenXRExtensionWrapper { +public: + static OpenXRDPadBindingExtension *get_singleton(); + + OpenXRDPadBindingExtension(); + virtual ~OpenXRDPadBindingExtension() override; + + virtual HashMap get_requested_extensions() override; + + bool is_available(); + +private: + static OpenXRDPadBindingExtension *singleton; + + bool binding_modifier_ext = false; + bool dpad_binding_ext = false; +}; + +class OpenXRDpadBindingModifier : public OpenXRBindingModifier { + GDCLASS(OpenXRDpadBindingModifier, OpenXRBindingModifier); + +private: + PackedByteArray dpad_bindings_data; + XrInteractionProfileDpadBindingEXT *dpad_bindings = nullptr; + String input_path; + Ref action_set; + Ref on_haptic; + Ref off_haptic; + +protected: + static void _bind_methods(); + +public: + OpenXRDpadBindingModifier(); + + void set_action_set(const Ref p_action_set); + Ref get_action_set() const; + + void set_input_path(const String &p_input_path); + String get_input_path() const; + + void set_threshold(float p_threshold); + float get_threshold() const; + + void set_threshold_released(float p_threshold); + float get_threshold_released() const; + + void set_center_region(float p_center_region); + float get_center_region() const; + + void set_wedge_angle(float p_wedge_angle); + float get_wedge_angle() const; + + void set_wedge_angle_deg(float p_wedge_angle); + float get_wedge_angle_deg() const; + + void set_is_sticky(bool p_sticky); + bool get_is_sticky() const; + + void set_on_haptic(const Ref p_haptic); + Ref get_on_haptic() const; + + void set_off_haptic(const Ref p_haptic); + Ref get_off_haptic() const; + + virtual bool record_on_binding() const override { return false; } + virtual String get_description() const override { return "DPad modifier"; } + virtual PackedByteArray get_ip_modification() override; +}; + +#endif // OPENXR_DPAD_BINDING_EXTENSION_H diff --git a/modules/openxr/extensions/openxr_htc_controller_extension.cpp b/modules/openxr/extensions/openxr_htc_controller_extension.cpp index 416934fa47ce..36894cb0cea3 100644 --- a/modules/openxr/extensions/openxr_htc_controller_extension.cpp +++ b/modules/openxr/extensions/openxr_htc_controller_extension.cpp @@ -61,96 +61,88 @@ void OpenXRHTCControllerExtension::on_register_metadata() { metadata->register_top_level_path("HTC left hand tracker", "/user/hand_htc/left", XR_HTC_HAND_INTERACTION_EXTENSION_NAME); metadata->register_top_level_path("HTC right hand tracker", "/user/hand_htc/right", XR_HTC_HAND_INTERACTION_EXTENSION_NAME); - // HTC Vive Cosmos controller - metadata->register_interaction_profile("Vive Cosmos controller", "/interaction_profiles/htc/vive_cosmos_controller", XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME); - metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - - metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Shoulder click", "/user/hand/left", "/user/hand/left/input/shoulder/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Shoulder click", "/user/hand/right", "/user/hand/right/input/shoulder/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Squeeze click", "/user/hand/left", "/user/hand/left/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Squeeze click", "/user/hand/right", "/user/hand/right/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - - // HTC Vive Focus 3 controller - metadata->register_interaction_profile("Vive Focus 3 controller", "/interaction_profiles/htc/vive_focus3_controller", XR_HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME); - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger touch", "/user/hand/left", "/user/hand/left/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger touch", "/user/hand/right", "/user/hand/right/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Squeeze click", "/user/hand/left", "/user/hand/left/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Squeeze touch", "/user/hand/left", "/user/hand/left/input/squeeze/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Squeeze click", "/user/hand/right", "/user/hand/right/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Squeeze touch", "/user/hand/right", "/user/hand/right/input/squeeze/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbrest touch", "/user/hand/left", "/user/hand/left/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbrest touch", "/user/hand/right", "/user/hand/right/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - - // HTC Hand interaction profile - metadata->register_interaction_profile("HTC Hand interaction", "/interaction_profiles/htc/hand_interaction", XR_HTC_HAND_INTERACTION_EXTENSION_NAME); - metadata->register_io_path("/interaction_profiles/htc/hand_interaction", "Grip pose", "/user/hand_htc/left", "/user/hand_htc/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/htc/hand_interaction", "Grip pose", "/user/hand_htc/right", "/user/hand_htc/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/htc/hand_interaction", "Aim pose", "/user/hand_htc/left", "/user/hand_htc/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/htc/hand_interaction", "Aim pose", "/user/hand_htc/right", "/user/hand_htc/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - - metadata->register_io_path("/interaction_profiles/htc/hand_interaction", "Select (pinch)", "/user/hand_htc/left", "/user/hand_htc/left/input/select/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/htc/hand_interaction", "Select (pinch)", "/user/hand_htc/right", "/user/hand_htc/right/input/select/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - - metadata->register_io_path("/interaction_profiles/htc/hand_interaction", "Squeeze (grab)", "/user/hand_htc/left", "/user/hand_htc/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/htc/hand_interaction", "Squeeze (grab)", "/user/hand_htc/right", "/user/hand_htc/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + { // HTC Vive Cosmos controller + const String profile_path = "/interaction_profiles/htc/vive_cosmos_controller"; + metadata->register_interaction_profile("Vive Cosmos controller", profile_path, XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME); + for (const String user_path : { "/user/hand/left", "/user/hand/right" }) { + metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + + metadata->register_io_path(profile_path, "Shoulder click", user_path, user_path + "/input/shoulder/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path(profile_path, "Trigger click", user_path, user_path + "/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Squeeze click", user_path, user_path + "/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick touch", user_path, user_path + "/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + } + + metadata->register_io_path(profile_path, "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + } + + { // HTC Vive Focus 3 controller + const String profile_path = "/interaction_profiles/htc/vive_focus3_controller"; + metadata->register_interaction_profile("Vive Focus 3 controller", profile_path, XR_HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME); + for (const String user_path : { "/user/hand/left", "/user/hand/right" }) { + metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + + metadata->register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path(profile_path, "Trigger click", user_path, user_path + "/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trigger touch", user_path, user_path + "/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Squeeze click", user_path, user_path + "/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Squeeze touch", user_path, user_path + "/input/squeeze/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick touch", user_path, user_path + "/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Thumbrest touch", user_path, user_path + "/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + } + + metadata->register_io_path(profile_path, "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + } + + { // HTC Hand interaction profile + const String profile_path = "/interaction_profiles/htc/hand_interaction"; + metadata->register_interaction_profile("HTC Hand interaction", profile_path, XR_HTC_HAND_INTERACTION_EXTENSION_NAME); + for (const String user_path : { "/user/hand_htc/left", "/user/hand_htc/right" }) { + metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + + metadata->register_io_path(profile_path, "Select (pinch)", user_path, user_path + "/input/select/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + + metadata->register_io_path(profile_path, "Squeeze (grab)", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + } + } } diff --git a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp index b2ddf71f5ef4..20c07cd25425 100644 --- a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp +++ b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp @@ -83,134 +83,45 @@ void OpenXRHTCViveTrackerExtension::on_register_metadata() { metadata->register_top_level_path("Camera tracker", "/user/vive_tracker_htcx/role/camera", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME); metadata->register_top_level_path("Keyboard tracker", "/user/vive_tracker_htcx/role/keyboard", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME); - // HTC Vive tracker - // Interestingly enough trackers don't have buttons or inputs, yet these are defined in the spec. - // I think this can be supported through attachments on the trackers. - metadata->register_interaction_profile("HTC Vive tracker", "/interaction_profiles/htc/vive_tracker_htcx", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - // metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - - // metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - // metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - // metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - - // metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - // metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - // register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - - // metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + { // HTC Vive tracker + // Interestingly enough trackers don't have buttons or inputs, yet these are defined in the spec. + // I think this can be supported through attachments on the trackers. + const String profile_path = "/interaction_profiles/htc/vive_tracker_htcx"; + metadata->register_interaction_profile("HTC Vive tracker", profile_path, XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME); + for (const String user_path : { + /* "/user/vive_tracker_htcx/role/handheld_object", */ + "/user/vive_tracker_htcx/role/left_foot", + "/user/vive_tracker_htcx/role/right_foot", + "/user/vive_tracker_htcx/role/left_shoulder", + "/user/vive_tracker_htcx/role/right_shoulder", + "/user/vive_tracker_htcx/role/left_elbow", + "/user/vive_tracker_htcx/role/right_elbow", + "/user/vive_tracker_htcx/role/left_knee", + "/user/vive_tracker_htcx/role/right_knee", + "/user/vive_tracker_htcx/role/waist", + "/user/vive_tracker_htcx/role/chest", + "/user/vive_tracker_htcx/role/camera", + "/user/vive_tracker_htcx/role/keyboard", + }) { + metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + + metadata->register_io_path(profile_path, "Menu click", user_path, user_path + "/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path(profile_path, "Trigger click", user_path, user_path + "/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Squeeze click", user_path, user_path + "/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Trackpad", user_path, user_path + "/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path(profile_path, "Trackpad click", user_path, user_path + "/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trackpad touch", user_path, user_path + "/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trackpad Dpad Up", user_path, user_path + "/input/trackpad/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trackpad Dpad Down", user_path, user_path + "/input/trackpad/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trackpad Dpad Left", user_path, user_path + "/input/trackpad/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trackpad Dpad Right", user_path, user_path + "/input/trackpad/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trackpad Dpad Center", user_path, user_path + "/input/trackpad/dpad_center", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + } + } } bool OpenXRHTCViveTrackerExtension::on_event_polled(const XrEventDataBuffer &event) { diff --git a/modules/openxr/extensions/openxr_huawei_controller_extension.cpp b/modules/openxr/extensions/openxr_huawei_controller_extension.cpp index baa6d6ded85c..844ce22d20d5 100644 --- a/modules/openxr/extensions/openxr_huawei_controller_extension.cpp +++ b/modules/openxr/extensions/openxr_huawei_controller_extension.cpp @@ -48,37 +48,33 @@ void OpenXRHuaweiControllerExtension::on_register_metadata() { OpenXRInteractionProfileMetadata *metadata = OpenXRInteractionProfileMetadata::get_singleton(); ERR_FAIL_NULL(metadata); - // Huawei controller - metadata->register_interaction_profile("Huawei controller", "/interaction_profiles/huawei/controller", XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME); - metadata->register_io_path("/interaction_profiles/huawei/controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/huawei/controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/huawei/controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/huawei/controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/huawei/controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/huawei/controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + { // Huawei controller + const String profile_path = "/interaction_profiles/huawei/controller"; + metadata->register_interaction_profile("Huawei controller", profile_path, XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME); + for (const String user_path : { "/user/hand/left", "/user/hand/right" }) { + metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/huawei/controller", "Home click", "/user/hand/left", "/user/hand/left/input/home/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/huawei/controller", "Home click", "/user/hand/right", "/user/hand/right/input/home/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/huawei/controller", "Back click", "/user/hand/left", "/user/hand/left/input/back/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/huawei/controller", "Back click", "/user/hand/right", "/user/hand/right/input/back/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Home click", user_path, user_path + "/input/home/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Back click", user_path, user_path + "/input/back/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/huawei/controller", "Volume up click", "/user/hand/left", "/user/hand/left/input/volume_up/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/huawei/controller", "Volume up click", "/user/hand/right", "/user/hand/right/input/volume_up/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/huawei/controller", "Volume down click", "/user/hand/left", "/user/hand/left/input/volume_down/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/huawei/controller", "Volume down click", "/user/hand/right", "/user/hand/right/input/volume_down/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Volume up click", user_path, user_path + "/input/volume_up/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Volume down click", user_path, user_path + "/input/volume_down/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/huawei/controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/huawei/controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/huawei/controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/huawei/controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path(profile_path, "Trigger click", user_path, user_path + "/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/huawei/controller", "Trackpad", "/user/hand/left", "/user/hand/left/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/huawei/controller", "Trackpad click", "/user/hand/left", "/user/hand/left/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/huawei/controller", "Trackpad touch", "/user/hand/left", "/user/hand/left/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/huawei/controller", "Trackpad", "/user/hand/right", "/user/hand/right/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/huawei/controller", "Trackpad click", "/user/hand/right", "/user/hand/right/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/huawei/controller", "Trackpad touch", "/user/hand/right", "/user/hand/right/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trackpad", user_path, user_path + "/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path(profile_path, "Trackpad click", user_path, user_path + "/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trackpad touch", user_path, user_path + "/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trackpad Dpad Up", user_path, user_path + "/input/trackpad/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trackpad Dpad Down", user_path, user_path + "/input/trackpad/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trackpad Dpad Left", user_path, user_path + "/input/trackpad/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trackpad Dpad Right", user_path, user_path + "/input/trackpad/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trackpad Dpad Center", user_path, user_path + "/input/trackpad/dpad_center", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/huawei/controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - metadata->register_io_path("/interaction_profiles/huawei/controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + } + } } diff --git a/modules/openxr/extensions/openxr_meta_controller_extension.cpp b/modules/openxr/extensions/openxr_meta_controller_extension.cpp index 72dc74bf64e8..ad62f584c138 100644 --- a/modules/openxr/extensions/openxr_meta_controller_extension.cpp +++ b/modules/openxr/extensions/openxr_meta_controller_extension.cpp @@ -52,133 +52,110 @@ void OpenXRMetaControllerExtension::on_register_metadata() { // Note, we register controllers regardless if they are supported on the current hardware. - // Normal touch controller is part of the core spec, but we do have some extensions. - metadata->register_io_path("/interaction_profiles/oculus/touch_controller", "Trigger proximity", "/user/hand/left", "/user/hand/left/input/trigger/proximity_fb ", "XR_FB_touch_controller_proximity", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/oculus/touch_controller", "Trigger proximity", "/user/hand/right", "/user/hand/right/input/trigger/proximity_fb ", "XR_FB_touch_controller_proximity", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/oculus/touch_controller", "Thumb proximity", "/user/hand/left", "/user/hand/left/input/thumb_fb/proximity_fb ", "XR_FB_touch_controller_proximity", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/oculus/touch_controller", "Thumb proximity", "/user/hand/right", "/user/hand/right/input/thumb_fb/proximity_fb ", "XR_FB_touch_controller_proximity", OpenXRAction::OPENXR_ACTION_BOOL); - - // Touch controller pro (Quest Pro) - metadata->register_interaction_profile("Touch controller pro", "/interaction_profiles/facebook/touch_controller_pro", "XR_FB_touch_controller_pro"); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger touch", "/user/hand/left", "/user/hand/left/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger proximity", "/user/hand/left", "/user/hand/left/input/trigger/proximity_fb", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger curl", "/user/hand/left", "/user/hand/left/input/trigger/curl_fb", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger slide", "/user/hand/left", "/user/hand/left/input/trigger/slide_fb", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger force", "/user/hand/left", "/user/hand/left/input/trigger/force", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger touch", "/user/hand/right", "/user/hand/right/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger proximity", "/user/hand/right", "/user/hand/right/input/trigger/proximity_fb", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger curl", "/user/hand/right", "/user/hand/right/input/trigger/curl_fb", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger slide", "/user/hand/right", "/user/hand/right/input/trigger/slide_fb", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger force", "/user/hand/right", "/user/hand/right/input/trigger/force", "", OpenXRAction::OPENXR_ACTION_FLOAT); - - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Squeeze", "/user/hand/left", "/user/hand/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Squeeze", "/user/hand/right", "/user/hand/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumb proximity", "/user/hand/left", "/user/hand/left/input/thumb_fb/proximity_fb", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumb proximity", "/user/hand/right", "/user/hand/right/input/thumb_fb/proximity_fb", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick X", "/user/hand/left", "/user/hand/left/input/thumbstick/x", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick Y", "/user/hand/left", "/user/hand/left/input/thumbstick/y", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick X", "/user/hand/right", "/user/hand/right/input/thumbstick/x", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick Y", "/user/hand/right", "/user/hand/right/input/thumbstick/y", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbrest touch", "/user/hand/left", "/user/hand/left/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbrest force", "/user/hand/left", "/user/hand/left/input/thumbrest/force", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbrest touch", "/user/hand/right", "/user/hand/right/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbrest force", "/user/hand/right", "/user/hand/right/input/thumbrest/force", "", OpenXRAction::OPENXR_ACTION_FLOAT); - - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Stylus force", "/user/hand/left", "/user/hand/left/input/stylus_fb/force", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Stylus force", "/user/hand/right", "/user/hand/right/input/stylus_fb/force", "", OpenXRAction::OPENXR_ACTION_FLOAT); - - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Haptic trigger output", "/user/hand/left", "/user/hand/left/output/haptic_trigger_fb", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Haptic thumb output", "/user/hand/left", "/user/hand/left/output/haptic_thumb_fb", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Haptic trigger output", "/user/hand/right", "/user/hand/right/output/haptic_trigger_fb", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Haptic thumb output", "/user/hand/right", "/user/hand/right/output/haptic_thumb_fb", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - - // Touch controller plus (Quest 3) - metadata->register_interaction_profile("Touch controller plus", "/interaction_profiles/meta/touch_controller_plus", "XR_META_touch_controller_plus"); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger touch", "/user/hand/left", "/user/hand/left/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger proximity", "/user/hand/left", "/user/hand/left/input/trigger/proximity_meta", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger curl", "/user/hand/left", "/user/hand/left/input/trigger/curl_meta", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger slide", "/user/hand/left", "/user/hand/left/input/trigger/slide_meta", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger force", "/user/hand/left", "/user/hand/left/input/trigger/force", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger touch", "/user/hand/right", "/user/hand/right/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger proximity", "/user/hand/right", "/user/hand/right/input/trigger/proximity_meta", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger curl", "/user/hand/right", "/user/hand/right/input/trigger/curl_meta", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger slide", "/user/hand/right", "/user/hand/right/input/trigger/slide_meta", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger force", "/user/hand/right", "/user/hand/right/input/trigger/force", "", OpenXRAction::OPENXR_ACTION_FLOAT); - - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Squeeze", "/user/hand/left", "/user/hand/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Squeeze", "/user/hand/right", "/user/hand/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumb proximity", "/user/hand/left", "/user/hand/left/input/thumb_meta/proximity_meta", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumb proximity", "/user/hand/right", "/user/hand/right/input/thumb_meta/proximity_meta", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick X", "/user/hand/left", "/user/hand/left/input/thumbstick/x", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick Y", "/user/hand/left", "/user/hand/left/input/thumbstick/y", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick X", "/user/hand/right", "/user/hand/right/input/thumbstick/x", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick Y", "/user/hand/right", "/user/hand/right/input/thumbstick/y", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbrest touch", "/user/hand/left", "/user/hand/left/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbrest touch", "/user/hand/right", "/user/hand/right/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + { // Normal touch controller is part of the core spec, but we do have some extensions. + const String profile_path = "/interaction_profiles/oculus/touch_controller"; + for (const String user_path : { "/user/hand/left", "/user/hand/right" }) { + metadata->register_io_path(profile_path, "Trigger proximity", user_path, user_path + "/input/trigger/proximity_fb ", "XR_FB_touch_controller_proximity", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumb proximity", user_path, user_path + "/input/thumb_fb/proximity_fb ", "XR_FB_touch_controller_proximity", OpenXRAction::OPENXR_ACTION_BOOL); + } + } + + { // Touch controller pro (Quest Pro) + const String profile_path = "/interaction_profiles/facebook/touch_controller_pro"; + metadata->register_interaction_profile("Touch controller pro", profile_path, "XR_FB_touch_controller_pro"); + for (const String user_path : { "/user/hand/left", "/user/hand/right" }) { + metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path(profile_path, "Palm pose", user_path, user_path + "/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + + metadata->register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path(profile_path, "Trigger touch", user_path, user_path + "/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trigger proximity", user_path, user_path + "/input/trigger/proximity_fb", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trigger curl", user_path, user_path + "/input/trigger/curl_fb", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path(profile_path, "Trigger slide", user_path, user_path + "/input/trigger/slide_fb", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path(profile_path, "Trigger force", user_path, user_path + "/input/trigger/force", "", OpenXRAction::OPENXR_ACTION_FLOAT); + + metadata->register_io_path(profile_path, "Squeeze", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + + metadata->register_io_path(profile_path, "Thumb proximity", user_path, user_path + "/input/thumb_fb/proximity_fb", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path(profile_path, "Thumbstick X", user_path, user_path + "/input/thumbstick/x", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path(profile_path, "Thumbstick Y", user_path, user_path + "/input/thumbstick/y", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick touch", user_path, user_path + "/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Thumbrest touch", user_path, user_path + "/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbrest force", user_path, user_path + "/input/thumbrest/force", "", OpenXRAction::OPENXR_ACTION_FLOAT); + + metadata->register_io_path(profile_path, "Stylus force", user_path, user_path + "/input/stylus_fb/force", "", OpenXRAction::OPENXR_ACTION_FLOAT); + + metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + metadata->register_io_path(profile_path, "Haptic trigger output", user_path, user_path + "/output/haptic_trigger_fb", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + metadata->register_io_path(profile_path, "Haptic thumb output", user_path, user_path + "/output/haptic_thumb_fb", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + } + + metadata->register_io_path(profile_path, "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + } + + { // Touch controller plus (Quest 3) + const String profile_path = "/interaction_profiles/meta/touch_controller_plus"; + metadata->register_interaction_profile("Touch controller plus", profile_path, "XR_META_touch_controller_plus"); + for (const String user_path : { "/user/hand/left", "/user/hand/right" }) { + metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + + metadata->register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path(profile_path, "Trigger touch", user_path, user_path + "/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trigger proximity", user_path, user_path + "/input/trigger/proximity_meta", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trigger curl", user_path, user_path + "/input/trigger/curl_meta", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path(profile_path, "Trigger slide", user_path, user_path + "/input/trigger/slide_meta", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path(profile_path, "Trigger force", user_path, user_path + "/input/trigger/force", "", OpenXRAction::OPENXR_ACTION_FLOAT); + + metadata->register_io_path(profile_path, "Squeeze", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + + metadata->register_io_path(profile_path, "Thumb proximity", user_path, user_path + "/input/thumb_meta/proximity_meta", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path(profile_path, "Thumbstick X", user_path, user_path + "/input/thumbstick/x", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path(profile_path, "Thumbstick Y", user_path, user_path + "/input/thumbstick/y", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick touch", user_path, user_path + "/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Thumbrest touch", user_path, user_path + "/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + } + + metadata->register_io_path(profile_path, "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + } } diff --git a/modules/openxr/extensions/openxr_ml2_controller_extension.cpp b/modules/openxr/extensions/openxr_ml2_controller_extension.cpp index 979ac22d087f..f36273658d53 100644 --- a/modules/openxr/extensions/openxr_ml2_controller_extension.cpp +++ b/modules/openxr/extensions/openxr_ml2_controller_extension.cpp @@ -50,7 +50,7 @@ void OpenXRML2ControllerExtension::on_register_metadata() { // Magic Leap 2 Controller const String profile_path = "/interaction_profiles/ml/ml2_controller"; - metadata->register_interaction_profile("Magic Leap 2 controller", "/interaction_profiles/ml/ml2_controller", XR_ML_ML2_CONTROLLER_INTERACTION_EXTENSION_NAME); + metadata->register_interaction_profile("Magic Leap 2 controller", profile_path, XR_ML_ML2_CONTROLLER_INTERACTION_EXTENSION_NAME); for (const String user_path : { "/user/hand/left", "/user/hand/right" }) { metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); @@ -66,6 +66,11 @@ void OpenXRML2ControllerExtension::on_register_metadata() { metadata->register_io_path(profile_path, "Trackpad X", user_path, user_path + "/input/trackpad/x", "", OpenXRAction::OPENXR_ACTION_FLOAT); metadata->register_io_path(profile_path, "Trackpad Y", user_path, user_path + "/input/trackpad/y", "", OpenXRAction::OPENXR_ACTION_FLOAT); metadata->register_io_path(profile_path, "Trackpad touch", user_path, user_path + "/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path(profile_path, "Trackpad Dpad Up", user_path, user_path + "/input/trackpad/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trackpad Dpad Down", user_path, user_path + "/input/trackpad/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trackpad Dpad Left", user_path, user_path + "/input/trackpad/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trackpad Dpad Right", user_path, user_path + "/input/trackpad/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trackpad Dpad Center", user_path, user_path + "/input/trackpad/dpad_center", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); } diff --git a/modules/openxr/extensions/openxr_pico_controller_extension.cpp b/modules/openxr/extensions/openxr_pico_controller_extension.cpp index f2901d49f779..b4419d103d10 100644 --- a/modules/openxr/extensions/openxr_pico_controller_extension.cpp +++ b/modules/openxr/extensions/openxr_pico_controller_extension.cpp @@ -55,85 +55,79 @@ void OpenXRPicoControllerExtension::on_register_metadata() { // Make sure we switch to our new name. metadata->register_profile_rename("/interaction_profiles/pico/neo3_controller", "/interaction_profiles/bytedance/pico_neo3_controller"); - // Pico neo 3 controller. - metadata->register_interaction_profile("Pico Neo3 controller", "/interaction_profiles/bytedance/pico_neo3_controller", XR_BD_CONTROLLER_INTERACTION_EXTENSION_NAME); - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Menu click", "/user/hand/right", "/user/hand/right/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "System click", "/user/hand/left", "/user/hand/left/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Trigger touch", "/user/hand/left", "/user/hand/left/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Trigger touch", "/user/hand/right", "/user/hand/right/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Squeeze", "/user/hand/left", "/user/hand/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Squeeze", "/user/hand/right", "/user/hand/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - - // Pico 4 controller. - metadata->register_interaction_profile("Pico 4 controller", "/interaction_profiles/bytedance/pico4_controller", XR_BD_CONTROLLER_INTERACTION_EXTENSION_NAME); - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - // Note, no menu on right controller! - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "System click", "/user/hand/left", "/user/hand/left/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Trigger touch", "/user/hand/left", "/user/hand/left/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Trigger touch", "/user/hand/right", "/user/hand/right/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Squeeze", "/user/hand/left", "/user/hand/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Squeeze", "/user/hand/right", "/user/hand/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + { // Pico neo 3 controller. + const String profile_path = "/interaction_profiles/bytedance/pico_neo3_controller"; + metadata->register_interaction_profile("Pico Neo3 controller", profile_path, XR_BD_CONTROLLER_INTERACTION_EXTENSION_NAME); + for (const String user_path : { "/user/hand/left", "/user/hand/right" }) { + metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + + metadata->register_io_path(profile_path, "Menu click", user_path, user_path + "/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "System click", user_path, user_path + "/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path(profile_path, "Trigger touch", user_path, user_path + "/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Squeeze", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + + metadata->register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick touch", user_path, user_path + "/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + } + + metadata->register_io_path(profile_path, "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + } + + { // Pico 4 controller. + const String profile_path = "/interaction_profiles/bytedance/pico4_controller"; + metadata->register_interaction_profile("Pico 4 controller", profile_path, XR_BD_CONTROLLER_INTERACTION_EXTENSION_NAME); + for (const String user_path : { "/user/hand/left", "/user/hand/right" }) { + metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + + metadata->register_io_path(profile_path, "System click", user_path, user_path + "/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path(profile_path, "Trigger touch", user_path, user_path + "/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Squeeze", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + + metadata->register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick touch", user_path, user_path + "/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + } + + metadata->register_io_path(profile_path, "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + // Note, no menu on right controller! + + metadata->register_io_path(profile_path, "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + } } diff --git a/modules/openxr/extensions/openxr_valve_analog_threshold_extension.cpp b/modules/openxr/extensions/openxr_valve_analog_threshold_extension.cpp new file mode 100644 index 000000000000..ac17d4766d77 --- /dev/null +++ b/modules/openxr/extensions/openxr_valve_analog_threshold_extension.cpp @@ -0,0 +1,193 @@ +/**************************************************************************/ +/* openxr_valve_analog_threshold_extension.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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_valve_analog_threshold_extension.h" +#include "../action_map/openxr_action_set.h" +#include "../action_map/openxr_interaction_profile.h" +#include "../openxr_api.h" + +// Implementation for: +// https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#XR_VALVE_analog_threshold + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// OpenXRValveAnalogThresholdExtension + +OpenXRValveAnalogThresholdExtension *OpenXRValveAnalogThresholdExtension::singleton = nullptr; + +OpenXRValveAnalogThresholdExtension *OpenXRValveAnalogThresholdExtension::get_singleton() { + return singleton; +} + +OpenXRValveAnalogThresholdExtension::OpenXRValveAnalogThresholdExtension() { + singleton = this; +} + +OpenXRValveAnalogThresholdExtension::~OpenXRValveAnalogThresholdExtension() { + singleton = nullptr; +} + +HashMap OpenXRValveAnalogThresholdExtension::get_requested_extensions() { + HashMap request_extensions; + + // Note, we're dependent on the binding modifier extension, this may be requested by multiple extension wrappers. + request_extensions[XR_KHR_BINDING_MODIFICATION_EXTENSION_NAME] = &binding_modifier_ext; + request_extensions[XR_VALVE_ANALOG_THRESHOLD_EXTENSION_NAME] = &threshold_ext; + + return request_extensions; +} + +bool OpenXRValveAnalogThresholdExtension::is_available() { + return binding_modifier_ext && threshold_ext; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// OpenXRAnalogThresholdModifier + +void OpenXRAnalogThresholdModifier::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_on_threshold", "on_threshold"), &OpenXRAnalogThresholdModifier::set_on_threshold); + ClassDB::bind_method(D_METHOD("get_on_threshold"), &OpenXRAnalogThresholdModifier::get_on_threshold); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "on_threshold", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_on_threshold", "get_on_threshold"); + + ClassDB::bind_method(D_METHOD("set_off_threshold", "off_threshold"), &OpenXRAnalogThresholdModifier::set_off_threshold); + ClassDB::bind_method(D_METHOD("get_off_threshold"), &OpenXRAnalogThresholdModifier::get_off_threshold); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "off_threshold", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_off_threshold", "get_off_threshold"); + + ClassDB::bind_method(D_METHOD("set_on_haptic", "haptic"), &OpenXRAnalogThresholdModifier::set_on_haptic); + ClassDB::bind_method(D_METHOD("get_on_haptic"), &OpenXRAnalogThresholdModifier::get_on_haptic); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "on_haptic", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRHapticBase"), "set_on_haptic", "get_on_haptic"); + + ClassDB::bind_method(D_METHOD("set_off_haptic", "haptic"), &OpenXRAnalogThresholdModifier::set_off_haptic); + ClassDB::bind_method(D_METHOD("get_off_haptic"), &OpenXRAnalogThresholdModifier::get_off_haptic); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "off_haptic", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRHapticBase"), "set_off_haptic", "get_off_haptic"); +} + +OpenXRAnalogThresholdModifier::OpenXRAnalogThresholdModifier() { + analog_threshold.type = XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE; + analog_threshold.next = nullptr; + + analog_threshold.onThreshold = 0.6; + analog_threshold.offThreshold = 0.4; +} + +void OpenXRAnalogThresholdModifier::set_on_threshold(float p_threshold) { + ERR_FAIL_COND(p_threshold < 0.0 || p_threshold > 1.0); + + analog_threshold.onThreshold = p_threshold; + emit_changed(); +} + +float OpenXRAnalogThresholdModifier::get_on_threshold() const { + return analog_threshold.onThreshold; +} + +void OpenXRAnalogThresholdModifier::set_off_threshold(float p_threshold) { + ERR_FAIL_COND(p_threshold < 0.0 || p_threshold > 1.0); + + analog_threshold.offThreshold = p_threshold; + emit_changed(); +} + +float OpenXRAnalogThresholdModifier::get_off_threshold() const { + return analog_threshold.offThreshold; +} + +void OpenXRAnalogThresholdModifier::set_on_haptic(const Ref p_haptic) { + on_haptic = p_haptic; + emit_changed(); +} + +Ref OpenXRAnalogThresholdModifier::get_on_haptic() const { + return on_haptic; +} + +void OpenXRAnalogThresholdModifier::set_off_haptic(const Ref p_haptic) { + off_haptic = p_haptic; + emit_changed(); +} + +Ref OpenXRAnalogThresholdModifier::get_off_haptic() const { + return off_haptic; +} + +PackedByteArray OpenXRAnalogThresholdModifier::get_ip_modification() { + PackedByteArray ret; + + OpenXRAPI *openxr_api = OpenXRAPI::get_singleton(); + ERR_FAIL_NULL_V(openxr_api, ret); + + OpenXRValveAnalogThresholdExtension *analog_threshold_ext = OpenXRValveAnalogThresholdExtension::get_singleton(); + if (!analog_threshold_ext || !analog_threshold_ext->is_available()) { + // Extension not enabled! + WARN_PRINT("Analog threshold extension is not enabled or available."); + return ret; + } + + ERR_FAIL_NULL_V(ip_binding, ret); + + Ref action = ip_binding->get_action(); + ERR_FAIL_COND_V(!action.is_valid(), ret); + + // Get our action set + Ref action_set = action->get_action_set(); + ERR_FAIL_COND_V(!action_set.is_valid(), ret); + RID action_set_rid = openxr_api->find_action_set(action_set->get_name()); + ERR_FAIL_COND_V(!action_set_rid.is_valid(), ret); + + // Get our action + RID action_rid = openxr_api->find_action(action->get_name(), action_set_rid); + ERR_FAIL_COND_V(!action_rid.is_valid(), ret); + + analog_threshold.action = openxr_api->action_get_handle(action_rid); + + analog_threshold.binding = openxr_api->get_xr_path(ip_binding->get_binding_path()); + ERR_FAIL_COND_V(analog_threshold.binding == XR_NULL_PATH, ret); + + // These are set already: + // - analog_threshold.onThreshold + // - analog_threshold.offThreshold + + if (on_haptic.is_valid()) { + analog_threshold.onHaptic = on_haptic->get_xr_structure(); + } else { + analog_threshold.onHaptic = nullptr; + } + + if (off_haptic.is_valid()) { + analog_threshold.offHaptic = off_haptic->get_xr_structure(); + } else { + analog_threshold.offHaptic = nullptr; + } + + // Copy into byte array so we can return it. + ERR_FAIL_COND_V(ret.resize(sizeof(XrInteractionProfileAnalogThresholdVALVE)) != OK, ret); + memcpy(&analog_threshold, ret.ptrw(), sizeof(XrInteractionProfileAnalogThresholdVALVE)); + + return ret; +} diff --git a/modules/openxr/extensions/openxr_valve_analog_threshold_extension.h b/modules/openxr/extensions/openxr_valve_analog_threshold_extension.h new file mode 100644 index 000000000000..7a71ab40f01b --- /dev/null +++ b/modules/openxr/extensions/openxr_valve_analog_threshold_extension.h @@ -0,0 +1,88 @@ +/**************************************************************************/ +/* openxr_valve_analog_threshold_extension.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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_VALVE_ANALOG_THRESHOLD_EXTENSION_H +#define OPENXR_VALVE_ANALOG_THRESHOLD_EXTENSION_H + +#include "../action_map/openxr_binding_modifier.h" +#include "../action_map/openxr_haptic_feedback.h" +#include "../util.h" +#include "core/io/resource.h" +#include "openxr_extension_wrapper.h" + +class OpenXRValveAnalogThresholdExtension : public OpenXRExtensionWrapper { +public: + static OpenXRValveAnalogThresholdExtension *get_singleton(); + + OpenXRValveAnalogThresholdExtension(); + virtual ~OpenXRValveAnalogThresholdExtension() override; + + virtual HashMap get_requested_extensions() override; + + bool is_available(); + +private: + static OpenXRValveAnalogThresholdExtension *singleton; + + bool binding_modifier_ext = false; + bool threshold_ext = false; +}; + +class OpenXRAnalogThresholdModifier : public OpenXRBindingModifier { + GDCLASS(OpenXRAnalogThresholdModifier, OpenXRBindingModifier); + +private: + XrInteractionProfileAnalogThresholdVALVE analog_threshold; + Ref on_haptic; + Ref off_haptic; + +protected: + static void _bind_methods(); + +public: + OpenXRAnalogThresholdModifier(); + + void set_on_threshold(float p_threshold); + float get_on_threshold() const; + + void set_off_threshold(float p_threshold); + float get_off_threshold() const; + + void set_on_haptic(const Ref p_haptic); + Ref get_on_haptic() const; + + void set_off_haptic(const Ref p_haptic); + Ref get_off_haptic() const; + + virtual String get_description() const override { return "Analog threshold modifier"; } + virtual PackedByteArray get_ip_modification() override; +}; + +#endif // OPENXR_VALVE_ANALOG_THRESHOLD_EXTENSION_H diff --git a/modules/openxr/extensions/openxr_wmr_controller_extension.cpp b/modules/openxr/extensions/openxr_wmr_controller_extension.cpp index 343732045211..6b0ccca3ea43 100644 --- a/modules/openxr/extensions/openxr_wmr_controller_extension.cpp +++ b/modules/openxr/extensions/openxr_wmr_controller_extension.cpp @@ -51,90 +51,85 @@ void OpenXRWMRControllerExtension::on_register_metadata() { OpenXRInteractionProfileMetadata *metadata = OpenXRInteractionProfileMetadata::get_singleton(); ERR_FAIL_NULL(metadata); - // HP MR controller (newer G2 controllers) - metadata->register_interaction_profile("HPMR controller", "/interaction_profiles/hp/mixed_reality_controller", XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME); - metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - - metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Menu click", "/user/hand/right", "/user/hand/right/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Squeeze", "/user/hand/left", "/user/hand/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Squeeze", "/user/hand/right", "/user/hand/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - - metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - - // Samsung Odyssey controller - metadata->register_interaction_profile("Samsung Odyssey controller", "/interaction_profiles/samsung/odyssey_controller", XR_EXT_SAMSUNG_ODYSSEY_CONTROLLER_EXTENSION_NAME); - metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - - metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Menu click", "/user/hand/right", "/user/hand/right/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Squeeze click", "/user/hand/left", "/user/hand/left/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Squeeze click", "/user/hand/right", "/user/hand/right/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad", "/user/hand/left", "/user/hand/left/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad click", "/user/hand/left", "/user/hand/left/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad touch", "/user/hand/left", "/user/hand/left/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad", "/user/hand/right", "/user/hand/right/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad click", "/user/hand/right", "/user/hand/right/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad touch", "/user/hand/right", "/user/hand/right/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - - // MSFT Hand interaction profile, also supported by other headsets - metadata->register_interaction_profile("MSFT Hand interaction", "/interaction_profiles/microsoft/hand_interaction", XR_MSFT_HAND_INTERACTION_EXTENSION_NAME); - metadata->register_io_path("/interaction_profiles/microsoft/hand_interaction", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/microsoft/hand_interaction", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/microsoft/hand_interaction", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/microsoft/hand_interaction", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/microsoft/hand_interaction", "Pinch pose", "/user/hand/left", "/user/hand/left/input/pinch_ext/pose", XR_EXT_HAND_INTERACTION_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/microsoft/hand_interaction", "Pinch pose", "/user/hand/right", "/user/hand/right/input/pinch_ext/pose", XR_EXT_HAND_INTERACTION_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/microsoft/hand_interaction", "Poke pose", "/user/hand/left", "/user/hand/left/input/poke_ext/pose", XR_EXT_HAND_INTERACTION_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/microsoft/hand_interaction", "Poke pose", "/user/hand/right", "/user/hand/right/input/poke_ext/pose", XR_EXT_HAND_INTERACTION_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/microsoft/hand_interaction", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - metadata->register_io_path("/interaction_profiles/microsoft/hand_interaction", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - - metadata->register_io_path("/interaction_profiles/microsoft/hand_interaction", "Select (pinch)", "/user/hand/left", "/user/hand/left/input/select/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/microsoft/hand_interaction", "Select (pinch)", "/user/hand/right", "/user/hand/right/input/select/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - - metadata->register_io_path("/interaction_profiles/microsoft/hand_interaction", "Squeeze (grab)", "/user/hand/left", "/user/hand/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - metadata->register_io_path("/interaction_profiles/microsoft/hand_interaction", "Squeeze (grab)", "/user/hand/right", "/user/hand/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + { // HP MR controller (newer G2 controllers) + const String profile_path = "/interaction_profiles/hp/mixed_reality_controller"; + metadata->register_interaction_profile("HPMR controller", profile_path, XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME); + for (const String user_path : { "/user/hand/left", "/user/hand/right" }) { + metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + + metadata->register_io_path(profile_path, "Menu click", user_path, user_path + "/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path(profile_path, "Trigger click", user_path, user_path + "/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Squeeze", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + + metadata->register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + } + + metadata->register_io_path(profile_path, "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + } + + { // Samsung Odyssey controller + const String profile_path = "/interaction_profiles/samsung/odyssey_controller"; + metadata->register_interaction_profile("Samsung Odyssey controller", profile_path, XR_EXT_SAMSUNG_ODYSSEY_CONTROLLER_EXTENSION_NAME); + for (const String user_path : { "/user/hand/left", "/user/hand/right" }) { + metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + + metadata->register_io_path(profile_path, "Menu click", user_path, user_path + "/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path(profile_path, "Trigger click", user_path, user_path + "/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Squeeze click", user_path, user_path + "/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Trackpad", user_path, user_path + "/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path(profile_path, "Trackpad click", user_path, user_path + "/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trackpad touch", user_path, user_path + "/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trackpad Dpad Up", user_path, user_path + "/input/trackpad/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trackpad Dpad Down", user_path, user_path + "/input/trackpad/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trackpad Dpad Left", user_path, user_path + "/input/trackpad/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trackpad Dpad Right", user_path, user_path + "/input/trackpad/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trackpad Dpad Center", user_path, user_path + "/input/trackpad/dpad_center", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + } + } + + { // MSFT Hand interaction profile, also supported by other headsets + const String profile_path = "/interaction_profiles/microsoft/hand_interaction"; + metadata->register_interaction_profile("MSFT Hand interaction", profile_path, XR_MSFT_HAND_INTERACTION_EXTENSION_NAME); + for (const String user_path : { "/user/hand/left", "/user/hand/right" }) { + metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path(profile_path, "Pinch pose", user_path, user_path + "/input/pinch_ext/pose", XR_EXT_HAND_INTERACTION_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path(profile_path, "Poke pose", user_path, user_path + "/input/poke_ext/pose", XR_EXT_HAND_INTERACTION_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + + metadata->register_io_path(profile_path, "Select (pinch)", user_path, user_path + "/input/select/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + + metadata->register_io_path(profile_path, "Squeeze (grab)", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + } + } } diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index c67be5a2b313..9fc97a35c346 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -513,6 +513,24 @@ void OpenXRAPI::copy_string_to_char_buffer(const String p_string, char *p_buffer } } +PackedStringArray OpenXRAPI::get_all_requested_extensions() { + // This returns all extensions we will request regardless of whether they are available. + // This is mostly used by the editor to filter features not enabled through project settings. + + PackedStringArray requested_extensions; + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + const HashMap &wrapper_request_extensions = wrapper->get_requested_extensions(); + + for (const KeyValue &requested_extension : wrapper_request_extensions) { + if (!requested_extensions.has(requested_extension.key)) { + requested_extensions.push_back(requested_extension.key); + } + } + } + + return requested_extensions; +} + bool OpenXRAPI::create_instance() { // Create our OpenXR instance, this will query any registered extension wrappers for extensions we need to enable. @@ -542,11 +560,23 @@ bool OpenXRAPI::create_instance() { // Set this extension as supported. *requested_extension.value = true; - // And record that we want to enable it. - enabled_extensions.push_back(requested_extension.key.ascii()); + // And record that we want to enable it (dependent extensions may be requested multiple times). + CharString ext_name = requested_extension.key.ascii(); + if (!enabled_extensions.has(ext_name)) { + enabled_extensions.push_back(ext_name); + } else { + // just testing + print_line("Extension " + requested_extension.key + " was already requested."); + } } else { - // Record that we want to enable this. - enabled_extensions.push_back(requested_extension.key.ascii()); + // Record that we want to enable this (dependent extensions may be requested multiple times). + CharString ext_name = requested_extension.key.ascii(); + if (!enabled_extensions.has(ext_name)) { + enabled_extensions.push_back(ext_name); + } else { + // just testing + print_line("Extension " + requested_extension.key + " was already requested."); + } } } @@ -2763,6 +2793,25 @@ bool OpenXRAPI::xr_result(XrResult result, const char *format, Array args) const return false; } +XrPath OpenXRAPI::get_xr_path(const String &p_path) { + ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, XR_NULL_PATH); + + if (p_path.is_empty()) { + // This isn't necesairily an issue, so silently return a null path. + return XR_NULL_PATH; + } + + XrPath path = XR_NULL_PATH; + + XrResult result = xrStringToPath(instance, p_path.utf8().get_data(), &path); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to get path for ", p_path, "! [", get_error_string(result), "]"); + return XR_NULL_PATH; + } + + return path; +} + RID OpenXRAPI::get_tracker_rid(XrPath p_path) { List current; tracker_owner.get_owned_list(¤t); @@ -2797,11 +2846,8 @@ RID OpenXRAPI::tracker_create(const String p_name) { new_tracker.toplevel_path = XR_NULL_PATH; new_tracker.active_profile_rid = RID(); - XrResult result = xrStringToPath(instance, p_name.utf8().get_data(), &new_tracker.toplevel_path); - if (XR_FAILED(result)) { - print_line("OpenXR: failed to get path for ", p_name, "! [", get_error_string(result), "]"); - return RID(); - } + new_tracker.toplevel_path = get_xr_path(p_name); + ERR_FAIL_COND_V(new_tracker.toplevel_path == XR_NULL_PATH, RID()); return tracker_owner.make_rid(new_tracker); } @@ -2892,6 +2938,19 @@ RID OpenXRAPI::action_set_create(const String p_name, const String p_localized_n return action_set_owner.make_rid(action_set); } +RID OpenXRAPI::find_action_set(const String p_name) { + List current; + action_set_owner.get_owned_list(¤t); + for (const RID &E : current) { + ActionSet *action_set = action_set_owner.get_or_null(E); + if (action_set && action_set->name == p_name) { + return E; + } + } + + return RID(); +} + String OpenXRAPI::action_set_get_name(RID p_action_set) { if (p_action_set.is_null()) { return String("None"); @@ -2903,6 +2962,17 @@ String OpenXRAPI::action_set_get_name(RID p_action_set) { return action_set->name; } +XrActionSet OpenXRAPI::action_set_get_handle(RID p_action_set) { + if (p_action_set.is_null()) { + return XR_NULL_HANDLE; + } + + ActionSet *action_set = action_set_owner.get_or_null(p_action_set); + ERR_FAIL_NULL_V(action_set, XR_NULL_HANDLE); + + return action_set->handle; +} + bool OpenXRAPI::attach_action_sets(const Vector &p_action_sets) { ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false); @@ -2985,12 +3055,12 @@ RID OpenXRAPI::get_action_rid(XrAction p_action) { return RID(); } -RID OpenXRAPI::find_action(const String &p_name) { +RID OpenXRAPI::find_action(const String &p_name, const RID &p_action_set) { List current; action_owner.get_owned_list(¤t); for (const RID &E : current) { Action *action = action_owner.get_or_null(E); - if (action && action->name == p_name) { + if (action && action->name == p_name && (p_action_set.is_null() || action->action_set_rid == p_action_set)) { return E; } } @@ -3080,6 +3150,17 @@ String OpenXRAPI::action_get_name(RID p_action) { return action->name; } +XrAction OpenXRAPI::action_get_handle(RID p_action) { + if (p_action.is_null()) { + return XR_NULL_HANDLE; + } + + Action *action = action_owner.get_or_null(p_action); + ERR_FAIL_NULL_V(action, XR_NULL_HANDLE); + + return action->handle; +} + void OpenXRAPI::action_free(RID p_action) { Action *action = action_owner.get_or_null(p_action); ERR_FAIL_NULL(action); @@ -3156,29 +3237,41 @@ void OpenXRAPI::interaction_profile_clear_bindings(RID p_interaction_profile) { ip->bindings.clear(); } -bool OpenXRAPI::interaction_profile_add_binding(RID p_interaction_profile, RID p_action, const String p_path) { +int OpenXRAPI::interaction_profile_add_binding(RID p_interaction_profile, RID p_action, const String p_path) { InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile); - ERR_FAIL_NULL_V(ip, false); + ERR_FAIL_NULL_V(ip, -1); if (!interaction_profile_supports_io_path(ip->name, p_path)) { - return false; + return -1; } XrActionSuggestedBinding binding; Action *action = action_owner.get_or_null(p_action); - ERR_FAIL_COND_V(action == nullptr || action->handle == XR_NULL_HANDLE, false); + ERR_FAIL_COND_V(action == nullptr || action->handle == XR_NULL_HANDLE, -1); binding.action = action->handle; XrResult result = xrStringToPath(instance, p_path.utf8().get_data(), &binding.binding); if (XR_FAILED(result)) { print_line("OpenXR: failed to get path for ", p_path, "! [", get_error_string(result), "]"); - return false; + return -1; } ip->bindings.push_back(binding); + return ip->bindings.size() - 1; +} + +bool OpenXRAPI::interaction_profile_add_modifier(RID p_interaction_profile, const PackedByteArray &p_modifier) { + InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile); + ERR_FAIL_NULL_V(ip, false); + + if (!p_modifier.is_empty()) { + // Add it to our stack. + ip->modifiers.push_back(p_modifier); + } + return true; } @@ -3188,9 +3281,26 @@ bool OpenXRAPI::interaction_profile_suggest_bindings(RID p_interaction_profile) InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile); ERR_FAIL_NULL_V(ip, false); + void *next = nullptr; + + // Note, extensions should only add binding modifiers if they are supported, else this may fail. + XrBindingModificationsKHR binding_modifiers; + Vector modifiers; + if (!ip->modifiers.is_empty()) { + for (const PackedByteArray &modifier : ip->modifiers) { + modifiers.push_back((const XrBindingModificationBaseHeaderKHR *)modifier.ptr()); + } + + binding_modifiers.type = XR_TYPE_BINDING_MODIFICATIONS_KHR; + binding_modifiers.next = next; + binding_modifiers.bindingModificationCount = modifiers.size(); + binding_modifiers.bindingModifications = modifiers.ptr(); + next = &binding_modifiers; + } + const XrInteractionProfileSuggestedBinding suggested_bindings = { XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING, // type - nullptr, // next + next, // next ip->path, // interactionProfile uint32_t(ip->bindings.size()), // countSuggestedBindings ip->bindings.ptr() // suggestedBindings @@ -3229,6 +3339,7 @@ void OpenXRAPI::interaction_profile_free(RID p_interaction_profile) { ERR_FAIL_NULL(ip); ip->bindings.clear(); + ip->modifiers.clear(); interaction_profile_owner.free(p_interaction_profile); } diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h index 0d1e4eb414ac..0cd0873baa6a 100644 --- a/modules/openxr/openxr_api.h +++ b/modules/openxr/openxr_api.h @@ -300,6 +300,7 @@ class OpenXRAPI { String name; // Name of the interaction profile (i.e. "/interaction_profiles/valve/index_controller") XrPath path; // OpenXR path for this profile Vector bindings; // OpenXR action bindings + Vector modifiers; // Array of modifiers we'll add into XrBindingModificationsKHR }; RID_Owner interaction_profile_owner; RID get_interaction_profile_rid(XrPath p_path); @@ -410,8 +411,8 @@ class OpenXRAPI { 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); - bool xr_result(XrResult result, const char *format, Array args = Array()) const; + XrPath get_xr_path(const String &p_path); bool is_top_level_path_supported(const String &p_toplevel_path); bool is_interaction_profile_supported(const String &p_ip_path); bool interaction_profile_supports_io_path(const String &p_ip_path, const String &p_io_path); @@ -435,6 +436,7 @@ class OpenXRAPI { static const Vector &get_registered_extension_wrappers(); static void register_extension_metadata(); static void cleanup_extension_wrappers(); + static PackedStringArray get_all_requested_extensions(); void set_form_factor(XrFormFactor p_form_factor); XrFormFactor get_form_factor() const { return form_factor; } @@ -515,22 +517,26 @@ class OpenXRAPI { RID action_set_create(const String p_name, const String p_localized_name, const int p_priority); String action_set_get_name(RID p_action_set); + XrActionSet action_set_get_handle(RID p_action_set); bool attach_action_sets(const Vector &p_action_sets); 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 &p_trackers); String action_get_name(RID p_action); + XrAction action_get_handle(RID p_action); void action_free(RID p_action); RID interaction_profile_create(const String p_name); String interaction_profile_get_name(RID p_interaction_profile); void interaction_profile_clear_bindings(RID p_interaction_profile); - bool interaction_profile_add_binding(RID p_interaction_profile, RID p_action, const String p_path); + int interaction_profile_add_binding(RID p_interaction_profile, RID p_action, const String p_path); + bool interaction_profile_add_modifier(RID p_interaction_profile, const PackedByteArray &p_modifier); bool interaction_profile_suggest_bindings(RID p_interaction_profile); void interaction_profile_free(RID p_interaction_profile); RID find_tracker(const String &p_name); - RID find_action(const String &p_name); + RID find_action_set(const String p_name); + RID find_action(const String &p_name, const RID &p_action_set = RID()); bool sync_action_sets(const Vector p_active_sets); bool get_action_bool(RID p_action, RID p_tracker); diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp index 500a58acc37b..e05f307f919e 100644 --- a/modules/openxr/openxr_interface.cpp +++ b/modules/openxr/openxr_interface.cpp @@ -287,6 +287,13 @@ void OpenXRInterface::_load_action_map() { if (ip.is_valid()) { openxr_api->interaction_profile_clear_bindings(ip); + for (Ref xr_binding_modifier : xr_interaction_profile->get_binding_modifiers()) { + PackedByteArray bm = xr_binding_modifier->get_ip_modification(); + if (!bm.is_empty()) { + openxr_api->interaction_profile_add_modifier(ip, bm); + } + } + Array xr_bindings = xr_interaction_profile->get_bindings(); for (int j = 0; j < xr_bindings.size(); j++) { Ref xr_binding = xr_bindings[j]; @@ -300,7 +307,18 @@ void OpenXRInterface::_load_action_map() { continue; } - openxr_api->interaction_profile_add_binding(ip, action->action_rid, xr_binding->get_binding_path()); + int binding_no = openxr_api->interaction_profile_add_binding(ip, action->action_rid, xr_binding->get_binding_path()); + if (binding_no >= 0) { + for (Ref xr_binding_modifier : xr_binding->get_binding_modifiers()) { + // Binding modifiers on bindings can be added to the interaction profile. + PackedByteArray bm = xr_binding_modifier->get_ip_modification(); + if (!bm.is_empty()) { + openxr_api->interaction_profile_add_modifier(ip, bm); + } + + // And possibly in the future on the binding itself, we're just preparing for that eventuality. + } + } } // Now submit our suggestions diff --git a/modules/openxr/register_types.cpp b/modules/openxr/register_types.cpp index f3fda2517ce6..cb39c58e53a7 100644 --- a/modules/openxr/register_types.cpp +++ b/modules/openxr/register_types.cpp @@ -33,6 +33,7 @@ #include "action_map/openxr_action.h" #include "action_map/openxr_action_map.h" #include "action_map/openxr_action_set.h" +#include "action_map/openxr_haptic_feedback.h" #include "action_map/openxr_interaction_profile.h" #include "action_map/openxr_interaction_profile_metadata.h" #include "openxr_interface.h" @@ -49,6 +50,7 @@ #include "extensions/openxr_composition_layer_depth_extension.h" #include "extensions/openxr_composition_layer_extension.h" #include "extensions/openxr_debug_utils_extension.h" +#include "extensions/openxr_dpad_binding_extension.h" #include "extensions/openxr_eye_gaze_interaction.h" #include "extensions/openxr_fb_display_refresh_rate_extension.h" #include "extensions/openxr_hand_interaction_extension.h" @@ -62,6 +64,7 @@ #include "extensions/openxr_mxink_extension.h" #include "extensions/openxr_palm_pose_extension.h" #include "extensions/openxr_pico_controller_extension.h" +#include "extensions/openxr_valve_analog_threshold_extension.h" #include "extensions/openxr_visibility_mask_extension.h" #include "extensions/openxr_wmr_controller_extension.h" @@ -78,6 +81,10 @@ #ifdef TOOLS_ENABLED #include "editor/editor_node.h" + +#include "editor/openxr_binding_modifier_editor.h" +#include "editor/openxr_interaction_profile_editor.h" + #endif static OpenXRAPI *openxr_api = nullptr; @@ -140,6 +147,14 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) { if (GLOBAL_GET("xr/openxr/extensions/hand_tracking")) { OpenXRAPI::register_extension_wrapper(memnew(OpenXRHandTrackingExtension)); } + + // register gated binding modifiers + if (GLOBAL_GET("xr/openxr/binding_modifiers/analog_threshold")) { + OpenXRAPI::register_extension_wrapper(memnew(OpenXRValveAnalogThresholdExtension)); + } + if (GLOBAL_GET("xr/openxr/binding_modifiers/dpad_binding")) { + OpenXRAPI::register_extension_wrapper(memnew(OpenXRDPadBindingExtension)); + } } if (OpenXRAPI::openxr_is_enabled()) { @@ -181,6 +196,13 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) { GDREGISTER_CLASS(OpenXRIPBinding); GDREGISTER_CLASS(OpenXRInteractionProfile); + GDREGISTER_ABSTRACT_CLASS(OpenXRBindingModifier); + GDREGISTER_CLASS(OpenXRAnalogThresholdModifier); + GDREGISTER_CLASS(OpenXRDpadBindingModifier); + + GDREGISTER_ABSTRACT_CLASS(OpenXRHapticBase); + GDREGISTER_CLASS(OpenXRHapticVibration); + GDREGISTER_ABSTRACT_CLASS(OpenXRCompositionLayer); GDREGISTER_CLASS(OpenXRCompositionLayerEquirect); GDREGISTER_CLASS(OpenXRCompositionLayerCylinder); @@ -201,6 +223,10 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) { } #ifdef TOOLS_ENABLED + GDREGISTER_ABSTRACT_CLASS(OpenXRInteractionProfileEditorBase); + GDREGISTER_CLASS(OpenXRInteractionProfileEditor); + GDREGISTER_CLASS(OpenXRBindingModifierEditor); + EditorNode::add_init_callback(_editor_init); #endif }