generated from hertog/godot-module-template
Initial commit
This commit is contained in:
commit
65227bf3a5
12416 changed files with 6001067 additions and 0 deletions
116
engine/modules/openxr/SCsub
Normal file
116
engine/modules/openxr/SCsub
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
#!/usr/bin/env python
|
||||
from misc.utility.scons_hints import *
|
||||
|
||||
import sys
|
||||
|
||||
Import("env")
|
||||
Import("env_modules")
|
||||
|
||||
env_openxr = env_modules.Clone()
|
||||
|
||||
# Thirdparty source files
|
||||
|
||||
thirdparty_obj = []
|
||||
|
||||
# Khronos OpenXR loader
|
||||
|
||||
# Needs even for build against shared library, at least the defines used in public headers.
|
||||
if env["platform"] == "android":
|
||||
# may need to set OPENXR_ANDROID_VERSION_SUFFIX
|
||||
env_openxr.AppendUnique(CPPDEFINES=["XR_OS_ANDROID", "XR_USE_PLATFORM_ANDROID"])
|
||||
env_openxr.AppendUnique(CPPDEFINES=["JSON_USE_EXCEPTION=0"])
|
||||
|
||||
# may need to include java parts of the openxr loader
|
||||
elif env["platform"] == "linuxbsd":
|
||||
env_openxr.AppendUnique(CPPDEFINES=["XR_OS_LINUX"])
|
||||
|
||||
if env["x11"]:
|
||||
env_openxr.AppendUnique(CPPDEFINES=["XR_USE_PLATFORM_XLIB"])
|
||||
|
||||
if env["wayland"]:
|
||||
env_openxr.AppendUnique(CPPDEFINES=["XR_USE_PLATFORM_EGL"])
|
||||
|
||||
# FIXME: Review what needs to be set for Android and macOS.
|
||||
# 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":
|
||||
env_openxr.AppendUnique(CPPDEFINES=["XR_OS_APPLE"])
|
||||
|
||||
# There does not seem to be a XR_USE_PLATFORM_XYZ for Apple
|
||||
|
||||
|
||||
# may need to check and set:
|
||||
# - XR_USE_TIMESPEC
|
||||
|
||||
if env["builtin_openxr"]:
|
||||
thirdparty_dir = "#thirdparty/openxr"
|
||||
|
||||
env_openxr.Prepend(
|
||||
CPPPATH=[
|
||||
thirdparty_dir,
|
||||
thirdparty_dir + "/include",
|
||||
thirdparty_dir + "/src",
|
||||
thirdparty_dir + "/src/common",
|
||||
thirdparty_dir + "/src/external/jsoncpp/include",
|
||||
]
|
||||
)
|
||||
|
||||
env_thirdparty = env_openxr.Clone()
|
||||
env_thirdparty.disable_warnings()
|
||||
|
||||
env_thirdparty.AppendUnique(CPPDEFINES=["DISABLE_STD_FILESYSTEM"])
|
||||
if env["disable_exceptions"]:
|
||||
env_thirdparty.AppendUnique(CPPDEFINES=["XRLOADER_DISABLE_EXCEPTION_HANDLING", ("JSON_USE_EXCEPTION", 0)])
|
||||
|
||||
env_thirdparty.Append(CPPPATH=[thirdparty_dir + "/src/loader"])
|
||||
|
||||
# add in external jsoncpp dependency
|
||||
thirdparty_jsoncpp_dir = thirdparty_dir + "/src/external/jsoncpp/src/lib_json/"
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_jsoncpp_dir + "json_reader.cpp")
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_jsoncpp_dir + "json_value.cpp")
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_jsoncpp_dir + "json_writer.cpp")
|
||||
|
||||
# add in load
|
||||
if env["platform"] != "android":
|
||||
# On Android the openxr_loader is provided by separate plugins for each device
|
||||
# Build the engine using object files
|
||||
khrloader_obj = []
|
||||
env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/xr_generated_dispatch_table_core.c")
|
||||
|
||||
env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/common/filesystem_utils.cpp")
|
||||
env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/common/object_info.cpp")
|
||||
|
||||
env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/api_layer_interface.cpp")
|
||||
env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_core.cpp")
|
||||
env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_instance.cpp")
|
||||
env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_logger_recorders.cpp")
|
||||
env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_logger.cpp")
|
||||
env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/manifest_file.cpp")
|
||||
env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/runtime_interface.cpp")
|
||||
env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/xr_generated_loader.cpp")
|
||||
env.modules_sources += khrloader_obj
|
||||
|
||||
env.modules_sources += thirdparty_obj
|
||||
|
||||
|
||||
# Godot source files
|
||||
|
||||
module_obj = []
|
||||
|
||||
env_openxr.add_source_files(module_obj, "*.cpp")
|
||||
env.modules_sources += module_obj
|
||||
|
||||
Export("env_openxr")
|
||||
|
||||
SConscript("action_map/SCsub")
|
||||
SConscript("extensions/SCsub")
|
||||
SConscript("scene/SCsub")
|
||||
|
||||
if env.editor_build:
|
||||
SConscript("editor/SCsub")
|
||||
|
||||
# Needed to force rebuilding the module files when the thirdparty library is updated.
|
||||
env.Depends(module_obj, thirdparty_obj)
|
||||
11
engine/modules/openxr/action_map/SCsub
Normal file
11
engine/modules/openxr/action_map/SCsub
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/env python
|
||||
from misc.utility.scons_hints import *
|
||||
|
||||
Import("env")
|
||||
Import("env_openxr")
|
||||
|
||||
module_obj = []
|
||||
|
||||
env_openxr.add_source_files(module_obj, "*.cpp")
|
||||
|
||||
env.modules_sources += module_obj
|
||||
121
engine/modules/openxr/action_map/openxr_action.cpp
Normal file
121
engine/modules/openxr/action_map/openxr_action.cpp
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_action.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_action.h"
|
||||
|
||||
#include "openxr_action_set.h"
|
||||
|
||||
void OpenXRAction::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_localized_name", "localized_name"), &OpenXRAction::set_localized_name);
|
||||
ClassDB::bind_method(D_METHOD("get_localized_name"), &OpenXRAction::get_localized_name);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "localized_name"), "set_localized_name", "get_localized_name");
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_action_type", "action_type"), &OpenXRAction::set_action_type);
|
||||
ClassDB::bind_method(D_METHOD("get_action_type"), &OpenXRAction::get_action_type);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "action_type", PROPERTY_HINT_ENUM, "bool,float,vector2,pose"), "set_action_type", "get_action_type");
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_toplevel_paths", "toplevel_paths"), &OpenXRAction::set_toplevel_paths);
|
||||
ClassDB::bind_method(D_METHOD("get_toplevel_paths"), &OpenXRAction::get_toplevel_paths);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "toplevel_paths"), "set_toplevel_paths", "get_toplevel_paths");
|
||||
|
||||
BIND_ENUM_CONSTANT(OPENXR_ACTION_BOOL);
|
||||
BIND_ENUM_CONSTANT(OPENXR_ACTION_FLOAT);
|
||||
BIND_ENUM_CONSTANT(OPENXR_ACTION_VECTOR2);
|
||||
BIND_ENUM_CONSTANT(OPENXR_ACTION_POSE);
|
||||
}
|
||||
|
||||
Ref<OpenXRAction> OpenXRAction::new_action(const char *p_name, const char *p_localized_name, const ActionType p_action_type, const char *p_toplevel_paths) {
|
||||
// This is a helper function to help build our default action sets
|
||||
|
||||
Ref<OpenXRAction> action;
|
||||
action.instantiate();
|
||||
action->set_name(String(p_name));
|
||||
action->set_localized_name(String(p_localized_name));
|
||||
action->set_action_type(p_action_type);
|
||||
action->parse_toplevel_paths(String(p_toplevel_paths));
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
String OpenXRAction::get_name_with_set() const {
|
||||
String action_name = get_name();
|
||||
|
||||
if (action_set != nullptr) {
|
||||
action_name = action_set->get_name() + "/" + action_name;
|
||||
}
|
||||
|
||||
return action_name;
|
||||
}
|
||||
|
||||
void OpenXRAction::set_localized_name(const String p_localized_name) {
|
||||
localized_name = p_localized_name;
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
String OpenXRAction::get_localized_name() const {
|
||||
return localized_name;
|
||||
}
|
||||
|
||||
void OpenXRAction::set_action_type(const OpenXRAction::ActionType p_action_type) {
|
||||
action_type = p_action_type;
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
OpenXRAction::ActionType OpenXRAction::get_action_type() const {
|
||||
return action_type;
|
||||
}
|
||||
|
||||
void OpenXRAction::set_toplevel_paths(const PackedStringArray p_toplevel_paths) {
|
||||
toplevel_paths = p_toplevel_paths;
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
PackedStringArray OpenXRAction::get_toplevel_paths() const {
|
||||
return toplevel_paths;
|
||||
}
|
||||
|
||||
void OpenXRAction::add_toplevel_path(const String p_toplevel_path) {
|
||||
if (!toplevel_paths.has(p_toplevel_path)) {
|
||||
toplevel_paths.push_back(p_toplevel_path);
|
||||
emit_changed();
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRAction::rem_toplevel_path(const String p_toplevel_path) {
|
||||
if (toplevel_paths.has(p_toplevel_path)) {
|
||||
toplevel_paths.erase(p_toplevel_path);
|
||||
emit_changed();
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRAction::parse_toplevel_paths(const String p_toplevel_paths) {
|
||||
toplevel_paths = p_toplevel_paths.split(",", false);
|
||||
emit_changed();
|
||||
}
|
||||
87
engine/modules/openxr/action_map/openxr_action.h
Normal file
87
engine/modules/openxr/action_map/openxr_action.h
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_action.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_ACTION_H
|
||||
#define OPENXR_ACTION_H
|
||||
|
||||
#include "core/io/resource.h"
|
||||
|
||||
class OpenXRActionSet;
|
||||
|
||||
class OpenXRAction : public Resource {
|
||||
GDCLASS(OpenXRAction, Resource);
|
||||
|
||||
public:
|
||||
enum ActionType {
|
||||
OPENXR_ACTION_BOOL,
|
||||
OPENXR_ACTION_FLOAT,
|
||||
OPENXR_ACTION_VECTOR2,
|
||||
OPENXR_ACTION_POSE,
|
||||
OPENXR_ACTION_HAPTIC,
|
||||
OPENXR_ACTION_MAX
|
||||
};
|
||||
|
||||
private:
|
||||
String localized_name;
|
||||
ActionType action_type = OPENXR_ACTION_FLOAT;
|
||||
|
||||
PackedStringArray toplevel_paths;
|
||||
|
||||
protected:
|
||||
friend class OpenXRActionSet;
|
||||
|
||||
OpenXRActionSet *action_set = nullptr; // action belongs to this action set.
|
||||
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
static Ref<OpenXRAction> new_action(const char *p_name, const char *p_localized_name, const ActionType p_action_type, const char *p_toplevel_paths); // Helper function to add and configure an action
|
||||
OpenXRActionSet *get_action_set() const { return action_set; } // Get the action set this action belongs to
|
||||
|
||||
String get_name_with_set() const; // Retrieve the name of this action as <action_set>/<action>
|
||||
|
||||
void set_localized_name(const String p_localized_name); // Set the localized name of this action
|
||||
String get_localized_name() const; // Get the localized name of this action
|
||||
|
||||
void set_action_type(const ActionType p_action_type); // Set the type of this action
|
||||
ActionType get_action_type() const; // Get the type of this action
|
||||
|
||||
void set_toplevel_paths(const PackedStringArray p_toplevel_paths); // Set the toplevel paths of this action
|
||||
PackedStringArray get_toplevel_paths() const; // Get the toplevel paths of this action
|
||||
|
||||
void add_toplevel_path(const String p_toplevel_path); // Add a top level path to this action
|
||||
void rem_toplevel_path(const String p_toplevel_path); // Remove a toplevel path from this action
|
||||
|
||||
void parse_toplevel_paths(const String p_toplevel_paths); // Parse and set the top level paths from a comma separated string
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(OpenXRAction::ActionType);
|
||||
|
||||
#endif // OPENXR_ACTION_H
|
||||
620
engine/modules/openxr/action_map/openxr_action_map.cpp
Normal file
620
engine/modules/openxr/action_map/openxr_action_map.cpp
Normal file
|
|
@ -0,0 +1,620 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_action_map.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_action_map.h"
|
||||
|
||||
void OpenXRActionMap::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_action_sets", "action_sets"), &OpenXRActionMap::set_action_sets);
|
||||
ClassDB::bind_method(D_METHOD("get_action_sets"), &OpenXRActionMap::get_action_sets);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "action_sets", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRActionSet", PROPERTY_USAGE_NO_EDITOR), "set_action_sets", "get_action_sets");
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_action_set_count"), &OpenXRActionMap::get_action_set_count);
|
||||
ClassDB::bind_method(D_METHOD("find_action_set", "name"), &OpenXRActionMap::find_action_set);
|
||||
ClassDB::bind_method(D_METHOD("get_action_set", "idx"), &OpenXRActionMap::get_action_set);
|
||||
ClassDB::bind_method(D_METHOD("add_action_set", "action_set"), &OpenXRActionMap::add_action_set);
|
||||
ClassDB::bind_method(D_METHOD("remove_action_set", "action_set"), &OpenXRActionMap::remove_action_set);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_interaction_profiles", "interaction_profiles"), &OpenXRActionMap::set_interaction_profiles);
|
||||
ClassDB::bind_method(D_METHOD("get_interaction_profiles"), &OpenXRActionMap::get_interaction_profiles);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "interaction_profiles", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRInteractionProfile", PROPERTY_USAGE_NO_EDITOR), "set_interaction_profiles", "get_interaction_profiles");
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_interaction_profile_count"), &OpenXRActionMap::get_interaction_profile_count);
|
||||
ClassDB::bind_method(D_METHOD("find_interaction_profile", "name"), &OpenXRActionMap::find_interaction_profile);
|
||||
ClassDB::bind_method(D_METHOD("get_interaction_profile", "idx"), &OpenXRActionMap::get_interaction_profile);
|
||||
ClassDB::bind_method(D_METHOD("add_interaction_profile", "interaction_profile"), &OpenXRActionMap::add_interaction_profile);
|
||||
ClassDB::bind_method(D_METHOD("remove_interaction_profile", "interaction_profile"), &OpenXRActionMap::remove_interaction_profile);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("create_default_action_sets"), &OpenXRActionMap::create_default_action_sets);
|
||||
}
|
||||
|
||||
void OpenXRActionMap::set_action_sets(Array p_action_sets) {
|
||||
action_sets.clear();
|
||||
|
||||
for (int i = 0; i < p_action_sets.size(); i++) {
|
||||
Ref<OpenXRActionSet> action_set = p_action_sets[i];
|
||||
if (action_set.is_valid() && !action_sets.has(action_set)) {
|
||||
action_sets.push_back(action_set);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Array OpenXRActionMap::get_action_sets() const {
|
||||
return action_sets;
|
||||
}
|
||||
|
||||
int OpenXRActionMap::get_action_set_count() const {
|
||||
return action_sets.size();
|
||||
}
|
||||
|
||||
Ref<OpenXRActionSet> OpenXRActionMap::find_action_set(String p_name) const {
|
||||
for (int i = 0; i < action_sets.size(); i++) {
|
||||
Ref<OpenXRActionSet> action_set = action_sets[i];
|
||||
if (action_set->get_name() == p_name) {
|
||||
return action_set;
|
||||
}
|
||||
}
|
||||
|
||||
return Ref<OpenXRActionSet>();
|
||||
}
|
||||
|
||||
Ref<OpenXRActionSet> OpenXRActionMap::get_action_set(int p_idx) const {
|
||||
ERR_FAIL_INDEX_V(p_idx, action_sets.size(), Ref<OpenXRActionSet>());
|
||||
|
||||
return action_sets[p_idx];
|
||||
}
|
||||
|
||||
void OpenXRActionMap::add_action_set(Ref<OpenXRActionSet> p_action_set) {
|
||||
ERR_FAIL_COND(p_action_set.is_null());
|
||||
|
||||
if (!action_sets.has(p_action_set)) {
|
||||
action_sets.push_back(p_action_set);
|
||||
emit_changed();
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRActionMap::remove_action_set(Ref<OpenXRActionSet> p_action_set) {
|
||||
int idx = action_sets.find(p_action_set);
|
||||
if (idx != -1) {
|
||||
action_sets.remove_at(idx);
|
||||
emit_changed();
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRActionMap::clear_interaction_profiles() {
|
||||
if (interaction_profiles.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Interaction profiles held within our action map set should be released and destroyed but just in case they are still used some where else.
|
||||
for (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);
|
||||
}
|
||||
}
|
||||
|
||||
Array OpenXRActionMap::get_interaction_profiles() const {
|
||||
return interaction_profiles;
|
||||
}
|
||||
|
||||
int OpenXRActionMap::get_interaction_profile_count() const {
|
||||
return interaction_profiles.size();
|
||||
}
|
||||
|
||||
Ref<OpenXRInteractionProfile> OpenXRActionMap::find_interaction_profile(String p_path) const {
|
||||
for (Ref<OpenXRInteractionProfile> interaction_profile : interaction_profiles) {
|
||||
if (interaction_profile->get_interaction_profile_path() == p_path) {
|
||||
return interaction_profile;
|
||||
}
|
||||
}
|
||||
|
||||
return Ref<OpenXRInteractionProfile>();
|
||||
}
|
||||
|
||||
Ref<OpenXRInteractionProfile> OpenXRActionMap::get_interaction_profile(int p_idx) const {
|
||||
ERR_FAIL_INDEX_V(p_idx, interaction_profiles.size(), Ref<OpenXRInteractionProfile>());
|
||||
|
||||
return interaction_profiles[p_idx];
|
||||
}
|
||||
|
||||
void OpenXRActionMap::add_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRActionMap::remove_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile) {
|
||||
int idx = interaction_profiles.find(p_interaction_profile);
|
||||
if (idx != -1) {
|
||||
interaction_profiles.remove_at(idx);
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRActionMap::create_default_action_sets() {
|
||||
// Note:
|
||||
// - if you make changes here make sure to delete your default_action_map.tres file of it will load an old version.
|
||||
// - our palm pose is only available if the relevant extension is supported,
|
||||
// we still want it to be part of our action map as we may deploy the same game to platforms that do and don't support it.
|
||||
// - the same applies for interaction profiles that are only supported if the relevant extension is supported.
|
||||
|
||||
// Create our Godot action set.
|
||||
Ref<OpenXRActionSet> action_set = OpenXRActionSet::new_action_set("godot", "Godot action set");
|
||||
add_action_set(action_set);
|
||||
|
||||
// Create our actions.
|
||||
Ref<OpenXRAction> trigger = action_set->add_new_action("trigger", "Trigger", OpenXRAction::OPENXR_ACTION_FLOAT, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> trigger_click = action_set->add_new_action("trigger_click", "Trigger click", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> trigger_touch = action_set->add_new_action("trigger_touch", "Trigger touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> grip = action_set->add_new_action("grip", "Grip", OpenXRAction::OPENXR_ACTION_FLOAT, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> grip_click = action_set->add_new_action("grip_click", "Grip click", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> grip_force = action_set->add_new_action("grip_force", "Grip force", OpenXRAction::OPENXR_ACTION_FLOAT, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> primary = action_set->add_new_action("primary", "Primary joystick/thumbstick/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> primary_click = action_set->add_new_action("primary_click", "Primary joystick/thumbstick/trackpad click", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> primary_touch = action_set->add_new_action("primary_touch", "Primary joystick/thumbstick/trackpad touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> secondary = action_set->add_new_action("secondary", "Secondary joystick/thumbstick/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> secondary_click = action_set->add_new_action("secondary_click", "Secondary joystick/thumbstick/trackpad click", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> secondary_touch = action_set->add_new_action("secondary_touch", "Secondary joystick/thumbstick/trackpad touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> menu_button = action_set->add_new_action("menu_button", "Menu button", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> select_button = action_set->add_new_action("select_button", "Select button", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> ax_button = action_set->add_new_action("ax_button", "A/X button", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> ax_touch = action_set->add_new_action("ax_touch", "A/X touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> by_button = action_set->add_new_action("by_button", "B/Y button", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> by_touch = action_set->add_new_action("by_touch", "B/Y touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> default_pose = action_set->add_new_action("default_pose", "Default pose", OpenXRAction::OPENXR_ACTION_POSE,
|
||||
"/user/hand/left,"
|
||||
"/user/hand/right,"
|
||||
// "/user/vive_tracker_htcx/role/handheld_object," <-- getting errors on this one.
|
||||
"/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,"
|
||||
"/user/eyes_ext");
|
||||
Ref<OpenXRAction> aim_pose = action_set->add_new_action("aim_pose", "Aim pose", OpenXRAction::OPENXR_ACTION_POSE, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> grip_pose = action_set->add_new_action("grip_pose", "Grip pose", OpenXRAction::OPENXR_ACTION_POSE, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> palm_pose = action_set->add_new_action("palm_pose", "Palm pose", OpenXRAction::OPENXR_ACTION_POSE, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> haptic = action_set->add_new_action("haptic", "Haptic", OpenXRAction::OPENXR_ACTION_HAPTIC,
|
||||
"/user/hand/left,"
|
||||
"/user/hand/right,"
|
||||
// "/user/vive_tracker_htcx/role/handheld_object," <-- getting errors on this one.
|
||||
"/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");
|
||||
|
||||
// Create our interaction profiles.
|
||||
Ref<OpenXRInteractionProfile> profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/khr/simple_controller");
|
||||
profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
|
||||
profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");
|
||||
profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click");
|
||||
profile->add_new_binding(select_button, "/user/hand/left/input/select/click,/user/hand/right/input/select/click");
|
||||
// generic has no support for triggers, grip, A/B buttons, nor joystick/trackpad inputs.
|
||||
profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
|
||||
add_interaction_profile(profile);
|
||||
|
||||
// Create our Vive controller profile.
|
||||
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_controller");
|
||||
profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
|
||||
profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");
|
||||
profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click");
|
||||
profile->add_new_binding(select_button, "/user/hand/left/input/system/click,/user/hand/right/input/system/click");
|
||||
// wmr controller has no a/b/x/y buttons.
|
||||
profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
|
||||
profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click");
|
||||
profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); // OpenXR will convert bool to float.
|
||||
profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");
|
||||
// primary on our vive controller is our trackpad.
|
||||
profile->add_new_binding(primary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad");
|
||||
profile->add_new_binding(primary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click");
|
||||
profile->add_new_binding(primary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch");
|
||||
// vive controllers have no secondary input.
|
||||
profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
|
||||
add_interaction_profile(profile);
|
||||
|
||||
// Create our WMR controller profile.
|
||||
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/microsoft/motion_controller");
|
||||
profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
|
||||
profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");
|
||||
// wmr controllers have no select button we can use.
|
||||
profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click");
|
||||
// wmr controller has no a/b/x/y buttons.
|
||||
profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
|
||||
profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); // OpenXR will convert float to bool.
|
||||
profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); // OpenXR will convert bool to float.
|
||||
profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");
|
||||
// primary on our wmr controller is our thumbstick, no touch.
|
||||
profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");
|
||||
profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");
|
||||
// secondary on our wmr controller is our trackpad.
|
||||
profile->add_new_binding(secondary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad");
|
||||
profile->add_new_binding(secondary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click");
|
||||
profile->add_new_binding(secondary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch");
|
||||
profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
|
||||
add_interaction_profile(profile);
|
||||
|
||||
// Create our Meta touch controller profile.
|
||||
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/oculus/touch_controller");
|
||||
profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
|
||||
profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");
|
||||
// touch controllers have no select button we can use.
|
||||
profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/system/click"); // right hand system click may not be available.
|
||||
profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand.
|
||||
profile->add_new_binding(ax_touch, "/user/hand/left/input/x/touch,/user/hand/right/input/a/touch");
|
||||
profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand.
|
||||
profile->add_new_binding(by_touch, "/user/hand/left/input/y/touch,/user/hand/right/input/b/touch");
|
||||
profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
|
||||
profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); // should be converted to boolean.
|
||||
profile->add_new_binding(trigger_touch, "/user/hand/left/input/trigger/touch,/user/hand/right/input/trigger/touch");
|
||||
profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); // should be converted to boolean.
|
||||
profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value");
|
||||
// primary on our touch controller is our thumbstick.
|
||||
profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");
|
||||
profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");
|
||||
profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch");
|
||||
// touch controller has no secondary input.
|
||||
profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
|
||||
add_interaction_profile(profile);
|
||||
|
||||
// Create our Pico 4 controller profile.
|
||||
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/bytedance/pico4_controller");
|
||||
profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
|
||||
profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");
|
||||
profile->add_new_binding(select_button, "/user/hand/left/input/system/click,/user/hand/right/input/system/click"); // system click may not be available.
|
||||
profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click");
|
||||
profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand.
|
||||
profile->add_new_binding(ax_touch, "/user/hand/left/input/x/touch,/user/hand/right/input/a/touch");
|
||||
profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand.
|
||||
profile->add_new_binding(by_touch, "/user/hand/left/input/y/touch,/user/hand/right/input/b/touch");
|
||||
profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
|
||||
profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); // should be converted to boolean.
|
||||
profile->add_new_binding(trigger_touch, "/user/hand/left/input/trigger/touch,/user/hand/right/input/trigger/touch");
|
||||
profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); // should be converted to boolean.
|
||||
profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value");
|
||||
// primary on our pico controller is our thumbstick.
|
||||
profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");
|
||||
profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");
|
||||
profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch");
|
||||
// pico controller has no secondary input.
|
||||
profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
|
||||
add_interaction_profile(profile);
|
||||
|
||||
// Create our Valve index controller profile.
|
||||
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/valve/index_controller");
|
||||
profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
|
||||
profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");
|
||||
// index controllers have no select button we can use.
|
||||
profile->add_new_binding(menu_button, "/user/hand/left/input/system/click,/user/hand/right/input/system/click");
|
||||
profile->add_new_binding(ax_button, "/user/hand/left/input/a/click,/user/hand/right/input/a/click"); // a on both controllers.
|
||||
profile->add_new_binding(ax_touch, "/user/hand/left/input/a/touch,/user/hand/right/input/a/touch");
|
||||
profile->add_new_binding(by_button, "/user/hand/left/input/b/click,/user/hand/right/input/b/click"); // b on both controllers.
|
||||
profile->add_new_binding(by_touch, "/user/hand/left/input/b/touch,/user/hand/right/input/b/touch");
|
||||
profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
|
||||
profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click");
|
||||
profile->add_new_binding(trigger_touch, "/user/hand/left/input/trigger/touch,/user/hand/right/input/trigger/touch");
|
||||
profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value");
|
||||
profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); // this should do a float to bool conversion.
|
||||
profile->add_new_binding(grip_force, "/user/hand/left/input/squeeze/force,/user/hand/right/input/squeeze/force"); // grip force seems to be unique to the Valve Index.
|
||||
// primary on our index controller is our thumbstick.
|
||||
profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");
|
||||
profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");
|
||||
profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch");
|
||||
// secondary on our index controller is our trackpad.
|
||||
profile->add_new_binding(secondary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad");
|
||||
profile->add_new_binding(secondary_click, "/user/hand/left/input/trackpad/force,/user/hand/right/input/trackpad/force"); // not sure if this will work but doesn't seem to support click...
|
||||
profile->add_new_binding(secondary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch");
|
||||
profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
|
||||
add_interaction_profile(profile);
|
||||
|
||||
// Create our HP MR controller profile.
|
||||
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/hp/mixed_reality_controller");
|
||||
profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
|
||||
profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");
|
||||
// hpmr controllers have no select button we can use.
|
||||
profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click");
|
||||
// hpmr controllers only register click, not touch, on our a/b/x/y buttons.
|
||||
profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand.
|
||||
profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand.
|
||||
profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
|
||||
profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
|
||||
profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value");
|
||||
profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value");
|
||||
// primary on our hpmr controller is our thumbstick.
|
||||
profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");
|
||||
profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");
|
||||
// No secondary on our hpmr controller.
|
||||
profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
|
||||
add_interaction_profile(profile);
|
||||
|
||||
// Create our Samsung Odyssey controller profile,
|
||||
// Note that this controller is only identified specifically on WMR, on SteamVR this is identified as a normal WMR controller.
|
||||
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/samsung/odyssey_controller");
|
||||
profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
|
||||
profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");
|
||||
// Odyssey controllers have no select button we can use.
|
||||
profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click");
|
||||
// Odyssey controller has no a/b/x/y buttons.
|
||||
profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
|
||||
profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
|
||||
profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");
|
||||
profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");
|
||||
// primary on our Odyssey controller is our thumbstick, no touch.
|
||||
profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");
|
||||
profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");
|
||||
// secondary on our Odyssey controller is our trackpad.
|
||||
profile->add_new_binding(secondary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad");
|
||||
profile->add_new_binding(secondary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click");
|
||||
profile->add_new_binding(secondary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch");
|
||||
profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
|
||||
add_interaction_profile(profile);
|
||||
|
||||
// Create our Vive Cosmos controller.
|
||||
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_cosmos_controller");
|
||||
profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
|
||||
profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");
|
||||
profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click");
|
||||
profile->add_new_binding(select_button, "/user/hand/right/input/system/click"); // we'll map system to select.
|
||||
profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand.
|
||||
profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand.
|
||||
profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
|
||||
profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click");
|
||||
profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");
|
||||
profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");
|
||||
// primary on our Cosmos controller is our thumbstick.
|
||||
profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");
|
||||
profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");
|
||||
profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch");
|
||||
// No secondary on our cosmos controller.
|
||||
profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
|
||||
add_interaction_profile(profile);
|
||||
|
||||
// Create our Vive Focus 3 controller.
|
||||
// Note, Vive Focus 3 currently is not yet supported as a stand alone device
|
||||
// however HTC currently has a beta OpenXR runtime in testing we may support in the near future.
|
||||
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_focus3_controller");
|
||||
profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
|
||||
profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");
|
||||
profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click");
|
||||
profile->add_new_binding(select_button, "/user/hand/right/input/system/click"); // we'll map system to select.
|
||||
profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand.
|
||||
profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand.
|
||||
profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
|
||||
profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click");
|
||||
profile->add_new_binding(trigger_touch, "/user/hand/left/input/trigger/touch,/user/hand/right/input/trigger/touch");
|
||||
profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");
|
||||
profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");
|
||||
// primary on our Focus 3 controller is our thumbstick.
|
||||
profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");
|
||||
profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");
|
||||
profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch");
|
||||
// We only have a thumb rest.
|
||||
profile->add_new_binding(secondary_touch, "/user/hand/left/input/thumbrest/touch,/user/hand/right/input/thumbrest/touch");
|
||||
profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
|
||||
add_interaction_profile(profile);
|
||||
|
||||
// Create our Huawei controller.
|
||||
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/huawei/controller");
|
||||
profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
|
||||
profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");
|
||||
profile->add_new_binding(menu_button, "/user/hand/left/input/home/click,/user/hand/right/input/home/click");
|
||||
profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
|
||||
profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click");
|
||||
// primary on our Huawei controller is our trackpad.
|
||||
profile->add_new_binding(primary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad");
|
||||
profile->add_new_binding(primary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click");
|
||||
profile->add_new_binding(primary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch");
|
||||
profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
|
||||
add_interaction_profile(profile);
|
||||
|
||||
// Create our HTC Vive tracker profile.
|
||||
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_tracker_htcx");
|
||||
profile->add_new_binding(default_pose,
|
||||
// "/user/vive_tracker_htcx/role/handheld_object/input/grip/pose," <-- getting errors on this one.
|
||||
"/user/vive_tracker_htcx/role/left_foot/input/grip/pose,"
|
||||
"/user/vive_tracker_htcx/role/right_foot/input/grip/pose,"
|
||||
"/user/vive_tracker_htcx/role/left_shoulder/input/grip/pose,"
|
||||
"/user/vive_tracker_htcx/role/right_shoulder/input/grip/pose,"
|
||||
"/user/vive_tracker_htcx/role/left_elbow/input/grip/pose,"
|
||||
"/user/vive_tracker_htcx/role/right_elbow/input/grip/pose,"
|
||||
"/user/vive_tracker_htcx/role/left_knee/input/grip/pose,"
|
||||
"/user/vive_tracker_htcx/role/right_knee/input/grip/pose,"
|
||||
"/user/vive_tracker_htcx/role/waist/input/grip/pose,"
|
||||
"/user/vive_tracker_htcx/role/chest/input/grip/pose,"
|
||||
"/user/vive_tracker_htcx/role/camera/input/grip/pose,"
|
||||
"/user/vive_tracker_htcx/role/keyboard/input/grip/pose");
|
||||
profile->add_new_binding(haptic,
|
||||
// "/user/vive_tracker_htcx/role/handheld_object/output/haptic," <-- getting errors on this one.
|
||||
"/user/vive_tracker_htcx/role/left_foot/output/haptic,"
|
||||
"/user/vive_tracker_htcx/role/right_foot/output/haptic,"
|
||||
"/user/vive_tracker_htcx/role/left_shoulder/output/haptic,"
|
||||
"/user/vive_tracker_htcx/role/right_shoulder/output/haptic,"
|
||||
"/user/vive_tracker_htcx/role/left_elbow/output/haptic,"
|
||||
"/user/vive_tracker_htcx/role/right_elbow/output/haptic,"
|
||||
"/user/vive_tracker_htcx/role/left_knee/output/haptic,"
|
||||
"/user/vive_tracker_htcx/role/right_knee/output/haptic,"
|
||||
"/user/vive_tracker_htcx/role/waist/output/haptic,"
|
||||
"/user/vive_tracker_htcx/role/chest/output/haptic,"
|
||||
"/user/vive_tracker_htcx/role/camera/output/haptic,"
|
||||
"/user/vive_tracker_htcx/role/keyboard/output/haptic");
|
||||
add_interaction_profile(profile);
|
||||
|
||||
// Create our eye gaze interaction profile.
|
||||
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/ext/eye_gaze_interaction");
|
||||
profile->add_new_binding(default_pose, "/user/eyes_ext/input/gaze_ext/pose");
|
||||
add_interaction_profile(profile);
|
||||
|
||||
// Create our hand interaction profile.
|
||||
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/ext/hand_interaction_ext");
|
||||
profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
|
||||
profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");
|
||||
|
||||
// Use pinch as primary.
|
||||
profile->add_new_binding(primary, "/user/hand/left/input/pinch_ext/value,/user/hand/right/input/pinch_ext/value");
|
||||
profile->add_new_binding(primary_click, "/user/hand/left/input/pinch_ext/ready_ext,/user/hand/right/input/pinch_ext/ready_ext");
|
||||
|
||||
// Use activation as secondary.
|
||||
profile->add_new_binding(secondary, "/user/hand/left/input/aim_activate_ext/value,/user/hand/right/input/aim_activate_ext/value");
|
||||
profile->add_new_binding(secondary_click, "/user/hand/left/input/aim_activate_ext/ready_ext,/user/hand/right/input/aim_activate_ext/ready_ext");
|
||||
|
||||
// We link grasp to our grip.
|
||||
profile->add_new_binding(grip, "/user/hand/left/input/grasp_ext/value,/user/hand/right/input/grasp_ext/value");
|
||||
profile->add_new_binding(grip_click, "/user/hand/left/input/grasp_ext/ready_ext,/user/hand/right/input/grasp_ext/ready_ext");
|
||||
add_interaction_profile(profile);
|
||||
}
|
||||
|
||||
void OpenXRActionMap::create_editor_action_sets() {
|
||||
// TODO implement
|
||||
}
|
||||
|
||||
Ref<OpenXRAction> OpenXRActionMap::get_action(const String p_path) const {
|
||||
PackedStringArray paths = p_path.split("/", false);
|
||||
ERR_FAIL_COND_V(paths.size() != 2, Ref<OpenXRAction>());
|
||||
|
||||
Ref<OpenXRActionSet> action_set = find_action_set(paths[0]);
|
||||
if (action_set.is_valid()) {
|
||||
return action_set->get_action(paths[1]);
|
||||
}
|
||||
|
||||
return Ref<OpenXRAction>();
|
||||
}
|
||||
|
||||
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 (Ref<OpenXRInteractionProfile> interaction_profile : interaction_profiles) {
|
||||
if (p_remove_interaction_profiles) {
|
||||
// Remove any bindings for this action
|
||||
interaction_profile->remove_binding_for_action(action);
|
||||
} else {
|
||||
ERR_FAIL_COND(interaction_profile->has_binding_for_action(action));
|
||||
}
|
||||
}
|
||||
|
||||
OpenXRActionSet *action_set = action->get_action_set();
|
||||
if (action_set != nullptr) {
|
||||
// Remove the action from this action set
|
||||
action_set->remove_action(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PackedStringArray OpenXRActionMap::get_top_level_paths(const Ref<OpenXRAction> p_action) {
|
||||
PackedStringArray arr;
|
||||
|
||||
for (Ref<OpenXRInteractionProfile> ip : interaction_profiles) {
|
||||
const OpenXRInteractionProfileMetadata::InteractionProfile *profile = OpenXRInteractionProfileMetadata::get_singleton()->get_profile(ip->get_interaction_profile_path());
|
||||
|
||||
if (profile != nullptr) {
|
||||
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;
|
||||
|
||||
if (!arr.has(top_path)) {
|
||||
arr.push_back(top_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// print_line("Toplevel paths for", p_action->get_name_with_set(), "are", arr);
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
OpenXRActionMap::~OpenXRActionMap() {
|
||||
action_sets.clear();
|
||||
clear_interaction_profiles();
|
||||
}
|
||||
83
engine/modules/openxr/action_map/openxr_action_map.h
Normal file
83
engine/modules/openxr/action_map/openxr_action_map.h
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_action_map.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_ACTION_MAP_H
|
||||
#define OPENXR_ACTION_MAP_H
|
||||
|
||||
#include "openxr_action.h"
|
||||
#include "openxr_action_set.h"
|
||||
#include "openxr_interaction_profile.h"
|
||||
|
||||
#include "core/io/resource.h"
|
||||
|
||||
class OpenXRActionMap : public Resource {
|
||||
GDCLASS(OpenXRActionMap, Resource);
|
||||
|
||||
private:
|
||||
Array action_sets;
|
||||
Array interaction_profiles;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_action_sets(Array p_action_sets); // Set our actions sets by providing an array with action sets (for loading from resource)
|
||||
Array get_action_sets() const; // Get our action sets as an array (for saving to resource)
|
||||
|
||||
int get_action_set_count() const; // Retrieve the number of action sets we have
|
||||
Ref<OpenXRActionSet> find_action_set(String p_name) const; // Find an action set by name
|
||||
Ref<OpenXRActionSet> get_action_set(int p_idx) const; // Retrieve an action set by index
|
||||
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)
|
||||
|
||||
int get_interaction_profile_count() const; // Retrieve the number of interaction profiles we have
|
||||
Ref<OpenXRInteractionProfile> find_interaction_profile(String p_path) const; // Find an interaction profile by path
|
||||
Ref<OpenXRInteractionProfile> get_interaction_profile(int p_idx) const; // Retrieve an interaction profile by index
|
||||
void add_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile); // Add an interaction profile to our action map
|
||||
void remove_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile); // remove an interaction profile from our action map
|
||||
|
||||
void create_default_action_sets(); // Create our default action set for runtime
|
||||
void create_editor_action_sets(); // Create our action set for the editor
|
||||
|
||||
// Helper functions for editor
|
||||
Ref<OpenXRAction> get_action(const String p_path) const; // Retrieve an action using <action name>/<action> as our parameter
|
||||
void remove_action(const String p_path, bool p_remove_interaction_profiles = false); // Remove action from action set, also removes it from interaction profiles
|
||||
PackedStringArray get_top_level_paths(const Ref<OpenXRAction> p_action); // Determines the top level paths based on where an action is bound in interaction profiles
|
||||
|
||||
// TODO add validation to display in the interface that checks if we have action sets with the same name or if we have interaction profiles for the same path
|
||||
|
||||
~OpenXRActionMap();
|
||||
};
|
||||
|
||||
#endif // OPENXR_ACTION_MAP_H
|
||||
161
engine/modules/openxr/action_map/openxr_action_set.cpp
Normal file
161
engine/modules/openxr/action_map/openxr_action_set.cpp
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_action_set.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_action_set.h"
|
||||
|
||||
void OpenXRActionSet::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_localized_name", "localized_name"), &OpenXRActionSet::set_localized_name);
|
||||
ClassDB::bind_method(D_METHOD("get_localized_name"), &OpenXRActionSet::get_localized_name);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "localized_name"), "set_localized_name", "get_localized_name");
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_priority", "priority"), &OpenXRActionSet::set_priority);
|
||||
ClassDB::bind_method(D_METHOD("get_priority"), &OpenXRActionSet::get_priority);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "priority"), "set_priority", "get_priority");
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_action_count"), &OpenXRActionSet::get_action_count);
|
||||
ClassDB::bind_method(D_METHOD("set_actions", "actions"), &OpenXRActionSet::set_actions);
|
||||
ClassDB::bind_method(D_METHOD("get_actions"), &OpenXRActionSet::get_actions);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "actions", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRAction", PROPERTY_USAGE_NO_EDITOR), "set_actions", "get_actions");
|
||||
|
||||
ClassDB::bind_method(D_METHOD("add_action", "action"), &OpenXRActionSet::add_action);
|
||||
ClassDB::bind_method(D_METHOD("remove_action", "action"), &OpenXRActionSet::remove_action);
|
||||
}
|
||||
|
||||
Ref<OpenXRActionSet> OpenXRActionSet::new_action_set(const char *p_name, const char *p_localized_name, const int p_priority) {
|
||||
// This is a helper function to help build our default action sets
|
||||
|
||||
Ref<OpenXRActionSet> action_set;
|
||||
action_set.instantiate();
|
||||
action_set->set_name(String(p_name));
|
||||
action_set->set_localized_name(p_localized_name);
|
||||
action_set->set_priority(p_priority);
|
||||
|
||||
return action_set;
|
||||
}
|
||||
|
||||
void OpenXRActionSet::set_localized_name(const String p_localized_name) {
|
||||
localized_name = p_localized_name;
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
String OpenXRActionSet::get_localized_name() const {
|
||||
return localized_name;
|
||||
}
|
||||
|
||||
void OpenXRActionSet::set_priority(const int p_priority) {
|
||||
priority = p_priority;
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
int OpenXRActionSet::get_priority() const {
|
||||
return priority;
|
||||
}
|
||||
|
||||
int OpenXRActionSet::get_action_count() const {
|
||||
return actions.size();
|
||||
}
|
||||
|
||||
void OpenXRActionSet::clear_actions() {
|
||||
// Actions held within our action set should be released and destroyed but just in case they are still used some where else
|
||||
if (actions.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < actions.size(); i++) {
|
||||
Ref<OpenXRAction> action = actions[i];
|
||||
action->action_set = nullptr;
|
||||
}
|
||||
actions.clear();
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void OpenXRActionSet::set_actions(Array p_actions) {
|
||||
// Any actions not retained in p_actions should be freed automatically, those held within our Array will have be relinked to our action set.
|
||||
clear_actions();
|
||||
|
||||
for (int i = 0; i < p_actions.size(); i++) {
|
||||
// add them anew so we verify our action_set pointer
|
||||
add_action(p_actions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Array OpenXRActionSet::get_actions() const {
|
||||
return actions;
|
||||
}
|
||||
|
||||
Ref<OpenXRAction> OpenXRActionSet::get_action(const String p_name) const {
|
||||
for (int i = 0; i < actions.size(); i++) {
|
||||
Ref<OpenXRAction> action = actions[i];
|
||||
if (action->get_name() == p_name) {
|
||||
return action;
|
||||
}
|
||||
}
|
||||
|
||||
return Ref<OpenXRAction>();
|
||||
}
|
||||
|
||||
void OpenXRActionSet::add_action(Ref<OpenXRAction> p_action) {
|
||||
ERR_FAIL_COND(p_action.is_null());
|
||||
|
||||
if (!actions.has(p_action)) {
|
||||
if (p_action->action_set && p_action->action_set != this) {
|
||||
// action should only relate to our action set
|
||||
p_action->action_set->remove_action(p_action);
|
||||
}
|
||||
|
||||
p_action->action_set = this;
|
||||
actions.push_back(p_action);
|
||||
emit_changed();
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRActionSet::remove_action(Ref<OpenXRAction> p_action) {
|
||||
int idx = actions.find(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!
|
||||
p_action->action_set = nullptr;
|
||||
|
||||
emit_changed();
|
||||
}
|
||||
}
|
||||
|
||||
Ref<OpenXRAction> OpenXRActionSet::add_new_action(const char *p_name, const char *p_localized_name, const OpenXRAction::ActionType p_action_type, const char *p_toplevel_paths) {
|
||||
// This is a helper function to help build our default action sets
|
||||
|
||||
Ref<OpenXRAction> new_action = OpenXRAction::new_action(p_name, p_localized_name, p_action_type, p_toplevel_paths);
|
||||
add_action(new_action);
|
||||
return new_action;
|
||||
}
|
||||
|
||||
OpenXRActionSet::~OpenXRActionSet() {
|
||||
clear_actions();
|
||||
}
|
||||
75
engine/modules/openxr/action_map/openxr_action_set.h
Normal file
75
engine/modules/openxr/action_map/openxr_action_set.h
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_action_set.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_ACTION_SET_H
|
||||
#define OPENXR_ACTION_SET_H
|
||||
|
||||
#include "openxr_action.h"
|
||||
|
||||
#include "core/io/resource.h"
|
||||
|
||||
class OpenXRActionSet : public Resource {
|
||||
GDCLASS(OpenXRActionSet, Resource);
|
||||
|
||||
private:
|
||||
String localized_name;
|
||||
int priority = 0;
|
||||
|
||||
Array actions;
|
||||
void clear_actions();
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
static Ref<OpenXRActionSet> new_action_set(const char *p_name, const char *p_localized_name, const int p_priority = 0); // Helper function for adding and setting up an action set
|
||||
|
||||
void set_localized_name(const String p_localized_name); // Set the localized name of this action set
|
||||
String get_localized_name() const; // Get the localized name of this action set
|
||||
|
||||
void set_priority(const int p_priority); // Set the priority of this action set
|
||||
int get_priority() const; // Get the priority of this action set
|
||||
|
||||
int get_action_count() const; // Retrieve the number of actions in our action set
|
||||
void set_actions(Array p_actions); // Set our actions using an array of actions (for loading a resource)
|
||||
Array get_actions() const; // Get our actions as an array (for saving a resource)
|
||||
|
||||
Ref<OpenXRAction> get_action(const String p_name) const; // Retrieve an action by name
|
||||
void add_action(Ref<OpenXRAction> p_action); // Add a new action to our action set
|
||||
void remove_action(Ref<OpenXRAction> p_action); // remove a action from our action set
|
||||
|
||||
Ref<OpenXRAction> add_new_action(const char *p_name, const char *p_localized_name, const OpenXRAction::ActionType p_action_type, const char *p_toplevel_paths); // Helper function for adding and setting up an action
|
||||
|
||||
// TODO add validation to display in the interface that checks if we have duplicate action names within our action set
|
||||
|
||||
~OpenXRActionSet();
|
||||
};
|
||||
|
||||
#endif // OPENXR_ACTION_SET_H
|
||||
52
engine/modules/openxr/action_map/openxr_binding_modifier.cpp
Normal file
52
engine/modules/openxr/action_map/openxr_binding_modifier.cpp
Normal 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();
|
||||
}
|
||||
81
engine/modules/openxr/action_map/openxr_binding_modifier.h
Normal file
81
engine/modules/openxr/action_map/openxr_binding_modifier.h
Normal 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
|
||||
93
engine/modules/openxr/action_map/openxr_haptic_feedback.cpp
Normal file
93
engine/modules/openxr/action_map/openxr_haptic_feedback.cpp
Normal 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;
|
||||
}
|
||||
72
engine/modules/openxr/action_map/openxr_haptic_feedback.h
Normal file
72
engine/modules/openxr/action_map/openxr_haptic_feedback.h
Normal 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
|
||||
431
engine/modules/openxr/action_map/openxr_interaction_profile.cpp
Normal file
431
engine/modules/openxr/action_map/openxr_interaction_profile.cpp
Normal file
|
|
@ -0,0 +1,431 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_interaction_profile.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_interaction_profile.h"
|
||||
|
||||
void OpenXRIPBinding::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_action", "action"), &OpenXRIPBinding::set_action);
|
||||
ClassDB::bind_method(D_METHOD("get_action"), &OpenXRIPBinding::get_action);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "action", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRAction"), "set_action", "get_action");
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_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", 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 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->set_binding_path(p_binding_path);
|
||||
|
||||
return binding;
|
||||
}
|
||||
|
||||
void OpenXRIPBinding::set_action(const Ref<OpenXRAction> &p_action) {
|
||||
action = p_action;
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
Ref<OpenXRAction> OpenXRIPBinding::get_action() const {
|
||||
return action;
|
||||
}
|
||||
|
||||
void OpenXRIPBinding::set_binding_path(const String &path) {
|
||||
binding_path = path;
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
#endif // DISABLE_DEPRECATED
|
||||
|
||||
OpenXRIPBinding::~OpenXRIPBinding() {
|
||||
action.unref();
|
||||
}
|
||||
|
||||
void OpenXRInteractionProfile::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_interaction_profile_path", "interaction_profile_path"), &OpenXRInteractionProfile::set_interaction_profile_path);
|
||||
ClassDB::bind_method(D_METHOD("get_interaction_profile_path"), &OpenXRInteractionProfile::get_interaction_profile_path);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "interaction_profile_path"), "set_interaction_profile_path", "get_interaction_profile_path");
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_binding_count"), &OpenXRInteractionProfile::get_binding_count);
|
||||
ClassDB::bind_method(D_METHOD("get_binding", "index"), &OpenXRInteractionProfile::get_binding);
|
||||
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) {
|
||||
Ref<OpenXRInteractionProfile> profile;
|
||||
profile.instantiate();
|
||||
profile->set_interaction_profile_path(String(p_input_profile_path));
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
void OpenXRInteractionProfile::set_interaction_profile_path(const String p_input_profile_path) {
|
||||
OpenXRInteractionProfileMetadata *pmd = OpenXRInteractionProfileMetadata::get_singleton();
|
||||
if (pmd) {
|
||||
interaction_profile_path = pmd->check_profile_name(p_input_profile_path);
|
||||
} else {
|
||||
// OpenXR module not enabled, ignore checks.
|
||||
interaction_profile_path = p_input_profile_path;
|
||||
}
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
String OpenXRInteractionProfile::get_interaction_profile_path() const {
|
||||
return interaction_profile_path;
|
||||
}
|
||||
|
||||
int OpenXRInteractionProfile::get_binding_count() const {
|
||||
return bindings.size();
|
||||
}
|
||||
|
||||
Ref<OpenXRIPBinding> OpenXRInteractionProfile::get_binding(int p_index) const {
|
||||
ERR_FAIL_INDEX_V(p_index, bindings.size(), Ref<OpenXRIPBinding>());
|
||||
|
||||
return bindings[p_index];
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
Array OpenXRInteractionProfile::get_bindings() const {
|
||||
return bindings;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return Ref<OpenXRIPBinding>();
|
||||
}
|
||||
|
||||
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(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(const Ref<OpenXRIPBinding> &p_binding) {
|
||||
int idx = bindings.find(p_binding);
|
||||
if (idx != -1) {
|
||||
bindings.remove_at(idx);
|
||||
emit_changed();
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
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) {
|
||||
for (int i = bindings.size() - 1; i >= 0; i--) {
|
||||
Ref<OpenXRIPBinding> binding = bindings[i];
|
||||
if (binding->get_action() == p_action) {
|
||||
remove_binding(binding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
141
engine/modules/openxr/action_map/openxr_interaction_profile.h
Normal file
141
engine/modules/openxr/action_map/openxr_interaction_profile.h
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_interaction_profile.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_INTERACTION_PROFILE_H
|
||||
#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;
|
||||
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 String &p_binding_path); // Helper function for adding a new binding.
|
||||
|
||||
OpenXRActionMap *get_action_map() { return action_map; } // Return the action map we're a part of.
|
||||
|
||||
void set_action(const Ref<OpenXRAction> &p_action); // Set the action for this binding.
|
||||
Ref<OpenXRAction> get_action() const; // Get the action for this binding.
|
||||
|
||||
void set_binding_path(const String &path);
|
||||
String get_binding_path() const;
|
||||
|
||||
int get_binding_modifier_count() const; // Retrieve the number of binding modifiers in this profile path
|
||||
Ref<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
|
||||
|
||||
~OpenXRIPBinding();
|
||||
};
|
||||
|
||||
class OpenXRInteractionProfile : public Resource {
|
||||
GDCLASS(OpenXRInteractionProfile, 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(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> 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 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();
|
||||
};
|
||||
|
||||
#endif // OPENXR_INTERACTION_PROFILE_H
|
||||
|
|
@ -0,0 +1,388 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_interaction_profile_metadata.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_interaction_profile_metadata.h"
|
||||
|
||||
#include "../openxr_api.h"
|
||||
|
||||
OpenXRInteractionProfileMetadata *OpenXRInteractionProfileMetadata::singleton = nullptr;
|
||||
|
||||
OpenXRInteractionProfileMetadata::OpenXRInteractionProfileMetadata() {
|
||||
singleton = this;
|
||||
|
||||
_register_core_metadata();
|
||||
OpenXRAPI::register_extension_metadata();
|
||||
}
|
||||
|
||||
OpenXRInteractionProfileMetadata::~OpenXRInteractionProfileMetadata() {
|
||||
singleton = nullptr;
|
||||
}
|
||||
|
||||
void OpenXRInteractionProfileMetadata::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("register_profile_rename", "old_name", "new_name"), &OpenXRInteractionProfileMetadata::register_profile_rename);
|
||||
ClassDB::bind_method(D_METHOD("register_top_level_path", "display_name", "openxr_path", "openxr_extension_name"), &OpenXRInteractionProfileMetadata::register_top_level_path);
|
||||
ClassDB::bind_method(D_METHOD("register_interaction_profile", "display_name", "openxr_path", "openxr_extension_name"), &OpenXRInteractionProfileMetadata::register_interaction_profile);
|
||||
ClassDB::bind_method(D_METHOD("register_io_path", "interaction_profile", "display_name", "toplevel_path", "openxr_path", "openxr_extension_name", "action_type"), &OpenXRInteractionProfileMetadata::register_io_path);
|
||||
}
|
||||
|
||||
void OpenXRInteractionProfileMetadata::register_profile_rename(const String &p_old_name, const String &p_new_name) {
|
||||
ERR_FAIL_COND(profile_renames.has(p_old_name));
|
||||
|
||||
profile_renames[p_old_name] = p_new_name;
|
||||
}
|
||||
|
||||
String OpenXRInteractionProfileMetadata::check_profile_name(const String &p_name) const {
|
||||
if (profile_renames.has(p_name)) {
|
||||
return profile_renames[p_name];
|
||||
}
|
||||
|
||||
return p_name;
|
||||
}
|
||||
|
||||
void OpenXRInteractionProfileMetadata::register_top_level_path(const String &p_display_name, const String &p_openxr_path, const String &p_openxr_extension_name) {
|
||||
ERR_FAIL_COND_MSG(has_top_level_path(p_openxr_path), p_openxr_path + " had already been registered");
|
||||
|
||||
TopLevelPath new_toplevel_path = {
|
||||
p_display_name,
|
||||
p_openxr_path,
|
||||
p_openxr_extension_name
|
||||
};
|
||||
|
||||
top_level_paths.push_back(new_toplevel_path);
|
||||
}
|
||||
|
||||
void OpenXRInteractionProfileMetadata::register_interaction_profile(const String &p_display_name, const String &p_openxr_path, const String &p_openxr_extension_name) {
|
||||
ERR_FAIL_COND_MSG(has_interaction_profile(p_openxr_path), p_openxr_path + " has already been registered");
|
||||
|
||||
InteractionProfile new_profile;
|
||||
new_profile.display_name = p_display_name;
|
||||
new_profile.openxr_path = p_openxr_path;
|
||||
new_profile.openxr_extension_name = p_openxr_extension_name;
|
||||
|
||||
interaction_profiles.push_back(new_profile);
|
||||
}
|
||||
|
||||
void OpenXRInteractionProfileMetadata::register_io_path(const String &p_interaction_profile, const String &p_display_name, const String &p_toplevel_path, const String &p_openxr_path, const String &p_openxr_extension_name, OpenXRAction::ActionType p_action_type) {
|
||||
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 (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,
|
||||
p_toplevel_path,
|
||||
p_openxr_path,
|
||||
p_openxr_extension_name,
|
||||
p_action_type
|
||||
};
|
||||
|
||||
interaction_profile.io_paths.push_back(new_io_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool OpenXRInteractionProfileMetadata::has_top_level_path(const String p_openxr_path) const {
|
||||
for (int i = 0; i < top_level_paths.size(); i++) {
|
||||
if (top_level_paths[i].openxr_path == p_openxr_path) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
String OpenXRInteractionProfileMetadata::get_top_level_name(const String p_openxr_path) const {
|
||||
for (int i = 0; i < top_level_paths.size(); i++) {
|
||||
if (top_level_paths[i].openxr_path == p_openxr_path) {
|
||||
return top_level_paths[i].display_name;
|
||||
}
|
||||
}
|
||||
|
||||
return String();
|
||||
}
|
||||
|
||||
String OpenXRInteractionProfileMetadata::get_top_level_extension(const String p_openxr_path) const {
|
||||
for (int i = 0; i < top_level_paths.size(); i++) {
|
||||
if (top_level_paths[i].openxr_path == p_openxr_path) {
|
||||
return top_level_paths[i].openxr_extension_name;
|
||||
}
|
||||
}
|
||||
|
||||
return XR_PATH_UNSUPPORTED_NAME;
|
||||
}
|
||||
|
||||
bool OpenXRInteractionProfileMetadata::has_interaction_profile(const String p_openxr_path) const {
|
||||
for (const InteractionProfile &interaction_profile : interaction_profiles) {
|
||||
if (interaction_profile.openxr_path == p_openxr_path) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
String OpenXRInteractionProfileMetadata::get_interaction_profile_extension(const String p_openxr_path) const {
|
||||
for (const InteractionProfile &interaction_profile : interaction_profiles) {
|
||||
if (interaction_profile.openxr_path == p_openxr_path) {
|
||||
return interaction_profile.openxr_extension_name;
|
||||
}
|
||||
}
|
||||
|
||||
return XR_PATH_UNSUPPORTED_NAME;
|
||||
}
|
||||
|
||||
const OpenXRInteractionProfileMetadata::InteractionProfile *OpenXRInteractionProfileMetadata::get_profile(const String p_openxr_path) const {
|
||||
for (const InteractionProfile &interaction_profile : interaction_profiles) {
|
||||
if (interaction_profile.openxr_path == p_openxr_path) {
|
||||
return &interaction_profile;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool OpenXRInteractionProfileMetadata::InteractionProfile::has_io_path(const String p_io_path) const {
|
||||
for (int i = 0; i < io_paths.size(); i++) {
|
||||
if (io_paths[i].openxr_path == p_io_path) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const OpenXRInteractionProfileMetadata::IOPath *OpenXRInteractionProfileMetadata::InteractionProfile::get_io_path(const String p_io_path) const {
|
||||
for (int i = 0; i < io_paths.size(); i++) {
|
||||
if (io_paths[i].openxr_path == p_io_path) {
|
||||
return &io_paths[i];
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const OpenXRInteractionProfileMetadata::IOPath *OpenXRInteractionProfileMetadata::get_io_path(const String p_interaction_profile, const String p_io_path) const {
|
||||
const OpenXRInteractionProfileMetadata::InteractionProfile *profile = get_profile(p_interaction_profile);
|
||||
if (profile != nullptr) {
|
||||
return profile->get_io_path(p_io_path);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PackedStringArray OpenXRInteractionProfileMetadata::get_interaction_profile_paths() const {
|
||||
PackedStringArray arr;
|
||||
|
||||
for (const InteractionProfile &interaction_profile : interaction_profiles) {
|
||||
arr.push_back(interaction_profile.openxr_path);
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
void OpenXRInteractionProfileMetadata::_register_core_metadata() {
|
||||
// Note, currently we add definitions that belong in extensions.
|
||||
// Extensions are registered when our OpenXRAPI is instantiated
|
||||
// however this does not happen in the editor.
|
||||
// We are changing this in another PR, once that is accepted we
|
||||
// can make the changes to move code into extensions where needed.
|
||||
|
||||
// Note that we'll make an exception for XR_EXT_palm_pose, which is used everywhere
|
||||
|
||||
// Our core toplevel paths
|
||||
register_top_level_path("Left hand controller", "/user/hand/left", "");
|
||||
register_top_level_path("Right hand controller", "/user/hand/right", "");
|
||||
register_top_level_path("Head", "/user/head", "");
|
||||
register_top_level_path("Gamepad", "/user/gamepad", "");
|
||||
register_top_level_path("Treadmill", "/user/treadmill", "");
|
||||
|
||||
{ // Fallback Khronos simple controller
|
||||
const String profile_path = "/interaction_profiles/khr/simple_controller";
|
||||
register_interaction_profile("Simple controller", profile_path, "");
|
||||
for (const String user_path : { "/user/hand/left", "/user/hand/right" }) {
|
||||
register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
|
||||
|
||||
register_io_path(profile_path, "Menu click", user_path, user_path + "/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Select click", user_path, user_path + "/input/select/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
|
||||
}
|
||||
}
|
||||
|
||||
{ // Original HTC Vive wands
|
||||
const String profile_path = "/interaction_profiles/htc/vive_controller";
|
||||
register_interaction_profile("HTC Vive wand", profile_path, "");
|
||||
for (const String user_path : { "/user/hand/left", "/user/hand/right" }) {
|
||||
register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
|
||||
|
||||
register_io_path(profile_path, "Menu click", user_path, user_path + "/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "System click", user_path, user_path + "/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
register_io_path(profile_path, "Trigger click", user_path, user_path + "/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
register_io_path(profile_path, "Squeeze click", user_path, user_path + "/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
register_io_path(profile_path, "Trackpad", user_path, user_path + "/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
|
||||
register_io_path(profile_path, "Trackpad click", user_path, user_path + "/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Trackpad touch", user_path, user_path + "/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Trackpad Dpad Up", user_path, user_path + "/input/trackpad/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Trackpad Dpad Down", user_path, user_path + "/input/trackpad/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Trackpad Dpad Left", user_path, user_path + "/input/trackpad/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Trackpad Dpad Right", user_path, user_path + "/input/trackpad/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Trackpad Dpad Center", user_path, user_path + "/input/trackpad/dpad_center", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
|
||||
}
|
||||
}
|
||||
|
||||
{ // Microsoft motion controller (original WMR controllers)
|
||||
const String profile_path = "/interaction_profiles/microsoft/motion_controller";
|
||||
register_interaction_profile("MS Motion controller", profile_path, "");
|
||||
for (const String user_path : { "/user/hand/left", "/user/hand/right" }) {
|
||||
register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
|
||||
|
||||
register_io_path(profile_path, "Menu click", user_path, user_path + "/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
register_io_path(profile_path, "Trigger click", user_path, user_path + "/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
register_io_path(profile_path, "Squeeze click", user_path, user_path + "/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
|
||||
register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
register_io_path(profile_path, "Trackpad", user_path, user_path + "/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
|
||||
register_io_path(profile_path, "Trackpad click", user_path, user_path + "/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Trackpad touch", user_path, user_path + "/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Trackpad Dpad Up", user_path, user_path + "/input/trackpad/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Trackpad Dpad Down", user_path, user_path + "/input/trackpad/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Trackpad Dpad Left", user_path, user_path + "/input/trackpad/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Trackpad Dpad Right", user_path, user_path + "/input/trackpad/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Trackpad Dpad Center", user_path, user_path + "/input/trackpad/dpad_center", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
|
||||
}
|
||||
}
|
||||
|
||||
{ // Meta touch controller (original touch controllers, Quest 1 and Quest 2 controllers)
|
||||
const String profile_path = "/interaction_profiles/oculus/touch_controller";
|
||||
register_interaction_profile("Touch controller", profile_path, "");
|
||||
for (const String user_path : { "/user/hand/left", "/user/hand/right" }) {
|
||||
register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
|
||||
|
||||
register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
register_io_path(profile_path, "Trigger touch", user_path, user_path + "/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
register_io_path(profile_path, "Squeeze", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
|
||||
register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
|
||||
register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Thumbstick touch", user_path, user_path + "/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
register_io_path(profile_path, "Thumbrest touch", user_path, user_path + "/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
|
||||
}
|
||||
|
||||
register_io_path(profile_path, "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
register_io_path(profile_path, "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
}
|
||||
|
||||
{ // Valve Index controller
|
||||
const String profile_path = "/interaction_profiles/valve/index_controller";
|
||||
register_interaction_profile("Index controller", profile_path, "");
|
||||
for (const String user_path : { "/user/hand/left", "/user/hand/right" }) {
|
||||
register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
|
||||
|
||||
register_io_path(profile_path, "System click", user_path, user_path + "/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
register_io_path(profile_path, "A click", user_path, user_path + "/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "A touch", user_path, user_path + "/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "B click", user_path, user_path + "/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "B touch", user_path, user_path + "/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
register_io_path(profile_path, "Trigger click", user_path, user_path + "/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Trigger touch", user_path, user_path + "/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
register_io_path(profile_path, "Squeeze", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
register_io_path(profile_path, "Squeeze force", user_path, user_path + "/input/squeeze/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
|
||||
register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
|
||||
register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Thumbstick touch", user_path, user_path + "/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
register_io_path(profile_path, "Trackpad", user_path, user_path + "/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
|
||||
register_io_path(profile_path, "Trackpad force", user_path, user_path + "/input/trackpad/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
register_io_path(profile_path, "Trackpad touch", user_path, user_path + "/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Trackpad Dpad Up", user_path, user_path + "/input/trackpad/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Trackpad Dpad Down", user_path, user_path + "/input/trackpad/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Trackpad Dpad Left", user_path, user_path + "/input/trackpad/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Trackpad Dpad Right", user_path, user_path + "/input/trackpad/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
register_io_path(profile_path, "Trackpad Dpad Center", user_path, user_path + "/input/trackpad/dpad_center", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_interaction_profile_metadata.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_INTERACTION_PROFILE_METADATA_H
|
||||
#define OPENXR_INTERACTION_PROFILE_METADATA_H
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Stores available interaction profile metadata
|
||||
//
|
||||
// OpenXR defines and hardcodes all the supported input devices and their
|
||||
// paths as part of the OpenXR spec. When support for new devices is
|
||||
// introduced this often starts life as an extension that needs to be enabled
|
||||
// until it's adopted into the core. As there is no interface to
|
||||
// enumerate the possibly paths, and that any OpenXR runtime would likely
|
||||
// limit such enumeration to those input devices supported by that runtime
|
||||
// there is no other option than to hardcode this.
|
||||
//
|
||||
// Note that we need to include paths of our extensions in our action map
|
||||
// regardless of whether the developers machine supports the extension or
|
||||
// not. Unsupported paths are filtered out when the action map is submitted
|
||||
// to the OpenXR runtime.
|
||||
//
|
||||
// Note on action type that automatic conversions between boolean and float
|
||||
// are supported but otherwise action types should match between action and
|
||||
// input/output paths.
|
||||
|
||||
#include "openxr_action.h"
|
||||
|
||||
#include "core/object/object.h"
|
||||
#include "core/templates/hash_map.h"
|
||||
|
||||
#define XR_PATH_UNSUPPORTED_NAME "unsupported"
|
||||
|
||||
class OpenXRInteractionProfileMetadata : public Object {
|
||||
GDCLASS(OpenXRInteractionProfileMetadata, Object);
|
||||
|
||||
public:
|
||||
struct TopLevelPath {
|
||||
String display_name; // User friendly display name (i.e. Left controller)
|
||||
String openxr_path; // Path in OpenXR (i.e. /user/hand/left)
|
||||
String openxr_extension_name; // If set, only available if extension is enabled (i.e. XR_HTCX_vive_tracker_interaction)
|
||||
};
|
||||
|
||||
struct IOPath {
|
||||
String display_name; // User friendly display name (i.e. Grip pose (left controller))
|
||||
String top_level_path; // Top level path identifying the usage of the device in relation to this input/output
|
||||
String openxr_path; // Path in OpenXR (i.e. /user/hand/left/input/grip/pose)
|
||||
String openxr_extension_name; // If set, only available if extension is enabled (i.e. XR_EXT_palm_pose)
|
||||
OpenXRAction::ActionType action_type; // Type of input/output
|
||||
};
|
||||
|
||||
struct InteractionProfile {
|
||||
String display_name; // User friendly display name (i.e. Simple controller)
|
||||
String openxr_path; // Path in OpenXR (i.e. /interaction_profiles/khr/simple_controller)
|
||||
String openxr_extension_name; // If set, only available if extension is enabled (i.e. XR_HTCX_vive_tracker_interaction)
|
||||
Vector<IOPath> io_paths; // Inputs and outputs for this device
|
||||
|
||||
bool has_io_path(const String p_io_path) const;
|
||||
const IOPath *get_io_path(const String p_io_path) const;
|
||||
};
|
||||
|
||||
private:
|
||||
static OpenXRInteractionProfileMetadata *singleton;
|
||||
|
||||
HashMap<String, String> profile_renames;
|
||||
Vector<TopLevelPath> top_level_paths;
|
||||
Vector<InteractionProfile> interaction_profiles;
|
||||
|
||||
void _register_core_metadata();
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
static OpenXRInteractionProfileMetadata *get_singleton() { return singleton; }
|
||||
|
||||
OpenXRInteractionProfileMetadata();
|
||||
~OpenXRInteractionProfileMetadata();
|
||||
|
||||
void register_profile_rename(const String &p_old_name, const String &p_new_name);
|
||||
String check_profile_name(const String &p_name) const;
|
||||
|
||||
void register_top_level_path(const String &p_display_name, const String &p_openxr_path, const String &p_openxr_extension_name);
|
||||
bool has_top_level_path(const String p_openxr_path) const;
|
||||
String get_top_level_name(const String p_openxr_path) const;
|
||||
String get_top_level_extension(const String p_openxr_path) const;
|
||||
|
||||
void register_interaction_profile(const String &p_display_name, const String &p_openxr_path, const String &p_openxr_extension_name);
|
||||
bool has_interaction_profile(const String p_openxr_path) const;
|
||||
String get_interaction_profile_extension(const String p_openxr_path) const;
|
||||
const InteractionProfile *get_profile(const String p_openxr_path) const;
|
||||
PackedStringArray get_interaction_profile_paths() const;
|
||||
|
||||
void register_io_path(const String &p_interaction_profile, const String &p_display_name, const String &p_toplevel_path, const String &p_openxr_path, const String &p_openxr_extension_name, OpenXRAction::ActionType p_action_type);
|
||||
const IOPath *get_io_path(const String p_interaction_profile, const String p_io_path) const;
|
||||
};
|
||||
|
||||
#endif // OPENXR_INTERACTION_PROFILE_METADATA_H
|
||||
44
engine/modules/openxr/config.py
Normal file
44
engine/modules/openxr/config.py
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
def can_build(env, platform):
|
||||
if platform in ("linuxbsd", "windows", "android", "macos"):
|
||||
return env["openxr"] and not env["disable_3d"]
|
||||
else:
|
||||
# not supported on these platforms
|
||||
return False
|
||||
|
||||
|
||||
def configure(env):
|
||||
pass
|
||||
|
||||
|
||||
def get_doc_classes():
|
||||
return [
|
||||
"OpenXRInterface",
|
||||
"OpenXRAction",
|
||||
"OpenXRActionSet",
|
||||
"OpenXRActionMap",
|
||||
"OpenXRAPIExtension",
|
||||
"OpenXRExtensionWrapperExtension",
|
||||
"OpenXRInteractionProfile",
|
||||
"OpenXRInteractionProfileMetadata",
|
||||
"OpenXRIPBinding",
|
||||
"OpenXRHand",
|
||||
"OpenXRVisibilityMask",
|
||||
"OpenXRCompositionLayer",
|
||||
"OpenXRCompositionLayerQuad",
|
||||
"OpenXRCompositionLayerCylinder",
|
||||
"OpenXRCompositionLayerEquirect",
|
||||
"OpenXRBindingModifier",
|
||||
"OpenXRIPBindingModifier",
|
||||
"OpenXRActionBindingModifier",
|
||||
"OpenXRAnalogThresholdModifier",
|
||||
"OpenXRDpadBindingModifier",
|
||||
"OpenXRInteractionProfileEditorBase",
|
||||
"OpenXRInteractionProfileEditor",
|
||||
"OpenXRBindingModifierEditor",
|
||||
"OpenXRHapticBase",
|
||||
"OpenXRHapticVibration",
|
||||
]
|
||||
|
||||
|
||||
def get_doc_path():
|
||||
return "doc_classes"
|
||||
326
engine/modules/openxr/doc_classes/OpenXRAPIExtension.xml
Normal file
326
engine/modules/openxr/doc_classes/OpenXRAPIExtension.xml
Normal file
|
|
@ -0,0 +1,326 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="OpenXRAPIExtension" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Makes the OpenXR API available for GDExtension.
|
||||
</brief_description>
|
||||
<description>
|
||||
[OpenXRAPIExtension] makes OpenXR available for GDExtension. It provides the OpenXR API to GDExtension through the [method get_instance_proc_addr] method, and the OpenXR instance through [method get_instance].
|
||||
It also provides methods for querying the status of OpenXR initialization, and helper methods for ease of use of the API with GDExtension.
|
||||
</description>
|
||||
<tutorials>
|
||||
<link title="XrResult documentation">https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrResult.html</link>
|
||||
<link title="XrInstance documentation">https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrInstance.html</link>
|
||||
<link title="XrSpace documentation">https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrSpace.html</link>
|
||||
<link title="XrSession documentation">https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrSession.html</link>
|
||||
<link title="XrSystemId documentation">https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrSystemId.html</link>
|
||||
<link title="xrBeginSession documentation">https://registry.khronos.org/OpenXR/specs/1.0/man/html/xrBeginSession.html</link>
|
||||
<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" />
|
||||
<description>
|
||||
Returns an error string for the given [url=https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrResult.html]XrResult[/url].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_hand_tracker">
|
||||
<return type="int" />
|
||||
<param index="0" name="hand_index" type="int" />
|
||||
<description>
|
||||
Returns the corresponding [code]XRHandTrackerEXT[/code] handle for the given hand index value.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_instance">
|
||||
<return type="int" />
|
||||
<description>
|
||||
Returns the [url=https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrInstance.html]XrInstance[/url] created during the initialization of the OpenXR API.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_instance_proc_addr">
|
||||
<return type="int" />
|
||||
<param index="0" name="name" type="String" />
|
||||
<description>
|
||||
Returns the function pointer of the OpenXR function with the specified name, cast to an integer. If the function with the given name does not exist, the method returns [code]0[/code].
|
||||
[b]Note:[/b] [code]openxr/util.h[/code] contains utility macros for acquiring OpenXR functions, e.g. [code]GDEXTENSION_INIT_XR_FUNC_V(xrCreateAction)[/code].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_next_frame_time">
|
||||
<return type="int" />
|
||||
<description>
|
||||
Returns the predicted display timing for the next frame.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_play_space">
|
||||
<return type="int" />
|
||||
<description>
|
||||
Returns the play space, which is an [url=https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrSpace.html]XrSpace[/url] cast to an integer.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_predicted_display_time">
|
||||
<return type="int" />
|
||||
<description>
|
||||
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" />
|
||||
<description>
|
||||
Returns the name of the specified swapchain format.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_system_id">
|
||||
<return type="int" />
|
||||
<description>
|
||||
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>
|
||||
Returns [enum OpenXRAPIExtension.OpenXRAlphaBlendModeSupport] denoting if [constant XRInterface.XR_ENV_BLEND_MODE_ALPHA_BLEND] is really supported, emulated or not supported at all.
|
||||
</description>
|
||||
</method>
|
||||
<method name="is_initialized">
|
||||
<return type="bool" />
|
||||
<description>
|
||||
Returns [code]true[/code] if OpenXR is initialized.
|
||||
</description>
|
||||
</method>
|
||||
<method name="is_running">
|
||||
<return type="bool" />
|
||||
<description>
|
||||
Returns [code]true[/code] if OpenXR is running ([url=https://registry.khronos.org/OpenXR/specs/1.0/man/html/xrBeginSession.html]xrBeginSession[/url] was successfully called and the swapchains were created).
|
||||
</description>
|
||||
</method>
|
||||
<method name="openxr_is_enabled" qualifiers="static">
|
||||
<return type="bool" />
|
||||
<param index="0" name="check_run_in_editor" type="bool" />
|
||||
<description>
|
||||
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" />
|
||||
<description>
|
||||
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" />
|
||||
<description>
|
||||
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*" />
|
||||
<description>
|
||||
Creates a [Transform3D] from an [url=https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrPosef.html]XrPosef[/url].
|
||||
</description>
|
||||
</method>
|
||||
<method name="unregister_composition_layer_provider">
|
||||
<return type="void" />
|
||||
<param index="0" name="extension" type="OpenXRExtensionWrapperExtension" />
|
||||
<description>
|
||||
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" />
|
||||
<param index="1" name="format" type="String" />
|
||||
<param index="2" name="args" type="Array" />
|
||||
<description>
|
||||
Returns [code]true[/code] if the provided [url=https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrResult.html]XrResult[/url] (cast to an integer) is successful. Otherwise returns [code]false[/code] and prints the [url=https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrResult.html]XrResult[/url] converted to a string, with the specified additional information.
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<constants>
|
||||
<constant name="OPENXR_ALPHA_BLEND_MODE_SUPPORT_NONE" value="0" enum="OpenXRAlphaBlendModeSupport">
|
||||
Means that [constant XRInterface.XR_ENV_BLEND_MODE_ALPHA_BLEND] isn't supported at all.
|
||||
</constant>
|
||||
<constant name="OPENXR_ALPHA_BLEND_MODE_SUPPORT_REAL" value="1" enum="OpenXRAlphaBlendModeSupport">
|
||||
Means that [constant XRInterface.XR_ENV_BLEND_MODE_ALPHA_BLEND] is really supported.
|
||||
</constant>
|
||||
<constant name="OPENXR_ALPHA_BLEND_MODE_SUPPORT_EMULATING" value="2" enum="OpenXRAlphaBlendModeSupport">
|
||||
Means that [constant XRInterface.XR_ENV_BLEND_MODE_ALPHA_BLEND] is emulated.
|
||||
</constant>
|
||||
</constants>
|
||||
</class>
|
||||
38
engine/modules/openxr/doc_classes/OpenXRAction.xml
Normal file
38
engine/modules/openxr/doc_classes/OpenXRAction.xml
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="OpenXRAction" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
An OpenXR action.
|
||||
</brief_description>
|
||||
<description>
|
||||
This resource defines an OpenXR action. Actions can be used both for inputs (buttons, joysticks, triggers, etc.) and outputs (haptics).
|
||||
OpenXR performs automatic conversion between action type and input type whenever possible. An analog trigger bound to a boolean action will thus return [code]false[/code] if the trigger is depressed and [code]true[/code] if pressed fully.
|
||||
Actions are not directly bound to specific devices, instead OpenXR recognizes a limited number of top level paths that identify devices by usage. We can restrict which devices an action can be bound to by these top level paths. For instance an action that should only be used for hand held controllers can have the top level paths "/user/hand/left" and "/user/hand/right" associated with them. See the [url=https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#semantic-path-reserved]reserved path section in the OpenXR specification[/url] for more info on the top level paths.
|
||||
Note that the name of the resource is used to register the action with.
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<members>
|
||||
<member name="action_type" type="int" setter="set_action_type" getter="get_action_type" enum="OpenXRAction.ActionType" default="1">
|
||||
The type of action.
|
||||
</member>
|
||||
<member name="localized_name" type="String" setter="set_localized_name" getter="get_localized_name" default="""">
|
||||
The localized description of this action.
|
||||
</member>
|
||||
<member name="toplevel_paths" type="PackedStringArray" setter="set_toplevel_paths" getter="get_toplevel_paths" default="PackedStringArray()">
|
||||
A collections of toplevel paths to which this action can be bound.
|
||||
</member>
|
||||
</members>
|
||||
<constants>
|
||||
<constant name="OPENXR_ACTION_BOOL" value="0" enum="ActionType">
|
||||
This action provides a boolean value.
|
||||
</constant>
|
||||
<constant name="OPENXR_ACTION_FLOAT" value="1" enum="ActionType">
|
||||
This action provides a float value between [code]0.0[/code] and [code]1.0[/code] for any analog input such as triggers.
|
||||
</constant>
|
||||
<constant name="OPENXR_ACTION_VECTOR2" value="2" enum="ActionType">
|
||||
This action provides a [Vector2] value and can be bound to embedded trackpads and joysticks.
|
||||
</constant>
|
||||
<constant name="OPENXR_ACTION_POSE" value="3" enum="ActionType">
|
||||
</constant>
|
||||
</constants>
|
||||
</class>
|
||||
|
|
@ -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>
|
||||
97
engine/modules/openxr/doc_classes/OpenXRActionMap.xml
Normal file
97
engine/modules/openxr/doc_classes/OpenXRActionMap.xml
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="OpenXRActionMap" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Collection of [OpenXRActionSet] and [OpenXRInteractionProfile] resources for the OpenXR module.
|
||||
</brief_description>
|
||||
<description>
|
||||
OpenXR uses an action system similar to Godots Input map system to bind inputs and outputs on various types of XR controllers to named actions. OpenXR specifies more detail on these inputs and outputs than Godot supports.
|
||||
Another important distinction is that OpenXR offers no control over these bindings. The bindings we register are suggestions, it is up to the XR runtime to offer users the ability to change these bindings. This allows the XR runtime to fill in the gaps if new hardware becomes available.
|
||||
The action map therefore needs to be loaded at startup and can't be changed afterwards. This resource is a container for the entire action map.
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="add_action_set">
|
||||
<return type="void" />
|
||||
<param index="0" name="action_set" type="OpenXRActionSet" />
|
||||
<description>
|
||||
Add an action set.
|
||||
</description>
|
||||
</method>
|
||||
<method name="add_interaction_profile">
|
||||
<return type="void" />
|
||||
<param index="0" name="interaction_profile" type="OpenXRInteractionProfile" />
|
||||
<description>
|
||||
Add an interaction profile.
|
||||
</description>
|
||||
</method>
|
||||
<method name="create_default_action_sets">
|
||||
<return type="void" />
|
||||
<description>
|
||||
Setup this action set with our default actions.
|
||||
</description>
|
||||
</method>
|
||||
<method name="find_action_set" qualifiers="const">
|
||||
<return type="OpenXRActionSet" />
|
||||
<param index="0" name="name" type="String" />
|
||||
<description>
|
||||
Retrieve an action set by name.
|
||||
</description>
|
||||
</method>
|
||||
<method name="find_interaction_profile" qualifiers="const">
|
||||
<return type="OpenXRInteractionProfile" />
|
||||
<param index="0" name="name" type="String" />
|
||||
<description>
|
||||
Find an interaction profile by its name (path).
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_action_set" qualifiers="const">
|
||||
<return type="OpenXRActionSet" />
|
||||
<param index="0" name="idx" type="int" />
|
||||
<description>
|
||||
Retrieve the action set at this index.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_action_set_count" qualifiers="const">
|
||||
<return type="int" />
|
||||
<description>
|
||||
Retrieve the number of actions sets in our action map.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_interaction_profile" qualifiers="const">
|
||||
<return type="OpenXRInteractionProfile" />
|
||||
<param index="0" name="idx" type="int" />
|
||||
<description>
|
||||
Get the interaction profile at this index.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_interaction_profile_count" qualifiers="const">
|
||||
<return type="int" />
|
||||
<description>
|
||||
Retrieve the number of interaction profiles in our action map.
|
||||
</description>
|
||||
</method>
|
||||
<method name="remove_action_set">
|
||||
<return type="void" />
|
||||
<param index="0" name="action_set" type="OpenXRActionSet" />
|
||||
<description>
|
||||
Remove an action set.
|
||||
</description>
|
||||
</method>
|
||||
<method name="remove_interaction_profile">
|
||||
<return type="void" />
|
||||
<param index="0" name="interaction_profile" type="OpenXRInteractionProfile" />
|
||||
<description>
|
||||
Remove an interaction profile.
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<members>
|
||||
<member name="action_sets" type="Array" setter="set_action_sets" getter="get_action_sets" default="[]">
|
||||
Collection of [OpenXRActionSet]s that are part of this action map.
|
||||
</member>
|
||||
<member name="interaction_profiles" type="Array" setter="set_interaction_profiles" getter="get_interaction_profiles" default="[]">
|
||||
Collection of [OpenXRInteractionProfile]s that are part of this action map.
|
||||
</member>
|
||||
</members>
|
||||
</class>
|
||||
45
engine/modules/openxr/doc_classes/OpenXRActionSet.xml
Normal file
45
engine/modules/openxr/doc_classes/OpenXRActionSet.xml
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="OpenXRActionSet" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Collection of [OpenXRAction] resources that make up an action set.
|
||||
</brief_description>
|
||||
<description>
|
||||
Action sets in OpenXR define a collection of actions that can be activated in unison. This allows games to easily change between different states that require different inputs or need to reinterpret inputs. For instance we could have an action set that is active when a menu is open, an action set that is active when the player is freely walking around and an action set that is active when the player is controlling a vehicle.
|
||||
Action sets can contain the same action with the same name, if such action sets are active at the same time the action set with the highest priority defines which binding is active.
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="add_action">
|
||||
<return type="void" />
|
||||
<param index="0" name="action" type="OpenXRAction" />
|
||||
<description>
|
||||
Add an action to this action set.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_action_count" qualifiers="const">
|
||||
<return type="int" />
|
||||
<description>
|
||||
Retrieve the number of actions in our action set.
|
||||
</description>
|
||||
</method>
|
||||
<method name="remove_action">
|
||||
<return type="void" />
|
||||
<param index="0" name="action" type="OpenXRAction" />
|
||||
<description>
|
||||
Remove an action from this action set.
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<members>
|
||||
<member name="actions" type="Array" setter="set_actions" getter="get_actions" default="[]">
|
||||
Collection of actions for this action set.
|
||||
</member>
|
||||
<member name="localized_name" type="String" setter="set_localized_name" getter="get_localized_name" default="""">
|
||||
The localized name of this action set.
|
||||
</member>
|
||||
<member name="priority" type="int" setter="set_priority" getter="get_priority" default="0">
|
||||
The priority for this action set.
|
||||
</member>
|
||||
</members>
|
||||
</class>
|
||||
|
|
@ -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>
|
||||
26
engine/modules/openxr/doc_classes/OpenXRBindingModifier.xml
Normal file
26
engine/modules/openxr/doc_classes/OpenXRBindingModifier.xml
Normal 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>
|
||||
|
|
@ -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>
|
||||
62
engine/modules/openxr/doc_classes/OpenXRCompositionLayer.xml
Normal file
62
engine/modules/openxr/doc_classes/OpenXRCompositionLayer.xml
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="OpenXRCompositionLayer" inherits="Node3D" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
The parent class of all OpenXR composition layer nodes.
|
||||
</brief_description>
|
||||
<description>
|
||||
Composition layers allow 2D viewports to be displayed inside of the headset by the XR compositor through special projections that retain their quality. This allows for rendering clear text while keeping the layer at a native resolution.
|
||||
[b]Note:[/b] If the OpenXR runtime doesn't support the given composition layer type, a fallback mesh can be generated with a [ViewportTexture], in order to emulate the composition layer.
|
||||
</description>
|
||||
<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" />
|
||||
<param index="1" name="direction" type="Vector3" />
|
||||
<description>
|
||||
Returns UV coordinates where the given ray intersects with the composition layer. [param origin] and [param direction] must be in global space.
|
||||
Returns [code]Vector2(-1.0, -1.0)[/code] if the ray doesn't intersect.
|
||||
</description>
|
||||
</method>
|
||||
<method name="is_natively_supported" qualifiers="const">
|
||||
<return type="bool" />
|
||||
<description>
|
||||
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>
|
||||
</methods>
|
||||
<members>
|
||||
<member name="alpha_blend" type="bool" setter="set_alpha_blend" getter="get_alpha_blend" default="false">
|
||||
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.
|
||||
</member>
|
||||
<member name="layer_viewport" type="SubViewport" setter="set_layer_viewport" getter="get_layer_viewport">
|
||||
The [SubViewport] to render on the composition layer.
|
||||
</member>
|
||||
<member name="sort_order" type="int" setter="set_sort_order" getter="get_sort_order" default="1">
|
||||
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>
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="OpenXRCompositionLayerCylinder" inherits="OpenXRCompositionLayer" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
An OpenXR composition layer that is rendered as an internal slice of a cylinder.
|
||||
</brief_description>
|
||||
<description>
|
||||
An OpenXR composition layer that allows rendering a [SubViewport] on an internal slice of a cylinder.
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<members>
|
||||
<member name="aspect_ratio" type="float" setter="set_aspect_ratio" getter="get_aspect_ratio" default="1.0">
|
||||
The aspect ratio of the slice. Used to set the height relative to the width.
|
||||
</member>
|
||||
<member name="central_angle" type="float" setter="set_central_angle" getter="get_central_angle" default="1.5708">
|
||||
The central angle of the cylinder. Used to set the width.
|
||||
</member>
|
||||
<member name="fallback_segments" type="int" setter="set_fallback_segments" getter="get_fallback_segments" default="10">
|
||||
The number of segments to use in the fallback mesh.
|
||||
</member>
|
||||
<member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0">
|
||||
The radius of the cylinder.
|
||||
</member>
|
||||
</members>
|
||||
</class>
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="OpenXRCompositionLayerEquirect" inherits="OpenXRCompositionLayer" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
An OpenXR composition layer that is rendered as an internal slice of a sphere.
|
||||
</brief_description>
|
||||
<description>
|
||||
An OpenXR composition layer that allows rendering a [SubViewport] on an internal slice of a sphere.
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<members>
|
||||
<member name="central_horizontal_angle" type="float" setter="set_central_horizontal_angle" getter="get_central_horizontal_angle" default="1.5708">
|
||||
The central horizontal angle of the sphere. Used to set the width.
|
||||
</member>
|
||||
<member name="fallback_segments" type="int" setter="set_fallback_segments" getter="get_fallback_segments" default="10">
|
||||
The number of segments to use in the fallback mesh.
|
||||
</member>
|
||||
<member name="lower_vertical_angle" type="float" setter="set_lower_vertical_angle" getter="get_lower_vertical_angle" default="0.785398">
|
||||
The lower vertical angle of the sphere. Used (together with [member upper_vertical_angle]) to set the height.
|
||||
</member>
|
||||
<member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0">
|
||||
The radius of the sphere.
|
||||
</member>
|
||||
<member name="upper_vertical_angle" type="float" setter="set_upper_vertical_angle" getter="get_upper_vertical_angle" default="0.785398">
|
||||
The upper vertical angle of the sphere. Used (together with [member lower_vertical_angle]) to set the height.
|
||||
</member>
|
||||
</members>
|
||||
</class>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="OpenXRCompositionLayerQuad" inherits="OpenXRCompositionLayer" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
An OpenXR composition layer that is rendered as a quad.
|
||||
</brief_description>
|
||||
<description>
|
||||
An OpenXR composition layer that allows rendering a [SubViewport] on a quad.
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<members>
|
||||
<member name="quad_size" type="Vector2" setter="set_quad_size" getter="get_quad_size" default="Vector2(1, 1)">
|
||||
The dimensions of the quad.
|
||||
</member>
|
||||
</members>
|
||||
</class>
|
||||
|
|
@ -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="""">
|
||||
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>
|
||||
|
|
@ -0,0 +1,273 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="OpenXRExtensionWrapperExtension" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Allows clients to implement OpenXR extensions with GDExtension.
|
||||
</brief_description>
|
||||
<description>
|
||||
[OpenXRExtensionWrapperExtension] allows clients to implement OpenXR extensions with GDExtension. The extension should be registered with [method register_extension_wrapper].
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="_get_composition_layer" qualifiers="virtual">
|
||||
<return type="int" />
|
||||
<param index="0" name="index" type="int" />
|
||||
<description>
|
||||
Returns a pointer to an [code]XrCompositionLayerBaseHeader[/code] struct to provide the given composition layer.
|
||||
This will only be called if the extension previously registered itself with [method OpenXRAPIExtension.register_composition_layer_provider].
|
||||
</description>
|
||||
</method>
|
||||
<method name="_get_composition_layer_count" qualifiers="virtual">
|
||||
<return type="int" />
|
||||
<description>
|
||||
Returns the number of composition layers this extension wrapper provides via [method _get_composition_layer].
|
||||
This will only be called if the extension previously registered itself with [method OpenXRAPIExtension.register_composition_layer_provider].
|
||||
</description>
|
||||
</method>
|
||||
<method name="_get_composition_layer_order" qualifiers="virtual">
|
||||
<return type="int" />
|
||||
<param index="0" name="index" type="int" />
|
||||
<description>
|
||||
Returns an integer that will be used to sort the given composition layer provided via [method _get_composition_layer]. Lower numbers will move the layer to the front of the list, and higher numbers to the end. The default projection layer has an order of [code]0[/code], so layers provided by this method should probably be above or below (but not exactly) [code]0[/code].
|
||||
This will only be called if the extension previously registered itself with [method OpenXRAPIExtension.register_composition_layer_provider].
|
||||
</description>
|
||||
</method>
|
||||
<method name="_get_requested_extensions" qualifiers="virtual">
|
||||
<return type="Dictionary" />
|
||||
<description>
|
||||
Returns a [Dictionary] of OpenXR extensions related to this extension. The [Dictionary] should contain the name of the extension, mapped to a [code]bool *[/code] cast to an integer:
|
||||
- If the [code]bool *[/code] is a [code]nullptr[/code] this extension is mandatory.
|
||||
- If the [code]bool *[/code] points to a boolean, the boolean will be updated to [code]true[/code] if the extension is enabled.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_get_suggested_tracker_names" qualifiers="virtual">
|
||||
<return type="PackedStringArray" />
|
||||
<description>
|
||||
Returns a [PackedStringArray] of positional tracker names that are used within the extension wrapper.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_get_viewport_composition_layer_extension_properties" qualifiers="virtual">
|
||||
<return type="Dictionary[]" />
|
||||
<description>
|
||||
Gets an array of [Dictionary]s that represent properties, just like [method Object._get_property_list], that will be added to [OpenXRCompositionLayer] nodes.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_get_viewport_composition_layer_extension_property_defaults" qualifiers="virtual">
|
||||
<return type="Dictionary" />
|
||||
<description>
|
||||
Gets a [Dictionary] containing the default values for the properties returned by [method _get_viewport_composition_layer_extension_properties].
|
||||
</description>
|
||||
</method>
|
||||
<method name="_on_before_instance_created" qualifiers="virtual">
|
||||
<return type="void" />
|
||||
<description>
|
||||
Called before the OpenXR instance is created.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_on_event_polled" qualifiers="virtual">
|
||||
<return type="bool" />
|
||||
<param index="0" name="event" type="const void*" />
|
||||
<description>
|
||||
Called when there is an OpenXR event to process. When implementing, return [code]true[/code] if the event was handled, return [code]false[/code] otherwise.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_on_instance_created" qualifiers="virtual">
|
||||
<return type="void" />
|
||||
<param index="0" name="instance" type="int" />
|
||||
<description>
|
||||
Called right after the OpenXR instance is created.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_on_instance_destroyed" qualifiers="virtual">
|
||||
<return type="void" />
|
||||
<description>
|
||||
Called right before the OpenXR instance is destroyed.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_on_main_swapchains_created" qualifiers="virtual">
|
||||
<return type="void" />
|
||||
<description>
|
||||
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>
|
||||
Called right before the XR viewports begin their rendering step.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_on_process" qualifiers="virtual">
|
||||
<return type="void" />
|
||||
<description>
|
||||
Called as part of the OpenXR process handling. This happens right before general and physics processing steps of the main loop. During this step controller data is queried and made available to game logic.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_on_register_metadata" qualifiers="virtual">
|
||||
<return type="void" />
|
||||
<description>
|
||||
Allows extensions to register additional controller metadata. This function is called even when the OpenXR API is not constructed as the metadata needs to be available to the editor.
|
||||
Extensions should also provide metadata regardless of whether they are supported on the host system. The controller data is used to setup action maps for users who may have access to the relevant hardware.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_on_session_created" qualifiers="virtual">
|
||||
<return type="void" />
|
||||
<param index="0" name="session" type="int" />
|
||||
<description>
|
||||
Called right after the OpenXR session is created.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_on_session_destroyed" qualifiers="virtual">
|
||||
<return type="void" />
|
||||
<description>
|
||||
Called right before the OpenXR session is destroyed.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_on_state_exiting" qualifiers="virtual">
|
||||
<return type="void" />
|
||||
<description>
|
||||
Called when the OpenXR session state is changed to exiting.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_on_state_focused" qualifiers="virtual">
|
||||
<return type="void" />
|
||||
<description>
|
||||
Called when the OpenXR session state is changed to focused. This state is the active state when the game runs.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_on_state_idle" qualifiers="virtual">
|
||||
<return type="void" />
|
||||
<description>
|
||||
Called when the OpenXR session state is changed to idle.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_on_state_loss_pending" qualifiers="virtual">
|
||||
<return type="void" />
|
||||
<description>
|
||||
Called when the OpenXR session state is changed to loss pending.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_on_state_ready" qualifiers="virtual">
|
||||
<return type="void" />
|
||||
<description>
|
||||
Called when the OpenXR session state is changed to ready. This means OpenXR is ready to set up the session.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_on_state_stopping" qualifiers="virtual">
|
||||
<return type="void" />
|
||||
<description>
|
||||
Called when the OpenXR session state is changed to stopping.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_on_state_synchronized" qualifiers="virtual">
|
||||
<return type="void" />
|
||||
<description>
|
||||
Called when the OpenXR session state is changed to synchronized. OpenXR also returns to this state when the application loses focus.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_on_state_visible" qualifiers="virtual">
|
||||
<return type="void" />
|
||||
<description>
|
||||
Called when the OpenXR session state is changed to visible. This means OpenXR is now ready to receive frames.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_on_viewport_composition_layer_destroyed" qualifiers="virtual">
|
||||
<return type="void" />
|
||||
<param index="0" name="layer" type="const void*" />
|
||||
<description>
|
||||
Called when a composition layer created via [OpenXRCompositionLayer] is destroyed.
|
||||
[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" />
|
||||
<param index="1" name="next_pointer" type="void*" />
|
||||
<description>
|
||||
Adds additional data structures when each hand tracker is created.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_set_instance_create_info_and_get_next_pointer" qualifiers="virtual">
|
||||
<return type="int" />
|
||||
<param index="0" name="next_pointer" type="void*" />
|
||||
<description>
|
||||
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*" />
|
||||
<description>
|
||||
Adds additional data structures when the OpenXR session is created.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_set_swapchain_create_info_and_get_next_pointer" qualifiers="virtual">
|
||||
<return type="int" />
|
||||
<param index="0" name="next_pointer" type="void*" />
|
||||
<description>
|
||||
Adds additional data structures when creating OpenXR swapchains.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_set_system_properties_and_get_next_pointer" qualifiers="virtual">
|
||||
<return type="int" />
|
||||
<param index="0" name="next_pointer" type="void*" />
|
||||
<description>
|
||||
Adds additional data structures when querying OpenXR system abilities.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_set_viewport_composition_layer_and_get_next_pointer" qualifiers="virtual">
|
||||
<return type="int" />
|
||||
<param index="0" name="layer" type="const void*" />
|
||||
<param index="1" name="property_values" type="Dictionary" />
|
||||
<param index="2" name="next_pointer" type="void*" />
|
||||
<description>
|
||||
Adds additional data structures to composition layers created by [OpenXRCompositionLayer].
|
||||
[param property_values] contains the values of the properties returned by [method _get_viewport_composition_layer_extension_properties].
|
||||
[param layer] is a pointer to an [code]XrCompositionLayerBaseHeader[/code] struct.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_openxr_api">
|
||||
<return type="OpenXRAPIExtension" />
|
||||
<description>
|
||||
Returns the created [OpenXRAPIExtension], which can be used to access the OpenXR API.
|
||||
</description>
|
||||
</method>
|
||||
<method name="register_extension_wrapper">
|
||||
<return type="void" />
|
||||
<description>
|
||||
Registers the extension. This should happen at core module initialization level.
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
</class>
|
||||
69
engine/modules/openxr/doc_classes/OpenXRHand.xml
Normal file
69
engine/modules/openxr/doc_classes/OpenXRHand.xml
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="OpenXRHand" inherits="Node3D" deprecated="Use [XRHandModifier3D] instead." xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Node supporting hand and finger tracking in OpenXR.
|
||||
</brief_description>
|
||||
<description>
|
||||
This node enables OpenXR's hand tracking functionality. The node should be a child node of an [XROrigin3D] node, tracking will update its position to the player's tracked hand Palm joint location (the center of the middle finger's metacarpal bone). This node also updates the skeleton of a properly skinned hand or avatar model.
|
||||
If the skeleton is a hand (one of the hand bones is the root node of the skeleton), then the skeleton will be placed relative to the hand palm location and the hand mesh and skeleton should be children of the OpenXRHand node.
|
||||
If the hand bones are part of a full skeleton, then the root of the hand will keep its location with the assumption that IK is used to position the hand and arm.
|
||||
By default the skeleton hand bones are repositioned to match the size of the tracked hand. To preserve the modeled bone sizes change [member bone_update] to apply rotation only.
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<members>
|
||||
<member name="bone_update" type="int" setter="set_bone_update" getter="get_bone_update" enum="OpenXRHand.BoneUpdate" default="0">
|
||||
Specify the type of updates to perform on the bone.
|
||||
</member>
|
||||
<member name="hand" type="int" setter="set_hand" getter="get_hand" enum="OpenXRHand.Hands" default="0">
|
||||
Specifies whether this node tracks the left or right hand of the player.
|
||||
</member>
|
||||
<member name="hand_skeleton" type="NodePath" setter="set_hand_skeleton" getter="get_hand_skeleton" default="NodePath("")">
|
||||
Set a [Skeleton3D] node for which the pose positions will be updated.
|
||||
</member>
|
||||
<member name="motion_range" type="int" setter="set_motion_range" getter="get_motion_range" enum="OpenXRHand.MotionRange" default="0">
|
||||
Set the motion range (if supported) limiting the hand motion.
|
||||
</member>
|
||||
<member name="skeleton_rig" type="int" setter="set_skeleton_rig" getter="get_skeleton_rig" enum="OpenXRHand.SkeletonRig" default="0">
|
||||
Set the type of skeleton rig the [member hand_skeleton] is compliant with.
|
||||
</member>
|
||||
</members>
|
||||
<constants>
|
||||
<constant name="HAND_LEFT" value="0" enum="Hands">
|
||||
Tracking the player's left hand.
|
||||
</constant>
|
||||
<constant name="HAND_RIGHT" value="1" enum="Hands">
|
||||
Tracking the player's right hand.
|
||||
</constant>
|
||||
<constant name="HAND_MAX" value="2" enum="Hands">
|
||||
Maximum supported hands.
|
||||
</constant>
|
||||
<constant name="MOTION_RANGE_UNOBSTRUCTED" value="0" enum="MotionRange">
|
||||
When player grips, hand skeleton will form a full fist.
|
||||
</constant>
|
||||
<constant name="MOTION_RANGE_CONFORM_TO_CONTROLLER" value="1" enum="MotionRange">
|
||||
When player grips, hand skeleton conforms to the controller the player is holding.
|
||||
</constant>
|
||||
<constant name="MOTION_RANGE_MAX" value="2" enum="MotionRange">
|
||||
Maximum supported motion ranges.
|
||||
</constant>
|
||||
<constant name="SKELETON_RIG_OPENXR" value="0" enum="SkeletonRig">
|
||||
An OpenXR compliant skeleton.
|
||||
</constant>
|
||||
<constant name="SKELETON_RIG_HUMANOID" value="1" enum="SkeletonRig">
|
||||
A [SkeletonProfileHumanoid] compliant skeleton.
|
||||
</constant>
|
||||
<constant name="SKELETON_RIG_MAX" value="2" enum="SkeletonRig">
|
||||
Maximum supported hands.
|
||||
</constant>
|
||||
<constant name="BONE_UPDATE_FULL" value="0" enum="BoneUpdate">
|
||||
The skeletons bones are fully updated (both position and rotation) to match the tracked bones.
|
||||
</constant>
|
||||
<constant name="BONE_UPDATE_ROTATION_ONLY" value="1" enum="BoneUpdate">
|
||||
The skeletons bones are only rotated to align with the tracked bones, preserving bone length.
|
||||
</constant>
|
||||
<constant name="BONE_UPDATE_MAX" value="2" enum="BoneUpdate">
|
||||
Maximum supported bone update mode.
|
||||
</constant>
|
||||
</constants>
|
||||
</class>
|
||||
11
engine/modules/openxr/doc_classes/OpenXRHapticBase.xml
Normal file
11
engine/modules/openxr/doc_classes/OpenXRHapticBase.xml
Normal 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>
|
||||
22
engine/modules/openxr/doc_classes/OpenXRHapticVibration.xml
Normal file
22
engine/modules/openxr/doc_classes/OpenXRHapticVibration.xml
Normal 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>
|
||||
68
engine/modules/openxr/doc_classes/OpenXRIPBinding.xml
Normal file
68
engine/modules/openxr/doc_classes/OpenXRIPBinding.xml
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="OpenXRIPBinding" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Defines a binding between an [OpenXRAction] and an XR input or output.
|
||||
</brief_description>
|
||||
<description>
|
||||
This binding resource binds an [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" 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_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" 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" deprecated="Binding is for a single path.">
|
||||
<return type="void" />
|
||||
<param index="0" name="path" type="String" />
|
||||
<description>
|
||||
Removes this input/output path from this binding.
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<members>
|
||||
<member name="action" type="OpenXRAction" setter="set_action" getter="get_action">
|
||||
[OpenXRAction] that is bound to [member binding_path].
|
||||
</member>
|
||||
<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="""">
|
||||
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>
|
||||
</class>
|
||||
|
|
@ -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>
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="OpenXRInteractionProfile" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Suggested bindings object for OpenXR.
|
||||
</brief_description>
|
||||
<description>
|
||||
This object stores suggested bindings for an interaction profile. Interaction profiles define the metadata for a tracked XR device such as an XR controller.
|
||||
For more information see the [url=https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#semantic-path-interaction-profiles]interaction profiles info in the OpenXR specification[/url].
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="get_binding" qualifiers="const">
|
||||
<return type="OpenXRIPBinding" />
|
||||
<param index="0" name="index" type="int" />
|
||||
<description>
|
||||
Retrieve the binding at this index.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_binding_count" qualifiers="const">
|
||||
<return type="int" />
|
||||
<description>
|
||||
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>
|
||||
<member name="interaction_profile_path" type="String" setter="set_interaction_profile_path" getter="get_interaction_profile_path" default="""">
|
||||
The interaction profile path identifying the XR device.
|
||||
</member>
|
||||
</members>
|
||||
</class>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="OpenXRInteractionProfileMetadata" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Meta class registering supported devices in OpenXR.
|
||||
</brief_description>
|
||||
<description>
|
||||
This class allows OpenXR core and extensions to register metadata relating to supported interaction devices such as controllers, trackers, haptic devices, etc. It is primarily used by the action map editor and to sanitize any action map by removing extension-dependent entries when applicable.
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="register_interaction_profile">
|
||||
<return type="void" />
|
||||
<param index="0" name="display_name" type="String" />
|
||||
<param index="1" name="openxr_path" type="String" />
|
||||
<param index="2" name="openxr_extension_name" type="String" />
|
||||
<description>
|
||||
Registers an interaction profile using its OpenXR designation (e.g. [code]/interaction_profiles/khr/simple_controller[/code] is the profile for OpenXR's simple controller profile).
|
||||
[param display_name] is the description shown to the user. [param openxr_path] is the interaction profile path being registered. [param openxr_extension_name] optionally restricts this profile to the given extension being enabled/available. If the extension is not available, the profile and all related entries used in an action map are filtered out.
|
||||
</description>
|
||||
</method>
|
||||
<method name="register_io_path">
|
||||
<return type="void" />
|
||||
<param index="0" name="interaction_profile" type="String" />
|
||||
<param index="1" name="display_name" type="String" />
|
||||
<param index="2" name="toplevel_path" type="String" />
|
||||
<param index="3" name="openxr_path" type="String" />
|
||||
<param index="4" name="openxr_extension_name" type="String" />
|
||||
<param index="5" name="action_type" type="int" enum="OpenXRAction.ActionType" />
|
||||
<description>
|
||||
Registers an input/output path for the given [param interaction_profile]. The profile should previously have been registered using [method register_interaction_profile]. [param display_name] is the description shown to the user. [param toplevel_path] specifies the bind path this input/output can be bound to (e.g. [code]/user/hand/left[/code] or [code]/user/hand/right[/code]). [param openxr_path] is the action input/output being registered (e.g. [code]/user/hand/left/input/aim/pose[/code]). [param openxr_extension_name] restricts this input/output to an enabled/available extension, this doesn't need to repeat the extension on the profile but relates to overlapping extension (e.g. [code]XR_EXT_palm_pose[/code] that introduces [code]…/input/palm_ext/pose[/code] input paths). [param action_type] defines the type of input or output provided by OpenXR.
|
||||
</description>
|
||||
</method>
|
||||
<method name="register_profile_rename">
|
||||
<return type="void" />
|
||||
<param index="0" name="old_name" type="String" />
|
||||
<param index="1" name="new_name" type="String" />
|
||||
<description>
|
||||
Allows for renaming old interaction profile paths to new paths to maintain backwards compatibility with older action maps.
|
||||
</description>
|
||||
</method>
|
||||
<method name="register_top_level_path">
|
||||
<return type="void" />
|
||||
<param index="0" name="display_name" type="String" />
|
||||
<param index="1" name="openxr_path" type="String" />
|
||||
<param index="2" name="openxr_extension_name" type="String" />
|
||||
<description>
|
||||
Registers a top level path to which profiles can be bound. For instance [code]/user/hand/left[/code] refers to the bind point for the player's left hand. Extensions can register additional top level paths, for instance a haptic vest extension might register [code]/user/body/vest[/code].
|
||||
[param display_name] is the name shown to the user. [param openxr_path] is the top level path being registered. [param openxr_extension_name] is optional and ensures the top level path is only used if the specified extension is available/enabled.
|
||||
When a top level path ends up being bound by OpenXR, a [XRPositionalTracker] is instantiated to manage the state of the device.
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
</class>
|
||||
342
engine/modules/openxr/doc_classes/OpenXRInterface.xml
Normal file
342
engine/modules/openxr/doc_classes/OpenXRInterface.xml
Normal file
|
|
@ -0,0 +1,342 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="OpenXRInterface" inherits="XRInterface" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Our OpenXR interface.
|
||||
</brief_description>
|
||||
<description>
|
||||
The OpenXR interface allows Godot to interact with OpenXR runtimes and make it possible to create XR experiences and games.
|
||||
Due to the needs of OpenXR this interface works slightly different than other plugin based XR interfaces. It needs to be initialized when Godot starts. You need to enable OpenXR, settings for this can be found in your games project settings under the XR heading. You do need to mark a viewport for use with XR in order for Godot to know which render result should be output to the headset.
|
||||
</description>
|
||||
<tutorials>
|
||||
<link title="Setting up XR">$DOCS_URL/tutorials/xr/setting_up_xr.html</link>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="get_action_sets" qualifiers="const">
|
||||
<return type="Array" />
|
||||
<description>
|
||||
Returns a list of action sets registered with Godot (loaded from the action map at runtime).
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_available_display_refresh_rates" qualifiers="const">
|
||||
<return type="Array" />
|
||||
<description>
|
||||
Returns display refresh rates supported by the current HMD. Only returned if this feature is supported by the OpenXR runtime and after the interface has been initialized.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_hand_joint_angular_velocity" qualifiers="const" deprecated="Use [method XRHandTracker.get_hand_joint_angular_velocity] obtained from [method XRServer.get_tracker] instead.">
|
||||
<return type="Vector3" />
|
||||
<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
|
||||
<param index="1" name="joint" type="int" enum="OpenXRInterface.HandJoints" />
|
||||
<description>
|
||||
If handtracking is enabled, returns the angular velocity of a joint ([param joint]) of a hand ([param hand]) as provided by OpenXR. This is relative to [XROrigin3D]!
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_hand_joint_flags" qualifiers="const" deprecated="Use [method XRHandTracker.get_hand_joint_flags] obtained from [method XRServer.get_tracker] instead.">
|
||||
<return type="int" enum="OpenXRInterface.HandJointFlags" is_bitfield="true" />
|
||||
<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
|
||||
<param index="1" name="joint" type="int" enum="OpenXRInterface.HandJoints" />
|
||||
<description>
|
||||
If handtracking is enabled, returns flags that inform us of the validity of the tracking data.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_hand_joint_linear_velocity" qualifiers="const" deprecated="Use [method XRHandTracker.get_hand_joint_linear_velocity] obtained from [method XRServer.get_tracker] instead.">
|
||||
<return type="Vector3" />
|
||||
<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
|
||||
<param index="1" name="joint" type="int" enum="OpenXRInterface.HandJoints" />
|
||||
<description>
|
||||
If handtracking is enabled, returns the linear velocity of a joint ([param joint]) of a hand ([param hand]) as provided by OpenXR. This is relative to [XROrigin3D] without worldscale applied!
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_hand_joint_position" qualifiers="const" deprecated="Use [method XRHandTracker.get_hand_joint_transform] obtained from [method XRServer.get_tracker] instead.">
|
||||
<return type="Vector3" />
|
||||
<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
|
||||
<param index="1" name="joint" type="int" enum="OpenXRInterface.HandJoints" />
|
||||
<description>
|
||||
If handtracking is enabled, returns the position of a joint ([param joint]) of a hand ([param hand]) as provided by OpenXR. This is relative to [XROrigin3D] without worldscale applied!
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_hand_joint_radius" qualifiers="const" deprecated="Use [method XRHandTracker.get_hand_joint_radius] obtained from [method XRServer.get_tracker] instead.">
|
||||
<return type="float" />
|
||||
<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
|
||||
<param index="1" name="joint" type="int" enum="OpenXRInterface.HandJoints" />
|
||||
<description>
|
||||
If handtracking is enabled, returns the radius of a joint ([param joint]) of a hand ([param hand]) as provided by OpenXR. This is without worldscale applied!
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_hand_joint_rotation" qualifiers="const" deprecated="Use [method XRHandTracker.get_hand_joint_transform] obtained from [method XRServer.get_tracker] instead.">
|
||||
<return type="Quaternion" />
|
||||
<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
|
||||
<param index="1" name="joint" type="int" enum="OpenXRInterface.HandJoints" />
|
||||
<description>
|
||||
If handtracking is enabled, returns the rotation of a joint ([param joint]) of a hand ([param hand]) as provided by OpenXR.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_hand_tracking_source" qualifiers="const" deprecated="Use [member XRHandTracker.hand_tracking_source] obtained from [method XRServer.get_tracker] instead.">
|
||||
<return type="int" enum="OpenXRInterface.HandTrackedSource" />
|
||||
<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
|
||||
<description>
|
||||
If handtracking is enabled and hand tracking source is supported, gets the source of the hand tracking data for [param hand].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_motion_range" qualifiers="const">
|
||||
<return type="int" enum="OpenXRInterface.HandMotionRange" />
|
||||
<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
|
||||
<description>
|
||||
If handtracking is enabled and motion range is supported, gets the currently configured motion range for [param hand].
|
||||
</description>
|
||||
</method>
|
||||
<method name="is_action_set_active" qualifiers="const">
|
||||
<return type="bool" />
|
||||
<param index="0" name="name" type="String" />
|
||||
<description>
|
||||
Returns [code]true[/code] if the given action set is active.
|
||||
</description>
|
||||
</method>
|
||||
<method name="is_eye_gaze_interaction_supported">
|
||||
<return type="bool" />
|
||||
<description>
|
||||
Returns the capabilities of the eye gaze interaction extension.
|
||||
[b]Note:[/b] This only returns a valid value after OpenXR has been initialized.
|
||||
</description>
|
||||
</method>
|
||||
<method name="is_foveation_supported" qualifiers="const">
|
||||
<return type="bool" />
|
||||
<description>
|
||||
Returns [code]true[/code] if OpenXR's foveation extension is supported, the interface must be initialized before this returns a valid value.
|
||||
[b]Note:[/b] This feature is only available on the compatibility renderer and currently only available on some stand alone headsets. For Vulkan set [member Viewport.vrs_mode] to [code]VRS_XR[/code] on desktop.
|
||||
</description>
|
||||
</method>
|
||||
<method name="is_hand_interaction_supported" qualifiers="const">
|
||||
<return type="bool" />
|
||||
<description>
|
||||
Returns [code]true[/code] if OpenXR's hand interaction profile is supported and enabled.
|
||||
[b]Note:[/b] This only returns a valid value after OpenXR has been initialized.
|
||||
</description>
|
||||
</method>
|
||||
<method name="is_hand_tracking_supported">
|
||||
<return type="bool" />
|
||||
<description>
|
||||
Returns [code]true[/code] if OpenXR's hand tracking is supported and enabled.
|
||||
[b]Note:[/b] This only returns a valid value after OpenXR has been initialized.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_action_set_active">
|
||||
<return type="void" />
|
||||
<param index="0" name="name" type="String" />
|
||||
<param index="1" name="active" type="bool" />
|
||||
<description>
|
||||
Sets the given action set as active or inactive.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_motion_range">
|
||||
<return type="void" />
|
||||
<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
|
||||
<param index="1" name="motion_range" type="int" enum="OpenXRInterface.HandMotionRange" />
|
||||
<description>
|
||||
If handtracking is enabled and motion range is supported, sets the currently configured motion range for [param hand] to [param motion_range].
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<members>
|
||||
<member name="display_refresh_rate" type="float" setter="set_display_refresh_rate" getter="get_display_refresh_rate" default="0.0">
|
||||
The display refresh rate for the current HMD. Only functional if this feature is supported by the OpenXR runtime and after the interface has been initialized.
|
||||
</member>
|
||||
<member name="foveation_dynamic" type="bool" setter="set_foveation_dynamic" getter="get_foveation_dynamic" default="false">
|
||||
Enable dynamic foveation adjustment, the interface must be initialized before this is accessible. If enabled foveation will automatically adjusted between low and [member foveation_level].
|
||||
[b]Note:[/b] Only works on compatibility renderer.
|
||||
</member>
|
||||
<member name="foveation_level" type="int" setter="set_foveation_level" getter="get_foveation_level" default="0">
|
||||
Set foveation level from 0 (off) to 3 (high), the interface must be initialized before this is accessible.
|
||||
[b]Note:[/b] Only works on compatibility renderer.
|
||||
</member>
|
||||
<member name="render_target_size_multiplier" type="float" setter="set_render_target_size_multiplier" getter="get_render_target_size_multiplier" default="1.0">
|
||||
The render size multiplier for the current HMD. Must be set before the interface has been initialized.
|
||||
</member>
|
||||
<member name="vrs_min_radius" type="float" setter="set_vrs_min_radius" getter="get_vrs_min_radius" default="20.0">
|
||||
The minimum radius around the focal point where full quality is guaranteed if VRS is used as a percentage of screen size.
|
||||
[b]Note:[/b] Mobile and Forward+ renderers only. Requires [member Viewport.vrs_mode] to be set to [constant Viewport.VRS_XR].
|
||||
</member>
|
||||
<member name="vrs_strength" type="float" setter="set_vrs_strength" getter="get_vrs_strength" default="1.0">
|
||||
The strength used to calculate the VRS density map. The greater this value, the more noticeable VRS is. This improves performance at the cost of quality.
|
||||
[b]Note:[/b] Mobile and Forward+ renderers only. Requires [member Viewport.vrs_mode] to be set to [constant Viewport.VRS_XR].
|
||||
</member>
|
||||
</members>
|
||||
<signals>
|
||||
<signal name="instance_exiting">
|
||||
<description>
|
||||
Informs our OpenXR instance is exiting.
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="pose_recentered">
|
||||
<description>
|
||||
Informs the user queued a recenter of the player position.
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="refresh_rate_changed">
|
||||
<param index="0" name="refresh_rate" type="float" />
|
||||
<description>
|
||||
Informs the user the HMD refresh rate has changed.
|
||||
[b]Note:[/b] Only emitted if XR runtime supports the refresh rate extension.
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="session_begun">
|
||||
<description>
|
||||
Informs our OpenXR session has been started.
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="session_focussed">
|
||||
<description>
|
||||
Informs our OpenXR session now has focus.
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="session_loss_pending">
|
||||
<description>
|
||||
Informs our OpenXR session is in the process of being lost.
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="session_stopping">
|
||||
<description>
|
||||
Informs our OpenXR session is stopping.
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="session_visible">
|
||||
<description>
|
||||
Informs our OpenXR session is now visible (output is being sent to the HMD).
|
||||
</description>
|
||||
</signal>
|
||||
</signals>
|
||||
<constants>
|
||||
<constant name="HAND_LEFT" value="0" enum="Hand">
|
||||
Left hand.
|
||||
</constant>
|
||||
<constant name="HAND_RIGHT" value="1" enum="Hand">
|
||||
Right hand.
|
||||
</constant>
|
||||
<constant name="HAND_MAX" value="2" enum="Hand">
|
||||
Maximum value for the hand enum.
|
||||
</constant>
|
||||
<constant name="HAND_MOTION_RANGE_UNOBSTRUCTED" value="0" enum="HandMotionRange">
|
||||
Full hand range, if user closes their hands, we make a full fist.
|
||||
</constant>
|
||||
<constant name="HAND_MOTION_RANGE_CONFORM_TO_CONTROLLER" value="1" enum="HandMotionRange">
|
||||
Conform to controller, if user closes their hands, the tracked data conforms to the shape of the controller.
|
||||
</constant>
|
||||
<constant name="HAND_MOTION_RANGE_MAX" value="2" enum="HandMotionRange">
|
||||
Maximum value for the motion range enum.
|
||||
</constant>
|
||||
<constant name="HAND_TRACKED_SOURCE_UNKNOWN" value="0" enum="HandTrackedSource">
|
||||
The source of hand tracking data is unknown (the extension is likely unsupported).
|
||||
</constant>
|
||||
<constant name="HAND_TRACKED_SOURCE_UNOBSTRUCTED" value="1" enum="HandTrackedSource">
|
||||
The source of hand tracking is unobstructed, this means that an accurate method of hand tracking is used, e.g. optical hand tracking, data gloves, etc.
|
||||
</constant>
|
||||
<constant name="HAND_TRACKED_SOURCE_CONTROLLER" value="2" enum="HandTrackedSource">
|
||||
The source of hand tracking is a controller, bone positions are inferred from controller inputs.
|
||||
</constant>
|
||||
<constant name="HAND_TRACKED_SOURCE_MAX" value="3" enum="HandTrackedSource">
|
||||
Maximum value for the hand tracked source enum.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_PALM" value="0" enum="HandJoints">
|
||||
Palm joint.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_WRIST" value="1" enum="HandJoints">
|
||||
Wrist joint.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_THUMB_METACARPAL" value="2" enum="HandJoints">
|
||||
Thumb metacarpal joint.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_THUMB_PROXIMAL" value="3" enum="HandJoints">
|
||||
Thumb proximal joint.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_THUMB_DISTAL" value="4" enum="HandJoints">
|
||||
Thumb distal joint.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_THUMB_TIP" value="5" enum="HandJoints">
|
||||
Thumb tip joint.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_INDEX_METACARPAL" value="6" enum="HandJoints">
|
||||
Index metacarpal joint.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_INDEX_PROXIMAL" value="7" enum="HandJoints">
|
||||
Index proximal joint.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_INDEX_INTERMEDIATE" value="8" enum="HandJoints">
|
||||
Index intermediate joint.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_INDEX_DISTAL" value="9" enum="HandJoints">
|
||||
Index distal joint.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_INDEX_TIP" value="10" enum="HandJoints">
|
||||
Index tip joint.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_MIDDLE_METACARPAL" value="11" enum="HandJoints">
|
||||
Middle metacarpal joint.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_MIDDLE_PROXIMAL" value="12" enum="HandJoints">
|
||||
Middle proximal joint.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_MIDDLE_INTERMEDIATE" value="13" enum="HandJoints">
|
||||
Middle intermediate joint.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_MIDDLE_DISTAL" value="14" enum="HandJoints">
|
||||
Middle distal joint.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_MIDDLE_TIP" value="15" enum="HandJoints">
|
||||
Middle tip joint.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_RING_METACARPAL" value="16" enum="HandJoints">
|
||||
Ring metacarpal joint.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_RING_PROXIMAL" value="17" enum="HandJoints">
|
||||
Ring proximal joint.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_RING_INTERMEDIATE" value="18" enum="HandJoints">
|
||||
Ring intermediate joint.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_RING_DISTAL" value="19" enum="HandJoints">
|
||||
Ring distal joint.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_RING_TIP" value="20" enum="HandJoints">
|
||||
Ring tip joint.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_LITTLE_METACARPAL" value="21" enum="HandJoints">
|
||||
Little metacarpal joint.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_LITTLE_PROXIMAL" value="22" enum="HandJoints">
|
||||
Little proximal joint.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_LITTLE_INTERMEDIATE" value="23" enum="HandJoints">
|
||||
Little intermediate joint.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_LITTLE_DISTAL" value="24" enum="HandJoints">
|
||||
Little distal joint.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_LITTLE_TIP" value="25" enum="HandJoints">
|
||||
Little tip joint.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_MAX" value="26" enum="HandJoints">
|
||||
Maximum value for the hand joint enum.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_NONE" value="0" enum="HandJointFlags" is_bitfield="true">
|
||||
No flags are set.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_ORIENTATION_VALID" value="1" enum="HandJointFlags" is_bitfield="true">
|
||||
If set, the orientation data is valid, otherwise, the orientation data is unreliable and should not be used.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_ORIENTATION_TRACKED" value="2" enum="HandJointFlags" is_bitfield="true">
|
||||
If set, the orientation data comes from tracking data, otherwise, the orientation data contains predicted data.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_POSITION_VALID" value="4" enum="HandJointFlags" is_bitfield="true">
|
||||
If set, the positional data is valid, otherwise, the positional data is unreliable and should not be used.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_POSITION_TRACKED" value="8" enum="HandJointFlags" is_bitfield="true">
|
||||
If set, the positional data comes from tracking data, otherwise, the positional data contains predicted data.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_LINEAR_VELOCITY_VALID" value="16" enum="HandJointFlags" is_bitfield="true">
|
||||
If set, our linear velocity data is valid, otherwise, the linear velocity data is unreliable and should not be used.
|
||||
</constant>
|
||||
<constant name="HAND_JOINT_ANGULAR_VELOCITY_VALID" value="32" enum="HandJointFlags" is_bitfield="true">
|
||||
If set, our angular velocity data is valid, otherwise, the angular velocity data is unreliable and should not be used.
|
||||
</constant>
|
||||
</constants>
|
||||
</class>
|
||||
12
engine/modules/openxr/doc_classes/OpenXRVisibilityMask.xml
Normal file
12
engine/modules/openxr/doc_classes/OpenXRVisibilityMask.xml
Normal 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>
|
||||
11
engine/modules/openxr/editor/SCsub
Normal file
11
engine/modules/openxr/editor/SCsub
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/env python
|
||||
from misc.utility.scons_hints import *
|
||||
|
||||
Import("env")
|
||||
Import("env_openxr")
|
||||
|
||||
module_obj = []
|
||||
|
||||
env_openxr.add_source_files(module_obj, "*.cpp")
|
||||
|
||||
env.modules_sources += module_obj
|
||||
165
engine/modules/openxr/editor/openxr_action_editor.cpp
Normal file
165
engine/modules/openxr/editor/openxr_action_editor.cpp
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_action_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_action_editor.h"
|
||||
|
||||
#include "editor/editor_string_names.h"
|
||||
|
||||
void OpenXRActionEditor::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("_do_set_name", "name"), &OpenXRActionEditor::_do_set_name);
|
||||
ClassDB::bind_method(D_METHOD("_do_set_localized_name", "name"), &OpenXRActionEditor::_do_set_localized_name);
|
||||
ClassDB::bind_method(D_METHOD("_do_set_action_type", "type"), &OpenXRActionEditor::_do_set_action_type);
|
||||
|
||||
ADD_SIGNAL(MethodInfo("remove", PropertyInfo(Variant::OBJECT, "action_editor")));
|
||||
}
|
||||
|
||||
void OpenXRActionEditor::_theme_changed() {
|
||||
rem_action->set_button_icon(get_theme_icon(SNAME("Remove"), EditorStringName(EditorIcons)));
|
||||
}
|
||||
|
||||
void OpenXRActionEditor::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_ENTER_TREE:
|
||||
case NOTIFICATION_THEME_CHANGED: {
|
||||
_theme_changed();
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRActionEditor::_on_action_name_changed(const String p_new_text) {
|
||||
if (action->get_name() != p_new_text) {
|
||||
undo_redo->create_action(TTR("Rename Action"));
|
||||
undo_redo->add_do_method(this, "_do_set_name", p_new_text);
|
||||
undo_redo->add_undo_method(this, "_do_set_name", action->get_name());
|
||||
undo_redo->commit_action(false);
|
||||
|
||||
// If our localized name matches our action name, set this too
|
||||
if (action->get_name() == action->get_localized_name()) {
|
||||
undo_redo->create_action(TTR("Rename Actions Localized name"));
|
||||
undo_redo->add_do_method(this, "_do_set_localized_name", p_new_text);
|
||||
undo_redo->add_undo_method(this, "_do_set_localized_name", action->get_localized_name());
|
||||
undo_redo->commit_action(false);
|
||||
|
||||
action->set_localized_name(p_new_text);
|
||||
action_localized_name->set_text(p_new_text);
|
||||
}
|
||||
action->set_name(p_new_text);
|
||||
action->set_edited(true);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRActionEditor::_do_set_name(const String p_new_text) {
|
||||
action->set_name(p_new_text);
|
||||
action->set_edited(true);
|
||||
action_name->set_text(p_new_text);
|
||||
}
|
||||
|
||||
void OpenXRActionEditor::_on_action_localized_name_changed(const String p_new_text) {
|
||||
if (action->get_localized_name() != p_new_text) {
|
||||
undo_redo->create_action(TTR("Rename Actions Localized name"));
|
||||
undo_redo->add_do_method(this, "_do_set_localized_name", p_new_text);
|
||||
undo_redo->add_undo_method(this, "_do_set_localized_name", action->get_localized_name());
|
||||
undo_redo->commit_action(false);
|
||||
|
||||
action->set_localized_name(p_new_text);
|
||||
action->set_edited(true);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRActionEditor::_do_set_localized_name(const String p_new_text) {
|
||||
action->set_localized_name(p_new_text);
|
||||
action->set_edited(true);
|
||||
action_localized_name->set_text(p_new_text);
|
||||
}
|
||||
|
||||
void OpenXRActionEditor::_on_item_selected(int p_idx) {
|
||||
ERR_FAIL_INDEX(p_idx, OpenXRAction::OPENXR_ACTION_MAX);
|
||||
|
||||
OpenXRAction::ActionType action_type = OpenXRAction::ActionType(p_idx);
|
||||
|
||||
if (action->get_action_type() != action_type) {
|
||||
undo_redo->create_action(TTR("Change Action Type"));
|
||||
undo_redo->add_do_method(this, "_do_set_action_type", action_type);
|
||||
undo_redo->add_undo_method(this, "_do_set_action_type", action->get_action_type());
|
||||
undo_redo->commit_action(false);
|
||||
|
||||
action->set_action_type(action_type);
|
||||
action->set_edited(true);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRActionEditor::_do_set_action_type(OpenXRAction::ActionType p_action_type) {
|
||||
action->set_action_type(p_action_type);
|
||||
action->set_edited(true);
|
||||
action_type_button->select(int(action->get_action_type()));
|
||||
}
|
||||
|
||||
void OpenXRActionEditor::_on_remove_action() {
|
||||
emit_signal("remove", this);
|
||||
}
|
||||
|
||||
OpenXRActionEditor::OpenXRActionEditor(Ref<OpenXRAction> p_action) {
|
||||
undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
action = p_action;
|
||||
|
||||
set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
|
||||
action_name = memnew(LineEdit);
|
||||
action_name->set_text(action->get_name());
|
||||
action_name->set_custom_minimum_size(Size2(150.0, 0.0));
|
||||
action_name->connect(SceneStringName(text_changed), callable_mp(this, &OpenXRActionEditor::_on_action_name_changed));
|
||||
add_child(action_name);
|
||||
|
||||
action_localized_name = memnew(LineEdit);
|
||||
action_localized_name->set_text(action->get_localized_name());
|
||||
action_localized_name->set_custom_minimum_size(Size2(150.0, 0.0));
|
||||
action_localized_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
action_localized_name->connect(SceneStringName(text_changed), callable_mp(this, &OpenXRActionEditor::_on_action_localized_name_changed));
|
||||
add_child(action_localized_name);
|
||||
|
||||
action_type_button = memnew(OptionButton);
|
||||
action_type_button->add_item("Bool", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
action_type_button->add_item("Float", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
action_type_button->add_item("Vector2", OpenXRAction::OPENXR_ACTION_VECTOR2);
|
||||
action_type_button->add_item("Pose", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
action_type_button->add_item("Haptic", OpenXRAction::OPENXR_ACTION_HAPTIC);
|
||||
action_type_button->select(int(action->get_action_type()));
|
||||
action_type_button->set_custom_minimum_size(Size2(100.0, 0.0));
|
||||
action_type_button->connect(SceneStringName(item_selected), callable_mp(this, &OpenXRActionEditor::_on_item_selected));
|
||||
add_child(action_type_button);
|
||||
|
||||
// maybe add dropdown to edit our toplevel paths, or do we deduce them from our suggested bindings?
|
||||
|
||||
rem_action = memnew(Button);
|
||||
rem_action->set_tooltip_text(TTR("Remove action"));
|
||||
rem_action->connect(SceneStringName(pressed), callable_mp(this, &OpenXRActionEditor::_on_remove_action));
|
||||
rem_action->set_flat(true);
|
||||
add_child(rem_action);
|
||||
}
|
||||
75
engine/modules/openxr/editor/openxr_action_editor.h
Normal file
75
engine/modules/openxr/editor/openxr_action_editor.h
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_action_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_ACTION_EDITOR_H
|
||||
#define OPENXR_ACTION_EDITOR_H
|
||||
|
||||
#include "../action_map/openxr_action.h"
|
||||
|
||||
#include "editor/editor_undo_redo_manager.h"
|
||||
#include "scene/gui/box_container.h"
|
||||
#include "scene/gui/button.h"
|
||||
#include "scene/gui/line_edit.h"
|
||||
#include "scene/gui/option_button.h"
|
||||
#include "scene/gui/text_edit.h"
|
||||
|
||||
class OpenXRActionEditor : public HBoxContainer {
|
||||
GDCLASS(OpenXRActionEditor, HBoxContainer);
|
||||
|
||||
private:
|
||||
EditorUndoRedoManager *undo_redo;
|
||||
Ref<OpenXRAction> action;
|
||||
|
||||
LineEdit *action_name = nullptr;
|
||||
LineEdit *action_localized_name = nullptr;
|
||||
OptionButton *action_type_button = nullptr;
|
||||
Button *rem_action = nullptr;
|
||||
|
||||
void _theme_changed();
|
||||
void _on_action_name_changed(const String p_new_text);
|
||||
void _on_action_localized_name_changed(const String p_new_text);
|
||||
void _on_item_selected(int p_idx);
|
||||
void _on_remove_action();
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
void _notification(int p_what);
|
||||
|
||||
// used for undo/redo
|
||||
void _do_set_name(const String p_new_text);
|
||||
void _do_set_localized_name(const String p_new_text);
|
||||
void _do_set_action_type(OpenXRAction::ActionType p_action_type);
|
||||
|
||||
public:
|
||||
Ref<OpenXRAction> get_action() { return action; }
|
||||
OpenXRActionEditor(Ref<OpenXRAction> p_action);
|
||||
};
|
||||
|
||||
#endif // OPENXR_ACTION_EDITOR_H
|
||||
501
engine/modules/openxr/editor/openxr_action_map_editor.cpp
Normal file
501
engine/modules/openxr/editor/openxr_action_map_editor.cpp
Normal file
|
|
@ -0,0 +1,501 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_action_map_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_action_map_editor.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor/gui/editor_bottom_panel.h"
|
||||
#include "editor/gui/editor_file_dialog.h"
|
||||
|
||||
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);
|
||||
ClassDB::bind_method("_add_interaction_profile_editor", &OpenXRActionMapEditor::_add_interaction_profile_editor);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("_add_action_set", "name"), &OpenXRActionMapEditor::_add_action_set);
|
||||
ClassDB::bind_method(D_METHOD("_remove_action_set", "name"), &OpenXRActionMapEditor::_remove_action_set);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("_do_add_action_set_editor", "action_set_editor"), &OpenXRActionMapEditor::_do_add_action_set_editor);
|
||||
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) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_ENTER_TREE:
|
||||
case NOTIFICATION_THEME_CHANGED: {
|
||||
for (int i = 0; i < tabs->get_child_count(); i++) {
|
||||
Control *tab = Object::cast_to<Control>(tabs->get_child(i));
|
||||
if (tab) {
|
||||
tab->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_READY: {
|
||||
_create_action_sets();
|
||||
_create_interaction_profiles();
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
OpenXRActionSetEditor *OpenXRActionMapEditor::_add_action_set_editor(Ref<OpenXRActionSet> p_action_set) {
|
||||
ERR_FAIL_COND_V(p_action_set.is_null(), nullptr);
|
||||
|
||||
OpenXRActionSetEditor *action_set_editor = memnew(OpenXRActionSetEditor(action_map, p_action_set));
|
||||
action_set_editor->connect("remove", callable_mp(this, &OpenXRActionMapEditor::_on_remove_action_set));
|
||||
action_set_editor->connect("action_removed", callable_mp(this, &OpenXRActionMapEditor::_on_action_removed));
|
||||
|
||||
actionsets_vb->add_child(action_set_editor);
|
||||
|
||||
return action_set_editor;
|
||||
}
|
||||
|
||||
void OpenXRActionMapEditor::_create_action_sets() {
|
||||
if (action_map.is_valid()) {
|
||||
Array action_sets = action_map->get_action_sets();
|
||||
for (int i = 0; i < action_sets.size(); i++) {
|
||||
Ref<OpenXRActionSet> action_set = action_sets[i];
|
||||
_add_action_set_editor(action_set);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OpenXRInteractionProfileEditorBase *OpenXRActionMapEditor::_add_interaction_profile_editor(Ref<OpenXRInteractionProfile> p_interaction_profile) {
|
||||
ERR_FAIL_COND_V(p_interaction_profile.is_null(), nullptr);
|
||||
|
||||
String profile_path = p_interaction_profile->get_interaction_profile_path();
|
||||
|
||||
// need to instance the correct editor for our profile
|
||||
OpenXRInteractionProfileEditorBase *new_profile_editor = nullptr;
|
||||
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);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
void OpenXRActionMapEditor::_create_interaction_profiles() {
|
||||
if (action_map.is_valid()) {
|
||||
Array new_interaction_profiles = action_map->get_interaction_profiles();
|
||||
for (int i = 0; i < new_interaction_profiles.size(); i++) {
|
||||
Ref<OpenXRInteractionProfile> interaction_profile = new_interaction_profiles[i];
|
||||
_add_interaction_profile_editor(interaction_profile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OpenXRActionSetEditor *OpenXRActionMapEditor::_add_action_set(String p_name) {
|
||||
ERR_FAIL_COND_V(action_map.is_null(), nullptr);
|
||||
Ref<OpenXRActionSet> new_action_set;
|
||||
|
||||
// add our new action set
|
||||
new_action_set.instantiate();
|
||||
new_action_set->set_name(p_name);
|
||||
new_action_set->set_localized_name(p_name);
|
||||
action_map->add_action_set(new_action_set);
|
||||
action_map->set_edited(true);
|
||||
|
||||
// update our editor right away
|
||||
OpenXRActionSetEditor *action_set_editor = _add_action_set_editor(new_action_set);
|
||||
|
||||
undo_redo->create_action(TTR("Add action set"));
|
||||
undo_redo->add_do_method(this, "_do_add_action_set_editor", action_set_editor);
|
||||
undo_redo->add_undo_method(this, "_do_remove_action_set_editor", action_set_editor);
|
||||
undo_redo->commit_action(false);
|
||||
|
||||
return action_set_editor;
|
||||
}
|
||||
|
||||
void OpenXRActionMapEditor::_remove_action_set(String p_name) {
|
||||
ERR_FAIL_COND(action_map.is_null());
|
||||
Ref<OpenXRActionSet> action_set = action_map->find_action_set(p_name);
|
||||
ERR_FAIL_COND(action_set.is_null());
|
||||
|
||||
for (int i = 0; i < actionsets_vb->get_child_count(); i++) {
|
||||
OpenXRActionSetEditor *action_set_editor = Object::cast_to<OpenXRActionSetEditor>(actionsets_vb->get_child(i));
|
||||
if (action_set_editor && action_set_editor->get_action_set() == action_set) {
|
||||
_on_remove_action_set(action_set_editor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRActionMapEditor::_on_add_action_set() {
|
||||
ERR_FAIL_COND(action_map.is_null());
|
||||
String new_name = "New";
|
||||
int count = 0;
|
||||
|
||||
while (action_map->find_action_set(new_name).is_valid()) {
|
||||
new_name = "New_" + itos(count++);
|
||||
}
|
||||
|
||||
OpenXRActionSetEditor *new_action_set_editor = _add_action_set(new_name);
|
||||
|
||||
// Make sure our action set is the current tab
|
||||
tabs->set_current_tab(0);
|
||||
|
||||
callable_mp(this, &OpenXRActionMapEditor::_set_focus_on_action_set).call_deferred(new_action_set_editor);
|
||||
}
|
||||
|
||||
void OpenXRActionMapEditor::_set_focus_on_action_set(OpenXRActionSetEditor *p_action_set_editor) {
|
||||
// Scroll down to our new entry
|
||||
actionsets_scroll->ensure_control_visible(p_action_set_editor);
|
||||
|
||||
// Set focus on this entry
|
||||
p_action_set_editor->set_focus_on_entry();
|
||||
}
|
||||
|
||||
void OpenXRActionMapEditor::_on_remove_action_set(Object *p_action_set_editor) {
|
||||
ERR_FAIL_COND(action_map.is_null());
|
||||
|
||||
OpenXRActionSetEditor *action_set_editor = Object::cast_to<OpenXRActionSetEditor>(p_action_set_editor);
|
||||
ERR_FAIL_NULL(action_set_editor);
|
||||
ERR_FAIL_COND(action_set_editor->get_parent() != actionsets_vb);
|
||||
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);
|
||||
undo_redo->commit_action(true);
|
||||
|
||||
action_map->set_edited(true);
|
||||
}
|
||||
|
||||
void OpenXRActionMapEditor::_on_action_removed(Ref<OpenXRAction> p_action) {
|
||||
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(p_action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRActionMapEditor::_on_add_interaction_profile() {
|
||||
ERR_FAIL_COND(action_map.is_null());
|
||||
|
||||
PackedStringArray already_selected;
|
||||
|
||||
for (int i = 0; i < action_map->get_interaction_profile_count(); i++) {
|
||||
already_selected.push_back(action_map->get_interaction_profile(i)->get_interaction_profile_path());
|
||||
}
|
||||
|
||||
select_interaction_profile_dialog->open(already_selected);
|
||||
}
|
||||
|
||||
void OpenXRActionMapEditor::_on_interaction_profile_selected(const String p_path) {
|
||||
ERR_FAIL_COND(action_map.is_null());
|
||||
|
||||
Ref<OpenXRInteractionProfile> new_profile;
|
||||
new_profile.instantiate();
|
||||
new_profile->set_interaction_profile_path(p_path);
|
||||
action_map->add_interaction_profile(new_profile);
|
||||
action_map->set_edited(true);
|
||||
|
||||
OpenXRInteractionProfileEditorBase *interaction_profile_editor = _add_interaction_profile_editor(new_profile);
|
||||
|
||||
undo_redo->create_action(TTR("Add interaction profile"));
|
||||
undo_redo->add_do_method(this, "_do_add_interaction_profile_editor", interaction_profile_editor);
|
||||
undo_redo->add_undo_method(this, "_do_remove_interaction_profile_editor", interaction_profile_editor);
|
||||
undo_redo->commit_action(false);
|
||||
|
||||
tabs->set_current_tab(tabs->get_tab_count() - 1);
|
||||
}
|
||||
|
||||
void OpenXRActionMapEditor::_load_action_map(const String p_path, bool p_create_new_if_missing) {
|
||||
Error err = OK;
|
||||
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
||||
if (da->file_exists(p_path)) {
|
||||
action_map = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &err);
|
||||
if (err != OK) {
|
||||
EditorNode::get_singleton()->show_warning(vformat(TTR("Error loading %s: %s."), edited_path, error_names[err]));
|
||||
|
||||
edited_path = "";
|
||||
header_label->set_text("");
|
||||
return;
|
||||
}
|
||||
} else if (p_create_new_if_missing) {
|
||||
action_map.instantiate();
|
||||
action_map->create_default_action_sets();
|
||||
action_map->set_path(p_path);
|
||||
|
||||
// Save it immediately
|
||||
err = ResourceSaver::save(action_map, p_path);
|
||||
if (err != OK) {
|
||||
// Show warning but continue.
|
||||
EditorNode::get_singleton()->show_warning(vformat(TTR("Error saving file %s: %s"), edited_path, error_names[err]));
|
||||
}
|
||||
}
|
||||
|
||||
edited_path = p_path;
|
||||
header_label->set_text(TTR("OpenXR Action map:") + " " + edited_path.get_file());
|
||||
}
|
||||
|
||||
void OpenXRActionMapEditor::_on_save_action_map() {
|
||||
Error err = ResourceSaver::save(action_map, edited_path);
|
||||
if (err != OK) {
|
||||
EditorNode::get_singleton()->show_warning(vformat(TTR("Error saving file %s: %s"), edited_path, error_names[err]));
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO should clear undo/redo history
|
||||
|
||||
// out with the old
|
||||
_clear_action_map();
|
||||
|
||||
_create_action_sets();
|
||||
_create_interaction_profiles();
|
||||
}
|
||||
|
||||
void OpenXRActionMapEditor::_on_reset_to_default_layout() {
|
||||
// TODO should clear undo/redo history
|
||||
|
||||
// out with the old
|
||||
_clear_action_map();
|
||||
|
||||
// create a new one
|
||||
action_map.unref();
|
||||
action_map.instantiate();
|
||||
action_map->create_default_action_sets();
|
||||
action_map->set_edited(true);
|
||||
|
||||
_create_action_sets();
|
||||
_create_interaction_profiles();
|
||||
}
|
||||
|
||||
void OpenXRActionMapEditor::_on_tabs_tab_changed(int p_tab) {
|
||||
}
|
||||
|
||||
void OpenXRActionMapEditor::_on_tab_button_pressed(int p_tab) {
|
||||
OpenXRInteractionProfileEditorBase *interaction_profile_editor = Object::cast_to<OpenXRInteractionProfileEditorBase>(tabs->get_tab_control(p_tab));
|
||||
ERR_FAIL_NULL(interaction_profile_editor);
|
||||
|
||||
undo_redo->create_action(TTR("Remove interaction profile"));
|
||||
undo_redo->add_do_method(this, "_do_remove_interaction_profile_editor", interaction_profile_editor);
|
||||
undo_redo->add_undo_method(this, "_do_add_interaction_profile_editor", interaction_profile_editor);
|
||||
undo_redo->commit_action(true);
|
||||
|
||||
action_map->set_edited(true);
|
||||
}
|
||||
|
||||
void OpenXRActionMapEditor::_do_add_action_set_editor(OpenXRActionSetEditor *p_action_set_editor) {
|
||||
Ref<OpenXRActionSet> action_set = p_action_set_editor->get_action_set();
|
||||
ERR_FAIL_COND(action_set.is_null());
|
||||
|
||||
action_map->add_action_set(action_set);
|
||||
actionsets_vb->add_child(p_action_set_editor);
|
||||
}
|
||||
|
||||
void OpenXRActionMapEditor::_do_remove_action_set_editor(OpenXRActionSetEditor *p_action_set_editor) {
|
||||
Ref<OpenXRActionSet> action_set = p_action_set_editor->get_action_set();
|
||||
ERR_FAIL_COND(action_set.is_null());
|
||||
|
||||
actionsets_vb->remove_child(p_action_set_editor);
|
||||
action_map->remove_action_set(action_set);
|
||||
}
|
||||
|
||||
void OpenXRActionMapEditor::_do_add_interaction_profile_editor(OpenXRInteractionProfileEditorBase *p_interaction_profile_editor) {
|
||||
Ref<OpenXRInteractionProfile> interaction_profile = p_interaction_profile_editor->get_interaction_profile();
|
||||
ERR_FAIL_COND(interaction_profile.is_null());
|
||||
|
||||
action_map->add_interaction_profile(interaction_profile);
|
||||
tabs->add_child(p_interaction_profile_editor);
|
||||
tabs->set_tab_button_icon(tabs->get_tab_count() - 1, get_theme_icon(SNAME("close"), SNAME("TabBar")));
|
||||
|
||||
tabs->set_current_tab(tabs->get_tab_count() - 1);
|
||||
}
|
||||
|
||||
void OpenXRActionMapEditor::_do_remove_interaction_profile_editor(OpenXRInteractionProfileEditorBase *p_interaction_profile_editor) {
|
||||
Ref<OpenXRInteractionProfile> interaction_profile = p_interaction_profile_editor->get_interaction_profile();
|
||||
ERR_FAIL_COND(interaction_profile.is_null());
|
||||
|
||||
tabs->remove_child(p_interaction_profile_editor);
|
||||
action_map->remove_interaction_profile(interaction_profile);
|
||||
}
|
||||
|
||||
void OpenXRActionMapEditor::open_action_map(String p_path) {
|
||||
EditorNode::get_bottom_panel()->make_item_visible(this);
|
||||
|
||||
// out with the old...
|
||||
_clear_action_map();
|
||||
|
||||
// now load in our new action map
|
||||
_load_action_map(p_path);
|
||||
|
||||
_create_action_sets();
|
||||
_create_interaction_profiles();
|
||||
}
|
||||
|
||||
void OpenXRActionMapEditor::_clear_action_map() {
|
||||
while (actionsets_vb->get_child_count() > 0) {
|
||||
Node *child = actionsets_vb->get_child(0);
|
||||
actionsets_vb->remove_child(child);
|
||||
child->queue_free();
|
||||
}
|
||||
|
||||
for (int i = tabs->get_tab_count() - 1; i >= 0; --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) {
|
||||
tabs->remove_child(interaction_profile_editor);
|
||||
interaction_profile_editor->queue_free();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
top_hb = memnew(HBoxContainer);
|
||||
add_child(top_hb);
|
||||
|
||||
header_label = memnew(Label);
|
||||
header_label->set_text(String(TTR("Action Map")));
|
||||
header_label->set_clip_text(true);
|
||||
header_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
top_hb->add_child(header_label);
|
||||
|
||||
add_action_set = memnew(Button);
|
||||
add_action_set->set_text(TTR("Add Action Set"));
|
||||
add_action_set->set_tooltip_text(TTR("Add an action set."));
|
||||
add_action_set->connect(SceneStringName(pressed), callable_mp(this, &OpenXRActionMapEditor::_on_add_action_set));
|
||||
top_hb->add_child(add_action_set);
|
||||
|
||||
add_interaction_profile = memnew(Button);
|
||||
add_interaction_profile->set_text(TTR("Add profile"));
|
||||
add_interaction_profile->set_tooltip_text(TTR("Add an interaction profile."));
|
||||
add_interaction_profile->connect(SceneStringName(pressed), callable_mp(this, &OpenXRActionMapEditor::_on_add_interaction_profile));
|
||||
top_hb->add_child(add_interaction_profile);
|
||||
|
||||
VSeparator *vseparator = memnew(VSeparator);
|
||||
top_hb->add_child(vseparator);
|
||||
|
||||
save_as = memnew(Button);
|
||||
save_as->set_text(TTR("Save"));
|
||||
save_as->set_tooltip_text(TTR("Save this OpenXR action map."));
|
||||
save_as->connect(SceneStringName(pressed), callable_mp(this, &OpenXRActionMapEditor::_on_save_action_map));
|
||||
top_hb->add_child(save_as);
|
||||
|
||||
_default = memnew(Button);
|
||||
_default->set_text(TTR("Reset to Default"));
|
||||
_default->set_tooltip_text(TTR("Reset to default OpenXR action map."));
|
||||
_default->connect(SceneStringName(pressed), callable_mp(this, &OpenXRActionMapEditor::_on_reset_to_default_layout));
|
||||
top_hb->add_child(_default);
|
||||
|
||||
tabs = memnew(TabContainer);
|
||||
tabs->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
tabs->set_v_size_flags(SIZE_EXPAND_FILL);
|
||||
tabs->set_theme_type_variation("TabContainerOdd");
|
||||
tabs->connect("tab_changed", callable_mp(this, &OpenXRActionMapEditor::_on_tabs_tab_changed));
|
||||
tabs->connect("tab_button_pressed", callable_mp(this, &OpenXRActionMapEditor::_on_tab_button_pressed));
|
||||
add_child(tabs);
|
||||
|
||||
actionsets_scroll = memnew(ScrollContainer);
|
||||
actionsets_scroll->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
actionsets_scroll->set_v_size_flags(SIZE_EXPAND_FILL);
|
||||
actionsets_scroll->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
|
||||
tabs->add_child(actionsets_scroll);
|
||||
actionsets_scroll->set_name(TTR("Action Sets"));
|
||||
|
||||
actionsets_vb = memnew(VBoxContainer);
|
||||
actionsets_vb->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
actionsets_scroll->add_child(actionsets_vb);
|
||||
|
||||
select_interaction_profile_dialog = memnew(OpenXRSelectInteractionProfileDialog);
|
||||
select_interaction_profile_dialog->connect("interaction_profile_selected", callable_mp(this, &OpenXRActionMapEditor::_on_interaction_profile_selected));
|
||||
add_child(select_interaction_profile_dialog);
|
||||
|
||||
// Our Action map editor is only shown if openxr is enabled in project settings
|
||||
// So load our action map and if it doesn't exist, create it right away.
|
||||
_load_action_map(GLOBAL_GET("xr/openxr/default_action_map"), true);
|
||||
}
|
||||
|
||||
OpenXRActionMapEditor::~OpenXRActionMapEditor() {
|
||||
}
|
||||
117
engine/modules/openxr/editor/openxr_action_map_editor.h
Normal file
117
engine/modules/openxr/editor/openxr_action_map_editor.h
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_action_map_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_ACTION_MAP_EDITOR_H
|
||||
#define OPENXR_ACTION_MAP_EDITOR_H
|
||||
|
||||
#include "../action_map/openxr_action_map.h"
|
||||
#include "openxr_action_set_editor.h"
|
||||
#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"
|
||||
#include "scene/gui/button.h"
|
||||
#include "scene/gui/label.h"
|
||||
#include "scene/gui/scroll_container.h"
|
||||
#include "scene/gui/tab_container.h"
|
||||
|
||||
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;
|
||||
|
||||
HBoxContainer *top_hb = nullptr;
|
||||
Label *header_label = nullptr;
|
||||
Button *add_action_set = nullptr;
|
||||
Button *add_interaction_profile = nullptr;
|
||||
Button *load = nullptr;
|
||||
Button *save_as = nullptr;
|
||||
Button *_default = nullptr;
|
||||
TabContainer *tabs = nullptr;
|
||||
ScrollContainer *actionsets_scroll = nullptr;
|
||||
VBoxContainer *actionsets_vb = nullptr;
|
||||
OpenXRSelectInteractionProfileDialog *select_interaction_profile_dialog = nullptr;
|
||||
|
||||
OpenXRActionSetEditor *_add_action_set_editor(Ref<OpenXRActionSet> p_action_set);
|
||||
void _create_action_sets();
|
||||
OpenXRInteractionProfileEditorBase *_add_interaction_profile_editor(Ref<OpenXRInteractionProfile> p_interaction_profile);
|
||||
void _create_interaction_profiles();
|
||||
|
||||
OpenXRActionSetEditor *_add_action_set(String p_name);
|
||||
void _remove_action_set(String p_name);
|
||||
|
||||
void _on_add_action_set();
|
||||
void _set_focus_on_action_set(OpenXRActionSetEditor *p_action_set_editor);
|
||||
void _on_remove_action_set(Object *p_action_set_editor);
|
||||
void _on_action_removed(Ref<OpenXRAction> p_action);
|
||||
|
||||
void _on_add_interaction_profile();
|
||||
void _on_interaction_profile_selected(const String p_path);
|
||||
|
||||
void _load_action_map(const String p_path, bool p_create_new_if_missing = false);
|
||||
void _on_save_action_map();
|
||||
void _on_reset_to_default_layout();
|
||||
|
||||
void _on_tabs_tab_changed(int p_tab);
|
||||
void _on_tab_button_pressed(int p_tab);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
void _notification(int p_what);
|
||||
|
||||
void _clear_action_map();
|
||||
|
||||
// used for undo/redo
|
||||
void _do_add_action_set_editor(OpenXRActionSetEditor *p_action_set_editor);
|
||||
void _do_remove_action_set_editor(OpenXRActionSetEditor *p_action_set_editor);
|
||||
void _do_add_interaction_profile_editor(OpenXRInteractionProfileEditorBase *p_interaction_profile_editor);
|
||||
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();
|
||||
~OpenXRActionMapEditor();
|
||||
};
|
||||
|
||||
#endif // OPENXR_ACTION_MAP_EDITOR_H
|
||||
285
engine/modules/openxr/editor/openxr_action_set_editor.cpp
Normal file
285
engine/modules/openxr/editor/openxr_action_set_editor.cpp
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_action_set_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_action_set_editor.h"
|
||||
|
||||
#include "editor/editor_string_names.h"
|
||||
#include "openxr_action_editor.h"
|
||||
|
||||
void OpenXRActionSetEditor::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("_do_set_name", "name"), &OpenXRActionSetEditor::_do_set_name);
|
||||
ClassDB::bind_method(D_METHOD("_do_set_localized_name", "name"), &OpenXRActionSetEditor::_do_set_localized_name);
|
||||
ClassDB::bind_method(D_METHOD("_do_set_priority", "value"), &OpenXRActionSetEditor::_do_set_priority);
|
||||
ClassDB::bind_method(D_METHOD("_do_add_action_editor", "action_editor"), &OpenXRActionSetEditor::_do_add_action_editor);
|
||||
ClassDB::bind_method(D_METHOD("_do_remove_action_editor", "action_editor"), &OpenXRActionSetEditor::_do_remove_action_editor);
|
||||
|
||||
ADD_SIGNAL(MethodInfo("remove", PropertyInfo(Variant::OBJECT, "action_set_editor")));
|
||||
ADD_SIGNAL(MethodInfo("action_removed", PropertyInfo(Variant::OBJECT, "action")));
|
||||
}
|
||||
|
||||
void OpenXRActionSetEditor::_set_fold_icon() {
|
||||
if (is_expanded) {
|
||||
fold_btn->set_button_icon(get_theme_icon(SNAME("GuiTreeArrowDown"), EditorStringName(EditorIcons)));
|
||||
} else {
|
||||
fold_btn->set_button_icon(get_theme_icon(SNAME("GuiTreeArrowRight"), EditorStringName(EditorIcons)));
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRActionSetEditor::_theme_changed() {
|
||||
_set_fold_icon();
|
||||
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) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_ENTER_TREE:
|
||||
case NOTIFICATION_THEME_CHANGED: {
|
||||
_theme_changed();
|
||||
panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("TabContainer")));
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
OpenXRActionEditor *OpenXRActionSetEditor::_add_action_editor(Ref<OpenXRAction> p_action) {
|
||||
OpenXRActionEditor *action_editor = memnew(OpenXRActionEditor(p_action));
|
||||
action_editor->connect("remove", callable_mp(this, &OpenXRActionSetEditor::_on_remove_action));
|
||||
actions_vb->add_child(action_editor);
|
||||
|
||||
return action_editor;
|
||||
}
|
||||
|
||||
void OpenXRActionSetEditor::_on_toggle_expand() {
|
||||
is_expanded = !is_expanded;
|
||||
actions_vb->set_visible(is_expanded);
|
||||
_set_fold_icon();
|
||||
}
|
||||
|
||||
void OpenXRActionSetEditor::_on_action_set_name_changed(const String p_new_text) {
|
||||
if (action_set->get_name() != p_new_text) {
|
||||
undo_redo->create_action(TTR("Rename Action Set"));
|
||||
undo_redo->add_do_method(this, "_do_set_name", p_new_text);
|
||||
undo_redo->add_undo_method(this, "_do_set_name", action_set->get_name());
|
||||
undo_redo->commit_action(false);
|
||||
|
||||
// If our localized name matches our action set name, set this too
|
||||
if (action_set->get_name() == action_set->get_localized_name()) {
|
||||
undo_redo->create_action(TTR("Rename Action Sets Localized name"));
|
||||
undo_redo->add_do_method(this, "_do_set_localized_name", p_new_text);
|
||||
undo_redo->add_undo_method(this, "_do_set_localized_name", action_set->get_localized_name());
|
||||
undo_redo->commit_action(false);
|
||||
|
||||
action_set->set_localized_name(p_new_text);
|
||||
action_set_localized_name->set_text(p_new_text);
|
||||
}
|
||||
action_set->set_name(p_new_text);
|
||||
action_set->set_edited(true);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRActionSetEditor::_do_set_name(const String p_new_text) {
|
||||
action_set->set_name(p_new_text);
|
||||
action_set_name->set_text(p_new_text);
|
||||
}
|
||||
|
||||
void OpenXRActionSetEditor::_on_action_set_localized_name_changed(const String p_new_text) {
|
||||
if (action_set->get_localized_name() != p_new_text) {
|
||||
undo_redo->create_action(TTR("Rename Action Sets Localized name"));
|
||||
undo_redo->add_do_method(this, "_do_set_localized_name", p_new_text);
|
||||
undo_redo->add_undo_method(this, "_do_set_localized_name", action_set->get_localized_name());
|
||||
undo_redo->commit_action(false);
|
||||
|
||||
action_set->set_localized_name(p_new_text);
|
||||
action_set->set_edited(true);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRActionSetEditor::_do_set_localized_name(const String p_new_text) {
|
||||
action_set->set_localized_name(p_new_text);
|
||||
action_set_localized_name->set_text(p_new_text);
|
||||
}
|
||||
|
||||
void OpenXRActionSetEditor::_on_action_set_priority_changed(const String p_new_text) {
|
||||
int64_t value = p_new_text.to_int();
|
||||
|
||||
if (action_set->get_priority() != value) {
|
||||
undo_redo->create_action(TTR("Change Action Sets priority"));
|
||||
undo_redo->add_do_method(this, "_do_set_priority", value);
|
||||
undo_redo->add_undo_method(this, "_do_set_priority", action_set->get_priority());
|
||||
undo_redo->commit_action(false);
|
||||
|
||||
action_set->set_priority(value);
|
||||
action_set->set_edited(true);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRActionSetEditor::_do_set_priority(int64_t p_value) {
|
||||
action_set->set_priority(p_value);
|
||||
action_set_priority->set_text(itos(p_value));
|
||||
}
|
||||
|
||||
void OpenXRActionSetEditor::_on_add_action() {
|
||||
Ref<OpenXRAction> new_action;
|
||||
|
||||
new_action.instantiate();
|
||||
new_action->set_name("New");
|
||||
new_action->set_localized_name("New");
|
||||
action_set->add_action(new_action);
|
||||
action_set->set_edited(true);
|
||||
|
||||
OpenXRActionEditor *action_editor = _add_action_editor(new_action);
|
||||
|
||||
undo_redo->create_action(TTR("Add action"));
|
||||
undo_redo->add_do_method(this, "_do_add_action_editor", action_editor);
|
||||
undo_redo->add_undo_method(this, "_do_remove_action_editor", action_editor);
|
||||
undo_redo->commit_action(false);
|
||||
|
||||
// TODO handle focus
|
||||
}
|
||||
|
||||
void OpenXRActionSetEditor::_on_remove_action_set() {
|
||||
emit_signal("remove", this);
|
||||
}
|
||||
|
||||
void OpenXRActionSetEditor::_on_remove_action(Object *p_action_editor) {
|
||||
OpenXRActionEditor *action_editor = Object::cast_to<OpenXRActionEditor>(p_action_editor);
|
||||
ERR_FAIL_NULL(action_editor);
|
||||
ERR_FAIL_COND(action_editor->get_parent() != actions_vb);
|
||||
Ref<OpenXRAction> action = action_editor->get_action();
|
||||
ERR_FAIL_COND(action.is_null());
|
||||
|
||||
emit_signal("action_removed", action);
|
||||
|
||||
undo_redo->create_action(TTR("Delete action"));
|
||||
undo_redo->add_do_method(this, "_do_remove_action_editor", action_editor);
|
||||
undo_redo->add_undo_method(this, "_do_add_action_editor", action_editor);
|
||||
undo_redo->commit_action(true);
|
||||
|
||||
action_set->set_edited(true);
|
||||
}
|
||||
|
||||
void OpenXRActionSetEditor::_do_add_action_editor(OpenXRActionEditor *p_action_editor) {
|
||||
Ref<OpenXRAction> action = p_action_editor->get_action();
|
||||
ERR_FAIL_COND(action.is_null());
|
||||
|
||||
action_set->add_action(action);
|
||||
actions_vb->add_child(p_action_editor);
|
||||
}
|
||||
|
||||
void OpenXRActionSetEditor::_do_remove_action_editor(OpenXRActionEditor *p_action_editor) {
|
||||
Ref<OpenXRAction> action = p_action_editor->get_action();
|
||||
ERR_FAIL_COND(action.is_null());
|
||||
|
||||
actions_vb->remove_child(p_action_editor);
|
||||
action_set->remove_action(action);
|
||||
}
|
||||
|
||||
void OpenXRActionSetEditor::remove_all_actions() {
|
||||
for (int i = actions_vb->get_child_count(); i > 0; --i) {
|
||||
_on_remove_action(actions_vb->get_child(i));
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRActionSetEditor::set_focus_on_entry() {
|
||||
ERR_FAIL_NULL(action_set_name);
|
||||
action_set_name->grab_focus();
|
||||
}
|
||||
|
||||
OpenXRActionSetEditor::OpenXRActionSetEditor(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRActionSet> p_action_set) {
|
||||
undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
action_map = p_action_map;
|
||||
action_set = p_action_set;
|
||||
|
||||
set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
|
||||
panel = memnew(PanelContainer);
|
||||
panel->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
add_child(panel);
|
||||
|
||||
HBoxContainer *panel_hb = memnew(HBoxContainer);
|
||||
panel_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
panel->add_child(panel_hb);
|
||||
|
||||
fold_btn = memnew(Button);
|
||||
fold_btn->set_v_size_flags(Control::SIZE_SHRINK_BEGIN);
|
||||
fold_btn->connect(SceneStringName(pressed), callable_mp(this, &OpenXRActionSetEditor::_on_toggle_expand));
|
||||
fold_btn->set_flat(true);
|
||||
panel_hb->add_child(fold_btn);
|
||||
|
||||
main_vb = memnew(VBoxContainer);
|
||||
main_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
panel_hb->add_child(main_vb);
|
||||
|
||||
action_set_hb = memnew(HBoxContainer);
|
||||
action_set_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
main_vb->add_child(action_set_hb);
|
||||
|
||||
action_set_name = memnew(LineEdit);
|
||||
action_set_name->set_text(action_set->get_name());
|
||||
action_set_name->set_custom_minimum_size(Size2(150.0, 0.0));
|
||||
action_set_name->connect(SceneStringName(text_changed), callable_mp(this, &OpenXRActionSetEditor::_on_action_set_name_changed));
|
||||
action_set_hb->add_child(action_set_name);
|
||||
|
||||
action_set_localized_name = memnew(LineEdit);
|
||||
action_set_localized_name->set_text(action_set->get_localized_name());
|
||||
action_set_localized_name->set_custom_minimum_size(Size2(150.0, 0.0));
|
||||
action_set_localized_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
action_set_localized_name->connect(SceneStringName(text_changed), callable_mp(this, &OpenXRActionSetEditor::_on_action_set_localized_name_changed));
|
||||
action_set_hb->add_child(action_set_localized_name);
|
||||
|
||||
action_set_priority = memnew(TextEdit);
|
||||
action_set_priority->set_text(itos(action_set->get_priority()));
|
||||
action_set_priority->set_custom_minimum_size(Size2(50.0, 0.0));
|
||||
action_set_priority->connect(SceneStringName(text_changed), callable_mp(this, &OpenXRActionSetEditor::_on_action_set_priority_changed));
|
||||
action_set_hb->add_child(action_set_priority);
|
||||
|
||||
add_action = memnew(Button);
|
||||
add_action->set_tooltip_text(TTR("Add action."));
|
||||
add_action->connect(SceneStringName(pressed), callable_mp(this, &OpenXRActionSetEditor::_on_add_action));
|
||||
add_action->set_flat(true);
|
||||
action_set_hb->add_child(add_action);
|
||||
|
||||
rem_action_set = memnew(Button);
|
||||
rem_action_set->set_tooltip_text(TTR("Remove action set."));
|
||||
rem_action_set->connect(SceneStringName(pressed), callable_mp(this, &OpenXRActionSetEditor::_on_remove_action_set));
|
||||
rem_action_set->set_flat(true);
|
||||
action_set_hb->add_child(rem_action_set);
|
||||
|
||||
actions_vb = memnew(VBoxContainer);
|
||||
actions_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
main_vb->add_child(actions_vb);
|
||||
|
||||
// Add our existing actions
|
||||
Array actions = action_set->get_actions();
|
||||
for (int i = 0; i < actions.size(); i++) {
|
||||
Ref<OpenXRAction> action = actions[i];
|
||||
_add_action_editor(action);
|
||||
}
|
||||
}
|
||||
98
engine/modules/openxr/editor/openxr_action_set_editor.h
Normal file
98
engine/modules/openxr/editor/openxr_action_set_editor.h
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_action_set_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_ACTION_SET_EDITOR_H
|
||||
#define OPENXR_ACTION_SET_EDITOR_H
|
||||
|
||||
#include "../action_map/openxr_action_map.h"
|
||||
#include "../action_map/openxr_action_set.h"
|
||||
#include "openxr_action_editor.h"
|
||||
|
||||
#include "scene/gui/box_container.h"
|
||||
#include "scene/gui/button.h"
|
||||
#include "scene/gui/line_edit.h"
|
||||
#include "scene/gui/panel_container.h"
|
||||
#include "scene/gui/text_edit.h"
|
||||
|
||||
class OpenXRActionSetEditor : public HBoxContainer {
|
||||
GDCLASS(OpenXRActionSetEditor, HBoxContainer);
|
||||
|
||||
private:
|
||||
EditorUndoRedoManager *undo_redo;
|
||||
Ref<OpenXRActionMap> action_map;
|
||||
Ref<OpenXRActionSet> action_set;
|
||||
|
||||
bool is_expanded = true;
|
||||
|
||||
PanelContainer *panel = nullptr;
|
||||
Button *fold_btn = nullptr;
|
||||
VBoxContainer *main_vb = nullptr;
|
||||
HBoxContainer *action_set_hb = nullptr;
|
||||
LineEdit *action_set_name = nullptr;
|
||||
LineEdit *action_set_localized_name = nullptr;
|
||||
TextEdit *action_set_priority = nullptr;
|
||||
Button *add_action = nullptr;
|
||||
Button *rem_action_set = nullptr;
|
||||
VBoxContainer *actions_vb = nullptr;
|
||||
|
||||
void _set_fold_icon();
|
||||
void _theme_changed();
|
||||
OpenXRActionEditor *_add_action_editor(Ref<OpenXRAction> p_action);
|
||||
|
||||
void _on_toggle_expand();
|
||||
void _on_action_set_name_changed(const String p_new_text);
|
||||
void _on_action_set_localized_name_changed(const String p_new_text);
|
||||
void _on_action_set_priority_changed(const String p_new_text);
|
||||
void _on_add_action();
|
||||
void _on_remove_action_set();
|
||||
|
||||
void _on_remove_action(Object *p_action_editor);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
void _notification(int p_what);
|
||||
|
||||
// used for undo/redo
|
||||
void _do_set_name(const String p_new_text);
|
||||
void _do_set_localized_name(const String p_new_text);
|
||||
void _do_set_priority(int64_t value);
|
||||
void _do_add_action_editor(OpenXRActionEditor *p_action_editor);
|
||||
void _do_remove_action_editor(OpenXRActionEditor *p_action_editor);
|
||||
|
||||
public:
|
||||
Ref<OpenXRActionSet> get_action_set() { return action_set; }
|
||||
void set_focus_on_entry();
|
||||
|
||||
void remove_all_actions();
|
||||
|
||||
OpenXRActionSetEditor(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRActionSet> p_action_set);
|
||||
};
|
||||
|
||||
#endif // OPENXR_ACTION_SET_EDITOR_H
|
||||
289
engine/modules/openxr/editor/openxr_binding_modifier_editor.cpp
Normal file
289
engine/modules/openxr/editor/openxr_binding_modifier_editor.cpp
Normal 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());
|
||||
}
|
||||
}
|
||||
113
engine/modules/openxr/editor/openxr_binding_modifier_editor.h
Normal file
113
engine/modules/openxr/editor/openxr_binding_modifier_editor.h
Normal 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
|
||||
257
engine/modules/openxr/editor/openxr_binding_modifiers_dialog.cpp
Normal file
257
engine/modules/openxr/editor/openxr_binding_modifiers_dialog.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
69
engine/modules/openxr/editor/openxr_editor_plugin.cpp
Normal file
69
engine/modules/openxr/editor/openxr_editor_plugin.cpp
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_editor_plugin.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_editor_plugin.h"
|
||||
|
||||
#include "../action_map/openxr_action_map.h"
|
||||
|
||||
#include "editor/editor_command_palette.h"
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor/gui/editor_bottom_panel.h"
|
||||
|
||||
void OpenXREditorPlugin::edit(Object *p_node) {
|
||||
if (Object::cast_to<OpenXRActionMap>(p_node)) {
|
||||
String path = Object::cast_to<OpenXRActionMap>(p_node)->get_path();
|
||||
if (path.is_resource_file()) {
|
||||
action_map_editor->open_action_map(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool OpenXREditorPlugin::handles(Object *p_node) const {
|
||||
return (Object::cast_to<OpenXRActionMap>(p_node) != nullptr);
|
||||
}
|
||||
|
||||
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", 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);
|
||||
add_control_to_container(CONTAINER_TOOLBAR, select_runtime);
|
||||
#endif
|
||||
}
|
||||
|
||||
OpenXREditorPlugin::~OpenXREditorPlugin() {
|
||||
}
|
||||
60
engine/modules/openxr/editor/openxr_editor_plugin.h
Normal file
60
engine/modules/openxr/editor/openxr_editor_plugin.h
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_editor_plugin.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_EDITOR_PLUGIN_H
|
||||
#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"
|
||||
|
||||
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_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;
|
||||
virtual void make_visible(bool p_visible) override;
|
||||
|
||||
OpenXREditorPlugin();
|
||||
~OpenXREditorPlugin();
|
||||
};
|
||||
|
||||
#endif // OPENXR_EDITOR_PLUGIN_H
|
||||
|
|
@ -0,0 +1,399 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_interaction_profile_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_interaction_profile_editor.h"
|
||||
#include "../openxr_api.h"
|
||||
#include "editor/editor_string_names.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);
|
||||
}
|
||||
|
||||
void OpenXRInteractionProfileEditorBase::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
_update_interaction_profile();
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_THEME_CHANGED: {
|
||||
_theme_changed();
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRInteractionProfileEditorBase::_do_update_interaction_profile() {
|
||||
if (!is_dirty) {
|
||||
is_dirty = true;
|
||||
callable_mp(this, &OpenXRInteractionProfileEditorBase::_update_interaction_profile).call_deferred();
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRInteractionProfileEditorBase::_add_binding(const String p_action, const String p_path) {
|
||||
ERR_FAIL_COND(action_map.is_null());
|
||||
ERR_FAIL_COND(interaction_profile.is_null());
|
||||
|
||||
Ref<OpenXRAction> action = action_map->get_action(p_action);
|
||||
ERR_FAIL_COND(action.is_null());
|
||||
|
||||
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->set_edited(true);
|
||||
}
|
||||
|
||||
// Update our toplevel paths
|
||||
action->set_toplevel_paths(action_map->get_top_level_paths(action));
|
||||
|
||||
_do_update_interaction_profile();
|
||||
}
|
||||
|
||||
void OpenXRInteractionProfileEditorBase::_remove_binding(const String p_action, const String p_path) {
|
||||
ERR_FAIL_COND(action_map.is_null());
|
||||
ERR_FAIL_COND(interaction_profile.is_null());
|
||||
|
||||
Ref<OpenXRAction> action = action_map->get_action(p_action);
|
||||
ERR_FAIL_COND(action.is_null());
|
||||
|
||||
Ref<OpenXRIPBinding> binding = interaction_profile->find_binding(action, p_path);
|
||||
if (binding.is_valid()) {
|
||||
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));
|
||||
|
||||
_do_update_interaction_profile();
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
undo_redo->create_action(TTR("Remove action from interaction profile"));
|
||||
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 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
|
||||
p_action->set_toplevel_paths(action_map->get_top_level_paths(p_action));
|
||||
|
||||
_do_update_interaction_profile();
|
||||
}
|
||||
}
|
||||
void OpenXRInteractionProfileEditorBase::_on_open_binding_modifiers() {
|
||||
binding_modifiers_dialog->popup_centered(Size2i(500, 400));
|
||||
}
|
||||
|
||||
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();
|
||||
String profile_name = profile_path;
|
||||
|
||||
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);
|
||||
|
||||
// Make sure it is updated when it enters the tree...
|
||||
is_dirty = true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Default interaction profile editor
|
||||
|
||||
void OpenXRInteractionProfileEditor::select_action_for(const String p_io_path) {
|
||||
selecting_for_io_path = p_io_path;
|
||||
select_action_dialog->open();
|
||||
}
|
||||
|
||||
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);
|
||||
undo_redo->commit_action(true);
|
||||
|
||||
selecting_for_io_path = "";
|
||||
}
|
||||
|
||||
void OpenXRInteractionProfileEditor::_on_remove_pressed(const String p_action, const String p_for_io_path) {
|
||||
undo_redo->create_action(TTR("Remove binding"));
|
||||
undo_redo->add_do_method(this, "_remove_binding", p_action, p_for_io_path);
|
||||
undo_redo->add_undo_method(this, "_add_binding", p_action, p_for_io_path);
|
||||
undo_redo->commit_action(true);
|
||||
}
|
||||
|
||||
void OpenXRInteractionProfileEditor::_add_io_path(VBoxContainer *p_container, const OpenXRInteractionProfileMetadata::IOPath *p_io_path) {
|
||||
HBoxContainer *path_hb = memnew(HBoxContainer);
|
||||
path_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
p_container->add_child(path_hb);
|
||||
|
||||
Label *path_label = memnew(Label);
|
||||
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);
|
||||
|
||||
Label *type_label = memnew(Label);
|
||||
switch (p_io_path->action_type) {
|
||||
case OpenXRAction::OPENXR_ACTION_BOOL: {
|
||||
type_label->set_text(TTR("Boolean"));
|
||||
} break;
|
||||
case OpenXRAction::OPENXR_ACTION_FLOAT: {
|
||||
type_label->set_text(TTR("Float"));
|
||||
} break;
|
||||
case OpenXRAction::OPENXR_ACTION_VECTOR2: {
|
||||
type_label->set_text(TTR("Vector2"));
|
||||
} break;
|
||||
case OpenXRAction::OPENXR_ACTION_POSE: {
|
||||
type_label->set_text(TTR("Pose"));
|
||||
} break;
|
||||
case OpenXRAction::OPENXR_ACTION_HAPTIC: {
|
||||
type_label->set_text(TTR("Haptic"));
|
||||
} break;
|
||||
default: {
|
||||
type_label->set_text(TTR("Unknown"));
|
||||
} break;
|
||||
}
|
||||
type_label->set_custom_minimum_size(Size2(50.0, 0.0));
|
||||
path_hb->add_child(type_label);
|
||||
|
||||
Button *path_add = memnew(Button);
|
||||
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);
|
||||
|
||||
if (interaction_profile.is_valid()) {
|
||||
String io_path = String(p_io_path->openxr_path);
|
||||
Array bindings = interaction_profile->get_bindings();
|
||||
for (Ref<OpenXRIPBinding> binding : bindings) {
|
||||
if (binding->get_binding_path() == io_path) {
|
||||
Ref<OpenXRAction> action = binding->get_action();
|
||||
|
||||
HBoxContainer *action_hb = memnew(HBoxContainer);
|
||||
action_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
p_container->add_child(action_hb);
|
||||
|
||||
Control *indent_node = memnew(Control);
|
||||
indent_node->set_custom_minimum_size(Size2(10.0, 0.0));
|
||||
action_hb->add_child(indent_node);
|
||||
|
||||
Label *action_label = memnew(Label);
|
||||
action_label->set_text(action->get_name_with_set() + ": " + action->get_localized_name());
|
||||
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_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRInteractionProfileEditor::_update_interaction_profile() {
|
||||
ERR_FAIL_NULL(profile_def);
|
||||
|
||||
if (!is_dirty) {
|
||||
// no need to update
|
||||
return;
|
||||
}
|
||||
|
||||
PackedStringArray requested_extensions = OpenXRAPI::get_all_requested_extensions();
|
||||
|
||||
// out with the old...
|
||||
while (interaction_profile_hb->get_child_count() > 0) {
|
||||
memdelete(interaction_profile_hb->get_child(0));
|
||||
}
|
||||
|
||||
// in with the new...
|
||||
|
||||
// Determine toplevel paths
|
||||
Vector<String> top_level_paths;
|
||||
for (int i = 0; i < profile_def->io_paths.size(); i++) {
|
||||
const OpenXRInteractionProfileMetadata::IOPath *io_path = &profile_def->io_paths[i];
|
||||
|
||||
if (!top_level_paths.has(io_path->top_level_path)) {
|
||||
top_level_paths.push_back(io_path->top_level_path);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < top_level_paths.size(); i++) {
|
||||
PanelContainer *panel = memnew(PanelContainer);
|
||||
panel->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
interaction_profile_hb->add_child(panel);
|
||||
panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("TabContainer")));
|
||||
|
||||
VBoxContainer *container = memnew(VBoxContainer);
|
||||
panel->add_child(container);
|
||||
|
||||
Label *label = memnew(Label);
|
||||
label->set_text(OpenXRInteractionProfileMetadata::get_singleton()->get_top_level_name(top_level_paths[i]));
|
||||
container->add_child(label);
|
||||
|
||||
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] && (io_path->openxr_extension_name.is_empty() || requested_extensions.has(io_path->openxr_extension_name))) {
|
||||
_add_io_path(container, io_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OpenXRInteractionProfileEditorBase::_update_interaction_profile();
|
||||
}
|
||||
|
||||
void OpenXRInteractionProfileEditor::_theme_changed() {
|
||||
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() {
|
||||
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::_on_action_selected));
|
||||
add_child(select_action_dialog);
|
||||
}
|
||||
110
engine/modules/openxr/editor/openxr_interaction_profile_editor.h
Normal file
110
engine/modules/openxr/editor/openxr_interaction_profile_editor.h
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_interaction_profile_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_INTERACTION_PROFILE_EDITOR_H
|
||||
#define OPENXR_INTERACTION_PROFILE_EDITOR_H
|
||||
|
||||
#include "../action_map/openxr_action_map.h"
|
||||
#include "../action_map/openxr_interaction_profile.h"
|
||||
#include "../action_map/openxr_interaction_profile_metadata.h"
|
||||
#include "../editor/openxr_binding_modifiers_dialog.h"
|
||||
#include "editor/editor_undo_redo_manager.h"
|
||||
#include "openxr_select_action_dialog.h"
|
||||
#include "scene/gui/box_container.h"
|
||||
#include "scene/gui/button.h"
|
||||
|
||||
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();
|
||||
void _notification(int p_what);
|
||||
|
||||
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();
|
||||
|
||||
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_for_action_set(Ref<OpenXRActionSet> p_action_set);
|
||||
void remove_all_for_action(Ref<OpenXRAction> p_action);
|
||||
|
||||
virtual void setup(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile);
|
||||
|
||||
OpenXRInteractionProfileEditorBase();
|
||||
};
|
||||
|
||||
class OpenXRInteractionProfileEditor : public OpenXRInteractionProfileEditorBase {
|
||||
GDCLASS(OpenXRInteractionProfileEditor, OpenXRInteractionProfileEditorBase);
|
||||
|
||||
private:
|
||||
String selecting_for_io_path;
|
||||
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 _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;
|
||||
virtual void setup(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile) override;
|
||||
|
||||
OpenXRInteractionProfileEditor();
|
||||
};
|
||||
|
||||
#endif // OPENXR_INTERACTION_PROFILE_EDITOR_H
|
||||
133
engine/modules/openxr/editor/openxr_select_action_dialog.cpp
Normal file
133
engine/modules/openxr/editor/openxr_select_action_dialog.cpp
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_select_action_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_select_action_dialog.h"
|
||||
|
||||
void OpenXRSelectActionDialog::_bind_methods() {
|
||||
ADD_SIGNAL(MethodInfo("action_selected", PropertyInfo(Variant::STRING, "action")));
|
||||
}
|
||||
|
||||
void OpenXRSelectActionDialog::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_ENTER_TREE:
|
||||
case NOTIFICATION_THEME_CHANGED: {
|
||||
scroll->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRSelectActionDialog::_on_select_action(const String p_action) {
|
||||
if (selected_action != "") {
|
||||
NodePath button_path = action_buttons[selected_action];
|
||||
Button *button = Object::cast_to<Button>(get_node(button_path));
|
||||
if (button != nullptr) {
|
||||
button->set_flat(true);
|
||||
}
|
||||
}
|
||||
|
||||
selected_action = p_action;
|
||||
|
||||
if (selected_action != "") {
|
||||
NodePath button_path = action_buttons[selected_action];
|
||||
Button *button = Object::cast_to<Button>(get_node(button_path));
|
||||
if (button != nullptr) {
|
||||
button->set_flat(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRSelectActionDialog::open() {
|
||||
ERR_FAIL_COND(action_map.is_null());
|
||||
|
||||
// Out with the old.
|
||||
while (main_vb->get_child_count() > 0) {
|
||||
memdelete(main_vb->get_child(0));
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
Label *action_set_label = memnew(Label);
|
||||
action_set_label->set_text(action_set->get_localized_name());
|
||||
main_vb->add_child(action_set_label);
|
||||
|
||||
Array actions = action_set->get_actions();
|
||||
for (int j = 0; j < actions.size(); j++) {
|
||||
Ref<OpenXRAction> action = actions[j];
|
||||
|
||||
HBoxContainer *action_hb = memnew(HBoxContainer);
|
||||
main_vb->add_child(action_hb);
|
||||
|
||||
Control *indent_node = memnew(Control);
|
||||
indent_node->set_custom_minimum_size(Size2(10.0, 0.0));
|
||||
action_hb->add_child(indent_node);
|
||||
|
||||
Button *action_button = memnew(Button);
|
||||
String action_name = action->get_name_with_set();
|
||||
action_button->set_flat(true);
|
||||
action_button->set_text(action->get_name() + ": " + action->get_localized_name());
|
||||
action_button->connect(SceneStringName(pressed), callable_mp(this, &OpenXRSelectActionDialog::_on_select_action).bind(action_name));
|
||||
action_hb->add_child(action_button);
|
||||
|
||||
action_buttons[action_name] = action_button->get_path();
|
||||
}
|
||||
}
|
||||
|
||||
popup_centered();
|
||||
}
|
||||
|
||||
void OpenXRSelectActionDialog::ok_pressed() {
|
||||
if (selected_action == "") {
|
||||
return;
|
||||
}
|
||||
|
||||
emit_signal("action_selected", selected_action);
|
||||
|
||||
hide();
|
||||
}
|
||||
|
||||
OpenXRSelectActionDialog::OpenXRSelectActionDialog(Ref<OpenXRActionMap> p_action_map) {
|
||||
action_map = p_action_map;
|
||||
|
||||
set_title(TTR("Select an action"));
|
||||
|
||||
scroll = memnew(ScrollContainer);
|
||||
scroll->set_custom_minimum_size(Size2(600.0, 400.0));
|
||||
add_child(scroll);
|
||||
|
||||
main_vb = memnew(VBoxContainer);
|
||||
main_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
scroll->add_child(main_vb);
|
||||
}
|
||||
68
engine/modules/openxr/editor/openxr_select_action_dialog.h
Normal file
68
engine/modules/openxr/editor/openxr_select_action_dialog.h
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_select_action_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_SELECT_ACTION_DIALOG_H
|
||||
#define OPENXR_SELECT_ACTION_DIALOG_H
|
||||
|
||||
#include "../action_map/openxr_action_map.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 OpenXRSelectActionDialog : public ConfirmationDialog {
|
||||
GDCLASS(OpenXRSelectActionDialog, ConfirmationDialog);
|
||||
|
||||
private:
|
||||
Ref<OpenXRActionMap> action_map;
|
||||
String selected_action;
|
||||
Dictionary action_buttons;
|
||||
|
||||
VBoxContainer *main_vb = nullptr;
|
||||
ScrollContainer *scroll = nullptr;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
void _notification(int p_what);
|
||||
|
||||
public:
|
||||
void _on_select_action(const String p_action);
|
||||
void open();
|
||||
virtual void ok_pressed() override;
|
||||
|
||||
OpenXRSelectActionDialog(Ref<OpenXRActionMap> p_action_map);
|
||||
};
|
||||
|
||||
#endif // OPENXR_SELECT_ACTION_DIALOG_H
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_select_interaction_profile_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_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")));
|
||||
}
|
||||
|
||||
void OpenXRSelectInteractionProfileDialog::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_ENTER_TREE:
|
||||
case NOTIFICATION_THEME_CHANGED: {
|
||||
scroll->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRSelectInteractionProfileDialog::_on_select_interaction_profile(const String p_interaction_profile) {
|
||||
if (selected_interaction_profile != "") {
|
||||
NodePath button_path = ip_buttons[selected_interaction_profile];
|
||||
Button *button = Object::cast_to<Button>(get_node(button_path));
|
||||
if (button != nullptr) {
|
||||
button->set_flat(true);
|
||||
}
|
||||
}
|
||||
|
||||
selected_interaction_profile = p_interaction_profile;
|
||||
|
||||
if (selected_interaction_profile != "") {
|
||||
NodePath button_path = ip_buttons[selected_interaction_profile];
|
||||
Button *button = Object::cast_to<Button>(get_node(button_path));
|
||||
if (button != nullptr) {
|
||||
button->set_flat(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRSelectInteractionProfileDialog::open(PackedStringArray p_do_not_include) {
|
||||
int available_count = 0;
|
||||
|
||||
OpenXRInteractionProfileMetadata *meta_data = OpenXRInteractionProfileMetadata::get_singleton();
|
||||
ERR_FAIL_NULL(meta_data);
|
||||
|
||||
// Out with the old.
|
||||
while (main_vb->get_child_count() > 1) {
|
||||
memdelete(main_vb->get_child(1));
|
||||
}
|
||||
|
||||
PackedStringArray requested_extensions = OpenXRAPI::get_all_requested_extensions();
|
||||
|
||||
selected_interaction_profile = "";
|
||||
ip_buttons.clear();
|
||||
|
||||
// In with the new.
|
||||
PackedStringArray interaction_profiles = 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(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);
|
||||
|
||||
ip_buttons[path] = ip_button->get_path();
|
||||
available_count++;
|
||||
}
|
||||
}
|
||||
|
||||
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 != "") {
|
||||
emit_signal("interaction_profile_selected", selected_interaction_profile);
|
||||
}
|
||||
|
||||
hide();
|
||||
}
|
||||
|
||||
OpenXRSelectInteractionProfileDialog::OpenXRSelectInteractionProfileDialog() {
|
||||
set_title(TTR("Select an interaction profile"));
|
||||
|
||||
scroll = memnew(ScrollContainer);
|
||||
scroll->set_custom_minimum_size(Size2(600.0, 400.0));
|
||||
add_child(scroll);
|
||||
|
||||
main_vb = memnew(VBoxContainer);
|
||||
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);
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_select_interaction_profile_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_SELECT_INTERACTION_PROFILE_DIALOG_H
|
||||
#define OPENXR_SELECT_INTERACTION_PROFILE_DIALOG_H
|
||||
|
||||
#include "scene/gui/box_container.h"
|
||||
#include "scene/gui/dialogs.h"
|
||||
#include "scene/gui/label.h"
|
||||
#include "scene/gui/scroll_container.h"
|
||||
|
||||
class OpenXRSelectInteractionProfileDialog : public ConfirmationDialog {
|
||||
GDCLASS(OpenXRSelectInteractionProfileDialog, ConfirmationDialog);
|
||||
|
||||
private:
|
||||
String selected_interaction_profile;
|
||||
Dictionary ip_buttons;
|
||||
|
||||
VBoxContainer *main_vb = nullptr;
|
||||
ScrollContainer *scroll = nullptr;
|
||||
Label *all_selected = nullptr;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
void _notification(int p_what);
|
||||
|
||||
public:
|
||||
void _on_select_interaction_profile(const String p_interaction_profile);
|
||||
void open(PackedStringArray p_do_not_include);
|
||||
virtual void ok_pressed() override;
|
||||
|
||||
OpenXRSelectInteractionProfileDialog();
|
||||
};
|
||||
|
||||
#endif // OPENXR_SELECT_INTERACTION_PROFILE_DIALOG_H
|
||||
129
engine/modules/openxr/editor/openxr_select_runtime.cpp
Normal file
129
engine/modules/openxr/editor/openxr_select_runtime.cpp
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_select_runtime.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_select_runtime.h"
|
||||
|
||||
#include "core/io/dir_access.h"
|
||||
#include "core/os/os.h"
|
||||
#include "editor/editor_settings.h"
|
||||
|
||||
void OpenXRSelectRuntime::_update_items() {
|
||||
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||
OS *os = OS::get_singleton();
|
||||
Dictionary runtimes = EDITOR_GET("xr/openxr/runtime_paths");
|
||||
|
||||
int current_runtime = 0;
|
||||
int index = 0;
|
||||
String current_path = os->get_environment("XR_RUNTIME_JSON");
|
||||
|
||||
// Parse the user's home folder.
|
||||
String home_folder = os->get_environment("HOME");
|
||||
if (home_folder.is_empty()) {
|
||||
home_folder = os->get_environment("HOMEDRIVE") + os->get_environment("HOMEPATH");
|
||||
}
|
||||
|
||||
clear();
|
||||
add_item("Default", -1);
|
||||
set_item_metadata(index, "");
|
||||
index++;
|
||||
|
||||
Array keys = runtimes.keys();
|
||||
for (int i = 0; i < keys.size(); i++) {
|
||||
String key = keys[i];
|
||||
String path = runtimes[key];
|
||||
String adj_path = path.replace("~", home_folder);
|
||||
|
||||
if (da->file_exists(adj_path)) {
|
||||
add_item(key, index);
|
||||
set_item_metadata(index, adj_path);
|
||||
|
||||
if (current_path == adj_path) {
|
||||
current_runtime = index;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
select(current_runtime);
|
||||
}
|
||||
|
||||
void OpenXRSelectRuntime::_on_item_selected(int p_which) {
|
||||
OS *os = OS::get_singleton();
|
||||
|
||||
if (p_which == 0) {
|
||||
// Return to default runtime
|
||||
os->set_environment("XR_RUNTIME_JSON", "");
|
||||
} else {
|
||||
// Select the runtime we want
|
||||
String runtime_path = get_item_metadata(p_which);
|
||||
os->set_environment("XR_RUNTIME_JSON", runtime_path);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRSelectRuntime::_notification(int p_notification) {
|
||||
switch (p_notification) {
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
// Update dropdown
|
||||
_update_items();
|
||||
|
||||
// Connect signal
|
||||
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::_on_item_selected));
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
OpenXRSelectRuntime::OpenXRSelectRuntime() {
|
||||
Dictionary default_runtimes;
|
||||
|
||||
// Add known common runtimes by default.
|
||||
#ifdef WINDOWS_ENABLED
|
||||
default_runtimes["Meta"] = "C:\\Program Files\\Oculus\\Support\\oculus-runtime\\oculus_openxr_64.json";
|
||||
default_runtimes["SteamVR"] = "C:\\Program Files (x86)\\Steam\\steamapps\\common\\SteamVR\\steamxr_win64.json";
|
||||
default_runtimes["Varjo"] = "C:\\Program Files\\Varjo\\varjo-openxr\\VarjoOpenXR.json";
|
||||
default_runtimes["WMR"] = "C:\\WINDOWS\\system32\\MixedRealityRuntime.json";
|
||||
#endif
|
||||
#ifdef LINUXBSD_ENABLED
|
||||
default_runtimes["Monado"] = "/usr/share/openxr/1/openxr_monado.json";
|
||||
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);
|
||||
set_theme_type_variation("TopBarOptionButton");
|
||||
set_fit_to_longest_item(false);
|
||||
set_focus_mode(Control::FOCUS_NONE);
|
||||
set_tooltip_text(TTR("Choose an XR runtime."));
|
||||
}
|
||||
50
engine/modules/openxr/editor/openxr_select_runtime.h
Normal file
50
engine/modules/openxr/editor/openxr_select_runtime.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_select_runtime.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_SELECT_RUNTIME_H
|
||||
#define OPENXR_SELECT_RUNTIME_H
|
||||
|
||||
#include "scene/gui/option_button.h"
|
||||
|
||||
class OpenXRSelectRuntime : public OptionButton {
|
||||
GDCLASS(OpenXRSelectRuntime, OptionButton);
|
||||
|
||||
public:
|
||||
OpenXRSelectRuntime();
|
||||
|
||||
protected:
|
||||
void _notification(int p_notification);
|
||||
|
||||
private:
|
||||
void _update_items();
|
||||
void _on_item_selected(int p_which);
|
||||
};
|
||||
|
||||
#endif // OPENXR_SELECT_RUNTIME_H
|
||||
21
engine/modules/openxr/extensions/SCsub
Normal file
21
engine/modules/openxr/extensions/SCsub
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env python
|
||||
from misc.utility.scons_hints import *
|
||||
|
||||
Import("env")
|
||||
Import("env_openxr")
|
||||
|
||||
module_obj = []
|
||||
|
||||
env_openxr.add_source_files(module_obj, "*.cpp")
|
||||
|
||||
# These are platform dependent
|
||||
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")
|
||||
|
||||
env.modules_sources += module_obj
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_composition_layer_depth_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_composition_layer_depth_extension.h"
|
||||
|
||||
OpenXRCompositionLayerDepthExtension *OpenXRCompositionLayerDepthExtension::singleton = nullptr;
|
||||
|
||||
OpenXRCompositionLayerDepthExtension *OpenXRCompositionLayerDepthExtension::get_singleton() {
|
||||
return singleton;
|
||||
}
|
||||
|
||||
OpenXRCompositionLayerDepthExtension::OpenXRCompositionLayerDepthExtension() {
|
||||
singleton = this;
|
||||
}
|
||||
|
||||
OpenXRCompositionLayerDepthExtension::~OpenXRCompositionLayerDepthExtension() {
|
||||
singleton = nullptr;
|
||||
}
|
||||
|
||||
HashMap<String, bool *> OpenXRCompositionLayerDepthExtension::get_requested_extensions() {
|
||||
HashMap<String, bool *> request_extensions;
|
||||
|
||||
request_extensions[XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME] = &available;
|
||||
|
||||
return request_extensions;
|
||||
}
|
||||
|
||||
bool OpenXRCompositionLayerDepthExtension::is_available() {
|
||||
return available;
|
||||
}
|
||||
|
||||
int OpenXRCompositionLayerDepthExtension::get_composition_layer_count() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
XrCompositionLayerBaseHeader *OpenXRCompositionLayerDepthExtension::get_composition_layer(int p_index) {
|
||||
// Seems this is all done in our base layer... Just in case this changes...
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int OpenXRCompositionLayerDepthExtension::get_composition_layer_order(int p_index) {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_composition_layer_depth_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_COMPOSITION_LAYER_DEPTH_EXTENSION_H
|
||||
#define OPENXR_COMPOSITION_LAYER_DEPTH_EXTENSION_H
|
||||
|
||||
#include "openxr_composition_layer_provider.h"
|
||||
#include "openxr_extension_wrapper.h"
|
||||
|
||||
class OpenXRCompositionLayerDepthExtension : public OpenXRExtensionWrapper, public OpenXRCompositionLayerProvider {
|
||||
public:
|
||||
static OpenXRCompositionLayerDepthExtension *get_singleton();
|
||||
|
||||
OpenXRCompositionLayerDepthExtension();
|
||||
virtual ~OpenXRCompositionLayerDepthExtension() override;
|
||||
|
||||
virtual HashMap<String, bool *> get_requested_extensions() override;
|
||||
bool is_available();
|
||||
virtual int get_composition_layer_count() override;
|
||||
virtual XrCompositionLayerBaseHeader *get_composition_layer(int p_index) override;
|
||||
virtual int get_composition_layer_order(int p_index) override;
|
||||
|
||||
private:
|
||||
static OpenXRCompositionLayerDepthExtension *singleton;
|
||||
|
||||
bool available = false;
|
||||
};
|
||||
|
||||
#endif // OPENXR_COMPOSITION_LAYER_DEPTH_EXTENSION_H
|
||||
|
|
@ -0,0 +1,493 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_composition_layer_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_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"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// OpenXRCompositionLayerExtension
|
||||
|
||||
OpenXRCompositionLayerExtension *OpenXRCompositionLayerExtension::singleton = nullptr;
|
||||
|
||||
OpenXRCompositionLayerExtension *OpenXRCompositionLayerExtension::get_singleton() {
|
||||
return singleton;
|
||||
}
|
||||
|
||||
OpenXRCompositionLayerExtension::OpenXRCompositionLayerExtension() {
|
||||
singleton = this;
|
||||
}
|
||||
|
||||
OpenXRCompositionLayerExtension::~OpenXRCompositionLayerExtension() {
|
||||
singleton = nullptr;
|
||||
}
|
||||
|
||||
HashMap<String, bool *> OpenXRCompositionLayerExtension::get_requested_extensions() {
|
||||
HashMap<String, bool *> request_extensions;
|
||||
|
||||
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_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();
|
||||
}
|
||||
}
|
||||
|
||||
int OpenXRCompositionLayerExtension::get_composition_layer_count() {
|
||||
return composition_layers.size();
|
||||
}
|
||||
|
||||
XrCompositionLayerBaseHeader *OpenXRCompositionLayerExtension::get_composition_layer(int p_index) {
|
||||
ERR_FAIL_INDEX_V(p_index, composition_layers.size(), nullptr);
|
||||
return composition_layers[p_index]->get_composition_layer();
|
||||
}
|
||||
|
||||
int OpenXRCompositionLayerExtension::get_composition_layer_order(int p_index) {
|
||||
ERR_FAIL_INDEX_V(p_index, composition_layers.size(), 1);
|
||||
return composition_layers[p_index]->get_sort_order();
|
||||
}
|
||||
|
||||
void OpenXRCompositionLayerExtension::register_viewport_composition_layer_provider(OpenXRViewportCompositionLayerProvider *p_composition_layer) {
|
||||
composition_layers.push_back(p_composition_layer);
|
||||
}
|
||||
|
||||
void OpenXRCompositionLayerExtension::unregister_viewport_composition_layer_provider(OpenXRViewportCompositionLayerProvider *p_composition_layer) {
|
||||
composition_layers.erase(p_composition_layer);
|
||||
}
|
||||
|
||||
bool OpenXRCompositionLayerExtension::is_available(XrStructureType p_which) {
|
||||
switch (p_which) {
|
||||
case XR_TYPE_COMPOSITION_LAYER_QUAD: {
|
||||
// Doesn't require an extension.
|
||||
return true;
|
||||
} break;
|
||||
case XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR: {
|
||||
return cylinder_ext_available;
|
||||
} break;
|
||||
case XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR: {
|
||||
return equirect_ext_available;
|
||||
} break;
|
||||
default: {
|
||||
ERR_PRINT(vformat("Unsupported composition layer type: %s", p_which));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
OpenXRViewportCompositionLayerProvider::OpenXRViewportCompositionLayerProvider(XrCompositionLayerBaseHeader *p_composition_layer) {
|
||||
composition_layer = p_composition_layer;
|
||||
openxr_api = OpenXRAPI::get_singleton();
|
||||
composition_layer_extension = OpenXRCompositionLayerExtension::get_singleton();
|
||||
}
|
||||
|
||||
OpenXRViewportCompositionLayerProvider::~OpenXRViewportCompositionLayerProvider() {
|
||||
for (OpenXRExtensionWrapper *extension : OpenXRAPI::get_registered_extension_wrappers()) {
|
||||
extension->on_viewport_composition_layer_destroyed(composition_layer);
|
||||
}
|
||||
|
||||
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) {
|
||||
if (alpha_blend != p_alpha_blend) {
|
||||
alpha_blend = p_alpha_blend;
|
||||
if (alpha_blend) {
|
||||
composition_layer->layerFlags |= XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
|
||||
} else {
|
||||
composition_layer->layerFlags &= ~XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 (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());
|
||||
}
|
||||
|
||||
subviewport.viewport = p_viewport;
|
||||
|
||||
if (subviewport.viewport.is_valid()) {
|
||||
subviewport.viewport_size = p_size;
|
||||
} else {
|
||||
free_swapchain();
|
||||
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 (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(subviewport.viewport);
|
||||
RSG::texture_storage->render_target_set_override(rt, get_current_swapchain_texture(), RID(), RID(), RID());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
XrCompositionLayerBaseHeader *OpenXRViewportCompositionLayerProvider::get_composition_layer() {
|
||||
if (openxr_api == nullptr || composition_layer_extension == nullptr) {
|
||||
// OpenXR not initialized or we're in the editor?
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!composition_layer_extension->is_available(composition_layer->type)) {
|
||||
// Selected type is not supported, ignore our layer.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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 = 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 = 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 = subimage;
|
||||
} break;
|
||||
|
||||
default: {
|
||||
return nullptr;
|
||||
} break;
|
||||
}
|
||||
|
||||
if (extension_property_values_changed) {
|
||||
extension_property_values_changed = false;
|
||||
|
||||
void *next_pointer = nullptr;
|
||||
for (OpenXRExtensionWrapper *extension : OpenXRAPI::get_registered_extension_wrappers()) {
|
||||
void *np = extension->set_viewport_composition_layer_and_get_next_pointer(composition_layer, extension_property_values, next_pointer);
|
||||
if (np) {
|
||||
next_pointer = np;
|
||||
}
|
||||
}
|
||||
composition_layer->next = next_pointer;
|
||||
}
|
||||
|
||||
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(get_openxr_type())) {
|
||||
// Selected type is not supported?
|
||||
return false;
|
||||
}
|
||||
|
||||
// See if our current swapchain is outdated.
|
||||
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 == 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 subviewport.swapchain_info.acquire(should_render);
|
||||
}
|
||||
|
||||
subviewport.swapchain_info.queue_free();
|
||||
}
|
||||
|
||||
// Create our new swap chain
|
||||
int64_t swapchain_format = openxr_api->get_color_swapchain_format();
|
||||
const uint32_t sample_count = 1;
|
||||
const uint32_t array_size = 1;
|
||||
XrSwapchainCreateFlags create_flags = 0;
|
||||
if (p_static_image) {
|
||||
create_flags |= XR_SWAPCHAIN_CREATE_STATIC_IMAGE_BIT;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
// 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 = subviewport.swapchain_info.acquire(should_render);
|
||||
|
||||
swapchain_size = subviewport.viewport_size;
|
||||
subviewport.static_image = p_static_image;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void OpenXRViewportCompositionLayerProvider::free_swapchain() {
|
||||
#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();
|
||||
}
|
||||
|
||||
RID OpenXRViewportCompositionLayerProvider::get_current_swapchain_texture() {
|
||||
ERR_FAIL_COND_V(use_android_surface, RID());
|
||||
|
||||
if (openxr_api == nullptr) {
|
||||
return RID();
|
||||
}
|
||||
|
||||
return subviewport.swapchain_info.get_image();
|
||||
}
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_composition_layer_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_COMPOSITION_LAYER_EXTENSION_H
|
||||
#define OPENXR_COMPOSITION_LAYER_EXTENSION_H
|
||||
|
||||
#include "openxr_composition_layer_provider.h"
|
||||
#include "openxr_extension_wrapper.h"
|
||||
|
||||
#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.
|
||||
|
||||
// OpenXRCompositionLayerExtension enables the extensions related to this functionality
|
||||
class OpenXRCompositionLayerExtension : public OpenXRExtensionWrapper, public OpenXRCompositionLayerProvider {
|
||||
public:
|
||||
static OpenXRCompositionLayerExtension *get_singleton();
|
||||
|
||||
OpenXRCompositionLayerExtension();
|
||||
virtual ~OpenXRCompositionLayerExtension() 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_session) override;
|
||||
virtual void on_session_destroyed() override;
|
||||
virtual void on_pre_render() override;
|
||||
|
||||
virtual int get_composition_layer_count() override;
|
||||
virtual XrCompositionLayerBaseHeader *get_composition_layer(int p_index) override;
|
||||
virtual int get_composition_layer_order(int p_index) override;
|
||||
|
||||
void register_viewport_composition_layer_provider(OpenXRViewportCompositionLayerProvider *p_composition_layer);
|
||||
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;
|
||||
|
||||
Vector<OpenXRViewportCompositionLayerProvider *> composition_layers;
|
||||
|
||||
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 {
|
||||
XrCompositionLayerBaseHeader *composition_layer = nullptr;
|
||||
int sort_order = 1;
|
||||
bool alpha_blend = false;
|
||||
Dictionary extension_property_values;
|
||||
bool extension_property_values_changed = true;
|
||||
|
||||
struct {
|
||||
RID viewport;
|
||||
Size2i viewport_size;
|
||||
OpenXRAPI::OpenXRSwapChainInfo swapchain_info;
|
||||
bool static_image = false;
|
||||
} subviewport;
|
||||
|
||||
#ifdef ANDROID_ENABLED
|
||||
struct {
|
||||
XrSwapchain swapchain = XR_NULL_HANDLE;
|
||||
Ref<JavaObject> surface;
|
||||
} android_surface;
|
||||
#endif
|
||||
|
||||
bool use_android_surface = false;
|
||||
Size2i swapchain_size;
|
||||
|
||||
OpenXRAPI *openxr_api = nullptr;
|
||||
OpenXRCompositionLayerExtension *composition_layer_extension = nullptr;
|
||||
|
||||
// Only for SubViewports.
|
||||
bool update_and_acquire_swapchain(bool p_static_image);
|
||||
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; }
|
||||
|
||||
void set_sort_order(int p_sort_order) { sort_order = p_sort_order; }
|
||||
int get_sort_order() const { return sort_order; }
|
||||
|
||||
void set_alpha_blend(bool p_alpha_blend);
|
||||
bool get_alpha_blend() const { return alpha_blend; }
|
||||
|
||||
void set_viewport(RID p_viewport, Size2i p_size);
|
||||
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);
|
||||
|
||||
void on_pre_render();
|
||||
XrCompositionLayerBaseHeader *get_composition_layer();
|
||||
|
||||
OpenXRViewportCompositionLayerProvider(XrCompositionLayerBaseHeader *p_composition_layer);
|
||||
~OpenXRViewportCompositionLayerProvider();
|
||||
};
|
||||
|
||||
#endif // OPENXR_COMPOSITION_LAYER_EXTENSION_H
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_composition_layer_provider.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_COMPOSITION_LAYER_PROVIDER_H
|
||||
#define OPENXR_COMPOSITION_LAYER_PROVIDER_H
|
||||
|
||||
#include "openxr_extension_wrapper.h"
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
// Interface for OpenXR extensions that provide a composition layer.
|
||||
class OpenXRCompositionLayerProvider {
|
||||
public:
|
||||
virtual int get_composition_layer_count() = 0;
|
||||
virtual XrCompositionLayerBaseHeader *get_composition_layer(int p_index) = 0;
|
||||
virtual int get_composition_layer_order(int p_index) = 0;
|
||||
|
||||
virtual ~OpenXRCompositionLayerProvider() {}
|
||||
};
|
||||
|
||||
#endif // OPENXR_COMPOSITION_LAYER_PROVIDER_H
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
109
engine/modules/openxr/extensions/openxr_dpad_binding_extension.h
Normal file
109
engine/modules/openxr/extensions/openxr_dpad_binding_extension.h
Normal 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
|
||||
129
engine/modules/openxr/extensions/openxr_extension_wrapper.h
Normal file
129
engine/modules/openxr/extensions/openxr_extension_wrapper.h
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_extension_wrapper.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_EXTENSION_WRAPPER_H
|
||||
#define OPENXR_EXTENSION_WRAPPER_H
|
||||
|
||||
#include "core/error/error_macros.h"
|
||||
#include "core/math/projection.h"
|
||||
#include "core/templates/hash_map.h"
|
||||
#include "core/templates/rid.h"
|
||||
#include "core/variant/variant.h"
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
class OpenXRAPI;
|
||||
class OpenXRActionMap;
|
||||
|
||||
// `OpenXRExtensionWrapper` allows us to implement OpenXR extensions.
|
||||
class OpenXRExtensionWrapper {
|
||||
public:
|
||||
// `get_requested_extensions` should return a list of OpenXR extensions related to this extension.
|
||||
// If the bool * is a nullptr this extension is mandatory
|
||||
// If the bool * points to a boolean, the boolean will be updated
|
||||
// to true if the extension is enabled.
|
||||
virtual HashMap<String, bool *> get_requested_extensions() = 0;
|
||||
|
||||
// These functions allow an extension to add entries to a struct chain.
|
||||
// `p_next_pointer` points to the last struct that was created for this chain
|
||||
// and should be used as the value for the `pNext` pointer in the first struct you add.
|
||||
// You should return the pointer to the last struct you define as your result.
|
||||
// If you are not adding any structs, just return `p_next_pointer`.
|
||||
// See existing extensions for examples of this implementation.
|
||||
virtual void *set_system_properties_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } // 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(); }
|
||||
|
||||
// `on_register_metadata` allows extensions to register additional controller metadata.
|
||||
// This function is called even when OpenXRApi is not constructured as the metadata
|
||||
// needs to be available to the editor.
|
||||
// Also extensions should provide metadata regardless of whether they are supported
|
||||
// on the host system as the controller data is used to setup action maps for users
|
||||
// who may have access to the relevant hardware.
|
||||
virtual void on_register_metadata() {}
|
||||
|
||||
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_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,
|
||||
// this happens right before physics process and normal processing is run.
|
||||
// This is when controller data is queried and made available to game logic.
|
||||
virtual void on_process() {}
|
||||
virtual void on_pre_render() {} // `on_pre_render` is called right before we start rendering our XR viewports.
|
||||
virtual void on_main_swapchains_created() {} // `on_main_swapchains_created` is called right after our main swapchains are (re)created.
|
||||
virtual void on_pre_draw_viewport(RID p_render_target) {} // `on_pre_draw_viewport` is called right before we start rendering this viewport
|
||||
virtual void on_post_draw_viewport(RID p_render_target) {} // `on_port_draw_viewport` is called right after we start rendering this viewport (note that on Vulkan draw commands may only be queued)
|
||||
|
||||
virtual void on_state_idle() {} // `on_state_idle` is called when the OpenXR session state is changed to idle.
|
||||
virtual void on_state_ready() {} // `on_state_ready` is called when the OpenXR session state is changed to ready, this means OpenXR is ready to setup our session.
|
||||
virtual void on_state_synchronized() {} // `on_state_synchronized` is called when the OpenXR session state is changed to synchronized, note that OpenXR also returns to this state when our application looses focus.
|
||||
virtual void on_state_visible() {} // `on_state_visible` is called when the OpenXR session state is changed to visible, OpenXR is now ready to receive frames.
|
||||
virtual void on_state_focused() {} // `on_state_focused` is called when the OpenXR session state is changed to focused, this state is the active state when our game runs.
|
||||
virtual void on_state_stopping() {} // `on_state_stopping` is called when the OpenXR session state is changed to stopping.
|
||||
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, 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.
|
||||
virtual bool on_event_polled(const XrEventDataBuffer &event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
OpenXRExtensionWrapper() = default;
|
||||
virtual ~OpenXRExtensionWrapper() = default;
|
||||
};
|
||||
|
||||
// `OpenXRGraphicsExtensionWrapper` implements specific logic for each supported graphics API.
|
||||
class OpenXRGraphicsExtensionWrapper : public OpenXRExtensionWrapper {
|
||||
public:
|
||||
virtual void get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) = 0; // `get_usable_swapchain_formats` should return a list of usable color formats.
|
||||
virtual void get_usable_depth_formats(Vector<int64_t> &p_usable_swap_chains) = 0; // `get_usable_depth_formats` should return a list of usable depth formats.
|
||||
virtual String get_swapchain_format_name(int64_t p_swapchain_format) const = 0; // `get_swapchain_format_name` should return the constant name of a given format.
|
||||
virtual bool get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) = 0; // `get_swapchain_image_data` extracts image IDs for the swapchain images and stores there in an implementation dependent data structure.
|
||||
virtual void cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) = 0; // `cleanup_swapchain_graphics_data` cleans up the data held in our implementation dependent data structure and should free up its memory.
|
||||
virtual bool create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) = 0; // `create_projection_fov` creates a proper projection matrix based on asymmetric FOV data provided by OpenXR.
|
||||
virtual RID get_texture(void *p_swapchain_graphics_data, int p_image_index) = 0; // `get_texture` returns a Godot texture RID for the current active texture in our swapchain.
|
||||
};
|
||||
|
||||
#endif // OPENXR_EXTENSION_WRAPPER_H
|
||||
|
|
@ -0,0 +1,327 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_extension_wrapper_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_extension_wrapper_extension.h"
|
||||
|
||||
#include "../openxr_api.h"
|
||||
|
||||
void OpenXRExtensionWrapperExtension::_bind_methods() {
|
||||
GDVIRTUAL_BIND(_get_requested_extensions);
|
||||
GDVIRTUAL_BIND(_set_system_properties_and_get_next_pointer, "next_pointer");
|
||||
GDVIRTUAL_BIND(_set_instance_create_info_and_get_next_pointer, "next_pointer");
|
||||
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");
|
||||
GDVIRTUAL_BIND(_get_suggested_tracker_names);
|
||||
GDVIRTUAL_BIND(_on_register_metadata);
|
||||
GDVIRTUAL_BIND(_on_before_instance_created);
|
||||
GDVIRTUAL_BIND(_on_instance_created, "instance");
|
||||
GDVIRTUAL_BIND(_on_instance_destroyed);
|
||||
GDVIRTUAL_BIND(_on_session_created, "session");
|
||||
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);
|
||||
GDVIRTUAL_BIND(_on_state_synchronized);
|
||||
GDVIRTUAL_BIND(_on_state_visible);
|
||||
GDVIRTUAL_BIND(_on_state_focused);
|
||||
GDVIRTUAL_BIND(_on_state_stopping);
|
||||
GDVIRTUAL_BIND(_on_state_loss_pending);
|
||||
GDVIRTUAL_BIND(_on_state_exiting);
|
||||
GDVIRTUAL_BIND(_on_event_polled, "event");
|
||||
GDVIRTUAL_BIND(_set_viewport_composition_layer_and_get_next_pointer, "layer", "property_values", "next_pointer");
|
||||
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);
|
||||
}
|
||||
|
||||
HashMap<String, bool *> OpenXRExtensionWrapperExtension::get_requested_extensions() {
|
||||
Dictionary request_extension;
|
||||
|
||||
if (GDVIRTUAL_CALL(_get_requested_extensions, request_extension)) {
|
||||
HashMap<String, bool *> result;
|
||||
Array keys = request_extension.keys();
|
||||
for (int i = 0; i < keys.size(); i++) {
|
||||
String key = keys.get(i);
|
||||
GDExtensionPtr<bool> value = VariantCaster<GDExtensionPtr<bool>>::cast(request_extension.get(key, GDExtensionPtr<bool>(nullptr)));
|
||||
result.insert(key, value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return HashMap<String, bool *>();
|
||||
}
|
||||
|
||||
void *OpenXRExtensionWrapperExtension::set_system_properties_and_get_next_pointer(void *p_next_pointer) {
|
||||
uint64_t pointer;
|
||||
|
||||
if (GDVIRTUAL_CALL(_set_system_properties_and_get_next_pointer, GDExtensionPtr<void>(p_next_pointer), pointer)) {
|
||||
return reinterpret_cast<void *>(pointer);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void *OpenXRExtensionWrapperExtension::set_instance_create_info_and_get_next_pointer(void *p_next_pointer) {
|
||||
uint64_t pointer;
|
||||
|
||||
if (GDVIRTUAL_CALL(_set_instance_create_info_and_get_next_pointer, GDExtensionPtr<void>(p_next_pointer), pointer)) {
|
||||
return reinterpret_cast<void *>(pointer);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void *OpenXRExtensionWrapperExtension::set_session_create_and_get_next_pointer(void *p_next_pointer) {
|
||||
uint64_t pointer;
|
||||
|
||||
if (GDVIRTUAL_CALL(_set_session_create_and_get_next_pointer, GDExtensionPtr<void>(p_next_pointer), pointer)) {
|
||||
return reinterpret_cast<void *>(pointer);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void *OpenXRExtensionWrapperExtension::set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) {
|
||||
uint64_t pointer;
|
||||
|
||||
if (GDVIRTUAL_CALL(_set_swapchain_create_info_and_get_next_pointer, GDExtensionPtr<void>(p_next_pointer), pointer)) {
|
||||
return reinterpret_cast<void *>(pointer);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void *OpenXRExtensionWrapperExtension::set_hand_joint_locations_and_get_next_pointer(int p_hand_index, void *p_next_pointer) {
|
||||
uint64_t pointer;
|
||||
|
||||
if (GDVIRTUAL_CALL(_set_hand_joint_locations_and_get_next_pointer, p_hand_index, GDExtensionPtr<void>(p_next_pointer), pointer)) {
|
||||
return reinterpret_cast<void *>(pointer);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (GDVIRTUAL_CALL(_get_suggested_tracker_names, ret)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return PackedStringArray();
|
||||
}
|
||||
|
||||
int OpenXRExtensionWrapperExtension::get_composition_layer_count() {
|
||||
int count = 0;
|
||||
GDVIRTUAL_CALL(_get_composition_layer_count, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
XrCompositionLayerBaseHeader *OpenXRExtensionWrapperExtension::get_composition_layer(int p_index) {
|
||||
uint64_t pointer;
|
||||
|
||||
if (GDVIRTUAL_CALL(_get_composition_layer, p_index, pointer)) {
|
||||
return reinterpret_cast<XrCompositionLayerBaseHeader *>(pointer);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int OpenXRExtensionWrapperExtension::get_composition_layer_order(int p_index) {
|
||||
int order = 0;
|
||||
GDVIRTUAL_CALL(_get_composition_layer_order, p_index, order);
|
||||
return order;
|
||||
}
|
||||
|
||||
void OpenXRExtensionWrapperExtension::on_register_metadata() {
|
||||
GDVIRTUAL_CALL(_on_register_metadata);
|
||||
}
|
||||
|
||||
void OpenXRExtensionWrapperExtension::on_before_instance_created() {
|
||||
GDVIRTUAL_CALL(_on_before_instance_created);
|
||||
}
|
||||
|
||||
void OpenXRExtensionWrapperExtension::on_instance_created(const XrInstance p_instance) {
|
||||
uint64_t instance = (uint64_t)p_instance;
|
||||
GDVIRTUAL_CALL(_on_instance_created, instance);
|
||||
}
|
||||
|
||||
void OpenXRExtensionWrapperExtension::on_instance_destroyed() {
|
||||
GDVIRTUAL_CALL(_on_instance_destroyed);
|
||||
}
|
||||
|
||||
void OpenXRExtensionWrapperExtension::on_session_created(const XrSession p_session) {
|
||||
uint64_t session = (uint64_t)p_session;
|
||||
GDVIRTUAL_CALL(_on_session_created, session);
|
||||
}
|
||||
|
||||
void OpenXRExtensionWrapperExtension::on_process() {
|
||||
GDVIRTUAL_CALL(_on_process);
|
||||
}
|
||||
|
||||
void OpenXRExtensionWrapperExtension::on_pre_render() {
|
||||
GDVIRTUAL_CALL(_on_pre_render);
|
||||
}
|
||||
|
||||
void OpenXRExtensionWrapperExtension::on_main_swapchains_created() {
|
||||
GDVIRTUAL_CALL(_on_main_swapchains_created);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void OpenXRExtensionWrapperExtension::on_state_ready() {
|
||||
GDVIRTUAL_CALL(_on_state_ready);
|
||||
}
|
||||
|
||||
void OpenXRExtensionWrapperExtension::on_state_synchronized() {
|
||||
GDVIRTUAL_CALL(_on_state_synchronized);
|
||||
}
|
||||
|
||||
void OpenXRExtensionWrapperExtension::on_state_visible() {
|
||||
GDVIRTUAL_CALL(_on_state_visible);
|
||||
}
|
||||
|
||||
void OpenXRExtensionWrapperExtension::on_state_focused() {
|
||||
GDVIRTUAL_CALL(_on_state_focused);
|
||||
}
|
||||
|
||||
void OpenXRExtensionWrapperExtension::on_state_stopping() {
|
||||
GDVIRTUAL_CALL(_on_state_stopping);
|
||||
}
|
||||
|
||||
void OpenXRExtensionWrapperExtension::on_state_loss_pending() {
|
||||
GDVIRTUAL_CALL(_on_state_loss_pending);
|
||||
}
|
||||
|
||||
void OpenXRExtensionWrapperExtension::on_state_exiting() {
|
||||
GDVIRTUAL_CALL(_on_state_exiting);
|
||||
}
|
||||
|
||||
bool OpenXRExtensionWrapperExtension::on_event_polled(const XrEventDataBuffer &p_event) {
|
||||
bool event_polled;
|
||||
|
||||
if (GDVIRTUAL_CALL(_on_event_polled, GDExtensionConstPtr<void>(&p_event), event_polled)) {
|
||||
return event_polled;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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)) {
|
||||
return reinterpret_cast<void *>(pointer);
|
||||
}
|
||||
|
||||
return p_next_pointer;
|
||||
}
|
||||
|
||||
void OpenXRExtensionWrapperExtension::on_viewport_composition_layer_destroyed(const XrCompositionLayerBaseHeader *p_layer) {
|
||||
GDVIRTUAL_CALL(_on_viewport_composition_layer_destroyed, GDExtensionConstPtr<void>(p_layer));
|
||||
}
|
||||
|
||||
void OpenXRExtensionWrapperExtension::get_viewport_composition_layer_extension_properties(List<PropertyInfo> *p_property_list) {
|
||||
TypedArray<Dictionary> properties;
|
||||
|
||||
if (GDVIRTUAL_CALL(_get_viewport_composition_layer_extension_properties, properties)) {
|
||||
for (int i = 0; i < properties.size(); i++) {
|
||||
p_property_list->push_back(PropertyInfo::from_dict(properties[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary OpenXRExtensionWrapperExtension::get_viewport_composition_layer_extension_property_defaults() {
|
||||
Dictionary property_defaults;
|
||||
GDVIRTUAL_CALL(_get_viewport_composition_layer_extension_property_defaults, property_defaults);
|
||||
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;
|
||||
}
|
||||
|
||||
void OpenXRExtensionWrapperExtension::register_extension_wrapper() {
|
||||
OpenXRAPI::register_extension_wrapper(this);
|
||||
}
|
||||
|
||||
OpenXRExtensionWrapperExtension::OpenXRExtensionWrapperExtension() {
|
||||
openxr_api.instantiate();
|
||||
}
|
||||
|
||||
OpenXRExtensionWrapperExtension::~OpenXRExtensionWrapperExtension() {
|
||||
}
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_extension_wrapper_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_EXTENSION_WRAPPER_EXTENSION_H
|
||||
#define OPENXR_EXTENSION_WRAPPER_EXTENSION_H
|
||||
|
||||
#include "../openxr_api_extension.h"
|
||||
#include "openxr_extension_wrapper.h"
|
||||
|
||||
#include "core/object/ref_counted.h"
|
||||
#include "core/os/thread_safe.h"
|
||||
#include "core/variant/native_ptr.h"
|
||||
#include "core/variant/typed_array.h"
|
||||
|
||||
class OpenXRExtensionWrapperExtension : public Object, public OpenXRExtensionWrapper, public OpenXRCompositionLayerProvider {
|
||||
GDCLASS(OpenXRExtensionWrapperExtension, Object);
|
||||
|
||||
protected:
|
||||
_THREAD_SAFE_CLASS_
|
||||
|
||||
static void _bind_methods();
|
||||
|
||||
Ref<OpenXRAPIExtension> openxr_api;
|
||||
|
||||
public:
|
||||
virtual HashMap<String, bool *> get_requested_extensions() override;
|
||||
|
||||
GDVIRTUAL0R(Dictionary, _get_requested_extensions);
|
||||
|
||||
virtual void *set_system_properties_and_get_next_pointer(void *p_next_pointer) override;
|
||||
virtual void *set_instance_create_info_and_get_next_pointer(void *p_next_pointer) override;
|
||||
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;
|
||||
virtual int get_composition_layer_order(int p_index) override;
|
||||
|
||||
//TODO workaround as GDExtensionPtr<void> return type results in build error in godot-cpp
|
||||
GDVIRTUAL1R(uint64_t, _set_system_properties_and_get_next_pointer, GDExtensionPtr<void>);
|
||||
GDVIRTUAL1R(uint64_t, _set_instance_create_info_and_get_next_pointer, GDExtensionPtr<void>);
|
||||
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);
|
||||
|
||||
virtual PackedStringArray get_suggested_tracker_names() override;
|
||||
|
||||
GDVIRTUAL0R(PackedStringArray, _get_suggested_tracker_names);
|
||||
|
||||
virtual void on_register_metadata() override;
|
||||
virtual void on_before_instance_created() override;
|
||||
virtual void on_instance_created(const XrInstance p_instance) override;
|
||||
virtual void on_instance_destroyed() override;
|
||||
virtual void on_session_created(const XrSession p_session) override;
|
||||
virtual void on_process() override;
|
||||
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);
|
||||
GDVIRTUAL1(_on_instance_created, uint64_t);
|
||||
GDVIRTUAL0(_on_instance_destroyed);
|
||||
GDVIRTUAL1(_on_session_created, uint64_t);
|
||||
GDVIRTUAL0(_on_process);
|
||||
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;
|
||||
virtual void on_state_synchronized() override;
|
||||
virtual void on_state_visible() override;
|
||||
virtual void on_state_focused() override;
|
||||
virtual void on_state_stopping() override;
|
||||
virtual void on_state_loss_pending() override;
|
||||
virtual void on_state_exiting() override;
|
||||
|
||||
GDVIRTUAL0(_on_state_idle);
|
||||
GDVIRTUAL0(_on_state_ready);
|
||||
GDVIRTUAL0(_on_state_synchronized);
|
||||
GDVIRTUAL0(_on_state_visible);
|
||||
GDVIRTUAL0(_on_state_focused);
|
||||
GDVIRTUAL0(_on_state_stopping);
|
||||
GDVIRTUAL0(_on_state_loss_pending);
|
||||
GDVIRTUAL0(_on_state_exiting);
|
||||
|
||||
virtual bool on_event_polled(const XrEventDataBuffer &p_event) override;
|
||||
|
||||
GDVIRTUAL1R(bool, _on_event_polled, GDExtensionConstPtr<void>);
|
||||
|
||||
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();
|
||||
|
||||
void register_extension_wrapper();
|
||||
|
||||
OpenXRExtensionWrapperExtension();
|
||||
virtual ~OpenXRExtensionWrapperExtension() override;
|
||||
};
|
||||
|
||||
#endif // OPENXR_EXTENSION_WRAPPER_EXTENSION_H
|
||||
144
engine/modules/openxr/extensions/openxr_eye_gaze_interaction.cpp
Normal file
144
engine/modules/openxr/extensions/openxr_eye_gaze_interaction.cpp
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_eye_gaze_interaction.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_eye_gaze_interaction.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/os/os.h"
|
||||
|
||||
#include "../action_map/openxr_interaction_profile_metadata.h"
|
||||
#include "../openxr_api.h"
|
||||
|
||||
OpenXREyeGazeInteractionExtension *OpenXREyeGazeInteractionExtension::singleton = nullptr;
|
||||
|
||||
OpenXREyeGazeInteractionExtension *OpenXREyeGazeInteractionExtension::get_singleton() {
|
||||
ERR_FAIL_NULL_V(singleton, nullptr);
|
||||
return singleton;
|
||||
}
|
||||
|
||||
OpenXREyeGazeInteractionExtension::OpenXREyeGazeInteractionExtension() {
|
||||
singleton = this;
|
||||
}
|
||||
|
||||
OpenXREyeGazeInteractionExtension::~OpenXREyeGazeInteractionExtension() {
|
||||
singleton = nullptr;
|
||||
}
|
||||
|
||||
HashMap<String, bool *> OpenXREyeGazeInteractionExtension::get_requested_extensions() {
|
||||
HashMap<String, bool *> request_extensions;
|
||||
|
||||
// Only enable this extension when requested.
|
||||
// We still register our meta data or the action map editor will fail.
|
||||
if (GLOBAL_GET("xr/openxr/extensions/eye_gaze_interaction") && (!OS::get_singleton()->has_feature("mobile") || OS::get_singleton()->has_feature(XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME))) {
|
||||
request_extensions[XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME] = &available;
|
||||
}
|
||||
|
||||
return request_extensions;
|
||||
}
|
||||
|
||||
void *OpenXREyeGazeInteractionExtension::set_system_properties_and_get_next_pointer(void *p_next_pointer) {
|
||||
if (!available) {
|
||||
return p_next_pointer;
|
||||
}
|
||||
|
||||
properties.type = XR_TYPE_SYSTEM_EYE_GAZE_INTERACTION_PROPERTIES_EXT;
|
||||
properties.next = p_next_pointer;
|
||||
properties.supportsEyeGazeInteraction = false;
|
||||
|
||||
return &properties;
|
||||
}
|
||||
|
||||
PackedStringArray OpenXREyeGazeInteractionExtension::get_suggested_tracker_names() {
|
||||
PackedStringArray arr = { "/user/eyes_ext" };
|
||||
return arr;
|
||||
}
|
||||
|
||||
bool OpenXREyeGazeInteractionExtension::is_available() {
|
||||
return available;
|
||||
}
|
||||
|
||||
bool OpenXREyeGazeInteractionExtension::supports_eye_gaze_interaction() {
|
||||
// The extension being available only means that the OpenXR Runtime supports the extension.
|
||||
// The `supportsEyeGazeInteraction` is set to true if the device also supports this.
|
||||
// Thus both need to be true.
|
||||
// In addition, on mobile runtimes, the proper permission needs to be granted.
|
||||
if (available && properties.supportsEyeGazeInteraction) {
|
||||
return !OS::get_singleton()->has_feature("mobile") || OS::get_singleton()->has_feature("PERMISSION_XR_EXT_eye_gaze_interaction");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void OpenXREyeGazeInteractionExtension::on_register_metadata() {
|
||||
OpenXRInteractionProfileMetadata *metadata = OpenXRInteractionProfileMetadata::get_singleton();
|
||||
ERR_FAIL_NULL(metadata);
|
||||
|
||||
// Eyes top path
|
||||
metadata->register_top_level_path("Eye gaze tracker", "/user/eyes_ext", XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME);
|
||||
|
||||
// Eye gaze interaction
|
||||
metadata->register_interaction_profile("Eye gaze", "/interaction_profiles/ext/eye_gaze_interaction", XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME);
|
||||
metadata->register_io_path("/interaction_profiles/ext/eye_gaze_interaction", "Gaze pose", "/user/eyes_ext", "/user/eyes_ext/input/gaze_ext/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
}
|
||||
|
||||
bool OpenXREyeGazeInteractionExtension::get_eye_gaze_pose(double p_dist, Vector3 &r_eye_pose) {
|
||||
OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
|
||||
ERR_FAIL_NULL_V(openxr_api, false);
|
||||
|
||||
if (!init_eye_gaze_pose) {
|
||||
init_eye_gaze_pose = true;
|
||||
|
||||
eye_tracker = openxr_api->find_tracker("/user/eyes_ext");
|
||||
if (eye_tracker.is_null()) {
|
||||
WARN_PRINT("Couldn't obtain eye tracker");
|
||||
}
|
||||
|
||||
eye_action = openxr_api->find_action("eye_gaze_pose");
|
||||
if (eye_action.is_null()) {
|
||||
WARN_PRINT("Couldn't obtain pose action for `eye_gaze_pose`, make sure to add this to your action map.");
|
||||
}
|
||||
}
|
||||
|
||||
if (eye_tracker.is_null() || eye_action.is_null()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Transform3D eye_transform;
|
||||
Vector3 linear_velocity;
|
||||
Vector3 angular_velocity;
|
||||
XRPose::TrackingConfidence confidence = openxr_api->get_action_pose(eye_action, eye_tracker, eye_transform, linear_velocity, angular_velocity);
|
||||
if (confidence == XRPose::XR_TRACKING_CONFIDENCE_NONE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
r_eye_pose = eye_transform.origin + eye_transform.basis[2] * p_dist;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_eye_gaze_interaction.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_EYE_GAZE_INTERACTION_H
|
||||
#define OPENXR_EYE_GAZE_INTERACTION_H
|
||||
|
||||
#include "openxr_extension_wrapper.h"
|
||||
|
||||
class OpenXREyeGazeInteractionExtension : public OpenXRExtensionWrapper {
|
||||
public:
|
||||
static OpenXREyeGazeInteractionExtension *get_singleton();
|
||||
|
||||
OpenXREyeGazeInteractionExtension();
|
||||
~OpenXREyeGazeInteractionExtension();
|
||||
|
||||
virtual HashMap<String, bool *> get_requested_extensions() override;
|
||||
virtual void *set_system_properties_and_get_next_pointer(void *p_next_pointer) override;
|
||||
|
||||
PackedStringArray get_suggested_tracker_names() override;
|
||||
|
||||
bool is_available();
|
||||
bool supports_eye_gaze_interaction();
|
||||
|
||||
virtual void on_register_metadata() override;
|
||||
|
||||
bool get_eye_gaze_pose(double p_dist, Vector3 &r_eye_pose);
|
||||
|
||||
private:
|
||||
static OpenXREyeGazeInteractionExtension *singleton;
|
||||
|
||||
bool available = false;
|
||||
XrSystemEyeGazeInteractionPropertiesEXT properties;
|
||||
|
||||
bool init_eye_gaze_pose = false;
|
||||
RID eye_tracker;
|
||||
RID eye_action;
|
||||
};
|
||||
|
||||
#endif // OPENXR_EYE_GAZE_INTERACTION_H
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_fb_display_refresh_rate_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_fb_display_refresh_rate_extension.h"
|
||||
#include "../openxr_interface.h"
|
||||
|
||||
OpenXRDisplayRefreshRateExtension *OpenXRDisplayRefreshRateExtension::singleton = nullptr;
|
||||
|
||||
OpenXRDisplayRefreshRateExtension *OpenXRDisplayRefreshRateExtension::get_singleton() {
|
||||
return singleton;
|
||||
}
|
||||
|
||||
OpenXRDisplayRefreshRateExtension::OpenXRDisplayRefreshRateExtension() {
|
||||
singleton = this;
|
||||
}
|
||||
|
||||
OpenXRDisplayRefreshRateExtension::~OpenXRDisplayRefreshRateExtension() {
|
||||
display_refresh_rate_ext = false;
|
||||
}
|
||||
|
||||
HashMap<String, bool *> OpenXRDisplayRefreshRateExtension::get_requested_extensions() {
|
||||
HashMap<String, bool *> request_extensions;
|
||||
|
||||
request_extensions[XR_FB_DISPLAY_REFRESH_RATE_EXTENSION_NAME] = &display_refresh_rate_ext;
|
||||
|
||||
return request_extensions;
|
||||
}
|
||||
|
||||
void OpenXRDisplayRefreshRateExtension::on_instance_created(const XrInstance p_instance) {
|
||||
if (display_refresh_rate_ext) {
|
||||
EXT_INIT_XR_FUNC(xrEnumerateDisplayRefreshRatesFB);
|
||||
EXT_INIT_XR_FUNC(xrGetDisplayRefreshRateFB);
|
||||
EXT_INIT_XR_FUNC(xrRequestDisplayRefreshRateFB);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRDisplayRefreshRateExtension::on_instance_destroyed() {
|
||||
display_refresh_rate_ext = false;
|
||||
}
|
||||
|
||||
bool OpenXRDisplayRefreshRateExtension::on_event_polled(const XrEventDataBuffer &event) {
|
||||
switch (event.type) {
|
||||
case XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB: {
|
||||
const XrEventDataDisplayRefreshRateChangedFB *event_fb = (XrEventDataDisplayRefreshRateChangedFB *)&event;
|
||||
|
||||
OpenXRInterface *xr_interface = OpenXRAPI::get_singleton()->get_xr_interface();
|
||||
if (xr_interface) {
|
||||
xr_interface->on_refresh_rate_changes(event_fb->toDisplayRefreshRate);
|
||||
}
|
||||
|
||||
return true;
|
||||
} break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
float OpenXRDisplayRefreshRateExtension::get_refresh_rate() const {
|
||||
float refresh_rate = 0.0;
|
||||
|
||||
if (display_refresh_rate_ext) {
|
||||
float rate;
|
||||
XrResult result = xrGetDisplayRefreshRateFB(OpenXRAPI::get_singleton()->get_session(), &rate);
|
||||
if (XR_FAILED(result)) {
|
||||
print_line("OpenXR: Failed to obtain refresh rate [", OpenXRAPI::get_singleton()->get_error_string(result), "]");
|
||||
} else {
|
||||
refresh_rate = rate;
|
||||
}
|
||||
}
|
||||
|
||||
return refresh_rate;
|
||||
}
|
||||
|
||||
void OpenXRDisplayRefreshRateExtension::set_refresh_rate(float p_refresh_rate) {
|
||||
if (display_refresh_rate_ext) {
|
||||
XrResult result = xrRequestDisplayRefreshRateFB(OpenXRAPI::get_singleton()->get_session(), p_refresh_rate);
|
||||
if (XR_FAILED(result)) {
|
||||
print_line("OpenXR: Failed to set refresh rate [", OpenXRAPI::get_singleton()->get_error_string(result), "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Array OpenXRDisplayRefreshRateExtension::get_available_refresh_rates() const {
|
||||
Array arr;
|
||||
XrResult result;
|
||||
|
||||
if (display_refresh_rate_ext) {
|
||||
uint32_t display_refresh_rate_count = 0;
|
||||
result = xrEnumerateDisplayRefreshRatesFB(OpenXRAPI::get_singleton()->get_session(), 0, &display_refresh_rate_count, nullptr);
|
||||
if (XR_FAILED(result)) {
|
||||
print_line("OpenXR: Failed to obtain refresh rates count [", OpenXRAPI::get_singleton()->get_error_string(result), "]");
|
||||
}
|
||||
|
||||
if (display_refresh_rate_count > 0) {
|
||||
float *display_refresh_rates = (float *)memalloc(sizeof(float) * display_refresh_rate_count);
|
||||
if (display_refresh_rates == nullptr) {
|
||||
print_line("OpenXR: Failed to obtain refresh rates memory buffer [", OpenXRAPI::get_singleton()->get_error_string(result), "]");
|
||||
return arr;
|
||||
}
|
||||
|
||||
result = xrEnumerateDisplayRefreshRatesFB(OpenXRAPI::get_singleton()->get_session(), display_refresh_rate_count, &display_refresh_rate_count, display_refresh_rates);
|
||||
if (XR_FAILED(result)) {
|
||||
print_line("OpenXR: Failed to obtain refresh rates count [", OpenXRAPI::get_singleton()->get_error_string(result), "]");
|
||||
memfree(display_refresh_rates);
|
||||
return arr;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < display_refresh_rate_count; i++) {
|
||||
float refresh_rate = display_refresh_rates[i];
|
||||
arr.push_back(Variant(refresh_rate));
|
||||
}
|
||||
|
||||
memfree(display_refresh_rates);
|
||||
}
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_fb_display_refresh_rate_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_FB_DISPLAY_REFRESH_RATE_EXTENSION_H
|
||||
#define OPENXR_FB_DISPLAY_REFRESH_RATE_EXTENSION_H
|
||||
|
||||
// This extension gives us access to the possible display refresh rates
|
||||
// supported by the HMD.
|
||||
// While this is an FB extension it has been adopted by most runtimes and
|
||||
// will likely become core in the near future.
|
||||
|
||||
#include "../openxr_api.h"
|
||||
#include "../util.h"
|
||||
#include "openxr_extension_wrapper.h"
|
||||
|
||||
class OpenXRDisplayRefreshRateExtension : public OpenXRExtensionWrapper {
|
||||
public:
|
||||
static OpenXRDisplayRefreshRateExtension *get_singleton();
|
||||
|
||||
OpenXRDisplayRefreshRateExtension();
|
||||
virtual ~OpenXRDisplayRefreshRateExtension() 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;
|
||||
virtual bool on_event_polled(const XrEventDataBuffer &event) override;
|
||||
|
||||
float get_refresh_rate() const;
|
||||
void set_refresh_rate(float p_refresh_rate);
|
||||
|
||||
Array get_available_refresh_rates() const;
|
||||
|
||||
private:
|
||||
static OpenXRDisplayRefreshRateExtension *singleton;
|
||||
|
||||
bool display_refresh_rate_ext = false;
|
||||
|
||||
// OpenXR API call wrappers
|
||||
EXT_PROTO_XRRESULT_FUNC4(xrEnumerateDisplayRefreshRatesFB, (XrSession), session, (uint32_t), displayRefreshRateCapacityInput, (uint32_t *), displayRefreshRateCountOutput, (float *), displayRefreshRates);
|
||||
EXT_PROTO_XRRESULT_FUNC2(xrGetDisplayRefreshRateFB, (XrSession), session, (float *), display_refresh_rate);
|
||||
EXT_PROTO_XRRESULT_FUNC2(xrRequestDisplayRefreshRateFB, (XrSession), session, (float), display_refresh_rate);
|
||||
};
|
||||
|
||||
#endif // OPENXR_FB_DISPLAY_REFRESH_RATE_EXTENSION_H
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_fb_foveation_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_fb_foveation_extension.h"
|
||||
#include "core/config/project_settings.h"
|
||||
|
||||
OpenXRFBFoveationExtension *OpenXRFBFoveationExtension::singleton = nullptr;
|
||||
|
||||
OpenXRFBFoveationExtension *OpenXRFBFoveationExtension::get_singleton() {
|
||||
return singleton;
|
||||
}
|
||||
|
||||
OpenXRFBFoveationExtension::OpenXRFBFoveationExtension(const String &p_rendering_driver) {
|
||||
singleton = this;
|
||||
rendering_driver = p_rendering_driver;
|
||||
swapchain_update_state_ext = OpenXRFBUpdateSwapchainExtension::get_singleton();
|
||||
int fov_level = GLOBAL_GET("xr/openxr/foveation_level");
|
||||
if (fov_level >= 0 && fov_level < 4) {
|
||||
foveation_level = XrFoveationLevelFB(fov_level);
|
||||
}
|
||||
bool fov_dyn = GLOBAL_GET("xr/openxr/foveation_dynamic");
|
||||
foveation_dynamic = fov_dyn ? XR_FOVEATION_DYNAMIC_LEVEL_ENABLED_FB : XR_FOVEATION_DYNAMIC_DISABLED_FB;
|
||||
|
||||
swapchain_create_info_foveation_fb.type = XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB;
|
||||
swapchain_create_info_foveation_fb.next = nullptr;
|
||||
swapchain_create_info_foveation_fb.flags = 0;
|
||||
}
|
||||
|
||||
OpenXRFBFoveationExtension::~OpenXRFBFoveationExtension() {
|
||||
singleton = nullptr;
|
||||
swapchain_update_state_ext = nullptr;
|
||||
}
|
||||
|
||||
HashMap<String, bool *> OpenXRFBFoveationExtension::get_requested_extensions() {
|
||||
HashMap<String, bool *> request_extensions;
|
||||
|
||||
if (rendering_driver == "vulkan") {
|
||||
// This is currently only supported on OpenGL, but we may add Vulkan support in the future...
|
||||
|
||||
} else if (rendering_driver == "opengl3") {
|
||||
request_extensions[XR_FB_FOVEATION_EXTENSION_NAME] = &fb_foveation_ext;
|
||||
request_extensions[XR_FB_FOVEATION_CONFIGURATION_EXTENSION_NAME] = &fb_foveation_configuration_ext;
|
||||
}
|
||||
|
||||
return request_extensions;
|
||||
}
|
||||
|
||||
void OpenXRFBFoveationExtension::on_instance_created(const XrInstance p_instance) {
|
||||
if (fb_foveation_ext) {
|
||||
EXT_INIT_XR_FUNC(xrCreateFoveationProfileFB);
|
||||
EXT_INIT_XR_FUNC(xrDestroyFoveationProfileFB);
|
||||
}
|
||||
|
||||
if (fb_foveation_configuration_ext) {
|
||||
// nothing to register here...
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRFBFoveationExtension::on_instance_destroyed() {
|
||||
fb_foveation_ext = false;
|
||||
fb_foveation_configuration_ext = false;
|
||||
}
|
||||
|
||||
bool OpenXRFBFoveationExtension::is_enabled() const {
|
||||
return swapchain_update_state_ext != nullptr && swapchain_update_state_ext->is_enabled() && fb_foveation_ext && fb_foveation_configuration_ext;
|
||||
}
|
||||
|
||||
void *OpenXRFBFoveationExtension::set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) {
|
||||
if (is_enabled()) {
|
||||
swapchain_create_info_foveation_fb.next = p_next_pointer;
|
||||
return &swapchain_create_info_foveation_fb;
|
||||
} else {
|
||||
return p_next_pointer;
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRFBFoveationExtension::on_main_swapchains_created() {
|
||||
update_profile();
|
||||
}
|
||||
|
||||
XrFoveationLevelFB OpenXRFBFoveationExtension::get_foveation_level() const {
|
||||
return foveation_level;
|
||||
}
|
||||
|
||||
void OpenXRFBFoveationExtension::set_foveation_level(XrFoveationLevelFB p_foveation_level) {
|
||||
foveation_level = p_foveation_level;
|
||||
|
||||
// Update profile will do nothing if we're not yet initialized.
|
||||
update_profile();
|
||||
}
|
||||
|
||||
XrFoveationDynamicFB OpenXRFBFoveationExtension::get_foveation_dynamic() const {
|
||||
return foveation_dynamic;
|
||||
}
|
||||
|
||||
void OpenXRFBFoveationExtension::set_foveation_dynamic(XrFoveationDynamicFB p_foveation_dynamic) {
|
||||
foveation_dynamic = p_foveation_dynamic;
|
||||
|
||||
// Update profile will do nothing if we're not yet initialized.
|
||||
update_profile();
|
||||
}
|
||||
|
||||
void OpenXRFBFoveationExtension::_update_profile() {
|
||||
// Must be called from rendering thread!
|
||||
ERR_NOT_ON_RENDER_THREAD;
|
||||
|
||||
OpenXRFBFoveationExtension *fov_ext = OpenXRFBFoveationExtension::get_singleton();
|
||||
ERR_FAIL_NULL(fov_ext);
|
||||
|
||||
if (!fov_ext->is_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
|
||||
ERR_FAIL_NULL(openxr_api);
|
||||
|
||||
XrSwapchain main_color_swapchain = openxr_api->get_color_swapchain();
|
||||
if (main_color_swapchain == XR_NULL_HANDLE) {
|
||||
// Our swapchain hasn't been created yet, we'll call this again once it has.
|
||||
return;
|
||||
}
|
||||
|
||||
XrFoveationLevelProfileCreateInfoFB level_profile_create_info;
|
||||
level_profile_create_info.type = XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB;
|
||||
level_profile_create_info.next = nullptr;
|
||||
level_profile_create_info.level = fov_ext->foveation_level;
|
||||
level_profile_create_info.verticalOffset = 0.0f;
|
||||
level_profile_create_info.dynamic = fov_ext->foveation_dynamic;
|
||||
|
||||
XrFoveationProfileCreateInfoFB profile_create_info;
|
||||
profile_create_info.type = XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB;
|
||||
profile_create_info.next = &level_profile_create_info;
|
||||
|
||||
XrFoveationProfileFB foveation_profile;
|
||||
XrResult result = fov_ext->xrCreateFoveationProfileFB(openxr_api->get_session(), &profile_create_info, &foveation_profile);
|
||||
if (XR_FAILED(result)) {
|
||||
print_line("OpenXR: Unable to create the foveation profile [", openxr_api->get_error_string(result), "]");
|
||||
return;
|
||||
}
|
||||
|
||||
XrSwapchainStateFoveationFB foveation_update_state;
|
||||
foveation_update_state.type = XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB;
|
||||
foveation_update_state.profile = foveation_profile;
|
||||
|
||||
result = fov_ext->swapchain_update_state_ext->xrUpdateSwapchainFB(main_color_swapchain, (XrSwapchainStateBaseHeaderFB *)&foveation_update_state);
|
||||
if (XR_FAILED(result)) {
|
||||
print_line("OpenXR: Unable to update the swapchain [", openxr_api->get_error_string(result), "]");
|
||||
|
||||
// We still want to destroy our profile so keep going...
|
||||
}
|
||||
|
||||
result = fov_ext->xrDestroyFoveationProfileFB(foveation_profile);
|
||||
if (XR_FAILED(result)) {
|
||||
print_line("OpenXR: Unable to destroy the foveation profile [", openxr_api->get_error_string(result), "]");
|
||||
}
|
||||
}
|
||||
104
engine/modules/openxr/extensions/openxr_fb_foveation_extension.h
Normal file
104
engine/modules/openxr/extensions/openxr_fb_foveation_extension.h
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_fb_foveation_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_FB_FOVEATION_EXTENSION_H
|
||||
#define OPENXR_FB_FOVEATION_EXTENSION_H
|
||||
|
||||
// This extension implements the FB Foveation extension.
|
||||
// This is an extension Meta added due to VRS being unavailable on Android.
|
||||
// Other Android based devices are implementing this as well, see:
|
||||
// https://github.khronos.org/OpenXR-Inventory/extension_support.html#XR_FB_foveation
|
||||
|
||||
// Note: Currently we only support this for OpenGL.
|
||||
// This extension works on enabling foveated rendering on the swapchain.
|
||||
// Vulkan does not render 3D content directly to the swapchain image
|
||||
// hence this extension can't be used.
|
||||
|
||||
#include "../openxr_api.h"
|
||||
#include "../util.h"
|
||||
#include "openxr_extension_wrapper.h"
|
||||
#include "openxr_fb_update_swapchain_extension.h"
|
||||
|
||||
class OpenXRFBFoveationExtension : public OpenXRExtensionWrapper {
|
||||
public:
|
||||
static OpenXRFBFoveationExtension *get_singleton();
|
||||
|
||||
OpenXRFBFoveationExtension(const String &p_rendering_driver);
|
||||
virtual ~OpenXRFBFoveationExtension() 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;
|
||||
|
||||
virtual void *set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) override;
|
||||
|
||||
virtual void on_main_swapchains_created() override;
|
||||
|
||||
bool is_enabled() const;
|
||||
|
||||
XrFoveationLevelFB get_foveation_level() const;
|
||||
void set_foveation_level(XrFoveationLevelFB p_foveation_level);
|
||||
|
||||
XrFoveationDynamicFB get_foveation_dynamic() const;
|
||||
void set_foveation_dynamic(XrFoveationDynamicFB p_foveation_dynamic);
|
||||
|
||||
private:
|
||||
static OpenXRFBFoveationExtension *singleton;
|
||||
|
||||
// Setup
|
||||
String rendering_driver;
|
||||
bool fb_foveation_ext = false;
|
||||
bool fb_foveation_configuration_ext = false;
|
||||
|
||||
// Configuration
|
||||
XrFoveationLevelFB foveation_level = XR_FOVEATION_LEVEL_NONE_FB;
|
||||
XrFoveationDynamicFB foveation_dynamic = XR_FOVEATION_DYNAMIC_DISABLED_FB;
|
||||
|
||||
static void _update_profile();
|
||||
|
||||
void update_profile() {
|
||||
// If we're rendering on a separate thread, we may still be processing the last frame, don't communicate this till we're ready...
|
||||
RenderingServer *rendering_server = RenderingServer::get_singleton();
|
||||
ERR_FAIL_NULL(rendering_server);
|
||||
|
||||
rendering_server->call_on_render_thread(callable_mp_static(&OpenXRFBFoveationExtension::_update_profile));
|
||||
}
|
||||
|
||||
// Enable foveation on this swapchain
|
||||
XrSwapchainCreateInfoFoveationFB swapchain_create_info_foveation_fb;
|
||||
OpenXRFBUpdateSwapchainExtension *swapchain_update_state_ext = nullptr;
|
||||
|
||||
// OpenXR API call wrappers
|
||||
EXT_PROTO_XRRESULT_FUNC3(xrCreateFoveationProfileFB, (XrSession), session, (const XrFoveationProfileCreateInfoFB *), create_info, (XrFoveationProfileFB *), profile);
|
||||
EXT_PROTO_XRRESULT_FUNC1(xrDestroyFoveationProfileFB, (XrFoveationProfileFB), profile);
|
||||
};
|
||||
|
||||
#endif // OPENXR_FB_FOVEATION_EXTENSION_H
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_fb_update_swapchain_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_fb_update_swapchain_extension.h"
|
||||
|
||||
// Always include this as late as possible.
|
||||
#include "../openxr_platform_inc.h"
|
||||
|
||||
OpenXRFBUpdateSwapchainExtension *OpenXRFBUpdateSwapchainExtension::singleton = nullptr;
|
||||
|
||||
OpenXRFBUpdateSwapchainExtension *OpenXRFBUpdateSwapchainExtension::get_singleton() {
|
||||
return singleton;
|
||||
}
|
||||
|
||||
OpenXRFBUpdateSwapchainExtension::OpenXRFBUpdateSwapchainExtension(const String &p_rendering_driver) {
|
||||
singleton = this;
|
||||
rendering_driver = p_rendering_driver;
|
||||
}
|
||||
|
||||
OpenXRFBUpdateSwapchainExtension::~OpenXRFBUpdateSwapchainExtension() {
|
||||
singleton = nullptr;
|
||||
}
|
||||
|
||||
HashMap<String, bool *> OpenXRFBUpdateSwapchainExtension::get_requested_extensions() {
|
||||
HashMap<String, bool *> request_extensions;
|
||||
|
||||
request_extensions[XR_FB_SWAPCHAIN_UPDATE_STATE_EXTENSION_NAME] = &fb_swapchain_update_state_ext;
|
||||
|
||||
if (rendering_driver == "vulkan") {
|
||||
#ifdef XR_USE_GRAPHICS_API_VULKAN
|
||||
request_extensions[XR_FB_SWAPCHAIN_UPDATE_STATE_VULKAN_EXTENSION_NAME] = &fb_swapchain_update_state_vulkan_ext;
|
||||
#endif
|
||||
} else if (rendering_driver == "opengl3") {
|
||||
#ifdef XR_USE_GRAPHICS_API_OPENGL_ES
|
||||
request_extensions[XR_FB_SWAPCHAIN_UPDATE_STATE_OPENGL_ES_EXTENSION_NAME] = &fb_swapchain_update_state_opengles_ext;
|
||||
#endif
|
||||
}
|
||||
|
||||
return request_extensions;
|
||||
}
|
||||
|
||||
void OpenXRFBUpdateSwapchainExtension::on_instance_created(const XrInstance p_instance) {
|
||||
if (fb_swapchain_update_state_ext) {
|
||||
EXT_INIT_XR_FUNC(xrUpdateSwapchainFB);
|
||||
EXT_INIT_XR_FUNC(xrGetSwapchainStateFB);
|
||||
}
|
||||
|
||||
if (fb_swapchain_update_state_vulkan_ext) {
|
||||
// nothing to register here...
|
||||
}
|
||||
|
||||
if (fb_swapchain_update_state_opengles_ext) {
|
||||
// nothing to register here...
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRFBUpdateSwapchainExtension::on_instance_destroyed() {
|
||||
fb_swapchain_update_state_ext = false;
|
||||
fb_swapchain_update_state_vulkan_ext = false;
|
||||
fb_swapchain_update_state_opengles_ext = false;
|
||||
}
|
||||
|
||||
bool OpenXRFBUpdateSwapchainExtension::is_enabled() const {
|
||||
if (rendering_driver == "vulkan") {
|
||||
return fb_swapchain_update_state_ext && fb_swapchain_update_state_vulkan_ext;
|
||||
} else if (rendering_driver == "opengl3") {
|
||||
#ifdef XR_USE_GRAPHICS_API_OPENGL_ES
|
||||
return fb_swapchain_update_state_ext && fb_swapchain_update_state_opengles_ext;
|
||||
#else
|
||||
return fb_swapchain_update_state_ext;
|
||||
#endif
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_fb_update_swapchain_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_FB_UPDATE_SWAPCHAIN_EXTENSION_H
|
||||
#define OPENXR_FB_UPDATE_SWAPCHAIN_EXTENSION_H
|
||||
|
||||
// This extension implements the FB update swapchain extension.
|
||||
// This is an extension Meta added to further configure the swapchain.
|
||||
// Other Android based devices are implementing this as well, see:
|
||||
// https://github.khronos.org/OpenXR-Inventory/extension_support.html#XR_FB_swapchain_update_state
|
||||
|
||||
#include "../openxr_api.h"
|
||||
#include "../util.h"
|
||||
#include "openxr_extension_wrapper.h"
|
||||
|
||||
class OpenXRFBUpdateSwapchainExtension : public OpenXRExtensionWrapper {
|
||||
friend class OpenXRFBFoveationExtension;
|
||||
|
||||
public:
|
||||
static OpenXRFBUpdateSwapchainExtension *get_singleton();
|
||||
|
||||
OpenXRFBUpdateSwapchainExtension(const String &p_rendering_driver);
|
||||
virtual ~OpenXRFBUpdateSwapchainExtension() 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 is_enabled() const;
|
||||
|
||||
private:
|
||||
static OpenXRFBUpdateSwapchainExtension *singleton;
|
||||
|
||||
// Setup
|
||||
String rendering_driver;
|
||||
bool fb_swapchain_update_state_ext = false;
|
||||
bool fb_swapchain_update_state_vulkan_ext = false;
|
||||
bool fb_swapchain_update_state_opengles_ext = false;
|
||||
|
||||
// OpenXR API call wrappers
|
||||
EXT_PROTO_XRRESULT_FUNC2(xrUpdateSwapchainFB, (XrSwapchain), swapchain, (const XrSwapchainStateBaseHeaderFB *), state);
|
||||
EXT_PROTO_XRRESULT_FUNC2(xrGetSwapchainStateFB, (XrSwapchain), swapchain, (XrSwapchainStateBaseHeaderFB *), state);
|
||||
};
|
||||
|
||||
#endif // OPENXR_FB_UPDATE_SWAPCHAIN_EXTENSION_H
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_hand_interaction_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_hand_interaction_extension.h"
|
||||
|
||||
#include "../action_map/openxr_interaction_profile_metadata.h"
|
||||
#include "core/config/project_settings.h"
|
||||
|
||||
OpenXRHandInteractionExtension *OpenXRHandInteractionExtension::singleton = nullptr;
|
||||
|
||||
OpenXRHandInteractionExtension *OpenXRHandInteractionExtension::get_singleton() {
|
||||
return singleton;
|
||||
}
|
||||
|
||||
OpenXRHandInteractionExtension::OpenXRHandInteractionExtension() {
|
||||
singleton = this;
|
||||
}
|
||||
|
||||
OpenXRHandInteractionExtension::~OpenXRHandInteractionExtension() {
|
||||
singleton = nullptr;
|
||||
}
|
||||
|
||||
HashMap<String, bool *> OpenXRHandInteractionExtension::get_requested_extensions() {
|
||||
HashMap<String, bool *> request_extensions;
|
||||
|
||||
// Only enable this extension when requested.
|
||||
// We still register our meta data or the action map editor will fail.
|
||||
if (GLOBAL_GET("xr/openxr/extensions/hand_interaction_profile")) {
|
||||
request_extensions[XR_EXT_HAND_INTERACTION_EXTENSION_NAME] = &available;
|
||||
}
|
||||
|
||||
return request_extensions;
|
||||
}
|
||||
|
||||
bool OpenXRHandInteractionExtension::is_available() {
|
||||
return available;
|
||||
}
|
||||
|
||||
void OpenXRHandInteractionExtension::on_register_metadata() {
|
||||
OpenXRInteractionProfileMetadata *metadata = OpenXRInteractionProfileMetadata::get_singleton();
|
||||
ERR_FAIL_NULL(metadata);
|
||||
|
||||
// Hand interaction profile
|
||||
metadata->register_interaction_profile("Hand interaction", "/interaction_profiles/ext/hand_interaction_ext", XR_EXT_HAND_INTERACTION_EXTENSION_NAME);
|
||||
metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Pinch pose", "/user/hand/left", "/user/hand/left/input/pinch_ext/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Pinch pose", "/user/hand/right", "/user/hand/right/input/pinch_ext/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Poke pose", "/user/hand/left", "/user/hand/left/input/poke_ext/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Poke pose", "/user/hand/right", "/user/hand/right/input/poke_ext/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "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/ext/hand_interaction_ext", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
|
||||
|
||||
metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Pinch", "/user/hand/left", "/user/hand/left/input/pinch_ext/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Pinch", "/user/hand/right", "/user/hand/right/input/pinch_ext/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Pinch ready", "/user/hand/left", "/user/hand/left/input/pinch_ext/ready_ext", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Pinch ready", "/user/hand/right", "/user/hand/right/input/pinch_ext/ready_ext", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Aim activate", "/user/hand/left", "/user/hand/left/input/aim_activate_ext/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Aim activate", "/user/hand/right", "/user/hand/right/input/aim_activate_ext/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Aim activate ready", "/user/hand/left", "/user/hand/left/input/aim_activate_ext/ready_ext", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Aim activate ready", "/user/hand/right", "/user/hand/right/input/aim_activate_ext/ready_ext", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Grasp", "/user/hand/left", "/user/hand/left/input/grasp_ext/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Grasp", "/user/hand/right", "/user/hand/right/input/grasp_ext/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Grasp ready", "/user/hand/left", "/user/hand/left/input/grasp_ext/ready_ext", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path("/interaction_profiles/ext/hand_interaction_ext", "Grasp ready", "/user/hand/right", "/user/hand/right/input/grasp_ext/ready_ext", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_hand_interaction_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_HAND_INTERACTION_EXTENSION_H
|
||||
#define OPENXR_HAND_INTERACTION_EXTENSION_H
|
||||
|
||||
#include "openxr_extension_wrapper.h"
|
||||
|
||||
// When supported the hand interaction extension introduces an interaction
|
||||
// profile that becomes active when the user either lets go of their
|
||||
// controllers or isn't using controllers at all.
|
||||
//
|
||||
// The OpenXR specification states that all XR runtimes that support this
|
||||
// interaction profile should also allow it's controller to use this
|
||||
// interaction profile.
|
||||
// This means that if you only supply this interaction profile in your
|
||||
// action map, it should work both when the player is holding a controller
|
||||
// or using visual hand tracking.
|
||||
//
|
||||
// This allows easier portability between games that use controller
|
||||
// tracking or hand tracking.
|
||||
//
|
||||
// See: https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#XR_EXT_hand_interaction
|
||||
// for more information.
|
||||
|
||||
class OpenXRHandInteractionExtension : public OpenXRExtensionWrapper {
|
||||
public:
|
||||
static OpenXRHandInteractionExtension *get_singleton();
|
||||
|
||||
OpenXRHandInteractionExtension();
|
||||
virtual ~OpenXRHandInteractionExtension() override;
|
||||
|
||||
virtual HashMap<String, bool *> get_requested_extensions() override;
|
||||
|
||||
bool is_available();
|
||||
|
||||
virtual void on_register_metadata() override;
|
||||
|
||||
private:
|
||||
static OpenXRHandInteractionExtension *singleton;
|
||||
|
||||
bool available = false;
|
||||
};
|
||||
|
||||
#endif // OPENXR_HAND_INTERACTION_EXTENSION_H
|
||||
|
|
@ -0,0 +1,479 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_hand_tracking_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_hand_tracking_extension.h"
|
||||
|
||||
#include "../openxr_api.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/string/print_string.h"
|
||||
#include "servers/xr_server.h"
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
OpenXRHandTrackingExtension *OpenXRHandTrackingExtension::singleton = nullptr;
|
||||
|
||||
OpenXRHandTrackingExtension *OpenXRHandTrackingExtension::get_singleton() {
|
||||
return singleton;
|
||||
}
|
||||
|
||||
OpenXRHandTrackingExtension::OpenXRHandTrackingExtension() {
|
||||
singleton = this;
|
||||
|
||||
// Make sure this is cleared until we actually request it
|
||||
handTrackingSystemProperties.supportsHandTracking = false;
|
||||
}
|
||||
|
||||
OpenXRHandTrackingExtension::~OpenXRHandTrackingExtension() {
|
||||
singleton = nullptr;
|
||||
}
|
||||
|
||||
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;
|
||||
if (unobstructed_data_source || controller_data_source) {
|
||||
request_extensions[XR_EXT_HAND_TRACKING_DATA_SOURCE_EXTENSION_NAME] = &hand_tracking_source_ext;
|
||||
}
|
||||
|
||||
return request_extensions;
|
||||
}
|
||||
|
||||
void OpenXRHandTrackingExtension::on_instance_created(const XrInstance p_instance) {
|
||||
if (hand_tracking_ext) {
|
||||
EXT_INIT_XR_FUNC(xrCreateHandTrackerEXT);
|
||||
EXT_INIT_XR_FUNC(xrDestroyHandTrackerEXT);
|
||||
EXT_INIT_XR_FUNC(xrLocateHandJointsEXT);
|
||||
|
||||
hand_tracking_ext = xrCreateHandTrackerEXT_ptr && xrDestroyHandTrackerEXT_ptr && xrLocateHandJointsEXT_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRHandTrackingExtension::on_session_destroyed() {
|
||||
cleanup_hand_tracking();
|
||||
}
|
||||
|
||||
void OpenXRHandTrackingExtension::on_instance_destroyed() {
|
||||
xrCreateHandTrackerEXT_ptr = nullptr;
|
||||
xrDestroyHandTrackerEXT_ptr = nullptr;
|
||||
xrLocateHandJointsEXT_ptr = nullptr;
|
||||
}
|
||||
|
||||
void *OpenXRHandTrackingExtension::set_system_properties_and_get_next_pointer(void *p_next_pointer) {
|
||||
if (!hand_tracking_ext) {
|
||||
// not supported...
|
||||
return p_next_pointer;
|
||||
}
|
||||
|
||||
handTrackingSystemProperties = {
|
||||
XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT, // type
|
||||
p_next_pointer, // next
|
||||
false, // supportsHandTracking
|
||||
};
|
||||
|
||||
return &handTrackingSystemProperties;
|
||||
}
|
||||
|
||||
void OpenXRHandTrackingExtension::on_state_ready() {
|
||||
if (!handTrackingSystemProperties.supportsHandTracking) {
|
||||
// not supported...
|
||||
return;
|
||||
}
|
||||
|
||||
// Setup our hands and reset data
|
||||
for (int i = 0; i < OPENXR_MAX_TRACKED_HANDS; i++) {
|
||||
// we'll do this later
|
||||
hand_trackers[i].is_initialized = false;
|
||||
hand_trackers[i].hand_tracker = XR_NULL_HANDLE;
|
||||
|
||||
hand_trackers[i].locations.isActive = false;
|
||||
|
||||
for (int j = 0; j < XR_HAND_JOINT_COUNT_EXT; j++) {
|
||||
hand_trackers[i].joint_locations[j] = { 0, { { 0.0, 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 } }, 0.0 };
|
||||
hand_trackers[i].joint_velocities[j] = { 0, { 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 } };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRHandTrackingExtension::on_process() {
|
||||
if (!handTrackingSystemProperties.supportsHandTracking) {
|
||||
// not supported...
|
||||
return;
|
||||
}
|
||||
|
||||
// process our hands
|
||||
const XrTime time = OpenXRAPI::get_singleton()->get_predicted_display_time();
|
||||
if (time == 0) {
|
||||
// we don't have timing info yet, or we're skipping a frame...
|
||||
return;
|
||||
}
|
||||
|
||||
XrResult result;
|
||||
|
||||
for (int i = 0; i < OPENXR_MAX_TRACKED_HANDS; i++) {
|
||||
if (hand_trackers[i].hand_tracker == XR_NULL_HANDLE) {
|
||||
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 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;
|
||||
}
|
||||
|
||||
XrHandTrackerCreateInfoEXT create_info = {
|
||||
XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT, // type
|
||||
next_pointer, // next
|
||||
i == 0 ? XR_HAND_LEFT_EXT : XR_HAND_RIGHT_EXT, // hand
|
||||
XR_HAND_JOINT_SET_DEFAULT_EXT, // handJointSet
|
||||
};
|
||||
|
||||
result = xrCreateHandTrackerEXT(OpenXRAPI::get_singleton()->get_session(), &create_info, &hand_trackers[i].hand_tracker);
|
||||
if (XR_FAILED(result)) {
|
||||
// not successful? then we do nothing.
|
||||
print_line("OpenXR: Failed to obtain hand tracking information [", OpenXRAPI::get_singleton()->get_error_string(result), "]");
|
||||
hand_trackers[i].is_initialized = false;
|
||||
} else {
|
||||
next_pointer = nullptr;
|
||||
|
||||
hand_trackers[i].velocities.type = XR_TYPE_HAND_JOINT_VELOCITIES_EXT;
|
||||
hand_trackers[i].velocities.next = next_pointer;
|
||||
hand_trackers[i].velocities.jointCount = XR_HAND_JOINT_COUNT_EXT;
|
||||
hand_trackers[i].velocities.jointVelocities = hand_trackers[i].joint_velocities;
|
||||
next_pointer = &hand_trackers[i].velocities;
|
||||
|
||||
if (hand_tracking_source_ext) {
|
||||
hand_trackers[i].data_source.type = XR_TYPE_HAND_TRACKING_DATA_SOURCE_STATE_EXT;
|
||||
hand_trackers[i].data_source.next = next_pointer;
|
||||
hand_trackers[i].data_source.isActive = false;
|
||||
hand_trackers[i].data_source.dataSource = XrHandTrackingDataSourceEXT(0);
|
||||
next_pointer = &hand_trackers[i].data_source;
|
||||
}
|
||||
|
||||
// Needed for vendor hand tracking extensions implemented from GDExtension.
|
||||
for (OpenXRExtensionWrapper *wrapper : OpenXRAPI::get_singleton()->get_registered_extension_wrappers()) {
|
||||
void *np = wrapper->set_hand_joint_locations_and_get_next_pointer(i, next_pointer);
|
||||
if (np != nullptr) {
|
||||
next_pointer = np;
|
||||
}
|
||||
}
|
||||
|
||||
hand_trackers[i].locations.type = XR_TYPE_HAND_JOINT_LOCATIONS_EXT;
|
||||
hand_trackers[i].locations.next = next_pointer;
|
||||
hand_trackers[i].locations.isActive = false;
|
||||
hand_trackers[i].locations.jointCount = XR_HAND_JOINT_COUNT_EXT;
|
||||
hand_trackers[i].locations.jointLocations = hand_trackers[i].joint_locations;
|
||||
|
||||
Ref<XRHandTracker> godot_tracker;
|
||||
godot_tracker.instantiate();
|
||||
godot_tracker->set_tracker_hand(i == 0 ? XRPositionalTracker::TRACKER_HAND_LEFT : XRPositionalTracker::TRACKER_HAND_RIGHT);
|
||||
godot_tracker->set_tracker_name(i == 0 ? "/user/hand_tracker/left" : "/user/hand_tracker/right");
|
||||
XRServer::get_singleton()->add_tracker(godot_tracker);
|
||||
hand_trackers[i].godot_tracker = godot_tracker;
|
||||
|
||||
hand_trackers[i].is_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hand_trackers[i].is_initialized) {
|
||||
Ref<XRHandTracker> godot_tracker = hand_trackers[i].godot_tracker;
|
||||
void *next_pointer = nullptr;
|
||||
|
||||
XrHandJointsMotionRangeInfoEXT motion_range_info = { XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT, next_pointer, hand_trackers[i].motion_range };
|
||||
if (hand_motion_range_ext) {
|
||||
next_pointer = &motion_range_info;
|
||||
}
|
||||
|
||||
XrHandJointsLocateInfoEXT locateInfo = {
|
||||
XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT, // type
|
||||
next_pointer, // next
|
||||
OpenXRAPI::get_singleton()->get_play_space(), // baseSpace
|
||||
time, // time
|
||||
};
|
||||
|
||||
result = xrLocateHandJointsEXT(hand_trackers[i].hand_tracker, &locateInfo, &hand_trackers[i].locations);
|
||||
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;
|
||||
}
|
||||
|
||||
// For some reason an inactive controller isn't coming back as inactive but has coordinates either as NAN or very large
|
||||
const XrPosef &palm = hand_trackers[i].joint_locations[XR_HAND_JOINT_PALM_EXT].pose;
|
||||
if (!hand_trackers[i].locations.isActive || isnan(palm.position.x) || palm.position.x < -1000000.00 || palm.position.x > 1000000.00) {
|
||||
hand_trackers[i].locations.isActive = false; // workaround, make sure its inactive
|
||||
}
|
||||
|
||||
if (hand_trackers[i].locations.isActive) {
|
||||
// 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)
|
||||
const Quaternion bone_adjustment(0.0, -Math_SQRT12, Math_SQRT12, 0.0);
|
||||
|
||||
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 XrPosef &pose = location.pose;
|
||||
|
||||
Transform3D transform;
|
||||
Vector3 linear_velocity;
|
||||
Vector3 angular_velocity;
|
||||
BitField<XRHandTracker::HandJointFlags> flags;
|
||||
|
||||
if (location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) {
|
||||
if (pose.orientation.x != 0 || pose.orientation.y != 0 || pose.orientation.z != 0 || pose.orientation.w != 0) {
|
||||
flags.set_flag(XRHandTracker::HAND_JOINT_FLAG_ORIENTATION_VALID);
|
||||
transform.basis = Basis(Quaternion(pose.orientation.x, pose.orientation.y, pose.orientation.z, pose.orientation.w) * bone_adjustment);
|
||||
}
|
||||
}
|
||||
if (location.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) {
|
||||
flags.set_flag(XRHandTracker::HAND_JOINT_FLAG_POSITION_VALID);
|
||||
transform.origin = Vector3(pose.position.x, pose.position.y, pose.position.z);
|
||||
}
|
||||
if (location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT) {
|
||||
flags.set_flag(XRHandTracker::HAND_JOINT_FLAG_ORIENTATION_TRACKED);
|
||||
}
|
||||
if (location.locationFlags & XR_SPACE_LOCATION_POSITION_TRACKED_BIT) {
|
||||
flags.set_flag(XRHandTracker::HAND_JOINT_FLAG_POSITION_TRACKED);
|
||||
}
|
||||
if (location.locationFlags & XR_SPACE_VELOCITY_LINEAR_VALID_BIT) {
|
||||
flags.set_flag(XRHandTracker::HAND_JOINT_FLAG_LINEAR_VELOCITY_VALID);
|
||||
linear_velocity = Vector3(velocity.linearVelocity.x, velocity.linearVelocity.y, velocity.linearVelocity.z);
|
||||
godot_tracker->set_hand_joint_linear_velocity((XRHandTracker::HandJoint)joint, linear_velocity);
|
||||
}
|
||||
if (location.locationFlags & XR_SPACE_VELOCITY_ANGULAR_VALID_BIT) {
|
||||
flags.set_flag(XRHandTracker::HAND_JOINT_FLAG_ANGULAR_VELOCITY_VALID);
|
||||
angular_velocity = Vector3(velocity.angularVelocity.x, velocity.angularVelocity.y, velocity.angularVelocity.z);
|
||||
godot_tracker->set_hand_joint_angular_velocity((XRHandTracker::HandJoint)joint, angular_velocity);
|
||||
}
|
||||
|
||||
godot_tracker->set_hand_joint_flags((XRHandTracker::HandJoint)joint, flags);
|
||||
godot_tracker->set_hand_joint_transform((XRHandTracker::HandJoint)joint, transform);
|
||||
godot_tracker->set_hand_joint_radius((XRHandTracker::HandJoint)joint, location.radius);
|
||||
|
||||
if (joint == XR_HAND_JOINT_PALM_EXT) {
|
||||
if (location.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) {
|
||||
XrHandTrackingDataSourceStateEXT &data_source = hand_trackers[i].data_source;
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRHandTrackingExtension::on_state_stopping() {
|
||||
// cleanup
|
||||
cleanup_hand_tracking();
|
||||
}
|
||||
|
||||
void OpenXRHandTrackingExtension::cleanup_hand_tracking() {
|
||||
XRServer *xr_server = XRServer::get_singleton();
|
||||
ERR_FAIL_NULL(xr_server);
|
||||
|
||||
for (int i = 0; i < OPENXR_MAX_TRACKED_HANDS; i++) {
|
||||
if (hand_trackers[i].hand_tracker != XR_NULL_HANDLE) {
|
||||
xrDestroyHandTrackerEXT(hand_trackers[i].hand_tracker);
|
||||
|
||||
hand_trackers[i].is_initialized = false;
|
||||
hand_trackers[i].hand_tracker = XR_NULL_HANDLE;
|
||||
|
||||
XRServer::get_singleton()->remove_tracker(hand_trackers[i].godot_tracker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool OpenXRHandTrackingExtension::get_active() {
|
||||
return handTrackingSystemProperties.supportsHandTracking;
|
||||
}
|
||||
|
||||
const OpenXRHandTrackingExtension::HandTracker *OpenXRHandTrackingExtension::get_hand_tracker(HandTrackedHands p_hand) const {
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_hand, OPENXR_MAX_TRACKED_HANDS, nullptr);
|
||||
|
||||
return &hand_trackers[p_hand];
|
||||
}
|
||||
|
||||
XrHandJointsMotionRangeEXT OpenXRHandTrackingExtension::get_motion_range(HandTrackedHands p_hand) const {
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_hand, OPENXR_MAX_TRACKED_HANDS, XR_HAND_JOINTS_MOTION_RANGE_MAX_ENUM_EXT);
|
||||
|
||||
return hand_trackers[p_hand].motion_range;
|
||||
}
|
||||
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return OPENXR_SOURCE_UNKNOWN;
|
||||
}
|
||||
|
||||
void OpenXRHandTrackingExtension::set_motion_range(HandTrackedHands p_hand, XrHandJointsMotionRangeEXT p_motion_range) {
|
||||
ERR_FAIL_UNSIGNED_INDEX(p_hand, OPENXR_MAX_TRACKED_HANDS);
|
||||
hand_trackers[p_hand].motion_range = p_motion_range;
|
||||
}
|
||||
|
||||
XrSpaceLocationFlags OpenXRHandTrackingExtension::get_hand_joint_location_flags(HandTrackedHands p_hand, XrHandJointEXT p_joint) const {
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_hand, OPENXR_MAX_TRACKED_HANDS, XrSpaceLocationFlags(0));
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_joint, XR_HAND_JOINT_COUNT_EXT, XrSpaceLocationFlags(0));
|
||||
|
||||
if (!hand_trackers[p_hand].is_initialized) {
|
||||
return XrSpaceLocationFlags(0);
|
||||
}
|
||||
|
||||
const XrHandJointLocationEXT &location = hand_trackers[p_hand].joint_locations[p_joint];
|
||||
return location.locationFlags;
|
||||
}
|
||||
|
||||
Quaternion OpenXRHandTrackingExtension::get_hand_joint_rotation(HandTrackedHands p_hand, XrHandJointEXT p_joint) const {
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_hand, OPENXR_MAX_TRACKED_HANDS, Quaternion());
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_joint, XR_HAND_JOINT_COUNT_EXT, Quaternion());
|
||||
|
||||
if (!hand_trackers[p_hand].is_initialized) {
|
||||
return Quaternion();
|
||||
}
|
||||
|
||||
const XrHandJointLocationEXT &location = hand_trackers[p_hand].joint_locations[p_joint];
|
||||
return Quaternion(location.pose.orientation.x, location.pose.orientation.y, location.pose.orientation.z, location.pose.orientation.w);
|
||||
}
|
||||
|
||||
Vector3 OpenXRHandTrackingExtension::get_hand_joint_position(HandTrackedHands p_hand, XrHandJointEXT p_joint) const {
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_hand, OPENXR_MAX_TRACKED_HANDS, Vector3());
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_joint, XR_HAND_JOINT_COUNT_EXT, Vector3());
|
||||
|
||||
if (!hand_trackers[p_hand].is_initialized) {
|
||||
return Vector3();
|
||||
}
|
||||
|
||||
const XrHandJointLocationEXT &location = hand_trackers[p_hand].joint_locations[p_joint];
|
||||
return Vector3(location.pose.position.x, location.pose.position.y, location.pose.position.z);
|
||||
}
|
||||
|
||||
float OpenXRHandTrackingExtension::get_hand_joint_radius(HandTrackedHands p_hand, XrHandJointEXT p_joint) const {
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_hand, OPENXR_MAX_TRACKED_HANDS, 0.0);
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_joint, XR_HAND_JOINT_COUNT_EXT, 0.0);
|
||||
|
||||
if (!hand_trackers[p_hand].is_initialized) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return hand_trackers[p_hand].joint_locations[p_joint].radius;
|
||||
}
|
||||
|
||||
XrSpaceVelocityFlags OpenXRHandTrackingExtension::get_hand_joint_velocity_flags(HandTrackedHands p_hand, XrHandJointEXT p_joint) const {
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_hand, OPENXR_MAX_TRACKED_HANDS, XrSpaceVelocityFlags(0));
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_joint, XR_HAND_JOINT_COUNT_EXT, XrSpaceVelocityFlags(0));
|
||||
|
||||
if (!hand_trackers[p_hand].is_initialized) {
|
||||
return XrSpaceVelocityFlags(0);
|
||||
}
|
||||
|
||||
const XrHandJointVelocityEXT &velocity = hand_trackers[p_hand].joint_velocities[p_joint];
|
||||
return velocity.velocityFlags;
|
||||
}
|
||||
|
||||
Vector3 OpenXRHandTrackingExtension::get_hand_joint_linear_velocity(HandTrackedHands p_hand, XrHandJointEXT p_joint) const {
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_hand, OPENXR_MAX_TRACKED_HANDS, Vector3());
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_joint, XR_HAND_JOINT_COUNT_EXT, Vector3());
|
||||
|
||||
if (!hand_trackers[p_hand].is_initialized) {
|
||||
return Vector3();
|
||||
}
|
||||
|
||||
const XrHandJointVelocityEXT &velocity = hand_trackers[p_hand].joint_velocities[p_joint];
|
||||
return Vector3(velocity.linearVelocity.x, velocity.linearVelocity.y, velocity.linearVelocity.z);
|
||||
}
|
||||
|
||||
Vector3 OpenXRHandTrackingExtension::get_hand_joint_angular_velocity(HandTrackedHands p_hand, XrHandJointEXT p_joint) const {
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_hand, OPENXR_MAX_TRACKED_HANDS, Vector3());
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_joint, XR_HAND_JOINT_COUNT_EXT, Vector3());
|
||||
|
||||
if (!hand_trackers[p_hand].is_initialized) {
|
||||
return Vector3();
|
||||
}
|
||||
|
||||
const XrHandJointVelocityEXT &velocity = hand_trackers[p_hand].joint_velocities[p_joint];
|
||||
return Vector3(velocity.angularVelocity.x, velocity.angularVelocity.y, velocity.angularVelocity.z);
|
||||
}
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_hand_tracking_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_HAND_TRACKING_EXTENSION_H
|
||||
#define OPENXR_HAND_TRACKING_EXTENSION_H
|
||||
|
||||
#include "../util.h"
|
||||
#include "core/math/quaternion.h"
|
||||
#include "openxr_extension_wrapper.h"
|
||||
#include "servers/xr/xr_hand_tracker.h"
|
||||
|
||||
class OpenXRHandTrackingExtension : public OpenXRExtensionWrapper {
|
||||
public:
|
||||
enum HandTrackedHands {
|
||||
OPENXR_TRACKED_LEFT_HAND,
|
||||
OPENXR_TRACKED_RIGHT_HAND,
|
||||
OPENXR_MAX_TRACKED_HANDS
|
||||
};
|
||||
|
||||
enum HandTrackedSource {
|
||||
OPENXR_SOURCE_UNKNOWN,
|
||||
OPENXR_SOURCE_UNOBSTRUCTED,
|
||||
OPENXR_SOURCE_CONTROLLER,
|
||||
OPENXR_SOURCE_NOT_TRACKED,
|
||||
OPENXR_SOURCE_MAX
|
||||
};
|
||||
|
||||
struct HandTracker {
|
||||
bool is_initialized = false;
|
||||
Ref<XRHandTracker> godot_tracker;
|
||||
XrHandJointsMotionRangeEXT motion_range = XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT;
|
||||
HandTrackedSource source = OPENXR_SOURCE_UNKNOWN;
|
||||
|
||||
XrHandTrackerEXT hand_tracker = XR_NULL_HANDLE;
|
||||
XrHandJointLocationEXT joint_locations[XR_HAND_JOINT_COUNT_EXT];
|
||||
XrHandJointVelocityEXT joint_velocities[XR_HAND_JOINT_COUNT_EXT];
|
||||
|
||||
XrHandJointVelocitiesEXT velocities;
|
||||
XrHandJointLocationsEXT locations;
|
||||
XrHandTrackingDataSourceStateEXT data_source;
|
||||
};
|
||||
|
||||
static OpenXRHandTrackingExtension *get_singleton();
|
||||
|
||||
OpenXRHandTrackingExtension();
|
||||
virtual ~OpenXRHandTrackingExtension() 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;
|
||||
virtual void on_session_destroyed() override;
|
||||
|
||||
virtual void *set_system_properties_and_get_next_pointer(void *p_next_pointer) override;
|
||||
virtual void on_state_ready() override;
|
||||
virtual void on_process() override;
|
||||
virtual void on_state_stopping() override;
|
||||
|
||||
bool get_active();
|
||||
const HandTracker *get_hand_tracker(HandTrackedHands p_hand) const;
|
||||
|
||||
XrHandJointsMotionRangeEXT get_motion_range(HandTrackedHands p_hand) const;
|
||||
void set_motion_range(HandTrackedHands p_hand, XrHandJointsMotionRangeEXT p_motion_range);
|
||||
|
||||
HandTrackedSource get_hand_tracking_source(HandTrackedHands p_hand) const;
|
||||
|
||||
XrSpaceLocationFlags get_hand_joint_location_flags(HandTrackedHands p_hand, XrHandJointEXT p_joint) const;
|
||||
Quaternion get_hand_joint_rotation(HandTrackedHands p_hand, XrHandJointEXT p_joint) const;
|
||||
Vector3 get_hand_joint_position(HandTrackedHands p_hand, XrHandJointEXT p_joint) const;
|
||||
float get_hand_joint_radius(HandTrackedHands p_hand, XrHandJointEXT p_joint) const;
|
||||
|
||||
XrSpaceVelocityFlags get_hand_joint_velocity_flags(HandTrackedHands p_hand, XrHandJointEXT p_joint) const;
|
||||
Vector3 get_hand_joint_linear_velocity(HandTrackedHands p_hand, XrHandJointEXT p_joint) const;
|
||||
Vector3 get_hand_joint_angular_velocity(HandTrackedHands p_hand, XrHandJointEXT p_joint) const;
|
||||
|
||||
private:
|
||||
static OpenXRHandTrackingExtension *singleton;
|
||||
|
||||
// state
|
||||
XrSystemHandTrackingPropertiesEXT handTrackingSystemProperties;
|
||||
HandTracker hand_trackers[OPENXR_MAX_TRACKED_HANDS]; // Fixed for left and right hand
|
||||
|
||||
// related extensions
|
||||
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();
|
||||
|
||||
// OpenXR API call wrappers
|
||||
EXT_PROTO_XRRESULT_FUNC3(xrCreateHandTrackerEXT, (XrSession), p_session, (const XrHandTrackerCreateInfoEXT *), p_createInfo, (XrHandTrackerEXT *), p_handTracker)
|
||||
EXT_PROTO_XRRESULT_FUNC1(xrDestroyHandTrackerEXT, (XrHandTrackerEXT), p_handTracker)
|
||||
EXT_PROTO_XRRESULT_FUNC3(xrLocateHandJointsEXT, (XrHandTrackerEXT), p_handTracker, (const XrHandJointsLocateInfoEXT *), p_locateInfo, (XrHandJointLocationsEXT *), p_locations)
|
||||
};
|
||||
|
||||
#endif // OPENXR_HAND_TRACKING_EXTENSION_H
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_htc_controller_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_htc_controller_extension.h"
|
||||
|
||||
#include "../action_map/openxr_interaction_profile_metadata.h"
|
||||
|
||||
HashMap<String, bool *> OpenXRHTCControllerExtension::get_requested_extensions() {
|
||||
HashMap<String, bool *> request_extensions;
|
||||
|
||||
request_extensions[XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME] = &available[HTC_VIVE_COSMOS];
|
||||
request_extensions[XR_HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME] = &available[HTC_VIVE_FOCUS3];
|
||||
request_extensions[XR_HTC_HAND_INTERACTION_EXTENSION_NAME] = &available[HTC_HAND_INTERACTION];
|
||||
|
||||
return request_extensions;
|
||||
}
|
||||
|
||||
PackedStringArray OpenXRHTCControllerExtension::get_suggested_tracker_names() {
|
||||
PackedStringArray arr = {
|
||||
"/user/hand_htc/left",
|
||||
"/user/hand_htc/right",
|
||||
};
|
||||
return arr;
|
||||
}
|
||||
|
||||
bool OpenXRHTCControllerExtension::is_available(HTCControllers p_type) {
|
||||
return available[p_type];
|
||||
}
|
||||
|
||||
void OpenXRHTCControllerExtension::on_register_metadata() {
|
||||
OpenXRInteractionProfileMetadata *metadata = OpenXRInteractionProfileMetadata::get_singleton();
|
||||
ERR_FAIL_NULL(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
|
||||
const String profile_path = "/interaction_profiles/htc/vive_cosmos_controller";
|
||||
metadata->register_interaction_profile("Vive Cosmos controller", profile_path, XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME);
|
||||
for (const String user_path : { "/user/hand/left", "/user/hand/right" }) {
|
||||
metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
metadata->register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
|
||||
|
||||
metadata->register_io_path(profile_path, "Shoulder click", user_path, user_path + "/input/shoulder/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
metadata->register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
metadata->register_io_path(profile_path, "Trigger click", user_path, user_path + "/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
metadata->register_io_path(profile_path, "Squeeze click", user_path, user_path + "/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
metadata->register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
|
||||
metadata->register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Thumbstick touch", user_path, user_path + "/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
|
||||
}
|
||||
|
||||
metadata->register_io_path(profile_path, "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
metadata->register_io_path(profile_path, "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
}
|
||||
|
||||
{ // HTC Vive Focus 3 controller
|
||||
const String profile_path = "/interaction_profiles/htc/vive_focus3_controller";
|
||||
metadata->register_interaction_profile("Vive Focus 3 controller", profile_path, XR_HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME);
|
||||
for (const String user_path : { "/user/hand/left", "/user/hand/right" }) {
|
||||
metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
metadata->register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
|
||||
|
||||
metadata->register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
metadata->register_io_path(profile_path, "Trigger click", user_path, user_path + "/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Trigger touch", user_path, user_path + "/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
metadata->register_io_path(profile_path, "Squeeze click", user_path, user_path + "/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Squeeze touch", user_path, user_path + "/input/squeeze/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
metadata->register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
|
||||
metadata->register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Thumbstick touch", user_path, user_path + "/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
metadata->register_io_path(profile_path, "Thumbrest touch", user_path, user_path + "/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
|
||||
}
|
||||
|
||||
metadata->register_io_path(profile_path, "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
metadata->register_io_path(profile_path, "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
}
|
||||
|
||||
{ // HTC Hand interaction profile
|
||||
const String profile_path = "/interaction_profiles/htc/hand_interaction";
|
||||
metadata->register_interaction_profile("HTC Hand interaction", profile_path, XR_HTC_HAND_INTERACTION_EXTENSION_NAME);
|
||||
for (const String user_path : { "/user/hand_htc/left", "/user/hand_htc/right" }) {
|
||||
metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
|
||||
metadata->register_io_path(profile_path, "Select (pinch)", user_path, user_path + "/input/select/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
|
||||
metadata->register_io_path(profile_path, "Squeeze (grab)", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_htc_controller_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_HTC_CONTROLLER_EXTENSION_H
|
||||
#define OPENXR_HTC_CONTROLLER_EXTENSION_H
|
||||
|
||||
#include "openxr_extension_wrapper.h"
|
||||
|
||||
class OpenXRHTCControllerExtension : public OpenXRExtensionWrapper {
|
||||
public:
|
||||
enum HTCControllers {
|
||||
// Note, HTC Vive Wand controllers are part of the core spec and not part of our extension.
|
||||
HTC_VIVE_COSMOS,
|
||||
HTC_VIVE_FOCUS3,
|
||||
HTC_HAND_INTERACTION,
|
||||
HTC_MAX_CONTROLLERS
|
||||
};
|
||||
|
||||
virtual HashMap<String, bool *> get_requested_extensions() override;
|
||||
|
||||
PackedStringArray get_suggested_tracker_names() override;
|
||||
|
||||
bool is_available(HTCControllers p_type);
|
||||
|
||||
virtual void on_register_metadata() override;
|
||||
|
||||
private:
|
||||
bool available[HTC_MAX_CONTROLLERS] = { false, false };
|
||||
};
|
||||
|
||||
#endif // OPENXR_HTC_CONTROLLER_EXTENSION_H
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_htc_vive_tracker_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_htc_vive_tracker_extension.h"
|
||||
|
||||
#include "../action_map/openxr_interaction_profile_metadata.h"
|
||||
|
||||
#include "core/string/print_string.h"
|
||||
|
||||
HashMap<String, bool *> OpenXRHTCViveTrackerExtension::get_requested_extensions() {
|
||||
HashMap<String, bool *> request_extensions;
|
||||
|
||||
request_extensions[XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME] = &available;
|
||||
|
||||
return request_extensions;
|
||||
}
|
||||
|
||||
PackedStringArray OpenXRHTCViveTrackerExtension::get_suggested_tracker_names() {
|
||||
PackedStringArray arr = {
|
||||
"/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",
|
||||
};
|
||||
return arr;
|
||||
}
|
||||
|
||||
bool OpenXRHTCViveTrackerExtension::is_available() {
|
||||
return available;
|
||||
}
|
||||
|
||||
void OpenXRHTCViveTrackerExtension::on_register_metadata() {
|
||||
OpenXRInteractionProfileMetadata *metadata = OpenXRInteractionProfileMetadata::get_singleton();
|
||||
ERR_FAIL_NULL(metadata);
|
||||
|
||||
// register_top_level_path("Handheld object tracker", "/user/vive_tracker_htcx/role/handheld_object", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
|
||||
metadata->register_top_level_path("Left foot tracker", "/user/vive_tracker_htcx/role/left_foot", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
|
||||
metadata->register_top_level_path("Right foot tracker", "/user/vive_tracker_htcx/role/right_foot", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
|
||||
metadata->register_top_level_path("Left shoulder tracker", "/user/vive_tracker_htcx/role/left_shoulder", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
|
||||
metadata->register_top_level_path("Right shoulder tracker", "/user/vive_tracker_htcx/role/right_shoulder", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
|
||||
metadata->register_top_level_path("Left elbow tracker", "/user/vive_tracker_htcx/role/left_elbow", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
|
||||
metadata->register_top_level_path("Right elbow tracker", "/user/vive_tracker_htcx/role/right_elbow", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
|
||||
metadata->register_top_level_path("Left knee tracker", "/user/vive_tracker_htcx/role/left_knee", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
|
||||
metadata->register_top_level_path("Right knee tracker", "/user/vive_tracker_htcx/role/right_knee", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
|
||||
metadata->register_top_level_path("Waist tracker", "/user/vive_tracker_htcx/role/waist", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
|
||||
metadata->register_top_level_path("Chest tracker", "/user/vive_tracker_htcx/role/chest", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
|
||||
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.
|
||||
const String profile_path = "/interaction_profiles/htc/vive_tracker_htcx";
|
||||
metadata->register_interaction_profile("HTC Vive tracker", profile_path, XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
|
||||
for (const String user_path : {
|
||||
/* "/user/vive_tracker_htcx/role/handheld_object", */
|
||||
"/user/vive_tracker_htcx/role/left_foot",
|
||||
"/user/vive_tracker_htcx/role/right_foot",
|
||||
"/user/vive_tracker_htcx/role/left_shoulder",
|
||||
"/user/vive_tracker_htcx/role/right_shoulder",
|
||||
"/user/vive_tracker_htcx/role/left_elbow",
|
||||
"/user/vive_tracker_htcx/role/right_elbow",
|
||||
"/user/vive_tracker_htcx/role/left_knee",
|
||||
"/user/vive_tracker_htcx/role/right_knee",
|
||||
"/user/vive_tracker_htcx/role/waist",
|
||||
"/user/vive_tracker_htcx/role/chest",
|
||||
"/user/vive_tracker_htcx/role/camera",
|
||||
"/user/vive_tracker_htcx/role/keyboard",
|
||||
}) {
|
||||
metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
|
||||
metadata->register_io_path(profile_path, "Menu click", user_path, user_path + "/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
metadata->register_io_path(profile_path, "Trigger click", user_path, user_path + "/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Squeeze click", user_path, user_path + "/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
metadata->register_io_path(profile_path, "Trackpad", user_path, user_path + "/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
|
||||
metadata->register_io_path(profile_path, "Trackpad click", user_path, user_path + "/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Trackpad touch", user_path, user_path + "/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Trackpad Dpad Up", user_path, user_path + "/input/trackpad/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Trackpad Dpad Down", user_path, user_path + "/input/trackpad/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Trackpad Dpad Left", user_path, user_path + "/input/trackpad/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Trackpad Dpad Right", user_path, user_path + "/input/trackpad/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Trackpad Dpad Center", user_path, user_path + "/input/trackpad/dpad_center", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool OpenXRHTCViveTrackerExtension::on_event_polled(const XrEventDataBuffer &event) {
|
||||
switch (event.type) {
|
||||
case XR_TYPE_EVENT_DATA_VIVE_TRACKER_CONNECTED_HTCX: {
|
||||
// Investigate if we need to do more here
|
||||
print_verbose("OpenXR EVENT: VIVE tracker connected");
|
||||
|
||||
return true;
|
||||
} break;
|
||||
default: {
|
||||
return false;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_htc_vive_tracker_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_HTC_VIVE_TRACKER_EXTENSION_H
|
||||
#define OPENXR_HTC_VIVE_TRACKER_EXTENSION_H
|
||||
|
||||
#include "openxr_extension_wrapper.h"
|
||||
|
||||
class OpenXRHTCViveTrackerExtension : public OpenXRExtensionWrapper {
|
||||
public:
|
||||
virtual HashMap<String, bool *> get_requested_extensions() override;
|
||||
|
||||
PackedStringArray get_suggested_tracker_names() override;
|
||||
|
||||
bool is_available();
|
||||
|
||||
virtual void on_register_metadata() override;
|
||||
virtual bool on_event_polled(const XrEventDataBuffer &event) override;
|
||||
|
||||
private:
|
||||
bool available = false;
|
||||
};
|
||||
|
||||
#endif // OPENXR_HTC_VIVE_TRACKER_EXTENSION_H
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_huawei_controller_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_huawei_controller_extension.h"
|
||||
|
||||
#include "../action_map/openxr_interaction_profile_metadata.h"
|
||||
|
||||
HashMap<String, bool *> OpenXRHuaweiControllerExtension::get_requested_extensions() {
|
||||
HashMap<String, bool *> request_extensions;
|
||||
|
||||
request_extensions[XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME] = &available;
|
||||
|
||||
return request_extensions;
|
||||
}
|
||||
|
||||
bool OpenXRHuaweiControllerExtension::is_available() {
|
||||
return available;
|
||||
}
|
||||
|
||||
void OpenXRHuaweiControllerExtension::on_register_metadata() {
|
||||
OpenXRInteractionProfileMetadata *metadata = OpenXRInteractionProfileMetadata::get_singleton();
|
||||
ERR_FAIL_NULL(metadata);
|
||||
|
||||
{ // 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(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(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(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, "Trackpad", user_path, user_path + "/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
|
||||
metadata->register_io_path(profile_path, "Trackpad click", user_path, user_path + "/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Trackpad touch", user_path, user_path + "/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Trackpad Dpad Up", user_path, user_path + "/input/trackpad/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Trackpad Dpad Down", user_path, user_path + "/input/trackpad/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Trackpad Dpad Left", user_path, user_path + "/input/trackpad/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Trackpad Dpad Right", user_path, user_path + "/input/trackpad/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Trackpad Dpad Center", user_path, user_path + "/input/trackpad/dpad_center", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_huawei_controller_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_HUAWEI_CONTROLLER_EXTENSION_H
|
||||
#define OPENXR_HUAWEI_CONTROLLER_EXTENSION_H
|
||||
|
||||
#include "openxr_extension_wrapper.h"
|
||||
|
||||
class OpenXRHuaweiControllerExtension : 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_HUAWEI_CONTROLLER_EXTENSION_H
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_local_floor_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_local_floor_extension.h"
|
||||
|
||||
OpenXRLocalFloorExtension *OpenXRLocalFloorExtension::singleton = nullptr;
|
||||
|
||||
OpenXRLocalFloorExtension *OpenXRLocalFloorExtension::get_singleton() {
|
||||
return singleton;
|
||||
}
|
||||
|
||||
OpenXRLocalFloorExtension::OpenXRLocalFloorExtension() {
|
||||
singleton = this;
|
||||
}
|
||||
|
||||
OpenXRLocalFloorExtension::~OpenXRLocalFloorExtension() {
|
||||
singleton = nullptr;
|
||||
}
|
||||
|
||||
HashMap<String, bool *> OpenXRLocalFloorExtension::get_requested_extensions() {
|
||||
HashMap<String, bool *> request_extensions;
|
||||
|
||||
request_extensions[XR_EXT_LOCAL_FLOOR_EXTENSION_NAME] = &available;
|
||||
|
||||
return request_extensions;
|
||||
}
|
||||
|
||||
bool OpenXRLocalFloorExtension::is_available() {
|
||||
return available;
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_local_floor_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_LOCAL_FLOOR_EXTENSION_H
|
||||
#define OPENXR_LOCAL_FLOOR_EXTENSION_H
|
||||
|
||||
#include "openxr_extension_wrapper.h"
|
||||
|
||||
class OpenXRLocalFloorExtension : public OpenXRExtensionWrapper {
|
||||
public:
|
||||
static OpenXRLocalFloorExtension *get_singleton();
|
||||
|
||||
OpenXRLocalFloorExtension();
|
||||
virtual ~OpenXRLocalFloorExtension() override;
|
||||
|
||||
virtual HashMap<String, bool *> get_requested_extensions() override;
|
||||
|
||||
bool is_available();
|
||||
|
||||
private:
|
||||
static OpenXRLocalFloorExtension *singleton;
|
||||
|
||||
bool available = false;
|
||||
};
|
||||
|
||||
#endif // OPENXR_LOCAL_FLOOR_EXTENSION_H
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_meta_controller_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_meta_controller_extension.h"
|
||||
|
||||
#include "../action_map/openxr_interaction_profile_metadata.h"
|
||||
|
||||
HashMap<String, bool *> OpenXRMetaControllerExtension::get_requested_extensions() {
|
||||
HashMap<String, bool *> request_extensions;
|
||||
|
||||
request_extensions[XR_FB_TOUCH_CONTROLLER_PROXIMITY_EXTENSION_NAME] = &available[META_TOUCH_PROXIMITY];
|
||||
request_extensions[XR_FB_TOUCH_CONTROLLER_PRO_EXTENSION_NAME] = &available[META_TOUCH_PRO];
|
||||
request_extensions[XR_META_TOUCH_CONTROLLER_PLUS_EXTENSION_NAME] = &available[META_TOUCH_PLUS];
|
||||
|
||||
return request_extensions;
|
||||
}
|
||||
|
||||
bool OpenXRMetaControllerExtension::is_available(MetaControllers p_type) {
|
||||
return available[p_type];
|
||||
}
|
||||
|
||||
void OpenXRMetaControllerExtension::on_register_metadata() {
|
||||
OpenXRInteractionProfileMetadata *metadata = OpenXRInteractionProfileMetadata::get_singleton();
|
||||
ERR_FAIL_NULL(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.
|
||||
const String profile_path = "/interaction_profiles/oculus/touch_controller";
|
||||
for (const String user_path : { "/user/hand/left", "/user/hand/right" }) {
|
||||
metadata->register_io_path(profile_path, "Trigger proximity", user_path, user_path + "/input/trigger/proximity_fb ", "XR_FB_touch_controller_proximity", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Thumb proximity", user_path, user_path + "/input/thumb_fb/proximity_fb ", "XR_FB_touch_controller_proximity", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
}
|
||||
}
|
||||
|
||||
{ // Touch controller pro (Quest Pro)
|
||||
const String profile_path = "/interaction_profiles/facebook/touch_controller_pro";
|
||||
metadata->register_interaction_profile("Touch controller pro", profile_path, "XR_FB_touch_controller_pro");
|
||||
for (const String user_path : { "/user/hand/left", "/user/hand/right" }) {
|
||||
metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
metadata->register_io_path(profile_path, "Palm pose", user_path, user_path + "/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
|
||||
|
||||
metadata->register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
metadata->register_io_path(profile_path, "Trigger touch", user_path, user_path + "/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Trigger proximity", user_path, user_path + "/input/trigger/proximity_fb", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Trigger curl", user_path, user_path + "/input/trigger/curl_fb", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
metadata->register_io_path(profile_path, "Trigger slide", user_path, user_path + "/input/trigger/slide_fb", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
metadata->register_io_path(profile_path, "Trigger force", user_path, user_path + "/input/trigger/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
|
||||
metadata->register_io_path(profile_path, "Squeeze", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
|
||||
metadata->register_io_path(profile_path, "Thumb proximity", user_path, user_path + "/input/thumb_fb/proximity_fb", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
metadata->register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
|
||||
metadata->register_io_path(profile_path, "Thumbstick X", user_path, user_path + "/input/thumbstick/x", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
metadata->register_io_path(profile_path, "Thumbstick Y", user_path, user_path + "/input/thumbstick/y", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
metadata->register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Thumbstick touch", user_path, user_path + "/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
metadata->register_io_path(profile_path, "Thumbrest touch", user_path, user_path + "/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Thumbrest force", user_path, user_path + "/input/thumbrest/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
|
||||
metadata->register_io_path(profile_path, "Stylus force", user_path, user_path + "/input/stylus_fb/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
|
||||
metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
|
||||
metadata->register_io_path(profile_path, "Haptic trigger output", user_path, user_path + "/output/haptic_trigger_fb", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
|
||||
metadata->register_io_path(profile_path, "Haptic thumb output", user_path, user_path + "/output/haptic_thumb_fb", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
|
||||
}
|
||||
|
||||
metadata->register_io_path(profile_path, "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
metadata->register_io_path(profile_path, "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
}
|
||||
|
||||
{ // Touch controller plus (Quest 3)
|
||||
const String profile_path = "/interaction_profiles/meta/touch_controller_plus";
|
||||
metadata->register_interaction_profile("Touch controller plus", profile_path, "XR_META_touch_controller_plus");
|
||||
for (const String user_path : { "/user/hand/left", "/user/hand/right" }) {
|
||||
metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
|
||||
metadata->register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
|
||||
|
||||
metadata->register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
metadata->register_io_path(profile_path, "Trigger touch", user_path, user_path + "/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Trigger proximity", user_path, user_path + "/input/trigger/proximity_meta", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Trigger curl", user_path, user_path + "/input/trigger/curl_meta", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
metadata->register_io_path(profile_path, "Trigger slide", user_path, user_path + "/input/trigger/slide_meta", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
metadata->register_io_path(profile_path, "Trigger force", user_path, user_path + "/input/trigger/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
|
||||
metadata->register_io_path(profile_path, "Squeeze", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
|
||||
metadata->register_io_path(profile_path, "Thumb proximity", user_path, user_path + "/input/thumb_meta/proximity_meta", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
metadata->register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
|
||||
metadata->register_io_path(profile_path, "Thumbstick X", user_path, user_path + "/input/thumbstick/x", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
metadata->register_io_path(profile_path, "Thumbstick Y", user_path, user_path + "/input/thumbstick/y", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
metadata->register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Thumbstick touch", user_path, user_path + "/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
metadata->register_io_path(profile_path, "Thumbrest touch", user_path, user_path + "/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
|
||||
}
|
||||
|
||||
metadata->register_io_path(profile_path, "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
metadata->register_io_path(profile_path, "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
metadata->register_io_path(profile_path, "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_meta_controller_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_META_CONTROLLER_EXTENSION_H
|
||||
#define OPENXR_META_CONTROLLER_EXTENSION_H
|
||||
|
||||
#include "openxr_extension_wrapper.h"
|
||||
|
||||
class OpenXRMetaControllerExtension : public OpenXRExtensionWrapper {
|
||||
public:
|
||||
enum MetaControllers {
|
||||
META_TOUCH_PROXIMITY, // Proximity extensions for normal touch controllers
|
||||
META_TOUCH_PRO, // Touch controller for the Quest Pro
|
||||
META_TOUCH_PLUS, // Touch controller for the Quest Plus
|
||||
META_MAX_CONTROLLERS
|
||||
};
|
||||
|
||||
virtual HashMap<String, bool *> get_requested_extensions() override;
|
||||
|
||||
bool is_available(MetaControllers p_type);
|
||||
|
||||
virtual void on_register_metadata() override;
|
||||
|
||||
private:
|
||||
bool available[META_MAX_CONTROLLERS] = { false, false, false };
|
||||
};
|
||||
|
||||
#endif // OPENXR_META_CONTROLLER_EXTENSION_H
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_ml2_controller_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_ml2_controller_extension.h"
|
||||
|
||||
#include "../action_map/openxr_interaction_profile_metadata.h"
|
||||
|
||||
HashMap<String, bool *> OpenXRML2ControllerExtension::get_requested_extensions() {
|
||||
HashMap<String, bool *> request_extensions;
|
||||
|
||||
request_extensions[XR_ML_ML2_CONTROLLER_INTERACTION_EXTENSION_NAME] = &available;
|
||||
|
||||
return request_extensions;
|
||||
}
|
||||
|
||||
bool OpenXRML2ControllerExtension::is_available() {
|
||||
return available;
|
||||
}
|
||||
|
||||
void OpenXRML2ControllerExtension::on_register_metadata() {
|
||||
OpenXRInteractionProfileMetadata *metadata = OpenXRInteractionProfileMetadata::get_singleton();
|
||||
ERR_FAIL_NULL(metadata);
|
||||
|
||||
// Magic Leap 2 Controller
|
||||
const String profile_path = "/interaction_profiles/ml/ml2_controller";
|
||||
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);
|
||||
|
||||
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, "Shoulder click", user_path, user_path + "/input/shoulder/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
|
||||
|
||||
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 force", user_path, user_path + "/input/trackpad/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_ml2_controller_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_ML2_CONTROLLER_EXTENSION_H
|
||||
#define OPENXR_ML2_CONTROLLER_EXTENSION_H
|
||||
|
||||
#include "openxr_extension_wrapper.h"
|
||||
|
||||
class OpenXRML2ControllerExtension : 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_ML2_CONTROLLER_EXTENSION_H
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue