Skip to content

Commit

Permalink
OpenXR: Add support for binding modifiers
Browse files Browse the repository at this point in the history
  • Loading branch information
BastiaanOlij committed Oct 30, 2024
1 parent 8004c75 commit 7d8bef8
Show file tree
Hide file tree
Showing 51 changed files with 3,167 additions and 813 deletions.
6 changes: 6 additions & 0 deletions doc/classes/ProjectSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2977,6 +2977,12 @@
<member name="threading/worker_pool/max_threads" type="int" setter="" getter="" default="-1">
Maximum number of threads to be used by [WorkerThreadPool]. Value of [code]-1[/code] means no limit.
</member>
<member name="xr/openxr/binding_modifiers/analog_threshold" type="bool" setter="" getter="" default="false">
Enables the analog threshold binding modifier if supported by the XR runtime.
</member>
<member name="xr/openxr/binding_modifiers/dpad_binding" type="bool" setter="" getter="" default="false">
Enabled the dpad binding modifier if supported by the XR runtime.
</member>
<member name="xr/openxr/default_action_map" type="String" setter="" getter="" default="&quot;res://openxr_action_map.tres&quot;">
Action map configuration to load by default.
</member>
Expand Down
1 change: 1 addition & 0 deletions editor/editor_inspector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4095,6 +4095,7 @@ void EditorInspector::_notification(int p_what) {
} break;

case NOTIFICATION_READY: {
ERR_FAIL_NULL(EditorFeatureProfileManager::get_singleton());
EditorFeatureProfileManager::get_singleton()->connect("current_feature_profile_changed", callable_mp(this, &EditorInspector::_feature_profile_changed));
set_process(is_visible_in_tree());
add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));
Expand Down
1 change: 1 addition & 0 deletions editor/icons/Modifiers.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 5 additions & 1 deletion main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2618,7 +2618,11 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
GLOBAL_DEF_BASIC("xr/openxr/extensions/hand_tracking_unobstructed_data_source", false); // XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT
GLOBAL_DEF_BASIC("xr/openxr/extensions/hand_tracking_controller_data_source", false); // XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT
GLOBAL_DEF_RST_BASIC("xr/openxr/extensions/hand_interaction_profile", false);
GLOBAL_DEF_BASIC("xr/openxr/extensions/eye_gaze_interaction", false);
GLOBAL_DEF_RST_BASIC("xr/openxr/extensions/eye_gaze_interaction", false);

// OpenXR Binding modifier settings
GLOBAL_DEF_BASIC("xr/openxr/binding_modifiers/analog_threshold", false);
GLOBAL_DEF_RST_BASIC("xr/openxr/binding_modifiers/dpad_binding", false);

#ifdef TOOLS_ENABLED
// Disabled for now, using XR inside of the editor we'll be working on during the coming months.
Expand Down
35 changes: 29 additions & 6 deletions modules/openxr/action_map/openxr_action_map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,26 @@ void OpenXRActionMap::remove_action_set(Ref<OpenXRActionSet> p_action_set) {
}
}

void OpenXRActionMap::set_interaction_profiles(Array p_interaction_profiles) {
void OpenXRActionMap::clear_interaction_profiles() {
if (interaction_profiles.size() == 0) {
return;
}

// Interaction profiles held within our action map set should be released and destroyed but just in case they are still used some where else.
for (int i = 0; i < interaction_profiles.size(); i++) {
Ref<OpenXRInteractionProfile> 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<OpenXRInteractionProfile> 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]);
}
}

