From 3db345a2403b838d0a7344e010d42fcd9f741685 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 | 4 + .../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 | 92 +++++ .../action_map/openxr_haptic_feedback.h | 72 ++++ .../action_map/openxr_interaction_profile.cpp | 153 ++++++++ .../action_map/openxr_interaction_profile.h | 33 ++ .../openxr_interaction_profile_metadata.cpp | 335 +++++++++-------- modules/openxr/config.py | 10 + .../OpenXRAnalogThresholdEditor.xml | 9 + .../OpenXRAnalogThresholdModifier.xml | 20 ++ .../doc_classes/OpenXRBindingModifier.xml | 11 + .../OpenXRBindingModifierEditor.xml | 19 + .../doc_classes/OpenXRDpadBindingEditor.xml | 9 + .../doc_classes/OpenXRDpadBindingModifier.xml | 35 ++ .../openxr/doc_classes/OpenXRIPBinding.xml | 16 + .../doc_classes/OpenXRInteractionProfile.xml | 16 + .../OpenXRInteractionProfileEditor.xml | 9 + .../OpenXRInteractionProfileEditorBase.xml | 9 + .../editor/openxr_action_map_editor.cpp | 49 ++- .../openxr/editor/openxr_action_map_editor.h | 8 + .../editor/openxr_binding_modifier_editor.cpp | 236 ++++++++++++ .../editor/openxr_binding_modifier_editor.h | 110 ++++++ .../openxr_binding_modifiers_dialog.cpp | 266 ++++++++++++++ .../editor/openxr_binding_modifiers_dialog.h | 81 +++++ .../openxr/editor/openxr_editor_plugin.cpp | 3 + .../openxr_interaction_profile_editor.cpp | 106 ++++-- .../openxr_interaction_profile_editor.h | 30 +- .../openxr_dpad_binding_extension.cpp | 339 ++++++++++++++++++ .../openxr_dpad_binding_extension.h | 141 ++++++++ .../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 | 216 +++++++++++ .../openxr_valve_analog_threshold_extension.h | 112 ++++++ .../openxr_wmr_controller_extension.cpp | 167 +++++---- modules/openxr/openxr_api.cpp | 127 ++++++- modules/openxr/openxr_api.h | 11 +- modules/openxr/openxr_interface.cpp | 20 +- modules/openxr/register_types.cpp | 28 ++ 47 files changed, 3056 insertions(+), 782 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/OpenXRAnalogThresholdEditor.xml 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/OpenXRDpadBindingEditor.xml create mode 100644 modules/openxr/doc_classes/OpenXRDpadBindingModifier.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 4266bab2a175..8be3b8437d0b 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -2952,6 +2952,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..2d87ccde51f6 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -2604,6 +2604,10 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph GLOBAL_DEF_RST_BASIC("xr/openxr/extensions/hand_interaction_profile", false); GLOBAL_DEF_BASIC("xr/openxr/extensions/eye_gaze_interaction", false); + // OpenXR Binding modifier settings + GLOBAL_DEF_BASIC("xr/openxr/binding_modifiers/analog_threshold", false); + GLOBAL_DEF_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..20d563e3ddd8 --- /dev/null +++ b/modules/openxr/action_map/openxr_haptic_feedback.cpp @@ -0,0 +1,92 @@ +/**************************************************************************/ +/* 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 907da5997230..cc9ba39d0f75 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 ClassDB::bind_method(D_METHOD("set_paths", "paths"), &OpenXRIPBinding::set_paths); ClassDB::bind_method(D_METHOD("get_paths"), &OpenXRIPBinding::get_paths); @@ -80,6 +86,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(); + } +} + void OpenXRIPBinding::set_paths(const PackedStringArray p_paths) { // Deprecated, but needed for loading old action maps. // Fallback logic, this should ONLY be called when loading older action maps. // We'll parse this momentarily and extract individual bindings. @@ -147,6 +223,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) { @@ -274,6 +356,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 d51e79fdf523..4b62dce24dfc 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. void set_paths(const PackedStringArray p_paths); // Set our paths (for loading from resource), needed for loading old action maps. PackedStringArray get_paths() const; // Get our paths (for saving to resource), needed for converted old action maps. @@ -76,8 +95,13 @@ 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: @@ -100,6 +124,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..2f02229955eb 100644 --- a/modules/openxr/config.py +++ b/modules/openxr/config.py @@ -27,6 +27,16 @@ def get_doc_classes(): "OpenXRCompositionLayerQuad", "OpenXRCompositionLayerCylinder", "OpenXRCompositionLayerEquirect", + "OpenXRBindingModifier", + "OpenXRAnalogThresholdModifier", + "OpenXRDpadBindingModifier", + "OpenXRInteractionProfileEditorBase", + "OpenXRInteractionProfileEditor", + "OpenXRBindingModifierEditor", + "OpenXRAnalogThresholdEditor", + "OpenXRDpadBindingEditor", + "OpenXRHapticBase", + "OpenXRHapticVibration", ] diff --git a/modules/openxr/doc_classes/OpenXRAnalogThresholdEditor.xml b/modules/openxr/doc_classes/OpenXRAnalogThresholdEditor.xml new file mode 100644 index 000000000000..3ab58b8ad365 --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRAnalogThresholdEditor.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/modules/openxr/doc_classes/OpenXRAnalogThresholdModifier.xml b/modules/openxr/doc_classes/OpenXRAnalogThresholdModifier.xml new file mode 100644 index 000000000000..bd0df01cf501 --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRAnalogThresholdModifier.xml @@ -0,0 +1,20 @@ + + + + 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. + + + + + + When our input value falls below this, our output becomes false. + + + 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..813c9cc6c2bb --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRBindingModifierEditor.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/modules/openxr/doc_classes/OpenXRDpadBindingEditor.xml b/modules/openxr/doc_classes/OpenXRDpadBindingEditor.xml new file mode 100644 index 000000000000..4e0b826e1b61 --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRDpadBindingEditor.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/modules/openxr/doc_classes/OpenXRDpadBindingModifier.xml b/modules/openxr/doc_classes/OpenXRDpadBindingModifier.xml new file mode 100644 index 000000000000..1b54ef171087 --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRDpadBindingModifier.xml @@ -0,0 +1,35 @@ + + + + The DPad binding modifier converts an axis input to a dpad output. + + + The DPad binding modifier converts an axis input to a dpad output. New input paths for each dpad direction will be added to the interaction profile. + 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. + + + + + + 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. + + + 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. + + + + + diff --git a/modules/openxr/doc_classes/OpenXRIPBinding.xml b/modules/openxr/doc_classes/OpenXRIPBinding.xml index c5d894811362..a4ce0234deb9 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..05c431000231 --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRInteractionProfileEditor.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/modules/openxr/doc_classes/OpenXRInteractionProfileEditorBase.xml b/modules/openxr/doc_classes/OpenXRInteractionProfileEditorBase.xml new file mode 100644 index 000000000000..430380a679a4 --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRInteractionProfileEditorBase.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/modules/openxr/editor/openxr_action_map_editor.cpp b/modules/openxr/editor/openxr_action_map_editor.cpp index a353073f215b..3688c3734992 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,9 +104,17 @@ 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)); } @@ -195,8 +207,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 +233,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 +410,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 ""; +} + 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..27aad7e09c59 --- /dev/null +++ b/modules/openxr/editor/openxr_binding_modifier_editor.cpp @@ -0,0 +1,236 @@ +/**************************************************************************/ +/* 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 + +void OpenXRBindingModifierEditor::_bind_methods() { + 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); +} + +void OpenXRBindingModifierEditor::add_property_editor(const String &p_property, EditorProperty *p_editor) { + p_editor->set_label(p_property.capitalize()); + p_editor->connect("property_changed", callable_mp(this, &OpenXRBindingModifierEditor::_on_property_changed)); + main_vb->add_child(p_editor); + property_editors[StringName(p_property)] = p_editor; +} + +void OpenXRBindingModifierEditor::_on_property_changed(const String &p_property, const Variant &p_value, const String &p_name, bool p_changing) { + ERR_FAIL_NULL(undo_redo); + ERR_FAIL_COND(binding_modifier.is_null()); + + undo_redo->create_action(vformat(TTR("Modify '%s' for binding modifier '%s'"), p_property, binding_modifier->get_description())); + undo_redo->add_do_property(binding_modifier.ptr(), p_property, p_value); + undo_redo->add_do_method(property_editors[p_property], "update_property"); + undo_redo->add_undo_property(binding_modifier.ptr(), p_property, binding_modifier->get(p_property)); + undo_redo->add_undo_method(property_editors[p_property], "update_property"); + undo_redo->commit_action(); +} + +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); +} + +void OpenXRBindingModifierEditor::set_binding_modifier(Ref p_action_map, Ref p_binding_modifier) { + action_map = p_action_map; + binding_modifier = p_binding_modifier; + + binding_modifier_title->set_text(p_binding_modifier->get_description()); + + for (const KeyValue &editor : property_editors) { + editor.value->set_object_and_property(binding_modifier.ptr(), editor.key); + editor.value->update_property(); + } +} 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..5f040befd09d --- /dev/null +++ b/modules/openxr/editor/openxr_binding_modifier_editor.h @@ -0,0 +1,110 @@ +/**************************************************************************/ +/* 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 OpenXRBindingModifierEditor : public PanelContainer { + GDCLASS(OpenXRBindingModifierEditor, PanelContainer); + +private: + HBoxContainer *header_hb = nullptr; + Label *binding_modifier_title = nullptr; + Button *rem_binding_modifier_btn = nullptr; + +protected: + VBoxContainer *main_vb = nullptr; + HashMap property_editors; + + EditorUndoRedoManager *undo_redo; + Ref binding_modifier; + Ref action_map; + + static void _bind_methods(); + void _notification(int p_what); + + void add_property_editor(const String &p_property, EditorProperty *p_editor); + + void _on_remove_binding_modifier(); + +public: + Ref get_binding_modifier() const { return binding_modifier; } + + void _on_property_changed(const String &p_property, const Variant &p_value, const String &p_name, bool p_changing); + + virtual void set_binding_modifier(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..7ccbf50bc607 --- /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->set_binding_modifier(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..477dd9b01460 100644 --- a/modules/openxr/editor/openxr_editor_plugin.cpp +++ b/modules/openxr/editor/openxr_editor_plugin.cpp @@ -53,6 +53,9 @@ void OpenXREditorPlugin::make_visible(bool p_visible) { } OpenXREditorPlugin::OpenXREditorPlugin() { + OpenXRActionMapEditor::register_binding_modifier_editor("OpenXRAnalogThresholdModifier", "OpenXRAnalogThresholdEditor"); + OpenXRActionMapEditor::register_binding_modifier_editor("OpenXRDpadBindingModifier", "OpenXRDpadBindingEditor"); + 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"))); diff --git a/modules/openxr/editor/openxr_interaction_profile_editor.cpp b/modules/openxr/editor/openxr_interaction_profile_editor.cpp index 09a9a990ed9f..21d9be62829e 100644 --- a/modules/openxr/editor/openxr_interaction_profile_editor.cpp +++ b/modules/openxr/editor/openxr_interaction_profile_editor.cpp @@ -29,15 +29,8 @@ /**************************************************************************/ #include "openxr_interaction_profile_editor.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 @@ -112,12 +105,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 +142,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 +154,39 @@ void OpenXRInteractionProfileEditorBase::remove_all_bindings_for_action(Refpopup_centered(Size2i(500, 400)); +} + +OpenXRInteractionProfileEditorBase::OpenXRInteractionProfileEditorBase() { + // Note, this class is not normally instantiated this way except when Godot does introspection. +} OpenXRInteractionProfileEditorBase::OpenXRInteractionProfileEditorBase(Ref p_action_map, Ref p_interaction_profile) { 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); + binding_modifiers_dialog->setup(p_action_map, p_interaction_profile); + 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); + action_map = p_action_map; interaction_profile = p_interaction_profile; String profile_path = interaction_profile->get_interaction_profile_path(); @@ -152,8 +198,6 @@ OpenXRInteractionProfileEditorBase::OpenXRInteractionProfileEditorBase(Refset_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))); @@ -262,8 +317,8 @@ void OpenXRInteractionProfileEditor::_update_interaction_profile() { } // 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 +336,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); @@ -299,23 +354,30 @@ void OpenXRInteractionProfileEditor::_update_interaction_profile() { } } - // 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() { + // Note, this class is not normally instantiated this way except when Godot does introspection. +} + 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); + interaction_profile_hb = memnew(HBoxContainer); + interaction_profile_sc->add_child(interaction_profile_hb); 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..f65eedd8d697 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); + +private: + OpenXRBindingModifiersDialog *binding_modifiers_dialog = nullptr; + VBoxContainer *toolbar_vb = nullptr; + Button *binding_modifiers_btn = nullptr; -class OpenXRInteractionProfileEditorBase : public ScrollContainer { - GDCLASS(OpenXRInteractionProfileEditorBase, ScrollContainer); + 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(); @@ -57,15 +67,17 @@ class OpenXRInteractionProfileEditorBase : public ScrollContainer { public: 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); + OpenXRInteractionProfileEditorBase(); OpenXRInteractionProfileEditorBase(Ref p_action_map, Ref p_interaction_profile); }; @@ -74,7 +86,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,6 +99,7 @@ class OpenXRInteractionProfileEditor : public OpenXRInteractionProfileEditorBase virtual void _update_interaction_profile() override; virtual void _theme_changed() override; + OpenXRInteractionProfileEditor(); OpenXRInteractionProfileEditor(Ref p_action_map, Ref p_interaction_profile); }; 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..70b7d796e31e --- /dev/null +++ b/modules/openxr/extensions/openxr_dpad_binding_extension.cpp @@ -0,0 +1,339 @@ +/**************************************************************************/ +/* 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"), "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::FLOAT, "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->forceThresholdReleased; +} + +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; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// OpenXRDpadBindingEditor + +#ifdef TOOLS_ENABLED + +void OpenXRDpadBindingEditor::_bind_methods() { +} + +OpenXRDpadBindingEditor::OpenXRDpadBindingEditor() { + action_set_property = memnew(EditorPropertyActionSet); + add_property_editor("action_set", action_set_property); + + input_path_property = memnew(EditorPropertyBindingPath); + add_property_editor("input_path", input_path_property); + + threshold_property = memnew(EditorPropertyFloat); + threshold_property->setup(0.0, 1.0, 0.01, false, false, false, false, "", false); + add_property_editor("threshold", threshold_property); + + threshold_release_property = memnew(EditorPropertyFloat); + threshold_release_property->setup(0.0, 1.0, 0.01, false, false, false, false, "", false); + add_property_editor("threshold_released", threshold_release_property); + + center_region_property = memnew(EditorPropertyFloat); + center_region_property->setup(0.0, 1.0, 0.01, false, false, false, false, "", false); + add_property_editor("center_region", center_region_property); + + wedge_angle_property = memnew(EditorPropertyFloat); + wedge_angle_property->setup(0.0, 360.0, 1.0, false, false, false, false, "", true); + add_property_editor("wedge_angle", wedge_angle_property); + + is_sticky_property = memnew(EditorPropertyCheck); + add_property_editor("is_sticky", is_sticky_property); + + on_haptic_property = memnew(EditorPropertyResource); + // on_haptic_property->set_use_sub_inspector(false); + add_property_editor("on_haptic", on_haptic_property); + + off_haptic_property = memnew(EditorPropertyResource); + // off_haptic_property->set_use_sub_inspector(false); + add_property_editor("off_haptic", off_haptic_property); +} + +void OpenXRDpadBindingEditor::set_binding_modifier(Ref p_action_map, Ref p_binding_modifier) { + if (p_action_map.is_valid()) { + action_set_property->setup(p_action_map); + } + + if (p_binding_modifier.is_valid()) { + OpenXRInteractionProfile *interaction_profile = p_binding_modifier->get_interaction_profile(); + if (interaction_profile) { + Vector action_types; + action_types.push_back(OpenXRAction::OPENXR_ACTION_VECTOR2); + input_path_property->setup(interaction_profile->get_interaction_profile_path(), action_types); + } + + on_haptic_property->setup(p_binding_modifier.ptr(), "on_haptic", "OpenXRHapticBase"); + off_haptic_property->setup(p_binding_modifier.ptr(), "off_haptic", "OpenXRHapticBase"); + } + + OpenXRBindingModifierEditor::set_binding_modifier(p_action_map, p_binding_modifier); +} + +#endif // TOOLS_ENABLED 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..2caf8d6e3113 --- /dev/null +++ b/modules/openxr/extensions/openxr_dpad_binding_extension.h @@ -0,0 +1,141 @@ +/**************************************************************************/ +/* 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" + +#ifdef TOOLS_ENABLED +#include "../editor/openxr_binding_modifier_editor.h" +#endif // TOOLS_ENABLED + +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; +}; + +#ifdef TOOLS_ENABLED + +class OpenXRDpadBindingEditor : public OpenXRBindingModifierEditor { + GDCLASS(OpenXRDpadBindingEditor, OpenXRBindingModifierEditor); + +private: + EditorPropertyActionSet *action_set_property = nullptr; + EditorPropertyBindingPath *input_path_property = nullptr; + EditorPropertyFloat *threshold_property = nullptr; + EditorPropertyFloat *threshold_release_property = nullptr; + EditorPropertyFloat *center_region_property = nullptr; + EditorPropertyFloat *wedge_angle_property = nullptr; + EditorPropertyCheck *is_sticky_property = nullptr; + EditorPropertyResource *on_haptic_property = nullptr; + EditorPropertyResource *off_haptic_property = nullptr; + +protected: + static void _bind_methods(); + +public: + virtual void set_binding_modifier(Ref p_action_map, Ref p_binding_modifier) override; + + OpenXRDpadBindingEditor(); +}; + +#endif // TOOLS_ENABLED + +#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..eb59c19bb35a --- /dev/null +++ b/modules/openxr/extensions/openxr_valve_analog_threshold_extension.cpp @@ -0,0 +1,216 @@ +/**************************************************************************/ +/* 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 "../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; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// OpenXRAnalogThresholdEditor + +#ifdef TOOLS_ENABLED + +void OpenXRAnalogThresholdEditor::_bind_methods() { +} + +OpenXRAnalogThresholdEditor::OpenXRAnalogThresholdEditor() { + on_threshold_property = memnew(EditorPropertyFloat); + on_threshold_property->setup(0.0, 1.0, 0.01, false, false, false, false, "", false); + add_property_editor("on_threshold", on_threshold_property); + + off_threshold_property = memnew(EditorPropertyFloat); + off_threshold_property->setup(0.0, 1.0, 0.01, false, false, false, false, "", false); + add_property_editor("off_threshold", off_threshold_property); +} + +void OpenXRAnalogThresholdEditor::set_binding_modifier(Ref p_action_map, Ref p_binding_modifier) { + OpenXRBindingModifierEditor::set_binding_modifier(p_action_map, p_binding_modifier); +} + +#endif // TOOLS_ENABLED 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..7f517949d80d --- /dev/null +++ b/modules/openxr/extensions/openxr_valve_analog_threshold_extension.h @@ -0,0 +1,112 @@ +/**************************************************************************/ +/* 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" + +#ifdef TOOLS_ENABLED +#include "../editor/openxr_binding_modifier_editor.h" +#endif // TOOLS_ENABLED + +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; +}; + +#ifdef TOOLS_ENABLED + +class OpenXRAnalogThresholdEditor : public OpenXRBindingModifierEditor { + GDCLASS(OpenXRAnalogThresholdEditor, OpenXRBindingModifierEditor); + +private: + EditorPropertyFloat *on_threshold_property = nullptr; + EditorPropertyFloat *off_threshold_property = nullptr; + +protected: + static void _bind_methods(); + +public: + virtual void set_binding_modifier(Ref p_action_map, Ref p_binding_modifier) override; + + OpenXRAnalogThresholdEditor(); +}; + +#endif // TOOLS_ENABLED + +#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..8215a9ee035c 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -542,11 +542,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 +2775,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 +2828,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 +2920,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 +2944,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 +3037,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 +3132,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 +3219,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 +3263,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 +3321,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..537ce5a4b635 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); @@ -515,22 +516,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..3c396d36efe8 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 (const 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 (const 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..2a4f4ce6e551 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,12 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) { } #ifdef TOOLS_ENABLED + GDREGISTER_ABSTRACT_CLASS(OpenXRInteractionProfileEditorBase); + GDREGISTER_CLASS(OpenXRInteractionProfileEditor); + GDREGISTER_ABSTRACT_CLASS(OpenXRBindingModifierEditor); + GDREGISTER_CLASS(OpenXRAnalogThresholdEditor); + GDREGISTER_CLASS(OpenXRDpadBindingEditor); + EditorNode::add_init_callback(_editor_init); #endif }