diff options
314 files changed, 5150 insertions, 2595 deletions
diff --git a/.github/workflows/windows_builds.yml b/.github/workflows/windows_builds.yml index f9513af5e3..7a3347d49c 100644 --- a/.github/workflows/windows_builds.yml +++ b/.github/workflows/windows_builds.yml @@ -7,7 +7,7 @@ on: env: # Used for the cache key. Add version suffix to force clean build. GODOT_BASE_BRANCH: master - SCONSFLAGS: verbose=yes warnings=extra werror=yes module_text_server_fb_enabled=yes d3d12=yes + SCONSFLAGS: verbose=yes warnings=extra werror=yes module_text_server_fb_enabled=yes d3d12=yes "angle_libs=${{github.workspace}}/" SCONS_CACHE_MSVC_CONFIG: true concurrency: @@ -54,6 +54,17 @@ jobs: - name: Download Direct3D 12 SDK components run: python ./misc/scripts/install_d3d12_sdk_windows.py + - name: Download pre-built ANGLE static libraries + uses: dsaltares/fetch-gh-release-asset@1.1.2 + with: + repo: godotengine/godot-angle-static + version: tags/chromium/6029 + file: Windows.6029-1.MSVC_17.x86_64.x86_32.zip + target: angle/angle.zip + + - name: Extract pre-built ANGLE static libraries + run: Expand-Archive -Force angle/angle.zip ${{github.workspace}}/ + - name: Setup MSVC problem matcher uses: ammaraskar/msvc-problem-matcher@master diff --git a/SConstruct b/SConstruct index 6fa3e00325..9cc1408b53 100644 --- a/SConstruct +++ b/SConstruct @@ -218,7 +218,7 @@ opts.Add(BoolVariable("brotli", "Enable Brotli for decompresson and WOFF2 fonts opts.Add(BoolVariable("xaudio2", "Enable the XAudio2 audio driver", False)) opts.Add(BoolVariable("vulkan", "Enable the vulkan rendering driver", True)) opts.Add(BoolVariable("opengl3", "Enable the OpenGL/GLES3 rendering driver", True)) -opts.Add(BoolVariable("d3d12", "Enable the Direct3D 12 rendering driver (Windows only)", False)) +opts.Add(BoolVariable("d3d12", "Enable the Direct3D 12 rendering driver", False)) opts.Add(BoolVariable("openxr", "Enable the OpenXR driver", True)) opts.Add(BoolVariable("use_volk", "Use the volk library to load the Vulkan loader dynamically", True)) opts.Add(BoolVariable("disable_exceptions", "Force disabling exception handling code", True)) @@ -374,6 +374,14 @@ if env["platform"] in platform_opts: for opt in platform_opts[env["platform"]]: opts.Add(opt) +# Platform-specific flags. +# These can sometimes override default options, so they need to be processed +# as early as possible to ensure that we're using the correct values. +flag_list = platform_flags[env["platform"]] +for key, value in flag_list.items(): + if key not in ARGUMENTS or ARGUMENTS[key] == "auto": # Allow command line to override platform flags + env[key] = value + # Update the environment to take platform-specific options into account. opts.Update(env, {**ARGUMENTS, **env.Dictionary()}) @@ -568,17 +576,8 @@ if env["build_profile"] != "": print_error('Failed to open feature build profile: "{}"'.format(env["build_profile"])) Exit(255) -# Platform specific flags. -# These can sometimes override default options. -flag_list = platform_flags[env["platform"]] -for key, value in flag_list.items(): - if key not in ARGUMENTS or ARGUMENTS[key] == "auto": # Allow command line to override platform flags - env[key] = value - # 'dev_mode' and 'production' are aliases to set default options if they haven't been # set manually by the user. -# These need to be checked *after* platform specific flags so that different -# default values can be set (e.g. to keep LTO off for `production` on some platforms). if env["dev_mode"]: env["verbose"] = methods.get_cmdline_bool("verbose", True) env["warnings"] = ARGUMENTS.get("warnings", "extra") diff --git a/core/extension/gdextension.compat.inc b/core/extension/gdextension.compat.inc new file mode 100644 index 0000000000..9dea865dbd --- /dev/null +++ b/core/extension/gdextension.compat.inc @@ -0,0 +1,49 @@ +/**************************************************************************/ +/* gdextension.compat.inc */ +/**************************************************************************/ +/* 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 DISABLE_DEPRECATED + +Error GDExtension::_open_library_bind_compat_88418(const String &p_path, const String &p_entry_symbol) { + return ERR_UNAVAILABLE; +} + +void GDExtension::_close_library_bind_compat_88418() { +} + +void GDExtension::_initialize_library_bind_compat_88418(InitializationLevel p_level) { +} + +void GDExtension::_bind_compatibility_methods() { + ClassDB::bind_compatibility_method(D_METHOD("open_library", "path", "entry_symbol"), &GDExtension::_open_library_bind_compat_88418); + ClassDB::bind_compatibility_method(D_METHOD("close_library"), &GDExtension::_close_library_bind_compat_88418); + ClassDB::bind_compatibility_method(D_METHOD("initialize_library", "level"), &GDExtension::_initialize_library_bind_compat_88418); +} + +#endif diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp index a26bb3e8f3..47628e4ea0 100644 --- a/core/extension/gdextension.cpp +++ b/core/extension/gdextension.cpp @@ -29,6 +29,8 @@ /**************************************************************************/ #include "gdextension.h" +#include "gdextension.compat.inc" + #include "core/config/project_settings.h" #include "core/io/dir_access.h" #include "core/object/class_db.h" diff --git a/core/extension/gdextension.h b/core/extension/gdextension.h index 3b15639890..9393e7399b 100644 --- a/core/extension/gdextension.h +++ b/core/extension/gdextension.h @@ -137,6 +137,15 @@ public: INITIALIZATION_LEVEL_EDITOR = GDEXTENSION_INITIALIZATION_EDITOR }; +protected: +#ifndef DISABLE_DEPRECATED + Error _open_library_bind_compat_88418(const String &p_path, const String &p_entry_symbol); + void _close_library_bind_compat_88418(); + void _initialize_library_bind_compat_88418(InitializationLevel p_level); + static void _bind_compatibility_methods(); +#endif + +public: bool is_library_open() const; #ifdef TOOLS_ENABLED diff --git a/core/input/input.cpp b/core/input/input.cpp index a8409cc06d..aa4b47934e 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -1029,6 +1029,14 @@ void Input::parse_input_event(const Ref<InputEvent> &p_event) { } } +#ifdef DEBUG_ENABLED +void Input::flush_frame_parsed_events() { + _THREAD_SAFE_METHOD_ + + frame_parsed_events.clear(); +} +#endif + void Input::flush_buffered_events() { _THREAD_SAFE_METHOD_ @@ -1244,7 +1252,7 @@ void Input::_update_action_cache(const StringName &p_action_name, ActionState &r r_action_state.cache.strength = 0.0; r_action_state.cache.raw_strength = 0.0; - int max_event = InputMap::get_singleton()->action_get_events(p_action_name)->size(); + int max_event = InputMap::get_singleton()->action_get_events(p_action_name)->size() + 1; // +1 comes from InputEventAction. for (const KeyValue<int, ActionState::DeviceState> &kv : r_action_state.device_states) { const ActionState::DeviceState &device_state = kv.value; for (int i = 0; i < max_event; i++) { diff --git a/core/input/input.h b/core/input/input.h index 6e7ab43082..4daea0c9e8 100644 --- a/core/input/input.h +++ b/core/input/input.h @@ -363,6 +363,9 @@ public: Dictionary get_joy_info(int p_device) const; void set_fallback_mapping(const String &p_guid); +#ifdef DEBUG_ENABLED + void flush_frame_parsed_events(); +#endif void flush_buffered_events(); bool is_using_input_buffering(); void set_use_input_buffering(bool p_enable); diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp index bf1de8d3b2..de3efa7a3a 100644 --- a/core/input/input_event.cpp +++ b/core/input/input_event.cpp @@ -1585,6 +1585,14 @@ float InputEventAction::get_strength() const { return strength; } +void InputEventAction::set_event_index(int p_index) { + event_index = p_index; +} + +int InputEventAction::get_event_index() const { + return event_index; +} + bool InputEventAction::is_match(const Ref<InputEvent> &p_event, bool p_exact_match) const { if (p_event.is_null()) { return false; @@ -1649,9 +1657,13 @@ void InputEventAction::_bind_methods() { ClassDB::bind_method(D_METHOD("set_strength", "strength"), &InputEventAction::set_strength); ClassDB::bind_method(D_METHOD("get_strength"), &InputEventAction::get_strength); + ClassDB::bind_method(D_METHOD("set_event_index", "index"), &InputEventAction::set_event_index); + ClassDB::bind_method(D_METHOD("get_event_index"), &InputEventAction::get_event_index); + ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "action"), "set_action", "get_action"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "strength", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_strength", "get_strength"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "event_index", PROPERTY_HINT_RANGE, "-1,31,1"), "set_event_index", "get_event_index"); // The max value equals to Input::MAX_EVENT - 1. } /////////////////////////////////// diff --git a/core/input/input_event.h b/core/input/input_event.h index 21b61f3bc2..19176f748e 100644 --- a/core/input/input_event.h +++ b/core/input/input_event.h @@ -453,6 +453,7 @@ class InputEventAction : public InputEvent { StringName action; float strength = 1.0f; + int event_index = -1; protected: static void _bind_methods(); @@ -466,6 +467,9 @@ public: void set_strength(float p_strength); float get_strength() const; + void set_event_index(int p_index); + int get_event_index() const; + virtual bool is_action(const StringName &p_action) const; virtual bool action_match(const Ref<InputEvent> &p_event, bool p_exact_match, float p_deadzone, bool *r_pressed, float *r_strength, float *r_raw_strength) const override; diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp index 7fd1806b31..178d02b987 100644 --- a/core/input/input_map.cpp +++ b/core/input/input_map.cpp @@ -274,6 +274,13 @@ bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const Str if (r_raw_strength != nullptr) { *r_raw_strength = strength; } + if (r_event_index) { + if (input_event_action->get_event_index() >= 0) { + *r_event_index = input_event_action->get_event_index(); + } else { + *r_event_index = E->value.inputs.size(); + } + } return input_event_action->get_action() == p_action; } diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h index 5caf699d32..486f7bbf37 100644 --- a/core/io/resource_loader.h +++ b/core/io/resource_loader.h @@ -226,7 +226,7 @@ public: // Loaders can safely use this regardless which thread they are running on. static void notify_load_error(const String &p_err) { if (err_notify) { - callable_mp_static(err_notify).bind(p_err).call_deferred(); + callable_mp_static(err_notify).call_deferred(p_err); } } static void set_error_notify_func(ResourceLoadErrorNotify p_err_notify) { @@ -239,7 +239,7 @@ public: if (Thread::get_caller_id() == Thread::get_main_id()) { dep_err_notify(p_path, p_dependency, p_type); } else { - callable_mp_static(dep_err_notify).bind(p_path, p_dependency, p_type).call_deferred(); + callable_mp_static(dep_err_notify).call_deferred(p_path, p_dependency, p_type); } } } diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp index 3d93ce8e73..fe4345aa0d 100644 --- a/core/object/class_db.cpp +++ b/core/object/class_db.cpp @@ -505,7 +505,7 @@ Object *ClassDB::_instantiate_internal(const StringName &p_class, bool p_require ERR_FAIL_NULL_V_MSG(ti->creation_func, nullptr, "Class '" + String(p_class) + "' or its base class cannot be instantiated."); } #ifdef TOOLS_ENABLED - if (ti->api == API_EDITOR && !Engine::get_singleton()->is_editor_hint()) { + if ((ti->api == API_EDITOR || ti->api == API_EDITOR_EXTENSION) && !Engine::get_singleton()->is_editor_hint()) { ERR_PRINT("Class '" + String(p_class) + "' can only be instantiated by editor."); return nullptr; } @@ -664,7 +664,7 @@ bool ClassDB::can_instantiate(const StringName &p_class) { return scr.is_valid() && scr->is_valid() && !scr->is_abstract(); } #ifdef TOOLS_ENABLED - if (ti->api == API_EDITOR && !Engine::get_singleton()->is_editor_hint()) { + if ((ti->api == API_EDITOR || ti->api == API_EDITOR_EXTENSION) && !Engine::get_singleton()->is_editor_hint()) { return false; } #endif @@ -684,7 +684,7 @@ bool ClassDB::is_virtual(const StringName &p_class) { return scr.is_valid() && scr->is_valid() && scr->is_abstract(); } #ifdef TOOLS_ENABLED - if (ti->api == API_EDITOR && !Engine::get_singleton()->is_editor_hint()) { + if ((ti->api == API_EDITOR || ti->api == API_EDITOR_EXTENSION) && !Engine::get_singleton()->is_editor_hint()) { return false; } #endif diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp index 4d67cd930e..0f7884305a 100644 --- a/core/object/undo_redo.cpp +++ b/core/object/undo_redo.cpp @@ -159,10 +159,11 @@ void UndoRedo::add_do_method(const Callable &p_callable) { do_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(object)); } do_op.type = Operation::TYPE_METHOD; - do_op.name = p_callable.get_method(); - if (do_op.name == StringName()) { - // There's no `get_method()` for custom callables, so use `operator String()` instead. + // There's no `get_method()` for custom callables, so use `operator String()` instead. + if (p_callable.is_custom()) { do_op.name = static_cast<String>(p_callable); + } else { + do_op.name = p_callable.get_method(); } actions.write[current_action + 1].do_ops.push_back(do_op); @@ -190,10 +191,11 @@ void UndoRedo::add_undo_method(const Callable &p_callable) { } undo_op.type = Operation::TYPE_METHOD; undo_op.force_keep_in_merge_ends = force_keep_in_merge_ends; - undo_op.name = p_callable.get_method(); - if (undo_op.name == StringName()) { - // There's no `get_method()` for custom callables, so use `operator String()` instead. + // There's no `get_method()` for custom callables, so use `operator String()` instead. + if (p_callable.is_custom()) { undo_op.name = static_cast<String>(p_callable); + } else { + undo_op.name = p_callable.get_method(); } actions.write[current_action + 1].undo_ops.push_back(undo_op); diff --git a/doc/classes/AnimationMixer.xml b/doc/classes/AnimationMixer.xml index a77e9e28c6..c635eba2ab 100644 --- a/doc/classes/AnimationMixer.xml +++ b/doc/classes/AnimationMixer.xml @@ -273,7 +273,7 @@ The number of possible simultaneous sounds for each of the assigned AudioStreamPlayers. For example, if this value is [code]32[/code] and the animation has two audio tracks, the two [AudioStreamPlayer]s assigned can play simultaneously up to [code]32[/code] voices each. </member> - <member name="callback_mode_discrete" type="int" setter="set_callback_mode_discrete" getter="get_callback_mode_discrete" enum="AnimationMixer.AnimationCallbackModeDiscrete" default="0"> + <member name="callback_mode_discrete" type="int" setter="set_callback_mode_discrete" getter="get_callback_mode_discrete" enum="AnimationMixer.AnimationCallbackModeDiscrete" default="1"> Ordinarily, tracks can be set to [constant Animation.UPDATE_DISCRETE] to update infrequently, usually when using nearest interpolation. However, when blending with [constant Animation.UPDATE_CONTINUOUS] several results are considered. The [member callback_mode_discrete] specify it explicitly. See also [enum AnimationCallbackModeDiscrete]. To make the blended results look good, it is recommended to set this to [constant ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS] to update every frame during blending. Other values exist for compatibility and they are fine if there is no blending, but not so, may produce artifacts. @@ -361,14 +361,14 @@ Make method calls immediately when reached in the animation. </constant> <constant name="ANIMATION_CALLBACK_MODE_DISCRETE_DOMINANT" value="0" enum="AnimationCallbackModeDiscrete"> - An [constant Animation.UPDATE_DISCRETE] track value takes precedence when blending [constant Animation.UPDATE_CONTINUOUS] or [constant Animation.UPDATE_CAPTURE] track values and [constant Animation.UPDATE_DISCRETE] track values. This is the default behavior for [AnimationPlayer]. - [b]Note:[/b] If a value track has non-numeric type key values, it is internally converted to use [constant ANIMATION_CALLBACK_MODE_DISCRETE_DOMINANT] with [constant Animation.UPDATE_DISCRETE]. + An [constant Animation.UPDATE_DISCRETE] track value takes precedence when blending [constant Animation.UPDATE_CONTINUOUS] or [constant Animation.UPDATE_CAPTURE] track values and [constant Animation.UPDATE_DISCRETE] track values. </constant> <constant name="ANIMATION_CALLBACK_MODE_DISCRETE_RECESSIVE" value="1" enum="AnimationCallbackModeDiscrete"> - An [constant Animation.UPDATE_CONTINUOUS] or [constant Animation.UPDATE_CAPTURE] track value takes precedence when blending the [constant Animation.UPDATE_CONTINUOUS] or [constant Animation.UPDATE_CAPTURE] track values and the [constant Animation.UPDATE_DISCRETE] track values. + An [constant Animation.UPDATE_CONTINUOUS] or [constant Animation.UPDATE_CAPTURE] track value takes precedence when blending the [constant Animation.UPDATE_CONTINUOUS] or [constant Animation.UPDATE_CAPTURE] track values and the [constant Animation.UPDATE_DISCRETE] track values. This is the default behavior for [AnimationPlayer]. </constant> <constant name="ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS" value="2" enum="AnimationCallbackModeDiscrete"> Always treat the [constant Animation.UPDATE_DISCRETE] track value as [constant Animation.UPDATE_CONTINUOUS] with [constant Animation.INTERPOLATION_NEAREST]. This is the default behavior for [AnimationTree]. + If a value track has non-numeric type key values, it is internally converted to use [constant ANIMATION_CALLBACK_MODE_DISCRETE_RECESSIVE] with [constant Animation.UPDATE_DISCRETE]. </constant> </constants> </class> diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index e157cbb96c..ff1c390b3c 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -63,6 +63,7 @@ <param index="2" name="callback" type="Callable" /> <description> Creates a new application status indicator with the specified icon, tooltip, and activation callback. + [param callback] should take two arguments: the pressed mouse button (one of the [enum MouseButton] constants) and the click position in screen coordinates (a [Vector2i]). </description> </method> <method name="cursor_get_shape" qualifiers="const"> @@ -875,7 +876,7 @@ <param index="1" name="open_callback" type="Callable" /> <param index="2" name="close_callback" type="Callable" /> <description> - Registers callables to emit when the menu is respectively about to show or closed. + Registers callables to emit when the menu is respectively about to show or closed. Callback methods should have zero arguments. </description> </method> <method name="has_feature" qualifiers="const"> @@ -1187,7 +1188,7 @@ <param index="0" name="id" type="int" /> <param index="1" name="callback" type="Callable" /> <description> - Sets the application status indicator activation callback. + Sets the application status indicator activation callback. [param callback] should take two arguments: [int] mouse button index (one of [enum MouseButton] values) and [Vector2i] click position in screen coordinates. [b]Note:[/b] This method is implemented on macOS and Windows. </description> </method> @@ -1568,7 +1569,7 @@ <param index="0" name="callback" type="Callable" /> <param index="1" name="window_id" type="int" default="0" /> <description> - Sets the [param callback] that should be called when files are dropped from the operating system's file manager to the window specified by [param window_id]. + Sets the [param callback] that should be called when files are dropped from the operating system's file manager to the window specified by [param window_id]. [param callback] should take one [PackedStringArray] argument, which is the list of dropped files. [b]Warning:[/b] Advanced users only! Adding such a callback to a [Window] node will override its default implementation, which can introduce bugs. [b]Note:[/b] This method is implemented on Windows, macOS, Linux (X11/Wayland), and Web. </description> diff --git a/doc/classes/EditorExportPlugin.xml b/doc/classes/EditorExportPlugin.xml index 436f471e5d..3e2b3ea111 100644 --- a/doc/classes/EditorExportPlugin.xml +++ b/doc/classes/EditorExportPlugin.xml @@ -313,7 +313,7 @@ <method name="skip"> <return type="void" /> <description> - To be called inside [method _export_file]. Skips the current file, so it's not included in the export. + To be called inside [method _export_file], [method _customize_resource], or [method _customize_scene]. Skips the current file, so it's not included in the export. </description> </method> </methods> diff --git a/doc/classes/EditorInspectorPlugin.xml b/doc/classes/EditorInspectorPlugin.xml index e5e6905cd2..4f6ef76c4c 100644 --- a/doc/classes/EditorInspectorPlugin.xml +++ b/doc/classes/EditorInspectorPlugin.xml @@ -78,9 +78,11 @@ <param index="0" name="property" type="String" /> <param index="1" name="editor" type="Control" /> <param index="2" name="add_to_end" type="bool" default="false" /> + <param index="3" name="label" type="String" default="""" /> <description> Adds a property editor for an individual property. The [param editor] control must extend [EditorProperty]. There can be multiple property editors for a property. If [param add_to_end] is [code]true[/code], this newly added editor will be displayed after all the other editors of the property whose [param add_to_end] is [code]false[/code]. For example, the editor uses this parameter to add an "Edit Region" button for [member Sprite2D.region_rect] below the regular [Rect2] editor. + [param label] can be used to choose a custom label for the property editor in the inspector. If left empty, the label is computed from the name of the property instead. </description> </method> <method name="add_property_editor_for_multiple_properties"> diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index 3e3d2205f2..90b8d07592 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -577,7 +577,7 @@ The maximum idle uptime (in seconds) of the Blender process. This prevents Godot from having to create a new process for each import within the given seconds. </member> - <member name="filesystem/import/fbx2gltf/fbx2gltf_path" type="String" setter="" getter=""> + <member name="filesystem/import/fbx/fbx2gltf_path" type="String" setter="" getter=""> The path to the FBX2glTF executable used for converting Autodesk FBX 3D scene files [code].fbx[/code] to glTF 2.0 format during import. To enable this feature for your specific project, use [member ProjectSettings.filesystem/import/fbx2gltf/enabled]. </member> @@ -925,14 +925,14 @@ <member name="run/auto_save/save_before_running" type="bool" setter="" getter=""> If [code]true[/code], saves all scenes and scripts automatically before running the project. Setting this to [code]false[/code] prevents the editor from saving if there are no changes which can speed up the project startup slightly, but it makes it possible to run a project that has unsaved changes. (Unsaved changes will not be visible in the running project.) </member> - <member name="run/output/always_clear_output_on_play" type="bool" setter="" getter=""> - If [code]true[/code], the editor will clear the Output panel when running the project. + <member name="run/bottom_panel/action_on_play" type="int" setter="" getter=""> + The action to execute on the bottom panel when running the project. </member> - <member name="run/output/always_close_output_on_stop" type="bool" setter="" getter=""> - If [code]true[/code], the editor will collapse the Output panel when stopping the project. + <member name="run/bottom_panel/action_on_stop" type="int" setter="" getter=""> + The action to execute on the bottom panel when stopping the project. </member> - <member name="run/output/always_open_output_on_play" type="bool" setter="" getter=""> - If [code]true[/code], the editor will expand the Output panel when running the project. + <member name="run/output/always_clear_output_on_play" type="bool" setter="" getter=""> + If [code]true[/code], the editor will clear the Output panel when running the project. </member> <member name="run/output/font_size" type="int" setter="" getter=""> The size of the font in the [b]Output[/b] panel at the bottom of the editor. This setting does not impact the font size of the script editor (see [member interface/editor/code_font_size]). @@ -1028,6 +1028,9 @@ <member name="text_editor/behavior/files/restore_scripts_on_load" type="bool" setter="" getter=""> If [code]true[/code], reopens scripts that were opened in the last session when the editor is reopened on a given project. </member> + <member name="text_editor/behavior/files/trim_final_newlines_on_save" type="bool" setter="" getter=""> + If [code]true[/code], trims all empty newlines after the final newline when saving a script. Final newlines refer to the empty newlines found at the end of files. Since these serve no practical purpose, they can and should be removed to make version control diffs less noisy. + </member> <member name="text_editor/behavior/files/trim_trailing_whitespace_on_save" type="bool" setter="" getter=""> If [code]true[/code], trims trailing whitespace when saving a script. Trailing whitespace refers to tab and space characters placed at the end of lines. Since these serve no practical purpose, they can and should be removed to make version control diffs less noisy. </member> diff --git a/doc/classes/FileAccess.xml b/doc/classes/FileAccess.xml index 99574da808..71a1fc8e09 100644 --- a/doc/classes/FileAccess.xml +++ b/doc/classes/FileAccess.xml @@ -524,14 +524,14 @@ </constant> <constant name="WRITE" value="2" enum="ModeFlags"> Opens the file for write operations. The file is created if it does not exist, and truncated if it does. - [b]Note:[/b] When creating a file it must be in an already existing directory. To recursively create directories for a file path, see [method DirAccess.make_dir_recursive]). + [b]Note:[/b] When creating a file it must be in an already existing directory. To recursively create directories for a file path, see [method DirAccess.make_dir_recursive]. </constant> <constant name="READ_WRITE" value="3" enum="ModeFlags"> Opens the file for read and write operations. Does not truncate the file. The cursor is positioned at the beginning of the file. </constant> <constant name="WRITE_READ" value="7" enum="ModeFlags"> Opens the file for read and write operations. The file is created if it does not exist, and truncated if it does. The cursor is positioned at the beginning of the file. - [b]Note:[/b] When creating a file it must be in an already existing directory. To recursively create directories for a file path, see [method DirAccess.make_dir_recursive]). + [b]Note:[/b] When creating a file it must be in an already existing directory. To recursively create directories for a file path, see [method DirAccess.make_dir_recursive]. </constant> <constant name="COMPRESSION_FASTLZ" value="0" enum="CompressionMode"> Uses the [url=https://fastlz.org/]FastLZ[/url] compression method. diff --git a/doc/classes/InputEventAction.xml b/doc/classes/InputEventAction.xml index 4715f9fe95..e082adeca0 100644 --- a/doc/classes/InputEventAction.xml +++ b/doc/classes/InputEventAction.xml @@ -16,6 +16,9 @@ <member name="action" type="StringName" setter="set_action" getter="get_action" default="&"""> The action's name. Actions are accessed via this [String]. </member> + <member name="event_index" type="int" setter="set_event_index" getter="get_event_index" default="-1"> + The real event index in action this event corresponds to (from events defined for this action in the [InputMap]). If [code]-1[/code], a unique ID will be used and actions pressed with this ID will need to be released with another [InputEventAction]. + </member> <member name="pressed" type="bool" setter="set_pressed" getter="is_pressed" default="false"> If [code]true[/code], the action's state is pressed. If [code]false[/code], the action's state is released. </member> diff --git a/doc/classes/Joint2D.xml b/doc/classes/Joint2D.xml index af0a54815f..0099c76d08 100644 --- a/doc/classes/Joint2D.xml +++ b/doc/classes/Joint2D.xml @@ -4,7 +4,7 @@ Abstract base class for all 2D physics joints. </brief_description> <description> - Abstract base class for all joints in 2D physics. 2D joints bind together two physics bodies and apply a constraint. + Abstract base class for all joints in 2D physics. 2D joints bind together two physics bodies ([member node_a] and [member node_b]) and apply a constraint. </description> <tutorials> </tutorials> @@ -12,7 +12,7 @@ <method name="get_rid" qualifiers="const"> <return type="RID" /> <description> - Returns the joint's [RID]. + Returns the joint's internal [RID] from the [PhysicsServer2D]. </description> </method> </methods> @@ -22,13 +22,13 @@ When set to [code]0[/code], the default value from [member ProjectSettings.physics/2d/solver/default_constraint_bias] is used. </member> <member name="disable_collision" type="bool" setter="set_exclude_nodes_from_collision" getter="get_exclude_nodes_from_collision" default="true"> - If [code]true[/code], [member node_a] and [member node_b] can not collide. + If [code]true[/code], the two bodies bound together do not collide with each other. </member> <member name="node_a" type="NodePath" setter="set_node_a" getter="get_node_a" default="NodePath("")"> - The first body attached to the joint. Must derive from [PhysicsBody2D]. + Path to the first body (A) attached to the joint. The node must inherit [PhysicsBody2D]. </member> <member name="node_b" type="NodePath" setter="set_node_b" getter="get_node_b" default="NodePath("")"> - The second body attached to the joint. Must derive from [PhysicsBody2D]. + Path to the second body (B) attached to the joint. The node must inherit [PhysicsBody2D]. </member> </members> </class> diff --git a/doc/classes/Joint3D.xml b/doc/classes/Joint3D.xml index ea0dda881a..950129806a 100644 --- a/doc/classes/Joint3D.xml +++ b/doc/classes/Joint3D.xml @@ -4,7 +4,7 @@ Abstract base class for all 3D physics joints. </brief_description> <description> - Abstract base class for all joints in 3D physics. 3D joints bind together two physics bodies and apply a constraint. + Abstract base class for all joints in 3D physics. 3D joints bind together two physics bodies ([member node_a] and [member node_b]) and apply a constraint. If only one body is defined, it is attached to a fixed [StaticBody3D] without collision shapes. </description> <tutorials> <link title="3D Truck Town Demo">https://godotengine.org/asset-library/asset/2752</link> @@ -13,19 +13,21 @@ <method name="get_rid" qualifiers="const"> <return type="RID" /> <description> - Returns the joint's [RID]. + Returns the joint's internal [RID] from the [PhysicsServer3D]. </description> </method> </methods> <members> <member name="exclude_nodes_from_collision" type="bool" setter="set_exclude_nodes_from_collision" getter="get_exclude_nodes_from_collision" default="true"> - If [code]true[/code], the two bodies of the nodes are not able to collide with each other. + If [code]true[/code], the two bodies bound together do not collide with each other. </member> <member name="node_a" type="NodePath" setter="set_node_a" getter="get_node_a" default="NodePath("")"> - The node attached to the first side (A) of the joint. + Path to the first node (A) attached to the joint. The node must inherit [PhysicsBody3D]. + If left empty and [member node_b] is set, the body is attached to a fixed [StaticBody3D] without collision shapes. </member> <member name="node_b" type="NodePath" setter="set_node_b" getter="get_node_b" default="NodePath("")"> - The node attached to the second side (B) of the joint. + Path to the second node (B) attached to the joint. The node must inherit [PhysicsBody3D]. + If left empty and [member node_a] is set, the body is attached to a fixed [StaticBody3D] without collision shapes. </member> <member name="solver_priority" type="int" setter="set_solver_priority" getter="get_solver_priority" default="1"> The priority used to define which solver is executed first for multiple joints. The lower the value, the higher the priority. diff --git a/doc/classes/Light3D.xml b/doc/classes/Light3D.xml index c1fc49cf9f..bda5fb69de 100644 --- a/doc/classes/Light3D.xml +++ b/doc/classes/Light3D.xml @@ -199,7 +199,7 @@ </constant> <constant name="BAKE_DISABLED" value="0" enum="BakeMode"> Light is ignored when baking. This is the fastest mode, but the light will be taken into account when baking global illumination. This mode should generally be used for dynamic lights that change quickly, as the effect of global illumination is less noticeable on those lights. - [b]Note:[/b] Hiding a light does [i]not[/i] affect baking [LightmapGI]. Hiding a light will still affect baking [VoxelGI] and SDFGI (see [member Environment.sdfgi_enabled). + [b]Note:[/b] Hiding a light does [i]not[/i] affect baking [LightmapGI]. Hiding a light will still affect baking [VoxelGI] and SDFGI (see [member Environment.sdfgi_enabled]). </constant> <constant name="BAKE_STATIC" value="1" enum="BakeMode"> Light is taken into account in static baking ([VoxelGI], [LightmapGI], SDFGI ([member Environment.sdfgi_enabled])). The light can be moved around or modified, but its global illumination will not update in real-time. This is suitable for subtle changes (such as flickering torches), but generally not large changes such as toggling a light on and off. diff --git a/doc/classes/Material.xml b/doc/classes/Material.xml index 4a73bc2271..760773d5d9 100644 --- a/doc/classes/Material.xml +++ b/doc/classes/Material.xml @@ -56,7 +56,7 @@ [b]Note:[/b] This only applies to [StandardMaterial3D]s and [ShaderMaterial]s with type "Spatial". </member> <member name="render_priority" type="int" setter="set_render_priority" getter="get_render_priority"> - Sets the render priority for objects in 3D scenes. Higher priority objects will be sorted in front of lower priority objects. In other words, all objects with [member render_priority] [code]1[/code] will render before all objects with [member render_priority] [code]0[/code]). + Sets the render priority for objects in 3D scenes. Higher priority objects will be sorted in front of lower priority objects. In other words, all objects with [member render_priority] [code]1[/code] will render before all objects with [member render_priority] [code]0[/code]. [b]Note:[/b] This only applies to [StandardMaterial3D]s and [ShaderMaterial]s with type "Spatial". [b]Note:[/b] This will not impact how transparent objects are sorted relative to opaque objects or how dynamic meshes will be sorted relative to other opaque meshes. This is because all transparent objects are drawn after all opaque objects and all dynamic opaque meshes are drawn before other opaque meshes. </member> diff --git a/doc/classes/Mesh.xml b/doc/classes/Mesh.xml index 966e870940..6b5a50d97b 100644 --- a/doc/classes/Mesh.xml +++ b/doc/classes/Mesh.xml @@ -4,7 +4,7 @@ A [Resource] that contains vertex array-based geometry. </brief_description> <description> - Mesh is a type of [Resource] that contains vertex array-based geometry, divided in [i]surfaces[/i]. Each surface contains a completely separate array and a material used to draw it. Design wise, a mesh with multiple surfaces is preferred to a single surface, because objects created in 3D editing software commonly contain multiple materials. + Mesh is a type of [Resource] that contains vertex array-based geometry, divided in [i]surfaces[/i]. Each surface contains a completely separate array and a material used to draw it. Design wise, a mesh with multiple surfaces is preferred to a single surface, because objects created in 3D editing software commonly contain multiple materials. The maximum number of surfaces per mesh is [constant RenderingServer.MAX_MESH_SURFACES]. </description> <tutorials> <link title="3D Material Testers Demo">https://godotengine.org/asset-library/asset/2742</link> diff --git a/doc/classes/MeshLibrary.xml b/doc/classes/MeshLibrary.xml index c5e8d8cbe7..f65e29af8e 100644 --- a/doc/classes/MeshLibrary.xml +++ b/doc/classes/MeshLibrary.xml @@ -29,7 +29,7 @@ <return type="int" /> <param index="0" name="name" type="String" /> <description> - Returns the first item with the given name. + Returns the first item with the given name, or [code]-1[/code] if no item is found. </description> </method> <method name="get_item_list" qualifiers="const"> diff --git a/doc/classes/NavigationAgent2D.xml b/doc/classes/NavigationAgent2D.xml index 6f0561e66e..94c372106b 100644 --- a/doc/classes/NavigationAgent2D.xml +++ b/doc/classes/NavigationAgent2D.xml @@ -261,7 +261,7 @@ <signal name="velocity_computed"> <param index="0" name="safe_velocity" type="Vector2" /> <description> - Notifies when the collision avoidance velocity is calculated. Emitted when [member velocity] is set. Only emitted when [member avoidance_enabled] is true. + Notifies when the collision avoidance velocity is calculated. Emitted every update as long as [member avoidance_enabled] is [code]true[/code] and the agent has a navigation map. </description> </signal> <signal name="waypoint_reached"> diff --git a/doc/classes/NavigationAgent3D.xml b/doc/classes/NavigationAgent3D.xml index 64ee35a84b..5f9f4991d1 100644 --- a/doc/classes/NavigationAgent3D.xml +++ b/doc/classes/NavigationAgent3D.xml @@ -271,7 +271,7 @@ <signal name="velocity_computed"> <param index="0" name="safe_velocity" type="Vector3" /> <description> - Notifies when the collision avoidance velocity is calculated. Emitted when [member velocity] is set. Only emitted when [member avoidance_enabled] is true. + Notifies when the collision avoidance velocity is calculated. Emitted every update as long as [member avoidance_enabled] is [code]true[/code] and the agent has a navigation map. </description> </signal> <signal name="waypoint_reached"> diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index 176bdea4a1..2662b34aec 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -1017,7 +1017,7 @@ Change the process thread group order. Groups with a lesser order will process before groups with a greater order. This is useful when a large amount of nodes process in sub thread and, afterwards, another group wants to collect their result in the main thread, as an example. </member> <member name="process_thread_messages" type="int" setter="set_process_thread_messages" getter="get_process_thread_messages" enum="Node.ProcessThreadMessages" is_bitfield="true"> - Set whether the current thread group will process messages (calls to [method call_deferred_thread_group] on threads, and whether it wants to receive them during regular process or physics process callbacks. + Set whether the current thread group will process messages (calls to [method call_deferred_thread_group] on threads), and whether it wants to receive them during regular process or physics process callbacks. </member> <member name="scene_file_path" type="String" setter="set_scene_file_path" getter="get_scene_file_path"> The original scene's file path, if the node has been instantiated from a [PackedScene] file. Only scene root nodes contains this. diff --git a/doc/classes/PhysicsMaterial.xml b/doc/classes/PhysicsMaterial.xml index 1601a1040e..03cbfb4ce7 100644 --- a/doc/classes/PhysicsMaterial.xml +++ b/doc/classes/PhysicsMaterial.xml @@ -14,7 +14,7 @@ </member> <member name="bounce" type="float" setter="set_bounce" getter="get_bounce" default="0.0"> The body's bounciness. Values range from [code]0[/code] (no bounce) to [code]1[/code] (full bounciness). - [b]Note:[/b] Even with [member bounce] set to [code]1.0[/code], some energy will be lost over time due to linear and angular damping. To have a [PhysicsBody3D] that preserves all its energy over time, set [member bounce] to [code]1.0[/code], the body's linear damp mode to [b]Replace[/b] (if applicable), its linear damp to [code]0.0[/code], its angular damp mode to [b]Replace[/b] (if applicable), and its angular damp to [code]0.0[/code]. + [b]Note:[/b] Even with [member bounce] set to [code]1.0[/code], some energy will be lost over time due to linear and angular damping. To have a physics body that preserves all its energy over time, set [member bounce] to [code]1.0[/code], the body's linear damp mode to [b]Replace[/b] (if applicable), its linear damp to [code]0.0[/code], its angular damp mode to [b]Replace[/b] (if applicable), and its angular damp to [code]0.0[/code]. </member> <member name="friction" type="float" setter="set_friction" getter="get_friction" default="1.0"> The body's friction. Values range from [code]0[/code] (frictionless) to [code]1[/code] (maximum friction). diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml index e835724e36..a7b55387a4 100644 --- a/doc/classes/PhysicsServer3D.xml +++ b/doc/classes/PhysicsServer3D.xml @@ -990,6 +990,14 @@ Returns the shape data. </description> </method> + <method name="shape_get_margin" qualifiers="const"> + <return type="float" /> + <param index="0" name="shape" type="RID" /> + <description> + Returns the collision margin for the shape. + [b]Note:[/b] This is not used in Godot Physics, so will always return [code]0[/code]. + </description> + </method> <method name="shape_get_type" qualifiers="const"> <return type="int" enum="PhysicsServer3D.ShapeType" /> <param index="0" name="shape" type="RID" /> @@ -1005,6 +1013,15 @@ Sets the shape data that defines its shape and size. The data to be passed depends on the kind of shape created [method shape_get_type]. </description> </method> + <method name="shape_set_margin"> + <return type="void" /> + <param index="0" name="shape" type="RID" /> + <param index="1" name="margin" type="float" /> + <description> + Sets the collision margin for the shape. + [b]Note:[/b] This is not used in Godot Physics. + </description> + </method> <method name="slider_joint_get_param" qualifiers="const"> <return type="float" /> <param index="0" name="joint" type="RID" /> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 5ac4c96d93..c8a11427b9 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -902,8 +902,9 @@ <member name="display/window/vsync/vsync_mode" type="int" setter="" getter="" default="1"> Sets the V-Sync mode for the main game window. The editor's own V-Sync mode can be set using [member EditorSettings.interface/editor/vsync_mode]. See [enum DisplayServer.VSyncMode] for possible values and how they affect the behavior of your application. - Depending on the platform and used renderer, the engine will fall back to [b]Enabled[/b] if the desired mode is not supported. - [b]Note:[/b] V-Sync modes other than [b]Enabled[/b] are only supported in the Forward+ and Mobile rendering methods, not Compatibility. + Depending on the platform and rendering method, the engine will fall back to [b]Enabled[/b] if the desired mode is not supported. + V-Sync can be disabled on the command line using the [code]--disable-vsync[/code] [url=$DOCS_URL/tutorials/editor/command_line_tutorial.html]command line argument[/url]. + [b]Note:[/b] The [b]Adaptive[/b] and [b]Mailbox[/b] V-Sync modes are only supported in the Forward+ and Mobile rendering methods, not Compatibility. [b]Note:[/b] This property is only read when the project starts. To change the V-Sync mode at runtime, call [method DisplayServer.window_set_vsync_mode] instead. </member> <member name="dotnet/project/assembly_name" type="String" setter="" getter="" default=""""> @@ -1002,7 +1003,7 @@ </member> <member name="filesystem/import/fbx2gltf/enabled" type="bool" setter="" getter="" default="true"> If [code]true[/code], Autodesk FBX 3D scene files with the [code].fbx[/code] extension will be imported by converting them to glTF 2.0. - This requires configuring a path to an FBX2glTF executable in the editor settings at [member EditorSettings.filesystem/import/fbx2gltf/fbx2gltf_path]. + This requires configuring a path to an FBX2glTF executable in the editor settings at [member EditorSettings.filesystem/import/fbx/fbx2gltf_path]. </member> <member name="filesystem/import/fbx2gltf/enabled.android" type="bool" setter="" getter="" default="false"> Override for [member filesystem/import/fbx2gltf/enabled] on Android where FBX2glTF can't easily be accessed from Godot. diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index 3ddc0d8f7b..3c9f0fc7af 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -4239,6 +4239,9 @@ <constant name="MAX_2D_DIRECTIONAL_LIGHTS" value="8"> The maximum number of directional lights that can be rendered at a given time in 2D. </constant> + <constant name="MAX_MESH_SURFACES" value="256"> + The maximum number of surfaces a mesh can have. + </constant> <constant name="TEXTURE_LAYERED_2D_ARRAY" value="0" enum="TextureLayeredType"> Array of 2-dimensional textures (see [Texture2DArray]). </constant> diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml index f4e3c1209f..24d2d26beb 100644 --- a/doc/classes/RichTextLabel.xml +++ b/doc/classes/RichTextLabel.xml @@ -335,7 +335,7 @@ <method name="push_cell"> <return type="void" /> <description> - Adds a [code skip-lint][cell][/code] tag to the tag stack. Must be inside a [code skip-lint][table][/code] tag. See [method push_table] for details. + Adds a [code skip-lint][cell][/code] tag to the tag stack. Must be inside a [code skip-lint][table][/code] tag. See [method push_table] for details. Use [method set_table_column_expand] to set column expansion ratio, [method set_cell_border_color] to set cell border, [method set_cell_row_background_color] to set cell background, [method set_cell_size_override] to override cell size, and [method set_cell_padding] to set padding. </description> </method> <method name="push_color"> @@ -492,7 +492,7 @@ <param index="1" name="inline_align" type="int" enum="InlineAlignment" default="0" /> <param index="2" name="align_to_row" type="int" default="-1" /> <description> - Adds a [code skip-lint][table=columns,inline_align][/code] tag to the tag stack. + Adds a [code skip-lint][table=columns,inline_align][/code] tag to the tag stack. Use [method set_table_column_expand] to set column expansion ratio. Use [method push_cell] to add cells. </description> </method> <method name="push_underline"> diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml index 9c0e8011dc..286b35d642 100644 --- a/doc/classes/Window.xml +++ b/doc/classes/Window.xml @@ -118,12 +118,14 @@ <return type="Vector2i" /> <description> Returns the window's position including its border. + [b]Note:[/b] If [member visible] is [code]false[/code], this method returns the same value as [member position]. </description> </method> <method name="get_size_with_decorations" qualifiers="const"> <return type="Vector2i" /> <description> Returns the window's size including its border. + [b]Note:[/b] If [member visible] is [code]false[/code], this method returns the same value as [member size]. </description> </method> <method name="get_theme_color" qualifiers="const"> diff --git a/doc/classes/XRServer.xml b/doc/classes/XRServer.xml index 4179ba821c..49b13986ca 100644 --- a/doc/classes/XRServer.xml +++ b/doc/classes/XRServer.xml @@ -135,6 +135,11 @@ Emitted when an interface is removed. </description> </signal> + <signal name="reference_frame_changed"> + <description> + Emitted when the reference frame transform changes. + </description> + </signal> <signal name="tracker_added"> <param index="0" name="tracker_name" type="StringName" /> <param index="1" name="type" type="int" /> diff --git a/doc/tools/make_rst.py b/doc/tools/make_rst.py index bc379f8553..761a7f8f4a 100755 --- a/doc/tools/make_rst.py +++ b/doc/tools/make_rst.py @@ -1110,11 +1110,13 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir: # Create signal signature and anchor point. - f.write(f".. _class_{class_name}_signal_{signal.name}:\n\n") + signal_anchor = f"class_{class_name}_signal_{signal.name}" + f.write(f".. _{signal_anchor}:\n\n") + self_link = f":ref:`🔗<{signal_anchor}>`" f.write(".. rst-class:: classref-signal\n\n") _, signature = make_method_signature(class_def, signal, "", state) - f.write(f"{signature}\n\n") + f.write(f"{signature} {self_link}\n\n") # Add signal description, or a call to action if it's missing. @@ -1147,13 +1149,15 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir: # Create enumeration signature and anchor point. - f.write(f".. _enum_{class_name}_{e.name}:\n\n") + enum_anchor = f"enum_{class_name}_{e.name}" + f.write(f".. _{enum_anchor}:\n\n") + self_link = f":ref:`🔗<{enum_anchor}>`" f.write(".. rst-class:: classref-enumeration\n\n") if e.is_bitfield: - f.write(f"flags **{e.name}**:\n\n") + f.write(f"flags **{e.name}**: {self_link}\n\n") else: - f.write(f"enum **{e.name}**:\n\n") + f.write(f"enum **{e.name}**: {self_link}\n\n") for value in e.values.values(): # Also create signature and anchor point for each enum constant. @@ -1191,10 +1195,12 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir: for constant in class_def.constants.values(): # Create constant signature and anchor point. - f.write(f".. _class_{class_name}_constant_{constant.name}:\n\n") + constant_anchor = f"class_{class_name}_constant_{constant.name}" + f.write(f".. _{constant_anchor}:\n\n") + self_link = f":ref:`🔗<{constant_anchor}>`" f.write(".. rst-class:: classref-constant\n\n") - f.write(f"**{constant.name}** = ``{constant.value}``\n\n") + f.write(f"**{constant.name}** = ``{constant.value}`` {self_link}\n\n") # Add constant description. @@ -1227,13 +1233,16 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir: # Create annotation signature and anchor point. + self_link = "" if i == 0: - f.write(f".. _class_{class_name}_annotation_{m.name}:\n\n") + annotation_anchor = f"class_{class_name}_annotation_{m.name}" + f.write(f".. _{annotation_anchor}:\n\n") + self_link = f" :ref:`🔗<{annotation_anchor}>`" f.write(".. rst-class:: classref-annotation\n\n") _, signature = make_method_signature(class_def, m, "", state) - f.write(f"{signature}\n\n") + f.write(f"{signature}{self_link}\n\n") # Add annotation description, or a call to action if it's missing. @@ -1267,13 +1276,17 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir: # Create property signature and anchor point. - f.write(f".. _class_{class_name}_property_{property_def.name}:\n\n") + property_anchor = f"class_{class_name}_property_{property_def.name}" + f.write(f".. _{property_anchor}:\n\n") + self_link = f":ref:`🔗<{property_anchor}>`" f.write(".. rst-class:: classref-property\n\n") property_default = "" if property_def.default_value is not None: property_default = f" = {property_def.default_value}" - f.write(f"{property_def.type_name.to_rst(state)} **{property_def.name}**{property_default}\n\n") + f.write( + f"{property_def.type_name.to_rst(state)} **{property_def.name}**{property_default} {self_link}\n\n" + ) # Create property setter and getter records. @@ -1327,13 +1340,16 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir: # Create constructor signature and anchor point. + self_link = "" if i == 0: - f.write(f".. _class_{class_name}_constructor_{m.name}:\n\n") + constructor_anchor = f"class_{class_name}_constructor_{m.name}" + f.write(f".. _{constructor_anchor}:\n\n") + self_link = f" :ref:`🔗<{constructor_anchor}>`" f.write(".. rst-class:: classref-constructor\n\n") ret_type, signature = make_method_signature(class_def, m, "", state) - f.write(f"{ret_type} {signature}\n\n") + f.write(f"{ret_type} {signature}{self_link}\n\n") # Add constructor description, or a call to action if it's missing. @@ -1366,17 +1382,21 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir: # Create method signature and anchor point. + self_link = "" + if i == 0: method_qualifier = "" if m.name.startswith("_"): method_qualifier = "private_" - - f.write(f".. _class_{class_name}_{method_qualifier}method_{m.name}:\n\n") + method_anchor = f"class_{class_name}_{method_qualifier}method_{m.name}" + f.write(f".. _{method_anchor}:\n\n") + self_link = f" :ref:`🔗<{method_anchor}>`" f.write(".. rst-class:: classref-method\n\n") ret_type, signature = make_method_signature(class_def, m, "", state) - f.write(f"{ret_type} {signature}\n\n") + + f.write(f"{ret_type} {signature}{self_link}\n\n") # Add method description, or a call to action if it's missing. @@ -1409,16 +1429,16 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir: # Create operator signature and anchor point. - operator_anchor = f".. _class_{class_name}_operator_{sanitize_operator_name(m.name, state)}" + operator_anchor = f"class_{class_name}_operator_{sanitize_operator_name(m.name, state)}" for parameter in m.parameters: operator_anchor += f"_{parameter.type_name.type_name}" - operator_anchor += ":\n\n" - f.write(operator_anchor) + f.write(f".. _{operator_anchor}:\n\n") + self_link = f":ref:`🔗<{operator_anchor}>`" f.write(".. rst-class:: classref-operator\n\n") ret_type, signature = make_method_signature(class_def, m, "", state) - f.write(f"{ret_type} {signature}\n\n") + f.write(f"{ret_type} {signature} {self_link}\n\n") # Add operator description, or a call to action if it's missing. @@ -1451,13 +1471,17 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir: # Create theme property signature and anchor point. - f.write(f".. _class_{class_name}_theme_{theme_item_def.data_name}_{theme_item_def.name}:\n\n") + theme_item_anchor = f"class_{class_name}_theme_{theme_item_def.data_name}_{theme_item_def.name}" + f.write(f".. _{theme_item_anchor}:\n\n") + self_link = f":ref:`🔗<{theme_item_anchor}>`" f.write(".. rst-class:: classref-themeproperty\n\n") theme_item_default = "" if theme_item_def.default_value is not None: theme_item_default = f" = {theme_item_def.default_value}" - f.write(f"{theme_item_def.type_name.to_rst(state)} **{theme_item_def.name}**{theme_item_default}\n\n") + f.write( + f"{theme_item_def.type_name.to_rst(state)} **{theme_item_def.name}**{theme_item_default} {self_link}\n\n" + ) # Add theme property description, or a call to action if it's missing. diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp index b042d41524..fb278a4d56 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.cpp +++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp @@ -538,15 +538,6 @@ void RenderingDeviceDriverD3D12::_resource_transition_batch(ResourceInfo *p_reso #endif ResourceInfo::States *res_states = p_resource->states_ptr; - - if (p_new_state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS) { - if (unlikely(!res_states->xfamily_fallback.subresources_dirty.is_empty())) { - uint32_t subres_qword = p_subresource / 64; - uint64_t subres_mask = (uint64_t(1) << (p_subresource % 64)); - res_states->xfamily_fallback.subresources_dirty[subres_qword] |= subres_mask; - } - } - D3D12_RESOURCE_STATES *curr_state = &res_states->subresource_states[p_subresource]; // Transitions can be considered redundant if the current state has all the bits of the new state. @@ -869,7 +860,7 @@ RDD::BufferID RenderingDeviceDriverD3D12::buffer_create(uint64_t p_size, BitFiel // but also if you give a rounded size at that point because it will extend beyond the // memory of the resource. Therefore, it seems the only way is to create it with a // rounded size. - CD3DX12_RESOURCE_DESC resource_desc = CD3DX12_RESOURCE_DESC::Buffer(STEPIFY(p_size, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT)); + CD3DX12_RESOURCE_DESC1 resource_desc = CD3DX12_RESOURCE_DESC1::Buffer(STEPIFY(p_size, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT)); if (p_usage.has_flag(RDD::BUFFER_USAGE_STORAGE_BIT)) { resource_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; } else { @@ -878,7 +869,6 @@ RDD::BufferID RenderingDeviceDriverD3D12::buffer_create(uint64_t p_size, BitFiel D3D12MA::ALLOCATION_DESC allocation_desc = {}; allocation_desc.HeapType = D3D12_HEAP_TYPE_DEFAULT; - D3D12_RESOURCE_STATES initial_state = D3D12_RESOURCE_STATE_COPY_DEST; switch (p_allocation_type) { case MEMORY_ALLOCATION_TYPE_CPU: { bool is_src = p_usage.has_flag(BUFFER_USAGE_TRANSFER_FROM_BIT); @@ -886,7 +876,6 @@ RDD::BufferID RenderingDeviceDriverD3D12::buffer_create(uint64_t p_size, BitFiel if (is_src && !is_dst) { // Looks like a staging buffer: CPU maps, writes sequentially, then GPU copies to VRAM. allocation_desc.HeapType = D3D12_HEAP_TYPE_UPLOAD; - initial_state = D3D12_RESOURCE_STATE_GENERIC_READ; } if (is_dst && !is_src) { // Looks like a readback buffer: GPU copies from VRAM, then CPU maps and reads. @@ -904,13 +893,27 @@ RDD::BufferID RenderingDeviceDriverD3D12::buffer_create(uint64_t p_size, BitFiel ComPtr<ID3D12Resource> buffer; ComPtr<D3D12MA::Allocation> allocation; - HRESULT res = allocator->CreateResource( - &allocation_desc, - &resource_desc, - initial_state, - nullptr, - allocation.GetAddressOf(), - IID_PPV_ARGS(buffer.GetAddressOf())); + HRESULT res; + if (barrier_capabilities.enhanced_barriers_supported) { + res = allocator->CreateResource3( + &allocation_desc, + &resource_desc, + D3D12_BARRIER_LAYOUT_UNDEFINED, + nullptr, + 0, + nullptr, + allocation.GetAddressOf(), + IID_PPV_ARGS(buffer.GetAddressOf())); + } else { + res = allocator->CreateResource( + &allocation_desc, + reinterpret_cast<const D3D12_RESOURCE_DESC *>(&resource_desc), + D3D12_RESOURCE_STATE_COMMON, + nullptr, + allocation.GetAddressOf(), + IID_PPV_ARGS(buffer.GetAddressOf())); + } + ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), BufferID(), "Can't create buffer of size: " + itos(p_size) + ", error " + vformat("0x%08ux", (uint64_t)res) + "."); // Bookkeep. @@ -919,11 +922,10 @@ RDD::BufferID RenderingDeviceDriverD3D12::buffer_create(uint64_t p_size, BitFiel buf_info->resource = buffer.Get(); buf_info->owner_info.resource = buffer; buf_info->owner_info.allocation = allocation; - buf_info->owner_info.states.subresource_states.push_back(initial_state); + buf_info->owner_info.states.subresource_states.push_back(D3D12_RESOURCE_STATE_COMMON); buf_info->states_ptr = &buf_info->owner_info.states; buf_info->size = p_size; buf_info->flags.usable_as_uav = (resource_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS); - buf_info->flags.is_for_upload = allocation_desc.HeapType == D3D12_HEAP_TYPE_UPLOAD; return BufferID(buf_info); } @@ -1052,8 +1054,7 @@ UINT RenderingDeviceDriverD3D12::_compute_plane_slice(DataFormat p_format, BitFi if (p_aspect_bits.has_flag(TEXTURE_ASPECT_DEPTH_BIT)) { DEV_ASSERT(aspect == TEXTURE_ASPECT_MAX); aspect = TEXTURE_ASPECT_DEPTH; - } - if (p_aspect_bits.has_flag(TEXTURE_ASPECT_STENCIL_BIT)) { + } else if (p_aspect_bits.has_flag(TEXTURE_ASPECT_STENCIL_BIT)) { DEV_ASSERT(aspect == TEXTURE_ASPECT_MAX); aspect = TEXTURE_ASPECT_STENCIL; } @@ -1080,6 +1081,10 @@ UINT RenderingDeviceDriverD3D12::_compute_plane_slice(DataFormat p_format, Textu } } +UINT RenderingDeviceDriverD3D12::_compute_subresource_from_layers(TextureInfo *p_texture, const TextureSubresourceLayers &p_layers, uint32_t p_layer_offset) { + return D3D12CalcSubresource(p_layers.mipmap, p_layers.base_layer + p_layer_offset, _compute_plane_slice(p_texture->format, p_layers.aspect), p_texture->desc.MipLevels, p_texture->desc.ArraySize()); +} + void RenderingDeviceDriverD3D12::_discard_texture_subresources(const TextureInfo *p_tex_info, const CommandBufferInfo *p_cmd_buf_info) { uint32_t planes = 1; if ((p_tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) { @@ -1117,6 +1122,64 @@ void RenderingDeviceDriverD3D12::_discard_texture_subresources(const TextureInfo } } +bool RenderingDeviceDriverD3D12::_unordered_access_supported_by_format(DataFormat p_format) { + switch (p_format) { + case DATA_FORMAT_R4G4_UNORM_PACK8: + case DATA_FORMAT_R4G4B4A4_UNORM_PACK16: + case DATA_FORMAT_B4G4R4A4_UNORM_PACK16: + case DATA_FORMAT_R5G6B5_UNORM_PACK16: + case DATA_FORMAT_B5G6R5_UNORM_PACK16: + case DATA_FORMAT_R5G5B5A1_UNORM_PACK16: + case DATA_FORMAT_B5G5R5A1_UNORM_PACK16: + case DATA_FORMAT_A1R5G5B5_UNORM_PACK16: + case DATA_FORMAT_A8B8G8R8_UNORM_PACK32: + case DATA_FORMAT_A8B8G8R8_SNORM_PACK32: + case DATA_FORMAT_A8B8G8R8_USCALED_PACK32: + case DATA_FORMAT_A8B8G8R8_SSCALED_PACK32: + case DATA_FORMAT_A8B8G8R8_UINT_PACK32: + case DATA_FORMAT_A8B8G8R8_SINT_PACK32: + case DATA_FORMAT_A8B8G8R8_SRGB_PACK32: + case DATA_FORMAT_A2R10G10B10_UNORM_PACK32: + case DATA_FORMAT_A2R10G10B10_SNORM_PACK32: + case DATA_FORMAT_A2R10G10B10_USCALED_PACK32: + case DATA_FORMAT_A2R10G10B10_SSCALED_PACK32: + case DATA_FORMAT_A2R10G10B10_UINT_PACK32: + case DATA_FORMAT_A2R10G10B10_SINT_PACK32: + case DATA_FORMAT_A2B10G10R10_UNORM_PACK32: + case DATA_FORMAT_A2B10G10R10_SNORM_PACK32: + case DATA_FORMAT_A2B10G10R10_USCALED_PACK32: + case DATA_FORMAT_A2B10G10R10_SSCALED_PACK32: + case DATA_FORMAT_A2B10G10R10_UINT_PACK32: + case DATA_FORMAT_A2B10G10R10_SINT_PACK32: + case DATA_FORMAT_B10G11R11_UFLOAT_PACK32: + case DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32: + case DATA_FORMAT_X8_D24_UNORM_PACK32: + case DATA_FORMAT_R10X6_UNORM_PACK16: + case DATA_FORMAT_R10X6G10X6_UNORM_2PACK16: + case DATA_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16: + case DATA_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16: + case DATA_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16: + case DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16: + case DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16: + case DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16: + case DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16: + case DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16: + case DATA_FORMAT_R12X4_UNORM_PACK16: + case DATA_FORMAT_R12X4G12X4_UNORM_2PACK16: + case DATA_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16: + case DATA_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16: + case DATA_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16: + case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16: + case DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16: + case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16: + case DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16: + case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16: + return false; + default: + return true; + } +} + RDD::TextureID RenderingDeviceDriverD3D12::texture_create(const TextureFormat &p_format, const TextureView &p_view) { // Using D3D12_RESOURCE_DESC1. Thanks to the layout, it's sliceable down to D3D12_RESOURCE_DESC if needed. CD3DX12_RESOURCE_DESC1 resource_desc = {}; @@ -1137,12 +1200,10 @@ RDD::TextureID RenderingDeviceDriverD3D12::texture_create(const TextureFormat &p resource_desc.Format = RD_TO_D3D12_FORMAT[p_format.format].family; // If views of different families are wanted, special setup is needed for proper sharing among them. - // Two options here: - // 1. If the driver reports relaxed casting is, leverage its new extended resource creation API (via D3D12MA). - // 2. Otherwise, fall back to an approach based on having multiple versions of the resource and copying as needed. [[CROSS_FAMILY_FALLBACK]] + // If the driver reports relaxed casting is, leverage its new extended resource creation API (via D3D12MA). if (p_format.shareable_formats.size() && format_capabilities.relaxed_casting_supported) { relaxed_casting_available = true; - relaxed_casting_formats = ALLOCA_ARRAY(DXGI_FORMAT, p_format.shareable_formats.size()); + relaxed_casting_formats = ALLOCA_ARRAY(DXGI_FORMAT, p_format.shareable_formats.size() + 1); relaxed_casting_formats[0] = RD_TO_D3D12_FORMAT[p_format.format].general_format; relaxed_casting_format_count++; } @@ -1156,9 +1217,9 @@ RDD::TextureID RenderingDeviceDriverD3D12::texture_create(const TextureFormat &p if (RD_TO_D3D12_FORMAT[curr_format].family != RD_TO_D3D12_FORMAT[p_format.format].family) { cross_family_sharing = true; - if (!relaxed_casting_available) { - break; - } + } + + if (relaxed_casting_available) { relaxed_casting_formats[relaxed_casting_format_count] = RD_TO_D3D12_FORMAT[curr_format].general_format; relaxed_casting_format_count++; } @@ -1185,7 +1246,7 @@ RDD::TextureID RenderingDeviceDriverD3D12::texture_create(const TextureFormat &p if ((p_format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) { resource_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; } else { - if ((p_format.usage_bits & TEXTURE_USAGE_CAN_COPY_TO_BIT)) { + if ((p_format.usage_bits & TEXTURE_USAGE_CAN_COPY_TO_BIT) && _unordered_access_supported_by_format(p_format.format)) { resource_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; // For clearing via UAV. } } @@ -1242,17 +1303,19 @@ RDD::TextureID RenderingDeviceDriverD3D12::texture_create(const TextureFormat &p D3D12_CLEAR_VALUE *clear_value_ptr = (resource_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) ? &clear_value : nullptr; { HRESULT res = E_FAIL; - if (cross_family_sharing && relaxed_casting_available) { + if (barrier_capabilities.enhanced_barriers_supported || (cross_family_sharing && relaxed_casting_available)) { + // Create with undefined layout if enhanced barriers are supported. Leave as common otherwise for interop with legacy barriers. + D3D12_BARRIER_LAYOUT initial_layout = barrier_capabilities.enhanced_barriers_supported ? D3D12_BARRIER_LAYOUT_UNDEFINED : D3D12_BARRIER_LAYOUT_COMMON; res = allocator->CreateResource3( &allocation_desc, &resource_desc, - D3D12_BARRIER_LAYOUT_COMMON, // Needed for barrier interop. + initial_layout, clear_value_ptr, relaxed_casting_format_count, relaxed_casting_formats, allocation.GetAddressOf(), IID_PPV_ARGS(main_texture.GetAddressOf())); - initial_state = D3D12_RESOURCE_STATE_COMMON; // Needed for barrier interop. + initial_state = D3D12_RESOURCE_STATE_COMMON; } else { res = allocator->CreateResource( &allocation_desc, @@ -1353,7 +1416,10 @@ RDD::TextureID RenderingDeviceDriverD3D12::texture_create(const TextureFormat &p tex_info->mipmaps = resource_desc.MipLevels; tex_info->view_descs.srv = srv_desc; tex_info->view_descs.uav = uav_desc; - if ((p_format.usage_bits & (TEXTURE_USAGE_STORAGE_BIT | TEXTURE_USAGE_COLOR_ATTACHMENT_BIT))) { + + if (!barrier_capabilities.enhanced_barriers_supported && (p_format.usage_bits & (TEXTURE_USAGE_STORAGE_BIT | TEXTURE_USAGE_COLOR_ATTACHMENT_BIT))) { + // Fallback to clear resources when they're first used in a uniform set. Not necessary if enhanced barriers + // are supported, as the discard flag will be used instead when transitioning from an undefined layout. textures_pending_clear.add(&tex_info->pending_clear); } @@ -1380,45 +1446,8 @@ RDD::TextureID RenderingDeviceDriverD3D12::_texture_create_shared_from_slice(Tex ComPtr<ID3D12Resource> new_texture; ComPtr<D3D12MA::Allocation> new_allocation; - ID3D12Resource *resource = nullptr; + ID3D12Resource *resource = owner_tex_info->resource; CD3DX12_RESOURCE_DESC new_tex_resource_desc = owner_tex_info->desc; - bool cross_family = RD_TO_D3D12_FORMAT[p_view.format].family != RD_TO_D3D12_FORMAT[owner_tex_info->format].family; - if (cross_family && !format_capabilities.relaxed_casting_supported) { - // [[CROSS_FAMILY_FALLBACK]]. - // We have to create a new texture of the alternative format. - - D3D12MA::ALLOCATION_DESC allocation_desc = {}; - allocation_desc.HeapType = D3D12_HEAP_TYPE_DEFAULT; - allocation_desc.ExtraHeapFlags = D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES; - - if (p_slice_type != -1) { -#ifdef DEV_ENABLED - // Actual slicing is not contemplated. If ever needed, let's at least realize. - if (p_slice_type != -1) { - uint32_t new_texture_subresorce_count = owner_tex_info->mipmaps * owner_tex_info->layers; - uint32_t slice_subresorce_count = p_mipmaps * p_layers; - DEV_ASSERT(new_texture_subresorce_count == slice_subresorce_count); - } -#endif - new_tex_resource_desc.DepthOrArraySize = p_layers; - new_tex_resource_desc.MipLevels = p_mipmaps; - } - new_tex_resource_desc.Format = RD_TO_D3D12_FORMAT[p_view.format].family; - new_tex_resource_desc.Flags = D3D12_RESOURCE_FLAG_NONE; // Alternative formats can only be used as SRVs. - - HRESULT res = allocator->CreateResource( - &allocation_desc, - &new_tex_resource_desc, - D3D12_RESOURCE_STATE_COPY_DEST, - nullptr, - new_allocation.GetAddressOf(), - IID_PPV_ARGS(new_texture.GetAddressOf())); - ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), TextureID(), vformat("D3D12MA::CreateResource failed with error 0x%08ux.", (uint64_t)res)); - - resource = new_texture.Get(); - } else { - resource = owner_tex_info->resource; - } // Describe views. @@ -1528,58 +1557,7 @@ RDD::TextureID RenderingDeviceDriverD3D12::_texture_create_shared_from_slice(Tex TextureInfo *tex_info = VersatileResource::allocate<TextureInfo>(resources_allocator); tex_info->resource = resource; - if (new_texture.Get()) { - // [[CROSS_FAMILY_FALLBACK]]. - - DEV_ASSERT(cross_family && !format_capabilities.relaxed_casting_supported); - - uint32_t new_texture_subresorce_count = owner_tex_info->mipmaps * owner_tex_info->layers; -#ifdef DEV_ENABLED - // Actual slicing is not contemplated. If ever needed, let's at least realize. - if (p_slice_type != -1) { - uint32_t slice_subresorce_count = p_mipmaps * p_layers; - DEV_ASSERT(new_texture_subresorce_count == slice_subresorce_count); - } -#endif - - tex_info->owner_info.resource = new_texture; - tex_info->owner_info.allocation = new_allocation; - tex_info->owner_info.states.subresource_states.resize(new_texture_subresorce_count); - for (uint32_t i = 0; i < tex_info->owner_info.states.subresource_states.size(); i++) { - tex_info->owner_info.states.subresource_states[i] = D3D12_RESOURCE_STATE_COPY_DEST; - } - tex_info->states_ptr = &tex_info->owner_info.states; - - ResourceInfo::States::CrossFamillyFallback &xfamily = owner_tex_info->owner_info.states.xfamily_fallback; - if (xfamily.subresources_dirty.is_empty()) { - uint32_t items_required = STEPIFY(new_texture_subresorce_count, sizeof(uint64_t)) / sizeof(uint64_t); - xfamily.subresources_dirty.resize(items_required); - memset(xfamily.subresources_dirty.ptr(), 255, sizeof(uint64_t) * xfamily.subresources_dirty.size()); - - // Create buffer for non-direct copy if it's a format not supporting reinterpret-copy. - DEV_ASSERT(!xfamily.interim_buffer.Get()); - if (owner_tex_info->format == DATA_FORMAT_R16_UINT && p_view.format == DATA_FORMAT_R4G4B4A4_UNORM_PACK16) { - uint32_t row_pitch = STEPIFY(owner_tex_info->desc.Width * sizeof(uint16_t), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); - uint32_t buffer_size = sizeof(uint16_t) * row_pitch * owner_tex_info->desc.Height * owner_tex_info->desc.Depth(); - CD3DX12_RESOURCE_DESC resource_desc = CD3DX12_RESOURCE_DESC::Buffer(STEPIFY(buffer_size, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT)); - resource_desc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE; - - D3D12MA::ALLOCATION_DESC allocation_desc = {}; - allocation_desc.HeapType = D3D12_HEAP_TYPE_DEFAULT; - - HRESULT res = allocator->CreateResource( - &allocation_desc, - &resource_desc, - D3D12_RESOURCE_STATE_COPY_SOURCE, // Makes the code that makes the copy easier. - nullptr, - xfamily.interim_buffer_alloc.GetAddressOf(), - IID_PPV_ARGS(xfamily.interim_buffer.GetAddressOf())); - ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), TextureID(), "D3D12MA::CreateResource failed with error " + vformat("0x%08ux", (uint64_t)res) + "."); - } - } - } else { - tex_info->states_ptr = owner_tex_info->states_ptr; - } + tex_info->states_ptr = owner_tex_info->states_ptr; tex_info->format = p_view.format; tex_info->desc = new_tex_resource_desc; if (p_slice_type == -1) { @@ -1710,6 +1688,28 @@ BitField<RDD::TextureUsageBits> RenderingDeviceDriverD3D12::texture_get_usages_s return supported; } +bool RenderingDeviceDriverD3D12::texture_can_make_shared_with_format(TextureID p_texture, DataFormat p_format, bool &r_raw_reinterpretation) { + r_raw_reinterpretation = false; + + if (format_capabilities.relaxed_casting_supported) { + // Relaxed casting is supported, there should be no need to check for format family compatibility. + return true; + } else { + TextureInfo *tex_info = (TextureInfo *)p_texture.id; + if (tex_info->format == DATA_FORMAT_R16_UINT && p_format == DATA_FORMAT_R4G4B4A4_UNORM_PACK16) { + // Specific cases that require buffer reinterpretation. + r_raw_reinterpretation = true; + return false; + } else if (RD_TO_D3D12_FORMAT[tex_info->format].family != RD_TO_D3D12_FORMAT[p_format].family) { + // Format family is different but copying resources directly is possible. + return false; + } else { + // Format family is the same and the view can just cast the format. + return true; + } + } +} + /*****************/ /**** SAMPLER ****/ /*****************/ @@ -1842,20 +1842,328 @@ void RenderingDeviceDriverD3D12::vertex_format_free(VertexFormatID p_vertex_form /**** BARRIERS ****/ /******************/ -void RenderingDeviceDriverD3D12::command_pipeline_barrier( - CommandBufferID p_cmd_buffer, - BitField<RDD::PipelineStageBits> p_src_stages, - BitField<RDD::PipelineStageBits> p_dst_stages, +static D3D12_BARRIER_ACCESS _rd_texture_layout_access_mask(RDD::TextureLayout p_texture_layout) { + switch (p_texture_layout) { + case RDD::TEXTURE_LAYOUT_STORAGE_OPTIMAL: + return D3D12_BARRIER_ACCESS_UNORDERED_ACCESS; + case RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + return D3D12_BARRIER_ACCESS_RENDER_TARGET; + case RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + return D3D12_BARRIER_ACCESS_DEPTH_STENCIL_READ | D3D12_BARRIER_ACCESS_DEPTH_STENCIL_WRITE; + case RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: + return D3D12_BARRIER_ACCESS_DEPTH_STENCIL_READ; + case RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + return D3D12_BARRIER_ACCESS_SHADER_RESOURCE; + case RDD::TEXTURE_LAYOUT_COPY_SRC_OPTIMAL: + return D3D12_BARRIER_ACCESS_COPY_SOURCE; + case RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL: + return D3D12_BARRIER_ACCESS_COPY_DEST; + case RDD::TEXTURE_LAYOUT_RESOLVE_SRC_OPTIMAL: + return D3D12_BARRIER_ACCESS_RESOLVE_SOURCE; + case RDD::TEXTURE_LAYOUT_RESOLVE_DST_OPTIMAL: + return D3D12_BARRIER_ACCESS_RESOLVE_DEST; + case RDD::TEXTURE_LAYOUT_VRS_ATTACHMENT_OPTIMAL: + return D3D12_BARRIER_ACCESS_SHADING_RATE_SOURCE; + default: + return D3D12_BARRIER_ACCESS_NO_ACCESS; + } +} + +static void _rd_access_to_d3d12_and_mask(BitField<RDD::BarrierAccessBits> p_access, RDD::TextureLayout p_texture_layout, D3D12_BARRIER_ACCESS &r_access, D3D12_BARRIER_SYNC &r_sync_mask) { + r_access = D3D12_BARRIER_ACCESS_COMMON; + r_sync_mask = D3D12_BARRIER_SYNC_NONE; + + if (p_access.has_flag(RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT)) { + r_access |= D3D12_BARRIER_ACCESS_INDIRECT_ARGUMENT; + r_sync_mask |= D3D12_BARRIER_SYNC_EXECUTE_INDIRECT; + } + + if (p_access.has_flag(RDD::BARRIER_ACCESS_INDEX_READ_BIT)) { + r_access |= D3D12_BARRIER_ACCESS_INDEX_BUFFER; + r_sync_mask |= D3D12_BARRIER_SYNC_INDEX_INPUT | D3D12_BARRIER_SYNC_DRAW; + } + + if (p_access.has_flag(RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT)) { + r_access |= D3D12_BARRIER_ACCESS_VERTEX_BUFFER; + r_sync_mask |= D3D12_BARRIER_SYNC_VERTEX_SHADING | D3D12_BARRIER_SYNC_DRAW | D3D12_BARRIER_SYNC_ALL_SHADING; + } + + if (p_access.has_flag(RDD::BARRIER_ACCESS_UNIFORM_READ_BIT)) { + r_access |= D3D12_BARRIER_ACCESS_CONSTANT_BUFFER; + r_sync_mask |= D3D12_BARRIER_SYNC_VERTEX_SHADING | D3D12_BARRIER_SYNC_PIXEL_SHADING | D3D12_BARRIER_SYNC_COMPUTE_SHADING | + D3D12_BARRIER_SYNC_DRAW | D3D12_BARRIER_SYNC_ALL_SHADING; + } + + if (p_access.has_flag(RDD::BARRIER_ACCESS_INPUT_ATTACHMENT_READ_BIT)) { + r_access |= D3D12_BARRIER_ACCESS_RENDER_TARGET; + r_sync_mask |= D3D12_BARRIER_SYNC_DRAW | D3D12_BARRIER_SYNC_RENDER_TARGET; + } + + if (p_access.has_flag(RDD::BARRIER_ACCESS_COPY_READ_BIT)) { + r_access |= D3D12_BARRIER_ACCESS_COPY_SOURCE; + r_sync_mask |= D3D12_BARRIER_SYNC_COPY; + } + + if (p_access.has_flag(RDD::BARRIER_ACCESS_COPY_WRITE_BIT)) { + r_access |= D3D12_BARRIER_ACCESS_COPY_DEST; + r_sync_mask |= D3D12_BARRIER_SYNC_COPY; + } + + if (p_access.has_flag(RDD::BARRIER_ACCESS_RESOLVE_READ_BIT)) { + r_access |= D3D12_BARRIER_ACCESS_RESOLVE_SOURCE; + r_sync_mask |= D3D12_BARRIER_SYNC_RESOLVE; + } + + if (p_access.has_flag(RDD::BARRIER_ACCESS_RESOLVE_WRITE_BIT)) { + r_access |= D3D12_BARRIER_ACCESS_RESOLVE_DEST; + r_sync_mask |= D3D12_BARRIER_SYNC_RESOLVE; + } + + if (p_access.has_flag(RDD::BARRIER_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT)) { + r_access |= D3D12_BARRIER_ACCESS_SHADING_RATE_SOURCE; + r_sync_mask |= D3D12_BARRIER_SYNC_PIXEL_SHADING | D3D12_BARRIER_SYNC_ALL_SHADING; + } + + const D3D12_BARRIER_SYNC unordered_access_mask = D3D12_BARRIER_SYNC_VERTEX_SHADING | D3D12_BARRIER_SYNC_PIXEL_SHADING | D3D12_BARRIER_SYNC_COMPUTE_SHADING | + D3D12_BARRIER_SYNC_VERTEX_SHADING | D3D12_BARRIER_SYNC_DRAW | D3D12_BARRIER_SYNC_ALL_SHADING | D3D12_BARRIER_SYNC_CLEAR_UNORDERED_ACCESS_VIEW; + + if (p_access.has_flag(RDD::BARRIER_ACCESS_STORAGE_CLEAR_BIT)) { + r_access |= D3D12_BARRIER_ACCESS_UNORDERED_ACCESS; + r_sync_mask |= unordered_access_mask; + } + + // These access bits only have compatibility with certain layouts unlike in Vulkan where they imply specific operations in the same layout. + if (p_access.has_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT)) { + r_access |= D3D12_BARRIER_ACCESS_UNORDERED_ACCESS; + r_sync_mask |= unordered_access_mask; + } else if (p_access.has_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT)) { + if (p_texture_layout == RDD::TEXTURE_LAYOUT_STORAGE_OPTIMAL) { + // Unordered access must be enforced if the texture is using the storage layout. + r_access |= D3D12_BARRIER_ACCESS_UNORDERED_ACCESS; + r_sync_mask |= unordered_access_mask; + } else { + r_access |= D3D12_BARRIER_ACCESS_SHADER_RESOURCE; + r_sync_mask |= D3D12_BARRIER_SYNC_VERTEX_SHADING | D3D12_BARRIER_SYNC_PIXEL_SHADING | D3D12_BARRIER_SYNC_COMPUTE_SHADING | D3D12_BARRIER_SYNC_DRAW | D3D12_BARRIER_SYNC_ALL_SHADING; + } + } + + if (p_access.has_flag(RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT) || p_access.has_flag(RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_READ_BIT)) { + r_access |= D3D12_BARRIER_ACCESS_RENDER_TARGET; + r_sync_mask |= D3D12_BARRIER_SYNC_DRAW | D3D12_BARRIER_SYNC_RENDER_TARGET; + } + + if (p_access.has_flag(RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT)) { + r_access |= D3D12_BARRIER_ACCESS_DEPTH_STENCIL_WRITE; + r_sync_mask |= D3D12_BARRIER_SYNC_DRAW | D3D12_BARRIER_SYNC_DEPTH_STENCIL; + } else if (p_access.has_flag(RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT)) { + r_access |= D3D12_BARRIER_ACCESS_DEPTH_STENCIL_READ; + r_sync_mask |= D3D12_BARRIER_SYNC_DRAW | D3D12_BARRIER_SYNC_DEPTH_STENCIL; + } +} + +static void _rd_stages_to_d3d12(BitField<RDD::PipelineStageBits> p_stages, D3D12_BARRIER_SYNC &r_sync) { + if (p_stages.has_flag(RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT)) { + r_sync = D3D12_BARRIER_SYNC_ALL; + } else { + if (p_stages.has_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT)) { + r_sync |= D3D12_BARRIER_SYNC_EXECUTE_INDIRECT; + } + + if (p_stages.has_flag(RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT)) { + r_sync |= D3D12_BARRIER_SYNC_INDEX_INPUT; + } + + if (p_stages.has_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT)) { + r_sync |= D3D12_BARRIER_SYNC_VERTEX_SHADING; + } + + if (p_stages.has_flag(RDD::PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT) || p_stages.has_flag(RDD::PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT) || p_stages.has_flag(RDD::PIPELINE_STAGE_GEOMETRY_SHADER_BIT)) { + // There's no granularity for tessellation or geometry stages. The specification defines it as part of vertex shading. + r_sync |= D3D12_BARRIER_SYNC_VERTEX_SHADING; + } + + if (p_stages.has_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT)) { + r_sync |= D3D12_BARRIER_SYNC_PIXEL_SHADING; + } + + if (p_stages.has_flag(RDD::PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT) || p_stages.has_flag(RDD::PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT)) { + // Covers both read and write operations for depth stencil. + r_sync |= D3D12_BARRIER_SYNC_DEPTH_STENCIL; + } + + if (p_stages.has_flag(RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)) { + r_sync |= D3D12_BARRIER_SYNC_RENDER_TARGET; + } + + if (p_stages.has_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT)) { + r_sync |= D3D12_BARRIER_SYNC_COMPUTE_SHADING; + } + + if (p_stages.has_flag(RDD::PIPELINE_STAGE_COPY_BIT)) { + r_sync |= D3D12_BARRIER_SYNC_COPY; + } + + if (p_stages.has_flag(RDD::PIPELINE_STAGE_RESOLVE_BIT)) { + r_sync |= D3D12_BARRIER_SYNC_RESOLVE; + } + + if (p_stages.has_flag(RDD::PIPELINE_STAGE_CLEAR_STORAGE_BIT)) { + r_sync |= D3D12_BARRIER_SYNC_CLEAR_UNORDERED_ACCESS_VIEW; + } + + if (p_stages.has_flag(RDD::PIPELINE_STAGE_ALL_GRAPHICS_BIT)) { + r_sync |= D3D12_BARRIER_SYNC_DRAW; + } + } +} + +static void _rd_stages_and_access_to_d3d12(BitField<RDD::PipelineStageBits> p_stages, RDD::TextureLayout p_texture_layout, BitField<RDD::BarrierAccessBits> p_access, D3D12_BARRIER_SYNC &r_sync, D3D12_BARRIER_ACCESS &r_access) { + D3D12_BARRIER_SYNC sync_mask; + r_sync = D3D12_BARRIER_SYNC_NONE; + + if (p_texture_layout == RDD::TEXTURE_LAYOUT_UNDEFINED) { + // Undefined texture layouts are a special case where no access bits or synchronization scopes are allowed. + r_access = D3D12_BARRIER_ACCESS_NO_ACCESS; + return; + } + + // Convert access bits to the D3D12 barrier access bits. + _rd_access_to_d3d12_and_mask(p_access, p_texture_layout, r_access, sync_mask); + + if (p_texture_layout != RDD::TEXTURE_LAYOUT_MAX) { + // Only allow the access bits compatible with the texture layout. + r_access &= _rd_texture_layout_access_mask(p_texture_layout); + } + + // Convert stage bits to the D3D12 synchronization scope bits. + _rd_stages_to_d3d12(p_stages, r_sync); + + // Only enable synchronization stages compatible with the access bits that were used. + r_sync &= sync_mask; + + if (r_sync == D3D12_BARRIER_SYNC_NONE) { + if (p_access.is_empty()) { + // No valid synchronization scope was defined and no access in particular is required. + r_access = D3D12_BARRIER_ACCESS_NO_ACCESS; + } else { + // Access is required but the synchronization scope wasn't compatible. We fall back to the global synchronization scope and access. + r_sync = D3D12_BARRIER_SYNC_ALL; + r_access = D3D12_BARRIER_ACCESS_COMMON; + } + } +} + +static D3D12_BARRIER_LAYOUT _rd_texture_layout_to_d3d12_barrier_layout(RDD::TextureLayout p_texture_layout) { + switch (p_texture_layout) { + case RDD::TEXTURE_LAYOUT_UNDEFINED: + return D3D12_BARRIER_LAYOUT_UNDEFINED; + case RDD::TEXTURE_LAYOUT_STORAGE_OPTIMAL: + return D3D12_BARRIER_LAYOUT_UNORDERED_ACCESS; + case RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + return D3D12_BARRIER_LAYOUT_RENDER_TARGET; + case RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + return D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_WRITE; + case RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: + return D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_READ; + case RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + return D3D12_BARRIER_LAYOUT_SHADER_RESOURCE; + case RDD::TEXTURE_LAYOUT_COPY_SRC_OPTIMAL: + return D3D12_BARRIER_LAYOUT_COPY_SOURCE; + case RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL: + return D3D12_BARRIER_LAYOUT_COPY_DEST; + case RDD::TEXTURE_LAYOUT_RESOLVE_SRC_OPTIMAL: + return D3D12_BARRIER_LAYOUT_RESOLVE_SOURCE; + case RDD::TEXTURE_LAYOUT_RESOLVE_DST_OPTIMAL: + return D3D12_BARRIER_LAYOUT_RESOLVE_DEST; + case RDD::TEXTURE_LAYOUT_VRS_ATTACHMENT_OPTIMAL: + return D3D12_BARRIER_LAYOUT_SHADING_RATE_SOURCE; + default: + DEV_ASSERT(false && "Unknown texture layout."); + return D3D12_BARRIER_LAYOUT_UNDEFINED; + } +} + +void RenderingDeviceDriverD3D12::command_pipeline_barrier(CommandBufferID p_cmd_buffer, + BitField<PipelineStageBits> p_src_stages, + BitField<PipelineStageBits> p_dst_stages, VectorView<RDD::MemoryBarrier> p_memory_barriers, VectorView<RDD::BufferBarrier> p_buffer_barriers, VectorView<RDD::TextureBarrier> p_texture_barriers) { - if (p_src_stages.has_flag(PIPELINE_STAGE_ALL_COMMANDS_BIT) && p_dst_stages.has_flag(PIPELINE_STAGE_ALL_COMMANDS_BIT)) { - // Looks like the intent is a full barrier. - // In the resource barriers world, we can force a full barrier by discarding some resource, as per - // https://microsoft.github.io/DirectX-Specs/d3d/D3D12EnhancedBarriers.html#synchronous-copy-discard-and-resolve. - const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id; - cmd_buf_info->cmd_list->DiscardResource(frames[frame_idx].aux_resource->GetResource(), nullptr); + if (!barrier_capabilities.enhanced_barriers_supported) { + // Enhanced barriers are a requirement for this function. + return; + } + + if (p_memory_barriers.size() == 0 && p_buffer_barriers.size() == 0 && p_texture_barriers.size() == 0) { + // At least one barrier must be present in the arguments. + return; } + + // The command list must support the required interface. + const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)(p_cmd_buffer.id); + ID3D12GraphicsCommandList7 *cmd_list_7 = nullptr; + HRESULT res = cmd_buf_info->cmd_list->QueryInterface(IID_PPV_ARGS(&cmd_list_7)); + ERR_FAIL_COND(FAILED(res)); + + // Convert the RDD barriers to D3D12 enhanced barriers. + thread_local LocalVector<D3D12_GLOBAL_BARRIER> global_barriers; + thread_local LocalVector<D3D12_BUFFER_BARRIER> buffer_barriers; + thread_local LocalVector<D3D12_TEXTURE_BARRIER> texture_barriers; + global_barriers.clear(); + buffer_barriers.clear(); + texture_barriers.clear(); + + D3D12_GLOBAL_BARRIER global_barrier = {}; + for (uint32_t i = 0; i < p_memory_barriers.size(); i++) { + const MemoryBarrier &memory_barrier = p_memory_barriers[i]; + _rd_stages_and_access_to_d3d12(p_src_stages, RDD::TEXTURE_LAYOUT_MAX, memory_barrier.src_access, global_barrier.SyncBefore, global_barrier.AccessBefore); + _rd_stages_and_access_to_d3d12(p_dst_stages, RDD::TEXTURE_LAYOUT_MAX, memory_barrier.dst_access, global_barrier.SyncAfter, global_barrier.AccessAfter); + global_barriers.push_back(global_barrier); + } + + D3D12_BUFFER_BARRIER buffer_barrier_d3d12 = {}; + buffer_barrier_d3d12.Offset = 0; + buffer_barrier_d3d12.Size = UINT64_MAX; // The specification says this must be the size of the buffer barrier. + for (uint32_t i = 0; i < p_buffer_barriers.size(); i++) { + const BufferBarrier &buffer_barrier_rd = p_buffer_barriers[i]; + const BufferInfo *buffer_info = (const BufferInfo *)(buffer_barrier_rd.buffer.id); + _rd_stages_and_access_to_d3d12(p_src_stages, RDD::TEXTURE_LAYOUT_MAX, buffer_barrier_rd.src_access, buffer_barrier_d3d12.SyncBefore, buffer_barrier_d3d12.AccessBefore); + _rd_stages_and_access_to_d3d12(p_dst_stages, RDD::TEXTURE_LAYOUT_MAX, buffer_barrier_rd.dst_access, buffer_barrier_d3d12.SyncAfter, buffer_barrier_d3d12.AccessAfter); + buffer_barrier_d3d12.pResource = buffer_info->resource; + buffer_barriers.push_back(buffer_barrier_d3d12); + } + + D3D12_TEXTURE_BARRIER texture_barrier_d3d12 = {}; + for (uint32_t i = 0; i < p_texture_barriers.size(); i++) { + const TextureBarrier &texture_barrier_rd = p_texture_barriers[i]; + const TextureInfo *texture_info = (const TextureInfo *)(texture_barrier_rd.texture.id); + _rd_stages_and_access_to_d3d12(p_src_stages, texture_barrier_rd.prev_layout, texture_barrier_rd.src_access, texture_barrier_d3d12.SyncBefore, texture_barrier_d3d12.AccessBefore); + _rd_stages_and_access_to_d3d12(p_dst_stages, texture_barrier_rd.next_layout, texture_barrier_rd.dst_access, texture_barrier_d3d12.SyncAfter, texture_barrier_d3d12.AccessAfter); + texture_barrier_d3d12.LayoutBefore = _rd_texture_layout_to_d3d12_barrier_layout(texture_barrier_rd.prev_layout); + texture_barrier_d3d12.LayoutAfter = _rd_texture_layout_to_d3d12_barrier_layout(texture_barrier_rd.next_layout); + texture_barrier_d3d12.pResource = texture_info->resource; + texture_barrier_d3d12.Subresources.IndexOrFirstMipLevel = texture_barrier_rd.subresources.base_mipmap; + texture_barrier_d3d12.Subresources.NumMipLevels = texture_barrier_rd.subresources.mipmap_count; + texture_barrier_d3d12.Subresources.FirstArraySlice = texture_barrier_rd.subresources.base_layer; + texture_barrier_d3d12.Subresources.NumArraySlices = texture_barrier_rd.subresources.layer_count; + texture_barrier_d3d12.Subresources.FirstPlane = _compute_plane_slice(texture_info->format, texture_barrier_rd.subresources.aspect); + texture_barrier_d3d12.Subresources.NumPlanes = format_get_plane_count(texture_info->format); + texture_barrier_d3d12.Flags = (texture_barrier_rd.prev_layout == RDD::TEXTURE_LAYOUT_UNDEFINED) ? D3D12_TEXTURE_BARRIER_FLAG_DISCARD : D3D12_TEXTURE_BARRIER_FLAG_NONE; + texture_barriers.push_back(texture_barrier_d3d12); + } + + // Define the barrier groups and execute. + D3D12_BARRIER_GROUP barrier_groups[3] = {}; + barrier_groups[0].Type = D3D12_BARRIER_TYPE_GLOBAL; + barrier_groups[1].Type = D3D12_BARRIER_TYPE_BUFFER; + barrier_groups[2].Type = D3D12_BARRIER_TYPE_TEXTURE; + barrier_groups[0].NumBarriers = global_barriers.size(); + barrier_groups[1].NumBarriers = buffer_barriers.size(); + barrier_groups[2].NumBarriers = texture_barriers.size(); + barrier_groups[0].pGlobalBarriers = global_barriers.ptr(); + barrier_groups[1].pBufferBarriers = buffer_barriers.ptr(); + barrier_groups[2].pTextureBarriers = texture_barriers.ptr(); + cmd_list_7->Barrier(ARRAY_SIZE(barrier_groups), barrier_groups); } /****************/ @@ -3476,6 +3784,8 @@ RDD::ShaderID RenderingDeviceDriverD3D12::shader_create_from_bytecode(const Vect zstd_size = STEPIFY(zstd_size, 4); read_offset += zstd_size; ERR_FAIL_COND_V(read_offset > binsize, ShaderID()); + + r_shader_desc.stages.push_back(ShaderStage(stage)); } const uint8_t *root_sig_data_ptr = binptr + read_offset; @@ -3807,6 +4117,10 @@ void RenderingDeviceDriverD3D12::uniform_set_free(UniformSetID p_uniform_set) { // ----- COMMANDS ----- void RenderingDeviceDriverD3D12::command_uniform_set_prepare_for_use(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index) { + if (barrier_capabilities.enhanced_barriers_supported) { + return; + } + // Perform pending blackouts. { SelfList<TextureInfo> *E = textures_pending_clear.first(); @@ -3814,7 +4128,7 @@ void RenderingDeviceDriverD3D12::command_uniform_set_prepare_for_use(CommandBuff TextureSubresourceRange subresources; subresources.layer_count = E->self()->layers; subresources.mipmap_count = E->self()->mipmaps; - command_clear_color_texture(p_cmd_buffer, TextureID(E->self()), TEXTURE_LAYOUT_GENERAL, Color(), subresources); + command_clear_color_texture(p_cmd_buffer, TextureID(E->self()), TEXTURE_LAYOUT_UNDEFINED, Color(), subresources); SelfList<TextureInfo> *next = E->next(); E->remove_from_list(); @@ -3947,34 +4261,6 @@ void RenderingDeviceDriverD3D12::command_uniform_set_prepare_for_use(CommandBuff for (uint32_t i = 0; i < tex_info->layers; i++) { for (uint32_t j = 0; j < tex_info->mipmaps; j++) { uint32_t subresource = D3D12CalcSubresource(tex_info->base_mip + j, tex_info->base_layer + i, 0, tex_info->desc.MipLevels, tex_info->desc.ArraySize()); - - if ((wanted_state & D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE)) { - // [[CROSS_FAMILY_FALLBACK]]. - if (tex_info->owner_info.resource && tex_info->main_texture && tex_info->main_texture != tex_info) { - uint32_t subres_qword = subresource / 64; - uint64_t subres_mask = (uint64_t(1) << (subresource % 64)); - if ((tex_info->main_texture->states_ptr->xfamily_fallback.subresources_dirty[subres_qword] & subres_mask)) { - // Prepare for copying the write-to texture to this one, if out-of-date. - _resource_transition_batch(tex_info->main_texture, subresource, planes, D3D12_RESOURCE_STATE_COPY_SOURCE); - _resource_transition_batch(tex_info, subresource, planes, D3D12_RESOURCE_STATE_COPY_DEST); - - CommandBufferInfo::FamilyFallbackCopy ffc; - ffc.texture = tex_info; - ffc.subresource = subresource; - ffc.mipmap = j; - ffc.dst_wanted_state = wanted_state; - - CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id; - cmd_buf_info->family_fallback_copies.resize(cmd_buf_info->family_fallback_copies.size() + 1); - cmd_buf_info->family_fallback_copies[cmd_buf_info->family_fallback_copy_count] = ffc; - cmd_buf_info->family_fallback_copy_count++; - - tex_info->main_texture->states_ptr->xfamily_fallback.subresources_dirty[subres_qword] &= ~subres_mask; - } - continue; - } - } - _resource_transition_batch(tex_info, subresource, planes, wanted_state); } } @@ -3986,55 +4272,6 @@ void RenderingDeviceDriverD3D12::command_uniform_set_prepare_for_use(CommandBuff if (p_set_index == shader_info_in->sets.size() - 1) { CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id; _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); - - // [[CROSS_FAMILY_FALLBACK]]. - for (uint32_t i = 0; i < cmd_buf_info->family_fallback_copy_count; i++) { - const CommandBufferInfo::FamilyFallbackCopy &ffc = cmd_buf_info->family_fallback_copies[i]; - - D3D12_TEXTURE_COPY_LOCATION dst_tex = {}; - dst_tex.pResource = ffc.texture->resource; - dst_tex.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - dst_tex.SubresourceIndex = ffc.subresource; - - D3D12_TEXTURE_COPY_LOCATION src_tex = {}; - src_tex.pResource = ffc.texture->main_texture->resource; - src_tex.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - src_tex.SubresourceIndex = ffc.subresource; - - const ResourceInfo::States::CrossFamillyFallback &xfamily = ffc.texture->main_texture->owner_info.states.xfamily_fallback; - if (xfamily.interim_buffer.Get()) { - // Must copy via a buffer due to reinterpret-copy known not to be available for these data types. - D3D12_TEXTURE_COPY_LOCATION buf_loc = {}; - buf_loc.pResource = xfamily.interim_buffer.Get(); - buf_loc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - buf_loc.PlacedFootprint.Offset = 0; - buf_loc.PlacedFootprint.Footprint.Format = ffc.texture->main_texture->desc.Format; - buf_loc.PlacedFootprint.Footprint.Width = MAX(1u, ffc.texture->main_texture->desc.Width >> ffc.mipmap); - buf_loc.PlacedFootprint.Footprint.Height = MAX(1u, ffc.texture->main_texture->desc.Height >> ffc.mipmap); - buf_loc.PlacedFootprint.Footprint.Depth = MAX(1u, (uint32_t)ffc.texture->main_texture->desc.Depth() >> ffc.mipmap); - buf_loc.PlacedFootprint.Footprint.RowPitch = STEPIFY(buf_loc.PlacedFootprint.Footprint.Width * sizeof(uint16_t), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); - - D3D12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(xfamily.interim_buffer.Get(), D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_COPY_DEST); - cmd_buf_info->cmd_list->ResourceBarrier(1, &barrier); - - cmd_buf_info->cmd_list->CopyTextureRegion(&buf_loc, 0, 0, 0, &src_tex, nullptr); - - barrier = CD3DX12_RESOURCE_BARRIER::Transition(xfamily.interim_buffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE); - cmd_buf_info->cmd_list->ResourceBarrier(1, &barrier); - - buf_loc.PlacedFootprint.Footprint.Format = ffc.texture->desc.Format; - cmd_buf_info->cmd_list->CopyTextureRegion(&dst_tex, 0, 0, 0, &buf_loc, nullptr); - } else { - // Direct copy is possible. - cmd_buf_info->cmd_list->CopyTextureRegion(&dst_tex, 0, 0, 0, &src_tex, nullptr); - } - - // Set the specific SRV state we wanted from the beginning to the alternative version of the texture. - _resource_transition_batch(ffc.texture, ffc.subresource, 1, ffc.dst_wanted_state); - } - cmd_buf_info->family_fallback_copy_count = 0; - - _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); } } @@ -4311,8 +4548,10 @@ void RenderingDeviceDriverD3D12::command_clear_buffer(CommandBufferID p_cmd_buff } } - _resource_transition_batch(buf_info, 0, 1, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); - _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + if (!barrier_capabilities.enhanced_barriers_supported) { + _resource_transition_batch(buf_info, 0, 1, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + } D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = {}; uav_desc.Format = DXGI_FORMAT_R32_TYPELESS; @@ -4352,9 +4591,11 @@ void RenderingDeviceDriverD3D12::command_copy_buffer(CommandBufferID p_cmd_buffe BufferInfo *src_buf_info = (BufferInfo *)p_src_buffer.id; BufferInfo *buf_loc_info = (BufferInfo *)p_buf_locfer.id; - _resource_transition_batch(src_buf_info, 0, 1, D3D12_RESOURCE_STATE_COPY_SOURCE); - _resource_transition_batch(buf_loc_info, 0, 1, D3D12_RESOURCE_STATE_COPY_DEST); - _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + if (!barrier_capabilities.enhanced_barriers_supported) { + _resource_transition_batch(src_buf_info, 0, 1, D3D12_RESOURCE_STATE_COPY_SOURCE); + _resource_transition_batch(buf_loc_info, 0, 1, D3D12_RESOURCE_STATE_COPY_DEST); + _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + } for (uint32_t i = 0; i < p_regions.size(); i++) { cmd_buf_info->cmd_list->CopyBufferRegion(buf_loc_info->resource, p_regions[i].dst_offset, src_buf_info->resource, p_regions[i].src_offset, p_regions[i].size); @@ -4366,43 +4607,37 @@ void RenderingDeviceDriverD3D12::command_copy_texture(CommandBufferID p_cmd_buff TextureInfo *src_tex_info = (TextureInfo *)p_src_texture.id; TextureInfo *dst_tex_info = (TextureInfo *)p_dst_texture.id; - for (uint32_t i = 0; i < p_regions.size(); i++) { - UINT src_subresource = D3D12CalcSubresource( - p_regions[i].src_subresources.mipmap, - p_regions[i].src_subresources.base_layer, - _compute_plane_slice(src_tex_info->format, p_regions[i].src_subresources.aspect), - src_tex_info->desc.MipLevels, - src_tex_info->desc.ArraySize()); - _resource_transition_batch(src_tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_COPY_SOURCE); - - UINT dst_subresource = D3D12CalcSubresource( - p_regions[i].dst_subresources.mipmap, - p_regions[i].dst_subresources.base_layer, - _compute_plane_slice(dst_tex_info->format, p_regions[i].dst_subresources.aspect), - dst_tex_info->desc.MipLevels, - dst_tex_info->desc.ArraySize()); - _resource_transition_batch(dst_tex_info, dst_subresource, 1, D3D12_RESOURCE_STATE_COPY_DEST); + if (!barrier_capabilities.enhanced_barriers_supported) { + // Batch all barrier transitions for the textures before performing the copies. + for (uint32_t i = 0; i < p_regions.size(); i++) { + uint32_t layer_count = MIN(p_regions[i].src_subresources.layer_count, p_regions[i].dst_subresources.layer_count); + for (uint32_t j = 0; j < layer_count; j++) { + UINT src_subresource = _compute_subresource_from_layers(src_tex_info, p_regions[i].src_subresources, j); + UINT dst_subresource = _compute_subresource_from_layers(dst_tex_info, p_regions[i].dst_subresources, j); + _resource_transition_batch(src_tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_COPY_SOURCE); + _resource_transition_batch(dst_tex_info, dst_subresource, 1, D3D12_RESOURCE_STATE_COPY_DEST); + } + } _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + } - CD3DX12_TEXTURE_COPY_LOCATION src_location(src_tex_info->resource, src_subresource); - CD3DX12_TEXTURE_COPY_LOCATION dst_location(dst_tex_info->resource, dst_subresource); - - CD3DX12_BOX src_box( - p_regions[i].src_offset.x, - p_regions[i].src_offset.y, - p_regions[i].src_offset.z, - p_regions[i].src_offset.x + p_regions[i].size.x, - p_regions[i].src_offset.y + p_regions[i].size.y, - p_regions[i].src_offset.z + p_regions[i].size.z); - - cmd_buf_info->cmd_list->CopyTextureRegion( - &dst_location, - p_regions[i].dst_offset.x, - p_regions[i].dst_offset.y, - p_regions[i].dst_offset.z, - &src_location, - &src_box); + CD3DX12_BOX src_box; + for (uint32_t i = 0; i < p_regions.size(); i++) { + uint32_t layer_count = MIN(p_regions[i].src_subresources.layer_count, p_regions[i].dst_subresources.layer_count); + for (uint32_t j = 0; j < layer_count; j++) { + UINT src_subresource = _compute_subresource_from_layers(src_tex_info, p_regions[i].src_subresources, j); + UINT dst_subresource = _compute_subresource_from_layers(dst_tex_info, p_regions[i].dst_subresources, j); + CD3DX12_TEXTURE_COPY_LOCATION src_location(src_tex_info->resource, src_subresource); + CD3DX12_TEXTURE_COPY_LOCATION dst_location(dst_tex_info->resource, dst_subresource); + src_box.left = p_regions[i].src_offset.x; + src_box.top = p_regions[i].src_offset.y; + src_box.front = p_regions[i].src_offset.z; + src_box.right = p_regions[i].src_offset.x + p_regions[i].size.x; + src_box.bottom = p_regions[i].src_offset.y + p_regions[i].size.y; + src_box.back = p_regions[i].src_offset.z + p_regions[i].size.z; + cmd_buf_info->cmd_list->CopyTextureRegion(&dst_location, p_regions[i].dst_offset.x, p_regions[i].dst_offset.y, p_regions[i].dst_offset.z, &src_location, &src_box); + } } } @@ -4412,12 +4647,12 @@ void RenderingDeviceDriverD3D12::command_resolve_texture(CommandBufferID p_cmd_b TextureInfo *dst_tex_info = (TextureInfo *)p_dst_texture.id; UINT src_subresource = D3D12CalcSubresource(p_src_mipmap, p_src_layer, 0, src_tex_info->desc.MipLevels, src_tex_info->desc.ArraySize()); - _resource_transition_batch(src_tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_RESOLVE_SOURCE); - UINT dst_subresource = D3D12CalcSubresource(p_dst_mipmap, p_dst_layer, 0, dst_tex_info->desc.MipLevels, dst_tex_info->desc.ArraySize()); - _resource_transition_batch(dst_tex_info, dst_subresource, 1, D3D12_RESOURCE_STATE_RESOLVE_DEST); - - _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + if (!barrier_capabilities.enhanced_barriers_supported) { + _resource_transition_batch(src_tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_RESOLVE_SOURCE); + _resource_transition_batch(dst_tex_info, dst_subresource, 1, D3D12_RESOURCE_STATE_RESOLVE_DEST); + _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + } cmd_buf_info->cmd_list->ResolveSubresource(dst_tex_info->resource, dst_subresource, src_tex_info->resource, src_subresource, RD_TO_D3D12_FORMAT[src_tex_info->format].general_format); } @@ -4458,7 +4693,9 @@ void RenderingDeviceDriverD3D12::command_clear_color_texture(CommandBufferID p_c } } - _transition_subresources(D3D12_RESOURCE_STATE_RENDER_TARGET); + if (!barrier_capabilities.enhanced_barriers_supported) { + _transition_subresources(D3D12_RESOURCE_STATE_RENDER_TARGET); + } for (uint32_t i = 0; i < p_subresources.mipmap_count; i++) { D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = _make_rtv_for_texture(tex_info, p_subresources.base_mipmap + i, p_subresources.base_layer, p_subresources.layer_count, false); @@ -4476,7 +4713,7 @@ void RenderingDeviceDriverD3D12::command_clear_color_texture(CommandBufferID p_c frames[frame_idx].desc_heap_walkers.rtv.advance(); } - } else { + } else if (tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS) { // Clear via UAV. _command_check_descriptor_sets(p_cmd_buffer); @@ -4501,7 +4738,9 @@ void RenderingDeviceDriverD3D12::command_clear_color_texture(CommandBufferID p_c } } - _transition_subresources(D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + if (!barrier_capabilities.enhanced_barriers_supported) { + _transition_subresources(D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + } for (uint32_t i = 0; i < p_subresources.mipmap_count; i++) { D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = _make_ranged_uav_for_texture(tex_info, p_subresources.base_mipmap + i, p_subresources.base_layer, p_subresources.layer_count, false); @@ -4522,6 +4761,7 @@ void RenderingDeviceDriverD3D12::command_clear_color_texture(CommandBufferID p_c (UINT)p_color.get_b8(), (UINT)p_color.get_a8(), }; + cmd_buf_info->cmd_list->ClearUnorderedAccessViewUint( frames[frame_idx].desc_heap_walkers.resources.get_curr_gpu_handle(), frames[frame_idx].desc_heap_walkers.aux.get_curr_cpu_handle(), @@ -4533,6 +4773,8 @@ void RenderingDeviceDriverD3D12::command_clear_color_texture(CommandBufferID p_c frames[frame_idx].desc_heap_walkers.resources.advance(); frames[frame_idx].desc_heap_walkers.aux.advance(); } + } else { + ERR_FAIL_MSG("Cannot clear texture because its format does not support UAV writes. You'll need to update its contents through another method."); } } @@ -4540,8 +4782,7 @@ void RenderingDeviceDriverD3D12::command_copy_buffer_to_texture(CommandBufferID const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id; BufferInfo *buf_info = (BufferInfo *)p_src_buffer.id; TextureInfo *tex_info = (TextureInfo *)p_dst_texture.id; - - if (buf_info->flags.is_for_upload) { + if (!barrier_capabilities.enhanced_barriers_supported) { _resource_transition_batch(buf_info, 0, 1, D3D12_RESOURCE_STATE_COPY_SOURCE); } @@ -4569,19 +4810,21 @@ void RenderingDeviceDriverD3D12::command_copy_buffer_to_texture(CommandBufferID STEPIFY(p_regions[i].texture_region_size.y, block_h), p_regions[i].texture_region_size.z); - for (uint32_t j = 0; j < p_regions[i].texture_subresources.layer_count; j++) { - UINT dst_subresource = D3D12CalcSubresource( - p_regions[i].texture_subresources.mipmap, - p_regions[i].texture_subresources.base_layer + j, - _compute_plane_slice(tex_info->format, p_regions[i].texture_subresources.aspect), - tex_info->desc.MipLevels, - tex_info->desc.ArraySize()); - CD3DX12_TEXTURE_COPY_LOCATION copy_dst(tex_info->resource, dst_subresource); + if (!barrier_capabilities.enhanced_barriers_supported) { + for (uint32_t j = 0; j < p_regions[i].texture_subresources.layer_count; j++) { + UINT dst_subresource = D3D12CalcSubresource( + p_regions[i].texture_subresources.mipmap, + p_regions[i].texture_subresources.base_layer + j, + _compute_plane_slice(tex_info->format, p_regions[i].texture_subresources.aspect), + tex_info->desc.MipLevels, + tex_info->desc.ArraySize()); + CD3DX12_TEXTURE_COPY_LOCATION copy_dst(tex_info->resource, dst_subresource); - _resource_transition_batch(tex_info, dst_subresource, 1, D3D12_RESOURCE_STATE_COPY_DEST); - } + _resource_transition_batch(tex_info, dst_subresource, 1, D3D12_RESOURCE_STATE_COPY_DEST); + } - _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + } for (uint32_t j = 0; j < p_regions[i].texture_subresources.layer_count; j++) { UINT dst_subresource = D3D12CalcSubresource( @@ -4608,24 +4851,28 @@ void RenderingDeviceDriverD3D12::command_copy_texture_to_buffer(CommandBufferID TextureInfo *tex_info = (TextureInfo *)p_src_texture.id; BufferInfo *buf_info = (BufferInfo *)p_buf_locfer.id; - _resource_transition_batch(buf_info, 0, 1, D3D12_RESOURCE_STATE_COPY_DEST); + if (!barrier_capabilities.enhanced_barriers_supported) { + _resource_transition_batch(buf_info, 0, 1, D3D12_RESOURCE_STATE_COPY_DEST); + } uint32_t block_w = 0, block_h = 0; get_compressed_image_format_block_dimensions(tex_info->format, block_w, block_h); for (uint32_t i = 0; i < p_regions.size(); i++) { - for (uint32_t j = 0; j < p_regions[i].texture_subresources.layer_count; j++) { - UINT src_subresource = D3D12CalcSubresource( - p_regions[i].texture_subresources.mipmap, - p_regions[i].texture_subresources.base_layer + j, - _compute_plane_slice(tex_info->format, p_regions[i].texture_subresources.aspect), - tex_info->desc.MipLevels, - tex_info->desc.ArraySize()); + if (!barrier_capabilities.enhanced_barriers_supported) { + for (uint32_t j = 0; j < p_regions[i].texture_subresources.layer_count; j++) { + UINT src_subresource = D3D12CalcSubresource( + p_regions[i].texture_subresources.mipmap, + p_regions[i].texture_subresources.base_layer + j, + _compute_plane_slice(tex_info->format, p_regions[i].texture_subresources.aspect), + tex_info->desc.MipLevels, + tex_info->desc.ArraySize()); - _resource_transition_batch(tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_COPY_SOURCE); - } + _resource_transition_batch(tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_COPY_SOURCE); + } - _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + } for (uint32_t j = 0; j < p_regions[i].texture_subresources.layer_count; j++) { UINT src_subresource = D3D12CalcSubresource( @@ -4775,22 +5022,25 @@ void RenderingDeviceDriverD3D12::command_begin_render_pass(CommandBufferID p_cmd } }; - for (uint32_t i = 0; i < fb_info->attachments.size(); i++) { - TextureInfo *tex_info = (TextureInfo *)fb_info->attachments[i].id; - if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)) { - _transition_subresources(tex_info, D3D12_RESOURCE_STATE_RENDER_TARGET); - } else if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) { - _transition_subresources(tex_info, D3D12_RESOURCE_STATE_DEPTH_WRITE); - } else { - DEV_ASSERT(false); + if (fb_info->is_screen || !barrier_capabilities.enhanced_barriers_supported) { + // Screen framebuffers must perform this transition even if enhanced barriers are supported. + for (uint32_t i = 0; i < fb_info->attachments.size(); i++) { + TextureInfo *tex_info = (TextureInfo *)fb_info->attachments[i].id; + if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)) { + _transition_subresources(tex_info, D3D12_RESOURCE_STATE_RENDER_TARGET); + } else if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) { + _transition_subresources(tex_info, D3D12_RESOURCE_STATE_DEPTH_WRITE); + } else { + DEV_ASSERT(false); + } + } + if (fb_info->vrs_attachment) { + TextureInfo *tex_info = (TextureInfo *)fb_info->vrs_attachment.id; + _transition_subresources(tex_info, D3D12_RESOURCE_STATE_SHADING_RATE_SOURCE); } - } - if (fb_info->vrs_attachment) { - TextureInfo *tex_info = (TextureInfo *)fb_info->vrs_attachment.id; - _transition_subresources(tex_info, D3D12_RESOURCE_STATE_SHADING_RATE_SOURCE); - } - _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + } cmd_buf_info->render_pass_state.region_rect = CD3DX12_RECT( p_rect.position.x, @@ -5152,8 +5402,11 @@ void RenderingDeviceDriverD3D12::command_render_draw_indexed_indirect(CommandBuf CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id; _bind_vertex_buffers(cmd_buf_info); BufferInfo *indirect_buf_info = (BufferInfo *)p_indirect_buffer.id; - _resource_transition_batch(indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT); - _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + if (!barrier_capabilities.enhanced_barriers_supported) { + _resource_transition_batch(indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT); + _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + } + cmd_buf_info->cmd_list->ExecuteIndirect(indirect_cmd_signatures.draw_indexed.Get(), p_draw_count, indirect_buf_info->resource, p_offset, nullptr, 0); } @@ -5162,9 +5415,12 @@ void RenderingDeviceDriverD3D12::command_render_draw_indexed_indirect_count(Comm _bind_vertex_buffers(cmd_buf_info); BufferInfo *indirect_buf_info = (BufferInfo *)p_indirect_buffer.id; BufferInfo *count_buf_info = (BufferInfo *)p_count_buffer.id; - _resource_transition_batch(indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT); - _resource_transition_batch(count_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT); - _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + if (!barrier_capabilities.enhanced_barriers_supported) { + _resource_transition_batch(indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT); + _resource_transition_batch(count_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT); + _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + } + cmd_buf_info->cmd_list->ExecuteIndirect(indirect_cmd_signatures.draw_indexed.Get(), p_max_draw_count, indirect_buf_info->resource, p_offset, count_buf_info->resource, p_count_buffer_offset); } @@ -5172,8 +5428,11 @@ void RenderingDeviceDriverD3D12::command_render_draw_indirect(CommandBufferID p_ CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id; _bind_vertex_buffers(cmd_buf_info); BufferInfo *indirect_buf_info = (BufferInfo *)p_indirect_buffer.id; - _resource_transition_batch(indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT); - _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + if (!barrier_capabilities.enhanced_barriers_supported) { + _resource_transition_batch(indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT); + _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + } + cmd_buf_info->cmd_list->ExecuteIndirect(indirect_cmd_signatures.draw.Get(), p_draw_count, indirect_buf_info->resource, p_offset, nullptr, 0); } @@ -5182,9 +5441,12 @@ void RenderingDeviceDriverD3D12::command_render_draw_indirect_count(CommandBuffe _bind_vertex_buffers(cmd_buf_info); BufferInfo *indirect_buf_info = (BufferInfo *)p_indirect_buffer.id; BufferInfo *count_buf_info = (BufferInfo *)p_count_buffer.id; - _resource_transition_batch(indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT); - _resource_transition_batch(count_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT); - _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + if (!barrier_capabilities.enhanced_barriers_supported) { + _resource_transition_batch(indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT); + _resource_transition_batch(count_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT); + _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + } + cmd_buf_info->cmd_list->ExecuteIndirect(indirect_cmd_signatures.draw.Get(), p_max_draw_count, indirect_buf_info->resource, p_offset, count_buf_info->resource, p_count_buffer_offset); } @@ -5203,10 +5465,15 @@ void RenderingDeviceDriverD3D12::command_render_bind_vertex_buffers(CommandBuffe cmd_buf_info->render_pass_state.vertex_buffer_views[i] = {}; cmd_buf_info->render_pass_state.vertex_buffer_views[i].BufferLocation = buffer_info->resource->GetGPUVirtualAddress() + p_offsets[i]; cmd_buf_info->render_pass_state.vertex_buffer_views[i].SizeInBytes = buffer_info->size - p_offsets[i]; + if (!barrier_capabilities.enhanced_barriers_supported) { + _resource_transition_batch(buffer_info, 0, 1, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER); + } + } - _resource_transition_batch(buffer_info, 0, 1, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER); + if (!barrier_capabilities.enhanced_barriers_supported) { + _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); } - _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + cmd_buf_info->render_pass_state.vertex_buffer_count = p_binding_count; } @@ -5219,8 +5486,10 @@ void RenderingDeviceDriverD3D12::command_render_bind_index_buffer(CommandBufferI d3d12_ib_view.SizeInBytes = buffer_info->size - p_offset; d3d12_ib_view.Format = p_format == INDEX_BUFFER_FORMAT_UINT16 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT; - _resource_transition_batch(buffer_info, 0, 1, D3D12_RESOURCE_STATE_INDEX_BUFFER); - _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + if (!barrier_capabilities.enhanced_barriers_supported) { + _resource_transition_batch(buffer_info, 0, 1, D3D12_RESOURCE_STATE_INDEX_BUFFER); + _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + } cmd_buf_info->cmd_list->IASetIndexBuffer(&d3d12_ib_view); } @@ -5616,15 +5885,21 @@ void RenderingDeviceDriverD3D12::command_bind_compute_uniform_set(CommandBufferI void RenderingDeviceDriverD3D12::command_compute_dispatch(CommandBufferID p_cmd_buffer, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) { const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id; - _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + if (!barrier_capabilities.enhanced_barriers_supported) { + _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + } + cmd_buf_info->cmd_list->Dispatch(p_x_groups, p_y_groups, p_z_groups); } void RenderingDeviceDriverD3D12::command_compute_dispatch_indirect(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset) { const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id; BufferInfo *indirect_buf_info = (BufferInfo *)p_indirect_buffer.id; - _resource_transition_batch(indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT); - _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + if (!barrier_capabilities.enhanced_barriers_supported) { + _resource_transition_batch(indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT); + _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + } + cmd_buf_info->cmd_list->ExecuteIndirect(indirect_cmd_signatures.dispatch.Get(), 1, indirect_buf_info->resource, p_offset, nullptr, 0); } @@ -5939,11 +6214,7 @@ uint64_t RenderingDeviceDriverD3D12::limit_get(Limit p_limit) { uint64_t RenderingDeviceDriverD3D12::api_trait_get(ApiTrait p_trait) { switch (p_trait) { case API_TRAIT_HONORS_PIPELINE_BARRIERS: - // TODO: - // 1. Map fine/Vulkan/enhanced barriers to legacy barriers as closely as possible - // so there's still some advantage even without enhanced barriers available. - // 2. Implement enhanced barriers and return true where available. - return 0; + return barrier_capabilities.enhanced_barriers_supported; case API_TRAIT_SHADER_CHANGE_INVALIDATION: return (uint64_t)SHADER_CHANGE_INVALIDATION_ALL_OR_NONE_ACCORDING_TO_LAYOUT_HASH; case API_TRAIT_TEXTURE_TRANSFER_ALIGNMENT: @@ -5952,6 +6223,8 @@ uint64_t RenderingDeviceDriverD3D12::api_trait_get(ApiTrait p_trait) { return D3D12_TEXTURE_DATA_PITCH_ALIGNMENT; case API_TRAIT_SECONDARY_VIEWPORT_SCISSOR: return false; + case API_TRAIT_CLEARS_WITH_COPY_ENGINE: + return false; default: return RenderingDeviceDriver::api_trait_get(p_trait); } @@ -6101,6 +6374,8 @@ Error RenderingDeviceDriverD3D12::_initialize_device() { // These happen due to how D3D12MA manages buffers; seems benign. D3D12_MESSAGE_ID_HEAP_ADDRESS_RANGE_HAS_NO_RESOURCE, D3D12_MESSAGE_ID_HEAP_ADDRESS_RANGE_INTERSECTS_MULTIPLE_BUFFERS, + // Seemingly a false positive. + D3D12_MESSAGE_ID_DATA_STATIC_WHILE_SET_AT_EXECUTE_DESCRIPTOR_INVALID_DATA_CHANGE, }; D3D12_INFO_QUEUE_FILTER filter = {}; @@ -6250,6 +6525,7 @@ Error RenderingDeviceDriverD3D12::_check_capabilities() { res = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS12, &options12, sizeof(options12)); if (SUCCEEDED(res)) { format_capabilities.relaxed_casting_supported = options12.RelaxedFormatCastingSupported; + barrier_capabilities.enhanced_barriers_supported = options12.EnhancedBarriersSupported; } if (vrs_capabilities.draw_call_supported || vrs_capabilities.primitive_supported || vrs_capabilities.ss_image_supported) { @@ -6282,7 +6558,7 @@ Error RenderingDeviceDriverD3D12::_check_capabilities() { #if 0 print_verbose("- Relaxed casting supported"); #else - // Certain configurations (Windows 11 with an updated Nvida driver) crash when using relaxed casting. + // Certain configurations (Windows 11 with an updated NVIDIA driver) crash when using relaxed casting. // Therefore, we disable it temporarily until we can assure that it's reliable. // There are fallbacks in place that work in every case, if less efficient. format_capabilities.relaxed_casting_supported = false; @@ -6382,10 +6658,6 @@ Error RenderingDeviceDriverD3D12::_initialize_frames(uint32_t p_frame_count) { frames[i].desc_heap_walkers.samplers = frames[i].desc_heaps.samplers.make_walker(); frames[i].desc_heap_walkers.aux = frames[i].desc_heaps.aux.make_walker(); frames[i].desc_heap_walkers.rtv = frames[i].desc_heaps.rtv.make_walker(); - - ID3D12Resource *resource = nullptr; - HRESULT res = allocator->CreateResource(&allocation_desc, &resource_desc, D3D12_RESOURCE_STATE_COMMON, nullptr, &frames[frame_idx].aux_resource, IID_PPV_ARGS(&resource)); - ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_CANT_CREATE, "D3D12MA::CreateResource failed with error " + vformat("0x%08ux", (uint64_t)res) + "."); } return OK; diff --git a/drivers/d3d12/rendering_device_driver_d3d12.h b/drivers/d3d12/rendering_device_driver_d3d12.h index 3a9677485e..1782819238 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.h +++ b/drivers/d3d12/rendering_device_driver_d3d12.h @@ -122,6 +122,10 @@ class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver { bool relaxed_casting_supported = false; }; + struct BarrierCapabilities { + bool enhanced_barriers_supported = false; + }; + RenderingContextDriverD3D12 *context_driver = nullptr; RenderingContextDriver::Device context_device; ComPtr<IDXGIAdapter> adapter; @@ -136,6 +140,7 @@ class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver { ShaderCapabilities shader_capabilities; StorageBufferCapabilities storage_buffer_capabilities; FormatCapabilities format_capabilities; + BarrierCapabilities barrier_capabilities; String pipeline_cache_id; class DescriptorsHeap { @@ -218,11 +223,6 @@ private: // As many subresources as mipmaps * layers; planes (for depth-stencil) are tracked together. TightLocalVector<D3D12_RESOURCE_STATES> subresource_states; // Used only if not a view. uint32_t last_batch_with_uav_barrier = 0; - struct CrossFamillyFallback { - TightLocalVector<uint64_t> subresources_dirty; - ComPtr<ID3D12Resource> interim_buffer; - ComPtr<D3D12MA::Allocation> interim_buffer_alloc; - } xfamily_fallback; // [[CROSS_FAMILY_FALLBACK]]. }; ID3D12Resource *resource = nullptr; // Non-null even if not owned. @@ -275,7 +275,6 @@ private: uint64_t size = 0; struct { bool usable_as_uav : 1; - bool is_for_upload : 1; } flags = {}; }; @@ -317,10 +316,14 @@ private: UINT _compute_component_mapping(const TextureView &p_view); UINT _compute_plane_slice(DataFormat p_format, BitField<TextureAspectBits> p_aspect_bits); UINT _compute_plane_slice(DataFormat p_format, TextureAspect p_aspect); + UINT _compute_subresource_from_layers(TextureInfo *p_texture, const TextureSubresourceLayers &p_layers, uint32_t p_layer_offset); struct CommandBufferInfo; void _discard_texture_subresources(const TextureInfo *p_tex_info, const CommandBufferInfo *p_cmd_buf_info); +protected: + virtual bool _unordered_access_supported_by_format(DataFormat p_format); + public: virtual TextureID texture_create(const TextureFormat &p_format, const TextureView &p_view) override final; virtual TextureID texture_create_from_extension(uint64_t p_native_texture, TextureType p_type, DataFormat p_format, uint32_t p_array_layers, bool p_depth_stencil) override final; @@ -332,6 +335,7 @@ public: virtual uint8_t *texture_map(TextureID p_texture, const TextureSubresource &p_subresource) override final; virtual void texture_unmap(TextureID p_texture) override final; virtual BitField<TextureUsageBits> texture_get_usages_supported_by_format(DataFormat p_format, bool p_cpu_readable) override final; + virtual bool texture_can_make_shared_with_format(TextureID p_texture, DataFormat p_format, bool &r_raw_reinterpretation) override final; private: TextureID _texture_create_shared_from_slice(TextureID p_original_texture, const TextureView &p_view, TextureSliceType p_slice_type, uint32_t p_layer, uint32_t p_layers, uint32_t p_mipmap, uint32_t p_mipmaps); @@ -367,8 +371,8 @@ public: virtual void command_pipeline_barrier( CommandBufferID p_cmd_buffer, - BitField<RDD::PipelineStageBits> p_src_stages, - BitField<RDD::PipelineStageBits> p_dst_stages, + BitField<PipelineStageBits> p_src_stages, + BitField<PipelineStageBits> p_dst_stages, VectorView<RDD::MemoryBarrier> p_memory_barriers, VectorView<RDD::BufferBarrier> p_buffer_barriers, VectorView<RDD::TextureBarrier> p_texture_barriers) override final; @@ -465,16 +469,6 @@ private: RenderPassState render_pass_state; bool descriptor_heaps_set = false; - - // [[CROSS_FAMILY_FALLBACK]]. - struct FamilyFallbackCopy { - TextureInfo *texture = nullptr; - uint32_t subresource = 0; - uint32_t mipmap = 0; - D3D12_RESOURCE_STATES dst_wanted_state = {}; - }; - LocalVector<FamilyFallbackCopy> family_fallback_copies; - uint32_t family_fallback_copy_count = 0; }; public: @@ -961,7 +955,6 @@ private: bool rtv = false; } desc_heaps_exhausted_reported; CD3DX12_CPU_DESCRIPTOR_HANDLE null_rtv_handle = {}; // For [[MANUAL_SUBPASSES]]. - ComPtr<D3D12MA::Allocation> aux_resource; uint32_t segment_serial = 0; #ifdef DEV_ENABLED diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 03f947cd05..6cbdf5e935 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1359,23 +1359,26 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const // LOD if (p_render_data->screen_mesh_lod_threshold > 0.0 && mesh_storage->mesh_surface_has_lod(surf->surface)) { - // Get the LOD support points on the mesh AABB. - Vector3 lod_support_min = inst->transformed_aabb.get_support(p_render_data->cam_transform.basis.get_column(Vector3::AXIS_Z)); - Vector3 lod_support_max = inst->transformed_aabb.get_support(-p_render_data->cam_transform.basis.get_column(Vector3::AXIS_Z)); - - // Get the distances to those points on the AABB from the camera origin. - float distance_min = (float)p_render_data->cam_transform.origin.distance_to(lod_support_min); - float distance_max = (float)p_render_data->cam_transform.origin.distance_to(lod_support_max); - float distance = 0.0; - if (distance_min * distance_max < 0.0) { - //crossing plane - distance = 0.0; - } else if (distance_min >= 0.0) { - distance = distance_min; - } else if (distance_max <= 0.0) { - distance = -distance_max; + // Check if camera is NOT inside the mesh AABB. + if (!inst->transformed_aabb.has_point(p_render_data->main_cam_transform.origin)) { + // Get the LOD support points on the mesh AABB. + Vector3 lod_support_min = inst->transformed_aabb.get_support(p_render_data->main_cam_transform.basis.get_column(Vector3::AXIS_Z)); + Vector3 lod_support_max = inst->transformed_aabb.get_support(-p_render_data->main_cam_transform.basis.get_column(Vector3::AXIS_Z)); + + // Get the distances to those points on the AABB from the camera origin. + float distance_min = (float)p_render_data->main_cam_transform.origin.distance_to(lod_support_min); + float distance_max = (float)p_render_data->main_cam_transform.origin.distance_to(lod_support_max); + + if (distance_min * distance_max < 0.0) { + //crossing plane + distance = 0.0; + } else if (distance_min >= 0.0) { + distance = distance_min; + } else if (distance_max <= 0.0) { + distance = -distance_max; + } } if (p_render_data->cam_orthogonal) { @@ -1985,7 +1988,6 @@ void RasterizerSceneGLES3::_render_shadows(const RenderDataGLES3 *p_render_data, LocalVector<int> shadows; LocalVector<int> directional_shadows; - Plane camera_plane(-p_render_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->cam_transform.origin); float lod_distance_multiplier = p_render_data->cam_projection.get_lod_multiplier(); // Put lights into buckets for omni (cube shadows), directional, and spot. @@ -2014,20 +2016,20 @@ void RasterizerSceneGLES3::_render_shadows(const RenderDataGLES3 *p_render_data, // Render cubemap shadows. for (const int &index : cube_shadows) { - _render_shadow_pass(p_render_data->render_shadows[index].light, p_render_data->shadow_atlas, p_render_data->render_shadows[index].pass, p_render_data->render_shadows[index].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->render_info, p_viewport_size, p_render_data->cam_transform); + _render_shadow_pass(p_render_data->render_shadows[index].light, p_render_data->shadow_atlas, p_render_data->render_shadows[index].pass, p_render_data->render_shadows[index].instances, lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->render_info, p_viewport_size, p_render_data->cam_transform); } // Render directional shadows. for (uint32_t i = 0; i < directional_shadows.size(); i++) { - _render_shadow_pass(p_render_data->render_shadows[directional_shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[directional_shadows[i]].pass, p_render_data->render_shadows[directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->render_info, p_viewport_size, p_render_data->cam_transform); + _render_shadow_pass(p_render_data->render_shadows[directional_shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[directional_shadows[i]].pass, p_render_data->render_shadows[directional_shadows[i]].instances, lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->render_info, p_viewport_size, p_render_data->cam_transform); } // Render positional shadows (Spotlight and Omnilight with dual-paraboloid). for (uint32_t i = 0; i < shadows.size(); i++) { - _render_shadow_pass(p_render_data->render_shadows[shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[shadows[i]].pass, p_render_data->render_shadows[shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->render_info, p_viewport_size, p_render_data->cam_transform); + _render_shadow_pass(p_render_data->render_shadows[shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[shadows[i]].pass, p_render_data->render_shadows[shadows[i]].instances, lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->render_info, p_viewport_size, p_render_data->cam_transform); } } } -void RasterizerSceneGLES3::_render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, RenderingMethod::RenderInfo *p_render_info, const Size2i &p_viewport_size, const Transform3D &p_main_cam_transform) { +void RasterizerSceneGLES3::_render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, RenderingMethod::RenderInfo *p_render_info, const Size2i &p_viewport_size, const Transform3D &p_main_cam_transform) { GLES3::LightStorage *light_storage = GLES3::LightStorage::get_singleton(); ERR_FAIL_COND(!light_storage->owns_light_instance(p_light)); diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 5cde4ee9de..b6c7a0c5a5 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -640,7 +640,7 @@ private: void _setup_environment(const RenderDataGLES3 *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_pancake_shadows, float p_shadow_bias = 0.0); void _fill_render_list(RenderListType p_render_list, const RenderDataGLES3 *p_render_data, PassMode p_pass_mode, bool p_append = false); void _render_shadows(const RenderDataGLES3 *p_render_data, const Size2i &p_viewport_size = Size2i(1, 1)); - void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, RenderingMethod::RenderInfo *p_render_info = nullptr, const Size2i &p_viewport_size = Size2i(1, 1), const Transform3D &p_main_cam_transform = Transform3D()); + void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, RenderingMethod::RenderInfo *p_render_info = nullptr, const Size2i &p_viewport_size = Size2i(1, 1), const Transform3D &p_main_cam_transform = Transform3D()); void _render_post_processing(const RenderDataGLES3 *p_render_data); template <PassMode p_pass_mode> diff --git a/drivers/vulkan/rendering_device_driver_vulkan.cpp b/drivers/vulkan/rendering_device_driver_vulkan.cpp index b03a8418ed..2a9e9ba264 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.cpp +++ b/drivers/vulkan/rendering_device_driver_vulkan.cpp @@ -264,6 +264,63 @@ static const VkFormat RD_TO_VK_FORMAT[RDD::DATA_FORMAT_MAX] = { VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, }; +static VkImageLayout RD_TO_VK_LAYOUT[RDD::TEXTURE_LAYOUT_MAX] = { + VK_IMAGE_LAYOUT_UNDEFINED, // TEXTURE_LAYOUT_UNDEFINED + VK_IMAGE_LAYOUT_GENERAL, // TEXTURE_LAYOUT_STORAGE_OPTIMAL + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL + VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, // TEXTURE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // TEXTURE_LAYOUT_COPY_SRC_OPTIMAL + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // TEXTURE_LAYOUT_COPY_DST_OPTIMAL + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // TEXTURE_LAYOUT_RESOLVE_SRC_OPTIMAL + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // TEXTURE_LAYOUT_RESOLVE_DST_OPTIMAL + VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR, // TEXTURE_LAYOUT_VRS_ATTACHMENT_OPTIMAL +}; + +static VkPipelineStageFlags _rd_to_vk_pipeline_stages(BitField<RDD::PipelineStageBits> p_stages) { + VkPipelineStageFlags vk_flags = 0; + if (p_stages.has_flag(RDD::PIPELINE_STAGE_COPY_BIT) || p_stages.has_flag(RDD::PIPELINE_STAGE_RESOLVE_BIT)) { + // Transfer has been split into copy and resolve bits. Clear them and merge them into one bit. + vk_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT; + p_stages.clear_flag(RDD::PIPELINE_STAGE_COPY_BIT); + p_stages.clear_flag(RDD::PIPELINE_STAGE_RESOLVE_BIT); + } + + if (p_stages.has_flag(RDD::PIPELINE_STAGE_CLEAR_STORAGE_BIT)) { + // Vulkan should never use this as API_TRAIT_CLEAR_RESOURCES_WITH_VIEWS is not specified. + // Therefore, storage is never cleared with an explicit command. + p_stages.clear_flag(RDD::PIPELINE_STAGE_CLEAR_STORAGE_BIT); + } + + // The rest of the flags have compatible numeric values with Vulkan. + return VkPipelineStageFlags(p_stages) | vk_flags; +} + +static VkAccessFlags _rd_to_vk_access_flags(BitField<RDD::BarrierAccessBits> p_access) { + VkAccessFlags vk_flags = 0; + if (p_access.has_flag(RDD::BARRIER_ACCESS_COPY_READ_BIT) || p_access.has_flag(RDD::BARRIER_ACCESS_RESOLVE_READ_BIT)) { + vk_flags |= VK_ACCESS_TRANSFER_READ_BIT; + p_access.clear_flag(RDD::BARRIER_ACCESS_COPY_READ_BIT); + p_access.clear_flag(RDD::BARRIER_ACCESS_RESOLVE_READ_BIT); + } + + if (p_access.has_flag(RDD::BARRIER_ACCESS_COPY_WRITE_BIT) || p_access.has_flag(RDD::BARRIER_ACCESS_RESOLVE_WRITE_BIT)) { + vk_flags |= VK_ACCESS_TRANSFER_WRITE_BIT; + p_access.clear_flag(RDD::BARRIER_ACCESS_COPY_WRITE_BIT); + p_access.clear_flag(RDD::BARRIER_ACCESS_RESOLVE_WRITE_BIT); + } + + if (p_access.has_flag(RDD::BARRIER_ACCESS_STORAGE_CLEAR_BIT)) { + // Vulkan should never use this as API_TRAIT_CLEAR_RESOURCES_WITH_VIEWS is not specified. + // Therefore, storage is never cleared with an explicit command. + p_access.clear_flag(RDD::BARRIER_ACCESS_STORAGE_CLEAR_BIT); + } + + // The rest of the flags have compatible numeric values with Vulkan. + return VkAccessFlags(p_access) | vk_flags; +} + // RDD::CompareOperator == VkCompareOp. static_assert(ENUM_MEMBERS_EQUAL(RDD::COMPARE_OP_NEVER, VK_COMPARE_OP_NEVER)); static_assert(ENUM_MEMBERS_EQUAL(RDD::COMPARE_OP_LESS, VK_COMPARE_OP_LESS)); @@ -1334,18 +1391,6 @@ static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_SWIZZLE_G, VK_COMPONENT_SWIZZLE_G) static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_SWIZZLE_B, VK_COMPONENT_SWIZZLE_B)); static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_SWIZZLE_A, VK_COMPONENT_SWIZZLE_A)); -// RDD::TextureLayout == VkImageLayout. -static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_UNDEFINED)); -static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL)); -static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)); -static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)); -static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL)); -static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)); -static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)); -static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)); -static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_PREINITIALIZED)); -static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_VRS_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR)); - // RDD::TextureAspectBits == VkImageAspectFlagBits. static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_ASPECT_COLOR_BIT, VK_IMAGE_ASPECT_COLOR_BIT)); static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_ASPECT_DEPTH_BIT, VK_IMAGE_ASPECT_DEPTH_BIT)); @@ -1774,6 +1819,11 @@ BitField<RDD::TextureUsageBits> RenderingDeviceDriverVulkan::texture_get_usages_ return supported; } +bool RenderingDeviceDriverVulkan::texture_can_make_shared_with_format(TextureID p_texture, DataFormat p_format, bool &r_raw_reinterpretation) { + r_raw_reinterpretation = false; + return true; +} + /*****************/ /**** SAMPLER ****/ /*****************/ @@ -1893,7 +1943,6 @@ static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, V static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT)); static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)); static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT)); -static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT)); static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT)); static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT)); static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT)); @@ -1910,8 +1959,6 @@ static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_READ_BIT, static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT)); static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT)); static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT)); -static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_TRANSFER_READ_BIT)); -static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT)); static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_HOST_READ_BIT, VK_ACCESS_HOST_READ_BIT)); static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_HOST_WRITE_BIT, VK_ACCESS_HOST_WRITE_BIT)); static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_MEMORY_READ_BIT, VK_ACCESS_MEMORY_READ_BIT)); @@ -1929,8 +1976,8 @@ void RenderingDeviceDriverVulkan::command_pipeline_barrier( for (uint32_t i = 0; i < p_memory_barriers.size(); i++) { vk_memory_barriers[i] = {}; vk_memory_barriers[i].sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; - vk_memory_barriers[i].srcAccessMask = (VkPipelineStageFlags)p_memory_barriers[i].src_access; - vk_memory_barriers[i].dstAccessMask = (VkAccessFlags)p_memory_barriers[i].dst_access; + vk_memory_barriers[i].srcAccessMask = _rd_to_vk_access_flags(p_memory_barriers[i].src_access); + vk_memory_barriers[i].dstAccessMask = _rd_to_vk_access_flags(p_memory_barriers[i].dst_access); } VkBufferMemoryBarrier *vk_buffer_barriers = ALLOCA_ARRAY(VkBufferMemoryBarrier, p_buffer_barriers.size()); @@ -1939,8 +1986,8 @@ void RenderingDeviceDriverVulkan::command_pipeline_barrier( vk_buffer_barriers[i].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; vk_buffer_barriers[i].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; vk_buffer_barriers[i].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - vk_buffer_barriers[i].srcAccessMask = (VkAccessFlags)p_buffer_barriers[i].src_access; - vk_buffer_barriers[i].dstAccessMask = (VkAccessFlags)p_buffer_barriers[i].dst_access; + vk_buffer_barriers[i].srcAccessMask = _rd_to_vk_access_flags(p_buffer_barriers[i].src_access); + vk_buffer_barriers[i].dstAccessMask = _rd_to_vk_access_flags(p_buffer_barriers[i].dst_access); vk_buffer_barriers[i].buffer = ((const BufferInfo *)p_buffer_barriers[i].buffer.id)->vk_buffer; vk_buffer_barriers[i].offset = p_buffer_barriers[i].offset; vk_buffer_barriers[i].size = p_buffer_barriers[i].size; @@ -1951,10 +1998,10 @@ void RenderingDeviceDriverVulkan::command_pipeline_barrier( const TextureInfo *tex_info = (const TextureInfo *)p_texture_barriers[i].texture.id; vk_image_barriers[i] = {}; vk_image_barriers[i].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - vk_image_barriers[i].srcAccessMask = (VkAccessFlags)p_texture_barriers[i].src_access; - vk_image_barriers[i].dstAccessMask = (VkAccessFlags)p_texture_barriers[i].dst_access; - vk_image_barriers[i].oldLayout = (VkImageLayout)p_texture_barriers[i].prev_layout; - vk_image_barriers[i].newLayout = (VkImageLayout)p_texture_barriers[i].next_layout; + vk_image_barriers[i].srcAccessMask = _rd_to_vk_access_flags(p_texture_barriers[i].src_access); + vk_image_barriers[i].dstAccessMask = _rd_to_vk_access_flags(p_texture_barriers[i].dst_access); + vk_image_barriers[i].oldLayout = RD_TO_VK_LAYOUT[p_texture_barriers[i].prev_layout]; + vk_image_barriers[i].newLayout = RD_TO_VK_LAYOUT[p_texture_barriers[i].next_layout]; vk_image_barriers[i].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; vk_image_barriers[i].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; vk_image_barriers[i].image = tex_info->vk_view_create_info.image; @@ -1984,8 +2031,8 @@ void RenderingDeviceDriverVulkan::command_pipeline_barrier( vkCmdPipelineBarrier( (VkCommandBuffer)p_cmd_buffer.id, - (VkPipelineStageFlags)p_src_stages, - (VkPipelineStageFlags)p_dst_stages, + _rd_to_vk_pipeline_stages(p_src_stages), + _rd_to_vk_pipeline_stages(p_dst_stages), 0, p_memory_barriers.size(), vk_memory_barriers, p_buffer_barriers.size(), vk_buffer_barriers, @@ -3727,7 +3774,7 @@ void RenderingDeviceDriverVulkan::command_copy_texture(CommandBufferID p_cmd_buf const TextureInfo *src_tex_info = (const TextureInfo *)p_src_texture.id; const TextureInfo *dst_tex_info = (const TextureInfo *)p_dst_texture.id; - vkCmdCopyImage((VkCommandBuffer)p_cmd_buffer.id, src_tex_info->vk_view_create_info.image, (VkImageLayout)p_src_texture_layout, dst_tex_info->vk_view_create_info.image, (VkImageLayout)p_dst_texture_layout, p_regions.size(), vk_copy_regions); + vkCmdCopyImage((VkCommandBuffer)p_cmd_buffer.id, src_tex_info->vk_view_create_info.image, RD_TO_VK_LAYOUT[p_src_texture_layout], dst_tex_info->vk_view_create_info.image, RD_TO_VK_LAYOUT[p_dst_texture_layout], p_regions.size(), vk_copy_regions); } void RenderingDeviceDriverVulkan::command_resolve_texture(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, uint32_t p_src_layer, uint32_t p_src_mipmap, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, uint32_t p_dst_layer, uint32_t p_dst_mipmap) { @@ -3747,7 +3794,7 @@ void RenderingDeviceDriverVulkan::command_resolve_texture(CommandBufferID p_cmd_ vk_resolve.extent.height = MAX(1u, src_tex_info->vk_create_info.extent.height >> p_src_mipmap); vk_resolve.extent.depth = MAX(1u, src_tex_info->vk_create_info.extent.depth >> p_src_mipmap); - vkCmdResolveImage((VkCommandBuffer)p_cmd_buffer.id, src_tex_info->vk_view_create_info.image, (VkImageLayout)p_src_texture_layout, dst_tex_info->vk_view_create_info.image, (VkImageLayout)p_dst_texture_layout, 1, &vk_resolve); + vkCmdResolveImage((VkCommandBuffer)p_cmd_buffer.id, src_tex_info->vk_view_create_info.image, RD_TO_VK_LAYOUT[p_src_texture_layout], dst_tex_info->vk_view_create_info.image, RD_TO_VK_LAYOUT[p_dst_texture_layout], 1, &vk_resolve); } void RenderingDeviceDriverVulkan::command_clear_color_texture(CommandBufferID p_cmd_buffer, TextureID p_texture, TextureLayout p_texture_layout, const Color &p_color, const TextureSubresourceRange &p_subresources) { @@ -3758,7 +3805,7 @@ void RenderingDeviceDriverVulkan::command_clear_color_texture(CommandBufferID p_ _texture_subresource_range_to_vk(p_subresources, &vk_subresources); const TextureInfo *tex_info = (const TextureInfo *)p_texture.id; - vkCmdClearColorImage((VkCommandBuffer)p_cmd_buffer.id, tex_info->vk_view_create_info.image, (VkImageLayout)p_texture_layout, &vk_color, 1, &vk_subresources); + vkCmdClearColorImage((VkCommandBuffer)p_cmd_buffer.id, tex_info->vk_view_create_info.image, RD_TO_VK_LAYOUT[p_texture_layout], &vk_color, 1, &vk_subresources); } void RenderingDeviceDriverVulkan::command_copy_buffer_to_texture(CommandBufferID p_cmd_buffer, BufferID p_src_buffer, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, VectorView<BufferTextureCopyRegion> p_regions) { @@ -3769,7 +3816,7 @@ void RenderingDeviceDriverVulkan::command_copy_buffer_to_texture(CommandBufferID const BufferInfo *buf_info = (const BufferInfo *)p_src_buffer.id; const TextureInfo *tex_info = (const TextureInfo *)p_dst_texture.id; - vkCmdCopyBufferToImage((VkCommandBuffer)p_cmd_buffer.id, buf_info->vk_buffer, tex_info->vk_view_create_info.image, (VkImageLayout)p_dst_texture_layout, p_regions.size(), vk_copy_regions); + vkCmdCopyBufferToImage((VkCommandBuffer)p_cmd_buffer.id, buf_info->vk_buffer, tex_info->vk_view_create_info.image, RD_TO_VK_LAYOUT[p_dst_texture_layout], p_regions.size(), vk_copy_regions); } void RenderingDeviceDriverVulkan::command_copy_texture_to_buffer(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, BufferID p_dst_buffer, VectorView<BufferTextureCopyRegion> p_regions) { @@ -3780,7 +3827,7 @@ void RenderingDeviceDriverVulkan::command_copy_texture_to_buffer(CommandBufferID const TextureInfo *tex_info = (const TextureInfo *)p_src_texture.id; const BufferInfo *buf_info = (const BufferInfo *)p_dst_buffer.id; - vkCmdCopyImageToBuffer((VkCommandBuffer)p_cmd_buffer.id, tex_info->vk_view_create_info.image, (VkImageLayout)p_src_texture_layout, buf_info->vk_buffer, p_regions.size(), vk_copy_regions); + vkCmdCopyImageToBuffer((VkCommandBuffer)p_cmd_buffer.id, tex_info->vk_view_create_info.image, RD_TO_VK_LAYOUT[p_src_texture_layout], buf_info->vk_buffer, p_regions.size(), vk_copy_regions); } /******************/ @@ -3926,7 +3973,7 @@ static void _attachment_reference_to_vk(const RDD::AttachmentReference &p_attach *r_vk_attachment_reference = {}; r_vk_attachment_reference->sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR; r_vk_attachment_reference->attachment = p_attachment_reference.attachment; - r_vk_attachment_reference->layout = (VkImageLayout)p_attachment_reference.layout; + r_vk_attachment_reference->layout = RD_TO_VK_LAYOUT[p_attachment_reference.layout]; r_vk_attachment_reference->aspectMask = (VkImageAspectFlags)p_attachment_reference.aspect; } @@ -3945,8 +3992,8 @@ RDD::RenderPassID RenderingDeviceDriverVulkan::render_pass_create(VectorView<Att vk_attachments[i].storeOp = (VkAttachmentStoreOp)p_attachments[i].store_op; vk_attachments[i].stencilLoadOp = (VkAttachmentLoadOp)p_attachments[i].stencil_load_op; vk_attachments[i].stencilStoreOp = (VkAttachmentStoreOp)p_attachments[i].stencil_store_op; - vk_attachments[i].initialLayout = (VkImageLayout)p_attachments[i].initial_layout; - vk_attachments[i].finalLayout = (VkImageLayout)p_attachments[i].final_layout; + vk_attachments[i].initialLayout = RD_TO_VK_LAYOUT[p_attachments[i].initial_layout]; + vk_attachments[i].finalLayout = RD_TO_VK_LAYOUT[p_attachments[i].final_layout]; } VkSubpassDescription2KHR *vk_subpasses = ALLOCA_ARRAY(VkSubpassDescription2KHR, p_subpasses.size()); @@ -4010,10 +4057,10 @@ RDD::RenderPassID RenderingDeviceDriverVulkan::render_pass_create(VectorView<Att vk_subpass_dependencies[i].sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2; vk_subpass_dependencies[i].srcSubpass = p_subpass_dependencies[i].src_subpass; vk_subpass_dependencies[i].dstSubpass = p_subpass_dependencies[i].dst_subpass; - vk_subpass_dependencies[i].srcStageMask = (VkPipelineStageFlags)p_subpass_dependencies[i].src_stages; - vk_subpass_dependencies[i].dstStageMask = (VkPipelineStageFlags)p_subpass_dependencies[i].dst_stages; - vk_subpass_dependencies[i].srcAccessMask = (VkAccessFlags)p_subpass_dependencies[i].src_access; - vk_subpass_dependencies[i].dstAccessMask = (VkAccessFlags)p_subpass_dependencies[i].dst_access; + vk_subpass_dependencies[i].srcStageMask = _rd_to_vk_pipeline_stages(p_subpass_dependencies[i].src_stages); + vk_subpass_dependencies[i].dstStageMask = _rd_to_vk_pipeline_stages(p_subpass_dependencies[i].dst_stages); + vk_subpass_dependencies[i].srcAccessMask = _rd_to_vk_access_flags(p_subpass_dependencies[i].src_access); + vk_subpass_dependencies[i].dstAccessMask = _rd_to_vk_access_flags(p_subpass_dependencies[i].dst_access); } VkRenderPassCreateInfo2KHR create_info = {}; diff --git a/drivers/vulkan/rendering_device_driver_vulkan.h b/drivers/vulkan/rendering_device_driver_vulkan.h index b9e7563069..6847ae00be 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.h +++ b/drivers/vulkan/rendering_device_driver_vulkan.h @@ -210,6 +210,7 @@ public: virtual uint8_t *texture_map(TextureID p_texture, const TextureSubresource &p_subresource) override final; virtual void texture_unmap(TextureID p_texture) override final; virtual BitField<TextureUsageBits> texture_get_usages_supported_by_format(DataFormat p_format, bool p_cpu_readable) override final; + virtual bool texture_can_make_shared_with_format(TextureID p_texture, DataFormat p_format, bool &r_raw_reinterpretation) override final; /*****************/ /**** SAMPLER ****/ diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp index 3023c5907a..f70730d540 100644 --- a/editor/action_map_editor.cpp +++ b/editor/action_map_editor.cpp @@ -428,6 +428,7 @@ void ActionMapEditor::update_action_list(const Vector<ActionInfo> &p_action_info // Update Tree... TreeItem *action_item = action_tree->create_item(root); + ERR_FAIL_NULL(action_item); action_item->set_meta("__action", action_info.action); action_item->set_meta("__name", action_info.name); @@ -604,7 +605,7 @@ ActionMapEditor::ActionMapEditor() { action_tree->set_column_custom_minimum_width(1, 80 * EDSCALE); action_tree->set_column_expand(2, false); action_tree->set_column_custom_minimum_width(2, 50 * EDSCALE); - action_tree->connect("item_edited", callable_mp(this, &ActionMapEditor::_action_edited)); + action_tree->connect("item_edited", callable_mp(this, &ActionMapEditor::_action_edited), CONNECT_DEFERRED); action_tree->connect("item_activated", callable_mp(this, &ActionMapEditor::_tree_item_activated)); action_tree->connect("button_clicked", callable_mp(this, &ActionMapEditor::_tree_button_pressed)); main_vbox->add_child(action_tree); diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp index baec996016..2136a843b6 100644 --- a/editor/animation_bezier_editor.cpp +++ b/editor/animation_bezier_editor.cpp @@ -1950,5 +1950,5 @@ AnimationBezierTrackEdit::AnimationBezierTrackEdit() { menu = memnew(PopupMenu); add_child(menu); - menu->connect("id_pressed", callable_mp(this, &AnimationBezierTrackEdit::_menu_selected)); + menu->connect(SceneStringName(id_pressed), callable_mp(this, &AnimationBezierTrackEdit::_menu_selected)); } diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 045774080c..2d497a281f 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -2810,7 +2810,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) { if (!menu) { menu = memnew(PopupMenu); add_child(menu); - menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected)); + menu->connect(SceneStringName(id_pressed), callable_mp(this, &AnimationTrackEdit::_menu_selected)); } menu->clear(); if (animation->track_get_type(track) == Animation::TYPE_AUDIO) { @@ -2833,7 +2833,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) { if (!menu) { menu = memnew(PopupMenu); add_child(menu); - menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected)); + menu->connect(SceneStringName(id_pressed), callable_mp(this, &AnimationTrackEdit::_menu_selected)); } menu->clear(); menu->add_icon_item(get_editor_theme_icon(SNAME("InterpRaw")), TTR("Nearest"), MENU_INTERPOLATION_NEAREST); @@ -2879,7 +2879,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) { if (!menu) { menu = memnew(PopupMenu); add_child(menu); - menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected)); + menu->connect(SceneStringName(id_pressed), callable_mp(this, &AnimationTrackEdit::_menu_selected)); } menu->clear(); menu->add_icon_item(get_editor_theme_icon(SNAME("InterpWrapClamp")), TTR("Clamp Loop Interp"), MENU_LOOP_CLAMP); @@ -2913,7 +2913,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) { if (!menu) { menu = memnew(PopupMenu); add_child(menu); - menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected)); + menu->connect(SceneStringName(id_pressed), callable_mp(this, &AnimationTrackEdit::_menu_selected)); } bool selected = _try_select_at_ui_pos(pos, mb->is_command_or_control_pressed() || mb->is_shift_pressed(), false); @@ -4850,7 +4850,7 @@ void AnimationTrackEditor::_notification(int p_what) { imported_anim_warning->set_icon(get_editor_theme_icon(SNAME("NodeWarning"))); dummy_player_warning->set_icon(get_editor_theme_icon(SNAME("NodeWarning"))); inactive_player_warning->set_icon(get_editor_theme_icon(SNAME("NodeWarning"))); - main_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); + main_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree"))); edit->get_popup()->set_item_icon(edit->get_popup()->get_item_index(EDIT_APPLY_RESET), get_editor_theme_icon(SNAME("Reload"))); auto_fit->set_icon(get_editor_theme_icon(SNAME("AnimationAutoFit"))); auto_fit_bezier->set_icon(get_editor_theme_icon(SNAME("AnimationAutoFitBezier"))); @@ -7365,7 +7365,7 @@ AnimationTrackEditor::AnimationTrackEditor() { edit->get_popup()->add_item(TTR("Optimize Animation (no undo)..."), EDIT_OPTIMIZE_ANIMATION); edit->get_popup()->add_item(TTR("Clean-Up Animation (no undo)..."), EDIT_CLEAN_UP_ANIMATION); - edit->get_popup()->connect("id_pressed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed)); + edit->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed)); edit->get_popup()->connect("about_to_popup", callable_mp(this, &AnimationTrackEditor::_edit_menu_about_to_popup)); pick_track = memnew(SceneTreeDialog); diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index ee0108df8e..0e272429a3 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -1124,6 +1124,31 @@ void CodeTextEditor::trim_trailing_whitespace() { } } +void CodeTextEditor::trim_final_newlines() { + int final_line = text_editor->get_line_count() - 1; + int check_line = final_line; + + String line = text_editor->get_line(check_line); + + while (line.is_empty() && check_line > -1) { + --check_line; + + line = text_editor->get_line(check_line); + } + + ++check_line; + + if (check_line < final_line) { + text_editor->begin_complex_operation(); + + text_editor->remove_text(check_line, 0, final_line, 0); + + text_editor->merge_overlapping_carets(); + text_editor->end_complex_operation(); + text_editor->queue_redraw(); + } +} + void CodeTextEditor::insert_final_newline() { int final_line = text_editor->get_line_count() - 1; String line = text_editor->get_line(final_line); @@ -1769,7 +1794,7 @@ CodeTextEditor::CodeTextEditor() { zoom_menu->set_item_metadata(i, z); } - zoom_menu->connect("id_pressed", callable_mp(this, &CodeTextEditor::_zoom_popup_id_pressed)); + zoom_menu->connect(SceneStringName(id_pressed), callable_mp(this, &CodeTextEditor::_zoom_popup_id_pressed)); status_bar->add_child(memnew(VSeparator)); diff --git a/editor/code_editor.h b/editor/code_editor.h index 75a2a68d58..af33a3fac8 100644 --- a/editor/code_editor.h +++ b/editor/code_editor.h @@ -224,6 +224,7 @@ protected: public: void trim_trailing_whitespace(); + void trim_final_newlines(); void insert_final_newline(); enum CaseStyle { diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index cb775a67e7..4f669c774b 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -465,10 +465,10 @@ void ConnectDialog::_notification(int p_what) { type_list->set_item_icon(i, get_editor_theme_icon(type_name)); } - Ref<StyleBox> style = get_theme_stylebox("normal", "LineEdit")->duplicate(); + Ref<StyleBox> style = get_theme_stylebox(CoreStringName(normal), "LineEdit")->duplicate(); if (style.is_valid()) { style->set_content_margin(SIDE_TOP, style->get_content_margin(SIDE_TOP) + 1.0); - from_signal->add_theme_style_override("normal", style); + from_signal->add_theme_style_override(CoreStringName(normal), style); } method_search->set_right_icon(get_editor_theme_icon("Search")); open_method_tree->set_icon(get_editor_theme_icon("Edit")); @@ -1596,13 +1596,13 @@ ConnectionsDock::ConnectionsDock() { disconnect_all_dialog->set_text(TTR("Are you sure you want to remove all connections from this signal?")); class_menu = memnew(PopupMenu); - class_menu->connect("id_pressed", callable_mp(this, &ConnectionsDock::_handle_class_menu_option)); + class_menu->connect(SceneStringName(id_pressed), callable_mp(this, &ConnectionsDock::_handle_class_menu_option)); class_menu->connect("about_to_popup", callable_mp(this, &ConnectionsDock::_class_menu_about_to_popup)); class_menu->add_item(TTR("Open Documentation"), CLASS_MENU_OPEN_DOCS); add_child(class_menu); signal_menu = memnew(PopupMenu); - signal_menu->connect("id_pressed", callable_mp(this, &ConnectionsDock::_handle_signal_menu_option)); + signal_menu->connect(SceneStringName(id_pressed), callable_mp(this, &ConnectionsDock::_handle_signal_menu_option)); signal_menu->connect("about_to_popup", callable_mp(this, &ConnectionsDock::_signal_menu_about_to_popup)); signal_menu->add_item(TTR("Connect..."), SIGNAL_MENU_CONNECT); signal_menu->add_item(TTR("Disconnect All"), SIGNAL_MENU_DISCONNECT_ALL); @@ -1612,7 +1612,7 @@ ConnectionsDock::ConnectionsDock() { add_child(signal_menu); slot_menu = memnew(PopupMenu); - slot_menu->connect("id_pressed", callable_mp(this, &ConnectionsDock::_handle_slot_menu_option)); + slot_menu->connect(SceneStringName(id_pressed), callable_mp(this, &ConnectionsDock::_handle_slot_menu_option)); slot_menu->connect("about_to_popup", callable_mp(this, &ConnectionsDock::_slot_menu_about_to_popup)); slot_menu->add_item(TTR("Edit..."), SLOT_MENU_EDIT); slot_menu->add_item(TTR("Go to Method"), SLOT_MENU_GO_TO_METHOD); diff --git a/editor/debugger/debug_adapter/debug_adapter_server.cpp b/editor/debugger/debug_adapter/debug_adapter_server.cpp index a16c494299..6041fec06c 100644 --- a/editor/debugger/debug_adapter/debug_adapter_server.cpp +++ b/editor/debugger/debug_adapter/debug_adapter_server.cpp @@ -35,6 +35,8 @@ #include "editor/editor_node.h" #include "editor/editor_settings.h" +int DebugAdapterServer::port_override = -1; + DebugAdapterServer::DebugAdapterServer() { _EDITOR_DEF("network/debug_adapter/remote_port", remote_port); _EDITOR_DEF("network/debug_adapter/request_timeout", protocol._request_timeout); @@ -67,7 +69,7 @@ void DebugAdapterServer::_notification(int p_what) { } protocol._request_timeout = EDITOR_GET("network/debug_adapter/request_timeout"); protocol._sync_breakpoints = EDITOR_GET("network/debug_adapter/sync_breakpoints"); - int port = _EDITOR_GET("network/debug_adapter/remote_port"); + int port = (DebugAdapterServer::port_override > -1) ? DebugAdapterServer::port_override : (int)_EDITOR_GET("network/debug_adapter/remote_port"); if (port != remote_port) { stop(); start(); @@ -77,9 +79,9 @@ void DebugAdapterServer::_notification(int p_what) { } void DebugAdapterServer::start() { - remote_port = (int)_EDITOR_GET("network/debug_adapter/remote_port"); + remote_port = (DebugAdapterServer::port_override > -1) ? DebugAdapterServer::port_override : (int)_EDITOR_GET("network/debug_adapter/remote_port"); if (protocol.start(remote_port, IPAddress("127.0.0.1")) == OK) { - EditorNode::get_log()->add_message("--- Debug adapter server started ---", EditorLog::MSG_TYPE_EDITOR); + EditorNode::get_log()->add_message("--- Debug adapter server started on port " + itos(remote_port) + " ---", EditorLog::MSG_TYPE_EDITOR); set_process_internal(true); started = true; } diff --git a/editor/debugger/debug_adapter/debug_adapter_server.h b/editor/debugger/debug_adapter/debug_adapter_server.h index 310bac1b6c..52271b1666 100644 --- a/editor/debugger/debug_adapter/debug_adapter_server.h +++ b/editor/debugger/debug_adapter/debug_adapter_server.h @@ -49,6 +49,7 @@ private: void _notification(int p_what); public: + static int port_override; DebugAdapterServer(); void start(); void stop(); diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp index 1d3c7aec3f..3f8df5e313 100644 --- a/editor/debugger/editor_debugger_node.cpp +++ b/editor/debugger/editor_debugger_node.cpp @@ -75,7 +75,7 @@ EditorDebuggerNode::EditorDebuggerNode() { Ref<StyleBoxEmpty> empty; empty.instantiate(); - tabs->add_theme_style_override("panel", empty); + tabs->add_theme_style_override(SceneStringName(panel), empty); auto_switch_remote_scene_tree = EDITOR_GET("debugger/auto_switch_to_remote_scene_tree"); _add_debugger(); @@ -123,7 +123,7 @@ ScriptEditorDebugger *EditorDebuggerNode::_add_debugger() { if (tabs->get_tab_count() > 1) { node->clear_style(); tabs->set_tabs_visible(true); - tabs->add_theme_style_override("panel", EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("DebuggerPanel"), EditorStringName(EditorStyles))); + tabs->add_theme_style_override(SceneStringName(panel), EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("DebuggerPanel"), EditorStringName(EditorStyles))); } if (!debugger_plugins.is_empty()) { @@ -268,11 +268,7 @@ Error EditorDebuggerNode::start(const String &p_uri) { } stop(true); current_uri = p_uri; - if (EDITOR_GET("run/output/always_open_output_on_play")) { - EditorNode::get_bottom_panel()->make_item_visible(EditorNode::get_log()); - } else { - EditorNode::get_bottom_panel()->make_item_visible(this); - } + server = Ref<EditorDebuggerServer>(EditorDebuggerServer::create(p_uri.substr(0, p_uri.find("://") + 3))); const Error err = server->start(p_uri); if (err != OK) { @@ -314,12 +310,18 @@ void EditorDebuggerNode::stop(bool p_force) { void EditorDebuggerNode::_notification(int p_what) { switch (p_what) { case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { - if (tabs->get_tab_count() > 1 && EditorThemeManager::is_generated_theme_outdated()) { + if (!EditorThemeManager::is_generated_theme_outdated()) { + return; + } + + if (tabs->get_tab_count() > 1) { add_theme_constant_override("margin_left", -EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("BottomPanelDebuggerOverride"), EditorStringName(EditorStyles))->get_margin(SIDE_LEFT)); add_theme_constant_override("margin_right", -EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("BottomPanelDebuggerOverride"), EditorStringName(EditorStyles))->get_margin(SIDE_RIGHT)); - tabs->add_theme_style_override("panel", EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("DebuggerPanel"), EditorStringName(EditorStyles))); + tabs->add_theme_style_override(SceneStringName(panel), EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("DebuggerPanel"), EditorStringName(EditorStyles))); } + + remote_scene_tree->update_icon_max_width(); } break; case NOTIFICATION_READY: { @@ -494,7 +496,7 @@ void EditorDebuggerNode::set_script_debug_button(MenuButton *p_button) { p->add_shortcut(ED_GET_SHORTCUT("debugger/continue"), DEBUG_CONTINUE); p->add_separator(); p->add_check_shortcut(ED_GET_SHORTCUT("debugger/debug_with_external_editor"), DEBUG_WITH_EXTERNAL_EDITOR); - p->connect("id_pressed", callable_mp(this, &EditorDebuggerNode::_menu_option)); + p->connect(SceneStringName(id_pressed), callable_mp(this, &EditorDebuggerNode::_menu_option)); _break_state_changed(); script_menu->show(); diff --git a/editor/debugger/editor_debugger_tree.cpp b/editor/debugger/editor_debugger_tree.cpp index 63053d2574..f8ffce0c83 100644 --- a/editor/debugger/editor_debugger_tree.cpp +++ b/editor/debugger/editor_debugger_tree.cpp @@ -31,6 +31,7 @@ #include "editor_debugger_tree.h" #include "editor/editor_node.h" +#include "editor/editor_string_names.h" #include "editor/gui/editor_file_dialog.h" #include "editor/scene_tree_dock.h" #include "scene/debugger/scene_debugger.h" @@ -44,7 +45,7 @@ EditorDebuggerTree::EditorDebuggerTree() { // Popup item_menu = memnew(PopupMenu); - item_menu->connect("id_pressed", callable_mp(this, &EditorDebuggerTree::_item_menu_id_pressed)); + item_menu->connect(SceneStringName(id_pressed), callable_mp(this, &EditorDebuggerTree::_item_menu_id_pressed)); add_child(item_menu); // File Dialog @@ -62,6 +63,10 @@ void EditorDebuggerTree::_notification(int p_what) { connect("item_collapsed", callable_mp(this, &EditorDebuggerTree::_scene_tree_folded)); connect("item_mouse_selected", callable_mp(this, &EditorDebuggerTree::_scene_tree_rmb_selected)); } break; + + case NOTIFICATION_ENTER_TREE: { + update_icon_max_width(); + } break; } } @@ -293,6 +298,10 @@ Variant EditorDebuggerTree::get_drag_data(const Point2 &p_point) { return vformat("\"%s\"", path); } +void EditorDebuggerTree::update_icon_max_width() { + add_theme_constant_override("icon_max_width", get_theme_constant("class_icon_size", EditorStringName(Editor))); +} + String EditorDebuggerTree::get_selected_path() { if (!get_selected()) { return ""; diff --git a/editor/debugger/editor_debugger_tree.h b/editor/debugger/editor_debugger_tree.h index 895f33f1a2..dbffb0f219 100644 --- a/editor/debugger/editor_debugger_tree.h +++ b/editor/debugger/editor_debugger_tree.h @@ -72,6 +72,7 @@ public: virtual Variant get_drag_data(const Point2 &p_point) override; + void update_icon_max_width(); String get_selected_path(); ObjectID get_selected_object(); int get_current_debugger(); // Would love to have one tree for every debugger. diff --git a/editor/debugger/editor_profiler.cpp b/editor/debugger/editor_profiler.cpp index 69cf13ea0b..0e2a7ee599 100644 --- a/editor/debugger/editor_profiler.cpp +++ b/editor/debugger/editor_profiler.cpp @@ -34,6 +34,7 @@ #include "editor/editor_settings.h" #include "editor/editor_string_names.h" #include "editor/themes/editor_scale.h" +#include "editor/themes/editor_theme_manager.h" #include "scene/resources/image_texture.h" void EditorProfiler::_make_metric_ptrs(Metric &m) { @@ -423,6 +424,15 @@ void EditorProfiler::_notification(int p_what) { case NOTIFICATION_TRANSLATION_CHANGED: { activate->set_icon(get_editor_theme_icon(SNAME("Play"))); clear_button->set_icon(get_editor_theme_icon(SNAME("Clear"))); + + theme_cache.seek_line_color = get_theme_color(SNAME("font_color"), EditorStringName(Editor)); + theme_cache.seek_line_color.a = 0.8; + theme_cache.seek_line_hover_color = theme_cache.seek_line_color; + theme_cache.seek_line_hover_color.a = 0.4; + + if (total_metrics > 0) { + _update_plot(); + } } break; } } @@ -434,11 +444,11 @@ void EditorProfiler::_graph_tex_draw() { if (seeking) { int frame = cursor_metric_edit->get_value() - _get_frame_metric(0).frame_number; int cur_x = (2 * frame + 1) * graph->get_size().x / (2 * frame_metrics.size()) + 1; - graph->draw_line(Vector2(cur_x, 0), Vector2(cur_x, graph->get_size().y), Color(1, 1, 1, 0.8)); + graph->draw_line(Vector2(cur_x, 0), Vector2(cur_x, graph->get_size().y), theme_cache.seek_line_color); } if (hover_metric > -1 && hover_metric < total_metrics) { int cur_x = (2 * hover_metric + 1) * graph->get_size().x / (2 * frame_metrics.size()) + 1; - graph->draw_line(Vector2(cur_x, 0), Vector2(cur_x, graph->get_size().y), Color(1, 1, 1, 0.4)); + graph->draw_line(Vector2(cur_x, 0), Vector2(cur_x, graph->get_size().y), theme_cache.seek_line_hover_color); } } diff --git a/editor/debugger/editor_profiler.h b/editor/debugger/editor_profiler.h index 620d21fe98..64253070b1 100644 --- a/editor/debugger/editor_profiler.h +++ b/editor/debugger/editor_profiler.h @@ -94,6 +94,11 @@ public: }; private: + struct ThemeCache { + Color seek_line_color; + Color seek_line_hover_color; + } theme_cache; + Button *activate = nullptr; Button *clear_button = nullptr; TextureRect *graph = nullptr; diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp index 156e740509..e35ca590b3 100644 --- a/editor/debugger/script_editor_debugger.cpp +++ b/editor/debugger/script_editor_debugger.cpp @@ -154,7 +154,7 @@ void ScriptEditorDebugger::update_tabs() { } void ScriptEditorDebugger::clear_style() { - tabs->remove_theme_style_override("panel"); + tabs->remove_theme_style_override(SceneStringName(panel)); } void ScriptEditorDebugger::save_node(ObjectID p_id, const String &p_file) { @@ -857,7 +857,7 @@ void ScriptEditorDebugger::_notification(int p_what) { [[fallthrough]]; } case NOTIFICATION_THEME_CHANGED: { - tabs->add_theme_style_override("panel", get_theme_stylebox(SNAME("DebuggerPanel"), EditorStringName(EditorStyles))); + tabs->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("DebuggerPanel"), EditorStringName(EditorStyles))); skip_breakpoints->set_icon(get_editor_theme_icon(skip_breakpoints_value ? SNAME("DebugSkipBreakpointsOn") : SNAME("DebugSkipBreakpointsOff"))); copy->set_icon(get_editor_theme_icon(SNAME("ActionCopy"))); @@ -1009,7 +1009,6 @@ void ScriptEditorDebugger::start(Ref<RemoteDebuggerPeer> p_peer) { set_process(true); camera_override = CameraOverride::OVERRIDE_NONE; - tabs->set_current_tab(0); _set_reason_text(TTR("Debug session started."), MESSAGE_SUCCESS); _update_buttons_state(); emit_signal(SNAME("started")); @@ -1938,7 +1937,7 @@ ScriptEditorDebugger::ScriptEditorDebugger() { tabs->add_child(dbg); breakpoints_menu = memnew(PopupMenu); - breakpoints_menu->connect("id_pressed", callable_mp(this, &ScriptEditorDebugger::_item_menu_id_pressed)); + breakpoints_menu->connect(SceneStringName(id_pressed), callable_mp(this, &ScriptEditorDebugger::_item_menu_id_pressed)); breakpoints_tree->add_child(breakpoints_menu); } @@ -1991,7 +1990,7 @@ ScriptEditorDebugger::ScriptEditorDebugger() { errors_tab->add_child(error_tree); item_menu = memnew(PopupMenu); - item_menu->connect("id_pressed", callable_mp(this, &ScriptEditorDebugger::_item_menu_id_pressed)); + item_menu->connect(SceneStringName(id_pressed), callable_mp(this, &ScriptEditorDebugger::_item_menu_id_pressed)); error_tree->add_child(item_menu); tabs->add_child(errors_tab); diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp index 4c21f51e9c..0c870baec1 100644 --- a/editor/dependency_editor.cpp +++ b/editor/dependency_editor.cpp @@ -396,7 +396,7 @@ void DependencyEditorOwners::show(const String &p_path) { DependencyEditorOwners::DependencyEditorOwners() { file_options = memnew(PopupMenu); add_child(file_options); - file_options->connect("id_pressed", callable_mp(this, &DependencyEditorOwners::_file_option)); + file_options->connect(SceneStringName(id_pressed), callable_mp(this, &DependencyEditorOwners::_file_option)); owners = memnew(ItemList); owners->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp index 0b5122fce2..a4994d1f92 100644 --- a/editor/editor_audio_buses.cpp +++ b/editor/editor_audio_buses.cpp @@ -107,7 +107,7 @@ void EditorAudioBus::_notification(int p_what) { audio_value_preview_label->add_theme_color_override("font_color", get_theme_color(SNAME("font_color"), SNAME("TooltipLabel"))); audio_value_preview_label->add_theme_color_override("font_shadow_color", get_theme_color(SNAME("font_shadow_color"), SNAME("TooltipLabel"))); - audio_value_preview_box->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TooltipPanel"))); + audio_value_preview_box->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("TooltipPanel"))); for (int i = 0; i < effect_options->get_item_count(); i++) { String class_name = effect_options->get_item_metadata(i); @@ -127,7 +127,7 @@ void EditorAudioBus::_notification(int p_what) { } else if (has_focus()) { draw_style_box(get_theme_stylebox(SNAME("focus"), SNAME("Button")), Rect2(Vector2(), get_size())); } else { - draw_style_box(get_theme_stylebox(SNAME("panel"), SNAME("TabContainer")), Rect2(Vector2(), get_size())); + draw_style_box(get_theme_stylebox(SceneStringName(panel), SNAME("TabContainer")), Rect2(Vector2(), get_size())); } if (get_index() != 0 && hovering_drop) { @@ -608,7 +608,7 @@ Variant EditorAudioBus::get_drag_data(const Point2 &p_point) { Panel *p = memnew(Panel); c->add_child(p); p->set_modulate(Color(1, 1, 1, 0.7)); - p->add_theme_style_override("panel", get_theme_stylebox(SNAME("focus"), SNAME("Button"))); + p->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("focus"), SNAME("Button"))); p->set_size(get_size()); p->set_position(-p_point); set_drag_preview(c); @@ -837,7 +837,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) { for (int i = 0; i < hbc->get_child_count(); i++) { Control *child = Object::cast_to<Control>(hbc->get_child(i)); child->begin_bulk_theme_override(); - child->add_theme_style_override("normal", sbempty); + child->add_theme_style_override(CoreStringName(normal), sbempty); child->add_theme_style_override("hover", sbempty); child->add_theme_style_override("focus", sbempty); @@ -1062,7 +1062,7 @@ void EditorAudioBuses::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { - bus_scroll->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); + bus_scroll->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree"))); } break; case NOTIFICATION_READY: { diff --git a/editor/editor_dock_manager.cpp b/editor/editor_dock_manager.cpp index 5d98fefa76..ccb47220db 100644 --- a/editor/editor_dock_manager.cpp +++ b/editor/editor_dock_manager.cpp @@ -838,7 +838,7 @@ EditorDockManager::EditorDockManager() { docks_menu = memnew(PopupMenu); docks_menu->set_hide_on_item_selection(false); - docks_menu->connect("id_pressed", callable_mp(this, &EditorDockManager::_docks_menu_option)); + docks_menu->connect(SceneStringName(id_pressed), callable_mp(this, &EditorDockManager::_docks_menu_option)); EditorNode::get_singleton()->get_gui_base()->connect(SceneStringName(theme_changed), callable_mp(this, &EditorDockManager::_update_docks_menu)); } diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp index 020706c714..ba04f36abe 100644 --- a/editor/editor_feature_profile.cpp +++ b/editor/editor_feature_profile.cpp @@ -1010,7 +1010,7 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() { // Add some spacing above the help label. Ref<StyleBoxEmpty> sb = memnew(StyleBoxEmpty); sb->set_content_margin(SIDE_TOP, 20 * EDSCALE); - no_profile_selected_help->add_theme_style_override("normal", sb); + no_profile_selected_help->add_theme_style_override(CoreStringName(normal), sb); no_profile_selected_help->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); no_profile_selected_help->set_v_size_flags(Control::SIZE_EXPAND_FILL); h_split->add_child(no_profile_selected_help); diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 9884241708..ec064a92d7 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -37,7 +37,7 @@ #include "core/object/script_language.h" #include "core/os/keyboard.h" #include "core/string/string_builder.h" -#include "core/version.h" +#include "core/version_generated.gen.h" #include "editor/doc_data_compressed.gen.h" #include "editor/editor_node.h" #include "editor/editor_paths.h" @@ -345,7 +345,7 @@ void EditorHelp::_class_desc_resized(bool p_force_update_theme) { Ref<StyleBox> class_desc_stylebox = theme_cache.background_style->duplicate(); class_desc_stylebox->set_content_margin(SIDE_LEFT, display_margin); class_desc_stylebox->set_content_margin(SIDE_RIGHT, display_margin); - class_desc->add_theme_style_override("normal", class_desc_stylebox); + class_desc->add_theme_style_override(CoreStringName(normal), class_desc_stylebox); class_desc->add_theme_style_override("focused", class_desc_stylebox); } } @@ -2340,6 +2340,9 @@ void EditorHelp::_help_callback(const String &p_topic) { if (class_desc->is_ready()) { // call_deferred() is not enough. + if (class_desc->is_connected(SceneStringName(draw), callable_mp(class_desc, &RichTextLabel::scroll_to_paragraph))) { + class_desc->disconnect(SceneStringName(draw), callable_mp(class_desc, &RichTextLabel::scroll_to_paragraph)); + } class_desc->connect(SceneStringName(draw), callable_mp(class_desc, &RichTextLabel::scroll_to_paragraph).bind(line), CONNECT_ONE_SHOT | CONNECT_DEFERRED); } else { scroll_to = line; @@ -2890,7 +2893,7 @@ void EditorHelp::_load_doc_thread(void *p_udata) { callable_mp_static(&EditorHelp::_gen_extensions_docs).call_deferred(); } else { // We have to go back to the main thread to start from scratch, bypassing any possibly existing cache. - callable_mp_static(&EditorHelp::generate_doc).bind(false).call_deferred(); + callable_mp_static(&EditorHelp::generate_doc).call_deferred(false); } OS::get_singleton()->benchmark_end_measure("EditorHelp", vformat("Generate Documentation (Run %d)", doc_generation_count)); @@ -3380,6 +3383,7 @@ EditorHelpBit::HelpData EditorHelpBit::_get_theme_item_help_data(const StringNam if (theme_item.name == p_theme_item_name) { result = current; found = true; + if (!is_native) { break; } @@ -3719,7 +3723,7 @@ void EditorHelpBit::set_content_height_limits(float p_min, float p_max) { void EditorHelpBit::update_content_height() { float content_height = content->get_content_height(); - const Ref<StyleBox> style = content->get_theme_stylebox("normal"); + const Ref<StyleBox> style = content->get_theme_stylebox(CoreStringName(normal)); if (style.is_valid()) { content_height += style->get_content_margin(SIDE_TOP) + style->get_content_margin(SIDE_BOTTOM); } diff --git a/editor/editor_inspector.compat.inc b/editor/editor_inspector.compat.inc new file mode 100644 index 0000000000..53c410ba26 --- /dev/null +++ b/editor/editor_inspector.compat.inc @@ -0,0 +1,41 @@ +/**************************************************************************/ +/* editor_inspector.compat.inc */ +/**************************************************************************/ +/* 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 DISABLE_DEPRECATED + +void EditorInspectorPlugin::_add_property_editor_bind_compat_92322(const String &p_for_property, Control *p_prop, bool p_add_to_end) { + add_property_editor(p_for_property, p_prop, p_add_to_end, ""); +} + +void EditorInspectorPlugin::_bind_compatibility_methods() { + ClassDB::bind_compatibility_method(D_METHOD("add_property_editor", "property", "editor", "add_to_end"), &EditorInspectorPlugin::_add_property_editor_bind_compat_92322, DEFVAL(false)); +} + +#endif // DISABLE_DEPRECATED diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index a9f32927a8..c1ee2ef0e0 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -29,6 +29,7 @@ /**************************************************************************/ #include "editor_inspector.h" +#include "editor_inspector.compat.inc" #include "core/os/keyboard.h" #include "editor/doc_tools.h" @@ -516,9 +517,9 @@ void EditorProperty::_update_property_bg() { add_theme_style_override("bg_selected", get_theme_stylebox("sub_inspector_property_bg" + itos(count_subinspectors), EditorStringName(EditorStyles))); add_theme_style_override("bg", get_theme_stylebox("sub_inspector_property_bg" + itos(count_subinspectors), EditorStringName(EditorStyles))); add_theme_color_override("property_color", get_theme_color(SNAME("sub_inspector_property_color"), EditorStringName(EditorStyles))); - bottom_editor->add_theme_style_override("panel", get_theme_stylebox("sub_inspector_bg" + itos(count_subinspectors), EditorStringName(EditorStyles))); + bottom_editor->add_theme_style_override(SceneStringName(panel), get_theme_stylebox("sub_inspector_bg" + itos(count_subinspectors), EditorStringName(EditorStyles))); } else { - bottom_editor->add_theme_style_override("panel", get_theme_stylebox("sub_inspector_bg_no_border", EditorStringName(EditorStyles))); + bottom_editor->add_theme_style_override(SceneStringName(panel), get_theme_stylebox("sub_inspector_bg_no_border", EditorStringName(EditorStyles))); } } else { remove_theme_style_override("bg_selected"); @@ -1093,7 +1094,7 @@ void EditorProperty::_update_popup() { } else { menu = memnew(PopupMenu); add_child(menu); - menu->connect("id_pressed", callable_mp(this, &EditorProperty::menu_option)); + menu->connect(SceneStringName(id_pressed), callable_mp(this, &EditorProperty::menu_option)); } menu->add_icon_shortcut(get_editor_theme_icon(SNAME("ActionCopy")), ED_GET_SHORTCUT("property_editor/copy_value"), MENU_COPY_VALUE); menu->add_icon_shortcut(get_editor_theme_icon(SNAME("ActionPaste")), ED_GET_SHORTCUT("property_editor/paste_value"), MENU_PASTE_VALUE); @@ -1128,11 +1129,12 @@ void EditorInspectorPlugin::add_custom_control(Control *control) { added_editors.push_back(ae); } -void EditorInspectorPlugin::add_property_editor(const String &p_for_property, Control *p_prop, bool p_add_to_end) { +void EditorInspectorPlugin::add_property_editor(const String &p_for_property, Control *p_prop, bool p_add_to_end, const String &p_label) { AddedEditor ae; ae.properties.push_back(p_for_property); ae.property_editor = p_prop; ae.add_to_end = p_add_to_end; + ae.label = p_label; added_editors.push_back(ae); } @@ -1174,7 +1176,7 @@ void EditorInspectorPlugin::parse_end(Object *p_object) { void EditorInspectorPlugin::_bind_methods() { ClassDB::bind_method(D_METHOD("add_custom_control", "control"), &EditorInspectorPlugin::add_custom_control); - ClassDB::bind_method(D_METHOD("add_property_editor", "property", "editor", "add_to_end"), &EditorInspectorPlugin::add_property_editor, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("add_property_editor", "property", "editor", "add_to_end", "label"), &EditorInspectorPlugin::add_property_editor, DEFVAL(false), DEFVAL(String())); ClassDB::bind_method(D_METHOD("add_property_editor_for_multiple_properties", "label", "properties", "editor"), &EditorInspectorPlugin::add_property_editor_for_multiple_properties); GDVIRTUAL_BIND(_can_handle, "object") @@ -1288,7 +1290,7 @@ void EditorInspectorCategory::gui_input(const Ref<InputEvent> &p_event) { EditorInspectorCategory::EditorInspectorCategory() { menu = memnew(PopupMenu); - menu->connect("id_pressed", callable_mp(this, &EditorInspectorCategory::_handle_menu_option)); + menu->connect(SceneStringName(id_pressed), callable_mp(this, &EditorInspectorCategory::_handle_menu_option)); menu->add_item(TTR("Open Documentation"), MENU_OPEN_DOCS); add_child(menu); } @@ -2172,7 +2174,7 @@ void EditorInspectorArray::_setup() { ae.panel->connect(SceneStringName(focus_exited), callable_mp((CanvasItem *)ae.panel, &PanelContainer::queue_redraw)); ae.panel->connect(SceneStringName(draw), callable_mp(this, &EditorInspectorArray::_panel_draw).bind(i)); ae.panel->connect(SceneStringName(gui_input), callable_mp(this, &EditorInspectorArray::_panel_gui_input).bind(i)); - ae.panel->add_theme_style_override(SNAME("panel"), i % 2 ? odd_style : even_style); + ae.panel->add_theme_style_override(SceneStringName(panel), i % 2 ? odd_style : even_style); elements_vbox->add_child(ae.panel); ae.margin = memnew(MarginContainer); @@ -2425,7 +2427,7 @@ EditorInspectorArray::EditorInspectorArray(bool p_read_only) { rmb_popup->add_separator(); rmb_popup->add_item(TTR("Clear Array"), OPTION_CLEAR_ARRAY); rmb_popup->add_item(TTR("Resize Array..."), OPTION_RESIZE_ARRAY); - rmb_popup->connect("id_pressed", callable_mp(this, &EditorInspectorArray::_rmb_popup_id_pressed)); + rmb_popup->connect(SceneStringName(id_pressed), callable_mp(this, &EditorInspectorArray::_rmb_popup_id_pressed)); add_child(rmb_popup); elements_vbox = memnew(VBoxContainer); @@ -2867,15 +2869,6 @@ void EditorInspector::update_tree() { // Otherwise the category was probably added via `@export_category` or `_get_property_list()`. const bool is_custom_category = p.hint_string.is_empty(); - if ((is_custom_category && !show_custom_categories) || (!is_custom_category && !show_standard_categories)) { - continue; - } - - // Hide the "MultiNodeEdit" category for MultiNodeEdit. - if (Object::cast_to<MultiNodeEdit>(object) && p.name == "MultiNodeEdit") { - continue; - } - // Iterate over remaining properties. If no properties in category, skip the category. List<PropertyInfo>::Element *N = E_property->next(); bool valid = true; @@ -2896,22 +2889,20 @@ void EditorInspector::update_tree() { continue; // Empty, ignore it. } - // Create an EditorInspectorCategory and add it to the inspector. - EditorInspectorCategory *category = memnew(EditorInspectorCategory); - main_vbox->add_child(category); - category_vbox = nullptr; //reset + String category_label; + String category_tooltip; + Ref<Texture> category_icon; // Do not add an icon, do not change the current class (`doc_name`) for custom categories. if (is_custom_category) { - category->label = p.name; - category->set_tooltip_text(p.name); + category_label = p.name; + category_tooltip = p.name; } else { - String type = p.name; - String label = p.name; doc_name = p.name; + category_label = p.name; // Use category's owner script to update some of its information. - if (!EditorNode::get_editor_data().is_type_recognized(type) && ResourceLoader::exists(p.hint_string)) { + if (!EditorNode::get_editor_data().is_type_recognized(p.name) && ResourceLoader::exists(p.hint_string)) { Ref<Script> scr = ResourceLoader::load(p.hint_string, "Script"); if (scr.is_valid()) { StringName script_name = EditorNode::get_editor_data().script_class_get_name(scr->get_path()); @@ -2924,32 +2915,50 @@ void EditorInspector::update_tree() { doc_name = docs[docs.size() - 1].name; } if (script_name != StringName()) { - label = script_name; + category_label = script_name; } // Find the icon corresponding to the script. if (script_name != StringName()) { - category->icon = EditorNode::get_singleton()->get_class_icon(script_name); + category_icon = EditorNode::get_singleton()->get_class_icon(script_name); } else { - category->icon = EditorNode::get_singleton()->get_object_icon(scr.ptr(), "Object"); + category_icon = EditorNode::get_singleton()->get_object_icon(scr.ptr(), "Object"); } } } - if (category->icon.is_null() && !type.is_empty()) { - category->icon = EditorNode::get_singleton()->get_class_icon(type); + if (category_icon.is_null() && !p.name.is_empty()) { + category_icon = EditorNode::get_singleton()->get_class_icon(p.name); } - // Set the category label. - category->label = label; - category->doc_class_name = doc_name; - if (use_doc_hints) { // `|` separators used in `EditorHelpBit`. - category->set_tooltip_text("class|" + doc_name + "|"); + category_tooltip = "class|" + doc_name + "|"; } } + if ((is_custom_category && !show_custom_categories) || (!is_custom_category && !show_standard_categories)) { + continue; + } + + // Hide the "MultiNodeEdit" category for MultiNodeEdit. + if (Object::cast_to<MultiNodeEdit>(object) && p.name == "MultiNodeEdit") { + continue; + } + + // Create an EditorInspectorCategory and add it to the inspector. + EditorInspectorCategory *category = memnew(EditorInspectorCategory); + main_vbox->add_child(category); + category_vbox = nullptr; // Reset. + + // Set the category info. + category->label = category_label; + category->set_tooltip_text(category_tooltip); + category->icon = category_icon; + if (!is_custom_category) { + category->doc_class_name = doc_name; + } + // Add editors at the start of a category. for (Ref<EditorInspectorPlugin> &ped : valid_plugins) { ped->parse_category(object, p.name); @@ -4044,7 +4053,7 @@ void EditorInspector::_notification(int p_what) { case NOTIFICATION_READY: { EditorFeatureProfileManager::get_singleton()->connect("current_feature_profile_changed", callable_mp(this, &EditorInspector::_feature_profile_changed)); set_process(is_visible_in_tree()); - add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); + add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree"))); if (!sub_inspector) { get_tree()->connect("node_removed", callable_mp(this, &EditorInspector::_node_removed)); } @@ -4111,7 +4120,7 @@ void EditorInspector::_notification(int p_what) { case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { bool needs_update = false; if (EditorThemeManager::is_generated_theme_outdated() && !sub_inspector) { - add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); + add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree"))); } if (use_settings_name_style && EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor/localize_settings")) { diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h index e52903101d..a0ced55bd8 100644 --- a/editor/editor_inspector.h +++ b/editor/editor_inspector.h @@ -252,9 +252,13 @@ protected: GDVIRTUAL7R(bool, _parse_property, Object *, Variant::Type, String, PropertyHint, String, BitField<PropertyUsageFlags>, bool) GDVIRTUAL1(_parse_end, Object *) +#ifndef DISABLE_DEPRECATED + void _add_property_editor_bind_compat_92322(const String &p_for_property, Control *p_prop, bool p_add_to_end); + static void _bind_compatibility_methods(); +#endif // DISABLE_DEPRECATED public: void add_custom_control(Control *control); - void add_property_editor(const String &p_for_property, Control *p_prop, bool p_add_to_end = false); + void add_property_editor(const String &p_for_property, Control *p_prop, bool p_add_to_end = false, const String &p_label = String()); void add_property_editor_for_multiple_properties(const String &p_label, const Vector<String> &p_properties, Control *p_prop); virtual bool can_handle(Object *p_object); diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp index 2a6fe808dd..166d09af30 100644 --- a/editor/editor_log.cpp +++ b/editor/editor_log.cpp @@ -59,7 +59,7 @@ void EditorLog::_error_handler(void *p_self, const char *p_func, const char *p_f MessageType message_type = p_type == ERR_HANDLER_WARNING ? MSG_TYPE_WARNING : MSG_TYPE_ERROR; if (self->current != Thread::get_caller_id()) { - callable_mp(self, &EditorLog::add_message).bind(err_str, message_type).call_deferred(); + callable_mp(self, &EditorLog::add_message).call_deferred(err_str, message_type); } else { self->add_message(err_str, message_type); } diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 949916c2a3..087e9ff075 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -514,14 +514,14 @@ void EditorNode::_update_theme(bool p_skip_creation) { // Update styles. { - gui_base->add_theme_style_override("panel", theme->get_stylebox(SNAME("Background"), EditorStringName(EditorStyles))); + gui_base->add_theme_style_override(SceneStringName(panel), theme->get_stylebox(SNAME("Background"), EditorStringName(EditorStyles))); main_vbox->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT, Control::PRESET_MODE_MINSIZE, theme->get_constant(SNAME("window_border_margin"), EditorStringName(Editor))); main_vbox->add_theme_constant_override("separation", theme->get_constant(SNAME("top_bar_separation"), EditorStringName(Editor))); - scene_root_parent->add_theme_style_override("panel", theme->get_stylebox(SNAME("Content"), EditorStringName(EditorStyles))); - bottom_panel->add_theme_style_override("panel", theme->get_stylebox(SNAME("BottomPanel"), EditorStringName(EditorStyles))); + scene_root_parent->add_theme_style_override(SceneStringName(panel), theme->get_stylebox(SNAME("Content"), EditorStringName(EditorStyles))); + bottom_panel->add_theme_style_override(SceneStringName(panel), theme->get_stylebox(SNAME("BottomPanel"), EditorStringName(EditorStyles))); distraction_free->set_icon(theme->get_icon(SNAME("DistractionFree"), EditorStringName(EditorIcons))); - distraction_free->add_theme_style_override(SceneStringName(pressed), theme->get_stylebox("normal", "FlatMenuButton")); + distraction_free->add_theme_style_override(SceneStringName(pressed), theme->get_stylebox(CoreStringName(normal), "FlatMenuButton")); help_menu->set_item_icon(help_menu->get_item_index(HELP_SEARCH), theme->get_icon(SNAME("HelpSearch"), EditorStringName(EditorIcons))); help_menu->set_item_icon(help_menu->get_item_index(HELP_COPY_SYSTEM_INFO), theme->get_icon(SNAME("ActionCopy"), EditorStringName(EditorIcons))); @@ -529,7 +529,7 @@ void EditorNode::_update_theme(bool p_skip_creation) { help_menu->set_item_icon(help_menu->get_item_index(HELP_SUPPORT_GODOT_DEVELOPMENT), theme->get_icon(SNAME("Heart"), EditorStringName(EditorIcons))); if (EditorDebuggerNode::get_singleton()->is_visible()) { - bottom_panel->add_theme_style_override("panel", theme->get_stylebox(SNAME("BottomPanelDebuggerOverride"), EditorStringName(EditorStyles))); + bottom_panel->add_theme_style_override(SceneStringName(panel), theme->get_stylebox(SNAME("BottomPanelDebuggerOverride"), EditorStringName(EditorStyles))); } for (int i = 0; i < main_editor_buttons.size(); i++) { @@ -671,7 +671,7 @@ void EditorNode::_notification(int p_what) { callable_mp(this, &EditorNode::_begin_first_scan).call_deferred(); - DisplayServer::get_singleton()->set_system_theme_change_callback(callable_mp(this, &EditorNode::_update_theme)); + DisplayServer::get_singleton()->set_system_theme_change_callback(callable_mp(this, &EditorNode::_update_theme).bind(false)); /* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */ } break; @@ -1067,7 +1067,7 @@ void EditorNode::_resources_reimported(const Vector<String> &p_resources) { reload_instances_with_path_in_edited_scenes(E); } - scene_tabs->set_current_tab(current_tab); + _set_current_scene_nocheck(current_tab); } void EditorNode::_sources_changed(bool p_exist) { @@ -4107,7 +4107,7 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b return OK; } -HashMap<StringName, Variant> EditorNode::get_modified_properties_for_node(Node *p_node) { +HashMap<StringName, Variant> EditorNode::get_modified_properties_for_node(Node *p_node, bool p_node_references_only) { HashMap<StringName, Variant> modified_property_map; List<PropertyInfo> pinfo; @@ -4119,7 +4119,17 @@ HashMap<StringName, Variant> EditorNode::get_modified_properties_for_node(Node * Variant current_value = p_node->get(E.name); if (is_valid_revert) { if (PropertyUtils::is_property_value_different(current_value, revert_value)) { - modified_property_map[E.name] = current_value; + // If this property is a direct node reference, save a NodePath instead to prevent corrupted references. + if (E.type == Variant::OBJECT && E.hint == PROPERTY_HINT_NODE_TYPE) { + Node *target_node = Object::cast_to<Node>(current_value); + if (target_node) { + modified_property_map[E.name] = p_node->get_path_to(target_node); + } + } else { + if (!p_node_references_only) { + modified_property_map[E.name] = current_value; + } + } } } } @@ -4137,10 +4147,118 @@ void EditorNode::update_ownership_table_for_addition_node_ancestors(Node *p_curr } } -void EditorNode::update_diff_data_for_node( - Node *p_edited_scene, +void EditorNode::update_node_from_node_modification_entry(Node *p_node, ModificationNodeEntry &p_node_modification) { + if (p_node) { + // First, attempt to restore the script property since it may affect the get_property_list method. + Variant *script_property_table_entry = p_node_modification.property_table.getptr(CoreStringName(script)); + if (script_property_table_entry) { + p_node->set_script(*script_property_table_entry); + } + + // Get properties for this node. + List<PropertyInfo> pinfo; + p_node->get_property_list(&pinfo); + + // Get names of all valid property names. + HashMap<StringName, bool> property_node_reference_table; + for (const PropertyInfo &E : pinfo) { + if (E.usage & PROPERTY_USAGE_STORAGE) { + if (E.type == Variant::OBJECT && E.hint == PROPERTY_HINT_NODE_TYPE) { + property_node_reference_table[E.name] = true; + } else { + property_node_reference_table[E.name] = false; + } + } + } + + // Restore the modified properties for this node. + for (const KeyValue<StringName, Variant> &E : p_node_modification.property_table) { + bool *property_node_reference_table_entry = property_node_reference_table.getptr(E.key); + if (property_node_reference_table_entry) { + // If the property is a node reference, attempt to restore from the node path instead. + bool is_node_reference = *property_node_reference_table_entry; + if (is_node_reference) { + if (E.value.get_type() == Variant::NODE_PATH) { + p_node->set(E.key, p_node->get_node_or_null(E.value)); + } + } else { + p_node->set(E.key, E.value); + } + } + } + + // Restore the connections to other nodes. + for (const ConnectionWithNodePath &E : p_node_modification.connections_to) { + Connection conn = E.connection; + + // Get the node the callable is targeting. + Node *target_node = Object::cast_to<Node>(conn.callable.get_object()); + + // If the callable object no longer exists or is marked for deletion, + // attempt to reaccquire the closest match by using the node path + // we saved earlier. + if (!target_node || !target_node->is_queued_for_deletion()) { + target_node = p_node->get_node_or_null(E.node_path); + } + + if (target_node) { + // Reconstruct the callable. + Callable new_callable = Callable(target_node, conn.callable.get_method()); + + if (!p_node->is_connected(conn.signal.get_name(), new_callable)) { + ERR_FAIL_COND(p_node->connect(conn.signal.get_name(), new_callable, conn.flags) != OK); + } + } + } + + // Restore the connections from other nodes. + for (const Connection &E : p_node_modification.connections_from) { + Connection conn = E; + + bool valid = p_node->has_method(conn.callable.get_method()) || Ref<Script>(p_node->get_script()).is_null() || Ref<Script>(p_node->get_script())->has_method(conn.callable.get_method()); + ERR_CONTINUE_MSG(!valid, vformat("Attempt to connect signal '%s.%s' to nonexistent method '%s.%s'.", conn.signal.get_object()->get_class(), conn.signal.get_name(), conn.callable.get_object()->get_class(), conn.callable.get_method())); + + // Get the object which the signal is connected from. + Object *source_object = conn.signal.get_object(); + + if (source_object) { + ERR_FAIL_COND(source_object->connect(conn.signal.get_name(), Callable(p_node, conn.callable.get_method()), conn.flags) != OK); + } + } + + // Re-add the groups. + for (const Node::GroupInfo &E : p_node_modification.groups) { + p_node->add_to_group(E.name, E.persistent); + } + } +} + +void EditorNode::update_node_reference_modification_table_for_node( Node *p_root, Node *p_node, + List<Node *> p_excluded_nodes, + HashMap<NodePath, ModificationNodeEntry> &p_modification_table) { + if (!p_excluded_nodes.find(p_node)) { + HashMap<StringName, Variant> modified_properties = get_modified_properties_for_node(p_node, false); + + if (!modified_properties.is_empty()) { + ModificationNodeEntry modification_node_entry; + modification_node_entry.property_table = modified_properties; + + p_modification_table[p_root->get_path_to(p_node)] = modification_node_entry; + } + + for (int i = 0; i < p_node->get_child_count(); i++) { + Node *child = p_node->get_child(i); + update_node_reference_modification_table_for_node(p_root, child, p_excluded_nodes, p_modification_table); + } + } +} + +void EditorNode::update_reimported_diff_data_for_node( + Node *p_edited_scene, + Node *p_reimported_root, + Node *p_node, HashMap<NodePath, ModificationNodeEntry> &p_modification_table, List<AdditiveNodeEntry> &p_addition_list) { bool node_part_of_subscene = p_node != p_edited_scene && @@ -4150,14 +4268,14 @@ void EditorNode::update_diff_data_for_node( // Loop through the owners until either we reach the root node or nullptr Node *valid_node_owner = p_node->get_owner(); while (valid_node_owner) { - if (valid_node_owner == p_root) { + if (valid_node_owner == p_reimported_root) { break; } valid_node_owner = valid_node_owner->get_owner(); } - if ((valid_node_owner == p_root && (p_root != p_edited_scene || !p_edited_scene->get_scene_file_path().is_empty())) || node_part_of_subscene || p_node == p_root) { - HashMap<StringName, Variant> modified_properties = get_modified_properties_for_node(p_node); + if ((valid_node_owner == p_reimported_root && (p_reimported_root != p_edited_scene || !p_edited_scene->get_scene_file_path().is_empty())) || node_part_of_subscene || p_node == p_reimported_root) { + HashMap<StringName, Variant> modified_properties = get_modified_properties_for_node(p_node, false); // Find all valid connections to other nodes. List<Connection> connections_to; @@ -4189,7 +4307,7 @@ void EditorNode::update_diff_data_for_node( if (source_node) { valid_source_owner = source_node->get_owner(); while (valid_source_owner) { - if (valid_source_owner == p_root) { + if (valid_source_owner == p_reimported_root) { break; } valid_source_owner = valid_source_owner->get_owner(); @@ -4215,41 +4333,55 @@ void EditorNode::update_diff_data_for_node( modification_node_entry.connections_from = valid_connections_from; modification_node_entry.groups = groups; - p_modification_table[p_root->get_path_to(p_node)] = modification_node_entry; + p_modification_table[p_reimported_root->get_path_to(p_node)] = modification_node_entry; } } else { - AdditiveNodeEntry new_additive_node_entry; - new_additive_node_entry.node = p_node; - new_additive_node_entry.parent = p_root->get_path_to(p_node->get_parent()); - new_additive_node_entry.owner = p_node->get_owner(); - new_additive_node_entry.index = p_node->get_index(); + // Only save additional nodes which have an owner since this was causing issues transient ownerless nodes + // which get recreated upon scene tree entry. + // For now instead, assume all ownerless nodes are transient and will have to be recreated. + if (p_node->get_owner()) { + HashMap<StringName, Variant> modified_properties = get_modified_properties_for_node(p_node, true); + + if (p_node->get_parent()->get_owner() != nullptr && p_node->get_parent()->get_owner() != p_edited_scene) { + AdditiveNodeEntry new_additive_node_entry; + new_additive_node_entry.node = p_node; + new_additive_node_entry.parent = p_reimported_root->get_path_to(p_node->get_parent()); + new_additive_node_entry.owner = p_node->get_owner(); + new_additive_node_entry.index = p_node->get_index(); + + Node2D *node_2d = Object::cast_to<Node2D>(p_node); + if (node_2d) { + new_additive_node_entry.transform_2d = node_2d->get_relative_transform_to_parent(node_2d->get_parent()); + } + Node3D *node_3d = Object::cast_to<Node3D>(p_node); + if (node_3d) { + new_additive_node_entry.transform_3d = node_3d->get_relative_transform(node_3d->get_parent()); + } - Node2D *node_2d = Object::cast_to<Node2D>(p_node); - if (node_2d) { - new_additive_node_entry.transform_2d = node_2d->get_relative_transform_to_parent(node_2d->get_parent()); - } - Node3D *node_3d = Object::cast_to<Node3D>(p_node); - if (node_3d) { - new_additive_node_entry.transform_3d = node_3d->get_relative_transform(node_3d->get_parent()); - } + // Gathers the ownership of all ancestor nodes for later use. + HashMap<Node *, Node *> ownership_table; + for (int i = 0; i < p_node->get_child_count(); i++) { + Node *child = p_node->get_child(i); + update_ownership_table_for_addition_node_ancestors(child, ownership_table); + } - // Gathers the ownership of all ancestor nodes for later use. - HashMap<Node *, Node *> ownership_table; - for (int i = 0; i < p_node->get_child_count(); i++) { - Node *child = p_node->get_child(i); - update_ownership_table_for_addition_node_ancestors(child, ownership_table); - } + new_additive_node_entry.ownership_table = ownership_table; - new_additive_node_entry.ownership_table = ownership_table; + p_addition_list.push_back(new_additive_node_entry); + } - p_addition_list.push_back(new_additive_node_entry); + if (!modified_properties.is_empty()) { + ModificationNodeEntry modification_node_entry; + modification_node_entry.property_table = modified_properties; - return; + p_modification_table[p_reimported_root->get_path_to(p_node)] = modification_node_entry; + } + } } for (int i = 0; i < p_node->get_child_count(); i++) { Node *child = p_node->get_child(i); - update_diff_data_for_node(p_edited_scene, p_root, child, p_modification_table, p_addition_list); + update_reimported_diff_data_for_node(p_edited_scene, p_reimported_root, child, p_modification_table, p_addition_list); } } // @@ -4411,17 +4543,19 @@ void EditorNode::_project_run_started() { log->clear(); } - if (bool(EDITOR_GET("run/output/always_open_output_on_play"))) { + int action_on_play = EDITOR_GET("run/bottom_panel/action_on_play"); + if (action_on_play == ACTION_ON_PLAY_OPEN_OUTPUT) { bottom_panel->make_item_visible(log); + } else if (action_on_play == ACTION_ON_PLAY_OPEN_DEBUGGER) { + bottom_panel->make_item_visible(EditorDebuggerNode::get_singleton()); } } void EditorNode::_project_run_stopped() { - if (!bool(EDITOR_GET("run/output/always_close_output_on_stop"))) { - return; + int action_on_stop = EDITOR_GET("run/bottom_panel/action_on_stop"); + if (action_on_stop == ACTION_ON_STOP_CLOSE_BUTTOM_PANEL) { + bottom_panel->hide_bottom_panel(); } - - bottom_panel->make_item_visible(log, false); } void EditorNode::notify_all_debug_sessions_exited() { @@ -5541,19 +5675,18 @@ void EditorNode::_add_dropped_files_recursive(const Vector<String> &p_files, Str } void EditorNode::_file_access_close_error_notify(const String &p_str) { - callable_mp_static(&EditorNode::_file_access_close_error_notify_impl).bind(p_str).call_deferred(); + callable_mp_static(&EditorNode::_file_access_close_error_notify_impl).call_deferred(p_str); } void EditorNode::_file_access_close_error_notify_impl(const String &p_str) { add_io_error(vformat(TTR("Unable to write to file '%s', file in use, locked or lacking permissions."), p_str)); } -// Since we felt that a bespoke NOTIFICATION might not be desirable, this function -// provides the hardcoded callbacks to address known bugs which occur on certain -// nodes during reimport. -// Ideally, we should probably agree on a standardized method name which could be -// called from here instead. -void EditorNode::_notify_scene_updated(Node *p_node) { +// Recursive function to inform nodes that an array of nodes have had their scene reimported. +// It will attempt to call a method named '_nodes_scene_reimported' on every node in the +// tree so that editor scripts which create transient nodes will have the opportunity +// to recreate them. +void EditorNode::_notify_nodes_scene_reimported(Node *p_node, Array p_reimported_nodes) { Skeleton3D *skel_3d = Object::cast_to<Skeleton3D>(p_node); if (skel_3d) { skel_3d->reset_bone_poses(); @@ -5564,8 +5697,12 @@ void EditorNode::_notify_scene_updated(Node *p_node) { } } + if (p_node->has_method("_nodes_scene_reimported")) { + p_node->call("_nodes_scene_reimported", p_reimported_nodes); + } + for (int i = 0; i < p_node->get_child_count(); i++) { - _notify_scene_updated(p_node->get_child(i)); + _notify_nodes_scene_reimported(p_node->get_child(i), p_reimported_nodes); } } @@ -5582,8 +5719,14 @@ void EditorNode::reload_scene(const String &p_path) { if (scene_idx == -1) { if (get_edited_scene()) { + int current_history_id = editor_data.get_current_edited_scene_history_id(); + bool is_unsaved = EditorUndoRedoManager::get_singleton()->is_history_unsaved(current_history_id); + // Scene is not open, so at it might be instantiated. We'll refresh the whole scene later. - EditorUndoRedoManager::get_singleton()->clear_history(false, editor_data.get_current_edited_scene_history_id()); + EditorUndoRedoManager::get_singleton()->clear_history(false, current_history_id); + if (is_unsaved) { + EditorUndoRedoManager::get_singleton()->set_history_as_unsaved(current_history_id); + } } return; } @@ -5633,8 +5776,8 @@ void EditorNode::find_all_instances_inheriting_path_in_node(Node *p_root, Node * } void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_instance_path) { - int original_edited_scene_idx = editor_data.get_edited_scene(); HashMap<int, List<Node *>> edited_scene_map; + Array replaced_nodes; // Walk through each opened scene to get a global list of all instances which match // the current reimported scenes. @@ -5663,24 +5806,94 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins HashMap<String, Ref<PackedScene>> local_scene_cache; local_scene_cache[p_instance_path] = instance_scene_packed_scene; + // Save the current scene state/selection in case of lost. + Dictionary editor_state = _get_main_scene_state(); + editor_data.save_edited_scene_state(editor_selection, &editor_history, editor_state); + editor_selection->clear(); + + int original_edited_scene_idx = editor_data.get_edited_scene(); + Node *original_edited_scene_root = editor_data.get_edited_scene_root(); + + // Prevent scene roots with the same name from being in the tree at the same time. + scene_root->remove_child(original_edited_scene_root); + for (const KeyValue<int, List<Node *>> &edited_scene_map_elem : edited_scene_map) { // Set the current scene. int current_scene_idx = edited_scene_map_elem.key; editor_data.set_edited_scene(current_scene_idx); Node *current_edited_scene = editor_data.get_edited_scene_root(current_scene_idx); - // Clear the history for this tab (should we allow history to be retained?). - EditorUndoRedoManager::get_singleton()->clear_history(); + // Make sure the node is in the tree so that editor_selection can add node smoothly. + scene_root->add_child(current_edited_scene); + + // Restore the state so that the selection can be updated. + editor_state = editor_data.restore_edited_scene_state(editor_selection, &editor_history); + + int current_history_id = editor_data.get_current_edited_scene_history_id(); + bool is_unsaved = EditorUndoRedoManager::get_singleton()->is_history_unsaved(current_history_id); + + // Clear the history for this affected tab. + EditorUndoRedoManager::get_singleton()->clear_history(false, current_history_id); // Update the version editor_data.is_scene_changed(current_scene_idx); + // Contains modifications in the edited scene which reference nodes inside of any nodes we will be reimporting. + HashMap<NodePath, ModificationNodeEntry> edited_scene_global_modification_table; + update_node_reference_modification_table_for_node(current_edited_scene, current_edited_scene, edited_scene_map_elem.value, edited_scene_global_modification_table); + for (Node *original_node : edited_scene_map_elem.value) { + String original_node_file_path = original_node->get_scene_file_path(); + + // Load a replacement scene for the node. + Ref<PackedScene> current_packed_scene; + if (original_node_file_path == p_instance_path) { + // If the node file name directly matches the scene we're replacing, + // just load it since we already cached it. + current_packed_scene = instance_scene_packed_scene; + } else { + // Otherwise, check the inheritance chain, reloading and caching any scenes + // we require along the way. + List<String> required_load_paths; + + // Do we need to check if the paths are empty? + if (!original_node_file_path.is_empty()) { + required_load_paths.push_front(original_node_file_path); + } + Ref<SceneState> inherited_state = original_node->get_scene_inherited_state(); + while (inherited_state.is_valid()) { + String inherited_path = inherited_state->get_path(); + // Do we need to check if the paths are empty? + if (!inherited_path.is_empty()) { + required_load_paths.push_front(inherited_path); + } + inherited_state = inherited_state->get_base_scene_state(); + } + + // Ensure the inheritance chain is loaded in the correct order so that cache can + // be properly updated. + for (String path : required_load_paths) { + if (!local_scene_cache.find(path)) { + current_packed_scene = ResourceLoader::load(path, "", ResourceFormatLoader::CACHE_MODE_REPLACE_DEEP, &err); + local_scene_cache[path] = current_packed_scene; + } else { + current_packed_scene = local_scene_cache[path]; + } + } + } + + ERR_FAIL_COND(current_packed_scene.is_null()); + + // Instantiate early so that caches cleared on load in SceneState can be rebuilt early. + Node *instantiated_node = current_packed_scene->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE); + + ERR_FAIL_NULL(instantiated_node); + // Walk the tree for the current node and extract relevant diff data, storing it in the modification table. // For additional nodes which are part of the current scene, they get added to the addition table. HashMap<NodePath, ModificationNodeEntry> modification_table; List<AdditiveNodeEntry> addition_list; - update_diff_data_for_node(current_edited_scene, original_node, original_node, modification_table, addition_list); + update_reimported_diff_data_for_node(current_edited_scene, original_node, original_node, modification_table, addition_list); // Disconnect all relevant connections, all connections from and persistent connections to. for (const KeyValue<NodePath, ModificationNodeEntry> &modification_table_entry : modification_table) { @@ -5733,52 +5946,8 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins is_editable = owner->is_editable_instance(original_node); } - // Load a replacement scene for the node. - Ref<PackedScene> current_packed_scene; - if (original_node->get_scene_file_path() == p_instance_path) { - // If the node file name directly matches the scene we're replacing, - // just load it since we already cached it. - current_packed_scene = instance_scene_packed_scene; - } else { - // Otherwise, check the inheritance chain, reloading and caching any scenes - // we require along the way. - List<String> required_load_paths; - String scene_path = original_node->get_scene_file_path(); - // Do we need to check if the paths are empty? - if (!scene_path.is_empty()) { - required_load_paths.push_front(scene_path); - } - Ref<SceneState> inherited_state = original_node->get_scene_inherited_state(); - while (inherited_state.is_valid()) { - String inherited_path = inherited_state->get_path(); - // Do we need to check if the paths are empty? - if (!inherited_path.is_empty()) { - required_load_paths.push_front(inherited_path); - } - inherited_state = inherited_state->get_base_scene_state(); - } - - // Ensure the inheritance chain is loaded in the correct order so that cache can - // be properly updated. - for (String path : required_load_paths) { - if (!local_scene_cache.find(path)) { - current_packed_scene = ResourceLoader::load(path, "", ResourceFormatLoader::CACHE_MODE_REPLACE, &err); - local_scene_cache[path] = current_packed_scene; - } else { - current_packed_scene = local_scene_cache[path]; - } - } - } - - ERR_FAIL_COND(current_packed_scene.is_null()); - - // Instantiate the node. - Node *instantiated_node = nullptr; - if (current_packed_scene.is_valid()) { - instantiated_node = current_packed_scene->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE); - } - - ERR_FAIL_NULL(instantiated_node); + // For clear instance state for path recaching. + instantiated_node->set_scene_instance_state(Ref<SceneState>()); bool original_node_is_displayed_folded = original_node->is_displayed_folded(); bool original_node_scene_instance_load_placeholder = original_node->get_scene_instance_load_placeholder(); @@ -5787,7 +5956,6 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins instantiated_node->set_name(original_node->get_name()); // Is this replacing the edited root node? - String original_node_file_path = original_node->get_scene_file_path(); if (current_edited_scene == original_node) { instantiated_node->set_scene_instance_state(original_node->get_scene_instance_state()); @@ -5798,13 +5966,7 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins instantiated_node->set_scene_inherited_state(state); instantiated_node->set_scene_file_path(String()); } - editor_data.set_edited_scene_root(instantiated_node); current_edited_scene = instantiated_node; - - if (original_node->is_inside_tree()) { - SceneTreeDock::get_singleton()->set_edited_scene(current_edited_scene); - original_node->get_tree()->set_edited_scene_root(instantiated_node); - } } // Replace the original node with the instantiated version. @@ -5885,82 +6047,49 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins NodePath new_current_path = E.key; Node *modifiable_node = instantiated_node->get_node_or_null(new_current_path); - if (modifiable_node) { - // Get properties for this node. - List<PropertyInfo> pinfo; - modifiable_node->get_property_list(&pinfo); + update_node_from_node_modification_entry(modifiable_node, E.value); + } + // Add the newly instantiated node to the edited scene's replaced node list. + replaced_nodes.push_back(instantiated_node); + } - // Get names of all valid property names (TODO: make this more efficient). - List<String> property_names; - for (const PropertyInfo &E2 : pinfo) { - if (E2.usage & PROPERTY_USAGE_STORAGE) { - property_names.push_back(E2.name); - } - } + // Attempt to restore the modified properties and signals for the instantitated node and all its owned children. + for (KeyValue<NodePath, ModificationNodeEntry> &E : edited_scene_global_modification_table) { + NodePath new_current_path = E.key; + Node *modifiable_node = current_edited_scene->get_node_or_null(new_current_path); - // Restore the modified properties for this node. - for (const KeyValue<StringName, Variant> &E2 : E.value.property_table) { - if (property_names.find(E2.key)) { - modifiable_node->set(E2.key, E2.value); - } - } - // Restore the connections to other nodes. - for (const ConnectionWithNodePath &E2 : E.value.connections_to) { - Connection conn = E2.connection; - - // Get the node the callable is targeting. - Node *target_node = cast_to<Node>(conn.callable.get_object()); - - // If the callable object no longer exists or is marked for deletion, - // attempt to reaccquire the closest match by using the node path - // we saved earlier. - if (!target_node || !target_node->is_queued_for_deletion()) { - target_node = modifiable_node->get_node_or_null(E2.node_path); - } + if (modifiable_node) { + update_node_from_node_modification_entry(modifiable_node, E.value); + } + } - if (target_node) { - // Reconstruct the callable. - Callable new_callable = Callable(target_node, conn.callable.get_method()); + if (is_unsaved) { + EditorUndoRedoManager::get_singleton()->set_history_as_unsaved(current_history_id); + } - if (!modifiable_node->is_connected(conn.signal.get_name(), new_callable)) { - ERR_FAIL_COND(modifiable_node->connect(conn.signal.get_name(), new_callable, conn.flags) != OK); - } - } - } + // Save the current handled scene state. + editor_data.save_edited_scene_state(editor_selection, &editor_history, editor_state); + editor_selection->clear(); - // Restore the connections from other nodes. - for (const Connection &E2 : E.value.connections_from) { - Connection conn = E2; + // Cleanup the history of the changes. + editor_history.cleanup_history(); - bool valid = modifiable_node->has_method(conn.callable.get_method()) || Ref<Script>(modifiable_node->get_script()).is_null() || Ref<Script>(modifiable_node->get_script())->has_method(conn.callable.get_method()); - ERR_CONTINUE_MSG(!valid, vformat("Attempt to connect signal '%s.%s' to nonexistent method '%s.%s'.", conn.signal.get_object()->get_class(), conn.signal.get_name(), conn.callable.get_object()->get_class(), conn.callable.get_method())); + scene_root->remove_child(current_edited_scene); + } - // Get the object which the signal is connected from. - Object *source_object = conn.signal.get_object(); + // For the whole editor, call the _notify_nodes_scene_reimported with a list of replaced nodes. + // To inform anything that depends on them that they should update as appropriate. + _notify_nodes_scene_reimported(this, replaced_nodes); - if (source_object) { - ERR_FAIL_COND(source_object->connect(conn.signal.get_name(), Callable(modifiable_node, conn.callable.get_method()), conn.flags) != OK); - } - } + edited_scene_map.clear(); - // Re-add the groups. - for (const Node::GroupInfo &E2 : E.value.groups) { - modifiable_node->add_to_group(E2.name, E2.persistent); - } - } - } - } + editor_data.set_edited_scene(original_edited_scene_idx); - // Cleanup the history of the changes. - editor_history.cleanup_history(); + original_edited_scene_root = editor_data.get_edited_scene_root(); + scene_root->add_child(original_edited_scene_root); - _notify_scene_updated(current_edited_scene); - } - edited_scene_map.clear(); + editor_data.restore_edited_scene_state(editor_selection, &editor_history); } - editor_data.set_edited_scene(original_edited_scene_idx); - - _edit_current(); } int EditorNode::plugin_init_callback_count = 0; @@ -6163,7 +6292,7 @@ static Node *_resource_get_edited_scene() { } void EditorNode::_print_handler(void *p_this, const String &p_string, bool p_error, bool p_rich) { - callable_mp_static(&EditorNode::_print_handler_impl).bind(p_string, p_error, p_rich).call_deferred(); + callable_mp_static(&EditorNode::_print_handler_impl).call_deferred(p_string, p_error, p_rich); } void EditorNode::_print_handler_impl(const String &p_string, bool p_error, bool p_rich) { @@ -6663,7 +6792,7 @@ EditorNode::EditorNode() { scene_root_parent = memnew(PanelContainer); scene_root_parent->set_custom_minimum_size(Size2(0, 80) * EDSCALE); - scene_root_parent->add_theme_style_override("panel", theme->get_stylebox(SNAME("Content"), EditorStringName(EditorStyles))); + scene_root_parent->add_theme_style_override(SceneStringName(panel), theme->get_stylebox(SNAME("Content"), EditorStringName(EditorStyles))); scene_root_parent->set_draw_behind_parent(true); srt->add_child(scene_root_parent); scene_root_parent->set_v_size_flags(Control::SIZE_EXPAND_FILL); @@ -6773,7 +6902,7 @@ EditorNode::EditorNode() { recent_scenes = memnew(PopupMenu); file_menu->add_submenu_node_item(TTR("Open Recent"), recent_scenes, FILE_OPEN_RECENT); - recent_scenes->connect("id_pressed", callable_mp(this, &EditorNode::_open_recent_scene)); + recent_scenes->connect(SceneStringName(id_pressed), callable_mp(this, &EditorNode::_open_recent_scene)); file_menu->add_separator(); file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/save_scene", TTR("Save Scene"), KeyModifierMask::CMD_OR_CTRL + Key::S), FILE_SAVE_SCENE); @@ -6818,7 +6947,7 @@ EditorNode::EditorNode() { apple_menu->add_shortcut(ED_GET_SHORTCUT("editor/editor_settings"), SETTINGS_PREFERENCES); apple_menu->add_separator(); - apple_menu->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option)); + apple_menu->connect(SceneStringName(id_pressed), callable_mp(this, &EditorNode::_menu_option)); } #endif @@ -6827,7 +6956,7 @@ EditorNode::EditorNode() { main_menu->add_child(project_menu); project_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/project_settings", TTR("Project Settings..."), Key::NONE, TTR("Project Settings")), RUN_SETTINGS); - project_menu->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option)); + project_menu->connect(SceneStringName(id_pressed), callable_mp(this, &EditorNode::_menu_option)); project_menu->add_separator(); project_menu->add_item(TTR("Version Control"), VCS_MENU); @@ -6899,7 +7028,7 @@ EditorNode::EditorNode() { editor_layouts = memnew(PopupMenu); editor_layouts->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); settings_menu->add_submenu_node_item(TTR("Editor Layout"), editor_layouts); - editor_layouts->connect("id_pressed", callable_mp(this, &EditorNode::_layout_menu_option)); + editor_layouts->connect(SceneStringName(id_pressed), callable_mp(this, &EditorNode::_layout_menu_option)); settings_menu->add_separator(); ED_SHORTCUT_AND_COMMAND("editor/take_screenshot", TTR("Take Screenshot"), KeyModifierMask::CTRL | Key::F12); @@ -6942,7 +7071,7 @@ EditorNode::EditorNode() { } main_menu->add_child(help_menu); - help_menu->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option)); + help_menu->connect(SceneStringName(id_pressed), callable_mp(this, &EditorNode::_menu_option)); ED_SHORTCUT_AND_COMMAND("editor/editor_help", TTR("Search Help..."), Key::F1); ED_SHORTCUT_OVERRIDE("editor/editor_help", "macos", KeyModifierMask::ALT | Key::SPACE); @@ -7041,7 +7170,7 @@ EditorNode::EditorNode() { update_spinner = memnew(MenuButton); right_menu_hb->add_child(update_spinner); update_spinner->set_icon(theme->get_icon(SNAME("Progress1"), EditorStringName(EditorIcons))); - update_spinner->get_popup()->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option)); + update_spinner->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &EditorNode::_menu_option)); PopupMenu *p = update_spinner->get_popup(); p->add_radio_check_item(TTR("Update Continuously"), SETTINGS_UPDATE_CONTINUOUSLY); p->add_radio_check_item(TTR("Update When Changed"), SETTINGS_UPDATE_WHEN_CHANGED); @@ -7212,11 +7341,11 @@ EditorNode::EditorNode() { gui_base->add_child(file_script); file_script->connect("file_selected", callable_mp(this, &EditorNode::_dialog_action)); - file_menu->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option)); + file_menu->connect(SceneStringName(id_pressed), callable_mp(this, &EditorNode::_menu_option)); file_menu->connect("about_to_popup", callable_mp(this, &EditorNode::_update_file_menu_opened)); file_menu->connect("popup_hide", callable_mp(this, &EditorNode::_update_file_menu_closed)); - settings_menu->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option)); + settings_menu->connect(SceneStringName(id_pressed), callable_mp(this, &EditorNode::_menu_option)); file->connect("file_selected", callable_mp(this, &EditorNode::_dialog_action)); file_templates->connect("file_selected", callable_mp(this, &EditorNode::_dialog_action)); @@ -7228,6 +7357,8 @@ EditorNode::EditorNode() { disk_changed = memnew(ConfirmationDialog); { + disk_changed->set_title(TTR("Files have been modified on disk")); + VBoxContainer *vbc = memnew(VBoxContainer); disk_changed->add_child(vbc); @@ -7241,9 +7372,9 @@ EditorNode::EditorNode() { disk_changed->connect("confirmed", callable_mp(this, &EditorNode::_reload_modified_scenes)); disk_changed->connect("confirmed", callable_mp(this, &EditorNode::_reload_project_settings)); - disk_changed->set_ok_button_text(TTR("Reload")); + disk_changed->set_ok_button_text(TTR("Discard local changes and reload")); - disk_changed->add_button(TTR("Resave"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "resave"); + disk_changed->add_button(TTR("Keep local changes and overwrite"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "resave"); disk_changed->connect("custom_action", callable_mp(this, &EditorNode::_resave_scenes)); } diff --git a/editor/editor_node.h b/editor/editor_node.h index 6b3359eaee..5d7bd5b4f8 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -140,6 +140,17 @@ public: SCENE_NAME_CASING_KEBAB_CASE, }; + enum ActionOnPlay { + ACTION_ON_PLAY_DO_NOTHING, + ACTION_ON_PLAY_OPEN_OUTPUT, + ACTION_ON_PLAY_OPEN_DEBUGGER, + }; + + enum ActionOnStop { + ACTION_ON_STOP_DO_NOTHING, + ACTION_ON_STOP_CLOSE_BUTTOM_PANEL, + }; + struct ExecuteThreadArgs { String path; List<String> args; @@ -662,7 +673,7 @@ private: void _begin_first_scan(); - void _notify_scene_updated(Node *p_node); + void _notify_nodes_scene_reimported(Node *p_node, Array p_reimported_nodes); protected: friend class FileSystemDock; @@ -779,7 +790,7 @@ public: Error load_scene(const String &p_scene, bool p_ignore_broken_deps = false, bool p_set_inherited = false, bool p_clear_errors = true, bool p_force_open_imported = false, bool p_silent_change_tab = false); Error load_resource(const String &p_resource, bool p_ignore_broken_deps = false); - HashMap<StringName, Variant> get_modified_properties_for_node(Node *p_node); + HashMap<StringName, Variant> get_modified_properties_for_node(Node *p_node, bool p_node_references_only); struct AdditiveNodeEntry { Node *node = nullptr; @@ -806,11 +817,18 @@ public: }; void update_ownership_table_for_addition_node_ancestors(Node *p_current_node, HashMap<Node *, Node *> &p_ownership_table); + void update_node_from_node_modification_entry(Node *p_node, ModificationNodeEntry &p_node_modification); - void update_diff_data_for_node( - Node *p_edited_scene, + void update_node_reference_modification_table_for_node( Node *p_root, Node *p_node, + List<Node *> p_excluded_nodes, + HashMap<NodePath, ModificationNodeEntry> &p_modification_table); + + void update_reimported_diff_data_for_node( + Node *p_edited_scene, + Node *p_reimported_root, + Node *p_node, HashMap<NodePath, ModificationNodeEntry> &p_modification_table, List<AdditiveNodeEntry> &p_addition_list); diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index fe50961b54..ecc31bb0e2 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -854,7 +854,7 @@ EditorPropertyLayersGrid::EditorPropertyLayersGrid() { layer_rename = memnew(PopupMenu); layer_rename->add_item(TTR("Rename layer"), 0); add_child(layer_rename); - layer_rename->connect("id_pressed", callable_mp(this, &EditorPropertyLayersGrid::_rename_pressed)); + layer_rename->connect(SceneStringName(id_pressed), callable_mp(this, &EditorPropertyLayersGrid::_rename_pressed)); } Size2 EditorPropertyLayersGrid::get_grid_size() const { @@ -1304,7 +1304,7 @@ EditorPropertyLayers::EditorPropertyLayers() { layers = memnew(PopupMenu); add_child(layers); layers->set_hide_on_checkable_item_selection(false); - layers->connect("id_pressed", callable_mp(this, &EditorPropertyLayers::_menu_pressed)); + layers->connect(SceneStringName(id_pressed), callable_mp(this, &EditorPropertyLayers::_menu_pressed)); layers->connect("popup_hide", callable_mp((BaseButton *)button, &BaseButton::set_pressed).bind(false)); ProjectSettings::get_singleton()->connect("settings_changed", callable_mp(this, &EditorPropertyLayers::_refresh_names)); } @@ -1687,7 +1687,7 @@ EditorPropertyEasing::EditorPropertyEasing() { preset = memnew(PopupMenu); add_child(preset); - preset->connect("id_pressed", callable_mp(this, &EditorPropertyEasing::_set_preset)); + preset->connect(SceneStringName(id_pressed), callable_mp(this, &EditorPropertyEasing::_set_preset)); spin = memnew(EditorSpinSlider); spin->set_flat(true); @@ -2922,8 +2922,7 @@ void EditorPropertyNodePath::update_property() { assign->set_icon(EditorNode::get_singleton()->get_object_icon(target_node, "Node")); } -void EditorPropertyNodePath::setup(const NodePath &p_base_hint, const Vector<StringName> &p_valid_types, bool p_use_path_from_scene_root, bool p_editing_node) { - base_hint = p_base_hint; +void EditorPropertyNodePath::setup(const Vector<StringName> &p_valid_types, bool p_use_path_from_scene_root, bool p_editing_node) { valid_types = p_valid_types; editing_node = p_editing_node; use_path_from_scene_root = p_use_path_from_scene_root; @@ -2943,10 +2942,6 @@ void EditorPropertyNodePath::_notification(int p_what) { } Node *EditorPropertyNodePath::get_base_node() { - if (!base_hint.is_empty() && get_tree()->get_root()->has_node(base_hint)) { - return get_tree()->get_root()->get_node(base_hint); - } - Node *base_node = Object::cast_to<Node>(get_edited_object()); if (!base_node) { @@ -2995,7 +2990,7 @@ EditorPropertyNodePath::EditorPropertyNodePath() { menu->get_popup()->add_item(TTR("Copy as Text"), ACTION_COPY); menu->get_popup()->add_item(TTR("Edit"), ACTION_EDIT); menu->get_popup()->add_item(TTR("Show Node in Tree"), ACTION_SELECT); - menu->get_popup()->connect(SNAME("id_pressed"), callable_mp(this, &EditorPropertyNodePath::_menu_option)); + menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &EditorPropertyNodePath::_menu_option)); edit = memnew(LineEdit); edit->set_h_size_flags(SIZE_EXPAND_FILL); @@ -3218,7 +3213,7 @@ void EditorPropertyResource::_open_editor_pressed() { Ref<Resource> res = get_edited_property_value(); if (res.is_valid()) { // May clear the editor so do it deferred. - callable_mp(EditorNode::get_singleton(), &EditorNode::edit_item).bind(res.ptr(), this).call_deferred(); + callable_mp(EditorNode::get_singleton(), &EditorNode::edit_item).call_deferred(res.ptr(), this); } } @@ -3800,7 +3795,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_ if (p_hint == PROPERTY_HINT_NODE_PATH_VALID_TYPES && !p_hint_text.is_empty()) { Vector<String> types = p_hint_text.split(",", false); Vector<StringName> sn = Variant(types); //convert via variant - editor->setup(NodePath(), sn, (p_usage & PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT)); + editor->setup(sn, (p_usage & PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT)); } return editor; @@ -3814,7 +3809,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_ EditorPropertyNodePath *editor = memnew(EditorPropertyNodePath); Vector<String> types = p_hint_text.split(",", false); Vector<StringName> sn = Variant(types); //convert via variant - editor->setup(NodePath(), sn, false, true); + editor->setup(sn, false, true); return editor; } else { EditorPropertyResource *editor = memnew(EditorPropertyResource); diff --git a/editor/editor_properties.h b/editor/editor_properties.h index f2c5497e4f..e9e788ab7b 100644 --- a/editor/editor_properties.h +++ b/editor/editor_properties.h @@ -653,7 +653,6 @@ class EditorPropertyNodePath : public EditorProperty { LineEdit *edit = nullptr; SceneTreeDialog *scene_tree = nullptr; - NodePath base_hint; bool use_path_from_scene_root = false; bool editing_node = false; @@ -679,7 +678,7 @@ protected: public: virtual void update_property() override; - void setup(const NodePath &p_base_hint, const Vector<StringName> &p_valid_types, bool p_use_path_from_scene_root = true, bool p_editing_node = false); + void setup(const Vector<StringName> &p_valid_types, bool p_use_path_from_scene_root = true, bool p_editing_node = false); EditorPropertyNodePath(); }; diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index ca1070d7f3..555165c156 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -235,6 +235,9 @@ void EditorPropertyArray::_property_changed(const String &p_property, Variant p_ Variant array = object->get_array().duplicate(); array.set(index, p_value); emit_changed(get_edited_property(), array, p_name, p_changing); + if (p_changing) { + object->set_array(array); + } } void EditorPropertyArray::_change_type(Object *p_button, int p_slot_index) { @@ -838,7 +841,7 @@ EditorPropertyArray::EditorPropertyArray() { change_type = memnew(PopupMenu); add_child(change_type); - change_type->connect("id_pressed", callable_mp(this, &EditorPropertyArray::_change_type_menu)); + change_type->connect(SceneStringName(id_pressed), callable_mp(this, &EditorPropertyArray::_change_type_menu)); changing_type_index = -1; subtype = Variant::NIL; @@ -960,6 +963,7 @@ void EditorPropertyDictionary::update_property() { memdelete(container); button_add_item = nullptr; container = nullptr; + add_panel = nullptr; slots.clear(); } return; @@ -1001,7 +1005,7 @@ void EditorPropertyDictionary::update_property() { add_panel = memnew(PanelContainer); property_vbox->add_child(add_panel); - add_panel->add_theme_style_override(SNAME("panel"), get_theme_stylebox(SNAME("DictionaryAddItem"))); + add_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("DictionaryAddItem"))); VBoxContainer *add_vbox = memnew(VBoxContainer); add_panel->add_child(add_vbox); @@ -1097,7 +1101,7 @@ void EditorPropertyDictionary::_notification(int p_what) { if (button_add_item) { button_add_item->set_icon(get_editor_theme_icon(SNAME("Add"))); - add_panel->add_theme_style_override(SNAME("panel"), get_theme_stylebox(SNAME("DictionaryAddItem"))); + add_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("DictionaryAddItem"))); } } break; } @@ -1153,7 +1157,7 @@ EditorPropertyDictionary::EditorPropertyDictionary() { paginator = nullptr; change_type = memnew(PopupMenu); add_child(change_type); - change_type->connect("id_pressed", callable_mp(this, &EditorPropertyDictionary::_change_type_menu)); + change_type->connect(SceneStringName(id_pressed), callable_mp(this, &EditorPropertyDictionary::_change_type_menu)); changing_type_index = -1; has_borders = true; } diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp index 50820ac12f..fbd9d84e26 100644 --- a/editor/editor_resource_picker.cpp +++ b/editor/editor_resource_picker.cpp @@ -811,7 +811,7 @@ void EditorResourcePicker::_notification(int p_what) { } break; case NOTIFICATION_DRAW: { - draw_style_box(get_theme_stylebox(SNAME("panel"), SNAME("Tree")), Rect2(Point2(), get_size())); + draw_style_box(get_theme_stylebox(SceneStringName(panel), SNAME("Tree")), Rect2(Point2(), get_size())); } break; case NOTIFICATION_DRAG_BEGIN: { @@ -947,7 +947,7 @@ void EditorResourcePicker::_ensure_resource_menu() { edit_menu = memnew(PopupMenu); edit_menu->add_theme_constant_override("icon_max_width", get_theme_constant(SNAME("class_icon_size"), EditorStringName(Editor))); add_child(edit_menu); - edit_menu->connect("id_pressed", callable_mp(this, &EditorResourcePicker::_edit_menu_cbk)); + edit_menu->connect(SceneStringName(id_pressed), callable_mp(this, &EditorResourcePicker::_edit_menu_cbk)); edit_menu->connect("popup_hide", callable_mp((BaseButton *)edit_button, &BaseButton::set_pressed).bind(false)); } diff --git a/editor/editor_run_native.cpp b/editor/editor_run_native.cpp index 5c50231623..715f310b5b 100644 --- a/editor/editor_run_native.cpp +++ b/editor/editor_run_native.cpp @@ -188,7 +188,7 @@ EditorRunNative::EditorRunNative() { remote_debug = memnew(MenuButton); remote_debug->set_flat(false); remote_debug->set_theme_type_variation("RunBarButton"); - remote_debug->get_popup()->connect("id_pressed", callable_mp(this, &EditorRunNative::start_run_native)); + remote_debug->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &EditorRunNative::start_run_native)); remote_debug->set_tooltip_text(TTR("Remote Debug")); remote_debug->set_disabled(true); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index d7bc3502ce..782d64621f 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -571,7 +571,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "filesystem/import/blender/blender_path", "", "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) EDITOR_SETTING_USAGE(Variant::INT, PROPERTY_HINT_RANGE, "filesystem/import/blender/rpc_port", 6011, "0,65535,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) EDITOR_SETTING_USAGE(Variant::FLOAT, PROPERTY_HINT_RANGE, "filesystem/import/blender/rpc_server_uptime", 5, "0,300,1,or_greater,suffix:s", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) - EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "filesystem/import/fbx2gltf/fbx2gltf_path", "", "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) + EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "filesystem/import/fbx/fbx2gltf_path", "", "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) // Tools (denoise) EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_GLOBAL_DIR, "filesystem/tools/oidn/oidn_denoise_path", "", "", PROPERTY_USAGE_DEFAULT) @@ -651,6 +651,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { // Behavior: Files _initial_set("text_editor/behavior/files/trim_trailing_whitespace_on_save", false); + _initial_set("text_editor/behavior/files/trim_final_newlines_on_save", true); _initial_set("text_editor/behavior/files/autosave_interval_secs", 0); _initial_set("text_editor/behavior/files/restore_scripts_on_load", true); _initial_set("text_editor/behavior/files/convert_indent_on_save", true); @@ -818,11 +819,13 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { // Auto save _initial_set("run/auto_save/save_before_running", true); + // Bottom panel + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "run/bottom_panel/action_on_play", EditorNode::ACTION_ON_PLAY_OPEN_OUTPUT, "Do Nothing,Open Output,Open Debugger") + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "run/bottom_panel/action_on_stop", EditorNode::ACTION_ON_STOP_DO_NOTHING, "Do Nothing,Close Bottom Panel") + // Output EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "run/output/font_size", 13, "8,48,1") _initial_set("run/output/always_clear_output_on_play", true); - _initial_set("run/output/always_open_output_on_play", true); - _initial_set("run/output/always_close_output_on_stop", false); EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "run/output/max_lines", 10000, "100,100000,1") diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp index b1f3875175..7f9310f715 100644 --- a/editor/editor_settings_dialog.cpp +++ b/editor/editor_settings_dialog.cpp @@ -211,7 +211,7 @@ void EditorSettingsDialog::_update_icons() { shortcut_search_box->set_clear_button_enabled(true); restart_close_button->set_icon(shortcuts->get_editor_theme_icon(SNAME("Close"))); - restart_container->add_theme_style_override("panel", shortcuts->get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); + restart_container->add_theme_style_override(SceneStringName(panel), shortcuts->get_theme_stylebox(SceneStringName(panel), SNAME("Tree"))); restart_icon->set_texture(shortcuts->get_editor_theme_icon(SNAME("StatusWarning"))); restart_label->add_theme_color_override("font_color", shortcuts->get_theme_color(SNAME("warning_color"), EditorStringName(Editor))); } diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp index aa44189782..5a95b553e9 100644 --- a/editor/export/editor_export_platform.cpp +++ b/editor/export/editor_export_platform.cpp @@ -797,6 +797,10 @@ String EditorExportPlatform::_export_customize(const String &p_path, LocalVector if (!customize_scenes_plugins.is_empty()) { for (Ref<EditorExportPlugin> &plugin : customize_scenes_plugins) { Node *customized = plugin->_customize_scene(node, p_path); + if (plugin->skipped) { + plugin->_clear(); + return String(); + } if (customized != nullptr) { node = customized; modified = true; @@ -830,6 +834,10 @@ String EditorExportPlatform::_export_customize(const String &p_path, LocalVector if (!customize_resources_plugins.is_empty()) { for (Ref<EditorExportPlugin> &plugin : customize_resources_plugins) { Ref<Resource> new_res = plugin->_customize_resource(res, p_path); + if (plugin->skipped) { + plugin->_clear(); + return String(); + } if (new_res.is_valid()) { modified = true; if (new_res != res) { @@ -1135,6 +1143,10 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & // Before doing this, try to see if it can be customized. String export_path = _export_customize(path, customize_resources_plugins, customize_scenes_plugins, export_cache, export_base_path, false); + if (export_path.is_empty()) { + // Skipped from plugin. + continue; + } if (export_path != path) { // It was actually customized. diff --git a/editor/export/export_template_manager.cpp b/editor/export/export_template_manager.cpp index 339a6e4b7f..b6584a6092 100644 --- a/editor/export/export_template_manager.cpp +++ b/editor/export/export_template_manager.cpp @@ -973,7 +973,7 @@ ExportTemplateManager::ExportTemplateManager() { mirror_options_button->get_popup()->add_item(TTR("Copy Mirror URL"), COPY_MIRROR_URL); mirror_options_button->set_disabled(!downloads_available); download_install_hb->add_child(mirror_options_button); - mirror_options_button->get_popup()->connect("id_pressed", callable_mp(this, &ExportTemplateManager::_mirror_options_button_cbk)); + mirror_options_button->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &ExportTemplateManager::_mirror_options_button_cbk)); download_install_hb->add_spacer(); diff --git a/editor/export/project_export.cpp b/editor/export/project_export.cpp index dd283ebfd6..7787512cc2 100644 --- a/editor/export/project_export.cpp +++ b/editor/export/project_export.cpp @@ -1373,7 +1373,7 @@ ProjectExportDialog::ProjectExportDialog() { file_mode_popup->add_item(TTR("Strip Visuals"), EditorExportPreset::MODE_FILE_STRIP); file_mode_popup->add_item(TTR("Keep"), EditorExportPreset::MODE_FILE_KEEP); file_mode_popup->add_item(TTR("Remove"), EditorExportPreset::MODE_FILE_REMOVE); - file_mode_popup->connect("id_pressed", callable_mp(this, &ProjectExportDialog::_set_file_export_mode)); + file_mode_popup->connect(SceneStringName(id_pressed), callable_mp(this, &ProjectExportDialog::_set_file_export_mode)); include_filters = memnew(LineEdit); resources_vb->add_margin_child( diff --git a/editor/fbx_importer_manager.cpp b/editor/fbx_importer_manager.cpp index f9673771e1..1fded345c8 100644 --- a/editor/fbx_importer_manager.cpp +++ b/editor/fbx_importer_manager.cpp @@ -50,7 +50,7 @@ void FBXImporterManager::_notification(int p_what) { } void FBXImporterManager::show_dialog(bool p_exclusive) { - String fbx2gltf_path = EDITOR_GET("filesystem/import/fbx2gltf/fbx2gltf_path"); + String fbx2gltf_path = EDITOR_GET("filesystem/import/fbx/fbx2gltf_path"); fbx_path->set_text(fbx2gltf_path); _validate_path(fbx2gltf_path); @@ -109,7 +109,7 @@ void FBXImporterManager::_select_file(const String &p_path) { void FBXImporterManager::_path_confirmed() { String path = fbx_path->get_text(); - EditorSettings::get_singleton()->set("filesystem/import/fbx2gltf/fbx2gltf_path", path); + EditorSettings::get_singleton()->set("filesystem/import/fbx/fbx2gltf_path", path); EditorSettings::get_singleton()->save(); } diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 5f311ae445..f91e970283 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -556,8 +556,8 @@ void FileSystemDock::_notification(int p_what) { files->connect("item_activated", callable_mp(this, &FileSystemDock::_file_list_activate_file)); button_hist_next->connect(SceneStringName(pressed), callable_mp(this, &FileSystemDock::_fw_history)); button_hist_prev->connect(SceneStringName(pressed), callable_mp(this, &FileSystemDock::_bw_history)); - file_list_popup->connect("id_pressed", callable_mp(this, &FileSystemDock::_file_list_rmb_option)); - tree_popup->connect("id_pressed", callable_mp(this, &FileSystemDock::_tree_rmb_option)); + file_list_popup->connect(SceneStringName(id_pressed), callable_mp(this, &FileSystemDock::_file_list_rmb_option)); + tree_popup->connect(SceneStringName(id_pressed), callable_mp(this, &FileSystemDock::_tree_rmb_option)); current_path_line_edit->connect("text_submitted", callable_mp(this, &FileSystemDock::_navigate_to_path).bind(false)); always_show_folders = bool(EDITOR_GET("docks/filesystem/always_show_folders")); @@ -646,7 +646,7 @@ void FileSystemDock::_notification(int p_what) { button_hist_prev->set_icon(get_editor_theme_icon(SNAME("Back"))); } - overwrite_dialog_scroll->add_theme_style_override("panel", get_theme_stylebox("panel", "Tree")); + overwrite_dialog_scroll->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), "Tree")); } break; case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { @@ -3174,7 +3174,7 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, const Vect if (p_paths.size() == 1 && p_display_path_dependent_options) { PopupMenu *new_menu = memnew(PopupMenu); - new_menu->connect("id_pressed", callable_mp(this, &FileSystemDock::_tree_rmb_option)); + new_menu->connect(SceneStringName(id_pressed), callable_mp(this, &FileSystemDock::_tree_rmb_option)); p_popup->add_submenu_node_item(TTR("Create New"), new_menu, FILE_NEW); p_popup->set_item_icon(p_popup->get_item_index(FILE_NEW), get_editor_theme_icon(SNAME("Add"))); @@ -3199,7 +3199,7 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, const Vect if (p_paths[0] != "res://") { PopupMenu *folder_colors_menu = memnew(PopupMenu); - folder_colors_menu->connect("id_pressed", callable_mp(this, &FileSystemDock::_folder_color_index_pressed).bind(folder_colors_menu)); + folder_colors_menu->connect(SceneStringName(id_pressed), callable_mp(this, &FileSystemDock::_folder_color_index_pressed).bind(folder_colors_menu)); p_popup->add_submenu_node_item(TTR("Set Folder Color..."), folder_colors_menu); p_popup->set_item_icon(-1, get_editor_theme_icon(SNAME("Paint"))); @@ -3279,7 +3279,7 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, const Vect if (p_paths.size() == 1) { const String &fpath = p_paths[0]; - bool added_separator = false; + [[maybe_unused]] bool added_separator = false; if (favorites_list.has(fpath)) { TreeItem *favorites_item = tree->get_root()->get_first_child(); @@ -3310,15 +3310,15 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, const Vect // Opening the system file manager is not supported on the Android and web editors. const bool is_directory = fpath.ends_with("/"); - p_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Filesystem")), ED_GET_SHORTCUT("filesystem_dock/show_in_explorer"), FILE_SHOW_IN_EXPLORER); - p_popup->set_item_text(p_popup->get_item_index(FILE_SHOW_IN_EXPLORER), is_directory ? TTR("Open in File Manager") : TTR("Show in File Manager")); + p_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Terminal")), ED_GET_SHORTCUT("filesystem_dock/open_in_terminal"), FILE_OPEN_IN_TERMINAL); + p_popup->set_item_text(p_popup->get_item_index(FILE_OPEN_IN_TERMINAL), is_directory ? TTR("Open in Terminal") : TTR("Open Containing Folder in Terminal")); if (!is_directory) { p_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("ExternalLink")), ED_GET_SHORTCUT("filesystem_dock/open_in_external_program"), FILE_OPEN_EXTERNAL); } - p_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Terminal")), ED_GET_SHORTCUT("filesystem_dock/open_in_terminal"), FILE_OPEN_IN_TERMINAL); - p_popup->set_item_text(p_popup->get_item_index(FILE_OPEN_IN_TERMINAL), is_directory ? TTR("Open in Terminal") : TTR("Open Containing Folder in Terminal")); + p_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Filesystem")), ED_GET_SHORTCUT("filesystem_dock/show_in_explorer"), FILE_SHOW_IN_EXPLORER); + p_popup->set_item_text(p_popup->get_item_index(FILE_SHOW_IN_EXPLORER), is_directory ? TTR("Open in File Manager") : TTR("Show in File Manager")); #endif current_path = fpath; @@ -3362,8 +3362,8 @@ void FileSystemDock::_tree_empty_click(const Vector2 &p_pos, MouseButton p_butto #if !defined(ANDROID_ENABLED) && !defined(WEB_ENABLED) // Opening the system file manager is not supported on the Android and web editors. tree_popup->add_separator(); - tree_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Filesystem")), ED_GET_SHORTCUT("filesystem_dock/show_in_explorer"), FILE_SHOW_IN_EXPLORER); tree_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Terminal")), ED_GET_SHORTCUT("filesystem_dock/open_in_terminal"), FILE_OPEN_IN_TERMINAL); + tree_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Filesystem")), ED_GET_SHORTCUT("filesystem_dock/show_in_explorer"), FILE_SHOW_IN_EXPLORER); #endif tree_popup->set_position(tree->get_screen_position() + p_pos); @@ -3425,8 +3425,8 @@ void FileSystemDock::_file_list_empty_clicked(const Vector2 &p_pos, MouseButton file_list_popup->add_icon_item(get_editor_theme_icon(SNAME("Object")), TTR("New Resource..."), FILE_NEW_RESOURCE); file_list_popup->add_icon_item(get_editor_theme_icon(SNAME("TextFile")), TTR("New TextFile..."), FILE_NEW_TEXTFILE); file_list_popup->add_separator(); - file_list_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Filesystem")), ED_GET_SHORTCUT("filesystem_dock/show_in_explorer"), FILE_SHOW_IN_EXPLORER); file_list_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Terminal")), ED_GET_SHORTCUT("filesystem_dock/open_in_terminal"), FILE_OPEN_IN_TERMINAL); + file_list_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Filesystem")), ED_GET_SHORTCUT("filesystem_dock/show_in_explorer"), FILE_SHOW_IN_EXPLORER); file_list_popup->set_position(files->get_screen_position() + p_pos); file_list_popup->reset_size(); @@ -3771,7 +3771,7 @@ MenuButton *FileSystemDock::_create_file_menu_button() { button->set_tooltip_text(TTR("Sort Files")); PopupMenu *p = button->get_popup(); - p->connect("id_pressed", callable_mp(this, &FileSystemDock::_file_sort_popup)); + p->connect(SceneStringName(id_pressed), callable_mp(this, &FileSystemDock::_file_sort_popup)); p->add_radio_check_item(TTR("Sort by Name (Ascending)"), FILE_SORT_NAME); p->add_radio_check_item(TTR("Sort by Name (Descending)"), FILE_SORT_NAME_REVERSE); p->add_radio_check_item(TTR("Sort by Type (Ascending)"), FILE_SORT_TYPE); diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp index fc2ea80be9..ed83ae98f3 100644 --- a/editor/groups_editor.cpp +++ b/editor/groups_editor.cpp @@ -858,7 +858,7 @@ GroupsEditor::GroupsEditor() { add_child(tree); menu = memnew(PopupMenu); - menu->connect("id_pressed", callable_mp(this, &GroupsEditor::_menu_id_pressed)); + menu->connect(SceneStringName(id_pressed), callable_mp(this, &GroupsEditor::_menu_id_pressed)); tree->add_child(menu); ProjectSettingsEditor::get_singleton()->get_group_settings()->connect("group_changed", callable_mp(this, &GroupsEditor::_update_groups_and_tree)); diff --git a/editor/gui/editor_bottom_panel.cpp b/editor/gui/editor_bottom_panel.cpp index 3dbefa5cbc..f2c4a13e05 100644 --- a/editor/gui/editor_bottom_panel.cpp +++ b/editor/gui/editor_bottom_panel.cpp @@ -81,9 +81,9 @@ void EditorBottomPanel::_switch_to_item(bool p_visible, int p_idx) { } if (EditorDebuggerNode::get_singleton() == items[p_idx].control) { // This is the debug panel which uses tabs, so the top section should be smaller. - add_theme_style_override("panel", get_theme_stylebox(SNAME("BottomPanelDebuggerOverride"), EditorStringName(EditorStyles))); + add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("BottomPanelDebuggerOverride"), EditorStringName(EditorStyles))); } else { - add_theme_style_override("panel", get_theme_stylebox(SNAME("BottomPanel"), EditorStringName(EditorStyles))); + add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("BottomPanel"), EditorStringName(EditorStyles))); } center_split->set_dragger_visibility(SplitContainer::DRAGGER_VISIBLE); center_split->set_collapsed(false); @@ -92,7 +92,7 @@ void EditorBottomPanel::_switch_to_item(bool p_visible, int p_idx) { } expand_button->show(); } else { - add_theme_style_override("panel", get_theme_stylebox(SNAME("BottomPanel"), EditorStringName(EditorStyles))); + add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("BottomPanel"), EditorStringName(EditorStyles))); items[p_idx].button->set_pressed_no_signal(false); items[p_idx].control->set_visible(false); center_split->set_dragger_visibility(SplitContainer::DRAGGER_HIDDEN); diff --git a/editor/gui/editor_file_dialog.cpp b/editor/gui/editor_file_dialog.cpp index 8883c0b9af..97c54e8f48 100644 --- a/editor/gui/editor_file_dialog.cpp +++ b/editor/gui/editor_file_dialog.cpp @@ -2265,7 +2265,7 @@ EditorFileDialog::EditorFileDialog() { list_vb->add_child(item_list); item_menu = memnew(PopupMenu); - item_menu->connect("id_pressed", callable_mp(this, &EditorFileDialog::_item_menu_id_pressed)); + item_menu->connect(SceneStringName(id_pressed), callable_mp(this, &EditorFileDialog::_item_menu_id_pressed)); add_child(item_menu); // Other stuff. diff --git a/editor/gui/editor_file_dialog.h b/editor/gui/editor_file_dialog.h index 7d6fa19a44..6272e27f82 100644 --- a/editor/gui/editor_file_dialog.h +++ b/editor/gui/editor_file_dialog.h @@ -268,7 +268,7 @@ protected: void _notification(int p_what); bool _set(const StringName &p_name, const Variant &p_value) { return property_helper.property_set_value(p_name, p_value); } bool _get(const StringName &p_name, Variant &r_ret) const { return property_helper.property_get_value(p_name, r_ret); } - void _get_property_list(List<PropertyInfo> *p_list) const { property_helper.get_property_list(p_list, options.size()); } + void _get_property_list(List<PropertyInfo> *p_list) const { property_helper.get_property_list(p_list); } bool _property_can_revert(const StringName &p_name) const { return property_helper.property_can_revert(p_name); } bool _property_get_revert(const StringName &p_name, Variant &r_property) const { return property_helper.property_get_revert(p_name, r_property); } static void _bind_methods(); diff --git a/editor/gui/editor_object_selector.cpp b/editor/gui/editor_object_selector.cpp index a713aa1ecd..0985753430 100644 --- a/editor/gui/editor_object_selector.cpp +++ b/editor/gui/editor_object_selector.cpp @@ -251,7 +251,7 @@ EditorObjectSelector::EditorObjectSelector(EditorSelectionHistory *p_history) { sub_objects_menu->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); add_child(sub_objects_menu); sub_objects_menu->connect("about_to_popup", callable_mp(this, &EditorObjectSelector::_about_to_show)); - sub_objects_menu->connect("id_pressed", callable_mp(this, &EditorObjectSelector::_id_pressed)); + sub_objects_menu->connect(SceneStringName(id_pressed), callable_mp(this, &EditorObjectSelector::_id_pressed)); set_tooltip_text(TTR("Open a list of sub-resources.")); } diff --git a/editor/gui/editor_run_bar.cpp b/editor/gui/editor_run_bar.cpp index 31331126b2..af044cbfce 100644 --- a/editor/gui/editor_run_bar.cpp +++ b/editor/gui/editor_run_bar.cpp @@ -56,11 +56,11 @@ void EditorRunBar::_notification(int p_what) { stop_button->set_icon(get_editor_theme_icon(SNAME("Stop"))); if (is_movie_maker_enabled()) { - main_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("LaunchPadMovieMode"), EditorStringName(EditorStyles))); - write_movie_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("MovieWriterButtonPressed"), EditorStringName(EditorStyles))); + main_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("LaunchPadMovieMode"), EditorStringName(EditorStyles))); + write_movie_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("MovieWriterButtonPressed"), EditorStringName(EditorStyles))); } else { - main_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("LaunchPadNormal"), EditorStringName(EditorStyles))); - write_movie_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("MovieWriterButtonNormal"), EditorStringName(EditorStyles))); + main_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("LaunchPadNormal"), EditorStringName(EditorStyles))); + write_movie_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("MovieWriterButtonNormal"), EditorStringName(EditorStyles))); } write_movie_button->set_icon(get_editor_theme_icon(SNAME("MainMovieWrite"))); @@ -112,11 +112,11 @@ void EditorRunBar::_update_play_buttons() { void EditorRunBar::_write_movie_toggled(bool p_enabled) { if (p_enabled) { - add_theme_style_override("panel", get_theme_stylebox(SNAME("LaunchPadMovieMode"), EditorStringName(EditorStyles))); - write_movie_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("MovieWriterButtonPressed"), EditorStringName(EditorStyles))); + add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("LaunchPadMovieMode"), EditorStringName(EditorStyles))); + write_movie_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("MovieWriterButtonPressed"), EditorStringName(EditorStyles))); } else { - add_theme_style_override("panel", get_theme_stylebox(SNAME("LaunchPadNormal"), EditorStringName(EditorStyles))); - write_movie_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("MovieWriterButtonNormal"), EditorStringName(EditorStyles))); + add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("LaunchPadNormal"), EditorStringName(EditorStyles))); + write_movie_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("MovieWriterButtonNormal"), EditorStringName(EditorStyles))); } } diff --git a/editor/gui/editor_scene_tabs.cpp b/editor/gui/editor_scene_tabs.cpp index f1ca59e0ac..2622645d7c 100644 --- a/editor/gui/editor_scene_tabs.cpp +++ b/editor/gui/editor_scene_tabs.cpp @@ -50,7 +50,7 @@ EditorSceneTabs *EditorSceneTabs::singleton = nullptr; void EditorSceneTabs::_notification(int p_what) { switch (p_what) { case NOTIFICATION_THEME_CHANGED: { - tabbar_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("tabbar_background"), SNAME("TabContainer"))); + tabbar_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("tabbar_background"), SNAME("TabContainer"))); scene_tabs->add_theme_constant_override("icon_max_width", get_theme_constant(SNAME("class_icon_size"), EditorStringName(Editor))); scene_tab_add->set_icon(get_editor_theme_icon(SNAME("Add"))); @@ -409,7 +409,7 @@ EditorSceneTabs::EditorSceneTabs() { scene_tabs_context_menu = memnew(PopupMenu); tabbar_container->add_child(scene_tabs_context_menu); - scene_tabs_context_menu->connect("id_pressed", callable_mp(EditorNode::get_singleton(), &EditorNode::trigger_menu_option).bind(false)); + scene_tabs_context_menu->connect(SceneStringName(id_pressed), callable_mp(EditorNode::get_singleton(), &EditorNode::trigger_menu_option).bind(false)); scene_tab_add = memnew(Button); scene_tab_add->set_flat(true); diff --git a/editor/gui/editor_spin_slider.cpp b/editor/gui/editor_spin_slider.cpp index bf487a5769..a838299288 100644 --- a/editor/gui/editor_spin_slider.cpp +++ b/editor/gui/editor_spin_slider.cpp @@ -300,7 +300,7 @@ void EditorSpinSlider::_update_value_input_stylebox() { stylebox->set_content_margin(SIDE_LEFT, (!get_label().is_empty() ? 23 : 16) * EDSCALE); } - value_input->add_theme_style_override("normal", stylebox); + value_input->add_theme_style_override(CoreStringName(normal), stylebox); } void EditorSpinSlider::_draw_spin_slider() { diff --git a/editor/gui/editor_toaster.cpp b/editor/gui/editor_toaster.cpp index 7aa5335b77..9be58326ac 100644 --- a/editor/gui/editor_toaster.cpp +++ b/editor/gui/editor_toaster.cpp @@ -149,7 +149,7 @@ void EditorToaster::_notification(int p_what) { void EditorToaster::_error_handler(void *p_self, const char *p_func, const char *p_file, int p_line, const char *p_error, const char *p_errorexp, bool p_editor_notify, ErrorHandlerType p_type) { // This may be called from a thread. Since we will deal with non-thread-safe elements, // we have to put it in the queue for safety. - callable_mp_static(&EditorToaster::_error_handler_impl).bind(String::utf8(p_file), p_line, String::utf8(p_error), String::utf8(p_errorexp), p_editor_notify, p_type).call_deferred(); + callable_mp_static(&EditorToaster::_error_handler_impl).call_deferred(String::utf8(p_file), p_line, String::utf8(p_error), String::utf8(p_errorexp), p_editor_notify, p_type); } void EditorToaster::_error_handler_impl(const String &p_file, int p_line, const String &p_error, const String &p_errorexp, bool p_editor_notify, int p_type) { @@ -348,13 +348,13 @@ Control *EditorToaster::popup(Control *p_control, Severity p_severity, double p_ panel->set_tooltip_text(p_tooltip); switch (p_severity) { case SEVERITY_INFO: - panel->add_theme_style_override("panel", info_panel_style_background); + panel->add_theme_style_override(SceneStringName(panel), info_panel_style_background); break; case SEVERITY_WARNING: - panel->add_theme_style_override("panel", warning_panel_style_background); + panel->add_theme_style_override(SceneStringName(panel), warning_panel_style_background); break; case SEVERITY_ERROR: - panel->add_theme_style_override("panel", error_panel_style_background); + panel->add_theme_style_override(SceneStringName(panel), error_panel_style_background); break; default: break; @@ -552,7 +552,7 @@ EditorToaster::EditorToaster() { // Disable notification button. disable_notifications_panel = memnew(PanelContainer); disable_notifications_panel->set_as_top_level(true); - disable_notifications_panel->add_theme_style_override("panel", info_panel_style_background); + disable_notifications_panel->add_theme_style_override(SceneStringName(panel), info_panel_style_background); add_child(disable_notifications_panel); disable_notifications_button = memnew(Button); diff --git a/editor/gui/editor_zoom_widget.cpp b/editor/gui/editor_zoom_widget.cpp index e3d8d4b224..73afbc3ab5 100644 --- a/editor/gui/editor_zoom_widget.cpp +++ b/editor/gui/editor_zoom_widget.cpp @@ -205,7 +205,7 @@ EditorZoomWidget::EditorZoomWidget() { zoom_reset->set_flat(true); Ref<StyleBoxEmpty> empty_stylebox = memnew(StyleBoxEmpty); - zoom_reset->add_theme_style_override("normal", empty_stylebox); + zoom_reset->add_theme_style_override(CoreStringName(normal), empty_stylebox); zoom_reset->add_theme_style_override("hover", empty_stylebox); zoom_reset->add_theme_style_override("focus", empty_stylebox); zoom_reset->add_theme_style_override(SceneStringName(pressed), empty_stylebox); diff --git a/editor/import/3d/scene_import_settings.cpp b/editor/import/3d/scene_import_settings.cpp index 4c78c620c1..129d0544c3 100644 --- a/editor/import/3d/scene_import_settings.cpp +++ b/editor/import/3d/scene_import_settings.cpp @@ -1261,7 +1261,7 @@ void SceneImportSettingsDialog::_notification(int p_what) { case NOTIFICATION_THEME_CHANGED: { action_menu->begin_bulk_theme_override(); - action_menu->add_theme_style_override("normal", get_theme_stylebox("normal", "Button")); + action_menu->add_theme_style_override(CoreStringName(normal), get_theme_stylebox(CoreStringName(normal), "Button")); action_menu->add_theme_style_override("hover", get_theme_stylebox("hover", "Button")); action_menu->add_theme_style_override(SceneStringName(pressed), get_theme_stylebox(SceneStringName(pressed), "Button")); action_menu->end_bulk_theme_override(); @@ -1584,7 +1584,7 @@ SceneImportSettingsDialog::SceneImportSettingsDialog() { action_menu->get_popup()->add_item(TTR("Set Animation Save Paths"), ACTION_CHOOSE_ANIMATION_SAVE_PATHS); action_menu->get_popup()->add_item(TTR("Set Mesh Save Paths"), ACTION_CHOOSE_MESH_SAVE_PATHS); - action_menu->get_popup()->connect("id_pressed", callable_mp(this, &SceneImportSettingsDialog::_menu_callback)); + action_menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &SceneImportSettingsDialog::_menu_callback)); tree_split = memnew(HSplitContainer); main_vb->add_child(tree_split); diff --git a/editor/import/dynamic_font_import_settings.cpp b/editor/import/dynamic_font_import_settings.cpp index aad7302ec5..9b6a7b9a93 100644 --- a/editor/import/dynamic_font_import_settings.cpp +++ b/editor/import/dynamic_font_import_settings.cpp @@ -1515,8 +1515,8 @@ DynamicFontImportSettingsDialog::DynamicFontImportSettingsDialog() { for (int i = 0; i < 16; i++) { glyph_table->set_column_title(i + 1, String::num_int64(i, 16)); } - glyph_table->add_theme_style_override("selected", glyph_table->get_theme_stylebox(SNAME("panel"))); - glyph_table->add_theme_style_override("selected_focus", glyph_table->get_theme_stylebox(SNAME("panel"))); + glyph_table->add_theme_style_override("selected", glyph_table->get_theme_stylebox(SceneStringName(panel))); + glyph_table->add_theme_style_override("selected_focus", glyph_table->get_theme_stylebox(SceneStringName(panel))); glyph_table->add_theme_constant_override("h_separation", 0); glyph_table->set_h_size_flags(Control::SIZE_EXPAND_FILL); glyph_table->set_v_size_flags(Control::SIZE_EXPAND_FILL); diff --git a/editor/import/resource_importer_shader_file.cpp b/editor/import/resource_importer_shader_file.cpp index bde2e3d0bf..b7508e7644 100644 --- a/editor/import/resource_importer_shader_file.cpp +++ b/editor/import/resource_importer_shader_file.cpp @@ -92,6 +92,7 @@ static String _include_function(const String &p_path, void *userpointer) { Error ResourceImporterShaderFile::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { /* STEP 1, Read shader code */ ERR_FAIL_COND_V_EDMSG((OS::get_singleton()->get_current_rendering_method() == "gl_compatibility"), ERR_UNAVAILABLE, "Cannot import custom .glsl shaders when using the gl_compatibility rendering_method. Please switch to the forward_plus or mobile rendering methods to use custom shaders."); + ERR_FAIL_COND_V_EDMSG((DisplayServer::get_singleton()->get_name() == "headless"), ERR_UNAVAILABLE, "Cannot import custom .glsl shaders when running in headless mode."); Error err; Ref<FileAccess> file = FileAccess::open(p_source_file, FileAccess::READ, &err); @@ -106,7 +107,7 @@ Error ResourceImporterShaderFile::import(const String &p_source_file, const Stri if (err != OK) { if (!ShaderFileEditor::singleton->is_visible_in_tree()) { - callable_mp_static(&EditorNode::add_io_error).bind(vformat(TTR("Error importing GLSL shader file: '%s'. Open the file in the filesystem dock in order to see the reason."), p_source_file)).call_deferred(); + callable_mp_static(&EditorNode::add_io_error).call_deferred(vformat(TTR("Error importing GLSL shader file: '%s'. Open the file in the filesystem dock in order to see the reason."), p_source_file)); } } diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp index 2d87e6592f..3c06c68414 100644 --- a/editor/import_dock.cpp +++ b/editor/import_dock.cpp @@ -718,7 +718,7 @@ void ImportDock::_notification(int p_what) { switch (p_what) { case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { if (EditorThemeManager::is_generated_theme_outdated()) { - imported->add_theme_style_override("normal", get_theme_stylebox(CoreStringName(normal), SNAME("LineEdit"))); + imported->add_theme_style_override(CoreStringName(normal), get_theme_stylebox(CoreStringName(normal), SNAME("LineEdit"))); } } break; @@ -775,7 +775,7 @@ ImportDock::ImportDock() { content->hide(); imported = memnew(Label); - imported->add_theme_style_override("normal", EditorNode::get_singleton()->get_editor_theme()->get_stylebox(CoreStringName(normal), SNAME("LineEdit"))); + imported->add_theme_style_override(CoreStringName(normal), EditorNode::get_singleton()->get_editor_theme()->get_stylebox(CoreStringName(normal), SNAME("LineEdit"))); imported->set_clip_text(true); content->add_child(imported); HBoxContainer *hb = memnew(HBoxContainer); diff --git a/editor/input_event_configuration_dialog.cpp b/editor/input_event_configuration_dialog.cpp index 865729c7c3..2ecce2f739 100644 --- a/editor/input_event_configuration_dialog.cpp +++ b/editor/input_event_configuration_dialog.cpp @@ -446,6 +446,11 @@ void InputEventConfigurationDialog::_key_location_selected(int p_location) { _set_event(k, original_event); } +void InputEventConfigurationDialog::_input_list_item_activated() { + TreeItem *selected = input_list_tree->get_selected(); + selected->set_collapsed(!selected->is_collapsed()); +} + void InputEventConfigurationDialog::_input_list_item_selected() { TreeItem *selected = input_list_tree->get_selected(); @@ -670,6 +675,7 @@ InputEventConfigurationDialog::InputEventConfigurationDialog() { input_list_tree = memnew(Tree); input_list_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); input_list_tree->set_custom_minimum_size(Size2(0, 100 * EDSCALE)); // Min height for tree + input_list_tree->connect("item_activated", callable_mp(this, &InputEventConfigurationDialog::_input_list_item_activated)); input_list_tree->connect("item_selected", callable_mp(this, &InputEventConfigurationDialog::_input_list_item_selected)); input_list_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL); manual_vbox->add_child(input_list_tree); diff --git a/editor/input_event_configuration_dialog.h b/editor/input_event_configuration_dialog.h index 1d2cc8ba36..b27f25a5b7 100644 --- a/editor/input_event_configuration_dialog.h +++ b/editor/input_event_configuration_dialog.h @@ -107,6 +107,7 @@ private: void _search_term_updated(const String &p_term); void _update_input_list(); + void _input_list_item_activated(); void _input_list_item_selected(); void _mod_toggled(bool p_checked, int p_index); diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp index 5455933809..ad2e16636b 100644 --- a/editor/inspector_dock.cpp +++ b/editor/inspector_dock.cpp @@ -666,7 +666,7 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) { general_options_hb->add_child(resource_save_button); resource_save_button->get_popup()->add_item(TTR("Save"), RESOURCE_SAVE); resource_save_button->get_popup()->add_item(TTR("Save As..."), RESOURCE_SAVE_AS); - resource_save_button->get_popup()->connect("id_pressed", callable_mp(this, &InspectorDock::_menu_option)); + resource_save_button->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &InspectorDock::_menu_option)); resource_save_button->set_focus_mode(Control::FOCUS_NONE); resource_save_button->set_disabled(true); @@ -683,7 +683,7 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) { resource_extra_button->get_popup()->add_shortcut(ED_SHORTCUT("property_editor/show_in_filesystem", TTR("Show in FileSystem")), RESOURCE_SHOW_IN_FILESYSTEM); resource_extra_button->get_popup()->add_shortcut(ED_SHORTCUT("property_editor/unref_resource", TTR("Make Resource Built-In")), RESOURCE_MAKE_BUILT_IN); resource_extra_button->get_popup()->set_item_disabled(3, true); - resource_extra_button->get_popup()->connect("id_pressed", callable_mp(this, &InspectorDock::_menu_option)); + resource_extra_button->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &InspectorDock::_menu_option)); general_options_hb->add_spacer(); @@ -708,7 +708,7 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) { history_menu->set_tooltip_text(TTR("History of recently edited objects.")); general_options_hb->add_child(history_menu); history_menu->connect("about_to_popup", callable_mp(this, &InspectorDock::_prepare_history)); - history_menu->get_popup()->connect("id_pressed", callable_mp(this, &InspectorDock::_select_history)); + history_menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &InspectorDock::_select_history)); HBoxContainer *subresource_hb = memnew(HBoxContainer); add_child(subresource_hb); @@ -745,7 +745,7 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) { property_tools_hb->add_child(object_menu); object_menu->set_tooltip_text(TTR("Manage object properties.")); object_menu->get_popup()->connect("about_to_popup", callable_mp(this, &InspectorDock::_prepare_menu)); - object_menu->get_popup()->connect("id_pressed", callable_mp(this, &InspectorDock::_menu_option)); + object_menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &InspectorDock::_menu_option)); info = memnew(Button); add_child(info); diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp index 95b184b8ab..52ea7ff0ba 100644 --- a/editor/plugins/animation_blend_space_1d_editor.cpp +++ b/editor/plugins/animation_blend_space_1d_editor.cpp @@ -573,9 +573,9 @@ void AnimationNodeBlendSpace1DEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { - error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); + error_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree"))); error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), EditorStringName(Editor))); - panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); + panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree"))); tool_blend->set_icon(get_editor_theme_icon(SNAME("EditPivot"))); tool_select->set_icon(get_editor_theme_icon(SNAME("ToolSelect"))); tool_create->set_icon(get_editor_theme_icon(SNAME("EditKey"))); @@ -799,7 +799,7 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() { menu = memnew(PopupMenu); add_child(menu); - menu->connect("id_pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_add_menu_type)); + menu->connect(SceneStringName(id_pressed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_add_menu_type)); animations_menu = memnew(PopupMenu); animations_menu->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp index 7ee86c77d2..ef61a95ee7 100644 --- a/editor/plugins/animation_blend_space_2d_editor.cpp +++ b/editor/plugins/animation_blend_space_2d_editor.cpp @@ -795,9 +795,9 @@ void AnimationNodeBlendSpace2DEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { - error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); + error_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree"))); error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), EditorStringName(Editor))); - panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); + panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree"))); tool_blend->set_icon(get_editor_theme_icon(SNAME("EditPivot"))); tool_select->set_icon(get_editor_theme_icon(SNAME("ToolSelect"))); tool_create->set_icon(get_editor_theme_icon(SNAME("EditKey"))); @@ -1078,7 +1078,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() { menu = memnew(PopupMenu); add_child(menu); - menu->connect("id_pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_add_menu_type)); + menu->connect(SceneStringName(id_pressed), callable_mp(this, &AnimationNodeBlendSpace2DEditor::_add_menu_type)); animations_menu = memnew(PopupMenu); animations_menu->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index 26a90c3ce8..28e1eeccc4 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -265,7 +265,7 @@ void AnimationNodeBlendTreeEditor::update_graph() { } // TODO: Avoid using strings, expose a method on GraphNode instead. - Ref<StyleBoxFlat> sb = node->get_theme_stylebox(SNAME("panel")); + Ref<StyleBoxFlat> sb = node->get_theme_stylebox(SceneStringName(panel)); Color c = sb->get_border_color(); Color mono_color = ((c.r + c.g + c.b) / 3) < 0.7 ? Color(1.0, 1.0, 1.0) : Color(0.0, 0.0, 0.0); mono_color.a = 0.85; @@ -942,7 +942,7 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) { } break; case NOTIFICATION_THEME_CHANGED: { - error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); + error_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree"))); error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), EditorStringName(Editor))); if (is_visible_in_tree()) { @@ -1193,7 +1193,7 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() { graph->get_menu_hbox()->add_child(add_node); add_node->set_text(TTR("Add Node...")); graph->get_menu_hbox()->move_child(add_node, 0); - add_node->get_popup()->connect("id_pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_add_node)); + add_node->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &AnimationNodeBlendTreeEditor::_add_node)); add_node->get_popup()->connect("popup_hide", callable_mp(this, &AnimationNodeBlendTreeEditor::_popup_hide), CONNECT_DEFERRED); add_node->connect("about_to_popup", callable_mp(this, &AnimationNodeBlendTreeEditor::_update_options_menu).bind(false)); add_node->set_disabled(read_only); diff --git a/editor/plugins/animation_library_editor.cpp b/editor/plugins/animation_library_editor.cpp index 8620c3b883..a2f1fa5614 100644 --- a/editor/plugins/animation_library_editor.cpp +++ b/editor/plugins/animation_library_editor.cpp @@ -839,7 +839,7 @@ AnimationLibraryEditor::AnimationLibraryEditor() { file_popup = memnew(PopupMenu); add_child(file_popup); - file_popup->connect("id_pressed", callable_mp(this, &AnimationLibraryEditor::_file_popup_selected)); + file_popup->connect(SceneStringName(id_pressed), callable_mp(this, &AnimationLibraryEditor::_file_popup_selected)); add_child(vb); diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 1366a38bec..fe56f48889 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -121,20 +121,20 @@ void AnimationPlayerEditor::_notification(int p_what) { } break; case NOTIFICATION_ENTER_TREE: { - tool_anim->get_popup()->connect(SNAME("id_pressed"), callable_mp(this, &AnimationPlayerEditor::_animation_tool_menu)); + tool_anim->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &AnimationPlayerEditor::_animation_tool_menu)); - onion_skinning->get_popup()->connect(SNAME("id_pressed"), callable_mp(this, &AnimationPlayerEditor::_onion_skinning_menu)); + onion_skinning->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &AnimationPlayerEditor::_onion_skinning_menu)); blend_editor.next->connect(SNAME("item_selected"), callable_mp(this, &AnimationPlayerEditor::_blend_editor_next_changed)); get_tree()->connect(SNAME("node_removed"), callable_mp(this, &AnimationPlayerEditor::_node_removed)); - add_theme_style_override("panel", EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("panel"), SNAME("Panel"))); + add_theme_style_override(SceneStringName(panel), EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SceneStringName(panel), SNAME("Panel"))); } break; case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { if (EditorThemeManager::is_generated_theme_outdated()) { - add_theme_style_override("panel", EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("panel"), SNAME("Panel"))); + add_theme_style_override(SceneStringName(panel), EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SceneStringName(panel), SNAME("Panel"))); } } break; @@ -172,8 +172,8 @@ void AnimationPlayerEditor::_notification(int p_what) { pin->set_icon(get_editor_theme_icon(SNAME("Pin"))); - tool_anim->add_theme_style_override("normal", get_theme_stylebox(CoreStringName(normal), SNAME("Button"))); - track_editor->get_edit_menu()->add_theme_style_override("normal", get_theme_stylebox(CoreStringName(normal), SNAME("Button"))); + tool_anim->add_theme_style_override(CoreStringName(normal), get_theme_stylebox(CoreStringName(normal), SNAME("Button"))); + track_editor->get_edit_menu()->add_theme_style_override(CoreStringName(normal), get_theme_stylebox(CoreStringName(normal), SNAME("Button"))); #define ITEM_ICON(m_item, m_icon) tool_anim->get_popup()->set_item_icon(tool_anim->get_popup()->get_item_index(m_item), get_editor_theme_icon(SNAME(m_icon))) @@ -547,13 +547,18 @@ void AnimationPlayerEditor::_animation_name_edited() { } break; case TOOL_NEW_ANIM: { - String current = animation->get_item_text(animation->get_selected()); - Ref<Animation> current_anim = player->get_animation(current); Ref<Animation> new_anim = Ref<Animation>(memnew(Animation)); new_anim->set_name(new_name); - if (current_anim.is_valid()) { - new_anim->set_step(current_anim->get_step()); + + if (animation->get_item_count() > 0) { + String current = animation->get_item_text(animation->get_selected()); + Ref<Animation> current_anim = player->get_animation(current); + + if (current_anim.is_valid()) { + new_anim->set_step(current_anim->get_step()); + } } + String library_name; Ref<AnimationLibrary> al; library_name = library->get_item_metadata(library->get_selected()); @@ -881,6 +886,7 @@ void AnimationPlayerEditor::_update_player() { tool_anim->set_disabled(player == nullptr); pin->set_disabled(player == nullptr); + _set_controls_disabled(player == nullptr); if (!player) { AnimationPlayerEditor::get_singleton()->get_track_editor()->update_keying(); @@ -931,17 +937,6 @@ void AnimationPlayerEditor::_update_player() { ITEM_CHECK_DISABLED(TOOL_NEW_ANIM); #undef ITEM_CHECK_DISABLED - stop->set_disabled(no_anims_found); - play->set_disabled(no_anims_found); - play_bw->set_disabled(no_anims_found); - play_bw_from->set_disabled(no_anims_found); - play_from->set_disabled(no_anims_found); - frame->set_editable(!no_anims_found); - animation->set_disabled(no_anims_found); - autoplay->set_disabled(no_anims_found); - onion_toggle->set_disabled(no_anims_found); - onion_skinning->set_disabled(no_anims_found); - _update_animation_list_icons(); updating = false; @@ -958,7 +953,9 @@ void AnimationPlayerEditor::_update_player() { _animation_selected(0); } - if (!no_anims_found) { + if (no_anims_found) { + _set_controls_disabled(true); + } else { String current = animation->get_item_text(animation->get_selected()); Ref<Animation> anim = player->get_animation(current); @@ -974,6 +971,20 @@ void AnimationPlayerEditor::_update_player() { _update_animation(); } +void AnimationPlayerEditor::_set_controls_disabled(bool p_disabled) { + frame->set_editable(!p_disabled); + + stop->set_disabled(p_disabled); + play->set_disabled(p_disabled); + play_bw->set_disabled(p_disabled); + play_bw_from->set_disabled(p_disabled); + play_from->set_disabled(p_disabled); + animation->set_disabled(p_disabled); + autoplay->set_disabled(p_disabled); + onion_toggle->set_disabled(p_disabled); + onion_skinning->set_disabled(p_disabled); +} + void AnimationPlayerEditor::_update_animation_list_icons() { for (int i = 0; i < animation->get_item_count(); i++) { String anim_name = animation->get_item_text(i); @@ -1076,9 +1087,6 @@ void AnimationPlayerEditor::_ensure_dummy_player() { } } - // Make some options disabled. - onion_toggle->set_disabled(dummy_exists); - onion_skinning->set_disabled(dummy_exists); int selected = animation->get_selected(); autoplay->set_disabled(selected != -1 ? (animation->get_item_text(selected).is_empty() ? true : dummy_exists) : true); @@ -1711,7 +1719,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2_step_prepare(int p_step_offs OS::get_singleton()->get_main_loop()->process(0); // This is the key: process the frame and let all callbacks/updates/notifications happen // so everything (transforms, skeletons, etc.) is up-to-date visually. - callable_mp(this, &AnimationPlayerEditor::_prepare_onion_layers_2_step_capture).bind(p_step_offset, p_capture_idx).call_deferred(); + callable_mp(this, &AnimationPlayerEditor::_prepare_onion_layers_2_step_capture).call_deferred(p_step_offset, p_capture_idx); return; } else { next_capture_idx++; diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h index 70b31759fc..e624522566 100644 --- a/editor/plugins/animation_player_editor_plugin.h +++ b/editor/plugins/animation_player_editor_plugin.h @@ -206,6 +206,7 @@ class AnimationPlayerEditor : public VBoxContainer { void _current_animation_changed(const String &p_name); void _update_animation(); void _update_player(); + void _set_controls_disabled(bool p_disabled); void _update_animation_list_icons(); void _update_name_dialog_library_dropdown(); void _blend_edited(); diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index b6d81ce461..8be010c00b 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -118,7 +118,7 @@ String AnimationNodeStateMachineEditor::_get_root_playback_path(String &r_node_d if (node_directory_path.size()) { r_node_directory += "/"; } - base_path = !edited_path.size() ? String(SceneStringName(parameters_base_path)) + "playback" : String(SceneStringName(parameters_base_path)) + base_path + "/playback"; + base_path = !edited_path.size() ? Animation::PARAMETERS_BASE_PATH + "playback" : Animation::PARAMETERS_BASE_PATH + base_path + "/playback"; } else { // Hmmm, we have to return Grouped state machine playback... // It will give the user the error that Root/Nested state machine should be retrieved, that would be kind :-) @@ -606,7 +606,7 @@ bool AnimationNodeStateMachineEditor::_create_submenu(PopupMenu *p_menu, Ref<Ani PopupMenu *nodes_menu = memnew(PopupMenu); nodes_menu->set_name(p_name); - nodes_menu->connect("id_pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_connect_to)); + nodes_menu->connect(SceneStringName(id_pressed), callable_mp(this, &AnimationNodeStateMachineEditor::_connect_to)); p_menu->add_child(nodes_menu); bool node_added = false; @@ -1267,8 +1267,8 @@ void AnimationNodeStateMachineEditor::_update_graph() { void AnimationNodeStateMachineEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_THEME_CHANGED: { - panel->add_theme_style_override("panel", theme_cache.panel_style); - error_panel->add_theme_style_override("panel", theme_cache.error_panel_style); + panel->add_theme_style_override(SceneStringName(panel), theme_cache.panel_style); + error_panel->add_theme_style_override(SceneStringName(panel), theme_cache.error_panel_style); error_label->add_theme_color_override("font_color", theme_cache.error_color); tool_select->set_icon(theme_cache.tool_icon_select); @@ -1766,7 +1766,7 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { menu = memnew(PopupMenu); add_child(menu); - menu->connect("id_pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_add_menu_type)); + menu->connect(SceneStringName(id_pressed), callable_mp(this, &AnimationNodeStateMachineEditor::_add_menu_type)); menu->connect("popup_hide", callable_mp(this, &AnimationNodeStateMachineEditor::_stop_connecting)); animations_menu = memnew(PopupMenu); @@ -1776,17 +1776,17 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { connect_menu = memnew(PopupMenu); add_child(connect_menu); - connect_menu->connect("id_pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_connect_to)); + connect_menu->connect(SceneStringName(id_pressed), callable_mp(this, &AnimationNodeStateMachineEditor::_connect_to)); connect_menu->connect("popup_hide", callable_mp(this, &AnimationNodeStateMachineEditor::_stop_connecting)); state_machine_menu = memnew(PopupMenu); state_machine_menu->set_name("state_machines"); - state_machine_menu->connect("id_pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_connect_to)); + state_machine_menu->connect(SceneStringName(id_pressed), callable_mp(this, &AnimationNodeStateMachineEditor::_connect_to)); connect_menu->add_child(state_machine_menu); end_menu = memnew(PopupMenu); end_menu->set_name("end_nodes"); - end_menu->connect("id_pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_connect_to)); + end_menu->connect(SceneStringName(id_pressed), callable_mp(this, &AnimationNodeStateMachineEditor::_connect_to)); connect_menu->add_child(end_menu); name_edit_popup = memnew(Popup); diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp index cc1f51348d..757d410b78 100644 --- a/editor/plugins/animation_tree_editor_plugin.cpp +++ b/editor/plugins/animation_tree_editor_plugin.cpp @@ -220,7 +220,7 @@ void AnimationTreeEditor::remove_plugin(AnimationTreeNodeEditorPlugin *p_editor) } String AnimationTreeEditor::get_base_path() { - String path = SceneStringName(parameters_base_path); + String path = Animation::PARAMETERS_BASE_PATH; for (int i = 0; i < edited_path.size(); i++) { path += edited_path[i] + "/"; } diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 99c7ab63e9..25c173ed35 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -127,7 +127,7 @@ EditorAssetLibraryItem::EditorAssetLibraryItem(bool p_clickable) { Ref<StyleBoxEmpty> border; border.instantiate(); border->set_content_margin_all(5 * EDSCALE); - add_theme_style_override("panel", border); + add_theme_style_override(SceneStringName(panel), border); HBoxContainer *hb = memnew(HBoxContainer); // Add some spacing to visually separate the icon from the asset details. @@ -181,7 +181,7 @@ EditorAssetLibraryItem::EditorAssetLibraryItem(bool p_clickable) { label_margin->set_content_margin_all(0); price = memnew(Label); - price->add_theme_style_override("normal", label_margin); + price->add_theme_style_override(CoreStringName(normal), label_margin); price->set_tooltip_text(TTR("License")); price->set_mouse_filter(MOUSE_FILTER_PASS); @@ -240,7 +240,7 @@ void EditorAssetLibraryItemDescription::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { - previews_bg->add_theme_style_override("panel", previews->get_theme_stylebox(CoreStringName(normal), SNAME("TextEdit"))); + previews_bg->add_theme_style_override(SceneStringName(panel), previews->get_theme_stylebox(CoreStringName(normal), SNAME("TextEdit"))); } break; } } @@ -456,7 +456,7 @@ void EditorAssetLibraryItemDownload::configure(const String &p_title, int p_asse void EditorAssetLibraryItemDownload::_notification(int p_what) { switch (p_what) { case NOTIFICATION_THEME_CHANGED: { - panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("AssetLib"))); + panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("AssetLib"))); status->add_theme_color_override("font_color", get_theme_color(SNAME("status_color"), SNAME("AssetLib"))); dismiss_button->set_texture_normal(get_theme_icon(SNAME("dismiss"), SNAME("AssetLib"))); } break; @@ -631,7 +631,7 @@ EditorAssetLibraryItemDownload::EditorAssetLibraryItemDownload() { void EditorAssetLibrary::_notification(int p_what) { switch (p_what) { case NOTIFICATION_READY: { - add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("AssetLib"))); + add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("bg"), SNAME("AssetLib"))); error_label->move_to_front(); } break; @@ -639,8 +639,8 @@ void EditorAssetLibrary::_notification(int p_what) { case NOTIFICATION_THEME_CHANGED: { error_tr->set_texture(get_editor_theme_icon(SNAME("Error"))); filter->set_right_icon(get_editor_theme_icon(SNAME("Search"))); - library_scroll_bg->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); - downloads_scroll->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); + library_scroll_bg->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree"))); + downloads_scroll->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree"))); error_label->add_theme_color_override("color", get_theme_color(SNAME("error_color"), EditorStringName(Editor))); } break; @@ -1679,7 +1679,7 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { support->get_popup()->add_check_item(TTRGET(support_text[SUPPORT_TESTING]), SUPPORT_TESTING); support->get_popup()->set_item_checked(SUPPORT_FEATURED, true); support->get_popup()->set_item_checked(SUPPORT_COMMUNITY, true); - support->get_popup()->connect("id_pressed", callable_mp(this, &EditorAssetLibrary::_support_toggled)); + support->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &EditorAssetLibrary::_support_toggled)); ///////// @@ -1698,7 +1698,7 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { PanelContainer *library_vb_border = memnew(PanelContainer); library_scroll->add_child(library_vb_border); - library_vb_border->add_theme_style_override("panel", border2); + library_vb_border->add_theme_style_override(SceneStringName(panel), border2); library_vb_border->set_h_size_flags(Control::SIZE_EXPAND_FILL); library_vb = memnew(VBoxContainer); diff --git a/editor/plugins/bit_map_editor_plugin.cpp b/editor/plugins/bit_map_editor_plugin.cpp index f1d86de537..668ea04d69 100644 --- a/editor/plugins/bit_map_editor_plugin.cpp +++ b/editor/plugins/bit_map_editor_plugin.cpp @@ -55,7 +55,7 @@ BitMapEditor::BitMapEditor() { Ref<StyleBoxEmpty> stylebox; stylebox.instantiate(); stylebox->set_content_margin(SIDE_RIGHT, 4 * EDSCALE); - size_label->add_theme_style_override("normal", stylebox); + size_label->add_theme_style_override(CoreStringName(normal), stylebox); } /////////////////////// diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index ee96de8f23..5c7d02dcfa 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -3058,6 +3058,7 @@ void CanvasItemEditor::_draw_ruler_tool() { return; } + const Ref<Texture2D> position_icon = get_editor_theme_icon(SNAME("EditorPosition")); if (ruler_tool_active) { Color ruler_primary_color = get_theme_color(SNAME("accent_color"), EditorStringName(Editor)); Color ruler_secondary_color = ruler_primary_color; @@ -3126,8 +3127,7 @@ void CanvasItemEditor::_draw_ruler_tool() { if (begin.is_equal_approx(end)) { viewport->draw_string_outline(font, text_pos, (String)ruler_tool_origin, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color); viewport->draw_string(font, text_pos, (String)ruler_tool_origin, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color); - Ref<Texture2D> position_icon = get_editor_theme_icon(SNAME("EditorPosition")); - viewport->draw_texture(get_editor_theme_icon(SNAME("EditorPosition")), (ruler_tool_origin - view_offset) * zoom - position_icon->get_size() / 2); + viewport->draw_texture(position_icon, (ruler_tool_origin - view_offset) * zoom - position_icon->get_size() / 2); return; } @@ -3198,7 +3198,6 @@ void CanvasItemEditor::_draw_ruler_tool() { } } else { if (grid_snap_active) { - Ref<Texture2D> position_icon = get_editor_theme_icon(SNAME("EditorPosition")); viewport->draw_texture(position_icon, (ruler_tool_origin - view_offset) * zoom - position_icon->get_size() / 2); } } @@ -3953,7 +3952,7 @@ void CanvasItemEditor::_update_editor_settings() { key_auto_insert_button->add_theme_color_override("icon_pressed_color", key_auto_color.lerp(Color(1, 0, 0), 0.55)); animation_menu->set_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl"))); - context_toolbar_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("ContextualToolbar"), EditorStringName(EditorStyles))); + context_toolbar_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("ContextualToolbar"), EditorStringName(EditorStyles))); panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/2d_editor_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EDITOR_GET("editors/panning/simple_panning"))); panner->set_scroll_speed(EDITOR_GET("editors/panning/2d_editor_pan_speed")); @@ -5389,7 +5388,7 @@ CanvasItemEditor::CanvasItemEditor() { snap_config_menu->set_switch_on_hover(true); PopupMenu *p = snap_config_menu->get_popup(); - p->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_popup_callback)); + p->connect(SceneStringName(id_pressed), callable_mp(this, &CanvasItemEditor::_popup_callback)); p->set_hide_on_checkable_item_selection(false); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/use_rotation_snap", TTR("Use Rotation Snap")), SNAP_USE_ROTATION); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/use_scale_snap", TTR("Use Scale Snap")), SNAP_USE_SCALE); @@ -5397,7 +5396,7 @@ CanvasItemEditor::CanvasItemEditor() { p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/use_pixel_snap", TTR("Use Pixel Snap")), SNAP_USE_PIXEL); smartsnap_config_popup = memnew(PopupMenu); - smartsnap_config_popup->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_popup_callback)); + smartsnap_config_popup->connect(SceneStringName(id_pressed), callable_mp(this, &CanvasItemEditor::_popup_callback)); smartsnap_config_popup->set_hide_on_checkable_item_selection(false); smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_parent", TTR("Snap to Parent")), SNAP_USE_NODE_PARENT); smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_anchors", TTR("Snap to Node Anchor")), SNAP_USE_NODE_ANCHORS); @@ -5460,7 +5459,7 @@ CanvasItemEditor::CanvasItemEditor() { p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_show_bones", TTR("Show Bones")), SKELETON_SHOW_BONES); p->add_separator(); p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_make_bones", TTR("Make Bone2D Node(s) from Node(s)"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::B), SKELETON_MAKE_BONES); - p->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_popup_callback)); + p->connect(SceneStringName(id_pressed), callable_mp(this, &CanvasItemEditor::_popup_callback)); main_menu_hbox->add_child(memnew(VSeparator)); @@ -5482,14 +5481,14 @@ CanvasItemEditor::CanvasItemEditor() { view_menu->set_switch_on_hover(true); view_menu->set_shortcut_context(this); main_menu_hbox->add_child(view_menu); - view_menu->get_popup()->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_popup_callback)); + view_menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &CanvasItemEditor::_popup_callback)); p = view_menu->get_popup(); p->set_hide_on_checkable_item_selection(false); grid_menu = memnew(PopupMenu); grid_menu->connect("about_to_popup", callable_mp(this, &CanvasItemEditor::_prepare_grid_menu)); - grid_menu->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_on_grid_menu_id_pressed)); + grid_menu->connect(SceneStringName(id_pressed), callable_mp(this, &CanvasItemEditor::_on_grid_menu_id_pressed)); grid_menu->add_radio_check_item(TTR("Show"), GRID_VISIBILITY_SHOW); grid_menu->add_radio_check_item(TTR("Show When Snapping"), GRID_VISIBILITY_SHOW_WHEN_SNAPPING); grid_menu->add_radio_check_item(TTR("Hide"), GRID_VISIBILITY_HIDE); @@ -5506,7 +5505,7 @@ CanvasItemEditor::CanvasItemEditor() { gizmos_menu = memnew(PopupMenu); gizmos_menu->set_name("GizmosMenu"); - gizmos_menu->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_popup_callback)); + gizmos_menu->connect(SceneStringName(id_pressed), callable_mp(this, &CanvasItemEditor::_popup_callback)); gizmos_menu->set_hide_on_checkable_item_selection(false); gizmos_menu->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_position_gizmos", TTR("Position")), SHOW_POSITION_GIZMOS); gizmos_menu->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_lock_gizmos", TTR("Lock")), SHOW_LOCK_GIZMOS); @@ -5523,7 +5522,7 @@ CanvasItemEditor::CanvasItemEditor() { p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/preview_canvas_scale", TTR("Preview Canvas Scale")), PREVIEW_CANVAS_SCALE); theme_menu = memnew(PopupMenu); - theme_menu->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_switch_theme_preview)); + theme_menu->connect(SceneStringName(id_pressed), callable_mp(this, &CanvasItemEditor::_switch_theme_preview)); theme_menu->add_radio_check_item(TTR("Project theme"), THEME_PREVIEW_PROJECT); theme_menu->add_radio_check_item(TTR("Editor theme"), THEME_PREVIEW_EDITOR); theme_menu->add_radio_check_item(TTR("Default theme"), THEME_PREVIEW_DEFAULT); @@ -5597,7 +5596,7 @@ CanvasItemEditor::CanvasItemEditor() { animation_menu->set_shortcut_context(this); animation_menu->set_tooltip_text(TTR("Animation Key and Pose Options")); animation_hb->add_child(animation_menu); - animation_menu->get_popup()->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_popup_callback)); + animation_menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &CanvasItemEditor::_popup_callback)); animation_menu->set_switch_on_hover(true); p = animation_menu->get_popup(); @@ -5619,12 +5618,12 @@ CanvasItemEditor::CanvasItemEditor() { add_child(selection_menu); selection_menu->set_min_size(Vector2(100, 0)); selection_menu->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); - selection_menu->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_selection_result_pressed)); + selection_menu->connect(SceneStringName(id_pressed), callable_mp(this, &CanvasItemEditor::_selection_result_pressed)); selection_menu->connect("popup_hide", callable_mp(this, &CanvasItemEditor::_selection_menu_hide), CONNECT_DEFERRED); add_node_menu = memnew(PopupMenu); add_child(add_node_menu); - add_node_menu->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_add_node_pressed)); + add_node_menu->connect(SceneStringName(id_pressed), callable_mp(this, &CanvasItemEditor::_add_node_pressed)); multiply_grid_step_shortcut = ED_SHORTCUT("canvas_item_editor/multiply_grid_step", TTR("Multiply grid step by 2"), Key::KP_MULTIPLY); divide_grid_step_shortcut = ED_SHORTCUT("canvas_item_editor/divide_grid_step", TTR("Divide grid step by 2"), Key::KP_DIVIDE); @@ -5638,7 +5637,7 @@ CanvasItemEditor::CanvasItemEditor() { clear(); // Make sure values are initialized. // Update the menus' checkboxes. - callable_mp(this, &CanvasItemEditor::set_state).bind(get_state()).call_deferred(); + callable_mp(this, &CanvasItemEditor::set_state).call_deferred(get_state()); } CanvasItemEditor *CanvasItemEditor::singleton = nullptr; diff --git a/editor/plugins/control_editor_plugin.cpp b/editor/plugins/control_editor_plugin.cpp index 1d5b0a832a..a3804eff00 100644 --- a/editor/plugins/control_editor_plugin.cpp +++ b/editor/plugins/control_editor_plugin.cpp @@ -65,7 +65,7 @@ void ControlPositioningWarning::_update_warning() { hint_label->set_text(TTR("Use anchors and the rectangle for positioning.")); } - bg_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg_group_note"), SNAME("EditorProperty"))); + bg_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("bg_group_note"), SNAME("EditorProperty"))); } void ControlPositioningWarning::_update_toggler() { diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp index 1d53a1b4d4..1c0d93248d 100644 --- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp @@ -251,7 +251,7 @@ void CPUParticles2DEditorPlugin::_generate_emission_mask() { void CPUParticles2DEditorPlugin::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { - menu->get_popup()->connect("id_pressed", callable_mp(this, &CPUParticles2DEditorPlugin::_menu_callback)); + menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &CPUParticles2DEditorPlugin::_menu_callback)); menu->set_icon(file->get_editor_theme_icon(SNAME("CPUParticles2D"))); file->connect("file_selected", callable_mp(this, &CPUParticles2DEditorPlugin::_file_selected)); } break; diff --git a/editor/plugins/cpu_particles_3d_editor_plugin.cpp b/editor/plugins/cpu_particles_3d_editor_plugin.cpp index baf70e45f0..a833c8c356 100644 --- a/editor/plugins/cpu_particles_3d_editor_plugin.cpp +++ b/editor/plugins/cpu_particles_3d_editor_plugin.cpp @@ -173,7 +173,7 @@ CPUParticles3DEditor::CPUParticles3DEditor() { options->get_popup()->add_item(TTR("Generate AABB"), MENU_OPTION_GENERATE_AABB); options->get_popup()->add_item(TTR("Create Emission Points From Node"), MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE); options->get_popup()->add_item(TTR("Convert to GPUParticles3D"), MENU_OPTION_CONVERT_TO_GPU_PARTICLES); - options->get_popup()->connect("id_pressed", callable_mp(this, &CPUParticles3DEditor::_menu_option)); + options->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &CPUParticles3DEditor::_menu_option)); generate_aabb = memnew(ConfirmationDialog); generate_aabb->set_title(TTR("Generate Visibility AABB")); diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp index ee9a2e99d9..278543dc36 100644 --- a/editor/plugins/curve_editor_plugin.cpp +++ b/editor/plugins/curve_editor_plugin.cpp @@ -788,7 +788,7 @@ void CurveEdit::_redraw() { // Draw background. Vector2 view_size = get_rect().size; - draw_style_box(get_theme_stylebox(SNAME("panel"), SNAME("Tree")), Rect2(Point2(), view_size)); + draw_style_box(get_theme_stylebox(SceneStringName(panel), SNAME("Tree")), Rect2(Point2(), view_size)); // Draw snapping grid, then primary grid. draw_set_transform_matrix(_world_to_view); @@ -1026,7 +1026,7 @@ CurveEditor::CurveEditor() { presets_button->set_switch_on_hover(true); presets_button->set_h_size_flags(SIZE_EXPAND | SIZE_SHRINK_END); toolbar->add_child(presets_button); - presets_button->get_popup()->connect("id_pressed", callable_mp(this, &CurveEditor::_on_preset_item_selected)); + presets_button->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &CurveEditor::_on_preset_item_selected)); curve_editor_rect = memnew(CurveEdit); add_child(curve_editor_rect); diff --git a/editor/plugins/debugger_editor_plugin.cpp b/editor/plugins/debugger_editor_plugin.cpp index 53cb76f133..55416ab4eb 100644 --- a/editor/plugins/debugger_editor_plugin.cpp +++ b/editor/plugins/debugger_editor_plugin.cpp @@ -99,7 +99,7 @@ DebuggerEditorPlugin::DebuggerEditorPlugin(PopupMenu *p_debug_menu) { // Multi-instance, start/stop. debug_menu->add_separator(); debug_menu->add_item(TTR("Customize Run Instances..."), RUN_MULTIPLE_INSTANCES); - debug_menu->connect("id_pressed", callable_mp(this, &DebuggerEditorPlugin::_menu_option)); + debug_menu->connect(SceneStringName(id_pressed), callable_mp(this, &DebuggerEditorPlugin::_menu_option)); run_instances_dialog = memnew(RunInstancesDialog); EditorNode::get_singleton()->get_gui_base()->add_child(run_instances_dialog); diff --git a/editor/plugins/font_config_plugin.cpp b/editor/plugins/font_config_plugin.cpp index 1b104f9075..6d1e102808 100644 --- a/editor/plugins/font_config_plugin.cpp +++ b/editor/plugins/font_config_plugin.cpp @@ -372,7 +372,7 @@ EditorPropertyFontMetaOverride::EditorPropertyFontMetaOverride(bool p_script) { } } add_child(menu); - menu->connect("id_pressed", callable_mp(this, &EditorPropertyFontMetaOverride::_add_script)); + menu->connect(SceneStringName(id_pressed), callable_mp(this, &EditorPropertyFontMetaOverride::_add_script)); locale_select = memnew(EditorLocaleDialog); locale_select->connect("locale_selected", callable_mp(this, &EditorPropertyFontMetaOverride::_add_lang)); @@ -840,12 +840,12 @@ EditorPropertyOTFeatures::EditorPropertyOTFeatures() { menu = memnew(PopupMenu); add_child(menu); - menu->connect("id_pressed", callable_mp(this, &EditorPropertyOTFeatures::_add_feature)); + menu->connect(SceneStringName(id_pressed), callable_mp(this, &EditorPropertyOTFeatures::_add_feature)); for (int i = 0; i < FGRP_MAX; i++) { menu_sub[i] = memnew(PopupMenu); menu->add_child(menu_sub[i]); - menu_sub[i]->connect("id_pressed", callable_mp(this, &EditorPropertyOTFeatures::_add_feature)); + menu_sub[i]->connect(SceneStringName(id_pressed), callable_mp(this, &EditorPropertyOTFeatures::_add_feature)); } group_names[FGRP_STYLISTIC_SET] = TTRC("Stylistic Sets"); @@ -1018,7 +1018,7 @@ EditorPropertyFontNamesArray::EditorPropertyFontNamesArray() { } } add_child(menu); - menu->connect("id_pressed", callable_mp(this, &EditorPropertyFontNamesArray::_add_font)); + menu->connect(SceneStringName(id_pressed), callable_mp(this, &EditorPropertyFontNamesArray::_add_font)); } /*************************************************************************/ diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.cpp b/editor/plugins/gpu_particles_2d_editor_plugin.cpp index 328b272562..ba28305cf0 100644 --- a/editor/plugins/gpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_2d_editor_plugin.cpp @@ -352,7 +352,7 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() { void GPUParticles2DEditorPlugin::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { - menu->get_popup()->connect("id_pressed", callable_mp(this, &GPUParticles2DEditorPlugin::_menu_callback)); + menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &GPUParticles2DEditorPlugin::_menu_callback)); menu->set_icon(menu->get_editor_theme_icon(SNAME("GPUParticles2D"))); file->connect("file_selected", callable_mp(this, &GPUParticles2DEditorPlugin::_file_selected)); EditorNode::get_singleton()->get_editor_selection()->connect("selection_changed", callable_mp(this, &GPUParticles2DEditorPlugin::_selection_changed)); diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp index 9063109ece..b682ec1de6 100644 --- a/editor/plugins/gpu_particles_3d_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp @@ -420,7 +420,7 @@ GPUParticles3DEditor::GPUParticles3DEditor() { options->get_popup()->add_item(TTR("Create Emission Points From Node"), MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE); options->get_popup()->add_item(TTR("Convert to CPUParticles3D"), MENU_OPTION_CONVERT_TO_CPU_PARTICLES); - options->get_popup()->connect("id_pressed", callable_mp(this, &GPUParticles3DEditor::_menu_option)); + options->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &GPUParticles3DEditor::_menu_option)); generate_aabb = memnew(ConfirmationDialog); generate_aabb->set_title(TTR("Generate Visibility AABB")); diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp index 4d1b31a8dc..6eae3b975a 100644 --- a/editor/plugins/mesh_instance_3d_editor_plugin.cpp +++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp @@ -540,7 +540,7 @@ MeshInstance3DEditor::MeshInstance3DEditor() { options->get_popup()->add_item(TTR("View UV2"), MENU_OPTION_DEBUG_UV2); options->get_popup()->add_item(TTR("Unwrap UV2 for Lightmap/AO"), MENU_OPTION_CREATE_UV2); - options->get_popup()->connect("id_pressed", callable_mp(this, &MeshInstance3DEditor::_menu_option)); + options->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &MeshInstance3DEditor::_menu_option)); outline_dialog = memnew(ConfirmationDialog); outline_dialog->set_title(TTR("Create Outline Mesh")); diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp index 950aced7a1..0b2549986c 100644 --- a/editor/plugins/mesh_library_editor_plugin.cpp +++ b/editor/plugins/mesh_library_editor_plugin.cpp @@ -271,7 +271,7 @@ MeshLibraryEditor::MeshLibraryEditor() { menu->get_popup()->add_item(TTR("Import from Scene (Apply Transforms)"), MENU_OPTION_IMPORT_FROM_SCENE_APPLY_XFORMS); menu->get_popup()->add_item(TTR("Update from Scene"), MENU_OPTION_UPDATE_FROM_SCENE); menu->get_popup()->set_item_disabled(menu->get_popup()->get_item_index(MENU_OPTION_UPDATE_FROM_SCENE), true); - menu->get_popup()->connect("id_pressed", callable_mp(this, &MeshLibraryEditor::_menu_cbk)); + menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &MeshLibraryEditor::_menu_cbk)); menu->hide(); cd_remove = memnew(ConfirmationDialog); diff --git a/editor/plugins/multimesh_editor_plugin.cpp b/editor/plugins/multimesh_editor_plugin.cpp index ffe46d5daa..3980f23c8a 100644 --- a/editor/plugins/multimesh_editor_plugin.cpp +++ b/editor/plugins/multimesh_editor_plugin.cpp @@ -278,7 +278,7 @@ MultiMeshEditor::MultiMeshEditor() { options->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("MultiMeshInstance3D"), EditorStringName(EditorIcons))); options->get_popup()->add_item(TTR("Populate Surface")); - options->get_popup()->connect("id_pressed", callable_mp(this, &MultiMeshEditor::_menu_option)); + options->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &MultiMeshEditor::_menu_option)); populate_dialog = memnew(ConfirmationDialog); populate_dialog->set_title(TTR("Populate MultiMesh")); diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index d211bd8588..295167eea2 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -739,9 +739,21 @@ void Node3DEditorViewport::_select_clicked(bool p_allow_locked) { return; } + Node *edited_scene = EditorNode::get_singleton()->get_edited_scene(); + + // Prevent selection of nodes not owned by the edited scene. + while (node && node != edited_scene->get_parent()) { + Node *node_owner = node->get_owner(); + if (node_owner == edited_scene || node == edited_scene || (node_owner != nullptr && edited_scene->is_editable_instance(node_owner))) { + break; + } + node = node->get_parent(); + selected = Object::cast_to<Node3D>(node); + } + if (!p_allow_locked) { // Replace the node by the group if grouped - while (node && node != EditorNode::get_singleton()->get_edited_scene()->get_parent()) { + while (node && node != edited_scene->get_parent()) { Node3D *selected_tmp = Object::cast_to<Node3D>(node); if (selected_tmp && node->has_meta("_edit_group_")) { selected = selected_tmp; @@ -1044,25 +1056,34 @@ void Node3DEditorViewport::_select_region() { found_nodes.insert(sp); - Node *item = Object::cast_to<Node>(sp); - if (item != edited_scene) { - item = edited_scene->get_deepest_editable_node(item); + Node *node = Object::cast_to<Node>(sp); + if (node != edited_scene) { + node = edited_scene->get_deepest_editable_node(node); + } + + // Prevent selection of nodes not owned by the edited scene. + while (node && node != edited_scene->get_parent()) { + Node *node_owner = node->get_owner(); + if (node_owner == edited_scene || node == edited_scene || (node_owner != nullptr && edited_scene->is_editable_instance(node_owner))) { + break; + } + node = node->get_parent(); } // Replace the node by the group if grouped - if (item->is_class("Node3D")) { - Node3D *sel = Object::cast_to<Node3D>(item); - while (item && item != EditorNode::get_singleton()->get_edited_scene()->get_parent()) { - Node3D *selected_tmp = Object::cast_to<Node3D>(item); - if (selected_tmp && item->has_meta("_edit_group_")) { + if (node->is_class("Node3D")) { + Node3D *sel = Object::cast_to<Node3D>(node); + while (node && node != EditorNode::get_singleton()->get_edited_scene()->get_parent()) { + Node3D *selected_tmp = Object::cast_to<Node3D>(node); + if (selected_tmp && node->has_meta("_edit_group_")) { sel = selected_tmp; } - item = item->get_parent(); + node = node->get_parent(); } - item = sel; + node = sel; } - if (_is_node_locked(item)) { + if (_is_node_locked(node)) { continue; } @@ -1074,7 +1095,7 @@ void Node3DEditorViewport::_select_region() { } if (seg->intersect_frustum(camera, frustum)) { - selected.push_back(item); + selected.push_back(node); } } } @@ -1531,23 +1552,35 @@ bool Node3DEditorViewport ::_is_node_locked(const Node *p_node) { } void Node3DEditorViewport::_list_select(Ref<InputEventMouseButton> b) { - _find_items_at_pos(b->get_position(), selection_results, spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT); + Vector<_RayResult> potential_selection_results; + _find_items_at_pos(b->get_position(), potential_selection_results, spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT); - Node *scene = EditorNode::get_singleton()->get_edited_scene(); + Node *edited_scene = EditorNode::get_singleton()->get_edited_scene(); - for (int i = 0; i < selection_results.size(); i++) { - Node3D *item = selection_results[i].item; - if (item != scene && item->get_owner() != scene && item != scene->get_deepest_editable_node(item)) { - //invalid result - selection_results.remove_at(i); - i--; + // Filter to a list of nodes which include either the edited scene or nodes directly owned by the edited scene. + // If a node has an invalid owner, recursively check their parents until a valid node is found. + for (int i = 0; i < potential_selection_results.size(); i++) { + Node3D *node = potential_selection_results[i].item; + while (true) { + if (node == nullptr || node == edited_scene->get_parent()) { + break; + } else { + Node *node_owner = node->get_owner(); + if (node == edited_scene || node_owner == edited_scene || (node_owner != nullptr && edited_scene->is_editable_instance(node_owner))) { + if (selection_results.has(node)) { + selection_results.append(node); + } + break; + } + } + node = Object::cast_to<Node3D>(node->get_parent()); } } clicked_wants_append = b->is_shift_pressed(); if (selection_results.size() == 1) { - clicked = selection_results[0].item->get_instance_id(); + clicked = selection_results[0]->get_instance_id(); selection_results.clear(); if (clicked.is_valid()) { @@ -1558,7 +1591,7 @@ void Node3DEditorViewport::_list_select(Ref<InputEventMouseButton> b) { StringName root_name = root_path.get_name(root_path.get_name_count() - 1); for (int i = 0; i < selection_results.size(); i++) { - Node3D *spat = selection_results[i].item; + Node3D *spat = selection_results[i]; Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(spat, "Node"); @@ -3011,7 +3044,7 @@ void Node3DEditorViewport::_notification(int p_what) { Control *gui_base = EditorNode::get_singleton()->get_gui_base(); view_menu->begin_bulk_theme_override(); - view_menu->add_theme_style_override("normal", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); + view_menu->add_theme_style_override(CoreStringName(normal), gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); view_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); view_menu->add_theme_style_override(SceneStringName(pressed), gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); view_menu->add_theme_style_override("focus", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); @@ -3019,7 +3052,7 @@ void Node3DEditorViewport::_notification(int p_what) { view_menu->end_bulk_theme_override(); preview_camera->begin_bulk_theme_override(); - preview_camera->add_theme_style_override("normal", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); + preview_camera->add_theme_style_override(CoreStringName(normal), gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); preview_camera->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); preview_camera->add_theme_style_override(SceneStringName(pressed), gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); preview_camera->add_theme_style_override("focus", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); @@ -3030,9 +3063,9 @@ void Node3DEditorViewport::_notification(int p_what) { frame_time_gradient->set_color(1, get_theme_color(SNAME("warning_color"), EditorStringName(Editor))); frame_time_gradient->set_color(2, get_theme_color(SNAME("error_color"), EditorStringName(Editor))); - info_label->add_theme_style_override("normal", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); + info_label->add_theme_style_override(CoreStringName(normal), gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); - frame_time_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); + frame_time_panel->add_theme_style_override(SceneStringName(panel), gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); // Set a minimum width to prevent the width from changing all the time // when numbers vary rapidly. This minimum width is set based on a // GPU time of 999.99 ms in the current editor language. @@ -3040,8 +3073,8 @@ void Node3DEditorViewport::_notification(int p_what) { frame_time_panel->set_custom_minimum_size(Size2(min_width, 0) * EDSCALE); frame_time_vbox->add_theme_constant_override("separation", Math::round(-1 * EDSCALE)); - cinema_label->add_theme_style_override("normal", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); - locked_label->add_theme_style_override("normal", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); + cinema_label->add_theme_style_override(CoreStringName(normal), gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); + locked_label->add_theme_style_override(CoreStringName(normal), gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); } break; case NOTIFICATION_DRAG_END: { @@ -3754,7 +3787,7 @@ void Node3DEditorViewport::_selection_result_pressed(int p_result) { return; } - clicked = selection_results_menu[p_result].item->get_instance_id(); + clicked = selection_results_menu[p_result]->get_instance_id(); if (clicked.is_valid()) { _select_clicked(spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT); @@ -5261,8 +5294,8 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/focus_selection"), VIEW_CENTER_TO_SELECTION); view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/align_transform_with_view"), VIEW_ALIGN_TRANSFORM_WITH_VIEW); view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/align_rotation_with_view"), VIEW_ALIGN_ROTATION_WITH_VIEW); - view_menu->get_popup()->connect("id_pressed", callable_mp(this, &Node3DEditorViewport::_menu_option)); - display_submenu->connect("id_pressed", callable_mp(this, &Node3DEditorViewport::_menu_option)); + view_menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &Node3DEditorViewport::_menu_option)); + display_submenu->connect(SceneStringName(id_pressed), callable_mp(this, &Node3DEditorViewport::_menu_option)); view_menu->set_disable_shortcuts(true); // TODO: Re-evaluate with new OpenGL3 renderer, and implement. @@ -5441,7 +5474,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p selection_menu = memnew(PopupMenu); add_child(selection_menu); selection_menu->set_min_size(Size2(100, 0) * EDSCALE); - selection_menu->connect("id_pressed", callable_mp(this, &Node3DEditorViewport::_selection_result_pressed)); + selection_menu->connect(SceneStringName(id_pressed), callable_mp(this, &Node3DEditorViewport::_selection_result_pressed)); selection_menu->connect("popup_hide", callable_mp(this, &Node3DEditorViewport::_selection_menu_hide)); if (p_index == 0) { @@ -7776,7 +7809,7 @@ void Node3DEditor::_update_theme() { environ_sky_color->set_custom_minimum_size(Size2(0, get_theme_constant(SNAME("color_picker_button_height"), EditorStringName(Editor)))); environ_ground_color->set_custom_minimum_size(Size2(0, get_theme_constant(SNAME("color_picker_button_height"), EditorStringName(Editor)))); - context_toolbar_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("ContextualToolbar"), EditorStringName(EditorStyles))); + context_toolbar_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("ContextualToolbar"), EditorStringName(EditorStyles))); } void Node3DEditor::_notification(int p_what) { @@ -8607,7 +8640,7 @@ Node3DEditor::Node3DEditor() { p->add_separator(); p->add_shortcut(ED_SHORTCUT("spatial_editor/configure_snap", TTR("Configure Snap...")), MENU_TRANSFORM_CONFIGURE_SNAP); - p->connect("id_pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed)); + p->connect(SceneStringName(id_pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed)); view_menu = memnew(MenuButton); view_menu->set_flat(false); @@ -8643,7 +8676,7 @@ Node3DEditor::Node3DEditor() { gizmos_menu = memnew(PopupMenu); gizmos_menu->set_hide_on_checkable_item_selection(false); p->add_submenu_node_item(TTR("Gizmos"), gizmos_menu); - gizmos_menu->connect("id_pressed", callable_mp(this, &Node3DEditor::_menu_gizmo_toggled)); + gizmos_menu->connect(SceneStringName(id_pressed), callable_mp(this, &Node3DEditor::_menu_gizmo_toggled)); p->add_separator(); p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_origin", TTR("View Origin")), MENU_VIEW_ORIGIN); @@ -8655,7 +8688,7 @@ Node3DEditor::Node3DEditor() { p->set_item_checked(p->get_item_index(MENU_VIEW_ORIGIN), true); p->set_item_checked(p->get_item_index(MENU_VIEW_GRID), true); - p->connect("id_pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed)); + p->connect(SceneStringName(id_pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed)); /* REST OF MENU */ diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index ebdf951773..859d075732 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -298,8 +298,8 @@ private: ObjectID clicked; ObjectID material_target; - Vector<_RayResult> selection_results; - Vector<_RayResult> selection_results_menu; + Vector<Node3D *> selection_results; + Vector<Node3D *> selection_results_menu; bool clicked_wants_append = false; bool selection_in_progress = false; diff --git a/editor/plugins/parallax_background_editor_plugin.cpp b/editor/plugins/parallax_background_editor_plugin.cpp index e14a81778e..6c55fd2753 100644 --- a/editor/plugins/parallax_background_editor_plugin.cpp +++ b/editor/plugins/parallax_background_editor_plugin.cpp @@ -118,7 +118,7 @@ void ParallaxBackgroundEditorPlugin::convert_to_parallax2d() { void ParallaxBackgroundEditorPlugin::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { - menu->get_popup()->connect("id_pressed", callable_mp(this, &ParallaxBackgroundEditorPlugin::_menu_callback)); + menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &ParallaxBackgroundEditorPlugin::_menu_callback)); menu->set_icon(menu->get_editor_theme_icon(SNAME("ParallaxBackground"))); } break; } diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp index f404dca88b..a5717c3bb3 100644 --- a/editor/plugins/path_2d_editor_plugin.cpp +++ b/editor/plugins/path_2d_editor_plugin.cpp @@ -672,7 +672,7 @@ Path2DEditor::Path2DEditor() { menu->set_item_checked(HANDLE_OPTION_ANGLE, mirror_handle_angle); menu->add_check_item(TTR("Mirror Handle Lengths")); menu->set_item_checked(HANDLE_OPTION_LENGTH, mirror_handle_length); - menu->connect("id_pressed", callable_mp(this, &Path2DEditor::_handle_option_pressed)); + menu->connect(SceneStringName(id_pressed), callable_mp(this, &Path2DEditor::_handle_option_pressed)); } void Path2DEditorPlugin::edit(Object *p_object) { diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp index 3f5ade8a03..447e82f70d 100644 --- a/editor/plugins/path_3d_editor_plugin.cpp +++ b/editor/plugins/path_3d_editor_plugin.cpp @@ -896,7 +896,7 @@ Path3DEditorPlugin::Path3DEditorPlugin() { menu->set_item_checked(HANDLE_OPTION_ANGLE, mirror_handle_angle); menu->add_check_item(TTR("Mirror Handle Lengths")); menu->set_item_checked(HANDLE_OPTION_LENGTH, mirror_handle_length); - menu->connect("id_pressed", callable_mp(this, &Path3DEditorPlugin::_handle_option_pressed)); + menu->connect(SceneStringName(id_pressed), callable_mp(this, &Path3DEditorPlugin::_handle_option_pressed)); curve_edit->set_pressed(true); } diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index 8bffbeaf15..61bd21db67 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -113,8 +113,8 @@ void Polygon2DEditor::_notification(int p_what) { [[fallthrough]]; } case NOTIFICATION_THEME_CHANGED: { - uv_edit_draw->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); - bone_scroll->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); + uv_edit_draw->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree"))); + bone_scroll->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree"))); } break; case NOTIFICATION_VISIBILITY_CHANGED: { @@ -1434,7 +1434,7 @@ Polygon2DEditor::Polygon2DEditor() { uv_menu->get_popup()->add_item(TTR("Clear UV"), UVEDIT_UV_CLEAR); uv_menu->get_popup()->add_separator(); uv_menu->get_popup()->add_item(TTR("Grid Settings"), UVEDIT_GRID_SETTINGS); - uv_menu->get_popup()->connect("id_pressed", callable_mp(this, &Polygon2DEditor::_menu_option)); + uv_menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &Polygon2DEditor::_menu_option)); uv_mode_hb->add_child(memnew(VSeparator)); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 22dbb6e9f2..334b253316 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -1008,6 +1008,10 @@ void ScriptEditor::_resave_scripts(const String &p_str) { se->trim_trailing_whitespace(); } + if (trim_final_newlines_on_save) { + se->trim_final_newlines(); + } + se->insert_final_newline(); if (convert_indent_on_save) { @@ -1402,6 +1406,10 @@ void ScriptEditor::_menu_option(int p_option) { current->trim_trailing_whitespace(); } + if (trim_final_newlines_on_save) { + current->trim_final_newlines(); + } + current->insert_final_newline(); if (convert_indent_on_save) { @@ -1711,7 +1719,7 @@ void ScriptEditor::_notification(int p_what) { case NOTIFICATION_TRANSLATION_CHANGED: case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: case NOTIFICATION_THEME_CHANGED: { - tab_container->add_theme_style_override("panel", get_theme_stylebox(SNAME("ScriptEditor"), EditorStringName(EditorStyles))); + tab_container->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("ScriptEditor"), EditorStringName(EditorStyles))); help_search->set_icon(get_editor_theme_icon(SNAME("HelpSearch"))); site_search->set_icon(get_editor_theme_icon(SNAME("ExternalLink"))); @@ -1729,7 +1737,7 @@ void ScriptEditor::_notification(int p_what) { filter_scripts->set_right_icon(get_editor_theme_icon(SNAME("Search"))); filter_methods->set_right_icon(get_editor_theme_icon(SNAME("Search"))); - filename->add_theme_style_override("normal", get_theme_stylebox(CoreStringName(normal), SNAME("LineEdit"))); + filename->add_theme_style_override(CoreStringName(normal), get_theme_stylebox(CoreStringName(normal), SNAME("LineEdit"))); recent_scripts->reset_size(); @@ -1740,7 +1748,7 @@ void ScriptEditor::_notification(int p_what) { case NOTIFICATION_READY: { // Can't set own styles in NOTIFICATION_THEME_CHANGED, so for now this will do. - add_theme_style_override("panel", get_theme_stylebox(SNAME("ScriptEditorPanel"), EditorStringName(EditorStyles))); + add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("ScriptEditorPanel"), EditorStringName(EditorStyles))); get_tree()->connect("tree_changed", callable_mp(this, &ScriptEditor::_tree_changed)); InspectorDock::get_singleton()->connect("request_help", callable_mp(this, &ScriptEditor::_help_class_open)); @@ -2602,6 +2610,10 @@ void ScriptEditor::save_current_script() { current->trim_trailing_whitespace(); } + if (trim_final_newlines_on_save) { + current->trim_final_newlines(); + } + current->insert_final_newline(); if (convert_indent_on_save) { @@ -2646,6 +2658,10 @@ void ScriptEditor::save_all_scripts() { se->trim_trailing_whitespace(); } + if (trim_final_newlines_on_save) { + se->trim_final_newlines(); + } + se->insert_final_newline(); if (!se->is_unsaved()) { @@ -2883,6 +2899,7 @@ void ScriptEditor::_apply_editor_settings() { } trim_trailing_whitespace_on_save = EDITOR_GET("text_editor/behavior/files/trim_trailing_whitespace_on_save"); + trim_final_newlines_on_save = EDITOR_GET("text_editor/behavior/files/trim_final_newlines_on_save"); convert_indent_on_save = EDITOR_GET("text_editor/behavior/files/convert_indent_on_save"); members_overview_enabled = EDITOR_GET("text_editor/script_list/show_members_overview"); @@ -4021,7 +4038,7 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) { context_menu = memnew(PopupMenu); add_child(context_menu); - context_menu->connect("id_pressed", callable_mp(this, &ScriptEditor::_menu_option)); + context_menu->connect(SceneStringName(id_pressed), callable_mp(this, &ScriptEditor::_menu_option)); overview_vbox = memnew(VBoxContainer); overview_vbox->set_custom_minimum_size(Size2(0, 90)); @@ -4035,7 +4052,7 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) { filename = memnew(Label); filename->set_clip_text(true); filename->set_h_size_flags(SIZE_EXPAND_FILL); - filename->add_theme_style_override("normal", EditorNode::get_singleton()->get_editor_theme()->get_stylebox(CoreStringName(normal), SNAME("LineEdit"))); + filename->add_theme_style_override(CoreStringName(normal), EditorNode::get_singleton()->get_editor_theme()->get_stylebox(CoreStringName(normal), SNAME("LineEdit"))); buttons_hbox->add_child(filename); members_overview_alphabeta_sort_button = memnew(Button); @@ -4105,7 +4122,7 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) { recent_scripts = memnew(PopupMenu); file_menu->get_popup()->add_submenu_node_item(TTR("Open Recent"), recent_scripts, FILE_OPEN_RECENT); - recent_scripts->connect("id_pressed", callable_mp(this, &ScriptEditor::_open_recent_script)); + recent_scripts->connect(SceneStringName(id_pressed), callable_mp(this, &ScriptEditor::_open_recent_script)); _update_recent_scripts(); @@ -4131,7 +4148,7 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) { theme_submenu->add_shortcut(ED_SHORTCUT("script_editor/import_theme", TTR("Import Theme...")), THEME_IMPORT); theme_submenu->add_shortcut(ED_SHORTCUT("script_editor/reload_theme", TTR("Reload Theme")), THEME_RELOAD); file_menu->get_popup()->add_submenu_node_item(TTR("Theme"), theme_submenu, FILE_THEME); - theme_submenu->connect("id_pressed", callable_mp(this, &ScriptEditor::_theme_option)); + theme_submenu->connect(SceneStringName(id_pressed), callable_mp(this, &ScriptEditor::_theme_option)); theme_submenu->add_separator(); theme_submenu->add_shortcut(ED_SHORTCUT("script_editor/save_theme", TTR("Save Theme")), THEME_SAVE); @@ -4148,7 +4165,7 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) { file_menu->get_popup()->add_separator(); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/toggle_scripts_panel", TTR("Toggle Scripts Panel"), KeyModifierMask::CMD_OR_CTRL | Key::BACKSLASH), TOGGLE_SCRIPTS_PANEL); - file_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptEditor::_menu_option)); + file_menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &ScriptEditor::_menu_option)); file_menu->get_popup()->connect("about_to_popup", callable_mp(this, &ScriptEditor::_prepare_file_menu)); file_menu->get_popup()->connect("popup_hide", callable_mp(this, &ScriptEditor::_file_menu_closed)); @@ -4156,7 +4173,7 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) { script_search_menu->set_text(TTR("Search")); script_search_menu->set_switch_on_hover(true); script_search_menu->set_shortcut_context(this); - script_search_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptEditor::_menu_option)); + script_search_menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &ScriptEditor::_menu_option)); menu_hb->add_child(script_search_menu); MenuButton *debug_menu_btn = memnew(MenuButton); @@ -4249,12 +4266,18 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) { disk_changed = memnew(ConfirmationDialog); { + disk_changed->set_title(TTR("Files have been modified on disk")); + VBoxContainer *vbc = memnew(VBoxContainer); disk_changed->add_child(vbc); - Label *dl = memnew(Label); - dl->set_text(TTR("The following files are newer on disk.\nWhat action should be taken?:")); - vbc->add_child(dl); + Label *files_are_newer_label = memnew(Label); + files_are_newer_label->set_text(TTR("The following files are newer on disk.")); + vbc->add_child(files_are_newer_label); + + Label *what_action_label = memnew(Label); + what_action_label->set_text(TTR("What action should be taken?:")); + vbc->add_child(what_action_label); disk_changed_list = memnew(Tree); vbc->add_child(disk_changed_list); @@ -4262,9 +4285,9 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) { disk_changed_list->set_v_size_flags(SIZE_EXPAND_FILL); disk_changed->connect("confirmed", callable_mp(this, &ScriptEditor::reload_scripts).bind(false)); - disk_changed->set_ok_button_text(TTR("Reload")); + disk_changed->set_ok_button_text(TTR("Discard local changes and reload")); - disk_changed->add_button(TTR("Resave"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "resave"); + disk_changed->add_button(TTR("Keep local changes and overwrite"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "resave"); disk_changed->connect("custom_action", callable_mp(this, &ScriptEditor::_resave_scripts)); } @@ -4301,6 +4324,7 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) { edit_pass = 0; trim_trailing_whitespace_on_save = EDITOR_GET("text_editor/behavior/files/trim_trailing_whitespace_on_save"); + trim_final_newlines_on_save = EDITOR_GET("text_editor/behavior/files/trim_final_newlines_on_save"); convert_indent_on_save = EDITOR_GET("text_editor/behavior/files/convert_indent_on_save"); ScriptServer::edit_request_func = _open_script_request; @@ -4332,9 +4356,9 @@ void ScriptEditorPlugin::_save_last_editor(const String &p_editor) { void ScriptEditorPlugin::_window_visibility_changed(bool p_visible) { _focus_another_editor(); if (p_visible) { - script_editor->add_theme_style_override("panel", script_editor->get_theme_stylebox("ScriptEditorPanelFloating", EditorStringName(EditorStyles))); + script_editor->add_theme_style_override(SceneStringName(panel), script_editor->get_theme_stylebox("ScriptEditorPanelFloating", EditorStringName(EditorStyles))); } else { - script_editor->add_theme_style_override("panel", script_editor->get_theme_stylebox("ScriptEditorPanel", EditorStringName(EditorStyles))); + script_editor->add_theme_style_override(SceneStringName(panel), script_editor->get_theme_stylebox("ScriptEditorPanel", EditorStringName(EditorStyles))); } } diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index 6f8e71ce75..9db1aff76a 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -174,6 +174,7 @@ public: virtual void set_executing_line(int p_line) = 0; virtual void clear_executing_line() = 0; virtual void trim_trailing_whitespace() = 0; + virtual void trim_final_newlines() = 0; virtual void insert_final_newline() = 0; virtual void convert_indent() = 0; virtual void ensure_focus() = 0; @@ -408,6 +409,7 @@ class ScriptEditor : public PanelContainer { bool open_textfile_after_create = true; bool trim_trailing_whitespace_on_save; + bool trim_final_newlines_on_save; bool convert_indent_on_save; bool external_editor_active; diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index a5d89ff54c..059e177874 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -431,6 +431,10 @@ void ScriptTextEditor::trim_trailing_whitespace() { code_editor->trim_trailing_whitespace(); } +void ScriptTextEditor::trim_final_newlines() { + code_editor->trim_final_newlines(); +} + void ScriptTextEditor::insert_final_newline() { code_editor->insert_final_newline(); } @@ -1427,6 +1431,9 @@ void ScriptTextEditor::_edit_option(int p_op) { case EDIT_TRIM_TRAILING_WHITESAPCE: { trim_trailing_whitespace(); } break; + case EDIT_TRIM_FINAL_NEWLINES: { + trim_final_newlines(); + } break; case EDIT_CONVERT_INDENT_TO_SPACES: { code_editor->set_indent_using_spaces(true); convert_indent(); @@ -1862,6 +1869,11 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data if (drop_modifier_pressed && ResourceLoader::exists(path)) { Ref<Resource> resource = ResourceLoader::load(path); + if (resource.is_null()) { + // Resource exists, but failed to load. We need only path and name, so we can use a dummy Resource instead. + resource.instantiate(); + resource->set_path_cache(path); + } text_to_drop += _get_dropped_resource_line(resource, is_empty_line); } else { text_to_drop += _quote_drop_data(path); @@ -2242,7 +2254,7 @@ void ScriptTextEditor::_enable_code_editor() { errors_panel->connect("meta_clicked", callable_mp(this, &ScriptTextEditor::_error_clicked)); add_child(context_menu); - context_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option)); + context_menu->connect(SceneStringName(id_pressed), callable_mp(this, &ScriptTextEditor::_edit_option)); add_child(color_panel); @@ -2285,7 +2297,7 @@ void ScriptTextEditor::_enable_code_editor() { sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unindent"), EDIT_UNINDENT); sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/delete_line"), EDIT_DELETE_LINE); sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT); - sub_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option)); + sub_menu->connect(SceneStringName(id_pressed), callable_mp(this, &ScriptTextEditor::_edit_option)); edit_menu->get_popup()->add_submenu_node_item(TTR("Line"), sub_menu); } { @@ -2294,32 +2306,33 @@ void ScriptTextEditor::_enable_code_editor() { sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_all_lines"), EDIT_FOLD_ALL_LINES); sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_all_lines"), EDIT_UNFOLD_ALL_LINES); sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/create_code_region"), EDIT_CREATE_CODE_REGION); - sub_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option)); + sub_menu->connect(SceneStringName(id_pressed), callable_mp(this, &ScriptTextEditor::_edit_option)); edit_menu->get_popup()->add_submenu_node_item(TTR("Folding"), sub_menu); } edit_menu->get_popup()->add_separator(); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_text_completion_query"), EDIT_COMPLETE); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/trim_trailing_whitespace"), EDIT_TRIM_TRAILING_WHITESAPCE); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/trim_final_newlines"), EDIT_TRIM_FINAL_NEWLINES); { PopupMenu *sub_menu = memnew(PopupMenu); sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_spaces"), EDIT_CONVERT_INDENT_TO_SPACES); sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_tabs"), EDIT_CONVERT_INDENT_TO_TABS); sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/auto_indent"), EDIT_AUTO_INDENT); - sub_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option)); + sub_menu->connect(SceneStringName(id_pressed), callable_mp(this, &ScriptTextEditor::_edit_option)); edit_menu->get_popup()->add_submenu_node_item(TTR("Indentation"), sub_menu); } - edit_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option)); + edit_menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &ScriptTextEditor::_edit_option)); edit_menu->get_popup()->add_separator(); { PopupMenu *sub_menu = memnew(PopupMenu); sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_to_uppercase"), EDIT_TO_UPPERCASE); sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_to_lowercase"), EDIT_TO_LOWERCASE); sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/capitalize"), EDIT_CAPITALIZE); - sub_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option)); + sub_menu->connect(SceneStringName(id_pressed), callable_mp(this, &ScriptTextEditor::_edit_option)); edit_menu->get_popup()->add_submenu_node_item(TTR("Convert Case"), sub_menu); } edit_menu->get_popup()->add_submenu_node_item(TTR("Syntax Highlighter"), highlighter_menu); - highlighter_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_change_syntax_highlighter)); + highlighter_menu->connect(SceneStringName(id_pressed), callable_mp(this, &ScriptTextEditor::_change_syntax_highlighter)); edit_hb->add_child(search_menu); search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find"), SEARCH_FIND); @@ -2331,7 +2344,7 @@ void ScriptTextEditor::_enable_code_editor() { 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)); + search_menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &ScriptTextEditor::_edit_option)); _load_theme_settings(); @@ -2350,7 +2363,7 @@ void ScriptTextEditor::_enable_code_editor() { breakpoints_menu->connect("about_to_popup", callable_mp(this, &ScriptTextEditor::_update_breakpoint_list)); breakpoints_menu->connect("index_pressed", callable_mp(this, &ScriptTextEditor::_breakpoint_item_pressed)); - goto_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option)); + goto_menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &ScriptTextEditor::_edit_option)); } ScriptTextEditor::ScriptTextEditor() { @@ -2485,6 +2498,7 @@ void ScriptTextEditor::register_editor() { ED_SHORTCUT("script_text_editor/evaluate_selection", TTR("Evaluate Selection"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::E); ED_SHORTCUT("script_text_editor/toggle_word_wrap", TTR("Toggle Word Wrap"), KeyModifierMask::ALT | Key::Z); ED_SHORTCUT("script_text_editor/trim_trailing_whitespace", TTR("Trim Trailing Whitespace"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT | Key::T); + ED_SHORTCUT("script_text_editor/trim_final_newlines", TTR("Trim Final Newlines"), Key::NONE); ED_SHORTCUT("script_text_editor/convert_indent_to_spaces", TTR("Convert Indent to Spaces"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::Y); ED_SHORTCUT("script_text_editor/convert_indent_to_tabs", TTR("Convert Indent to Tabs"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::I); ED_SHORTCUT("script_text_editor/auto_indent", TTR("Auto Indent"), KeyModifierMask::CMD_OR_CTRL | Key::I); diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index de89fe458c..8c2ec1561b 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -118,6 +118,7 @@ class ScriptTextEditor : public ScriptEditorBase { EDIT_COMPLETE, EDIT_AUTO_INDENT, EDIT_TRIM_TRAILING_WHITESAPCE, + EDIT_TRIM_FINAL_NEWLINES, EDIT_CONVERT_INDENT_TO_SPACES, EDIT_CONVERT_INDENT_TO_TABS, EDIT_TOGGLE_COMMENT, @@ -228,6 +229,7 @@ public: virtual Variant get_navigation_state() override; virtual void ensure_focus() override; virtual void trim_trailing_whitespace() override; + virtual void trim_final_newlines() override; virtual void insert_final_newline() override; virtual void convert_indent() override; virtual void tag_saved_version() override; diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index 222d010a7a..8dc398138c 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -436,8 +436,14 @@ void ShaderEditorPlugin::_menu_item_pressed(int p_index) { int index = shader_tabs->get_current_tab(); ERR_FAIL_INDEX(index, shader_tabs->get_tab_count()); TextShaderEditor *editor = edited_shaders[index].shader_editor; - if (editor && editor->get_trim_trailing_whitespace_on_save()) { - editor->trim_trailing_whitespace(); + if (editor) { + if (editor->get_trim_trailing_whitespace_on_save()) { + editor->trim_trailing_whitespace(); + } + + if (editor->get_trim_final_newlines_on_save()) { + editor->trim_final_newlines(); + } } if (edited_shaders[index].shader.is_valid()) { EditorNode::get_singleton()->save_resource(edited_shaders[index].shader); @@ -452,8 +458,14 @@ void ShaderEditorPlugin::_menu_item_pressed(int p_index) { int index = shader_tabs->get_current_tab(); ERR_FAIL_INDEX(index, shader_tabs->get_tab_count()); TextShaderEditor *editor = edited_shaders[index].shader_editor; - if (editor && editor->get_trim_trailing_whitespace_on_save()) { - editor->trim_trailing_whitespace(); + if (editor) { + if (editor->get_trim_trailing_whitespace_on_save()) { + editor->trim_trailing_whitespace(); + } + + if (editor->get_trim_final_newlines_on_save()) { + editor->trim_final_newlines(); + } } String path; if (edited_shaders[index].shader.is_valid()) { @@ -687,7 +699,7 @@ ShaderEditorPlugin::ShaderEditorPlugin() { file_menu->get_popup()->add_item(TTR("Open File in Inspector"), FILE_INSPECT); file_menu->get_popup()->add_separator(); file_menu->get_popup()->add_item(TTR("Close File"), FILE_CLOSE); - file_menu->get_popup()->connect("id_pressed", callable_mp(this, &ShaderEditorPlugin::_menu_item_pressed)); + file_menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &ShaderEditorPlugin::_menu_item_pressed)); menu_hb->add_child(file_menu); for (int i = FILE_SAVE; i < FILE_MAX; i++) { @@ -726,7 +738,7 @@ ShaderEditorPlugin::ShaderEditorPlugin() { main_split->add_child(shader_tabs); Ref<StyleBoxEmpty> empty; empty.instantiate(); - shader_tabs->add_theme_style_override("panel", empty); + shader_tabs->add_theme_style_override(SceneStringName(panel), empty); button = EditorNode::get_bottom_panel()->add_item(TTR("Shader Editor"), window_wrapper, ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_shader_editor_bottom_panel", TTR("Toggle Shader Editor Bottom Panel"), KeyModifierMask::ALT | Key::S)); diff --git a/editor/plugins/skeleton_2d_editor_plugin.cpp b/editor/plugins/skeleton_2d_editor_plugin.cpp index 44543ffa9f..8308fe6d6e 100644 --- a/editor/plugins/skeleton_2d_editor_plugin.cpp +++ b/editor/plugins/skeleton_2d_editor_plugin.cpp @@ -107,7 +107,7 @@ Skeleton2DEditor::Skeleton2DEditor() { options->get_popup()->add_item(TTR("Overwrite Rest Pose"), MENU_OPTION_MAKE_REST); options->set_switch_on_hover(true); - options->get_popup()->connect("id_pressed", callable_mp(this, &Skeleton2DEditor::_menu_option)); + options->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &Skeleton2DEditor::_menu_option)); err_dialog = memnew(AcceptDialog); add_child(err_dialog); diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp index e792f0998b..202817f6ee 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -735,7 +735,7 @@ void Skeleton3DEditor::create_editors() { p->add_item(TTR("Create Physical Skeleton"), SKELETON_OPTION_CREATE_PHYSICAL_SKELETON); p->add_item(TTR("Export Skeleton Profile"), SKELETON_OPTION_EXPORT_SKELETON_PROFILE); - p->connect("id_pressed", callable_mp(this, &Skeleton3DEditor::_on_click_skeleton_option)); + p->connect(SceneStringName(id_pressed), callable_mp(this, &Skeleton3DEditor::_on_click_skeleton_option)); set_bone_options_enabled(false); Vector<Variant> button_binds; diff --git a/editor/plugins/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp index 0b882e265d..c7a89484f0 100644 --- a/editor/plugins/sprite_2d_editor_plugin.cpp +++ b/editor/plugins/sprite_2d_editor_plugin.cpp @@ -587,7 +587,7 @@ Sprite2DEditor::Sprite2DEditor() { options->get_popup()->add_item(TTR("Create LightOccluder2D Sibling"), MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D); options->set_switch_on_hover(true); - options->get_popup()->connect("id_pressed", callable_mp(this, &Sprite2DEditor::_menu_option)); + options->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &Sprite2DEditor::_menu_option)); err_dialog = memnew(AcceptDialog); add_child(err_dialog); diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp index 56f8e1173f..ae6ec0f702 100644 --- a/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/editor/plugins/sprite_frames_editor_plugin.cpp @@ -587,7 +587,7 @@ void SpriteFramesEditor::_notification(int p_what) { split_sheet_zoom_out->set_icon(get_editor_theme_icon(SNAME("ZoomLess"))); split_sheet_zoom_reset->set_icon(get_editor_theme_icon(SNAME("ZoomReset"))); split_sheet_zoom_in->set_icon(get_editor_theme_icon(SNAME("ZoomMore"))); - split_sheet_scroll->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); + split_sheet_scroll->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree"))); _update_show_settings(); } break; @@ -2181,6 +2181,7 @@ SpriteFramesEditor::SpriteFramesEditor() { split_sheet_h->set_min(1); split_sheet_h->set_max(128); split_sheet_h->set_step(1); + split_sheet_h->set_select_all_on_focus(true); split_sheet_h_hb->add_child(split_sheet_h); split_sheet_h->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed).bind(PARAM_FRAME_COUNT)); split_sheet_settings_vb->add_child(split_sheet_h_hb); @@ -2197,6 +2198,7 @@ SpriteFramesEditor::SpriteFramesEditor() { split_sheet_v->set_min(1); split_sheet_v->set_max(128); split_sheet_v->set_step(1); + split_sheet_v->set_select_all_on_focus(true); split_sheet_v_hb->add_child(split_sheet_v); split_sheet_v->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed).bind(PARAM_FRAME_COUNT)); split_sheet_settings_vb->add_child(split_sheet_v_hb); @@ -2216,6 +2218,7 @@ SpriteFramesEditor::SpriteFramesEditor() { split_sheet_size_x->set_min(1); split_sheet_size_x->set_step(1); split_sheet_size_x->set_suffix("px"); + split_sheet_size_x->set_select_all_on_focus(true); split_sheet_size_x->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed).bind(PARAM_SIZE)); split_sheet_size_vb->add_child(split_sheet_size_x); split_sheet_size_y = memnew(SpinBox); @@ -2223,6 +2226,7 @@ SpriteFramesEditor::SpriteFramesEditor() { split_sheet_size_y->set_min(1); split_sheet_size_y->set_step(1); split_sheet_size_y->set_suffix("px"); + split_sheet_size_y->set_select_all_on_focus(true); split_sheet_size_y->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed).bind(PARAM_SIZE)); split_sheet_size_vb->add_child(split_sheet_size_y); split_sheet_size_hb->add_child(split_sheet_size_vb); @@ -2242,12 +2246,14 @@ SpriteFramesEditor::SpriteFramesEditor() { split_sheet_sep_x->set_min(0); split_sheet_sep_x->set_step(1); split_sheet_sep_x->set_suffix("px"); + split_sheet_sep_x->set_select_all_on_focus(true); split_sheet_sep_x->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed).bind(PARAM_USE_CURRENT)); split_sheet_sep_vb->add_child(split_sheet_sep_x); split_sheet_sep_y = memnew(SpinBox); split_sheet_sep_y->set_min(0); split_sheet_sep_y->set_step(1); split_sheet_sep_y->set_suffix("px"); + split_sheet_sep_y->set_select_all_on_focus(true); split_sheet_sep_y->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed).bind(PARAM_USE_CURRENT)); split_sheet_sep_vb->add_child(split_sheet_sep_y); split_sheet_sep_hb->add_child(split_sheet_sep_vb); @@ -2267,12 +2273,14 @@ SpriteFramesEditor::SpriteFramesEditor() { split_sheet_offset_x->set_min(0); split_sheet_offset_x->set_step(1); split_sheet_offset_x->set_suffix("px"); + split_sheet_offset_x->set_select_all_on_focus(true); split_sheet_offset_x->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed).bind(PARAM_USE_CURRENT)); split_sheet_offset_vb->add_child(split_sheet_offset_x); split_sheet_offset_y = memnew(SpinBox); split_sheet_offset_y->set_min(0); split_sheet_offset_y->set_step(1); split_sheet_offset_y->set_suffix("px"); + split_sheet_offset_y->set_select_all_on_focus(true); split_sheet_offset_y->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed).bind(PARAM_USE_CURRENT)); split_sheet_offset_vb->add_child(split_sheet_offset_y); split_sheet_offset_hb->add_child(split_sheet_offset_vb); diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp index 5bc3cafe19..ecdc4acf47 100644 --- a/editor/plugins/text_editor.cpp +++ b/editor/plugins/text_editor.cpp @@ -288,6 +288,10 @@ void TextEditor::trim_trailing_whitespace() { code_editor->trim_trailing_whitespace(); } +void TextEditor::trim_final_newlines() { + code_editor->trim_final_newlines(); +} + void TextEditor::insert_final_newline() { code_editor->insert_final_newline(); } @@ -414,6 +418,9 @@ void TextEditor::_edit_option(int p_op) { case EDIT_TRIM_TRAILING_WHITESAPCE: { trim_trailing_whitespace(); } break; + case EDIT_TRIM_FINAL_NEWLINES: { + trim_final_newlines(); + } break; case EDIT_CONVERT_INDENT_TO_SPACES: { code_editor->set_indent_using_spaces(true); convert_indent(); @@ -607,7 +614,7 @@ TextEditor::TextEditor() { context_menu = memnew(PopupMenu); add_child(context_menu); - context_menu->connect("id_pressed", callable_mp(this, &TextEditor::_edit_option)); + context_menu->connect(SceneStringName(id_pressed), callable_mp(this, &TextEditor::_edit_option)); edit_hb = memnew(HBoxContainer); @@ -617,7 +624,7 @@ TextEditor::TextEditor() { edit_menu->set_text(TTR("Edit")); edit_menu->set_switch_on_hover(true); edit_menu->connect("about_to_popup", callable_mp(this, &TextEditor::_prepare_edit_menu)); - edit_menu->get_popup()->connect("id_pressed", callable_mp(this, &TextEditor::_edit_option)); + edit_menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &TextEditor::_edit_option)); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_redo"), EDIT_REDO); @@ -641,6 +648,7 @@ TextEditor::TextEditor() { edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/duplicate_lines"), EDIT_DUPLICATE_LINES); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_word_wrap"), EDIT_TOGGLE_WORD_WRAP); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/trim_trailing_whitespace"), EDIT_TRIM_TRAILING_WHITESAPCE); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/trim_final_newlines"), EDIT_TRIM_FINAL_NEWLINES); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_spaces"), EDIT_CONVERT_INDENT_TO_SPACES); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_tabs"), EDIT_CONVERT_INDENT_TO_TABS); @@ -650,11 +658,11 @@ TextEditor::TextEditor() { convert_case->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_to_uppercase"), EDIT_TO_UPPERCASE); convert_case->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_to_lowercase"), EDIT_TO_LOWERCASE); convert_case->add_shortcut(ED_GET_SHORTCUT("script_text_editor/capitalize"), EDIT_CAPITALIZE); - convert_case->connect("id_pressed", callable_mp(this, &TextEditor::_edit_option)); + convert_case->connect(SceneStringName(id_pressed), callable_mp(this, &TextEditor::_edit_option)); highlighter_menu = memnew(PopupMenu); edit_menu->get_popup()->add_submenu_node_item(TTR("Syntax Highlighter"), highlighter_menu); - highlighter_menu->connect("id_pressed", callable_mp(this, &TextEditor::_change_syntax_highlighter)); + highlighter_menu->connect(SceneStringName(id_pressed), callable_mp(this, &TextEditor::_change_syntax_highlighter)); Ref<EditorPlainTextSyntaxHighlighter> plain_highlighter; plain_highlighter.instantiate(); @@ -670,7 +678,7 @@ TextEditor::TextEditor() { edit_hb->add_child(search_menu); search_menu->set_text(TTR("Search")); search_menu->set_switch_on_hover(true); - search_menu->get_popup()->connect("id_pressed", callable_mp(this, &TextEditor::_edit_option)); + search_menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &TextEditor::_edit_option)); search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find"), SEARCH_FIND); search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_next"), SEARCH_FIND_NEXT); @@ -685,7 +693,7 @@ TextEditor::TextEditor() { edit_hb->add_child(goto_menu); goto_menu->set_text(TTR("Go To")); goto_menu->set_switch_on_hover(true); - goto_menu->get_popup()->connect("id_pressed", callable_mp(this, &TextEditor::_edit_option)); + goto_menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &TextEditor::_edit_option)); goto_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_line"), SEARCH_GOTO_LINE); goto_menu->get_popup()->add_separator(); diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h index 38fddc45df..268e5c32b4 100644 --- a/editor/plugins/text_editor.h +++ b/editor/plugins/text_editor.h @@ -63,6 +63,7 @@ private: EDIT_PASTE, EDIT_SELECT_ALL, EDIT_TRIM_TRAILING_WHITESAPCE, + EDIT_TRIM_FINAL_NEWLINES, EDIT_CONVERT_INDENT_TO_SPACES, EDIT_CONVERT_INDENT_TO_TABS, EDIT_MOVE_LINE_UP, @@ -133,6 +134,7 @@ public: virtual void set_executing_line(int p_line) override; virtual void clear_executing_line() override; virtual void trim_trailing_whitespace() override; + virtual void trim_final_newlines() override; virtual void insert_final_newline() override; virtual void convert_indent() override; virtual void ensure_focus() override; diff --git a/editor/plugins/text_shader_editor.cpp b/editor/plugins/text_shader_editor.cpp index bb74bf8d1f..6c47f3aadb 100644 --- a/editor/plugins/text_shader_editor.cpp +++ b/editor/plugins/text_shader_editor.cpp @@ -30,12 +30,12 @@ #include "text_shader_editor.h" +#include "core/config/project_settings.h" #include "core/version_generated.gen.h" +#include "editor/editor_file_system.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" #include "editor/editor_string_names.h" -#include "editor/filesystem_dock.h" -#include "editor/project_settings_editor.h" #include "editor/themes/editor_scale.h" #include "editor/themes/editor_theme_manager.h" #include "scene/gui/split_container.h" @@ -735,6 +735,13 @@ void TextShaderEditor::_menu_option(int p_option) { } } +void TextShaderEditor::_prepare_edit_menu() { + const CodeEdit *tx = code_editor->get_text_editor(); + PopupMenu *popup = edit_menu->get_popup(); + popup->set_item_disabled(popup->get_item_index(EDIT_UNDO), !tx->has_undo()); + popup->set_item_disabled(popup->get_item_index(EDIT_REDO), !tx->has_redo()); +} + void TextShaderEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: @@ -763,6 +770,7 @@ void TextShaderEditor::_apply_editor_settings() { code_editor->update_editor_settings(); trim_trailing_whitespace_on_save = EDITOR_GET("text_editor/behavior/files/trim_trailing_whitespace_on_save"); + trim_final_newlines_on_save = EDITOR_GET("text_editor/behavior/files/trim_final_newlines_on_save"); } void TextShaderEditor::_show_warnings_panel(bool p_show) { @@ -927,6 +935,10 @@ void TextShaderEditor::save_external_data(const String &p_str) { trim_trailing_whitespace(); } + if (trim_final_newlines_on_save) { + trim_final_newlines(); + } + apply_shaders(); Ref<Shader> edited_shader = code_editor->get_edited_shader(); @@ -953,6 +965,10 @@ void TextShaderEditor::trim_trailing_whitespace() { code_editor->trim_trailing_whitespace(); } +void TextShaderEditor::trim_final_newlines() { + code_editor->trim_final_newlines(); +} + void TextShaderEditor::validate_script() { code_editor->_validate_script(); } @@ -1088,6 +1104,9 @@ void TextShaderEditor::_make_context_menu(bool p_selection, Vector2 p_position) context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT); context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_bookmark"), BOOKMARK_TOGGLE); + context_menu->set_item_disabled(context_menu->get_item_index(EDIT_UNDO), !code_editor->get_text_editor()->has_undo()); + context_menu->set_item_disabled(context_menu->get_item_index(EDIT_REDO), !code_editor->get_text_editor()->has_redo()); + context_menu->set_position(get_screen_position() + p_position); context_menu->reset_size(); context_menu->popup(); @@ -1119,7 +1138,7 @@ TextShaderEditor::TextShaderEditor() { context_menu = memnew(PopupMenu); add_child(context_menu); - context_menu->connect("id_pressed", callable_mp(this, &TextShaderEditor::_menu_option)); + context_menu->connect(SceneStringName(id_pressed), callable_mp(this, &TextShaderEditor::_menu_option)); VBoxContainer *main_container = memnew(VBoxContainer); HBoxContainer *hbc = memnew(HBoxContainer); @@ -1128,6 +1147,7 @@ TextShaderEditor::TextShaderEditor() { edit_menu->set_shortcut_context(this); edit_menu->set_text(TTR("Edit")); edit_menu->set_switch_on_hover(true); + edit_menu->connect("about_to_popup", callable_mp(this, &TextShaderEditor::_prepare_edit_menu)); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_redo"), EDIT_REDO); @@ -1149,7 +1169,7 @@ TextShaderEditor::TextShaderEditor() { edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_word_wrap"), EDIT_TOGGLE_WORD_WRAP); edit_menu->get_popup()->add_separator(); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_text_completion_query"), EDIT_COMPLETE); - edit_menu->get_popup()->connect("id_pressed", callable_mp(this, &TextShaderEditor::_menu_option)); + edit_menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &TextShaderEditor::_menu_option)); search_menu = memnew(MenuButton); search_menu->set_shortcut_context(this); @@ -1160,13 +1180,13 @@ TextShaderEditor::TextShaderEditor() { search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_next"), SEARCH_FIND_NEXT); search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_previous"), SEARCH_FIND_PREV); search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace"), SEARCH_REPLACE); - search_menu->get_popup()->connect("id_pressed", callable_mp(this, &TextShaderEditor::_menu_option)); + search_menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &TextShaderEditor::_menu_option)); MenuButton *goto_menu = memnew(MenuButton); goto_menu->set_shortcut_context(this); goto_menu->set_text(TTR("Go To")); goto_menu->set_switch_on_hover(true); - goto_menu->get_popup()->connect("id_pressed", callable_mp(this, &TextShaderEditor::_menu_option)); + goto_menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &TextShaderEditor::_menu_option)); goto_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_line"), SEARCH_GOTO_LINE); goto_menu->get_popup()->add_separator(); @@ -1181,7 +1201,7 @@ TextShaderEditor::TextShaderEditor() { help_menu->set_text(TTR("Help")); help_menu->set_switch_on_hover(true); help_menu->get_popup()->add_item(TTR("Online Docs"), HELP_DOCS); - help_menu->get_popup()->connect("id_pressed", callable_mp(this, &TextShaderEditor::_menu_option)); + help_menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &TextShaderEditor::_menu_option)); add_child(main_container); main_container->add_child(hbc); @@ -1189,7 +1209,7 @@ TextShaderEditor::TextShaderEditor() { hbc->add_child(edit_menu); hbc->add_child(goto_menu); hbc->add_child(help_menu); - hbc->add_theme_style_override("panel", EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("ScriptEditorPanel"), EditorStringName(EditorStyles))); + hbc->add_theme_style_override(SceneStringName(panel), EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("ScriptEditorPanel"), EditorStringName(EditorStyles))); VSplitContainer *editor_box = memnew(VSplitContainer); main_container->add_child(editor_box); diff --git a/editor/plugins/text_shader_editor.h b/editor/plugins/text_shader_editor.h index be16148744..61066ed7c6 100644 --- a/editor/plugins/text_shader_editor.h +++ b/editor/plugins/text_shader_editor.h @@ -34,7 +34,6 @@ #include "editor/code_editor.h" #include "scene/gui/margin_container.h" #include "scene/gui/menu_button.h" -#include "scene/gui/panel_container.h" #include "scene/gui/rich_text_label.h" #include "servers/rendering/shader_warnings.h" @@ -153,6 +152,7 @@ class TextShaderEditor : public MarginContainer { bool compilation_success = true; void _menu_option(int p_option); + void _prepare_edit_menu(); mutable Ref<Shader> shader; mutable Ref<ShaderInclude> shader_inc; @@ -176,6 +176,7 @@ class TextShaderEditor : public MarginContainer { uint32_t dependencies_version = 0xFFFFFFFF; bool trim_trailing_whitespace_on_save; + bool trim_final_newlines_on_save; protected: void _notification(int p_what); @@ -189,6 +190,7 @@ protected: public: bool was_compilation_successful() const { return compilation_success; } bool get_trim_trailing_whitespace_on_save() const { return trim_trailing_whitespace_on_save; } + bool get_trim_final_newlines_on_save() const { return trim_final_newlines_on_save; } void apply_shaders(); void ensure_select_current(); void edit(const Ref<Shader> &p_shader); @@ -196,6 +198,7 @@ public: void goto_line_selection(int p_line, int p_begin, int p_end); void save_external_data(const String &p_str = ""); void trim_trailing_whitespace(); + void trim_final_newlines(); void validate_script(); bool is_unsaved() const; void tag_saved_version(); diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index 6b90ea79b2..799d7c757d 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -842,8 +842,8 @@ void TextureRegionEditor::_notification(int p_what) { } break; case NOTIFICATION_THEME_CHANGED: { - texture_preview->add_theme_style_override("panel", get_theme_stylebox(SNAME("TextureRegionPreviewBG"), EditorStringName(EditorStyles))); - texture_overlay->add_theme_style_override("panel", get_theme_stylebox(SNAME("TextureRegionPreviewFG"), EditorStringName(EditorStyles))); + texture_preview->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("TextureRegionPreviewBG"), EditorStringName(EditorStyles))); + texture_overlay->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("TextureRegionPreviewFG"), EditorStringName(EditorStyles))); zoom_out->set_icon(get_editor_theme_icon(SNAME("ZoomLess"))); zoom_reset->set_icon(get_editor_theme_icon(SNAME("ZoomReset"))); diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index 8489574194..b307832ff6 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -3670,7 +3670,7 @@ void ThemeEditor::_notification(int p_what) { case NOTIFICATION_THEME_CHANGED: { preview_tabs->add_theme_style_override("tab_selected", get_theme_stylebox(SNAME("ThemeEditorPreviewFG"), EditorStringName(EditorStyles))); preview_tabs->add_theme_style_override("tab_unselected", get_theme_stylebox(SNAME("ThemeEditorPreviewBG"), EditorStringName(EditorStyles))); - preview_tabs_content->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TabContainerOdd"))); + preview_tabs_content->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("TabContainerOdd"))); add_preview_button->set_icon(get_editor_theme_icon(SNAME("Add"))); } break; diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp index 2b86268414..52b58b74a3 100644 --- a/editor/plugins/tiles/tile_atlas_view.cpp +++ b/editor/plugins/tiles/tile_atlas_view.cpp @@ -59,6 +59,9 @@ void TileAtlasView::_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<In } Size2i TileAtlasView::_compute_base_tiles_control_size() { + if (tile_set_atlas_source.is_null()) { + return Size2i(); + } // Update the texture. Vector2i size; Ref<Texture2D> texture = tile_set_atlas_source->get_texture(); @@ -69,6 +72,9 @@ Size2i TileAtlasView::_compute_base_tiles_control_size() { } Size2i TileAtlasView::_compute_alternative_tiles_control_size() { + if (tile_set_atlas_source.is_null()) { + return Size2i(); + } Vector2i size; for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) { Vector2i tile_id = tile_set_atlas_source->get_tile_id(i); @@ -89,6 +95,9 @@ Size2i TileAtlasView::_compute_alternative_tiles_control_size() { } void TileAtlasView::_update_zoom_and_panning(bool p_zoom_on_mouse_pos) { + if (tile_set_atlas_source.is_null()) { + return; + } float zoom = zoom_widget->get_zoom(); // Compute the minimum sizes. @@ -153,6 +162,9 @@ void TileAtlasView::_center_view() { } void TileAtlasView::_base_tiles_root_control_gui_input(const Ref<InputEvent> &p_event) { + if (tile_set_atlas_source.is_null()) { + return; + } base_tiles_root_control->set_tooltip_text(""); Ref<InputEventMouseMotion> mm = p_event; @@ -169,6 +181,9 @@ void TileAtlasView::_base_tiles_root_control_gui_input(const Ref<InputEvent> &p_ } void TileAtlasView::_draw_base_tiles() { + if (tile_set.is_null() || tile_set_atlas_source.is_null()) { + return; + } Ref<Texture2D> texture = tile_set_atlas_source->get_texture(); if (texture.is_valid()) { Vector2i margins = tile_set_atlas_source->get_margins(); @@ -314,6 +329,9 @@ void TileAtlasView::_clear_material_canvas_items() { } void TileAtlasView::_draw_base_tiles_texture_grid() { + if (tile_set_atlas_source.is_null()) { + return; + } Ref<Texture2D> texture = tile_set_atlas_source->get_texture(); if (texture.is_valid()) { Vector2i margins = tile_set_atlas_source->get_margins(); @@ -344,6 +362,9 @@ void TileAtlasView::_draw_base_tiles_texture_grid() { } void TileAtlasView::_draw_base_tiles_shape_grid() { + if (tile_set.is_null() || tile_set_atlas_source.is_null()) { + return; + } // Draw the shapes. Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color"); Vector2i tile_shape_size = tile_set->get_tile_size(); @@ -382,6 +403,9 @@ void TileAtlasView::_alternative_tiles_root_control_gui_input(const Ref<InputEve } void TileAtlasView::_draw_alternatives() { + if (tile_set.is_null() || tile_set_atlas_source.is_null()) { + return; + } // Draw the alternative tiles. Ref<Texture2D> texture = tile_set_atlas_source->get_texture(); if (texture.is_valid()) { @@ -432,12 +456,12 @@ void TileAtlasView::_draw_background_right() { } void TileAtlasView::set_atlas_source(TileSet *p_tile_set, TileSetAtlasSource *p_tile_set_atlas_source, int p_source_id) { - tile_set = p_tile_set; - tile_set_atlas_source = p_tile_set_atlas_source; + tile_set = Ref<TileSet>(p_tile_set); + tile_set_atlas_source = Ref<TileSetAtlasSource>(p_tile_set_atlas_source); _clear_material_canvas_items(); - if (!tile_set) { + if (tile_set.is_null()) { return; } @@ -485,6 +509,10 @@ void TileAtlasView::set_padding(Side p_side, int p_padding) { } Vector2i TileAtlasView::get_atlas_tile_coords_at_pos(const Vector2 p_pos, bool p_clamp) const { + if (tile_set_atlas_source.is_null()) { + return Vector2i(); + } + Ref<Texture2D> texture = tile_set_atlas_source->get_texture(); if (!texture.is_valid()) { return TileSetSource::INVALID_ATLAS_COORDS; @@ -508,6 +536,10 @@ Vector2i TileAtlasView::get_atlas_tile_coords_at_pos(const Vector2 p_pos, bool p } void TileAtlasView::_update_alternative_tiles_rect_cache() { + if (tile_set_atlas_source.is_null()) { + return; + } + alternative_tiles_rect_cache.clear(); Rect2i current; diff --git a/editor/plugins/tiles/tile_atlas_view.h b/editor/plugins/tiles/tile_atlas_view.h index e5b4863b05..8fcf942056 100644 --- a/editor/plugins/tiles/tile_atlas_view.h +++ b/editor/plugins/tiles/tile_atlas_view.h @@ -45,8 +45,8 @@ class TileAtlasView : public Control { GDCLASS(TileAtlasView, Control); private: - TileSet *tile_set = nullptr; - TileSetAtlasSource *tile_set_atlas_source = nullptr; + Ref<TileSet> tile_set; + Ref<TileSetAtlasSource> tile_set_atlas_source; int source_id = TileSet::INVALID_SOURCE; enum DragType { diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp index a94080e253..df90383678 100644 --- a/editor/plugins/tiles/tile_data_editors.cpp +++ b/editor/plugins/tiles/tile_data_editors.cpp @@ -903,7 +903,7 @@ GenericTilePolygonEditor::GenericTilePolygonEditor() { button_advanced_menu->get_popup()->add_item(TTR("Rotate Left"), ROTATE_LEFT, Key::E); button_advanced_menu->get_popup()->add_item(TTR("Flip Horizontally"), FLIP_HORIZONTALLY, Key::H); button_advanced_menu->get_popup()->add_item(TTR("Flip Vertically"), FLIP_VERTICALLY, Key::V); - button_advanced_menu->get_popup()->connect("id_pressed", callable_mp(this, &GenericTilePolygonEditor::_advanced_menu_item_pressed)); + button_advanced_menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &GenericTilePolygonEditor::_advanced_menu_item_pressed)); button_advanced_menu->set_focus_mode(FOCUS_ALL); toolbar->add_child(button_advanced_menu); diff --git a/editor/plugins/tiles/tile_map_layer_editor.cpp b/editor/plugins/tiles/tile_map_layer_editor.cpp index 5fd4fb3602..6cf0bec535 100644 --- a/editor/plugins/tiles/tile_map_layer_editor.cpp +++ b/editor/plugins/tiles/tile_map_layer_editor.cpp @@ -2389,7 +2389,7 @@ TileMapLayerEditorTilesPlugin::TileMapLayerEditorTilesPlugin() { source_sort_button->set_tooltip_text(TTR("Sort sources")); PopupMenu *p = source_sort_button->get_popup(); - p->connect("id_pressed", callable_mp(this, &TileMapLayerEditorTilesPlugin::_set_source_sort)); + p->connect(SceneStringName(id_pressed), callable_mp(this, &TileMapLayerEditorTilesPlugin::_set_source_sort)); p->add_radio_check_item(TTR("Sort by ID (Ascending)"), TilesEditorUtils::SOURCE_SORT_ID); p->add_radio_check_item(TTR("Sort by ID (Descending)"), TilesEditorUtils::SOURCE_SORT_ID_REVERSE); p->add_radio_check_item(TTR("Sort by Name (Ascending)"), TilesEditorUtils::SOURCE_SORT_NAME); @@ -4491,7 +4491,7 @@ TileMapLayerEditor::TileMapLayerEditor() { advanced_menu_button->set_theme_type_variation("FlatButton"); advanced_menu_button->get_popup()->add_item(TTR("Automatically Replace Tiles with Proxies"), ADVANCED_MENU_REPLACE_WITH_PROXIES); advanced_menu_button->get_popup()->add_item(TTR("Extract TileMap layers as individual TileMapLayer nodes"), ADVANCED_MENU_EXTRACT_TILE_MAP_LAYERS); - advanced_menu_button->get_popup()->connect("id_pressed", callable_mp(this, &TileMapLayerEditor::_advanced_menu_button_id_pressed)); + advanced_menu_button->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &TileMapLayerEditor::_advanced_menu_button_id_pressed)); tile_map_toolbar->add_child(advanced_menu_button); // A label for editing errors. diff --git a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp index 9add6ef586..35e64899fb 100644 --- a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp +++ b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp @@ -378,7 +378,7 @@ TileProxiesManagerDialog::TileProxiesManagerDialog() { popup_menu = memnew(PopupMenu); popup_menu->add_shortcut(ED_GET_SHORTCUT("ui_text_delete")); - popup_menu->connect("id_pressed", callable_mp(this, &TileProxiesManagerDialog::_menu_id_pressed)); + popup_menu->connect(SceneStringName(id_pressed), callable_mp(this, &TileProxiesManagerDialog::_menu_id_pressed)); add_child(popup_menu); // Add proxy panel. diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp index 1daba1f665..8b9d2a4e71 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp @@ -997,7 +997,7 @@ void TileSetAtlasSourceEditor::_update_atlas_view() { Button *button = memnew(Button); button->set_flat(true); button->set_icon(get_editor_theme_icon(SNAME("Add"))); - button->add_theme_style_override("normal", memnew(StyleBoxEmpty)); + button->add_theme_style_override(CoreStringName(normal), memnew(StyleBoxEmpty)); button->add_theme_style_override("hover", memnew(StyleBoxEmpty)); button->add_theme_style_override("focus", memnew(StyleBoxEmpty)); button->add_theme_style_override(SceneStringName(pressed), memnew(StyleBoxEmpty)); @@ -2637,7 +2637,7 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() { tool_advanced_menu_button->get_popup()->add_item(TTR("Create Tiles in Non-Transparent Texture Regions"), ADVANCED_AUTO_CREATE_TILES); tool_advanced_menu_button->get_popup()->add_item(TTR("Remove Tiles in Fully Transparent Texture Regions"), ADVANCED_AUTO_REMOVE_TILES); tool_advanced_menu_button->get_popup()->add_item(TTR("Remove Tiles Outside the Texture"), ADVANCED_CLEANUP_TILES); - tool_advanced_menu_button->get_popup()->connect("id_pressed", callable_mp(this, &TileSetAtlasSourceEditor::_menu_option)); + tool_advanced_menu_button->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &TileSetAtlasSourceEditor::_menu_option)); tool_settings->add_child(tool_advanced_menu_button); outside_tiles_warning = memnew(TextureRect); @@ -2689,12 +2689,12 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() { base_tile_popup_menu = memnew(PopupMenu); base_tile_popup_menu->add_shortcut(ED_GET_SHORTCUT("tiles_editor/delete"), TILE_DELETE); base_tile_popup_menu->add_item(TTR("Create an Alternative Tile"), TILE_CREATE_ALTERNATIVE); - base_tile_popup_menu->connect("id_pressed", callable_mp(this, &TileSetAtlasSourceEditor::_menu_option)); + base_tile_popup_menu->connect(SceneStringName(id_pressed), callable_mp(this, &TileSetAtlasSourceEditor::_menu_option)); tile_atlas_view->add_child(base_tile_popup_menu); empty_base_tile_popup_menu = memnew(PopupMenu); empty_base_tile_popup_menu->add_item(TTR("Create a Tile"), TILE_CREATE); - empty_base_tile_popup_menu->connect("id_pressed", callable_mp(this, &TileSetAtlasSourceEditor::_menu_option)); + empty_base_tile_popup_menu->connect(SceneStringName(id_pressed), callable_mp(this, &TileSetAtlasSourceEditor::_menu_option)); tile_atlas_view->add_child(empty_base_tile_popup_menu); tile_atlas_control = memnew(TileAtlasControl(this)); @@ -2710,7 +2710,7 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() { alternative_tile_popup_menu = memnew(PopupMenu); alternative_tile_popup_menu->add_shortcut(ED_SHORTCUT("tiles_editor/delete_tile", TTR("Delete"), Key::KEY_DELETE), TILE_DELETE); - alternative_tile_popup_menu->connect("id_pressed", callable_mp(this, &TileSetAtlasSourceEditor::_menu_option)); + alternative_tile_popup_menu->connect(SceneStringName(id_pressed), callable_mp(this, &TileSetAtlasSourceEditor::_menu_option)); tile_atlas_view->add_child(alternative_tile_popup_menu); alternative_tiles_control = memnew(Control); @@ -2938,6 +2938,18 @@ bool EditorInspectorPluginTileData::parse_property(Object *p_object, const Varia add_property_editor(p_path, ep); return true; } + } else if (p_path.begins_with("custom_data_") && p_path.trim_prefix("custom_data_").is_valid_int()) { + // Custom data layers. + int layer_index = components[0].trim_prefix("custom_data_").to_int(); + ERR_FAIL_COND_V(layer_index < 0, false); + EditorProperty *ep = EditorInspectorDefaultPlugin::get_editor_for_property(p_object, p_type, p_path, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT); + const TileSetAtlasSourceEditor::AtlasTileProxyObject *proxy_obj = Object::cast_to<TileSetAtlasSourceEditor::AtlasTileProxyObject>(p_object); + const TileSetAtlasSource *atlas_source = *proxy_obj->get_edited_tile_set_atlas_source(); + ERR_FAIL_NULL_V(atlas_source, false); + const TileSet *tile_set = atlas_source->get_tile_set(); + ERR_FAIL_NULL_V(tile_set, false); + add_property_editor(p_path, ep, false, tile_set->get_custom_data_layer_name(layer_index)); + return true; } return false; } diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp index 0efed44ac7..a20bd51328 100644 --- a/editor/plugins/tiles/tile_set_editor.cpp +++ b/editor/plugins/tiles/tile_set_editor.cpp @@ -371,7 +371,7 @@ void TileSetEditor::_notification(int p_what) { source_sort_button->set_icon(get_editor_theme_icon(SNAME("Sort"))); sources_advanced_menu_button->set_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl"))); missing_texture_texture = get_editor_theme_icon(SNAME("TileSet")); - expanded_area->add_theme_style_override("panel", get_theme_stylebox("panel", "Tree")); + expanded_area->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), "Tree")); _update_sources_list(); } break; @@ -849,7 +849,7 @@ TileSetEditor::TileSetEditor() { source_sort_button->set_tooltip_text(TTR("Sort Sources")); PopupMenu *p = source_sort_button->get_popup(); - p->connect("id_pressed", callable_mp(this, &TileSetEditor::_set_source_sort)); + p->connect(SceneStringName(id_pressed), callable_mp(this, &TileSetEditor::_set_source_sort)); p->add_radio_check_item(TTR("Sort by ID (Ascending)"), TilesEditorUtils::SOURCE_SORT_ID); p->add_radio_check_item(TTR("Sort by ID (Descending)"), TilesEditorUtils::SOURCE_SORT_ID_REVERSE); p->add_radio_check_item(TTR("Sort by Name (Ascending)"), TilesEditorUtils::SOURCE_SORT_NAME); @@ -887,7 +887,7 @@ TileSetEditor::TileSetEditor() { sources_add_button->get_popup()->set_item_tooltip(-1, TTR("A palette of tiles made from a texture.")); sources_add_button->get_popup()->add_item(TTR("Scenes Collection")); sources_add_button->get_popup()->set_item_tooltip(-1, TTR("A collection of scenes that can be instantiated and placed as tiles.")); - sources_add_button->get_popup()->connect("id_pressed", callable_mp(this, &TileSetEditor::_source_add_id_pressed)); + sources_add_button->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &TileSetEditor::_source_add_id_pressed)); sources_bottom_actions->add_child(sources_add_button); sources_advanced_menu_button = memnew(MenuButton); @@ -895,7 +895,7 @@ TileSetEditor::TileSetEditor() { sources_advanced_menu_button->set_theme_type_variation("FlatButton"); sources_advanced_menu_button->get_popup()->add_item(TTR("Open Atlas Merging Tool")); sources_advanced_menu_button->get_popup()->add_item(TTR("Manage Tile Proxies")); - sources_advanced_menu_button->get_popup()->connect("id_pressed", callable_mp(this, &TileSetEditor::_sources_advanced_menu_id_pressed)); + sources_advanced_menu_button->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &TileSetEditor::_sources_advanced_menu_id_pressed)); sources_bottom_actions->add_child(sources_advanced_menu_button); sources_bottom_actions->add_child(source_sort_button); diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp index beed89ea10..1e88916672 100644 --- a/editor/plugins/version_control_editor_plugin.cpp +++ b/editor/plugins/version_control_editor_plugin.cpp @@ -1432,7 +1432,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() { extra_options = memnew(MenuButton); extra_options->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("GuiTabMenuHl"), EditorStringName(EditorIcons))); extra_options->get_popup()->connect(SNAME("about_to_popup"), callable_mp(this, &VersionControlEditorPlugin::_update_extra_options)); - extra_options->get_popup()->connect(SNAME("id_pressed"), callable_mp(this, &VersionControlEditorPlugin::_extra_option_selected)); + extra_options->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &VersionControlEditorPlugin::_extra_option_selected)); menu_bar->add_child(extra_options); extra_options->get_popup()->add_item(TTR("Force Push"), EXTRA_OPTION_FORCE_PUSH); @@ -1440,14 +1440,14 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() { extra_options->get_popup()->add_item(TTR("Create New Branch"), EXTRA_OPTION_CREATE_BRANCH); extra_options_remove_branch_list = memnew(PopupMenu); - extra_options_remove_branch_list->connect(SNAME("id_pressed"), callable_mp(this, &VersionControlEditorPlugin::_popup_branch_remove_confirm)); + extra_options_remove_branch_list->connect(SceneStringName(id_pressed), callable_mp(this, &VersionControlEditorPlugin::_popup_branch_remove_confirm)); extra_options->get_popup()->add_submenu_node_item(TTR("Remove Branch"), extra_options_remove_branch_list); extra_options->get_popup()->add_separator(); extra_options->get_popup()->add_item(TTR("Create New Remote"), EXTRA_OPTION_CREATE_REMOTE); extra_options_remove_remote_list = memnew(PopupMenu); - extra_options_remove_remote_list->connect(SNAME("id_pressed"), callable_mp(this, &VersionControlEditorPlugin::_popup_remote_remove_confirm)); + extra_options_remove_remote_list->connect(SceneStringName(id_pressed), callable_mp(this, &VersionControlEditorPlugin::_popup_remote_remove_confirm)); extra_options->get_popup()->add_submenu_node_item(TTR("Remove Remote"), extra_options_remove_remote_list); change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_NEW] = TTR("New"); diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 438d798120..290e0a3239 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -789,7 +789,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool } // Set the minimum width of a node based on the preview size to avoid a resize when toggling the preview. - Ref<StyleBoxFlat> graph_node_stylebox = graph->get_theme_stylebox("panel", "GraphNode"); + Ref<StyleBoxFlat> graph_node_stylebox = graph->get_theme_stylebox(SceneStringName(panel), "GraphNode"); int port_preview_size = EDITOR_GET("editors/visual_editors/visual_shader/port_preview_size"); if (!is_frame && !is_reroute) { node->set_custom_minimum_size(Size2((Math::ceil(graph_node_stylebox->get_minimum_size().width) + port_preview_size) * EDSCALE, 0)); @@ -1138,14 +1138,14 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool Label *label = memnew(Label); label->set_auto_translate_mode(Node::AUTO_TRANSLATE_MODE_DISABLED); // TODO: Implement proper translation switch. label->set_text(name_left); - label->add_theme_style_override("normal", editor->get_theme_stylebox(SNAME("label_style"), SNAME("VShaderEditor"))); //more compact + label->add_theme_style_override(CoreStringName(normal), editor->get_theme_stylebox(SNAME("label_style"), SNAME("VShaderEditor"))); //more compact hb->add_child(label); if (vsnode->is_input_port_default(j, mode) && !port_left_used) { Label *hint_label = memnew(Label); hint_label->set_text(TTR("[default]")); hint_label->add_theme_color_override("font_color", editor->get_theme_color(SNAME("font_readonly_color"), SNAME("TextEdit"))); - hint_label->add_theme_style_override("normal", editor->get_theme_stylebox(SNAME("label_style"), SNAME("VShaderEditor"))); + hint_label->add_theme_style_override(CoreStringName(normal), editor->get_theme_stylebox(SNAME("label_style"), SNAME("VShaderEditor"))); hb->add_child(hint_label); } } @@ -1188,7 +1188,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool Label *label = memnew(Label); label->set_auto_translate_mode(Node::AUTO_TRANSLATE_MODE_DISABLED); // TODO: Implement proper translation switch. label->set_text(name_right); - label->add_theme_style_override("normal", editor->get_theme_stylebox(SNAME("label_style"), SNAME("VShaderEditor"))); //more compact + label->add_theme_style_override(CoreStringName(normal), editor->get_theme_stylebox(SNAME("label_style"), SNAME("VShaderEditor"))); //more compact hb->add_child(label); } } @@ -4929,7 +4929,7 @@ void VisualShaderEditor::_notification(int p_what) { preview_text->add_comment_delimiter("/*", "*/", false); preview_text->add_comment_delimiter("//", "", true); - error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Panel"))); + error_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Panel"))); error_label->begin_bulk_theme_override(); error_label->add_theme_font_override("font", get_theme_font(SNAME("status_source"), EditorStringName(EditorFonts))); error_label->add_theme_font_size_override("font_size", get_theme_font_size(SNAME("status_source_size"), EditorStringName(EditorFonts))); @@ -6195,7 +6195,7 @@ VisualShaderEditor::VisualShaderEditor() { PopupMenu *varying_menu = varying_button->get_popup(); varying_menu->add_item(TTR("Add Varying"), int(VaryingMenuOptions::ADD)); varying_menu->add_item(TTR("Remove Varying"), int(VaryingMenuOptions::REMOVE)); - varying_menu->connect("id_pressed", callable_mp(this, &VisualShaderEditor::_varying_menu_id_pressed)); + varying_menu->connect(SceneStringName(id_pressed), callable_mp(this, &VisualShaderEditor::_varying_menu_id_pressed)); preview_shader = memnew(Button); preview_shader->set_theme_type_variation("FlatButton"); @@ -6251,14 +6251,14 @@ VisualShaderEditor::VisualShaderEditor() { popup_menu->add_item(TTR("Delete"), NodeMenuOptions::DELETE); popup_menu->add_item(TTR("Duplicate"), NodeMenuOptions::DUPLICATE); popup_menu->add_item(TTR("Clear Copy Buffer"), NodeMenuOptions::CLEAR_COPY_BUFFER); - popup_menu->connect("id_pressed", callable_mp(this, &VisualShaderEditor::_node_menu_id_pressed)); + popup_menu->connect(SceneStringName(id_pressed), callable_mp(this, &VisualShaderEditor::_node_menu_id_pressed)); connection_popup_menu = memnew(PopupMenu); add_child(connection_popup_menu); connection_popup_menu->add_item(TTR("Disconnect"), ConnectionMenuOptions::DISCONNECT); connection_popup_menu->add_item(TTR("Insert New Node"), ConnectionMenuOptions::INSERT_NEW_NODE); connection_popup_menu->add_item(TTR("Insert New Reroute"), ConnectionMenuOptions::INSERT_NEW_REROUTE); - connection_popup_menu->connect("id_pressed", callable_mp(this, &VisualShaderEditor::_connection_menu_id_pressed)); + connection_popup_menu->connect(SceneStringName(id_pressed), callable_mp(this, &VisualShaderEditor::_connection_menu_id_pressed)); /////////////////////////////////////// // SHADER NODES TREE @@ -6280,7 +6280,7 @@ VisualShaderEditor::VisualShaderEditor() { tools = memnew(MenuButton); filter_hb->add_child(tools); tools->set_tooltip_text(TTR("Options")); - tools->get_popup()->connect("id_pressed", callable_mp(this, &VisualShaderEditor::_tools_menu_option)); + tools->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &VisualShaderEditor::_tools_menu_option)); tools->get_popup()->add_item(TTR("Expand All"), EXPAND_ALL); tools->get_popup()->add_item(TTR("Collapse All"), COLLAPSE_ALL); diff --git a/editor/progress_dialog.cpp b/editor/progress_dialog.cpp index 746b244bed..406425e9fd 100644 --- a/editor/progress_dialog.cpp +++ b/editor/progress_dialog.cpp @@ -130,7 +130,7 @@ void ProgressDialog::_popup() { Size2 ms = main->get_combined_minimum_size(); ms.width = MAX(500 * EDSCALE, ms.width); - Ref<StyleBox> style = main->get_theme_stylebox(SNAME("panel"), SNAME("PopupMenu")); + Ref<StyleBox> style = main->get_theme_stylebox(SceneStringName(panel), SNAME("PopupMenu")); ms += style->get_minimum_size(); main->set_offset(SIDE_LEFT, style->get_margin(SIDE_LEFT)); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 00aa78f342..79066608f9 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -220,8 +220,8 @@ void ProjectManager::_update_theme(bool p_skip_creation) { root_container->add_theme_constant_override("margin_right", top_bar_separation); main_vbox->add_theme_constant_override("separation", top_bar_separation); - background_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("Background"), EditorStringName(EditorStyles))); - main_view_container->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TabContainer"))); + background_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("Background"), EditorStringName(EditorStyles))); + main_view_container->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("TabContainer"))); title_bar_logo->set_icon(get_editor_theme_icon(SNAME("TitleBarLogo"))); @@ -231,7 +231,7 @@ void ProjectManager::_update_theme(bool p_skip_creation) { // Project list. { loading_label->add_theme_font_override("font", get_theme_font(SNAME("bold"), EditorStringName(EditorFonts))); - project_list_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("project_list"), SNAME("ProjectManager"))); + project_list_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("project_list"), SNAME("ProjectManager"))); empty_list_create_project->set_icon(get_editor_theme_icon(SNAME("Add"))); empty_list_import_project->set_icon(get_editor_theme_icon(SNAME("Load"))); @@ -273,7 +273,7 @@ void ProjectManager::_update_theme(bool p_skip_creation) { // Asset library popup. if (asset_library) { // Removes extra border margins. - asset_library->add_theme_style_override("panel", memnew(StyleBoxEmpty)); + asset_library->add_theme_style_override(SceneStringName(panel), memnew(StyleBoxEmpty)); } } } @@ -1297,7 +1297,7 @@ ProjectManager::ProjectManager() { empty_list_message->set_use_bbcode(true); empty_list_message->set_fit_content(true); empty_list_message->set_h_size_flags(SIZE_EXPAND_FILL); - empty_list_message->add_theme_style_override("normal", memnew(StyleBoxEmpty)); + empty_list_message->add_theme_style_override(CoreStringName(normal), memnew(StyleBoxEmpty)); const String line1 = TTR("You don't have any projects yet."); const String line2 = TTR("Get started by creating a new one,\nimporting one that exists, or by downloading a project template from the Asset Library!"); diff --git a/editor/project_manager/quick_settings_dialog.cpp b/editor/project_manager/quick_settings_dialog.cpp index 63fe423b1f..c9a43f863e 100644 --- a/editor/project_manager/quick_settings_dialog.cpp +++ b/editor/project_manager/quick_settings_dialog.cpp @@ -181,7 +181,7 @@ void QuickSettingsDialog::update_size_limits(const Size2 &p_max_popup_size) { void QuickSettingsDialog::_notification(int p_what) { switch (p_what) { case NOTIFICATION_THEME_CHANGED: { - settings_list_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("Background"), EditorStringName(EditorStyles))); + settings_list_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("Background"), EditorStringName(EditorStyles))); restart_required_label->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), EditorStringName(Editor))); custom_theme_label->add_theme_color_override("font_color", get_theme_color(SNAME("font_placeholder_color"), EditorStringName(Editor))); diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index dc9d1df4e8..cf1ad36adc 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -587,7 +587,7 @@ void ProjectSettingsEditor::_update_theme() { del_button->set_icon(get_editor_theme_icon(SNAME("Remove"))); search_box->set_right_icon(get_editor_theme_icon(SNAME("Search"))); restart_close_button->set_icon(get_editor_theme_icon(SNAME("Close"))); - restart_container->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); + restart_container->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree"))); restart_icon->set_texture(get_editor_theme_icon(SNAME("StatusWarning"))); restart_label->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), EditorStringName(Editor))); diff --git a/editor/renames_map_3_to_4.cpp b/editor/renames_map_3_to_4.cpp index c1d19fdd38..8eab3fbea9 100644 --- a/editor/renames_map_3_to_4.cpp +++ b/editor/renames_map_3_to_4.cpp @@ -1046,7 +1046,7 @@ const char *RenamesMap3To4::gdscript_properties_renames[][2] = { // make sure to add it to the C# rename map too. // Too common words, users may use these names for variables or in comments. - // { "bg", "panel" }, // Theme + // { "bg", SceneStringName(panel) }, // Theme // { "alt", "alt_pressed" }, // InputEventWithModifiers // { "command", "command_pressed" }, // InputEventWithModifiers // { "control", "ctrl_pressed" }, // InputEventWithModifiers diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index f90fa7603f..23588e0e6c 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -3333,9 +3333,9 @@ void SceneTreeDock::_files_dropped(const Vector<String> &p_files, NodePath p_to, // Either instantiate scenes or create AudioStreamPlayers. int to_pos = -1; _normalize_drop(node, to_pos, p_type); - if (res_type == "PackedScene") { + if (ClassDB::is_parent_class(res_type, "PackedScene")) { _perform_instantiate_scenes(p_files, node, to_pos); - } else { + } else if (ClassDB::is_parent_class(res_type, "AudioStream")) { _perform_create_audio_stream_players(p_files, node, to_pos); } } @@ -4397,12 +4397,12 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec filter->add_theme_constant_override("minimum_character_width", 0); filter->connect("text_changed", callable_mp(this, &SceneTreeDock::_filter_changed)); filter->connect(SceneStringName(gui_input), callable_mp(this, &SceneTreeDock::_filter_gui_input)); - filter->get_menu()->connect("id_pressed", callable_mp(this, &SceneTreeDock::_filter_option_selected)); + filter->get_menu()->connect(SceneStringName(id_pressed), callable_mp(this, &SceneTreeDock::_filter_option_selected)); _append_filter_options_to(filter->get_menu()); filter_quick_menu = memnew(PopupMenu); filter_quick_menu->set_theme_type_variation("FlatMenuButton"); - filter_quick_menu->connect("id_pressed", callable_mp(this, &SceneTreeDock::_filter_option_selected)); + filter_quick_menu->connect(SceneStringName(id_pressed), callable_mp(this, &SceneTreeDock::_filter_option_selected)); filter->add_child(filter_quick_menu); button_create_script = memnew(Button); @@ -4429,7 +4429,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec filter_hbc->add_child(button_tree_menu); PopupMenu *tree_menu = button_tree_menu->get_popup(); - tree_menu->connect("id_pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(false)); + tree_menu->connect(SceneStringName(id_pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(false)); button_hb = memnew(HBoxContainer); vbc->add_child(button_hb); @@ -4549,15 +4549,15 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec menu = memnew(PopupMenu); add_child(menu); - menu->connect("id_pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(false)); + menu->connect(SceneStringName(id_pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(false)); menu_subresources = memnew(PopupMenu); - menu_subresources->connect("id_pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(false)); + menu_subresources->connect(SceneStringName(id_pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(false)); menu->add_child(menu_subresources); menu_properties = memnew(PopupMenu); add_child(menu_properties); - menu_properties->connect("id_pressed", callable_mp(this, &SceneTreeDock::_property_selected)); + menu_properties->connect(SceneStringName(id_pressed), callable_mp(this, &SceneTreeDock::_property_selected)); clear_inherit_confirm = memnew(ConfirmationDialog); clear_inherit_confirm->set_text(TTR("Clear Inheritance? (No Undo!)")); diff --git a/editor/themes/editor_theme_manager.cpp b/editor/themes/editor_theme_manager.cpp index d56094b0f3..9a0941c75e 100644 --- a/editor/themes/editor_theme_manager.cpp +++ b/editor/themes/editor_theme_manager.cpp @@ -675,10 +675,10 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the // Panels. { // Panel. - p_theme->set_stylebox("panel", "Panel", make_flat_stylebox(p_config.dark_color_1, 6, 4, 6, 4, p_config.corner_radius)); + p_theme->set_stylebox(SceneStringName(panel), "Panel", make_flat_stylebox(p_config.dark_color_1, 6, 4, 6, 4, p_config.corner_radius)); // PanelContainer. - p_theme->set_stylebox("panel", "PanelContainer", p_config.panel_container_style); + p_theme->set_stylebox(SceneStringName(panel), "PanelContainer", p_config.panel_container_style); // TooltipPanel & TooltipLabel. { @@ -693,18 +693,18 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the style_tooltip->set_content_margin_all(p_config.base_margin * EDSCALE * 0.5); style_tooltip->set_bg_color(p_config.dark_color_3 * Color(0.8, 0.8, 0.8, 0.9)); style_tooltip->set_border_width_all(0); - p_theme->set_stylebox("panel", "TooltipPanel", style_tooltip); + p_theme->set_stylebox(SceneStringName(panel), "TooltipPanel", style_tooltip); } // PopupPanel - p_theme->set_stylebox("panel", "PopupPanel", p_config.popup_style); + p_theme->set_stylebox(SceneStringName(panel), "PopupPanel", p_config.popup_style); } // Buttons. { // Button. - p_theme->set_stylebox("normal", "Button", p_config.button_style); + p_theme->set_stylebox(CoreStringName(normal), "Button", p_config.button_style); p_theme->set_stylebox("hover", "Button", p_config.button_style_hover); p_theme->set_stylebox(SceneStringName(pressed), "Button", p_config.button_style_pressed); p_theme->set_stylebox("focus", "Button", p_config.button_style_focus); @@ -730,7 +730,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the // MenuButton. - p_theme->set_stylebox("normal", "MenuButton", p_config.panel_container_style); + p_theme->set_stylebox(CoreStringName(normal), "MenuButton", p_config.panel_container_style); p_theme->set_stylebox("hover", "MenuButton", p_config.button_style_hover); p_theme->set_stylebox(SceneStringName(pressed), "MenuButton", p_config.panel_container_style); p_theme->set_stylebox("focus", "MenuButton", p_config.panel_container_style); @@ -746,7 +746,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the // MenuBar. - p_theme->set_stylebox("normal", "MenuBar", p_config.button_style); + p_theme->set_stylebox(CoreStringName(normal), "MenuBar", p_config.button_style); p_theme->set_stylebox("hover", "MenuBar", p_config.button_style_hover); p_theme->set_stylebox(SceneStringName(pressed), "MenuBar", p_config.button_style_pressed); p_theme->set_stylebox("disabled", "MenuBar", p_config.button_style_disabled); @@ -783,7 +783,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the option_button_disabled_style->set_content_margin(SIDE_RIGHT, 4 * EDSCALE); p_theme->set_stylebox("focus", "OptionButton", option_button_focus_style); - p_theme->set_stylebox("normal", "OptionButton", p_config.button_style); + p_theme->set_stylebox(CoreStringName(normal), "OptionButton", p_config.button_style); p_theme->set_stylebox("hover", "OptionButton", p_config.button_style_hover); p_theme->set_stylebox(SceneStringName(pressed), "OptionButton", p_config.button_style_pressed); p_theme->set_stylebox("disabled", "OptionButton", p_config.button_style_disabled); @@ -816,7 +816,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the // CheckButton. - p_theme->set_stylebox("normal", "CheckButton", p_config.panel_container_style); + p_theme->set_stylebox(CoreStringName(normal), "CheckButton", p_config.panel_container_style); p_theme->set_stylebox(SceneStringName(pressed), "CheckButton", p_config.panel_container_style); p_theme->set_stylebox("disabled", "CheckButton", p_config.panel_container_style); p_theme->set_stylebox("hover", "CheckButton", p_config.panel_container_style); @@ -855,7 +855,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the Ref<StyleBoxFlat> checkbox_style = p_config.panel_container_style->duplicate(); checkbox_style->set_content_margin_all(p_config.base_margin * EDSCALE); - p_theme->set_stylebox("normal", "CheckBox", checkbox_style); + p_theme->set_stylebox(CoreStringName(normal), "CheckBox", checkbox_style); p_theme->set_stylebox(SceneStringName(pressed), "CheckBox", checkbox_style); p_theme->set_stylebox("disabled", "CheckBox", checkbox_style); p_theme->set_stylebox("hover", "CheckBox", checkbox_style); @@ -926,7 +926,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the p_theme->set_icon("updown", "Tree", p_theme->get_icon(SNAME("GuiTreeUpdown"), EditorStringName(EditorIcons))); p_theme->set_icon("select_arrow", "Tree", p_theme->get_icon(SNAME("GuiDropdown"), EditorStringName(EditorIcons))); - p_theme->set_stylebox("panel", "Tree", p_config.tree_panel_style); + p_theme->set_stylebox(SceneStringName(panel), "Tree", p_config.tree_panel_style); p_theme->set_stylebox("focus", "Tree", p_config.button_style_focus); p_theme->set_stylebox("custom_button", "Tree", make_empty_stylebox()); p_theme->set_stylebox("custom_button_pressed", "Tree", make_empty_stylebox()); @@ -1029,7 +1029,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the style_itemlist_hover->set_bg_color(p_config.highlight_color * Color(1, 1, 1, 0.3)); style_itemlist_hover->set_border_width_all(0); - p_theme->set_stylebox("panel", "ItemList", style_itemlist_bg); + p_theme->set_stylebox(SceneStringName(panel), "ItemList", style_itemlist_bg); p_theme->set_stylebox("focus", "ItemList", p_config.button_style_focus); p_theme->set_stylebox("cursor", "ItemList", style_itemlist_cursor); p_theme->set_stylebox("cursor_unfocused", "ItemList", style_itemlist_cursor); @@ -1100,7 +1100,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the style_tabbar_background->set_corner_radius(CORNER_BOTTOM_LEFT, 0); style_tabbar_background->set_corner_radius(CORNER_BOTTOM_RIGHT, 0); p_theme->set_stylebox("tabbar_background", "TabContainer", style_tabbar_background); - p_theme->set_stylebox("panel", "TabContainer", p_config.content_panel_style); + p_theme->set_stylebox(SceneStringName(panel), "TabContainer", p_config.content_panel_style); p_theme->set_stylebox("tab_selected", "TabContainer", style_tab_selected); p_theme->set_stylebox("tab_hovered", "TabContainer", style_tab_hovered); @@ -1177,7 +1177,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the // LineEdit. - p_theme->set_stylebox("normal", "LineEdit", text_editor_style); + p_theme->set_stylebox(CoreStringName(normal), "LineEdit", text_editor_style); p_theme->set_stylebox("focus", "LineEdit", p_config.button_style_focus); p_theme->set_stylebox("read_only", "LineEdit", text_editor_disabled_style); @@ -1199,7 +1199,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the // TextEdit. - p_theme->set_stylebox("normal", "TextEdit", text_editor_style); + p_theme->set_stylebox(CoreStringName(normal), "TextEdit", text_editor_style); p_theme->set_stylebox("focus", "TextEdit", p_config.button_style_focus); p_theme->set_stylebox("read_only", "TextEdit", text_editor_disabled_style); @@ -1274,7 +1274,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the p_theme->set_font_size("title_font_size", "Window", p_theme->get_font_size(SNAME("title_size"), EditorStringName(EditorFonts))); // AcceptDialog. - p_theme->set_stylebox("panel", "AcceptDialog", p_config.dialog_style); + p_theme->set_stylebox(SceneStringName(panel), "AcceptDialog", p_config.dialog_style); p_theme->set_constant("buttons_separation", "AcceptDialog", 8 * EDSCALE); // Make buttons with short texts such as "OK" easier to click/tap. p_theme->set_constant("buttons_min_width", "AcceptDialog", p_config.dialogs_buttons_min_size.x * EDSCALE); @@ -1294,7 +1294,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the p_theme->set_color("file_disabled_color", "FileDialog", p_config.font_disabled_color); // PopupDialog. - p_theme->set_stylebox("panel", "PopupDialog", p_config.popup_style); + p_theme->set_stylebox(SceneStringName(panel), "PopupDialog", p_config.popup_style); // PopupMenu. { @@ -1310,7 +1310,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the } else { style_popup_menu->set_border_color(p_config.dark_color_2); } - p_theme->set_stylebox("panel", "PopupMenu", style_popup_menu); + p_theme->set_stylebox(SceneStringName(panel), "PopupMenu", style_popup_menu); Ref<StyleBoxFlat> style_menu_hover = p_config.button_style_hover->duplicate(); // Don't use rounded corners for hover highlights since the StyleBox touches the PopupMenu's edges. @@ -1430,7 +1430,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the { // RichTextLabel. - p_theme->set_stylebox("normal", "RichTextLabel", p_config.tree_panel_style); + p_theme->set_stylebox(CoreStringName(normal), "RichTextLabel", p_config.tree_panel_style); p_theme->set_stylebox("focus", "RichTextLabel", make_empty_stylebox()); p_theme->set_color("default_color", "RichTextLabel", p_config.font_color); @@ -1445,7 +1445,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the // Label. - p_theme->set_stylebox("normal", "Label", p_config.base_empty_style); + p_theme->set_stylebox(CoreStringName(normal), "Label", p_config.base_empty_style); p_theme->set_color("font_color", "Label", p_config.font_color); p_theme->set_color("font_shadow_color", "Label", Color(0, 0, 0, 0)); @@ -1473,7 +1473,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the { // GraphEdit. - p_theme->set_stylebox("panel", "GraphEdit", p_config.tree_panel_style); + p_theme->set_stylebox(SceneStringName(panel), "GraphEdit", p_config.tree_panel_style); p_theme->set_stylebox("menu_panel", "GraphEdit", make_flat_stylebox(p_config.dark_color_1 * Color(1, 1, 1, 0.6), 4, 2, 4, 2, 3)); float grid_base_brightness = p_config.dark_theme ? 1.0 : 0.0; @@ -1513,7 +1513,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the Ref<StyleBoxFlat> style_minimap_bg = make_flat_stylebox(p_config.dark_color_1, 0, 0, 0, 0); style_minimap_bg->set_border_color(p_config.dark_color_3); style_minimap_bg->set_border_width_all(1); - p_theme->set_stylebox("panel", "GraphEditMinimap", style_minimap_bg); + p_theme->set_stylebox(SceneStringName(panel), "GraphEditMinimap", style_minimap_bg); Ref<StyleBoxFlat> style_minimap_camera; Ref<StyleBoxFlat> style_minimap_node; @@ -1590,7 +1590,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the // GraphElement. - p_theme->set_stylebox("panel", "GraphElement", gn_panel_style); + p_theme->set_stylebox(SceneStringName(panel), "GraphElement", gn_panel_style); p_theme->set_stylebox("panel_selected", "GraphElement", gn_panel_selected_style); p_theme->set_stylebox("titlebar", "GraphElement", gn_titlebar_style); p_theme->set_stylebox("titlebar_selected", "GraphElement", gn_titlebar_selected_style); @@ -1602,7 +1602,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the Ref<StyleBoxEmpty> gn_slot_style = make_empty_stylebox(12, 0, 12, 0); - p_theme->set_stylebox("panel", "GraphNode", gn_panel_style); + p_theme->set_stylebox(SceneStringName(panel), "GraphNode", gn_panel_style); p_theme->set_stylebox("panel_selected", "GraphNode", gn_panel_selected_style); p_theme->set_stylebox("titlebar", "GraphNode", gn_titlebar_style); p_theme->set_stylebox("titlebar_selected", "GraphNode", gn_titlebar_selected_style); @@ -1620,7 +1620,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the // GraphNode's title Label. p_theme->set_type_variation("GraphNodeTitleLabel", "Label"); - p_theme->set_stylebox("normal", "GraphNodeTitleLabel", make_empty_stylebox(0, 0, 0, 0)); + p_theme->set_stylebox(CoreStringName(normal), "GraphNodeTitleLabel", make_empty_stylebox(0, 0, 0, 0)); p_theme->set_color("font_color", "GraphNodeTitleLabel", p_config.dark_theme ? p_config.font_color : Color(1, 1, 1)); // Also use a bright font color for light themes. p_theme->set_color("font_shadow_color", "GraphNodeTitleLabel", Color(0, 0, 0, 0.35)); p_theme->set_constant("shadow_outline_size", "GraphNodeTitleLabel", 4); @@ -1644,7 +1644,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the Ref<StyleBoxFlat> graphframe_sb_selected = graphframe_sb->duplicate(); graphframe_sb_selected->set_border_color(gn_selected_border_color); - p_theme->set_stylebox("panel", "GraphFrame", graphframe_sb); + p_theme->set_stylebox(SceneStringName(panel), "GraphFrame", graphframe_sb); p_theme->set_stylebox("panel_selected", "GraphFrame", graphframe_sb_selected); p_theme->set_stylebox("titlebar", "GraphFrame", make_empty_stylebox(4, 4, 4, 4)); p_theme->set_stylebox("titlebar_selected", "GraphFrame", make_empty_stylebox(4, 4, 4, 4)); @@ -1652,7 +1652,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the // GraphFrame's title Label. p_theme->set_type_variation("GraphFrameTitleLabel", "Label"); - p_theme->set_stylebox("normal", "GraphFrameTitleLabel", memnew(StyleBoxEmpty)); + p_theme->set_stylebox(CoreStringName(normal), "GraphFrameTitleLabel", memnew(StyleBoxEmpty)); p_theme->set_font_size("font_size", "GraphFrameTitleLabel", 22); p_theme->set_color("font_color", "GraphFrameTitleLabel", Color(1, 1, 1)); p_theme->set_color("font_shadow_color", "GraphFrameTitleLabel", Color(0, 0, 0, 0)); @@ -1669,7 +1669,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the Ref<StyleBox> vs_reroute_panel_style = make_empty_stylebox(); Ref<StyleBox> vs_reroute_titlebar_style = vs_reroute_panel_style->duplicate(); vs_reroute_titlebar_style->set_content_margin_all(16); - p_theme->set_stylebox("panel", "VSRerouteNode", vs_reroute_panel_style); + p_theme->set_stylebox(SceneStringName(panel), "VSRerouteNode", vs_reroute_panel_style); p_theme->set_stylebox("panel_selected", "VSRerouteNode", vs_reroute_panel_style); p_theme->set_stylebox("titlebar", "VSRerouteNode", vs_reroute_titlebar_style); p_theme->set_stylebox("titlebar_selected", "VSRerouteNode", vs_reroute_titlebar_style); @@ -1730,7 +1730,7 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme tag->set_corner_radius(CORNER_BOTTOM_LEFT, 0); tag->set_corner_radius(CORNER_TOP_RIGHT, 4); tag->set_corner_radius(CORNER_BOTTOM_RIGHT, 4); - p_theme->set_stylebox("normal", "ProjectTag", tag); + p_theme->set_stylebox(CoreStringName(normal), "ProjectTag", tag); tag = p_config.button_style_hover->duplicate(); tag->set_corner_radius(CORNER_TOP_LEFT, 0); @@ -1809,13 +1809,13 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme menu_transparent_style->set_content_margin((Side)i, p_config.button_style->get_content_margin((Side)i)); main_screen_button_hover->set_content_margin((Side)i, p_config.button_style_hover->get_content_margin((Side)i)); } - p_theme->set_stylebox("normal", "MainScreenButton", menu_transparent_style); + p_theme->set_stylebox(CoreStringName(normal), "MainScreenButton", menu_transparent_style); p_theme->set_stylebox(SceneStringName(pressed), "MainScreenButton", menu_transparent_style); p_theme->set_stylebox("hover", "MainScreenButton", main_screen_button_hover); p_theme->set_stylebox("hover_pressed", "MainScreenButton", main_screen_button_hover); p_theme->set_type_variation("MainMenuBar", "FlatMenuButton"); - p_theme->set_stylebox("normal", "MainMenuBar", menu_transparent_style); + p_theme->set_stylebox(CoreStringName(normal), "MainMenuBar", menu_transparent_style); p_theme->set_stylebox(SceneStringName(pressed), "MainMenuBar", main_screen_button_hover); p_theme->set_stylebox("hover", "MainMenuBar", main_screen_button_hover); p_theme->set_stylebox("hover_pressed", "MainMenuBar", main_screen_button_hover); @@ -1830,7 +1830,7 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme style_bottom_panel->set_corner_radius_all(p_config.corner_radius * EDSCALE); p_theme->set_stylebox("BottomPanel", EditorStringName(EditorStyles), style_bottom_panel); p_theme->set_type_variation("BottomPanelButton", "FlatMenuButton"); - p_theme->set_stylebox("normal", "BottomPanelButton", menu_transparent_style); + p_theme->set_stylebox(CoreStringName(normal), "BottomPanelButton", menu_transparent_style); p_theme->set_stylebox(SceneStringName(pressed), "BottomPanelButton", menu_transparent_style); p_theme->set_stylebox("hover_pressed", "BottomPanelButton", main_screen_button_hover); p_theme->set_stylebox("hover", "BottomPanelButton", main_screen_button_hover); @@ -1900,12 +1900,12 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme } style_flat_button_pressed->set_bg_color(flat_pressed_color); - p_theme->set_stylebox("normal", "FlatButton", style_flat_button); + p_theme->set_stylebox(CoreStringName(normal), "FlatButton", style_flat_button); p_theme->set_stylebox("hover", "FlatButton", style_flat_button_hover); p_theme->set_stylebox(SceneStringName(pressed), "FlatButton", style_flat_button_pressed); p_theme->set_stylebox("disabled", "FlatButton", style_flat_button); - p_theme->set_stylebox("normal", "FlatMenuButton", style_flat_button); + p_theme->set_stylebox(CoreStringName(normal), "FlatMenuButton", style_flat_button); p_theme->set_stylebox("hover", "FlatMenuButton", style_flat_button_hover); p_theme->set_stylebox(SceneStringName(pressed), "FlatMenuButton", style_flat_button_pressed); p_theme->set_stylebox("disabled", "FlatMenuButton", style_flat_button); @@ -1930,7 +1930,7 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme if (!p_config.dark_theme) { editor_log_button_pressed->set_bg_color(flat_pressed_color.lightened(0.5)); } - p_theme->set_stylebox("normal", "EditorLogFilterButton", style_flat_button); + p_theme->set_stylebox(CoreStringName(normal), "EditorLogFilterButton", style_flat_button); p_theme->set_stylebox("hover", "EditorLogFilterButton", style_flat_button_hover); p_theme->set_stylebox(SceneStringName(pressed), "EditorLogFilterButton", editor_log_button_pressed); } @@ -1951,7 +1951,7 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme Ref<StyleBoxFlat> panel_button_style_disabled = p_config.button_style_disabled->duplicate(); panel_button_style_disabled->set_bg_color(p_config.disabled_bg_color); - p_theme->set_stylebox("normal", "PanelBackgroundButton", panel_button_style); + p_theme->set_stylebox(CoreStringName(normal), "PanelBackgroundButton", panel_button_style); p_theme->set_stylebox("hover", "PanelBackgroundButton", panel_button_style_hover); p_theme->set_stylebox(SceneStringName(pressed), "PanelBackgroundButton", panel_button_style_pressed); p_theme->set_stylebox("disabled", "PanelBackgroundButton", panel_button_style_disabled); @@ -1969,9 +1969,9 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme Ref<StyleBoxFlat> style_complex_window = p_config.window_style->duplicate(); style_complex_window->set_bg_color(p_config.dark_color_2); style_complex_window->set_border_color(p_config.dark_color_2); - p_theme->set_stylebox("panel", "EditorSettingsDialog", style_complex_window); - p_theme->set_stylebox("panel", "ProjectSettingsEditor", style_complex_window); - p_theme->set_stylebox("panel", "EditorAbout", style_complex_window); + p_theme->set_stylebox(SceneStringName(panel), "EditorSettingsDialog", style_complex_window); + p_theme->set_stylebox(SceneStringName(panel), "ProjectSettingsEditor", style_complex_window); + p_theme->set_stylebox(SceneStringName(panel), "EditorAbout", style_complex_window); } // InspectorActionButton. @@ -1986,7 +1986,7 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme Ref<StyleBoxFlat> style_inspector_action = p_config.button_style->duplicate(); style_inspector_action->set_bg_color(color_inspector_action); style_inspector_action->set_content_margin(SIDE_RIGHT, action_extra_margin); - p_theme->set_stylebox("normal", "InspectorActionButton", style_inspector_action); + p_theme->set_stylebox(CoreStringName(normal), "InspectorActionButton", style_inspector_action); style_inspector_action = p_config.button_style_hover->duplicate(); style_inspector_action->set_content_margin(SIDE_RIGHT, action_extra_margin); @@ -2016,7 +2016,7 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme // Unpressed icon is dim, so use a dim highlight. p_theme->set_color("icon_hover_color", "PreviewLightButton", dim_light_highlighted_color); - p_theme->set_stylebox("normal", "PreviewLightButton", sb_empty_borderless); + p_theme->set_stylebox(CoreStringName(normal), "PreviewLightButton", sb_empty_borderless); p_theme->set_stylebox("hover", "PreviewLightButton", sb_empty_borderless); p_theme->set_stylebox("focus", "PreviewLightButton", sb_empty_borderless); p_theme->set_stylebox(SceneStringName(pressed), "PreviewLightButton", sb_empty_borderless); @@ -2033,11 +2033,11 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme Ref<StyleBoxFlat> style_content_panel_odd = p_config.content_panel_style->duplicate(); style_content_panel_odd->set_bg_color(p_config.disabled_bg_color); - p_theme->set_stylebox("panel", "TabContainerOdd", style_content_panel_odd); + p_theme->set_stylebox(SceneStringName(panel), "TabContainerOdd", style_content_panel_odd); } // EditorValidationPanel. - p_theme->set_stylebox("panel", "EditorValidationPanel", p_config.tree_panel_style); + p_theme->set_stylebox(SceneStringName(panel), "EditorValidationPanel", p_config.tree_panel_style); // ControlEditor. { @@ -2051,7 +2051,7 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme control_editor_popup_style->set_content_margin(SIDE_BOTTOM, p_config.base_margin * EDSCALE); control_editor_popup_style->set_border_width_all(0); - p_theme->set_stylebox("panel", "ControlEditorPopupPanel", control_editor_popup_style); + p_theme->set_stylebox(SceneStringName(panel), "ControlEditorPopupPanel", control_editor_popup_style); } } @@ -2232,7 +2232,7 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme style->set_corner_radius(CORNER_BOTTOM_RIGHT, 0); p_theme->set_type_variation("EditorHelpBitTitle", "RichTextLabel"); - p_theme->set_stylebox("normal", "EditorHelpBitTitle", style); + p_theme->set_stylebox(CoreStringName(normal), "EditorHelpBitTitle", style); } // EditorHelpBitContent. @@ -2242,12 +2242,12 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme style->set_corner_radius(CORNER_TOP_RIGHT, 0); p_theme->set_type_variation("EditorHelpBitContent", "RichTextLabel"); - p_theme->set_stylebox("normal", "EditorHelpBitContent", style); + p_theme->set_stylebox(CoreStringName(normal), "EditorHelpBitContent", style); } // Asset Library. p_theme->set_stylebox("bg", "AssetLib", p_config.base_empty_style); - p_theme->set_stylebox("panel", "AssetLib", p_config.content_panel_style); + p_theme->set_stylebox(SceneStringName(panel), "AssetLib", p_config.content_panel_style); p_theme->set_color("status_color", "AssetLib", Color(0.5, 0.5, 0.5)); // FIXME: Use a defined color instead. p_theme->set_icon("dismiss", "AssetLib", p_theme->get_icon(SNAME("Close"), EditorStringName(EditorIcons))); @@ -2261,7 +2261,7 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme // FIXME: Introduce Theme::get_font_height() / Control::get_theme_font_height() / Window::get_theme_font_height(). const int offset_i1 = p_theme->get_font(SNAME("tab_selected"), SNAME("TabContainer"))->get_height(p_theme->get_font_size(SNAME("tab_selected"), SNAME("TabContainer"))); const int offset_i2 = p_theme->get_stylebox(SNAME("tab_selected"), SNAME("TabContainer"))->get_minimum_size().height; - const int offset_i3 = p_theme->get_stylebox(SNAME("panel"), SNAME("TabContainer"))->get_content_margin(SIDE_TOP); + const int offset_i3 = p_theme->get_stylebox(SceneStringName(panel), SNAME("TabContainer"))->get_content_margin(SIDE_TOP); const int invisible_top_offset = offset_i1 + offset_i2 + offset_i3; Ref<StyleBoxFlat> invisible_top_panel_style = p_config.content_panel_style->duplicate(); @@ -2308,7 +2308,7 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme // StateMachine graph. { - p_theme->set_stylebox("panel", "GraphStateMachine", p_config.tree_panel_style); + p_theme->set_stylebox(SceneStringName(panel), "GraphStateMachine", p_config.tree_panel_style); p_theme->set_stylebox("error_panel", "GraphStateMachine", p_config.tree_panel_style); p_theme->set_color("error_color", "GraphStateMachine", p_config.error_color); @@ -2486,7 +2486,7 @@ void EditorThemeManager::_populate_text_editor_styles(const Ref<EditorTheme> &p_ const Color background_color = EDITOR_GET("text_editor/theme/highlighting/background_color"); Ref<StyleBoxFlat> code_edit_stylebox = make_flat_stylebox(background_color, p_config.widget_margin.x, p_config.widget_margin.y, p_config.widget_margin.x, p_config.widget_margin.y, p_config.corner_radius); - p_theme->set_stylebox("normal", "CodeEdit", code_edit_stylebox); + p_theme->set_stylebox(CoreStringName(normal), "CodeEdit", code_edit_stylebox); p_theme->set_stylebox("read_only", "CodeEdit", code_edit_stylebox); p_theme->set_stylebox("focus", "CodeEdit", memnew(StyleBoxEmpty)); @@ -2554,7 +2554,7 @@ void EditorThemeManager::_populate_visual_shader_styles(const Ref<EditorTheme> & ed_settings->set_initial_value("editors/visual_editors/connection_colors/sampler_color", Color(1.0, 1.0, 0.0), true); // Node category colors (used for the node headers) - Ref<StyleBoxFlat> gn_panel_style = p_theme->get_stylebox("panel", "GraphNode"); + Ref<StyleBoxFlat> gn_panel_style = p_theme->get_stylebox(SceneStringName(panel), "GraphNode"); Color gn_bg_color = gn_panel_style->get_bg_color(); ed_settings->set_initial_value("editors/visual_editors/category_colors/output_color", gn_bg_color, true); ed_settings->set_initial_value("editors/visual_editors/category_colors/color_color", gn_bg_color, true); diff --git a/editor/window_wrapper.cpp b/editor/window_wrapper.cpp index b964a07285..b75d641509 100644 --- a/editor/window_wrapper.cpp +++ b/editor/window_wrapper.cpp @@ -152,7 +152,7 @@ void WindowWrapper::_notification(int p_what) { set_process_shortcut_input(true); } break; case NOTIFICATION_THEME_CHANGED: { - window_background->add_theme_style_override("panel", get_theme_stylebox("PanelForeground", EditorStringName(EditorStyles))); + window_background->add_theme_style_override(SceneStringName(panel), get_theme_stylebox("PanelForeground", EditorStringName(EditorStyles))); } break; } } @@ -391,7 +391,7 @@ void ScreenSelect::_notification(int p_what) { } break; case NOTIFICATION_THEME_CHANGED: { set_icon(get_editor_theme_icon("MakeFloating")); - popup_background->add_theme_style_override("panel", get_theme_stylebox("PanelForeground", EditorStringName(EditorStyles))); + popup_background->add_theme_style_override(SceneStringName(panel), get_theme_stylebox("PanelForeground", EditorStringName(EditorStyles))); const real_t popup_height = real_t(get_theme_font_size("font_size")) * 2.0; popup->set_min_size(Size2(0, popup_height * 3)); diff --git a/main/main.cpp b/main/main.cpp index 20ffdf5ae1..af29e18c46 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -90,6 +90,7 @@ #endif #ifdef TOOLS_ENABLED +#include "editor/debugger/debug_adapter/debug_adapter_server.h" #include "editor/debugger/editor_debugger_node.h" #include "editor/doc_data_class_path.gen.h" #include "editor/doc_tools.h" @@ -518,8 +519,9 @@ void Main::print_help(const char *p_binary) { print_help_option("-e, --editor", "Start the editor instead of running the scene.\n", CLI_OPTION_AVAILABILITY_EDITOR); print_help_option("-p, --project-manager", "Start the project manager, even if a project is auto-detected.\n", CLI_OPTION_AVAILABILITY_EDITOR); print_help_option("--debug-server <uri>", "Start the editor debug server (<protocol>://<host/IP>[:port], e.g. tcp://127.0.0.1:6007)\n", CLI_OPTION_AVAILABILITY_EDITOR); + print_help_option("--dap-port <port>", "Use the specified port for the GDScript Debugger Adaptor protocol. Recommended port range [1024, 49151].\n", CLI_OPTION_AVAILABILITY_EDITOR); #if defined(MODULE_GDSCRIPT_ENABLED) && !defined(GDSCRIPT_NO_LSP) - print_help_option("--lsp-port <port>", "Use the specified port for the GDScript language server protocol. The port should be between 1025 and 49150.\n", CLI_OPTION_AVAILABILITY_EDITOR); + print_help_option("--lsp-port <port>", "Use the specified port for the GDScript language server protocol. Recommended port range [1024, 49151].\n", CLI_OPTION_AVAILABILITY_EDITOR); #endif // MODULE_GDSCRIPT_ENABLED && !GDSCRIPT_NO_LSP #endif print_help_option("--quit", "Quit after the first iteration.\n"); @@ -1714,6 +1716,21 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph goto error; } #endif // TOOLS_ENABLED && MODULE_GDSCRIPT_ENABLED && !GDSCRIPT_NO_LSP +#if defined(TOOLS_ENABLED) + } else if (arg == "--dap-port") { + if (N) { + int port_override = N->get().to_int(); + if (port_override < 0 || port_override > 65535) { + OS::get_singleton()->print("<port> argument for --dap-port <port> must be between 0 and 65535.\n"); + goto error; + } + DebugAdapterServer::port_override = port_override; + N = N->next(); + } else { + OS::get_singleton()->print("Missing <port> argument for --dap-port <port>.\n"); + goto error; + } +#endif // TOOLS_ENABLED } else if (arg == "--" || arg == "++") { adding_user_args = true; } else { @@ -2841,8 +2858,10 @@ Error Main::setup2() { OS::get_singleton()->benchmark_end_measure("Startup", "Servers"); +#ifndef WEB_ENABLED // Add a blank line for readability. Engine::get_singleton()->print_header(""); +#endif // WEB_ENABLED register_core_singletons(); @@ -4180,6 +4199,12 @@ void Main::cleanup(bool p_force) { ERR_FAIL_COND(!_start_success); } +#ifdef DEBUG_ENABLED + if (input) { + input->flush_frame_parsed_events(); + } +#endif + for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) { TextServerManager::get_singleton()->get_interface(i)->cleanup(); } diff --git a/methods.py b/methods.py index 7600e6d445..f3798d121a 100644 --- a/methods.py +++ b/methods.py @@ -531,6 +531,7 @@ def no_verbose(env): link_shared_library_message = "{}Linking Shared Library {}$TARGET{} ...{}".format(*colors) java_library_message = "{}Creating Java Archive {}$TARGET{} ...{}".format(*colors) compiled_resource_message = "{}Creating Compiled Resource {}$TARGET{} ...{}".format(*colors) + zip_archive_message = "{}Archiving {}$TARGET{} ...{}".format(*colors) generated_file_message = "{}Generating {}$TARGET{} ...{}".format(*colors) env["CXXCOMSTR"] = compile_source_message @@ -544,6 +545,7 @@ def no_verbose(env): env["JARCOMSTR"] = java_library_message env["JAVACCOMSTR"] = java_compile_source_message env["RCCOMSTR"] = compiled_resource_message + env["ZIPCOMSTR"] = zip_archive_message env["GENCOMSTR"] = generated_file_message diff --git a/misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist b/misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist index ee5f1d35ae..3d2ae6b52b 100644 --- a/misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist +++ b/misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist @@ -54,7 +54,7 @@ </array> <key>UISupportedInterfaceOrientations~ipad</key> <array> - $interface_orientations + $ipad_interface_orientations </array> $additional_plist_content $plist_launch_screen_name diff --git a/misc/extension_api_validation/4.2-stable.expected b/misc/extension_api_validation/4.2-stable.expected index 6761512c15..b27f80ee29 100644 --- a/misc/extension_api_validation/4.2-stable.expected +++ b/misc/extension_api_validation/4.2-stable.expected @@ -357,3 +357,10 @@ Validate extension JSON: Error: Field 'classes/RenderingServer/methods/canvas_it Validate extension JSON: Error: Field 'classes/RenderingServer/methods/canvas_item_add_rect/arguments': size changed value in new API, from 3 to 4. Optional arguments added. Compatibility methods registered. + + +GH-92322 +-------- +Validate extension JSON: Error: Field 'classes/EditorInspectorPlugin/methods/add_property_editor/arguments': size changed value in new API, from 3 to 4. + +Optional arguments added. Compatibility methods registered. diff --git a/modules/fbx/doc_classes/EditorSceneFormatImporterFBX2GLTF.xml b/modules/fbx/doc_classes/EditorSceneFormatImporterFBX2GLTF.xml index e30782780f..3bf4e7ddc0 100644 --- a/modules/fbx/doc_classes/EditorSceneFormatImporterFBX2GLTF.xml +++ b/modules/fbx/doc_classes/EditorSceneFormatImporterFBX2GLTF.xml @@ -5,7 +5,7 @@ </brief_description> <description> Imports Autodesk FBX 3D scenes by way of converting them to glTF 2.0 using the FBX2glTF command line tool. - The location of the FBX2glTF binary is set via the [member EditorSettings.filesystem/import/fbx2gltf/fbx2gltf_path] editor setting. + The location of the FBX2glTF binary is set via the [member EditorSettings.filesystem/import/fbx/fbx2gltf_path] editor setting. This importer is only used if [member ProjectSettings.filesystem/import/fbx2gltf/enabled] is set to [code]true[/code]. </description> <tutorials> diff --git a/modules/fbx/editor/editor_scene_importer_fbx2gltf.cpp b/modules/fbx/editor/editor_scene_importer_fbx2gltf.cpp index 6629e05197..afb63246e4 100644 --- a/modules/fbx/editor/editor_scene_importer_fbx2gltf.cpp +++ b/modules/fbx/editor/editor_scene_importer_fbx2gltf.cpp @@ -73,7 +73,7 @@ Node *EditorSceneFormatImporterFBX2GLTF::import_scene(const String &p_path, uint // Run fbx2gltf. - String fbx2gltf_path = EDITOR_GET("filesystem/import/fbx2gltf/fbx2gltf_path"); + String fbx2gltf_path = EDITOR_GET("filesystem/import/fbx/fbx2gltf_path"); List<String> args; args.push_back("--pbr-metallic-roughness"); diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index a2680c932f..aa26bb222d 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -1971,7 +1971,12 @@ void GDScriptAnalyzer::resolve_assignable(GDScriptParser::AssignableNode *p_assi const bool is_parameter = p_assignable->type == GDScriptParser::Node::PARAMETER; const String declaration_type = is_constant ? "Constant" : (is_parameter ? "Parameter" : "Variable"); if (p_assignable->infer_datatype || is_constant) { - parser->push_warning(p_assignable, GDScriptWarning::INFERRED_DECLARATION, declaration_type, p_assignable->identifier->name); + // Do not produce the `INFERRED_DECLARATION` warning on type import because there is no way to specify the true type. + // And removing the metatype makes it impossible to use the constant as a type hint (especially for enums). + const bool is_type_import = is_constant && p_assignable->initializer != nullptr && p_assignable->initializer->datatype.is_meta_type; + if (!is_type_import) { + parser->push_warning(p_assignable, GDScriptWarning::INFERRED_DECLARATION, declaration_type, p_assignable->identifier->name); + } } else { parser->push_warning(p_assignable, GDScriptWarning::UNTYPED_DECLARATION, declaration_type, p_assignable->identifier->name); } @@ -4061,10 +4066,23 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident mark_lambda_use_self(); return; // No need to capture. } - // If the identifier is local, check if it's any kind of capture by comparing their source function. - // Only capture locals and enum values. Constants are still accessible from the lambda using the script reference. If not, this method is done. - if (p_identifier->source == GDScriptParser::IdentifierNode::UNDEFINED_SOURCE || p_identifier->source == GDScriptParser::IdentifierNode::MEMBER_CONSTANT) { - return; + + switch (p_identifier->source) { + case GDScriptParser::IdentifierNode::FUNCTION_PARAMETER: + case GDScriptParser::IdentifierNode::LOCAL_VARIABLE: + case GDScriptParser::IdentifierNode::LOCAL_ITERATOR: + case GDScriptParser::IdentifierNode::LOCAL_BIND: + break; // Need to capture. + case GDScriptParser::IdentifierNode::UNDEFINED_SOURCE: // A global. + case GDScriptParser::IdentifierNode::LOCAL_CONSTANT: + case GDScriptParser::IdentifierNode::MEMBER_VARIABLE: + case GDScriptParser::IdentifierNode::MEMBER_CONSTANT: + case GDScriptParser::IdentifierNode::MEMBER_FUNCTION: + case GDScriptParser::IdentifierNode::MEMBER_SIGNAL: + case GDScriptParser::IdentifierNode::MEMBER_CLASS: + case GDScriptParser::IdentifierNode::INHERITED_VARIABLE: + case GDScriptParser::IdentifierNode::STATIC_VARIABLE: + return; // No need to capture. } GDScriptParser::FunctionNode *function_test = current_lambda->function; @@ -4329,15 +4347,45 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri GDScriptParser::DataType base_type = p_subscript->base->get_datatype(); bool valid = false; + // If the base is a metatype, use the analyzer instead. - if (p_subscript->base->is_constant && !base_type.is_meta_type && base_type.kind != GDScriptParser::DataType::CLASS) { - // Just try to get it. - Variant value = p_subscript->base->reduced_value.get_named(p_subscript->attribute->name, valid); - if (valid) { - p_subscript->is_constant = true; - p_subscript->reduced_value = value; - result_type = type_from_variant(value, p_subscript); + if (p_subscript->base->is_constant && !base_type.is_meta_type) { + // GH-92534. If the base is a GDScript, use the analyzer instead. + bool base_is_gdscript = false; + if (p_subscript->base->reduced_value.get_type() == Variant::OBJECT) { + Ref<GDScript> gdscript = Object::cast_to<GDScript>(p_subscript->base->reduced_value.get_validated_object()); + if (gdscript.is_valid()) { + base_is_gdscript = true; + // Makes a metatype from a constant GDScript, since `base_type` is not a metatype. + GDScriptParser::DataType base_type_meta = type_from_variant(gdscript, p_subscript); + // First try to reduce the attribute from the metatype. + reduce_identifier_from_base(p_subscript->attribute, &base_type_meta); + GDScriptParser::DataType attr_type = p_subscript->attribute->get_datatype(); + if (attr_type.is_set()) { + valid = !attr_type.is_pseudo_type || p_can_be_pseudo_type; + result_type = attr_type; + p_subscript->is_constant = p_subscript->attribute->is_constant; + p_subscript->reduced_value = p_subscript->attribute->reduced_value; + } + if (!valid) { + // If unsuccessful, reset and return to the normal route. + p_subscript->attribute->set_datatype(GDScriptParser::DataType()); + } + } + } + if (!base_is_gdscript) { + // Just try to get it. + Variant value = p_subscript->base->reduced_value.get_named(p_subscript->attribute->name, valid); + if (valid) { + p_subscript->is_constant = true; + p_subscript->reduced_value = value; + result_type = type_from_variant(value, p_subscript); + } } + } + + if (valid) { + // Do nothing. } else if (base_type.is_variant() || !base_type.is_hard_type()) { valid = !base_type.is_pseudo_type || p_can_be_pseudo_type; result_type.kind = GDScriptParser::DataType::VARIANT; @@ -4375,6 +4423,7 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri mark_node_unsafe(p_subscript); } } + if (!valid) { GDScriptParser::DataType attr_type = p_subscript->attribute->get_datatype(); if (!p_can_be_pseudo_type && (attr_type.is_pseudo_type || result_type.is_pseudo_type)) { @@ -4393,6 +4442,7 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri if (p_subscript->base->is_constant && p_subscript->index->is_constant) { // Just try to get it. bool valid = false; + // TODO: Check if `p_subscript->base->reduced_value` is GDScript. Variant value = p_subscript->base->reduced_value.get(p_subscript->index->reduced_value, &valid); if (!valid) { push_error(vformat(R"(Cannot get index "%s" from "%s".)", p_subscript->index->reduced_value, p_subscript->base->reduced_value), p_subscript->index); diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 4ae39d80cd..11d4a4002c 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -754,13 +754,17 @@ static String _make_arguments_hint(const MethodInfo &p_info, int p_arg_idx, bool return arghint; } -static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_function, int p_arg_idx) { +static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_function, int p_arg_idx, bool p_just_args = false) { String arghint; - if (p_function->get_datatype().builtin_type == Variant::NIL) { - arghint = "void " + p_function->identifier->name.operator String() + "("; + if (p_just_args) { + arghint = "("; } else { - arghint = p_function->get_datatype().to_string() + " " + p_function->identifier->name.operator String() + "("; + if (p_function->get_datatype().builtin_type == Variant::NIL) { + arghint = "void " + p_function->identifier->name.operator String() + "("; + } else { + arghint = p_function->get_datatype().to_string() + " " + p_function->identifier->name.operator String() + "("; + } } for (int i = 0; i < p_function->parameters.size(); i++) { @@ -2731,6 +2735,25 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c while (base_type.is_set() && !base_type.is_variant()) { switch (base_type.kind) { case GDScriptParser::DataType::CLASS: { + if (base_type.is_meta_type && p_method == SNAME("new")) { + const GDScriptParser::ClassNode *current = base_type.class_type; + + do { + if (current->has_member("_init")) { + const GDScriptParser::ClassNode::Member &member = current->get_member("_init"); + + if (member.type == GDScriptParser::ClassNode::Member::FUNCTION) { + r_arghint = base_type.class_type->get_datatype().to_string() + " new" + _make_arguments_hint(member.function, p_argidx, true); + return; + } + } + current = current->base_type.class_type; + } while (current != nullptr); + + r_arghint = base_type.class_type->get_datatype().to_string() + " new()"; + return; + } + if (base_type.class_type->has_member(p_method)) { const GDScriptParser::ClassNode::Member &member = base_type.class_type->get_member(p_method); diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp index 9bf458e031..2224bb0040 100644 --- a/modules/gdscript/language_server/gdscript_text_document.cpp +++ b/modules/gdscript/language_server/gdscript_text_document.cpp @@ -490,7 +490,7 @@ void GDScriptTextDocument::sync_script_content(const String &p_path, const Strin } void GDScriptTextDocument::show_native_symbol_in_editor(const String &p_symbol_id) { - ScriptEditor::get_singleton()->call_deferred(SNAME("_help_class_goto"), p_symbol_id); + callable_mp(ScriptEditor::get_singleton(), &ScriptEditor::goto_help).call_deferred(p_symbol_id); DisplayServer::get_singleton()->window_move_to_foreground(); } diff --git a/modules/gdscript/tests/scripts/runtime/features/lambda_captures.gd b/modules/gdscript/tests/scripts/runtime/features/lambda_captures.gd new file mode 100644 index 0000000000..bbdf745540 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/lambda_captures.gd @@ -0,0 +1,26 @@ +# GH-92217 +# TODO: Add more tests. + +static var static_var: int: + set(value): + prints("set static_var", value) + get: + print("get static_var") + return 0 + +var member_var: int: + set(value): + prints("set member_var", value) + get: + print("get member_var") + return 0 + +func test(): + var lambda := func (): + var _tmp := static_var + _tmp = member_var + + static_var = 1 + member_var = 1 + + lambda.call() diff --git a/modules/gdscript/tests/scripts/runtime/features/lambda_captures.out b/modules/gdscript/tests/scripts/runtime/features/lambda_captures.out new file mode 100644 index 0000000000..0bdf74a43f --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/lambda_captures.out @@ -0,0 +1,5 @@ +GDTEST_OK +get static_var +get member_var +set static_var 1 +set member_var 1 diff --git a/modules/gdscript/tests/scripts/runtime/features/metatypes.gd b/modules/gdscript/tests/scripts/runtime/features/metatypes.gd index 6c5df32ffe..fd23ea0db5 100644 --- a/modules/gdscript/tests/scripts/runtime/features/metatypes.gd +++ b/modules/gdscript/tests/scripts/runtime/features/metatypes.gd @@ -25,12 +25,24 @@ func test(): if str(property.name).begins_with("test_"): print(Utils.get_property_signature(property)) + print("---") check_gdscript_native_class(test_native) check_gdscript(test_script) check_gdscript(test_class) check_enum(test_enum) + print("---") print(test_native.stringify([])) print(test_script.TEST) print(test_class.TEST) print(test_enum.keys()) + + print("---") + # Some users add unnecessary type hints to `const`-`preload`, which removes metatypes. + # For **constant** `GDScript` we still check the class members, despite the wider type. + const ScriptNoMeta: GDScript = Other + const ClassNoMeta: GDScript = MyClass + var a := ScriptNoMeta.TEST + var b := ClassNoMeta.TEST + print(a) + print(b) diff --git a/modules/gdscript/tests/scripts/runtime/features/metatypes.out b/modules/gdscript/tests/scripts/runtime/features/metatypes.out index 352d1caa59..c42287438c 100644 --- a/modules/gdscript/tests/scripts/runtime/features/metatypes.out +++ b/modules/gdscript/tests/scripts/runtime/features/metatypes.out @@ -3,11 +3,16 @@ var test_native: GDScriptNativeClass var test_script: GDScript var test_class: GDScript var test_enum: Dictionary +--- GDScriptNativeClass GDScript GDScript { "A": 0, "B": 1, "C": 2 } +--- [] 100 10 ["A", "B", "C"] +--- +100 +10 diff --git a/modules/gltf/doc_classes/GLTFAccessor.xml b/modules/gltf/doc_classes/GLTFAccessor.xml index ba7323b7cd..54762faed7 100644 --- a/modules/gltf/doc_classes/GLTFAccessor.xml +++ b/modules/gltf/doc_classes/GLTFAccessor.xml @@ -12,34 +12,50 @@ <link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link> </tutorials> <members> + <member name="accessor_type" type="int" setter="set_accessor_type" getter="get_accessor_type" default="0"> + The GLTF accessor type as an enum. Possible values are 0 for "SCALAR", 1 for "VEC2", 2 for "VEC3", 3 for "VEC4", 4 for "MAT2", 5 for "MAT3", and 6 for "MAT4". + </member> <member name="buffer_view" type="int" setter="set_buffer_view" getter="get_buffer_view" default="-1"> The index of the buffer view this accessor is referencing. If [code]-1[/code], this accessor is not referencing any buffer view. </member> <member name="byte_offset" type="int" setter="set_byte_offset" getter="get_byte_offset" default="0"> + The offset relative to the start of the buffer view in bytes. </member> <member name="component_type" type="int" setter="set_component_type" getter="get_component_type" default="0"> + The GLTF component type as an enum. Possible values are 5120 for "BYTE", 5121 for "UNSIGNED_BYTE", 5122 for "SHORT", 5123 for "UNSIGNED_SHORT", 5125 for "UNSIGNED_INT", and 5126 for "FLOAT". A value of 5125 or "UNSIGNED_INT" must not be used for any accessor that is not referenced by mesh.primitive.indices. </member> <member name="count" type="int" setter="set_count" getter="get_count" default="0"> + The number of elements referenced by this accessor. </member> <member name="max" type="PackedFloat64Array" setter="set_max" getter="get_max" default="PackedFloat64Array()"> + Maximum value of each component in this accessor. </member> <member name="min" type="PackedFloat64Array" setter="set_min" getter="get_min" default="PackedFloat64Array()"> + Minimum value of each component in this accessor. </member> <member name="normalized" type="bool" setter="set_normalized" getter="get_normalized" default="false"> + Specifies whether integer data values are normalized before usage. </member> <member name="sparse_count" type="int" setter="set_sparse_count" getter="get_sparse_count" default="0"> + Number of deviating accessor values stored in the sparse array. </member> <member name="sparse_indices_buffer_view" type="int" setter="set_sparse_indices_buffer_view" getter="get_sparse_indices_buffer_view" default="0"> + The index of the buffer view with sparse indices. The referenced buffer view MUST NOT have its target or byteStride properties defined. The buffer view and the optional byteOffset MUST be aligned to the componentType byte length. </member> <member name="sparse_indices_byte_offset" type="int" setter="set_sparse_indices_byte_offset" getter="get_sparse_indices_byte_offset" default="0"> + The offset relative to the start of the buffer view in bytes. </member> <member name="sparse_indices_component_type" type="int" setter="set_sparse_indices_component_type" getter="get_sparse_indices_component_type" default="0"> + The indices component data type as an enum. Possible values are 5121 for "UNSIGNED_BYTE", 5123 for "UNSIGNED_SHORT", and 5125 for "UNSIGNED_INT". </member> <member name="sparse_values_buffer_view" type="int" setter="set_sparse_values_buffer_view" getter="get_sparse_values_buffer_view" default="0"> + The index of the bufferView with sparse values. The referenced buffer view MUST NOT have its target or byteStride properties defined. </member> <member name="sparse_values_byte_offset" type="int" setter="set_sparse_values_byte_offset" getter="get_sparse_values_byte_offset" default="0"> + The offset relative to the start of the bufferView in bytes. </member> - <member name="type" type="int" setter="set_type" getter="get_type" default="0"> + <member name="type" type="int" setter="set_type" getter="get_type" default="0" deprecated="Use [member accessor_type] instead."> + The GLTF accessor type as an enum. Use [member accessor_type] instead. </member> </members> </class> diff --git a/modules/gltf/gltf_defines.h b/modules/gltf/gltf_defines.h index d044105b42..c1918e5908 100644 --- a/modules/gltf/gltf_defines.h +++ b/modules/gltf/gltf_defines.h @@ -66,14 +66,4 @@ using GLTFSkinIndex = int; using GLTFTextureIndex = int; using GLTFTextureSamplerIndex = int; -enum GLTFType { - TYPE_SCALAR, - TYPE_VEC2, - TYPE_VEC3, - TYPE_VEC4, - TYPE_MAT2, - TYPE_MAT3, - TYPE_MAT4, -}; - #endif // GLTF_DEFINES_H diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 5dcf67b768..42428231e6 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -886,7 +886,7 @@ Error GLTFDocument::_encode_accessors(Ref<GLTFState> p_state) { Ref<GLTFAccessor> accessor = p_state->accessors[i]; d["componentType"] = accessor->component_type; d["count"] = accessor->count; - d["type"] = _get_accessor_type_name(accessor->type); + d["type"] = _get_accessor_type_name(accessor->accessor_type); d["normalized"] = accessor->normalized; d["max"] = accessor->max; d["min"] = accessor->min; @@ -934,58 +934,58 @@ Error GLTFDocument::_encode_accessors(Ref<GLTFState> p_state) { return OK; } -String GLTFDocument::_get_accessor_type_name(const GLTFType p_type) { - if (p_type == GLTFType::TYPE_SCALAR) { +String GLTFDocument::_get_accessor_type_name(const GLTFAccessorType p_accessor_type) { + if (p_accessor_type == GLTFAccessorType::TYPE_SCALAR) { return "SCALAR"; } - if (p_type == GLTFType::TYPE_VEC2) { + if (p_accessor_type == GLTFAccessorType::TYPE_VEC2) { return "VEC2"; } - if (p_type == GLTFType::TYPE_VEC3) { + if (p_accessor_type == GLTFAccessorType::TYPE_VEC3) { return "VEC3"; } - if (p_type == GLTFType::TYPE_VEC4) { + if (p_accessor_type == GLTFAccessorType::TYPE_VEC4) { return "VEC4"; } - if (p_type == GLTFType::TYPE_MAT2) { + if (p_accessor_type == GLTFAccessorType::TYPE_MAT2) { return "MAT2"; } - if (p_type == GLTFType::TYPE_MAT3) { + if (p_accessor_type == GLTFAccessorType::TYPE_MAT3) { return "MAT3"; } - if (p_type == GLTFType::TYPE_MAT4) { + if (p_accessor_type == GLTFAccessorType::TYPE_MAT4) { return "MAT4"; } ERR_FAIL_V("SCALAR"); } -GLTFType GLTFDocument::_get_type_from_str(const String &p_string) { +GLTFAccessorType GLTFDocument::_get_accessor_type_from_str(const String &p_string) { if (p_string == "SCALAR") { - return GLTFType::TYPE_SCALAR; + return GLTFAccessorType::TYPE_SCALAR; } if (p_string == "VEC2") { - return GLTFType::TYPE_VEC2; + return GLTFAccessorType::TYPE_VEC2; } if (p_string == "VEC3") { - return GLTFType::TYPE_VEC3; + return GLTFAccessorType::TYPE_VEC3; } if (p_string == "VEC4") { - return GLTFType::TYPE_VEC4; + return GLTFAccessorType::TYPE_VEC4; } if (p_string == "MAT2") { - return GLTFType::TYPE_MAT2; + return GLTFAccessorType::TYPE_MAT2; } if (p_string == "MAT3") { - return GLTFType::TYPE_MAT3; + return GLTFAccessorType::TYPE_MAT3; } if (p_string == "MAT4") { - return GLTFType::TYPE_MAT4; + return GLTFAccessorType::TYPE_MAT4; } - ERR_FAIL_V(GLTFType::TYPE_SCALAR); + ERR_FAIL_V(GLTFAccessorType::TYPE_SCALAR); } Error GLTFDocument::_parse_accessors(Ref<GLTFState> p_state) { @@ -1004,7 +1004,7 @@ Error GLTFDocument::_parse_accessors(Ref<GLTFState> p_state) { ERR_FAIL_COND_V(!d.has("count"), ERR_PARSE_ERROR); accessor->count = d["count"]; ERR_FAIL_COND_V(!d.has("type"), ERR_PARSE_ERROR); - accessor->type = _get_type_from_str(d["type"]); + accessor->accessor_type = _get_accessor_type_from_str(d["type"]); if (d.has("bufferView")) { accessor->buffer_view = d["bufferView"]; //optional because it may be sparse... @@ -1088,26 +1088,12 @@ String GLTFDocument::_get_component_type_name(const uint32_t p_component) { return "<Error>"; } -String GLTFDocument::_get_type_name(const GLTFType p_component) { - static const char *names[] = { - "float", - "vec2", - "vec3", - "vec4", - "mat2", - "mat3", - "mat4" - }; - - return names[p_component]; -} - -Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> p_state, const double *p_src, const int p_count, const GLTFType p_type, const int p_component_type, const bool p_normalized, const int p_byte_offset, const bool p_for_vertex, GLTFBufferViewIndex &r_accessor, const bool p_for_vertex_indices) { +Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> p_state, const double *p_src, const int p_count, const GLTFAccessorType p_accessor_type, const int p_component_type, const bool p_normalized, const int p_byte_offset, const bool p_for_vertex, GLTFBufferViewIndex &r_accessor, const bool p_for_vertex_indices) { const int component_count_for_type[7] = { 1, 2, 3, 4, 4, 9, 16 }; - const int component_count = component_count_for_type[p_type]; + const int component_count = component_count_for_type[p_accessor_type]; const int component_size = _get_component_type_size(p_component_type); ERR_FAIL_COND_V(component_size == 0, FAILED); @@ -1117,18 +1103,18 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> p_state, const double *p_ switch (p_component_type) { case COMPONENT_TYPE_BYTE: case COMPONENT_TYPE_UNSIGNED_BYTE: { - if (p_type == TYPE_MAT2) { + if (p_accessor_type == TYPE_MAT2) { skip_every = 2; skip_bytes = 2; } - if (p_type == TYPE_MAT3) { + if (p_accessor_type == TYPE_MAT3) { skip_every = 3; skip_bytes = 1; } } break; case COMPONENT_TYPE_SHORT: case COMPONENT_TYPE_UNSIGNED_SHORT: { - if (p_type == TYPE_MAT3) { + if (p_accessor_type == TYPE_MAT3) { skip_every = 6; skip_bytes = 4; } @@ -1147,7 +1133,7 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> p_state, const double *p_ stride += 4 - (stride % 4); //according to spec must be multiple of 4 } //use to debug - print_verbose("glTF: encoding type " + _get_type_name(p_type) + " component type: " + _get_component_type_name(p_component_type) + " stride: " + itos(stride) + " amount " + itos(p_count)); + print_verbose("glTF: encoding accessor type " + _get_accessor_type_name(p_accessor_type) + " component type: " + _get_component_type_name(p_component_type) + " stride: " + itos(stride) + " amount " + itos(p_count)); print_verbose("glTF: encoding accessor offset " + itos(p_byte_offset) + " view offset: " + itos(bv->byte_offset) + " total buffer len: " + itos(gltf_buffer.size()) + " view len " + itos(bv->byte_length)); @@ -1310,7 +1296,7 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> p_state, const double *p_ return OK; } -Error GLTFDocument::_decode_buffer_view(Ref<GLTFState> p_state, double *p_dst, const GLTFBufferViewIndex p_buffer_view, const int p_skip_every, const int p_skip_bytes, const int p_element_size, const int p_count, const GLTFType p_type, const int p_component_count, const int p_component_type, const int p_component_size, const bool p_normalized, const int p_byte_offset, const bool p_for_vertex) { +Error GLTFDocument::_decode_buffer_view(Ref<GLTFState> p_state, double *p_dst, const GLTFBufferViewIndex p_buffer_view, const int p_skip_every, const int p_skip_bytes, const int p_element_size, const int p_count, const GLTFAccessorType p_accessor_type, const int p_component_count, const int p_component_type, const int p_component_size, const bool p_normalized, const int p_byte_offset, const bool p_for_vertex) { const Ref<GLTFBufferView> bv = p_state->buffer_views[p_buffer_view]; int stride = p_element_size; @@ -1328,7 +1314,7 @@ Error GLTFDocument::_decode_buffer_view(Ref<GLTFState> p_state, double *p_dst, c const uint8_t *bufptr = buffer.ptr(); //use to debug - print_verbose("glTF: type " + _get_type_name(p_type) + " component type: " + _get_component_type_name(p_component_type) + " stride: " + itos(stride) + " amount " + itos(p_count)); + print_verbose("glTF: accessor type " + _get_accessor_type_name(p_accessor_type) + " component type: " + _get_component_type_name(p_component_type) + " stride: " + itos(stride) + " amount " + itos(p_count)); print_verbose("glTF: accessor offset " + itos(p_byte_offset) + " view offset: " + itos(bv->byte_offset) + " total buffer len: " + itos(buffer.size()) + " view len " + itos(bv->byte_length)); const int buffer_end = (stride * (p_count - 1)) + p_element_size; @@ -1430,7 +1416,7 @@ Vector<double> GLTFDocument::_decode_accessor(Ref<GLTFState> p_state, const GLTF 1, 2, 3, 4, 4, 9, 16 }; - const int component_count = component_count_for_type[a->type]; + const int component_count = component_count_for_type[a->accessor_type]; const int component_size = _get_component_type_size(a->component_type); ERR_FAIL_COND_V(component_size == 0, Vector<double>()); int element_size = component_count * component_size; @@ -1441,12 +1427,12 @@ Vector<double> GLTFDocument::_decode_accessor(Ref<GLTFState> p_state, const GLTF switch (a->component_type) { case COMPONENT_TYPE_BYTE: case COMPONENT_TYPE_UNSIGNED_BYTE: { - if (a->type == TYPE_MAT2) { + if (a->accessor_type == TYPE_MAT2) { skip_every = 2; skip_bytes = 2; element_size = 8; //override for this case } - if (a->type == TYPE_MAT3) { + if (a->accessor_type == TYPE_MAT3) { skip_every = 3; skip_bytes = 1; element_size = 12; //override for this case @@ -1454,7 +1440,7 @@ Vector<double> GLTFDocument::_decode_accessor(Ref<GLTFState> p_state, const GLTF } break; case COMPONENT_TYPE_SHORT: case COMPONENT_TYPE_UNSIGNED_SHORT: { - if (a->type == TYPE_MAT3) { + if (a->accessor_type == TYPE_MAT3) { skip_every = 6; skip_bytes = 4; element_size = 16; //override for this case @@ -1471,7 +1457,7 @@ Vector<double> GLTFDocument::_decode_accessor(Ref<GLTFState> p_state, const GLTF if (a->buffer_view >= 0) { ERR_FAIL_INDEX_V(a->buffer_view, p_state->buffer_views.size(), Vector<double>()); - const Error err = _decode_buffer_view(p_state, dst, a->buffer_view, skip_every, skip_bytes, element_size, a->count, a->type, component_count, a->component_type, component_size, a->normalized, a->byte_offset, p_for_vertex); + const Error err = _decode_buffer_view(p_state, dst, a->buffer_view, skip_every, skip_bytes, element_size, a->count, a->accessor_type, component_count, a->component_type, component_size, a->normalized, a->byte_offset, p_for_vertex); if (err != OK) { return Vector<double>(); } @@ -1495,7 +1481,7 @@ Vector<double> GLTFDocument::_decode_accessor(Ref<GLTFState> p_state, const GLTF Vector<double> data; data.resize(component_count * a->sparse_count); - err = _decode_buffer_view(p_state, data.ptrw(), a->sparse_values_buffer_view, skip_every, skip_bytes, element_size, a->sparse_count, a->type, component_count, a->component_type, component_size, a->normalized, a->sparse_values_byte_offset, p_for_vertex); + err = _decode_buffer_view(p_state, data.ptrw(), a->sparse_values_buffer_view, skip_every, skip_bytes, element_size, a->sparse_count, a->accessor_type, component_count, a->component_type, component_size, a->normalized, a->sparse_values_byte_offset, p_for_vertex); if (err != OK) { return Vector<double>(); } @@ -1550,7 +1536,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_ints(Ref<GLTFState> p_state, p_state->buffers.push_back(Vector<uint8_t>()); } int64_t size = p_state->buffers[0].size(); - const GLTFType type = GLTFType::TYPE_SCALAR; + const GLTFAccessorType accessor_type = GLTFAccessorType::TYPE_SCALAR; int component_type; if (max_index > 65535 || p_for_vertex) { component_type = GLTFDocument::COMPONENT_TYPE_INT; @@ -1562,10 +1548,10 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_ints(Ref<GLTFState> p_state, accessor->min = type_min; accessor->normalized = false; accessor->count = ret_size; - accessor->type = type; + accessor->accessor_type = accessor_type; accessor->component_type = component_type; accessor->byte_offset = 0; - Error err = _encode_buffer_view(p_state, attribs.ptr(), attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i, p_for_vertex_indices); + Error err = _encode_buffer_view(p_state, attribs.ptr(), attribs.size(), accessor_type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i, p_for_vertex_indices); if (err != OK) { return -1; } @@ -1664,17 +1650,17 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec2(Ref<GLTFState> p_state, p_state->buffers.push_back(Vector<uint8_t>()); } int64_t size = p_state->buffers[0].size(); - const GLTFType type = GLTFType::TYPE_VEC2; + const GLTFAccessorType accessor_type = GLTFAccessorType::TYPE_VEC2; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; accessor->max = type_max; accessor->min = type_min; accessor->normalized = false; accessor->count = p_attribs.size(); - accessor->type = type; + accessor->accessor_type = accessor_type; accessor->component_type = component_type; accessor->byte_offset = 0; - Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); + Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), accessor_type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); if (err != OK) { return -1; } @@ -1717,17 +1703,17 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_color(Ref<GLTFState> p_state p_state->buffers.push_back(Vector<uint8_t>()); } int64_t size = p_state->buffers[0].size(); - const GLTFType type = GLTFType::TYPE_VEC4; + const GLTFAccessorType accessor_type = GLTFAccessorType::TYPE_VEC4; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; accessor->max = type_max; accessor->min = type_min; accessor->normalized = false; accessor->count = p_attribs.size(); - accessor->type = type; + accessor->accessor_type = accessor_type; accessor->component_type = component_type; accessor->byte_offset = 0; - Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); + Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), accessor_type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); if (err != OK) { return -1; } @@ -1784,17 +1770,17 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_weights(Ref<GLTFState> p_sta p_state->buffers.push_back(Vector<uint8_t>()); } int64_t size = p_state->buffers[0].size(); - const GLTFType type = GLTFType::TYPE_VEC4; + const GLTFAccessorType accessor_type = GLTFAccessorType::TYPE_VEC4; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; accessor->max = type_max; accessor->min = type_min; accessor->normalized = false; accessor->count = p_attribs.size(); - accessor->type = type; + accessor->accessor_type = accessor_type; accessor->component_type = component_type; accessor->byte_offset = 0; - Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); + Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), accessor_type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); if (err != OK) { return -1; } @@ -1835,17 +1821,17 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_joints(Ref<GLTFState> p_stat p_state->buffers.push_back(Vector<uint8_t>()); } int64_t size = p_state->buffers[0].size(); - const GLTFType type = GLTFType::TYPE_VEC4; + const GLTFAccessorType accessor_type = GLTFAccessorType::TYPE_VEC4; const int component_type = GLTFDocument::COMPONENT_TYPE_UNSIGNED_SHORT; accessor->max = type_max; accessor->min = type_min; accessor->normalized = false; accessor->count = p_attribs.size(); - accessor->type = type; + accessor->accessor_type = accessor_type; accessor->component_type = component_type; accessor->byte_offset = 0; - Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); + Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), accessor_type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); if (err != OK) { return -1; } @@ -1888,17 +1874,17 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_quaternions(Ref<GLTFState> p p_state->buffers.push_back(Vector<uint8_t>()); } int64_t size = p_state->buffers[0].size(); - const GLTFType type = GLTFType::TYPE_VEC4; + const GLTFAccessorType accessor_type = GLTFAccessorType::TYPE_VEC4; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; accessor->max = type_max; accessor->min = type_min; accessor->normalized = false; accessor->count = p_attribs.size(); - accessor->type = type; + accessor->accessor_type = accessor_type; accessor->component_type = component_type; accessor->byte_offset = 0; - Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); + Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), accessor_type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); if (err != OK) { return -1; } @@ -1963,17 +1949,17 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_floats(Ref<GLTFState> p_stat p_state->buffers.push_back(Vector<uint8_t>()); } int64_t size = p_state->buffers[0].size(); - const GLTFType type = GLTFType::TYPE_SCALAR; + const GLTFAccessorType accessor_type = GLTFAccessorType::TYPE_SCALAR; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; accessor->max = type_max; accessor->min = type_min; accessor->normalized = false; accessor->count = ret_size; - accessor->type = type; + accessor->accessor_type = accessor_type; accessor->component_type = component_type; accessor->byte_offset = 0; - Error err = _encode_buffer_view(p_state, attribs.ptr(), attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); + Error err = _encode_buffer_view(p_state, attribs.ptr(), attribs.size(), accessor_type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); if (err != OK) { return -1; } @@ -2013,17 +1999,17 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec3(Ref<GLTFState> p_state, p_state->buffers.push_back(Vector<uint8_t>()); } int64_t size = p_state->buffers[0].size(); - const GLTFType type = GLTFType::TYPE_VEC3; + const GLTFAccessorType accessor_type = GLTFAccessorType::TYPE_VEC3; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; accessor->max = type_max; accessor->min = type_min; accessor->normalized = false; accessor->count = p_attribs.size(); - accessor->type = type; + accessor->accessor_type = accessor_type; accessor->component_type = component_type; accessor->byte_offset = 0; - Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); + Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), accessor_type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); if (err != OK) { return -1; } @@ -2089,12 +2075,12 @@ GLTFAccessorIndex GLTFDocument::_encode_sparse_accessor_as_vec3(Ref<GLTFState> p p_state->buffers.push_back(Vector<uint8_t>()); } int64_t size = p_state->buffers[0].size(); - const GLTFType type = GLTFType::TYPE_VEC3; + const GLTFAccessorType accessor_type = GLTFAccessorType::TYPE_VEC3; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; sparse_accessor->normalized = false; sparse_accessor->count = p_attribs.size(); - sparse_accessor->type = type; + sparse_accessor->accessor_type = accessor_type; sparse_accessor->component_type = component_type; if (p_reference_accessor < p_state->accessors.size() && p_reference_accessor >= 0 && p_state->accessors[p_reference_accessor].is_valid()) { sparse_accessor->byte_offset = p_state->accessors[p_reference_accessor]->byte_offset; @@ -2117,11 +2103,11 @@ GLTFAccessorIndex GLTFDocument::_encode_sparse_accessor_as_vec3(Ref<GLTFState> p } else { sparse_accessor->sparse_indices_component_type = GLTFDocument::COMPONENT_TYPE_UNSIGNED_SHORT; } - if (_encode_buffer_view(p_state, changed_indices.ptr(), changed_indices.size(), GLTFType::TYPE_SCALAR, sparse_accessor->sparse_indices_component_type, sparse_accessor->normalized, sparse_accessor->sparse_indices_byte_offset, false, buffer_view_i_indices) != OK) { + if (_encode_buffer_view(p_state, changed_indices.ptr(), changed_indices.size(), GLTFAccessorType::TYPE_SCALAR, sparse_accessor->sparse_indices_component_type, sparse_accessor->normalized, sparse_accessor->sparse_indices_byte_offset, false, buffer_view_i_indices) != OK) { return -1; } // We use changed_indices.size() here, because we must pass the number of vec3 values rather than the number of components. - if (_encode_buffer_view(p_state, changed_values.ptr(), changed_indices.size(), sparse_accessor->type, sparse_accessor->component_type, sparse_accessor->normalized, sparse_accessor->sparse_values_byte_offset, false, buffer_view_i_values) != OK) { + if (_encode_buffer_view(p_state, changed_values.ptr(), changed_indices.size(), sparse_accessor->accessor_type, sparse_accessor->component_type, sparse_accessor->normalized, sparse_accessor->sparse_values_byte_offset, false, buffer_view_i_values) != OK) { return -1; } sparse_accessor->sparse_indices_buffer_view = buffer_view_i_indices; @@ -2130,7 +2116,7 @@ GLTFAccessorIndex GLTFDocument::_encode_sparse_accessor_as_vec3(Ref<GLTFState> p } else if (changed_indices.size() > 0) { GLTFBufferIndex buffer_view_i; sparse_accessor->byte_offset = 0; - Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, sparse_accessor->normalized, size, p_for_vertex, buffer_view_i); + Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), accessor_type, component_type, sparse_accessor->normalized, size, p_for_vertex, buffer_view_i); if (err != OK) { return -1; } @@ -2194,17 +2180,17 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> p_state p_state->buffers.push_back(Vector<uint8_t>()); } int64_t size = p_state->buffers[0].size(); - const GLTFType type = GLTFType::TYPE_MAT4; + const GLTFAccessorType accessor_type = GLTFAccessorType::TYPE_MAT4; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; accessor->max = type_max; accessor->min = type_min; accessor->normalized = false; accessor->count = p_attribs.size(); - accessor->type = type; + accessor->accessor_type = accessor_type; accessor->component_type = component_type; accessor->byte_offset = 0; - Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); + Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), accessor_type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); if (err != OK) { return -1; } @@ -2247,10 +2233,10 @@ Vector<Color> GLTFDocument::_decode_accessor_as_color(Ref<GLTFState> p_state, co return ret; } - const int type = p_state->accessors[p_accessor]->type; - ERR_FAIL_COND_V(!(type == TYPE_VEC3 || type == TYPE_VEC4), ret); + const int accessor_type = p_state->accessors[p_accessor]->accessor_type; + ERR_FAIL_COND_V(!(accessor_type == TYPE_VEC3 || accessor_type == TYPE_VEC4), ret); int vec_len = 3; - if (type == TYPE_VEC4) { + if (accessor_type == TYPE_VEC4) { vec_len = 4; } @@ -5133,7 +5119,11 @@ GLTFMeshIndex GLTFDocument::_convert_mesh_to_gltf(Ref<GLTFState> p_state, MeshIn ERR_FAIL_COND_V_MSG(p_mesh_instance->get_mesh().is_null(), -1, "glTF: Tried to export a MeshInstance3D node named " + p_mesh_instance->get_name() + ", but it has no mesh. This node will be exported without a mesh."); Ref<Mesh> mesh_resource = p_mesh_instance->get_mesh(); ERR_FAIL_COND_V_MSG(mesh_resource->get_surface_count() == 0, -1, "glTF: Tried to export a MeshInstance3D node named " + p_mesh_instance->get_name() + ", but its mesh has no surfaces. This node will be exported without a mesh."); - + TypedArray<Material> instance_materials; + for (int32_t surface_i = 0; surface_i < mesh_resource->get_surface_count(); surface_i++) { + Ref<Material> mat = p_mesh_instance->get_active_material(surface_i); + instance_materials.append(mat); + } Ref<ImporterMesh> current_mesh = _mesh_to_importer_mesh(mesh_resource); Vector<float> blend_weights; int32_t blend_count = mesh_resource->get_blend_shape_count(); @@ -5144,17 +5134,6 @@ GLTFMeshIndex GLTFDocument::_convert_mesh_to_gltf(Ref<GLTFState> p_state, MeshIn Ref<GLTFMesh> gltf_mesh; gltf_mesh.instantiate(); - TypedArray<Material> instance_materials; - for (int32_t surface_i = 0; surface_i < current_mesh->get_surface_count(); surface_i++) { - Ref<Material> mat = current_mesh->get_surface_material(surface_i); - if (p_mesh_instance->get_surface_override_material(surface_i).is_valid()) { - mat = p_mesh_instance->get_surface_override_material(surface_i); - } - if (p_mesh_instance->get_material_override().is_valid()) { - mat = p_mesh_instance->get_material_override(); - } - instance_materials.append(mat); - } gltf_mesh->set_instance_materials(instance_materials); gltf_mesh->set_mesh(current_mesh); gltf_mesh->set_blend_weights(blend_weights); @@ -5323,11 +5302,22 @@ void GLTFDocument::_convert_csg_shape_to_gltf(CSGShape3D *p_current, GLTFNodeInd Ref<ImporterMesh> mesh; mesh.instantiate(); { - Ref<Mesh> csg_mesh = csg->get_meshes()[1]; - + Ref<ArrayMesh> csg_mesh = csg->get_meshes()[1]; for (int32_t surface_i = 0; surface_i < csg_mesh->get_surface_count(); surface_i++) { Array array = csg_mesh->surface_get_arrays(surface_i); - Ref<Material> mat = csg_mesh->surface_get_material(surface_i); + + Ref<Material> mat; + + Ref<Material> mat_override = csg->get_material_override(); + if (mat_override.is_valid()) { + mat = mat_override; + } + + Ref<Material> mat_surface_override = csg_mesh->surface_get_material(surface_i); + if (mat_surface_override.is_valid() && mat.is_null()) { + mat = mat_surface_override; + } + String mat_name; if (mat.is_valid()) { mat_name = mat->get_name(); @@ -5335,6 +5325,7 @@ void GLTFDocument::_convert_csg_shape_to_gltf(CSGShape3D *p_current, GLTFNodeInd // Assign default material when no material is assigned. mat = Ref<StandardMaterial3D>(memnew(StandardMaterial3D)); } + mesh->add_surface(csg_mesh->surface_get_primitive_type(surface_i), array, csg_mesh->surface_get_blend_shape_arrays(surface_i), csg_mesh->surface_get_lods(surface_i), mat, mat_name, csg_mesh->surface_get_format(surface_i)); @@ -5348,7 +5339,7 @@ void GLTFDocument::_convert_csg_shape_to_gltf(CSGShape3D *p_current, GLTFNodeInd GLTFMeshIndex mesh_i = p_state->meshes.size(); p_state->meshes.push_back(gltf_mesh); p_gltf_node->mesh = mesh_i; - p_gltf_node->transform = csg->get_meshes()[0]; + p_gltf_node->transform = csg->get_transform(); p_gltf_node->set_original_name(csg->get_name()); p_gltf_node->set_name(_gen_unique_name(p_state, csg->get_name())); } diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h index 5eb9d90811..4f92ceccca 100644 --- a/modules/gltf/gltf_document.h +++ b/modules/gltf/gltf_document.h @@ -111,8 +111,7 @@ private: int _get_component_type_size(const int p_component_type); Error _parse_scenes(Ref<GLTFState> p_state); Error _parse_nodes(Ref<GLTFState> p_state); - String _get_type_name(const GLTFType p_component); - String _get_accessor_type_name(const GLTFType p_type); + String _get_accessor_type_name(const GLTFAccessorType p_accessor_type); String _sanitize_animation_name(const String &p_name); String _gen_unique_animation_name(Ref<GLTFState> p_state, const String &p_name); String _sanitize_bone_name(const String &p_name); @@ -132,13 +131,13 @@ private: void _compute_node_heights(Ref<GLTFState> p_state); Error _parse_buffers(Ref<GLTFState> p_state, const String &p_base_path); Error _parse_buffer_views(Ref<GLTFState> p_state); - GLTFType _get_type_from_str(const String &p_string); + GLTFAccessorType _get_accessor_type_from_str(const String &p_string); Error _parse_accessors(Ref<GLTFState> p_state); Error _decode_buffer_view(Ref<GLTFState> p_state, double *p_dst, const GLTFBufferViewIndex p_buffer_view, const int p_skip_every, const int p_skip_bytes, const int p_element_size, const int p_count, - const GLTFType p_type, const int p_component_count, + const GLTFAccessorType p_accessor_type, const int p_component_count, const int p_component_type, const int p_component_size, const bool p_normalized, const int p_byte_offset, const bool p_for_vertex); @@ -267,7 +266,7 @@ private: const Vector<Transform3D> p_attribs, const bool p_for_vertex); Error _encode_buffer_view(Ref<GLTFState> p_state, const double *p_src, - const int p_count, const GLTFType p_type, + const int p_count, const GLTFAccessorType p_accessor_type, const int p_component_type, const bool p_normalized, const int p_byte_offset, const bool p_for_vertex, GLTFBufferViewIndex &r_accessor, const bool p_for_indices = false); diff --git a/modules/gltf/structures/gltf_accessor.cpp b/modules/gltf/structures/gltf_accessor.cpp index 2119a0ee82..602f0d9dc4 100644 --- a/modules/gltf/structures/gltf_accessor.cpp +++ b/modules/gltf/structures/gltf_accessor.cpp @@ -41,8 +41,10 @@ void GLTFAccessor::_bind_methods() { ClassDB::bind_method(D_METHOD("set_normalized", "normalized"), &GLTFAccessor::set_normalized); ClassDB::bind_method(D_METHOD("get_count"), &GLTFAccessor::get_count); ClassDB::bind_method(D_METHOD("set_count", "count"), &GLTFAccessor::set_count); - ClassDB::bind_method(D_METHOD("get_type"), &GLTFAccessor::get_type); - ClassDB::bind_method(D_METHOD("set_type", "type"), &GLTFAccessor::set_type); + ClassDB::bind_method(D_METHOD("get_accessor_type"), &GLTFAccessor::get_accessor_type); + ClassDB::bind_method(D_METHOD("set_accessor_type", "accessor_type"), &GLTFAccessor::set_accessor_type); + ClassDB::bind_method(D_METHOD("get_type"), &GLTFAccessor::get_accessor_type); + ClassDB::bind_method(D_METHOD("set_type", "type"), &GLTFAccessor::set_accessor_type); ClassDB::bind_method(D_METHOD("get_min"), &GLTFAccessor::get_min); ClassDB::bind_method(D_METHOD("set_min", "min"), &GLTFAccessor::set_min); ClassDB::bind_method(D_METHOD("get_max"), &GLTFAccessor::get_max); @@ -65,7 +67,8 @@ void GLTFAccessor::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "component_type"), "set_component_type", "get_component_type"); // int ADD_PROPERTY(PropertyInfo(Variant::BOOL, "normalized"), "set_normalized", "get_normalized"); // bool ADD_PROPERTY(PropertyInfo(Variant::INT, "count"), "set_count", "get_count"); // int - ADD_PROPERTY(PropertyInfo(Variant::INT, "type"), "set_type", "get_type"); // GLTFType + ADD_PROPERTY(PropertyInfo(Variant::INT, "accessor_type"), "set_accessor_type", "get_accessor_type"); // GLTFAccessorType + ADD_PROPERTY(PropertyInfo(Variant::INT, "type"), "set_type", "get_type"); // Deprecated, GLTFAccessorType ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT64_ARRAY, "min"), "set_min", "get_min"); // Vector<real_t> ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT64_ARRAY, "max"), "set_max", "get_max"); // Vector<real_t> ADD_PROPERTY(PropertyInfo(Variant::INT, "sparse_count"), "set_sparse_count", "get_sparse_count"); // int @@ -116,12 +119,12 @@ void GLTFAccessor::set_count(int p_count) { count = p_count; } -int GLTFAccessor::get_type() { - return (int)type; +int GLTFAccessor::get_accessor_type() { + return (int)accessor_type; } -void GLTFAccessor::set_type(int p_type) { - type = (GLTFType)p_type; // TODO: Register enum +void GLTFAccessor::set_accessor_type(int p_accessor_type) { + accessor_type = (GLTFAccessorType)p_accessor_type; // TODO: Register enum } Vector<double> GLTFAccessor::get_min() { diff --git a/modules/gltf/structures/gltf_accessor.h b/modules/gltf/structures/gltf_accessor.h index 6b1734601a..51ca282630 100644 --- a/modules/gltf/structures/gltf_accessor.h +++ b/modules/gltf/structures/gltf_accessor.h @@ -35,6 +35,16 @@ #include "core/io/resource.h" +enum GLTFAccessorType { + TYPE_SCALAR, + TYPE_VEC2, + TYPE_VEC3, + TYPE_VEC4, + TYPE_MAT2, + TYPE_MAT3, + TYPE_MAT4, +}; + struct GLTFAccessor : public Resource { GDCLASS(GLTFAccessor, Resource); friend class GLTFDocument; @@ -45,7 +55,7 @@ private: int component_type = 0; bool normalized = false; int count = 0; - GLTFType type = GLTFType::TYPE_SCALAR; + GLTFAccessorType accessor_type = GLTFAccessorType::TYPE_SCALAR; Vector<double> min; Vector<double> max; int sparse_count = 0; @@ -74,8 +84,8 @@ public: int get_count(); void set_count(int p_count); - int get_type(); - void set_type(int p_type); + int get_accessor_type(); + void set_accessor_type(int p_accessor_type); Vector<double> get_min(); void set_min(Vector<double> p_min); diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp index 27c74421db..226cb48eb8 100644 --- a/modules/gridmap/editor/grid_map_editor_plugin.cpp +++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp @@ -1275,7 +1275,7 @@ GridMapEditor::GridMapEditor() { settings_pick_distance->set_value(EDITOR_GET("editors/grid_map/pick_distance")); settings_vbc->add_margin_child(TTR("Pick Distance:"), settings_pick_distance); - options->get_popup()->connect("id_pressed", callable_mp(this, &GridMapEditor::_menu_option)); + options->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &GridMapEditor::_menu_option)); HBoxContainer *hb = memnew(HBoxContainer); add_child(hb); diff --git a/modules/multiplayer/editor/replication_editor.cpp b/modules/multiplayer/editor/replication_editor.cpp index 3cc0a5ae53..b28572cf72 100644 --- a/modules/multiplayer/editor/replication_editor.cpp +++ b/modules/multiplayer/editor/replication_editor.cpp @@ -372,7 +372,7 @@ void ReplicationEditor::_notification(int p_what) { [[fallthrough]]; } case NOTIFICATION_ENTER_TREE: { - add_theme_style_override("panel", EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("panel"), SNAME("Panel"))); + add_theme_style_override(SceneStringName(panel), EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SceneStringName(panel), SNAME("Panel"))); add_pick_button->set_icon(get_theme_icon(SNAME("Add"), EditorStringName(EditorIcons))); pin->set_icon(get_theme_icon(SNAME("Pin"), EditorStringName(EditorIcons))); } break; diff --git a/modules/multiplayer/scene_cache_interface.cpp b/modules/multiplayer/scene_cache_interface.cpp index 2ea9ce8819..af43123b29 100644 --- a/modules/multiplayer/scene_cache_interface.cpp +++ b/modules/multiplayer/scene_cache_interface.cpp @@ -76,7 +76,7 @@ void SceneCacheInterface::on_peer_change(int p_id, bool p_connected) { for (KeyValue<int, ObjectID> E : pinfo->recv_nodes) { NodeCache *nc = nodes_cache.getptr(E.value); ERR_CONTINUE(!nc); - nc->recv_ids.erase(E.key); + nc->recv_ids.erase(p_id); } for (const ObjectID &oid : pinfo->sent_nodes) { NodeCache *nc = nodes_cache.getptr(oid); diff --git a/modules/navigation/2d/nav_mesh_generator_2d.cpp b/modules/navigation/2d/nav_mesh_generator_2d.cpp index 2198158f9c..ace361a08a 100644 --- a/modules/navigation/2d/nav_mesh_generator_2d.cpp +++ b/modules/navigation/2d/nav_mesh_generator_2d.cpp @@ -263,7 +263,7 @@ void NavMeshGenerator2D::generator_parse_geometry_node(Ref<NavigationPolygon> p_ // Special case for TileMap, so that internal layer get parsed even if p_recurse_children is false. for (int i = 0; i < p_node->get_child_count(); i++) { TileMapLayer *tile_map_layer = Object::cast_to<TileMapLayer>(p_node->get_child(i)); - if (tile_map_layer->get_index_in_tile_map() >= 0) { + if (tile_map_layer && tile_map_layer->get_index_in_tile_map() >= 0) { generator_parse_tile_map_layer_node(p_navigation_mesh, p_source_geometry_data, tile_map_layer); } } diff --git a/modules/openxr/editor/openxr_action_map_editor.cpp b/modules/openxr/editor/openxr_action_map_editor.cpp index 62b4a427b9..937973f388 100644 --- a/modules/openxr/editor/openxr_action_map_editor.cpp +++ b/modules/openxr/editor/openxr_action_map_editor.cpp @@ -59,7 +59,7 @@ void OpenXRActionMapEditor::_notification(int p_what) { 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("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); + tab->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree"))); } } } break; @@ -110,7 +110,7 @@ OpenXRInteractionProfileEditorBase *OpenXRActionMapEditor::_add_interaction_prof // now add it in.. ERR_FAIL_NULL_V(new_profile_editor, nullptr); tabs->add_child(new_profile_editor); - new_profile_editor->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); + 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"))); return new_profile_editor; diff --git a/modules/openxr/editor/openxr_action_set_editor.cpp b/modules/openxr/editor/openxr_action_set_editor.cpp index 5d9a3155fb..e2a843a051 100644 --- a/modules/openxr/editor/openxr_action_set_editor.cpp +++ b/modules/openxr/editor/openxr_action_set_editor.cpp @@ -63,7 +63,7 @@ void OpenXRActionSetEditor::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { _theme_changed(); - panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TabContainer"))); + panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("TabContainer"))); } break; } } diff --git a/modules/openxr/editor/openxr_interaction_profile_editor.cpp b/modules/openxr/editor/openxr_interaction_profile_editor.cpp index ab36c0744e..651171358c 100644 --- a/modules/openxr/editor/openxr_interaction_profile_editor.cpp +++ b/modules/openxr/editor/openxr_interaction_profile_editor.cpp @@ -285,7 +285,7 @@ void OpenXRInteractionProfileEditor::_update_interaction_profile() { PanelContainer *panel = memnew(PanelContainer); panel->set_v_size_flags(Control::SIZE_EXPAND_FILL); main_hb->add_child(panel); - panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TabContainer"))); + panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("TabContainer"))); VBoxContainer *container = memnew(VBoxContainer); panel->add_child(container); @@ -310,7 +310,7 @@ void OpenXRInteractionProfileEditor::_theme_changed() { for (int i = 0; i < main_hb->get_child_count(); i++) { Control *panel = Object::cast_to<Control>(main_hb->get_child(i)); if (panel) { - panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TabContainer"))); + panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("TabContainer"))); } } } diff --git a/modules/openxr/editor/openxr_select_action_dialog.cpp b/modules/openxr/editor/openxr_select_action_dialog.cpp index de0ab40f9e..a4ccc98408 100644 --- a/modules/openxr/editor/openxr_select_action_dialog.cpp +++ b/modules/openxr/editor/openxr_select_action_dialog.cpp @@ -38,7 +38,7 @@ void OpenXRSelectActionDialog::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { - scroll->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); + scroll->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree"))); } break; } } diff --git a/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp b/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp index e6705d5c82..53b8cbd401 100644 --- a/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp +++ b/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp @@ -38,7 +38,7 @@ void OpenXRSelectInteractionProfileDialog::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { - scroll->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); + scroll->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree"))); } break; } } diff --git a/modules/openxr/scene/openxr_composition_layer.cpp b/modules/openxr/scene/openxr_composition_layer.cpp index b02f3082ab..f69a907be9 100644 --- a/modules/openxr/scene/openxr_composition_layer.cpp +++ b/modules/openxr/scene/openxr_composition_layer.cpp @@ -151,6 +151,16 @@ void OpenXRCompositionLayer::update_fallback_mesh() { should_update_fallback_mesh = true; } +XrPosef OpenXRCompositionLayer::get_openxr_pose() { + Transform3D reference_frame = XRServer::get_singleton()->get_reference_frame(); + Transform3D transform = reference_frame.inverse() * get_transform(); + Quaternion quat(transform.basis.orthonormalized()); + return { + { (float)quat.x, (float)quat.y, (float)quat.z, (float)quat.w }, + { (float)transform.origin.x, (float)transform.origin.y, (float)transform.origin.z } + }; +} + bool OpenXRCompositionLayer::is_viewport_in_use(SubViewport *p_viewport) { for (const OpenXRCompositionLayer *other_composition_layer : composition_layer_nodes) { if (other_composition_layer != this && other_composition_layer->is_inside_tree() && other_composition_layer->get_layer_viewport() == p_viewport) { diff --git a/modules/openxr/scene/openxr_composition_layer.h b/modules/openxr/scene/openxr_composition_layer.h index 6792364295..55cae27d23 100644 --- a/modules/openxr/scene/openxr_composition_layer.h +++ b/modules/openxr/scene/openxr_composition_layer.h @@ -77,6 +77,8 @@ protected: void update_fallback_mesh(); + XrPosef get_openxr_pose(); + static Vector<OpenXRCompositionLayer *> composition_layer_nodes; bool is_viewport_in_use(SubViewport *p_viewport); diff --git a/modules/openxr/scene/openxr_composition_layer_cylinder.cpp b/modules/openxr/scene/openxr_composition_layer_cylinder.cpp index 728ba71006..6c8d2fc885 100644 --- a/modules/openxr/scene/openxr_composition_layer_cylinder.cpp +++ b/modules/openxr/scene/openxr_composition_layer_cylinder.cpp @@ -52,6 +52,7 @@ OpenXRCompositionLayerCylinder::OpenXRCompositionLayerCylinder() { aspect_ratio, // aspectRatio }; openxr_layer_provider = memnew(OpenXRViewportCompositionLayerProvider((XrCompositionLayerBaseHeader *)&composition_layer)); + XRServer::get_singleton()->connect("reference_frame_changed", callable_mp(this, &OpenXRCompositionLayerCylinder::update_transform)); } OpenXRCompositionLayerCylinder::~OpenXRCompositionLayerCylinder() { @@ -131,14 +132,15 @@ Ref<Mesh> OpenXRCompositionLayerCylinder::_create_fallback_mesh() { void OpenXRCompositionLayerCylinder::_notification(int p_what) { switch (p_what) { case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { - Transform3D transform = get_transform(); - Quaternion quat(transform.basis.orthonormalized()); - composition_layer.pose.orientation = { (float)quat.x, (float)quat.y, (float)quat.z, (float)quat.w }; - composition_layer.pose.position = { (float)transform.origin.x, (float)transform.origin.y, (float)transform.origin.z }; + update_transform(); } break; } } +void OpenXRCompositionLayerCylinder::update_transform() { + composition_layer.pose = get_openxr_pose(); +} + void OpenXRCompositionLayerCylinder::set_radius(float p_radius) { ERR_FAIL_COND(p_radius <= 0); radius = p_radius; diff --git a/modules/openxr/scene/openxr_composition_layer_cylinder.h b/modules/openxr/scene/openxr_composition_layer_cylinder.h index bb1d242267..9bd5a42d36 100644 --- a/modules/openxr/scene/openxr_composition_layer_cylinder.h +++ b/modules/openxr/scene/openxr_composition_layer_cylinder.h @@ -50,6 +50,8 @@ protected: void _notification(int p_what); + void update_transform(); + virtual Ref<Mesh> _create_fallback_mesh() override; public: diff --git a/modules/openxr/scene/openxr_composition_layer_equirect.cpp b/modules/openxr/scene/openxr_composition_layer_equirect.cpp index 14cfea8da6..b6f5d27ffe 100644 --- a/modules/openxr/scene/openxr_composition_layer_equirect.cpp +++ b/modules/openxr/scene/openxr_composition_layer_equirect.cpp @@ -53,6 +53,7 @@ OpenXRCompositionLayerEquirect::OpenXRCompositionLayerEquirect() { -lower_vertical_angle, // lowerVerticalAngle }; openxr_layer_provider = memnew(OpenXRViewportCompositionLayerProvider((XrCompositionLayerBaseHeader *)&composition_layer)); + XRServer::get_singleton()->connect("reference_frame_changed", callable_mp(this, &OpenXRCompositionLayerEquirect::update_transform)); } OpenXRCompositionLayerEquirect::~OpenXRCompositionLayerEquirect() { @@ -139,14 +140,15 @@ Ref<Mesh> OpenXRCompositionLayerEquirect::_create_fallback_mesh() { void OpenXRCompositionLayerEquirect::_notification(int p_what) { switch (p_what) { case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { - Transform3D transform = get_transform(); - Quaternion quat(transform.basis.orthonormalized()); - composition_layer.pose.orientation = { (float)quat.x, (float)quat.y, (float)quat.z, (float)quat.w }; - composition_layer.pose.position = { (float)transform.origin.x, (float)transform.origin.y, (float)transform.origin.z }; + update_transform(); } break; } } +void OpenXRCompositionLayerEquirect::update_transform() { + composition_layer.pose = get_openxr_pose(); +} + void OpenXRCompositionLayerEquirect::set_radius(float p_radius) { ERR_FAIL_COND(p_radius <= 0); radius = p_radius; diff --git a/modules/openxr/scene/openxr_composition_layer_equirect.h b/modules/openxr/scene/openxr_composition_layer_equirect.h index 66f8b0a91c..af6cd92cbe 100644 --- a/modules/openxr/scene/openxr_composition_layer_equirect.h +++ b/modules/openxr/scene/openxr_composition_layer_equirect.h @@ -51,6 +51,8 @@ protected: void _notification(int p_what); + void update_transform(); + virtual Ref<Mesh> _create_fallback_mesh() override; public: diff --git a/modules/openxr/scene/openxr_composition_layer_quad.cpp b/modules/openxr/scene/openxr_composition_layer_quad.cpp index 8c5b8ec26b..21919496d6 100644 --- a/modules/openxr/scene/openxr_composition_layer_quad.cpp +++ b/modules/openxr/scene/openxr_composition_layer_quad.cpp @@ -50,6 +50,7 @@ OpenXRCompositionLayerQuad::OpenXRCompositionLayerQuad() { { (float)quad_size.x, (float)quad_size.y }, // size }; openxr_layer_provider = memnew(OpenXRViewportCompositionLayerProvider((XrCompositionLayerBaseHeader *)&composition_layer)); + XRServer::get_singleton()->connect("reference_frame_changed", callable_mp(this, &OpenXRCompositionLayerQuad::update_transform)); } OpenXRCompositionLayerQuad::~OpenXRCompositionLayerQuad() { @@ -72,14 +73,15 @@ Ref<Mesh> OpenXRCompositionLayerQuad::_create_fallback_mesh() { void OpenXRCompositionLayerQuad::_notification(int p_what) { switch (p_what) { case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { - Transform3D transform = get_transform(); - Quaternion quat(transform.basis.orthonormalized()); - composition_layer.pose.orientation = { (float)quat.x, (float)quat.y, (float)quat.z, (float)quat.w }; - composition_layer.pose.position = { (float)transform.origin.x, (float)transform.origin.y, (float)transform.origin.z }; + update_transform(); } break; } } +void OpenXRCompositionLayerQuad::update_transform() { + composition_layer.pose = get_openxr_pose(); +} + void OpenXRCompositionLayerQuad::set_quad_size(const Size2 &p_size) { quad_size = p_size; composition_layer.size = { (float)quad_size.x, (float)quad_size.y }; diff --git a/modules/openxr/scene/openxr_composition_layer_quad.h b/modules/openxr/scene/openxr_composition_layer_quad.h index 21bb9b2d85..0c3172dbb2 100644 --- a/modules/openxr/scene/openxr_composition_layer_quad.h +++ b/modules/openxr/scene/openxr_composition_layer_quad.h @@ -47,6 +47,8 @@ protected: void _notification(int p_what); + void update_transform(); + virtual Ref<Mesh> _create_fallback_mesh() override; public: diff --git a/platform/android/android_input_handler.cpp b/platform/android/android_input_handler.cpp index 373dd399e4..41edc35276 100644 --- a/platform/android/android_input_handler.cpp +++ b/platform/android/android_input_handler.cpp @@ -176,6 +176,8 @@ void AndroidInputHandler::process_touch_event(int p_event, int p_pointer, const for (int i = 0; i < p_points.size(); i++) { touch.write[i].id = p_points[i].id; touch.write[i].pos = p_points[i].pos; + touch.write[i].pressure = p_points[i].pressure; + touch.write[i].tilt = p_points[i].tilt; } //send touch @@ -208,6 +210,8 @@ void AndroidInputHandler::process_touch_event(int p_event, int p_pointer, const ev->set_position(p_points[idx].pos); ev->set_relative(p_points[idx].pos - touch[i].pos); ev->set_relative_screen_position(ev->get_relative()); + ev->set_pressure(p_points[idx].pressure); + ev->set_tilt(p_points[idx].tilt); Input::get_singleton()->parse_input_event(ev); touch.write[i].pos = p_points[idx].pos; } diff --git a/platform/android/android_input_handler.h b/platform/android/android_input_handler.h index 78a484cf05..e3365d8cb8 100644 --- a/platform/android/android_input_handler.h +++ b/platform/android/android_input_handler.h @@ -42,6 +42,8 @@ public: struct TouchPos { int id = 0; Point2 pos; + float pressure = 0; + Vector2 tilt; }; struct MouseEventInfo { diff --git a/platform/android/detect.py b/platform/android/detect.py index ed0ceb5862..0b182aca90 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -68,7 +68,7 @@ def get_min_target_api(): def get_flags(): return { - "arch": "arm64", # Default for convenience. + "arch": "arm64", "target": "template_debug", "supported": ["mono"], } diff --git a/platform/android/java/app/build.gradle b/platform/android/java/app/build.gradle index b83ef1471c..bde6a93c86 100644 --- a/platform/android/java/app/build.gradle +++ b/platform/android/java/app/build.gradle @@ -124,6 +124,12 @@ android { // - https://stackoverflow.com/a/44704840 useLegacyPackaging shouldUseLegacyPackaging() } + + // Always select Godot's version of libc++_shared.so in case deps have their own + pickFirst 'lib/x86/libc++_shared.so' + pickFirst 'lib/x86_64/libc++_shared.so' + pickFirst 'lib/armeabi-v7a/libc++_shared.so' + pickFirst 'lib/arm64-v8a/libc++_shared.so' } signingConfigs { diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java index dc8a0e54bb..c085bb8886 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java @@ -266,8 +266,13 @@ public class GodotEditText extends EditText { boolean hasHardwareKeyboard() { Configuration config = getResources().getConfiguration(); - return config.keyboard != Configuration.KEYBOARD_NOKEYS && + boolean hasHardwareKeyboardConfig = config.keyboard != Configuration.KEYBOARD_NOKEYS && config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO; + if (hasHardwareKeyboardConfig) { + return true; + } + + return mRenderView.getInputHandler().hasHardwareKeyboard(); } // =========================================================== diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt index cfbbcf7d0e..49b34a5229 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt +++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt @@ -65,7 +65,7 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi private var lastDragY: Float = 0.0f override fun onDown(event: MotionEvent): Boolean { - GodotInputHandler.handleMotionEvent(event.source, MotionEvent.ACTION_DOWN, event.buttonState, event.x, event.y, nextDownIsDoubleTap) + GodotInputHandler.handleMotionEvent(event, MotionEvent.ACTION_DOWN, nextDownIsDoubleTap) nextDownIsDoubleTap = false return true } @@ -85,20 +85,14 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi } // Cancel the previous down event - GodotInputHandler.handleMotionEvent( - event.source, - MotionEvent.ACTION_CANCEL, - event.buttonState, - event.x, - event.y - ) + GodotInputHandler.handleMotionEvent(event, MotionEvent.ACTION_CANCEL) // Turn a context click into a single tap right mouse button click. GodotInputHandler.handleMouseEvent( + event, MotionEvent.ACTION_DOWN, MotionEvent.BUTTON_SECONDARY, - event.x, - event.y + false ) contextClickInProgress = true } @@ -110,16 +104,7 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi if (!hasCapture) { // Dispatch a mouse relative ACTION_UP event to signal the end of the capture - GodotInputHandler.handleMouseEvent( - MotionEvent.ACTION_UP, - 0, - 0f, - 0f, - 0f, - 0f, - false, - true - ) + GodotInputHandler.handleMouseEvent(MotionEvent.ACTION_UP, true) } pointerCaptureInProgress = hasCapture } @@ -142,26 +127,11 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi return true } - val sourceMouseRelative = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE) - } else { - false - } - if (pointerCaptureInProgress || dragInProgress || contextClickInProgress) { if (contextClickInProgress || GodotInputHandler.isMouseEvent(event)) { // This may be an ACTION_BUTTON_RELEASE event which we don't handle, // so we convert it to an ACTION_UP event. - GodotInputHandler.handleMouseEvent( - MotionEvent.ACTION_UP, - event.buttonState, - event.x, - event.y, - 0f, - 0f, - false, - sourceMouseRelative - ) + GodotInputHandler.handleMouseEvent(event, MotionEvent.ACTION_UP) } else { GodotInputHandler.handleTouchEvent(event) } @@ -178,21 +148,7 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi private fun onActionMove(event: MotionEvent): Boolean { if (contextClickInProgress) { - val sourceMouseRelative = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE) - } else { - false - } - GodotInputHandler.handleMouseEvent( - event.actionMasked, - MotionEvent.BUTTON_SECONDARY, - event.x, - event.y, - 0f, - 0f, - false, - sourceMouseRelative - ) + GodotInputHandler.handleMouseEvent(event, event.actionMasked, MotionEvent.BUTTON_SECONDARY, false) return true } else if (!scaleInProgress) { // The 'onScroll' event is triggered with a long delay. @@ -213,7 +169,7 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi if (event.actionMasked == MotionEvent.ACTION_UP) { nextDownIsDoubleTap = false GodotInputHandler.handleMotionEvent(event) - } else if (event.actionMasked == MotionEvent.ACTION_MOVE && panningAndScalingEnabled == false) { + } else if (event.actionMasked == MotionEvent.ACTION_MOVE && !panningAndScalingEnabled) { GodotInputHandler.handleMotionEvent(event) } @@ -235,13 +191,7 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi if (dragInProgress || lastDragX != 0.0f || lastDragY != 0.0f) { if (originEvent != null) { // Cancel the drag - GodotInputHandler.handleMotionEvent( - originEvent.source, - MotionEvent.ACTION_CANCEL, - originEvent.buttonState, - originEvent.x, - originEvent.y - ) + GodotInputHandler.handleMotionEvent(originEvent, MotionEvent.ACTION_CANCEL) } dragInProgress = false lastDragX = 0.0f diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java index fe971cf442..43ae71f8e1 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java @@ -62,6 +62,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { private final SparseIntArray mJoystickIds = new SparseIntArray(4); private final SparseArray<Joystick> mJoysticksDevices = new SparseArray<>(4); + private final HashSet<Integer> mHardwareKeyboardIds = new HashSet<>(); private final GodotRenderView mRenderView; private final InputManager mInputManager; @@ -114,6 +115,10 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { rotaryInputAxis = axis; } + boolean hasHardwareKeyboard() { + return !mHardwareKeyboardIds.isEmpty(); + } + private boolean isKeyEventGameDevice(int source) { // Note that keyboards are often (SOURCE_KEYBOARD | SOURCE_DPAD) if (source == (InputDevice.SOURCE_KEYBOARD | InputDevice.SOURCE_DPAD)) @@ -195,7 +200,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { } public boolean onTouchEvent(final MotionEvent event) { - lastSeenToolType = event.getToolType(0); + lastSeenToolType = getEventToolType(event); this.scaleGestureDetector.onTouchEvent(event); if (this.gestureDetector.onTouchEvent(event)) { @@ -221,7 +226,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { } public boolean onGenericMotionEvent(MotionEvent event) { - lastSeenToolType = event.getToolType(0); + lastSeenToolType = getEventToolType(event); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && gestureDetector.onGenericMotionEvent(event)) { // The gesture detector has handled the event. @@ -310,11 +315,17 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { return; } - int sources = device.getSources(); + // Device may be an external keyboard; store the device id + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && + device.supportsSource(InputDevice.SOURCE_KEYBOARD) && + device.isExternal() && + device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) { + mHardwareKeyboardIds.add(deviceId); + } // Device may not be a joystick or gamepad - if ((sources & InputDevice.SOURCE_GAMEPAD) != InputDevice.SOURCE_GAMEPAD && - (sources & InputDevice.SOURCE_JOYSTICK) != InputDevice.SOURCE_JOYSTICK) { + if (!device.supportsSource(InputDevice.SOURCE_GAMEPAD) && + !device.supportsSource(InputDevice.SOURCE_JOYSTICK)) { return; } @@ -359,6 +370,8 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { @Override public void onInputDeviceRemoved(int deviceId) { + mHardwareKeyboardIds.remove(deviceId); + // Check if the device has not been already removed if (mJoystickIds.indexOfKey(deviceId) < 0) { return; @@ -440,50 +453,65 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { return button; } - static boolean isMouseEvent(MotionEvent event) { - return isMouseEvent(event.getSource()); + private static int getEventToolType(MotionEvent event) { + return event.getPointerCount() > 0 ? event.getToolType(0) : MotionEvent.TOOL_TYPE_UNKNOWN; } - private static boolean isMouseEvent(int eventSource) { - boolean mouseSource = ((eventSource & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) || ((eventSource & InputDevice.SOURCE_STYLUS) == InputDevice.SOURCE_STYLUS); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - mouseSource = mouseSource || ((eventSource & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE); + static boolean isMouseEvent(MotionEvent event) { + int toolType = getEventToolType(event); + int eventSource = event.getSource(); + + switch (toolType) { + case MotionEvent.TOOL_TYPE_FINGER: + return false; + + case MotionEvent.TOOL_TYPE_MOUSE: + case MotionEvent.TOOL_TYPE_STYLUS: + case MotionEvent.TOOL_TYPE_ERASER: + return true; + + case MotionEvent.TOOL_TYPE_UNKNOWN: + default: + boolean mouseSource = + ((eventSource & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) || + ((eventSource & (InputDevice.SOURCE_TOUCHSCREEN | InputDevice.SOURCE_STYLUS)) == InputDevice.SOURCE_STYLUS); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + mouseSource = mouseSource || + ((eventSource & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE); + } + return mouseSource; } - return mouseSource; } static boolean handleMotionEvent(final MotionEvent event) { - if (isMouseEvent(event)) { - return handleMouseEvent(event); - } - - return handleTouchEvent(event); + return handleMotionEvent(event, event.getActionMasked()); } - static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y) { - return handleMotionEvent(eventSource, eventAction, buttonsMask, x, y, false); + static boolean handleMotionEvent(final MotionEvent event, int eventActionOverride) { + return handleMotionEvent(event, eventActionOverride, false); } - static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y, boolean doubleTap) { - return handleMotionEvent(eventSource, eventAction, buttonsMask, x, y, 0, 0, doubleTap); + static boolean handleMotionEvent(final MotionEvent event, int eventActionOverride, boolean doubleTap) { + if (isMouseEvent(event)) { + return handleMouseEvent(event, eventActionOverride, doubleTap); + } + return handleTouchEvent(event, eventActionOverride, doubleTap); } - static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleTap) { - if (isMouseEvent(eventSource)) { - return handleMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, doubleTap, false); - } + private static float getEventTiltX(MotionEvent event) { + // Orientation is returned as a radian value between 0 to pi clockwise or 0 to -pi counterclockwise. + final float orientation = event.getOrientation(); - return handleTouchEvent(eventAction, x, y, doubleTap); - } + // Tilt is zero is perpendicular to the screen and pi/2 is flat on the surface. + final float tilt = event.getAxisValue(MotionEvent.AXIS_TILT); - static boolean handleMouseEvent(final MotionEvent event) { - final int eventAction = event.getActionMasked(); - final float x = event.getX(); - final float y = event.getY(); - final int buttonsMask = event.getButtonState(); + float tiltMult = (float)Math.sin(tilt); - final float pressure = event.getPressure(); + // To be consistent with expected tilt. + return (float)-Math.sin(orientation) * tiltMult; + } + private static float getEventTiltY(MotionEvent event) { // Orientation is returned as a radian value between 0 to pi clockwise or 0 to -pi counterclockwise. final float orientation = event.getOrientation(); @@ -493,8 +521,26 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { float tiltMult = (float)Math.sin(tilt); // To be consistent with expected tilt. - final float tiltX = (float)-Math.sin(orientation) * tiltMult; - final float tiltY = (float)Math.cos(orientation) * tiltMult; + return (float)Math.cos(orientation) * tiltMult; + } + + static boolean handleMouseEvent(final MotionEvent event) { + return handleMouseEvent(event, event.getActionMasked()); + } + + static boolean handleMouseEvent(final MotionEvent event, int eventActionOverride) { + return handleMouseEvent(event, eventActionOverride, false); + } + + static boolean handleMouseEvent(final MotionEvent event, int eventActionOverride, boolean doubleTap) { + return handleMouseEvent(event, eventActionOverride, event.getButtonState(), doubleTap); + } + + static boolean handleMouseEvent(final MotionEvent event, int eventActionOverride, int buttonMaskOverride, boolean doubleTap) { + final float x = event.getX(); + final float y = event.getY(); + + final float pressure = event.getPressure(); float verticalFactor = 0; float horizontalFactor = 0; @@ -516,15 +562,11 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { sourceMouseRelative = event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE); } - return handleMouseEvent(eventAction, buttonsMask, x, y, horizontalFactor, verticalFactor, false, sourceMouseRelative, pressure, tiltX, tiltY); + return handleMouseEvent(eventActionOverride, buttonMaskOverride, x, y, horizontalFactor, verticalFactor, doubleTap, sourceMouseRelative, pressure, getEventTiltX(event), getEventTiltY(event)); } - static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y) { - return handleMouseEvent(eventAction, buttonsMask, x, y, 0, 0, false, false); - } - - static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative) { - return handleMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, doubleClick, sourceMouseRelative, 1, 0, 0); + static boolean handleMouseEvent(int eventAction, boolean sourceMouseRelative) { + return handleMouseEvent(eventAction, 0, 0f, 0f, 0f, 0f, false, sourceMouseRelative, 1f, 0f, 0f); } static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative, float pressure, float tiltX, float tiltY) { @@ -563,37 +605,39 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { } static boolean handleTouchEvent(final MotionEvent event) { + return handleTouchEvent(event, event.getActionMasked()); + } + + static boolean handleTouchEvent(final MotionEvent event, int eventActionOverride) { + return handleTouchEvent(event, eventActionOverride, false); + } + + static boolean handleTouchEvent(final MotionEvent event, int eventActionOverride, boolean doubleTap) { final int pointerCount = event.getPointerCount(); if (pointerCount == 0) { return true; } - final float[] positions = new float[pointerCount * 3]; // pointerId1, x1, y1, pointerId2, etc... + final float[] positions = new float[pointerCount * 6]; // pointerId1, x1, y1, pressure1, tiltX1, tiltY1, pointerId2, etc... for (int i = 0; i < pointerCount; i++) { - positions[i * 3 + 0] = event.getPointerId(i); - positions[i * 3 + 1] = event.getX(i); - positions[i * 3 + 2] = event.getY(i); + positions[i * 6 + 0] = event.getPointerId(i); + positions[i * 6 + 1] = event.getX(i); + positions[i * 6 + 2] = event.getY(i); + positions[i * 6 + 3] = event.getPressure(i); + positions[i * 6 + 4] = getEventTiltX(event); + positions[i * 6 + 5] = getEventTiltY(event); } - final int action = event.getActionMasked(); final int actionPointerId = event.getPointerId(event.getActionIndex()); - return handleTouchEvent(action, actionPointerId, pointerCount, positions, false); - } - - static boolean handleTouchEvent(int eventAction, float x, float y, boolean doubleTap) { - return handleTouchEvent(eventAction, 0, 1, new float[] { 0, x, y }, doubleTap); - } - - static boolean handleTouchEvent(int eventAction, int actionPointerId, int pointerCount, float[] positions, boolean doubleTap) { - switch (eventAction) { + switch (eventActionOverride) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: case MotionEvent.ACTION_MOVE: case MotionEvent.ACTION_POINTER_UP: case MotionEvent.ACTION_POINTER_DOWN: { - GodotLib.dispatchTouchEvent(eventAction, actionPointerId, pointerCount, positions, doubleTap); + GodotLib.dispatchTouchEvent(eventActionOverride, actionPointerId, pointerCount, positions, doubleTap); return true; } } diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp index 93743c4e35..40068745d6 100644 --- a/platform/android/java_godot_lib_jni.cpp +++ b/platform/android/java_godot_lib_jni.cpp @@ -298,11 +298,13 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchTouchEvent(JN Vector<AndroidInputHandler::TouchPos> points; for (int i = 0; i < pointer_count; i++) { - jfloat p[3]; - env->GetFloatArrayRegion(position, i * 3, 3, p); + jfloat p[6]; + env->GetFloatArrayRegion(position, i * 6, 6, p); AndroidInputHandler::TouchPos tp; - tp.pos = Point2(p[1], p[2]); tp.id = (int)p[0]; + tp.pos = Point2(p[1], p[2]); + tp.pressure = p[3]; + tp.tilt = Vector2(p[4], p[5]); points.push_back(tp); } diff --git a/platform/ios/detect.py b/platform/ios/detect.py index 35e1b9cd6d..53b367a0a7 100644 --- a/platform/ios/detect.py +++ b/platform/ios/detect.py @@ -48,7 +48,7 @@ def get_doc_path(): def get_flags(): return { - "arch": "arm64", # Default for convenience. + "arch": "arm64", "target": "template_debug", "use_volk": False, "supported": ["mono"], diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm index 5d7af25f28..a454dd5ba0 100644 --- a/platform/ios/display_server_ios.mm +++ b/platform/ios/display_server_ios.mm @@ -399,7 +399,12 @@ void DisplayServerIOS::set_system_theme_change_callback(const Callable &p_callab void DisplayServerIOS::emit_system_theme_changed() { if (system_theme_changed.is_valid()) { - system_theme_changed.call(); + Variant ret; + Callable::CallError ce; + system_theme_changed.callp(nullptr, 0, ret, ce); + if (ce.error != Callable::CallError::CALL_OK) { + ERR_PRINT(vformat("Failed to execute system theme changed callback: %s.", Variant::get_callable_error_text(system_theme_changed, nullptr, 0, ce))); + } } } diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp index 6a452f08fa..bc3a6d4628 100644 --- a/platform/ios/export/export_plugin.cpp +++ b/platform/ios/export/export_plugin.cpp @@ -541,6 +541,44 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_ } strnew += lines[i].replace("$interface_orientations", orientations); + } else if (lines[i].contains("$ipad_interface_orientations")) { + String orientations; + const DisplayServer::ScreenOrientation screen_orientation = + DisplayServer::ScreenOrientation(int(GLOBAL_GET("display/window/handheld/orientation"))); + + switch (screen_orientation) { + case DisplayServer::SCREEN_LANDSCAPE: + orientations += "<string>UIInterfaceOrientationLandscapeRight</string>\n"; + break; + case DisplayServer::SCREEN_PORTRAIT: + orientations += "<string>UIInterfaceOrientationPortrait</string>\n"; + break; + case DisplayServer::SCREEN_REVERSE_LANDSCAPE: + orientations += "<string>UIInterfaceOrientationLandscapeLeft</string>\n"; + break; + case DisplayServer::SCREEN_REVERSE_PORTRAIT: + orientations += "<string>UIInterfaceOrientationPortraitUpsideDown</string>\n"; + break; + case DisplayServer::SCREEN_SENSOR_LANDSCAPE: + // Allow both landscape orientations depending on sensor direction. + orientations += "<string>UIInterfaceOrientationLandscapeLeft</string>\n"; + orientations += "<string>UIInterfaceOrientationLandscapeRight</string>\n"; + break; + case DisplayServer::SCREEN_SENSOR_PORTRAIT: + // Allow both portrait orientations depending on sensor direction. + orientations += "<string>UIInterfaceOrientationPortrait</string>\n"; + orientations += "<string>UIInterfaceOrientationPortraitUpsideDown</string>\n"; + break; + case DisplayServer::SCREEN_SENSOR: + // Allow all screen orientations depending on sensor direction. + orientations += "<string>UIInterfaceOrientationLandscapeLeft</string>\n"; + orientations += "<string>UIInterfaceOrientationLandscapeRight</string>\n"; + orientations += "<string>UIInterfaceOrientationPortrait</string>\n"; + orientations += "<string>UIInterfaceOrientationPortraitUpsideDown</string>\n"; + break; + } + + strnew += lines[i].replace("$ipad_interface_orientations", orientations); } else if (lines[i].contains("$camera_usage_description")) { String description = p_preset->get("privacy/camera_usage_description"); strnew += lines[i].replace("$camera_usage_description", description) + "\n"; @@ -1332,7 +1370,12 @@ void EditorExportPlatformIOS::_add_assets_to_project(const String &p_out_dir, co type = "wrapper.framework"; } else if (asset.exported_path.ends_with(".xcframework")) { - if (asset.should_embed) { + int total_libs = 0; + int static_libs = 0; + int dylibs = 0; + int frameworks = 0; + _check_xcframework_content(p_out_dir.path_join(asset.exported_path), total_libs, static_libs, dylibs, frameworks); + if (asset.should_embed && static_libs != total_libs) { additional_asset_info_format += "$framework_id = {isa = PBXBuildFile; fileRef = $ref_id; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };\n"; framework_id = (++current_id).str(); pbx_embeded_frameworks += framework_id + ",\n"; diff --git a/platform/ios/view_controller.mm b/platform/ios/view_controller.mm index 6f6c04c2c8..787e767109 100644 --- a/platform/ios/view_controller.mm +++ b/platform/ios/view_controller.mm @@ -258,7 +258,11 @@ case DisplayServer::SCREEN_PORTRAIT: return UIInterfaceOrientationMaskPortrait; case DisplayServer::SCREEN_REVERSE_LANDSCAPE: - return UIInterfaceOrientationMaskLandscapeRight; + if (UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad) { + return UIInterfaceOrientationMaskLandscapeLeft; + } else { + return UIInterfaceOrientationMaskLandscapeRight; + } case DisplayServer::SCREEN_REVERSE_PORTRAIT: return UIInterfaceOrientationMaskPortraitUpsideDown; case DisplayServer::SCREEN_SENSOR_LANDSCAPE: @@ -268,7 +272,11 @@ case DisplayServer::SCREEN_SENSOR: return UIInterfaceOrientationMaskAll; case DisplayServer::SCREEN_LANDSCAPE: - return UIInterfaceOrientationMaskLandscapeLeft; + if (UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad) { + return UIInterfaceOrientationMaskLandscapeRight; + } else { + return UIInterfaceOrientationMaskLandscapeLeft; + } } } diff --git a/platform/linuxbsd/freedesktop_portal_desktop.cpp b/platform/linuxbsd/freedesktop_portal_desktop.cpp index e65404a531..671da7fc2a 100644 --- a/platform/linuxbsd/freedesktop_portal_desktop.cpp +++ b/platform/linuxbsd/freedesktop_portal_desktop.cpp @@ -591,13 +591,18 @@ void FreeDesktopPortalDesktop::_thread_monitor(void *p_ud) { dbus_connection_read_write(portal->monitor_connection, 0); } - usleep(50000); + OS::get_singleton()->delay_usec(50'000); } } void FreeDesktopPortalDesktop::_system_theme_changed_callback() { if (system_theme_changed.is_valid()) { - system_theme_changed.call(); + Variant ret; + Callable::CallError ce; + system_theme_changed.callp(nullptr, 0, ret, ce); + if (ce.error != Callable::CallError::CALL_OK) { + ERR_PRINT(vformat("Failed to execute system theme changed callback: %s.", Variant::get_callable_error_text(system_theme_changed, nullptr, 0, ce))); + } } } diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp index 6e546c4531..3534c1afee 100644 --- a/platform/linuxbsd/joypad_linux.cpp +++ b/platform/linuxbsd/joypad_linux.cpp @@ -225,7 +225,7 @@ void JoypadLinux::monitor_joypads(udev *p_udev) { udev_device_unref(dev); } } - usleep(50000); + OS::get_singleton()->delay_usec(50'000); } udev_monitor_unref(mon); } @@ -250,7 +250,7 @@ void JoypadLinux::monitor_joypads() { } } closedir(input_directory); - usleep(1000000); // 1s + OS::get_singleton()->delay_usec(1'000'000); } } @@ -508,7 +508,7 @@ void JoypadLinux::joypad_events_thread_run() { } } if (no_events) { - usleep(10000); // 10ms + OS::get_singleton()->delay_usec(10'000); } } } diff --git a/platform/linuxbsd/wayland/display_server_wayland.cpp b/platform/linuxbsd/wayland/display_server_wayland.cpp index ce8a53a856..12d3a6fd2f 100644 --- a/platform/linuxbsd/wayland/display_server_wayland.cpp +++ b/platform/linuxbsd/wayland/display_server_wayland.cpp @@ -1137,7 +1137,14 @@ void DisplayServerWayland::process_events() { WindowData wd = main_window; if (wd.drop_files_callback.is_valid()) { - wd.drop_files_callback.call(dropfiles_msg->files); + Variant v_files = dropfiles_msg->files; + const Variant *v_args[1] = { &v_files }; + Variant ret; + Callable::CallError ce; + wd.drop_files_callback.callp((const Variant **)&v_args, 1, ret, ce); + if (ce.error != Callable::CallError::CALL_OK) { + ERR_PRINT(vformat("Failed to execute drop files callback: %s.", Variant::get_callable_error_text(wd.drop_files_callback, v_args, 1, ce))); + } } } } @@ -1209,6 +1216,15 @@ void DisplayServerWayland::set_context(Context p_context) { wayland_thread.window_set_app_id(MAIN_WINDOW_ID, app_id); } +bool DisplayServerWayland::is_window_transparency_available() const { +#if defined(RD_ENABLED) + if (rendering_device && !rendering_device->is_composite_alpha_supported()) { + return false; + } +#endif + return OS::get_singleton()->is_layered_allowed(); +} + Vector<String> DisplayServerWayland::get_rendering_drivers_func() { Vector<String> drivers; diff --git a/platform/linuxbsd/wayland/display_server_wayland.h b/platform/linuxbsd/wayland/display_server_wayland.h index 38ecbd703d..c24eb0ee62 100644 --- a/platform/linuxbsd/wayland/display_server_wayland.h +++ b/platform/linuxbsd/wayland/display_server_wayland.h @@ -280,6 +280,8 @@ public: virtual void set_context(Context p_context) override; + virtual bool is_window_transparency_available() const override; + static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Point2i *p_position, const Size2i &p_resolution, int p_screen, Context p_context, Error &r_error); static Vector<String> get_rendering_drivers_func(); diff --git a/platform/linuxbsd/wayland/wayland_thread.h b/platform/linuxbsd/wayland/wayland_thread.h index d35a5b7139..0756b6b0ea 100644 --- a/platform/linuxbsd/wayland/wayland_thread.h +++ b/platform/linuxbsd/wayland/wayland_thread.h @@ -43,6 +43,9 @@ #else #include <wayland-client-core.h> #include <wayland-cursor.h> +#ifdef GLES3_ENABLED +#include <wayland-egl.h> +#endif #include <xkbcommon/xkbcommon.h> #endif // SOWRAP_ENABLED diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index 2c07acf94f..767ea927c1 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -2269,7 +2269,7 @@ void DisplayServerX11::window_set_size(const Size2i p_size, WindowID p_window) { break; } - usleep(10000); + OS::get_singleton()->delay_usec(10'000); } // Keep rendering context window size in sync @@ -2544,7 +2544,7 @@ void DisplayServerX11::_set_wm_maximized(WindowID p_window, bool p_enabled) { // Give up after 0.5s, it's not going to happen on this WM. // https://github.com/godotengine/godot/issues/19978 for (int attempt = 0; window_get_mode(p_window) != WINDOW_MODE_MAXIMIZED && attempt < 50; attempt++) { - usleep(10000); + OS::get_singleton()->delay_usec(10'000); } } wd.maximized = p_enabled; @@ -4206,7 +4206,10 @@ void DisplayServerX11::popup_close(WindowID p_window) { WindowID win_id = E->get(); popup_list.erase(E); - _send_window_event(windows[win_id], DisplayServerX11::WINDOW_EVENT_CLOSE_REQUEST); + if (win_id != p_window) { + // Only request close on related windows, not this window. We are already processing it. + _send_window_event(windows[win_id], DisplayServerX11::WINDOW_EVENT_CLOSE_REQUEST); + } E = F; } } @@ -5008,7 +5011,14 @@ void DisplayServerX11::process_events() { } if (windows[window_id].drop_files_callback.is_valid()) { - windows[window_id].drop_files_callback.call(files); + Variant v_files = files; + const Variant *v_args[1] = { &v_files }; + Variant ret; + Callable::CallError ce; + windows[window_id].drop_files_callback.callp((const Variant **)&v_args, 1, ret, ce); + if (ce.error != Callable::CallError::CALL_OK) { + ERR_PRINT(vformat("Failed to execute drop files callback: %s.", Variant::get_callable_error_text(windows[window_id].drop_files_callback, v_args, 1, ce))); + } } //Reply that all is well. diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm index db71c48eff..0ccce1ad6a 100644 --- a/platform/macos/display_server_macos.mm +++ b/platform/macos/display_server_macos.mm @@ -907,7 +907,12 @@ void DisplayServerMacOS::set_system_theme_change_callback(const Callable &p_call void DisplayServerMacOS::emit_system_theme_changed() { if (system_theme_changed.is_valid()) { - system_theme_changed.call(); + Variant ret; + Callable::CallError ce; + system_theme_changed.callp(nullptr, 0, ret, ce); + if (ce.error != Callable::CallError::CALL_OK) { + ERR_PRINT(vformat("Failed to execute system theme changed callback: %s.", Variant::get_callable_error_text(system_theme_changed, nullptr, 0, ce))); + } } } @@ -3448,7 +3453,10 @@ void DisplayServerMacOS::popup_close(WindowID p_window) { WindowID win_id = E->get(); popup_list.erase(E); - send_window_event(windows[win_id], DisplayServerMacOS::WINDOW_EVENT_CLOSE_REQUEST); + if (win_id != p_window) { + // Only request close on related windows, not this window. We are already processing it. + send_window_event(windows[win_id], DisplayServerMacOS::WINDOW_EVENT_CLOSE_REQUEST); + } E = F; } if (!was_empty && popup_list.is_empty()) { diff --git a/platform/macos/godot_content_view.mm b/platform/macos/godot_content_view.mm index 68a7288ad4..7dcb1ac9db 100644 --- a/platform/macos/godot_content_view.mm +++ b/platform/macos/godot_content_view.mm @@ -323,7 +323,14 @@ NSString *file = [NSURL URLWithString:url].path; files.push_back(String::utf8([file UTF8String])); } - wd.drop_files_callback.call(files); + Variant v_files = files; + const Variant *v_args[1] = { &v_files }; + Variant ret; + Callable::CallError ce; + wd.drop_files_callback.callp((const Variant **)&v_args, 1, ret, ce); + if (ce.error != Callable::CallError::CALL_OK) { + ERR_PRINT(vformat("Failed to execute drop files callback: %s.", Variant::get_callable_error_text(wd.drop_files_callback, v_args, 1, ce))); + } } return NO; diff --git a/platform/macos/godot_status_item.mm b/platform/macos/godot_status_item.mm index 0990a16b2b..1b16d496a2 100644 --- a/platform/macos/godot_status_item.mm +++ b/platform/macos/godot_status_item.mm @@ -66,10 +66,13 @@ if (cb.is_valid()) { Variant v_button = index; Variant v_pos = ds->mouse_get_position(); - Variant *v_args[2] = { &v_button, &v_pos }; + const Variant *v_args[2] = { &v_button, &v_pos }; Variant ret; Callable::CallError ce; cb.callp((const Variant **)&v_args, 2, ret, ce); + if (ce.error != Callable::CallError::CALL_OK) { + ERR_PRINT(vformat("Failed to execute status indicator callback: %s.", Variant::get_callable_error_text(cb, v_args, 2, ce))); + } } } diff --git a/platform/web/detect.py b/platform/web/detect.py index 3df8cbad7c..c6568625c1 100644 --- a/platform/web/detect.py +++ b/platform/web/detect.py @@ -181,7 +181,7 @@ def configure(env: "SConsEnvironment"): # Use TempFileMunge since some AR invocations are too long for cmd.exe. # Use POSIX-style paths, required with TempFileMunge. env["ARCOM_POSIX"] = env["ARCOM"].replace("$TARGET", "$TARGET.posix").replace("$SOURCES", "$SOURCES.posix") - env["ARCOM"] = "${TEMPFILE(ARCOM_POSIX)}" + env["ARCOM"] = "${TEMPFILE('$ARCOM_POSIX','$ARCOMSTR')}" # All intermediate files are just object files. env["OBJPREFIX"] = "" diff --git a/platform/web/display_server_web.cpp b/platform/web/display_server_web.cpp index 0420a01533..fab92b1894 100644 --- a/platform/web/display_server_web.cpp +++ b/platform/web/display_server_web.cpp @@ -70,7 +70,7 @@ bool DisplayServerWeb::check_size_force_redraw() { void DisplayServerWeb::fullscreen_change_callback(int p_fullscreen) { #ifdef PROXY_TO_PTHREAD_ENABLED if (!Thread::is_main_thread()) { - callable_mp_static(DisplayServerWeb::_fullscreen_change_callback).bind(p_fullscreen).call_deferred(); + callable_mp_static(DisplayServerWeb::_fullscreen_change_callback).call_deferred(p_fullscreen); return; } #endif @@ -96,7 +96,7 @@ void DisplayServerWeb::drop_files_js_callback(const char **p_filev, int p_filec) #ifdef PROXY_TO_PTHREAD_ENABLED if (!Thread::is_main_thread()) { - callable_mp_static(DisplayServerWeb::_drop_files_js_callback).bind(files).call_deferred(); + callable_mp_static(DisplayServerWeb::_drop_files_js_callback).call_deferred(files); return; } #endif @@ -112,7 +112,14 @@ void DisplayServerWeb::_drop_files_js_callback(const Vector<String> &p_files) { if (!ds->drop_files_callback.is_valid()) { return; } - ds->drop_files_callback.call(p_files); + Variant v_files = p_files; + const Variant *v_args[1] = { &v_files }; + Variant ret; + Callable::CallError ce; + ds->drop_files_callback.callp((const Variant **)&v_args, 1, ret, ce); + if (ce.error != Callable::CallError::CALL_OK) { + ERR_PRINT(vformat("Failed to execute drop files callback: %s.", Variant::get_callable_error_text(ds->drop_files_callback, v_args, 1, ce))); + } } // Web quit request callback. @@ -161,7 +168,7 @@ void DisplayServerWeb::key_callback(int p_pressed, int p_repeat, int p_modifiers #ifdef PROXY_TO_PTHREAD_ENABLED if (!Thread::is_main_thread()) { - callable_mp_static(DisplayServerWeb::_key_callback).bind(code, key, p_pressed, p_repeat, p_modifiers).call_deferred(); + callable_mp_static(DisplayServerWeb::_key_callback).call_deferred(code, key, p_pressed, p_repeat, p_modifiers); return; } #endif @@ -214,7 +221,7 @@ void DisplayServerWeb::_key_callback(const String &p_key_event_code, const Strin int DisplayServerWeb::mouse_button_callback(int p_pressed, int p_button, double p_x, double p_y, int p_modifiers) { #ifdef PROXY_TO_PTHREAD_ENABLED if (!Thread::is_main_thread()) { - callable_mp_static(DisplayServerWeb::_mouse_button_callback).bind(p_pressed, p_button, p_x, p_y, p_modifiers).call_deferred(); + callable_mp_static(DisplayServerWeb::_mouse_button_callback).call_deferred(p_pressed, p_button, p_x, p_y, p_modifiers); return true; } #endif @@ -301,7 +308,7 @@ int DisplayServerWeb::_mouse_button_callback(int p_pressed, int p_button, double void DisplayServerWeb::mouse_move_callback(double p_x, double p_y, double p_rel_x, double p_rel_y, int p_modifiers) { #ifdef PROXY_TO_PTHREAD_ENABLED if (!Thread::is_main_thread()) { - callable_mp_static(DisplayServerWeb::_mouse_move_callback).bind(p_x, p_y, p_rel_x, p_rel_y, p_modifiers).call_deferred(); + callable_mp_static(DisplayServerWeb::_mouse_move_callback).call_deferred(p_x, p_y, p_rel_x, p_rel_y, p_modifiers); return; } #endif @@ -394,7 +401,7 @@ void DisplayServerWeb::update_voices_callback(int p_size, const char **p_voice) #ifdef PROXY_TO_PTHREAD_ENABLED if (!Thread::is_main_thread()) { - callable_mp_static(DisplayServerWeb::_update_voices_callback).bind(voices).call_deferred(); + callable_mp_static(DisplayServerWeb::_update_voices_callback).call_deferred(voices); return; } #endif @@ -461,7 +468,7 @@ void DisplayServerWeb::tts_stop() { void DisplayServerWeb::js_utterance_callback(int p_event, int p_id, int p_pos) { #ifdef PROXY_TO_PTHREAD_ENABLED if (!Thread::is_main_thread()) { - callable_mp_static(DisplayServerWeb::_js_utterance_callback).bind(p_event, p_id, p_pos).call_deferred(); + callable_mp_static(DisplayServerWeb::_js_utterance_callback).call_deferred(p_event, p_id, p_pos); return; } #endif @@ -591,7 +598,7 @@ Point2i DisplayServerWeb::mouse_get_position() const { int DisplayServerWeb::mouse_wheel_callback(double p_delta_x, double p_delta_y) { #ifdef PROXY_TO_PTHREAD_ENABLED if (!Thread::is_main_thread()) { - callable_mp_static(DisplayServerWeb::_mouse_wheel_callback).bind(p_delta_x, p_delta_y).call_deferred(); + callable_mp_static(DisplayServerWeb::_mouse_wheel_callback).call_deferred(p_delta_x, p_delta_y); return true; } #endif @@ -654,7 +661,7 @@ int DisplayServerWeb::_mouse_wheel_callback(double p_delta_x, double p_delta_y) void DisplayServerWeb::touch_callback(int p_type, int p_count) { #ifdef PROXY_TO_PTHREAD_ENABLED if (!Thread::is_main_thread()) { - callable_mp_static(DisplayServerWeb::_touch_callback).bind(p_type, p_count).call_deferred(); + callable_mp_static(DisplayServerWeb::_touch_callback).call_deferred(p_type, p_count); return; } #endif @@ -712,7 +719,7 @@ void DisplayServerWeb::vk_input_text_callback(const char *p_text, int p_cursor) #ifdef PROXY_TO_PTHREAD_ENABLED if (!Thread::is_main_thread()) { - callable_mp_static(DisplayServerWeb::_vk_input_text_callback).bind(text, p_cursor).call_deferred(); + callable_mp_static(DisplayServerWeb::_vk_input_text_callback).call_deferred(text, p_cursor); return; } #endif @@ -774,7 +781,7 @@ void DisplayServerWeb::gamepad_callback(int p_index, int p_connected, const char #ifdef PROXY_TO_PTHREAD_ENABLED if (!Thread::is_main_thread()) { - callable_mp_static(DisplayServerWeb::_gamepad_callback).bind(p_index, p_connected, id, guid).call_deferred(); + callable_mp_static(DisplayServerWeb::_gamepad_callback).call_deferred(p_index, p_connected, id, guid); return; } #endif @@ -797,7 +804,7 @@ void DisplayServerWeb::ime_callback(int p_type, const char *p_text) { #ifdef PROXY_TO_PTHREAD_ENABLED if (!Thread::is_main_thread()) { - callable_mp_static(DisplayServerWeb::_ime_callback).bind(p_type, text).call_deferred(); + callable_mp_static(DisplayServerWeb::_ime_callback).call_deferred(p_type, text); return; } #endif @@ -866,6 +873,9 @@ void DisplayServerWeb::_ime_callback(int p_type, const String &p_text) { default: break; } + + ds->process_keys(); + Input::get_singleton()->flush_buffered_events(); } void DisplayServerWeb::window_set_ime_active(const bool p_active, WindowID p_window) { @@ -927,7 +937,7 @@ void DisplayServerWeb::update_clipboard_callback(const char *p_text) { #ifdef PROXY_TO_PTHREAD_ENABLED if (!Thread::is_main_thread()) { - callable_mp_static(DisplayServerWeb::_update_clipboard_callback).bind(text).call_deferred(); + callable_mp_static(DisplayServerWeb::_update_clipboard_callback).call_deferred(text); return; } #endif @@ -953,7 +963,7 @@ String DisplayServerWeb::clipboard_get() const { void DisplayServerWeb::send_window_event_callback(int p_notification) { #ifdef PROXY_TO_PTHREAD_ENABLED if (!Thread::is_main_thread()) { - callable_mp_static(DisplayServerWeb::_send_window_event_callback).bind(p_notification).call_deferred(); + callable_mp_static(DisplayServerWeb::_send_window_event_callback).call_deferred(p_notification); return; } #endif @@ -1353,29 +1363,33 @@ DisplayServer::VSyncMode DisplayServerWeb::window_get_vsync_mode(WindowID p_vsyn } void DisplayServerWeb::process_events() { + process_keys(); Input::get_singleton()->flush_buffered_events(); if (godot_js_input_gamepad_sample() == OK) { process_joypads(); - for (int i = 0; i < key_event_pos; i++) { - const DisplayServerWeb::KeyEvent &ke = key_event_buffer[i]; + } +} - Ref<InputEventKey> ev; - ev.instantiate(); - ev->set_pressed(ke.pressed); - ev->set_echo(ke.echo); - ev->set_keycode(ke.keycode); - ev->set_physical_keycode(ke.physical_keycode); - ev->set_key_label(ke.key_label); - ev->set_unicode(ke.unicode); - ev->set_location(ke.location); - if (ke.raw) { - dom2godot_mod(ev, ke.mod, ke.keycode); - } +void DisplayServerWeb::process_keys() { + for (int i = 0; i < key_event_pos; i++) { + const DisplayServerWeb::KeyEvent &ke = key_event_buffer[i]; - Input::get_singleton()->parse_input_event(ev); + Ref<InputEventKey> ev; + ev.instantiate(); + ev->set_pressed(ke.pressed); + ev->set_echo(ke.echo); + ev->set_keycode(ke.keycode); + ev->set_physical_keycode(ke.physical_keycode); + ev->set_key_label(ke.key_label); + ev->set_unicode(ke.unicode); + ev->set_location(ke.location); + if (ke.raw) { + dom2godot_mod(ev, ke.mod, ke.keycode); } - key_event_pos = 0; + + Input::get_singleton()->parse_input_event(ev); } + key_event_pos = 0; } int DisplayServerWeb::get_current_video_driver() const { diff --git a/platform/web/display_server_web.h b/platform/web/display_server_web.h index 276ca5210c..352b3fe523 100644 --- a/platform/web/display_server_web.h +++ b/platform/web/display_server_web.h @@ -145,6 +145,7 @@ private: static void _drop_files_js_callback(const Vector<String> &p_files); void process_joypads(); + void process_keys(); static Vector<String> get_rendering_drivers_func(); static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, Error &r_error); diff --git a/platform/web/emscripten_helpers.py b/platform/web/emscripten_helpers.py index 745b2457fa..2cee3e8110 100644 --- a/platform/web/emscripten_helpers.py +++ b/platform/web/emscripten_helpers.py @@ -123,7 +123,6 @@ def create_template_zip(env, js, wasm, worker, side): zip_files, ZIPROOT=zip_dir, ZIPSUFFIX="${PROGSUFFIX}${ZIPSUFFIX}", - ZIPCOMSTR="Archiving $SOURCES as $TARGET", ) diff --git a/platform/web/javascript_bridge_singleton.cpp b/platform/web/javascript_bridge_singleton.cpp index a2c83d2f2b..c4dbb405a3 100644 --- a/platform/web/javascript_bridge_singleton.cpp +++ b/platform/web/javascript_bridge_singleton.cpp @@ -262,7 +262,7 @@ void JavaScriptObjectImpl::callback(void *p_ref, int p_args_id, int p_argc) { #ifdef PROXY_TO_PTHREAD_ENABLED if (!Thread::is_main_thread()) { - callable_mp_static(JavaScriptObjectImpl::_callback).bind(obj, arg).call_deferred(); + callable_mp_static(JavaScriptObjectImpl::_callback).call_deferred(obj, arg); return; } #endif diff --git a/platform/web/js/libs/library_godot_input.js b/platform/web/js/libs/library_godot_input.js index 1292c468f5..7ea89d553f 100644 --- a/platform/web/js/libs/library_godot_input.js +++ b/platform/web/js/libs/library_godot_input.js @@ -63,8 +63,15 @@ const GodotIME = { ime_position: function (x, y) { if (GodotIME.ime) { - GodotIME.ime.style.left = `${x}px`; - GodotIME.ime.style.top = `${y}px`; + const canvas = GodotConfig.canvas; + const rect = canvas.getBoundingClientRect(); + const rw = canvas.width / rect.width; + const rh = canvas.height / rect.height; + const clx = (x / rw) + rect.x; + const cly = (y / rh) + rect.y; + + GodotIME.ime.style.left = `${clx}px`; + GodotIME.ime.style.top = `${cly}px`; } }, @@ -99,10 +106,12 @@ const GodotIME = { ime.style.background = 'none'; ime.style.opacity = 0.0; ime.style.position = 'fixed'; + ime.style.textAlign = 'left'; + ime.style.fontSize = '1px'; ime.style.left = '0px'; ime.style.top = '0px'; - ime.style.width = '2px'; - ime.style.height = '2px'; + ime.style.width = '100%'; + ime.style.height = '40px'; ime.style.display = 'none'; ime.contentEditable = 'true'; diff --git a/platform/windows/SCsub b/platform/windows/SCsub index 1c2bfb9b75..f2fb8616ae 100644 --- a/platform/windows/SCsub +++ b/platform/windows/SCsub @@ -50,6 +50,7 @@ def arrange_program_clean(prog): res_file = "godot_res.rc" res_target = "godot_res" + env["OBJSUFFIX"] res_obj = env.RES(res_target, res_file) +env.Depends(res_obj, "#core/version_generated.gen.h") env.add_source_files(sources, common_win) sources += res_obj @@ -63,6 +64,7 @@ if env["windows_subsystem"] == "gui": res_wrap_file = "godot_res_wrap.rc" res_wrap_target = "godot_res_wrap" + env["OBJSUFFIX"] res_wrap_obj = env_wrap.RES(res_wrap_target, res_wrap_file) + env_wrap.Depends(res_wrap_obj, "#core/version_generated.gen.h") if env.msvc: env_wrap.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"]) diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 03584977fe..4c52d88377 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -1832,24 +1832,6 @@ void DisplayServerWindows::window_set_size(const Size2i p_size, WindowID p_windo int w = p_size.width; int h = p_size.height; - - wd.width = w; - wd.height = h; - -#if defined(RD_ENABLED) - if (rendering_context) { - rendering_context->window_set_size(p_window, w, h); - } -#endif -#if defined(GLES3_ENABLED) - if (gl_manager_native) { - gl_manager_native->window_resize(p_window, w, h); - } - if (gl_manager_angle) { - gl_manager_angle->window_resize(p_window, w, h); - } -#endif - RECT rect; GetWindowRect(wd.hWnd, &rect); @@ -3613,6 +3595,30 @@ void DisplayServerWindows::popup_close(WindowID p_window) { } } +BitField<DisplayServerWindows::WinKeyModifierMask> DisplayServerWindows::_get_mods() const { + BitField<WinKeyModifierMask> mask; + static unsigned char keyboard_state[256]; + if (GetKeyboardState((PBYTE)&keyboard_state)) { + if ((keyboard_state[VK_LSHIFT] & 0x80) || (keyboard_state[VK_RSHIFT] & 0x80)) { + mask.set_flag(WinKeyModifierMask::SHIFT); + } + if ((keyboard_state[VK_LCONTROL] & 0x80) || (keyboard_state[VK_RCONTROL] & 0x80)) { + mask.set_flag(WinKeyModifierMask::CTRL); + } + if ((keyboard_state[VK_LMENU] & 0x80) || (keyboard_state[VK_RMENU] & 0x80)) { + mask.set_flag(WinKeyModifierMask::ALT); + } + if ((keyboard_state[VK_RMENU] & 0x80)) { + mask.set_flag(WinKeyModifierMask::ALT_GR); + } + if ((keyboard_state[VK_LWIN] & 0x80) || (keyboard_state[VK_RWIN] & 0x80)) { + mask.set_flag(WinKeyModifierMask::META); + } + } + + return mask; +} + LRESULT DisplayServerWindows::MouseProc(int code, WPARAM wParam, LPARAM lParam) { _THREAD_SAFE_METHOD_ @@ -3842,7 +3848,12 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } } if (system_theme_changed.is_valid()) { - system_theme_changed.call(); + Variant ret; + Callable::CallError ce; + system_theme_changed.callp(nullptr, 0, ret, ce); + if (ce.error != Callable::CallError::CALL_OK) { + ERR_PRINT(vformat("Failed to execute system theme changed callback: %s.", Variant::get_callable_error_text(system_theme_changed, nullptr, 0, ce))); + } } } break; case WM_THEMECHANGED: { @@ -3863,7 +3874,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA if (((lParam >> 16) <= 0) && !engine->is_project_manager_hint() && !engine->is_editor_hint() && !GLOBAL_GET("application/run/enable_alt_space_menu")) { return 0; } - if (!alt_mem || !(GetAsyncKeyState(VK_SPACE) & (1 << 15))) { + if (!_get_mods().has_flag(WinKeyModifierMask::ALT) || !(GetAsyncKeyState(VK_SPACE) & (1 << 15))) { return 0; } SendMessage(windows[window_id].hWnd, WM_SYSKEYUP, VK_SPACE, 0); @@ -3897,10 +3908,13 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } else if (indicators[iid].callback.is_valid()) { Variant v_button = mb; Variant v_pos = mouse_get_position(); - Variant *v_args[2] = { &v_button, &v_pos }; + const Variant *v_args[2] = { &v_button, &v_pos }; Variant ret; Callable::CallError ce; indicators[iid].callback.callp((const Variant **)&v_args, 2, ret, ce); + if (ce.error != Callable::CallError::CALL_OK) { + ERR_PRINT(vformat("Failed to execute status indicator callback: %s.", Variant::get_callable_error_text(indicators[iid].callback, v_args, 2, ce))); + } } } return 0; @@ -3946,20 +3960,22 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA RAWINPUT *raw = (RAWINPUT *)lpb; + const BitField<WinKeyModifierMask> &mods = _get_mods(); if (raw->header.dwType == RIM_TYPEKEYBOARD) { if (raw->data.keyboard.VKey == VK_SHIFT) { // If multiple Shifts are held down at the same time, // Windows natively only sends a KEYUP for the last one to be released. if (raw->data.keyboard.Flags & RI_KEY_BREAK) { - if (GetAsyncKeyState(VK_SHIFT) < 0) { + if (!mods.has_flag(WinKeyModifierMask::SHIFT)) { // A Shift is released, but another Shift is still held ERR_BREAK(key_event_pos >= KEY_EVENT_BUFFER_SIZE); KeyEvent ke; ke.shift = false; - ke.alt = alt_mem; - ke.control = control_mem; - ke.meta = meta_mem; + ke.altgr = mods.has_flag(WinKeyModifierMask::ALT_GR); + ke.alt = mods.has_flag(WinKeyModifierMask::ALT); + ke.control = mods.has_flag(WinKeyModifierMask::CTRL); + ke.meta = mods.has_flag(WinKeyModifierMask::META); ke.uMsg = WM_KEYUP; ke.window_id = window_id; @@ -3976,9 +3992,10 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA mm.instantiate(); mm->set_window_id(window_id); - mm->set_ctrl_pressed(control_mem); - mm->set_shift_pressed(shift_mem); - mm->set_alt_pressed(alt_mem); + mm->set_ctrl_pressed(mods.has_flag(WinKeyModifierMask::CTRL)); + mm->set_shift_pressed(mods.has_flag(WinKeyModifierMask::SHIFT)); + mm->set_alt_pressed(mods.has_flag(WinKeyModifierMask::ALT)); + mm->set_meta_pressed(mods.has_flag(WinKeyModifierMask::META)); mm->set_pressure((raw->data.mouse.ulButtons & RI_MOUSE_LEFT_BUTTON_DOWN) ? 1.0f : 0.0f); @@ -4073,12 +4090,14 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA break; } + const BitField<WinKeyModifierMask> &mods = _get_mods(); Ref<InputEventMouseMotion> mm; mm.instantiate(); mm->set_window_id(window_id); - mm->set_ctrl_pressed(GetKeyState(VK_CONTROL) < 0); - mm->set_shift_pressed(GetKeyState(VK_SHIFT) < 0); - mm->set_alt_pressed(alt_mem); + mm->set_ctrl_pressed(mods.has_flag(WinKeyModifierMask::CTRL)); + mm->set_shift_pressed(mods.has_flag(WinKeyModifierMask::SHIFT)); + mm->set_alt_pressed(mods.has_flag(WinKeyModifierMask::ALT)); + mm->set_meta_pressed(mods.has_flag(WinKeyModifierMask::META)); mm->set_pressure(windows[window_id].last_pressure); mm->set_tilt(windows[window_id].last_tilt); @@ -4223,9 +4242,11 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } mm->set_pen_inverted(pen_info.penFlags & (PEN_FLAG_INVERTED | PEN_FLAG_ERASER)); - mm->set_ctrl_pressed(GetKeyState(VK_CONTROL) < 0); - mm->set_shift_pressed(GetKeyState(VK_SHIFT) < 0); - mm->set_alt_pressed(alt_mem); + const BitField<WinKeyModifierMask> &mods = _get_mods(); + mm->set_ctrl_pressed(mods.has_flag(WinKeyModifierMask::CTRL)); + mm->set_shift_pressed(mods.has_flag(WinKeyModifierMask::SHIFT)); + mm->set_alt_pressed(mods.has_flag(WinKeyModifierMask::ALT)); + mm->set_meta_pressed(mods.has_flag(WinKeyModifierMask::META)); mm->set_button_mask(last_button_state); @@ -4328,12 +4349,15 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA if (receiving_window_id == INVALID_WINDOW_ID) { receiving_window_id = window_id; } + + const BitField<WinKeyModifierMask> &mods = _get_mods(); Ref<InputEventMouseMotion> mm; mm.instantiate(); mm->set_window_id(receiving_window_id); - mm->set_ctrl_pressed((wParam & MK_CONTROL) != 0); - mm->set_shift_pressed((wParam & MK_SHIFT) != 0); - mm->set_alt_pressed(alt_mem); + mm->set_ctrl_pressed(mods.has_flag(WinKeyModifierMask::CTRL)); + mm->set_shift_pressed(mods.has_flag(WinKeyModifierMask::SHIFT)); + mm->set_alt_pressed(mods.has_flag(WinKeyModifierMask::ALT)); + mm->set_meta_pressed(mods.has_flag(WinKeyModifierMask::META)); if ((tablet_get_current_driver() == "wintab") && wintab_available && windows[window_id].wtctx) { // Note: WinTab sends both WT_PACKET and WM_xBUTTONDOWN/UP/MOUSEMOVE events, use mouse 1/0 pressure only when last_pressure was not updated recently. @@ -4522,10 +4546,12 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } } - mb->set_ctrl_pressed((wParam & MK_CONTROL) != 0); - mb->set_shift_pressed((wParam & MK_SHIFT) != 0); - mb->set_alt_pressed(alt_mem); - // mb->is_alt_pressed()=(wParam&MK_MENU)!=0; + const BitField<WinKeyModifierMask> &mods = _get_mods(); + mb->set_ctrl_pressed(mods.has_flag(WinKeyModifierMask::CTRL)); + mb->set_shift_pressed(mods.has_flag(WinKeyModifierMask::SHIFT)); + mb->set_alt_pressed(mods.has_flag(WinKeyModifierMask::ALT)); + mb->set_meta_pressed(mods.has_flag(WinKeyModifierMask::META)); + if (mb->is_pressed()) { last_button_state.set_flag(mouse_button_to_mask(mb->get_button_index())); } else { @@ -4641,6 +4667,14 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA rendering_context->window_set_size(window_id, window.width, window.height); } #endif +#if defined(GLES3_ENABLED) + if (gl_manager_native) { + gl_manager_native->window_resize(window_id, window.width, window.height); + } + if (gl_manager_angle) { + gl_manager_angle->window_resize(window_id, window.width, window.height); + } +#endif } if (!window.minimized && (!(window_pos_params->flags & SWP_NOMOVE) || window_pos_params->flags & SWP_FRAMECHANGED)) { @@ -4693,19 +4727,6 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA case WM_KEYUP: case WM_SYSKEYDOWN: case WM_KEYDOWN: { - if (wParam == VK_SHIFT) { - shift_mem = (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN); - } - if (wParam == VK_CONTROL) { - control_mem = (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN); - } - if (wParam == VK_MENU) { - alt_mem = (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN); - if (lParam & (1 << 24)) { - gr_mem = alt_mem; - } - } - if (windows[window_id].ime_suppress_next_keyup && (uMsg == WM_KEYUP || uMsg == WM_SYSKEYUP)) { windows[window_id].ime_suppress_next_keyup = false; break; @@ -4716,7 +4737,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA if (mouse_mode == MOUSE_MODE_CAPTURED) { // When SetCapture is used, ALT+F4 hotkey is ignored by Windows, so handle it ourselves - if (wParam == VK_F4 && alt_mem && (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN)) { + if (wParam == VK_F4 && _get_mods().has_flag(WinKeyModifierMask::ALT) && (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN)) { _send_window_event(windows[window_id], WINDOW_EVENT_CLOSE_REQUEST); } } @@ -4724,13 +4745,14 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } case WM_CHAR: { ERR_BREAK(key_event_pos >= KEY_EVENT_BUFFER_SIZE); + const BitField<WinKeyModifierMask> &mods = _get_mods(); - // Make sure we don't include modifiers for the modifier key itself. KeyEvent ke; - ke.shift = (wParam != VK_SHIFT) ? shift_mem : false; - ke.alt = (!(wParam == VK_MENU && (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN))) ? alt_mem : false; - ke.control = (wParam != VK_CONTROL) ? control_mem : false; - ke.meta = meta_mem; + ke.shift = mods.has_flag(WinKeyModifierMask::SHIFT); + ke.alt = mods.has_flag(WinKeyModifierMask::ALT); + ke.altgr = mods.has_flag(WinKeyModifierMask::ALT_GR); + ke.control = mods.has_flag(WinKeyModifierMask::CTRL); + ke.meta = mods.has_flag(WinKeyModifierMask::META); ke.uMsg = uMsg; ke.window_id = window_id; @@ -4868,7 +4890,14 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } if (files.size() && windows[window_id].drop_files_callback.is_valid()) { - windows[window_id].drop_files_callback.call(files); + Variant v_files = files; + const Variant *v_args[1] = { &v_files }; + Variant ret; + Callable::CallError ce; + windows[window_id].drop_files_callback.callp((const Variant **)&v_args, 1, ret, ce); + if (ce.error != Callable::CallError::CALL_OK) { + ERR_PRINT(vformat("Failed to execute drop files callback: %s.", Variant::get_callable_error_text(windows[window_id].drop_files_callback, v_args, 1, ce))); + } } } break; default: { @@ -4894,10 +4923,6 @@ void DisplayServerWindows::_process_activate_event(WindowID p_window_id) { WindowData &wd = windows[p_window_id]; if (wd.activate_state == WA_ACTIVE || wd.activate_state == WA_CLICKACTIVE) { last_focused_window = p_window_id; - alt_mem = false; - control_mem = false; - shift_mem = false; - gr_mem = false; _set_mouse_mode_impl(mouse_mode); if (!IsIconic(wd.hWnd)) { SetFocus(wd.hWnd); @@ -4909,7 +4934,6 @@ void DisplayServerWindows::_process_activate_event(WindowID p_window_id) { track_mouse_leave_event(wd.hWnd); // Release capture unconditionally because it can be set due to dragging, in addition to captured mode. ReleaseCapture(); - alt_mem = false; wd.window_focused = false; _send_window_event(wd, WINDOW_EVENT_FOCUS_OUT); } @@ -4980,7 +5004,7 @@ void DisplayServerWindows::_process_key_events() { k->set_physical_keycode(physical_keycode); k->set_key_label(key_label); k->set_unicode(fix_unicode(unicode)); - if (k->get_unicode() && gr_mem) { + if (k->get_unicode() && ke.altgr) { k->set_alt_pressed(false); k->set_ctrl_pressed(false); } @@ -5056,7 +5080,7 @@ void DisplayServerWindows::_process_key_events() { } k->set_unicode(fix_unicode(unicode)); } - if (k->get_unicode() && gr_mem) { + if (k->get_unicode() && ke.altgr) { k->set_alt_pressed(false); k->set_ctrl_pressed(false); } @@ -5522,11 +5546,6 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win drop_events = false; key_event_pos = 0; - alt_mem = false; - gr_mem = false; - shift_mem = false; - control_mem = false; - meta_mem = false; hInstance = static_cast<OS_Windows *>(OS::get_singleton())->get_hinstance(); pressrc = 0; diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 9a4eeba486..7ef64d2ce3 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -337,7 +337,7 @@ class DisplayServerWindows : public DisplayServer { struct KeyEvent { WindowID window_id; - bool alt, shift, control, meta; + bool alt, shift, control, meta, altgr; UINT uMsg; WPARAM wParam; LPARAM lParam; @@ -478,11 +478,6 @@ class DisplayServerWindows : public DisplayServer { MouseMode mouse_mode; int restore_mouse_trails = 0; - bool alt_mem = false; - bool gr_mem = false; - bool shift_mem = false; - bool control_mem = false; - bool meta_mem = false; BitField<MouseButtonMask> last_button_state; bool use_raw_input = false; bool drop_events = false; @@ -519,6 +514,15 @@ class DisplayServerWindows : public DisplayServer { LRESULT _handle_early_window_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); Point2i _get_screens_origin() const; + enum class WinKeyModifierMask { + ALT_GR = (1 << 1), + SHIFT = (1 << 2), + ALT = (1 << 3), + META = (1 << 4), + CTRL = (1 << 5), + }; + BitField<WinKeyModifierMask> _get_mods() const; + Error _file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback, bool p_options_in_cb); public: diff --git a/platform/windows/windows_utils.cpp b/platform/windows/windows_utils.cpp index 147b8bcbae..9b53252b07 100644 --- a/platform/windows/windows_utils.cpp +++ b/platform/windows/windows_utils.cpp @@ -92,7 +92,7 @@ Error WindowsUtils::copy_and_rename_pdb(const String &p_dll_path) { DWORD Offset; }; - const DWORD nb10_magic = '01BN'; + const DWORD nb10_magic = 0x3031424e; // "01BN" (little-endian) struct CV_INFO_PDB20 { CV_HEADER CvHeader; // CvHeader.Signature = "NB10" DWORD Signature; @@ -100,7 +100,7 @@ Error WindowsUtils::copy_and_rename_pdb(const String &p_dll_path) { BYTE PdbFileName[1]; }; - const DWORD rsds_magic = 'SDSR'; + const DWORD rsds_magic = 0x53445352; // "SDSR" (little-endian) struct CV_INFO_PDB70 { DWORD Signature; // "RSDS" BYTE Guid[16]; diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index 822f1b58fd..18ef2d8505 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -54,16 +54,18 @@ void Camera2D::_update_scroll() { if (is_current()) { ERR_FAIL_COND(custom_viewport && !ObjectDB::get_instance(custom_viewport_id)); + Size2 screen_size = _get_camera_screen_size(); + Transform2D xform; if (is_physics_interpolated_and_enabled()) { xform = _interpolation_data.xform_prev.interpolate_with(_interpolation_data.xform_curr, Engine::get_singleton()->get_physics_interpolation_fraction()); + camera_screen_center = xform.affine_inverse().xform(0.5 * screen_size); } else { xform = get_camera_transform(); } viewport->set_canvas_transform(xform); - Size2 screen_size = _get_camera_screen_size(); Point2 screen_offset = (anchor_mode == ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5) : Point2()); Point2 adj_screen_pos = camera_screen_center - (screen_size * 0.5); diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index ab44e57d05..bad9de5daa 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -162,8 +162,19 @@ void NavigationRegion2D::_notification(int p_what) { set_physics_process_internal(true); } break; + case NOTIFICATION_VISIBILITY_CHANGED: { +#ifdef DEBUG_ENABLED + if (debug_instance_rid.is_valid()) { + RS::get_singleton()->canvas_item_set_visible(debug_instance_rid, is_visible_in_tree()); + } +#endif // DEBUG_ENABLED + } break; + case NOTIFICATION_EXIT_TREE: { _region_exit_navigation_map(); +#ifdef DEBUG_ENABLED + _free_debug(); +#endif // DEBUG_ENABLED } break; case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { @@ -189,6 +200,9 @@ void NavigationRegion2D::set_navigation_polygon(const Ref<NavigationPolygon> &p_ } navigation_polygon = p_navigation_polygon; +#ifdef DEBUG_ENABLED + debug_mesh_dirty = true; +#endif // DEBUG_ENABLED NavigationServer2D::get_singleton()->region_set_navigation_polygon(region, p_navigation_polygon); if (navigation_polygon.is_valid()) { @@ -420,12 +434,42 @@ void NavigationRegion2D::_region_update_transform() { #ifdef DEBUG_ENABLED void NavigationRegion2D::_update_debug_mesh() { - Vector<Vector2> navigation_polygon_vertices = navigation_polygon->get_vertices(); - if (navigation_polygon_vertices.size() < 3) { + if (!is_inside_tree()) { + _free_debug(); return; } const NavigationServer2D *ns2d = NavigationServer2D::get_singleton(); + RenderingServer *rs = RenderingServer::get_singleton(); + + if (!debug_instance_rid.is_valid()) { + debug_instance_rid = rs->canvas_item_create(); + } + if (!debug_mesh_rid.is_valid()) { + debug_mesh_rid = rs->mesh_create(); + } + + const Transform2D region_gt = get_global_transform(); + + rs->canvas_item_set_parent(debug_instance_rid, get_world_2d()->get_canvas()); + rs->canvas_item_set_transform(debug_instance_rid, region_gt); + + if (!debug_mesh_dirty) { + return; + } + + rs->mesh_clear(debug_mesh_rid); + debug_mesh_dirty = false; + + const Vector<Vector2> &vertices = navigation_polygon->get_vertices(); + if (vertices.size() < 3) { + return; + } + + int polygon_count = navigation_polygon->get_polygon_count(); + if (polygon_count == 0) { + return; + } bool enabled_geometry_face_random_color = ns2d->get_debug_navigation_enable_geometry_face_random_color(); bool enabled_edge_lines = ns2d->get_debug_navigation_enable_edge_lines(); @@ -438,39 +482,109 @@ void NavigationRegion2D::_update_debug_mesh() { debug_edge_color = ns2d->get_debug_navigation_geometry_edge_disabled_color(); } + int vertex_count = 0; + int line_count = 0; + + for (int i = 0; i < polygon_count; i++) { + const Vector<int> &polygon = navigation_polygon->get_polygon(i); + int polygon_size = polygon.size(); + if (polygon_size < 3) { + continue; + } + line_count += polygon_size * 2; + vertex_count += (polygon_size - 2) * 3; + } + + Vector<Vector2> face_vertex_array; + face_vertex_array.resize(vertex_count); + + Vector<Color> face_color_array; + if (enabled_geometry_face_random_color) { + face_color_array.resize(vertex_count); + } + + Vector<Vector2> line_vertex_array; + if (enabled_edge_lines) { + line_vertex_array.resize(line_count); + } + RandomPCG rand; + Color polygon_color = debug_face_color; - for (int i = 0; i < navigation_polygon->get_polygon_count(); i++) { - // An array of vertices for this polygon. - Vector<int> polygon = navigation_polygon->get_polygon(i); - Vector<Vector2> debug_polygon_vertices; - debug_polygon_vertices.resize(polygon.size()); - for (int j = 0; j < polygon.size(); j++) { - ERR_FAIL_INDEX(polygon[j], navigation_polygon_vertices.size()); - debug_polygon_vertices.write[j] = navigation_polygon_vertices[polygon[j]]; + int face_vertex_index = 0; + int line_vertex_index = 0; + + Vector2 *face_vertex_array_ptrw = face_vertex_array.ptrw(); + Color *face_color_array_ptrw = face_color_array.ptrw(); + Vector2 *line_vertex_array_ptrw = line_vertex_array.ptrw(); + + for (int polygon_index = 0; polygon_index < polygon_count; polygon_index++) { + const Vector<int> &polygon_indices = navigation_polygon->get_polygon(polygon_index); + int polygon_indices_size = polygon_indices.size(); + if (polygon_indices_size < 3) { + continue; } - // Generate the polygon color, slightly randomly modified from the settings one. - Color random_variation_color = debug_face_color; if (enabled_geometry_face_random_color) { - random_variation_color.set_hsv( - debug_face_color.get_h() + rand.random(-1.0, 1.0) * 0.1, - debug_face_color.get_s(), - debug_face_color.get_v() + rand.random(-1.0, 1.0) * 0.2); + // Generate the polygon color, slightly randomly modified from the settings one. + polygon_color.set_hsv(debug_face_color.get_h() + rand.random(-1.0, 1.0) * 0.1, debug_face_color.get_s(), debug_face_color.get_v() + rand.random(-1.0, 1.0) * 0.2); + polygon_color.a = debug_face_color.a; } - random_variation_color.a = debug_face_color.a; - Vector<Color> debug_face_colors; - debug_face_colors.push_back(random_variation_color); - RS::get_singleton()->canvas_item_add_polygon(get_canvas_item(), debug_polygon_vertices, debug_face_colors); + for (int polygon_indices_index = 0; polygon_indices_index < polygon_indices_size - 2; polygon_indices_index++) { + face_vertex_array_ptrw[face_vertex_index] = vertices[polygon_indices[0]]; + face_vertex_array_ptrw[face_vertex_index + 1] = vertices[polygon_indices[polygon_indices_index + 1]]; + face_vertex_array_ptrw[face_vertex_index + 2] = vertices[polygon_indices[polygon_indices_index + 2]]; + if (enabled_geometry_face_random_color) { + face_color_array_ptrw[face_vertex_index] = polygon_color; + face_color_array_ptrw[face_vertex_index + 1] = polygon_color; + face_color_array_ptrw[face_vertex_index + 2] = polygon_color; + } + face_vertex_index += 3; + } if (enabled_edge_lines) { - Vector<Color> debug_edge_colors; - debug_edge_colors.push_back(debug_edge_color); - debug_polygon_vertices.push_back(debug_polygon_vertices[0]); // Add first again for closing polyline. - RS::get_singleton()->canvas_item_add_polyline(get_canvas_item(), debug_polygon_vertices, debug_edge_colors); + for (int polygon_indices_index = 0; polygon_indices_index < polygon_indices_size; polygon_indices_index++) { + line_vertex_array_ptrw[line_vertex_index] = vertices[polygon_indices[polygon_indices_index]]; + line_vertex_index += 1; + if (polygon_indices_index + 1 == polygon_indices_size) { + line_vertex_array_ptrw[line_vertex_index] = vertices[polygon_indices[0]]; + line_vertex_index += 1; + } else { + line_vertex_array_ptrw[line_vertex_index] = vertices[polygon_indices[polygon_indices_index + 1]]; + line_vertex_index += 1; + } + } } } + + if (!enabled_geometry_face_random_color) { + face_color_array.resize(face_vertex_array.size()); + face_color_array.fill(debug_face_color); + } + + Array face_mesh_array; + face_mesh_array.resize(Mesh::ARRAY_MAX); + face_mesh_array[Mesh::ARRAY_VERTEX] = face_vertex_array; + face_mesh_array[Mesh::ARRAY_COLOR] = face_color_array; + + rs->mesh_add_surface_from_arrays(debug_mesh_rid, RS::PRIMITIVE_TRIANGLES, face_mesh_array, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES); + + if (enabled_edge_lines) { + Vector<Color> line_color_array; + line_color_array.resize(line_vertex_array.size()); + line_color_array.fill(debug_edge_color); + + Array line_mesh_array; + line_mesh_array.resize(Mesh::ARRAY_MAX); + line_mesh_array[Mesh::ARRAY_VERTEX] = line_vertex_array; + line_mesh_array[Mesh::ARRAY_COLOR] = line_color_array; + + rs->mesh_add_surface_from_arrays(debug_mesh_rid, RS::PRIMITIVE_LINES, line_mesh_array, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES); + } + + rs->canvas_item_add_mesh(debug_instance_rid, debug_mesh_rid, Transform2D()); + rs->canvas_item_set_visible(debug_instance_rid, is_visible_in_tree()); } #endif // DEBUG_ENABLED @@ -512,3 +626,19 @@ void NavigationRegion2D::_update_debug_baking_rect() { } } #endif // DEBUG_ENABLED + +#ifdef DEBUG_ENABLED +void NavigationRegion2D::_free_debug() { + RenderingServer *rs = RenderingServer::get_singleton(); + ERR_FAIL_NULL(rs); + if (debug_instance_rid.is_valid()) { + rs->canvas_item_clear(debug_instance_rid); + rs->free(debug_instance_rid); + debug_instance_rid = RID(); + } + if (debug_mesh_rid.is_valid()) { + rs->free(debug_mesh_rid); + debug_mesh_rid = RID(); + } +} +#endif // DEBUG_ENABLED diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h index 5a86dd607d..52101cb93e 100644 --- a/scene/2d/navigation_region_2d.h +++ b/scene/2d/navigation_region_2d.h @@ -52,6 +52,12 @@ class NavigationRegion2D : public Node2D { #ifdef DEBUG_ENABLED private: + RID debug_mesh_rid; + RID debug_instance_rid; + + bool debug_mesh_dirty = true; + + void _free_debug(); void _update_debug_mesh(); void _update_debug_edge_connections_mesh(); void _update_debug_baking_rect(); diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index f7d672620d..d1f1c97ca2 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -722,7 +722,7 @@ bool TileMap::_get(const StringName &p_name, Variant &r_ret) const { void TileMap::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::INT, "format", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); - property_helper.get_property_list(p_list, layers.size()); + property_helper.get_property_list(p_list); } Vector2 TileMap::map_to_local(const Vector2i &p_pos) const { diff --git a/scene/3d/physics/collision_object_3d.cpp b/scene/3d/physics/collision_object_3d.cpp index dddaf7eb4a..f11aa7012a 100644 --- a/scene/3d/physics/collision_object_3d.cpp +++ b/scene/3d/physics/collision_object_3d.cpp @@ -439,6 +439,9 @@ void CollisionObject3D::_on_transform_changed() { } const ShapeData::ShapeBase *shape_bases = shapedata.shapes.ptr(); for (int i = 0; i < shapedata.shapes.size(); i++) { + if (shape_bases[i].debug_shape.is_null()) { + continue; + } RS::get_singleton()->instance_set_transform(shape_bases[i].debug_shape, debug_shape_old_transform * shapedata.xform); } } diff --git a/scene/animation/animation_mixer.cpp b/scene/animation/animation_mixer.cpp index d4c6ca3ea0..e600de6b8b 100644 --- a/scene/animation/animation_mixer.cpp +++ b/scene/animation/animation_mixer.cpp @@ -501,6 +501,7 @@ AnimationMixer::AnimationCallbackModeMethod AnimationMixer::get_callback_mode_me void AnimationMixer::set_callback_mode_discrete(AnimationCallbackModeDiscrete p_mode) { callback_mode_discrete = p_mode; + _clear_caches(); emit_signal(SNAME("mixer_updated")); } @@ -688,7 +689,7 @@ bool AnimationMixer::_update_caches() { track_value->init_value = anim->track_get_key_value(i, 0); track_value->init_value.zero(); - track_value->init_use_continuous = callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS; + track_value->is_init = false; // Can't interpolate them, need to convert. track_value->is_variant_interpolatable = Animation::is_variant_interpolatable(track_value->init_value); @@ -698,7 +699,6 @@ bool AnimationMixer::_update_caches() { int rt = reset_anim->find_track(path, track_src_type); if (rt >= 0) { if (track_src_type == Animation::TYPE_VALUE) { - track_value->init_use_continuous = track_value->init_use_continuous || (reset_anim->value_track_get_update_mode(rt) != Animation::UPDATE_DISCRETE); // Take precedence Force Continuous. if (reset_anim->track_get_key_count(rt) > 0) { track_value->init_value = reset_anim->track_get_key_value(rt, 0); } @@ -1006,7 +1006,7 @@ void AnimationMixer::_blend_init() { TrackCacheValue *t = static_cast<TrackCacheValue *>(track); t->value = Animation::cast_to_blendwise(t->init_value); t->element_size = t->init_value.is_string() ? (real_t)(t->init_value.operator String()).length() : 0; - t->use_continuous = t->init_use_continuous; + t->use_continuous = false; t->use_discrete = false; } break; case Animation::TYPE_AUDIO: { @@ -1462,12 +1462,12 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { t->value = Animation::blend_variant(t->value, value, blend); } } else { - t->use_discrete = true; if (seeked) { int idx = a->track_find_key(i, time, is_external_seeking ? Animation::FIND_MODE_NEAREST : Animation::FIND_MODE_EXACT, true); if (idx < 0) { continue; } + t->use_discrete = true; Variant value = a->track_get_key_value(i, idx); value = post_process_key_value(a, i, value, t->object_id); Object *t_obj = ObjectDB::get_instance(t->object_id); @@ -1478,6 +1478,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { List<int> indices; a->track_get_key_indices_in_range(i, time, delta, &indices, looped_flag); for (int &F : indices) { + t->use_discrete = true; Variant value = a->track_get_key_value(i, F); value = post_process_key_value(a, i, value, t->object_id); Object *t_obj = ObjectDB::get_instance(t->object_id); @@ -1682,7 +1683,8 @@ void AnimationMixer::_blend_apply() { // Finally, set the tracks. for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) { TrackCache *track = K.value; - if (!deterministic && Math::is_zero_approx(track->total_weight)) { + bool is_zero_amount = Math::is_zero_approx(track->total_weight); + if (!deterministic && is_zero_amount) { continue; } switch (track->type) { @@ -1742,10 +1744,24 @@ void AnimationMixer::_blend_apply() { case Animation::TYPE_VALUE: { TrackCacheValue *t = static_cast<TrackCacheValue *>(track); - if (!t->is_variant_interpolatable || !t->use_continuous || (callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_DOMINANT && t->use_discrete)) { + if (t->use_discrete && !t->use_continuous) { + t->is_init = true; // If only disctere value is applied, no more RESET. + } + + if ((t->is_init && (is_zero_amount || !t->use_continuous)) || + (callback_mode_discrete != ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS && + !is_zero_amount && + callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_DOMINANT && + t->use_discrete)) { break; // Don't overwrite the value set by UPDATE_DISCRETE. } + if (callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS) { + t->is_init = false; // Always update in Force Continuous. + } else { + t->is_init = !t->use_continuous; // If there is no Continuous in non-Force Continuous type, it means RESET. + } + // Trim unused elements if init array/string is not blended. if (t->value.is_array()) { int actual_blended_size = (int)Math::round(Math::abs(t->element_size.operator real_t())); diff --git a/scene/animation/animation_mixer.h b/scene/animation/animation_mixer.h index b7898cffc9..089a210193 100644 --- a/scene/animation/animation_mixer.h +++ b/scene/animation/animation_mixer.h @@ -126,7 +126,7 @@ protected: /* ---- General settings for animation ---- */ AnimationCallbackModeProcess callback_mode_process = ANIMATION_CALLBACK_MODE_PROCESS_IDLE; AnimationCallbackModeMethod callback_mode_method = ANIMATION_CALLBACK_MODE_METHOD_DEFERRED; - AnimationCallbackModeDiscrete callback_mode_discrete = ANIMATION_CALLBACK_MODE_DISCRETE_DOMINANT; + AnimationCallbackModeDiscrete callback_mode_discrete = ANIMATION_CALLBACK_MODE_DISCRETE_RECESSIVE; int audio_max_polyphony = 32; NodePath root_node; @@ -224,7 +224,7 @@ protected: Vector<StringName> subpath; // TODO: There are many boolean, can be packed into one integer. - bool init_use_continuous = false; + bool is_init = false; bool use_continuous = false; bool use_discrete = false; bool is_using_angle = false; @@ -237,7 +237,7 @@ protected: init_value(p_other.init_value), value(p_other.value), subpath(p_other.subpath), - init_use_continuous(p_other.init_use_continuous), + is_init(p_other.is_init), use_continuous(p_other.use_continuous), use_discrete(p_other.use_discrete), is_using_angle(p_other.is_using_angle), diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 435776843c..0c24d79ad7 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -447,10 +447,10 @@ void AnimationPlayer::_play(const StringName &p_name, double p_custom_blend, flo } else { if (p_from_end && c.current.pos == 0) { // Animation reset but played backwards, set position to the end. - c.current.pos = c.current.from->animation->get_length(); + seek(c.current.from->animation->get_length(), true, true); } else if (!p_from_end && c.current.pos == c.current.from->animation->get_length()) { // Animation resumed but already ended, set position to the beginning. - c.current.pos = 0; + seek(0, true, true); } else if (playing) { return; } diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index d4061ab167..69287478db 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -626,7 +626,7 @@ bool AnimationTree::_blend_pre_process(double p_delta, int p_track_count, const for (int i = 0; i < p_track_count; i++) { src_blendsw[i] = 1.0; // By default all go to 1 for the root input. } - root_animation_node->node_state.base_path = SceneStringName(parameters_base_path); + root_animation_node->node_state.base_path = SNAME(Animation::PARAMETERS_BASE_PATH.ascii().get_data()); root_animation_node->node_state.parent = nullptr; } @@ -787,7 +787,7 @@ void AnimationTree::_update_properties() { input_activity_map_get.clear(); if (root_animation_node.is_valid()) { - _update_properties_for_node(SceneStringName(parameters_base_path), root_animation_node); + _update_properties_for_node(Animation::PARAMETERS_BASE_PATH, root_animation_node); } properties_dirty = false; diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp index 8131fe7aaa..c843bb8c44 100644 --- a/scene/gui/code_edit.cpp +++ b/scene/gui/code_edit.cpp @@ -3050,7 +3050,7 @@ void CodeEdit::_update_delimiter_cache(int p_from_line, int p_to_line) { } int CodeEdit::_is_in_delimiter(int p_line, int p_column, DelimiterType p_type) const { - if (delimiters.size() == 0) { + if (delimiters.size() == 0 || p_line >= delimiter_cache.size()) { return -1; } ERR_FAIL_INDEX_V(p_line, get_line_count(), 0); diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 245a086dda..8913650689 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -1560,7 +1560,7 @@ void ColorPicker::_pick_button_pressed_legacy() { picker_preview_style_box = (Ref<StyleBoxFlat>)memnew(StyleBoxFlat); picker_preview_style_box->set_bg_color(Color(1.0, 1.0, 1.0)); - picker_preview->add_theme_style_override("panel", picker_preview_style_box); + picker_preview->add_theme_style_override(SceneStringName(panel), picker_preview_style_box); } Rect2i screen_rect; @@ -1863,7 +1863,7 @@ ColorPicker::ColorPicker() { shape_popup->add_radio_check_item("VHS Circle", SHAPE_VHS_CIRCLE); shape_popup->add_radio_check_item("OKHSL Circle", SHAPE_OKHSL_CIRCLE); shape_popup->set_item_checked(current_shape, true); - shape_popup->connect("id_pressed", callable_mp(this, &ColorPicker::set_picker_shape)); + shape_popup->connect(SceneStringName(id_pressed), callable_mp(this, &ColorPicker::set_picker_shape)); add_mode(new ColorModeRGB(this)); add_mode(new ColorModeHSV(this)); @@ -1904,7 +1904,7 @@ ColorPicker::ColorPicker() { mode_popup->add_check_item("Colorized Sliders", MODE_MAX); mode_popup->set_item_checked(current_mode, true); mode_popup->set_item_checked(MODE_MAX + 1, true); - mode_popup->connect("id_pressed", callable_mp(this, &ColorPicker::_set_mode_popup_value)); + mode_popup->connect(SceneStringName(id_pressed), callable_mp(this, &ColorPicker::_set_mode_popup_value)); VBoxContainer *vbl = memnew(VBoxContainer); real_vbox->add_child(vbl); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 1c175f9f95..0682c11a9b 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -211,17 +211,17 @@ void Control::get_argument_options(const StringName &p_function, int p_idx, List const String pf = p_function; Theme::DataType type = Theme::DATA_TYPE_MAX; - if (pf == "add_theme_color_override" || pf == "has_theme_color" || pf == "has_theme_color_override" || pf == "get_theme_color") { + if (pf == "add_theme_color_override" || pf == "has_theme_color" || pf == "has_theme_color_override" || pf == "get_theme_color" || pf == "remove_theme_color_override") { type = Theme::DATA_TYPE_COLOR; - } else if (pf == "add_theme_constant_override" || pf == "has_theme_constant" || pf == "has_theme_constant_override" || pf == "get_theme_constant") { + } else if (pf == "add_theme_constant_override" || pf == "has_theme_constant" || pf == "has_theme_constant_override" || pf == "get_theme_constant" || pf == "remove_theme_constant_override") { type = Theme::DATA_TYPE_CONSTANT; - } else if (pf == "add_theme_font_override" || pf == "has_theme_font" || pf == "has_theme_font_override" || pf == "get_theme_font") { + } else if (pf == "add_theme_font_override" || pf == "has_theme_font" || pf == "has_theme_font_override" || pf == "get_theme_font" || pf == "remove_theme_font_override") { type = Theme::DATA_TYPE_FONT; - } else if (pf == "add_theme_font_size_override" || pf == "has_theme_font_size" || pf == "has_theme_font_size_override" || pf == "get_theme_font_size") { + } else if (pf == "add_theme_font_size_override" || pf == "has_theme_font_size" || pf == "has_theme_font_size_override" || pf == "get_theme_font_size" || pf == "remove_theme_font_size_override") { type = Theme::DATA_TYPE_FONT_SIZE; - } else if (pf == "add_theme_icon_override" || pf == "has_theme_icon" || pf == "has_theme_icon_override" || pf == "get_theme_icon") { + } else if (pf == "add_theme_icon_override" || pf == "has_theme_icon" || pf == "has_theme_icon_override" || pf == "get_theme_icon" || pf == "remove_theme_icon_override") { type = Theme::DATA_TYPE_ICON; - } else if (pf == "add_theme_style_override" || pf == "has_theme_style" || pf == "has_theme_style_override" || pf == "get_theme_style") { + } else if (pf == "add_theme_stylebox_override" || pf == "has_theme_stylebox" || pf == "has_theme_stylebox_override" || pf == "get_theme_stylebox" || pf == "remove_theme_stylebox_override") { type = Theme::DATA_TYPE_STYLEBOX; } @@ -1739,12 +1739,15 @@ void Control::_size_changed() { data.size_cache = new_size_cache; if (is_inside_tree()) { - if (size_changed) { - notification(NOTIFICATION_RESIZED); - } if (pos_changed || size_changed) { - item_rect_changed(size_changed); + // Ensure global transform is marked as dirty before `NOTIFICATION_RESIZED` / `item_rect_changed` signal + // so an up to date global transform could be obtained when handling these. _notify_transform(); + + if (size_changed) { + notification(NOTIFICATION_RESIZED); + } + item_rect_changed(size_changed); } if (pos_changed && !size_changed) { diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index 58961d370c..088c8fca26 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -47,7 +47,7 @@ void AcceptDialog::_input_from_window(const Ref<InputEvent> &p_event) { } void AcceptDialog::_parent_focused() { - if (!is_exclusive() && get_flag(FLAG_POPUP)) { + if (popped_up && !is_exclusive() && get_flag(FLAG_POPUP)) { _cancel_pressed(); } } @@ -71,6 +71,7 @@ void AcceptDialog::_notification(int p_what) { parent_visible->connect(SceneStringName(focus_entered), callable_mp(this, &AcceptDialog::_parent_focused)); } } else { + popped_up = false; if (parent_visible) { parent_visible->disconnect(SceneStringName(focus_entered), callable_mp(this, &AcceptDialog::_parent_focused)); parent_visible = nullptr; @@ -78,8 +79,16 @@ void AcceptDialog::_notification(int p_what) { } } break; + case NOTIFICATION_WM_WINDOW_FOCUS_IN: { + if (!is_in_edited_scene_root()) { + if (has_focus()) { + popped_up = true; + } + } + } break; + case NOTIFICATION_THEME_CHANGED: { - bg_panel->add_theme_style_override("panel", theme_cache.panel_style); + bg_panel->add_theme_style_override(SceneStringName(panel), theme_cache.panel_style); child_controls_changed(); if (is_visible()) { @@ -114,8 +123,14 @@ void AcceptDialog::_text_submitted(const String &p_text) { _ok_pressed(); } +void AcceptDialog::_post_popup() { + Window::_post_popup(); + popped_up = true; +} + void AcceptDialog::_ok_pressed() { if (hide_on_ok) { + popped_up = false; set_visible(false); } ok_pressed(); @@ -124,6 +139,7 @@ void AcceptDialog::_ok_pressed() { } void AcceptDialog::_cancel_pressed() { + popped_up = false; Window *parent_window = parent_visible; if (parent_visible) { parent_visible->disconnect(SceneStringName(focus_entered), callable_mp(this, &AcceptDialog::_parent_focused)); diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h index 12b48c903a..404237bfd8 100644 --- a/scene/gui/dialogs.h +++ b/scene/gui/dialogs.h @@ -51,6 +51,7 @@ class AcceptDialog : public Window { HBoxContainer *buttons_hbox = nullptr; Button *ok_button = nullptr; + bool popped_up = false; bool hide_on_ok = true; bool close_on_escape = true; @@ -72,6 +73,7 @@ class AcceptDialog : public Window { protected: virtual Size2 _get_contents_minimum_size() const override; virtual void _input_from_window(const Ref<InputEvent> &p_event) override; + virtual void _post_popup() override; void _notification(int p_what); static void _bind_methods(); diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h index 4236f0a56b..9680157f0a 100644 --- a/scene/gui/file_dialog.h +++ b/scene/gui/file_dialog.h @@ -194,7 +194,7 @@ protected: void _notification(int p_what); bool _set(const StringName &p_name, const Variant &p_value) { return property_helper.property_set_value(p_name, p_value); } bool _get(const StringName &p_name, Variant &r_ret) const { return property_helper.property_get_value(p_name, r_ret); } - void _get_property_list(List<PropertyInfo> *p_list) const { property_helper.get_property_list(p_list, options.size()); } + void _get_property_list(List<PropertyInfo> *p_list) const { property_helper.get_property_list(p_list); } bool _property_can_revert(const StringName &p_name) const { return property_helper.property_can_revert(p_name); } bool _property_get_revert(const StringName &p_name, Variant &r_property) const { return property_helper.property_get_revert(p_name, r_property); } static void _bind_methods(); diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index c9f3fc1dfe..e725bb5ba5 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -717,7 +717,7 @@ void GraphEdit::_notification(int p_what) { zoom_label->set_custom_minimum_size(Size2(48, 0) * theme_cache.base_scale); - menu_panel->add_theme_style_override("panel", theme_cache.menu_panel); + menu_panel->add_theme_style_override(SceneStringName(panel), theme_cache.menu_panel); } break; case NOTIFICATION_READY: { Size2 hmin = h_scrollbar->get_combined_minimum_size(); @@ -1299,18 +1299,26 @@ List<Ref<GraphEdit::Connection>> GraphEdit::get_connections_intersecting_with_re return intersecting_connections; } -void GraphEdit::_draw_minimap_connection_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_from_color, const Color &p_to_color) { - const Vector<Vector2> &points = get_connection_line(p_from, p_to); +void GraphEdit::_draw_minimap_connection_line(const Vector2 &p_from_graph_position, const Vector2 &p_to_graph_position, const Color &p_from_color, const Color &p_to_color) { + Vector<Vector2> points = get_connection_line(p_from_graph_position, p_to_graph_position); + ERR_FAIL_COND_MSG(points.size() < 2, "\"_get_connection_line()\" returned an invalid line."); + // Convert to minimap points. + for (Vector2 &point : points) { + point = minimap->_convert_from_graph_position(point) + minimap->minimap_offset; + } + + // Setup polyline colors. LocalVector<Color> colors; colors.reserve(points.size()); - - float length_inv = 1.0 / (p_from).distance_to(p_to); + const Vector2 &from = points[0]; + const Vector2 &to = points[points.size() - 1]; + float length_inv = 1.0 / (from).distance_to(to); for (const Vector2 &point : points) { - float normalized_curve_position = (p_from).distance_to(point) * length_inv; + float normalized_curve_position = from.distance_to(point) * length_inv; colors.push_back(p_from_color.lerp(p_to_color, normalized_curve_position)); } - p_where->draw_polyline_colors(points, colors, 0.5, lines_antialiased); + minimap->draw_polyline_colors(points, colors, 0.5, lines_antialiased); } void GraphEdit::_update_connections() { @@ -1528,7 +1536,7 @@ void GraphEdit::_minimap_draw() { Ref<StyleBoxFlat> sb_minimap = minimap->theme_cache.node_style->duplicate(); // Override default values with colors provided by the GraphNode's stylebox, if possible. - Ref<StyleBoxFlat> sb_frame = graph_frame->get_theme_stylebox(graph_frame->is_selected() ? SNAME("panel_selected") : SNAME("panel")); + Ref<StyleBoxFlat> sb_frame = graph_frame->get_theme_stylebox(graph_frame->is_selected() ? SNAME("panel_selected") : SceneStringName(panel)); if (sb_frame.is_valid()) { Color node_color = sb_frame->get_bg_color(); if (graph_frame->is_tint_color_enabled()) { @@ -1565,8 +1573,8 @@ void GraphEdit::_minimap_draw() { // Draw node connections. for (const Ref<Connection> &c : connections) { - Vector2 from_position = minimap->_convert_from_graph_position(c->_cache.from_pos * zoom - graph_offset) + minimap_offset; - Vector2 to_position = minimap->_convert_from_graph_position(c->_cache.to_pos * zoom - graph_offset) + minimap_offset; + Vector2 from_graph_position = c->_cache.from_pos * zoom - graph_offset; + Vector2 to_graph_position = c->_cache.to_pos * zoom - graph_offset; Color from_color = c->_cache.from_color; Color to_color = c->_cache.to_color; @@ -1574,7 +1582,8 @@ void GraphEdit::_minimap_draw() { from_color = from_color.lerp(theme_cache.activity_color, c->activity); to_color = to_color.lerp(theme_cache.activity_color, c->activity); } - _draw_minimap_connection_line(minimap, from_position, to_position, from_color, to_color); + + _draw_minimap_connection_line(from_graph_position, to_graph_position, from_color, to_color); } // Draw the "camera" viewport. diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h index eeda9ae200..20c98c462c 100644 --- a/scene/gui/graph_edit.h +++ b/scene/gui/graph_edit.h @@ -328,7 +328,7 @@ private: void _top_connection_layer_input(const Ref<InputEvent> &p_ev); float _get_shader_line_width(); - void _draw_minimap_connection_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color); + void _draw_minimap_connection_line(const Vector2 &p_from_graph_position, const Vector2 &p_to_graph_position, const Color &p_from_color, const Color &p_to_color); void _invalidate_connection_line_cache(); void _update_top_connection_layer(); void _update_connections(); diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h index 4c035ee4e6..9a57b9d8fe 100644 --- a/scene/gui/item_list.h +++ b/scene/gui/item_list.h @@ -162,7 +162,7 @@ protected: void _notification(int p_what); bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const { return property_helper.property_get_value(p_name, r_ret); } - void _get_property_list(List<PropertyInfo> *p_list) const { property_helper.get_property_list(p_list, items.size()); } + void _get_property_list(List<PropertyInfo> *p_list) const { property_helper.get_property_list(p_list); } bool _property_can_revert(const StringName &p_name) const { return property_helper.property_can_revert(p_name); } bool _property_get_revert(const StringName &p_name, Variant &r_property) const { return property_helper.property_get_revert(p_name, r_property); } static void _bind_methods(); diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 729e219825..aa41e46f82 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -2469,9 +2469,9 @@ void LineEdit::_generate_context_menu() { menu->add_check_item(ETR("Display Control Characters"), MENU_DISPLAY_UCC); menu->add_submenu_node_item(ETR("Insert Control Character"), menu_ctl, MENU_SUBMENU_INSERT_UCC); - menu->connect("id_pressed", callable_mp(this, &LineEdit::menu_option)); - menu_dir->connect("id_pressed", callable_mp(this, &LineEdit::menu_option)); - menu_ctl->connect("id_pressed", callable_mp(this, &LineEdit::menu_option)); + menu->connect(SceneStringName(id_pressed), callable_mp(this, &LineEdit::menu_option)); + menu_dir->connect(SceneStringName(id_pressed), callable_mp(this, &LineEdit::menu_option)); + menu_ctl->connect(SceneStringName(id_pressed), callable_mp(this, &LineEdit::menu_option)); menu->connect(SceneStringName(focus_entered), callable_mp(this, &LineEdit::_validate_caret_can_draw)); menu->connect(SceneStringName(focus_exited), callable_mp(this, &LineEdit::_validate_caret_can_draw)); diff --git a/scene/gui/menu_button.h b/scene/gui/menu_button.h index 2bd577ddd0..5a74d61091 100644 --- a/scene/gui/menu_button.h +++ b/scene/gui/menu_button.h @@ -52,7 +52,7 @@ protected: void _notification(int p_what); bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; - void _get_property_list(List<PropertyInfo> *p_list) const { property_helper.get_property_list(p_list, popup->get_item_count()); } + void _get_property_list(List<PropertyInfo> *p_list) const { property_helper.get_property_list(p_list); } bool _property_can_revert(const StringName &p_name) const { return property_helper.property_can_revert(p_name); } bool _property_get_revert(const StringName &p_name, Variant &r_property) const { return property_helper.property_get_revert(p_name, r_property); } static void _bind_methods(); diff --git a/scene/gui/option_button.h b/scene/gui/option_button.h index 4b5164161a..351df9a749 100644 --- a/scene/gui/option_button.h +++ b/scene/gui/option_button.h @@ -84,7 +84,7 @@ protected: void _notification(int p_what); bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const { return property_helper.property_get_value(p_name, r_ret); } - void _get_property_list(List<PropertyInfo> *p_list) const { property_helper.get_property_list(p_list, popup->get_item_count()); } + void _get_property_list(List<PropertyInfo> *p_list) const { property_helper.get_property_list(p_list); } bool _property_can_revert(const StringName &p_name) const { return property_helper.property_can_revert(p_name); } bool _property_get_revert(const StringName &p_name, Variant &r_property) const { return property_helper.property_get_revert(p_name, r_property); } void _validate_property(PropertyInfo &p_property) const; diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp index 38204af6d5..10fadeeba1 100644 --- a/scene/gui/popup.cpp +++ b/scene/gui/popup.cpp @@ -271,7 +271,7 @@ void PopupPanel::_notification(int p_what) { switch (p_what) { case NOTIFICATION_READY: case NOTIFICATION_THEME_CHANGED: { - panel->add_theme_style_override("panel", theme_cache.panel_style); + panel->add_theme_style_override(SceneStringName(panel), theme_cache.panel_style); _update_child_rects(); } break; diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index bdd0102b63..4f07fdb87b 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -1026,7 +1026,7 @@ void PopupMenu::_notification(int p_what) { } break; case NOTIFICATION_THEME_CHANGED: { - scroll_container->add_theme_style_override("panel", theme_cache.panel_style); + scroll_container->add_theme_style_override(SceneStringName(panel), theme_cache.panel_style); [[fallthrough]]; } @@ -2422,7 +2422,7 @@ void PopupMenu::activate_item(int p_idx) { hide(); } - emit_signal(SNAME("id_pressed"), id); + emit_signal(SceneStringName(id_pressed), id); emit_signal(SNAME("index_pressed"), p_idx); } diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h index 832c1bcc8b..c6eef03aca 100644 --- a/scene/gui/popup_menu.h +++ b/scene/gui/popup_menu.h @@ -218,7 +218,7 @@ protected: void _notification(int p_what); bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const { return property_helper.property_get_value(p_name, r_ret); } - void _get_property_list(List<PropertyInfo> *p_list) const { property_helper.get_property_list(p_list, items.size()); } + void _get_property_list(List<PropertyInfo> *p_list) const { property_helper.get_property_list(p_list); } bool _property_can_revert(const StringName &p_name) const { return property_helper.property_can_revert(p_name); } bool _property_get_revert(const StringName &p_name, Variant &r_property) const { return property_helper.property_get_revert(p_name, r_property); } static void _bind_methods(); diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 5122b0a155..048892a4a5 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -1607,8 +1607,34 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V if (p_meta) { int64_t glyph_idx = TS->shaped_text_hit_test_grapheme(rid, p_click.x - rect.position.x); if (glyph_idx >= 0) { + float baseline_y = rect.position.y + TS->shaped_text_get_ascent(rid); const Glyph *glyphs = TS->shaped_text_get_glyphs(rid); - char_pos = glyphs[glyph_idx].start; + if (glyphs[glyph_idx].flags & TextServer::GRAPHEME_IS_EMBEDDED_OBJECT) { + // Emebedded object. + for (int i = 0; i < objects.size(); i++) { + if (TS->shaped_text_get_object_glyph(rid, objects[i]) == glyph_idx) { + Rect2 obj_rect = TS->shaped_text_get_object_rect(rid, objects[i]); + obj_rect.position.y += baseline_y; + if (p_click.y >= obj_rect.position.y && p_click.y <= obj_rect.position.y + obj_rect.size.y) { + char_pos = glyphs[glyph_idx].start; + } + break; + } + } + } else if (glyphs[glyph_idx].font_rid != RID()) { + // Normal glyph. + float fa = TS->font_get_ascent(glyphs[glyph_idx].font_rid, glyphs[glyph_idx].font_size); + float fd = TS->font_get_descent(glyphs[glyph_idx].font_rid, glyphs[glyph_idx].font_size); + if (p_click.y >= baseline_y - fa && p_click.y <= baseline_y + fd) { + char_pos = glyphs[glyph_idx].start; + } + } else if (!(glyphs[glyph_idx].flags & TextServer::GRAPHEME_IS_VIRTUAL)) { + // Hex code box. + Vector2 gl_size = TS->get_hex_code_box_size(glyphs[glyph_idx].font_size, glyphs[glyph_idx].index); + if (p_click.y >= baseline_y - gl_size.y * 0.9 && p_click.y <= baseline_y + gl_size.y * 0.2) { + char_pos = glyphs[glyph_idx].start; + } + } } } else { char_pos = TS->shaped_text_hit_test_position(rid, p_click.x - rect.position.x); @@ -4512,6 +4538,7 @@ void RichTextLabel::append_text(const String &p_bbcode) { if (subtag_a.size() == 2) { if (subtag_a[0] == "justification_flags" || subtag_a[0] == "jst") { Vector<String> subtag_b = subtag_a[1].split(","); + jst_flags = 0; // Clear flags. for (const String &E : subtag_b) { if (E == "kashida" || E == "k") { jst_flags.set_flag(TextServer::JUSTIFICATION_KASHIDA); @@ -4525,7 +4552,7 @@ void RichTextLabel::append_text(const String &p_bbcode) { jst_flags.set_flag(TextServer::JUSTIFICATION_SKIP_LAST_LINE); } else if (E == "skip_last_with_chars" || E == "sv") { jst_flags.set_flag(TextServer::JUSTIFICATION_SKIP_LAST_LINE_WITH_VISIBLE_CHARS); - } else if (E == "do_not_skip_singe" || E == "ns") { + } else if (E == "do_not_skip_single" || E == "ns") { jst_flags.set_flag(TextServer::JUSTIFICATION_DO_NOT_SKIP_SINGLE_LINE); } } @@ -6282,7 +6309,7 @@ Size2 RichTextLabel::get_minimum_size() const { void RichTextLabel::_generate_context_menu() { menu = memnew(PopupMenu); add_child(menu, false, INTERNAL_MODE_FRONT); - menu->connect("id_pressed", callable_mp(this, &RichTextLabel::menu_option)); + menu->connect(SceneStringName(id_pressed), callable_mp(this, &RichTextLabel::menu_option)); menu->add_item(ETR("Copy"), MENU_COPY); menu->add_item(ETR("Select All"), MENU_SELECT_ALL); diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index 6f5d0cdcfb..1f4d1dbf52 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -31,7 +31,6 @@ #include "scroll_container.h" #include "core/config/project_settings.h" -#include "core/os/os.h" #include "scene/main/window.h" #include "scene/theme/theme_db.h" @@ -250,18 +249,21 @@ void ScrollContainer::_update_scrollbar_position() { return; } - Size2 hmin = h_scroll->get_combined_minimum_size(); - Size2 vmin = v_scroll->get_combined_minimum_size(); + Size2 hmin = h_scroll->is_visible() ? h_scroll->get_combined_minimum_size() : Size2(); + Size2 vmin = v_scroll->is_visible() ? v_scroll->get_combined_minimum_size() : Size2(); + + int lmar = is_layout_rtl() ? theme_cache.panel_style->get_margin(SIDE_RIGHT) : theme_cache.panel_style->get_margin(SIDE_LEFT); + int rmar = is_layout_rtl() ? theme_cache.panel_style->get_margin(SIDE_LEFT) : theme_cache.panel_style->get_margin(SIDE_RIGHT); - h_scroll->set_anchor_and_offset(SIDE_LEFT, ANCHOR_BEGIN, 0); - h_scroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0); - h_scroll->set_anchor_and_offset(SIDE_TOP, ANCHOR_END, -hmin.height); - h_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, 0); + h_scroll->set_anchor_and_offset(SIDE_LEFT, ANCHOR_BEGIN, lmar); + h_scroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, -rmar - vmin.width); + h_scroll->set_anchor_and_offset(SIDE_TOP, ANCHOR_END, -hmin.height - theme_cache.panel_style->get_margin(SIDE_BOTTOM)); + h_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -theme_cache.panel_style->get_margin(SIDE_BOTTOM)); - v_scroll->set_anchor_and_offset(SIDE_LEFT, ANCHOR_END, -vmin.width); - v_scroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0); - v_scroll->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, 0); - v_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, 0); + v_scroll->set_anchor_and_offset(SIDE_LEFT, ANCHOR_END, -vmin.width - rmar); + v_scroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, -rmar); + v_scroll->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, theme_cache.panel_style->get_margin(SIDE_TOP)); + v_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -hmin.height - theme_cache.panel_style->get_margin(SIDE_BOTTOM)); _updating_scrollbars = false; } @@ -339,7 +341,7 @@ void ScrollContainer::_notification(int p_what) { case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: case NOTIFICATION_TRANSLATION_CHANGED: { _updating_scrollbars = true; - callable_mp(this, &ScrollContainer::_update_scrollbar_position).call_deferred(); + callable_mp(this, is_ready() ? &ScrollContainer::_reposition_children : &ScrollContainer::_update_scrollbar_position).call_deferred(); } break; case NOTIFICATION_READY: { @@ -444,8 +446,8 @@ void ScrollContainer::update_scrollbars() { v_scroll->set_page((h_scroll->is_visible() && h_scroll->get_parent() == this) ? size.height - hmin.height : size.height); // Avoid scrollbar overlapping. - h_scroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, (v_scroll->is_visible() && v_scroll->get_parent() == this) ? -vmin.width : 0); - v_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, (h_scroll->is_visible() && h_scroll->get_parent() == this) ? -hmin.height : 0); + _updating_scrollbars = true; + callable_mp(this, &ScrollContainer::_update_scrollbar_position).call_deferred(); } void ScrollContainer::_scroll_moved(float) { diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp index f6cfe6ab18..c715aceb0b 100644 --- a/scene/gui/subviewport_container.cpp +++ b/scene/gui/subviewport_container.cpp @@ -287,7 +287,7 @@ void SubViewportContainer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_stretch_shrink"), &SubViewportContainer::get_stretch_shrink); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stretch"), "set_stretch", "is_stretch_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "stretch_shrink"), "set_stretch_shrink", "get_stretch_shrink"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "stretch_shrink", PROPERTY_HINT_RANGE, "1,32,1,or_greater"), "set_stretch_shrink", "get_stretch_shrink"); GDVIRTUAL_BIND(_propagate_input_event, "event"); } diff --git a/scene/gui/tab_bar.h b/scene/gui/tab_bar.h index 52f1da5ec8..d62b39ae16 100644 --- a/scene/gui/tab_bar.h +++ b/scene/gui/tab_bar.h @@ -175,7 +175,7 @@ protected: bool _set(const StringName &p_name, const Variant &p_value) { return property_helper.property_set_value(p_name, p_value); } bool _get(const StringName &p_name, Variant &r_ret) const { return property_helper.property_get_value(p_name, r_ret); } - void _get_property_list(List<PropertyInfo> *p_list) const { property_helper.get_property_list(p_list, tabs.size()); } + void _get_property_list(List<PropertyInfo> *p_list) const { property_helper.get_property_list(p_list); } bool _property_can_revert(const StringName &p_name) const { return property_helper.property_can_revert(p_name); } bool _property_get_revert(const StringName &p_name, Variant &r_property) const { return property_helper.property_get_revert(p_name, r_property); } void _notification(int p_what); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 69b84da23d..a9dc4c765c 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1003,23 +1003,12 @@ void TextEdit::_notification(int p_what) { } } - if (str.length() == 0) { - // Draw line background if empty as we won't loop at all. - if (caret_line_wrap_index_map.has(line) && caret_line_wrap_index_map[line].has(line_wrap_index) && highlight_current_line) { - if (rtl) { - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - ofs_x - xmargin_end, ofs_y, xmargin_end, row_height), theme_cache.current_line_color); - } else { - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(ofs_x, ofs_y, xmargin_end, row_height), theme_cache.current_line_color); - } - } - } else { - // If it has text, then draw current line marker in the margin, as line number etc will draw over it, draw the rest of line marker later. - if (caret_line_wrap_index_map.has(line) && caret_line_wrap_index_map[line].has(line_wrap_index) && highlight_current_line) { - if (rtl) { - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - ofs_x - xmargin_end, ofs_y, xmargin_end, row_height), theme_cache.current_line_color); - } else { - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(ofs_x, ofs_y, xmargin_end, row_height), theme_cache.current_line_color); - } + // Draw current line highlight. + if (highlight_current_line && caret_line_wrap_index_map.has(line) && caret_line_wrap_index_map[line].has(line_wrap_index)) { + if (rtl) { + RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - ofs_x - xmargin_end, ofs_y, xmargin_end, row_height), theme_cache.current_line_color); + } else { + RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(ofs_x, ofs_y, xmargin_end, row_height), theme_cache.current_line_color); } } @@ -4248,8 +4237,11 @@ String TextEdit::get_word_at_pos(const Vector2 &p_pos) const { } Point2i TextEdit::get_line_column_at_pos(const Point2i &p_pos, bool p_allow_out_of_bounds) const { - float rows = p_pos.y; - rows -= theme_cache.style_normal->get_margin(SIDE_TOP); + float rows = p_pos.y - theme_cache.style_normal->get_margin(SIDE_TOP); + if (!editable) { + rows -= theme_cache.style_readonly->get_offset().y / 2; + rows += theme_cache.style_normal->get_offset().y / 2; + } rows /= get_line_height(); rows += _get_v_scroll_offset(); int first_vis_line = get_first_visible_line(); @@ -4280,6 +4272,10 @@ Point2i TextEdit::get_line_column_at_pos(const Point2i &p_pos, bool p_allow_out_ int col = 0; int colx = p_pos.x - (theme_cache.style_normal->get_margin(SIDE_LEFT) + gutters_width + gutter_padding); colx += first_visible_col; + if (!editable) { + colx -= theme_cache.style_readonly->get_offset().x / 2; + colx += theme_cache.style_normal->get_offset().x / 2; + } col = _get_char_pos_for_line(colx, row, wrap_index); if (get_line_wrapping_mode() != LineWrappingMode::LINE_WRAPPING_NONE && wrap_index < get_line_wrap_count(row)) { // Move back one if we are at the end of the row. @@ -4397,13 +4393,7 @@ int TextEdit::get_minimap_line_at_pos(const Point2i &p_pos) const { } } - if (row < 0) { - row = 0; - } - - if (row >= text.size()) { - row = text.size() - 1; - } + row = CLAMP(row, 0, text.size() - 1); return row; } @@ -7192,9 +7182,9 @@ void TextEdit::_generate_context_menu() { menu->add_check_item(ETR("Display Control Characters"), MENU_DISPLAY_UCC); menu->add_submenu_node_item(ETR("Insert Control Character"), menu_ctl, MENU_SUBMENU_INSERT_UCC); - menu->connect("id_pressed", callable_mp(this, &TextEdit::menu_option)); - menu_dir->connect("id_pressed", callable_mp(this, &TextEdit::menu_option)); - menu_ctl->connect("id_pressed", callable_mp(this, &TextEdit::menu_option)); + menu->connect(SceneStringName(id_pressed), callable_mp(this, &TextEdit::menu_option)); + menu_dir->connect(SceneStringName(id_pressed), callable_mp(this, &TextEdit::menu_option)); + menu_ctl->connect(SceneStringName(id_pressed), callable_mp(this, &TextEdit::menu_option)); } void TextEdit::_update_context_menu() { @@ -7995,7 +7985,7 @@ void TextEdit::_update_minimap_click() { } Point2i next_line = get_next_visible_line_index_offset_from(row, 0, -get_visible_line_count() / 2); - int first_line = row - next_line.x + 1; + int first_line = MAX(0, row - next_line.x + 1); double delta = get_scroll_pos_for_line(first_line, next_line.y) - get_v_scroll(); if (delta < 0) { _scroll_up(-delta, true); diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp index df90257e03..c267ff93c6 100644 --- a/scene/gui/texture_button.cpp +++ b/scene/gui/texture_button.cpp @@ -178,13 +178,14 @@ void TextureButton::_notification(int p_what) { texdraw = focused; } - if (texdraw.is_valid()) { - size = texdraw->get_size(); - _texture_region = Rect2(Point2(), texdraw->get_size()); + if (texdraw.is_valid() || click_mask.is_valid()) { + const Size2 texdraw_size = texdraw.is_valid() ? texdraw->get_size() : Size2(click_mask->get_size()); + + size = texdraw_size; + _texture_region = Rect2(Point2(), texdraw_size); _tile = false; switch (stretch_mode) { case STRETCH_KEEP: - size = texdraw->get_size(); break; case STRETCH_SCALE: size = get_size(); @@ -194,18 +195,17 @@ void TextureButton::_notification(int p_what) { _tile = true; break; case STRETCH_KEEP_CENTERED: - ofs = (get_size() - texdraw->get_size()) / 2; - size = texdraw->get_size(); + ofs = (get_size() - texdraw_size) / 2; break; case STRETCH_KEEP_ASPECT_CENTERED: case STRETCH_KEEP_ASPECT: { Size2 _size = get_size(); - float tex_width = texdraw->get_width() * _size.height / texdraw->get_height(); + float tex_width = texdraw_size.width * _size.height / texdraw_size.height; float tex_height = _size.height; if (tex_width > _size.width) { tex_width = _size.width; - tex_height = texdraw->get_height() * tex_width / texdraw->get_width(); + tex_height = texdraw_size.height * tex_width / texdraw_size.width; } if (stretch_mode == STRETCH_KEEP_ASPECT_CENTERED) { @@ -217,10 +217,9 @@ void TextureButton::_notification(int p_what) { } break; case STRETCH_KEEP_ASPECT_COVERED: { size = get_size(); - Size2 tex_size = texdraw->get_size(); - Size2 scale_size(size.width / tex_size.width, size.height / tex_size.height); + Size2 scale_size = size / texdraw_size; float scale = scale_size.width > scale_size.height ? scale_size.width : scale_size.height; - Size2 scaled_tex_size = tex_size * scale; + Size2 scaled_tex_size = texdraw_size * scale; Point2 ofs2 = ((scaled_tex_size - size) / scale).abs() / 2.0f; _texture_region = Rect2(ofs2, size / scale); } break; @@ -233,10 +232,12 @@ void TextureButton::_notification(int p_what) { if (draw_focus_only) { // Do nothing, we only needed to calculate the rectangle. - } else if (_tile) { - draw_texture_rect(texdraw, Rect2(ofs, size), _tile); - } else { - draw_texture_rect_region(texdraw, Rect2(ofs, size), _texture_region); + } else if (texdraw.is_valid()) { + if (_tile) { + draw_texture_rect(texdraw, Rect2(ofs, size), _tile); + } else { + draw_texture_rect_region(texdraw, Rect2(ofs, size), _texture_region); + } } } else { _position_rect = Rect2(); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index fc5b942918..56be6b90a2 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -5821,7 +5821,7 @@ Tree::Tree() { line_editor->connect("text_submitted", callable_mp(this, &Tree::_line_editor_submit)); text_editor->connect(SceneStringName(gui_input), callable_mp(this, &Tree::_text_editor_gui_input)); popup_editor->connect("popup_hide", callable_mp(this, &Tree::_text_editor_popup_modal_close)); - popup_menu->connect("id_pressed", callable_mp(this, &Tree::popup_select)); + popup_menu->connect(SceneStringName(id_pressed), callable_mp(this, &Tree::popup_select)); value_editor->connect("value_changed", callable_mp(this, &Tree::value_editor_changed)); set_notify_transform(true); diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index 7ed1f130c8..c0386b056f 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -34,6 +34,7 @@ #include "scene/2d/canvas_group.h" #include "scene/main/canvas_layer.h" #include "scene/main/window.h" +#include "scene/resources/atlas_texture.h" #include "scene/resources/canvas_item_material.h" #include "scene/resources/font.h" #include "scene/resources/multimesh.h" @@ -850,18 +851,28 @@ void CanvasItem::draw_polygon(const Vector<Point2> &p_points, const Vector<Color ERR_THREAD_GUARD; ERR_DRAW_GUARD; - RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); + const Ref<AtlasTexture> atlas = p_texture; + if (atlas.is_valid() && atlas->get_atlas().is_valid()) { + const Ref<Texture2D> &texture = atlas->get_atlas(); + const Vector2 atlas_size = texture->get_size(); + + const Vector2 remap_min = atlas->get_region().position / atlas_size; + const Vector2 remap_max = atlas->get_region().get_end() / atlas_size; - RenderingServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, p_colors, p_uvs, rid); + PackedVector2Array uvs = p_uvs; + for (Vector2 &p : uvs) { + p.x = Math::remap(p.x, 0, 1, remap_min.x, remap_max.x); + p.y = Math::remap(p.y, 0, 1, remap_min.y, remap_max.y); + } + RenderingServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, p_colors, uvs, texture->get_rid()); + } else { + RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); + RenderingServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, p_colors, p_uvs, texture_rid); + } } void CanvasItem::draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture) { - ERR_THREAD_GUARD; - ERR_DRAW_GUARD; - - Vector<Color> colors = { p_color }; - RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); - RenderingServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, colors, p_uvs, rid); + draw_polygon(p_points, { p_color }, p_uvs, p_texture); } void CanvasItem::draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture2D> &p_texture, const Transform2D &p_transform, const Color &p_modulate) { diff --git a/scene/main/instance_placeholder.cpp b/scene/main/instance_placeholder.cpp index fe23ca1800..f36bbe9395 100644 --- a/scene/main/instance_placeholder.cpp +++ b/scene/main/instance_placeholder.cpp @@ -88,16 +88,16 @@ Node *InstancePlaceholder::create_instance(bool p_replace, const Ref<PackedScene if (!ps.is_valid()) { return nullptr; } - Node *scene = ps->instantiate(); - if (!scene) { + Node *instance = ps->instantiate(); + if (!instance) { return nullptr; } - scene->set_name(get_name()); - scene->set_multiplayer_authority(get_multiplayer_authority()); + instance->set_name(get_name()); + instance->set_multiplayer_authority(get_multiplayer_authority()); int pos = get_index(); for (const PropSet &E : stored_values) { - scene->set(E.name, E.value); + set_value_on_instance(this, instance, E); } if (p_replace) { @@ -105,10 +105,125 @@ Node *InstancePlaceholder::create_instance(bool p_replace, const Ref<PackedScene base->remove_child(this); } - base->add_child(scene); - base->move_child(scene, pos); + base->add_child(instance); + base->move_child(instance, pos); - return scene; + return instance; +} + +// This method will attempt to set the correct values on the placeholder instance +// for regular types this is trivial and unnecessary. +// For nodes however this becomes a bit tricky because they might now have existed until the instantiation, +// so this method will try to find the correct nodes and resolve them. +void InstancePlaceholder::set_value_on_instance(InstancePlaceholder *p_placeholder, Node *p_instance, const PropSet &p_set) { + bool is_valid; + + // If we don't have any info, we can't do anything, + // so try setting the value directly. + Variant current = p_instance->get(p_set.name, &is_valid); + if (!is_valid) { + p_instance->set(p_set.name, p_set.value, &is_valid); + return; + } + + Variant::Type current_type = current.get_type(); + Variant::Type placeholder_type = p_set.value.get_type(); + + // Arrays are a special case, because their containing type might be different. + if (current_type != Variant::Type::ARRAY) { + // Check if the variant types match. + if (Variant::evaluate(Variant::OP_EQUAL, current_type, placeholder_type)) { + p_instance->set(p_set.name, p_set.value, &is_valid); + if (is_valid) { + return; + } + // Types match but setting failed? This is strange, so let's print a warning! + WARN_PRINT(vformat("Property '%s' with type '%s' could not be set when creating instance of '%s'.", p_set.name, Variant::get_type_name(current_type), p_placeholder->get_name())); + return; + } + } else { + // We are dealing with an Array. + // Let's check if the subtype of the array matches first. + // This is needed because the set method of ScriptInstance checks for type, + // but the ClassDB set method doesn't! So we cannot reliably know what actually happens. + Array current_array = current; + Array placeholder_array = p_set.value; + if (current_array.is_same_typed(placeholder_array)) { + p_instance->set(p_set.name, p_set.value, &is_valid); + if (is_valid) { + return; + } + // Internal array types match but setting failed? This is strange, so let's print a warning! + WARN_PRINT(vformat("Array Property '%s' with type '%s' could not be set when creating instance of '%s'.", p_set.name, Variant::get_type_name(Variant::Type(current_array.get_typed_builtin())), p_placeholder->get_name())); + } + // Arrays are not the same internal type. This should be happening because we have a NodePath Array, + // but the instance wants a Node Array. + } + + switch (current_type) { + case Variant::Type::NIL: + if (placeholder_type != Variant::Type::NODE_PATH) { + break; + } + // If it's nil but we have a NodePath, we guess what works. + + p_instance->set(p_set.name, p_set.value, &is_valid); + if (is_valid) { + break; + } + + p_instance->set(p_set.name, try_get_node(p_placeholder, p_instance, p_set.value), &is_valid); + break; + case Variant::Type::OBJECT: + if (placeholder_type != Variant::Type::NODE_PATH) { + break; + } + // Easiest case, we want a node, but we have a deferred NodePath. + p_instance->set(p_set.name, try_get_node(p_placeholder, p_instance, p_set.value)); + break; + case Variant::Type::ARRAY: { + // If we have reached here it means our array types don't match, + // so we will convert the placeholder array into the correct type + // and resolve nodes if necessary. + Array current_array = current; + Array converted_array; + Array placeholder_array = p_set.value; + converted_array = current_array.duplicate(); + converted_array.resize(placeholder_array.size()); + + if (Variant::evaluate(Variant::OP_EQUAL, current_array.get_typed_builtin(), Variant::Type::NODE_PATH)) { + // We want a typed NodePath array. + for (int i = 0; i < placeholder_array.size(); i++) { + converted_array.set(i, placeholder_array[i]); + } + } else { + // We want Nodes, convert NodePaths. + for (int i = 0; i < placeholder_array.size(); i++) { + converted_array.set(i, try_get_node(p_placeholder, p_instance, placeholder_array[i])); + } + } + + p_instance->set(p_set.name, converted_array, &is_valid); + if (!is_valid) { + WARN_PRINT(vformat("Property '%s' with type '%s' could not be set when creating instance of '%s'.", p_set.name, Variant::get_type_name(current_type), p_placeholder->get_name())); + } + break; + } + default: + WARN_PRINT(vformat("Property '%s' with type '%s' could not be set when creating instance of '%s'.", p_set.name, Variant::get_type_name(current_type), p_placeholder->get_name())); + break; + } +} + +Node *InstancePlaceholder::try_get_node(InstancePlaceholder *p_placeholder, Node *p_instance, const NodePath &p_path) { + // First try to resolve internally, + // if that fails try resolving externally. + Node *node = p_instance->get_node_or_null(p_path); + if (node == nullptr) { + node = p_placeholder->get_node_or_null(p_path); + } + + return node; } Dictionary InstancePlaceholder::get_stored_values(bool p_with_order) { diff --git a/scene/main/instance_placeholder.h b/scene/main/instance_placeholder.h index 480474d0bd..ccf1e63a16 100644 --- a/scene/main/instance_placeholder.h +++ b/scene/main/instance_placeholder.h @@ -46,6 +46,10 @@ class InstancePlaceholder : public Node { List<PropSet> stored_values; +private: + void set_value_on_instance(InstancePlaceholder *p_placeholder, Node *p_instance, const PropSet &p_set); + Node *try_get_node(InstancePlaceholder *p_placeholder, Node *p_instance, const NodePath &p_path); + protected: bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; diff --git a/scene/main/window.cpp b/scene/main/window.cpp index e9a7123da0..b5824bc695 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -306,10 +306,21 @@ String Window::get_title() const { return title; } +void Window::_settings_changed() { + if (visible && initial_position != WINDOW_INITIAL_POSITION_ABSOLUTE && is_in_edited_scene_root()) { + Size2 screen_size = Size2(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height")); + position = (screen_size - size) / 2; + if (embedder) { + embedder->_sub_window_update(this); + } + } +} + void Window::set_initial_position(Window::WindowInitialPosition p_initial_position) { ERR_MAIN_THREAD_GUARD; initial_position = p_initial_position; + _settings_changed(); notify_property_list_changed(); } @@ -397,6 +408,16 @@ Point2i Window::get_position_with_decorations() const { if (window_id != DisplayServer::INVALID_WINDOW_ID) { return DisplayServer::get_singleton()->window_get_position_with_decorations(window_id); } + if (visible && is_embedded() && !get_flag(Window::FLAG_BORDERLESS)) { + Size2 border_offset; + if (theme_cache.embedded_border.is_valid()) { + border_offset = theme_cache.embedded_border->get_offset(); + } + if (theme_cache.embedded_unfocused_border.is_valid()) { + border_offset = border_offset.max(theme_cache.embedded_unfocused_border->get_offset()); + } + return position - border_offset; + } return position; } @@ -405,6 +426,16 @@ Size2i Window::get_size_with_decorations() const { if (window_id != DisplayServer::INVALID_WINDOW_ID) { return DisplayServer::get_singleton()->window_get_size_with_decorations(window_id); } + if (visible && is_embedded() && !get_flag(Window::FLAG_BORDERLESS)) { + Size2 border_size; + if (theme_cache.embedded_border.is_valid()) { + border_size = theme_cache.embedded_border->get_minimum_size(); + } + if (theme_cache.embedded_unfocused_border.is_valid()) { + border_size = border_size.max(theme_cache.embedded_unfocused_border->get_minimum_size()); + } + return size + border_size; + } return size; } @@ -829,7 +860,12 @@ void Window::set_visible(bool p_visible) { if (visible) { embedder = embedder_vp; if (initial_position != WINDOW_INITIAL_POSITION_ABSOLUTE) { - position = (embedder->get_visible_rect().size - size) / 2; + if (is_in_edited_scene_root()) { + Size2 screen_size = Size2(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height")); + position = (screen_size - size) / 2; + } else { + position = (embedder->get_visible_rect().size - size) / 2; + } } embedder->_sub_window_register(this); RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE); @@ -1265,6 +1301,12 @@ void Window::_notification(int p_what) { } break; case NOTIFICATION_ENTER_TREE: { + if (is_in_edited_scene_root()) { + if (!ProjectSettings::get_singleton()->is_connected("settings_changed", callable_mp(this, &Window::_settings_changed))) { + ProjectSettings::get_singleton()->connect("settings_changed", callable_mp(this, &Window::_settings_changed)); + } + } + bool embedded = false; { embedder = get_embedder(); @@ -1280,7 +1322,12 @@ void Window::_notification(int p_what) { // Create as embedded. if (embedder) { if (initial_position != WINDOW_INITIAL_POSITION_ABSOLUTE) { - position = (embedder->get_visible_rect().size - size) / 2; + if (is_in_edited_scene_root()) { + Size2 screen_size = Size2(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height")); + position = (screen_size - size) / 2; + } else { + position = (embedder->get_visible_rect().size - size) / 2; + } } embedder->_sub_window_register(this); RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE); @@ -1377,6 +1424,10 @@ void Window::_notification(int p_what) { } break; case NOTIFICATION_EXIT_TREE: { + if (ProjectSettings::get_singleton()->is_connected("settings_changed", callable_mp(this, &Window::_settings_changed))) { + ProjectSettings::get_singleton()->disconnect("settings_changed", callable_mp(this, &Window::_settings_changed)); + } + set_theme_context(nullptr, false); if (transient) { diff --git a/scene/main/window.h b/scene/main/window.h index ffcf50ccdd..33d593711f 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -214,6 +214,8 @@ private: int resize_margin = 0; } theme_cache; + void _settings_changed(); + Viewport *embedder = nullptr; Transform2D window_transform; diff --git a/scene/property_list_helper.cpp b/scene/property_list_helper.cpp index 152ecaf89d..ce258ee8c3 100644 --- a/scene/property_list_helper.cpp +++ b/scene/property_list_helper.cpp @@ -122,8 +122,9 @@ bool PropertyListHelper::is_property_valid(const String &p_property, int *r_inde return property_list.has(components[1]); } -void PropertyListHelper::get_property_list(List<PropertyInfo> *p_list, int p_count) const { - for (int i = 0; i < p_count; i++) { +void PropertyListHelper::get_property_list(List<PropertyInfo> *p_list) const { + const int property_count = _call_array_length_getter(); + for (int i = 0; i < property_count; i++) { for (const KeyValue<String, Property> &E : property_list) { const Property &property = E.value; @@ -177,7 +178,9 @@ bool PropertyListHelper::property_get_revert(const String &p_property, Variant & PropertyListHelper::~PropertyListHelper() { // No object = it's the main helper. Do a cleanup. - if (!object) { + if (!object && is_initialized()) { + memdelete(array_length_getter); + for (const KeyValue<String, Property> &E : property_list) { if (E.value.setter) { memdelete(E.value.setter); diff --git a/scene/property_list_helper.h b/scene/property_list_helper.h index e19e7cd22e..6bc65f6e3e 100644 --- a/scene/property_list_helper.h +++ b/scene/property_list_helper.h @@ -77,7 +77,7 @@ public: void setup_for_instance(const PropertyListHelper &p_base, Object *p_object); bool is_property_valid(const String &p_property, int *r_index = nullptr) const; - void get_property_list(List<PropertyInfo> *p_list, int p_count) const; + void get_property_list(List<PropertyInfo> *p_list) const; bool property_get_value(const String &p_property, Variant &r_ret) const; bool property_set_value(const String &p_property, const Variant &p_value) const; bool property_can_revert(const String &p_property) const; diff --git a/scene/resources/2d/tile_set.cpp b/scene/resources/2d/tile_set.cpp index 0f73577768..6c3356a205 100644 --- a/scene/resources/2d/tile_set.cpp +++ b/scene/resources/2d/tile_set.cpp @@ -6378,7 +6378,7 @@ Ref<ConvexPolygonShape2D> TileData::get_collision_polygon_shape(int p_layer_id, for (int i = 0; i < size; i++) { Ref<ConvexPolygonShape2D> transformed_polygon; transformed_polygon.instantiate(); - transformed_polygon->set_points(get_transformed_vertices(shapes_data.shapes[shape_index]->get_points(), p_flip_h, p_flip_v, p_transpose)); + transformed_polygon->set_points(get_transformed_vertices(shapes_data.shapes[i]->get_points(), p_flip_h, p_flip_v, p_transpose)); shapes_data.transformed_shapes[key][i] = transformed_polygon; } return shapes_data.transformed_shapes[key][shape_index]; diff --git a/scene/resources/animation.h b/scene/resources/animation.h index cc7bbae8a3..604bce497a 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -43,6 +43,8 @@ class Animation : public Resource { public: typedef uint32_t TypeHash; + static inline String PARAMETERS_BASE_PATH = "parameters/"; + enum TrackType { TYPE_VALUE, // Set a value in a property, can be interpolated. TYPE_POSITION_3D, // Position 3D track, can be compressed. diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 27da825bfe..8e49a8b56f 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -822,7 +822,18 @@ uniform float distance_fade_max : hint_range(0.0, 4096.0, 0.01); )"; } - if (flags[FLAG_ALBEDO_TEXTURE_MSDF]) { + if (flags[FLAG_ALBEDO_TEXTURE_MSDF] && flags[FLAG_UV1_USE_TRIPLANAR]) { + String msg = "MSDF is not supported on triplanar materials. Ignoring MSDF in favor of triplanar mapping."; + if (textures[TEXTURE_ALBEDO].is_valid()) { + WARN_PRINT(vformat("%s (albedo %s): " + msg, get_path(), textures[TEXTURE_ALBEDO]->get_path())); + } else if (!get_path().is_empty()) { + WARN_PRINT(vformat("%s: " + msg, get_path())); + } else { + WARN_PRINT(msg); + } + } + + if (flags[FLAG_ALBEDO_TEXTURE_MSDF] && !flags[FLAG_UV1_USE_TRIPLANAR]) { code += R"( uniform float msdf_pixel_range : hint_range(1.0, 100.0, 1.0); uniform float msdf_outline_size : hint_range(0.0, 250.0, 1.0); @@ -1271,7 +1282,7 @@ void vertex() {)"; code += "}\n"; - if (flags[FLAG_ALBEDO_TEXTURE_MSDF]) { + if (flags[FLAG_ALBEDO_TEXTURE_MSDF] && !flags[FLAG_UV1_USE_TRIPLANAR]) { code += R"( float msdf_median(float r, float g, float b, float a) { return min(max(min(r, g), min(max(r, g), b)), a); @@ -1414,7 +1425,7 @@ void fragment() {)"; } } - if (flags[FLAG_ALBEDO_TEXTURE_MSDF]) { + if (flags[FLAG_ALBEDO_TEXTURE_MSDF] && !flags[FLAG_UV1_USE_TRIPLANAR]) { code += R"( { // Albedo Texture MSDF: Enabled @@ -1427,11 +1438,7 @@ void fragment() {)"; if (flags[FLAG_USE_POINT_SIZE]) { code += " vec2 dest_size = vec2(1.0) / fwidth(POINT_COORD);\n"; } else { - if (flags[FLAG_UV1_USE_TRIPLANAR]) { - code += " vec2 dest_size = vec2(1.0) / fwidth(uv1_triplanar_pos);\n"; - } else { - code += " vec2 dest_size = vec2(1.0) / fwidth(base_uv);\n"; - } + code += " vec2 dest_size = vec2(1.0) / fwidth(base_uv);\n"; } code += R"( float px_size = max(0.5 * dot(msdf_size, dest_size), 1.0); diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 5e50b9a240..0c57c6b7ba 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -314,6 +314,16 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { ERR_FAIL_INDEX_V(nprops[j].value, prop_count, nullptr); if (nprops[j].name & FLAG_PATH_PROPERTY_IS_NODE) { + if (!Engine::get_singleton()->is_editor_hint() && node->get_scene_instance_load_placeholder()) { + // We cannot know if the referenced nodes exist yet, so instead of deferring, we write the NodePaths directly. + + uint32_t name_idx = nprops[j].name & (FLAG_PATH_PROPERTY_IS_NODE - 1); + ERR_FAIL_UNSIGNED_INDEX_V(name_idx, (uint32_t)sname_count, nullptr); + + node->set(snames[name_idx], props[nprops[j].value], &valid); + continue; + } + uint32_t name_idx = nprops[j].name & (FLAG_PATH_PROPERTY_IS_NODE - 1); ERR_FAIL_UNSIGNED_INDEX_V(name_idx, (uint32_t)sname_count, nullptr); diff --git a/scene/resources/particle_process_material.cpp b/scene/resources/particle_process_material.cpp index 01d26a8bed..ee986f5820 100644 --- a/scene/resources/particle_process_material.cpp +++ b/scene/resources/particle_process_material.cpp @@ -147,13 +147,13 @@ void ParticleProcessMaterial::finish_shaders() { void ParticleProcessMaterial::_update_shader() { MaterialKey mk = _compute_key(); if (mk == current_key) { - return; //no update required in the end + return; // No update required in the end. } if (shader_map.has(current_key)) { shader_map[current_key].users--; if (shader_map[current_key].users == 0) { - //deallocate shader, as it's no longer in use + // Deallocate shader, as it's no longer in use. RS::get_singleton()->free(shader_map[current_key].shader); shader_map.erase(current_key); } @@ -166,23 +166,26 @@ void ParticleProcessMaterial::_update_shader() { shader_map[mk].users++; return; } - //must create a shader! + + // No pre-existing shader, create one. // Add a comment to describe the shader origin (useful when converting to ShaderMaterial). String code = "// NOTE: Shader automatically converted from " VERSION_NAME " " VERSION_FULL_CONFIG "'s ParticleProcessMaterial.\n\n"; code += "shader_type particles;\n"; code += "render_mode disable_velocity;\n"; - if (collision_scale) { code += "render_mode collision_use_scale;\n"; } + code += "\n"; + + // Define uniforms. code += "uniform vec3 direction;\n"; code += "uniform float spread;\n"; code += "uniform float flatness;\n"; - code += "uniform float inherit_emitter_velocity_ratio = 0;\n"; + code += "uniform float inherit_emitter_velocity_ratio = 0.0;\n"; code += "uniform float initial_linear_velocity_min;\n"; code += "uniform float initial_linear_velocity_max;\n"; @@ -227,10 +230,10 @@ void ParticleProcessMaterial::_update_shader() { code += "uniform float anim_offset_max;\n"; code += "uniform float lifetime_randomness;\n"; - code += "uniform vec3 emission_shape_offset = vec3(0.);\n"; - code += "uniform vec3 emission_shape_scale = vec3(1.);\n"; + code += "uniform vec3 emission_shape_offset = vec3(0.0);\n"; + code += "uniform vec3 emission_shape_scale = vec3(1.0);\n"; - code += "uniform vec3 velocity_pivot = vec3(0.);\n"; + code += "uniform vec3 velocity_pivot = vec3(0.0);\n"; if (tex_parameters[PARAM_SCALE_OVER_VELOCITY].is_valid()) { code += "uniform float scale_over_velocity_min = 0.0;\n"; @@ -346,10 +349,10 @@ void ParticleProcessMaterial::_update_shader() { code += "uniform sampler2D scale_over_velocity_curve : repeat_disable;\n"; } if (tex_parameters[PARAM_DIRECTIONAL_VELOCITY].is_valid()) { - code += "uniform sampler2D directional_velocity_curve: repeat_disable;\n"; + code += "uniform sampler2D directional_velocity_curve : repeat_disable;\n"; } if (velocity_limit_curve.is_valid()) { - code += "uniform sampler2D velocity_limit_curve: repeat_disable;\n"; + code += "uniform sampler2D velocity_limit_curve : repeat_disable;\n"; } if (collision_mode == COLLISION_RIGID) { @@ -372,23 +375,29 @@ void ParticleProcessMaterial::_update_shader() { if (turbulence_color_ramp.is_valid()) { code += "uniform sampler2D turbulence_color_ramp;\n"; } - code += "\n"; + } + + code += "\n"; + + // Define helper functions. - //functions for 3D noise / turbulence - code += "\n\n"; + if (turbulence_enabled) { + // Functions for 3D noise / turbulence. + code += "// Functions for 3D noise / turbulence.\n"; code += "vec4 grad(vec4 p) {\n"; code += " p = fract(vec4(\n"; - code += " dot(p, vec4(0.143081, 0.001724, 0.280166, 0.262771)),\n"; - code += " dot(p, vec4(0.645401, -0.047791, -0.146698, 0.595016)),\n"; - code += " dot(p, vec4(-0.499665, -0.095734, 0.425674, -0.207367)),\n"; - code += " dot(p, vec4(-0.013596, -0.848588, 0.423736, 0.17044))));\n"; + code += " dot(p, vec4(0.143081, 0.001724, 0.280166, 0.262771)),\n"; + code += " dot(p, vec4(0.645401, -0.047791, -0.146698, 0.595016)),\n"; + code += " dot(p, vec4(-0.499665, -0.095734, 0.425674, -0.207367)),\n"; + code += " dot(p, vec4(-0.013596, -0.848588, 0.423736, 0.17044))));\n"; code += " return fract((p.xyzw * p.yzwx) * 2365.952041) * 2.0 - 1.0;\n"; - code += "}\n"; + code += "}\n\n"; + code += "float noise(vec4 coord) {\n"; code += " // Domain rotation to improve the look of XYZ slices + animation patterns.\n"; code += " coord = vec4(\n"; - code += " coord.xyz + dot(coord, vec4(vec3(-0.1666667), -0.5)),\n"; - code += " dot(coord, vec4(0.5)));\n\n"; + code += " coord.xyz + dot(coord, vec4(vec3(-0.1666667), -0.5)),\n"; + code += " dot(coord, vec4(0.5)));\n\n"; code += " vec4 base = floor(coord), delta = coord - base;\n\n"; code += " vec4 grad_0000 = grad(base + vec4(0.0, 0.0, 0.0, 0.0)), grad_1000 = grad(base + vec4(1.0, 0.0, 0.0, 0.0));\n"; code += " vec4 grad_0100 = grad(base + vec4(0.0, 1.0, 0.0, 0.0)), grad_1100 = grad(base + vec4(1.0, 1.0, 0.0, 0.0));\n"; @@ -399,23 +408,24 @@ void ParticleProcessMaterial::_update_shader() { code += " vec4 grad_0011 = grad(base + vec4(0.0, 0.0, 1.0, 1.0)), grad_1011 = grad(base + vec4(1.0, 0.0, 1.0, 1.0));\n"; code += " vec4 grad_0111 = grad(base + vec4(0.0, 1.0, 1.0, 1.0)), grad_1111 = grad(base + vec4(1.0, 1.0, 1.0, 1.0));\n\n"; code += " vec4 result_0123 = vec4(\n"; - code += " dot(delta - vec4(0.0, 0.0, 0.0, 0.0), grad_0000), dot(delta - vec4(1.0, 0.0, 0.0, 0.0), grad_1000),\n"; - code += " dot(delta - vec4(0.0, 1.0, 0.0, 0.0), grad_0100), dot(delta - vec4(1.0, 1.0, 0.0, 0.0), grad_1100));\n"; + code += " dot(delta - vec4(0.0, 0.0, 0.0, 0.0), grad_0000), dot(delta - vec4(1.0, 0.0, 0.0, 0.0), grad_1000),\n"; + code += " dot(delta - vec4(0.0, 1.0, 0.0, 0.0), grad_0100), dot(delta - vec4(1.0, 1.0, 0.0, 0.0), grad_1100));\n"; code += " vec4 result_4567 = vec4(\n"; - code += " dot(delta - vec4(0.0, 0.0, 1.0, 0.0), grad_0010), dot(delta - vec4(1.0, 0.0, 1.0, 0.0), grad_1010),\n"; - code += " dot(delta - vec4(0.0, 1.0, 1.0, 0.0), grad_0110), dot(delta - vec4(1.0, 1.0, 1.0, 0.0), grad_1110));\n"; + code += " dot(delta - vec4(0.0, 0.0, 1.0, 0.0), grad_0010), dot(delta - vec4(1.0, 0.0, 1.0, 0.0), grad_1010),\n"; + code += " dot(delta - vec4(0.0, 1.0, 1.0, 0.0), grad_0110), dot(delta - vec4(1.0, 1.0, 1.0, 0.0), grad_1110));\n"; code += " vec4 result_89AB = vec4(\n"; - code += " dot(delta - vec4(0.0, 0.0, 0.0, 1.0), grad_0001), dot(delta - vec4(1.0, 0.0, 0.0, 1.0), grad_1001),\n"; - code += " dot(delta - vec4(0.0, 1.0, 0.0, 1.0), grad_0101), dot(delta - vec4(1.0, 1.0, 0.0, 1.0), grad_1101));\n"; + code += " dot(delta - vec4(0.0, 0.0, 0.0, 1.0), grad_0001), dot(delta - vec4(1.0, 0.0, 0.0, 1.0), grad_1001),\n"; + code += " dot(delta - vec4(0.0, 1.0, 0.0, 1.0), grad_0101), dot(delta - vec4(1.0, 1.0, 0.0, 1.0), grad_1101));\n"; code += " vec4 result_CDEF = vec4(\n"; - code += " dot(delta - vec4(0.0, 0.0, 1.0, 1.0), grad_0011), dot(delta - vec4(1.0, 0.0, 1.0, 1.0), grad_1011),\n"; - code += " dot(delta - vec4(0.0, 1.0, 1.0, 1.0), grad_0111), dot(delta - vec4(1.0, 1.0, 1.0, 1.0), grad_1111));\n\n"; + code += " dot(delta - vec4(0.0, 0.0, 1.0, 1.0), grad_0011), dot(delta - vec4(1.0, 0.0, 1.0, 1.0), grad_1011),\n"; + code += " dot(delta - vec4(0.0, 1.0, 1.0, 1.0), grad_0111), dot(delta - vec4(1.0, 1.0, 1.0, 1.0), grad_1111));\n\n"; code += " vec4 fade = delta * delta * delta * (10.0 + delta * (-15.0 + delta * 6.0));\n"; code += " vec4 result_W0 = mix(result_0123, result_89AB, fade.w), result_W1 = mix(result_4567, result_CDEF, fade.w);\n"; code += " vec4 result_WZ = mix(result_W0, result_W1, fade.z);\n"; code += " vec2 result_WZY = mix(result_WZ.xy, result_WZ.zw, fade.y);\n"; code += " return mix(result_WZY.x, result_WZY.y, fade.x);\n"; code += "}\n\n"; + code += "// Curl 3D and three-noise function with friendly permission by Isaac Cohen.\n"; code += "// Modified to accept 4D noise.\n"; code += "vec3 noise_3x(vec4 p) {\n"; @@ -424,7 +434,8 @@ void ParticleProcessMaterial::_update_shader() { code += " float s2 = noise(p - vec4(vec3(0.0), 1.7320508 * 2048.333333));\n"; code += " vec3 c = vec3(s, s1, s2);\n"; code += " return c;\n"; - code += "}\n"; + code += "}\n\n"; + code += "vec3 curl_3d(vec4 p, float c) {\n"; code += " float epsilon = 0.001 + c;\n"; code += " vec4 dx = vec4(epsilon, 0.0, 0.0, 0.0);\n"; @@ -440,7 +451,8 @@ void ParticleProcessMaterial::_update_shader() { code += " float y = (z1.x - z0.x) - (x1.z - x0.z);\n"; code += " float z = (x1.y - x0.y) - (y1.x - y0.x);\n"; code += " return normalize(vec3(x, y, z));\n"; - code += "}\n"; + code += "}\n\n"; + code += "vec3 get_noise_direction(vec3 pos) {\n"; code += " float adj_contrast = max((turbulence_noise_strength - 1.0), 0.0) * 70.0;\n"; code += " vec4 noise_time = TIME * vec4(turbulence_noise_speed, turbulence_noise_speed_random);\n"; @@ -448,66 +460,70 @@ void ParticleProcessMaterial::_update_shader() { code += " vec3 noise_direction = curl_3d(noise_pos + noise_time, adj_contrast);\n"; code += " noise_direction = mix(0.9 * noise_direction, noise_direction, turbulence_noise_strength - 9.0);\n"; code += " return noise_direction;\n"; - code += "}\n"; + code += "}\n\n"; } - code += "vec4 rotate_hue(vec4 current_color, float hue_rot_angle){\n"; + + code += "vec4 rotate_hue(vec4 current_color, float hue_rot_angle) {\n"; code += " float hue_rot_c = cos(hue_rot_angle);\n"; code += " float hue_rot_s = sin(hue_rot_angle);\n"; - code += " mat4 hue_rot_mat = mat4(vec4(0.299, 0.587, 0.114, 0.0),\n"; - code += " vec4(0.299, 0.587, 0.114, 0.0),\n"; - code += " vec4(0.299, 0.587, 0.114, 0.0),\n"; - code += " vec4(0.000, 0.000, 0.000, 1.0)) +\n"; - code += " mat4(vec4(0.701, -0.587, -0.114, 0.0),\n"; - code += " vec4(-0.299, 0.413, -0.114, 0.0),\n"; - code += " vec4(-0.300, -0.588, 0.886, 0.0),\n"; - code += " vec4(0.000, 0.000, 0.000, 0.0)) * hue_rot_c +\n"; - code += " mat4(vec4(0.168, 0.330, -0.497, 0.0),\n"; - code += " vec4(-0.328, 0.035, 0.292, 0.0),\n"; - code += " vec4(1.250, -1.050, -0.203, 0.0),\n"; - code += " vec4(0.000, 0.000, 0.000, 0.0)) * hue_rot_s;\n"; + code += " mat4 hue_rot_mat =\n"; + code += " mat4(vec4(0.299, 0.587, 0.114, 0.0),\n"; + code += " vec4(0.299, 0.587, 0.114, 0.0),\n"; + code += " vec4(0.299, 0.587, 0.114, 0.0),\n"; + code += " vec4(0.000, 0.000, 0.000, 1.0)) +\n"; + code += " mat4(vec4(0.701, -0.587, -0.114, 0.0),\n"; + code += " vec4(-0.299, 0.413, -0.114, 0.0),\n"; + code += " vec4(-0.300, -0.588, 0.886, 0.0),\n"; + code += " vec4(0.000, 0.000, 0.000, 0.0)) *\n"; + code += " hue_rot_c +\n"; + code += " mat4(vec4(0.168, 0.330, -0.497, 0.0),\n"; + code += " vec4(-0.328, 0.035, 0.292, 0.0),\n"; + code += " vec4(1.250, -1.050, -0.203, 0.0),\n"; + code += " vec4(0.000, 0.000, 0.000, 0.0)) *\n"; + code += " hue_rot_s;\n"; code += " return hue_rot_mat * current_color;\n"; - code += "}\n"; + code += "}\n\n"; - //need a random function - code += "\n\n"; + // Random functions. code += "float rand_from_seed(inout uint seed) {\n"; code += " int k;\n"; code += " int s = int(seed);\n"; - code += " if (s == 0)\n"; - code += " s = 305420679;\n"; + code += " if (s == 0) {\n"; + code += " s = 305420679;\n"; + code += " }\n"; code += " k = s / 127773;\n"; code += " s = 16807 * (s - k * 127773) - 2836 * k;\n"; - code += " if (s < 0)\n"; + code += " if (s < 0) {\n"; code += " s += 2147483647;\n"; + code += " }\n"; code += " seed = uint(s);\n"; code += " return float(seed % uint(65536)) / 65535.0;\n"; - code += "}\n"; - code += "\n"; + code += "}\n\n"; code += "float rand_from_seed_m1_p1(inout uint seed) {\n"; code += " return rand_from_seed(seed) * 2.0 - 1.0;\n"; - code += "}\n"; - code += "\n"; + code += "}\n\n"; - //improve seed quality + // Improve seed quality. code += "uint hash(uint x) {\n"; code += " x = ((x >> uint(16)) ^ x) * uint(73244475);\n"; code += " x = ((x >> uint(16)) ^ x) * uint(73244475);\n"; code += " x = (x >> uint(16)) ^ x;\n"; code += " return x;\n"; - code += "}\n"; - code += "\n"; + code += "}\n\n"; + + // Define structs. - code += "struct DisplayParameters{\n"; + code += "struct DisplayParameters {\n"; code += " vec3 scale;\n"; code += " float hue_rotation;\n"; code += " float animation_speed;\n"; code += " float animation_offset;\n"; code += " float lifetime;\n"; code += " vec4 color;\n"; - code += "};\n"; - code += "\n"; - code += "struct DynamicsParameters{\n"; + code += "};\n\n"; + + code += "struct DynamicsParameters {\n"; code += " float angle;\n"; code += " float angular_velocity;\n"; code += " float initial_velocity_multiplier;\n"; @@ -517,44 +533,43 @@ void ParticleProcessMaterial::_update_shader() { if (turbulence_enabled) { code += " float turb_influence;\n"; } - code += "};\n"; - code += "struct PhysicalParameters{\n"; + code += "};\n\n"; + + code += "struct PhysicalParameters {\n"; code += " float linear_accel;\n"; code += " float radial_accel;\n"; code += " float tangent_accel;\n"; code += " float damping;\n"; - code += "};\n"; + code += "};\n\n"; - code += "\n"; - code += "void calculate_initial_physical_params(inout PhysicalParameters params, inout uint alt_seed){\n"; + code += "void calculate_initial_physical_params(inout PhysicalParameters params, inout uint alt_seed) {\n"; code += " params.linear_accel = mix(linear_accel_min, linear_accel_max, rand_from_seed(alt_seed));\n"; code += " params.radial_accel = mix(radial_accel_min, radial_accel_max, rand_from_seed(alt_seed));\n"; code += " params.tangent_accel = mix(tangent_accel_min, tangent_accel_max, rand_from_seed(alt_seed));\n"; code += " params.damping = mix(damping_min, damping_max, rand_from_seed(alt_seed));\n"; - code += "}\n"; - code += "\n"; - code += "void calculate_initial_dynamics_params(inout DynamicsParameters params,inout uint alt_seed){\n"; + code += "}\n\n"; + + code += "void calculate_initial_dynamics_params(inout DynamicsParameters params, inout uint alt_seed) {\n"; code += " // -------------------- DO NOT REORDER OPERATIONS, IT BREAKS VISUAL COMPATIBILITY\n"; code += " // -------------------- ADD NEW OPERATIONS AT THE BOTTOM\n"; code += " params.angle = mix(initial_angle_min, initial_angle_max, rand_from_seed(alt_seed));\n"; code += " params.angular_velocity = mix(angular_velocity_min, angular_velocity_max, rand_from_seed(alt_seed));\n"; - code += " params.initial_velocity_multiplier = mix(initial_linear_velocity_min, initial_linear_velocity_max,rand_from_seed(alt_seed));\n"; - code += " params.directional_velocity = mix(directional_velocity_min, directional_velocity_max,rand_from_seed(alt_seed));\n"; - code += " params.radial_velocity = mix(radial_velocity_min, radial_velocity_max,rand_from_seed(alt_seed));\n"; - code += " params.orbit_velocity = mix(orbit_velocity_min, orbit_velocity_max,rand_from_seed(alt_seed));\n"; + code += " params.initial_velocity_multiplier = mix(initial_linear_velocity_min, initial_linear_velocity_max, rand_from_seed(alt_seed));\n"; + code += " params.directional_velocity = mix(directional_velocity_min, directional_velocity_max, rand_from_seed(alt_seed));\n"; + code += " params.radial_velocity = mix(radial_velocity_min, radial_velocity_max, rand_from_seed(alt_seed));\n"; + code += " params.orbit_velocity = mix(orbit_velocity_min, orbit_velocity_max, rand_from_seed(alt_seed));\n"; if (turbulence_enabled) { - code += " params.turb_influence = mix(turbulence_influence_min,turbulence_influence_max,rand_from_seed(alt_seed));\n"; + code += " params.turb_influence = mix(turbulence_influence_min, turbulence_influence_max, rand_from_seed(alt_seed));\n"; } - code += "}\n"; - code += "void calculate_initial_display_params(inout DisplayParameters params,inout uint alt_seed){\n"; + code += "}\n\n"; + + code += "void calculate_initial_display_params(inout DisplayParameters params, inout uint alt_seed) {\n"; code += " // -------------------- DO NOT REORDER OPERATIONS, IT BREAKS VISUAL COMPATIBILITY\n"; code += " // -------------------- ADD NEW OPERATIONS AT THE BOTTOM\n"; code += " float pi = 3.14159;\n"; - code += " float degree_to_rad = pi / 180.0;\n"; - - code += " params.scale = vec3(mix(scale_min, scale_max, rand_from_seed(alt_seed)));\n"; - code += " params.scale = sign(params.scale) * max(abs(params.scale), 0.001);\n"; - code += " params.hue_rotation = pi * 2.0 * mix(hue_variation_min, hue_variation_max, rand_from_seed(alt_seed));\n"; + code += " params.scale = vec3(mix(scale_min, scale_max, rand_from_seed(alt_seed)));\n"; + code += " params.scale = sign(params.scale) * max(abs(params.scale), 0.001);\n"; + code += " params.hue_rotation = pi * 2.0 * mix(hue_variation_min, hue_variation_max, rand_from_seed(alt_seed));\n"; code += " params.animation_speed = mix(anim_speed_min, anim_speed_max, rand_from_seed(alt_seed));\n"; code += " params.animation_offset = mix(anim_offset_min, anim_offset_max, rand_from_seed(alt_seed));\n"; code += " params.lifetime = (1.0 - lifetime_randomness * rand_from_seed(alt_seed));\n"; @@ -568,11 +583,11 @@ void ParticleProcessMaterial::_update_shader() { code += " ivec2 emission_tex_ofs = ivec2(point % emission_tex_size.x, point / emission_tex_size.x);\n"; code += " params.color *= texelFetch(emission_texture_color, emission_tex_ofs, 0);\n"; } - code += "}\n"; + code += "}\n\n"; - // process display parameters that are bound solely by lifetime - code += "void process_display_param(inout DisplayParameters parameters, float lifetime){\n"; - code += " // compile-time add textures\n"; + // Process display parameters that are bound solely by lifetime. + code += "void process_display_param(inout DisplayParameters parameters, float lifetime) {\n"; + code += " // Compile-time add textures.\n"; if (tex_parameters[PARAM_SCALE].is_valid()) { code += " parameters.scale *= texture(scale_curve, vec2(lifetime)).rgb;\n"; } @@ -586,7 +601,7 @@ void ParticleProcessMaterial::_update_shader() { code += " parameters.animation_speed *= texture(animation_speed_curve, vec2(lifetime)).r;\n"; } if (color_ramp.is_valid()) { - code += " parameters.color *= texture(color_ramp, vec2(lifetime));\n"; + code += " parameters.color *= texture(color_ramp, vec2(lifetime));\n"; } if (alpha_curve.is_valid()) { code += " parameters.color.a *= texture(alpha_curve, vec2(lifetime)).r;\n"; @@ -595,14 +610,14 @@ void ParticleProcessMaterial::_update_shader() { if (emission_curve.is_valid()) { code += " parameters.color.rgb *= 1.0 + texture(emission_curve, vec2(lifetime)).r;\n"; } - code += "}\n"; + code += "}\n\n"; code += "vec3 calculate_initial_position(inout uint alt_seed) {\n"; code += " float pi = 3.14159;\n"; - code += " float degree_to_rad = pi / 180.0;\n"; - code += " vec3 pos = vec3(0.);\n"; + code += " vec3 pos = vec3(0.0);\n"; + code += " { // Emission shape.\n"; if (emission_shape == EMISSION_SHAPE_POINT) { - code += " pos = vec3(0.);\n"; + code += " pos = vec3(0.0);\n"; } if (emission_shape == EMISSION_SHAPE_SPHERE) { code += " float s = rand_from_seed(alt_seed) * 2.0 - 1.0;\n"; @@ -628,7 +643,6 @@ void ParticleProcessMaterial::_update_shader() { code += " pos = texelFetch(emission_texture_points, emission_tex_ofs, 0).xyz;\n"; } if (emission_shape == EMISSION_SHAPE_RING) { - code += " \n"; code += " float ring_spawn_angle = rand_from_seed(alt_seed) * 2.0 * pi;\n"; code += " float ring_random_radius = sqrt(rand_from_seed(alt_seed) * (emission_ring_radius * emission_ring_radius - emission_ring_inner_radius * emission_ring_inner_radius) + emission_ring_inner_radius * emission_ring_inner_radius);\n"; code += " vec3 axis = emission_ring_axis == vec3(0.0) ? vec3(0.0, 0.0, 1.0) : normalize(emission_ring_axis);\n"; @@ -650,91 +664,86 @@ void ParticleProcessMaterial::_update_shader() { code += " ortho_axis = normalize(ortho_axis);\n"; code += " pos = ortho_axis * ring_random_radius + (rand_from_seed(alt_seed) * emission_ring_height - emission_ring_height / 2.0) * axis;\n"; } - + code += " }\n"; code += " return pos * emission_shape_scale + emission_shape_offset;\n"; - code += "}\n"; - code += "\n"; + code += "}\n\n"; + if (tex_parameters[PARAM_ORBIT_VELOCITY].is_valid() || particle_flags[PARTICLE_FLAG_DISABLE_Z]) { - code += "vec3 process_orbit_displacement(DynamicsParameters param, float lifetime, inout uint alt_seed, mat4 transform, mat4 emission_transform,float delta, float total_lifetime){\n"; + code += "vec3 process_orbit_displacement(DynamicsParameters param, float lifetime, inout uint alt_seed, mat4 transform, mat4 emission_transform, float delta, float total_lifetime) {\n"; // No reason to run all these expensive calculation below if we have no orbit velocity // HOWEVER // May be a bad idea for fps consistency? - code += "if(abs(param.orbit_velocity) < 0.01 || delta < 0.001){ return vec3(0.0);}\n"; - code += "\n"; - code += " vec3 displacement = vec3(0.);\n"; + code += " if (abs(param.orbit_velocity) < 0.01 || delta < 0.001) {\n"; + code += " return vec3(0.0);\n"; + code += " }\n"; + code += " vec3 displacement = vec3(0.0);\n"; code += " float pi = 3.14159;\n"; - code += " float degree_to_rad = pi / 180.0;\n"; if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { code += " float orbit_amount = param.orbit_velocity;\n"; - if (tex_parameters[PARAM_ORBIT_VELOCITY].is_valid()) { CurveTexture *texture = Object::cast_to<CurveTexture>(tex_parameters[PARAM_ORBIT_VELOCITY].ptr()); if (texture) { - code += " orbit_amount *= texture(orbit_velocity_curve, vec2(lifetime)).r;\n"; + code += " orbit_amount *= texture(orbit_velocity_curve, vec2(lifetime)).r;\n"; } else { - code += " orbit_amount *= texture(orbit_velocity_curve, vec2(lifetime)).b;\n"; + code += " orbit_amount *= texture(orbit_velocity_curve, vec2(lifetime)).b;\n"; } } code += " if (orbit_amount != 0.0) {\n"; - code += " vec3 pos = transform[3].xyz;\n"; - code += " vec3 org = emission_transform[3].xyz;\n"; - code += " vec3 diff = pos - org;\n"; - code += " float ang = orbit_amount * pi * 2.0 * delta;\n"; - code += " mat2 rot = mat2(vec2(cos(ang), -sin(ang)), vec2(sin(ang), cos(ang)));\n"; - code += " displacement.xy -= diff.xy;\n"; - code += " displacement.xy += rot * diff.xy;\n"; + code += " vec3 pos = transform[3].xyz;\n"; + code += " vec3 org = emission_transform[3].xyz;\n"; + code += " vec3 diff = pos - org;\n"; + code += " float ang = orbit_amount * pi * 2.0 * delta;\n"; + code += " mat2 rot = mat2(vec2(cos(ang), -sin(ang)), vec2(sin(ang), cos(ang)));\n"; + code += " displacement.xy -= diff.xy;\n"; + code += " displacement.xy += rot * diff.xy;\n"; code += " }\n"; } else { code += " vec3 orbit_velocities = vec3(param.orbit_velocity);\n"; - code += " orbit_velocities *= texture(orbit_velocity_curve, vec2(lifetime)).rgb;\n"; - + code += " orbit_velocities *= texture(orbit_velocity_curve, vec2(lifetime)).rgb;\n"; code += " orbit_velocities *= pi * 2.0;\n"; - code += " orbit_velocities *= delta; // we wanna process those by the delta angle\n"; - code += " //vec3 local_velocity_pivot = ((emission_transform) * vec4(velocity_pivot,1.0)).xyz;\n"; - code += " // X axis\n"; + code += " orbit_velocities *= delta; // We wanna process those by the delta angle.\n\n"; + + code += " // X axis.\n"; code += " vec3 local_pos = (inverse(emission_transform) * transform[3]).xyz;\n"; code += " local_pos -= velocity_pivot;\n"; - code += " local_pos.x = 0.;\n"; + code += " local_pos.x = 0.0;\n"; code += " mat3 x_rotation_mat = mat3(\n"; - code += " vec3(1.0,0.0,0.0),\n"; + code += " vec3(1.0, 0.0, 0.0),\n"; code += " vec3(0.0, cos(orbit_velocities.x), sin(orbit_velocities.x)),\n"; code += " vec3(0.0, -sin(orbit_velocities.x), cos(orbit_velocities.x))\n"; code += " );\n"; code += " vec3 new_pos = x_rotation_mat * local_pos;\n"; - code += " displacement = new_pos - local_pos;\n"; - code += "\n"; - code += " // Y axis\n"; + code += " displacement = new_pos - local_pos;\n\n"; + + code += " // Y axis.\n"; code += " local_pos = (inverse(emission_transform) * transform[3]).xyz;\n"; code += " local_pos -= velocity_pivot;\n"; - code += " local_pos.y = 0.;\n"; + code += " local_pos.y = 0.0;\n"; code += " mat3 y_rotation_mat = mat3(\n"; code += " vec3(cos(orbit_velocities.y), 0.0, -sin(orbit_velocities.y)),\n"; - code += " vec3(0.0, 1.0,0.0),\n"; + code += " vec3(0.0, 1.0, 0.0),\n"; code += " vec3(sin(orbit_velocities.y), 0.0, cos(orbit_velocities.y))\n"; code += " );\n"; code += " new_pos = y_rotation_mat * local_pos;\n"; - code += " displacement += new_pos - local_pos;\n"; - code += " // z axis\n"; - code += "\n"; + code += " displacement += new_pos - local_pos;\n\n"; + + code += " // Z axis.\n"; code += " local_pos = (inverse(emission_transform) * transform[3]).xyz;\n"; code += " local_pos -= velocity_pivot;\n"; - code += " local_pos.z = 0.;\n"; + code += " local_pos.z = 0.0;\n"; code += " mat3 z_rotation_mat = mat3(\n"; - code += " vec3(cos(orbit_velocities.z),sin(orbit_velocities.z),0.0),\n"; - code += " vec3(-sin(orbit_velocities.z),cos(orbit_velocities.z), 0.0),\n"; - code += " vec3(0.0,0.0,1.0)\n"; + code += " vec3(cos(orbit_velocities.z), sin(orbit_velocities.z), 0.0),\n"; + code += " vec3(-sin(orbit_velocities.z), cos(orbit_velocities.z), 0.0),\n"; + code += " vec3(0.0, 0.0, 1.0)\n"; code += " );\n"; code += " new_pos = z_rotation_mat * local_pos;\n"; - code += " displacement += new_pos - local_pos;\n"; - code += "\n"; + code += " displacement += new_pos - local_pos;\n\n"; } - code += " return (emission_transform * vec4(displacement/delta, 0.0)).xyz;\n"; - code += "}\n"; - code += "\n"; - code += "\n"; + code += " return (emission_transform * vec4(displacement / delta, 0.0)).xyz;\n"; + code += "}\n\n"; } - code += "vec3 get_random_direction_from_spread(inout uint alt_seed, float spread_angle){\n"; + code += "vec3 get_random_direction_from_spread(inout uint alt_seed, float spread_angle) {\n"; code += " float pi = 3.14159;\n"; code += " float degree_to_rad = pi / 180.0;\n"; code += " float spread_rad = spread_angle * degree_to_rad;\n"; @@ -750,13 +759,13 @@ void ParticleProcessMaterial::_update_shader() { code += " float angle2_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad * (1.0 - flatness);\n"; code += " vec3 direction_xz = vec3(sin(angle1_rad), 0.0, cos(angle1_rad));\n"; code += " vec3 direction_yz = vec3(0.0, sin(angle2_rad), cos(angle2_rad));\n"; - code += " direction_yz.z = direction_yz.z / max(0.0001,sqrt(abs(direction_yz.z))); // better uniform distribution\n"; + code += " direction_yz.z = direction_yz.z / max(0.0001, sqrt(abs(direction_yz.z))); // Better uniform distribution.\n"; code += " vec3 spread_direction = vec3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);\n"; code += " vec3 direction_nrm = length(direction) > 0.0 ? normalize(direction) : vec3(0.0, 0.0, 1.0);\n"; - code += " // rotate spread to direction\n"; + code += " // Rotate spread to direction.\n"; code += " vec3 binormal = cross(vec3(0.0, 1.0, 0.0), direction_nrm);\n"; code += " if (length(binormal) < 0.0001) {\n"; - code += " // direction is parallel to Y. Choose Z as the binormal.\n"; + code += " // Direction is parallel to Y. Choose Z as the binormal.\n"; code += " binormal = vec3(0.0, 0.0, 1.0);\n"; code += " }\n"; code += " binormal = normalize(binormal);\n"; @@ -764,43 +773,41 @@ void ParticleProcessMaterial::_update_shader() { code += " spread_direction = binormal * spread_direction.x + normal * spread_direction.y + direction_nrm * spread_direction.z;\n"; code += " return normalize(spread_direction);\n"; } - code += "}\n"; + code += "}\n\n"; - code += "vec3 process_radial_displacement(DynamicsParameters param, float lifetime, inout uint alt_seed, mat4 transform, mat4 emission_transform, float delta){\n"; + code += "vec3 process_radial_displacement(DynamicsParameters param, float lifetime, inout uint alt_seed, mat4 transform, mat4 emission_transform, float delta) {\n"; code += " vec3 radial_displacement = vec3(0.0);\n"; - code += " if (delta < 0.001){\n"; + code += " if (delta < 0.001) {\n"; code += " return radial_displacement;\n"; code += " }\n"; code += " float radial_displacement_multiplier = 1.0;\n"; if (tex_parameters[PARAM_RADIAL_VELOCITY].is_valid()) { - code += " radial_displacement_multiplier = texture(radial_velocity_curve, vec2(lifetime)).r;\n"; + code += " radial_displacement_multiplier = texture(radial_velocity_curve, vec2(lifetime)).r;\n"; } code += " vec3 global_pivot = (emission_transform * vec4(velocity_pivot, 1.0)).xyz;\n"; - code += " if(length(transform[3].xyz - global_pivot) > 0.01){\n"; + code += " if (length(transform[3].xyz - global_pivot) > 0.01) {\n"; code += " radial_displacement = normalize(transform[3].xyz - global_pivot) * radial_displacement_multiplier * param.radial_velocity;\n"; - code += " }else{radial_displacement = get_random_direction_from_spread(alt_seed, 360.0)* param.radial_velocity;} \n"; - code += " if (radial_displacement_multiplier * param.radial_velocity < 0.0){\n // Prevent inwards velocity to flicker once the point is reached."; - code += " if (length(radial_displacement) > 0.01){\n"; - code += " radial_displacement = normalize(radial_displacement) * min(abs((radial_displacement_multiplier * param.radial_velocity)), length(transform[3].xyz - global_pivot) / delta);\n"; - code += " }\n"; - code += " \n"; + code += " } else {\n"; + code += " radial_displacement = get_random_direction_from_spread(alt_seed, 360.0) * param.radial_velocity;\n"; + code += " }\n"; + code += " if (radial_displacement_multiplier * param.radial_velocity < 0.0) {\n"; + code += " // Prevent inwards velocity to flicker once the point is reached.\n"; + code += " radial_displacement = normalize(radial_displacement) * min(abs(radial_displacement_multiplier * param.radial_velocity), length(transform[3].xyz - global_pivot) / delta);\n"; + code += " }\n"; code += " return radial_displacement;\n"; - code += "}\n"; + code += "}\n\n"; + if (tex_parameters[PARAM_DIRECTIONAL_VELOCITY].is_valid()) { - code += "vec3 process_directional_displacement(DynamicsParameters param, float lifetime_percent,mat4 transform, mat4 emission_transform){\n"; - code += " vec3 displacement = vec3(0.);\n"; + code += "vec3 process_directional_displacement(DynamicsParameters param, float lifetime_percent, mat4 transform, mat4 emission_transform) {\n"; + code += " vec3 displacement = texture(directional_velocity_curve, vec2(lifetime_percent)).xyz * param.directional_velocity;\n"; if (directional_velocity_global) { - code += " displacement = texture(directional_velocity_curve, vec2(lifetime_percent)).xyz * param.directional_velocity;\n"; - code += " displacement = (emission_transform * vec4(displacement, 0.0)).xyz;\n"; - } else { - code += " displacement = texture(directional_velocity_curve, vec2(lifetime_percent)).xyz * param.directional_velocity;\n"; + code += " displacement = (emission_transform * vec4(displacement, 0.0)).xyz;\n"; } code += " return displacement;\n"; - code += "}\n"; + code += "}\n\n"; } - code += "\n"; - code += "void process_physical_parameters(inout PhysicalParameters params, float lifetime_percent){\n"; + code += "void process_physical_parameters(inout PhysicalParameters params, float lifetime_percent) {\n"; if (tex_parameters[PARAM_LINEAR_ACCEL].is_valid()) { code += " params.linear_accel *= texture(linear_accel_texture, vec2(lifetime_percent)).r;\n"; } @@ -813,35 +820,30 @@ void ParticleProcessMaterial::_update_shader() { if (tex_parameters[PARAM_DAMPING].is_valid()) { code += " params.damping *= texture(damping_texture, vec2(lifetime_percent)).r;\n"; } - code += " \n"; - code += "}\n"; - code += "\n"; + code += "}\n\n"; code += "void start() {\n"; code += " uint base_number = NUMBER;\n"; code += " uint alt_seed = hash(base_number + uint(1) + RANDOM_SEED);\n"; code += " DisplayParameters params;\n"; code += " calculate_initial_display_params(params, alt_seed);\n"; - code += " // reset alt seed?\n"; - code += " // alt_seed = hash(base_number + uint(1) + RANDOM_SEED);\n"; + code += " // Reset alt seed?\n"; + code += " //alt_seed = hash(base_number + uint(1) + RANDOM_SEED);\n"; code += " DynamicsParameters dynamic_params;\n"; code += " calculate_initial_dynamics_params(dynamic_params, alt_seed);\n"; code += " PhysicalParameters physics_params;\n"; code += " calculate_initial_physical_params(physics_params, alt_seed);\n"; - code += " process_display_param(params, 0.0);\n"; + code += " process_display_param(params, 0.0);\n"; code += " if (rand_from_seed(alt_seed) > AMOUNT_RATIO) {\n"; code += " ACTIVE = false;\n"; - code += " }\n"; - code += " \n"; - code += " float pi = 3.14159;\n"; - code += " float degree_to_rad = pi / 180.0;\n"; - code += " \n"; - code += " if (RESTART_CUSTOM){\n"; - code += " CUSTOM = vec4(0.);\n"; + code += " }\n\n"; + + code += " if (RESTART_CUSTOM) {\n"; + code += " CUSTOM = vec4(0.0);\n"; code += " CUSTOM.w = params.lifetime;\n"; code += " CUSTOM.x = dynamic_params.angle;\n"; code += " }\n"; - code += " if (RESTART_COLOR){\n"; + code += " if (RESTART_COLOR) {\n"; code += " COLOR = params.color;\n"; code += " }\n"; code += " if (RESTART_ROT_SCALE) {\n"; @@ -849,16 +851,15 @@ void ParticleProcessMaterial::_update_shader() { code += " TRANSFORM[1].xyz = vec3(0.0, 1.0, 0.0);\n"; code += " TRANSFORM[2].xyz = vec3(0.0, 0.0, 1.0);\n"; code += " }\n"; - code += "\n"; code += " if (RESTART_POSITION) {\n"; code += " TRANSFORM[3].xyz = calculate_initial_position(alt_seed);\n"; if (turbulence_enabled) { - code += " float initial_turbulence_displacement = mix(turbulence_initial_displacement_min, turbulence_initial_displacement_max, rand_from_seed(alt_seed));\n"; - code += " vec3 noise_direction = get_noise_direction(TRANSFORM[3].xyz);\n"; - code += " TRANSFORM[3].xyz += noise_direction * initial_turbulence_displacement;\n"; + code += " float initial_turbulence_displacement = mix(turbulence_initial_displacement_min, turbulence_initial_displacement_max, rand_from_seed(alt_seed));\n"; + code += " vec3 noise_direction = get_noise_direction(TRANSFORM[3].xyz);\n"; + code += " TRANSFORM[3].xyz += noise_direction * initial_turbulence_displacement;\n"; } code += " TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n"; - code += " }\n"; + code += " }\n"; code += " if (RESTART_VELOCITY) {\n"; code += " VELOCITY = get_random_direction_from_spread(alt_seed, spread) * dynamic_params.initial_velocity_multiplier;\n"; if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS) { @@ -867,7 +868,7 @@ void ParticleProcessMaterial::_update_shader() { code += " ivec2 emission_tex_ofs = ivec2(point % emission_tex_size.x, point / emission_tex_size.x);\n"; if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { code += " {\n"; - code += " mat2 rotm;"; + code += " mat2 rotm;\n"; code += " rotm[0] = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xy;\n"; code += " rotm[1] = rotm[0].yx * vec2(1.0, -1.0);\n"; code += " VELOCITY.xy = rotm * VELOCITY.xy;\n"; @@ -882,76 +883,66 @@ void ParticleProcessMaterial::_update_shader() { code += " }\n"; } } - code += " }\n"; - code += " process_display_param(params, 0.);\n"; - code += "// process_dynamic_parameters(dynamic_params, 0., alt_seed, TRANSFORM, EMISSION_TRANSFORM, DELTA);\n"; + code += " }\n\n"; + code += " process_display_param(params, 0.0);\n\n"; code += " VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY, 0.0)).xyz;\n"; code += " VELOCITY += EMITTER_VELOCITY * inherit_emitter_velocity_ratio;\n"; if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { - code += " VELOCITY.z = 0.;\n"; - code += " TRANSFORM[3].z = 0.;\n"; + code += " VELOCITY.z = 0.0;\n"; + code += " TRANSFORM[3].z = 0.0;\n"; } - code += "}\n"; - code += "\n"; + code += "}\n\n"; code += "void process() {\n"; code += " uint base_number = NUMBER;\n"; - // TODO add optional determinism here - code += "// if (repeatable){\n"; - code += "// base_number = INDEX;\n"; - code += "// }\n"; + // TODO: Add optional determinism here. + code += " //if (repeatable) {\n"; + code += " // base_number = INDEX;\n"; + code += " //}\n"; code += " uint alt_seed = hash(base_number + uint(1) + RANDOM_SEED);\n"; code += " DisplayParameters params;\n"; code += " calculate_initial_display_params(params, alt_seed);\n"; code += " DynamicsParameters dynamic_params;\n"; code += " calculate_initial_dynamics_params(dynamic_params, alt_seed);\n"; code += " PhysicalParameters physics_params;\n"; - code += " calculate_initial_physical_params(physics_params, alt_seed);\n"; + code += " calculate_initial_physical_params(physics_params, alt_seed);\n\n"; + code += " float pi = 3.14159;\n"; - code += " float degree_to_rad = pi / 180.0;\n"; - code += "\n"; + code += " float degree_to_rad = pi / 180.0;\n\n"; + code += " CUSTOM.y += DELTA / LIFETIME;\n"; code += " CUSTOM.y = mix(CUSTOM.y, 1.0, INTERPOLATE_TO_END);\n"; - code += " float lifetime_percent = CUSTOM.y/ params.lifetime;\n"; + code += " float lifetime_percent = CUSTOM.y / params.lifetime;\n"; code += " if (CUSTOM.y > CUSTOM.w) {\n"; code += " ACTIVE = false;\n"; - code += " }\n"; - code += " \n"; - code += " \n"; - code += " \n"; - code += " // will use this later to calculate final displacement and orient the particle.\n"; - code += " vec3 starting_position = TRANSFORM[3].xyz;\n"; + code += " }\n\n"; + + code += " // Calculate all velocity.\n"; code += " vec3 controlled_displacement = vec3(0.0);\n"; - code += " \n"; - code += "// VELOCITY += process_physics_parameters(dynamic_params, lifetime_percent, alt_seed, TRANSFORM, EMISSION_TRANSFORM, DELTA);\n"; - code += " \n"; if (tex_parameters[PARAM_ORBIT_VELOCITY].is_valid() || particle_flags[PARTICLE_FLAG_DISABLE_Z]) { code += " controlled_displacement += process_orbit_displacement(dynamic_params, lifetime_percent, alt_seed, TRANSFORM, EMISSION_TRANSFORM, DELTA, params.lifetime * LIFETIME);\n"; } - code += " // calculate all velocity\n"; - code += " \n"; code += " controlled_displacement += process_radial_displacement(dynamic_params, lifetime_percent, alt_seed, TRANSFORM, EMISSION_TRANSFORM, DELTA);\n"; - code += " \n"; if (tex_parameters[PARAM_DIRECTIONAL_VELOCITY].is_valid()) { code += " controlled_displacement += process_directional_displacement(dynamic_params, lifetime_percent, TRANSFORM, EMISSION_TRANSFORM);\n"; } - code += " \n"; + code += "\n"; code += " process_physical_parameters(physics_params, lifetime_percent);\n"; code += " vec3 force;\n"; code += " {\n"; - code += " // copied from previous version\n"; + code += " // Copied from previous version.\n"; code += " vec3 pos = TRANSFORM[3].xyz;\n"; code += " force = gravity;\n"; - code += " // apply linear acceleration\n"; + code += " // Apply linear acceleration.\n"; code += " force += length(VELOCITY) > 0.0 ? normalize(VELOCITY) * physics_params.linear_accel : vec3(0.0);\n"; - code += " // apply radial acceleration\n"; + code += " // Apply radial acceleration.\n"; code += " vec3 org = EMISSION_TRANSFORM[3].xyz;\n"; code += " vec3 diff = pos - org;\n"; code += " force += length(diff) > 0.0 ? normalize(diff) * physics_params.radial_accel : vec3(0.0);\n"; - code += " // apply tangential acceleration;\n"; + code += " // Apply tangential acceleration.\n"; code += " float tangent_accel_val = physics_params.tangent_accel;\n"; if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { - code += " force += length(diff.yx) > 0.0 ? vec3(normalize(diff.yx * vec2(-1.0, 1.0)), 0.0) * tangent_accel_val : vec3(0.0);\n"; + code += " force += length(diff.yx) > 0.0 ? vec3(normalize(diff.yx * vec2(-1.0, 1.0)), 0.0) * tangent_accel_val : vec3(0.0);\n"; } else { code += " vec3 crossDiff = cross(normalize(diff), normalize(gravity));\n"; code += " force += length(crossDiff) > 0.0 ? normalize(crossDiff) * tangent_accel_val : vec3(0.0);\n"; @@ -959,107 +950,103 @@ void ParticleProcessMaterial::_update_shader() { if (attractor_interaction_enabled) { code += " force += ATTRACTOR_FORCE;\n"; } - code += "\n"; - code += " // apply attractor forces\n"; if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { - code += " force.z = 0.;\n"; + code += " force.z = 0.0;\n"; } + code += " // Apply attractor forces.\n"; code += " VELOCITY += force * DELTA;\n"; code += " }\n"; code += " {\n"; - code += " // copied from previous version\n"; + code += " // Copied from previous version.\n"; code += " if (physics_params.damping > 0.0) {\n"; code += " float v = length(VELOCITY);\n"; if (!particle_flags[PARTICLE_FLAG_DAMPING_AS_FRICTION]) { code += " v -= physics_params.damping * DELTA;\n"; } else { code += " if (v > 0.001) {\n"; - code += " // Realistic friction formula. We assume the mass of a particle to be 0.05kg.\n"; + code += " // Realistic friction formula. We assume the mass of a particle to be 0.05 kg.\n"; code += " float damp = v * v * physics_params.damping * 0.05 * DELTA;\n"; code += " v -= damp;\n"; code += " }\n"; } - code += " if (v < 0.0) {\n"; code += " VELOCITY = vec3(0.0);\n"; code += " } else {\n"; code += " VELOCITY = normalize(VELOCITY) * v;\n"; code += " }\n"; code += " }\n"; - code += " \n"; - code += " }\n"; - code += " \n"; + code += " }\n\n"; + if (collision_mode == COLLISION_RIGID) { code += " if (COLLIDED) {\n"; code += " float collision_response = dot(COLLISION_NORMAL, VELOCITY);\n"; - code += " float slide_to_bounce_trigger = step(2.0/clamp(collision_bounce + 1.0, 1.0, 2.0), abs(collision_response));\n"; + code += " float slide_to_bounce_trigger = step(2.0 / clamp(collision_bounce + 1.0, 1.0, 2.0), abs(collision_response));\n"; code += " TRANSFORM[3].xyz += COLLISION_NORMAL * COLLISION_DEPTH;\n"; - code += " // Remove all components of VELOCITY that is not tangent to COLLISION_NORMAL\n"; + code += " // Remove all components of VELOCITY that are not tangential to COLLISION_NORMAL.\n"; code += " VELOCITY -= COLLISION_NORMAL * collision_response;\n"; - code += " // Apply friction only to VELOCITY across the surface (Effectively decouples friction and bounce behavior).\n"; - code += " VELOCITY = mix(VELOCITY,vec3(0.0),clamp(collision_friction, 0.0, 1.0));\n"; - code += " // Add bounce velocity to VELOCITY\n"; + code += " // Apply friction only to VELOCITY across the surface (effectively decouples friction and bounce behavior).\n"; + code += " VELOCITY = mix(VELOCITY, vec3(0.0), clamp(collision_friction, 0.0, 1.0));\n"; + code += " // Add bounce velocity to VELOCITY.\n"; code += " VELOCITY -= COLLISION_NORMAL * collision_response * (collision_bounce * slide_to_bounce_trigger);\n"; - code += " }\n"; + code += " }\n\n"; } else if (collision_mode == COLLISION_HIDE_ON_CONTACT) { code += " if (COLLIDED) {\n"; code += " ACTIVE = false;\n"; - code += " }\n"; + code += " }\n\n"; } - code += " \n"; - code += " // turbulence before limiting\n"; + + code += " // Turbulence before limiting.\n"; if (turbulence_enabled) { if (tex_parameters[PARAM_TURB_INFLUENCE_OVER_LIFE].is_valid()) { - code += " float turbulence_influence = textureLod(turbulence_influence_over_life, vec2(lifetime_percent, 0.0), 0.0).r;\n"; + code += " float turbulence_influence = textureLod(turbulence_influence_over_life, vec2(lifetime_percent, 0.0), 0.0).r;\n"; } else { - code += " float turbulence_influence = 1.0;\n"; + code += " float turbulence_influence = 1.0;\n"; } - code += " \n"; - code += " vec3 noise_direction = get_noise_direction(TRANSFORM[3].xyz);\n"; + code += "\n"; + code += " vec3 noise_direction = get_noise_direction(TRANSFORM[3].xyz);\n"; // Godot detects when the COLLIDED keyword is used. If it's used anywhere in the shader then Godot will generate the screen space SDF for collisions. // We don't need it as long as collision is disabled. Refer to GH-83744 for more info. if (collision_mode == COLLISION_RIGID) { - code += " if (!COLLIDED) {\n"; - } - code += " float vel_mag = length(VELOCITY);\n"; - code += " float vel_infl = clamp(dynamic_params.turb_influence * turbulence_influence, 0.0,1.0);\n"; - code += " VELOCITY = mix(VELOCITY, normalize(noise_direction) * vel_mag * (1.0 + (1.0 - vel_infl) * 0.2), vel_infl);\n"; - code += " vel_mag = length(controlled_displacement);\n"; - code += " controlled_displacement = mix(controlled_displacement, normalize(noise_direction) * vel_mag * (1.0 + (1.0 - vel_infl) * 0.2), vel_infl);\n"; - if (collision_mode == COLLISION_RIGID) { - code += " }\n"; + code += " if (!COLLIDED) {\n"; + } else { + code += " {\n"; } + code += " float vel_mag = length(VELOCITY);\n"; + code += " float vel_infl = clamp(dynamic_params.turb_influence * turbulence_influence, 0.0, 1.0);\n"; + code += " VELOCITY = mix(VELOCITY, normalize(noise_direction) * vel_mag * (1.0 + (1.0 - vel_infl) * 0.2), vel_infl);\n"; + code += " vel_mag = length(controlled_displacement);\n"; + code += " controlled_displacement = mix(controlled_displacement, normalize(noise_direction) * vel_mag * (1.0 + (1.0 - vel_infl) * 0.2), vel_infl);\n"; + code += " }\n"; } - code += " vec3 final_velocity = controlled_displacement + VELOCITY;\n"; - code += " \n"; - code += " // limit velocity\n"; + code += " vec3 final_velocity = controlled_displacement + VELOCITY;\n\n"; + if (velocity_limit_curve.is_valid()) { - code += " if (length(final_velocity) > 0.001){\n"; + code += " // Limit velocity.\n"; + code += " if (length(final_velocity) > 0.001) {\n"; code += " final_velocity = normalize(final_velocity) * min(abs(length(final_velocity)), abs(texture(velocity_limit_curve, vec2(lifetime_percent)).r));\n"; - code += " }\n"; + code += " }\n\n"; } - code += " \n"; + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { - code += " final_velocity.z = 0.;\n"; + code += " final_velocity.z = 0.0;\n\n"; } - code += " TRANSFORM[3].xyz += final_velocity * DELTA;\n"; - code += " \n"; - code += " \n"; - code += " process_display_param(params, lifetime_percent);\n"; - code += " \n"; + + code += " TRANSFORM[3].xyz += final_velocity * DELTA;\n\n"; + + code += " process_display_param(params, lifetime_percent);\n\n"; + code += " float base_angle = dynamic_params.angle;\n"; if (tex_parameters[PARAM_ANGLE].is_valid()) { code += " base_angle *= texture(angle_texture, vec2(lifetime_percent)).r;\n"; } if (tex_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) { code += " base_angle += CUSTOM.y * LIFETIME * dynamic_params.angular_velocity * texture(angular_velocity_texture, vec2(lifetime_percent)).r;\n"; - } else { code += " base_angle += CUSTOM.y * LIFETIME * dynamic_params.angular_velocity;\n"; } code += " CUSTOM.x = base_angle * degree_to_rad;\n"; - code += " COLOR = params.color;\n"; + code += " COLOR = params.color;\n\n"; if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { if (particle_flags[PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY]) { @@ -1075,9 +1062,8 @@ void ParticleProcessMaterial::_update_shader() { code += " TRANSFORM[1] = vec4(sin(CUSTOM.x), cos(CUSTOM.x), 0.0, 0.0);\n"; code += " TRANSFORM[2] = vec4(0.0, 0.0, 1.0, 0.0);\n"; } - } else { - // orient particle Y towards velocity + // Orient particle Y towards velocity. if (particle_flags[PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY]) { code += " if (length(final_velocity) > 0.0) {\n"; code += " TRANSFORM[1].xyz = normalize(final_velocity);\n"; @@ -1096,42 +1082,44 @@ void ParticleProcessMaterial::_update_shader() { code += " TRANSFORM[1].xyz = normalize(TRANSFORM[1].xyz);\n"; code += " TRANSFORM[2].xyz = normalize(TRANSFORM[2].xyz);\n"; } - // turn particle by rotation in Y + // Turn particle by rotation in Y. if (particle_flags[PARTICLE_FLAG_ROTATE_Y]) { code += " vec4 origin = TRANSFORM[3];\n"; code += " TRANSFORM = mat4(vec4(cos(CUSTOM.x), 0.0, -sin(CUSTOM.x), 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(sin(CUSTOM.x), 0.0, cos(CUSTOM.x), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n"; code += " TRANSFORM[3] = origin;\n"; } } - if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { - code += " TRANSFORM[3].z = 0.0;\n"; + code += " TRANSFORM[3].z = 0.0;\n\n"; } + if (tex_parameters[PARAM_SCALE_OVER_VELOCITY].is_valid()) { - code += " if(length(final_velocity) > 0.001){\n"; - code += " params.scale *= texture(scale_over_velocity_curve, vec2(clamp(length(final_velocity)/(scale_over_velocity_max - scale_over_velocity_min), 0.0,1.0), 0.0)).rgb;\n"; - code += " } else {params.scale *= texture(scale_over_velocity_curve, vec2(0.0)).rgb;}\n \n"; + code += " if (length(final_velocity) > 0.001) {\n"; + code += " params.scale *= texture(scale_over_velocity_curve, vec2(clamp(length(final_velocity) / (scale_over_velocity_max - scale_over_velocity_min), 0.0, 1.0), 0.0)).rgb;\n"; + code += " } else {\n"; + code += " params.scale *= texture(scale_over_velocity_curve, vec2(0.0)).rgb;\n"; + code += " }\n"; } - code += "// params.scale *= length(final_velocity)/100.0;\n"; - code += "\n"; code += " TRANSFORM[0].xyz *= sign(params.scale.x) * max(abs(params.scale.x), 0.001);\n"; code += " TRANSFORM[1].xyz *= sign(params.scale.y) * max(abs(params.scale.y), 0.001);\n"; code += " TRANSFORM[2].xyz *= sign(params.scale.z) * max(abs(params.scale.z), 0.001);\n"; - code += " \n"; - code += " // \n"; - code += " CUSTOM.z = params.animation_offset + lifetime_percent * params.animation_speed;\n"; - code += " \n"; + code += "\n"; + code += " CUSTOM.z = params.animation_offset + lifetime_percent * params.animation_speed;\n\n"; if (sub_emitter_mode != SUB_EMITTER_DISABLED && !RenderingServer::get_singleton()->is_low_end()) { code += " int emit_count = 0;\n"; switch (sub_emitter_mode) { case SUB_EMITTER_CONSTANT: { code += " float interval_from = CUSTOM.y * LIFETIME - DELTA;\n"; - code += " float interval_rem = sub_emitter_frequency - mod(interval_from,sub_emitter_frequency);\n"; - code += " if (DELTA >= interval_rem) emit_count = 1;\n"; + code += " float interval_rem = sub_emitter_frequency - mod(interval_from, sub_emitter_frequency);\n"; + code += " if (DELTA >= interval_rem) {\n"; + code += " emit_count = 1;\n"; + code += " }\n"; } break; case SUB_EMITTER_AT_COLLISION: { - code += " if (COLLIDED) emit_count = sub_emitter_amount_at_collision;\n"; + code += " if (COLLIDED) {\n"; + code += " emit_count = sub_emitter_amount_at_collision;\n"; + code += " }\n"; } break; case SUB_EMITTER_AT_END: { code += " if ((CUSTOM.y / CUSTOM.w * LIFETIME) > (LIFETIME - DELTA)) {\n"; @@ -1141,18 +1129,19 @@ void ParticleProcessMaterial::_update_shader() { default: { } } - code += " for(int i=0;i<emit_count;i++) {\n"; - code += " uint flags = FLAG_EMIT_POSITION|FLAG_EMIT_ROT_SCALE;\n"; - code += " if (sub_emitter_keep_velocity) flags|=FLAG_EMIT_VELOCITY;\n"; - code += " emit_subparticle(TRANSFORM,VELOCITY,vec4(0.0),vec4(0.0),flags);\n"; - code += " }"; + code += " for (int i = 0; i < emit_count; i++) {\n"; + code += " uint flags = FLAG_EMIT_POSITION | FLAG_EMIT_ROT_SCALE;\n"; + code += " if (sub_emitter_keep_velocity) {\n"; + code += " flags |= FLAG_EMIT_VELOCITY;\n"; + code += " }\n"; + code += " emit_subparticle(TRANSFORM, VELOCITY, vec4(0.0), vec4(0.0), flags);\n"; + code += " }\n\n"; } code += " if (CUSTOM.y > CUSTOM.w) {\n"; code += " ACTIVE = false;\n"; code += " }\n"; code += "}\n"; - code += "\n"; ShaderData shader_data; shader_data.shader = RS::get_singleton()->shader_create(); diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 2e27ac9198..7c13e623c2 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -33,9 +33,7 @@ #include "core/config/project_settings.h" #include "core/io/dir_access.h" #include "core/io/missing_resource.h" -#include "core/io/resource_format_binary.h" #include "core/object/script_language.h" -#include "core/version.h" // Version 2: Changed names for Basis, AABB, Vectors, etc. // Version 3: New string ID for ext/subresources, breaks forward compat. @@ -44,11 +42,6 @@ // For compat, save as version 3 if not using PackedVector4Array or no big PackedByteArray. #define FORMAT_VERSION_COMPAT 3 -#define BINARY_FORMAT_VERSION 4 - -#include "core/io/dir_access.h" -#include "core/version.h" - #define _printerr() ERR_PRINT(String(res_path + ":" + itos(lines) + " - Parse Error: " + error_text).utf8().get_data()); /// @@ -1127,298 +1120,6 @@ void ResourceLoaderText::open(Ref<FileAccess> p_f, bool p_skip_first_tag) { rp.userdata = this; } -static void bs_save_unicode_string(Ref<FileAccess> p_f, const String &p_string, bool p_bit_on_len = false) { - CharString utf8 = p_string.utf8(); - if (p_bit_on_len) { - p_f->store_32((utf8.length() + 1) | 0x80000000); - } else { - p_f->store_32(utf8.length() + 1); - } - p_f->store_buffer((const uint8_t *)utf8.get_data(), utf8.length() + 1); -} - -Error ResourceLoaderText::save_as_binary(const String &p_path) { - if (error) { - return error; - } - - Ref<FileAccess> wf = FileAccess::open(p_path, FileAccess::WRITE); - if (wf.is_null()) { - return ERR_CANT_OPEN; - } - - //save header compressed - static const uint8_t header[4] = { 'R', 'S', 'R', 'C' }; - wf->store_buffer(header, 4); - - wf->store_32(0); //endianness, little endian - wf->store_32(0); //64 bits file, false for now - wf->store_32(VERSION_MAJOR); - wf->store_32(VERSION_MINOR); - static const int save_format_version = BINARY_FORMAT_VERSION; - wf->store_32(save_format_version); - - bs_save_unicode_string(wf, is_scene ? "PackedScene" : resource_type); - wf->store_64(0); //offset to import metadata, this is no longer used - - wf->store_32(ResourceFormatSaverBinaryInstance::FORMAT_FLAG_NAMED_SCENE_IDS | ResourceFormatSaverBinaryInstance::FORMAT_FLAG_UIDS); - - wf->store_64(res_uid); - - for (int i = 0; i < ResourceFormatSaverBinaryInstance::RESERVED_FIELDS; i++) { - wf->store_32(0); // reserved - } - - wf->store_32(0); //string table size, will not be in use - uint64_t ext_res_count_pos = wf->get_position(); - - wf->store_32(0); //zero ext resources, still parsing them - - //go with external resources - - DummyReadData dummy_read; - VariantParser::ResourceParser rp_new; - rp_new.ext_func = _parse_ext_resource_dummys; - rp_new.sub_func = _parse_sub_resource_dummys; - rp_new.userdata = &dummy_read; - - while (next_tag.name == "ext_resource") { - if (!next_tag.fields.has("path")) { - error = ERR_FILE_CORRUPT; - error_text = "Missing 'path' in external resource tag"; - _printerr(); - return error; - } - - if (!next_tag.fields.has("type")) { - error = ERR_FILE_CORRUPT; - error_text = "Missing 'type' in external resource tag"; - _printerr(); - return error; - } - - if (!next_tag.fields.has("id")) { - error = ERR_FILE_CORRUPT; - error_text = "Missing 'id' in external resource tag"; - _printerr(); - return error; - } - - String path = next_tag.fields["path"]; - String type = next_tag.fields["type"]; - String id = next_tag.fields["id"]; - ResourceUID::ID uid = ResourceUID::INVALID_ID; - if (next_tag.fields.has("uid")) { - String uidt = next_tag.fields["uid"]; - uid = ResourceUID::get_singleton()->text_to_id(uidt); - } - - bs_save_unicode_string(wf, type); - bs_save_unicode_string(wf, path); - wf->store_64(uid); - - int lindex = dummy_read.external_resources.size(); - Ref<DummyResource> dr; - dr.instantiate(); - dr->set_path("res://dummy" + itos(lindex)); //anything is good to detect it for saving as external - dummy_read.external_resources[dr] = lindex; - dummy_read.rev_external_resources[id] = dr; - - error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp_new); - - if (error) { - _printerr(); - return error; - } - } - - // save external resource table - wf->seek(ext_res_count_pos); - wf->store_32(dummy_read.external_resources.size()); - wf->seek_end(); - - //now, save resources to a separate file, for now - - uint64_t sub_res_count_pos = wf->get_position(); - wf->store_32(0); //zero sub resources, still parsing them - - String temp_file = p_path + ".temp"; - Vector<uint64_t> local_offsets; - Vector<uint64_t> local_pointers_pos; - { - Ref<FileAccess> wf2 = FileAccess::open(temp_file, FileAccess::WRITE); - if (wf2.is_null()) { - return ERR_CANT_OPEN; - } - - while (next_tag.name == "sub_resource" || next_tag.name == "resource") { - String type; - String id; - bool main_res; - - if (next_tag.name == "sub_resource") { - if (!next_tag.fields.has("type")) { - error = ERR_FILE_CORRUPT; - error_text = "Missing 'type' in external resource tag"; - _printerr(); - return error; - } - - if (!next_tag.fields.has("id")) { - error = ERR_FILE_CORRUPT; - error_text = "Missing 'id' in external resource tag"; - _printerr(); - return error; - } - - type = next_tag.fields["type"]; - id = next_tag.fields["id"]; - main_res = false; - - if (!dummy_read.resource_map.has(id)) { - Ref<DummyResource> dr; - dr.instantiate(); - dr->set_scene_unique_id(id); - dummy_read.resource_map[id] = dr; - uint32_t im_size = dummy_read.resource_index_map.size(); - dummy_read.resource_index_map.insert(dr, im_size); - } - - } else { - type = res_type; - String uid_text = ResourceUID::get_singleton()->id_to_text(res_uid); - id = type + "_" + uid_text.replace("uid://", "").replace("<invalid>", "0"); - main_res = true; - } - - local_offsets.push_back(wf2->get_position()); - - bs_save_unicode_string(wf, "local://" + id); - local_pointers_pos.push_back(wf->get_position()); - wf->store_64(0); //temp local offset - - bs_save_unicode_string(wf2, type); - uint64_t propcount_ofs = wf2->get_position(); - wf2->store_32(0); - - int prop_count = 0; - - while (true) { - String assign; - Variant value; - - error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp_new); - - if (error) { - if (main_res && error == ERR_FILE_EOF) { - next_tag.name = ""; //exit - break; - } - - _printerr(); - return error; - } - - if (!assign.is_empty()) { - HashMap<StringName, int> empty_string_map; //unused - bs_save_unicode_string(wf2, assign, true); - ResourceFormatSaverBinaryInstance::write_variant(wf2, value, dummy_read.resource_index_map, dummy_read.external_resources, empty_string_map); - prop_count++; - - } else if (!next_tag.name.is_empty()) { - error = OK; - break; - } else { - error = ERR_FILE_CORRUPT; - error_text = "Premature end of file while parsing [sub_resource]"; - _printerr(); - return error; - } - } - - wf2->seek(propcount_ofs); - wf2->store_32(prop_count); - wf2->seek_end(); - } - - if (next_tag.name == "node") { - // This is a node, must save one more! - - if (!is_scene) { - error_text += "found the 'node' tag on a resource file!"; - _printerr(); - error = ERR_FILE_CORRUPT; - return error; - } - - Ref<PackedScene> packed_scene = _parse_node_tag(rp_new); - - if (!packed_scene.is_valid()) { - return error; - } - - error = OK; - //get it here - List<PropertyInfo> props; - packed_scene->get_property_list(&props); - - String id = "PackedScene_" + ResourceUID::get_singleton()->id_to_text(res_uid).replace("uid://", "").replace("<invalid>", "0"); - bs_save_unicode_string(wf, "local://" + id); - local_pointers_pos.push_back(wf->get_position()); - wf->store_64(0); //temp local offset - - local_offsets.push_back(wf2->get_position()); - bs_save_unicode_string(wf2, "PackedScene"); - uint64_t propcount_ofs = wf2->get_position(); - wf2->store_32(0); - - int prop_count = 0; - - for (const PropertyInfo &E : props) { - if (!(E.usage & PROPERTY_USAGE_STORAGE)) { - continue; - } - - String name = E.name; - Variant value = packed_scene->get(name); - - HashMap<StringName, int> empty_string_map; //unused - bs_save_unicode_string(wf2, name, true); - ResourceFormatSaverBinaryInstance::write_variant(wf2, value, dummy_read.resource_index_map, dummy_read.external_resources, empty_string_map); - prop_count++; - } - - wf2->seek(propcount_ofs); - wf2->store_32(prop_count); - wf2->seek_end(); - } - } - - uint64_t offset_from = wf->get_position(); - wf->seek(sub_res_count_pos); //plus one because the saved one - wf->store_32(local_offsets.size()); - - for (int i = 0; i < local_offsets.size(); i++) { - wf->seek(local_pointers_pos[i]); - wf->store_64(local_offsets[i] + offset_from); - } - - wf->seek_end(); - - Vector<uint8_t> data = FileAccess::get_file_as_bytes(temp_file); - wf->store_buffer(data.ptr(), data.size()); - { - Ref<DirAccess> dar = DirAccess::open(temp_file.get_base_dir()); - ERR_FAIL_COND_V(dar.is_null(), FAILED); - - dar->remove(temp_file); - } - - wf->store_buffer((const uint8_t *)"RSRC", 4); //magic at end - - return OK; -} - Error ResourceLoaderText::get_classes_used(HashSet<StringName> *r_classes) { if (error) { return error; @@ -1835,29 +1536,6 @@ Error ResourceFormatLoaderText::rename_dependencies(const String &p_path, const ResourceFormatLoaderText *ResourceFormatLoaderText::singleton = nullptr; -Error ResourceFormatLoaderText::convert_file_to_binary(const String &p_src_path, const String &p_dst_path) { - Error err; - Ref<FileAccess> f = FileAccess::open(p_src_path, FileAccess::READ, &err); - - ERR_FAIL_COND_V_MSG(err != OK, ERR_CANT_OPEN, "Cannot open file '" + p_src_path + "'."); - - ResourceLoaderText loader; - const String &path = p_src_path; - loader.local_path = ProjectSettings::get_singleton()->localize_path(path); - loader.res_path = loader.local_path; - loader.open(f); - return loader.save_as_binary(p_dst_path); -} - -/*****************************************************************************************************/ -/*****************************************************************************************************/ -/*****************************************************************************************************/ -/*****************************************************************************************************/ -/*****************************************************************************************************/ -/*****************************************************************************************************/ -/*****************************************************************************************************/ -/*****************************************************************************************************/ -/*****************************************************************************************************/ /*****************************************************************************************************/ String ResourceFormatSaverTextInstance::_write_resources(void *ud, const Ref<Resource> &p_resource) { diff --git a/scene/resources/resource_format_text.h b/scene/resources/resource_format_text.h index 41363fd975..b5542f77ba 100644 --- a/scene/resources/resource_format_text.h +++ b/scene/resources/resource_format_text.h @@ -87,11 +87,6 @@ class ResourceLoaderText { Error _parse_sub_resource(VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str); Error _parse_ext_resource(VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str); - // for converter - class DummyResource : public Resource { - public: - }; - struct DummyReadData { bool no_placeholders = false; HashMap<Ref<Resource>, int> external_resources; @@ -133,7 +128,6 @@ public: Error rename_dependencies(Ref<FileAccess> p_f, const String &p_path, const HashMap<String, String> &p_map); Error get_classes_used(HashSet<StringName> *r_classes); - Error save_as_binary(const String &p_path); ResourceLoaderText(); }; @@ -152,8 +146,6 @@ public: virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false) override; virtual Error rename_dependencies(const String &p_path, const HashMap<String, String> &p_map) override; - static Error convert_file_to_binary(const String &p_src_path, const String &p_dst_path); - ResourceFormatLoaderText() { singleton = this; } }; diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp index 2ee27c95e1..c6a2151de5 100644 --- a/scene/scene_string_names.cpp +++ b/scene/scene_string_names.cpp @@ -123,10 +123,12 @@ SceneStringNames::SceneStringNames() { window_input = StaticCString::create("window_input"); theme_changed = StaticCString::create("theme_changed"); - parameters_base_path = "parameters/"; shader_overrides_group = StaticCString::create("_shader_overrides_group_"); shader_overrides_group_active = StaticCString::create("_shader_overrides_group_active_"); pressed = StaticCString::create("pressed"); + id_pressed = StaticCString::create("id_pressed"); + + panel = StaticCString::create("panel"); } diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h index 7ed86cde46..9af5422391 100644 --- a/scene/scene_string_names.h +++ b/scene/scene_string_names.h @@ -134,7 +134,6 @@ public: StringName Master; - StringName parameters_base_path; StringName window_input; StringName theme_changed; @@ -142,6 +141,9 @@ public: StringName shader_overrides_group_active; StringName pressed; + StringName id_pressed; + + StringName panel; }; #define SceneStringName(m_name) SceneStringNames::get_singleton()->m_name diff --git a/scene/theme/default_theme.cpp b/scene/theme/default_theme.cpp index aa4d669238..6d187bbd64 100644 --- a/scene/theme/default_theme.cpp +++ b/scene/theme/default_theme.cpp @@ -147,7 +147,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const } // Panel - theme->set_stylebox("panel", "Panel", make_flat_stylebox(style_normal_color, 0, 0, 0, 0)); + theme->set_stylebox(SceneStringName(panel), "Panel", make_flat_stylebox(style_normal_color, 0, 0, 0, 0)); // Button @@ -159,7 +159,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // Make the focus outline appear to be flush with the buttons it's focusing. focus->set_expand_margin_all(Math::round(2 * scale)); - theme->set_stylebox("normal", "Button", button_normal); + theme->set_stylebox(CoreStringName(normal), "Button", button_normal); theme->set_stylebox("hover", "Button", button_hover); theme->set_stylebox(SceneStringName(pressed), "Button", button_pressed); theme->set_stylebox("disabled", "Button", button_disabled); @@ -188,7 +188,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("icon_max_width", "Button", 0); // MenuBar - theme->set_stylebox("normal", "MenuBar", button_normal); + theme->set_stylebox(CoreStringName(normal), "MenuBar", button_normal); theme->set_stylebox("hover", "MenuBar", button_hover); theme->set_stylebox(SceneStringName(pressed), "MenuBar", button_pressed); theme->set_stylebox("disabled", "MenuBar", button_disabled); @@ -231,7 +231,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<StyleBox> sb_optbutton_pressed = make_flat_stylebox(style_pressed_color, 2 * default_margin, default_margin, 2 * default_margin, default_margin); Ref<StyleBox> sb_optbutton_disabled = make_flat_stylebox(style_disabled_color, 2 * default_margin, default_margin, 2 * default_margin, default_margin); - theme->set_stylebox("normal", "OptionButton", sb_optbutton_normal); + theme->set_stylebox(CoreStringName(normal), "OptionButton", sb_optbutton_normal); theme->set_stylebox("hover", "OptionButton", sb_optbutton_hover); theme->set_stylebox(SceneStringName(pressed), "OptionButton", sb_optbutton_pressed); theme->set_stylebox("disabled", "OptionButton", sb_optbutton_disabled); @@ -266,7 +266,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // MenuButton - theme->set_stylebox("normal", "MenuButton", button_normal); + theme->set_stylebox(CoreStringName(normal), "MenuButton", button_normal); theme->set_stylebox(SceneStringName(pressed), "MenuButton", button_pressed); theme->set_stylebox("hover", "MenuButton", button_hover); theme->set_stylebox("disabled", "MenuButton", button_disabled); @@ -292,7 +292,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<StyleBox> cbx_focus = focus; cbx_focus->set_content_margin_all(Math::round(4 * scale)); - theme->set_stylebox("normal", "CheckBox", cbx_empty); + theme->set_stylebox(CoreStringName(normal), "CheckBox", cbx_empty); theme->set_stylebox(SceneStringName(pressed), "CheckBox", cbx_empty); theme->set_stylebox("disabled", "CheckBox", cbx_empty); theme->set_stylebox("hover", "CheckBox", cbx_empty); @@ -328,7 +328,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<StyleBox> cb_empty = memnew(StyleBoxEmpty); cb_empty->set_content_margin_individual(Math::round(6 * scale), Math::round(4 * scale), Math::round(6 * scale), Math::round(4 * scale)); - theme->set_stylebox("normal", "CheckButton", cb_empty); + theme->set_stylebox(CoreStringName(normal), "CheckButton", cb_empty); theme->set_stylebox(SceneStringName(pressed), "CheckButton", cb_empty); theme->set_stylebox("disabled", "CheckButton", cb_empty); theme->set_stylebox("hover", "CheckButton", cb_empty); @@ -372,19 +372,19 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<StyleBoxFlat> flat_button_pressed = button_pressed->duplicate(); flat_button_pressed->set_bg_color(style_pressed_color * Color(1, 1, 1, 0.85)); - theme->set_stylebox("normal", "FlatButton", flat_button_normal); + theme->set_stylebox(CoreStringName(normal), "FlatButton", flat_button_normal); theme->set_stylebox("hover", "FlatButton", flat_button_normal); theme->set_stylebox(SceneStringName(pressed), "FlatButton", flat_button_pressed); theme->set_stylebox("disabled", "FlatButton", flat_button_normal); - theme->set_stylebox("normal", "FlatMenuButton", flat_button_normal); + theme->set_stylebox(CoreStringName(normal), "FlatMenuButton", flat_button_normal); theme->set_stylebox("hover", "FlatMenuButton", flat_button_normal); theme->set_stylebox(SceneStringName(pressed), "FlatMenuButton", flat_button_pressed); theme->set_stylebox("disabled", "FlatMenuButton", flat_button_normal); // Label - theme->set_stylebox("normal", "Label", memnew(StyleBoxEmpty)); + theme->set_stylebox(CoreStringName(normal), "Label", memnew(StyleBoxEmpty)); theme->set_font("font", "Label", Ref<Font>()); theme->set_font_size("font_size", "Label", -1); @@ -413,7 +413,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // Add a line at the bottom to make LineEdits distinguishable from Buttons. style_line_edit->set_border_width(SIDE_BOTTOM, 2); style_line_edit->set_border_color(style_pressed_color); - theme->set_stylebox("normal", "LineEdit", style_line_edit); + theme->set_stylebox(CoreStringName(normal), "LineEdit", style_line_edit); theme->set_stylebox("focus", "LineEdit", focus); @@ -457,7 +457,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // TextEdit - theme->set_stylebox("normal", "TextEdit", style_line_edit); + theme->set_stylebox(CoreStringName(normal), "TextEdit", style_line_edit); theme->set_stylebox("focus", "TextEdit", focus); theme->set_stylebox("read_only", "TextEdit", style_line_edit_read_only); @@ -487,7 +487,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // CodeEdit - theme->set_stylebox("normal", "CodeEdit", style_line_edit); + theme->set_stylebox(CoreStringName(normal), "CodeEdit", style_line_edit); theme->set_stylebox("focus", "CodeEdit", focus); theme->set_stylebox("read_only", "CodeEdit", style_line_edit_read_only); theme->set_stylebox("completion", "CodeEdit", make_flat_stylebox(style_normal_color, 0, 0, 0, 0)); @@ -617,7 +617,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<StyleBoxEmpty> empty; empty.instantiate(); - theme->set_stylebox("panel", "ScrollContainer", empty); + theme->set_stylebox(SceneStringName(panel), "ScrollContainer", empty); // Window @@ -640,7 +640,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // Dialogs // AcceptDialog is currently the base dialog, so this defines styles for all extending nodes. - theme->set_stylebox("panel", "AcceptDialog", make_flat_stylebox(style_popup_color, Math::round(8 * scale), Math::round(8 * scale), Math::round(8 * scale), Math::round(8 * scale), 0)); + theme->set_stylebox(SceneStringName(panel), "AcceptDialog", make_flat_stylebox(style_popup_color, Math::round(8 * scale), Math::round(8 * scale), Math::round(8 * scale), Math::round(8 * scale), 0)); theme->set_constant("buttons_separation", "AcceptDialog", Math::round(10 * scale)); // File Dialog @@ -659,11 +659,11 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // Popup - theme->set_stylebox("panel", "PopupPanel", make_flat_stylebox(style_normal_color)); + theme->set_stylebox(SceneStringName(panel), "PopupPanel", make_flat_stylebox(style_normal_color)); // PopupDialog - theme->set_stylebox("panel", "PopupDialog", make_flat_stylebox(style_normal_color)); + theme->set_stylebox(SceneStringName(panel), "PopupDialog", make_flat_stylebox(style_normal_color)); // PopupMenu @@ -680,7 +680,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const style_popup_panel->set_border_width_all(2); style_popup_panel->set_border_color(style_popup_border_color); - theme->set_stylebox("panel", "PopupMenu", style_popup_panel); + theme->set_stylebox(SceneStringName(panel), "PopupMenu", style_popup_panel); theme->set_stylebox("hover", "PopupMenu", make_flat_stylebox(style_popup_hover_color)); theme->set_stylebox("separator", "PopupMenu", separator_horizontal); theme->set_stylebox("labeled_separator_left", "PopupMenu", separator_horizontal); @@ -731,7 +731,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const graphn_sb_titlebar_selected->set_bg_color(Color(1.0, 0.625, 0.625, 0.6)); Ref<StyleBoxEmpty> graphnode_slot = make_empty_stylebox(0, 0, 0, 0); - theme->set_stylebox("panel", "GraphNode", graphnode_normal); + theme->set_stylebox(SceneStringName(panel), "GraphNode", graphnode_normal); theme->set_stylebox("panel_selected", "GraphNode", graphnode_selected); theme->set_stylebox("titlebar", "GraphNode", graphn_sb_titlebar); theme->set_stylebox("titlebar_selected", "GraphNode", graphn_sb_titlebar_selected); @@ -746,7 +746,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_type_variation("GraphNodeTitleLabel", "Label"); - theme->set_stylebox("normal", "GraphNodeTitleLabel", make_empty_stylebox(0, 0, 0, 0)); + theme->set_stylebox(CoreStringName(normal), "GraphNodeTitleLabel", make_empty_stylebox(0, 0, 0, 0)); theme->set_font("font", "GraphNodeTitleLabel", Ref<Font>()); theme->set_font_size("font_size", "GraphNodeTitleLabel", -1); theme->set_color("font_color", "GraphNodeTitleLabel", control_font_color); @@ -766,7 +766,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<StyleBoxFlat> graphframe_sb_selected = graphframe_sb->duplicate(); graphframe_sb_selected->set_border_color(style_hover_color); - theme->set_stylebox("panel", "GraphFrame", graphframe_sb); + theme->set_stylebox(SceneStringName(panel), "GraphFrame", graphframe_sb); theme->set_stylebox("panel_selected", "GraphFrame", graphframe_sb_selected); theme->set_stylebox("titlebar", "GraphFrame", make_empty_stylebox(4, 4, 4, 4)); theme->set_stylebox("titlebar_selected", "GraphFrame", make_empty_stylebox(4, 4, 4, 4)); @@ -777,7 +777,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_type_variation("GraphFrameTitleLabel", "Label"); - theme->set_stylebox("normal", "GraphFrameTitleLabel", memnew(StyleBoxEmpty)); + theme->set_stylebox(CoreStringName(normal), "GraphFrameTitleLabel", memnew(StyleBoxEmpty)); theme->set_font_size("font_size", "GraphFrameTitleLabel", 22); theme->set_color("font_color", "GraphFrameTitleLabel", Color(1, 1, 1)); theme->set_color("font_shadow_color", "GraphFrameTitleLabel", Color(0, 0, 0, 0)); @@ -790,7 +790,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // Tree - theme->set_stylebox("panel", "Tree", make_flat_stylebox(style_normal_color, 4, 4, 4, 5)); + theme->set_stylebox(SceneStringName(panel), "Tree", make_flat_stylebox(style_normal_color, 4, 4, 4, 5)); theme->set_stylebox("focus", "Tree", focus); theme->set_stylebox("selected", "Tree", make_flat_stylebox(style_selected_color)); theme->set_stylebox("selected_focus", "Tree", make_flat_stylebox(style_selected_color)); @@ -860,7 +860,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // ItemList - theme->set_stylebox("panel", "ItemList", make_flat_stylebox(style_normal_color)); + theme->set_stylebox(SceneStringName(panel), "ItemList", make_flat_stylebox(style_normal_color)); theme->set_stylebox("focus", "ItemList", focus); theme->set_constant("h_separation", "ItemList", Math::round(4 * scale)); theme->set_constant("v_separation", "ItemList", Math::round(4 * scale)); @@ -904,7 +904,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_stylebox("tab_unselected", "TabContainer", style_tab_unselected); theme->set_stylebox("tab_disabled", "TabContainer", style_tab_disabled); theme->set_stylebox("tab_focus", "TabContainer", style_tab_focus); - theme->set_stylebox("panel", "TabContainer", make_flat_stylebox(style_normal_color, 0, 0, 0, 0)); + theme->set_stylebox(SceneStringName(panel), "TabContainer", make_flat_stylebox(style_normal_color, 0, 0, 0, 0)); theme->set_stylebox("tabbar_background", "TabContainer", make_empty_stylebox(0, 0, 0, 0)); theme->set_icon("increment", "TabContainer", icons["scroll_button_right"]); @@ -1050,7 +1050,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // ColorPickerButton theme->set_icon("bg", "ColorPickerButton", icons["mini_checkerboard"]); - theme->set_stylebox("normal", "ColorPickerButton", button_normal); + theme->set_stylebox(CoreStringName(normal), "ColorPickerButton", button_normal); theme->set_stylebox(SceneStringName(pressed), "ColorPickerButton", button_pressed); theme->set_stylebox("hover", "ColorPickerButton", button_hover); theme->set_stylebox("disabled", "ColorPickerButton", button_disabled); @@ -1083,7 +1083,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // TooltipPanel + TooltipLabel theme->set_type_variation("TooltipPanel", "PopupPanel"); - theme->set_stylebox("panel", "TooltipPanel", + theme->set_stylebox(SceneStringName(panel), "TooltipPanel", make_flat_stylebox(Color(0, 0, 0, 0.5), 2 * default_margin, 0.5 * default_margin, 2 * default_margin, 0.5 * default_margin)); theme->set_type_variation("TooltipLabel", "Label"); @@ -1101,7 +1101,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // RichTextLabel theme->set_stylebox("focus", "RichTextLabel", focus); - theme->set_stylebox("normal", "RichTextLabel", make_empty_stylebox(0, 0, 0, 0)); + theme->set_stylebox(CoreStringName(normal), "RichTextLabel", make_empty_stylebox(0, 0, 0, 0)); theme->set_font("normal_font", "RichTextLabel", Ref<Font>()); theme->set_font("bold_font", "RichTextLabel", bold_font); @@ -1171,7 +1171,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("h_separation", "VFlowContainer", Math::round(4 * scale)); theme->set_constant("v_separation", "VFlowContainer", Math::round(4 * scale)); - theme->set_stylebox("panel", "PanelContainer", make_flat_stylebox(style_normal_color, 0, 0, 0, 0)); + theme->set_stylebox(SceneStringName(panel), "PanelContainer", make_flat_stylebox(style_normal_color, 0, 0, 0, 0)); theme->set_icon("zoom_out", "GraphEdit", icons["zoom_less"]); theme->set_icon("zoom_in", "GraphEdit", icons["zoom_more"]); @@ -1181,7 +1181,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_icon("snapping_toggle", "GraphEdit", icons["grid_snap"]); theme->set_icon("layout", "GraphEdit", icons["grid_layout"]); - theme->set_stylebox("panel", "GraphEdit", make_flat_stylebox(style_normal_color, 4, 4, 4, 5)); + theme->set_stylebox(SceneStringName(panel), "GraphEdit", make_flat_stylebox(style_normal_color, 4, 4, 4, 5)); Ref<StyleBoxFlat> graph_toolbar_style = make_flat_stylebox(Color(0.24, 0.24, 0.24, 0.6), 4, 2, 4, 2); theme->set_stylebox("menu_panel", "GraphEdit", graph_toolbar_style); @@ -1200,7 +1200,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("port_hotzone_inner_extent", "GraphEdit", 22 * scale); theme->set_constant("port_hotzone_outer_extent", "GraphEdit", 26 * scale); - theme->set_stylebox("panel", "GraphEditMinimap", make_flat_stylebox(Color(0.24, 0.24, 0.24), 0, 0, 0, 0)); + theme->set_stylebox(SceneStringName(panel), "GraphEditMinimap", make_flat_stylebox(Color(0.24, 0.24, 0.24), 0, 0, 0, 0)); Ref<StyleBoxFlat> style_minimap_camera = make_flat_stylebox(Color(0.65, 0.65, 0.65, 0.2), 0, 0, 0, 0, 0); style_minimap_camera->set_border_color(Color(0.65, 0.65, 0.65, 0.45)); style_minimap_camera->set_border_width_all(1); diff --git a/servers/audio/audio_stream.h b/servers/audio/audio_stream.h index 01a4a09942..aa1ad4cc3a 100644 --- a/servers/audio/audio_stream.h +++ b/servers/audio/audio_stream.h @@ -260,7 +260,7 @@ protected: bool _set(const StringName &p_name, const Variant &p_value) { return property_helper.property_set_value(p_name, p_value); } bool _get(const StringName &p_name, Variant &r_ret) const { return property_helper.property_get_value(p_name, r_ret); } - void _get_property_list(List<PropertyInfo> *p_list) const { property_helper.get_property_list(p_list, audio_stream_pool.size()); } + void _get_property_list(List<PropertyInfo> *p_list) const { property_helper.get_property_list(p_list); } bool _property_can_revert(const StringName &p_name) const { return property_helper.property_can_revert(p_name); } bool _property_get_revert(const StringName &p_name, Variant &r_property) const { return property_helper.property_get_revert(p_name, r_property); } diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp index f56ef11c14..cda04e0aae 100644 --- a/servers/physics_server_3d.cpp +++ b/servers/physics_server_3d.cpp @@ -704,9 +704,11 @@ void PhysicsServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("custom_shape_create"), &PhysicsServer3D::custom_shape_create); ClassDB::bind_method(D_METHOD("shape_set_data", "shape", "data"), &PhysicsServer3D::shape_set_data); + ClassDB::bind_method(D_METHOD("shape_set_margin", "shape", "margin"), &PhysicsServer3D::shape_set_margin); ClassDB::bind_method(D_METHOD("shape_get_type", "shape"), &PhysicsServer3D::shape_get_type); ClassDB::bind_method(D_METHOD("shape_get_data", "shape"), &PhysicsServer3D::shape_get_data); + ClassDB::bind_method(D_METHOD("shape_get_margin", "shape"), &PhysicsServer3D::shape_get_margin); ClassDB::bind_method(D_METHOD("space_create"), &PhysicsServer3D::space_create); ClassDB::bind_method(D_METHOD("space_set_active", "space", "active"), &PhysicsServer3D::space_set_active); diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index 068f9d9ef2..aae32f0b3e 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -972,14 +972,14 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con float distance = 0.0; // Check if camera is NOT inside the mesh AABB. - if (!inst->transformed_aabb.has_point(p_render_data->scene_data->cam_transform.origin)) { + if (!inst->transformed_aabb.has_point(p_render_data->scene_data->main_cam_transform.origin)) { // Get the LOD support points on the mesh AABB. - Vector3 lod_support_min = inst->transformed_aabb.get_support(p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z)); - Vector3 lod_support_max = inst->transformed_aabb.get_support(-p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z)); + Vector3 lod_support_min = inst->transformed_aabb.get_support(p_render_data->scene_data->main_cam_transform.basis.get_column(Vector3::AXIS_Z)); + Vector3 lod_support_max = inst->transformed_aabb.get_support(-p_render_data->scene_data->main_cam_transform.basis.get_column(Vector3::AXIS_Z)); // Get the distances to those points on the AABB from the camera origin. - float distance_min = (float)p_render_data->scene_data->cam_transform.origin.distance_to(lod_support_min); - float distance_max = (float)p_render_data->scene_data->cam_transform.origin.distance_to(lod_support_max); + float distance_min = (float)p_render_data->scene_data->main_cam_transform.origin.distance_to(lod_support_min); + float distance_max = (float)p_render_data->scene_data->main_cam_transform.origin.distance_to(lod_support_max); if (distance_min * distance_max < 0.0) { //crossing plane @@ -1388,7 +1388,6 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo p_render_data->shadows.clear(); p_render_data->directional_shadows.clear(); - Plane camera_plane(-p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->scene_data->cam_transform.origin); float lod_distance_multiplier = p_render_data->scene_data->cam_projection.get_lod_multiplier(); { for (int i = 0; i < p_render_data->render_shadow_count; i++) { @@ -1407,7 +1406,7 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo RENDER_TIMESTAMP("Render OmniLight Shadows"); // Cube shadows are rendered in their own way. for (const int &index : p_render_data->cube_shadows) { - _render_shadow_pass(p_render_data->render_shadows[index].light, p_render_data->shadow_atlas, p_render_data->render_shadows[index].pass, p_render_data->render_shadows[index].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info, viewport_size, p_render_data->scene_data->cam_transform); + _render_shadow_pass(p_render_data->render_shadows[index].light, p_render_data->shadow_atlas, p_render_data->render_shadows[index].pass, p_render_data->render_shadows[index].instances, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info, viewport_size, p_render_data->scene_data->cam_transform); } if (p_render_data->directional_shadows.size()) { @@ -1437,11 +1436,11 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo //render directional shadows for (uint32_t i = 0; i < p_render_data->directional_shadows.size(); i++) { - _render_shadow_pass(p_render_data->render_shadows[p_render_data->directional_shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->directional_shadows[i]].pass, p_render_data->render_shadows[p_render_data->directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, false, i == p_render_data->directional_shadows.size() - 1, false, p_render_data->render_info, viewport_size, p_render_data->scene_data->cam_transform); + _render_shadow_pass(p_render_data->render_shadows[p_render_data->directional_shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->directional_shadows[i]].pass, p_render_data->render_shadows[p_render_data->directional_shadows[i]].instances, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, false, i == p_render_data->directional_shadows.size() - 1, false, p_render_data->render_info, viewport_size, p_render_data->scene_data->cam_transform); } //render positional shadows for (uint32_t i = 0; i < p_render_data->shadows.size(); i++) { - _render_shadow_pass(p_render_data->render_shadows[p_render_data->shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->shadows[i]].pass, p_render_data->render_shadows[p_render_data->shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, i == 0, i == p_render_data->shadows.size() - 1, true, p_render_data->render_info, viewport_size, p_render_data->scene_data->cam_transform); + _render_shadow_pass(p_render_data->render_shadows[p_render_data->shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->shadows[i]].pass, p_render_data->render_shadows[p_render_data->shadows[i]].instances, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, i == 0, i == p_render_data->shadows.size() - 1, true, p_render_data->render_info, viewport_size, p_render_data->scene_data->cam_transform); } _render_shadow_process(); @@ -2371,7 +2370,7 @@ void RenderForwardClustered::_render_buffers_debug_draw(const RenderDataRD *p_re } } -void RenderForwardClustered::_render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, bool p_open_pass, bool p_close_pass, bool p_clear_region, RenderingMethod::RenderInfo *p_render_info, const Size2i &p_viewport_size, const Transform3D &p_main_cam_transform) { +void RenderForwardClustered::_render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, bool p_open_pass, bool p_close_pass, bool p_clear_region, RenderingMethod::RenderInfo *p_render_info, const Size2i &p_viewport_size, const Transform3D &p_main_cam_transform) { RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); ERR_FAIL_COND(!light_storage->owns_light_instance(p_light)); @@ -2526,7 +2525,7 @@ void RenderForwardClustered::_render_shadow_pass(RID p_light, RID p_shadow_atlas if (render_cubemap) { //rendering to cubemap - _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, reverse_cull_face, false, false, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, Rect2(), false, true, true, true, p_render_info, p_viewport_size, p_main_cam_transform); + _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, reverse_cull_face, false, false, use_pancake, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, Rect2(), false, true, true, true, p_render_info, p_viewport_size, p_main_cam_transform); if (finalize_cubemap) { _render_shadow_process(); _render_shadow_end(); @@ -2544,7 +2543,7 @@ void RenderForwardClustered::_render_shadow_pass(RID p_light, RID p_shadow_atlas } else { //render shadow - _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, reverse_cull_face, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, atlas_rect, flip_y, p_clear_region, p_open_pass, p_close_pass, p_render_info, p_viewport_size, p_main_cam_transform); + _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, reverse_cull_face, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, atlas_rect, flip_y, p_clear_region, p_open_pass, p_close_pass, p_render_info, p_viewport_size, p_main_cam_transform); } } @@ -2557,7 +2556,7 @@ void RenderForwardClustered::_render_shadow_begin() { scene_state.instance_data[RENDER_LIST_SECONDARY].clear(); } -void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_reverse_cull_face, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end, RenderingMethod::RenderInfo *p_render_info, const Size2i &p_viewport_size, const Transform3D &p_main_cam_transform) { +void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_reverse_cull_face, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end, RenderingMethod::RenderInfo *p_render_info, const Size2i &p_viewport_size, const Transform3D &p_main_cam_transform) { uint32_t shadow_pass_index = scene_state.shadow_passes.size(); SceneState::ShadowPass shadow_pass; @@ -2615,7 +2614,6 @@ void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const Page shadow_pass.pass_mode = pass_mode; shadow_pass.rp_uniform_set = RID(); //will be filled later when instance buffer is complete - shadow_pass.camera_plane = p_camera_plane; shadow_pass.screen_mesh_lod_threshold = scene_data.screen_mesh_lod_threshold; shadow_pass.lod_distance_multiplier = scene_data.lod_distance_multiplier; diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h index 1f12d92754..ae9e5e7c10 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -347,7 +347,6 @@ class RenderForwardClustered : public RendererSceneRenderRD { PassMode pass_mode; RID rp_uniform_set; - Plane camera_plane; float lod_distance_multiplier; float screen_mesh_lod_threshold; @@ -594,9 +593,9 @@ class RenderForwardClustered : public RendererSceneRenderRD { /* Render shadows */ - void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true, RenderingMethod::RenderInfo *p_render_info = nullptr, const Size2i &p_viewport_size = Size2i(1, 1), const Transform3D &p_main_cam_transform = Transform3D()); + void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true, RenderingMethod::RenderInfo *p_render_info = nullptr, const Size2i &p_viewport_size = Size2i(1, 1), const Transform3D &p_main_cam_transform = Transform3D()); void _render_shadow_begin(); - void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_reverse_cull_face, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr, const Size2i &p_viewport_size = Size2i(1, 1), const Transform3D &p_main_cam_transform = Transform3D()); + void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_reverse_cull_face, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr, const Size2i &p_viewport_size = Size2i(1, 1), const Transform3D &p_main_cam_transform = Transform3D()); void _render_shadow_process(); void _render_shadow_end(); diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index bd45dbfbc9..194a70dc22 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -590,7 +590,6 @@ void RenderForwardMobile::_pre_opaque_render(RenderDataRD *p_render_data) { p_render_data->shadows.clear(); p_render_data->directional_shadows.clear(); - Plane camera_plane(-p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->scene_data->cam_transform.origin); float lod_distance_multiplier = p_render_data->scene_data->cam_projection.get_lod_multiplier(); { for (int i = 0; i < p_render_data->render_shadow_count; i++) { @@ -608,7 +607,7 @@ void RenderForwardMobile::_pre_opaque_render(RenderDataRD *p_render_data) { //cube shadows are rendered in their own way for (const int &index : p_render_data->cube_shadows) { - _render_shadow_pass(p_render_data->render_shadows[index].light, p_render_data->shadow_atlas, p_render_data->render_shadows[index].pass, p_render_data->render_shadows[index].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info, p_render_data->scene_data->cam_transform); + _render_shadow_pass(p_render_data->render_shadows[index].light, p_render_data->shadow_atlas, p_render_data->render_shadows[index].pass, p_render_data->render_shadows[index].instances, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info, p_render_data->scene_data->cam_transform); } if (p_render_data->directional_shadows.size()) { @@ -629,11 +628,11 @@ void RenderForwardMobile::_pre_opaque_render(RenderDataRD *p_render_data) { //render directional shadows for (uint32_t i = 0; i < p_render_data->directional_shadows.size(); i++) { - _render_shadow_pass(p_render_data->render_shadows[p_render_data->directional_shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->directional_shadows[i]].pass, p_render_data->render_shadows[p_render_data->directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, false, i == p_render_data->directional_shadows.size() - 1, false, p_render_data->render_info, p_render_data->scene_data->cam_transform); + _render_shadow_pass(p_render_data->render_shadows[p_render_data->directional_shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->directional_shadows[i]].pass, p_render_data->render_shadows[p_render_data->directional_shadows[i]].instances, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, false, i == p_render_data->directional_shadows.size() - 1, false, p_render_data->render_info, p_render_data->scene_data->cam_transform); } //render positional shadows for (uint32_t i = 0; i < p_render_data->shadows.size(); i++) { - _render_shadow_pass(p_render_data->render_shadows[p_render_data->shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->shadows[i]].pass, p_render_data->render_shadows[p_render_data->shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, i == 0, i == p_render_data->shadows.size() - 1, true, p_render_data->render_info, p_render_data->scene_data->cam_transform); + _render_shadow_pass(p_render_data->render_shadows[p_render_data->shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->shadows[i]].pass, p_render_data->render_shadows[p_render_data->shadows[i]].instances, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, i == 0, i == p_render_data->shadows.size() - 1, true, p_render_data->render_info, p_render_data->scene_data->cam_transform); } _render_shadow_process(); @@ -1115,7 +1114,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color /* these are being called from RendererSceneRenderRD::_pre_opaque_render */ -void RenderForwardMobile::_render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, bool p_open_pass, bool p_close_pass, bool p_clear_region, RenderingMethod::RenderInfo *p_render_info, const Transform3D &p_main_cam_transform) { +void RenderForwardMobile::_render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, bool p_open_pass, bool p_close_pass, bool p_clear_region, RenderingMethod::RenderInfo *p_render_info, const Transform3D &p_main_cam_transform) { RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); ERR_FAIL_COND(!light_storage->owns_light_instance(p_light)); @@ -1269,7 +1268,7 @@ void RenderForwardMobile::_render_shadow_pass(RID p_light, RID p_shadow_atlas, i if (render_cubemap) { //rendering to cubemap - _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, false, false, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, Rect2(), false, true, true, true, p_render_info, p_main_cam_transform); + _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, false, false, use_pancake, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, Rect2(), false, true, true, true, p_render_info, p_main_cam_transform); if (finalize_cubemap) { _render_shadow_process(); _render_shadow_end(); @@ -1288,7 +1287,7 @@ void RenderForwardMobile::_render_shadow_pass(RID p_light, RID p_shadow_atlas, i } else { //render shadow - _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, atlas_rect, flip_y, p_clear_region, p_open_pass, p_close_pass, p_render_info, p_main_cam_transform); + _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, atlas_rect, flip_y, p_clear_region, p_open_pass, p_close_pass, p_render_info, p_main_cam_transform); } } @@ -1300,7 +1299,7 @@ void RenderForwardMobile::_render_shadow_begin() { render_list[RENDER_LIST_SECONDARY].clear(); } -void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end, RenderingMethod::RenderInfo *p_render_info, const Transform3D &p_main_cam_transform) { +void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end, RenderingMethod::RenderInfo *p_render_info, const Transform3D &p_main_cam_transform) { uint32_t shadow_pass_index = scene_state.shadow_passes.size(); SceneState::ShadowPass shadow_pass; @@ -1357,7 +1356,6 @@ void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedAr shadow_pass.pass_mode = pass_mode; shadow_pass.rp_uniform_set = RID(); //will be filled later when instance buffer is complete - shadow_pass.camera_plane = p_camera_plane; shadow_pass.screen_mesh_lod_threshold = scene_data.screen_mesh_lod_threshold; shadow_pass.lod_distance_multiplier = scene_data.lod_distance_multiplier; @@ -1882,14 +1880,14 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const float distance = 0.0; // Check if camera is NOT inside the mesh AABB. - if (!inst->transformed_aabb.has_point(p_render_data->scene_data->cam_transform.origin)) { + if (!inst->transformed_aabb.has_point(p_render_data->scene_data->main_cam_transform.origin)) { // Get the LOD support points on the mesh AABB. - Vector3 lod_support_min = inst->transformed_aabb.get_support(p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z)); - Vector3 lod_support_max = inst->transformed_aabb.get_support(-p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z)); + Vector3 lod_support_min = inst->transformed_aabb.get_support(p_render_data->scene_data->main_cam_transform.basis.get_column(Vector3::AXIS_Z)); + Vector3 lod_support_max = inst->transformed_aabb.get_support(-p_render_data->scene_data->main_cam_transform.basis.get_column(Vector3::AXIS_Z)); // Get the distances to those points on the AABB from the camera origin. - float distance_min = (float)p_render_data->scene_data->cam_transform.origin.distance_to(lod_support_min); - float distance_max = (float)p_render_data->scene_data->cam_transform.origin.distance_to(lod_support_max); + float distance_min = (float)p_render_data->scene_data->main_cam_transform.origin.distance_to(lod_support_min); + float distance_max = (float)p_render_data->scene_data->main_cam_transform.origin.distance_to(lod_support_max); if (distance_min * distance_max < 0.0) { //crossing plane diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h index f29503e5ec..aa1b8f34b2 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -178,9 +178,9 @@ private: /* Render shadows */ - void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true, RenderingMethod::RenderInfo *p_render_info = nullptr, const Transform3D &p_main_cam_transform = Transform3D()); + void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true, RenderingMethod::RenderInfo *p_render_info = nullptr, const Transform3D &p_main_cam_transform = Transform3D()); void _render_shadow_begin(); - void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr, const Transform3D &p_main_cam_transform = Transform3D()); + void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr, const Transform3D &p_main_cam_transform = Transform3D()); void _render_shadow_process(); void _render_shadow_end(); @@ -270,7 +270,6 @@ private: PassMode pass_mode; RID rp_uniform_set; - Plane camera_plane; float lod_distance_multiplier; float screen_mesh_lod_threshold; diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp index a10c672379..d1c8c71b7f 100644 --- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp @@ -746,8 +746,10 @@ MaterialStorage::MaterialData::~MaterialData() { material_storage->global_shader_uniforms.materials_using_texture.erase(global_texture_E); } - if (uniform_buffer.is_valid()) { - RD::get_singleton()->free(uniform_buffer); + for (int i = 0; i < 2; i++) { + if (uniform_buffer[i].is_valid()) { + RD::get_singleton()->free(uniform_buffer[i]); + } } } @@ -987,17 +989,17 @@ void MaterialStorage::MaterialData::free_parameters_uniform_set(RID p_uniform_se } bool MaterialStorage::MaterialData::update_parameters_uniform_set(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, const HashMap<StringName, HashMap<int, RID>> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, bool p_use_linear_color, bool p_3d_material) { - if ((uint32_t)ubo_data.size() != p_ubo_size) { + if ((uint32_t)ubo_data[p_use_linear_color].size() != p_ubo_size) { p_uniform_dirty = true; - if (uniform_buffer.is_valid()) { - RD::get_singleton()->free(uniform_buffer); - uniform_buffer = RID(); + if (uniform_buffer[p_use_linear_color].is_valid()) { + RD::get_singleton()->free(uniform_buffer[p_use_linear_color]); + uniform_buffer[p_use_linear_color] = RID(); } - ubo_data.resize(p_ubo_size); - if (ubo_data.size()) { - uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size()); - memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear + ubo_data[p_use_linear_color].resize(p_ubo_size); + if (ubo_data[p_use_linear_color].size()) { + uniform_buffer[p_use_linear_color] = RD::get_singleton()->uniform_buffer_create(ubo_data[p_use_linear_color].size()); + memset(ubo_data[p_use_linear_color].ptrw(), 0, ubo_data[p_use_linear_color].size()); //clear } //clear previous uniform set @@ -1009,9 +1011,9 @@ bool MaterialStorage::MaterialData::update_parameters_uniform_set(const HashMap< } //check whether buffer changed - if (p_uniform_dirty && ubo_data.size()) { - update_uniform_buffer(p_uniforms, p_uniform_offsets, p_parameters, ubo_data.ptrw(), ubo_data.size(), p_use_linear_color); - RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw()); + if (p_uniform_dirty && ubo_data[p_use_linear_color].size()) { + update_uniform_buffer(p_uniforms, p_uniform_offsets, p_parameters, ubo_data[p_use_linear_color].ptrw(), ubo_data[p_use_linear_color].size(), p_use_linear_color); + RD::get_singleton()->buffer_update(uniform_buffer[p_use_linear_color], 0, ubo_data[p_use_linear_color].size(), ubo_data[p_use_linear_color].ptrw()); } uint32_t tex_uniform_count = 0U; @@ -1053,7 +1055,7 @@ bool MaterialStorage::MaterialData::update_parameters_uniform_set(const HashMap< RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 0; - u.append_id(uniform_buffer); + u.append_id(uniform_buffer[p_use_linear_color]); uniforms.push_back(u); } diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.h b/servers/rendering/renderer_rd/storage_rd/material_storage.h index fe769a778d..9c53450462 100644 --- a/servers/rendering/renderer_rd/storage_rd/material_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/material_storage.h @@ -100,8 +100,8 @@ public: HashMap<StringName, uint64_t> used_global_textures; //internally by update_parameters_uniform_set - Vector<uint8_t> ubo_data; - RID uniform_buffer; + Vector<uint8_t> ubo_data[2]; // 0: linear buffer; 1: sRGB buffer. + RID uniform_buffer[2]; // 0: linear buffer; 1: sRGB buffer. Vector<RID> texture_cache; }; diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 0227472d0e..f9883106c2 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -824,8 +824,8 @@ RID RenderingDevice::texture_create(const TextureFormat &p_format, const Texture } if (texture.draw_tracker != nullptr) { - // Draw tracker can assume the texture will be in transfer destination. - texture.draw_tracker->usage = RDG::RESOURCE_USAGE_TRANSFER_TO; + // Draw tracker can assume the texture will be in copy destination. + texture.draw_tracker->usage = RDG::RESOURCE_USAGE_COPY_TO; } } @@ -847,8 +847,11 @@ RID RenderingDevice::texture_create_shared(const TextureView &p_view, RID p_with // Create view. Texture texture = *src_texture; + texture.shared_fallback = nullptr; RDD::TextureView tv; + bool create_shared = true; + bool raw_reintepretation = false; if (p_view.format_override == DATA_FORMAT_MAX || p_view.format_override == texture.format) { tv.format = texture.format; } else { @@ -857,13 +860,47 @@ RID RenderingDevice::texture_create_shared(const TextureView &p_view, RID p_with ERR_FAIL_COND_V_MSG(!texture.allowed_shared_formats.has(p_view.format_override), RID(), "Format override is not in the list of allowed shareable formats for original texture."); tv.format = p_view.format_override; + create_shared = driver->texture_can_make_shared_with_format(texture.driver_id, p_view.format_override, raw_reintepretation); } tv.swizzle_r = p_view.swizzle_r; tv.swizzle_g = p_view.swizzle_g; tv.swizzle_b = p_view.swizzle_b; tv.swizzle_a = p_view.swizzle_a; - texture.driver_id = driver->texture_create_shared(texture.driver_id, tv); + if (create_shared) { + texture.driver_id = driver->texture_create_shared(texture.driver_id, tv); + } else { + // The regular view will use the same format as the main texture. + RDD::TextureView regular_view = tv; + regular_view.format = src_texture->format; + texture.driver_id = driver->texture_create_shared(texture.driver_id, regular_view); + + // Create the independent texture for the alias. + RDD::TextureFormat alias_format = texture.texture_format(); + alias_format.format = tv.format; + alias_format.usage_bits = TEXTURE_USAGE_SAMPLING_BIT | TEXTURE_USAGE_CAN_COPY_TO_BIT; + + _texture_check_shared_fallback(src_texture); + _texture_check_shared_fallback(&texture); + + texture.shared_fallback->texture = driver->texture_create(alias_format, tv); + texture.shared_fallback->raw_reinterpretation = raw_reintepretation; + texture_memory += driver->texture_get_allocation_size(texture.shared_fallback->texture); + + RDG::ResourceTracker *tracker = RDG::resource_tracker_create(); + tracker->texture_driver_id = texture.shared_fallback->texture; + tracker->texture_subresources = texture.barrier_range(); + tracker->texture_usage = alias_format.usage_bits; + tracker->reference_count = 1; + texture.shared_fallback->texture_tracker = tracker; + texture.shared_fallback->revision = 0; + + if (raw_reintepretation && src_texture->shared_fallback->buffer.id == 0) { + // For shared textures of the same size, we create the buffer on the main texture if it doesn't have it already. + _texture_create_reinterpret_buffer(src_texture); + } + } + ERR_FAIL_COND_V(!texture.driver_id, RID()); texture.slice_trackers.clear(); @@ -965,6 +1002,7 @@ RID RenderingDevice::texture_create_shared_from_slice(const TextureView &p_view, } Texture texture = *src_texture; + texture.shared_fallback = nullptr; get_image_format_required_size(texture.format, texture.width, texture.height, texture.depth, p_mipmap + 1, &texture.width, &texture.height); texture.mipmaps = p_mipmaps; @@ -979,6 +1017,8 @@ RID RenderingDevice::texture_create_shared_from_slice(const TextureView &p_view, } RDD::TextureView tv; + bool create_shared = true; + bool raw_reintepretation = false; if (p_view.format_override == DATA_FORMAT_MAX || p_view.format_override == texture.format) { tv.format = texture.format; } else { @@ -987,7 +1027,9 @@ RID RenderingDevice::texture_create_shared_from_slice(const TextureView &p_view, ERR_FAIL_COND_V_MSG(!texture.allowed_shared_formats.has(p_view.format_override), RID(), "Format override is not in the list of allowed shareable formats for original texture."); tv.format = p_view.format_override; + create_shared = driver->texture_can_make_shared_with_format(texture.driver_id, p_view.format_override, raw_reintepretation); } + tv.swizzle_r = p_view.swizzle_r; tv.swizzle_g = p_view.swizzle_g; tv.swizzle_b = p_view.swizzle_b; @@ -1000,7 +1042,47 @@ RID RenderingDevice::texture_create_shared_from_slice(const TextureView &p_view, "Specified layer must be a multiple of 6."); } - texture.driver_id = driver->texture_create_shared_from_slice(src_texture->driver_id, tv, p_slice_type, p_layer, slice_layers, p_mipmap, p_mipmaps); + if (create_shared) { + texture.driver_id = driver->texture_create_shared_from_slice(src_texture->driver_id, tv, p_slice_type, p_layer, slice_layers, p_mipmap, p_mipmaps); + } else { + // The regular view will use the same format as the main texture. + RDD::TextureView regular_view = tv; + regular_view.format = src_texture->format; + texture.driver_id = driver->texture_create_shared_from_slice(src_texture->driver_id, regular_view, p_slice_type, p_layer, slice_layers, p_mipmap, p_mipmaps); + + // Create the independent texture for the slice. + RDD::TextureSubresourceRange slice_range = texture.barrier_range(); + slice_range.base_mipmap = 0; + slice_range.base_layer = 0; + + RDD::TextureFormat slice_format = texture.texture_format(); + slice_format.width = MAX(texture.width >> p_mipmap, 1U); + slice_format.height = MAX(texture.height >> p_mipmap, 1U); + slice_format.depth = MAX(texture.depth >> p_mipmap, 1U); + slice_format.format = tv.format; + slice_format.usage_bits = TEXTURE_USAGE_SAMPLING_BIT | TEXTURE_USAGE_CAN_COPY_TO_BIT; + + _texture_check_shared_fallback(src_texture); + _texture_check_shared_fallback(&texture); + + texture.shared_fallback->texture = driver->texture_create(slice_format, tv); + texture.shared_fallback->raw_reinterpretation = raw_reintepretation; + texture_memory += driver->texture_get_allocation_size(texture.shared_fallback->texture); + + RDG::ResourceTracker *tracker = RDG::resource_tracker_create(); + tracker->texture_driver_id = texture.shared_fallback->texture; + tracker->texture_subresources = slice_range; + tracker->texture_usage = slice_format.usage_bits; + tracker->reference_count = 1; + texture.shared_fallback->texture_tracker = tracker; + texture.shared_fallback->revision = 0; + + if (raw_reintepretation && src_texture->shared_fallback->buffer.id == 0) { + // For shared texture slices, we create the buffer on the slice if the source texture has no reinterpretation buffer. + _texture_create_reinterpret_buffer(&texture); + } + } + ERR_FAIL_COND_V(!texture.driver_id, RID()); const Rect2i slice_rect(p_mipmap, p_layer, p_mipmaps, slice_layers); @@ -1093,15 +1175,18 @@ Error RenderingDevice::_texture_update(RID p_texture, uint32_t p_layer, const Ve // When using the setup queue directly, we transition the texture to the optimal layout. RDD::TextureBarrier tb; tb.texture = texture->driver_id; - tb.dst_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT; + tb.dst_access = RDD::BARRIER_ACCESS_COPY_WRITE_BIT; tb.prev_layout = RDD::TEXTURE_LAYOUT_UNDEFINED; - tb.next_layout = RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL; + tb.next_layout = RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL; tb.subresources.aspect = texture->barrier_aspect_flags; tb.subresources.mipmap_count = texture->mipmaps; tb.subresources.base_layer = p_layer; tb.subresources.layer_count = 1; - driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, {}, tb); + driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, RDD::PIPELINE_STAGE_COPY_BIT, {}, {}, tb); + } else if (!p_use_setup_queue) { + // Indicate the texture will get modified for the shared texture fallback. + _texture_update_shared_fallback(p_texture, texture, true); } uint32_t mipmap_offset = 0; @@ -1199,7 +1284,7 @@ Error RenderingDevice::_texture_update(RID p_texture, uint32_t p_layer, const Ve copy_region.texture_region_size = Vector3i(region_logic_w, region_logic_h, 1); if (p_use_setup_queue) { - driver->command_copy_buffer_to_texture(frames[frame].setup_command_buffer, staging_buffer_blocks[staging_buffer_current].driver_id, texture->driver_id, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, copy_region); + driver->command_copy_buffer_to_texture(frames[frame].setup_command_buffer, staging_buffer_blocks[staging_buffer_current].driver_id, texture->driver_id, RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL, copy_region); } else { RDG::RecordedBufferToTextureCopy buffer_to_texture_copy; buffer_to_texture_copy.from_buffer = staging_buffer_blocks[staging_buffer_current].driver_id; @@ -1221,14 +1306,14 @@ Error RenderingDevice::_texture_update(RID p_texture, uint32_t p_layer, const Ve // If the texture does not have a tracker, it means it must be transitioned to the sampling state. RDD::TextureBarrier tb; tb.texture = texture->driver_id; - tb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT; - tb.prev_layout = RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL; + tb.src_access = RDD::BARRIER_ACCESS_COPY_WRITE_BIT; + tb.prev_layout = RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL; tb.next_layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; tb.subresources.aspect = texture->barrier_aspect_flags; tb.subresources.mipmap_count = texture->mipmaps; tb.subresources.base_layer = p_layer; tb.subresources.layer_count = 1; - driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, {}, {}, tb); + driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_COPY_BIT, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, {}, {}, tb); } else if (!p_use_setup_queue && !command_buffer_to_texture_copies_vector.is_empty()) { if (_texture_make_mutable(texture, p_texture)) { // The texture must be mutable to be used as a copy destination. @@ -1241,6 +1326,186 @@ Error RenderingDevice::_texture_update(RID p_texture, uint32_t p_layer, const Ve return OK; } +void RenderingDevice::_texture_check_shared_fallback(Texture *p_texture) { + if (p_texture->shared_fallback == nullptr) { + p_texture->shared_fallback = memnew(Texture::SharedFallback); + } +} + +void RenderingDevice::_texture_update_shared_fallback(RID p_texture_rid, Texture *p_texture, bool p_for_writing) { + if (p_texture->shared_fallback == nullptr) { + // This texture does not use any of the shared texture fallbacks. + return; + } + + if (p_texture->owner.is_valid()) { + Texture *owner_texture = texture_owner.get_or_null(p_texture->owner); + ERR_FAIL_NULL(owner_texture); + if (p_for_writing) { + // Only the main texture is used for writing when using the shared fallback. + owner_texture->shared_fallback->revision++; + } else if (p_texture->shared_fallback->revision != owner_texture->shared_fallback->revision) { + // Copy the contents of the main texture into the shared texture fallback slice. Update the revision. + _texture_copy_shared(p_texture->owner, owner_texture, p_texture_rid, p_texture); + p_texture->shared_fallback->revision = owner_texture->shared_fallback->revision; + } + } else if (p_for_writing) { + // Increment the revision of the texture so shared texture fallback slices must be updated. + p_texture->shared_fallback->revision++; + } +} + +void RenderingDevice::_texture_free_shared_fallback(Texture *p_texture) { + if (p_texture->shared_fallback != nullptr) { + if (p_texture->shared_fallback->texture_tracker != nullptr) { + RDG::resource_tracker_free(p_texture->shared_fallback->texture_tracker); + } + + if (p_texture->shared_fallback->buffer_tracker != nullptr) { + RDG::resource_tracker_free(p_texture->shared_fallback->buffer_tracker); + } + + if (p_texture->shared_fallback->texture.id != 0) { + texture_memory -= driver->texture_get_allocation_size(p_texture->shared_fallback->texture); + driver->texture_free(p_texture->shared_fallback->texture); + } + + if (p_texture->shared_fallback->buffer.id != 0) { + buffer_memory -= driver->buffer_get_allocation_size(p_texture->shared_fallback->buffer); + driver->buffer_free(p_texture->shared_fallback->buffer); + } + + memdelete(p_texture->shared_fallback); + p_texture->shared_fallback = nullptr; + } +} + +void RenderingDevice::_texture_copy_shared(RID p_src_texture_rid, Texture *p_src_texture, RID p_dst_texture_rid, Texture *p_dst_texture) { + // The only type of copying allowed is from the main texture to the slice texture, as slice textures are not allowed to be used for writing when using this fallback. + DEV_ASSERT(p_src_texture != nullptr); + DEV_ASSERT(p_dst_texture != nullptr); + DEV_ASSERT(p_src_texture->owner.is_null()); + DEV_ASSERT(p_dst_texture->owner == p_src_texture_rid); + + bool src_made_mutable = _texture_make_mutable(p_src_texture, p_src_texture_rid); + bool dst_made_mutable = _texture_make_mutable(p_dst_texture, p_dst_texture_rid); + if (src_made_mutable || dst_made_mutable) { + draw_graph.add_synchronization(); + } + + if (p_dst_texture->shared_fallback->raw_reinterpretation) { + // If one of the textures is a main texture and they have a reinterpret buffer, we prefer using that as it's guaranteed to be big enough to hold + // anything and it's how the shared textures that don't use slices are created. + bool src_has_buffer = p_src_texture->shared_fallback->buffer.id != 0; + bool dst_has_buffer = p_dst_texture->shared_fallback->buffer.id != 0; + bool from_src = p_src_texture->owner.is_null() && src_has_buffer; + bool from_dst = p_dst_texture->owner.is_null() && dst_has_buffer; + if (!from_src && !from_dst) { + // If neither texture passed the condition, we just pick whichever texture has a reinterpretation buffer. + from_src = src_has_buffer; + from_dst = dst_has_buffer; + } + + // Pick the buffer and tracker to use from the right texture. + RDD::BufferID shared_buffer; + RDG::ResourceTracker *shared_buffer_tracker = nullptr; + if (from_src) { + shared_buffer = p_src_texture->shared_fallback->buffer; + shared_buffer_tracker = p_src_texture->shared_fallback->buffer_tracker; + } else if (from_dst) { + shared_buffer = p_dst_texture->shared_fallback->buffer; + shared_buffer_tracker = p_dst_texture->shared_fallback->buffer_tracker; + } else { + DEV_ASSERT(false && "This path should not be reachable."); + } + + // FIXME: When using reinterpretation buffers, the only texture aspect supported is color. Depth or stencil contents won't get copied. + RDD::BufferTextureCopyRegion get_data_region; + RDG::RecordedBufferToTextureCopy update_copy; + RDD::TextureCopyableLayout first_copyable_layout; + RDD::TextureCopyableLayout copyable_layout; + RDD::TextureSubresource texture_subresource; + texture_subresource.aspect = RDD::TEXTURE_ASPECT_COLOR; + texture_subresource.layer = 0; + texture_subresource.mipmap = 0; + driver->texture_get_copyable_layout(p_dst_texture->shared_fallback->texture, texture_subresource, &first_copyable_layout); + + // Copying each mipmap from main texture to a buffer and then to the slice texture. + thread_local LocalVector<RDD::BufferTextureCopyRegion> get_data_vector; + thread_local LocalVector<RDG::RecordedBufferToTextureCopy> update_vector; + get_data_vector.clear(); + update_vector.clear(); + for (uint32_t i = 0; i < p_dst_texture->mipmaps; i++) { + driver->texture_get_copyable_layout(p_dst_texture->shared_fallback->texture, texture_subresource, ©able_layout); + + uint32_t mipmap = p_dst_texture->base_mipmap + i; + get_data_region.buffer_offset = copyable_layout.offset - first_copyable_layout.offset; + get_data_region.texture_subresources.aspect = RDD::TEXTURE_ASPECT_COLOR_BIT; + get_data_region.texture_subresources.base_layer = p_dst_texture->base_layer; + get_data_region.texture_subresources.mipmap = mipmap; + get_data_region.texture_subresources.layer_count = p_dst_texture->layers; + get_data_region.texture_region_size.x = MAX(1U, p_src_texture->width >> mipmap); + get_data_region.texture_region_size.y = MAX(1U, p_src_texture->height >> mipmap); + get_data_region.texture_region_size.z = MAX(1U, p_src_texture->depth >> mipmap); + get_data_vector.push_back(get_data_region); + + update_copy.from_buffer = shared_buffer; + update_copy.region.buffer_offset = get_data_region.buffer_offset; + update_copy.region.texture_subresources.aspect = RDD::TEXTURE_ASPECT_COLOR_BIT; + update_copy.region.texture_subresources.base_layer = texture_subresource.layer; + update_copy.region.texture_subresources.mipmap = texture_subresource.mipmap; + update_copy.region.texture_subresources.layer_count = get_data_region.texture_subresources.layer_count; + update_copy.region.texture_region_size.x = get_data_region.texture_region_size.x; + update_copy.region.texture_region_size.y = get_data_region.texture_region_size.y; + update_copy.region.texture_region_size.z = get_data_region.texture_region_size.z; + update_vector.push_back(update_copy); + + texture_subresource.mipmap++; + } + + draw_graph.add_texture_get_data(p_src_texture->driver_id, p_src_texture->draw_tracker, shared_buffer, get_data_vector, shared_buffer_tracker); + draw_graph.add_texture_update(p_dst_texture->shared_fallback->texture, p_dst_texture->shared_fallback->texture_tracker, update_vector, shared_buffer_tracker); + } else { + // Raw reinterpretation is not required. Use a regular texture copy. + RDD::TextureCopyRegion copy_region; + copy_region.src_subresources.aspect = p_src_texture->read_aspect_flags; + copy_region.src_subresources.base_layer = p_dst_texture->base_layer; + copy_region.src_subresources.layer_count = p_dst_texture->layers; + copy_region.dst_subresources.aspect = p_dst_texture->read_aspect_flags; + copy_region.dst_subresources.base_layer = 0; + copy_region.dst_subresources.layer_count = copy_region.src_subresources.layer_count; + + // Copying each mipmap from main texture to to the slice texture. + thread_local LocalVector<RDD::TextureCopyRegion> region_vector; + region_vector.clear(); + for (uint32_t i = 0; i < p_dst_texture->mipmaps; i++) { + uint32_t mipmap = p_dst_texture->base_mipmap + i; + copy_region.src_subresources.mipmap = mipmap; + copy_region.dst_subresources.mipmap = i; + copy_region.size.x = MAX(1U, p_src_texture->width >> mipmap); + copy_region.size.y = MAX(1U, p_src_texture->height >> mipmap); + copy_region.size.z = MAX(1U, p_src_texture->depth >> mipmap); + region_vector.push_back(copy_region); + } + + draw_graph.add_texture_copy(p_src_texture->driver_id, p_src_texture->draw_tracker, p_dst_texture->shared_fallback->texture, p_dst_texture->shared_fallback->texture_tracker, region_vector); + } +} + +void RenderingDevice::_texture_create_reinterpret_buffer(Texture *p_texture) { + uint64_t row_pitch_step = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP); + uint64_t transfer_alignment = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_TRANSFER_ALIGNMENT); + uint32_t pixel_bytes = get_image_format_pixel_size(p_texture->format); + uint32_t row_pitch = STEPIFY(p_texture->width * pixel_bytes, row_pitch_step); + uint64_t buffer_size = STEPIFY(pixel_bytes * row_pitch * p_texture->height * p_texture->depth, transfer_alignment); + p_texture->shared_fallback->buffer = driver->buffer_create(buffer_size, RDD::BUFFER_USAGE_TRANSFER_FROM_BIT | RDD::BUFFER_USAGE_TRANSFER_TO_BIT, RDD::MEMORY_ALLOCATION_TYPE_GPU); + buffer_memory += driver->buffer_get_allocation_size(p_texture->shared_fallback->buffer); + + RDG::ResourceTracker *tracker = RDG::resource_tracker_create(); + tracker->buffer_driver_id = p_texture->shared_fallback->buffer; + p_texture->shared_fallback->buffer_tracker = tracker; +} + Vector<uint8_t> RenderingDevice::_texture_get_data(Texture *tex, uint32_t p_layer, bool p_2d) { uint32_t width, height, depth; uint32_t tight_mip_size = get_image_format_required_size(tex->format, tex->width, tex->height, p_2d ? 1 : tex->depth, tex->mipmaps, &width, &height, &depth); @@ -1535,6 +1800,9 @@ Error RenderingDevice::texture_copy(RID p_from_texture, RID p_to_texture, const copy_region.size = p_size; + // Indicate the texture will get modified for the shared texture fallback. + _texture_update_shared_fallback(p_to_texture, dst_tex, true); + // The textures must be mutable to be used in the copy operation. bool src_made_mutable = _texture_make_mutable(src_tex, p_from_texture); bool dst_made_mutable = _texture_make_mutable(dst_tex, p_to_texture); @@ -1578,6 +1846,9 @@ Error RenderingDevice::texture_resolve_multisample(RID p_from_texture, RID p_to_ ERR_FAIL_COND_V_MSG(src_tex->read_aspect_flags != dst_tex->read_aspect_flags, ERR_INVALID_PARAMETER, "Source and destination texture must be of the same type (color or depth)."); + // Indicate the texture will get modified for the shared texture fallback. + _texture_update_shared_fallback(p_to_texture, dst_tex, true); + // The textures must be mutable to be used in the resolve operation. bool src_made_mutable = _texture_make_mutable(src_tex, p_from_texture); bool dst_made_mutable = _texture_make_mutable(dst_tex, p_to_texture); @@ -1620,6 +1891,9 @@ Error RenderingDevice::texture_clear(RID p_texture, const Color &p_color, uint32 range.base_layer = src_tex->base_layer + p_base_layer; range.layer_count = p_layers; + // Indicate the texture will get modified for the shared texture fallback. + _texture_update_shared_fallback(p_texture, src_tex, true); + if (_texture_make_mutable(src_tex, p_texture)) { // The texture must be mutable to be used as a clear destination. draw_graph.add_synchronization(); @@ -2526,6 +2800,14 @@ RID RenderingDevice::uniform_buffer_create(uint32_t p_size_bytes, const Vector<u return id; } +void RenderingDevice::_uniform_set_update_shared(UniformSet *p_uniform_set) { + for (UniformSet::SharedTexture shared : p_uniform_set->shared_textures_to_update) { + Texture *texture = texture_owner.get_or_null(shared.texture); + ERR_CONTINUE(texture == nullptr); + _texture_update_shared_fallback(shared.texture, texture, shared.writing); + } +} + RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set) { _THREAD_SAFE_METHOD_ @@ -2554,6 +2836,7 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p Vector<RDG::ResourceTracker *> draw_trackers; Vector<RDG::ResourceUsage> draw_trackers_usage; HashMap<RID, RDG::ResourceUsage> untracked_usage; + Vector<UniformSet::SharedTexture> shared_textures_to_update; for (uint32_t i = 0; i < set_uniform_count; i++) { const ShaderUniform &set_uniform = set_uniforms[i]; @@ -2619,8 +2902,16 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p attachable_textures.push_back(attachable_texture); } - if (texture->draw_tracker != nullptr) { - draw_trackers.push_back(texture->draw_tracker); + RDD::TextureID driver_id = texture->driver_id; + RDG::ResourceTracker *tracker = texture->draw_tracker; + if (texture->shared_fallback != nullptr && texture->shared_fallback->texture.id != 0) { + driver_id = texture->shared_fallback->texture; + tracker = texture->shared_fallback->texture_tracker; + shared_textures_to_update.push_back({ false, texture_id }); + } + + if (tracker != nullptr) { + draw_trackers.push_back(tracker); draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_TEXTURE_SAMPLE); } else { untracked_usage[texture_id] = RDG::RESOURCE_USAGE_TEXTURE_SAMPLE; @@ -2629,7 +2920,7 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner)); driver_uniform.ids.push_back(*sampler_driver_id); - driver_uniform.ids.push_back(texture->driver_id); + driver_uniform.ids.push_back(driver_id); } } break; case UNIFORM_TYPE_TEXTURE: { @@ -2656,8 +2947,16 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p attachable_textures.push_back(attachable_texture); } - if (texture->draw_tracker != nullptr) { - draw_trackers.push_back(texture->draw_tracker); + RDD::TextureID driver_id = texture->driver_id; + RDG::ResourceTracker *tracker = texture->draw_tracker; + if (texture->shared_fallback != nullptr && texture->shared_fallback->texture.id != 0) { + driver_id = texture->shared_fallback->texture; + tracker = texture->shared_fallback->texture_tracker; + shared_textures_to_update.push_back({ false, texture_id }); + } + + if (tracker != nullptr) { + draw_trackers.push_back(tracker); draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_TEXTURE_SAMPLE); } else { untracked_usage[texture_id] = RDG::RESOURCE_USAGE_TEXTURE_SAMPLE; @@ -2665,7 +2964,7 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner)); - driver_uniform.ids.push_back(texture->driver_id); + driver_uniform.ids.push_back(driver_id); } } break; case UNIFORM_TYPE_IMAGE: { @@ -2687,6 +2986,10 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT), RID(), "Image (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_STORAGE_BIT usage flag set in order to be used as uniform."); + if (texture->owner.is_null() && texture->shared_fallback != nullptr) { + shared_textures_to_update.push_back({ true, texture_id }); + } + if (_texture_make_mutable(texture, texture_id)) { // The texture must be mutable as a layout transition will be required. draw_graph.add_synchronization(); @@ -2872,6 +3175,7 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p uniform_set.draw_trackers = draw_trackers; uniform_set.draw_trackers_usage = draw_trackers_usage; uniform_set.untracked_usage = untracked_usage; + uniform_set.shared_textures_to_update = shared_textures_to_update; uniform_set.shader_set = p_shader_set; uniform_set.shader_id = p_shader; @@ -3347,12 +3651,16 @@ Error RenderingDevice::_draw_list_render_pass_begin(Framebuffer *p_framebuffer, for (int i = 0; i < p_framebuffer->texture_ids.size(); i++) { RDD::RenderPassClearValue clear_value; - Texture *texture = texture_owner.get_or_null(p_framebuffer->texture_ids[i]); + RID texture_rid = p_framebuffer->texture_ids[i]; + Texture *texture = texture_owner.get_or_null(texture_rid); if (!texture) { color_index++; continue; } + // Indicate the texture will get modified for the shared texture fallback. + _texture_update_shared_fallback(texture_rid, texture, true); + if (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { if (color_index < p_clear_colors.size()) { ERR_FAIL_INDEX_V(color_index, p_clear_colors.size(), ERR_BUG); // A bug. @@ -3816,6 +4124,8 @@ void RenderingDevice::draw_list_draw(DrawListID p_list, bool p_use_indices, uint draw_graph.add_draw_list_bind_uniform_set(dl->state.pipeline_shader_driver_id, dl->state.sets[i].uniform_set_driver_id, i); UniformSet *uniform_set = uniform_set_owner.get_or_null(dl->state.sets[i].uniform_set); + _uniform_set_update_shared(uniform_set); + draw_graph.add_draw_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage); dl->state.sets[i].bound = true; @@ -4222,6 +4532,8 @@ void RenderingDevice::compute_list_dispatch(ComputeListID p_list, uint32_t p_x_g draw_graph.add_compute_list_bind_uniform_set(cl->state.pipeline_shader_driver_id, cl->state.sets[i].uniform_set_driver_id, i); UniformSet *uniform_set = uniform_set_owner.get_or_null(cl->state.sets[i].uniform_set); + _uniform_set_update_shared(uniform_set); + draw_graph.add_compute_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage); cl->state.sets[i].bound = true; @@ -4329,6 +4641,8 @@ void RenderingDevice::compute_list_dispatch_indirect(ComputeListID p_list, RID p draw_graph.add_compute_list_bind_uniform_set(cl->state.pipeline_shader_driver_id, cl->state.sets[i].uniform_set_driver_id, i); UniformSet *uniform_set = uniform_set_owner.get_or_null(cl->state.sets[i].uniform_set); + _uniform_set_update_shared(uniform_set); + draw_graph.add_compute_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage); cl->state.sets[i].bound = true; @@ -4420,6 +4734,7 @@ bool RenderingDevice::_texture_make_mutable(Texture *p_texture, RID p_texture_id draw_tracker->parent = owner_texture->draw_tracker; draw_tracker->texture_driver_id = p_texture->driver_id; draw_tracker->texture_subresources = p_texture->barrier_range(); + draw_tracker->texture_usage = p_texture->usage_flags; draw_tracker->texture_slice_or_dirty_rect = p_texture->slice_rect; owner_texture->slice_trackers[p_texture->slice_rect] = draw_tracker; } @@ -4441,6 +4756,7 @@ bool RenderingDevice::_texture_make_mutable(Texture *p_texture, RID p_texture_id p_texture->draw_tracker = RDG::resource_tracker_create(); p_texture->draw_tracker->texture_driver_id = p_texture->driver_id; p_texture->draw_tracker->texture_subresources = p_texture->barrier_range(); + p_texture->draw_tracker->texture_usage = p_texture->usage_flags; p_texture->draw_tracker->reference_count = 1; if (p_texture_id.is_valid()) { @@ -4837,6 +5153,8 @@ void RenderingDevice::_free_pending_resources(int p_frame) { WARN_PRINT("Deleted a texture while it was bound."); } + _texture_free_shared_fallback(texture); + texture_memory -= driver->texture_get_allocation_size(texture->driver_id); driver->texture_free(texture->driver_id); diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index d0fa4ab1fa..38ffd5d23d 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -207,6 +207,15 @@ public: // for a framebuffer to render into it. struct Texture { + struct SharedFallback { + uint32_t revision = 1; + RDD::TextureID texture; + RDG::ResourceTracker *texture_tracker = nullptr; + RDD::BufferID buffer; + RDG::ResourceTracker *buffer_tracker = nullptr; + bool raw_reinterpretation = false; + }; + RDD::TextureID driver_id; TextureType type = TEXTURE_TYPE_MAX; @@ -235,6 +244,7 @@ public: RDG::ResourceTracker *draw_tracker = nullptr; HashMap<Rect2i, RDG::ResourceTracker *> slice_trackers; + SharedFallback *shared_fallback = nullptr; RDD::TextureSubresourceRange barrier_range() const { RDD::TextureSubresourceRange r; @@ -245,6 +255,22 @@ public: r.layer_count = layers; return r; } + + TextureFormat texture_format() const { + TextureFormat tf; + tf.format = format; + tf.width = width; + tf.height = height; + tf.depth = depth; + tf.array_layers = layers; + tf.mipmaps = mipmaps; + tf.texture_type = type; + tf.samples = samples; + tf.usage_bits = usage_flags; + tf.shareable_formats = allowed_shared_formats; + tf.is_resolve_buffer = is_resolve_buffer; + return tf; + } }; RID_Owner<Texture> texture_owner; @@ -252,6 +278,11 @@ public: Vector<uint8_t> _texture_get_data(Texture *tex, uint32_t p_layer, bool p_2d = false); Error _texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, bool p_use_setup_queue, bool p_validate_can_update); + void _texture_check_shared_fallback(Texture *p_texture); + void _texture_update_shared_fallback(RID p_texture_rid, Texture *p_texture, bool p_for_writing); + void _texture_free_shared_fallback(Texture *p_texture); + void _texture_copy_shared(RID p_src_texture_rid, Texture *p_src_texture, RID p_dst_texture_rid, Texture *p_dst_texture); + void _texture_create_reinterpret_buffer(Texture *p_texture); public: struct TextureView { @@ -916,16 +947,24 @@ private: RID texture; }; + struct SharedTexture { + uint32_t writing = 0; + RID texture; + }; + LocalVector<AttachableTexture> attachable_textures; // Used for validation. Vector<RDG::ResourceTracker *> draw_trackers; Vector<RDG::ResourceUsage> draw_trackers_usage; HashMap<RID, RDG::ResourceUsage> untracked_usage; + LocalVector<SharedTexture> shared_textures_to_update; InvalidationCallback invalidated_callback = nullptr; void *invalidated_callback_userdata = nullptr; }; RID_Owner<UniformSet> uniform_set_owner; + void _uniform_set_update_shared(UniformSet *p_uniform_set); + public: RID uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set); bool uniform_set_is_valid(RID p_uniform_set); diff --git a/servers/rendering/rendering_device_driver.cpp b/servers/rendering/rendering_device_driver.cpp index be74467340..3b8e3efeb8 100644 --- a/servers/rendering/rendering_device_driver.cpp +++ b/servers/rendering/rendering_device_driver.cpp @@ -372,6 +372,8 @@ uint64_t RenderingDeviceDriver::api_trait_get(ApiTrait p_trait) { return 1; case API_TRAIT_SECONDARY_VIEWPORT_SCISSOR: return 1; + case API_TRAIT_CLEARS_WITH_COPY_ENGINE: + return true; default: ERR_FAIL_V(0); } diff --git a/servers/rendering/rendering_device_driver.h b/servers/rendering/rendering_device_driver.h index f9a861426a..0b5fc51a1d 100644 --- a/servers/rendering/rendering_device_driver.h +++ b/servers/rendering/rendering_device_driver.h @@ -220,15 +220,17 @@ public: enum TextureLayout { TEXTURE_LAYOUT_UNDEFINED, - TEXTURE_LAYOUT_GENERAL, + TEXTURE_LAYOUT_STORAGE_OPTIMAL, TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, TEXTURE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, - TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, - TEXTURE_LAYOUT_PREINITIALIZED, - TEXTURE_LAYOUT_VRS_ATTACHMENT_OPTIMAL = 1000164003, + TEXTURE_LAYOUT_COPY_SRC_OPTIMAL, + TEXTURE_LAYOUT_COPY_DST_OPTIMAL, + TEXTURE_LAYOUT_RESOLVE_SRC_OPTIMAL, + TEXTURE_LAYOUT_RESOLVE_DST_OPTIMAL, + TEXTURE_LAYOUT_VRS_ATTACHMENT_OPTIMAL, + TEXTURE_LAYOUT_MAX }; enum TextureAspect { @@ -284,6 +286,7 @@ public: virtual uint8_t *texture_map(TextureID p_texture, const TextureSubresource &p_subresource) = 0; virtual void texture_unmap(TextureID p_texture) = 0; virtual BitField<TextureUsageBits> texture_get_usages_supported_by_format(DataFormat p_format, bool p_cpu_readable) = 0; + virtual bool texture_can_make_shared_with_format(TextureID p_texture, DataFormat p_format, bool &r_raw_reinterpretation) = 0; /*****************/ /**** SAMPLER ****/ @@ -317,10 +320,12 @@ public: PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT = (1 << 9), PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT = (1 << 10), PIPELINE_STAGE_COMPUTE_SHADER_BIT = (1 << 11), - PIPELINE_STAGE_TRANSFER_BIT = (1 << 12), + PIPELINE_STAGE_COPY_BIT = (1 << 12), PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT = (1 << 13), + PIPELINE_STAGE_RESOLVE_BIT = (1 << 14), PIPELINE_STAGE_ALL_GRAPHICS_BIT = (1 << 15), PIPELINE_STAGE_ALL_COMMANDS_BIT = (1 << 16), + PIPELINE_STAGE_CLEAR_STORAGE_BIT = (1 << 17), }; enum BarrierAccessBits { @@ -335,13 +340,16 @@ public: BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT = (1 << 8), BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT = (1 << 9), BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = (1 << 10), - BARRIER_ACCESS_TRANSFER_READ_BIT = (1 << 11), - BARRIER_ACCESS_TRANSFER_WRITE_BIT = (1 << 12), + BARRIER_ACCESS_COPY_READ_BIT = (1 << 11), + BARRIER_ACCESS_COPY_WRITE_BIT = (1 << 12), BARRIER_ACCESS_HOST_READ_BIT = (1 << 13), BARRIER_ACCESS_HOST_WRITE_BIT = (1 << 14), BARRIER_ACCESS_MEMORY_READ_BIT = (1 << 15), BARRIER_ACCESS_MEMORY_WRITE_BIT = (1 << 16), BARRIER_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT = (1 << 23), + BARRIER_ACCESS_RESOLVE_READ_BIT = (1 << 24), + BARRIER_ACCESS_RESOLVE_WRITE_BIT = (1 << 25), + BARRIER_ACCESS_STORAGE_CLEAR_BIT = (1 << 27), }; struct MemoryBarrier { @@ -735,7 +743,9 @@ public: API_TRAIT_TEXTURE_TRANSFER_ALIGNMENT, API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP, API_TRAIT_SECONDARY_VIEWPORT_SCISSOR, + API_TRAIT_CLEARS_WITH_COPY_ENGINE, }; + enum ShaderChangeInvalidation { SHADER_CHANGE_INVALIDATION_ALL_BOUND_UNIFORM_SETS, // What Vulkan does. diff --git a/servers/rendering/rendering_device_graph.cpp b/servers/rendering/rendering_device_graph.cpp index c7de5c67cb..221ec72e4a 100644 --- a/servers/rendering/rendering_device_graph.cpp +++ b/servers/rendering/rendering_device_graph.cpp @@ -36,7 +36,8 @@ #define PRINT_COMMAND_RECORDING 0 RenderingDeviceGraph::RenderingDeviceGraph() { - // Default initialization. + driver_honors_barriers = false; + driver_clears_with_copy_engine = false; } RenderingDeviceGraph::~RenderingDeviceGraph() { @@ -44,7 +45,8 @@ RenderingDeviceGraph::~RenderingDeviceGraph() { bool RenderingDeviceGraph::_is_write_usage(ResourceUsage p_usage) { switch (p_usage) { - case RESOURCE_USAGE_TRANSFER_FROM: + case RESOURCE_USAGE_COPY_FROM: + case RESOURCE_USAGE_RESOLVE_FROM: case RESOURCE_USAGE_UNIFORM_BUFFER_READ: case RESOURCE_USAGE_INDIRECT_BUFFER_READ: case RESOURCE_USAGE_TEXTURE_BUFFER_READ: @@ -54,7 +56,8 @@ bool RenderingDeviceGraph::_is_write_usage(ResourceUsage p_usage) { case RESOURCE_USAGE_TEXTURE_SAMPLE: case RESOURCE_USAGE_STORAGE_IMAGE_READ: return false; - case RESOURCE_USAGE_TRANSFER_TO: + case RESOURCE_USAGE_COPY_TO: + case RESOURCE_USAGE_RESOLVE_TO: case RESOURCE_USAGE_TEXTURE_BUFFER_READ_WRITE: case RESOURCE_USAGE_STORAGE_BUFFER_READ_WRITE: case RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE: @@ -69,15 +72,19 @@ bool RenderingDeviceGraph::_is_write_usage(ResourceUsage p_usage) { RDD::TextureLayout RenderingDeviceGraph::_usage_to_image_layout(ResourceUsage p_usage) { switch (p_usage) { - case RESOURCE_USAGE_TRANSFER_FROM: - return RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL; - case RESOURCE_USAGE_TRANSFER_TO: - return RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL; + case RESOURCE_USAGE_COPY_FROM: + return RDD::TEXTURE_LAYOUT_COPY_SRC_OPTIMAL; + case RESOURCE_USAGE_COPY_TO: + return RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL; + case RESOURCE_USAGE_RESOLVE_FROM: + return RDD::TEXTURE_LAYOUT_RESOLVE_SRC_OPTIMAL; + case RESOURCE_USAGE_RESOLVE_TO: + return RDD::TEXTURE_LAYOUT_RESOLVE_DST_OPTIMAL; case RESOURCE_USAGE_TEXTURE_SAMPLE: return RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; case RESOURCE_USAGE_STORAGE_IMAGE_READ: case RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE: - return RDD::TEXTURE_LAYOUT_GENERAL; + return RDD::TEXTURE_LAYOUT_STORAGE_OPTIMAL; case RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE: return RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; case RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE: @@ -97,10 +104,14 @@ RDD::BarrierAccessBits RenderingDeviceGraph::_usage_to_access_bits(ResourceUsage switch (p_usage) { case RESOURCE_USAGE_NONE: return RDD::BarrierAccessBits(0); - case RESOURCE_USAGE_TRANSFER_FROM: - return RDD::BARRIER_ACCESS_TRANSFER_READ_BIT; - case RESOURCE_USAGE_TRANSFER_TO: - return RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT; + case RESOURCE_USAGE_COPY_FROM: + return RDD::BARRIER_ACCESS_COPY_READ_BIT; + case RESOURCE_USAGE_COPY_TO: + return RDD::BARRIER_ACCESS_COPY_WRITE_BIT; + case RESOURCE_USAGE_RESOLVE_FROM: + return RDD::BARRIER_ACCESS_RESOLVE_READ_BIT; + case RESOURCE_USAGE_RESOLVE_TO: + return RDD::BARRIER_ACCESS_RESOLVE_WRITE_BIT; case RESOURCE_USAGE_UNIFORM_BUFFER_READ: return RDD::BARRIER_ACCESS_UNIFORM_READ_BIT; case RESOURCE_USAGE_INDIRECT_BUFFER_READ: @@ -818,26 +829,27 @@ void RenderingDeviceGraph::_run_render_commands(int32_t p_level, const RecordedC } break; case RecordedCommand::TYPE_TEXTURE_CLEAR: { const RecordedTextureClearCommand *texture_clear_command = reinterpret_cast<const RecordedTextureClearCommand *>(command); - driver->command_clear_color_texture(r_command_buffer, texture_clear_command->texture, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, texture_clear_command->color, texture_clear_command->range); + driver->command_clear_color_texture(r_command_buffer, texture_clear_command->texture, RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL, texture_clear_command->color, texture_clear_command->range); } break; case RecordedCommand::TYPE_TEXTURE_COPY: { const RecordedTextureCopyCommand *texture_copy_command = reinterpret_cast<const RecordedTextureCopyCommand *>(command); - driver->command_copy_texture(r_command_buffer, texture_copy_command->from_texture, RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, texture_copy_command->to_texture, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, texture_copy_command->region); + const VectorView<RDD::TextureCopyRegion> command_texture_copy_regions_view(texture_copy_command->texture_copy_regions(), texture_copy_command->texture_copy_regions_count); + driver->command_copy_texture(r_command_buffer, texture_copy_command->from_texture, RDD::TEXTURE_LAYOUT_COPY_SRC_OPTIMAL, texture_copy_command->to_texture, RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL, command_texture_copy_regions_view); } break; case RecordedCommand::TYPE_TEXTURE_GET_DATA: { const RecordedTextureGetDataCommand *texture_get_data_command = reinterpret_cast<const RecordedTextureGetDataCommand *>(command); const VectorView<RDD::BufferTextureCopyRegion> command_buffer_texture_copy_regions_view(texture_get_data_command->buffer_texture_copy_regions(), texture_get_data_command->buffer_texture_copy_regions_count); - driver->command_copy_texture_to_buffer(r_command_buffer, texture_get_data_command->from_texture, RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, texture_get_data_command->to_buffer, command_buffer_texture_copy_regions_view); + driver->command_copy_texture_to_buffer(r_command_buffer, texture_get_data_command->from_texture, RDD::TEXTURE_LAYOUT_COPY_SRC_OPTIMAL, texture_get_data_command->to_buffer, command_buffer_texture_copy_regions_view); } break; case RecordedCommand::TYPE_TEXTURE_RESOLVE: { const RecordedTextureResolveCommand *texture_resolve_command = reinterpret_cast<const RecordedTextureResolveCommand *>(command); - driver->command_resolve_texture(r_command_buffer, texture_resolve_command->from_texture, RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, texture_resolve_command->src_layer, texture_resolve_command->src_mipmap, texture_resolve_command->to_texture, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, texture_resolve_command->dst_layer, texture_resolve_command->dst_mipmap); + driver->command_resolve_texture(r_command_buffer, texture_resolve_command->from_texture, RDD::TEXTURE_LAYOUT_RESOLVE_SRC_OPTIMAL, texture_resolve_command->src_layer, texture_resolve_command->src_mipmap, texture_resolve_command->to_texture, RDD::TEXTURE_LAYOUT_RESOLVE_DST_OPTIMAL, texture_resolve_command->dst_layer, texture_resolve_command->dst_mipmap); } break; case RecordedCommand::TYPE_TEXTURE_UPDATE: { const RecordedTextureUpdateCommand *texture_update_command = reinterpret_cast<const RecordedTextureUpdateCommand *>(command); const RecordedBufferToTextureCopy *command_buffer_to_texture_copies = texture_update_command->buffer_to_texture_copies(); for (uint32_t j = 0; j < texture_update_command->buffer_to_texture_copies_count; j++) { - driver->command_copy_buffer_to_texture(r_command_buffer, command_buffer_to_texture_copies[j].from_buffer, texture_update_command->to_texture, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, command_buffer_to_texture_copies[j].region); + driver->command_copy_buffer_to_texture(r_command_buffer, command_buffer_to_texture_copies[j].from_buffer, texture_update_command->to_texture, RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL, command_buffer_to_texture_copies[j].region); } } break; case RecordedCommand::TYPE_CAPTURE_TIMESTAMP: { @@ -1271,6 +1283,7 @@ void RenderingDeviceGraph::initialize(RDD *p_driver, RenderingContextDriver::Dev } driver_honors_barriers = driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS); + driver_clears_with_copy_engine = driver->api_trait_get(RDD::API_TRAIT_CLEARS_WITH_COPY_ENGINE); } void RenderingDeviceGraph::finalize() { @@ -1321,12 +1334,12 @@ void RenderingDeviceGraph::add_buffer_clear(RDD::BufferID p_dst, ResourceTracker int32_t command_index; RecordedBufferClearCommand *command = static_cast<RecordedBufferClearCommand *>(_allocate_command(sizeof(RecordedBufferClearCommand), command_index)); command->type = RecordedCommand::TYPE_BUFFER_CLEAR; - command->self_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT; + command->self_stages = RDD::PIPELINE_STAGE_COPY_BIT; command->buffer = p_dst; command->offset = p_offset; command->size = p_size; - ResourceUsage usage = RESOURCE_USAGE_TRANSFER_TO; + ResourceUsage usage = RESOURCE_USAGE_COPY_TO; _add_command_to_graph(&p_dst_tracker, &usage, 1, command_index, command); } @@ -1337,13 +1350,13 @@ void RenderingDeviceGraph::add_buffer_copy(RDD::BufferID p_src, ResourceTracker int32_t command_index; RecordedBufferCopyCommand *command = static_cast<RecordedBufferCopyCommand *>(_allocate_command(sizeof(RecordedBufferCopyCommand), command_index)); command->type = RecordedCommand::TYPE_BUFFER_COPY; - command->self_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT; + command->self_stages = RDD::PIPELINE_STAGE_COPY_BIT; command->source = p_src; command->destination = p_dst; command->region = p_region; ResourceTracker *trackers[2] = { p_dst_tracker, p_src_tracker }; - ResourceUsage usages[2] = { RESOURCE_USAGE_TRANSFER_TO, RESOURCE_USAGE_TRANSFER_FROM }; + ResourceUsage usages[2] = { RESOURCE_USAGE_COPY_TO, RESOURCE_USAGE_COPY_FROM }; _add_command_to_graph(trackers, usages, p_src_tracker != nullptr ? 2 : 1, command_index, command); } @@ -1352,13 +1365,13 @@ void RenderingDeviceGraph::add_buffer_get_data(RDD::BufferID p_src, ResourceTrac int32_t command_index; RecordedBufferGetDataCommand *command = static_cast<RecordedBufferGetDataCommand *>(_allocate_command(sizeof(RecordedBufferGetDataCommand), command_index)); command->type = RecordedCommand::TYPE_BUFFER_GET_DATA; - command->self_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT; + command->self_stages = RDD::PIPELINE_STAGE_COPY_BIT; command->source = p_src; command->destination = p_dst; command->region = p_region; if (p_src_tracker != nullptr) { - ResourceUsage usage = RESOURCE_USAGE_TRANSFER_FROM; + ResourceUsage usage = RESOURCE_USAGE_COPY_FROM; _add_command_to_graph(&p_src_tracker, &usage, 1, command_index, command); } else { _add_command_to_graph(nullptr, nullptr, 0, command_index, command); @@ -1373,7 +1386,7 @@ void RenderingDeviceGraph::add_buffer_update(RDD::BufferID p_dst, ResourceTracke int32_t command_index; RecordedBufferUpdateCommand *command = static_cast<RecordedBufferUpdateCommand *>(_allocate_command(command_size, command_index)); command->type = RecordedCommand::TYPE_BUFFER_UPDATE; - command->self_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT; + command->self_stages = RDD::PIPELINE_STAGE_COPY_BIT; command->destination = p_dst; command->buffer_copies_count = p_buffer_copies.size(); @@ -1382,7 +1395,7 @@ void RenderingDeviceGraph::add_buffer_update(RDD::BufferID p_dst, ResourceTracke buffer_copies[i] = p_buffer_copies[i]; } - ResourceUsage buffer_usage = RESOURCE_USAGE_TRANSFER_TO; + ResourceUsage buffer_usage = RESOURCE_USAGE_COPY_TO; _add_command_to_graph(&p_dst_tracker, &buffer_usage, 1, command_index, command); } @@ -1710,40 +1723,60 @@ void RenderingDeviceGraph::add_texture_clear(RDD::TextureID p_dst, ResourceTrack int32_t command_index; RecordedTextureClearCommand *command = static_cast<RecordedTextureClearCommand *>(_allocate_command(sizeof(RecordedTextureClearCommand), command_index)); command->type = RecordedCommand::TYPE_TEXTURE_CLEAR; - command->self_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT; command->texture = p_dst; command->color = p_color; command->range = p_range; - ResourceUsage usage = RESOURCE_USAGE_TRANSFER_TO; + ResourceUsage usage; + if (driver_clears_with_copy_engine) { + command->self_stages = RDD::PIPELINE_STAGE_COPY_BIT; + usage = RESOURCE_USAGE_COPY_TO; + } else { + // If the driver is uncapable of using the copy engine for clearing the image (e.g. D3D12), we must either transition the + // resource to a render target or a storage image as that's the only two ways it can perform the operation. + if (p_dst_tracker->texture_usage & RDD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + command->self_stages = RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + usage = RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE; + } else { + command->self_stages = RDD::PIPELINE_STAGE_CLEAR_STORAGE_BIT; + usage = RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE; + } + } + _add_command_to_graph(&p_dst_tracker, &usage, 1, command_index, command); } -void RenderingDeviceGraph::add_texture_copy(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, RDD::TextureCopyRegion p_region) { +void RenderingDeviceGraph::add_texture_copy(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, VectorView<RDD::TextureCopyRegion> p_texture_copy_regions) { DEV_ASSERT(p_src_tracker != nullptr); DEV_ASSERT(p_dst_tracker != nullptr); int32_t command_index; - RecordedTextureCopyCommand *command = static_cast<RecordedTextureCopyCommand *>(_allocate_command(sizeof(RecordedTextureCopyCommand), command_index)); + uint64_t command_size = sizeof(RecordedTextureCopyCommand) + p_texture_copy_regions.size() * sizeof(RDD::TextureCopyRegion); + RecordedTextureCopyCommand *command = static_cast<RecordedTextureCopyCommand *>(_allocate_command(command_size, command_index)); command->type = RecordedCommand::TYPE_TEXTURE_COPY; - command->self_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT; + command->self_stages = RDD::PIPELINE_STAGE_COPY_BIT; command->from_texture = p_src; command->to_texture = p_dst; - command->region = p_region; + command->texture_copy_regions_count = p_texture_copy_regions.size(); + + RDD::TextureCopyRegion *texture_copy_regions = command->texture_copy_regions(); + for (uint32_t i = 0; i < command->texture_copy_regions_count; i++) { + texture_copy_regions[i] = p_texture_copy_regions[i]; + } ResourceTracker *trackers[2] = { p_dst_tracker, p_src_tracker }; - ResourceUsage usages[2] = { RESOURCE_USAGE_TRANSFER_TO, RESOURCE_USAGE_TRANSFER_FROM }; + ResourceUsage usages[2] = { RESOURCE_USAGE_COPY_TO, RESOURCE_USAGE_COPY_FROM }; _add_command_to_graph(trackers, usages, 2, command_index, command); } -void RenderingDeviceGraph::add_texture_get_data(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::BufferID p_dst, VectorView<RDD::BufferTextureCopyRegion> p_buffer_texture_copy_regions) { +void RenderingDeviceGraph::add_texture_get_data(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::BufferID p_dst, VectorView<RDD::BufferTextureCopyRegion> p_buffer_texture_copy_regions, ResourceTracker *p_dst_tracker) { DEV_ASSERT(p_src_tracker != nullptr); int32_t command_index; uint64_t command_size = sizeof(RecordedTextureGetDataCommand) + p_buffer_texture_copy_regions.size() * sizeof(RDD::BufferTextureCopyRegion); RecordedTextureGetDataCommand *command = static_cast<RecordedTextureGetDataCommand *>(_allocate_command(command_size, command_index)); command->type = RecordedCommand::TYPE_TEXTURE_GET_DATA; - command->self_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT; + command->self_stages = RDD::PIPELINE_STAGE_COPY_BIT; command->from_texture = p_src; command->to_buffer = p_dst; command->buffer_texture_copy_regions_count = p_buffer_texture_copy_regions.size(); @@ -1753,8 +1786,15 @@ void RenderingDeviceGraph::add_texture_get_data(RDD::TextureID p_src, ResourceTr buffer_texture_copy_regions[i] = p_buffer_texture_copy_regions[i]; } - ResourceUsage usage = RESOURCE_USAGE_TRANSFER_FROM; - _add_command_to_graph(&p_src_tracker, &usage, 1, command_index, command); + if (p_dst_tracker != nullptr) { + // Add the optional destination tracker if it was provided. + ResourceTracker *trackers[2] = { p_dst_tracker, p_src_tracker }; + ResourceUsage usages[2] = { RESOURCE_USAGE_COPY_TO, RESOURCE_USAGE_COPY_FROM }; + _add_command_to_graph(trackers, usages, 2, command_index, command); + } else { + ResourceUsage usage = RESOURCE_USAGE_COPY_FROM; + _add_command_to_graph(&p_src_tracker, &usage, 1, command_index, command); + } } void RenderingDeviceGraph::add_texture_resolve(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, uint32_t p_src_layer, uint32_t p_src_mipmap, uint32_t p_dst_layer, uint32_t p_dst_mipmap) { @@ -1764,7 +1804,7 @@ void RenderingDeviceGraph::add_texture_resolve(RDD::TextureID p_src, ResourceTra int32_t command_index; RecordedTextureResolveCommand *command = static_cast<RecordedTextureResolveCommand *>(_allocate_command(sizeof(RecordedTextureResolveCommand), command_index)); command->type = RecordedCommand::TYPE_TEXTURE_RESOLVE; - command->self_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT; + command->self_stages = RDD::PIPELINE_STAGE_RESOLVE_BIT; command->from_texture = p_src; command->to_texture = p_dst; command->src_layer = p_src_layer; @@ -1773,18 +1813,18 @@ void RenderingDeviceGraph::add_texture_resolve(RDD::TextureID p_src, ResourceTra command->dst_mipmap = p_dst_mipmap; ResourceTracker *trackers[2] = { p_dst_tracker, p_src_tracker }; - ResourceUsage usages[2] = { RESOURCE_USAGE_TRANSFER_TO, RESOURCE_USAGE_TRANSFER_FROM }; + ResourceUsage usages[2] = { RESOURCE_USAGE_RESOLVE_TO, RESOURCE_USAGE_RESOLVE_FROM }; _add_command_to_graph(trackers, usages, 2, command_index, command); } -void RenderingDeviceGraph::add_texture_update(RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, VectorView<RecordedBufferToTextureCopy> p_buffer_copies) { +void RenderingDeviceGraph::add_texture_update(RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, VectorView<RecordedBufferToTextureCopy> p_buffer_copies, VectorView<ResourceTracker *> p_buffer_trackers) { DEV_ASSERT(p_dst_tracker != nullptr); int32_t command_index; uint64_t command_size = sizeof(RecordedTextureUpdateCommand) + p_buffer_copies.size() * sizeof(RecordedBufferToTextureCopy); RecordedTextureUpdateCommand *command = static_cast<RecordedTextureUpdateCommand *>(_allocate_command(command_size, command_index)); command->type = RecordedCommand::TYPE_TEXTURE_UPDATE; - command->self_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT; + command->self_stages = RDD::PIPELINE_STAGE_COPY_BIT; command->to_texture = p_dst; command->buffer_to_texture_copies_count = p_buffer_copies.size(); @@ -1793,8 +1833,25 @@ void RenderingDeviceGraph::add_texture_update(RDD::TextureID p_dst, ResourceTrac buffer_to_texture_copies[i] = p_buffer_copies[i]; } - ResourceUsage usage = RESOURCE_USAGE_TRANSFER_TO; - _add_command_to_graph(&p_dst_tracker, &usage, 1, command_index, command); + if (p_buffer_trackers.size() > 0) { + // Add the optional buffer trackers if they were provided. + thread_local LocalVector<ResourceTracker *> trackers; + thread_local LocalVector<ResourceUsage> usages; + trackers.clear(); + usages.clear(); + for (uint32_t i = 0; i < p_buffer_trackers.size(); i++) { + trackers.push_back(p_buffer_trackers[i]); + usages.push_back(RESOURCE_USAGE_COPY_FROM); + } + + trackers.push_back(p_dst_tracker); + usages.push_back(RESOURCE_USAGE_COPY_TO); + + _add_command_to_graph(trackers.ptr(), usages.ptr(), trackers.size(), command_index, command); + } else { + ResourceUsage usage = RESOURCE_USAGE_COPY_TO; + _add_command_to_graph(&p_dst_tracker, &usage, 1, command_index, command); + } } void RenderingDeviceGraph::add_capture_timestamp(RDD::QueryPoolID p_query_pool, uint32_t p_index) { diff --git a/servers/rendering/rendering_device_graph.h b/servers/rendering/rendering_device_graph.h index a96382e0cc..baa15f63f6 100644 --- a/servers/rendering/rendering_device_graph.h +++ b/servers/rendering/rendering_device_graph.h @@ -129,8 +129,10 @@ public: enum ResourceUsage { RESOURCE_USAGE_NONE, - RESOURCE_USAGE_TRANSFER_FROM, - RESOURCE_USAGE_TRANSFER_TO, + RESOURCE_USAGE_COPY_FROM, + RESOURCE_USAGE_COPY_TO, + RESOURCE_USAGE_RESOLVE_FROM, + RESOURCE_USAGE_RESOLVE_TO, RESOURCE_USAGE_UNIFORM_BUFFER_READ, RESOURCE_USAGE_INDIRECT_BUFFER_READ, RESOURCE_USAGE_TEXTURE_BUFFER_READ, @@ -161,6 +163,7 @@ public: RDD::BufferID buffer_driver_id; RDD::TextureID texture_driver_id; RDD::TextureSubresourceRange texture_subresources; + uint32_t texture_usage = 0; int32_t texture_slice_command_index = -1; ResourceTracker *parent = nullptr; ResourceTracker *dirty_shared_list = nullptr; @@ -337,7 +340,15 @@ private: struct RecordedTextureCopyCommand : RecordedCommand { RDD::TextureID from_texture; RDD::TextureID to_texture; - RDD::TextureCopyRegion region; + uint32_t texture_copy_regions_count = 0; + + _FORCE_INLINE_ RDD::TextureCopyRegion *texture_copy_regions() { + return reinterpret_cast<RDD::TextureCopyRegion *>(&this[1]); + } + + _FORCE_INLINE_ const RDD::TextureCopyRegion *texture_copy_regions() const { + return reinterpret_cast<const RDD::TextureCopyRegion *>(&this[1]); + } }; struct RecordedTextureGetDataCommand : RecordedCommand { @@ -596,7 +607,8 @@ private: int32_t command_synchronization_index = -1; bool command_synchronization_pending = false; BarrierGroup barrier_group; - bool driver_honors_barriers = false; + bool driver_honors_barriers : 1; + bool driver_clears_with_copy_engine : 1; WorkaroundsState workarounds_state; TightLocalVector<Frame> frames; uint32_t frame = 0; @@ -672,10 +684,10 @@ public: void add_draw_list_usages(VectorView<ResourceTracker *> p_trackers, VectorView<ResourceUsage> p_usages); void add_draw_list_end(); void add_texture_clear(RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, const Color &p_color, const RDD::TextureSubresourceRange &p_range); - void add_texture_copy(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, RDD::TextureCopyRegion p_region); - void add_texture_get_data(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::BufferID p_dst, VectorView<RDD::BufferTextureCopyRegion> p_buffer_texture_copy_regions); + void add_texture_copy(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, VectorView<RDD::TextureCopyRegion> p_texture_copy_regions); + void add_texture_get_data(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::BufferID p_dst, VectorView<RDD::BufferTextureCopyRegion> p_buffer_texture_copy_regions, ResourceTracker *p_dst_tracker = nullptr); void add_texture_resolve(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, uint32_t p_src_layer, uint32_t p_src_mipmap, uint32_t p_dst_layer, uint32_t p_dst_mipmap); - void add_texture_update(RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, VectorView<RecordedBufferToTextureCopy> p_buffer_copies); + void add_texture_update(RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, VectorView<RecordedBufferToTextureCopy> p_buffer_copies, VectorView<ResourceTracker *> p_buffer_trackers = VectorView<ResourceTracker *>()); void add_capture_timestamp(RDD::QueryPoolID p_query_pool, uint32_t p_index); void add_synchronization(); void begin_label(const String &p_label_name, const Color &p_color); diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp index 87f608bfe6..a4ee33ecc0 100644 --- a/servers/rendering/shader_compiler.cpp +++ b/servers/rendering/shader_compiler.cpp @@ -362,7 +362,7 @@ void ShaderCompiler::_dump_function_deps(const SL::ShaderNode *p_node, const Str } header += _constr(fnode->arguments[i].is_const); if (fnode->arguments[i].type == SL::TYPE_STRUCT) { - header += _qualstr(fnode->arguments[i].qualifier) + _mkid(fnode->arguments[i].type_str) + " " + _mkid(fnode->arguments[i].name); + header += _qualstr(fnode->arguments[i].qualifier) + _mkid(fnode->arguments[i].struct_name) + " " + _mkid(fnode->arguments[i].name); } else { header += _qualstr(fnode->arguments[i].qualifier) + _prestr(fnode->arguments[i].precision) + _typestr(fnode->arguments[i].type) + " " + _mkid(fnode->arguments[i].name); } @@ -743,7 +743,7 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene gcode += _constr(true); gcode += _prestr(cnode.precision, ShaderLanguage::is_float_type(cnode.type)); if (cnode.type == SL::TYPE_STRUCT) { - gcode += _mkid(cnode.type_str); + gcode += _mkid(cnode.struct_name); } else { gcode += _typestr(cnode.type); } diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 5a02980929..9aa54d0bb7 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -1389,7 +1389,7 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea *r_data_type = function->arguments[i].type; } if (r_struct_name) { - *r_struct_name = function->arguments[i].type_str; + *r_struct_name = function->arguments[i].struct_name; } if (r_array_size) { *r_array_size = function->arguments[i].array_size; @@ -1442,7 +1442,7 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea *r_array_size = shader->constants[p_identifier].array_size; } if (r_struct_name) { - *r_struct_name = shader->constants[p_identifier].type_str; + *r_struct_name = shader->constants[p_identifier].struct_name; } if (r_constant_value) { if (shader->constants[p_identifier].initializer && shader->constants[p_identifier].initializer->values.size() == 1) { @@ -3067,6 +3067,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { nullptr, TYPE_VOID, { TYPE_VOID }, { "" }, TAG_GLOBAL, false } }; +HashSet<StringName> global_func_set; + const ShaderLanguage::BuiltinFuncOutArgs ShaderLanguage::builtin_func_out_args[] = { { "modf", { 1, -1 } }, { "umulExtended", { 2, 3 } }, @@ -3432,7 +3434,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI } String func_arg_name; if (pfunc->arguments[j].type == TYPE_STRUCT) { - func_arg_name = pfunc->arguments[j].type_str; + func_arg_name = pfunc->arguments[j].struct_name; } else { func_arg_name = get_datatype_name(pfunc->arguments[j].type); } @@ -3455,10 +3457,10 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI for (int j = 0; j < args.size(); j++) { if (get_scalar_type(args[j]) == args[j] && p_func->arguments[j + 1]->type == Node::NODE_TYPE_CONSTANT && args3[j] == 0 && convert_constant(static_cast<ConstantNode *>(p_func->arguments[j + 1]), pfunc->arguments[j].type)) { //all good, but it needs implicit conversion later - } else if (args[j] != pfunc->arguments[j].type || (args[j] == TYPE_STRUCT && args2[j] != pfunc->arguments[j].type_str) || args3[j] != pfunc->arguments[j].array_size) { + } else if (args[j] != pfunc->arguments[j].type || (args[j] == TYPE_STRUCT && args2[j] != pfunc->arguments[j].struct_name) || args3[j] != pfunc->arguments[j].array_size) { String func_arg_name; if (pfunc->arguments[j].type == TYPE_STRUCT) { - func_arg_name = pfunc->arguments[j].type_str; + func_arg_name = pfunc->arguments[j].struct_name; } else { func_arg_name = get_datatype_name(pfunc->arguments[j].type); } @@ -9211,7 +9213,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f return ERR_PARSE_ERROR; } - if (shader->structs.has(name) || _find_identifier(nullptr, false, constants, name) || has_builtin(p_functions, name)) { + if (shader->structs.has(name) || _find_identifier(nullptr, false, constants, name) || has_builtin(p_functions, name, !is_constant)) { _set_redefinition_error(String(name)); return ERR_PARSE_ERROR; } @@ -9228,7 +9230,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f ShaderNode::Constant constant; constant.name = name; constant.type = is_struct ? TYPE_STRUCT : type; - constant.type_str = struct_name; + constant.struct_name = struct_name; constant.precision = precision; constant.initializer = nullptr; constant.array_size = array_size; @@ -9407,7 +9409,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f expr->datatype = constant.type; - expr->struct_name = constant.type_str; + expr->struct_name = constant.struct_name; expr->array_size = constant.array_size; @@ -9748,7 +9750,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f FunctionNode::Argument arg; arg.type = param_type; arg.name = param_name; - arg.type_str = param_struct_name; + arg.struct_name = param_struct_name; arg.precision = param_precision; arg.qualifier = param_qualifier; arg.tex_argument_check = false; @@ -9831,7 +9833,11 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f return OK; } -bool ShaderLanguage::has_builtin(const HashMap<StringName, ShaderLanguage::FunctionInfo> &p_functions, const StringName &p_name) { +bool ShaderLanguage::has_builtin(const HashMap<StringName, ShaderLanguage::FunctionInfo> &p_functions, const StringName &p_name, bool p_check_global_funcs) { + if (p_check_global_funcs && global_func_set.has(p_name)) { + return true; + } + for (const KeyValue<StringName, ShaderLanguage::FunctionInfo> &E : p_functions) { if (E.value.built_ins.has(p_name)) { return true; @@ -10371,7 +10377,11 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_ if (shader->vfunctions[i].name == completion_function) { String calltip; - calltip += get_datatype_name(shader->vfunctions[i].function->return_type); + if (shader->vfunctions[i].function->return_type == TYPE_STRUCT) { + calltip += String(shader->vfunctions[i].function->return_struct_name); + } else { + calltip += get_datatype_name(shader->vfunctions[i].function->return_type); + } if (shader->vfunctions[i].function->return_array_size > 0) { calltip += "["; @@ -10406,7 +10416,11 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_ } } - calltip += get_datatype_name(shader->vfunctions[i].function->arguments[j].type); + if (shader->vfunctions[i].function->arguments[j].type == TYPE_STRUCT) { + calltip += String(shader->vfunctions[i].function->arguments[j].struct_name); + } else { + calltip += get_datatype_name(shader->vfunctions[i].function->arguments[j].type); + } calltip += " "; calltip += shader->vfunctions[i].function->arguments[j].name; @@ -10693,6 +10707,18 @@ ShaderLanguage::ShaderLanguage() { nodes = nullptr; completion_class = TAG_GLOBAL; + int idx = 0; + while (builtin_func_defs[idx].name) { + if (builtin_func_defs[idx].tag == SubClassTag::TAG_GLOBAL) { + const StringName &name = StringName(builtin_func_defs[idx].name); + + if (!global_func_set.has(name)) { + global_func_set.insert(name); + } + } + idx++; + } + #ifdef DEBUG_ENABLED warnings_check_map.insert(ShaderWarning::UNUSED_CONSTANT, &used_constants); warnings_check_map.insert(ShaderWarning::UNUSED_FUNCTION, &used_functions); diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index 816a202b50..5615d7f457 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -583,7 +583,7 @@ public: ArgumentQualifier qualifier; StringName name; DataType type; - StringName type_str; + StringName struct_name; DataPrecision precision; //for passing textures as arguments bool tex_argument_check; @@ -618,7 +618,7 @@ public: struct Constant { StringName name; DataType type; - StringName type_str; + StringName struct_name; DataPrecision precision; ConstantNode *initializer = nullptr; int array_size; @@ -884,7 +884,7 @@ public: bool can_discard = false; bool main_function = false; }; - static bool has_builtin(const HashMap<StringName, ShaderLanguage::FunctionInfo> &p_functions, const StringName &p_name); + static bool has_builtin(const HashMap<StringName, ShaderLanguage::FunctionInfo> &p_functions, const StringName &p_name, bool p_check_global_funcs = false); typedef DataType (*GlobalShaderUniformGetTypeFunc)(const StringName &p_name); diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 5cfd8d3cd2..7637d4e7da 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2229,6 +2229,7 @@ void RenderingServer::_bind_methods() { BIND_CONSTANT(MAX_GLOW_LEVELS); BIND_CONSTANT(MAX_CURSORS); BIND_CONSTANT(MAX_2D_DIRECTIONAL_LIGHTS); + BIND_CONSTANT(MAX_MESH_SURFACES); /* TEXTURE */ diff --git a/servers/xr_server.cpp b/servers/xr_server.cpp index 2cfe98ea1e..a4e68afee0 100644 --- a/servers/xr_server.cpp +++ b/servers/xr_server.cpp @@ -98,6 +98,8 @@ void XRServer::_bind_methods() { BIND_ENUM_CONSTANT(RESET_BUT_KEEP_TILT); BIND_ENUM_CONSTANT(DONT_RESET_ROTATION); + ADD_SIGNAL(MethodInfo("reference_frame_changed")); + ADD_SIGNAL(MethodInfo("interface_added", PropertyInfo(Variant::STRING_NAME, "interface_name"))); ADD_SIGNAL(MethodInfo("interface_removed", PropertyInfo(Variant::STRING_NAME, "interface_name"))); @@ -213,11 +215,13 @@ void XRServer::center_on_hmd(RotationMode p_rotation_mode, bool p_keep_height) { reference_frame = new_reference_frame.inverse(); set_render_reference_frame(reference_frame); + emit_signal(SNAME("reference_frame_changed")); } void XRServer::clear_reference_frame() { reference_frame = Transform3D(); set_render_reference_frame(reference_frame); + emit_signal(SNAME("reference_frame_changed")); } void XRServer::_set_render_reference_frame(const Transform3D &p_reference_frame) { diff --git a/tests/core/math/test_transform_2d.h b/tests/core/math/test_transform_2d.h index 36d27ce7a9..6d3c80e5ca 100644 --- a/tests/core/math/test_transform_2d.h +++ b/tests/core/math/test_transform_2d.h @@ -45,48 +45,132 @@ Transform2D identity() { return Transform2D(); } +TEST_CASE("[Transform2D] Default constructor") { + Transform2D default_constructor = Transform2D(); + CHECK(default_constructor == Transform2D(Vector2(1, 0), Vector2(0, 1), Vector2(0, 0))); +} + +TEST_CASE("[Transform2D] Copy constructor") { + Transform2D T = create_dummy_transform(); + Transform2D copy_constructor = Transform2D(T); + CHECK(T == copy_constructor); +} + +TEST_CASE("[Transform2D] Constructor from angle and position") { + constexpr float ROTATION = Math_PI / 4; + const Vector2 TRANSLATION = Vector2(20, -20); + + const Transform2D test = Transform2D(ROTATION, TRANSLATION); + const Transform2D expected = Transform2D().rotated(ROTATION).translated(TRANSLATION); + CHECK(test == expected); +} + +TEST_CASE("[Transform2D] Constructor from angle, scale, skew and position") { + constexpr float ROTATION = Math_PI / 2; + const Vector2 SCALE = Vector2(2, 0.5); + constexpr float SKEW = Math_PI / 4; + const Vector2 TRANSLATION = Vector2(30, 0); + + const Transform2D test = Transform2D(ROTATION, SCALE, SKEW, TRANSLATION); + Transform2D expected = Transform2D().scaled(SCALE).rotated(ROTATION).translated(TRANSLATION); + expected.set_skew(SKEW); + + CHECK(test.is_equal_approx(expected)); +} + +TEST_CASE("[Transform2D] Constructor from raw values") { + const Transform2D test = Transform2D(1, 2, 3, 4, 5, 6); + const Transform2D expected = Transform2D(Vector2(1, 2), Vector2(3, 4), Vector2(5, 6)); + CHECK(test == expected); +} + +TEST_CASE("[Transform2D] xform") { + const Vector2 v = Vector2(2, 3); + const Transform2D T = Transform2D(Vector2(1, 2), Vector2(3, 4), Vector2(5, 6)); + const Vector2 expected = Vector2(1 * 2 + 3 * 3 + 5 * 1, 2 * 2 + 4 * 3 + 6 * 1); + CHECK(T.xform(v) == expected); +} + +TEST_CASE("[Transform2D] Basis xform") { + const Vector2 v = Vector2(2, 2); + const Transform2D T1 = Transform2D(Vector2(1, 2), Vector2(3, 4), Vector2(0, 0)); + + // Both versions should be the same when the origin is (0,0). + CHECK(T1.basis_xform(v) == T1.xform(v)); + + const Transform2D T2 = Transform2D(Vector2(1, 2), Vector2(3, 4), Vector2(5, 6)); + + // Each version should be different when the origin is not (0,0). + CHECK_FALSE(T2.basis_xform(v) == T2.xform(v)); +} + +TEST_CASE("[Transform2D] Affine inverse") { + const Transform2D orig = create_dummy_transform(); + const Transform2D affine_inverted = orig.affine_inverse(); + const Transform2D affine_inverted_again = affine_inverted.affine_inverse(); + CHECK(affine_inverted_again == orig); +} + +TEST_CASE("[Transform2D] Orthonormalized") { + const Transform2D T = create_dummy_transform(); + const Transform2D orthonormalized_T = T.orthonormalized(); + + // Check each basis has length 1. + CHECK(Math::is_equal_approx(orthonormalized_T[0].length_squared(), 1)); + CHECK(Math::is_equal_approx(orthonormalized_T[1].length_squared(), 1)); + + const Vector2 vx = Vector2(orthonormalized_T[0].x, orthonormalized_T[1].x); + const Vector2 vy = Vector2(orthonormalized_T[0].y, orthonormalized_T[1].y); + + // Check the basis are orthogonal. + CHECK(Math::is_equal_approx(orthonormalized_T.tdotx(vx), 1)); + CHECK(Math::is_equal_approx(orthonormalized_T.tdotx(vy), 0)); + CHECK(Math::is_equal_approx(orthonormalized_T.tdoty(vx), 0)); + CHECK(Math::is_equal_approx(orthonormalized_T.tdoty(vy), 1)); +} + TEST_CASE("[Transform2D] translation") { - Vector2 offset = Vector2(1, 2); + const Vector2 offset = Vector2(1, 2); // Both versions should give the same result applied to identity. CHECK(identity().translated(offset) == identity().translated_local(offset)); // Check both versions against left and right multiplications. - Transform2D orig = create_dummy_transform(); - Transform2D T = identity().translated(offset); + const Transform2D orig = create_dummy_transform(); + const Transform2D T = identity().translated(offset); CHECK(orig.translated(offset) == T * orig); CHECK(orig.translated_local(offset) == orig * T); } TEST_CASE("[Transform2D] scaling") { - Vector2 scaling = Vector2(1, 2); + const Vector2 scaling = Vector2(1, 2); // Both versions should give the same result applied to identity. CHECK(identity().scaled(scaling) == identity().scaled_local(scaling)); // Check both versions against left and right multiplications. - Transform2D orig = create_dummy_transform(); - Transform2D S = identity().scaled(scaling); + const Transform2D orig = create_dummy_transform(); + const Transform2D S = identity().scaled(scaling); CHECK(orig.scaled(scaling) == S * orig); CHECK(orig.scaled_local(scaling) == orig * S); } TEST_CASE("[Transform2D] rotation") { - real_t phi = 1.0; + constexpr real_t phi = 1.0; // Both versions should give the same result applied to identity. CHECK(identity().rotated(phi) == identity().rotated_local(phi)); // Check both versions against left and right multiplications. - Transform2D orig = create_dummy_transform(); - Transform2D R = identity().rotated(phi); + const Transform2D orig = create_dummy_transform(); + const Transform2D R = identity().rotated(phi); CHECK(orig.rotated(phi) == R * orig); CHECK(orig.rotated_local(phi) == orig * R); } TEST_CASE("[Transform2D] Interpolation") { - Transform2D rotate_scale_skew_pos = Transform2D(Math::deg_to_rad(170.0), Vector2(3.6, 8.0), Math::deg_to_rad(20.0), Vector2(2.4, 6.8)); - Transform2D rotate_scale_skew_pos_halfway = Transform2D(Math::deg_to_rad(85.0), Vector2(2.3, 4.5), Math::deg_to_rad(10.0), Vector2(1.2, 3.4)); + const Transform2D rotate_scale_skew_pos = Transform2D(Math::deg_to_rad(170.0), Vector2(3.6, 8.0), Math::deg_to_rad(20.0), Vector2(2.4, 6.8)); + const Transform2D rotate_scale_skew_pos_halfway = Transform2D(Math::deg_to_rad(85.0), Vector2(2.3, 4.5), Math::deg_to_rad(10.0), Vector2(1.2, 3.4)); Transform2D interpolated = Transform2D().interpolate_with(rotate_scale_skew_pos, 0.5); CHECK(interpolated.get_origin().is_equal_approx(rotate_scale_skew_pos_halfway.get_origin())); CHECK(interpolated.get_rotation() == doctest::Approx(rotate_scale_skew_pos_halfway.get_rotation())); @@ -98,8 +182,8 @@ TEST_CASE("[Transform2D] Interpolation") { } TEST_CASE("[Transform2D] Finite number checks") { - const Vector2 x(0, 1); - const Vector2 infinite(NAN, NAN); + const Vector2 x = Vector2(0, 1); + const Vector2 infinite = Vector2(NAN, NAN); CHECK_MESSAGE( Transform2D(x, x, x).is_finite(), diff --git a/tests/scene/test_instance_placeholder.h b/tests/scene/test_instance_placeholder.h new file mode 100644 index 0000000000..8e8cf7c9df --- /dev/null +++ b/tests/scene/test_instance_placeholder.h @@ -0,0 +1,532 @@ +/**************************************************************************/ +/* test_instance_placeholder.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 TEST_INSTANCE_PLACEHOLDER_H +#define TEST_INSTANCE_PLACEHOLDER_H + +#include "scene/main/instance_placeholder.h" +#include "scene/resources/packed_scene.h" + +#include "tests/test_macros.h" + +class _TestInstancePlaceholderNode : public Node { + GDCLASS(_TestInstancePlaceholderNode, Node); + +protected: + static void _bind_methods() { + ClassDB::bind_method(D_METHOD("set_int_property", "int_property"), &_TestInstancePlaceholderNode::set_int_property); + ClassDB::bind_method(D_METHOD("get_int_property"), &_TestInstancePlaceholderNode::get_int_property); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "int_property"), "set_int_property", "get_int_property"); + + ClassDB::bind_method(D_METHOD("set_reference_property", "reference_property"), &_TestInstancePlaceholderNode::set_reference_property); + ClassDB::bind_method(D_METHOD("get_reference_property"), &_TestInstancePlaceholderNode::get_reference_property); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "reference_property", PROPERTY_HINT_NODE_TYPE), "set_reference_property", "get_reference_property"); + + ClassDB::bind_method(D_METHOD("set_reference_array_property", "reference_array_property"), &_TestInstancePlaceholderNode::set_reference_array_property); + ClassDB::bind_method(D_METHOD("get_reference_array_property"), &_TestInstancePlaceholderNode::get_reference_array_property); + + // The hint string value "24/34:Node" is determined from existing PackedScenes with typed Array properties. + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "reference_array_property", PROPERTY_HINT_TYPE_STRING, "24/34:Node"), "set_reference_array_property", "get_reference_array_property"); + } + +public: + int int_property = 0; + + void set_int_property(int p_int) { + int_property = p_int; + } + + int get_int_property() const { + return int_property; + } + + Variant reference_property; + + void set_reference_property(const Variant &p_node) { + reference_property = p_node; + } + + Variant get_reference_property() const { + return reference_property; + } + + Array reference_array_property; + + void set_reference_array_property(const Array &p_array) { + reference_array_property = p_array; + } + + Array get_reference_array_property() const { + return reference_array_property; + } + + _TestInstancePlaceholderNode() { + reference_array_property.set_typed(Variant::OBJECT, "Node", Variant()); + } +}; + +namespace TestInstancePlaceholder { + +TEST_CASE("[SceneTree][InstancePlaceholder] Instantiate from placeholder with no overrides") { + GDREGISTER_CLASS(_TestInstancePlaceholderNode); + + SUBCASE("with non-node values") { + InstancePlaceholder *ip = memnew(InstancePlaceholder); + ip->set_name("TestScene"); + Node *root = memnew(Node); + SceneTree::get_singleton()->get_root()->add_child(root); + + root->add_child(ip); + // Create a scene to instance. + _TestInstancePlaceholderNode *scene = memnew(_TestInstancePlaceholderNode); + scene->set_int_property(12); + + // Pack the scene. + PackedScene *packed_scene = memnew(PackedScene); + const Error err = packed_scene->pack(scene); + REQUIRE(err == OK); + + // Instantiate the scene. + _TestInstancePlaceholderNode *created = Object::cast_to<_TestInstancePlaceholderNode>(ip->create_instance(true, packed_scene)); + REQUIRE(created != nullptr); + CHECK(created->get_name() == "TestScene"); + CHECK(created->get_int_property() == 12); + + root->queue_free(); + memdelete(scene); + } + + SUBCASE("with node value") { + InstancePlaceholder *ip = memnew(InstancePlaceholder); + ip->set_name("TestScene"); + Node *root = memnew(Node); + SceneTree::get_singleton()->get_root()->add_child(root); + + root->add_child(ip); + // Create a scene to instance. + _TestInstancePlaceholderNode *scene = memnew(_TestInstancePlaceholderNode); + Node *referenced = memnew(Node); + scene->add_child(referenced); + referenced->set_owner(scene); + scene->set_reference_property(referenced); + // Pack the scene. + PackedScene *packed_scene = memnew(PackedScene); + const Error err = packed_scene->pack(scene); + REQUIRE(err == OK); + + // Instantiate the scene. + _TestInstancePlaceholderNode *created = Object::cast_to<_TestInstancePlaceholderNode>(ip->create_instance(true, packed_scene)); + REQUIRE(created != nullptr); + CHECK(created->get_name() == "TestScene"); + CHECK(created->get_child_count() == 1); + CHECK(created->get_reference_property().identity_compare(created->get_child(0, false))); + CHECK_FALSE(created->get_reference_property().identity_compare(referenced)); + + root->queue_free(); + memdelete(scene); + } + + SUBCASE("with node-array value") { + InstancePlaceholder *ip = memnew(InstancePlaceholder); + ip->set_name("TestScene"); + Node *root = memnew(Node); + SceneTree::get_singleton()->get_root()->add_child(root); + + root->add_child(ip); + // Create a scene to instance. + _TestInstancePlaceholderNode *scene = memnew(_TestInstancePlaceholderNode); + Node *referenced1 = memnew(Node); + Node *referenced2 = memnew(Node); + scene->add_child(referenced1); + scene->add_child(referenced2); + referenced1->set_owner(scene); + referenced2->set_owner(scene); + Array node_array; + node_array.set_typed(Variant::OBJECT, "Node", Variant()); + node_array.push_back(referenced1); + node_array.push_back(referenced2); + scene->set_reference_array_property(node_array); + // Pack the scene. + PackedScene *packed_scene = memnew(PackedScene); + const Error err = packed_scene->pack(scene); + REQUIRE(err == OK); + + // Instantiate the scene. + _TestInstancePlaceholderNode *created = Object::cast_to<_TestInstancePlaceholderNode>(ip->create_instance(true, packed_scene)); + REQUIRE(created != nullptr); + CHECK(created->get_name() == "TestScene"); + CHECK(created->get_child_count() == 2); + Array created_array = created->get_reference_array_property(); + REQUIRE(created_array.size() == node_array.size()); + REQUIRE(created_array.size() == created->get_child_count()); + + // Iterate over all nodes, since the ordering is not guaranteed. + for (int i = 0; i < node_array.size(); i++) { + bool node_found = false; + for (int j = 0; j < created->get_child_count(); j++) { + if (created_array[i].identity_compare(created->get_child(j, true))) { + node_found = true; + } + } + CHECK(node_found); + } + root->queue_free(); + memdelete(scene); + } +} + +TEST_CASE("[SceneTree][InstancePlaceholder] Instantiate from placeholder with overrides") { + GDREGISTER_CLASS(_TestInstancePlaceholderNode); + + SUBCASE("with non-node values") { + InstancePlaceholder *ip = memnew(InstancePlaceholder); + Node *root = memnew(Node); + SceneTree::get_singleton()->get_root()->add_child(root); + + root->add_child(ip); + ip->set_name("TestScene"); + ip->set("int_property", 45); + // Create a scene to pack. + _TestInstancePlaceholderNode *scene = memnew(_TestInstancePlaceholderNode); + scene->set_int_property(12); + + // Pack the scene. + PackedScene *packed_scene = memnew(PackedScene); + packed_scene->pack(scene); + + // Instantiate the scene. + _TestInstancePlaceholderNode *created = Object::cast_to<_TestInstancePlaceholderNode>(ip->create_instance(true, packed_scene)); + REQUIRE(created != nullptr); + CHECK(created->get_int_property() == 45); + + root->queue_free(); + memdelete(scene); + } + + SUBCASE("with node values") { + InstancePlaceholder *ip = memnew(InstancePlaceholder); + ip->set_name("TestScene"); + Node *root = memnew(Node); + Node *overriding = memnew(Node); + SceneTree::get_singleton()->get_root()->add_child(root); + + root->add_child(ip); + root->add_child(overriding); + ip->set("reference_property", overriding); + // Create a scene to instance. + _TestInstancePlaceholderNode *scene = memnew(_TestInstancePlaceholderNode); + Node *referenced = memnew(Node); + scene->add_child(referenced); + referenced->set_owner(scene); + scene->set_reference_property(referenced); + // Pack the scene. + PackedScene *packed_scene = memnew(PackedScene); + const Error err = packed_scene->pack(scene); + REQUIRE(err == OK); + + // Instantiate the scene. + _TestInstancePlaceholderNode *created = Object::cast_to<_TestInstancePlaceholderNode>(ip->create_instance(true, packed_scene)); + REQUIRE(created != nullptr); + CHECK(created->get_name() == "TestScene"); + CHECK(created->get_child_count() == 1); + CHECK(created->get_reference_property().identity_compare(overriding)); + CHECK_FALSE(created->get_reference_property().identity_compare(referenced)); + + root->queue_free(); + memdelete(scene); + } + + SUBCASE("with node-array value") { + InstancePlaceholder *ip = memnew(InstancePlaceholder); + ip->set_name("TestScene"); + Node *root = memnew(Node); + SceneTree::get_singleton()->get_root()->add_child(root); + + Node *override1 = memnew(Node); + Node *override2 = memnew(Node); + Node *override3 = memnew(Node); + root->add_child(ip); + root->add_child(override1); + root->add_child(override2); + root->add_child(override3); + + Array override_node_array; + override_node_array.set_typed(Variant::OBJECT, "Node", Variant()); + override_node_array.push_back(override1); + override_node_array.push_back(override2); + override_node_array.push_back(override3); + + ip->set("reference_array_property", override_node_array); + + // Create a scene to instance. + _TestInstancePlaceholderNode *scene = memnew(_TestInstancePlaceholderNode); + Node *referenced1 = memnew(Node); + Node *referenced2 = memnew(Node); + + scene->add_child(referenced1); + scene->add_child(referenced2); + + referenced1->set_owner(scene); + referenced2->set_owner(scene); + Array referenced_array; + referenced_array.set_typed(Variant::OBJECT, "Node", Variant()); + referenced_array.push_back(referenced1); + referenced_array.push_back(referenced2); + + scene->set_reference_array_property(referenced_array); + // Pack the scene. + PackedScene *packed_scene = memnew(PackedScene); + const Error err = packed_scene->pack(scene); + REQUIRE(err == OK); + + // Instantiate the scene. + _TestInstancePlaceholderNode *created = Object::cast_to<_TestInstancePlaceholderNode>(ip->create_instance(true, packed_scene)); + REQUIRE(created != nullptr); + CHECK(created->get_name() == "TestScene"); + CHECK(created->get_child_count() == 2); + Array created_array = created->get_reference_array_property(); + REQUIRE_FALSE(created_array.size() == referenced_array.size()); + REQUIRE(created_array.size() == override_node_array.size()); + REQUIRE_FALSE(created_array.size() == created->get_child_count()); + + // Iterate over all nodes, since the ordering is not guaranteed. + for (int i = 0; i < override_node_array.size(); i++) { + bool node_found = false; + for (int j = 0; j < created_array.size(); j++) { + if (override_node_array[i].identity_compare(created_array[j])) { + node_found = true; + } + } + CHECK(node_found); + } + root->queue_free(); + memdelete(scene); + } +} + +TEST_CASE("[SceneTree][InstancePlaceholder] Instance a PackedScene containing an InstancePlaceholder with no overrides") { + GDREGISTER_CLASS(_TestInstancePlaceholderNode); + + // Create the internal scene. + _TestInstancePlaceholderNode *internal = memnew(_TestInstancePlaceholderNode); + internal->set_name("InternalNode"); + Node *referenced = memnew(Node); + referenced->set_name("OriginalReference"); + internal->add_child(referenced); + referenced->set_owner(internal); + internal->set_reference_property(referenced); + + // Pack the internal scene. + PackedScene *internal_scene = memnew(PackedScene); + Error err = internal_scene->pack(internal); + REQUIRE(err == OK); + + const String internal_path = OS::get_singleton()->get_cache_path().path_join("instance_placeholder_test_internal.tscn"); + err = ResourceSaver::save(internal_scene, internal_path); + REQUIRE(err == OK); + + Ref<PackedScene> internal_scene_loaded = ResourceLoader::load(internal_path, "PackedScene", ResourceFormatLoader::CacheMode::CACHE_MODE_IGNORE, &err); + REQUIRE(err == OK); + + // Create the main scene. + Node *root = memnew(Node); + root->set_name("MainNode"); + Node *overriding = memnew(Node); + overriding->set_name("OverridingReference"); + + _TestInstancePlaceholderNode *internal_created = Object::cast_to<_TestInstancePlaceholderNode>(internal_scene_loaded->instantiate(PackedScene::GEN_EDIT_STATE_MAIN_INHERITED)); + internal_created->set_scene_instance_load_placeholder(true); + root->add_child(internal_created); + internal_created->set_owner(root); + + root->add_child(overriding); + overriding->set_owner(root); + // Here we introduce an error, we override the property with an internal node to the instance placeholder. + // The InstancePlaceholder is now forced to properly resolve the Node. + internal_created->set("reference_property", NodePath("OriginalReference")); + + // Pack the main scene. + PackedScene *main_scene = memnew(PackedScene); + err = main_scene->pack(root); + REQUIRE(err == OK); + + const String main_path = OS::get_singleton()->get_cache_path().path_join("instance_placeholder_test_main.tscn"); + err = ResourceSaver::save(main_scene, main_path); + REQUIRE(err == OK); + + // // Instantiate the scene. + Ref<PackedScene> main_scene_loaded = ResourceLoader::load(main_path, "PackedScene", ResourceFormatLoader::CacheMode::CACHE_MODE_IGNORE, &err); + REQUIRE(err == OK); + + Node *instanced_main_node = main_scene_loaded->instantiate(); + REQUIRE(instanced_main_node != nullptr); + SceneTree::get_singleton()->get_root()->add_child(instanced_main_node); + CHECK(instanced_main_node->get_name() == "MainNode"); + REQUIRE(instanced_main_node->get_child_count() == 2); + InstancePlaceholder *instanced_placeholder = Object::cast_to<InstancePlaceholder>(instanced_main_node->get_child(0, true)); + REQUIRE(instanced_placeholder != nullptr); + + _TestInstancePlaceholderNode *final_node = Object::cast_to<_TestInstancePlaceholderNode>(instanced_placeholder->create_instance(true)); + REQUIRE(final_node != nullptr); + REQUIRE(final_node->get_child_count() == 1); + REQUIRE(final_node->get_reference_property().identity_compare(final_node->get_child(0, true))); + + instanced_main_node->queue_free(); + memdelete(overriding); + memdelete(root); + memdelete(internal); + DirAccess::remove_file_or_error(internal_path); + DirAccess::remove_file_or_error(main_path); +} + +TEST_CASE("[SceneTree][InstancePlaceholder] Instance a PackedScene containing an InstancePlaceholder with overrides") { + GDREGISTER_CLASS(_TestInstancePlaceholderNode); + + // Create the internal scene. + _TestInstancePlaceholderNode *internal = memnew(_TestInstancePlaceholderNode); + internal->set_name("InternalNode"); + Node *referenced = memnew(Node); + referenced->set_name("OriginalReference"); + internal->add_child(referenced); + referenced->set_owner(internal); + internal->set_reference_property(referenced); + + Node *array_ref1 = memnew(Node); + array_ref1->set_name("ArrayRef1"); + internal->add_child(array_ref1); + array_ref1->set_owner(internal); + Node *array_ref2 = memnew(Node); + array_ref2->set_name("ArrayRef2"); + internal->add_child(array_ref2); + array_ref2->set_owner(internal); + Array referenced_array; + referenced_array.set_typed(Variant::OBJECT, "Node", Variant()); + referenced_array.push_back(array_ref1); + referenced_array.push_back(array_ref2); + internal->set_reference_array_property(referenced_array); + + // Pack the internal scene. + PackedScene *internal_scene = memnew(PackedScene); + Error err = internal_scene->pack(internal); + REQUIRE(err == OK); + + const String internal_path = OS::get_singleton()->get_cache_path().path_join("instance_placeholder_test_internal_override.tscn"); + err = ResourceSaver::save(internal_scene, internal_path); + REQUIRE(err == OK); + + Ref<PackedScene> internal_scene_loaded = ResourceLoader::load(internal_path, "PackedScene", ResourceFormatLoader::CacheMode::CACHE_MODE_IGNORE, &err); + REQUIRE(err == OK); + + // Create the main scene. + Node *root = memnew(Node); + root->set_name("MainNode"); + Node *overriding = memnew(Node); + overriding->set_name("OverridingReference"); + Node *array_ext = memnew(Node); + array_ext->set_name("ExternalArrayMember"); + + _TestInstancePlaceholderNode *internal_created = Object::cast_to<_TestInstancePlaceholderNode>(internal_scene_loaded->instantiate(PackedScene::GEN_EDIT_STATE_MAIN_INHERITED)); + internal_created->set_scene_instance_load_placeholder(true); + root->add_child(internal_created); + internal_created->set_owner(root); + + root->add_child(overriding); + overriding->set_owner(root); + root->add_child(array_ext); + array_ext->set_owner(root); + // Here we introduce an error, we override the property with an internal node to the instance placeholder. + // The InstancePlaceholder is now forced to properly resolve the Node. + internal_created->set_reference_property(overriding); + Array internal_array = internal_created->get_reference_array_property(); + Array override_array; + override_array.set_typed(Variant::OBJECT, "Node", Variant()); + for (int i = 0; i < internal_array.size(); i++) { + override_array.push_back(internal_array[i]); + } + override_array.push_back(array_ext); + internal_created->set_reference_array_property(override_array); + + // Pack the main scene. + PackedScene *main_scene = memnew(PackedScene); + err = main_scene->pack(root); + REQUIRE(err == OK); + + const String main_path = OS::get_singleton()->get_cache_path().path_join("instance_placeholder_test_main_override.tscn"); + err = ResourceSaver::save(main_scene, main_path); + REQUIRE(err == OK); + + // // Instantiate the scene. + Ref<PackedScene> main_scene_loaded = ResourceLoader::load(main_path, "PackedScene", ResourceFormatLoader::CacheMode::CACHE_MODE_IGNORE, &err); + REQUIRE(err == OK); + + Node *instanced_main_node = main_scene_loaded->instantiate(); + REQUIRE(instanced_main_node != nullptr); + SceneTree::get_singleton()->get_root()->add_child(instanced_main_node); + CHECK(instanced_main_node->get_name() == "MainNode"); + REQUIRE(instanced_main_node->get_child_count() == 3); + InstancePlaceholder *instanced_placeholder = Object::cast_to<InstancePlaceholder>(instanced_main_node->get_child(0, true)); + REQUIRE(instanced_placeholder != nullptr); + + _TestInstancePlaceholderNode *final_node = Object::cast_to<_TestInstancePlaceholderNode>(instanced_placeholder->create_instance(true)); + REQUIRE(final_node != nullptr); + REQUIRE(final_node->get_child_count() == 3); + REQUIRE(final_node->get_reference_property().identity_compare(instanced_main_node->get_child(1, true))); + Array final_array = final_node->get_reference_array_property(); + REQUIRE(final_array.size() == 3); + Array wanted_node_array; + wanted_node_array.push_back(instanced_main_node->get_child(2, true)); // ExternalArrayMember + wanted_node_array.push_back(final_node->get_child(1, true)); // ArrayRef1 + wanted_node_array.push_back(final_node->get_child(2, true)); // ArrayRef2 + + // Iterate over all nodes, since the ordering is not guaranteed. + for (int i = 0; i < wanted_node_array.size(); i++) { + bool node_found = false; + for (int j = 0; j < final_array.size(); j++) { + if (wanted_node_array[i].identity_compare(final_array[j])) { + node_found = true; + } + } + CHECK(node_found); + } + + instanced_main_node->queue_free(); + memdelete(array_ext); + memdelete(overriding); + memdelete(root); + memdelete(internal); + DirAccess::remove_file_or_error(internal_path); + DirAccess::remove_file_or_error(main_path); +} + +} //namespace TestInstancePlaceholder + +#endif // TEST_INSTANCE_PLACEHOLDER_H diff --git a/tests/test_main.cpp b/tests/test_main.cpp index dd30003c01..041231888b 100644 --- a/tests/test_main.cpp +++ b/tests/test_main.cpp @@ -111,6 +111,7 @@ #include "tests/scene/test_curve_3d.h" #include "tests/scene/test_gradient.h" #include "tests/scene/test_image_texture.h" +#include "tests/scene/test_instance_placeholder.h" #include "tests/scene/test_node.h" #include "tests/scene/test_node_2d.h" #include "tests/scene/test_packed_scene.h" diff --git a/thirdparty/thorvg/inc/config.h b/thirdparty/thorvg/inc/config.h index 3ae166cf22..9c83f25c79 100644 --- a/thirdparty/thorvg/inc/config.h +++ b/thirdparty/thorvg/inc/config.h @@ -13,5 +13,5 @@ // For internal debugging: //#define THORVG_LOG_ENABLED -#define THORVG_VERSION_STRING "0.13.3" +#define THORVG_VERSION_STRING "0.13.5" #endif diff --git a/thirdparty/thorvg/inc/thorvg.h b/thirdparty/thorvg/inc/thorvg.h index 93ce18197e..f7396050d7 100644 --- a/thirdparty/thorvg/inc/thorvg.h +++ b/thirdparty/thorvg/inc/thorvg.h @@ -650,6 +650,30 @@ public: virtual Result draw() noexcept; /** + * @brief Sets the drawing region in the canvas. + * + * This function defines the rectangular area of the canvas that will be used for drawing operations. + * The specified viewport is used to clip the rendering output to the boundaries of the rectangle. + * + * @param[in] x The x-coordinate of the upper-left corner of the rectangle. + * @param[in] y The y-coordinate of the upper-left corner of the rectangle. + * @param[in] w The width of the rectangle. + * @param[in] h The height of the rectangle. + * + * @retval Result::Success when succeed, Result::InsufficientCondition otherwise. + * + * @see SwCanvas::target() + * @see GlCanvas::target() + * @see WgCanvas::target() + * + * @warning It's not allowed to change the viewport during Canvas::push() - Canvas::sync() or Canvas::update() - Canvas::sync(). + * + * @note When resetting the target, the viewport will also be reset to the target size. + * @note Experimental API + */ + virtual Result viewport(int32_t x, int32_t y, int32_t w, int32_t h) noexcept; + + /** * @brief Guarantees that drawing task is finished. * * The Canvas rendering can be performed asynchronously. To make sure that rendering is finished, @@ -1660,7 +1684,9 @@ public: * @retval Result::InvalidArguments In case no valid pointer is provided or the width, or the height or the stride is zero. * @retval Result::NonSupport In case the software engine is not supported. * - * @warning Do not access @p buffer during Canvas::draw() - Canvas::sync(). It should not be accessed while TVG is writing on it. + * @warning Do not access @p buffer during Canvas::push() - Canvas::sync(). It should not be accessed while the engine is writing on it. + * + * @see Canvas::viewport() */ Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, Colorspace cs) noexcept; @@ -1726,6 +1752,8 @@ public: * @warning This API is experimental and not officially supported. It may be modified or removed in future versions. * @warning Drawing on the main surface is currently not permitted. If the identifier (@p id) is set to @c 0, the operation will be aborted. * + * @see Canvas::viewport() + * * @note Currently, this only allows the GL_RGBA8 color space format. * @note Experimental API */ @@ -1764,6 +1792,7 @@ public: * @warning Please do not use it, this API is not official one. It could be modified in the next version. * * @note Experimental API + * @see Canvas::viewport() */ Result target(void* window, uint32_t w, uint32_t h) noexcept; @@ -1856,6 +1885,7 @@ public: * * @note For efficiency, ThorVG ignores updates to the new frame value if the difference from the current frame value * is less than 0.001. In such cases, it returns @c Result::InsufficientCondition. + * Values less than 0.001 may be disregarded and may not be accurately retained by the Animation. * * @see totalFrame() * diff --git a/thirdparty/thorvg/src/common/tvgMath.h b/thirdparty/thorvg/src/common/tvgMath.h index 60ea1d21b0..5c2966956a 100644 --- a/thirdparty/thorvg/src/common/tvgMath.h +++ b/thirdparty/thorvg/src/common/tvgMath.h @@ -31,6 +31,7 @@ #define MATH_PI 3.14159265358979323846f #define MATH_PI2 1.57079632679489661923f +#define FLOAT_EPSILON 1.0e-06f //1.192092896e-07f #define PATH_KAPPA 0.552284f #define mathMin(x, y) (((x) < (y)) ? (x) : (y)) @@ -58,13 +59,19 @@ static inline float mathRad2Deg(float radian) static inline bool mathZero(float a) { - return (fabsf(a) < FLT_EPSILON) ? true : false; + return (fabsf(a) <= FLOAT_EPSILON) ? true : false; +} + + +static inline bool mathZero(const Point& p) +{ + return mathZero(p.x) && mathZero(p.y); } static inline bool mathEqual(float a, float b) { - return (fabsf(a - b) < FLT_EPSILON); + return mathZero(a - b); } @@ -82,14 +89,14 @@ static inline bool mathEqual(const Matrix& a, const Matrix& b) static inline bool mathRightAngle(const Matrix* m) { auto radian = fabsf(atan2f(m->e21, m->e11)); - if (radian < FLT_EPSILON || mathEqual(radian, MATH_PI2) || mathEqual(radian, MATH_PI)) return true; + if (radian < FLOAT_EPSILON || mathEqual(radian, MATH_PI2) || mathEqual(radian, MATH_PI)) return true; return false; } static inline bool mathSkewed(const Matrix* m) { - return (fabsf(m->e21 + m->e12) > FLT_EPSILON); + return !mathZero(m->e21 + m->e12); } @@ -169,6 +176,12 @@ static inline float mathLength(const Point* a, const Point* b) } +static inline float mathLength(const Point& a) +{ + return sqrtf(a.x * a.x + a.y * a.y); +} + + static inline Point operator-(const Point& lhs, const Point& rhs) { return {lhs.x - rhs.x, lhs.y - rhs.y}; diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp index 7706051e3b..0a47112084 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp @@ -709,7 +709,7 @@ static bool _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char** *ref = _idFromUrl((const char*)(str + 3)); return true; } else if (len >= 10 && (str[0] == 'h' || str[0] == 'H') && (str[1] == 's' || str[1] == 'S') && (str[2] == 'l' || str[2] == 'L') && str[3] == '(' && str[len - 1] == ')') { - float_t th, ts, tb; + float th, ts, tb; const char *content, *hue, *satuation, *brightness; content = str + 4; content = _skipSpace(content, nullptr); @@ -988,7 +988,7 @@ static bool _attrParseSvgNode(void* data, const char* key, const char* value) } else if (!strcmp(key, "style")) { return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader); #ifdef THORVG_LOG_ENABLED - } else if ((!strcmp(key, "x") || !strcmp(key, "y")) && fabsf(strToFloat(value, nullptr)) > FLT_EPSILON) { + } else if ((!strcmp(key, "x") || !strcmp(key, "y")) && fabsf(strToFloat(value, nullptr)) > FLOAT_EPSILON) { TVGLOG("SVG", "Unsupported attributes used [Elements type: Svg][Attribute: %s][Value: %s]", key, value); #endif } else { @@ -1824,8 +1824,8 @@ static bool _attrParseRectNode(void* data, const char* key, const char* value) if (!strncmp(rectTags[i].tag, "rx", sz)) rect->hasRx = true; if (!strncmp(rectTags[i].tag, "ry", sz)) rect->hasRy = true; - if ((rect->rx >= FLT_EPSILON) && (rect->ry < FLT_EPSILON) && rect->hasRx && !rect->hasRy) rect->ry = rect->rx; - if ((rect->ry >= FLT_EPSILON) && (rect->rx < FLT_EPSILON) && !rect->hasRx && rect->hasRy) rect->rx = rect->ry; + if ((rect->rx >= FLOAT_EPSILON) && (rect->ry < FLOAT_EPSILON) && rect->hasRx && !rect->hasRy) rect->ry = rect->rx; + if ((rect->ry >= FLOAT_EPSILON) && (rect->rx < FLOAT_EPSILON) && !rect->hasRx && rect->hasRy) rect->rx = rect->ry; return ret; } } @@ -3708,7 +3708,7 @@ SvgLoader::~SvgLoader() void SvgLoader::run(unsigned tid) { //According to the SVG standard the value of the width/height of the viewbox set to 0 disables rendering - if ((viewFlag & SvgViewFlag::Viewbox) && (fabsf(vw) <= FLT_EPSILON || fabsf(vh) <= FLT_EPSILON)) { + if ((viewFlag & SvgViewFlag::Viewbox) && (fabsf(vw) <= FLOAT_EPSILON || fabsf(vh) <= FLOAT_EPSILON)) { TVGLOG("SVG", "The <viewBox> width and/or height set to 0 - rendering disabled."); root = Scene::gen().release(); return; diff --git a/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.h b/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.h index 30ca23b565..4151fbcdb3 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.h +++ b/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.h @@ -25,9 +25,9 @@ #include "tvgSvgLoaderCommon.h" -#define NUMBER_OF_XML_ENTITIES 8 -const char* const xmlEntity[] = {""", " ", "'", "&", "<", ">", "#", "'"}; -const int xmlEntityLength[] = {6, 6, 6, 5, 4, 4, 6, 6}; +#define NUMBER_OF_XML_ENTITIES 9 +const char* const xmlEntity[] = {" ", """, " ", "'", "&", "<", ">", "#", "'"}; +const int xmlEntityLength[] = {5, 6, 6, 6, 5, 4, 4, 6, 6}; enum class SimpleXMLType { diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp index 60763068d4..3d582d291c 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp @@ -140,7 +140,7 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const Matrix* tr fill->linear.dy = y2 - y1; fill->linear.len = fill->linear.dx * fill->linear.dx + fill->linear.dy * fill->linear.dy; - if (fill->linear.len < FLT_EPSILON) return true; + if (fill->linear.len < FLOAT_EPSILON) return true; fill->linear.dx /= fill->linear.len; fill->linear.dy /= fill->linear.len; @@ -182,7 +182,7 @@ bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix* tr auto fy = P(radial)->fy; auto fr = P(radial)->fr; - if (r < FLT_EPSILON) return true; + if (r < FLOAT_EPSILON) return true; fill->radial.dr = r - fr; fill->radial.dx = cx - fx; diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp index 4e0020ee52..04f36c727f 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp @@ -1553,7 +1553,7 @@ static bool _rasterSolidGradientRect(SwSurface* surface, const SwBBox& region, c static bool _rasterLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) { - if (fill->linear.len < FLT_EPSILON) return false; + if (fill->linear.len < FLOAT_EPSILON) return false; if (_compositing(surface)) { if (_matting(surface)) return _rasterGradientMattedRect<FillLinear>(surface, region, fill); diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp index 3387905761..0b2940c32d 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp @@ -434,10 +434,6 @@ bool SwRenderer::target(pixel_t* data, uint32_t stride, uint32_t w, uint32_t h, surface->channelSize = CHANNEL_SIZE(cs); surface->premultiplied = true; - vport.x = vport.y = 0; - vport.w = surface->w; - vport.h = surface->h; - return rasterCompositor(surface); } @@ -607,6 +603,12 @@ bool SwRenderer::mempool(bool shared) } +const Surface* SwRenderer::mainSurface() +{ + return surface; +} + + Compositor* SwRenderer::target(const RenderRegion& region, ColorSpace cs) { auto x = region.x; diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h index 02359e4a39..57be558988 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h @@ -49,6 +49,7 @@ public: bool viewport(const RenderRegion& vp) override; bool blend(BlendMethod method) override; ColorSpace colorSpace() override; + const Surface* mainSurface() override; bool clear() override; bool sync() override; diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp index e38f13db25..b9327374b6 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp @@ -124,7 +124,7 @@ static void _dashLineTo(SwDashStroke& dash, const Point* to, const Matrix* trans len -= dash.curLen; lineSplitAt(cur, dash.curLen, left, right); if (!dash.curOpGap) { - if (dash.move || dash.pattern[dash.curIdx] - dash.curLen < FLT_EPSILON) { + if (dash.move || dash.pattern[dash.curIdx] - dash.curLen < FLOAT_EPSILON) { _outlineMoveTo(*dash.outline, &left.pt1, transform); dash.move = false; } @@ -185,7 +185,7 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct len -= dash.curLen; bezSplitAt(cur, dash.curLen, left, right); if (!dash.curOpGap) { - if (dash.move || dash.pattern[dash.curIdx] - dash.curLen < FLT_EPSILON) { + if (dash.move || dash.pattern[dash.curIdx] - dash.curLen < FLOAT_EPSILON) { _outlineMoveTo(*dash.outline, &left.start, transform); dash.move = false; } diff --git a/thirdparty/thorvg/src/renderer/tvgCanvas.cpp b/thirdparty/thorvg/src/renderer/tvgCanvas.cpp index 11d6b778f7..1a36e41e78 100644 --- a/thirdparty/thorvg/src/renderer/tvgCanvas.cpp +++ b/thirdparty/thorvg/src/renderer/tvgCanvas.cpp @@ -81,6 +81,12 @@ Result Canvas::update(Paint* paint) noexcept } +Result Canvas::viewport(int32_t x, int32_t y, int32_t w, int32_t h) noexcept +{ + return pImpl->viewport(x, y, w, h); +} + + Result Canvas::sync() noexcept { return pImpl->sync(); diff --git a/thirdparty/thorvg/src/renderer/tvgCanvas.h b/thirdparty/thorvg/src/renderer/tvgCanvas.h index a1556702b1..a4b866eacb 100644 --- a/thirdparty/thorvg/src/renderer/tvgCanvas.h +++ b/thirdparty/thorvg/src/renderer/tvgCanvas.h @@ -28,10 +28,14 @@ struct Canvas::Impl { + enum Status : uint8_t {Synced = 0, Updating, Drawing}; + list<Paint*> paints; RenderMethod* renderer; + RenderRegion vport = {0, 0, INT32_MAX, INT32_MAX}; + Status status = Status::Synced; + bool refresh = false; //if all paints should be updated by force. - bool drawing = false; //on drawing condition? Impl(RenderMethod* pRenderer) : renderer(pRenderer) { @@ -41,14 +45,12 @@ struct Canvas::Impl ~Impl() { //make it sure any deffered jobs - if (renderer) { - renderer->sync(); - renderer->clear(); - } + renderer->sync(); + renderer->clear(); clearPaints(); - if (renderer && (renderer->unref() == 0)) delete(renderer); + if (renderer->unref() == 0) delete(renderer); } void clearPaints() @@ -62,7 +64,7 @@ struct Canvas::Impl Result push(unique_ptr<Paint> paint) { //You can not push paints during rendering. - if (drawing) return Result::InsufficientCondition; + if (status == Status::Drawing) return Result::InsufficientCondition; auto p = paint.release(); if (!p) return Result::MemoryCorruption; @@ -75,12 +77,12 @@ struct Canvas::Impl Result clear(bool free) { //Clear render target before drawing - if (!renderer || !renderer->clear()) return Result::InsufficientCondition; + if (!renderer->clear()) return Result::InsufficientCondition; //Free paints if (free) clearPaints(); - drawing = false; + status = Status::Synced; return Result::Success; } @@ -92,7 +94,7 @@ struct Canvas::Impl Result update(Paint* paint, bool force) { - if (paints.empty() || drawing || !renderer) return Result::InsufficientCondition; + if (paints.empty() || status == Status::Drawing) return Result::InsufficientCondition; Array<RenderData> clips; auto flag = RenderUpdateFlag::None; @@ -106,12 +108,13 @@ struct Canvas::Impl } refresh = false; } + status = Status::Updating; return Result::Success; } Result draw() { - if (drawing || paints.empty() || !renderer || !renderer->preRender()) return Result::InsufficientCondition; + if (status == Status::Drawing || paints.empty() || !renderer->preRender()) return Result::InsufficientCondition; bool rendered = false; for (auto paint : paints) { @@ -120,22 +123,37 @@ struct Canvas::Impl if (!rendered || !renderer->postRender()) return Result::InsufficientCondition; - drawing = true; - + status = Status::Drawing; return Result::Success; } Result sync() { - if (!drawing) return Result::InsufficientCondition; + if (status == Status::Synced) return Result::InsufficientCondition; if (renderer->sync()) { - drawing = false; + status = Status::Synced; return Result::Success; } return Result::InsufficientCondition; } + + Result viewport(int32_t x, int32_t y, int32_t w, int32_t h) + { + if (status != Status::Synced) return Result::InsufficientCondition; + RenderRegion val = {x, y, w, h}; + //intersect if the target buffer is already set. + auto surface = renderer->mainSurface(); + if (surface && surface->w > 0 && surface->h > 0) { + val.intersect({0, 0, (int32_t)surface->w, (int32_t)surface->h}); + } + if (vport == val) return Result::Success; + renderer->viewport(val); + vport = val; + needRefresh(); + return Result::Success; + } }; #endif /* _TVG_CANVAS_H_ */ diff --git a/thirdparty/thorvg/src/renderer/tvgGlCanvas.cpp b/thirdparty/thorvg/src/renderer/tvgGlCanvas.cpp index 940e6682f8..211dbb589c 100644 --- a/thirdparty/thorvg/src/renderer/tvgGlCanvas.cpp +++ b/thirdparty/thorvg/src/renderer/tvgGlCanvas.cpp @@ -68,6 +68,8 @@ Result GlCanvas::target(int32_t id, uint32_t w, uint32_t h) noexcept if (!renderer) return Result::MemoryCorruption; if (!renderer->target(id, w, h)) return Result::Unknown; + Canvas::pImpl->vport = {0, 0, (int32_t)w, (int32_t)h}; + renderer->viewport(Canvas::pImpl->vport); //Paints must be updated again with this new target. Canvas::pImpl->needRefresh(); diff --git a/thirdparty/thorvg/src/renderer/tvgPicture.cpp b/thirdparty/thorvg/src/renderer/tvgPicture.cpp index cfa1bccd08..5bd55a3f7b 100644 --- a/thirdparty/thorvg/src/renderer/tvgPicture.cpp +++ b/thirdparty/thorvg/src/renderer/tvgPicture.cpp @@ -29,7 +29,9 @@ RenderUpdateFlag Picture::Impl::load() { if (loader) { - if (!paint) { + if (paint) { + loader->sync(); + } else { paint = loader->paint(); if (paint) { if (w != loader->w || h != loader->h) { @@ -42,8 +44,7 @@ RenderUpdateFlag Picture::Impl::load() } return RenderUpdateFlag::None; } - } else loader->sync(); - + } if (!surface) { if ((surface = loader->bitmap())) { return RenderUpdateFlag::Image; diff --git a/thirdparty/thorvg/src/renderer/tvgRender.cpp b/thirdparty/thorvg/src/renderer/tvgRender.cpp index bdfb9f322e..14f77571fb 100644 --- a/thirdparty/thorvg/src/renderer/tvgRender.cpp +++ b/thirdparty/thorvg/src/renderer/tvgRender.cpp @@ -60,3 +60,35 @@ RenderTransform::RenderTransform(const RenderTransform* lhs, const RenderTransfo else if (rhs) m = rhs->m; else mathIdentity(&m); } + + +void RenderRegion::intersect(const RenderRegion& rhs) +{ + auto x1 = x + w; + auto y1 = y + h; + auto x2 = rhs.x + rhs.w; + auto y2 = rhs.y + rhs.h; + + x = (x > rhs.x) ? x : rhs.x; + y = (y > rhs.y) ? y : rhs.y; + w = ((x1 < x2) ? x1 : x2) - x; + h = ((y1 < y2) ? y1 : y2) - y; + + if (w < 0) w = 0; + if (h < 0) h = 0; +} + + +void RenderRegion::add(const RenderRegion& rhs) +{ + if (rhs.x < x) { + w += (x - rhs.x); + x = rhs.x; + } + if (rhs.y < y) { + h += (y - rhs.y); + y = rhs.y; + } + if (rhs.x + rhs.w > x + w) w = (rhs.x + rhs.w) - x; + if (rhs.y + rhs.h > y + h) h = (rhs.y + rhs.h) - y; +} diff --git a/thirdparty/thorvg/src/renderer/tvgRender.h b/thirdparty/thorvg/src/renderer/tvgRender.h index 4f54f2fe6b..6ea516c2f9 100644 --- a/thirdparty/thorvg/src/renderer/tvgRender.h +++ b/thirdparty/thorvg/src/renderer/tvgRender.h @@ -100,34 +100,13 @@ struct RenderRegion { int32_t x, y, w, h; - void intersect(const RenderRegion& rhs) - { - auto x1 = x + w; - auto y1 = y + h; - auto x2 = rhs.x + rhs.w; - auto y2 = rhs.y + rhs.h; - - x = (x > rhs.x) ? x : rhs.x; - y = (y > rhs.y) ? y : rhs.y; - w = ((x1 < x2) ? x1 : x2) - x; - h = ((y1 < y2) ? y1 : y2) - y; - - if (w < 0) w = 0; - if (h < 0) h = 0; - } + void intersect(const RenderRegion& rhs); + void add(const RenderRegion& rhs); - void add(const RenderRegion& rhs) + bool operator==(const RenderRegion& rhs) { - if (rhs.x < x) { - w += (x - rhs.x); - x = rhs.x; - } - if (rhs.y < y) { - h += (y - rhs.y); - y = rhs.y; - } - if (rhs.x + rhs.w > x + w) w = (rhs.x + rhs.w) - x; - if (rhs.y + rhs.h > y + h) h = (rhs.y + rhs.h) - y; + if (x == rhs.x && y == rhs.y && w == rhs.w && h == rhs.h) return true; + return false; } }; @@ -293,6 +272,7 @@ public: virtual bool viewport(const RenderRegion& vp) = 0; virtual bool blend(BlendMethod method) = 0; virtual ColorSpace colorSpace() = 0; + virtual const Surface* mainSurface() = 0; virtual bool clear() = 0; virtual bool sync() = 0; diff --git a/thirdparty/thorvg/src/renderer/tvgShape.h b/thirdparty/thorvg/src/renderer/tvgShape.h index 813cf9e2e3..55335214be 100644 --- a/thirdparty/thorvg/src/renderer/tvgShape.h +++ b/thirdparty/thorvg/src/renderer/tvgShape.h @@ -67,7 +67,7 @@ struct Shape::Impl if (opacity == 0) return false; //Shape composition is only necessary when stroking & fill are valid. - if (!rs.stroke || rs.stroke->width < FLT_EPSILON || (!rs.stroke->fill && rs.stroke->color[3] == 0)) return false; + if (!rs.stroke || rs.stroke->width < FLOAT_EPSILON || (!rs.stroke->fill && rs.stroke->color[3] == 0)) return false; if (!rs.fill && rs.color[3] == 0) return false; //translucent fill & stroke @@ -301,7 +301,7 @@ struct Shape::Impl } for (uint32_t i = 0; i < cnt; i++) { - if (pattern[i] < FLT_EPSILON) return Result::InvalidArguments; + if (pattern[i] < FLOAT_EPSILON) return Result::InvalidArguments; } //Reset dash diff --git a/thirdparty/thorvg/src/renderer/tvgSwCanvas.cpp b/thirdparty/thorvg/src/renderer/tvgSwCanvas.cpp index d154a600d5..52d85d8320 100644 --- a/thirdparty/thorvg/src/renderer/tvgSwCanvas.cpp +++ b/thirdparty/thorvg/src/renderer/tvgSwCanvas.cpp @@ -87,6 +87,8 @@ Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t if (!renderer) return Result::MemoryCorruption; if (!renderer->target(buffer, stride, w, h, static_cast<ColorSpace>(cs))) return Result::InvalidArguments; + Canvas::pImpl->vport = {0, 0, (int32_t)w, (int32_t)h}; + renderer->viewport(Canvas::pImpl->vport); //Paints must be updated again with this new target. Canvas::pImpl->needRefresh(); diff --git a/thirdparty/thorvg/src/renderer/tvgWgCanvas.cpp b/thirdparty/thorvg/src/renderer/tvgWgCanvas.cpp index 5205df1737..7db77f6d0c 100644 --- a/thirdparty/thorvg/src/renderer/tvgWgCanvas.cpp +++ b/thirdparty/thorvg/src/renderer/tvgWgCanvas.cpp @@ -63,6 +63,8 @@ Result WgCanvas::target(void* window, uint32_t w, uint32_t h) noexcept if (!renderer) return Result::MemoryCorruption; if (!renderer->target(window, w, h)) return Result::Unknown; + Canvas::pImpl->vport = {0, 0, (int32_t)w, (int32_t)h}; + renderer->viewport(Canvas::pImpl->vport); //Paints must be updated again with this new target. Canvas::pImpl->needRefresh(); diff --git a/thirdparty/thorvg/update-thorvg.sh b/thirdparty/thorvg/update-thorvg.sh index 796060d3fb..cd1aeadec0 100755 --- a/thirdparty/thorvg/update-thorvg.sh +++ b/thirdparty/thorvg/update-thorvg.sh @@ -1,6 +1,6 @@ #!/bin/bash -e -VERSION=0.13.3 +VERSION=0.13.5 cd thirdparty/thorvg/ || true rm -rf AUTHORS LICENSE inc/ src/ *.zip *.tar.gz tmp/ |
