feat: updated engine version to 4.4-rc1

This commit is contained in:
Sara 2025-02-23 14:38:14 +01:00
parent ee00efde1f
commit 21ba8e33af
5459 changed files with 1128836 additions and 198305 deletions

View file

@ -1,4 +1,7 @@
#!/usr/bin/env python
from misc.utility.scons_hints import *
import sys
Import("env")
Import("env_modules")
@ -25,10 +28,12 @@ elif env["platform"] == "linuxbsd":
env_openxr.AppendUnique(CPPDEFINES=["XR_USE_PLATFORM_XLIB"])
if env["wayland"]:
env_openxr.AppendUnique(CPPDEFINES=["XR_USE_PLATFORM_WAYLAND"])
env_openxr.AppendUnique(CPPDEFINES=["XR_USE_PLATFORM_EGL"])
# FIXME: Review what needs to be set for Android and macOS.
env_openxr.AppendUnique(CPPDEFINES=["HAVE_SECURE_GETENV"])
# FreeBSD uses non-standard getenv functions.
if not sys.platform.startswith("freebsd"):
env_openxr.AppendUnique(CPPDEFINES=["HAVE_SECURE_GETENV"])
elif env["platform"] == "windows":
env_openxr.AppendUnique(CPPDEFINES=["XR_OS_WINDOWS", "NOMINMAX", "XR_USE_PLATFORM_WIN32"])
elif env["platform"] == "macos":

View file

@ -1,4 +1,5 @@
#!/usr/bin/env python
from misc.utility.scons_hints import *
Import("env")
Import("env_openxr")

View file