Expand Down Expand Up @@ -147,6 +159,13 @@ void OpenXRActionMap::add_interaction_profile(Ref<OpenXRInteractionProfile> 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();
}
Expand All @@ -156,6 +175,10 @@ void OpenXRActionMap::remove_interaction_profile(Ref<OpenXRInteractionProfile> 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();
}
}
Expand Down Expand Up @@ -598,5 +621,5 @@ PackedStringArray OpenXRActionMap::get_top_level_paths(const Ref<OpenXRAction> p

OpenXRActionMap::~OpenXRActionMap() {
action_sets.clear();
interaction_profiles.clear();
clear_interaction_profiles();
}
1 change: 1 addition & 0 deletions modules/openxr/action_map/openxr_action_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class OpenXRActionMap : public Resource {
void add_action_set(Ref<OpenXRActionSet> p_action_set); // Add an action set to our action map
void remove_action_set(Ref<OpenXRActionSet> 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)

Expand Down
61 changes: 61 additions & 0 deletions modules/openxr/action_map/openxr_binding_modifier.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**************************************************************************/
/* 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() {
GDVIRTUAL_BIND(_record_on_binding);
GDVIRTUAL_BIND(_get_description);
GDVIRTUAL_BIND(_get_ip_modification);
}

bool OpenXRBindingModifier::record_on_binding() const {
bool res;
if (GDVIRTUAL_CALL(_record_on_binding, res)) {
return res;
}
return true;
}

String OpenXRBindingModifier::get_description() const {
String desc;
if (GDVIRTUAL_CALL(_get_description, desc)) {
return desc;
}
return "";
}

PackedByteArray OpenXRBindingModifier::get_ip_modification() {
PackedByteArray data;
if (GDVIRTUAL_CALL(_get_ip_modification, data)) {
return data;
}
return PackedByteArray();
}
70 changes: 70 additions & 0 deletions modules/openxr/action_map/openxr_binding_modifier.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**************************************************************************/
/* 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();

GDVIRTUAL0RC(bool, _record_on_binding)
GDVIRTUAL0RC(String, _get_description)
GDVIRTUAL0R(PackedByteArray, _get_ip_modification)

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; // 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; // Returns the description shown in the editor
virtual PackedByteArray get_ip_modification(); // Return the XrBindingModificationsKHR binding modifier struct data used when calling xrSuggestInteractionProfileBindings
};

#endif // OPENXR_BINDING_MODIFIER_H
93 changes: 93 additions & 0 deletions modules/openxr/action_map/openxr_haptic_feedback.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/**************************************************************************/
/* openxr_haptic_feedback.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/

#include "openxr_haptic_feedback.h"

////////////////////////////////////////////////////////////////////////////
// OpenXRHapticBase

void OpenXRHapticBase::_bind_methods() {
}

////////////////////////////////////////////////////////////////////////////
// OpenXRHapticVibration

void OpenXRHapticVibration::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_duration", "duration"), &OpenXRHapticVibration::set_duration);
ClassDB::bind_method(D_METHOD("get_duration"), &OpenXRHapticVibration::get_duration);
ADD_PROPERTY(PropertyInfo(Variant::INT, "duration"), "set_duration", "get_duration");

ClassDB::bind_method(D_METHOD("set_frequency", "frequency"), &OpenXRHapticVibration::set_frequency);
ClassDB::bind_method(D_METHOD("get_frequency"), &OpenXRHapticVibration::get_frequency);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frequency"), "set_frequency", "get_frequency");

ClassDB::bind_method(D_METHOD("set_amplitude", "amplitude"), &OpenXRHapticVibration::set_amplitude);
ClassDB::bind_method(D_METHOD("get_amplitude"), &OpenXRHapticVibration::get_amplitude);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "amplitude", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_amplitude", "get_amplitude");
}

void OpenXRHapticVibration::set_duration(int64_t p_duration) {
haptic_vibration.duration = p_duration;
emit_changed();
}

int64_t OpenXRHapticVibration::get_duration() const {
return haptic_vibration.duration;
}

void OpenXRHapticVibration::set_frequency(float p_frequency) {
haptic_vibration.frequency = p_frequency;
emit_changed();
}

float OpenXRHapticVibration::get_frequency() const {
return haptic_vibration.frequency;
}

void OpenXRHapticVibration::set_amplitude(float p_amplitude) {
haptic_vibration.amplitude = p_amplitude;
emit_changed();
}

float OpenXRHapticVibration::get_amplitude() const {
return haptic_vibration.amplitude;
}

const XrHapticBaseHeader *OpenXRHapticVibration::get_xr_structure() {
return (XrHapticBaseHeader *)&haptic_vibration;
}

OpenXRHapticVibration::OpenXRHapticVibration() {
haptic_vibration.type = XR_TYPE_HAPTIC_VIBRATION;
haptic_vibration.next = nullptr;
haptic_vibration.duration = -1;
haptic_vibration.frequency = 0.0;
haptic_vibration.amplitude = 1.0;
}
Loading

0 comments on commit 7d8bef8

Please sign in to comment.