diff options
51 files changed, 1130 insertions, 128 deletions
diff --git a/core/math/convex_hull.h b/core/math/convex_hull.h index bd86fe0eba..cc41a794bd 100644 --- a/core/math/convex_hull.h +++ b/core/math/convex_hull.h @@ -28,6 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifndef CONVEX_HULL_H +#define CONVEX_HULL_H + /* Copyright (c) 2011 Ole Kniemeyer, MAXON, www.maxon.net This software is provided 'as-is', without any express or implied warranty. @@ -40,9 +43,6 @@ subject to the following restrictions: 3. This notice may not be removed or altered from any source distribution. */ -#ifndef CONVEX_HULL_H -#define CONVEX_HULL_H - #include "core/math/geometry_3d.h" #include "core/math/vector3.h" #include "core/templates/local_vector.h" diff --git a/core/math/math_fieldwise.cpp b/core/math/math_fieldwise.cpp index f36b228543..726a2aeb97 100644 --- a/core/math/math_fieldwise.cpp +++ b/core/math/math_fieldwise.cpp @@ -56,6 +56,15 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const return target; } + case Variant::VECTOR2I: { + SETUP_TYPE(Vector2i) + + /**/ TRY_TRANSFER_FIELD("x", x) + else TRY_TRANSFER_FIELD("y", y) + + return target; + } + case Variant::RECT2: { SETUP_TYPE(Rect2) @@ -67,6 +76,17 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const return target; } + case Variant::RECT2I: { + SETUP_TYPE(Rect2i) + + /**/ TRY_TRANSFER_FIELD("x", position.x) + else TRY_TRANSFER_FIELD("y", position.y) + else TRY_TRANSFER_FIELD("w", size.x) + else TRY_TRANSFER_FIELD("h", size.y) + + return target; + } + case Variant::VECTOR3: { SETUP_TYPE(Vector3) @@ -192,6 +212,29 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const return target; } + case Variant::PROJECTION: { + SETUP_TYPE(Projection) + + /**/ TRY_TRANSFER_FIELD("xx", matrix[0].x) + else TRY_TRANSFER_FIELD("xy", matrix[0].y) + else TRY_TRANSFER_FIELD("xz", matrix[0].z) + else TRY_TRANSFER_FIELD("xw", matrix[0].w) + else TRY_TRANSFER_FIELD("yx", matrix[1].x) + else TRY_TRANSFER_FIELD("yy", matrix[1].y) + else TRY_TRANSFER_FIELD("yz", matrix[1].z) + else TRY_TRANSFER_FIELD("yw", matrix[1].w) + else TRY_TRANSFER_FIELD("zx", matrix[2].x) + else TRY_TRANSFER_FIELD("zy", matrix[2].y) + else TRY_TRANSFER_FIELD("zz", matrix[2].z) + else TRY_TRANSFER_FIELD("zw", matrix[2].w) + else TRY_TRANSFER_FIELD("xo", matrix[3].x) + else TRY_TRANSFER_FIELD("yo", matrix[3].y) + else TRY_TRANSFER_FIELD("zo", matrix[3].z) + else TRY_TRANSFER_FIELD("wo", matrix[3].w) + + return target; + } + default: { ERR_FAIL_V(p_target); } diff --git a/core/string/ustring.h b/core/string/ustring.h index b8ae3c2392..4b6568a502 100644 --- a/core/string/ustring.h +++ b/core/string/ustring.h @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -// Note: _GODOT suffix added to avoid conflict with ICU header with the same guard. - #ifndef USTRING_GODOT_H #define USTRING_GODOT_H +// Note: _GODOT suffix added to header guard to avoid conflict with ICU header. + #include "core/string/char_utils.h" #include "core/templates/cowdata.h" #include "core/templates/vector.h" diff --git a/core/templates/pooled_list.h b/core/templates/pooled_list.h index f13156b292..08f53572e7 100644 --- a/core/templates/pooled_list.h +++ b/core/templates/pooled_list.h @@ -28,7 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#pragma once +#ifndef POOLED_LIST_H +#define POOLED_LIST_H // Simple template to provide a pool with O(1) allocate and free. // The freelist could alternatively be a linked list placed within the unused elements @@ -206,3 +207,5 @@ private: LocalVector<U, U> _active_map; LocalVector<U, U> _active_list; }; + +#endif // POOLED_LIST_H diff --git a/editor/debugger/editor_debugger_tree.h b/editor/debugger/editor_debugger_tree.h index 5b2df8abd5..5af3a0d84a 100644 --- a/editor/debugger/editor_debugger_tree.h +++ b/editor/debugger/editor_debugger_tree.h @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "scene/gui/tree.h" - #ifndef EDITOR_DEBUGGER_TREE_H #define EDITOR_DEBUGGER_TREE_H +#include "scene/gui/tree.h" + class SceneDebuggerTree; class EditorFileDialog; diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp index 43961a7ceb..b0ea289bbe 100644 --- a/editor/dependency_editor.cpp +++ b/editor/dependency_editor.cpp @@ -286,7 +286,11 @@ void DependencyEditorOwners::_list_rmb_clicked(int p_item, const Vector2 &p_pos, file_options->clear(); file_options->reset_size(); if (p_item >= 0) { - file_options->add_item(TTR("Open"), FILE_OPEN); + if (owners->get_selected_items().size() == 1) { + file_options->add_icon_item(get_theme_icon(SNAME("Load"), SNAME("EditorIcons")), TTR("Open Scene"), FILE_OPEN); + } else { + file_options->add_icon_item(get_theme_icon(SNAME("Load"), SNAME("EditorIcons")), TTR("Open Scenes"), FILE_OPEN); + } } file_options->set_position(owners->get_screen_position() + p_pos); @@ -307,11 +311,14 @@ void DependencyEditorOwners::_select_file(int p_idx) { void DependencyEditorOwners::_file_option(int p_option) { switch (p_option) { case FILE_OPEN: { - int idx = owners->get_current(); - if (idx < 0 || idx >= owners->get_item_count()) { - break; + PackedInt32Array selected_items = owners->get_selected_items(); + for (int i = 0; i < selected_items.size(); i++) { + int item_idx = selected_items[i]; + if (item_idx < 0 || item_idx >= owners->get_item_count()) { + break; + } + _select_file(item_idx); } - _select_file(idx); } break; } } @@ -362,7 +369,7 @@ DependencyEditorOwners::DependencyEditorOwners() { file_options->connect("id_pressed", callable_mp(this, &DependencyEditorOwners::_file_option)); owners = memnew(ItemList); - owners->set_select_mode(ItemList::SELECT_SINGLE); + owners->set_select_mode(ItemList::SELECT_MULTI); owners->connect("item_clicked", callable_mp(this, &DependencyEditorOwners::_list_rmb_clicked)); owners->connect("item_activated", callable_mp(this, &DependencyEditorOwners::_select_file)); owners->set_allow_rmb_select(true); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 3679657567..18561fe3a0 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -3362,10 +3362,12 @@ void ScriptEditor::_update_selected_editor_menu() { script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_previous", TTR("Find Previous"), KeyModifierMask::SHIFT | Key::F3), HELP_SEARCH_FIND_PREVIOUS); script_search_menu->get_popup()->add_separator(); script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_in_files", TTR("Find in Files"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::F), SEARCH_IN_FILES); + script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/replace_in_files", TTR("Replace in Files"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::R), REPLACE_IN_FILES); script_search_menu->show(); } else { if (tab_container->get_tab_count() == 0) { script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_in_files", TTR("Find in Files"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::F), SEARCH_IN_FILES); + script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/replace_in_files", TTR("Replace in Files"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::R), REPLACE_IN_FILES); script_search_menu->show(); } else { script_search_menu->hide(); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 7a57f8a1e2..aef84919d2 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -1965,6 +1965,7 @@ void ScriptTextEditor::_enable_code_editor() { search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace"), SEARCH_REPLACE); search_menu->get_popup()->add_separator(); search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_in_files"), SEARCH_IN_FILES); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace_in_files"), REPLACE_IN_FILES); search_menu->get_popup()->add_separator(); search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/contextual_help"), HELP_CONTEXTUAL); search_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option)); @@ -2013,7 +2014,6 @@ void ScriptTextEditor::_enable_code_editor() { _load_theme_settings(); - search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace_in_files"), REPLACE_IN_FILES); edit_hb->add_child(goto_menu); goto_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_function"), SEARCH_LOCATE_FUNCTION); goto_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_line"), SEARCH_GOTO_LINE); diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index 0b1e9719b7..7bcc8aa078 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -1437,6 +1437,9 @@ void SceneTreeDialog::_notification(int p_what) { case NOTIFICATION_VISIBILITY_CHANGED: { if (is_visible()) { tree->update_tree(); + + // Select the search bar by default. + filter->call_deferred(SNAME("grab_focus")); } } break; diff --git a/misc/scripts/header_guards.sh b/misc/scripts/header_guards.sh index 9a830f3ad2..9fdc864f8c 100755 --- a/misc/scripts/header_guards.sh +++ b/misc/scripts/header_guards.sh @@ -5,11 +5,15 @@ if [ ! -f "version.py" ]; then echo "Some of the paths checks may not work as intended from a different folder." fi +files_invalid_guard="" + for file in $(find -name "thirdparty" -prune -o -name "*.h" -print); do # Skip *.gen.h and *-so_wrap.h, they're generated. if [[ "$file" == *".gen.h" || "$file" == *"-so_wrap.h" ]]; then continue; fi # Has important define before normal header guards. if [[ "$file" == *"thread.h" || "$file" == *"platform_config.h" ]]; then continue; fi + # Obj-C files don't use header guards. + if grep -q "#import " "$file"; then continue; fi bname=$(basename $file .h) @@ -43,8 +47,21 @@ for file in $(find -name "thirdparty" -prune -o -name "*.h" -print); do sed -i $file -e "$ s/#endif.*/\n#endif \/\/ $guard/" # Removes redundant \n added before, if they weren't needed. sed -i $file -e "/^$/N;/^\n$/D" + + # Check that first ifndef (should be header guard) is at the expected position. + # If not it can mean we have some code before the guard that should be after. + # "31" is the expected line with the copyright header. + first_ifndef=$(grep -n -m 1 "ifndef" $file | sed 's/\([0-9]*\).*/\1/') + if [[ "$first_ifndef" != "31" ]]; then + files_invalid_guard+="$file\n" + fi done +if [[ ! -z "$files_invalid_guard" ]]; then + echo -e "The following files were found to have potentially invalid header guard:\n" + echo -e "$files_invalid_guard" +fi + diff=$(git diff --color) # If no diff has been generated all is OK, clean up, and exit. diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 00e8223b9a..fd418ced47 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -2041,7 +2041,7 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ codegen.generator->write_newline(field->initializer->start_line); // For typed arrays we need to make sure this is already initialized correctly so typed assignment work. - if (field_type.is_hard_type() && field_type.builtin_type == Variant::ARRAY && field_type.has_container_element_type()) { + if (field_type.is_hard_type() && field_type.builtin_type == Variant::ARRAY) { if (field_type.has_container_element_type()) { codegen.generator->write_construct_typed_array(dst_address, _gdtype_from_datatype(field_type.get_container_element_type(), codegen.script), Vector<GDScriptCodeGenerator::Address>()); } else { diff --git a/modules/gltf/register_types.h b/modules/gltf/register_types.h index 90b9a83c88..bf2730d2ef 100644 --- a/modules/gltf/register_types.h +++ b/modules/gltf/register_types.h @@ -28,7 +28,12 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifndef GLTF_REGISTER_TYPES_H +#define GLTF_REGISTER_TYPES_H + #include "modules/register_module_types.h" void initialize_gltf_module(ModuleInitializationLevel p_level); void uninitialize_gltf_module(ModuleInitializationLevel p_level); + +#endif // GLTF_REGISTER_TYPES_H diff --git a/modules/mono/utils/macos_utils.h b/modules/mono/utils/macos_utils.h index ca4957f5a7..0b74114685 100644 --- a/modules/mono/utils/macos_utils.h +++ b/modules/mono/utils/macos_utils.h @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "core/string/ustring.h" - #ifndef MONO_MACOS_UTILS_H #define MONO_MACOS_UTILS_H #ifdef MACOS_ENABLED +#include "core/string/ustring.h" + bool macos_is_app_bundle_installed(const String &p_bundle_id); #endif diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub index 298977f96d..11cc525484 100644 --- a/modules/openxr/SCsub +++ b/modules/openxr/SCsub @@ -83,6 +83,7 @@ module_obj = [] env_openxr.add_source_files(module_obj, "*.cpp") env_openxr.add_source_files(module_obj, "action_map/*.cpp") +env_openxr.add_source_files(module_obj, "scene/*.cpp") # We're a little more targeted with our extensions if env["platform"] == "android": @@ -91,6 +92,7 @@ if env["vulkan"]: env_openxr.add_source_files(module_obj, "extensions/openxr_vulkan_extension.cpp") env_openxr.add_source_files(module_obj, "extensions/openxr_htc_vive_tracker_extension.cpp") +env_openxr.add_source_files(module_obj, "extensions/openxr_hand_tracking_extension.cpp") env.modules_sources += module_obj diff --git a/modules/openxr/config.py b/modules/openxr/config.py index 650146fdd3..279168cc59 100644 --- a/modules/openxr/config.py +++ b/modules/openxr/config.py @@ -18,6 +18,7 @@ def get_doc_classes(): "OpenXRActionMap", "OpenXRInteractionProfile", "OpenXRIPBinding", + "OpenXRHand", ] diff --git a/modules/openxr/doc_classes/OpenXRHand.xml b/modules/openxr/doc_classes/OpenXRHand.xml new file mode 100644 index 0000000000..5d5f8a6126 --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRHand.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="OpenXRHand" inherits="Node3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> + <brief_description> + Node supporting 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 where the player's actual hand is positioned. This node also updates the skeleton of a properly skinned hand model. The hand mesh should be a child node of this node. + </description> + <tutorials> + </tutorials> + <members> + <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> + </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> + </constants> +</class> diff --git a/modules/openxr/extensions/openxr_hand_tracking_extension.cpp b/modules/openxr/extensions/openxr_hand_tracking_extension.cpp new file mode 100644 index 0000000000..4b30965ce5 --- /dev/null +++ b/modules/openxr/extensions/openxr_hand_tracking_extension.cpp @@ -0,0 +1,268 @@ +/*************************************************************************/ +/* openxr_hand_tracking_extension.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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/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(OpenXRAPI *p_openxr_api) : + OpenXRExtensionWrapper(p_openxr_api) { + singleton = this; + + // Extensions we use for our hand tracking. + request_extensions[XR_EXT_HAND_TRACKING_EXTENSION_NAME] = &hand_tracking_ext; + request_extensions[XR_EXT_HAND_JOINTS_MOTION_RANGE_EXTENSION_NAME] = &hand_motion_range_ext; + request_extensions[XR_FB_HAND_TRACKING_AIM_EXTENSION_NAME] = &hand_tracking_aim_state_ext; + + // Make sure this is cleared until we actually request it + handTrackingSystemProperties.supportsHandTracking = false; +} + +OpenXRHandTrackingExtension::~OpenXRHandTrackingExtension() { + singleton = nullptr; +} + +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 < MAX_OPENXR_TRACKED_HANDS; i++) { + // we'll do this later + hand_trackers[i].is_initialised = false; + hand_trackers[i].hand_tracker = XR_NULL_HANDLE; + + hand_trackers[i].aimState.aimPose = { { 0.0, 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 } }; + hand_trackers[i].aimState.pinchStrengthIndex = 0.0; + hand_trackers[i].aimState.pinchStrengthMiddle = 0.0; + hand_trackers[i].aimState.pinchStrengthRing = 0.0; + hand_trackers[i].aimState.pinchStrengthLittle = 0.0; + + 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 = openxr_api->get_next_frame_time(); // This data will be used for the next frame we render + + XrResult result; + + for (int i = 0; i < MAX_OPENXR_TRACKED_HANDS; i++) { + if (hand_trackers[i].hand_tracker == XR_NULL_HANDLE) { + XrHandTrackerCreateInfoEXT createInfo = { + XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT, // type + nullptr, // next + i == 0 ? XR_HAND_LEFT_EXT : XR_HAND_RIGHT_EXT, // hand + XR_HAND_JOINT_SET_DEFAULT_EXT, // handJointSet + }; + + result = xrCreateHandTrackerEXT(openxr_api->get_session(), &createInfo, &hand_trackers[i].hand_tracker); + if (XR_FAILED(result)) { + // not successful? then we do nothing. + print_line("OpenXR: Failed to obtain hand tracking information [", openxr_api->get_error_string(result), "]"); + hand_trackers[i].is_initialised = false; + } else { + void *next_pointer = nullptr; + if (hand_tracking_aim_state_ext) { + hand_trackers[i].aimState.type = XR_TYPE_HAND_TRACKING_AIM_STATE_FB; + hand_trackers[i].aimState.next = next_pointer; + hand_trackers[i].aimState.status = 0; + hand_trackers[i].aimState.aimPose = { { 0.0, 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 } }; + hand_trackers[i].aimState.pinchStrengthIndex = 0.0; + hand_trackers[i].aimState.pinchStrengthMiddle = 0.0; + hand_trackers[i].aimState.pinchStrengthRing = 0.0; + hand_trackers[i].aimState.pinchStrengthLittle = 0.0; + + next_pointer = &hand_trackers[i].aimState; + } + + 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; + + 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; + + hand_trackers[i].is_initialised = true; + } + } + + if (hand_trackers[i].is_initialised) { + void *next_pointer = nullptr; + + XrHandJointsMotionRangeInfoEXT motionRangeInfo; + + if (hand_motion_range_ext) { + motionRangeInfo.type = XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT; + motionRangeInfo.next = next_pointer; + motionRangeInfo.handJointsMotionRange = hand_trackers[i].motion_range; + + next_pointer = &motionRangeInfo; + } + + XrHandJointsLocateInfoEXT locateInfo = { + XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT, // type + next_pointer, // next + openxr_api->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, "[", openxr_api->get_error_string(result), "]"); + 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 + } + + /* TODO change this to managing the controller from openxr_interface + if (hand_tracking_aim_state_ext && hand_trackers[i].locations.isActive && check_bit(XR_HAND_TRACKING_AIM_VALID_BIT_FB, hand_trackers[i].aimState.status)) { + // Controllers are updated based on the aim state's pose and pinches' strength + if (hand_trackers[i].aim_state_godot_controller == -1) { + hand_trackers[i].aim_state_godot_controller = + arvr_api->godot_arvr_add_controller( + const_cast<char *>(hand_controller_names[i]), + i + HAND_CONTROLLER_ID_OFFSET, + true, + true); + } + } + */ + } + } +} + +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 < MAX_OPENXR_TRACKED_HANDS; i++) { + if (hand_trackers[i].hand_tracker != XR_NULL_HANDLE) { + xrDestroyHandTrackerEXT(hand_trackers[i].hand_tracker); + + hand_trackers[i].is_initialised = false; + hand_trackers[i].hand_tracker = XR_NULL_HANDLE; + } + } +} + +bool OpenXRHandTrackingExtension::get_active() { + return handTrackingSystemProperties.supportsHandTracking; +} + +const OpenXRHandTrackingExtension::HandTracker *OpenXRHandTrackingExtension::get_hand_tracker(uint32_t p_hand) const { + ERR_FAIL_UNSIGNED_INDEX_V(p_hand, MAX_OPENXR_TRACKED_HANDS, nullptr); + + return &hand_trackers[p_hand]; +} + +XrHandJointsMotionRangeEXT OpenXRHandTrackingExtension::get_motion_range(uint32_t p_hand) const { + ERR_FAIL_UNSIGNED_INDEX_V(p_hand, MAX_OPENXR_TRACKED_HANDS, XR_HAND_JOINTS_MOTION_RANGE_MAX_ENUM_EXT); + + return hand_trackers[p_hand].motion_range; +} + +void OpenXRHandTrackingExtension::set_motion_range(uint32_t p_hand, XrHandJointsMotionRangeEXT p_motion_range) { + ERR_FAIL_UNSIGNED_INDEX(p_hand, MAX_OPENXR_TRACKED_HANDS); + hand_trackers[p_hand].motion_range = p_motion_range; +} diff --git a/modules/openxr/extensions/openxr_hand_tracking_extension.h b/modules/openxr/extensions/openxr_hand_tracking_extension.h new file mode 100644 index 0000000000..f8c26339b0 --- /dev/null +++ b/modules/openxr/extensions/openxr_hand_tracking_extension.h @@ -0,0 +1,96 @@ +/*************************************************************************/ +/* openxr_hand_tracking_extension.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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 "openxr_extension_wrapper.h" + +#include "../util.h" + +#define MAX_OPENXR_TRACKED_HANDS 2 + +class OpenXRHandTrackingExtension : public OpenXRExtensionWrapper { +public: + struct HandTracker { + bool is_initialised = false; + XrHandJointsMotionRangeEXT motion_range = XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT; + + XrHandTrackerEXT hand_tracker = XR_NULL_HANDLE; + XrHandJointLocationEXT joint_locations[XR_HAND_JOINT_COUNT_EXT]; + XrHandJointVelocityEXT joint_velocities[XR_HAND_JOINT_COUNT_EXT]; + + XrHandTrackingAimStateFB aimState; + XrHandJointVelocitiesEXT velocities; + XrHandJointLocationsEXT locations; + }; + + static OpenXRHandTrackingExtension *get_singleton(); + + OpenXRHandTrackingExtension(OpenXRAPI *p_openxr_api); + virtual ~OpenXRHandTrackingExtension() 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(uint32_t p_hand) const; + + XrHandJointsMotionRangeEXT get_motion_range(uint32_t p_hand) const; + void set_motion_range(uint32_t p_hand, XrHandJointsMotionRangeEXT p_motion_range); + +private: + static OpenXRHandTrackingExtension *singleton; + + // state + XrSystemHandTrackingPropertiesEXT handTrackingSystemProperties; + HandTracker hand_trackers[MAX_OPENXR_TRACKED_HANDS]; // Fixed for left and right hand + + // related extensions + bool hand_tracking_ext = false; + bool hand_motion_range_ext = false; + bool hand_tracking_aim_state_ext = 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 diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index 76f7b2a60a..08b76ddc6b 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -49,6 +49,7 @@ #include "extensions/openxr_vulkan_extension.h" #endif +#include "extensions/openxr_hand_tracking_extension.h" #include "extensions/openxr_htc_vive_tracker_extension.h" #include "modules/openxr/openxr_interface.h" @@ -1742,6 +1743,7 @@ OpenXRAPI::OpenXRAPI() { // register our other extensions register_extension_wrapper(memnew(OpenXRHTCViveTrackerExtension(this))); + register_extension_wrapper(memnew(OpenXRHandTrackingExtension(this))); } OpenXRAPI::~OpenXRAPI() { diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h index 4f84cc3b5b..fd32c2633e 100644 --- a/modules/openxr/openxr_api.h +++ b/modules/openxr/openxr_api.h @@ -102,7 +102,7 @@ private: XrFormFactor form_factor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY; XrViewConfigurationType view_configuration = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO; XrReferenceSpaceType reference_space = XR_REFERENCE_SPACE_TYPE_STAGE; - XrEnvironmentBlendMode environment_blend_mode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE; + // XrEnvironmentBlendMode environment_blend_mode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE; // state XrInstance instance = XR_NULL_HANDLE; @@ -139,7 +139,10 @@ private: bool openxr_loader_init(); bool resolve_instance_openxr_symbols(); +#ifdef ANDROID_ENABLED + // On Android we keep tracker of our external OpenXR loader void *openxr_loader_library_handle = nullptr; +#endif // function pointers #ifdef ANDROID_ENABLED @@ -269,9 +272,7 @@ private: // convencience void copy_string_to_char_buffer(const String p_string, char *p_buffer, int p_buffer_len); -protected: - friend class OpenXRVulkanExtension; - +public: XrInstance get_instance() const { return instance; }; XrSystemId get_system_id() const { return system_id; }; XrSession get_session() const { return session; }; @@ -284,7 +285,6 @@ protected: XRPose::TrackingConfidence transform_from_location(const XrHandJointLocationEXT &p_location, Transform3D &r_transform); void parse_velocities(const XrSpaceVelocity &p_velocity, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity); -public: static bool openxr_is_enabled(bool p_check_run_in_editor = true); static OpenXRAPI *get_singleton(); @@ -301,8 +301,9 @@ public: bool initialize_session(); void finish(); - XrTime get_next_frame_time() { return frame_state.predictedDisplayTime + frame_state.predictedDisplayPeriod; }; - bool can_render() { return instance != XR_NULL_HANDLE && session != XR_NULL_HANDLE && running && view_pose_valid && frame_state.shouldRender; }; + XrSpace get_play_space() const { return play_space; } + XrTime get_next_frame_time() { return frame_state.predictedDisplayTime + frame_state.predictedDisplayPeriod; } + bool can_render() { return instance != XR_NULL_HANDLE && session != XR_NULL_HANDLE && running && view_pose_valid && frame_state.shouldRender; } Size2 get_recommended_target_size(); XRPose::TrackingConfidence get_head_center(Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity); diff --git a/modules/openxr/register_types.cpp b/modules/openxr/register_types.cpp index c765f169dc..5694fffe39 100644 --- a/modules/openxr/register_types.cpp +++ b/modules/openxr/register_types.cpp @@ -38,6 +38,8 @@ #include "action_map/openxr_action_set.h" #include "action_map/openxr_interaction_profile.h" +#include "scene/openxr_hand.h" + #ifdef TOOLS_ENABLED #include "editor/editor_node.h" @@ -82,6 +84,8 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) { GDREGISTER_CLASS(OpenXRIPBinding); GDREGISTER_CLASS(OpenXRInteractionProfile); + GDREGISTER_CLASS(OpenXRHand); + XRServer *xr_server = XRServer::get_singleton(); if (xr_server) { openxr_interface.instantiate(); diff --git a/modules/openxr/scene/openxr_hand.cpp b/modules/openxr/scene/openxr_hand.cpp new file mode 100644 index 0000000000..2ae13a1026 --- /dev/null +++ b/modules/openxr/scene/openxr_hand.cpp @@ -0,0 +1,307 @@ +/*************************************************************************/ +/* openxr_hand.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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 "../extensions/openxr_hand_tracking_extension.h" +#include "../openxr_api.h" + +#include "openxr_hand.h" +#include "scene/3d/skeleton_3d.h" +#include "servers/xr_server.h" + +void OpenXRHand::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_hand", "hand"), &OpenXRHand::set_hand); + ClassDB::bind_method(D_METHOD("get_hand"), &OpenXRHand::get_hand); + + ClassDB::bind_method(D_METHOD("set_hand_skeleton", "hand_skeleton"), &OpenXRHand::set_hand_skeleton); + ClassDB::bind_method(D_METHOD("get_hand_skeleton"), &OpenXRHand::get_hand_skeleton); + + ClassDB::bind_method(D_METHOD("set_motion_range", "motion_range"), &OpenXRHand::set_motion_range); + ClassDB::bind_method(D_METHOD("get_motion_range"), &OpenXRHand::get_motion_range); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "hand", PROPERTY_HINT_ENUM, "Left,Right"), "set_hand", "get_hand"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "motion_range", PROPERTY_HINT_ENUM, "Unobstructed,Conform to controller"), "set_motion_range", "get_motion_range"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "hand_skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton3D"), "set_hand_skeleton", "get_hand_skeleton"); + + BIND_ENUM_CONSTANT(HAND_LEFT); + BIND_ENUM_CONSTANT(HAND_RIGHT); + BIND_ENUM_CONSTANT(HAND_MAX); + + BIND_ENUM_CONSTANT(MOTION_RANGE_UNOBSTRUCTED); + BIND_ENUM_CONSTANT(MOTION_RANGE_CONFORM_TO_CONTROLLER); + BIND_ENUM_CONSTANT(MOTION_RANGE_MAX); +} + +OpenXRHand::OpenXRHand() { + openxr_api = OpenXRAPI::get_singleton(); + hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton(); +} + +void OpenXRHand::set_hand(const Hands p_hand) { + ERR_FAIL_INDEX(p_hand, HAND_MAX); + + hand = p_hand; +} + +OpenXRHand::Hands OpenXRHand::get_hand() const { + return hand; +} + +void OpenXRHand::set_hand_skeleton(const NodePath &p_hand_skeleton) { + hand_skeleton = p_hand_skeleton; + + // TODO if inside tree call _get_bones() +} + +void OpenXRHand::set_motion_range(const MotionRange p_motion_range) { + ERR_FAIL_INDEX(p_motion_range, MOTION_RANGE_MAX); + motion_range = p_motion_range; + + _set_motion_range(); +} + +OpenXRHand::MotionRange OpenXRHand::get_motion_range() const { + return motion_range; +} + +NodePath OpenXRHand::get_hand_skeleton() const { + return hand_skeleton; +} + +void OpenXRHand::_set_motion_range() { + if (!hand_tracking_ext) { + return; + } + + XrHandJointsMotionRangeEXT xr_motion_range; + switch (motion_range) { + case MOTION_RANGE_UNOBSTRUCTED: + xr_motion_range = XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT; + break; + case MOTION_RANGE_CONFORM_TO_CONTROLLER: + xr_motion_range = XR_HAND_JOINTS_MOTION_RANGE_CONFORMING_TO_CONTROLLER_EXT; + break; + default: + xr_motion_range = XR_HAND_JOINTS_MOTION_RANGE_CONFORMING_TO_CONTROLLER_EXT; + break; + } + + hand_tracking_ext->set_motion_range(hand, xr_motion_range); +} + +Skeleton3D *OpenXRHand::get_skeleton() { + if (!has_node(hand_skeleton)) { + return nullptr; + } + + Node *node = get_node(hand_skeleton); + if (!node) { + return nullptr; + } + + Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(node); + return skeleton; +} + +void OpenXRHand::_get_bones() { + const char *bone_names[XR_HAND_JOINT_COUNT_EXT] = { + "Palm", + "Wrist", + "Thumb_Metacarpal", + "Thumb_Proximal", + "Thumb_Distal", + "Thumb_Tip", + "Index_Metacarpal", + "Index_Proximal", + "Index_Intermediate", + "Index_Distal", + "Index_Tip", + "Middle_Metacarpal", + "Middle_Proximal", + "Middle_Intermediate", + "Middle_Distal", + "Middle_Tip", + "Ring_Metacarpal", + "Ring_Proximal", + "Ring_Intermediate", + "Ring_Distal", + "Ring_Tip", + "Little_Metacarpal", + "Little_Proximal", + "Little_Intermediate", + "Little_Distal", + "Little_Tip", + }; + + // reset JIC + for (int i = 0; i < XR_HAND_JOINT_COUNT_EXT; i++) { + bones[i] = -1; + } + + Skeleton3D *skeleton = get_skeleton(); + if (!skeleton) { + return; + } + + // We cast to spatials which should allow us to use any subclass of that. + for (int i = 0; i < XR_HAND_JOINT_COUNT_EXT; i++) { + String bone_name = bone_names[i]; + if (hand == 0) { + bone_name += String("_L"); + } else { + bone_name += String("_R"); + } + + bones[i] = skeleton->find_bone(bone_name); + if (bones[i] == -1) { + print_line("Couldn't obtain bone for", bone_name); + } + } +} + +void OpenXRHand::_update_skeleton() { + if (openxr_api == nullptr || !openxr_api->is_initialized()) { + return; + } else if (hand_tracking_ext == nullptr || !hand_tracking_ext->get_active()) { + return; + } + + Skeleton3D *skeleton = get_skeleton(); + if (!skeleton) { + return; + } + + // we cache our transforms so we can quickly calculate local transforms + XRPose::TrackingConfidence confidences[XR_HAND_JOINT_COUNT_EXT]; + Quaternion quaternions[XR_HAND_JOINT_COUNT_EXT]; + Quaternion inv_quaternions[XR_HAND_JOINT_COUNT_EXT]; + Vector3 positions[XR_HAND_JOINT_COUNT_EXT]; + + const OpenXRHandTrackingExtension::HandTracker *hand_tracker = hand_tracking_ext->get_hand_tracker(hand); + const float ws = XRServer::get_singleton()->get_world_scale(); + + if (hand_tracker->is_initialised && hand_tracker->locations.isActive) { + for (int i = 0; i < XR_HAND_JOINT_COUNT_EXT; i++) { + confidences[i] = XRPose::XR_TRACKING_CONFIDENCE_NONE; + quaternions[i] = Quaternion(); + positions[i] = Vector3(); + + const auto &location = hand_tracker->joint_locations[i]; + const auto &pose = location.pose; + + if (location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) { + if (pose.orientation.x != 0 || pose.orientation.y != 0 || pose.orientation.y != 0 || pose.orientation.w != 0) { + quaternions[i] = Quaternion(pose.orientation.x, pose.orientation.y, pose.orientation.z, pose.orientation.w); + inv_quaternions[i] = quaternions[i].inverse(); + + if (location.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) { + confidences[i] = XRPose::XR_TRACKING_CONFIDENCE_HIGH; + positions[i] = Vector3(pose.position.x * ws, pose.position.y * ws, pose.position.z * ws); + + // TODO get inverse of position, we'll do this later. For now we're ignoring bone positions which generally works better anyway + } else { + confidences[i] = XRPose::XR_TRACKING_CONFIDENCE_LOW; + } + } + } + } + + if (confidences[XR_HAND_JOINT_PALM_EXT] != XRPose::XR_TRACKING_CONFIDENCE_NONE) { + // now update our skeleton + for (int i = 0; i < XR_HAND_JOINT_COUNT_EXT; i++) { + if (bones[i] != -1) { + int bone = bones[i]; + int parent = skeleton->get_bone_parent(bone); + + // Get our target quaternion + Quaternion q = quaternions[i]; + + // get local translation, parent should already be processed + if (parent == -1) { + // use our palm location here, that is what we are tracking + q = inv_quaternions[XR_HAND_JOINT_PALM_EXT] * q; + } else { + int found = false; + for (int b = 0; b < XR_HAND_JOINT_COUNT_EXT && !found; b++) { + if (bones[b] == parent) { + q = inv_quaternions[b] * q; + found = true; + } + } + } + + // And get the movement from our rest position + // Transform3D rest = skeleton->get_bone_rest(bones[i]); + // q = rest.basis.get_quaternion().inverse() * q; + + // and set our pose + // skeleton->set_bone_pose_position(bones[i], v); + skeleton->set_bone_pose_rotation(bones[i], q); + } + } + + Transform3D t; + t.basis = Basis(quaternions[XR_HAND_JOINT_PALM_EXT]); + t.origin = positions[XR_HAND_JOINT_PALM_EXT]; + set_transform(t); + + // show it + set_visible(true); + } else { + // hide it + set_visible(false); + } + } else { + // hide it + set_visible(false); + } +} + +void OpenXRHand::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + _get_bones(); + + set_process_internal(true); + } break; + case NOTIFICATION_EXIT_TREE: { + set_process_internal(false); + + // reset + for (int i = 0; i < XR_HAND_JOINT_COUNT_EXT; i++) { + bones[i] = -1; + } + } break; + case NOTIFICATION_INTERNAL_PROCESS: { + _update_skeleton(); + } break; + default: { + } break; + } +} diff --git a/modules/openxr/scene/openxr_hand.h b/modules/openxr/scene/openxr_hand.h new file mode 100644 index 0000000000..f8499cc172 --- /dev/null +++ b/modules/openxr/scene/openxr_hand.h @@ -0,0 +1,93 @@ +/*************************************************************************/ +/* openxr_hand.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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_H +#define OPENXR_HAND_H + +#include "scene/3d/node_3d.h" +#include "scene/3d/skeleton_3d.h" + +class OpenXRAPI; +class OpenXRHandTrackingExtension; + +class OpenXRHand : public Node3D { + GDCLASS(OpenXRHand, Node3D); + +public: + enum Hands { + HAND_LEFT, + HAND_RIGHT, + HAND_MAX + }; + + enum MotionRange { + MOTION_RANGE_UNOBSTRUCTED, + MOTION_RANGE_CONFORM_TO_CONTROLLER, + MOTION_RANGE_MAX + }; + +private: + OpenXRAPI *openxr_api = nullptr; + OpenXRHandTrackingExtension *hand_tracking_ext = nullptr; + + Hands hand = HAND_LEFT; + MotionRange motion_range = MOTION_RANGE_UNOBSTRUCTED; + NodePath hand_skeleton; + + int64_t bones[XR_HAND_JOINT_COUNT_EXT]; + + void _set_motion_range(); + + Skeleton3D *get_skeleton(); + void _get_bones(); + void _update_skeleton(); + +protected: + static void _bind_methods(); + +public: + OpenXRHand(); + + void set_hand(const Hands p_hand); + Hands get_hand() const; + + void set_motion_range(const MotionRange p_motion_range); + MotionRange get_motion_range() const; + + void set_hand_skeleton(const NodePath &p_hand_skeleton); + NodePath get_hand_skeleton() const; + + void _notification(int p_what); +}; + +VARIANT_ENUM_CAST(OpenXRHand::Hands) +VARIANT_ENUM_CAST(OpenXRHand::MotionRange) + +#endif // OPENXR_HAND_H diff --git a/modules/raycast/lightmap_raycaster.cpp b/modules/raycast/lightmap_raycaster_embree.cpp index 9b35b5616e..e6a579bd3a 100644 --- a/modules/raycast/lightmap_raycaster.cpp +++ b/modules/raycast/lightmap_raycaster_embree.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* lightmap_raycaster.cpp */ +/* lightmap_raycaster_embree.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -30,7 +30,7 @@ #ifdef TOOLS_ENABLED -#include "lightmap_raycaster.h" +#include "lightmap_raycaster_embree.h" #ifdef __SSE2__ #include <pmmintrin.h> @@ -193,4 +193,4 @@ LightmapRaycasterEmbree::~LightmapRaycasterEmbree() { } } -#endif +#endif // TOOLS_ENABLED diff --git a/modules/raycast/lightmap_raycaster.h b/modules/raycast/lightmap_raycaster_embree.h index 2e9f59dda4..0c3371f07c 100644 --- a/modules/raycast/lightmap_raycaster.h +++ b/modules/raycast/lightmap_raycaster_embree.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* lightmap_raycaster.h */ +/* lightmap_raycaster_embree.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,6 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifndef LIGHTMAP_RAYCASTER_EMBREE_H +#define LIGHTMAP_RAYCASTER_EMBREE_H + #ifdef TOOLS_ENABLED #include "core/io/image.h" @@ -74,4 +77,6 @@ public: ~LightmapRaycasterEmbree(); }; -#endif // LIGHTMAP_RAYCASTER_H +#endif // TOOLS_ENABLED + +#endif // LIGHTMAP_RAYCASTER_EMBREE_H diff --git a/modules/raycast/register_types.cpp b/modules/raycast/register_types.cpp index 42de1d971d..a8380b00ba 100644 --- a/modules/raycast/register_types.cpp +++ b/modules/raycast/register_types.cpp @@ -30,9 +30,9 @@ #include "register_types.h" -#include "lightmap_raycaster.h" +#include "lightmap_raycaster_embree.h" #include "raycast_occlusion_cull.h" -#include "static_raycaster.h" +#include "static_raycaster_embree.h" RaycastOcclusionCull *raycast_occlusion_cull = nullptr; diff --git a/modules/raycast/register_types.h b/modules/raycast/register_types.h index a917285390..25a6c346b9 100644 --- a/modules/raycast/register_types.h +++ b/modules/raycast/register_types.h @@ -28,7 +28,12 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifndef RAYCAST_REGISTER_TYPES_H +#define RAYCAST_REGISTER_TYPES_H + #include "modules/register_module_types.h" void initialize_raycast_module(ModuleInitializationLevel p_level); void uninitialize_raycast_module(ModuleInitializationLevel p_level); + +#endif // RAYCAST_REGISTER_TYPES_H diff --git a/modules/raycast/static_raycaster.cpp b/modules/raycast/static_raycaster_embree.cpp index 7659eea27f..b5a4ab42d4 100644 --- a/modules/raycast/static_raycaster.cpp +++ b/modules/raycast/static_raycaster_embree.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* static_raycaster.cpp */ +/* static_raycaster_embree.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -30,7 +30,7 @@ #ifdef TOOLS_ENABLED -#include "static_raycaster.h" +#include "static_raycaster_embree.h" #ifdef __SSE2__ #include <pmmintrin.h> @@ -134,4 +134,4 @@ StaticRaycasterEmbree::~StaticRaycasterEmbree() { } } -#endif +#endif // TOOLS_ENABLED diff --git a/modules/raycast/static_raycaster.h b/modules/raycast/static_raycaster_embree.h index 607a392683..4d631e3ca0 100644 --- a/modules/raycast/static_raycaster.h +++ b/modules/raycast/static_raycaster_embree.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* static_raycaster.h */ +/* static_raycaster_embree.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,6 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifndef STATIC_RAYCASTER_EMBREE_H +#define STATIC_RAYCASTER_EMBREE_H + #ifdef TOOLS_ENABLED #include "core/math/static_raycaster.h" @@ -61,4 +64,6 @@ public: ~StaticRaycasterEmbree(); }; -#endif // STATIC_RAYCASTER_H +#endif // TOOLS_ENABLED + +#endif // STATIC_RAYCASTER_EMBREE_H diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index 1a4831857f..3565254ac7 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -3826,19 +3826,11 @@ void TextServerAdvanced::shaped_set_span_update_font(const RID &p_shaped, int64_ ERR_FAIL_INDEX(p_index, sd->spans.size()); ShapedTextDataAdvanced::Span &span = sd->spans.ptrw()[p_index]; - bool changed = (span.font_size != p_size) || (span.features != p_opentype_features) || (p_fonts.size() != span.fonts.size()); - if (!changed) { - for (int i = 0; i < p_fonts.size(); i++) { - changed = changed || (span.fonts[i] != p_fonts[i]); - } - } - if (changed) { - span.fonts = p_fonts; - span.font_size = p_size; - span.features = p_opentype_features; + span.fonts = p_fonts; + span.font_size = p_size; + span.features = p_opentype_features; - invalidate(sd, false); - } + invalidate(sd, false); } bool TextServerAdvanced::shaped_text_add_string(const RID &p_shaped, const String &p_text, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) { diff --git a/platform/android/java_godot_io_wrapper.h b/platform/android/java_godot_io_wrapper.h index 9a1a877b6f..24995147d4 100644 --- a/platform/android/java_godot_io_wrapper.h +++ b/platform/android/java_godot_io_wrapper.h @@ -28,9 +28,6 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -// note, swapped java and godot around in the file name so all the java -// wrappers are together - #ifndef JAVA_GODOT_IO_WRAPPER_H #define JAVA_GODOT_IO_WRAPPER_H diff --git a/platform/android/java_godot_wrapper.h b/platform/android/java_godot_wrapper.h index a6c7853107..0e96a4e1f3 100644 --- a/platform/android/java_godot_wrapper.h +++ b/platform/android/java_godot_wrapper.h @@ -28,9 +28,6 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -// note, swapped java and godot around in the file name so all the java -// wrappers are together - #ifndef JAVA_GODOT_WRAPPER_H #define JAVA_GODOT_WRAPPER_H diff --git a/platform/ios/os_ios.h b/platform/ios/os_ios.h index 00d91da771..400040875f 100644 --- a/platform/ios/os_ios.h +++ b/platform/ios/os_ios.h @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef IOS_ENABLED - #ifndef OS_IOS_H #define OS_IOS_H +#ifdef IOS_ENABLED + #include "drivers/coreaudio/audio_driver_coreaudio.h" #include "drivers/unix/os_unix.h" #include "ios.h" @@ -124,6 +124,6 @@ public: void on_focus_in(); }; -#endif // OS_IOS_H +#endif // IOS_ENABLED #endif // OS_IOS_H diff --git a/platform/linuxbsd/detect_prime_x11.h b/platform/linuxbsd/detect_prime_x11.h index 21ebaead32..7eb7064cc5 100644 --- a/platform/linuxbsd/detect_prime_x11.h +++ b/platform/linuxbsd/detect_prime_x11.h @@ -28,11 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef X11_ENABLED -#if defined(GLES3_ENABLED) +#ifndef DETECT_PRIME_X11_H +#define DETECT_PRIME_X11_H + +#if defined(X11_ENABLED) && defined(GLES3_ENABLED) int detect_prime(); -#endif +#endif // X11_ENABLED && GLES3_ENABLED #endif // DETECT_PRIME_X11_H diff --git a/platform/macos/export/codesign.h b/platform/macos/export/codesign.h index fea7b117d0..01e97bca81 100644 --- a/platform/macos/export/codesign.h +++ b/platform/macos/export/codesign.h @@ -28,6 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifndef MACOS_CODESIGN_H +#define MACOS_CODESIGN_H + // macOS code signature creation utility. // // Current implementation has the following limitation: @@ -38,9 +41,6 @@ // - Requirements code generator is not implemented (only hard-coded requirements for the ad-hoc signing is supported). // - RFC5652/CMS blob generation is not implemented, supports ad-hoc signing only. -#ifndef MACOS_CODESIGN_H -#define MACOS_CODESIGN_H - #include "core/crypto/crypto_core.h" #include "core/io/dir_access.h" #include "core/io/file_access.h" diff --git a/platform/macos/export/lipo.h b/platform/macos/export/lipo.h index 516ef99860..6378f9899c 100644 --- a/platform/macos/export/lipo.h +++ b/platform/macos/export/lipo.h @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -// Universal / Universal 2 fat binary file creator and extractor. - #ifndef MACOS_LIPO_H #define MACOS_LIPO_H +// Universal / Universal 2 fat binary file creator and extractor. + #include "core/io/file_access.h" #include "core/object/ref_counted.h" #include "modules/modules_enabled.gen.h" // For regex. diff --git a/platform/macos/export/macho.h b/platform/macos/export/macho.h index 7ef0d9067e..0d42a7013f 100644 --- a/platform/macos/export/macho.h +++ b/platform/macos/export/macho.h @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -// Mach-O binary object file format parser and editor. - #ifndef MACOS_MACHO_H #define MACOS_MACHO_H +// Mach-O binary object file format parser and editor. + #include "core/crypto/crypto.h" #include "core/crypto/crypto_core.h" #include "core/io/file_access.h" diff --git a/platform/macos/export/plist.h b/platform/macos/export/plist.h index 79cb928d0a..b3c51a9635 100644 --- a/platform/macos/export/plist.h +++ b/platform/macos/export/plist.h @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -// Property list file format (application/x-plist) parser, property list ASN-1 serialization. - #ifndef MACOS_PLIST_H #define MACOS_PLIST_H +// Property list file format (application/x-plist) parser, property list ASN-1 serialization. + #include "core/crypto/crypto_core.h" #include "core/io/file_access.h" #include "modules/modules_enabled.gen.h" // For regex. diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index 49a59de9b2..facffb99ee 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "animation_node_state_machine.h" +#include "scene/main/window.h" ///////////////////////////////////////////////// @@ -169,7 +170,7 @@ void AnimationNodeStateMachineTransition::_bind_methods() { ADD_GROUP("Advance", "advance_"); ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "advance_condition"), "set_advance_condition", "get_advance_condition"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "advance_expression", PROPERTY_HINT_EXPRESSION, ""), "set_advance_expression", "get_advance_expression"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "advance_expression_base_node"), "set_advance_expression_base_node", "get_advance_expression_base_node"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "advance_expression_base_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node"), "set_advance_expression_base_node", "get_advance_expression_base_node"); ADD_GROUP("Disabling", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled"); @@ -656,13 +657,15 @@ bool AnimationNodeStateMachinePlayback::_check_advance_condition(const Ref<Anima ERR_FAIL_COND_V(tree_base == nullptr, false); NodePath advance_expression_base_node_path; - if (!transition->advance_expression_base_node.is_empty()) { - advance_expression_base_node_path = transition->advance_expression_base_node; + Node *expression_base = nullptr; + if (!transition->get_advance_expression_base_node().is_empty()) { + advance_expression_base_node_path = transition->get_advance_expression_base_node(); + expression_base = tree_base->get_tree()->get_root()->get_child(0)->get_node_or_null(advance_expression_base_node_path); } else { advance_expression_base_node_path = tree_base->get_advance_expression_base_node(); + expression_base = tree_base->get_node_or_null(advance_expression_base_node_path); } - Node *expression_base = tree_base->get_node_or_null(advance_expression_base_node_path); if (expression_base) { Ref<Expression> exp = transition->expression; bool ret = exp->execute(Array(), expression_base, false, Engine::get_singleton()->is_editor_hint()); // Avoids allowing the user to crash the system with an expression by only allowing const calls. diff --git a/scene/animation/easing_equations.h b/scene/animation/easing_equations.h index 094829e406..03d9e16454 100644 --- a/scene/animation/easing_equations.h +++ b/scene/animation/easing_equations.h @@ -28,6 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifndef EASING_EQUATIONS_H +#define EASING_EQUATIONS_H + /* * Derived from Robert Penner's easing equations: http://robertpenner.com/easing/ * @@ -52,9 +55,6 @@ * SOFTWARE. */ -#ifndef EASING_EQUATIONS_H -#define EASING_EQUATIONS_H - namespace linear { static real_t in(real_t t, real_t b, real_t c, real_t d) { return c * t / d + b; diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 3c45b90612..8bccf3ada1 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -2196,24 +2196,69 @@ RichTextLabel::ItemFont *RichTextLabel::_find_font(Item *p_item) { ItemFont *fi = static_cast<ItemFont *>(fontitem); switch (fi->def_font) { case NORMAL_FONT: { - fi->font = theme_cache.normal_font; - fi->font_size = theme_cache.normal_font_size; + if (fi->variation) { + Ref<FontVariation> fc = fi->font; + if (fc.is_valid()) { + fc->set_base_font(theme_cache.normal_font); + } + } else { + fi->font = theme_cache.normal_font; + } + if (fi->def_size) { + fi->font_size = theme_cache.normal_font_size; + } } break; case BOLD_FONT: { - fi->font = theme_cache.bold_font; - fi->font_size = theme_cache.bold_font_size; + if (fi->variation) { + Ref<FontVariation> fc = fi->font; + if (fc.is_valid()) { + fc->set_base_font(theme_cache.bold_font); + } + } else { + fi->font = theme_cache.bold_font; + } + if (fi->def_size) { + fi->font_size = theme_cache.bold_font_size; + } } break; case ITALICS_FONT: { - fi->font = theme_cache.italics_font; - fi->font_size = theme_cache.italics_font_size; + if (fi->variation) { + Ref<FontVariation> fc = fi->font; + if (fc.is_valid()) { + fc->set_base_font(theme_cache.italics_font); + } + } else { + fi->font = theme_cache.italics_font; + } + if (fi->def_size) { + fi->font_size = theme_cache.italics_font_size; + } } break; case BOLD_ITALICS_FONT: { - fi->font = theme_cache.bold_italics_font; - fi->font_size = theme_cache.bold_italics_font_size; + if (fi->variation) { + Ref<FontVariation> fc = fi->font; + if (fc.is_valid()) { + fc->set_base_font(theme_cache.bold_italics_font); + } + } else { + fi->font = theme_cache.bold_italics_font; + } + if (fi->def_size) { + fi->font_size = theme_cache.bold_italics_font_size; + } } break; case MONO_FONT: { - fi->font = theme_cache.mono_font; - fi->font_size = theme_cache.mono_font_size; + if (fi->variation) { + Ref<FontVariation> fc = fi->font; + if (fc.is_valid()) { + fc->set_base_font(theme_cache.mono_font); + } + } else { + fi->font = theme_cache.mono_font; + } + if (fi->def_size) { + fi->font_size = theme_cache.mono_font_size; + } } break; default: { } break; @@ -3034,14 +3079,30 @@ void RichTextLabel::push_dropcap(const String &p_string, const Ref<Font> &p_font _add_item(item, false); } -void RichTextLabel::_push_def_font(DefaultFont p_font) { +void RichTextLabel::_push_def_font_var(DefaultFont p_def_font, const Ref<Font> &p_font, int p_size) { + _stop_thread(); + MutexLock data_lock(data_mutex); + + ERR_FAIL_COND(current->type == ITEM_TABLE); + ItemFont *item = memnew(ItemFont); + + item->def_font = p_def_font; + item->variation = true; + item->font = p_font; + item->font_size = p_size; + item->def_size = (p_size <= 0); + _add_item(item, true); +} + +void RichTextLabel::_push_def_font(DefaultFont p_def_font) { _stop_thread(); MutexLock data_lock(data_mutex); ERR_FAIL_COND(current->type == ITEM_TABLE); ItemFont *item = memnew(ItemFont); - item->def_font = p_font; + item->def_font = p_def_font; + item->def_size = true; _add_item(item, true); } @@ -4122,24 +4183,21 @@ void RichTextLabel::append_text(const String &p_bbcode) { pos = brk_end + 1; tag_stack.push_front("font_size"); - } else if (tag.begins_with("opentype_features=")) { - String fnt_ftr = tag.substr(18, tag.length()); + } else if (tag.begins_with("opentype_features=") || tag.begins_with("otf=")) { + int value_pos = tag.find("="); + String fnt_ftr = tag.substr(value_pos + 1); Vector<String> subtag = fnt_ftr.split(","); if (subtag.size() > 0) { Ref<Font> font = theme_cache.normal_font; - int font_size = 0; + DefaultFont def_font = NORMAL_FONT; + ItemFont *font_it = _find_font(current); if (font_it) { if (font_it->font.is_valid()) { font = font_it->font; - } - if (font_it->font_size > 0) { - font_size = font_it->font_size; + def_font = font_it->def_font; } } - Ref<FontVariation> fc; - fc.instantiate(); - fc->set_base_font(font); Dictionary features; for (int i = 0; i < subtag.size(); i++) { Vector<String> subtag_a = subtag[i].split("="); @@ -4149,11 +4207,21 @@ void RichTextLabel::append_text(const String &p_bbcode) { features[TS->name_to_tag(subtag_a[0])] = 1; } } + + Ref<FontVariation> fc; + fc.instantiate(); + + fc->set_base_font(font); fc->set_opentype_features(features); - push_font(fc, font_size); + + if (def_font != CUSTOM_FONT) { + _push_def_font_var(def_font, fc); + } else { + push_font(fc); + } } pos = brk_end + 1; - tag_stack.push_front("opentype_features"); + tag_stack.push_front(tag.substr(0, value_pos)); } else if (tag.begins_with("font=")) { String fnt = tag.substr(5, tag.length()); @@ -4169,9 +4237,21 @@ void RichTextLabel::append_text(const String &p_bbcode) { } else if (tag.begins_with("font ")) { Vector<String> subtag = tag.substr(2, tag.length()).split(" "); + Ref<Font> font = theme_cache.normal_font; + DefaultFont def_font = NORMAL_FONT; + + ItemFont *font_it = _find_font(current); + if (font_it) { + if (font_it->font.is_valid()) { + font = font_it->font; + def_font = font_it->def_font; + } + } + Ref<FontVariation> fc; fc.instantiate(); - int fnt_size = 0; + + int fnt_size = -1; for (int i = 1; i < subtag.size(); i++) { Vector<String> subtag_a = subtag[i].split("=", true, 2); if (subtag_a.size() == 2) { @@ -4179,7 +4259,8 @@ void RichTextLabel::append_text(const String &p_bbcode) { String fnt = subtag_a[1]; Ref<Font> font_data = ResourceLoader::load(fnt, "Font"); if (font_data.is_valid()) { - fc->set_base_font(font_data); + font = font_data; + def_font = CUSTOM_FONT; } } else if (subtag_a[0] == "size" || subtag_a[0] == "s") { fnt_size = subtag_a[1].to_int(); @@ -4233,7 +4314,14 @@ void RichTextLabel::append_text(const String &p_bbcode) { } } } - push_font(fc, fnt_size); + fc->set_base_font(font); + + if (def_font != CUSTOM_FONT) { + _push_def_font_var(def_font, fc, fnt_size); + } else { + push_font(fc, fnt_size); + } + pos = brk_end + 1; tag_stack.push_front("font"); diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index e714cb4ced..71123602ad 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -189,6 +189,8 @@ private: struct ItemFont : public Item { DefaultFont def_font = CUSTOM_FONT; Ref<Font> font; + bool variation = false; + bool def_size = false; int font_size = 0; ItemFont() { type = ITEM_FONT; } }; @@ -571,7 +573,8 @@ public: void add_newline(); bool remove_line(const int p_line); void push_dropcap(const String &p_string, const Ref<Font> &p_font, int p_size, const Rect2 &p_dropcap_margins = Rect2(), const Color &p_color = Color(1, 1, 1), int p_ol_size = 0, const Color &p_ol_color = Color(0, 0, 0, 0)); - void _push_def_font(DefaultFont p_font); + void _push_def_font(DefaultFont p_def_font); + void _push_def_font_var(DefaultFont p_def_font, const Ref<Font> &p_font, int p_size = -1); void push_font(const Ref<Font> &p_font, int p_size = 0); void push_font_size(int p_font_size); void push_outline_size(int p_font_size); diff --git a/scene/main/window.cpp b/scene/main/window.cpp index cf30ca259d..73f278bb50 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -1251,6 +1251,15 @@ void Window::popup(const Rect2i &p_screen_rect) { set_transient(true); set_visible(true); + + int screen_id = DisplayServer::get_singleton()->window_get_current_screen(get_window_id()); + Rect2i screen_rect = DisplayServer::get_singleton()->screen_get_usable_rect(screen_id); + if (screen_rect != Rect2i() && !screen_rect.intersects(Rect2i(position, size))) { + ERR_PRINT(vformat("Window %d spawned at invalid position: %s.", get_window_id(), position)); + // Window appeared on unavailable screen area, so force it to the center. + set_position(screen_rect.size / 2 - size / 2); + } + _post_popup(); notification(NOTIFICATION_POST_POPUP); } diff --git a/scene/resources/particle_process_material.h b/scene/resources/particle_process_material.h index fe4741d6e5..9430e5797d 100644 --- a/scene/resources/particle_process_material.h +++ b/scene/resources/particle_process_material.h @@ -28,12 +28,12 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "core/templates/rid.h" -#include "scene/resources/material.h" - #ifndef PARTICLE_PROCESS_MATERIAL_H #define PARTICLE_PROCESS_MATERIAL_H +#include "core/templates/rid.h" +#include "scene/resources/material.h" + /* TODO: -Path following diff --git a/scene/resources/sky_material.h b/scene/resources/sky_material.h index fbb202d8d8..3de1a4b26f 100644 --- a/scene/resources/sky_material.h +++ b/scene/resources/sky_material.h @@ -28,12 +28,12 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "core/templates/rid.h" -#include "scene/resources/material.h" - #ifndef SKY_MATERIAL_H #define SKY_MATERIAL_H +#include "core/templates/rid.h" +#include "scene/resources/material.h" + class ProceduralSkyMaterial : public Material { GDCLASS(ProceduralSkyMaterial, Material); diff --git a/servers/physics_3d/joints/godot_cone_twist_joint_3d.h b/servers/physics_3d/joints/godot_cone_twist_joint_3d.h index fdcc2ceea3..1651d34916 100644 --- a/servers/physics_3d/joints/godot_cone_twist_joint_3d.h +++ b/servers/physics_3d/joints/godot_cone_twist_joint_3d.h @@ -28,6 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifndef GODOT_CONE_TWIST_JOINT_3D_H +#define GODOT_CONE_TWIST_JOINT_3D_H + /* Adapted to Godot from the Bullet library. */ @@ -49,9 +52,6 @@ subject to the following restrictions: Written by: Marcus Hennix */ -#ifndef GODOT_CONE_TWIST_JOINT_3D_H -#define GODOT_CONE_TWIST_JOINT_3D_H - #include "servers/physics_3d/godot_joint_3d.h" #include "servers/physics_3d/joints/godot_jacobian_entry_3d.h" diff --git a/servers/physics_3d/joints/godot_generic_6dof_joint_3d.h b/servers/physics_3d/joints/godot_generic_6dof_joint_3d.h index bcf2d18647..6a0ab81461 100644 --- a/servers/physics_3d/joints/godot_generic_6dof_joint_3d.h +++ b/servers/physics_3d/joints/godot_generic_6dof_joint_3d.h @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifndef GODOT_GENERIC_6DOF_JOINT_3D_H +#define GODOT_GENERIC_6DOF_JOINT_3D_H + /* Adapted to Godot from the Bullet library. */ -#ifndef GODOT_GENERIC_6DOF_JOINT_3D_H -#define GODOT_GENERIC_6DOF_JOINT_3D_H - #include "servers/physics_3d/godot_joint_3d.h" #include "servers/physics_3d/joints/godot_jacobian_entry_3d.h" diff --git a/servers/physics_3d/joints/godot_hinge_joint_3d.h b/servers/physics_3d/joints/godot_hinge_joint_3d.h index b934540e8d..f1187771af 100644 --- a/servers/physics_3d/joints/godot_hinge_joint_3d.h +++ b/servers/physics_3d/joints/godot_hinge_joint_3d.h @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifndef GODOT_HINGE_JOINT_3D_H +#define GODOT_HINGE_JOINT_3D_H + /* Adapted to Godot from the Bullet library. */ -#ifndef GODOT_HINGE_JOINT_3D_H -#define GODOT_HINGE_JOINT_3D_H - #include "servers/physics_3d/godot_joint_3d.h" #include "servers/physics_3d/joints/godot_jacobian_entry_3d.h" diff --git a/servers/physics_3d/joints/godot_jacobian_entry_3d.h b/servers/physics_3d/joints/godot_jacobian_entry_3d.h index 0fe15751d5..a46ce830ec 100644 --- a/servers/physics_3d/joints/godot_jacobian_entry_3d.h +++ b/servers/physics_3d/joints/godot_jacobian_entry_3d.h @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifndef GODOT_JACOBIAN_ENTRY_3D_H +#define GODOT_JACOBIAN_ENTRY_3D_H + /* Adapted to Godot from the Bullet library. */ -#ifndef GODOT_JACOBIAN_ENTRY_3D_H -#define GODOT_JACOBIAN_ENTRY_3D_H - /* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ diff --git a/servers/physics_3d/joints/godot_pin_joint_3d.h b/servers/physics_3d/joints/godot_pin_joint_3d.h index eeeaa650bd..b3e2389d5a 100644 --- a/servers/physics_3d/joints/godot_pin_joint_3d.h +++ b/servers/physics_3d/joints/godot_pin_joint_3d.h @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifndef GODOT_PIN_JOINT_3D_H +#define GODOT_PIN_JOINT_3D_H + /* Adapted to Godot from the Bullet library. */ -#ifndef GODOT_PIN_JOINT_3D_H -#define GODOT_PIN_JOINT_3D_H - #include "servers/physics_3d/godot_joint_3d.h" #include "servers/physics_3d/joints/godot_jacobian_entry_3d.h" diff --git a/servers/physics_3d/joints/godot_slider_joint_3d.h b/servers/physics_3d/joints/godot_slider_joint_3d.h index f596c9ff75..29d19be0d7 100644 --- a/servers/physics_3d/joints/godot_slider_joint_3d.h +++ b/servers/physics_3d/joints/godot_slider_joint_3d.h @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifndef GODOT_SLIDER_JOINT_3D_H +#define GODOT_SLIDER_JOINT_3D_H + /* Adapted to Godot from the Bullet library. */ -#ifndef GODOT_SLIDER_JOINT_3D_H -#define GODOT_SLIDER_JOINT_3D_H - #include "servers/physics_3d/godot_joint_3d.h" #include "servers/physics_3d/joints/godot_jacobian_entry_3d.h" |