@ -107,14 +107,25 @@ void OpenXRActionMap::remove_action_set(Ref<OpenXRActionSet> p_action_set) {
}
}
void OpenXRActionMap::set_interaction_profiles(Array p_interaction_profiles) {
interaction_profiles.clear();
void OpenXRActionMap::clear_interaction_profiles() {
if (interaction_profiles.is_empty()) {
return;
}
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);
}
// 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 (Ref<OpenXRInteractionProfile> interaction_profile : interaction_profiles) {
interaction_profile->action_map = nullptr;
}
interaction_profiles.clear();
emit_changed();
}
void OpenXRActionMap::set_interaction_profiles(Array p_interaction_profiles) {
clear_interaction_profiles();
for (const Variant &interaction_profile : p_interaction_profiles) {
// Add them anew so we verify our interaction profile pointer.
add_interaction_profile(interaction_profile);
}
}
@ -127,8 +138,7 @@ int OpenXRActionMap::get_interaction_profile_count() const {
}
Ref<OpenXRInteractionProfile> OpenXRActionMap::find_interaction_profile(String p_path) const {
for (int i = 0; i < interaction_profiles.size(); i++) {
Ref<OpenXRInteractionProfile> interaction_profile = interaction_profiles[i];
for (Ref<OpenXRInteractionProfile> interaction_profile : interaction_profiles) {
if (interaction_profile->get_interaction_profile_path() == p_path) {
return interaction_profile;
}
@ -147,6 +157,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();
}
@ -156,6 +173,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();
}
}
@ -549,9 +570,7 @@ Ref<OpenXRAction> OpenXRActionMap::get_action(const String p_path) const {
void OpenXRActionMap::remove_action(const String p_path, bool p_remove_interaction_profiles) {
Ref<OpenXRAction> action = get_action(p_path);
if (action.is_valid()) {
for (int i = 0; i < interaction_profiles.size(); i++) {
Ref<OpenXRInteractionProfile> interaction_profile = interaction_profiles[i];
for (Ref<OpenXRInteractionProfile> interaction_profile : interaction_profiles) {
if (p_remove_interaction_profiles) {
// Remove any bindings for this action
interaction_profile->remove_binding_for_action(action);
@ -571,25 +590,19 @@ void OpenXRActionMap::remove_action(const String p_path, bool p_remove_interacti
PackedStringArray OpenXRActionMap::get_top_level_paths(const Ref<OpenXRAction> p_action) {
PackedStringArray arr;
for (int i = 0; i < interaction_profiles.size(); i++) {
Ref<OpenXRInteractionProfile> ip = interaction_profiles[i];
for (Ref<OpenXRInteractionProfile> ip : interaction_profiles) {
const OpenXRInteractionProfileMetadata::InteractionProfile *profile = OpenXRInteractionProfileMetadata::get_singleton()->get_profile(ip->get_interaction_profile_path());
if (profile != nullptr) {
for (int j = 0; j < ip->get_binding_count(); j++) {
Ref<OpenXRIPBinding> binding = ip->get_binding(j);
if (binding->get_action() == p_action) {
PackedStringArray paths = binding->get_paths();
Vector<Ref<OpenXRIPBinding>> bindings = ip->get_bindings_for_action(p_action);
for (const Ref<OpenXRIPBinding> &binding : bindings) {
String binding_path = binding->get_binding_path();
const OpenXRInteractionProfileMetadata::IOPath *io_path = profile->get_io_path(binding_path);
if (io_path != nullptr) {
String top_path = io_path->top_level_path;
for (int k = 0; k < paths.size(); k++) {
const OpenXRInteractionProfileMetadata::IOPath *io_path = profile->get_io_path(paths[k]);
if (io_path != nullptr) {
String top_path = io_path->top_level_path;
if (!arr.has(top_path)) {
arr.push_back(top_path);
}
}
if (!arr.has(top_path)) {
arr.push_back(top_path);
}
}
}
@ -603,5 +616,5 @@ PackedStringArray OpenXRActionMap::get_top_level_paths(const Ref<OpenXRAction> p
OpenXRActionMap::~OpenXRActionMap() {
action_sets.clear();
interaction_profiles.clear();
clear_interaction_profiles();
}

View file

@ -57,6 +57,7 @@ public:
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)

View file

@ -141,7 +141,7 @@ void OpenXRActionSet::remove_action(Ref<OpenXRAction> p_action) {
if (idx != -1) {
actions.remove_at(idx);
ERR_FAIL_COND_MSG(p_action->action_set != this, "Removing action that belongs to this action set but had incorrect action set pointer."); // this should never happen!
ERR_FAIL_COND_MSG(p_action->action_set != this, "Removing action that belongs to this action set but had incorrect action set pointer."); // This should never happen!
p_action->action_set = nullptr;
emit_changed();

View file

@ -0,0 +1,52 @@
/**************************************************************************/
/* 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(_get_description);
GDVIRTUAL_BIND(_get_ip_modification);
}
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();
}

View file

@ -0,0 +1,81 @@
/**************************************************************************/
/* 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);
protected:
static void _bind_methods();
GDVIRTUAL0RC_REQUIRED(String, _get_description)
GDVIRTUAL0R_REQUIRED(PackedByteArray, _get_ip_modification)
public:
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
};
class OpenXRIPBindingModifier : public OpenXRBindingModifier {
GDCLASS(OpenXRIPBindingModifier, OpenXRBindingModifier);
protected:
friend class OpenXRInteractionProfile;
OpenXRInteractionProfile *interaction_profile = nullptr; // action belongs to this interaction profile
public:
OpenXRInteractionProfile *get_interaction_profile() const { return interaction_profile; }
};
class OpenXRActionBindingModifier : public OpenXRBindingModifier {
GDCLASS(OpenXRActionBindingModifier, OpenXRBindingModifier);
protected:
friend class OpenXRIPBinding;
OpenXRIPBinding *ip_binding = nullptr; // action belongs to this binding
public:
OpenXRIPBinding *get_ip_binding() const { return ip_binding; }
};
#endif // OPENXR_BINDING_MODIFIER_H

View file

@ -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;
}

View file

@ -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 <openxr/openxr.h>
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

View file

@ -35,28 +35,41 @@ void OpenXRIPBinding::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_action"), &OpenXRIPBinding::get_action);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "action", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRAction"), "set_action", "get_action");
ClassDB::bind_method(D_METHOD("get_path_count"), &OpenXRIPBinding::get_path_count);
ClassDB::bind_method(D_METHOD("set_binding_path", "binding_path"), &OpenXRIPBinding::set_binding_path);
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, "OpenXRActionBindingModifier", PROPERTY_USAGE_NO_EDITOR), "set_binding_modifiers", "get_binding_modifiers");
// Deprecated
#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("set_paths", "paths"), &OpenXRIPBinding::set_paths);
ClassDB::bind_method(D_METHOD("get_paths"), &OpenXRIPBinding::get_paths);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "paths"), "set_paths", "get_paths");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "paths", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_paths", "get_paths");
ClassDB::bind_method(D_METHOD("get_path_count"), &OpenXRIPBinding::get_path_count);
ClassDB::bind_method(D_METHOD("has_path", "path"), &OpenXRIPBinding::has_path);
ClassDB::bind_method(D_METHOD("add_path", "path"), &OpenXRIPBinding::add_path);
ClassDB::bind_method(D_METHOD("remove_path", "path"), &OpenXRIPBinding::remove_path);
#endif // DISABLE_DEPRECATED
}
Ref<OpenXRIPBinding> OpenXRIPBinding::new_binding(const Ref<OpenXRAction> p_action, const char *p_paths) {
Ref<OpenXRIPBinding> OpenXRIPBinding::new_binding(const Ref<OpenXRAction> p_action, const String &p_binding_path) {
// This is a helper function to help build our default action sets
Ref<OpenXRIPBinding> binding;
binding.instantiate();
binding->set_action(p_action);
binding->parse_paths(String(p_paths));
binding->set_binding_path(p_binding_path);
return binding;
}
void OpenXRIPBinding::set_action(const Ref<OpenXRAction> p_action) {
void OpenXRIPBinding::set_action(const Ref<OpenXRAction> &p_action) {
action = p_action;
emit_changed();
}
@ -65,41 +78,136 @@ Ref<OpenXRAction> OpenXRIPBinding::get_action() const {
return action;
}
int OpenXRIPBinding::get_path_count() const {
return paths.size();
}
void OpenXRIPBinding::set_paths(const PackedStringArray p_paths) {
paths = p_paths;
void OpenXRIPBinding::set_binding_path(const String &path) {
binding_path = path;
emit_changed();
}
PackedStringArray OpenXRIPBinding::get_paths() const {
String OpenXRIPBinding::get_binding_path() const {
return binding_path;
}
int OpenXRIPBinding::get_binding_modifier_count() const {
return binding_modifiers.size();
}
Ref<OpenXRActionBindingModifier> 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.is_empty()) {
return;
}
for (int i = 0; i < binding_modifiers.size(); i++) {
Ref<OpenXRActionBindingModifier> binding_modifier = binding_modifiers[i];
binding_modifier->ip_binding = nullptr;
}
binding_modifiers.clear();
emit_changed();
}
void OpenXRIPBinding::set_binding_modifiers(const Array &p_binding_modifiers) {
clear_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.
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<OpenXRActionBindingModifier> &binding_modifier : binding_modifiers) {
ret.push_back(binding_modifier);
}
return ret;
}
void OpenXRIPBinding::add_binding_modifier(const Ref<OpenXRActionBindingModifier> &p_binding_modifier) {
ERR_FAIL_COND(p_binding_modifier.is_null());
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(const Ref<OpenXRActionBindingModifier> &p_binding_modifier) {
int idx = binding_modifiers.find(p_binding_modifier);
if (idx != -1) {
binding_modifiers.remove_at(idx);
ERR_FAIL_COND_MSG(p_binding_modifier->ip_binding != this, "Removing binding modifier that belongs to this binding but had incorrect binding pointer."); // This should never happen!
p_binding_modifier->ip_binding = nullptr;
emit_changed();
}
}
#ifndef DISABLE_DEPRECATED
void OpenXRIPBinding::set_paths(const PackedStringArray p_paths) { // Deprecated, but needed for loading old action maps.
// Fallback logic, this should ONLY be called when loading older action maps.
// We'll parse this momentarily and extract individual bindings.
binding_path = "";
for (const String &path : p_paths) {
if (!binding_path.is_empty()) {
binding_path += ",";
}
binding_path += path;
}
}
PackedStringArray OpenXRIPBinding::get_paths() const { // Deprecated, but needed for converting old action maps.
// Fallback logic, return an array.
// If we just loaded an old action map from disc, this will be a comma separated list of actions.
// Once parsed there should be only one path in our array.
PackedStringArray paths = binding_path.split(",", false);
return paths;
}
void OpenXRIPBinding::parse_paths(const String p_paths) {
paths = p_paths.split(",", false);
int OpenXRIPBinding::get_path_count() const { // Deprecated.
// Fallback logic, we only have one entry.
return binding_path.is_empty() ? 0 : 1;
}
bool OpenXRIPBinding::has_path(const String p_path) const { // Deprecated.
// Fallback logic, return true if this is our path.
return binding_path == p_path;
}
void OpenXRIPBinding::add_path(const String p_path) { // Deprecated.
// Fallback logic, only assign first time this is called.
if (binding_path != p_path) {
ERR_FAIL_COND_MSG(!binding_path.is_empty(), "Method add_path has been deprecated. A binding path was already set, create separate binding resources for each path and use set_binding_path instead.");
binding_path = p_path;
emit_changed();
}
}
void OpenXRIPBinding::remove_path(const String p_path) { // Deprecated.
ERR_FAIL_COND_MSG(binding_path != p_path, "Method remove_path has been deprecated. Attempt at removing a different binding path, remove the correct binding record from the interaction profile instead.");
// Fallback logic, clear if this is our path.
binding_path = p_path;
emit_changed();
}
bool OpenXRIPBinding::has_path(const String p_path) const {
return paths.has(p_path);
}
void OpenXRIPBinding::add_path(const String p_path) {
if (!paths.has(p_path)) {
paths.push_back(p_path);
emit_changed();
}
}
void OpenXRIPBinding::remove_path(const String p_path) {
if (paths.has(p_path)) {
paths.erase(p_path);
emit_changed();
}
}
#endif // DISABLE_DEPRECATED
OpenXRIPBinding::~OpenXRIPBinding() {
action.unref();
@ -115,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, "OpenXRIPBindingModifier", PROPERTY_USAGE_NO_EDITOR), "set_binding_modifiers", "get_binding_modifiers");
}
Ref<OpenXRInteractionProfile> OpenXRInteractionProfile::new_profile(const char *p_input_profile_path) {
@ -150,10 +264,19 @@ Ref<OpenXRIPBinding> OpenXRInteractionProfile::get_binding(int p_index) const {
return bindings[p_index];
}
void OpenXRInteractionProfile::set_bindings(Array p_bindings) {
// TODO add check here that our bindings don't contain duplicate actions
void OpenXRInteractionProfile::set_bindings(const Array &p_bindings) {
bindings.clear();
for (Ref<OpenXRIPBinding> binding : p_bindings) {
String binding_path = binding->get_binding_path();
if (binding_path.find_char(',') >= 0) {
// Convert old binding approach to new...
add_new_binding(binding->get_action(), binding_path);
} else {
add_binding(binding);
}
}
bindings = p_bindings;
emit_changed();
}
@ -161,10 +284,9 @@ Array OpenXRInteractionProfile::get_bindings() const {
return bindings;
}
Ref<OpenXRIPBinding> OpenXRInteractionProfile::get_binding_for_action(const Ref<OpenXRAction> p_action) const {
for (int i = 0; i < bindings.size(); i++) {
Ref<OpenXRIPBinding> binding = bindings[i];
if (binding->get_action() == p_action) {
Ref<OpenXRIPBinding> OpenXRInteractionProfile::find_binding(const Ref<OpenXRAction> &p_action, const String &p_binding_path) const {
for (Ref<OpenXRIPBinding> binding : bindings) {
if (binding->get_action() == p_action && binding->get_binding_path() == p_binding_path) {
return binding;
}
}
@ -172,18 +294,30 @@ Ref<OpenXRIPBinding> OpenXRInteractionProfile::get_binding_for_action(const Ref<
return Ref<OpenXRIPBinding>();
}
void OpenXRInteractionProfile::add_binding(Ref<OpenXRIPBinding> p_binding) {
Vector<Ref<OpenXRIPBinding>> OpenXRInteractionProfile::get_bindings_for_action(const Ref<OpenXRAction> &p_action) const {
Vector<Ref<OpenXRIPBinding>> ret_bindings;
for (Ref<OpenXRIPBinding> binding : bindings) {
if (binding->get_action() == p_action) {
ret_bindings.push_back(binding);
}
}
return ret_bindings;
}
void OpenXRInteractionProfile::add_binding(const Ref<OpenXRIPBinding> &p_binding) {
ERR_FAIL_COND(p_binding.is_null());
if (!bindings.has(p_binding)) {
ERR_FAIL_COND_MSG(get_binding_for_action(p_binding->get_action()).is_valid(), "There is already a binding for this action in this interaction profile");
ERR_FAIL_COND_MSG(find_binding(p_binding->get_action(), p_binding->get_binding_path()).is_valid(), "There is already a binding for this action and binding path in this interaction profile.");
bindings.push_back(p_binding);
emit_changed();
}
}
void OpenXRInteractionProfile::remove_binding(Ref<OpenXRIPBinding> p_binding) {
void OpenXRInteractionProfile::remove_binding(const Ref<OpenXRIPBinding> &p_binding) {
int idx = bindings.find(p_binding);
if (idx != -1) {
bindings.remove_at(idx);
@ -191,14 +325,18 @@ void OpenXRInteractionProfile::remove_binding(Ref<OpenXRIPBinding> p_binding) {
}
}
void OpenXRInteractionProfile::add_new_binding(const Ref<OpenXRAction> p_action, const char *p_paths) {
void OpenXRInteractionProfile::add_new_binding(const Ref<OpenXRAction> &p_action, const String &p_paths) {
// This is a helper function to help build our default action sets
Ref<OpenXRIPBinding> binding = OpenXRIPBinding::new_binding(p_action, p_paths);
add_binding(binding);
PackedStringArray paths = p_paths.split(",", false);
for (const String &path : paths) {
Ref<OpenXRIPBinding> binding = OpenXRIPBinding::new_binding(p_action, path);
add_binding(binding);
}
}
void OpenXRInteractionProfile::remove_binding_for_action(const Ref<OpenXRAction> p_action) {
void OpenXRInteractionProfile::remove_binding_for_action(const Ref<OpenXRAction> &p_action) {
for (int i = bindings.size() - 1; i >= 0; i--) {
Ref<OpenXRIPBinding> binding = bindings[i];
if (binding->get_action() == p_action) {
@ -207,7 +345,7 @@ void OpenXRInteractionProfile::remove_binding_for_action(const Ref<OpenXRAction>
}
}
bool OpenXRInteractionProfile::has_binding_for_action(const Ref<OpenXRAction> p_action) {
bool OpenXRInteractionProfile::has_binding_for_action(const Ref<OpenXRAction> &p_action) {
for (int i = bindings.size() - 1; i >= 0; i--) {
Ref<OpenXRIPBinding> binding = bindings[i];
if (binding->get_action() == p_action) {
@ -218,6 +356,76 @@ bool OpenXRInteractionProfile::has_binding_for_action(const Ref<OpenXRAction> p_
return false;
}
int OpenXRInteractionProfile::get_binding_modifier_count() const {
return binding_modifiers.size();
}
Ref<OpenXRIPBindingModifier> 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.is_empty()) {
return;
}
for (int i = 0; i < binding_modifiers.size(); i++) {
Ref<OpenXRIPBindingModifier> binding_modifier = binding_modifiers[i];
binding_modifier->interaction_profile = nullptr;
}
binding_modifiers.clear();
emit_changed();
}
void OpenXRInteractionProfile::set_binding_modifiers(const Array &p_binding_modifiers) {
clear_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.
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<OpenXRIPBindingModifier> &binding_modifier : binding_modifiers) {
ret.push_back(binding_modifier);
}
return ret;
}
void OpenXRInteractionProfile::add_binding_modifier(const Ref<OpenXRIPBindingModifier> &p_binding_modifier) {
ERR_FAIL_COND(p_binding_modifier.is_null());
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(const Ref<OpenXRIPBindingModifier> &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();
}

View file

@ -32,35 +32,57 @@
#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<OpenXRAction> action;
PackedStringArray paths;
String binding_path;
Vector<Ref<OpenXRActionBindingModifier>> binding_modifiers;
protected:
friend class OpenXRActionMap;
OpenXRActionMap *action_map = nullptr;
static void _bind_methods();
public:
static Ref<OpenXRIPBinding> new_binding(const Ref<OpenXRAction> p_action, const char *p_paths); // Helper function for adding a new binding
static Ref<OpenXRIPBinding> new_binding(const Ref<OpenXRAction> p_action, const String &p_binding_path); // Helper function for adding a new binding.
void set_action(const Ref<OpenXRAction> p_action); // Set the action for this binding
Ref<OpenXRAction> get_action() const; // Get the action for this binding
OpenXRActionMap *get_action_map() { return action_map; } // Return the action map we're a part of.
int get_path_count() const; // Get the number of io paths
void set_paths(const PackedStringArray p_paths); // Set our paths (for loading from resource)
PackedStringArray get_paths() const; // Get our paths (for saving to resource)
void set_action(const Ref<OpenXRAction> &p_action); // Set the action for this binding.
Ref<OpenXRAction> get_action() const; // Get the action for this binding.
void parse_paths(const String p_paths); // Parse a comma separated string of io paths.
void set_binding_path(const String &path);
String get_binding_path() const;
bool has_path(const String p_path) const; // Has this io path
void add_path(const String p_path); // Add an io path
void remove_path(const String p_path); // Remove an io path
int get_binding_modifier_count() const; // Retrieve the number of binding modifiers in this profile path
Ref<OpenXRActionBindingModifier> get_binding_modifier(int p_index) const;
void clear_binding_modifiers(); // Remove all binding modifiers
void set_binding_modifiers(const 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(const Ref<OpenXRActionBindingModifier> &p_binding_modifier); // Add a binding modifier object
void remove_binding_modifier(const Ref<OpenXRActionBindingModifier> &p_binding_modifier); // Remove a binding modifier object
// Deprecated.
#ifndef DISABLE_DEPRECATED
void set_paths(const PackedStringArray p_paths); // Set our paths (for loading from resource), needed for loading old action maps.
PackedStringArray get_paths() const; // Get our paths (for saving to resource), needed for converted old action maps.
int get_path_count() const; // Get the number of io paths.
bool has_path(const String p_path) const; // Has this io path.
void add_path(const String p_path); // Add an io path.
void remove_path(const String p_path); // Remove an io path.
#endif // DISABLE_DEPRECATED
// TODO add validation that we can display in the interface that checks if no two paths belong to the same top level path
@ -73,28 +95,45 @@ class OpenXRInteractionProfile : public Resource {
private:
String interaction_profile_path;
Array bindings;
Vector<Ref<OpenXRIPBindingModifier>> binding_modifiers;
protected:
friend class OpenXRActionMap;
OpenXRActionMap *action_map = nullptr;
static void _bind_methods();
public:
static Ref<OpenXRInteractionProfile> new_profile(const char *p_input_profile_path); // Helper function to create a new interaction profile
OpenXRActionMap *get_action_map() { return action_map; }
void set_interaction_profile_path(const String p_input_profile_path); // Set our input profile path
String get_interaction_profile_path() const; // get our input profile path
int get_binding_count() const; // Retrieve the number of bindings in this profile path
Ref<OpenXRIPBinding> get_binding(int p_index) const;
void set_bindings(Array p_bindings); // Set the bindings (for loading from a resource)
void set_bindings(const Array &p_bindings); // Set the bindings (for loading from a resource)
Array get_bindings() const; // Get the bindings (for saving to a resource)
Ref<OpenXRIPBinding> get_binding_for_action(const Ref<OpenXRAction> p_action) const; // Get our binding record for a given action
void add_binding(Ref<OpenXRIPBinding> p_binding); // Add a binding object
void remove_binding(Ref<OpenXRIPBinding> p_binding); // Remove a binding object
Ref<OpenXRIPBinding> find_binding(const Ref<OpenXRAction> &p_action, const String &p_binding_path) const; // Get our binding record
Vector<Ref<OpenXRIPBinding>> get_bindings_for_action(const Ref<OpenXRAction> &p_action) const; // Get our binding record for a given action
void add_binding(const Ref<OpenXRIPBinding> &p_binding); // Add a binding object
void remove_binding(const Ref<OpenXRIPBinding> &p_binding); // Remove a binding object
void add_new_binding(const Ref<OpenXRAction> p_action, const char *p_paths); // Create a new binding for this profile
void remove_binding_for_action(const Ref<OpenXRAction> p_action); // Remove all bindings for this action
bool has_binding_for_action(const Ref<OpenXRAction> p_action); // Returns true if we have a binding for this action
void add_new_binding(const Ref<OpenXRAction> &p_action, const String &p_paths); // Create a new binding for this profile
void remove_binding_for_action(const Ref<OpenXRAction> &p_action); // Remove all bindings for this action
bool has_binding_for_action(const Ref<OpenXRAction> &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<OpenXRIPBindingModifier> get_binding_modifier(int p_index) const;
void clear_binding_modifiers(); // Remove all binding modifiers
void set_binding_modifiers(const 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(const Ref<OpenXRIPBindingModifier> &p_binding_modifier); // Add a binding modifier object
void remove_binding_modifier(const Ref<OpenXRIPBindingModifier> &p_binding_modifier); // Remove a binding modifier object
~OpenXRInteractionProfile();
};

View file

@ -93,9 +93,9 @@ void OpenXRInteractionProfileMetadata::register_io_path(const String &p_interact
ERR_FAIL_COND_MSG(!has_interaction_profile(p_interaction_profile), "Unknown interaction profile " + p_interaction_profile);
ERR_FAIL_COND_MSG(!has_top_level_path(p_toplevel_path), "Unknown top level path " + p_toplevel_path);
for (int i = 0; i < interaction_profiles.size(); i++) {
if (interaction_profiles[i].openxr_path == p_interaction_profile) {
ERR_FAIL_COND_MSG(interaction_profiles[i].has_io_path(p_openxr_path), p_interaction_profile + " already has io path " + p_openxr_path + " registered!");
for (InteractionProfile &interaction_profile : interaction_profiles) {
if (interaction_profile.openxr_path == p_interaction_profile) {
ERR_FAIL_COND_MSG(interaction_profile.has_io_path(p_openxr_path), p_interaction_profile + " already has io path " + p_openxr_path + " registered!");
IOPath new_io_path = {
p_display_name,
@ -105,7 +105,7 @@ void OpenXRInteractionProfileMetadata::register_io_path(const String &p_interact
p_action_type
};
interaction_profiles.ptrw()[i].io_paths.push_back(new_io_path);
interaction_profile.io_paths.push_back(new_io_path);
}
}
}
@ -141,8 +141,8 @@ String OpenXRInteractionProfileMetadata::get_top_level_extension(const String p_
}
bool OpenXRInteractionProfileMetadata::has_interaction_profile(const String p_openxr_path) const {
for (int i = 0; i < interaction_profiles.size(); i++) {
if (interaction_profiles[i].openxr_path == p_openxr_path) {
for (const InteractionProfile &interaction_profile : interaction_profiles) {
if (interaction_profile.openxr_path == p_openxr_path) {
return true;
}
}
@ -151,9 +151,9 @@ bool OpenXRInteractionProfileMetadata::has_interaction_profile(const String p_op
}
String OpenXRInteractionProfileMetadata::get_interaction_profile_extension(const String p_openxr_path) const {
for (int i = 0; i < interaction_profiles.size(); i++) {
if (interaction_profiles[i].openxr_path == p_openxr_path) {
return interaction_profiles[i].openxr_extension_name;
for (const InteractionProfile &interaction_profile : interaction_profiles) {
if (interaction_profile.openxr_path == p_openxr_path) {
return interaction_profile.openxr_extension_name;
}
}
@ -161,9 +161,9 @@ String OpenXRInteractionProfileMetadata::get_interaction_profile_extension(const
}
const OpenXRInteractionProfileMetadata::InteractionProfile *OpenXRInteractionProfileMetadata::get_profile(const String p_openxr_path) const {
for (int i = 0; i < interaction_profiles.size(); i++) {
if (interaction_profiles[i].openxr_path == p_openxr_path) {
return &interaction_profiles[i];
for (const InteractionProfile &interaction_profile : interaction_profiles) {
if (interaction_profile.openxr_path == p_openxr_path) {
return &interaction_profile;
}
}
@ -202,8 +202,8 @@ const OpenXRInteractionProfileMetadata::IOPath *OpenXRInteractionProfileMetadata
PackedStringArray OpenXRInteractionProfileMetadata::get_interaction_profile_paths() const {
PackedStringArray arr;
for (int i = 0; i < interaction_profiles.size(); i++) {
arr.push_back(interaction_profiles[i].openxr_path);
for (const InteractionProfile &interaction_profile : interaction_profiles) {
arr.push_back(interaction_profile.openxr_path);
}
return arr;
@ -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);
{ // 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("/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(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("/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);
register_io_path(profile_path, "Haptic output", user_path, user_path + "/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);
{ // 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("/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(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("/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(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("/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(profile_path, "Squeeze click", user_path, user_path + "/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(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("/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);
register_io_path(profile_path, "Haptic output", user_path, user_path + "/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);
{ // 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("/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(profile_path, "Menu click", user_path, user_path + "/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(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("/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(profile_path, "Squeeze click", user_path, user_path + "/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(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("/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(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("/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);
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)
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);
{ // 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("/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(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("/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(profile_path, "Squeeze", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
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(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("/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(profile_path, "Thumbrest touch", user_path, user_path + "/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
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(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
}
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(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("/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);
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
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);
{ // 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("/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(profile_path, "System click", user_path, user_path + "/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(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("/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(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("/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(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("/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(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("/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(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("/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);
register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
}
}
}

View file

@ -22,10 +22,21 @@ def get_doc_classes():
"OpenXRInteractionProfileMetadata",
"OpenXRIPBinding",
"OpenXRHand",
"OpenXRVisibilityMask",
"OpenXRCompositionLayer",
"OpenXRCompositionLayerQuad",
"OpenXRCompositionLayerCylinder",
"OpenXRCompositionLayerEquirect",
"OpenXRBindingModifier",
"OpenXRIPBindingModifier",
"OpenXRActionBindingModifier",
"OpenXRAnalogThresholdModifier",
"OpenXRDpadBindingModifier",
"OpenXRInteractionProfileEditorBase",
"OpenXRInteractionProfileEditor",
"OpenXRBindingModifierEditor",
"OpenXRHapticBase",
"OpenXRHapticVibration",
]

View file

@ -17,12 +17,40 @@
<link title="XrPosef documentation">https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrPosef.html</link>
</tutorials>
<methods>
<method name="action_get_handle">
<return type="int" />
<param index="0" name="action" type="RID" />
<description>
Returns the corresponding [code]XrAction[/code] OpenXR handle for the given action RID.
</description>
</method>
<method name="begin_debug_label_region">
<return type="void" />
<param index="0" name="label_name" type="String" />
<description>
Begins a new debug label region, this label will be reported in debug messages for any calls following this until [method end_debug_label_region] is called. Debug labels can be stacked.
</description>
</method>
<method name="can_render">
<return type="bool" />
<description>
Returns [code]true[/code] if OpenXR is initialized for rendering with an XR viewport.
</description>
</method>
<method name="end_debug_label_region">
<return type="void" />
<description>
Marks the end of a debug label region. Removes the latest debug label region added by calling [method begin_debug_label_region].
</description>
</method>
<method name="find_action">
<return type="RID" />
<param index="0" name="name" type="String" />
<param index="1" name="action_set" type="RID" />
<description>
Returns the [RID] corresponding to an [code]Action[/code] of a matching name, optionally limited to a specified action set.
</description>
</method>
<method name="get_error_string">
<return type="String" />
<param index="0" name="result" type="int" />
@ -69,12 +97,39 @@
Returns the predicted display timing for the current frame.
</description>
</method>
<method name="get_projection_layer">
<return type="int" />
<description>
Returns a pointer to the render state's [code]XrCompositionLayerProjection[/code] struct.
[b]Note:[/b] This method should only be called from the rendering thread.
</description>
</method>
<method name="get_render_state_z_far">
<return type="float" />
<description>
Returns the far boundary value of the camera frustum.
[b]Note:[/b] This is only accessible in the render thread.
</description>
</method>
<method name="get_render_state_z_near">
<return type="float" />
<description>
Returns the near boundary value of the camera frustum.
[b]Note:[/b] This is only accessible in the render thread.
</description>
</method>
<method name="get_session">
<return type="int" />
<description>
Returns the OpenXR session, which is an [url=https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrSession.html]XrSession[/url] cast to an integer.
</description>
</method>
<method name="get_supported_swapchain_formats">
<return type="PackedInt64Array" />
<description>
Returns an array of supported swapchain formats.
</description>
</method>
<method name="get_swapchain_format_name">
<return type="String" />
<param index="0" name="swapchain_format" type="int" />
@ -88,6 +143,13 @@
Returns the id of the system, which is a [url=https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrSystemId.html]XrSystemId[/url] cast to an integer.
</description>
</method>
<method name="insert_debug_label">
<return type="void" />
<param index="0" name="label_name" type="String" />
<description>
Inserts a debug label, this label is reported in any debug message resulting from the OpenXR calls that follows, until any of [method begin_debug_label_region], [method end_debug_label_region], or [method insert_debug_label] is called.
</description>
</method>
<method name="is_environment_blend_mode_alpha_supported">
<return type="int" enum="OpenXRAPIExtension.OpenXRAlphaBlendModeSupport" />
<description>
@ -113,6 +175,54 @@
Returns [code]true[/code] if OpenXR is enabled.
</description>
</method>
<method name="openxr_swapchain_acquire">
<return type="void" />
<param index="0" name="swapchain" type="int" />
<description>
Acquires the image of the provided swapchain.
</description>
</method>
<method name="openxr_swapchain_create">
<return type="int" />
<param index="0" name="create_flags" type="int" />
<param index="1" name="usage_flags" type="int" />
<param index="2" name="swapchain_format" type="int" />
<param index="3" name="width" type="int" />
<param index="4" name="height" type="int" />
<param index="5" name="sample_count" type="int" />
<param index="6" name="array_size" type="int" />
<description>
Returns a pointer to a new swapchain created using the provided parameters.
</description>
</method>
<method name="openxr_swapchain_free">
<return type="void" />
<param index="0" name="swapchain" type="int" />
<description>
Destroys the provided swapchain and frees it from memory.
</description>
</method>
<method name="openxr_swapchain_get_image">
<return type="RID" />
<param index="0" name="swapchain" type="int" />
<description>
Returns the RID of the provided swapchain's image.
</description>
</method>
<method name="openxr_swapchain_get_swapchain">
<return type="int" />
<param index="0" name="swapchain" type="int" />
<description>
Returns the [code]XrSwapchain[/code] handle of the provided swapchain.
</description>
</method>
<method name="openxr_swapchain_release">
<return type="void" />
<param index="0" name="swapchain" type="int" />
<description>
Releases the image of the provided swapchain.
</description>
</method>
<method name="register_composition_layer_provider">
<return type="void" />
<param index="0" name="extension" type="OpenXRExtensionWrapperExtension" />
@ -120,6 +230,13 @@
Registers the given extension as a composition layer provider.
</description>
</method>
<method name="register_projection_views_extension">
<return type="void" />
<param index="0" name="extension" type="OpenXRExtensionWrapperExtension" />
<description>
Registers the given extension as a provider of additional data structures to projections views.
</description>
</method>
<method name="set_emulate_environment_blend_mode_alpha_blend">
<return type="void" />
<param index="0" name="enabled" type="bool" />
@ -127,6 +244,43 @@
If set to [code]true[/code], an OpenXR extension is loaded which is capable of emulating the [constant XRInterface.XR_ENV_BLEND_MODE_ALPHA_BLEND] blend mode.
</description>
</method>
<method name="set_object_name">
<return type="void" />
<param index="0" name="object_type" type="int" />
<param index="1" name="object_handle" type="int" />
<param index="2" name="object_name" type="String" />
<description>
Set the object name of an OpenXR object, used for debug output. [param object_type] must be a valid OpenXR [code]XrObjectType[/code] enum and [param object_handle] must be a valid OpenXR object handle.
</description>
</method>
<method name="set_render_region">
<return type="void" />
<param index="0" name="render_region" type="Rect2i" />
<description>
Sets the render region to [param render_region], overriding the normal render target's rect.
</description>
</method>
<method name="set_velocity_depth_texture">
<return type="void" />
<param index="0" name="render_target" type="RID" />
<description>
Sets the render target of the velocity depth texture.
</description>
</method>
<method name="set_velocity_target_size">
<return type="void" />
<param index="0" name="target_size" type="Vector2i" />
<description>
Sets the target size of the velocity and velocity depth textures.
</description>
</method>
<method name="set_velocity_texture">
<return type="void" />
<param index="0" name="render_target" type="RID" />
<description>
Sets the render target of the velocity texture.
</description>
</method>
<method name="transform_from_pose">
<return type="Transform3D" />
<param index="0" name="pose" type="const void*" />
@ -141,6 +295,13 @@
Unregisters the given extension as a composition layer provider.
</description>
</method>
<method name="unregister_projection_views_extension">
<return type="void" />
<param index="0" name="extension" type="OpenXRExtensionWrapperExtension" />
<description>
Unregisters the given extension as a provider of additional data structures to projections views.
</description>
</method>
<method name="xr_result">
<return type="bool" />
<param index="0" name="result" type="int" />

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRActionBindingModifier" inherits="OpenXRBindingModifier" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Binding modifier that applies on individual actions related to an interaction profile.
</brief_description>
<description>
Binding modifier that applies on individual actions related to an interaction profile.
</description>
<tutorials>
</tutorials>
</class>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRAnalogThresholdModifier" inherits="OpenXRActionBindingModifier" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
The analog threshold binding modifier can modify a float input to a boolean input with specified thresholds.
</brief_description>
<description>
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 in-depth details.
</description>
<tutorials>
</tutorials>
<members>
<member name="off_haptic" type="OpenXRHapticBase" setter="set_off_haptic" getter="get_off_haptic">
Haptic pulse to emit when the user releases the input.
</member>
<member name="off_threshold" type="float" setter="set_off_threshold" getter="get_off_threshold" default="0.4">
When our input value falls below this, our output becomes false.
</member>
<member name="on_haptic" type="OpenXRHapticBase" setter="set_on_haptic" getter="get_on_haptic">
Haptic pulse to emit when the user presses the input.
</member>
<member name="on_threshold" type="float" setter="set_on_threshold" getter="get_on_threshold" default="0.6">
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.
</member>
</members>
</class>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRBindingModifier" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Binding modifier base class.
</brief_description>
<description>
Binding modifier base class. Subclasses implement various modifiers that alter how an OpenXR runtime processes inputs.
</description>
<tutorials>
</tutorials>
<methods>
<method name="_get_description" qualifiers="virtual const">
<return type="String" />
<description>
Return the description of this class that is used for the title bar of the binding modifier editor.
</description>
</method>
<method name="_get_ip_modification" qualifiers="virtual">
<return type="PackedByteArray" />
<description>
Returns the data that is sent to OpenXR when submitting the suggested interacting bindings this modifier is a part of.
[b]Note:[/b] This must be data compatible with a [code]XrBindingModificationBaseHeaderKHR[/code] structure.
</description>
</method>
</methods>
</class>

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRBindingModifierEditor" inherits="PanelContainer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Binding modifier editor.
</brief_description>
<description>
This is the default binding modifier editor used in the OpenXR action map.
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_binding_modifier" qualifiers="const">
<return type="OpenXRBindingModifier" />
<description>
Returns the [OpenXRBindingModifier] currently being edited.
</description>
</method>
<method name="setup">
<return type="void" />
<param index="0" name="action_map" type="OpenXRActionMap" />
<param index="1" name="binding_modifier" type="OpenXRBindingModifier" />
<description>
Setup this editor for the provided [param action_map] and [param binding_modifier].
</description>
</method>
</methods>
<members>
<member name="size_flags_horizontal" type="int" setter="set_h_size_flags" getter="get_h_size_flags" overrides="Control" enum="Control.SizeFlags" is_bitfield="true" default="3" />
</members>
<signals>
<signal name="binding_modifier_removed">
<param index="0" name="binding_modifier_editor" type="Object" />
<description>
Signal emitted when the user presses the delete binding modifier button for this modifier.
</description>
</signal>
</signals>
</class>

View file

@ -10,6 +10,13 @@
<tutorials>
</tutorials>
<methods>
<method name="get_android_surface">
<return type="JavaObject" />
<description>
Returns a [JavaObject] representing an [code]android.view.Surface[/code] if [member use_android_surface] is enabled and OpenXR has created the surface. Otherwise, this will return [code]null[/code].
[b]Note:[/b] The surface can only be created during an active OpenXR session. So, if [member use_android_surface] is enabled outside of an OpenXR session, it won't be created until a new session fully starts.
</description>
</method>
<method name="intersects_ray" qualifiers="const">
<return type="Vector2" />
<param index="0" name="origin" type="Vector3" />
@ -22,7 +29,7 @@
<method name="is_natively_supported" qualifiers="const">
<return type="bool" />
<description>
Returns true if the OpenXR runtime natively supports this composition layer type.
Returns [code]true[/code] if the OpenXR runtime natively supports this composition layer type.
[b]Note:[/b] This will only return an accurate result after the OpenXR session has started.
</description>
</method>
@ -32,6 +39,9 @@
Enables the blending the layer using its alpha channel.
Can be combined with [member Viewport.transparent_bg] to give the layer a transparent background.
</member>
<member name="android_surface_size" type="Vector2i" setter="set_android_surface_size" getter="get_android_surface_size" default="Vector2i(1024, 1024)">
The size of the Android surface to create if [member use_android_surface] is enabled.
</member>
<member name="enable_hole_punch" type="bool" setter="set_enable_hole_punch" getter="get_enable_hole_punch" default="false">
Enables a technique called "hole punching", which allows putting the composition layer behind the main projection layer (i.e. setting [member sort_order] to a negative value) while "punching a hole" through everything rendered by Godot so that the layer is still visible.
This can be used to create the illusion that the composition layer exists in the same 3D space as everything rendered by Godot, allowing objects to appear to pass both behind or in front of the composition layer.
@ -43,5 +53,10 @@
The sort order for this composition layer. Higher numbers will be shown in front of lower numbers.
[b]Note:[/b] This will have no effect if a fallback mesh is being used.
</member>
<member name="use_android_surface" type="bool" setter="set_use_android_surface" getter="get_use_android_surface" default="false">
If enabled, an Android surface will be created (with the dimensions from [member android_surface_size]) which will provide the 2D content for the composition layer, rather than using [member layer_viewport].
See [method get_android_surface] for information about how to get the surface so that your application can draw to it.
[b]Note:[/b] This will only work in Android builds.
</member>
</members>
</class>

View file

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRDpadBindingModifier" inherits="OpenXRIPBindingModifier" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
The DPad binding modifier converts an axis input to a dpad output.
</brief_description>
<description>
The DPad binding modifier converts an axis input to a dpad output, emulating a DPad. New input paths for each dpad direction will be added to the interaction profile. When bound to actions the DPad emulation will be activated. You should [b]not[/b] combine dpad inputs with normal inputs in the same action set for the same control, this will result in an error being returned when suggested bindings are submitted to OpenXR.
See [url=https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#XR_EXT_dpad_binding]XR_EXT_dpad_binding[/url] for in-depth details.
[b]Note:[/b] If the DPad binding modifier extension is enabled, all dpad binding paths will be available in the action map. Adding the modifier to an interaction profile allows you to further customize the behavior.
</description>
<tutorials>
</tutorials>
<members>
<member name="action_set" type="OpenXRActionSet" setter="set_action_set" getter="get_action_set">
Action set for which this dpad binding modifier is active.
</member>
<member name="center_region" type="float" setter="set_center_region" getter="get_center_region" default="0.1">
Center region in which our center position of our dpad return [code]true[/code].
</member>
<member name="input_path" type="String" setter="set_input_path" getter="get_input_path" default="&quot;&quot;">
Input path for this dpad binding modifier.
</member>
<member name="is_sticky" type="bool" setter="set_is_sticky" getter="get_is_sticky" default="false">
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.
</member>
<member name="off_haptic" type="OpenXRHapticBase" setter="set_off_haptic" getter="get_off_haptic">
Haptic pulse to emit when the user releases the input.
</member>
<member name="on_haptic" type="OpenXRHapticBase" setter="set_on_haptic" getter="get_on_haptic">
Haptic pulse to emit when the user presses the input.
</member>
<member name="threshold" type="float" setter="set_threshold" getter="get_threshold" default="0.6">
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.
</member>
<member name="threshold_released" type="float" setter="set_threshold_released" getter="get_threshold_released" default="0.4">
When our input value falls below this, our output becomes false.
</member>
<member name="wedge_angle" type="float" setter="set_wedge_angle" getter="get_wedge_angle" default="1.5708">
The angle of each wedge that identifies the 4 directions of the emulated dpad.
</member>
</members>
</class>

View file

@ -90,6 +90,21 @@
Called right after the main swapchains are (re)created.
</description>
</method>
<method name="_on_post_draw_viewport" qualifiers="virtual">
<return type="void" />
<param index="0" name="viewport" type="RID" />
<description>
Called right after the given viewport is rendered.
[b]Note:[/b] The draw commands might only be queued at this point, not executed.
</description>
</method>
<method name="_on_pre_draw_viewport" qualifiers="virtual">
<return type="void" />
<param index="0" name="viewport" type="RID" />
<description>
Called right before the given viewport is rendered.
</description>
</method>
<method name="_on_pre_render" qualifiers="virtual">
<return type="void" />
<description>
@ -178,6 +193,15 @@
[param layer] is a pointer to an [code]XrCompositionLayerBaseHeader[/code] struct.
</description>
</method>
<method name="_set_android_surface_swapchain_create_info_and_get_next_pointer" qualifiers="virtual">
<return type="int" />
<param index="0" name="property_values" type="Dictionary" />
<param index="1" name="next_pointer" type="void*" />
<description>
Adds additional data structures to Android surface swapchains created by [OpenXRCompositionLayer].
[param property_values] contains the values of the properties returned by [method _get_viewport_composition_layer_extension_properties].
</description>
</method>
<method name="_set_hand_joint_locations_and_get_next_pointer" qualifiers="virtual">
<return type="int" />
<param index="0" name="hand_index" type="int" />
@ -193,6 +217,14 @@
Adds additional data structures when the OpenXR instance is created.
</description>
</method>
<method name="_set_projection_views_and_get_next_pointer" qualifiers="virtual">
<return type="int" />
<param index="0" name="view_index" type="int" />
<param index="1" name="next_pointer" type="void*" />
<description>
Adds additional data structures to the projection view of the given [param view_index].
</description>
</method>
<method name="_set_session_create_and_get_next_pointer" qualifiers="virtual">
<return type="int" />
<param index="0" name="next_pointer" type="void*" />
@ -211,7 +243,7 @@
<return type="int" />
<param index="0" name="next_pointer" type="void*" />
<description>
Adds additional data structures when interogating OpenXR system abilities.
Adds additional data structures when querying OpenXR system abilities.
</description>
</method>
<method name="_set_viewport_composition_layer_and_get_next_pointer" qualifiers="virtual">

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRHapticBase" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
OpenXR Haptic feedback base class.
</brief_description>
<description>
This is a base class for haptic feedback resources.
</description>
<tutorials>
</tutorials>
</class>

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRHapticVibration" inherits="OpenXRHapticBase" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Vibration haptic feedback.
</brief_description>
<description>
This haptic feedback resource makes it possible to define a vibration based haptic feedback pulse that can be triggered through actions in the OpenXR action map.
</description>
<tutorials>
</tutorials>
<members>
<member name="amplitude" type="float" setter="set_amplitude" getter="get_amplitude" default="1.0">
The amplitude of the pulse between [code]0.0[/code] and [code]1.0[/code].
</member>
<member name="duration" type="int" setter="set_duration" getter="get_duration" default="-1">
The duration of the pulse in nanoseconds. Use [code]-1[/code] for a minimum duration pulse for the current XR runtime.
</member>
<member name="frequency" type="float" setter="set_frequency" getter="get_frequency" default="0.0">
The frequency of the pulse in Hz. [code]0.0[/code] will let the XR runtime chose an optimal frequency for the device used.
</member>
</members>
</class>

View file

@ -4,32 +4,45 @@
Defines a binding between an [OpenXRAction] and an XR input or output.
</brief_description>
<description>
This binding resource binds an [OpenXRAction] to inputs or outputs. As most controllers have left hand and right versions that are handled by the same interaction profile we can specify multiple bindings. For instance an action "Fire" could be bound to both "/user/hand/left/input/trigger" and "/user/hand/right/input/trigger".
This binding resource binds an [OpenXRAction] to an input or output. As most controllers have left hand and right versions that are handled by the same interaction profile we can specify multiple bindings. For instance an action "Fire" could be bound to both "/user/hand/left/input/trigger" and "/user/hand/right/input/trigger". This would require two binding entries.
</description>
<tutorials>
</tutorials>
<methods>
<method name="add_path">
<method name="add_path" deprecated="Binding is for a single path.">
<return type="void" />
<param index="0" name="path" type="String" />
<description>
Add an input/output path to this binding.
</description>
</method>
<method name="get_path_count" qualifiers="const">
<method name="get_binding_modifier" qualifiers="const">
<return type="OpenXRActionBindingModifier" />
<param index="0" name="index" type="int" />
<description>
Get the [OpenXRBindingModifier] at this index.
</description>
</method>
<method name="get_binding_modifier_count" qualifiers="const">
<return type="int" />
<description>
Get the number of binding modifiers for this binding.
</description>
</method>
<method name="get_path_count" qualifiers="const" deprecated="Binding is for a single path.">
<return type="int" />
<description>
Get the number of input/output paths in this binding.
</description>
</method>
<method name="has_path" qualifiers="const">
<method name="has_path" qualifiers="const" deprecated="Binding is for a single path.">
<return type="bool" />
<param index="0" name="path" type="String" />
<description>
Returns [code]true[/code] if this input/output path is part of this binding.
</description>
</method>
<method name="remove_path">
<method name="remove_path" deprecated="Binding is for a single path.">
<return type="void" />
<param index="0" name="path" type="String" />
<description>
@ -39,9 +52,16 @@
</methods>
<members>
<member name="action" type="OpenXRAction" setter="set_action" getter="get_action">
[OpenXRAction] that is bound to these paths.
[OpenXRAction] that is bound to [member binding_path].
</member>
<member name="paths" type="PackedStringArray" setter="set_paths" getter="get_paths" default="PackedStringArray()">
<member name="binding_modifiers" type="Array" setter="set_binding_modifiers" getter="get_binding_modifiers" default="[]">
Binding modifiers for this binding.
</member>
<member name="binding_path" type="String" setter="set_binding_path" getter="get_binding_path" default="&quot;&quot;">
Binding path that defines the input or output bound to [member action].
[b]Note:[/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.
</member>
<member name="paths" type="PackedStringArray" setter="set_paths" getter="get_paths" deprecated="Use [member binding_path] instead.">
Paths that define the inputs or outputs bound on the device.
</member>
</members>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRIPBindingModifier" inherits="OpenXRBindingModifier" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Binding modifier that applies directly on an interaction profile.
</brief_description>
<description>
Binding modifier that applies directly on an interaction profile.
</description>
<tutorials>
</tutorials>
</class>

View file

@ -23,8 +23,24 @@
Get the number of bindings in this interaction profile.
</description>
</method>
<method name="get_binding_modifier" qualifiers="const">
<return type="OpenXRIPBindingModifier" />
<param index="0" name="index" type="int" />
<description>
Get the [OpenXRBindingModifier] at this index.
</description>
</method>
<method name="get_binding_modifier_count" qualifiers="const">
<return type="int" />
<description>
Get the number of binding modifiers in this interaction profile.
</description>
</method>
</methods>
<members>
<member name="binding_modifiers" type="Array" setter="set_binding_modifiers" getter="get_binding_modifiers" default="[]">
Binding modifiers for this interaction profile.
</member>
<member name="bindings" type="Array" setter="set_bindings" getter="get_bindings" default="[]">
Action bindings for this interaction profile.
</member>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRInteractionProfileEditor" inherits="OpenXRInteractionProfileEditorBase" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Default OpenXR interaction profile editor.
</brief_description>
<description>
This is the default OpenXR interaction profile editor that provides a generic interface for editing any interaction profile for which no custom editor has been defined.
</description>
<tutorials>
</tutorials>
</class>

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRInteractionProfileEditorBase" inherits="HBoxContainer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Base class for editing interaction profiles.
</brief_description>
<description>
This is a base class for interaction profile editors used by the OpenXR action map editor. It can be used to create bespoke editors for specific interaction profiles.
</description>
<tutorials>
</tutorials>
<methods>
<method name="setup">
<return type="void" />
<param index="0" name="action_map" type="OpenXRActionMap" />
<param index="1" name="interaction_profile" type="OpenXRInteractionProfile" />
<description>
Setup this editor for the provided [param action_map] and [param interaction_profile].
</description>
</method>
</methods>
<members>
<member name="size_flags_horizontal" type="int" setter="set_h_size_flags" getter="get_h_size_flags" overrides="Control" enum="Control.SizeFlags" is_bitfield="true" default="3" />
<member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" enum="Control.SizeFlags" is_bitfield="true" default="3" />
</members>
</class>

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRVisibilityMask" inherits="VisualInstance3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Draws a stereo correct visibility mask.
</brief_description>
<description>
The visibility mask allows us to black out the part of the render result that is invisible due to lens distortion.
As this is rendered first, it prevents fragments with expensive lighting calculations to be processed as they are discarded through z-checking.
</description>
<tutorials>
</tutorials>
</class>

View file

@ -1,5 +1,11 @@
#!/usr/bin/env python
from misc.utility.scons_hints import *
Import("env")
Import("env_openxr")
env.add_source_files(env.modules_sources, "*.cpp")
module_obj = []
env_openxr.add_source_files(module_obj, "*.cpp")
env.modules_sources += module_obj

View file

@ -41,7 +41,7 @@ void OpenXRActionEditor::_bind_methods() {
}
void OpenXRActionEditor::_theme_changed() {
rem_action->set_icon(get_theme_icon(SNAME("Remove"), EditorStringName(EditorIcons)));
rem_action->set_button_icon(get_theme_icon(SNAME("Remove"), EditorStringName(EditorIcons)));
}
void OpenXRActionEditor::_notification(int p_what) {

View file

@ -68,7 +68,7 @@ protected:
void _do_set_action_type(OpenXRAction::ActionType p_action_type);
public:
Ref<OpenXRAction> get_action() { return action; };
Ref<OpenXRAction> get_action() { return action; }
OpenXRActionEditor(Ref<OpenXRAction> p_action);
};

View file

@ -32,12 +32,11 @@
#include "core/config/project_settings.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
#include "editor/gui/editor_bottom_panel.h"
#include "editor/gui/editor_file_dialog.h"
#include "editor/themes/editor_scale.h"
// TODO implement redo/undo system
HashMap<String, String> OpenXRActionMapEditor::interaction_profile_editors;
HashMap<String, String> OpenXRActionMapEditor::binding_modifier_editors;
void OpenXRActionMapEditor::_bind_methods() {
ClassDB::bind_method("_add_action_set_editor", &OpenXRActionMapEditor::_add_action_set_editor);
@ -50,6 +49,9 @@ void OpenXRActionMapEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_do_remove_action_set_editor", "action_set_editor"), &OpenXRActionMapEditor::_do_remove_action_set_editor);
ClassDB::bind_method(D_METHOD("_do_add_interaction_profile_editor", "interaction_profile_editor"), &OpenXRActionMapEditor::_do_add_interaction_profile_editor);
ClassDB::bind_method(D_METHOD("_do_remove_interaction_profile_editor", "interaction_profile_editor"), &OpenXRActionMapEditor::_do_remove_interaction_profile_editor);
ClassDB::bind_static_method("OpenXRActionMapEditor", D_METHOD("register_interaction_profile_editor", "interaction_profile_path", "editor_class"), &OpenXRActionMapEditor::register_interaction_profile_editor);
ClassDB::bind_static_method("OpenXRActionMapEditor", D_METHOD("register_binding_modifier_editor", "binding_modifier_class", "editor_class"), &OpenXRActionMapEditor::register_binding_modifier_editor);
}
void OpenXRActionMapEditor::_notification(int p_what) {
@ -100,19 +102,32 @@ OpenXRInteractionProfileEditorBase *OpenXRActionMapEditor::_add_interaction_prof
// need to instance the correct editor for our profile
OpenXRInteractionProfileEditorBase *new_profile_editor = nullptr;
if (profile_path == "placeholder_text") {
// instance specific editor for this type
} else {
if (interaction_profile_editors.has(profile_path)) {
Object *new_editor = ClassDB::instantiate(interaction_profile_editors[profile_path]);
if (new_editor) {
new_profile_editor = Object::cast_to<OpenXRInteractionProfileEditorBase>(new_editor);
if (!new_profile_editor) {
WARN_PRINT("Interaction profile editor type mismatch for " + profile_path);
memfree(new_editor);
}
}
}
if (!new_profile_editor) {
// instance generic editor
new_profile_editor = memnew(OpenXRInteractionProfileEditor(action_map, p_interaction_profile));
new_profile_editor = memnew(OpenXRInteractionProfileEditor);
}
// now add it in..
ERR_FAIL_NULL_V(new_profile_editor, nullptr);
new_profile_editor->setup(action_map, p_interaction_profile);
tabs->add_child(new_profile_editor);
new_profile_editor->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));
tabs->set_tab_button_icon(tabs->get_tab_count() - 1, get_theme_icon(SNAME("close"), SNAME("TabBar")));
if (!new_profile_editor->tooltip.is_empty()) {
tabs->set_tab_tooltip(tabs->get_tab_count() - 1, new_profile_editor->tooltip);
}
return new_profile_editor;
}
@ -195,8 +210,19 @@ void OpenXRActionMapEditor::_on_remove_action_set(Object *p_action_set_editor) {
Ref<OpenXRActionSet> 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<OpenXRInteractionProfileEditorBase>(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 +236,7 @@ void OpenXRActionMapEditor::_on_action_removed(Ref<OpenXRAction> p_action) {
// First tab won't be an interaction profile editor, but being thorough..
OpenXRInteractionProfileEditorBase *interaction_profile_editor = Object::cast_to<OpenXRInteractionProfileEditorBase>(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 +413,22 @@ void OpenXRActionMapEditor::_clear_action_map() {
}
}
void OpenXRActionMapEditor::register_interaction_profile_editor(const String &p_for_path, const String &p_editor_class) {
interaction_profile_editors[p_for_path] = p_editor_class;
}
void OpenXRActionMapEditor::register_binding_modifier_editor(const String &p_binding_modifier_class, const String &p_editor_class) {
binding_modifier_editors[p_binding_modifier_class] = p_editor_class;
}
String OpenXRActionMapEditor::get_binding_modifier_editor_class(const String &p_binding_modifier_class) {
if (binding_modifier_editors.has(p_binding_modifier_class)) {
return binding_modifier_editors[p_binding_modifier_class];
}
return OpenXRBindingModifierEditor::get_class_static();
}
OpenXRActionMapEditor::OpenXRActionMapEditor() {
undo_redo = EditorUndoRedoManager::get_singleton();
set_custom_minimum_size(Size2(0.0, 300.0));

View file

@ -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<String, String> interaction_profile_editors; // interaction profile path, interaction profile editor
static HashMap<String, String> binding_modifier_editors; // binding modifier class, binding modifiers editor
EditorUndoRedoManager *undo_redo;
String edited_path;
Ref<OpenXRActionMap> action_map;
@ -100,6 +104,10 @@ protected:
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();

View file

@ -46,16 +46,16 @@ void OpenXRActionSetEditor::_bind_methods() {
void OpenXRActionSetEditor::_set_fold_icon() {
if (is_expanded) {
fold_btn->set_icon(get_theme_icon(SNAME("GuiTreeArrowDown"), EditorStringName(EditorIcons)));
fold_btn->set_button_icon(get_theme_icon(SNAME("GuiTreeArrowDown"), EditorStringName(EditorIcons)));
} else {
fold_btn->set_icon(get_theme_icon(SNAME("GuiTreeArrowRight"), EditorStringName(EditorIcons)));
fold_btn->set_button_icon(get_theme_icon(SNAME("GuiTreeArrowRight"), EditorStringName(EditorIcons)));
}
}
void OpenXRActionSetEditor::_theme_changed() {
_set_fold_icon();
add_action->set_icon(get_theme_icon(SNAME("Add"), EditorStringName(EditorIcons)));
rem_action_set->set_icon(get_theme_icon(SNAME("Remove"), EditorStringName(EditorIcons)));
add_action->set_button_icon(get_theme_icon(SNAME("Add"), EditorStringName(EditorIcons)));
rem_action_set->set_button_icon(get_theme_icon(SNAME("Remove"), EditorStringName(EditorIcons)));
}
void OpenXRActionSetEditor::_notification(int p_what) {

View file

@ -87,7 +87,7 @@ protected:
void _do_remove_action_editor(OpenXRActionEditor *p_action_editor);
public:
Ref<OpenXRActionSet> get_action_set() { return action_set; };
Ref<OpenXRActionSet> get_action_set() { return action_set; }
void set_focus_on_entry();
void remove_all_actions();

View file

@ -0,0 +1,289 @@
/**************************************************************************/
/* 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<OpenXRActionSet> 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<OpenXRActionSet> which = current;
for (int i = 0; i < options->get_item_count(); i++) {
if (which == (Ref<OpenXRActionSet>)options->get_item_metadata(i)) {
options->select(i);
return;
}
}
// Couldn't find it? deselect..
options->select(-1);
}
void EditorPropertyActionSet::setup(const Ref<OpenXRActionMap> &p_action_map) {
options->clear();
Array action_sets = p_action_map->get_action_sets();
for (Ref<OpenXRActionSet> 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<OpenXRAction::ActionType> p_include_action_types) {
options->clear();
const OpenXRInteractionProfileMetadata::InteractionProfile *profile_def = OpenXRInteractionProfileMetadata::get_singleton()->get_profile(p_interaction_profile_path);
// Determine toplevel paths
Vector<String> top_level_paths;
for (const OpenXRInteractionProfileMetadata::IOPath &io_path : profile_def->io_paths) {
if (!top_level_paths.has(io_path.top_level_path)) {
top_level_paths.push_back(io_path.top_level_path);
}
}
for (const String &top_level_path : top_level_paths) {
String top_level_name = OpenXRInteractionProfileMetadata::get_singleton()->get_top_level_name(top_level_path);
for (const OpenXRInteractionProfileMetadata::IOPath &io_path : profile_def->io_paths) {
if (io_path.top_level_path == top_level_path && p_include_action_types.has(io_path.action_type)) {
options->add_item(top_level_name + "/" + io_path.display_name);
options->set_item_metadata(-1, io_path.openxr_path);
}
}
}
}
void EditorPropertyBindingPath::set_option_button_clip(bool p_enable) {
options->set_clip_text(p_enable);
}
EditorPropertyBindingPath::EditorPropertyBindingPath() {
options = memnew(OptionButton);
options->set_clip_text(true);
options->set_flat(true);
options->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
add_child(options);
add_focusable(options);
options->connect(SceneStringName(item_selected), callable_mp(this, &EditorPropertyBindingPath::_option_selected));
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// OpenXRBindingModifierEditor
bool EditorInspectorPluginBindingModifier::can_handle(Object *p_object) {
Ref<OpenXRBindingModifier> binding_modifier(Object::cast_to<OpenXRBindingModifier>(p_object));
return binding_modifier.is_valid();
}
bool EditorInspectorPluginBindingModifier::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide) {
Ref<OpenXRActionBindingModifier> action_binding_modifier(Object::cast_to<OpenXRActionBindingModifier>(p_object));
if (action_binding_modifier.is_valid()) {
if (p_type == Variant::OBJECT && p_hint == PROPERTY_HINT_RESOURCE_TYPE && p_hint_text == OpenXRActionSet::get_class_static()) {
OpenXRIPBinding *ip_binding = action_binding_modifier->get_ip_binding();
ERR_FAIL_NULL_V(ip_binding, false);
OpenXRActionMap *action_map = ip_binding->get_action_map();
ERR_FAIL_NULL_V(action_map, false);
EditorPropertyActionSet *action_set_property = memnew(EditorPropertyActionSet);
action_set_property->setup(action_map);
add_property_editor(p_path, action_set_property);
return true;
}
return false;
}
Ref<OpenXRIPBindingModifier> ip_binding_modifier(Object::cast_to<OpenXRIPBindingModifier>(p_object));
if (ip_binding_modifier.is_valid()) {
if (p_type == Variant::OBJECT && p_hint == PROPERTY_HINT_RESOURCE_TYPE && p_hint_text == OpenXRActionSet::get_class_static()) {
OpenXRInteractionProfile *interaction_profile = ip_binding_modifier->get_interaction_profile();
ERR_FAIL_NULL_V(interaction_profile, false);
OpenXRActionMap *action_map = interaction_profile->get_action_map();
ERR_FAIL_NULL_V(action_map, false);
EditorPropertyActionSet *action_set_property = memnew(EditorPropertyActionSet);
action_set_property->setup(action_map);
add_property_editor(p_path, action_set_property);
return true;
}
if (p_type == Variant::STRING && p_hint == PROPERTY_HINT_TYPE_STRING && p_hint_text == "binding_path") {
EditorPropertyBindingPath *binding_path_property = memnew(EditorPropertyBindingPath);
OpenXRInteractionProfile *interaction_profile = ip_binding_modifier->get_interaction_profile();
ERR_FAIL_NULL_V(interaction_profile, false);
Vector<OpenXRAction::ActionType> action_types;
action_types.push_back(OpenXRAction::OPENXR_ACTION_VECTOR2);
binding_path_property->setup(interaction_profile->get_interaction_profile_path(), action_types);
add_property_editor(p_path, binding_path_property);
return true;
}
return false;
}
return false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// OpenXRBindingModifierEditor
void OpenXRBindingModifierEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_binding_modifier"), &OpenXRBindingModifierEditor::get_binding_modifier);
ClassDB::bind_method(D_METHOD("setup", "action_map", "binding_modifier"), &OpenXRBindingModifierEditor::setup);
ADD_SIGNAL(MethodInfo("binding_modifier_removed", 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_button_icon(get_theme_icon(SNAME("Remove"), EditorStringName(EditorIcons)));
} break;
}
}
void OpenXRBindingModifierEditor::_on_remove_binding_modifier() {
// Tell parent to remove us
emit_signal("binding_modifier_removed", this);
}
OpenXRBindingModifierEditor::OpenXRBindingModifierEditor() {
undo_redo = EditorUndoRedoManager::get_singleton();
set_h_size_flags(Control::SIZE_EXPAND_FILL);
main_vb = memnew(VBoxContainer);
main_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
add_child(main_vb);
header_hb = memnew(HBoxContainer);
header_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
main_vb->add_child(header_hb);
binding_modifier_title = memnew(Label);
binding_modifier_title->set_h_size_flags(Control::SIZE_EXPAND_FILL);
header_hb->add_child(binding_modifier_title);
rem_binding_modifier_btn = memnew(Button);
rem_binding_modifier_btn->set_tooltip_text(TTR("Remove binding modifier."));
rem_binding_modifier_btn->connect(SceneStringName(pressed), callable_mp(this, &OpenXRBindingModifierEditor::_on_remove_binding_modifier));
rem_binding_modifier_btn->set_flat(true);
header_hb->add_child(rem_binding_modifier_btn);
editor_inspector = memnew(EditorInspector);
editor_inspector->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
editor_inspector->set_vertical_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
editor_inspector->set_h_size_flags(Control::SIZE_EXPAND_FILL);
main_vb->add_child(editor_inspector);
}
void OpenXRBindingModifierEditor::setup(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRBindingModifier> p_binding_modifier) {
ERR_FAIL_NULL(binding_modifier_title);
ERR_FAIL_NULL(editor_inspector);
action_map = p_action_map;
binding_modifier = p_binding_modifier;
if (p_binding_modifier.is_valid()) {
binding_modifier_title->set_text(p_binding_modifier->get_description());
editor_inspector->set_object_class(p_binding_modifier->get_class());
editor_inspector->edit(p_binding_modifier.ptr());
}
}

View file

@ -0,0 +1,113 @@
/**************************************************************************/
/* 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_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<OpenXRActionMap> &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<OpenXRAction::ActionType> p_include_action_types);
virtual void update_property() override;
void set_option_button_clip(bool p_enable);
EditorPropertyBindingPath();
};
class EditorInspectorPluginBindingModifier : public EditorInspectorPlugin {
GDCLASS(EditorInspectorPluginBindingModifier, EditorInspectorPlugin);
public:
virtual bool can_handle(Object *p_object) override;
virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide) override;
};
class OpenXRBindingModifierEditor : public PanelContainer {
GDCLASS(OpenXRBindingModifierEditor, PanelContainer);
private:
HBoxContainer *header_hb = nullptr;
Label *binding_modifier_title = nullptr;
Button *rem_binding_modifier_btn = nullptr;
EditorInspector *editor_inspector = nullptr;
protected:
VBoxContainer *main_vb = nullptr;
EditorUndoRedoManager *undo_redo;
Ref<OpenXRBindingModifier> binding_modifier;
Ref<OpenXRActionMap> action_map;
static void _bind_methods();
void _notification(int p_what);
void _on_remove_binding_modifier();
public:
Ref<OpenXRBindingModifier> get_binding_modifier() const { return binding_modifier; }
virtual void setup(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRBindingModifier> p_binding_modifier);
OpenXRBindingModifierEditor();
};
#endif // OPENXR_BINDING_MODIFIER_EDITOR_H

View file

@ -0,0 +1,257 @@
/**************************************************************************/
/* 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 "openxr_action_map_editor.h"
void OpenXRBindingModifiersDialog::_bind_methods() {
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<OpenXRBindingModifier> 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<OpenXRBindingModifierEditor>(obj);
if (!new_editor) {
// Not of correct type?? Free it.
memfree(obj);
}
}
ERR_FAIL_NULL_V(new_editor, nullptr);
new_editor->setup(action_map, p_binding_modifier);
new_editor->connect("binding_modifier_removed", 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<OpenXRBindingModifier> 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<OpenXRBindingModifierEditor>(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<OpenXRBindingModifier> new_binding_modifier = obj;
ERR_FAIL_COND(new_binding_modifier.is_null());
if (ip_binding.is_valid()) {
// Add it to our binding.
ip_binding->add_binding_modifier(new_binding_modifier);
ip_binding->set_edited(true);
} else if (interaction_profile.is_valid()) {
// 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<OpenXRBindingModifier> 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<OpenXRBindingModifier> 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->connect("create", callable_mp(this, &OpenXRBindingModifiersDialog::_on_dialog_created));
add_child(create_dialog);
}
void OpenXRBindingModifiersDialog::setup(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile, Ref<OpenXRIPBinding> 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<OpenXRAction> 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;
}
create_dialog->set_base_type("OpenXRActionBindingModifier");
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;
}
create_dialog->set_base_type("OpenXRIPBindingModifier");
set_title(TTR("Binding modifiers for:") + " " + profile_name);
}
}

View file

@ -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<OpenXRBindingModifier> 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<OpenXRActionMap> action_map;
Ref<OpenXRInteractionProfile> interaction_profile;
Ref<OpenXRIPBinding> 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<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile, Ref<OpenXRIPBinding> p_ip_binding = Ref<OpenXRIPBinding>());
};
#endif // OPENXR_BINDING_MODIFIERS_DIALOG_H

View file

@ -54,7 +54,10 @@ void OpenXREditorPlugin::make_visible(bool p_visible) {
OpenXREditorPlugin::OpenXREditorPlugin() {
action_map_editor = memnew(OpenXRActionMapEditor);
EditorNode::get_bottom_panel()->add_item(TTR("OpenXR Action Map"), action_map_editor, ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_openxr_action_map_bottom_panel", TTR("Toggle OpenXR Action Map Bottom Panel")));
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", TTRC("Toggle OpenXR Action Map Bottom Panel")));
binding_modifier_inspector_plugin = Ref<EditorInspectorPluginBindingModifier>(memnew(EditorInspectorPluginBindingModifier));
EditorInspector::add_inspector_plugin(binding_modifier_inspector_plugin);
#ifndef ANDROID_ENABLED
select_runtime = memnew(OpenXRSelectRuntime);

View file

@ -32,6 +32,7 @@
#define OPENXR_EDITOR_PLUGIN_H
#include "openxr_action_map_editor.h"
#include "openxr_binding_modifier_editor.h"
#include "openxr_select_runtime.h"
#include "editor/plugins/editor_plugin.h"
@ -40,12 +41,13 @@ class OpenXREditorPlugin : public EditorPlugin {
GDCLASS(OpenXREditorPlugin, EditorPlugin);
OpenXRActionMapEditor *action_map_editor = nullptr;
Ref<EditorInspectorPluginBindingModifier> binding_modifier_inspector_plugin = nullptr;
#ifndef ANDROID_ENABLED
OpenXRSelectRuntime *select_runtime = nullptr;
#endif
public:
virtual String get_name() const override { return "OpenXRPlugin"; }
virtual String get_plugin_name() const override { return "OpenXRPlugin"; }
bool has_main_screen() const override { return false; }
virtual void edit(Object *p_node) override;
virtual bool handles(Object *p_node) const override;

View file

@ -29,20 +29,15 @@
/**************************************************************************/
#include "openxr_interaction_profile_editor.h"
#include "../openxr_api.h"
#include "editor/editor_string_names.h"
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
#include "scene/gui/label.h"
#include "scene/gui/line_edit.h"
#include "scene/gui/panel_container.h"
#include "scene/gui/separator.h"
#include "scene/gui/text_edit.h"
///////////////////////////////////////////////////////////////////////////
// Interaction profile editor base
void OpenXRInteractionProfileEditorBase::_bind_methods() {
ClassDB::bind_method(D_METHOD("setup", "action_map", "interaction_profile"), &OpenXRInteractionProfileEditorBase::setup);
ClassDB::bind_method(D_METHOD("_add_binding", "action", "path"), &OpenXRInteractionProfileEditorBase::_add_binding);
ClassDB::bind_method(D_METHOD("_remove_binding", "action", "path"), &OpenXRInteractionProfileEditorBase::_remove_binding);
}
@ -73,17 +68,19 @@ void OpenXRInteractionProfileEditorBase::_add_binding(const String p_action, con
Ref<OpenXRAction> action = action_map->get_action(p_action);
ERR_FAIL_COND(action.is_null());
Ref<OpenXRIPBinding> binding = interaction_profile->get_binding_for_action(action);
Ref<OpenXRIPBinding> binding = interaction_profile->find_binding(action, p_path);
if (binding.is_null()) {
// create a new binding
binding.instantiate();
binding->set_action(action);
binding->set_binding_path(p_path);
// add it to our interaction profile
interaction_profile->add_binding(binding);
interaction_profile->set_edited(true);
}
binding->add_path(p_path);
binding->set_edited(true);
binding->set_edited(true);
}
// Update our toplevel paths
action->set_toplevel_paths(action_map->get_top_level_paths(action));
@ -98,15 +95,10 @@ void OpenXRInteractionProfileEditorBase::_remove_binding(const String p_action,
Ref<OpenXRAction> action = action_map->get_action(p_action);
ERR_FAIL_COND(action.is_null());
Ref<OpenXRIPBinding> binding = interaction_profile->get_binding_for_action(action);
Ref<OpenXRIPBinding> binding = interaction_profile->find_binding(action, p_path);
if (binding.is_valid()) {
binding->remove_path(p_path);
binding->set_edited(true);
if (binding->get_path_count() == 0) {
interaction_profile->remove_binding(binding);
interaction_profile->set_edited(true);
}
interaction_profile->remove_binding(binding);
interaction_profile->set_edited(true);
// Update our toplevel paths
action->set_toplevel_paths(action_map->get_top_level_paths(action));
@ -115,22 +107,47 @@ void OpenXRInteractionProfileEditorBase::_remove_binding(const String p_action,
}
}
void OpenXRInteractionProfileEditorBase::remove_all_bindings_for_action(Ref<OpenXRAction> p_action) {
Ref<OpenXRIPBinding> binding = interaction_profile->get_binding_for_action(p_action);
if (binding.is_valid()) {
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_button_icon(get_theme_icon(SNAME("Modifiers"), EditorStringName(EditorIcons)));
}
}
void OpenXRInteractionProfileEditorBase::remove_all_for_action_set(Ref<OpenXRActionSet> 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<OpenXRAction> p_action) {
Vector<Ref<OpenXRIPBinding>> 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"));
PackedStringArray paths = binding->get_paths();
for (const String &path : paths) {
undo_redo->add_do_method(this, "_remove_binding", action_name, path);
undo_redo->add_undo_method(this, "_add_binding", action_name, path);
for (const Ref<OpenXRIPBinding> &binding : bindings) {
undo_redo->add_do_method(this, "_remove_binding", action_name, binding->get_binding_path());
undo_redo->add_undo_method(this, "_add_binding", action_name, binding->get_binding_path());
}
undo_redo->commit_action(false);
// but we take a shortcut here :)
interaction_profile->remove_binding(binding);
// But remove them all in one go so we're more efficient in updating our UI.
for (const Ref<OpenXRIPBinding> &binding : bindings) {
interaction_profile->remove_binding(binding);
}
interaction_profile->set_edited(true);
// Update our toplevel paths
@ -139,10 +156,39 @@ void OpenXRInteractionProfileEditorBase::remove_all_bindings_for_action(Ref<Open
_do_update_interaction_profile();
}
}
void OpenXRInteractionProfileEditorBase::_on_open_binding_modifiers() {
binding_modifiers_dialog->popup_centered(Size2i(500, 400));
}
OpenXRInteractionProfileEditorBase::OpenXRInteractionProfileEditorBase(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile) {
OpenXRInteractionProfileEditorBase::OpenXRInteractionProfileEditorBase() {
undo_redo = EditorUndoRedoManager::get_singleton();
set_h_size_flags(SIZE_EXPAND_FILL);
set_v_size_flags(SIZE_EXPAND_FILL);
interaction_profile_sc = memnew(ScrollContainer);
interaction_profile_sc->set_h_size_flags(SIZE_EXPAND_FILL);
interaction_profile_sc->set_v_size_flags(SIZE_EXPAND_FILL);
add_child(interaction_profile_sc);
binding_modifiers_dialog = memnew(OpenXRBindingModifiersDialog);
add_child(binding_modifiers_dialog);
toolbar_vb = memnew(VBoxContainer);
toolbar_vb->set_v_size_flags(SIZE_EXPAND_FILL);
add_child(toolbar_vb);
binding_modifiers_btn = memnew(Button);
binding_modifiers_btn->set_tooltip_text(TTR("Edit binding modifiers"));
binding_modifiers_btn->connect("pressed", callable_mp(this, &OpenXRInteractionProfileEditorBase::_on_open_binding_modifiers));
// TODO show visual difference if there are binding modifiers for this interaction profile
toolbar_vb->add_child(binding_modifiers_btn);
}
void OpenXRInteractionProfileEditorBase::setup(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile) {
ERR_FAIL_NULL(binding_modifiers_dialog);
binding_modifiers_dialog->setup(p_action_map, p_interaction_profile);
action_map = p_action_map;
interaction_profile = p_interaction_profile;
String profile_path = interaction_profile->get_interaction_profile_path();
@ -151,11 +197,15 @@ OpenXRInteractionProfileEditorBase::OpenXRInteractionProfileEditorBase(Ref<OpenX
profile_def = OpenXRInteractionProfileMetadata::get_singleton()->get_profile(profile_path);
if (profile_def != nullptr) {
profile_name = profile_def->display_name;
if (!profile_def->openxr_extension_name.is_empty()) {
profile_name += "*";
tooltip = vformat(TTR("Note: This interaction profile requires extension %s support."), profile_def->openxr_extension_name);
}
}
set_name(profile_name);
set_h_size_flags(SIZE_EXPAND_FILL);
set_v_size_flags(SIZE_EXPAND_FILL);
// Make sure it is updated when it enters the tree...
is_dirty = true;
@ -169,7 +219,7 @@ void OpenXRInteractionProfileEditor::select_action_for(const String p_io_path) {
select_action_dialog->open();
}
void OpenXRInteractionProfileEditor::action_selected(const String p_action) {
void OpenXRInteractionProfileEditor::_on_action_selected(const String p_action) {
undo_redo->create_action(TTR("Add binding"));
undo_redo->add_do_method(this, "_add_binding", p_action, selecting_for_io_path);
undo_redo->add_undo_method(this, "_remove_binding", p_action, selecting_for_io_path);
@ -191,7 +241,12 @@ void OpenXRInteractionProfileEditor::_add_io_path(VBoxContainer *p_container, co
p_container->add_child(path_hb);
Label *path_label = memnew(Label);
path_label->set_text(p_io_path->display_name);
if (p_io_path->openxr_extension_name.is_empty()) {
path_label->set_text(p_io_path->display_name);
} else {
path_label->set_text(p_io_path->display_name + "*");
p_container->set_tooltip_text(vformat(TTR("Note: This binding path requires extension %s support."), p_io_path->openxr_extension_name));
}
path_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
path_hb->add_child(path_label);
@ -220,7 +275,7 @@ void OpenXRInteractionProfileEditor::_add_io_path(VBoxContainer *p_container, co
path_hb->add_child(type_label);
Button *path_add = memnew(Button);
path_add->set_icon(get_theme_icon(SNAME("Add"), EditorStringName(EditorIcons)));
path_add->set_button_icon(get_theme_icon(SNAME("Add"), EditorStringName(EditorIcons)));
path_add->set_flat(true);
path_add->connect(SceneStringName(pressed), callable_mp(this, &OpenXRInteractionProfileEditor::select_action_for).bind(String(p_io_path->openxr_path)));
path_hb->add_child(path_add);
@ -228,9 +283,8 @@ void OpenXRInteractionProfileEditor::_add_io_path(VBoxContainer *p_container, co
if (interaction_profile.is_valid()) {
String io_path = String(p_io_path->openxr_path);
Array bindings = interaction_profile->get_bindings();
for (int i = 0; i < bindings.size(); i++) {
Ref<OpenXRIPBinding> binding = bindings[i];
if (binding->has_path(io_path)) {
for (Ref<OpenXRIPBinding> binding : bindings) {
if (binding->get_binding_path() == io_path) {
Ref<OpenXRAction> action = binding->get_action();
HBoxContainer *action_hb = memnew(HBoxContainer);
@ -246,9 +300,20 @@ void OpenXRInteractionProfileEditor::_add_io_path(VBoxContainer *p_container, co
action_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
action_hb->add_child(action_label);
OpenXRBindingModifiersDialog *action_binding_modifiers_dialog = memnew(OpenXRBindingModifiersDialog);
action_binding_modifiers_dialog->setup(action_map, interaction_profile, binding);
action_hb->add_child(action_binding_modifiers_dialog);
Button *action_binding_modifiers_btn = memnew(Button);
action_binding_modifiers_btn->set_flat(true);
action_binding_modifiers_btn->set_button_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)));
action_rem->set_button_icon(get_theme_icon(SNAME("Remove"), EditorStringName(EditorIcons)));
action_rem->connect(SceneStringName(pressed), callable_mp((OpenXRInteractionProfileEditor *)this, &OpenXRInteractionProfileEditor::_on_remove_pressed).bind(action->get_name_with_set(), String(p_io_path->openxr_path)));
action_hb->add_child(action_rem);
}
@ -264,9 +329,11 @@ void OpenXRInteractionProfileEditor::_update_interaction_profile() {
return;
}
PackedStringArray requested_extensions = OpenXRAPI::get_all_requested_extensions();
// out with the old...
while (main_hb->get_child_count() > 0) {
memdelete(main_hb->get_child(0));
while (interaction_profile_hb->get_child_count() > 0) {
memdelete(interaction_profile_hb->get_child(0));
}
// in with the new...
@ -284,7 +351,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);
@ -296,31 +363,37 @@ void OpenXRInteractionProfileEditor::_update_interaction_profile() {
for (int j = 0; j < profile_def->io_paths.size(); j++) {
const OpenXRInteractionProfileMetadata::IOPath *io_path = &profile_def->io_paths[j];
if (io_path->top_level_path == top_level_paths[i]) {
if (io_path->top_level_path == top_level_paths[i] && (io_path->openxr_extension_name.is_empty() || requested_extensions.has(io_path->openxr_extension_name))) {
_add_io_path(container, io_path);
}
}
}
// and we've updated it...
is_dirty = false;
OpenXRInteractionProfileEditorBase::_update_interaction_profile();
}
void OpenXRInteractionProfileEditor::_theme_changed() {
for (int i = 0; i < main_hb->get_child_count(); i++) {
Control *panel = Object::cast_to<Control>(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<Control>(interaction_profile_hb->get_child(i));
if (panel) {
panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("TabContainer")));
}
}
}
OpenXRInteractionProfileEditor::OpenXRInteractionProfileEditor(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile) :
OpenXRInteractionProfileEditorBase(p_action_map, p_interaction_profile) {
main_hb = memnew(HBoxContainer);
add_child(main_hb);
OpenXRInteractionProfileEditor::OpenXRInteractionProfileEditor() {
interaction_profile_hb = memnew(HBoxContainer);
interaction_profile_sc->add_child(interaction_profile_hb);
}
void OpenXRInteractionProfileEditor::setup(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile) {
OpenXRInteractionProfileEditorBase::setup(p_action_map, p_interaction_profile);
select_action_dialog = memnew(OpenXRSelectActionDialog(p_action_map));
select_action_dialog->connect("action_selected", callable_mp(this, &OpenXRInteractionProfileEditor::action_selected));
select_action_dialog->connect("action_selected", callable_mp(this, &OpenXRInteractionProfileEditor::_on_action_selected));
add_child(select_action_dialog);
}

View file

@ -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 "openxr_select_action_dialog.h"
#include "../editor/openxr_binding_modifiers_dialog.h"
#include "editor/editor_undo_redo_manager.h"
#include "scene/gui/scroll_container.h"
#include "openxr_select_action_dialog.h"
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
class OpenXRInteractionProfileEditorBase : public ScrollContainer {
GDCLASS(OpenXRInteractionProfileEditorBase, ScrollContainer);
class OpenXRInteractionProfileEditorBase : public HBoxContainer {
GDCLASS(OpenXRInteractionProfileEditorBase, HBoxContainer);
private:
OpenXRBindingModifiersDialog *binding_modifiers_dialog = nullptr;
VBoxContainer *toolbar_vb = nullptr;
Button *binding_modifiers_btn = nullptr;
void _on_open_binding_modifiers();
protected:
EditorUndoRedoManager *undo_redo;
Ref<OpenXRInteractionProfile> interaction_profile;
Ref<OpenXRActionMap> action_map;
ScrollContainer *interaction_profile_sc = nullptr;
bool is_dirty = false;
static void _bind_methods();
@ -55,18 +65,23 @@ protected:
const OpenXRInteractionProfileMetadata::InteractionProfile *profile_def = nullptr;
public:
String tooltip; // Tooltip text to show on tab
Ref<OpenXRInteractionProfile> 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<OpenXRAction> p_action);
void remove_all_for_action_set(Ref<OpenXRActionSet> p_action_set);
void remove_all_for_action(Ref<OpenXRAction> p_action);
OpenXRInteractionProfileEditorBase(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile);
virtual void setup(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile);
OpenXRInteractionProfileEditorBase();
};
class OpenXRInteractionProfileEditor : public OpenXRInteractionProfileEditorBase {
@ -74,19 +89,22 @@ 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);
public:
void select_action_for(const String p_io_path);
void action_selected(const String p_action);
void _on_action_selected(const String p_action);
void _on_remove_pressed(const String p_action, const String p_for_io_path);
virtual void _update_interaction_profile() override;
virtual void _theme_changed() override;
OpenXRInteractionProfileEditor(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile);
virtual void setup(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile) override;
OpenXRInteractionProfileEditor();
};
#endif // OPENXR_INTERACTION_PROFILE_EDITOR_H

View file

@ -66,7 +66,7 @@ void OpenXRSelectActionDialog::_on_select_action(const String p_action) {
void OpenXRSelectActionDialog::open() {
ERR_FAIL_COND(action_map.is_null());
// out with the old...
// Out with the old.
while (main_vb->get_child_count() > 0) {
memdelete(main_vb->get_child(0));
}
@ -74,6 +74,7 @@ void OpenXRSelectActionDialog::open() {
selected_action = "";
action_buttons.clear();
// In with the new.
Array action_sets = action_map->get_action_sets();
for (int i = 0; i < action_sets.size(); i++) {
Ref<OpenXRActionSet> action_set = action_sets[i];

View file

@ -30,6 +30,9 @@
#include "openxr_select_interaction_profile_dialog.h"
#include "../action_map/openxr_interaction_profile_metadata.h"
#include "../openxr_api.h"
void OpenXRSelectInteractionProfileDialog::_bind_methods() {
ADD_SIGNAL(MethodInfo("interaction_profile_selected", PropertyInfo(Variant::STRING, "interaction_profile")));
}
@ -66,22 +69,28 @@ void OpenXRSelectInteractionProfileDialog::_on_select_interaction_profile(const
void OpenXRSelectInteractionProfileDialog::open(PackedStringArray p_do_not_include) {
int available_count = 0;
// out with the old...
while (main_vb->get_child_count() > 0) {
memdelete(main_vb->get_child(0));
OpenXRInteractionProfileMetadata *meta_data = OpenXRInteractionProfileMetadata::get_singleton();
ERR_FAIL_NULL(meta_data);
// Out with the old.
while (main_vb->get_child_count() > 1) {
memdelete(main_vb->get_child(1));
}
PackedStringArray requested_extensions = OpenXRAPI::get_all_requested_extensions();
selected_interaction_profile = "";
ip_buttons.clear();
// in with the new
PackedStringArray interaction_profiles = OpenXRInteractionProfileMetadata::get_singleton()->get_interaction_profile_paths();
for (int i = 0; i < interaction_profiles.size(); i++) {
const String &path = interaction_profiles[i];
if (!p_do_not_include.has(path)) {
// In with the new.
PackedStringArray interaction_profiles = meta_data->get_interaction_profile_paths();
for (const String &path : interaction_profiles) {
const String extension = meta_data->get_interaction_profile_extension(path);
if (!p_do_not_include.has(path) && (extension.is_empty() || requested_extensions.has(extension))) {
Button *ip_button = memnew(Button);
ip_button->set_flat(true);
ip_button->set_text(OpenXRInteractionProfileMetadata::get_singleton()->get_profile(path)->display_name);
ip_button->set_text(meta_data->get_profile(path)->display_name);
ip_button->set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT);
ip_button->connect(SceneStringName(pressed), callable_mp(this, &OpenXRSelectInteractionProfileDialog::_on_select_interaction_profile).bind(path));
main_vb->add_child(ip_button);
@ -90,23 +99,16 @@ void OpenXRSelectInteractionProfileDialog::open(PackedStringArray p_do_not_inclu
}
}
if (available_count == 0) {
// give warning that we have all profiles selected
} else {
// TODO maybe if we only have one, auto select it?
popup_centered();
}
all_selected->set_visible(available_count == 0);
get_cancel_button()->set_visible(available_count > 0);
popup_centered();
}
void OpenXRSelectInteractionProfileDialog::ok_pressed() {
if (selected_interaction_profile == "") {
return;
if (selected_interaction_profile != "") {
emit_signal("interaction_profile_selected", selected_interaction_profile);
}
emit_signal("interaction_profile_selected", selected_interaction_profile);
hide();
}
@ -118,6 +120,10 @@ OpenXRSelectInteractionProfileDialog::OpenXRSelectInteractionProfileDialog() {
add_child(scroll);
main_vb = memnew(VBoxContainer);
// main_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
main_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
scroll->add_child(main_vb);
all_selected = memnew(Label);
all_selected->set_text(TTR("All interaction profiles have been added to the action map."));
main_vb->add_child(all_selected);
}

View file

@ -31,16 +31,10 @@
#ifndef OPENXR_SELECT_INTERACTION_PROFILE_DIALOG_H
#define OPENXR_SELECT_INTERACTION_PROFILE_DIALOG_H
#include "../action_map/openxr_interaction_profile_metadata.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/line_edit.h"
#include "scene/gui/scroll_container.h"
#include "scene/gui/separator.h"
#include "scene/gui/text_edit.h"
class OpenXRSelectInteractionProfileDialog : public ConfirmationDialog {
GDCLASS(OpenXRSelectInteractionProfileDialog, ConfirmationDialog);
@ -51,6 +45,7 @@ private:
VBoxContainer *main_vb = nullptr;
ScrollContainer *scroll = nullptr;
Label *all_selected = nullptr;
protected:
static void _bind_methods();

View file

@ -33,10 +33,6 @@
#include "core/io/dir_access.h"
#include "core/os/os.h"
#include "editor/editor_settings.h"
#include "editor/editor_string_names.h"
void OpenXRSelectRuntime::_bind_methods() {
}
void OpenXRSelectRuntime::_update_items() {
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
@ -78,7 +74,7 @@ void OpenXRSelectRuntime::_update_items() {
select(current_runtime);
}
void OpenXRSelectRuntime::_item_selected(int p_which) {
void OpenXRSelectRuntime::_on_item_selected(int p_which) {
OS *os = OS::get_singleton();
if (p_which == 0) {
@ -98,11 +94,11 @@ void OpenXRSelectRuntime::_notification(int p_notification) {
_update_items();
// Connect signal
connect(SceneStringName(item_selected), callable_mp(this, &OpenXRSelectRuntime::_item_selected));
connect(SceneStringName(item_selected), callable_mp(this, &OpenXRSelectRuntime::_on_item_selected));
} break;
case NOTIFICATION_EXIT_TREE: {
// Disconnect signal
disconnect(SceneStringName(item_selected), callable_mp(this, &OpenXRSelectRuntime::_item_selected));
disconnect(SceneStringName(item_selected), callable_mp(this, &OpenXRSelectRuntime::_on_item_selected));
} break;
}
}
@ -122,6 +118,7 @@ OpenXRSelectRuntime::OpenXRSelectRuntime() {
default_runtimes["SteamVR"] = "~/.steam/steam/steamapps/common/SteamVR/steamxr_linux64.json";
#endif
// TODO: Move to editor_settings.cpp
EDITOR_DEF_RST("xr/openxr/runtime_paths", default_runtimes);
set_flat(true);

View file

@ -40,12 +40,11 @@ public:
OpenXRSelectRuntime();
protected:
static void _bind_methods();
void _notification(int p_notification);
private:
void _update_items();
void _item_selected(int p_which);
void _on_item_selected(int p_which);
};
#endif // OPENXR_SELECT_RUNTIME_H

View file

@ -1,4 +1,5 @@
#!/usr/bin/env python
from misc.utility.scons_hints import *
Import("env")
Import("env_openxr")
@ -12,6 +13,8 @@ if env["platform"] == "android":
env_openxr.add_source_files(module_obj, "platform/openxr_android_extension.cpp")
if env["vulkan"]:
env_openxr.add_source_files(module_obj, "platform/openxr_vulkan_extension.cpp")
if env["metal"]:
env_openxr.add_source_files(module_obj, "platform/openxr_metal_extension.mm")
if env["opengl3"] and env["platform"] != "macos":
env_openxr.add_source_files(module_obj, "platform/openxr_opengl_extension.cpp")

View file

@ -30,6 +30,12 @@
#include "openxr_composition_layer_extension.h"
#ifdef ANDROID_ENABLED
#include <openxr/openxr.h>
#include <openxr/openxr_platform.h>
#endif
#include "platform/android/api/java_class_wrapper.h"
#include "servers/rendering/rendering_server_globals.h"
////////////////////////////////////////////////////////////////////////////
@ -55,18 +61,37 @@ HashMap<String, bool *> OpenXRCompositionLayerExtension::get_requested_extension
request_extensions[XR_KHR_COMPOSITION_LAYER_CYLINDER_EXTENSION_NAME] = &cylinder_ext_available;
request_extensions[XR_KHR_COMPOSITION_LAYER_EQUIRECT2_EXTENSION_NAME] = &equirect_ext_available;
#ifdef ANDROID_ENABLED
request_extensions[XR_KHR_ANDROID_SURFACE_SWAPCHAIN_EXTENSION_NAME] = &android_surface_ext_available;
#endif
return request_extensions;
}
void OpenXRCompositionLayerExtension::on_session_created(const XrSession p_instance) {
void OpenXRCompositionLayerExtension::on_instance_created(const XrInstance p_instance) {
#ifdef ANDROID_ENABLED
EXT_INIT_XR_FUNC(xrDestroySwapchain);
EXT_INIT_XR_FUNC(xrCreateSwapchainAndroidSurfaceKHR);
#endif
}
void OpenXRCompositionLayerExtension::on_session_created(const XrSession p_session) {
OpenXRAPI::get_singleton()->register_composition_layer_provider(this);
}
void OpenXRCompositionLayerExtension::on_session_destroyed() {
OpenXRAPI::get_singleton()->unregister_composition_layer_provider(this);
#ifdef ANDROID_ENABLED
free_queued_android_surface_swapchains();
#endif
}
void OpenXRCompositionLayerExtension::on_pre_render() {
#ifdef ANDROID_ENABLED
free_queued_android_surface_swapchains();
#endif
for (OpenXRViewportCompositionLayerProvider *composition_layer : composition_layers) {
composition_layer->on_pre_render();
}
@ -113,6 +138,36 @@ bool OpenXRCompositionLayerExtension::is_available(XrStructureType p_which) {
}
}
#ifdef ANDROID_ENABLED
bool OpenXRCompositionLayerExtension::create_android_surface_swapchain(XrSwapchainCreateInfo *p_info, XrSwapchain *r_swapchain, jobject *r_surface) {
if (android_surface_ext_available) {
OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
ERR_FAIL_NULL_V(openxr_api, false);
XrResult result = xrCreateSwapchainAndroidSurfaceKHR(openxr_api->get_session(), p_info, r_swapchain, r_surface);
if (XR_FAILED(result)) {
print_line("OpenXR: Failed to create Android surface swapchain [", openxr_api->get_error_string(result), "]");
return false;
}
return true;
}
return false;
}
void OpenXRCompositionLayerExtension::free_android_surface_swapchain(XrSwapchain p_swapchain) {
android_surface_swapchain_free_queue.push_back(p_swapchain);
}
void OpenXRCompositionLayerExtension::free_queued_android_surface_swapchains() {
for (XrSwapchain swapchain : android_surface_swapchain_free_queue) {
xrDestroySwapchain(swapchain);
}
android_surface_swapchain_free_queue.clear();
}
#endif
////////////////////////////////////////////////////////////////////////////
// OpenXRViewportCompositionLayerProvider
@ -127,8 +182,12 @@ OpenXRViewportCompositionLayerProvider::~OpenXRViewportCompositionLayerProvider(
extension->on_viewport_composition_layer_destroyed(composition_layer);
}
// This will reset the viewport and free the swapchain too.
set_viewport(RID(), Size2i());
if (use_android_surface) {
free_swapchain();
} else {
// This will reset the viewport and free the swapchain too.
set_viewport(RID(), Size2i());
}
}
void OpenXRViewportCompositionLayerProvider::set_alpha_blend(bool p_alpha_blend) {
@ -143,43 +202,128 @@ void OpenXRViewportCompositionLayerProvider::set_alpha_blend(bool p_alpha_blend)
}
void OpenXRViewportCompositionLayerProvider::set_viewport(RID p_viewport, Size2i p_size) {
ERR_FAIL_COND(use_android_surface);
RenderingServer *rs = RenderingServer::get_singleton();
ERR_FAIL_NULL(rs);
if (viewport != p_viewport) {
if (viewport.is_valid()) {
RID rt = rs->viewport_get_render_target(viewport);
RSG::texture_storage->render_target_set_override(rt, RID(), RID(), RID());
if (subviewport.viewport != p_viewport) {
if (subviewport.viewport.is_valid()) {
RID rt = rs->viewport_get_render_target(subviewport.viewport);
RSG::texture_storage->render_target_set_override(rt, RID(), RID(), RID(), RID());
}
viewport = p_viewport;
subviewport.viewport = p_viewport;
if (viewport.is_valid()) {
viewport_size = p_size;
if (subviewport.viewport.is_valid()) {
subviewport.viewport_size = p_size;
} else {
free_swapchain();
viewport_size = Size2i();
subviewport.viewport_size = Size2i();
}
}
}
void OpenXRViewportCompositionLayerProvider::set_use_android_surface(bool p_use_android_surface, Size2i p_size) {
#ifdef ANDROID_ENABLED
if (p_use_android_surface == use_android_surface) {
return;
}
use_android_surface = p_use_android_surface;
if (use_android_surface) {
if (!composition_layer_extension->is_android_surface_swapchain_available()) {
ERR_PRINT_ONCE("OpenXR: Cannot use Android surface for composition layer because the extension isn't available");
}
if (subviewport.viewport.is_valid()) {
set_viewport(RID(), Size2i());
}
swapchain_size = p_size;
} else {
free_swapchain();
}
#endif
}
#ifdef ANDROID_ENABLED
void OpenXRViewportCompositionLayerProvider::create_android_surface() {
ERR_FAIL_COND(android_surface.swapchain != XR_NULL_HANDLE || android_surface.surface.is_valid());
ERR_FAIL_COND(!openxr_api || !openxr_api->is_running());
void *next_pointer = nullptr;
for (OpenXRExtensionWrapper *wrapper : openxr_api->get_registered_extension_wrappers()) {
void *np = wrapper->set_android_surface_swapchain_create_info_and_get_next_pointer(extension_property_values, next_pointer);
if (np != nullptr) {
next_pointer = np;
}
}
// The XR_FB_android_surface_swapchain_create extension mandates that format, sampleCount,
// faceCount, arraySize, and mipCount must be zero.
XrSwapchainCreateInfo info = {
XR_TYPE_SWAPCHAIN_CREATE_INFO, // type
next_pointer, // next
0, // createFlags
XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, // usageFlags
0, // format
0, // sampleCount
(uint32_t)swapchain_size.x, // width
(uint32_t)swapchain_size.y, // height
0, // faceCount
0, // arraySize
0, // mipCount
};
jobject surface;
composition_layer_extension->create_android_surface_swapchain(&info, &android_surface.swapchain, &surface);
if (surface) {
android_surface.surface.instantiate(JavaClassWrapper::get_singleton()->wrap("android.view.Surface"), surface);
}
}
#endif
Ref<JavaObject> OpenXRViewportCompositionLayerProvider::get_android_surface() {
#ifdef ANDROID_ENABLED
if (use_android_surface) {
if (android_surface.surface.is_null()) {
create_android_surface();
}
return android_surface.surface;
}
#endif
return Ref<JavaObject>();
}
void OpenXRViewportCompositionLayerProvider::set_extension_property_values(const Dictionary &p_extension_property_values) {
extension_property_values = p_extension_property_values;
extension_property_values_changed = true;
}
void OpenXRViewportCompositionLayerProvider::on_pre_render() {
#ifdef ANDROID_ENABLED
if (use_android_surface) {
if (android_surface.surface.is_null()) {
create_android_surface();
}
return;
}
#endif
RenderingServer *rs = RenderingServer::get_singleton();
ERR_FAIL_NULL(rs);
if (viewport.is_valid() && openxr_api && openxr_api->is_running()) {
RS::ViewportUpdateMode update_mode = rs->viewport_get_update_mode(viewport);
if (subviewport.viewport.is_valid() && openxr_api && openxr_api->is_running()) {
RS::ViewportUpdateMode update_mode = rs->viewport_get_update_mode(subviewport.viewport);
if (update_mode == RS::VIEWPORT_UPDATE_ONCE || update_mode == RS::VIEWPORT_UPDATE_ALWAYS) {
// Update our XR swapchain
if (update_and_acquire_swapchain(update_mode == RS::VIEWPORT_UPDATE_ONCE)) {
// Render to our XR swapchain image.
RID rt = rs->viewport_get_render_target(viewport);
RSG::texture_storage->render_target_set_override(rt, get_current_swapchain_texture(), RID(), RID());
RID rt = rs->viewport_get_render_target(subviewport.viewport);
RSG::texture_storage->render_target_set_override(rt, get_current_swapchain_texture(), RID(), RID(), RID());
}
}
}
@ -196,48 +340,36 @@ XrCompositionLayerBaseHeader *OpenXRViewportCompositionLayerProvider::get_compos
return nullptr;
}
if (swapchain_info.get_swapchain() == XR_NULL_HANDLE) {
XrSwapchainSubImage subimage = {
0, // swapchain // NOLINT(modernize-use-nullptr) - 32-bit uses non-pointer uint64
{ { 0, 0 }, { 0, 0 } }, // imageRect
0, // imageArrayIndex
};
update_swapchain_sub_image(subimage);
if (subimage.swapchain == XR_NULL_HANDLE) {
// Don't have a swapchain to display? Ignore our layer.
return nullptr;
}
if (swapchain_info.is_image_acquired()) {
swapchain_info.release();
}
// Update the layer struct for the swapchain.
switch (composition_layer->type) {
case XR_TYPE_COMPOSITION_LAYER_QUAD: {
XrCompositionLayerQuad *quad_layer = (XrCompositionLayerQuad *)composition_layer;
quad_layer->space = openxr_api->get_play_space();
quad_layer->subImage.swapchain = swapchain_info.get_swapchain();
quad_layer->subImage.imageArrayIndex = 0;
quad_layer->subImage.imageRect.offset.x = 0;
quad_layer->subImage.imageRect.offset.y = 0;
quad_layer->subImage.imageRect.extent.width = swapchain_size.width;
quad_layer->subImage.imageRect.extent.height = swapchain_size.height;
quad_layer->subImage = subimage;
} break;
case XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR: {
XrCompositionLayerCylinderKHR *cylinder_layer = (XrCompositionLayerCylinderKHR *)composition_layer;
cylinder_layer->space = openxr_api->get_play_space();
cylinder_layer->subImage.swapchain = swapchain_info.get_swapchain();
cylinder_layer->subImage.imageArrayIndex = 0;
cylinder_layer->subImage.imageRect.offset.x = 0;
cylinder_layer->subImage.imageRect.offset.y = 0;
cylinder_layer->subImage.imageRect.extent.width = swapchain_size.width;
cylinder_layer->subImage.imageRect.extent.height = swapchain_size.height;
cylinder_layer->subImage = subimage;
} break;
case XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR: {
XrCompositionLayerEquirect2KHR *equirect_layer = (XrCompositionLayerEquirect2KHR *)composition_layer;
equirect_layer->space = openxr_api->get_play_space();
equirect_layer->subImage.swapchain = swapchain_info.get_swapchain();
equirect_layer->subImage.imageArrayIndex = 0;
equirect_layer->subImage.imageRect.offset.x = 0;
equirect_layer->subImage.imageRect.offset.y = 0;
equirect_layer->subImage.imageRect.extent.width = swapchain_size.width;
equirect_layer->subImage.imageRect.extent.height = swapchain_size.height;
equirect_layer->subImage = subimage;
} break;
default: {
@ -261,27 +393,49 @@ XrCompositionLayerBaseHeader *OpenXRViewportCompositionLayerProvider::get_compos
return composition_layer;
}
void OpenXRViewportCompositionLayerProvider::update_swapchain_sub_image(XrSwapchainSubImage &r_subimage) {
#ifdef ANDROID_ENABLED
if (use_android_surface) {
r_subimage.swapchain = android_surface.swapchain;
} else
#endif
{
XrSwapchain swapchain = subviewport.swapchain_info.get_swapchain();
if (swapchain && subviewport.swapchain_info.is_image_acquired()) {
subviewport.swapchain_info.release();
}
r_subimage.swapchain = swapchain;
}
r_subimage.imageRect.extent.width = swapchain_size.width;
r_subimage.imageRect.extent.height = swapchain_size.height;
}
bool OpenXRViewportCompositionLayerProvider::update_and_acquire_swapchain(bool p_static_image) {
ERR_FAIL_COND_V(use_android_surface, false);
if (openxr_api == nullptr || composition_layer_extension == nullptr) {
// OpenXR not initialized or we're in the editor?
return false;
}
if (!composition_layer_extension->is_available(composition_layer->type)) {
if (!composition_layer_extension->is_available(get_openxr_type())) {
// Selected type is not supported?
return false;
}
// See if our current swapchain is outdated.
if (swapchain_info.get_swapchain() != XR_NULL_HANDLE) {
if (subviewport.swapchain_info.get_swapchain() != XR_NULL_HANDLE) {
// If this swap chain, or the previous one, were static, then we can't reuse it.
if (swapchain_size == viewport_size && !p_static_image && !static_image) {
if (swapchain_size == subviewport.viewport_size && !p_static_image && !subviewport.static_image) {
// We're all good! Just acquire it.
// We can ignore should_render here, return will be false.
bool should_render = true;
return swapchain_info.acquire(should_render);
return subviewport.swapchain_info.acquire(should_render);
}
swapchain_info.queue_free();
subviewport.swapchain_info.queue_free();
}
// Create our new swap chain
@ -292,7 +446,7 @@ bool OpenXRViewportCompositionLayerProvider::update_and_acquire_swapchain(bool p
if (p_static_image) {
create_flags |= XR_SWAPCHAIN_CREATE_STATIC_IMAGE_BIT;
}
if (!swapchain_info.create(create_flags, XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, swapchain_format, viewport_size.width, viewport_size.height, sample_count, array_size)) {
if (!subviewport.swapchain_info.create(create_flags, XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, swapchain_format, subviewport.viewport_size.width, subviewport.viewport_size.height, sample_count, array_size)) {
swapchain_size = Size2i();
return false;
}
@ -300,26 +454,40 @@ bool OpenXRViewportCompositionLayerProvider::update_and_acquire_swapchain(bool p
// Acquire our image so we can start rendering into it,
// we can ignore should_render here, ret will be false.
bool should_render = true;
bool ret = swapchain_info.acquire(should_render);
bool ret = subviewport.swapchain_info.acquire(should_render);
swapchain_size = viewport_size;
static_image = p_static_image;
swapchain_size = subviewport.viewport_size;
subviewport.static_image = p_static_image;
return ret;
}
void OpenXRViewportCompositionLayerProvider::free_swapchain() {
if (swapchain_info.get_swapchain() != XR_NULL_HANDLE) {
swapchain_info.queue_free();
#ifdef ANDROID_ENABLED
if (use_android_surface) {
if (android_surface.swapchain != XR_NULL_HANDLE) {
composition_layer_extension->free_android_surface_swapchain(android_surface.swapchain);
android_surface.swapchain = XR_NULL_HANDLE;
android_surface.surface.unref();
}
} else
#endif
{
if (subviewport.swapchain_info.get_swapchain() != XR_NULL_HANDLE) {
subviewport.swapchain_info.queue_free();
}
subviewport.static_image = false;
}
swapchain_size = Size2i();
static_image = false;
}
RID OpenXRViewportCompositionLayerProvider::get_current_swapchain_texture() {
ERR_FAIL_COND_V(use_android_surface, RID());
if (openxr_api == nullptr) {
return RID();
}
return swapchain_info.get_image();
return subviewport.swapchain_info.get_image();
}

View file

@ -36,6 +36,15 @@
#include "../openxr_api.h"
#ifdef ANDROID_ENABLED
#include <jni.h>
// Copied here from openxr_platform.h, in order to avoid including that whole header,
// which can cause compilation issues on some platforms.
typedef XrResult(XRAPI_PTR *PFN_xrCreateSwapchainAndroidSurfaceKHR)(XrSession session, const XrSwapchainCreateInfo *info, XrSwapchain *swapchain, jobject *surface);
#endif
class JavaObject;
class OpenXRViewportCompositionLayerProvider;
// This extension provides access to composition layers for displaying 2D content through the XR compositor.
@ -49,7 +58,8 @@ public:
virtual ~OpenXRCompositionLayerExtension() override;
virtual HashMap<String, bool *> get_requested_extensions() override;
virtual void on_session_created(const XrSession p_instance) override;
virtual void on_instance_created(const XrInstance p_instance) override;
virtual void on_session_created(const XrSession p_session) override;
virtual void on_session_destroyed() override;
virtual void on_pre_render() override;
@ -61,6 +71,12 @@ public:
void unregister_viewport_composition_layer_provider(OpenXRViewportCompositionLayerProvider *p_composition_layer);
bool is_available(XrStructureType p_which);
bool is_android_surface_swapchain_available() { return android_surface_ext_available; }
#ifdef ANDROID_ENABLED
bool create_android_surface_swapchain(XrSwapchainCreateInfo *p_info, XrSwapchain *r_swapchain, jobject *r_surface);
void free_android_surface_swapchain(XrSwapchain p_swapchain);
#endif
private:
static OpenXRCompositionLayerExtension *singleton;
@ -69,6 +85,15 @@ private:
bool cylinder_ext_available = false;
bool equirect_ext_available = false;
bool android_surface_ext_available = false;
#ifdef ANDROID_ENABLED
Vector<XrSwapchain> android_surface_swapchain_free_queue;
void free_queued_android_surface_swapchains();
EXT_PROTO_XRRESULT_FUNC1(xrDestroySwapchain, (XrSwapchain), swapchain)
EXT_PROTO_XRRESULT_FUNC4(xrCreateSwapchainAndroidSurfaceKHR, (XrSession), session, (const XrSwapchainCreateInfo *), info, (XrSwapchain *), swapchain, (jobject *), surface)
#endif
};
class OpenXRViewportCompositionLayerProvider {
@ -78,20 +103,37 @@ class OpenXRViewportCompositionLayerProvider {
Dictionary extension_property_values;
bool extension_property_values_changed = true;
RID viewport;
Size2i viewport_size;
struct {
RID viewport;
Size2i viewport_size;
OpenXRAPI::OpenXRSwapChainInfo swapchain_info;
bool static_image = false;
} subviewport;
OpenXRAPI::OpenXRSwapChainInfo swapchain_info;
#ifdef ANDROID_ENABLED
struct {
XrSwapchain swapchain = XR_NULL_HANDLE;
Ref<JavaObject> surface;
} android_surface;
#endif
bool use_android_surface = false;
Size2i swapchain_size;
bool static_image = false;
OpenXRAPI *openxr_api = nullptr;
OpenXRCompositionLayerExtension *composition_layer_extension = nullptr;
// Only for SubViewports.
bool update_and_acquire_swapchain(bool p_static_image);
void free_swapchain();
RID get_current_swapchain_texture();
void update_swapchain_sub_image(XrSwapchainSubImage &r_swapchain_sub_image);
void free_swapchain();
#ifdef ANDROID_ENABLED
void create_android_surface();
#endif
public:
XrStructureType get_openxr_type() { return composition_layer->type; }
@ -102,7 +144,12 @@ public:
bool get_alpha_blend() const { return alpha_blend; }
void set_viewport(RID p_viewport, Size2i p_size);
RID get_viewport() const { return viewport; }
RID get_viewport() const { return subviewport.viewport; }
void set_use_android_surface(bool p_enable, Size2i p_size);
bool get_use_android_surface() const { return use_android_surface; }
Ref<JavaObject> get_android_surface();
void set_extension_property_values(const Dictionary &p_property_values);

View file

@ -0,0 +1,287 @@
/**************************************************************************/
/* openxr_debug_utils_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_debug_utils_extension.h"
#include "../openxr_api.h"
#include "core/config/project_settings.h"
#include "core/string/print_string.h"
#include <openxr/openxr.h>
OpenXRDebugUtilsExtension *OpenXRDebugUtilsExtension::singleton = nullptr;
OpenXRDebugUtilsExtension *OpenXRDebugUtilsExtension::get_singleton() {
return singleton;
}
OpenXRDebugUtilsExtension::OpenXRDebugUtilsExtension() {
singleton = this;
}
OpenXRDebugUtilsExtension::~OpenXRDebugUtilsExtension() {
singleton = nullptr;
}
HashMap<String, bool *> OpenXRDebugUtilsExtension::get_requested_extensions() {
HashMap<String, bool *> request_extensions;
request_extensions[XR_EXT_DEBUG_UTILS_EXTENSION_NAME] = &debug_utils_ext;
return request_extensions;
}
void OpenXRDebugUtilsExtension::on_instance_created(const XrInstance p_instance) {
if (debug_utils_ext) {
EXT_INIT_XR_FUNC(xrCreateDebugUtilsMessengerEXT);
EXT_INIT_XR_FUNC(xrDestroyDebugUtilsMessengerEXT);
EXT_INIT_XR_FUNC(xrSetDebugUtilsObjectNameEXT);
EXT_INIT_XR_FUNC(xrSessionBeginDebugUtilsLabelRegionEXT);
EXT_INIT_XR_FUNC(xrSessionEndDebugUtilsLabelRegionEXT);
EXT_INIT_XR_FUNC(xrSessionInsertDebugUtilsLabelEXT);
debug_utils_ext = xrCreateDebugUtilsMessengerEXT_ptr && xrDestroyDebugUtilsMessengerEXT_ptr && xrSetDebugUtilsObjectNameEXT_ptr && xrSessionBeginDebugUtilsLabelRegionEXT_ptr && xrSessionEndDebugUtilsLabelRegionEXT_ptr && xrSessionInsertDebugUtilsLabelEXT_ptr;
} else {
WARN_PRINT("OpenXR: The debug utils extension is not available on this runtime. Debug logging is not enabled!");
}
// On successful init, setup our default messenger.
if (debug_utils_ext) {
int max_severity = GLOBAL_GET("xr/openxr/extensions/debug_utils");
int types = GLOBAL_GET("xr/openxr/extensions/debug_message_types");
XrDebugUtilsMessageSeverityFlagsEXT message_severities = 0;
if (max_severity >= 1) {
message_severities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
}
if (max_severity >= 2) {
message_severities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
}
if (max_severity >= 3) {
message_severities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
}
if (max_severity >= 4) {
message_severities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
}
XrDebugUtilsMessageTypeFlagsEXT message_types = 0;
// These should match up but just to be safe and future proof...
if (types & 1) {
message_types |= XR_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
}
if (types & 2) {
message_types |= XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
}
if (types & 4) {
message_types |= XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
}
if (types & 8) {
message_types |= XR_DEBUG_UTILS_MESSAGE_TYPE_CONFORMANCE_BIT_EXT;
}
XrDebugUtilsMessengerCreateInfoEXT callback_info = {
XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, // type
nullptr, // next
message_severities, // messageSeverities
message_types, // messageTypes
&OpenXRDebugUtilsExtension::_debug_callback, // userCallback
nullptr, // userData
};
XrResult result = xrCreateDebugUtilsMessengerEXT(p_instance, &callback_info, &default_messenger);
if (XR_FAILED(result)) {
ERR_PRINT("OpenXR: Failed to create debug callback [" + OpenXRAPI::get_singleton()->get_error_string(result) + "]");
}
set_object_name(XR_OBJECT_TYPE_INSTANCE, uint64_t(p_instance), "Main Godot OpenXR Instance");
}
}
void OpenXRDebugUtilsExtension::on_instance_destroyed() {
if (default_messenger != XR_NULL_HANDLE) {
XrResult result = xrDestroyDebugUtilsMessengerEXT(default_messenger);
if (XR_FAILED(result)) {
ERR_PRINT("OpenXR: Failed to destroy debug callback [" + OpenXRAPI::get_singleton()->get_error_string(result) + "]");
}
default_messenger = XR_NULL_HANDLE;
}
xrCreateDebugUtilsMessengerEXT_ptr = nullptr;
xrDestroyDebugUtilsMessengerEXT_ptr = nullptr;
xrSetDebugUtilsObjectNameEXT_ptr = nullptr;
xrSessionBeginDebugUtilsLabelRegionEXT_ptr = nullptr;
xrSessionEndDebugUtilsLabelRegionEXT_ptr = nullptr;
xrSessionInsertDebugUtilsLabelEXT_ptr = nullptr;
debug_utils_ext = false;
}
bool OpenXRDebugUtilsExtension::get_active() {
return debug_utils_ext;
}
void OpenXRDebugUtilsExtension::set_object_name(XrObjectType p_object_type, uint64_t p_object_handle, const char *p_object_name) {
ERR_FAIL_COND(!debug_utils_ext);
ERR_FAIL_NULL(xrSetDebugUtilsObjectNameEXT_ptr);
const XrDebugUtilsObjectNameInfoEXT space_name_info = {
XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, // type
nullptr, // next
p_object_type, // objectType
p_object_handle, // objectHandle
p_object_name, // objectName
};
XrResult result = xrSetDebugUtilsObjectNameEXT_ptr(OpenXRAPI::get_singleton()->get_instance(), &space_name_info);
if (XR_FAILED(result)) {
ERR_PRINT("OpenXR: Failed to set object name [" + OpenXRAPI::get_singleton()->get_error_string(result) + "]");
}
}
void OpenXRDebugUtilsExtension::begin_debug_label_region(const char *p_label_name) {
ERR_FAIL_COND(!debug_utils_ext);
ERR_FAIL_NULL(xrSessionBeginDebugUtilsLabelRegionEXT_ptr);
const XrDebugUtilsLabelEXT session_active_region_label = {
XR_TYPE_DEBUG_UTILS_LABEL_EXT, // type
nullptr, // next
p_label_name, // labelName
};
XrResult result = xrSessionBeginDebugUtilsLabelRegionEXT_ptr(OpenXRAPI::get_singleton()->get_session(), &session_active_region_label);
if (XR_FAILED(result)) {
ERR_PRINT("OpenXR: Failed to begin label region [" + OpenXRAPI::get_singleton()->get_error_string(result) + "]");
}
}
void OpenXRDebugUtilsExtension::end_debug_label_region() {
ERR_FAIL_COND(!debug_utils_ext);
ERR_FAIL_NULL(xrSessionEndDebugUtilsLabelRegionEXT_ptr);
XrResult result = xrSessionEndDebugUtilsLabelRegionEXT_ptr(OpenXRAPI::get_singleton()->get_session());
if (XR_FAILED(result)) {
ERR_PRINT("OpenXR: Failed to end label region [" + OpenXRAPI::get_singleton()->get_error_string(result) + "]");
}
}
void OpenXRDebugUtilsExtension::insert_debug_label(const char *p_label_name) {
ERR_FAIL_COND(!debug_utils_ext);
ERR_FAIL_NULL(xrSessionInsertDebugUtilsLabelEXT_ptr);
const XrDebugUtilsLabelEXT session_active_region_label = {
XR_TYPE_DEBUG_UTILS_LABEL_EXT, // type
nullptr, // next
p_label_name, // labelName
};
XrResult result = xrSessionInsertDebugUtilsLabelEXT_ptr(OpenXRAPI::get_singleton()->get_session(), &session_active_region_label);
if (XR_FAILED(result)) {
ERR_PRINT("OpenXR: Failed to insert label [" + OpenXRAPI::get_singleton()->get_error_string(result) + "]");
}
}
XrBool32 XRAPI_PTR OpenXRDebugUtilsExtension::_debug_callback(XrDebugUtilsMessageSeverityFlagsEXT p_message_severity, XrDebugUtilsMessageTypeFlagsEXT p_message_types, const XrDebugUtilsMessengerCallbackDataEXT *p_callback_data, void *p_user_data) {
OpenXRDebugUtilsExtension *debug_utils = OpenXRDebugUtilsExtension::get_singleton();
if (debug_utils) {
return debug_utils->debug_callback(p_message_severity, p_message_types, p_callback_data, p_user_data);
}
return XR_FALSE;
}
XrBool32 OpenXRDebugUtilsExtension::debug_callback(XrDebugUtilsMessageSeverityFlagsEXT p_message_severity, XrDebugUtilsMessageTypeFlagsEXT p_message_types, const XrDebugUtilsMessengerCallbackDataEXT *p_callback_data, void *p_user_data) {
String msg;
ERR_FAIL_NULL_V(p_callback_data, XR_FALSE);
if (p_message_types == XR_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) {
msg = ", type: General";
} else if (p_message_types == XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) {
msg = ", type: Validation";
} else if (p_message_types == XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) {
msg = ", type: Performance";
} else if (p_message_types == XR_DEBUG_UTILS_MESSAGE_TYPE_CONFORMANCE_BIT_EXT) {
msg = ", type: Conformance";
} else {
msg = ", type: Unknown (" + String::num_uint64(p_message_types) + ")";
}
if (p_callback_data->functionName) {
msg += ", function Name: " + String(p_callback_data->functionName);
}
if (p_callback_data->messageId) {
msg += "\nMessage ID: " + String(p_callback_data->messageId);
}
if (p_callback_data->message) {
msg += "\nMessage: " + String(p_callback_data->message);
}
if (p_callback_data->objectCount > 0) {
String objects;
for (uint32_t i = 0; i < p_callback_data->objectCount; i++) {
if (!objects.is_empty()) {
objects += ", ";
}
objects += p_callback_data->objects[i].objectName;
}
msg += "\nObjects: " + objects;
}
if (p_callback_data->sessionLabelCount > 0) {
String labels;
for (uint32_t i = 0; i < p_callback_data->sessionLabelCount; i++) {
if (!labels.is_empty()) {
labels += ", ";
}
labels += p_callback_data->sessionLabels[i].labelName;
}
msg += "\nLabels: " + labels;
}
if (p_message_severity == XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
ERR_PRINT("OpenXR: Severity: Error" + msg);
} else if (p_message_severity == XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
WARN_PRINT("OpenXR: Severity: Warning" + msg);
} else if (p_message_severity == XR_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) {
print_line("OpenXR: Severity: Info" + msg);
} else if (p_message_severity == XR_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) {
// This is a bit double because we won't output this unless verbose messaging in Godot is on.
print_verbose("OpenXR: Severity: Verbose" + msg);
}
return XR_FALSE;
}

View file

@ -0,0 +1,76 @@
/**************************************************************************/
/* openxr_debug_utils_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_DEBUG_UTILS_EXTENSION_H
#define OPENXR_DEBUG_UTILS_EXTENSION_H
#include "../util.h"
#include "openxr_extension_wrapper.h"
class OpenXRDebugUtilsExtension : public OpenXRExtensionWrapper {
public:
static OpenXRDebugUtilsExtension *get_singleton();
OpenXRDebugUtilsExtension();
virtual ~OpenXRDebugUtilsExtension() override;
virtual HashMap<String, bool *> get_requested_extensions() override;
virtual void on_instance_created(const XrInstance p_instance) override;
virtual void on_instance_destroyed() override;
bool get_active();
void set_object_name(XrObjectType p_object_type, uint64_t p_object_handle, const char *p_object_name);
void begin_debug_label_region(const char *p_label_name);
void end_debug_label_region();
void insert_debug_label(const char *p_label_name);
private:
static OpenXRDebugUtilsExtension *singleton;
// related extensions
bool debug_utils_ext = false;
// debug handlers
XrDebugUtilsMessengerEXT default_messenger = XR_NULL_HANDLE;
static XrBool32 XRAPI_PTR _debug_callback(XrDebugUtilsMessageSeverityFlagsEXT p_message_severity, XrDebugUtilsMessageTypeFlagsEXT p_message_types, const XrDebugUtilsMessengerCallbackDataEXT *p_callback_data, void *p_user_data);
XrBool32 debug_callback(XrDebugUtilsMessageSeverityFlagsEXT p_message_severity, XrDebugUtilsMessageTypeFlagsEXT p_message_types, const XrDebugUtilsMessengerCallbackDataEXT *p_callback_data, void *p_user_data);
// OpenXR API call wrappers
EXT_PROTO_XRRESULT_FUNC3(xrCreateDebugUtilsMessengerEXT, (XrInstance), p_instance, (const XrDebugUtilsMessengerCreateInfoEXT *), p_create_info, (XrDebugUtilsMessengerEXT *), p_messenger)
EXT_PROTO_XRRESULT_FUNC1(xrDestroyDebugUtilsMessengerEXT, (XrDebugUtilsMessengerEXT), p_messenger)
EXT_PROTO_XRRESULT_FUNC2(xrSetDebugUtilsObjectNameEXT, (XrInstance), p_instance, (const XrDebugUtilsObjectNameInfoEXT *), p_name_info)
EXT_PROTO_XRRESULT_FUNC2(xrSessionBeginDebugUtilsLabelRegionEXT, (XrSession), p_session, (const XrDebugUtilsLabelEXT *), p_label_info)
EXT_PROTO_XRRESULT_FUNC1(xrSessionEndDebugUtilsLabelRegionEXT, (XrSession), p_session)
EXT_PROTO_XRRESULT_FUNC2(xrSessionInsertDebugUtilsLabelEXT, (XrSession), p_session, (const XrDebugUtilsLabelEXT *), p_label_info)
};
#endif // OPENXR_DEBUG_UTILS_EXTENSION_H

View file

@ -0,0 +1,273 @@
/**************************************************************************/
/* 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 "../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<String, bool *> OpenXRDPadBindingExtension::get_requested_extensions() {
HashMap<String, bool *> request_extensions;
// Note, we're dependent on the binding modifier extension, this may be requested by multiple extension wrappers.
request_extensions[XR_KHR_BINDING_MODIFICATION_EXTENSION_NAME] = &binding_modifier_ext;
request_extensions[XR_EXT_DPAD_BINDING_EXTENSION_NAME] = &dpad_binding_ext;
return request_extensions;
}
bool OpenXRDPadBindingExtension::is_available() {
return binding_modifier_ext && dpad_binding_ext;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// OpenXRDpadBindingModifier
void OpenXRDpadBindingModifier::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_action_set", "action_set"), &OpenXRDpadBindingModifier::set_action_set);
ClassDB::bind_method(D_METHOD("get_action_set"), &OpenXRDpadBindingModifier::get_action_set);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "action_set", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRActionSet"), "set_action_set", "get_action_set");
ClassDB::bind_method(D_METHOD("set_input_path", "input_path"), &OpenXRDpadBindingModifier::set_input_path);
ClassDB::bind_method(D_METHOD("get_input_path"), &OpenXRDpadBindingModifier::get_input_path);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "input_path", PROPERTY_HINT_TYPE_STRING, "binding_path"), "set_input_path", "get_input_path");
ClassDB::bind_method(D_METHOD("set_threshold", "threshold"), &OpenXRDpadBindingModifier::set_threshold);
ClassDB::bind_method(D_METHOD("get_threshold"), &OpenXRDpadBindingModifier::get_threshold);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "threshold", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_threshold", "get_threshold");
ClassDB::bind_method(D_METHOD("set_threshold_released", "threshold_released"), &OpenXRDpadBindingModifier::set_threshold_released);
ClassDB::bind_method(D_METHOD("get_threshold_released"), &OpenXRDpadBindingModifier::get_threshold_released);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "threshold_released", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_threshold_released", "get_threshold_released");
ClassDB::bind_method(D_METHOD("set_center_region", "center_region"), &OpenXRDpadBindingModifier::set_center_region);
ClassDB::bind_method(D_METHOD("get_center_region"), &OpenXRDpadBindingModifier::get_center_region);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "center_region", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_center_region", "get_center_region");
ClassDB::bind_method(D_METHOD("set_wedge_angle", "wedge_angle"), &OpenXRDpadBindingModifier::set_wedge_angle);
ClassDB::bind_method(D_METHOD("get_wedge_angle"), &OpenXRDpadBindingModifier::get_wedge_angle);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wedge_angle", PROPERTY_HINT_RANGE, "1.0,180.0,0.1,radians_as_degrees"), "set_wedge_angle", "get_wedge_angle");
ClassDB::bind_method(D_METHOD("set_is_sticky", "is_sticky"), &OpenXRDpadBindingModifier::set_is_sticky);
ClassDB::bind_method(D_METHOD("get_is_sticky"), &OpenXRDpadBindingModifier::get_is_sticky);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "is_sticky"), "set_is_sticky", "get_is_sticky");
ClassDB::bind_method(D_METHOD("set_on_haptic", "haptic"), &OpenXRDpadBindingModifier::set_on_haptic);
ClassDB::bind_method(D_METHOD("get_on_haptic"), &OpenXRDpadBindingModifier::get_on_haptic);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "on_haptic", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRHapticBase"), "set_on_haptic", "get_on_haptic");
ClassDB::bind_method(D_METHOD("set_off_haptic", "haptic"), &OpenXRDpadBindingModifier::set_off_haptic);
ClassDB::bind_method(D_METHOD("get_off_haptic"), &OpenXRDpadBindingModifier::get_off_haptic);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "off_haptic", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRHapticBase"), "set_off_haptic", "get_off_haptic");
}
OpenXRDpadBindingModifier::OpenXRDpadBindingModifier() {
ERR_FAIL_COND(dpad_bindings_data.resize_zeroed(sizeof(XrInteractionProfileDpadBindingEXT)) != OK);
dpad_bindings = (XrInteractionProfileDpadBindingEXT *)dpad_bindings_data.ptrw();
dpad_bindings->type = XR_TYPE_INTERACTION_PROFILE_DPAD_BINDING_EXT;
dpad_bindings->next = nullptr;
dpad_bindings->forceThreshold = 0.6;
dpad_bindings->forceThresholdReleased = 0.4;
dpad_bindings->centerRegion = 0.1;
dpad_bindings->wedgeAngle = Math::deg_to_rad(90.0);
dpad_bindings->isSticky = false;
}
void OpenXRDpadBindingModifier::set_action_set(const Ref<OpenXRActionSet> p_action_set) {
action_set = p_action_set;
}
Ref<OpenXRActionSet> OpenXRDpadBindingModifier::get_action_set() const {
return action_set;
}
void OpenXRDpadBindingModifier::set_input_path(const String &p_input_path) {
input_path = p_input_path;
emit_changed();
}
String OpenXRDpadBindingModifier::get_input_path() const {
return input_path;
}
void OpenXRDpadBindingModifier::set_threshold(float p_threshold) {
ERR_FAIL_NULL(dpad_bindings);
ERR_FAIL_COND(p_threshold < 0.0 || p_threshold > 1.0);
dpad_bindings->forceThreshold = p_threshold;
emit_changed();
}
float OpenXRDpadBindingModifier::get_threshold() const {
ERR_FAIL_NULL_V(dpad_bindings, 0.0);
return dpad_bindings->forceThreshold;
}
void OpenXRDpadBindingModifier::set_threshold_released(float p_threshold) {
ERR_FAIL_NULL(dpad_bindings);
ERR_FAIL_COND(p_threshold < 0.0 || p_threshold > 1.0);
dpad_bindings->forceThresholdReleased = p_threshold;
emit_changed();
}
float OpenXRDpadBindingModifier::get_threshold_released() const {
ERR_FAIL_NULL_V(dpad_bindings, 0.0);
return dpad_bindings->forceThresholdReleased;
}
void OpenXRDpadBindingModifier::set_center_region(float p_center_region) {
ERR_FAIL_NULL(dpad_bindings);
ERR_FAIL_COND(p_center_region < 0.0 || p_center_region > 1.0);
dpad_bindings->centerRegion = p_center_region;
emit_changed();
}
float OpenXRDpadBindingModifier::get_center_region() const {
ERR_FAIL_NULL_V(dpad_bindings, 0.0);
return dpad_bindings->centerRegion;
}
void OpenXRDpadBindingModifier::set_wedge_angle(float p_wedge_angle) {
ERR_FAIL_NULL(dpad_bindings);
dpad_bindings->wedgeAngle = p_wedge_angle;
emit_changed();
}
float OpenXRDpadBindingModifier::get_wedge_angle() const {
ERR_FAIL_NULL_V(dpad_bindings, 0.0);
return dpad_bindings->wedgeAngle;
}
void OpenXRDpadBindingModifier::set_wedge_angle_deg(float p_wedge_angle) {
ERR_FAIL_NULL(dpad_bindings);
dpad_bindings->wedgeAngle = Math::deg_to_rad(p_wedge_angle);
emit_changed();
}
float OpenXRDpadBindingModifier::get_wedge_angle_deg() const {
ERR_FAIL_NULL_V(dpad_bindings, 0.0);
return Math::rad_to_deg(dpad_bindings->wedgeAngle);
}
void OpenXRDpadBindingModifier::set_is_sticky(bool p_sticky) {
ERR_FAIL_NULL(dpad_bindings);
dpad_bindings->isSticky = p_sticky;
emit_changed();
}
bool OpenXRDpadBindingModifier::get_is_sticky() const {
ERR_FAIL_NULL_V(dpad_bindings, false);
return dpad_bindings->isSticky;
}
void OpenXRDpadBindingModifier::set_on_haptic(const Ref<OpenXRHapticBase> &p_haptic) {
on_haptic = p_haptic;
emit_changed();
}
Ref<OpenXRHapticBase> OpenXRDpadBindingModifier::get_on_haptic() const {
return on_haptic;
}
void OpenXRDpadBindingModifier::set_off_haptic(const Ref<OpenXRHapticBase> &p_haptic) {
off_haptic = p_haptic;
emit_changed();
}
Ref<OpenXRHapticBase> 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_null(), 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;
}

View file

@ -0,0 +1,109 @@
/**************************************************************************/
/* openxr_dpad_binding_extension.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef OPENXR_DPAD_BINDING_EXTENSION_H
#define OPENXR_DPAD_BINDING_EXTENSION_H
#include "../action_map/openxr_action_set.h"
#include "../action_map/openxr_binding_modifier.h"
#include "../action_map/openxr_haptic_feedback.h"
#include "../util.h"
#include "openxr_extension_wrapper.h"
class OpenXRDPadBindingExtension : public OpenXRExtensionWrapper {
public:
static OpenXRDPadBindingExtension *get_singleton();
OpenXRDPadBindingExtension();
virtual ~OpenXRDPadBindingExtension() override;
virtual HashMap<String, bool *> get_requested_extensions() override;
bool is_available();
private:
static OpenXRDPadBindingExtension *singleton;
bool binding_modifier_ext = false;
bool dpad_binding_ext = false;
};
class OpenXRDpadBindingModifier : public OpenXRIPBindingModifier {
GDCLASS(OpenXRDpadBindingModifier, OpenXRIPBindingModifier);
private:
PackedByteArray dpad_bindings_data;
XrInteractionProfileDpadBindingEXT *dpad_bindings = nullptr;
String input_path;
Ref<OpenXRActionSet> action_set;
Ref<OpenXRHapticBase> on_haptic;
Ref<OpenXRHapticBase> off_haptic;
protected:
static void _bind_methods();
public:
OpenXRDpadBindingModifier();
void set_action_set(const Ref<OpenXRActionSet> p_action_set);
Ref<OpenXRActionSet> 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<OpenXRHapticBase> &p_haptic);
Ref<OpenXRHapticBase> get_on_haptic() const;
void set_off_haptic(const Ref<OpenXRHapticBase> &p_haptic);
Ref<OpenXRHapticBase> get_off_haptic() const;
virtual String get_description() const override { return "DPad modifier"; }
virtual PackedByteArray get_ip_modification() override;
};
#endif // OPENXR_DPAD_BINDING_EXTENSION_H

View file

@ -57,11 +57,12 @@ public:
// You should return the pointer to the last struct you define as your result.
// If you are not adding any structs, just return `p_next_pointer`.
// See existing extensions for examples of this implementation.
virtual void *set_system_properties_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } // Add additional data structures when we interogate OpenXRS system abilities.
virtual void *set_system_properties_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } // Add additional data structures when we interrogate OpenXRS system abilities.
virtual void *set_instance_create_info_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } // Add additional data structures when we create our OpenXR instance.
virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } // Add additional data structures when we create our OpenXR session.
virtual void *set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } // Add additional data structures when creating OpenXR swap chains.
virtual void *set_hand_joint_locations_and_get_next_pointer(int p_hand_index, void *p_next_pointer) { return p_next_pointer; }
virtual void *set_projection_views_and_get_next_pointer(int p_view_index, void *p_next_pointer) { return p_next_pointer; }
virtual PackedStringArray get_suggested_tracker_names() { return PackedStringArray(); }
@ -76,7 +77,7 @@ public:
virtual void on_before_instance_created() {} // `on_before_instance_created` is called before we create our OpenXR instance.
virtual void on_instance_created(const XrInstance p_instance) {} // `on_instance_created` is called right after we've successfully created our OpenXR instance.
virtual void on_instance_destroyed() {} // `on_instance_destroyed` is called right before we destroy our OpenXR instance.
virtual void on_session_created(const XrSession p_instance) {} // `on_session_created` is called right after we've successfully created our OpenXR session.
virtual void on_session_created(const XrSession p_session) {} // `on_session_created` is called right after we've successfully created our OpenXR session.
virtual void on_session_destroyed() {} // `on_session_destroyed` is called right before we destroy our OpenXR session.
// `on_process` is called as part of our OpenXR process handling,
@ -97,10 +98,11 @@ public:
virtual void on_state_loss_pending() {} // `on_state_loss_pending` is called when the OpenXR session state is changed to loss pending.
virtual void on_state_exiting() {} // `on_state_exiting` is called when the OpenXR session state is changed to exiting.
virtual void *set_viewport_composition_layer_and_get_next_pointer(const XrCompositionLayerBaseHeader *p_layer, Dictionary p_property_values, void *p_next_pointer) { return p_next_pointer; } // Add additional data structures to composition layers created via OpenXRCompositionLayer.
virtual void *set_viewport_composition_layer_and_get_next_pointer(const XrCompositionLayerBaseHeader *p_layer, const Dictionary &p_property_values, void *p_next_pointer) { return p_next_pointer; } // Add additional data structures to composition layers created via OpenXRCompositionLayer.
virtual void on_viewport_composition_layer_destroyed(const XrCompositionLayerBaseHeader *p_layer) {} // `on_viewport_composition_layer_destroyed` is called when a composition layer created via OpenXRCompositionLayer is destroyed.
virtual void get_viewport_composition_layer_extension_properties(List<PropertyInfo> *p_property_list) {} // Get additional property definitions for OpenXRCompositionLayer.
virtual Dictionary get_viewport_composition_layer_extension_property_defaults() { return Dictionary(); } // Get the default values for the additional property definitions for OpenXRCompositionLayer.
virtual void *set_android_surface_swapchain_create_info_and_get_next_pointer(const Dictionary &p_property_values, void *p_next_pointer) { return p_next_pointer; }
// `on_event_polled` is called when there is an OpenXR event to process.
// Should return true if the event was handled, false otherwise.

View file

@ -39,6 +39,7 @@ void OpenXRExtensionWrapperExtension::_bind_methods() {
GDVIRTUAL_BIND(_set_session_create_and_get_next_pointer, "next_pointer");
GDVIRTUAL_BIND(_set_swapchain_create_info_and_get_next_pointer, "next_pointer");
GDVIRTUAL_BIND(_set_hand_joint_locations_and_get_next_pointer, "hand_index", "next_pointer");
GDVIRTUAL_BIND(_set_projection_views_and_get_next_pointer, "view_index", "next_pointer");
GDVIRTUAL_BIND(_get_composition_layer_count);
GDVIRTUAL_BIND(_get_composition_layer, "index");
GDVIRTUAL_BIND(_get_composition_layer_order, "index");
@ -51,6 +52,8 @@ void OpenXRExtensionWrapperExtension::_bind_methods() {
GDVIRTUAL_BIND(_on_process);
GDVIRTUAL_BIND(_on_pre_render);
GDVIRTUAL_BIND(_on_main_swapchains_created);
GDVIRTUAL_BIND(_on_pre_draw_viewport, "viewport");
GDVIRTUAL_BIND(_on_post_draw_viewport, "viewport");
GDVIRTUAL_BIND(_on_session_destroyed);
GDVIRTUAL_BIND(_on_state_idle);
GDVIRTUAL_BIND(_on_state_ready);
@ -65,6 +68,7 @@ void OpenXRExtensionWrapperExtension::_bind_methods() {
GDVIRTUAL_BIND(_get_viewport_composition_layer_extension_properties);
GDVIRTUAL_BIND(_get_viewport_composition_layer_extension_property_defaults);
GDVIRTUAL_BIND(_on_viewport_composition_layer_destroyed, "layer");
GDVIRTUAL_BIND(_set_android_surface_swapchain_create_info_and_get_next_pointer, "property_values", "next_pointer");
ClassDB::bind_method(D_METHOD("get_openxr_api"), &OpenXRExtensionWrapperExtension::get_openxr_api);
ClassDB::bind_method(D_METHOD("register_extension_wrapper"), &OpenXRExtensionWrapperExtension::register_extension_wrapper);
@ -137,6 +141,16 @@ void *OpenXRExtensionWrapperExtension::set_hand_joint_locations_and_get_next_poi
return nullptr;
}
void *OpenXRExtensionWrapperExtension::set_projection_views_and_get_next_pointer(int p_view_index, void *p_next_pointer) {
uint64_t pointer = 0;
if (GDVIRTUAL_CALL(_set_projection_views_and_get_next_pointer, p_view_index, GDExtensionPtr<void>(p_next_pointer), pointer)) {
return reinterpret_cast<void *>(pointer);
}
return nullptr;
}
PackedStringArray OpenXRExtensionWrapperExtension::get_suggested_tracker_names() {
PackedStringArray ret;
@ -207,6 +221,14 @@ void OpenXRExtensionWrapperExtension::on_session_destroyed() {
GDVIRTUAL_CALL(_on_session_destroyed);
}
void OpenXRExtensionWrapperExtension::on_pre_draw_viewport(RID p_render_target) {
GDVIRTUAL_CALL(_on_pre_draw_viewport, p_render_target);
}
void OpenXRExtensionWrapperExtension::on_post_draw_viewport(RID p_render_target) {
GDVIRTUAL_CALL(_on_post_draw_viewport, p_render_target);
}
void OpenXRExtensionWrapperExtension::on_state_idle() {
GDVIRTUAL_CALL(_on_state_idle);
}
@ -249,7 +271,7 @@ bool OpenXRExtensionWrapperExtension::on_event_polled(const XrEventDataBuffer &p
return false;
}
void *OpenXRExtensionWrapperExtension::set_viewport_composition_layer_and_get_next_pointer(const XrCompositionLayerBaseHeader *p_layer, Dictionary p_property_values, void *p_next_pointer) {
void *OpenXRExtensionWrapperExtension::set_viewport_composition_layer_and_get_next_pointer(const XrCompositionLayerBaseHeader *p_layer, const Dictionary &p_property_values, void *p_next_pointer) {
uint64_t pointer = 0;
if (GDVIRTUAL_CALL(_set_viewport_composition_layer_and_get_next_pointer, GDExtensionConstPtr<void>(p_layer), p_property_values, GDExtensionPtr<void>(p_next_pointer), pointer)) {
@ -279,6 +301,16 @@ Dictionary OpenXRExtensionWrapperExtension::get_viewport_composition_layer_exten
return property_defaults;
}
void *OpenXRExtensionWrapperExtension::set_android_surface_swapchain_create_info_and_get_next_pointer(const Dictionary &p_property_values, void *p_next_pointer) {
uint64_t pointer = 0;
if (GDVIRTUAL_CALL(_set_android_surface_swapchain_create_info_and_get_next_pointer, p_property_values, GDExtensionPtr<void>(p_next_pointer), pointer)) {
return reinterpret_cast<void *>(pointer);
}
return p_next_pointer;
}
Ref<OpenXRAPIExtension> OpenXRExtensionWrapperExtension::get_openxr_api() {
return openxr_api;
}
@ -287,8 +319,7 @@ void OpenXRExtensionWrapperExtension::register_extension_wrapper() {
OpenXRAPI::register_extension_wrapper(this);
}
OpenXRExtensionWrapperExtension::OpenXRExtensionWrapperExtension() :
Object(), OpenXRExtensionWrapper() {
OpenXRExtensionWrapperExtension::OpenXRExtensionWrapperExtension() {
openxr_api.instantiate();
}

View file

@ -35,7 +35,6 @@
#include "openxr_extension_wrapper.h"
#include "core/object/ref_counted.h"
#include "core/os/os.h"
#include "core/os/thread_safe.h"
#include "core/variant/native_ptr.h"
#include "core/variant/typed_array.h"
@ -60,6 +59,7 @@ public:
virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) override;
virtual void *set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) override;
virtual void *set_hand_joint_locations_and_get_next_pointer(int p_hand_index, void *p_next_pointer) override;
virtual void *set_projection_views_and_get_next_pointer(int p_view_index, void *p_next_pointer) override;
virtual int get_composition_layer_count() override;
virtual XrCompositionLayerBaseHeader *get_composition_layer(int p_index) override;
@ -71,6 +71,7 @@ public:
GDVIRTUAL1R(uint64_t, _set_session_create_and_get_next_pointer, GDExtensionPtr<void>);
GDVIRTUAL1R(uint64_t, _set_swapchain_create_info_and_get_next_pointer, GDExtensionPtr<void>);
GDVIRTUAL2R(uint64_t, _set_hand_joint_locations_and_get_next_pointer, int, GDExtensionPtr<void>);
GDVIRTUAL2R(uint64_t, _set_projection_views_and_get_next_pointer, int, GDExtensionPtr<void>);
GDVIRTUAL0R(int, _get_composition_layer_count);
GDVIRTUAL1R(uint64_t, _get_composition_layer, int);
GDVIRTUAL1R(int, _get_composition_layer_order, int);
@ -88,6 +89,8 @@ public:
virtual void on_pre_render() override;
virtual void on_main_swapchains_created() override;
virtual void on_session_destroyed() override;
virtual void on_pre_draw_viewport(RID p_render_target) override;
virtual void on_post_draw_viewport(RID p_render_target) override;
GDVIRTUAL0(_on_register_metadata);
GDVIRTUAL0(_on_before_instance_created);
@ -98,6 +101,8 @@ public:
GDVIRTUAL0(_on_pre_render);
GDVIRTUAL0(_on_main_swapchains_created);
GDVIRTUAL0(_on_session_destroyed);
GDVIRTUAL1(_on_pre_draw_viewport, RID);
GDVIRTUAL1(_on_post_draw_viewport, RID);
virtual void on_state_idle() override;
virtual void on_state_ready() override;
@ -121,15 +126,17 @@ public:
GDVIRTUAL1R(bool, _on_event_polled, GDExtensionConstPtr<void>);
virtual void *set_viewport_composition_layer_and_get_next_pointer(const XrCompositionLayerBaseHeader *p_layer, Dictionary p_property_values, void *p_next_pointer) override;
virtual void *set_viewport_composition_layer_and_get_next_pointer(const XrCompositionLayerBaseHeader *p_layer, const Dictionary &p_property_values, void *p_next_pointer) override;
virtual void on_viewport_composition_layer_destroyed(const XrCompositionLayerBaseHeader *p_layer) override;
virtual void get_viewport_composition_layer_extension_properties(List<PropertyInfo> *p_property_list) override;
virtual Dictionary get_viewport_composition_layer_extension_property_defaults() override;
virtual void *set_android_surface_swapchain_create_info_and_get_next_pointer(const Dictionary &p_property_values, void *p_next_pointer) override;
GDVIRTUAL3R(uint64_t, _set_viewport_composition_layer_and_get_next_pointer, GDExtensionConstPtr<void>, Dictionary, GDExtensionPtr<void>);
GDVIRTUAL1(_on_viewport_composition_layer_destroyed, GDExtensionConstPtr<void>);
GDVIRTUAL0R(TypedArray<Dictionary>, _get_viewport_composition_layer_extension_properties);
GDVIRTUAL0R(Dictionary, _get_viewport_composition_layer_extension_property_defaults);
GDVIRTUAL2R(uint64_t, _set_android_surface_swapchain_create_info_and_get_next_pointer, Dictionary, GDExtensionPtr<void>);
Ref<OpenXRAPIExtension> get_openxr_api();

View file

@ -58,9 +58,14 @@ OpenXRHandTrackingExtension::~OpenXRHandTrackingExtension() {
HashMap<String, bool *> OpenXRHandTrackingExtension::get_requested_extensions() {
HashMap<String, bool *> request_extensions;
unobstructed_data_source = GLOBAL_GET("xr/openxr/extensions/hand_tracking_unobstructed_data_source");
controller_data_source = GLOBAL_GET("xr/openxr/extensions/hand_tracking_controller_data_source");
request_extensions[XR_EXT_HAND_TRACKING_EXTENSION_NAME] = &hand_tracking_ext;
request_extensions[XR_EXT_HAND_JOINTS_MOTION_RANGE_EXTENSION_NAME] = &hand_motion_range_ext;
request_extensions[XR_EXT_HAND_TRACKING_DATA_SOURCE_EXTENSION_NAME] = &hand_tracking_source_ext;
if (unobstructed_data_source || controller_data_source) {
request_extensions[XR_EXT_HAND_TRACKING_DATA_SOURCE_EXTENSION_NAME] = &hand_tracking_source_ext;
}
return request_extensions;
}
@ -141,10 +146,18 @@ void OpenXRHandTrackingExtension::on_process() {
void *next_pointer = nullptr;
// Originally not all XR runtimes supported hand tracking data sourced both from controllers and normal hand tracking.
// With this extension we can indicate we accept input from both sources so hand tracking data is consistently provided
// on runtimes that support this.
XrHandTrackingDataSourceEXT data_sources[2] = { XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT, XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT };
XrHandTrackingDataSourceInfoEXT data_source_info = { XR_TYPE_HAND_TRACKING_DATA_SOURCE_INFO_EXT, next_pointer, 2, data_sources };
// With this extension we can indicate we wish to accept input from either or both sources.
// This functionality is subject to the abilities of the XR runtime and requires the data source extension.
// Note: If the data source extension is not available, no guarantees can be made on what the XR runtime supports.
uint32_t data_source_count = 0;
XrHandTrackingDataSourceEXT data_sources[2];
if (unobstructed_data_source) {
data_sources[data_source_count++] = XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT;
}
if (controller_data_source) {
data_sources[data_source_count++] = XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT;
}
XrHandTrackingDataSourceInfoEXT data_source_info = { XR_TYPE_HAND_TRACKING_DATA_SOURCE_INFO_EXT, next_pointer, data_source_count, data_sources };
if (hand_tracking_source_ext) {
// If supported include this info
next_pointer = &data_source_info;
@ -224,7 +237,9 @@ void OpenXRHandTrackingExtension::on_process() {
if (XR_FAILED(result)) {
// not successful? then we do nothing.
print_line("OpenXR: Failed to get tracking for hand", i, "[", OpenXRAPI::get_singleton()->get_error_string(result), "]");
godot_tracker->set_hand_tracking_source(XRHandTracker::HAND_TRACKING_SOURCE_UNKNOWN);
godot_tracker->set_has_tracking_data(false);
godot_tracker->invalidate_pose("default");
continue;
}
@ -235,8 +250,6 @@ void OpenXRHandTrackingExtension::on_process() {
}
if (hand_trackers[i].locations.isActive) {
godot_tracker->set_has_tracking_data(true);
// SKELETON_RIG_HUMANOID bone adjustment. This rotation performs:
// OpenXR Z+ -> Godot Humanoid Y- (Back along the bone)
// OpenXR Y+ -> Godot Humanoid Z- (Out the back of the hand)
@ -245,7 +258,6 @@ void OpenXRHandTrackingExtension::on_process() {
for (int joint = 0; joint < XR_HAND_JOINT_COUNT_EXT; joint++) {
const XrHandJointLocationEXT &location = hand_trackers[i].joint_locations[joint];
const XrHandJointVelocityEXT &velocity = hand_trackers[i].joint_velocities[joint];
const XrHandTrackingDataSourceStateEXT &data_source = hand_trackers[i].data_source;
const XrPosef &pose = location.pose;
Transform3D transform;
@ -285,23 +297,35 @@ void OpenXRHandTrackingExtension::on_process() {
godot_tracker->set_hand_joint_radius((XRHandTracker::HandJoint)joint, location.radius);
if (joint == XR_HAND_JOINT_PALM_EXT) {
XRHandTracker::HandTrackingSource source = XRHandTracker::HAND_TRACKING_SOURCE_UNKNOWN;
if (data_source.dataSource == XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT) {
source = XRHandTracker::HAND_TRACKING_SOURCE_UNOBSTRUCTED;
} else if (data_source.dataSource == XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT) {
source = XRHandTracker::HAND_TRACKING_SOURCE_CONTROLLER;
}
if (location.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) {
XrHandTrackingDataSourceStateEXT &data_source = hand_trackers[i].data_source;
godot_tracker->set_hand_tracking_source(source);
if (location.locationFlags & XR_SPACE_LOCATION_POSITION_TRACKED_BIT) {
XRHandTracker::HandTrackingSource source = XRHandTracker::HAND_TRACKING_SOURCE_UNKNOWN;
if (hand_tracking_source_ext) {
if (!data_source.isActive) {
source = XRHandTracker::HAND_TRACKING_SOURCE_NOT_TRACKED;
} else if (data_source.dataSource == XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT) {
source = XRHandTracker::HAND_TRACKING_SOURCE_UNOBSTRUCTED;
} else if (data_source.dataSource == XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT) {
source = XRHandTracker::HAND_TRACKING_SOURCE_CONTROLLER;
} else {
// Data source shouldn't be active, if new data sources are added to OpenXR we need to enable them.
WARN_PRINT_ONCE("Unknown active data source found!");
source = XRHandTracker::HAND_TRACKING_SOURCE_UNKNOWN;
}
}
godot_tracker->set_hand_tracking_source(source);
godot_tracker->set_has_tracking_data(true);
godot_tracker->set_pose("default", transform, linear_velocity, angular_velocity);
} else {
godot_tracker->set_hand_tracking_source(hand_tracking_source_ext ? XRHandTracker::HAND_TRACKING_SOURCE_NOT_TRACKED : XRHandTracker::HAND_TRACKING_SOURCE_UNKNOWN);
godot_tracker->set_has_tracking_data(false);
godot_tracker->invalidate_pose("default");
}
}
}
} else {
godot_tracker->set_hand_tracking_source(hand_tracking_source_ext ? XRHandTracker::HAND_TRACKING_SOURCE_NOT_TRACKED : XRHandTracker::HAND_TRACKING_SOURCE_UNKNOWN);
godot_tracker->set_has_tracking_data(false);
godot_tracker->invalidate_pose("default");
}
@ -349,16 +373,17 @@ XrHandJointsMotionRangeEXT OpenXRHandTrackingExtension::get_motion_range(HandTra
OpenXRHandTrackingExtension::HandTrackedSource OpenXRHandTrackingExtension::get_hand_tracking_source(HandTrackedHands p_hand) const {
ERR_FAIL_UNSIGNED_INDEX_V(p_hand, OPENXR_MAX_TRACKED_HANDS, OPENXR_SOURCE_UNKNOWN);
if (hand_tracking_source_ext && hand_trackers[p_hand].data_source.isActive) {
switch (hand_trackers[p_hand].data_source.dataSource) {
case XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT:
return OPENXR_SOURCE_UNOBSTRUCTED;
case XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT:
return OPENXR_SOURCE_CONTROLLER;
default:
return OPENXR_SOURCE_UNKNOWN;
if (hand_tracking_source_ext) {
if (!hand_trackers[p_hand].data_source.isActive) {
return OPENXR_SOURCE_NOT_TRACKED;
} else if (hand_trackers[p_hand].data_source.dataSource == XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT) {
return OPENXR_SOURCE_UNOBSTRUCTED;
} else if (hand_trackers[p_hand].data_source.dataSource == XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT) {
return OPENXR_SOURCE_CONTROLLER;
} else {
// Data source shouldn't be active, if new data sources are added to OpenXR we need to enable them.
WARN_PRINT_ONCE("Unknown active data source found!");
return OPENXR_SOURCE_UNKNOWN;
}
}

View file

@ -48,6 +48,7 @@ public:
OPENXR_SOURCE_UNKNOWN,
OPENXR_SOURCE_UNOBSTRUCTED,
OPENXR_SOURCE_CONTROLLER,
OPENXR_SOURCE_NOT_TRACKED,
OPENXR_SOURCE_MAX
};
@ -110,6 +111,8 @@ private:
bool hand_tracking_ext = false;
bool hand_motion_range_ext = false;
bool hand_tracking_source_ext = false;
bool unobstructed_data_source = false;
bool controller_data_source = false;
// functions
void cleanup_hand_tracking();

View file

@ -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);
{ // 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("/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(profile_path, "Shoulder click", user_path, user_path + "/input/shoulder/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(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/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(profile_path, "Squeeze click", user_path, user_path + "/input/squeeze/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(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("/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(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
}
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(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("/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);
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
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);
{ // 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("/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(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("/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(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("/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(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("/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(profile_path, "Thumbrest touch", user_path, user_path + "/input/thumbrest/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(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
}
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(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("/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);
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
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);
{ // 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("/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(profile_path, "Select (pinch)", user_path, user_path + "/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);
metadata->register_io_path(profile_path, "Squeeze (grab)", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
}
}
}

View file

@ -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);
{ // 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("/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(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("/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(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/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);
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) {

View file

@ -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);
}
}
}

View file

@ -30,8 +30,6 @@
#include "openxr_local_floor_extension.h"
#include "core/string/print_string.h"
OpenXRLocalFloorExtension *OpenXRLocalFloorExtension::singleton = nullptr;
OpenXRLocalFloorExtension *OpenXRLocalFloorExtension::get_singleton() {

View file

@ -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);
{ // 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);
}
}
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)
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);
// 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(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("/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(profile_path, "Squeeze", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
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(profile_path, "Thumb proximity", user_path, user_path + "/input/thumb_fb/proximity_fb", "", 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(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("/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(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("/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(profile_path, "Stylus force", user_path, user_path + "/input/stylus_fb/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
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(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("/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(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("/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(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);
}
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)
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);
// 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(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("/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(profile_path, "Squeeze", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
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(profile_path, "Thumb proximity", user_path, user_path + "/input/thumb_meta/proximity_meta", "", 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(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("/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(profile_path, "Thumbrest touch", user_path, user_path + "/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
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(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
}
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(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("/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);
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);
}
}

View file

@ -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);
}

View file

@ -0,0 +1,83 @@
/**************************************************************************/
/* openxr_mxink_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_mxink_extension.h"
#include "../action_map/openxr_interaction_profile_metadata.h"
// Not in base XR libs needs def
#define XR_LOGITECH_MX_INK_STYLUS_INTERACTION_EXTENSION_NAME "XR_LOGITECH_mx_ink_stylus_interaction"
HashMap<String, bool *> OpenXRMxInkExtension::get_requested_extensions() {
HashMap<String, bool *> request_extensions;
request_extensions[XR_LOGITECH_MX_INK_STYLUS_INTERACTION_EXTENSION_NAME] = &available;
return request_extensions;
}
bool OpenXRMxInkExtension::is_available() {
return available;
}
void OpenXRMxInkExtension::on_register_metadata() {
OpenXRInteractionProfileMetadata *metadata = OpenXRInteractionProfileMetadata::get_singleton();
ERR_FAIL_NULL(metadata);
// Logitech MX Ink Stylus
metadata->register_interaction_profile("Logitech MX Ink Stylus", "/interaction_profiles/logitech/mx_ink_stylus_logitech", XR_LOGITECH_MX_INK_STYLUS_INTERACTION_EXTENSION_NAME);
metadata->register_io_path("/interaction_profiles/logitech/mx_ink_stylus_logitech", "Tip Force", "/user/hand/left", "/user/hand/left/input/tip_logitech/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
metadata->register_io_path("/interaction_profiles/logitech/mx_ink_stylus_logitech", "Middle force", "/user/hand/left", "/user/hand/left/input/cluster_middle_logitech/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
metadata->register_io_path("/interaction_profiles/logitech/mx_ink_stylus_logitech", "Front click", "/user/hand/left", "/user/hand/left/input/cluster_front_logitech/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
metadata->register_io_path("/interaction_profiles/logitech/mx_ink_stylus_logitech", "Front double", "/user/hand/left", "/user/hand/left/input/cluster_front_logitech/double_tap_logitech", "", OpenXRAction::OPENXR_ACTION_BOOL);
metadata->register_io_path("/interaction_profiles/logitech/mx_ink_stylus_logitech", "Back click", "/user/hand/left", "/user/hand/left/input/cluster_back_logitech/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
metadata->register_io_path("/interaction_profiles/logitech/mx_ink_stylus_logitech", "Back double", "/user/hand/left", "/user/hand/left/input/cluster_back_logitech/double_tap_logitech", "", OpenXRAction::OPENXR_ACTION_BOOL);
metadata->register_io_path("/interaction_profiles/logitech/mx_ink_stylus_logitech", "System click", "/user/hand/left", "/user/hand/left/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
metadata->register_io_path("/interaction_profiles/logitech/mx_ink_stylus_logitech", "Docked", "/user/hand/left", "/user/hand/left/input/dock_logitech/docked_logitech", "", OpenXRAction::OPENXR_ACTION_BOOL);
metadata->register_io_path("/interaction_profiles/logitech/mx_ink_stylus_logitech", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
metadata->register_io_path("/interaction_profiles/logitech/mx_ink_stylus_logitech", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
metadata->register_io_path("/interaction_profiles/logitech/mx_ink_stylus_logitech", "Tip pose", "/user/hand/left", "/user/hand/left/input/tip_logitech/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
metadata->register_io_path("/interaction_profiles/logitech/mx_ink_stylus_logitech", "Tip Force", "/user/hand/right", "/user/hand/right/input/tip_logitech/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
metadata->register_io_path("/interaction_profiles/logitech/mx_ink_stylus_logitech", "Middle force", "/user/hand/right", "/user/hand/right/input/cluster_middle_logitech/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
metadata->register_io_path("/interaction_profiles/logitech/mx_ink_stylus_logitech", "Front click", "/user/hand/right", "/user/hand/right/input/cluster_front_logitech/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
metadata->register_io_path("/interaction_profiles/logitech/mx_ink_stylus_logitech", "Front double", "/user/hand/right", "/user/hand/right/input/cluster_front_logitech/double_tap_logitech", "", OpenXRAction::OPENXR_ACTION_BOOL);
metadata->register_io_path("/interaction_profiles/logitech/mx_ink_stylus_logitech", "Back click", "/user/hand/right", "/user/hand/right/input/cluster_back_logitech/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
metadata->register_io_path("/interaction_profiles/logitech/mx_ink_stylus_logitech", "Back double", "/user/hand/right", "/user/hand/right/input/cluster_back_logitech/double_tap_logitech", "", OpenXRAction::OPENXR_ACTION_BOOL);
metadata->register_io_path("/interaction_profiles/logitech/mx_ink_stylus_logitech", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
metadata->register_io_path("/interaction_profiles/logitech/mx_ink_stylus_logitech", "Docked", "/user/hand/right", "/user/hand/right/input/dock_logitech/docked_logitech", "", OpenXRAction::OPENXR_ACTION_BOOL);
metadata->register_io_path("/interaction_profiles/logitech/mx_ink_stylus_logitech", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
metadata->register_io_path("/interaction_profiles/logitech/mx_ink_stylus_logitech", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
metadata->register_io_path("/interaction_profiles/logitech/mx_ink_stylus_logitech", "Tip pose", "/user/hand/right", "/user/hand/right/input/tip_logitech/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
metadata->register_io_path("/interaction_profiles/logitech/mx_ink_stylus_logitech", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
metadata->register_io_path("/interaction_profiles/logitech/mx_ink_stylus_logitech", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
}

View file

@ -0,0 +1,48 @@
/**************************************************************************/
/* openxr_mxink_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_MXINK_EXTENSION_H
#define OPENXR_MXINK_EXTENSION_H
#include "openxr_extension_wrapper.h"
class OpenXRMxInkExtension : public OpenXRExtensionWrapper {
public:
virtual HashMap<String, bool *> get_requested_extensions() override;
bool is_available();
virtual void on_register_metadata() override;
private:
bool available = false;
};
#endif // OPENXR_MXINK_EXTENSION_H

View file

@ -30,8 +30,6 @@
#include "openxr_palm_pose_extension.h"
#include "core/string/print_string.h"
OpenXRPalmPoseExtension *OpenXRPalmPoseExtension::singleton = nullptr;
OpenXRPalmPoseExtension *OpenXRPalmPoseExtension::get_singleton() {

View file

@ -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);
{ // 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("/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(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("/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(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("/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(profile_path, "Squeeze", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
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(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("/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(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
}
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);
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.
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);
{ // 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("/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(profile_path, "System click", user_path, user_path + "/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(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("/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(profile_path, "Squeeze", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
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(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("/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(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
}
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);
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);
}
}

View file

@ -0,0 +1,193 @@
/**************************************************************************/
/* openxr_valve_analog_threshold_extension.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "openxr_valve_analog_threshold_extension.h"
#include "../action_map/openxr_action_set.h"
#include "../action_map/openxr_interaction_profile.h"
#include "../openxr_api.h"
// Implementation for:
// https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#XR_VALVE_analog_threshold
///////////////////////////////////////////////////////////////////////////////////////////////////
// OpenXRValveAnalogThresholdExtension
OpenXRValveAnalogThresholdExtension *OpenXRValveAnalogThresholdExtension::singleton = nullptr;
OpenXRValveAnalogThresholdExtension *OpenXRValveAnalogThresholdExtension::get_singleton() {
return singleton;
}
OpenXRValveAnalogThresholdExtension::OpenXRValveAnalogThresholdExtension() {
singleton = this;
}
OpenXRValveAnalogThresholdExtension::~OpenXRValveAnalogThresholdExtension() {
singleton = nullptr;
}
HashMap<String, bool *> OpenXRValveAnalogThresholdExtension::get_requested_extensions() {
HashMap<String, bool *> 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<OpenXRHapticBase> &p_haptic) {
on_haptic = p_haptic;
emit_changed();
}
Ref<OpenXRHapticBase> OpenXRAnalogThresholdModifier::get_on_haptic() const {
return on_haptic;
}
void OpenXRAnalogThresholdModifier::set_off_haptic(const Ref<OpenXRHapticBase> &p_haptic) {
off_haptic = p_haptic;
emit_changed();
}
Ref<OpenXRHapticBase> 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<OpenXRAction> action = ip_binding->get_action();
ERR_FAIL_COND_V(action.is_null(), ret);
// Get our action set
Ref<OpenXRActionSet> action_set = action->get_action_set();
ERR_FAIL_COND_V(action_set.is_null(), 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(ret.ptrw(), &analog_threshold, sizeof(XrInteractionProfileAnalogThresholdVALVE));
return ret;
}

View file

@ -0,0 +1,88 @@
/**************************************************************************/
/* openxr_valve_analog_threshold_extension.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef OPENXR_VALVE_ANALOG_THRESHOLD_EXTENSION_H
#define OPENXR_VALVE_ANALOG_THRESHOLD_EXTENSION_H
#include "../action_map/openxr_binding_modifier.h"
#include "../action_map/openxr_haptic_feedback.h"
#include "../util.h"
#include "core/io/resource.h"
#include "openxr_extension_wrapper.h"
class OpenXRValveAnalogThresholdExtension : public OpenXRExtensionWrapper {
public:
static OpenXRValveAnalogThresholdExtension *get_singleton();
OpenXRValveAnalogThresholdExtension();
virtual ~OpenXRValveAnalogThresholdExtension() override;
virtual HashMap<String, bool *> get_requested_extensions() override;
bool is_available();
private:
static OpenXRValveAnalogThresholdExtension *singleton;
bool binding_modifier_ext = false;
bool threshold_ext = false;
};
class OpenXRAnalogThresholdModifier : public OpenXRActionBindingModifier {
GDCLASS(OpenXRAnalogThresholdModifier, OpenXRActionBindingModifier);
private:
XrInteractionProfileAnalogThresholdVALVE analog_threshold;
Ref<OpenXRHapticBase> on_haptic;
Ref<OpenXRHapticBase> 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<OpenXRHapticBase> &p_haptic);
Ref<OpenXRHapticBase> get_on_haptic() const;
void set_off_haptic(const Ref<OpenXRHapticBase> &p_haptic);
Ref<OpenXRHapticBase> get_off_haptic() const;
virtual String get_description() const override { return "Analog threshold modifier"; }
virtual PackedByteArray get_ip_modification() override;
};
#endif // OPENXR_VALVE_ANALOG_THRESHOLD_EXTENSION_H

View file

@ -0,0 +1,279 @@
/**************************************************************************/
/* openxr_visibility_mask_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_visibility_mask_extension.h"
#include "../openxr_api.h"
#include "core/string/print_string.h"
#include "core/variant/array.h"
#include "core/variant/variant.h"
#include "servers/rendering_server.h"
static const char *VISIBILITY_MASK_SHADER_CODE =
"shader_type spatial;\n"
"render_mode unshaded, shadows_disabled, cull_disabled;\n"
"void vertex() {\n"
"\tif (int(VERTEX.z) == VIEW_INDEX) {\n"
"\t\tVERTEX.z = -1.0;\n"
"\t\tVERTEX += EYE_OFFSET;\n"
"\t\tPOSITION = PROJECTION_MATRIX * vec4(VERTEX, 1.0);\n"
"\t\tPOSITION.xy /= POSITION.w;\n"
"\t\tPOSITION.z = 1.0;\n"
"\t\tPOSITION.w = 1.0;\n"
"\t} else {\n"
"\t\tPOSITION = vec4(2.0, 2.0, 2.0, 1.0);\n"
"\t}\n"
"}\n"
"void fragment() {\n"
"\tALBEDO = vec3(0.0, 0.0, 0.0);\n"
"}\n";
OpenXRVisibilityMaskExtension *OpenXRVisibilityMaskExtension::singleton = nullptr;
OpenXRVisibilityMaskExtension *OpenXRVisibilityMaskExtension::get_singleton() {
return singleton;
}
OpenXRVisibilityMaskExtension::OpenXRVisibilityMaskExtension() {
singleton = this;
}
OpenXRVisibilityMaskExtension::~OpenXRVisibilityMaskExtension() {
singleton = nullptr;
}
HashMap<String, bool *> OpenXRVisibilityMaskExtension::get_requested_extensions() {
HashMap<String, bool *> request_extensions;
request_extensions[XR_KHR_VISIBILITY_MASK_EXTENSION_NAME] = &available;
return request_extensions;
}
void OpenXRVisibilityMaskExtension::on_instance_created(const XrInstance p_instance) {
if (available) {
EXT_INIT_XR_FUNC(xrGetVisibilityMaskKHR);
}
}
void OpenXRVisibilityMaskExtension::on_session_created(const XrSession p_instance) {
if (available) {
RS *rendering_server = RS::get_singleton();
ERR_FAIL_NULL(rendering_server);
OpenXRAPI *openxr_api = (OpenXRAPI *)OpenXRAPI::get_singleton();
ERR_FAIL_NULL(openxr_api);
// Create our shader.
shader = rendering_server->shader_create();
rendering_server->shader_set_code(shader, VISIBILITY_MASK_SHADER_CODE);
// Create our material.
material = rendering_server->material_create();
rendering_server->material_set_shader(material, shader);
rendering_server->material_set_render_priority(material, 99);
// Create our mesh.
mesh = rendering_server->mesh_create();
// Get our initial mesh data.
mesh_count = openxr_api->get_view_count(); // We need a mesh for each view.
for (uint32_t i = 0; i < mesh_count; i++) {
_update_mesh_data(i);
}
// And update our mesh
_update_mesh();
}
}
void OpenXRVisibilityMaskExtension::on_session_destroyed() {
RS *rendering_server = RS::get_singleton();
ERR_FAIL_NULL(rendering_server);
// Free our mesh.
if (mesh.is_valid()) {
rendering_server->free(mesh);
mesh = RID();
}
// Free our material.
if (material.is_valid()) {
rendering_server->free(material);
material = RID();
}
// Free our shader.
if (shader.is_valid()) {
rendering_server->free(shader);
shader = RID();
}
mesh_count = 0;
}
void OpenXRVisibilityMaskExtension::on_pre_render() {
// Update mesh data if its dirty.
// Here we call this from the rendering thread however as we're going through the rendering server this is safe.
_update_mesh();
}
bool OpenXRVisibilityMaskExtension::on_event_polled(const XrEventDataBuffer &event) {
if (event.type == XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR) {
XrEventDataVisibilityMaskChangedKHR *vismask_event = (XrEventDataVisibilityMaskChangedKHR *)&event;
print_verbose("OpenXR EVENT: Visibility mask changed for view " + String::num_uint64(vismask_event->viewIndex));
if (available) { // This event won't be called if this extension is not available but better safe than sorry.
_update_mesh_data(vismask_event->viewIndex);
}
return true;
}
return false;
}
bool OpenXRVisibilityMaskExtension::is_available() {
return available;
}
RID OpenXRVisibilityMaskExtension::get_mesh() {
return mesh;
}
void OpenXRVisibilityMaskExtension::_update_mesh_data(uint32_t p_view) {
if (available) {
ERR_FAIL_UNSIGNED_INDEX(p_view, 4);
OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
ERR_FAIL_NULL(openxr_api);
XrSession session = openxr_api->get_session();
XrViewConfigurationType view_configuration_type = openxr_api->get_view_configuration();
// Figure out how much data we're getting.
XrVisibilityMaskKHR visibility_mask_data = {
XR_TYPE_VISIBILITY_MASK_KHR,
nullptr,
0,
0,
nullptr,
0,
0,
nullptr,
};
XrResult result = xrGetVisibilityMaskKHR(session, view_configuration_type, p_view, XR_VISIBILITY_MASK_TYPE_HIDDEN_TRIANGLE_MESH_KHR, &visibility_mask_data);
if (XR_FAILED(result)) {
print_line("OpenXR: Unable to obtain visibility mask metrics [", openxr_api->get_error_string(result), "]");
return;
}
// Resize buffers
mesh_data[p_view].vertices.resize(visibility_mask_data.vertexCountOutput);
mesh_data[p_view].indices.resize(visibility_mask_data.indexCountOutput);
visibility_mask_data.vertexCapacityInput = visibility_mask_data.vertexCountOutput;
visibility_mask_data.vertices = mesh_data[p_view].vertices.ptrw();
visibility_mask_data.indexCapacityInput = visibility_mask_data.indexCountOutput;
visibility_mask_data.indices = mesh_data[p_view].indices.ptrw();
result = xrGetVisibilityMaskKHR(session, view_configuration_type, p_view, XR_VISIBILITY_MASK_TYPE_HIDDEN_TRIANGLE_MESH_KHR, &visibility_mask_data);
if (XR_FAILED(result)) {
print_line("OpenXR: Unable to obtain visibility mask data [", openxr_api->get_error_string(result), "]");
return;
}
// Mark as dirty, we have updated mesh data.
is_dirty = true;
}
}
void OpenXRVisibilityMaskExtension::_update_mesh() {
if (available && is_dirty && mesh_count > 0) {
RS *rendering_server = RS::get_singleton();
ERR_FAIL_NULL(rendering_server);
OpenXRAPI *openxr_api = (OpenXRAPI *)OpenXRAPI::get_singleton();
ERR_FAIL_NULL(openxr_api);
// Combine all vertex and index buffers into one.
PackedVector3Array vertices;
PackedInt32Array indices;
uint64_t vertice_count = 0;
uint64_t index_count = 0;
for (uint32_t i = 0; i < mesh_count; i++) {
vertice_count += mesh_data[i].vertices.size();
index_count += mesh_data[i].indices.size();
}
vertices.resize(vertice_count);
indices.resize(index_count);
uint64_t offset = 0;
Vector3 *v_out = vertices.ptrw();
int32_t *i_out = indices.ptrw();
for (uint32_t i = 0; i < mesh_count; i++) {
const XrVector2f *v_in = mesh_data[i].vertices.ptr();
for (uint32_t j = 0; j < mesh_data[i].vertices.size(); j++) {
v_out->x = v_in->x;
v_out->y = v_in->y;
v_out->z = float(i); // We store our view in our Z component, our shader will filter the right faces out.
v_out++;
v_in++;
}
const uint32_t *i_in = mesh_data[i].indices.ptr();
for (uint32_t j = 0; j < mesh_data[i].indices.size(); j++) {
*i_out = offset + *i_in;
i_out++;
i_in++;
}
offset += mesh_data[i].vertices.size();
}
// Update our mesh.
Array arr;
arr.resize(RS::ARRAY_MAX);
arr[RS::ARRAY_VERTEX] = vertices;
arr[RS::ARRAY_INDEX] = indices;
rendering_server->mesh_clear(mesh);
rendering_server->mesh_add_surface_from_arrays(mesh, RS::PRIMITIVE_TRIANGLES, arr);
rendering_server->mesh_surface_set_material(mesh, 0, material);
// Set no longer dirty.
is_dirty = false;
}
}

View file

@ -0,0 +1,95 @@
/**************************************************************************/
/* openxr_visibility_mask_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_VISIBILITY_MASK_EXTENSION_H
#define OPENXR_VISIBILITY_MASK_EXTENSION_H
#include "../util.h"
#include "core/templates/vector.h"
#include "openxr_extension_wrapper.h"
#include "scene/resources/mesh.h"
// The OpenXR visibility mask extension provides a mesh for each eye that
// can be used as a mask to determine which part of our rendered result
// is actually visible to the user. Due to lens distortion the edges of
// the rendered image are never used in the final result output on the HMD.
//
// Blacking out this are of the render result can remove a fair amount of
// overhead in rendering part of the screen that is unused.
//
// https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#XR_KHR_visibility_mask
class OpenXRVisibilityMaskExtension : public OpenXRExtensionWrapper {
public:
static OpenXRVisibilityMaskExtension *get_singleton();
OpenXRVisibilityMaskExtension();
virtual ~OpenXRVisibilityMaskExtension() override;
virtual HashMap<String, bool *> get_requested_extensions() override;
virtual void on_instance_created(const XrInstance p_instance) override;
virtual void on_session_created(const XrSession p_instance) override;
virtual void on_session_destroyed() override;
virtual void on_pre_render() override;
virtual bool on_event_polled(const XrEventDataBuffer &event) override;
bool is_available();
RID get_mesh();
private:
static OpenXRVisibilityMaskExtension *singleton;
bool available = false;
bool is_dirty = false;
RID shader;
RID material;
RID mesh;
struct MeshData {
Vector<XrVector2f> vertices;
Vector<uint32_t> indices;
};
uint32_t mesh_count = 0;
MeshData mesh_data[4];
void _update_mesh_data(uint32_t p_view);
void _update_mesh();
// OpenXR API call wrappers
EXT_PROTO_XRRESULT_FUNC5(xrGetVisibilityMaskKHR, (XrSession), session, (XrViewConfigurationType), viewConfigurationType, (uint32_t), viewIndex, (XrVisibilityMaskTypeKHR), visibilityMaskType, (XrVisibilityMaskKHR *), visibilityMask);
};
#endif // OPENXR_VISIBILITY_MASK_EXTENSION_H

View file

@ -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);
{ // 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("/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(profile_path, "Menu click", user_path, user_path + "/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(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/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(profile_path, "Squeeze", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
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(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("/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(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
}
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);
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
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);
{ // 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("/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(profile_path, "Menu click", user_path, user_path + "/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(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/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(profile_path, "Squeeze click", user_path, user_path + "/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(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("/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(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/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);
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
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);
{ // 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("/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(profile_path, "Select (pinch)", user_path, user_path + "/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);
metadata->register_io_path(profile_path, "Squeeze (grab)", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
}
}
}

View file

@ -0,0 +1,72 @@
/**************************************************************************/
/* openxr_metal_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_METAL_EXTENSION_H
#define OPENXR_METAL_EXTENSION_H
#include "../../openxr_api.h"
#include "../../util.h"
#include "../openxr_extension_wrapper.h"
#include "core/templates/vector.h"
// Always include this as late as possible.
#include "../../openxr_platform_inc.h"
class OpenXRMetalExtension : public OpenXRGraphicsExtensionWrapper {
public:
virtual HashMap<String, bool *> get_requested_extensions() override;
virtual void on_instance_created(const XrInstance p_instance) override;
virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) override;
virtual void get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) override;
virtual void get_usable_depth_formats(Vector<int64_t> &p_usable_swap_chains) override;
virtual String get_swapchain_format_name(int64_t p_swapchain_format) const override;
virtual bool get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) override;
virtual void cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) override;
virtual bool create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) override;
virtual RID get_texture(void *p_swapchain_graphics_data, int p_image_index) override;
private:
static XrGraphicsBindingMetalKHR graphics_binding_metal;
struct SwapchainGraphicsData {
bool is_multiview;
Vector<RID> texture_rids;
};
bool check_graphics_api_support();
EXT_PROTO_XRRESULT_FUNC3(xrGetMetalGraphicsRequirementsKHR, (XrInstance), p_instance, (XrSystemId), p_system_id, (XrGraphicsRequirementsMetalKHR *), p_graphics_requirements)
EXT_PROTO_XRRESULT_FUNC4(xrEnumerateSwapchainImages, (XrSwapchain), p_swapchain, (uint32_t), p_image_capacity_input, (uint32_t *), p_image_count_output, (XrSwapchainImageBaseHeader *), p_images)
};
#endif // OPENXR_METAL_EXTENSION_H

View file

@ -0,0 +1,318 @@
/**************************************************************************/
/* openxr_metal_extension.mm */
/**************************************************************************/
/* 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_metal_extension.h"
#include "../../openxr_util.h"
#include "drivers/metal/rendering_device_driver_metal.h"
#include "servers/rendering/rendering_server_globals.h"
HashMap<String, bool *> OpenXRMetalExtension::get_requested_extensions() {
HashMap<String, bool *> request_extensions;
request_extensions[XR_KHR_METAL_ENABLE_EXTENSION_NAME] = nullptr;
return request_extensions;
}
void OpenXRMetalExtension::on_instance_created(const XrInstance p_instance) {
// Obtain pointers to functions we're accessing here.
ERR_FAIL_NULL(OpenXRAPI::get_singleton());
EXT_INIT_XR_FUNC(xrGetMetalGraphicsRequirementsKHR);
EXT_INIT_XR_FUNC(xrEnumerateSwapchainImages);
}
bool OpenXRMetalExtension::check_graphics_api_support() {
ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), false);
// TODO We may need to do a callback like we do in Vulkan where we run this first
// and provide the obtained metalDevice to our Metal driver to use.
// But according to Stuart Macs only have 1 device so it should always be the
// same one and we should be able to get away with not doing this just yet.
// If we do go forward with this, this means that just like with Vulkan,
// we have to start with OpenXR before Metal can be setup, and we thus
// can't support applications that want to add XR as an optional/temporary
// feature that users enable when needed.
XrSystemId system_id = OpenXRAPI::get_singleton()->get_system_id();
XrInstance instance = OpenXRAPI::get_singleton()->get_instance();
XrGraphicsRequirementsMetalKHR metal_requirements;
metal_requirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_METAL_KHR;
metal_requirements.next = nullptr;
metal_requirements.metalDevice = nullptr;
XrResult result = xrGetMetalGraphicsRequirementsKHR(instance, system_id, &metal_requirements);
if (!OpenXRAPI::get_singleton()->xr_result(result, "Failed to get Metal graphics requirements!")) {
return false;
}
// See what metal device we are using...
RenderingServer *rendering_server = RenderingServer::get_singleton();
ERR_FAIL_NULL_V(rendering_server, false);
RenderingDevice *rendering_device = rendering_server->get_rendering_device();
ERR_FAIL_NULL_V(rendering_device, false);
void *our_metal_device = (void *)rendering_device->get_driver_resource(RD::DRIVER_RESOURCE_LOGICAL_DEVICE);
// Make sure we're using the same one.
ERR_FAIL_COND_V(metal_requirements.metalDevice != our_metal_device, false);
return true;
}
XrGraphicsBindingMetalKHR OpenXRMetalExtension::graphics_binding_metal;
void *OpenXRMetalExtension::set_session_create_and_get_next_pointer(void *p_next_pointer) {
if (!check_graphics_api_support()) {
return p_next_pointer;
}
RenderingServer *rendering_server = RenderingServer::get_singleton();
ERR_FAIL_NULL_V(rendering_server, p_next_pointer);
RenderingDevice *rendering_device = rendering_server->get_rendering_device();
ERR_FAIL_NULL_V(rendering_device, p_next_pointer);
graphics_binding_metal.type = XR_TYPE_GRAPHICS_BINDING_METAL_KHR;
graphics_binding_metal.next = p_next_pointer;
graphics_binding_metal.commandQueue = (void *)rendering_device->get_driver_resource(RD::DRIVER_RESOURCE_COMMAND_QUEUE);
return &graphics_binding_metal;
}
void OpenXRMetalExtension::get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) {
p_usable_swap_chains.push_back(MTLPixelFormatRGBA8Unorm_sRGB);
p_usable_swap_chains.push_back(MTLPixelFormatBGRA8Unorm_sRGB);
p_usable_swap_chains.push_back(MTLPixelFormatRGBA8Uint);
}
void OpenXRMetalExtension::get_usable_depth_formats(Vector<int64_t> &p_usable_swap_chains) {
p_usable_swap_chains.push_back(MTLPixelFormatDepth24Unorm_Stencil8);
p_usable_swap_chains.push_back(MTLPixelFormatDepth32Float_Stencil8);
p_usable_swap_chains.push_back(MTLPixelFormatDepth32Float);
}
#define ENUM_TO_STRING_CASE(m_e) \
case m_e: { \
return String(#m_e); \
} break;
String OpenXRMetalExtension::get_swapchain_format_name(int64_t p_swapchain_format) const {
// This really should be in vulkan_context...
MTLPixelFormat format = MTLPixelFormat(p_swapchain_format);
switch (format) {
ENUM_TO_STRING_CASE(MTLPixelFormatRGBA8Unorm)
ENUM_TO_STRING_CASE(MTLPixelFormatRGBA8Unorm_sRGB)
ENUM_TO_STRING_CASE(MTLPixelFormatBGRA8Unorm)
ENUM_TO_STRING_CASE(MTLPixelFormatBGRA8Unorm_sRGB)
ENUM_TO_STRING_CASE(MTLPixelFormatRGBA8Uint)
ENUM_TO_STRING_CASE(MTLPixelFormatDepth24Unorm_Stencil8)
ENUM_TO_STRING_CASE(MTLPixelFormatDepth32Float_Stencil8)
ENUM_TO_STRING_CASE(MTLPixelFormatDepth32Float)
default: {
return String("Swapchain format ") + String::num_int64(int64_t(p_swapchain_format));
} break;
}
}
bool OpenXRMetalExtension::get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) {
LocalVector<XrSwapchainImageMetalKHR, uint32_t, false, true> images;
RenderingServer *rendering_server = RenderingServer::get_singleton();
ERR_FAIL_NULL_V(rendering_server, false);
RenderingDevice *rendering_device = rendering_server->get_rendering_device();
ERR_FAIL_NULL_V(rendering_device, false);
uint32_t swapchain_length;
XrResult result = xrEnumerateSwapchainImages(p_swapchain, 0, &swapchain_length, nullptr);
if (XR_FAILED(result)) {
print_line("OpenXR: Failed to get swapchaim image count [", OpenXRAPI::get_singleton()->get_error_string(result), "]");
return false;
}
images.resize(swapchain_length);
for (XrSwapchainImageMetalKHR &image : images) {
image.type = XR_TYPE_SWAPCHAIN_IMAGE_METAL_KHR;
image.next = nullptr;
image.texture = nullptr;
}
result = xrEnumerateSwapchainImages(p_swapchain, swapchain_length, &swapchain_length, (XrSwapchainImageBaseHeader *)images.ptr());
if (XR_FAILED(result)) {
print_line("OpenXR: Failed to get swapchaim images [", OpenXRAPI::get_singleton()->get_error_string(result), "]");
return false;
}
SwapchainGraphicsData *data = memnew(SwapchainGraphicsData);
if (data == nullptr) {
print_line("OpenXR: Failed to allocate memory for swapchain data");
return false;
}
*r_swapchain_graphics_data = data;
data->is_multiview = (p_array_size > 1);
RenderingDevice::DataFormat format = RenderingDevice::DATA_FORMAT_R8G8B8A8_SRGB;
RenderingDevice::TextureSamples samples = RenderingDevice::TEXTURE_SAMPLES_1;
uint64_t usage_flags = RenderingDevice::TEXTURE_USAGE_SAMPLING_BIT;
switch (p_swapchain_format) {
case MTLPixelFormatRGBA8Unorm_sRGB:
// Even though this is an sRGB framebuffer format we're using UNORM here.
// The reason here is because Godot does a linear to sRGB conversion while
// with the sRGB format, this conversion would be doubled by the hardware.
// This also means we're reading the values as is for our preview on screen.
// The OpenXR runtime however is still treating this as an sRGB format and
// will thus do an sRGB -> Linear conversion as expected.
//format = RenderingDevice::DATA_FORMAT_R8G8B8A8_SRGB;
format = RenderingDevice::DATA_FORMAT_R8G8B8A8_UNORM;
usage_flags |= RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
break;
case MTLPixelFormatBGRA8Unorm_sRGB:
format = RenderingDevice::DATA_FORMAT_B8G8R8A8_UNORM;
usage_flags |= RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
break;
case MTLPixelFormatRGBA8Uint:
format = RenderingDevice::DATA_FORMAT_R8G8B8A8_UINT;
usage_flags |= RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
break;
case MTLPixelFormatDepth32Float:
format = RenderingDevice::DATA_FORMAT_D32_SFLOAT;
usage_flags |= RenderingDevice::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
break;
case MTLPixelFormatDepth24Unorm_Stencil8:
format = RenderingDevice::DATA_FORMAT_D24_UNORM_S8_UINT;
usage_flags |= RenderingDevice::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
break;
case MTLPixelFormatDepth32Float_Stencil8:
format = RenderingDevice::DATA_FORMAT_D32_SFLOAT_S8_UINT;
usage_flags |= RenderingDevice::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
break;
default:
// Continue with our default value.
print_line("OpenXR: Unsupported swapchain format", p_swapchain_format);
break;
}
switch (p_sample_count) {
case 1:
samples = RenderingDevice::TEXTURE_SAMPLES_1;
break;
case 2:
samples = RenderingDevice::TEXTURE_SAMPLES_2;
break;
case 4:
samples = RenderingDevice::TEXTURE_SAMPLES_4;
break;
case 8:
samples = RenderingDevice::TEXTURE_SAMPLES_8;
break;
case 16:
samples = RenderingDevice::TEXTURE_SAMPLES_16;
break;
case 32:
samples = RenderingDevice::TEXTURE_SAMPLES_32;
break;
case 64:
samples = RenderingDevice::TEXTURE_SAMPLES_64;
break;
default:
// Continue with our default value.
print_line("OpenXR: Unsupported sample count", p_sample_count);
break;
}
Vector<RID> texture_rids;
// Create Godot texture objects for each entry in our swapchain.
for (uint64_t i = 0; i < swapchain_length; i++) {
// Note, the formats we sent to render_device are ignored on metal.
RID image_rid = rendering_device->texture_create_from_extension(
p_array_size == 1 ? RenderingDevice::TEXTURE_TYPE_2D : RenderingDevice::TEXTURE_TYPE_2D_ARRAY,
format,
samples,
usage_flags,
(uint64_t)images[i].texture,
p_width,
p_height,
1,
p_array_size);
texture_rids.push_back(image_rid);
}
data->texture_rids = texture_rids;
return true;
}
void OpenXRMetalExtension::cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) {
if (*p_swapchain_graphics_data == nullptr) {
return;
}
SwapchainGraphicsData *data = (SwapchainGraphicsData *)*p_swapchain_graphics_data;
RenderingServer *rendering_server = RenderingServer::get_singleton();
ERR_FAIL_NULL(rendering_server);
RenderingDevice *rendering_device = rendering_server->get_rendering_device();
ERR_FAIL_NULL(rendering_device);
for (const RID &texture_rid : data->texture_rids) {
rendering_device->free(texture_rid);
}
data->texture_rids.clear();
memdelete(data);
*p_swapchain_graphics_data = nullptr;
}
bool OpenXRMetalExtension::create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) {
// Even though this is a Metal renderer we're using OpenGL coordinate systems.
OpenXRUtil::XrMatrix4x4f matrix;
OpenXRUtil::XrMatrix4x4f_CreateProjectionFov(&matrix, OpenXRUtil::GRAPHICS_OPENGL, p_fov, (float)p_z_near, (float)p_z_far);
for (int j = 0; j < 4; j++) {
for (int i = 0; i < 4; i++) {
r_camera_matrix.columns[j][i] = matrix.m[j * 4 + i];
}
}
return true;
}
RID OpenXRMetalExtension::get_texture(void *p_swapchain_graphics_data, int p_image_index) {
SwapchainGraphicsData *data = (SwapchainGraphicsData *)p_swapchain_graphics_data;
ERR_FAIL_NULL_V(data, RID());
ERR_FAIL_INDEX_V(p_image_index, data->texture_rids.size(), RID());
return data->texture_rids[p_image_index];
}

View file

@ -56,11 +56,6 @@
// feature off.
// See: https://registry.khronos.org/OpenGL/extensions/EXT/EXT_sRGB_write_control.txt
// On OpenGLES this is not defined in our standard headers..
#ifndef GL_FRAMEBUFFER_SRGB
#define GL_FRAMEBUFFER_SRGB 0x8DB9
#endif
HashMap<String, bool *> OpenXROpenGLExtension::get_requested_extensions() {
HashMap<String, bool *> request_extensions;
@ -69,6 +64,9 @@ HashMap<String, bool *> OpenXROpenGLExtension::get_requested_extensions() {
#else
request_extensions[XR_KHR_OPENGL_ENABLE_EXTENSION_NAME] = nullptr;
#endif
#if defined(LINUXBSD_ENABLED) && defined(EGL_ENABLED) && defined(WAYLAND_ENABLED)
request_extensions[XR_MNDX_EGL_ENABLE_EXTENSION_NAME] = &egl_extension_enabled;
#endif
return request_extensions;
}
@ -133,9 +131,14 @@ bool OpenXROpenGLExtension::check_graphics_api_support(XrVersion p_desired_versi
XrGraphicsBindingOpenGLWin32KHR OpenXROpenGLExtension::graphics_binding_gl;
#elif defined(ANDROID_ENABLED)
XrGraphicsBindingOpenGLESAndroidKHR OpenXROpenGLExtension::graphics_binding_gl;
#elif defined(X11_ENABLED)
#elif defined(LINUXBSD_ENABLED)
#ifdef X11_ENABLED
XrGraphicsBindingOpenGLXlibKHR OpenXROpenGLExtension::graphics_binding_gl;
#endif
#if defined(EGL_ENABLED) && defined(WAYLAND_ENABLED)
XrGraphicsBindingEGLMNDX OpenXROpenGLExtension::graphics_binding_egl;
#endif
#endif
void *OpenXROpenGLExtension::set_session_create_and_get_next_pointer(void *p_next_pointer) {
XrVersion desired_version = XR_MAKE_VERSION(3, 3, 0);
@ -147,10 +150,6 @@ void *OpenXROpenGLExtension::set_session_create_and_get_next_pointer(void *p_nex
DisplayServer *display_server = DisplayServer::get_singleton();
#ifdef WAYLAND_ENABLED
ERR_FAIL_COND_V_MSG(display_server->get_name() == "Wayland", p_next_pointer, "OpenXR is not yet supported on OpenGL Wayland.");
#endif
#ifdef WIN32
graphics_binding_gl.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR,
graphics_binding_gl.next = p_next_pointer;
@ -164,7 +163,23 @@ void *OpenXROpenGLExtension::set_session_create_and_get_next_pointer(void *p_nex
graphics_binding_gl.display = (void *)display_server->window_get_native_handle(DisplayServer::DISPLAY_HANDLE);
graphics_binding_gl.config = (EGLConfig)0; // https://github.com/KhronosGroup/OpenXR-SDK-Source/blob/master/src/tests/hello_xr/graphicsplugin_opengles.cpp#L122
graphics_binding_gl.context = (void *)display_server->window_get_native_handle(DisplayServer::OPENGL_CONTEXT);
#elif defined(X11_ENABLED)
#else
#if defined(EGL_ENABLED) && defined(WAYLAND_ENABLED)
if (display_server->get_name() == "Wayland") {
ERR_FAIL_COND_V_MSG(!egl_extension_enabled, p_next_pointer, "OpenXR cannot initialize on Wayland without the XR_MNDX_egl_enable extension.");
graphics_binding_egl.type = XR_TYPE_GRAPHICS_BINDING_EGL_MNDX;
graphics_binding_egl.next = p_next_pointer;
graphics_binding_egl.getProcAddress = eglGetProcAddress;
graphics_binding_egl.display = (void *)display_server->window_get_native_handle(DisplayServer::EGL_DISPLAY);
graphics_binding_egl.config = (void *)display_server->window_get_native_handle(DisplayServer::EGL_CONFIG);
graphics_binding_egl.context = (void *)display_server->window_get_native_handle(DisplayServer::OPENGL_CONTEXT);
return &graphics_binding_egl;
}
#endif
#if defined(X11_ENABLED)
graphics_binding_gl.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR;
graphics_binding_gl.next = p_next_pointer;
@ -178,10 +193,15 @@ void *OpenXROpenGLExtension::set_session_create_and_get_next_pointer(void *p_nex
// spec says to use proper values but runtimes don't care
graphics_binding_gl.visualid = 0;
graphics_binding_gl.glxFBConfig = 0;
graphics_binding_gl.glxFBConfig = nullptr;
#endif
#endif
#if defined(WIN32) || defined(ANDROID_ENABLED) || defined(X11_ENABLED)
return &graphics_binding_gl;
#else
return p_next_pointer;
#endif
}
void OpenXROpenGLExtension::get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) {
@ -196,23 +216,6 @@ void OpenXROpenGLExtension::get_usable_depth_formats(Vector<int64_t> &p_usable_d
p_usable_depth_formats.push_back(GL_DEPTH_COMPONENT24);
}
void OpenXROpenGLExtension::on_pre_draw_viewport(RID p_render_target) {
if (srgb_ext_is_available) {
hw_linear_to_srgb_is_enabled = glIsEnabled(GL_FRAMEBUFFER_SRGB);
if (hw_linear_to_srgb_is_enabled) {
// Disable this.
glDisable(GL_FRAMEBUFFER_SRGB);
}
}
}
void OpenXROpenGLExtension::on_post_draw_viewport(RID p_render_target) {
if (srgb_ext_is_available && hw_linear_to_srgb_is_enabled) {
// Re-enable this.
glEnable(GL_FRAMEBUFFER_SRGB);
}
}
bool OpenXROpenGLExtension::get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) {
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
ERR_FAIL_NULL_V(texture_storage, false);
@ -225,33 +228,32 @@ bool OpenXROpenGLExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in
}
#ifdef ANDROID_ENABLED
XrSwapchainImageOpenGLESKHR *images = (XrSwapchainImageOpenGLESKHR *)memalloc(sizeof(XrSwapchainImageOpenGLESKHR) * swapchain_length);
LocalVector<XrSwapchainImageOpenGLESKHR> images;
#else
XrSwapchainImageOpenGLKHR *images = (XrSwapchainImageOpenGLKHR *)memalloc(sizeof(XrSwapchainImageOpenGLKHR) * swapchain_length);
LocalVector<XrSwapchainImageOpenGLKHR> images;
#endif
ERR_FAIL_NULL_V_MSG(images, false, "OpenXR Couldn't allocate memory for swap chain image");
images.resize(swapchain_length);
for (uint64_t i = 0; i < swapchain_length; i++) {
#ifdef ANDROID_ENABLED
images[i].type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR;
for (XrSwapchainImageOpenGLESKHR &image : images) {
image.type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR;
#else
images[i].type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR;
for (XrSwapchainImageOpenGLKHR &image : images) {
image.type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR;
#endif
images[i].next = nullptr;
images[i].image = 0;
image.next = nullptr;
image.image = 0;
}
result = xrEnumerateSwapchainImages(p_swapchain, swapchain_length, &swapchain_length, (XrSwapchainImageBaseHeader *)images);
result = xrEnumerateSwapchainImages(p_swapchain, swapchain_length, &swapchain_length, (XrSwapchainImageBaseHeader *)images.ptr());
if (XR_FAILED(result)) {
print_line("OpenXR: Failed to get swapchaim images [", OpenXRAPI::get_singleton()->get_error_string(result), "]");
memfree(images);
return false;
}
SwapchainGraphicsData *data = memnew(SwapchainGraphicsData);
if (data == nullptr) {
print_line("OpenXR: Failed to allocate memory for swapchain data");
memfree(images);
return false;
}
*r_swapchain_graphics_data = data;
@ -262,8 +264,8 @@ bool OpenXROpenGLExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in
Vector<RID> texture_rids;
for (uint64_t i = 0; i < swapchain_length; i++) {
RID texture_rid = texture_storage->texture_create_external(
p_array_size == 1 ? GLES3::Texture::TYPE_2D : GLES3::Texture::TYPE_LAYERED,
RID texture_rid = texture_storage->texture_create_from_native_handle(
p_array_size == 1 ? RS::TEXTURE_TYPE_2D : RS::TEXTURE_TYPE_LAYERED,
format,
images[i].image,
p_width,
@ -276,8 +278,6 @@ bool OpenXROpenGLExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in
data->texture_rids = texture_rids;
memfree(images);
return true;
}
@ -312,8 +312,8 @@ void OpenXROpenGLExtension::cleanup_swapchain_graphics_data(void **p_swapchain_g
SwapchainGraphicsData *data = (SwapchainGraphicsData *)*p_swapchain_graphics_data;
for (int i = 0; i < data->texture_rids.size(); i++) {
texture_storage->texture_free(data->texture_rids[i]);
for (const RID &texture_rid : data->texture_rids) {
texture_storage->texture_free(texture_rid);
}
data->texture_rids.clear();

View file

@ -49,9 +49,6 @@ public:
virtual void on_instance_created(const XrInstance p_instance) override;
virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) override;
virtual void on_pre_draw_viewport(RID p_render_target) override;
virtual void on_post_draw_viewport(RID p_render_target) override;
virtual void get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) override;
virtual void get_usable_depth_formats(Vector<int64_t> &p_usable_swap_chains) override;
virtual String get_swapchain_format_name(int64_t p_swapchain_format) const override;
@ -67,8 +64,17 @@ private:
static XrGraphicsBindingOpenGLWin32KHR graphics_binding_gl;
#elif defined(ANDROID_ENABLED)
static XrGraphicsBindingOpenGLESAndroidKHR graphics_binding_gl;
#else // Linux/X11
#elif defined(LINUXBSD_ENABLED)
#ifdef X11_ENABLED
static XrGraphicsBindingOpenGLXlibKHR graphics_binding_gl;
#endif
#if defined(EGL_ENABLED) && defined(WAYLAND_ENABLED)
static XrGraphicsBindingEGLMNDX graphics_binding_egl;
bool egl_extension_enabled = false;
#endif
#else
#error "OpenXR with OpenGL isn't supported on this platform"
#endif
struct SwapchainGraphicsData {
@ -76,9 +82,6 @@ private:
Vector<RID> texture_rids;
};
bool srgb_ext_is_available = true;
bool hw_linear_to_srgb_is_enabled = false;
bool check_graphics_api_support(XrVersion p_desired_version);
#ifdef ANDROID_ENABLED

View file

@ -239,7 +239,7 @@ void OpenXRVulkanExtension::get_usable_depth_formats(Vector<int64_t> &p_usable_s
}
bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) {
XrSwapchainImageVulkanKHR *images = nullptr;
LocalVector<XrSwapchainImageVulkanKHR> images;
RenderingServer *rendering_server = RenderingServer::get_singleton();
ERR_FAIL_NULL_V(rendering_server, false);
@ -253,27 +253,23 @@ bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in
return false;
}
images = (XrSwapchainImageVulkanKHR *)memalloc(sizeof(XrSwapchainImageVulkanKHR) * swapchain_length);
ERR_FAIL_NULL_V_MSG(images, false, "OpenXR Couldn't allocate memory for swap chain image");
images.resize(swapchain_length);
for (uint64_t i = 0; i < swapchain_length; i++) {
images[i].type = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR;
images[i].next = nullptr;
images[i].image = VK_NULL_HANDLE;
for (XrSwapchainImageVulkanKHR &image : images) {
image.type = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR;
image.next = nullptr;
image.image = VK_NULL_HANDLE;
}
result = xrEnumerateSwapchainImages(p_swapchain, swapchain_length, &swapchain_length, (XrSwapchainImageBaseHeader *)images);
result = xrEnumerateSwapchainImages(p_swapchain, swapchain_length, &swapchain_length, (XrSwapchainImageBaseHeader *)images.ptr());
if (XR_FAILED(result)) {
print_line("OpenXR: Failed to get swapchaim images [", OpenXRAPI::get_singleton()->get_error_string(result), "]");
memfree(images);
return false;
}
// SwapchainGraphicsData *data = (SwapchainGraphicsData *)memalloc(sizeof(SwapchainGraphicsData));
SwapchainGraphicsData *data = memnew(SwapchainGraphicsData);
if (data == nullptr) {
print_line("OpenXR: Failed to allocate memory for swapchain data");
memfree(images);
return false;
}
*r_swapchain_graphics_data = data;
@ -291,12 +287,12 @@ bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in
// This also means we're reading the values as is for our preview on screen.
// The OpenXR runtime however is still treating this as an sRGB format and
// will thus do an sRGB -> Linear conversion as expected.
// format = RenderingDevice::DATA_FORMAT_R8G8B8A8_SRGB;
//format = RenderingDevice::DATA_FORMAT_R8G8B8A8_SRGB;
format = RenderingDevice::DATA_FORMAT_R8G8B8A8_UNORM;
usage_flags |= RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
break;
case VK_FORMAT_B8G8R8A8_SRGB:
// format = RenderingDevice::DATA_FORMAT_B8G8R8A8_SRGB;
//format = RenderingDevice::DATA_FORMAT_B8G8R8A8_SRGB;
format = RenderingDevice::DATA_FORMAT_B8G8R8A8_UNORM;
usage_flags |= RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
break;
@ -322,7 +318,7 @@ bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in
break;
default:
// continue with our default value
print_line("Unsupported swapchain format ", p_swapchain_format);
print_line("OpenXR: Unsupported swapchain format", p_swapchain_format);
break;
}
@ -350,20 +346,20 @@ bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in
break;
default:
// continue with our default value
print_line("Unsupported sample count ", p_sample_count);
print_line("OpenXR: Unsupported sample count", p_sample_count);
break;
}
Vector<RID> texture_rids;
// create Godot texture objects for each entry in our swapchain
for (uint64_t i = 0; i < swapchain_length; i++) {
for (const XrSwapchainImageVulkanKHR &swapchain_image : images) {
RID image_rid = rendering_device->texture_create_from_extension(
p_array_size == 1 ? RenderingDevice::TEXTURE_TYPE_2D : RenderingDevice::TEXTURE_TYPE_2D_ARRAY,
format,
samples,
usage_flags,
(uint64_t)images[i].image,
(uint64_t)swapchain_image.image,
p_width,
p_height,
1,
@ -374,13 +370,11 @@ bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in
data->texture_rids = texture_rids;
memfree(images);
return true;
}
bool OpenXRVulkanExtension::create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) {
// Even though this is a Vulkan renderer we're using OpenGL coordinate systems
// Even though this is a Vulkan renderer we're using OpenGL coordinate systems.
OpenXRUtil::XrMatrix4x4f matrix;
OpenXRUtil::XrMatrix4x4f_CreateProjectionFov(&matrix, OpenXRUtil::GRAPHICS_OPENGL, p_fov, (float)p_z_near, (float)p_z_far);
@ -413,9 +407,9 @@ void OpenXRVulkanExtension::cleanup_swapchain_graphics_data(void **p_swapchain_g
RenderingDevice *rendering_device = rendering_server->get_rendering_device();
ERR_FAIL_NULL(rendering_device);
for (int i = 0; i < data->texture_rids.size(); i++) {
// This should clean up our RIDs and associated texture objects but shouldn't destroy the images, they are owned by our XrSwapchain
rendering_device->free(data->texture_rids[i]);
for (const RID &texture_rid : data->texture_rids) {
// This should clean up our RIDs and associated texture objects but shouldn't destroy the images, they are owned by our XrSwapchain.
rendering_device->free(texture_rid);
}
data->texture_rids.clear();

File diff suppressed because it is too large Load diff

View file

@ -40,10 +40,7 @@
#include "core/math/projection.h"
#include "core/math/transform_3d.h"
#include "core/math/vector2.h"
#include "core/os/memory.h"
#include "core/string/print_string.h"
#include "core/string/ustring.h"
#include "core/templates/rb_map.h"
#include "core/templates/rid_owner.h"
#include "core/templates/vector.h"
#include "servers/rendering_server.h"
@ -91,28 +88,26 @@ private:
OpenXRInterface *xr_interface = nullptr;
// layers
uint32_t num_layer_properties = 0;
XrApiLayerProperties *layer_properties = nullptr;
LocalVector<XrApiLayerProperties> layer_properties;
// extensions
uint32_t num_supported_extensions = 0;
XrExtensionProperties *supported_extensions = nullptr;
LocalVector<XrExtensionProperties> supported_extensions;
Vector<CharString> enabled_extensions;
// composition layer providers
Vector<OpenXRCompositionLayerProvider *> composition_layer_providers;
// projection views extensions
Vector<OpenXRExtensionWrapper *> projection_views_extensions;
// view configuration
uint32_t num_view_configuration_types = 0;
XrViewConfigurationType *supported_view_configuration_types = nullptr;
LocalVector<XrViewConfigurationType> supported_view_configuration_types;
// reference spaces
uint32_t num_reference_spaces = 0;
XrReferenceSpaceType *supported_reference_spaces = nullptr;
LocalVector<XrReferenceSpaceType> supported_reference_spaces;
// swapchains (note these are platform dependent)
uint32_t num_swapchain_formats = 0;
int64_t *supported_swapchain_formats = nullptr;
PackedInt64Array supported_swapchain_formats;
// system info
String runtime_name;
@ -128,8 +123,7 @@ private:
// blend mode
XrEnvironmentBlendMode environment_blend_mode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
XrEnvironmentBlendMode requested_environment_blend_mode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
uint32_t num_supported_environment_blend_modes = 0;
XrEnvironmentBlendMode *supported_environment_blend_modes = nullptr;
Vector<XrEnvironmentBlendMode> supported_environment_blend_modes;
bool emulate_environment_blend_mode_alpha_blend = false;
// state
@ -143,17 +137,16 @@ private:
bool running = false;
XrFrameState frame_state = { XR_TYPE_FRAME_STATE, nullptr, 0, 0, false };
double render_target_size_multiplier = 1.0;
Rect2i render_region;
OpenXRGraphicsExtensionWrapper *graphics_extension = nullptr;
XrSystemGraphicsProperties graphics_properties;
uint32_t view_count = 0;
XrViewConfigurationView *view_configuration_views = nullptr;
LocalVector<XrViewConfigurationView> view_configuration_views;
enum OpenXRSwapChainTypes {
OPENXR_SWAPCHAIN_COLOR,
OPENXR_SWAPCHAIN_DEPTH,
// OPENXR_SWAPCHAIN_VELOCITY,
OPENXR_SWAPCHAIN_MAX
};
@ -165,6 +158,10 @@ private:
XrSpace view_space = XR_NULL_HANDLE;
XRPose::TrackingConfidence head_pose_confidence = XRPose::XR_TRACKING_CONFIDENCE_NONE;
RID velocity_texture;
RID velocity_depth_texture;
Size2i velocity_target_size;
// When LOCAL_FLOOR isn't supported, we use an approach based on the example code in the
// OpenXR spec in order to emulate it.
// See: https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#XR_EXT_local_floor
@ -300,6 +297,7 @@ private:
String name; // Name of the interaction profile (i.e. "/interaction_profiles/valve/index_controller")
XrPath path; // OpenXR path for this profile
Vector<XrActionSuggestedBinding> bindings; // OpenXR action bindings
Vector<PackedByteArray> modifiers; // Array of modifiers we'll add into XrBindingModificationsKHR
};
RID_Owner<InteractionProfile, true> interaction_profile_owner;
RID get_interaction_profile_rid(XrPath p_path);
@ -336,14 +334,27 @@ private:
XrTime predicted_display_time = 0;
XrSpace play_space = XR_NULL_HANDLE;
double render_target_size_multiplier = 1.0;
uint64_t frame = 0;
Rect2i render_region;
uint32_t view_count = 0;
XrView *views = nullptr;
XrCompositionLayerProjectionView *projection_views = nullptr;
XrCompositionLayerDepthInfoKHR *depth_views = nullptr; // Only used by Composition Layer Depth Extension if available
LocalVector<XrView> views;
LocalVector<XrCompositionLayerProjectionView> projection_views;
LocalVector<XrCompositionLayerDepthInfoKHR> depth_views; // Only used by Composition Layer Depth Extension if available
bool submit_depth_buffer = false; // if set to true we submit depth buffers to OpenXR if a suitable extension is enabled.
bool view_pose_valid = false;
double z_near = 0.0;
double z_far = 0.0;
XrCompositionLayerProjection projection_layer = {
XR_TYPE_COMPOSITION_LAYER_PROJECTION, // type
nullptr, // next
0, // layerFlags
XR_NULL_HANDLE, // space
0, // viewCount
nullptr // views
};
Size2i main_swapchain_size;
OpenXRSwapChainInfo main_swapchains[OPENXR_SWAPCHAIN_MAX];
} render_state;
@ -353,6 +364,7 @@ private:
static void _set_render_display_info(XrTime p_predicted_display_time, bool p_should_render);
static void _set_render_play_space(uint64_t p_play_space);
static void _set_render_state_multiplier(double p_render_target_size_multiplier);
static void _set_render_state_render_region(const Rect2i &p_render_region);
_FORCE_INLINE_ void allocate_view_buffers(uint32_t p_view_count, bool p_submit_depth_buffer) {
// If we're rendering on a separate thread, we may still be processing the last frame, don't communicate this till we're ready...
@ -394,13 +406,20 @@ private:
rendering_server->call_on_render_thread(callable_mp_static(&OpenXRAPI::_set_render_state_multiplier).bind(p_render_target_size_multiplier));
}
_FORCE_INLINE_ void set_render_state_render_region(const Rect2i &p_render_region) {
RenderingServer *rendering_server = RenderingServer::get_singleton();
ERR_FAIL_NULL(rendering_server);
rendering_server->call_on_render_thread(callable_mp_static(&OpenXRAPI::_set_render_state_render_region).bind(p_render_region));
}
public:
XrInstance get_instance() const { return instance; };
XrSystemId get_system_id() const { return system_id; };
XrSession get_session() const { return session; };
OpenXRGraphicsExtensionWrapper *get_graphics_extension() const { return graphics_extension; };
String get_runtime_name() const { return runtime_name; };
String get_runtime_version() const { return runtime_version; };
XrInstance get_instance() const { return instance; }
XrSystemId get_system_id() const { return system_id; }
XrSession get_session() const { return session; }
OpenXRGraphicsExtensionWrapper *get_graphics_extension() const { return graphics_extension; }
String get_runtime_name() const { return runtime_name; }
String get_runtime_version() const { return runtime_version; }
// helper method to convert an XrPosef to a Transform3D
Transform3D transform_from_pose(const XrPosef &p_pose);
@ -409,8 +428,8 @@ public:
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);
@ -422,6 +441,10 @@ public:
XrResult get_instance_proc_addr(const char *p_name, PFN_xrVoidFunction *p_addr);
String get_error_string(XrResult result) const;
String get_swapchain_format_name(int64_t p_swapchain_format) const;
void set_object_name(XrObjectType p_object_type, uint64_t p_object_handle, const String &p_object_name);
void begin_debug_label_region(const String &p_label_name);
void end_debug_label_region();
void insert_debug_label(const String &p_label_name);
OpenXRInterface *get_xr_interface() const { return xr_interface; }
void set_xr_interface(OpenXRInterface *p_xr_interface);
@ -430,10 +453,12 @@ public:
static const Vector<OpenXRExtensionWrapper *> &get_registered_extension_wrappers();
static void register_extension_metadata();
static void cleanup_extension_wrappers();
static PackedStringArray get_all_requested_extensions();
void set_form_factor(XrFormFactor p_form_factor);
XrFormFactor get_form_factor() const { return form_factor; }
uint32_t get_view_count();
void set_view_configuration(XrViewConfigurationType p_view_configuration);
XrViewConfigurationType get_view_configuration() const { return view_configuration; }
@ -471,6 +496,13 @@ public:
XrSwapchain get_color_swapchain();
RID get_color_texture();
RID get_depth_texture();
void set_velocity_texture(RID p_render_target);
RID get_velocity_texture();
void set_velocity_depth_texture(RID p_render_target);
RID get_velocity_depth_texture();
void set_velocity_target_size(const Size2i &p_target_size);
Size2i get_velocity_target_size();
const XrCompositionLayerProjection *get_projection_layer() const;
void post_draw_viewport(RID p_render_target);
void end_frame();
@ -483,6 +515,9 @@ public:
double get_render_target_size_multiplier() const;
void set_render_target_size_multiplier(double multiplier);
Rect2i get_render_region() const;
void set_render_region(const Rect2i &p_render_region);
// Foveation settings
bool is_foveation_supported() const;
@ -496,9 +531,13 @@ public:
Size2 get_play_space_bounds() const;
// swapchains
PackedInt64Array get_supported_swapchain_formats();
int64_t get_color_swapchain_format() const { return color_swapchain_format; }
int64_t get_depth_swapchain_format() const { return depth_swapchain_format; }
double get_render_state_z_near() const { return render_state.z_near; }
double get_render_state_z_far() const { return render_state.z_far; }
// action map
String get_default_action_map_resource_name();
@ -509,22 +548,26 @@ public:
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<RID> &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<RID> &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<RID> p_active_sets);
bool get_action_bool(RID p_action, RID p_tracker);
@ -536,7 +579,10 @@ public:
void register_composition_layer_provider(OpenXRCompositionLayerProvider *provider);
void unregister_composition_layer_provider(OpenXRCompositionLayerProvider *provider);
const XrEnvironmentBlendMode *get_supported_environment_blend_modes(uint32_t &count);
void register_projection_views_extension(OpenXRExtensionWrapper *p_extension);
void unregister_projection_views_extension(OpenXRExtensionWrapper *p_extension);
const Vector<XrEnvironmentBlendMode> get_supported_environment_blend_modes();
bool is_environment_blend_mode_supported(XrEnvironmentBlendMode p_blend_mode) const;
bool set_environment_blend_mode(XrEnvironmentBlendMode p_blend_mode);
XrEnvironmentBlendMode get_environment_blend_mode() const { return requested_environment_blend_mode; }

View file

@ -43,6 +43,10 @@ void OpenXRAPIExtension::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_instance_proc_addr", "name"), &OpenXRAPIExtension::get_instance_proc_addr);
ClassDB::bind_method(D_METHOD("get_error_string", "result"), &OpenXRAPIExtension::get_error_string);
ClassDB::bind_method(D_METHOD("get_swapchain_format_name", "swapchain_format"), &OpenXRAPIExtension::get_swapchain_format_name);
ClassDB::bind_method(D_METHOD("set_object_name", "object_type", "object_handle", "object_name"), &OpenXRAPIExtension::set_object_name);
ClassDB::bind_method(D_METHOD("begin_debug_label_region", "label_name"), &OpenXRAPIExtension::begin_debug_label_region);
ClassDB::bind_method(D_METHOD("end_debug_label_region"), &OpenXRAPIExtension::end_debug_label_region);
ClassDB::bind_method(D_METHOD("insert_debug_label", "label_name"), &OpenXRAPIExtension::insert_debug_label);
ClassDB::bind_method(D_METHOD("is_initialized"), &OpenXRAPIExtension::is_initialized);
ClassDB::bind_method(D_METHOD("is_running"), &OpenXRAPIExtension::is_running);
@ -52,11 +56,37 @@ void OpenXRAPIExtension::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_next_frame_time"), &OpenXRAPIExtension::get_next_frame_time);
ClassDB::bind_method(D_METHOD("can_render"), &OpenXRAPIExtension::can_render);
ClassDB::bind_method(D_METHOD("find_action", "name", "action_set"), &OpenXRAPIExtension::find_action);
ClassDB::bind_method(D_METHOD("action_get_handle", "action"), &OpenXRAPIExtension::action_get_handle);
ClassDB::bind_method(D_METHOD("get_hand_tracker", "hand_index"), &OpenXRAPIExtension::get_hand_tracker);
ClassDB::bind_method(D_METHOD("register_composition_layer_provider", "extension"), &OpenXRAPIExtension::register_composition_layer_provider);
ClassDB::bind_method(D_METHOD("unregister_composition_layer_provider", "extension"), &OpenXRAPIExtension::unregister_composition_layer_provider);
ClassDB::bind_method(D_METHOD("register_projection_views_extension", "extension"), &OpenXRAPIExtension::register_projection_views_extension);
ClassDB::bind_method(D_METHOD("unregister_projection_views_extension", "extension"), &OpenXRAPIExtension::unregister_projection_views_extension);
ClassDB::bind_method(D_METHOD("get_render_state_z_near"), &OpenXRAPIExtension::get_render_state_z_near);
ClassDB::bind_method(D_METHOD("get_render_state_z_far"), &OpenXRAPIExtension::get_render_state_z_far);
ClassDB::bind_method(D_METHOD("set_velocity_texture", "render_target"), &OpenXRAPIExtension::set_velocity_texture);
ClassDB::bind_method(D_METHOD("set_velocity_depth_texture", "render_target"), &OpenXRAPIExtension::set_velocity_depth_texture);
ClassDB::bind_method(D_METHOD("set_velocity_target_size", "target_size"), &OpenXRAPIExtension::set_velocity_target_size);
ClassDB::bind_method(D_METHOD("get_supported_swapchain_formats"), &OpenXRAPIExtension::get_supported_swapchain_formats);
ClassDB::bind_method(D_METHOD("openxr_swapchain_create", "create_flags", "usage_flags", "swapchain_format", "width", "height", "sample_count", "array_size"), &OpenXRAPIExtension::openxr_swapchain_create);
ClassDB::bind_method(D_METHOD("openxr_swapchain_free", "swapchain"), &OpenXRAPIExtension::openxr_swapchain_free);
ClassDB::bind_method(D_METHOD("openxr_swapchain_get_swapchain", "swapchain"), &OpenXRAPIExtension::openxr_swapchain_get_swapchain);
ClassDB::bind_method(D_METHOD("openxr_swapchain_acquire", "swapchain"), &OpenXRAPIExtension::openxr_swapchain_acquire);
ClassDB::bind_method(D_METHOD("openxr_swapchain_get_image", "swapchain"), &OpenXRAPIExtension::openxr_swapchain_get_image);
ClassDB::bind_method(D_METHOD("openxr_swapchain_release", "swapchain"), &OpenXRAPIExtension::openxr_swapchain_release);
ClassDB::bind_method(D_METHOD("get_projection_layer"), &OpenXRAPIExtension::get_projection_layer);
ClassDB::bind_method(D_METHOD("set_render_region", "render_region"), &OpenXRAPIExtension::set_render_region);
ClassDB::bind_method(D_METHOD("set_emulate_environment_blend_mode_alpha_blend", "enabled"), &OpenXRAPIExtension::set_emulate_environment_blend_mode_alpha_blend);
ClassDB::bind_method(D_METHOD("is_environment_blend_mode_alpha_supported"), &OpenXRAPIExtension::is_environment_blend_mode_alpha_blend_supported);
@ -116,6 +146,30 @@ String OpenXRAPIExtension::get_swapchain_format_name(int64_t p_swapchain_format)
return OpenXRAPI::get_singleton()->get_swapchain_format_name(p_swapchain_format);
}
void OpenXRAPIExtension::set_object_name(int64_t p_object_type, uint64_t p_object_handle, const String &p_object_name) {
ERR_FAIL_NULL(OpenXRAPI::get_singleton());
OpenXRAPI::get_singleton()->set_object_name(XrObjectType(p_object_type), p_object_handle, p_object_name);
}
void OpenXRAPIExtension::begin_debug_label_region(const String &p_label_name) {
ERR_FAIL_NULL(OpenXRAPI::get_singleton());
OpenXRAPI::get_singleton()->begin_debug_label_region(p_label_name);
}
void OpenXRAPIExtension::end_debug_label_region() {
ERR_FAIL_NULL(OpenXRAPI::get_singleton());
OpenXRAPI::get_singleton()->end_debug_label_region();
}
void OpenXRAPIExtension::insert_debug_label(const String &p_label_name) {
ERR_FAIL_NULL(OpenXRAPI::get_singleton());
OpenXRAPI::get_singleton()->insert_debug_label(p_label_name);
}
bool OpenXRAPIExtension::is_initialized() {
ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), false);
return OpenXRAPI::get_singleton()->is_initialized();
@ -150,6 +204,17 @@ bool OpenXRAPIExtension::can_render() {
return OpenXRAPI::get_singleton()->can_render();
}
RID OpenXRAPIExtension::find_action(const String &p_name, const RID &p_action_set) {
ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), RID());
return OpenXRAPI::get_singleton()->find_action(p_name, p_action_set);
}
uint64_t OpenXRAPIExtension::action_get_handle(RID p_action) {
ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), 0);
XrAction action_handle = OpenXRAPI::get_singleton()->action_get_handle(p_action);
return (uint64_t)action_handle;
}
uint64_t OpenXRAPIExtension::get_hand_tracker(int p_hand_index) {
ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), 0);
return (uint64_t)OpenXRAPI::get_singleton()->get_hand_tracker(p_hand_index);
@ -165,6 +230,104 @@ void OpenXRAPIExtension::unregister_composition_layer_provider(OpenXRExtensionWr
OpenXRAPI::get_singleton()->unregister_composition_layer_provider(p_extension);
}
void OpenXRAPIExtension::register_projection_views_extension(OpenXRExtensionWrapperExtension *p_extension) {
ERR_FAIL_NULL(OpenXRAPI::get_singleton());
OpenXRAPI::get_singleton()->register_projection_views_extension(p_extension);
}
void OpenXRAPIExtension::unregister_projection_views_extension(OpenXRExtensionWrapperExtension *p_extension) {
ERR_FAIL_NULL(OpenXRAPI::get_singleton());
OpenXRAPI::get_singleton()->unregister_projection_views_extension(p_extension);
}
double OpenXRAPIExtension::get_render_state_z_near() {
ERR_NOT_ON_RENDER_THREAD_V(0.0);
ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), 0.0);
return OpenXRAPI::get_singleton()->get_render_state_z_near();
}
double OpenXRAPIExtension::get_render_state_z_far() {
ERR_NOT_ON_RENDER_THREAD_V(0.0);
ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), 0.0);
return OpenXRAPI::get_singleton()->get_render_state_z_far();
}
void OpenXRAPIExtension::set_velocity_texture(RID p_render_target) {
ERR_FAIL_NULL(OpenXRAPI::get_singleton());
OpenXRAPI::get_singleton()->set_velocity_texture(p_render_target);
}
void OpenXRAPIExtension::set_velocity_depth_texture(RID p_render_target) {
ERR_FAIL_NULL(OpenXRAPI::get_singleton());
OpenXRAPI::get_singleton()->set_velocity_depth_texture(p_render_target);
}
void OpenXRAPIExtension::set_velocity_target_size(const Size2i &p_target_size) {
ERR_FAIL_NULL(OpenXRAPI::get_singleton());
OpenXRAPI::get_singleton()->set_velocity_target_size(p_target_size);
}
PackedInt64Array OpenXRAPIExtension::get_supported_swapchain_formats() {
ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), PackedInt64Array());
return OpenXRAPI::get_singleton()->get_supported_swapchain_formats();
}
uint64_t OpenXRAPIExtension::openxr_swapchain_create(XrSwapchainCreateFlags p_create_flags, XrSwapchainUsageFlags p_usage_flags, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size) {
ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), 0);
OpenXRAPI::OpenXRSwapChainInfo *new_swapchain_info = memnew(OpenXRAPI::OpenXRSwapChainInfo);
new_swapchain_info->create(p_create_flags, p_usage_flags, p_swapchain_format, p_width, p_height, p_sample_count, p_array_size);
return reinterpret_cast<uint64_t>(new_swapchain_info);
}
void OpenXRAPIExtension::openxr_swapchain_free(uint64_t p_swapchain_info) {
ERR_FAIL_NULL(OpenXRAPI::get_singleton());
OpenXRAPI::OpenXRSwapChainInfo *swapchain_info = reinterpret_cast<OpenXRAPI::OpenXRSwapChainInfo *>(p_swapchain_info);
swapchain_info->free();
memfree(swapchain_info);
}
uint64_t OpenXRAPIExtension::openxr_swapchain_get_swapchain(uint64_t p_swapchain_info) {
ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), 0);
OpenXRAPI::OpenXRSwapChainInfo *swapchain_info = reinterpret_cast<OpenXRAPI::OpenXRSwapChainInfo *>(p_swapchain_info);
XrSwapchain swapchain = swapchain_info->get_swapchain();
return (uint64_t)swapchain;
}
void OpenXRAPIExtension::openxr_swapchain_acquire(uint64_t p_swapchain_info) {
ERR_FAIL_NULL(OpenXRAPI::get_singleton());
OpenXRAPI::OpenXRSwapChainInfo *swapchain_info = reinterpret_cast<OpenXRAPI::OpenXRSwapChainInfo *>(p_swapchain_info);
bool should_render = true; // Can ignore should_render.
swapchain_info->acquire(should_render);
}
RID OpenXRAPIExtension::openxr_swapchain_get_image(uint64_t p_swapchain_info) {
ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), RID());
OpenXRAPI::OpenXRSwapChainInfo *swapchain_info = reinterpret_cast<OpenXRAPI::OpenXRSwapChainInfo *>(p_swapchain_info);
return swapchain_info->get_image();
}
void OpenXRAPIExtension::openxr_swapchain_release(uint64_t p_swapchain_info) {
ERR_FAIL_NULL(OpenXRAPI::get_singleton());
OpenXRAPI::OpenXRSwapChainInfo *swapchain_info = reinterpret_cast<OpenXRAPI::OpenXRSwapChainInfo *>(p_swapchain_info);
swapchain_info->release();
}
uint64_t OpenXRAPIExtension::get_projection_layer() {
ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), 0);
return (uint64_t)OpenXRAPI::get_singleton()->get_projection_layer();
}
void OpenXRAPIExtension::set_render_region(const Rect2i &p_render_region) {
ERR_FAIL_NULL(OpenXRAPI::get_singleton());
OpenXRAPI::get_singleton()->set_render_region(p_render_region);
}
void OpenXRAPIExtension::set_emulate_environment_blend_mode_alpha_blend(bool p_enabled) {
ERR_FAIL_NULL(OpenXRAPI::get_singleton());
OpenXRAPI::get_singleton()->set_emulate_environment_blend_mode_alpha_blend(p_enabled);

View file

@ -34,7 +34,6 @@
#include "openxr_api.h"
#include "core/object/ref_counted.h"
#include "core/os/os.h"
#include "core/os/thread_safe.h"
#include "core/variant/native_ptr.h"
@ -64,6 +63,10 @@ public:
uint64_t get_instance_proc_addr(String p_name);
String get_error_string(uint64_t result);
String get_swapchain_format_name(int64_t p_swapchain_format);
void set_object_name(int64_t p_object_type, uint64_t p_object_handle, const String &p_object_name);
void begin_debug_label_region(const String &p_label_name);
void end_debug_label_region();
void insert_debug_label(const String &p_label_name);
bool is_initialized();
bool is_running();
@ -73,11 +76,37 @@ public:
int64_t get_next_frame_time();
bool can_render();
RID find_action(const String &p_name, const RID &p_action_set = RID());
uint64_t action_get_handle(RID p_action);
uint64_t get_hand_tracker(int p_hand_index);
void register_composition_layer_provider(OpenXRExtensionWrapperExtension *p_extension);
void unregister_composition_layer_provider(OpenXRExtensionWrapperExtension *p_extension);
void register_projection_views_extension(OpenXRExtensionWrapperExtension *p_extension);
void unregister_projection_views_extension(OpenXRExtensionWrapperExtension *p_extension);
double get_render_state_z_near();
double get_render_state_z_far();
void set_velocity_texture(RID p_render_target);
void set_velocity_depth_texture(RID p_render_target);
void set_velocity_target_size(const Size2i &p_target_size);
PackedInt64Array get_supported_swapchain_formats();
uint64_t openxr_swapchain_create(XrSwapchainCreateFlags p_create_flags, XrSwapchainUsageFlags p_usage_flags, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size);
void openxr_swapchain_free(uint64_t p_swapchain_info);
uint64_t openxr_swapchain_get_swapchain(uint64_t p_swapchain_info);
void openxr_swapchain_acquire(uint64_t p_swapchain_info);
RID openxr_swapchain_get_image(uint64_t p_swapchain_info);
void openxr_swapchain_release(uint64_t p_swapchain_info);
uint64_t get_projection_layer();
void set_render_region(const Rect2i &p_render_region);
enum OpenXRAlphaBlendModeSupport {
OPENXR_ALPHA_BLEND_MODE_SUPPORT_NONE = 0,
OPENXR_ALPHA_BLEND_MODE_SUPPORT_REAL = 1,

View file

@ -32,11 +32,12 @@
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#include "servers/rendering/rendering_server_globals.h"
#include "extensions/openxr_eye_gaze_interaction.h"
#include "extensions/openxr_hand_interaction_extension.h"
#include "thirdparty/openxr/include/openxr/openxr.h"
#include "servers/rendering/renderer_compositor.h"
#include <openxr/openxr.h>
void OpenXRInterface::_bind_methods() {
// lifecycle signals
@ -159,11 +160,11 @@ void OpenXRInterface::_bind_methods() {
StringName OpenXRInterface::get_name() const {
return StringName("OpenXR");
};
}
uint32_t OpenXRInterface::get_capabilities() const {
return XRInterface::XR_VR + XRInterface::XR_STEREO;
};
}
PackedStringArray OpenXRInterface::get_suggested_tracker_names() const {
// These are hardcoded in OpenXR, note that they will only be available if added to our action map
@ -286,6 +287,13 @@ void OpenXRInterface::_load_action_map() {
if (ip.is_valid()) {
openxr_api->interaction_profile_clear_bindings(ip);
for (Ref<OpenXRBindingModifier> 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<OpenXRIPBinding> xr_binding = xr_bindings[j];
@ -299,9 +307,17 @@ void OpenXRInterface::_load_action_map() {
continue;
}
PackedStringArray paths = xr_binding->get_paths();
for (int k = 0; k < paths.size(); k++) {
openxr_api->interaction_profile_add_binding(ip, action->action_rid, paths[k]);
int binding_no = openxr_api->interaction_profile_add_binding(ip, action->action_rid, xr_binding->get_binding_path());
if (binding_no >= 0) {
for (Ref<OpenXRBindingModifier> 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.
}
}
}
@ -595,8 +611,8 @@ void OpenXRInterface::free_trackers() {
void OpenXRInterface::free_interaction_profiles() {
ERR_FAIL_NULL(openxr_api);
for (int i = 0; i < interaction_profiles.size(); i++) {
openxr_api->interaction_profile_free(interaction_profiles[i]);
for (const RID &interaction_profile : interaction_profiles) {
openxr_api->interaction_profile_free(interaction_profile);
}
interaction_profiles.clear();
}
@ -613,7 +629,7 @@ bool OpenXRInterface::initialize_on_startup() const {
bool OpenXRInterface::is_initialized() const {
return initialized;
};
}
bool OpenXRInterface::initialize() {
XRServer *xr_server = XRServer::get_singleton();
@ -1039,6 +1055,14 @@ Projection OpenXRInterface::get_projection_for_view(uint32_t p_view, double p_as
return cm;
}
Rect2i OpenXRInterface::get_render_region() {
if (openxr_api) {
return openxr_api->get_render_region();
} else {
return Rect2i();
}
}
RID OpenXRInterface::get_color_texture() {
if (openxr_api) {
return openxr_api->get_color_texture();
@ -1055,6 +1079,30 @@ RID OpenXRInterface::get_depth_texture() {
}
}
RID OpenXRInterface::get_velocity_texture() {
if (openxr_api) {
return openxr_api->get_velocity_texture();
} else {
return RID();
}
}
RID OpenXRInterface::get_velocity_depth_texture() {
if (openxr_api) {
return openxr_api->get_velocity_depth_texture();
} else {
return RID();
}
}
Size2i OpenXRInterface::get_velocity_target_size() {
if (openxr_api) {
return openxr_api->get_velocity_target_size();
} else {
return Size2i();
}
}
void OpenXRInterface::handle_hand_tracking(const String &p_path, OpenXRHandTrackingExtension::HandTrackedHands p_hand) {
OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
if (hand_tracking_ext && hand_tracking_ext->get_active()) {
@ -1136,6 +1184,12 @@ void OpenXRInterface::process() {
if (head.is_valid()) {
head->set_pose("default", head_transform, head_linear_velocity, head_angular_velocity, head_confidence);
}
if (reference_stage_changing) {
// Now that we have updated tracking information in our updated reference space, trigger our pose recentered signal.
emit_signal(SNAME("pose_recentered"));
reference_stage_changing = false;
}
}
void OpenXRInterface::pre_render() {
@ -1220,15 +1274,10 @@ Array OpenXRInterface::get_supported_environment_blend_modes() {
return modes;
}
uint32_t count = 0;
const XrEnvironmentBlendMode *env_blend_modes = openxr_api->get_supported_environment_blend_modes(count);
const Vector<XrEnvironmentBlendMode> env_blend_modes = openxr_api->get_supported_environment_blend_modes();
if (!env_blend_modes) {
return modes;
}
for (uint32_t i = 0; i < count; i++) {
switch (env_blend_modes[i]) {
for (const XrEnvironmentBlendMode &env_blend_mode : env_blend_modes) {
switch (env_blend_mode) {
case XR_ENVIRONMENT_BLEND_MODE_OPAQUE:
modes.push_back(XR_ENV_BLEND_MODE_OPAQUE);
break;
@ -1239,7 +1288,7 @@ Array OpenXRInterface::get_supported_environment_blend_modes() {
modes.push_back(XR_ENV_BLEND_MODE_ALPHA_BLEND);
break;
default:
WARN_PRINT("Unsupported blend mode found: " + String::num_int64(int64_t(env_blend_modes[i])));
WARN_PRINT(vformat("Unsupported blend mode found: %s.", String::num_int64(int64_t(env_blend_mode))));
}
}
@ -1317,8 +1366,8 @@ void OpenXRInterface::on_state_exiting() {
emit_signal(SNAME("instance_exiting"));
}
void OpenXRInterface::on_pose_recentered() {
emit_signal(SNAME("pose_recentered"));
void OpenXRInterface::on_reference_space_change_pending() {
reference_stage_changing = true;
}
void OpenXRInterface::on_refresh_rate_changes(float p_new_rate) {
@ -1482,6 +1531,8 @@ RID OpenXRInterface::get_vrs_texture() {
eye_foci.push_back(openxr_api->get_eye_focus(v, aspect_ratio));
}
xr_vrs.set_vrs_render_region(get_render_region());
return xr_vrs.make_vrs_texture(target_size, eye_foci);
}

View file

@ -70,6 +70,7 @@ class OpenXRInterface : public XRInterface {
private:
OpenXRAPI *openxr_api = nullptr;
bool initialized = false;
bool reference_stage_changing = false;
XRInterface::TrackingStatus tracking_state;
// At a minimum we need a tracker for our head
@ -182,8 +183,13 @@ public:
virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) override;
virtual Projection get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) override;
virtual Rect2i get_render_region() override;
virtual RID get_color_texture() override;
virtual RID get_depth_texture() override;
virtual RID get_velocity_texture() override;
virtual RID get_velocity_depth_texture() override;
virtual Size2i get_velocity_target_size() override;
virtual void process() override;
virtual void pre_render() override;
@ -207,7 +213,7 @@ public:
void on_state_stopping();
void on_state_loss_pending();
void on_state_exiting();
void on_pose_recentered();
void on_reference_space_change_pending();
void on_refresh_rate_changes(float p_new_rate);
void tracker_profile_changed(RID p_tracker, RID p_interaction_profile);

View file

@ -39,6 +39,11 @@
#include "drivers/vulkan/rendering_context_driver_vulkan.h"
#endif // VULKAN_ENABLED
#ifdef METAL_ENABLED
#define XR_USE_GRAPHICS_API_METAL
#include "drivers/metal/rendering_context_driver_metal.h"
#endif // METAL_ENABLED
#if defined(GLES3_ENABLED) && !defined(MACOS_ENABLED)
#ifdef ANDROID_ENABLED
#define XR_USE_GRAPHICS_API_OPENGL_ES
@ -49,6 +54,13 @@
#else
#define XR_USE_GRAPHICS_API_OPENGL
#endif // ANDROID_ENABLED
#if defined(LINUXBSD_ENABLED) && defined(EGL_ENABLED)
#ifdef GLAD_ENABLED
#include "thirdparty/glad/glad/egl.h"
#else
#include <EGL/egl.h>
#endif // GLAD_ENABLED
#endif // defined(LINUXBSD_ENABLED) && defined(EGL_ENABLED)
#ifdef X11_ENABLED
#define GL_GLEXT_PROTOTYPES 1
#define GL3_PROTOTYPES 1

View file

@ -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"
@ -44,9 +45,12 @@
#include "scene/openxr_composition_layer_equirect.h"
#include "scene/openxr_composition_layer_quad.h"
#include "scene/openxr_hand.h"
#include "scene/openxr_visibility_mask.h"
#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"
@ -57,8 +61,11 @@
#include "extensions/openxr_local_floor_extension.h"
#include "extensions/openxr_meta_controller_extension.h"
#include "extensions/openxr_ml2_controller_extension.h"
#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"
#ifdef TOOLS_ENABLED
@ -74,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;
@ -126,11 +137,24 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) {
OpenXRAPI::register_extension_wrapper(memnew(OpenXRMetaControllerExtension));
OpenXRAPI::register_extension_wrapper(memnew(OpenXREyeGazeInteractionExtension));
OpenXRAPI::register_extension_wrapper(memnew(OpenXRHandInteractionExtension));
OpenXRAPI::register_extension_wrapper(memnew(OpenXRMxInkExtension));
OpenXRAPI::register_extension_wrapper(memnew(OpenXRVisibilityMaskExtension));
// register gated extensions
if (int(GLOBAL_GET("xr/openxr/extensions/debug_utils")) > 0) {
OpenXRAPI::register_extension_wrapper(memnew(OpenXRDebugUtilsExtension));
}
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()) {
@ -172,6 +196,15 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) {
GDREGISTER_CLASS(OpenXRIPBinding);
GDREGISTER_CLASS(OpenXRInteractionProfile);
GDREGISTER_ABSTRACT_CLASS(OpenXRBindingModifier);
GDREGISTER_VIRTUAL_CLASS(OpenXRIPBindingModifier);
GDREGISTER_VIRTUAL_CLASS(OpenXRActionBindingModifier);
GDREGISTER_CLASS(OpenXRAnalogThresholdModifier);
GDREGISTER_CLASS(OpenXRDpadBindingModifier);
GDREGISTER_ABSTRACT_CLASS(OpenXRHapticBase);
GDREGISTER_CLASS(OpenXRHapticVibration);
GDREGISTER_ABSTRACT_CLASS(OpenXRCompositionLayer);
GDREGISTER_CLASS(OpenXRCompositionLayerEquirect);
GDREGISTER_CLASS(OpenXRCompositionLayerCylinder);
@ -179,6 +212,8 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) {
GDREGISTER_CLASS(OpenXRHand);
GDREGISTER_CLASS(OpenXRVisibilityMask);
XRServer *xr_server = XRServer::get_singleton();
if (xr_server) {
openxr_interface.instantiate();
@ -190,6 +225,10 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) {
}
#ifdef TOOLS_ENABLED
GDREGISTER_ABSTRACT_CLASS(OpenXRInteractionProfileEditorBase);
GDREGISTER_CLASS(OpenXRInteractionProfileEditor);
GDREGISTER_CLASS(OpenXRBindingModifierEditor);
EditorNode::add_init_callback(_editor_init);
#endif
}

View file

@ -1,4 +1,5 @@
#!/usr/bin/env python
from misc.utility.scons_hints import *
Import("env")
Import("env_openxr")

View file

@ -38,6 +38,8 @@
#include "scene/3d/xr_nodes.h"
#include "scene/main/viewport.h"
#include "platform/android/api/java_class_wrapper.h"
Vector<OpenXRCompositionLayer *> OpenXRCompositionLayer::composition_layer_nodes;
static const char *HOLE_PUNCH_SHADER_CODE =
@ -47,10 +49,17 @@ static const char *HOLE_PUNCH_SHADER_CODE =
"\tALBEDO = vec3(0.0, 0.0, 0.0);\n"
"}\n";
OpenXRCompositionLayer::OpenXRCompositionLayer() {
OpenXRCompositionLayer::OpenXRCompositionLayer(XrCompositionLayerBaseHeader *p_composition_layer) {
composition_layer_base_header = p_composition_layer;
openxr_layer_provider = memnew(OpenXRViewportCompositionLayerProvider(composition_layer_base_header));
openxr_api = OpenXRAPI::get_singleton();
composition_layer_extension = OpenXRCompositionLayerExtension::get_singleton();
if (openxr_api) {
openxr_session_running = openxr_api->is_running();
}
Ref<OpenXRInterface> openxr_interface = XRServer::get_singleton()->find_interface("OpenXR");
if (openxr_interface.is_valid()) {
openxr_interface->connect("session_begun", callable_mp(this, &OpenXRCompositionLayer::_on_openxr_session_begun));
@ -76,6 +85,7 @@ OpenXRCompositionLayer::~OpenXRCompositionLayer() {
composition_layer_nodes.erase(this);
if (openxr_layer_provider != nullptr) {
_clear_composition_layer_provider();
memdelete(openxr_layer_provider);
openxr_layer_provider = nullptr;
}
@ -85,6 +95,12 @@ void OpenXRCompositionLayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_layer_viewport", "viewport"), &OpenXRCompositionLayer::set_layer_viewport);
ClassDB::bind_method(D_METHOD("get_layer_viewport"), &OpenXRCompositionLayer::get_layer_viewport);
ClassDB::bind_method(D_METHOD("set_use_android_surface", "enable"), &OpenXRCompositionLayer::set_use_android_surface);
ClassDB::bind_method(D_METHOD("get_use_android_surface"), &OpenXRCompositionLayer::get_use_android_surface);
ClassDB::bind_method(D_METHOD("set_android_surface_size", "size"), &OpenXRCompositionLayer::set_android_surface_size);
ClassDB::bind_method(D_METHOD("get_android_surface_size"), &OpenXRCompositionLayer::get_android_surface_size);
ClassDB::bind_method(D_METHOD("set_enable_hole_punch", "enable"), &OpenXRCompositionLayer::set_enable_hole_punch);
ClassDB::bind_method(D_METHOD("get_enable_hole_punch"), &OpenXRCompositionLayer::get_enable_hole_punch);
@ -94,11 +110,14 @@ void OpenXRCompositionLayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_alpha_blend", "enabled"), &OpenXRCompositionLayer::set_alpha_blend);
ClassDB::bind_method(D_METHOD("get_alpha_blend"), &OpenXRCompositionLayer::get_alpha_blend);
ClassDB::bind_method(D_METHOD("get_android_surface"), &OpenXRCompositionLayer::get_android_surface);
ClassDB::bind_method(D_METHOD("is_natively_supported"), &OpenXRCompositionLayer::is_natively_supported);
ClassDB::bind_method(D_METHOD("intersects_ray", "origin", "direction"), &OpenXRCompositionLayer::intersects_ray);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "layer_viewport", PROPERTY_HINT_NODE_TYPE, "SubViewport"), "set_layer_viewport", "get_layer_viewport");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_android_surface", PROPERTY_HINT_NONE, ""), "set_use_android_surface", "get_use_android_surface");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "android_surface_size", PROPERTY_HINT_NONE, ""), "set_android_surface_size", "get_android_surface_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "sort_order", PROPERTY_HINT_NONE, ""), "set_sort_order", "get_sort_order");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "alpha_blend", PROPERTY_HINT_NONE, ""), "set_alpha_blend", "get_alpha_blend");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enable_hole_punch", PROPERTY_HINT_NONE, ""), "set_enable_hole_punch", "get_enable_hole_punch");
@ -108,7 +127,7 @@ bool OpenXRCompositionLayer::_should_use_fallback_node() {
if (Engine::get_singleton()->is_editor_hint()) {
return true;
} else if (openxr_session_running) {
return enable_hole_punch || !is_natively_supported();
return enable_hole_punch || (!is_natively_supported() && !use_android_surface);
}
return false;
}
@ -128,10 +147,36 @@ void OpenXRCompositionLayer::_remove_fallback_node() {
fallback = nullptr;
}
void OpenXRCompositionLayer::_setup_composition_layer_provider() {
if (use_android_surface || layer_viewport) {
if (composition_layer_extension) {
composition_layer_extension->register_viewport_composition_layer_provider(openxr_layer_provider);
}
// NOTE: We don't setup/clear when using Android surfaces, so we don't destroy the surface unexpectedly.
if (layer_viewport) {
// Set our properties on the layer provider, which will create all the necessary resources (ex swap chains).
openxr_layer_provider->set_viewport(layer_viewport->get_viewport_rid(), layer_viewport->get_size());
}
}
}
void OpenXRCompositionLayer::_clear_composition_layer_provider() {
if (composition_layer_extension) {
composition_layer_extension->unregister_viewport_composition_layer_provider(openxr_layer_provider);
}
// NOTE: We don't setup/clear when using Android surfaces, so we don't destroy the surface unexpectedly.
if (!use_android_surface) {
// This will reset the viewport and free all the resources (ex swap chains) used by the layer.
openxr_layer_provider->set_viewport(RID(), Size2i());
}
}
void OpenXRCompositionLayer::_on_openxr_session_begun() {
openxr_session_running = true;
if (layer_viewport && is_natively_supported() && is_visible() && is_inside_tree()) {
openxr_layer_provider->set_viewport(layer_viewport->get_viewport_rid(), layer_viewport->get_size());
if (is_natively_supported() && is_visible() && is_inside_tree()) {
_setup_composition_layer_provider();
}
if (!fallback && _should_use_fallback_node()) {
_create_fallback_node();
@ -142,9 +187,8 @@ void OpenXRCompositionLayer::_on_openxr_session_stopping() {
openxr_session_running = false;
if (fallback && !_should_use_fallback_node()) {
_remove_fallback_node();
} else {
openxr_layer_provider->set_viewport(RID(), Size2i());
}
_clear_composition_layer_provider();
}
void OpenXRCompositionLayer::update_fallback_mesh() {
@ -162,6 +206,7 @@ XrPosef OpenXRCompositionLayer::get_openxr_pose() {
}
bool OpenXRCompositionLayer::is_viewport_in_use(SubViewport *p_viewport) {
ERR_FAIL_NULL_V(p_viewport, false);
for (const OpenXRCompositionLayer *other_composition_layer : composition_layer_nodes) {
if (other_composition_layer != this && other_composition_layer->is_inside_tree() && other_composition_layer->get_layer_viewport() == p_viewport) {
return true;
@ -178,6 +223,9 @@ void OpenXRCompositionLayer::set_layer_viewport(SubViewport *p_viewport) {
if (p_viewport != nullptr) {
ERR_FAIL_COND_EDMSG(is_viewport_in_use(p_viewport), RTR("Cannot use the same SubViewport with multiple OpenXR composition layers. Clear it from its current layer first."));
}
if (use_android_surface) {
ERR_FAIL_COND_MSG(p_viewport != nullptr, RTR("Cannot set SubViewport on an OpenXR composition layer when using an Android surface."));
}
layer_viewport = p_viewport;
@ -200,6 +248,41 @@ void OpenXRCompositionLayer::set_layer_viewport(SubViewport *p_viewport) {
}
}
void OpenXRCompositionLayer::set_use_android_surface(bool p_use_android_surface) {
if (use_android_surface == p_use_android_surface) {
return;
}
use_android_surface = p_use_android_surface;
if (use_android_surface) {
set_layer_viewport(nullptr);
openxr_layer_provider->set_use_android_surface(true, android_surface_size);
} else {
openxr_layer_provider->set_use_android_surface(false, Size2i());
}
notify_property_list_changed();
}
bool OpenXRCompositionLayer::get_use_android_surface() const {
return use_android_surface;
}
void OpenXRCompositionLayer::set_android_surface_size(Size2i p_size) {
if (android_surface_size == p_size) {
return;
}
android_surface_size = p_size;
if (use_android_surface) {
openxr_layer_provider->set_use_android_surface(true, android_surface_size);
}
}
Size2i OpenXRCompositionLayer::get_android_surface_size() const {
return android_surface_size;
}
SubViewport *OpenXRCompositionLayer::get_layer_viewport() const {
return layer_viewport;
}
@ -228,33 +311,23 @@ bool OpenXRCompositionLayer::get_enable_hole_punch() const {
}
void OpenXRCompositionLayer::set_sort_order(int p_order) {
if (openxr_layer_provider) {
openxr_layer_provider->set_sort_order(p_order);
update_configuration_warnings();
}
openxr_layer_provider->set_sort_order(p_order);
update_configuration_warnings();
}
int OpenXRCompositionLayer::get_sort_order() const {
if (openxr_layer_provider) {
return openxr_layer_provider->get_sort_order();
}
return 1;
return openxr_layer_provider->get_sort_order();
}
void OpenXRCompositionLayer::set_alpha_blend(bool p_alpha_blend) {
if (openxr_layer_provider) {
openxr_layer_provider->set_alpha_blend(p_alpha_blend);
if (fallback) {
_reset_fallback_material();
}
openxr_layer_provider->set_alpha_blend(p_alpha_blend);
if (fallback) {
_reset_fallback_material();
}
}
bool OpenXRCompositionLayer::get_alpha_blend() const {
if (openxr_layer_provider) {
return openxr_layer_provider->get_alpha_blend();
}
return false;
return openxr_layer_provider->get_alpha_blend();
}
bool OpenXRCompositionLayer::is_natively_supported() const {
@ -264,6 +337,10 @@ bool OpenXRCompositionLayer::is_natively_supported() const {
return false;
}
Ref<JavaObject> OpenXRCompositionLayer::get_android_surface() {
return openxr_layer_provider->get_android_surface();
}
Vector2 OpenXRCompositionLayer::intersects_ray(const Vector3 &p_origin, const Vector3 &p_direction) const {
return Vector2(-1.0, -1.0);
}
@ -298,19 +375,7 @@ void OpenXRCompositionLayer::_reset_fallback_material() {
material->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, !enable_hole_punch);
material->set_transparency(get_alpha_blend() ? StandardMaterial3D::TRANSPARENCY_ALPHA : StandardMaterial3D::TRANSPARENCY_DISABLED);
Ref<ViewportTexture> texture = material->get_texture(StandardMaterial3D::TEXTURE_ALBEDO);
if (texture.is_null()) {
texture.instantiate();
// ViewportTexture can't be configured without a local scene, so use this hack to set it.
HashMap<Ref<Resource>, Ref<Resource>> remap_cache;
texture->configure_for_local_scene(this, remap_cache);
}
Node *loc_scene = texture->get_local_scene();
NodePath viewport_path = loc_scene->get_path_to(layer_viewport);
texture->set_viewport_path_in_scene(viewport_path);
material->set_texture(StandardMaterial3D::TEXTURE_ALBEDO, texture);
material->set_texture(StandardMaterial3D::TEXTURE_ALBEDO, layer_viewport->get_texture());
} else {
fallback->set_surface_override_material(0, Ref<Material>());
}
@ -321,12 +386,10 @@ void OpenXRCompositionLayer::_notification(int p_what) {
case NOTIFICATION_POSTINITIALIZE: {
composition_layer_nodes.push_back(this);
if (openxr_layer_provider) {
for (OpenXRExtensionWrapper *extension : OpenXRAPI::get_registered_extension_wrappers()) {
extension_property_values.merge(extension->get_viewport_composition_layer_extension_property_defaults());
}
openxr_layer_provider->set_extension_property_values(extension_property_values);
for (OpenXRExtensionWrapper *extension : OpenXRAPI::get_registered_extension_wrappers()) {
extension_property_values.merge(extension->get_viewport_composition_layer_extension_property_defaults());
}
openxr_layer_provider->set_extension_property_values(extension_property_values);
} break;
case NOTIFICATION_INTERNAL_PROCESS: {
if (fallback) {
@ -338,11 +401,11 @@ void OpenXRCompositionLayer::_notification(int p_what) {
}
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
if (!fallback && openxr_session_running && is_inside_tree()) {
if (layer_viewport && is_visible()) {
openxr_layer_provider->set_viewport(layer_viewport->get_viewport_rid(), layer_viewport->get_size());
if (is_natively_supported() && openxr_session_running && is_inside_tree()) {
if (is_visible()) {
_setup_composition_layer_provider();
} else {
openxr_layer_provider->set_viewport(RID(), Size2i());
_clear_composition_layer_provider();
}
}
update_configuration_warnings();
@ -351,25 +414,15 @@ void OpenXRCompositionLayer::_notification(int p_what) {
update_configuration_warnings();
} break;
case NOTIFICATION_ENTER_TREE: {
if (composition_layer_extension) {
composition_layer_extension->register_viewport_composition_layer_provider(openxr_layer_provider);
}
if (is_viewport_in_use(layer_viewport)) {
set_layer_viewport(nullptr);
} else if (!fallback && layer_viewport && openxr_session_running && is_visible()) {
openxr_layer_provider->set_viewport(layer_viewport->get_viewport_rid(), layer_viewport->get_size());
if (layer_viewport && is_viewport_in_use(layer_viewport)) {
_clear_composition_layer_provider();
} else if (openxr_session_running && is_visible()) {
_setup_composition_layer_provider();
}
} break;
case NOTIFICATION_EXIT_TREE: {
if (composition_layer_extension) {
composition_layer_extension->unregister_viewport_composition_layer_provider(openxr_layer_provider);
}
if (!fallback) {
// This will clean up existing resources.
openxr_layer_provider->set_viewport(RID(), Size2i());
}
// This will clean up existing resources.
_clear_composition_layer_provider();
} break;
}
}
@ -382,7 +435,7 @@ void OpenXRCompositionLayer::_get_property_list(List<PropertyInfo> *p_property_l
for (const PropertyInfo &pinfo : extension_properties) {
StringName prop_name = pinfo.name;
if (!String(prop_name).contains("/")) {
if (!String(prop_name).contains_char('/')) {
WARN_PRINT_ONCE(vformat("Discarding OpenXRCompositionLayer property name '%s' from extension because it doesn't contain a '/'."));
continue;
}
@ -401,13 +454,27 @@ bool OpenXRCompositionLayer::_get(const StringName &p_property, Variant &r_value
bool OpenXRCompositionLayer::_set(const StringName &p_property, const Variant &p_value) {
extension_property_values[p_property] = p_value;
if (openxr_layer_provider) {
openxr_layer_provider->set_extension_property_values(extension_property_values);
}
openxr_layer_provider->set_extension_property_values(extension_property_values);
return true;
}
void OpenXRCompositionLayer::_validate_property(PropertyInfo &p_property) const {
if (p_property.name == "layer_viewport") {
if (use_android_surface) {
p_property.usage &= ~PROPERTY_USAGE_EDITOR;
} else {
p_property.usage |= PROPERTY_USAGE_EDITOR;
}
} else if (p_property.name == "android_surface_size") {
if (use_android_surface) {
p_property.usage |= PROPERTY_USAGE_EDITOR;
} else {
p_property.usage &= ~PROPERTY_USAGE_EDITOR;
}
}
}
PackedStringArray OpenXRCompositionLayer::get_configuration_warnings() const {
PackedStringArray warnings = Node3D::get_configuration_warnings();

View file

@ -35,6 +35,7 @@
#include "scene/3d/node_3d.h"
class JavaObject;
class MeshInstance3D;
class Mesh;
class OpenXRAPI;
@ -45,7 +46,12 @@ class SubViewport;
class OpenXRCompositionLayer : public Node3D {
GDCLASS(OpenXRCompositionLayer, Node3D);
XrCompositionLayerBaseHeader *composition_layer_base_header = nullptr;
OpenXRViewportCompositionLayerProvider *openxr_layer_provider = nullptr;
SubViewport *layer_viewport = nullptr;
bool use_android_surface = false;
Size2i android_surface_size = Size2i(1024, 1024);
bool enable_hole_punch = false;
MeshInstance3D *fallback = nullptr;
bool should_update_fallback_mesh = false;
@ -58,10 +64,12 @@ class OpenXRCompositionLayer : public Node3D {
void _reset_fallback_material();
void _remove_fallback_node();
void _setup_composition_layer_provider();
void _clear_composition_layer_provider();
protected:
OpenXRAPI *openxr_api = nullptr;
OpenXRCompositionLayerExtension *composition_layer_extension = nullptr;
OpenXRViewportCompositionLayerProvider *openxr_layer_provider = nullptr;
static void _bind_methods();
@ -69,6 +77,7 @@ protected:
void _get_property_list(List<PropertyInfo> *p_property_list) const;
bool _get(const StringName &p_property, Variant &r_value) const;
bool _set(const StringName &p_property, const Variant &p_value);
void _validate_property(PropertyInfo &p_property) const;
virtual void _on_openxr_session_begun();
virtual void _on_openxr_session_stopping();
@ -82,10 +91,18 @@ protected:
static Vector<OpenXRCompositionLayer *> composition_layer_nodes;
bool is_viewport_in_use(SubViewport *p_viewport);
OpenXRCompositionLayer(XrCompositionLayerBaseHeader *p_composition_layer);
public:
void set_layer_viewport(SubViewport *p_viewport);
SubViewport *get_layer_viewport() const;
void set_use_android_surface(bool p_use_android_surface);
bool get_use_android_surface() const;
void set_android_surface_size(Size2i p_size);
Size2i get_android_surface_size() const;
void set_enable_hole_punch(bool p_enable);
bool get_enable_hole_punch() const;
@ -95,13 +112,13 @@ public:
void set_alpha_blend(bool p_alpha_blend);
bool get_alpha_blend() const;
Ref<JavaObject> get_android_surface();
bool is_natively_supported() const;
virtual PackedStringArray get_configuration_warnings() const override;
virtual Vector2 intersects_ray(const Vector3 &p_origin, const Vector3 &p_direction) const;
OpenXRCompositionLayer();
~OpenXRCompositionLayer();
};

View file

@ -30,28 +30,12 @@
#include "openxr_composition_layer_cylinder.h"
#include "../extensions/openxr_composition_layer_extension.h"
#include "../openxr_api.h"
#include "../openxr_interface.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/main/viewport.h"
#include "scene/resources/mesh.h"
OpenXRCompositionLayerCylinder::OpenXRCompositionLayerCylinder() {
composition_layer = {
XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR, // type
nullptr, // next
0, // layerFlags
XR_NULL_HANDLE, // space
XR_EYE_VISIBILITY_BOTH, // eyeVisibility
{}, // subImage
{ { 0, 0, 0, 0 }, { 0, 0, 0 } }, // pose
radius, // radius
central_angle, // centralAngle
aspect_ratio, // aspectRatio
};
openxr_layer_provider = memnew(OpenXRViewportCompositionLayerProvider((XrCompositionLayerBaseHeader *)&composition_layer));
OpenXRCompositionLayerCylinder::OpenXRCompositionLayerCylinder() :
OpenXRCompositionLayer((XrCompositionLayerBaseHeader *)&composition_layer) {
XRServer::get_singleton()->connect("reference_frame_changed", callable_mp(this, &OpenXRCompositionLayerCylinder::update_transform));
}

View file

@ -38,7 +38,18 @@
class OpenXRCompositionLayerCylinder : public OpenXRCompositionLayer {
GDCLASS(OpenXRCompositionLayerCylinder, OpenXRCompositionLayer);
XrCompositionLayerCylinderKHR composition_layer;
XrCompositionLayerCylinderKHR composition_layer = {
XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR, // type
nullptr, // next
0, // layerFlags
XR_NULL_HANDLE, // space
XR_EYE_VISIBILITY_BOTH, // eyeVisibility
{}, // subImage
{ { 0, 0, 0, 0 }, { 0, 0, 0 } }, // pose
1.0, // radius
Math_PI / 2.0, // centralAngle
1.0, // aspectRatio
};
float radius = 1.0;
float aspect_ratio = 1.0;

View file

@ -30,29 +30,12 @@
#include "openxr_composition_layer_equirect.h"
#include "../extensions/openxr_composition_layer_extension.h"
#include "../openxr_api.h"
#include "../openxr_interface.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/main/viewport.h"
#include "scene/resources/mesh.h"
OpenXRCompositionLayerEquirect::OpenXRCompositionLayerEquirect() {
composition_layer = {
XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR, // type
nullptr, // next
0, // layerFlags
XR_NULL_HANDLE, // space
XR_EYE_VISIBILITY_BOTH, // eyeVisibility
{}, // subImage
{ { 0, 0, 0, 0 }, { 0, 0, 0 } }, // pose
radius, // radius
central_horizontal_angle, // centralHorizontalAngle
upper_vertical_angle, // upperVerticalAngle
-lower_vertical_angle, // lowerVerticalAngle
};
openxr_layer_provider = memnew(OpenXRViewportCompositionLayerProvider((XrCompositionLayerBaseHeader *)&composition_layer));
OpenXRCompositionLayerEquirect::OpenXRCompositionLayerEquirect() :
OpenXRCompositionLayer((XrCompositionLayerBaseHeader *)&composition_layer) {
XRServer::get_singleton()->connect("reference_frame_changed", callable_mp(this, &OpenXRCompositionLayerEquirect::update_transform));
}

View file

@ -38,7 +38,19 @@
class OpenXRCompositionLayerEquirect : public OpenXRCompositionLayer {
GDCLASS(OpenXRCompositionLayerEquirect, OpenXRCompositionLayer);
XrCompositionLayerEquirect2KHR composition_layer;
XrCompositionLayerEquirect2KHR composition_layer = {
XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR, // type
nullptr, // next
0, // layerFlags
XR_NULL_HANDLE, // space
XR_EYE_VISIBILITY_BOTH, // eyeVisibility
{}, // subImage
{ { 0, 0, 0, 0 }, { 0, 0, 0 } }, // pose
1.0, // radius
Math_PI / 2.0, // centralHorizontalAngle
Math_PI / 4.0, // upperVerticalAngle
-Math_PI / 4.0, // lowerVerticalAngle
};
float radius = 1.0;
float central_horizontal_angle = Math_PI / 2.0;

View file

@ -30,26 +30,12 @@
#include "openxr_composition_layer_quad.h"
#include "../extensions/openxr_composition_layer_extension.h"
#include "../openxr_api.h"
#include "../openxr_interface.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/main/viewport.h"
#include "scene/resources/3d/primitive_meshes.h"
OpenXRCompositionLayerQuad::OpenXRCompositionLayerQuad() {
composition_layer = {
XR_TYPE_COMPOSITION_LAYER_QUAD, // type
nullptr, // next
0, // layerFlags
XR_NULL_HANDLE, // space
XR_EYE_VISIBILITY_BOTH, // eyeVisibility
{}, // subImage
{ { 0, 0, 0, 0 }, { 0, 0, 0 } }, // pose
{ (float)quad_size.x, (float)quad_size.y }, // size
};
openxr_layer_provider = memnew(OpenXRViewportCompositionLayerProvider((XrCompositionLayerBaseHeader *)&composition_layer));
OpenXRCompositionLayerQuad::OpenXRCompositionLayerQuad() :
OpenXRCompositionLayer((XrCompositionLayerBaseHeader *)&composition_layer) {
XRServer::get_singleton()->connect("reference_frame_changed", callable_mp(this, &OpenXRCompositionLayerQuad::update_transform));
}

View file

@ -38,7 +38,16 @@
class OpenXRCompositionLayerQuad : public OpenXRCompositionLayer {
GDCLASS(OpenXRCompositionLayerQuad, OpenXRCompositionLayer);
XrCompositionLayerQuad composition_layer;
XrCompositionLayerQuad composition_layer = {
XR_TYPE_COMPOSITION_LAYER_QUAD, // type
nullptr, // next
0, // layerFlags
XR_NULL_HANDLE, // space
XR_EYE_VISIBILITY_BOTH, // eyeVisibility
{}, // subImage
{ { 0, 0, 0, 0 }, { 0, 0, 0 } }, // pose
{ 1.0, 1.0 }, // size
};
Size2 quad_size = Size2(1.0, 1.0);

View file

@ -0,0 +1,106 @@
/**************************************************************************/
/* openxr_visibility_mask.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_visibility_mask.h"
#include "../extensions/openxr_visibility_mask_extension.h"
#include "../openxr_interface.h"
#include "scene/3d/xr_nodes.h"
void OpenXRVisibilityMask::_bind_methods() {
}
void OpenXRVisibilityMask::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
OpenXRVisibilityMaskExtension *vis_mask_ext = OpenXRVisibilityMaskExtension::get_singleton();
if (vis_mask_ext && vis_mask_ext->is_available()) {
set_base(vis_mask_ext->get_mesh());
}
} break;
case NOTIFICATION_EXIT_TREE: {
set_base(RID());
} break;
}
}
void OpenXRVisibilityMask::_on_openxr_session_begun() {
if (is_inside_tree()) {
OpenXRVisibilityMaskExtension *vis_mask_ext = OpenXRVisibilityMaskExtension::get_singleton();
if (vis_mask_ext && vis_mask_ext->is_available()) {
set_base(vis_mask_ext->get_mesh());
}
}
}
void OpenXRVisibilityMask::_on_openxr_session_stopping() {
set_base(RID());
}
PackedStringArray OpenXRVisibilityMask::get_configuration_warnings() const {
PackedStringArray warnings = VisualInstance3D::get_configuration_warnings();
if (is_visible() && is_inside_tree()) {
XRCamera3D *camera = Object::cast_to<XRCamera3D>(get_parent());
if (camera == nullptr) {
warnings.push_back(RTR("OpenXR visibility mask must have an XRCamera3D node as their parent."));
}
}
return warnings;
}
AABB OpenXRVisibilityMask::get_aabb() const {
AABB ret;
// Make sure it's always visible, this is positioned through its shader.
ret.position = Vector3(-1000.0, -1000.0, -1000.0);
ret.size = Vector3(2000.0, 2000.0, 2000.0);
return ret;
}
OpenXRVisibilityMask::OpenXRVisibilityMask() {
Ref<OpenXRInterface> openxr_interface = XRServer::get_singleton()->find_interface("OpenXR");
if (openxr_interface.is_valid()) {
openxr_interface->connect("session_begun", callable_mp(this, &OpenXRVisibilityMask::_on_openxr_session_begun));
openxr_interface->connect("session_stopping", callable_mp(this, &OpenXRVisibilityMask::_on_openxr_session_stopping));
}
RS::get_singleton()->instance_geometry_set_cast_shadows_setting(get_instance(), RS::SHADOW_CASTING_SETTING_OFF);
}
OpenXRVisibilityMask::~OpenXRVisibilityMask() {
Ref<OpenXRInterface> openxr_interface = XRServer::get_singleton()->find_interface("OpenXR");
if (openxr_interface.is_valid()) {
openxr_interface->disconnect("session_begun", callable_mp(this, &OpenXRVisibilityMask::_on_openxr_session_begun));
openxr_interface->disconnect("session_stopping", callable_mp(this, &OpenXRVisibilityMask::_on_openxr_session_stopping));
}
}

View file

@ -0,0 +1,56 @@
/**************************************************************************/
/* openxr_visibility_mask.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_VISIBILITY_MASK_H
#define OPENXR_VISIBILITY_MASK_H
#include "scene/3d/visual_instance_3d.h"
class OpenXRVisibilityMask : public VisualInstance3D {
GDCLASS(OpenXRVisibilityMask, VisualInstance3D);
protected:
static void _bind_methods();
void _notification(int p_what);
void _on_openxr_session_begun();
void _on_openxr_session_stopping();
public:
virtual PackedStringArray get_configuration_warnings() const override;
virtual AABB get_aabb() const override;
OpenXRVisibilityMask();
~OpenXRVisibilityMask();
};
#endif // OPENXR_VISIBILITY_MASK_H