diff options
127 files changed, 647 insertions, 464 deletions
diff --git a/.github/workflows/web_builds.yml b/.github/workflows/web_builds.yml index 8e30c99fbc..ec57fa2f0d 100644 --- a/.github/workflows/web_builds.yml +++ b/.github/workflows/web_builds.yml @@ -8,7 +8,6 @@ env: GODOT_BASE_BRANCH: master SCONSFLAGS: verbose=yes warnings=extra werror=yes debug_symbols=no use_closure_compiler=yes strict_checks=yes EM_VERSION: 3.1.64 - EM_CACHE_FOLDER: emsdk-cache concurrency: group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-web @@ -46,8 +45,7 @@ jobs: uses: mymindstorm/setup-emsdk@v14 with: version: ${{ env.EM_VERSION }} - actions-cache-folder: ${{ env.EM_CACHE_FOLDER }} - cache-key: emsdk-${{ matrix.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}-${{ github.sha }} + no-cache: true - name: Verify Emscripten setup run: | diff --git a/SConstruct b/SConstruct index 49278070ae..ee34d421e0 100644 --- a/SConstruct +++ b/SConstruct @@ -851,6 +851,7 @@ if env.msvc and not methods.using_clang(env): # MSVC "/wd4245", "/wd4267", "/wd4305", # C4305 (truncation): double to float or real_t, too hard to avoid. + "/wd4324", # C4820 (structure was padded due to alignment specifier) "/wd4514", # C4514 (unreferenced inline function has been removed) "/wd4714", # C4714 (function marked as __forceinline not inlined) "/wd4820", # C4820 (padding added after construct) diff --git a/core/io/missing_resource.cpp b/core/io/missing_resource.cpp index c78195bc46..1c15cc7dd3 100644 --- a/core/io/missing_resource.cpp +++ b/core/io/missing_resource.cpp @@ -74,6 +74,10 @@ bool MissingResource::is_recording_properties() const { return recording_properties; } +String MissingResource::get_save_class() const { + return original_class; +} + void MissingResource::_bind_methods() { ClassDB::bind_method(D_METHOD("set_original_class", "name"), &MissingResource::set_original_class); ClassDB::bind_method(D_METHOD("get_original_class"), &MissingResource::get_original_class); diff --git a/core/io/missing_resource.h b/core/io/missing_resource.h index f32d818ccb..4cded5ca24 100644 --- a/core/io/missing_resource.h +++ b/core/io/missing_resource.h @@ -57,6 +57,8 @@ public: void set_recording_properties(bool p_enable); bool is_recording_properties() const; + virtual String get_save_class() const override; + MissingResource(); }; diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index 8bfa91a220..e6136603d4 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -833,7 +833,7 @@ Error ResourceLoaderBinary::load() { } bool set_valid = true; - if (value.get_type() == Variant::OBJECT && missing_resource != nullptr) { + if (value.get_type() == Variant::OBJECT && missing_resource == nullptr && ResourceLoader::is_creating_missing_resources_if_class_unavailable_enabled()) { // If the property being set is a missing resource (and the parent is not), // then setting it will most likely not work. // Instead, save it as metadata. @@ -2225,10 +2225,10 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const Ref<Re List<ResourceData> resources; - Dictionary missing_resource_properties = p_resource->get_meta(META_MISSING_RESOURCES, Dictionary()); - { for (const Ref<Resource> &E : saved_resources) { + Dictionary missing_resource_properties = E->get_meta(META_MISSING_RESOURCES, Dictionary()); + ResourceData &rd = resources.push_back(ResourceData())->get(); rd.type = _resource_get_class(E); @@ -2243,7 +2243,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const Ref<Re continue; } - if ((F.usage & PROPERTY_USAGE_STORAGE)) { + if ((F.usage & PROPERTY_USAGE_STORAGE) || missing_resource_properties.has(F.name)) { Property p; p.name_idx = get_string_index(F.name); @@ -2258,7 +2258,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const Ref<Re p.value = E->get(F.name); } - if (p.pi.type == Variant::OBJECT && missing_resource_properties.has(F.name)) { + if (F.type == Variant::OBJECT && missing_resource_properties.has(F.name)) { // Was this missing resource overridden? If so do not save the old value. Ref<Resource> res = p.value; if (res.is_null()) { diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h index 221f38494b..3ca8f7c05d 100644 --- a/core/io/resource_importer.h +++ b/core/io/resource_importer.h @@ -148,7 +148,7 @@ public: virtual String get_option_group_file() const { return String(); } virtual Error 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 = nullptr, Variant *r_metadata = nullptr) = 0; - virtual bool can_import_threaded() const { return true; } + virtual bool can_import_threaded() const { return false; } virtual void import_threaded_begin() {} virtual void import_threaded_end() {} diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp index bad224eff4..d48e1a3622 100644 --- a/core/object/class_db.cpp +++ b/core/object/class_db.cpp @@ -750,69 +750,87 @@ void ClassDB::set_object_extension_instance(Object *p_object, const StringName & } bool ClassDB::can_instantiate(const StringName &p_class) { - OBJTYPE_RLOCK; + String script_path; + { + OBJTYPE_RLOCK; - ClassInfo *ti = classes.getptr(p_class); - if (!ti) { - if (!ScriptServer::is_global_class(p_class)) { - ERR_FAIL_V_MSG(false, vformat("Cannot get class '%s'.", String(p_class))); + ClassInfo *ti = classes.getptr(p_class); + if (!ti) { + if (!ScriptServer::is_global_class(p_class)) { + ERR_FAIL_V_MSG(false, vformat("Cannot get class '%s'.", String(p_class))); + } + script_path = ScriptServer::get_global_class_path(p_class); + goto use_script; // Open the lock for resource loading. } - String path = ScriptServer::get_global_class_path(p_class); - Ref<Script> scr = ResourceLoader::load(path); - return scr.is_valid() && scr->is_valid() && !scr->is_abstract(); - } #ifdef TOOLS_ENABLED - if ((ti->api == API_EDITOR || ti->api == API_EDITOR_EXTENSION) && !Engine::get_singleton()->is_editor_hint()) { - return false; - } + if ((ti->api == API_EDITOR || ti->api == API_EDITOR_EXTENSION) && !Engine::get_singleton()->is_editor_hint()) { + return false; + } #endif - return _can_instantiate(ti); + return _can_instantiate(ti); + } + +use_script: + Ref<Script> scr = ResourceLoader::load(script_path); + return scr.is_valid() && scr->is_valid() && !scr->is_abstract(); } bool ClassDB::is_abstract(const StringName &p_class) { - OBJTYPE_RLOCK; + String script_path; + { + OBJTYPE_RLOCK; - ClassInfo *ti = classes.getptr(p_class); - if (!ti) { - if (!ScriptServer::is_global_class(p_class)) { - ERR_FAIL_V_MSG(false, vformat("Cannot get class '%s'.", String(p_class))); + ClassInfo *ti = classes.getptr(p_class); + if (!ti) { + if (!ScriptServer::is_global_class(p_class)) { + ERR_FAIL_V_MSG(false, vformat("Cannot get class '%s'.", String(p_class))); + } + script_path = ScriptServer::get_global_class_path(p_class); + goto use_script; // Open the lock for resource loading. } - String path = ScriptServer::get_global_class_path(p_class); - Ref<Script> scr = ResourceLoader::load(path); - return scr.is_valid() && scr->is_valid() && scr->is_abstract(); - } - if (ti->creation_func != nullptr) { - return false; - } - if (!ti->gdextension) { - return true; - } + if (ti->creation_func != nullptr) { + return false; + } + if (!ti->gdextension) { + return true; + } #ifndef DISABLE_DEPRECATED - return ti->gdextension->create_instance2 == nullptr && ti->gdextension->create_instance == nullptr; + return ti->gdextension->create_instance2 == nullptr && ti->gdextension->create_instance == nullptr; #else - return ti->gdextension->create_instance2 == nullptr; + return ti->gdextension->create_instance2 == nullptr; #endif // DISABLE_DEPRECATED + } + +use_script: + Ref<Script> scr = ResourceLoader::load(script_path); + return scr.is_valid() && scr->is_valid() && scr->is_abstract(); } bool ClassDB::is_virtual(const StringName &p_class) { - OBJTYPE_RLOCK; + String script_path; + { + OBJTYPE_RLOCK; - ClassInfo *ti = classes.getptr(p_class); - if (!ti) { - if (!ScriptServer::is_global_class(p_class)) { - ERR_FAIL_V_MSG(false, vformat("Cannot get class '%s'.", String(p_class))); + ClassInfo *ti = classes.getptr(p_class); + if (!ti) { + if (!ScriptServer::is_global_class(p_class)) { + ERR_FAIL_V_MSG(false, vformat("Cannot get class '%s'.", String(p_class))); + } + script_path = ScriptServer::get_global_class_path(p_class); + goto use_script; // Open the lock for resource loading. } - String path = ScriptServer::get_global_class_path(p_class); - Ref<Script> scr = ResourceLoader::load(path); - return scr.is_valid() && scr->is_valid() && scr->is_abstract(); - } #ifdef TOOLS_ENABLED - if ((ti->api == API_EDITOR || ti->api == API_EDITOR_EXTENSION) && !Engine::get_singleton()->is_editor_hint()) { - return false; - } + if ((ti->api == API_EDITOR || ti->api == API_EDITOR_EXTENSION) && !Engine::get_singleton()->is_editor_hint()) { + return false; + } #endif - return (_can_instantiate(ti) && ti->is_virtual); + return (_can_instantiate(ti) && ti->is_virtual); + } + +use_script: + Ref<Script> scr = ResourceLoader::load(script_path); + return scr.is_valid() && scr->is_valid() && scr->is_abstract(); } void ClassDB::_add_class2(const StringName &p_class, const StringName &p_inherits) { diff --git a/core/os/spin_lock.h b/core/os/spin_lock.h index d386cd5890..8c2d5667ff 100644 --- a/core/os/spin_lock.h +++ b/core/os/spin_lock.h @@ -33,6 +33,10 @@ #include "core/typedefs.h" +#ifdef _MSC_VER +#include <intrin.h> +#endif + #if defined(__APPLE__) #include <os/lock.h> @@ -52,19 +56,52 @@ public: #else +#include "core/os/thread.h" + #include <atomic> -class SpinLock { - mutable std::atomic_flag locked = ATOMIC_FLAG_INIT; +_ALWAYS_INLINE_ static void _cpu_pause() { +#if defined(_MSC_VER) +// ----- MSVC. +#if defined(_M_ARM) || defined(_M_ARM64) // ARM. + __yield(); +#elif defined(_M_IX86) || defined(_M_X64) // x86. + _mm_pause(); +#endif +#elif defined(__GNUC__) || defined(__clang__) +// ----- GCC/Clang. +#if defined(__i386__) || defined(__x86_64__) // x86. + __builtin_ia32_pause(); +#elif defined(__arm__) || defined(__aarch64__) // ARM. + asm volatile("yield"); +#elif defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) // PowerPC. + asm volatile("or 27,27,27"); +#elif defined(__riscv) // RISC-V. + asm volatile(".insn i 0x0F, 0, x0, x0, 0x010"); +#endif +#endif +} + +static_assert(std::atomic_bool::is_always_lock_free); + +class alignas(Thread::CACHE_LINE_BYTES) SpinLock { + mutable std::atomic<bool> locked = ATOMIC_VAR_INIT(false); public: _ALWAYS_INLINE_ void lock() const { - while (locked.test_and_set(std::memory_order_acquire)) { - // Continue. + while (true) { + bool expected = false; + if (locked.compare_exchange_weak(expected, true, std::memory_order_acquire, std::memory_order_relaxed)) { + break; + } + do { + _cpu_pause(); + } while (locked.load(std::memory_order_relaxed)); } } + _ALWAYS_INLINE_ void unlock() const { - locked.clear(std::memory_order_release); + locked.store(false, std::memory_order_release); } }; diff --git a/core/os/thread.h b/core/os/thread.h index a0ecc24c91..1c442b41f6 100644 --- a/core/os/thread.h +++ b/core/os/thread.h @@ -42,6 +42,8 @@ #include "core/templates/safe_refcount.h" #include "core/typedefs.h" +#include <new> + #ifdef MINGW_ENABLED #define MINGW_STDTHREAD_REDUNDANCY_WARNING #include "thirdparty/mingw-std-threads/mingw.thread.h" @@ -85,6 +87,20 @@ public: void (*term)() = nullptr; }; +#if defined(__cpp_lib_hardware_interference_size) && !defined(ANDROID_ENABLED) // This would be OK with NDK >= 26. +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Winterference-size" +#endif + static constexpr size_t CACHE_LINE_BYTES = std::hardware_destructive_interference_size; +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif +#else + // At a negligible memory cost, we use a conservatively high value. + static constexpr size_t CACHE_LINE_BYTES = 128; +#endif + private: friend class Main; @@ -135,6 +151,8 @@ public: typedef uint64_t ID; + static constexpr size_t CACHE_LINE_BYTES = sizeof(void *); + enum : ID { UNASSIGNED_ID = 0, MAIN_ID = 1 diff --git a/core/templates/list.h b/core/templates/list.h index 6663f06c30..02afeec74d 100644 --- a/core/templates/list.h +++ b/core/templates/list.h @@ -224,7 +224,7 @@ private: Element *last = nullptr; int size_cache = 0; - bool erase(const Element *p_I) { + bool erase(Element *p_I) { ERR_FAIL_NULL_V(p_I, false); ERR_FAIL_COND_V(p_I->data != this, false); @@ -244,7 +244,7 @@ private: p_I->next_ptr->prev_ptr = p_I->prev_ptr; } - memdelete_allocator<Element, A>(const_cast<Element *>(p_I)); + memdelete_allocator<Element, A>(p_I); size_cache--; return true; @@ -430,7 +430,7 @@ public: /** * erase an element in the list, by iterator pointing to it. Return true if it was found/erased. */ - bool erase(const Element *p_I) { + bool erase(Element *p_I) { if (_data && p_I) { bool ret = _data->erase(p_I); diff --git a/doc/classes/AABB.xml b/doc/classes/AABB.xml index 188d9652a8..ae2de055cb 100644 --- a/doc/classes/AABB.xml +++ b/doc/classes/AABB.xml @@ -326,13 +326,13 @@ <return type="bool" /> <param index="0" name="aabb" type="AABB" /> <description> - Returns [code]true[/code] if this bounding box and [param aabb] are approximately equal, by calling [method Vector2.is_equal_approx] on the [member position] and the [member size]. + Returns [code]true[/code] if this bounding box and [param aabb] are approximately equal, by calling [method Vector3.is_equal_approx] on the [member position] and the [member size]. </description> </method> <method name="is_finite" qualifiers="const"> <return type="bool" /> <description> - Returns [code]true[/code] if this bounding box's values are finite, by calling [method Vector2.is_finite] on the [member position] and the [member size]. + Returns [code]true[/code] if this bounding box's values are finite, by calling [method Vector3.is_finite] on the [member position] and the [member size]. </description> </method> <method name="merge" qualifiers="const"> diff --git a/doc/classes/AnimationNodeStateMachineTransition.xml b/doc/classes/AnimationNodeStateMachineTransition.xml index 7bd0bd7e7e..c729eeebba 100644 --- a/doc/classes/AnimationNodeStateMachineTransition.xml +++ b/doc/classes/AnimationNodeStateMachineTransition.xml @@ -26,7 +26,7 @@ Use an expression as a condition for state machine transitions. It is possible to create complex animation advance conditions for switching between states and gives much greater flexibility for creating complex state machines by directly interfacing with the script code. </member> <member name="advance_mode" type="int" setter="set_advance_mode" getter="get_advance_mode" enum="AnimationNodeStateMachineTransition.AdvanceMode" default="1"> - Determines whether the transition should disabled, enabled when using [method AnimationNodeStateMachinePlayback.travel], or traversed automatically if the [member advance_condition] and [member advance_expression] checks are true (if assigned). + Determines whether the transition should be disabled, enabled when using [method AnimationNodeStateMachinePlayback.travel], or traversed automatically if the [member advance_condition] and [member advance_expression] checks are [code]true[/code] (if assigned). </member> <member name="break_loop_at_end" type="bool" setter="set_break_loop_at_end" getter="is_loop_broken_at_end" default="false"> If [code]true[/code], breaks the loop at the end of the loop cycle for transition, even if the animation is looping. @@ -72,7 +72,7 @@ Only use this transition during [method AnimationNodeStateMachinePlayback.travel]. </constant> <constant name="ADVANCE_MODE_AUTO" value="2" enum="AdvanceMode"> - Automatically use this transition if the [member advance_condition] and [member advance_expression] checks are true (if assigned). + Automatically use this transition if the [member advance_condition] and [member advance_expression] checks are [code]true[/code] (if assigned). </constant> </constants> </class> diff --git a/doc/classes/AudioStreamPlaybackPolyphonic.xml b/doc/classes/AudioStreamPlaybackPolyphonic.xml index f71762d6a5..894c9b2262 100644 --- a/doc/classes/AudioStreamPlaybackPolyphonic.xml +++ b/doc/classes/AudioStreamPlaybackPolyphonic.xml @@ -13,7 +13,7 @@ <return type="bool" /> <param index="0" name="stream" type="int" /> <description> - Return true whether the stream associated with an integer ID is still playing. Check [method play_stream] for information on when this ID becomes invalid. + Returns [code]true[/code] if the stream associated with the given integer ID is still playing. Check [method play_stream] for information on when this ID becomes invalid. </description> </method> <method name="play_stream"> diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index d455bd7d68..0131f8f4af 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -993,8 +993,9 @@ Controls whether the control will be able to receive mouse button input events through [method _gui_input] and how these events should be handled. Also controls whether the control can receive the [signal mouse_entered], and [signal mouse_exited] signals. See the constants to learn what each does. </member> <member name="mouse_force_pass_scroll_events" type="bool" setter="set_force_pass_scroll_events" getter="is_force_pass_scroll_events" default="true"> - When enabled, scroll wheel events processed by [method _gui_input] will be passed to the parent control even if [member mouse_filter] is set to [constant MOUSE_FILTER_STOP]. As it defaults to true, this allows nested scrollable containers to work out of the box. + When enabled, scroll wheel events processed by [method _gui_input] will be passed to the parent control even if [member mouse_filter] is set to [constant MOUSE_FILTER_STOP]. You should disable it on the root of your UI if you do not want scroll events to go to the [method Node._unhandled_input] processing. + [b]Note:[/b] Because this property defaults to [code]true[/code], this allows nested scrollable containers to work out of the box. </member> <member name="offset_bottom" type="float" setter="set_offset" getter="get_offset" default="0.0"> Distance between the node's bottom edge and its parent control, based on [member anchor_bottom]. diff --git a/doc/classes/EditorFileSystemImportFormatSupportQuery.xml b/doc/classes/EditorFileSystemImportFormatSupportQuery.xml index b1a810fe6e..fc2feca911 100644 --- a/doc/classes/EditorFileSystemImportFormatSupportQuery.xml +++ b/doc/classes/EditorFileSystemImportFormatSupportQuery.xml @@ -24,7 +24,7 @@ <method name="_query" qualifiers="virtual const"> <return type="bool" /> <description> - Query support. Return false if import must not continue. + Query support. Return [code]false[/code] if import must not continue. </description> </method> </methods> diff --git a/doc/classes/EditorImportPlugin.xml b/doc/classes/EditorImportPlugin.xml index 28614b6631..e5f3010366 100644 --- a/doc/classes/EditorImportPlugin.xml +++ b/doc/classes/EditorImportPlugin.xml @@ -124,7 +124,8 @@ <return type="bool" /> <description> Tells whether this importer can be run in parallel on threads, or, on the contrary, it's only safe for the editor to call it from the main thread, for one file at a time. - If this method is not overridden, it will return [code]true[/code] by default (i.e., safe for parallel importing). + If this method is not overridden, it will return [code]false[/code] by default. + If this importer's implementation is thread-safe and can be run in parallel, override this with [code]true[/code] to optimize for concurrency. </description> </method> <method name="_get_import_options" qualifiers="virtual const"> diff --git a/doc/classes/EditorResourcePreview.xml b/doc/classes/EditorResourcePreview.xml index ed3fdae352..a0c1a43fb2 100644 --- a/doc/classes/EditorResourcePreview.xml +++ b/doc/classes/EditorResourcePreview.xml @@ -32,7 +32,7 @@ <param index="3" name="userdata" type="Variant" /> <description> Queue the [param resource] being edited for preview. Once the preview is ready, the [param receiver]'s [param receiver_func] will be called. The [param receiver_func] must take the following four arguments: [String] path, [Texture2D] preview, [Texture2D] thumbnail_preview, [Variant] userdata. [param userdata] can be anything, and will be returned when [param receiver_func] is called. - [b]Note:[/b] If it was not possible to create the preview the [param receiver_func] will still be called, but the preview will be null. + [b]Note:[/b] If it was not possible to create the preview the [param receiver_func] will still be called, but the preview will be [code]null[/code]. </description> </method> <method name="queue_resource_preview"> @@ -43,7 +43,7 @@ <param index="3" name="userdata" type="Variant" /> <description> Queue a resource file located at [param path] for preview. Once the preview is ready, the [param receiver]'s [param receiver_func] will be called. The [param receiver_func] must take the following four arguments: [String] path, [Texture2D] preview, [Texture2D] thumbnail_preview, [Variant] userdata. [param userdata] can be anything, and will be returned when [param receiver_func] is called. - [b]Note:[/b] If it was not possible to create the preview the [param receiver_func] will still be called, but the preview will be null. + [b]Note:[/b] If it was not possible to create the preview the [param receiver_func] will still be called, but the preview will be [code]null[/code]. </description> </method> <method name="remove_preview_generator"> diff --git a/doc/classes/EditorScenePostImportPlugin.xml b/doc/classes/EditorScenePostImportPlugin.xml index 5c1c898c9d..0004ec65c6 100644 --- a/doc/classes/EditorScenePostImportPlugin.xml +++ b/doc/classes/EditorScenePostImportPlugin.xml @@ -28,7 +28,7 @@ <param index="0" name="category" type="int" /> <param index="1" name="option" type="String" /> <description> - Return true whether updating the 3D view of the import dialog needs to be updated if an option has changed. + Should return [code]true[/code] if the 3D view of the import dialog needs to update when changing the given option. </description> </method> <method name="_get_internal_option_visibility" qualifiers="virtual const"> @@ -37,7 +37,7 @@ <param index="1" name="for_animation" type="bool" /> <param index="2" name="option" type="String" /> <description> - Return true or false whether a given option should be visible. Return null to ignore. + Should return [code]true[/code] to show the given option, [code]false[/code] to hide the given option, or [code]null[/code] to ignore. </description> </method> <method name="_get_option_visibility" qualifiers="virtual const"> @@ -46,7 +46,7 @@ <param index="1" name="for_animation" type="bool" /> <param index="2" name="option" type="String" /> <description> - Return true or false whether a given option should be visible. Return null to ignore. + Should return [code]true[/code] to show the given option, [code]false[/code] to hide the given option, or [code]null[/code] to ignore. </description> </method> <method name="_internal_process" qualifiers="virtual"> diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index a5097521dc..be5175c4bc 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -152,7 +152,7 @@ <param index="1" name="value" type="Variant" /> <param index="2" name="update_current" type="bool" /> <description> - Sets the initial value of the setting specified by [param name] to [param value]. This is used to provide a value for the Revert button in the Editor Settings. If [param update_current] is true, the current value of the setting will be set to [param value] as well. + Sets the initial value of the setting specified by [param name] to [param value]. This is used to provide a value for the Revert button in the Editor Settings. If [param update_current] is [code]true[/code], the setting is reset to [param value] as well. </description> </method> <method name="set_project_metadata"> @@ -230,7 +230,7 @@ If [code]true[/code], when a node is deleted with animation tracks referencing it, a confirmation dialog appears before the tracks are deleted. The dialog will appear even when using the "Delete (No Confirm)" shortcut. </member> <member name="docks/scene_tree/ask_before_revoking_unique_name" type="bool" setter="" getter=""> - If [code]true[/code], displays a confirmation dialog before left-clicking the "percent" icon next to a node name in the Scene tree dock. When clicked, this icon revokes the node's scene-unique name, which can impact the behavior of scripts that rely on this scene-unique name due to identifiers not being found anymore. + If [code]true[/code], displays a confirmation dialog after left-clicking the "percent" icon next to a node name in the Scene tree dock. When clicked, this icon revokes the node's scene-unique name, which can impact the behavior of scripts that rely on this scene-unique name due to identifiers not being found anymore. </member> <member name="docks/scene_tree/auto_expand_to_selected" type="bool" setter="" getter=""> If [code]true[/code], the scene tree dock will automatically unfold nodes when a node that has folded parents is selected. @@ -1395,7 +1395,7 @@ The script editor's documentation comment color. In GDScript, this is used for comments starting with [code]##[/code]. In C#, this is used for comments starting with [code]///[/code] or [code]/**[/code]. </member> <member name="text_editor/theme/highlighting/engine_type_color" type="Color" setter="" getter=""> - The script editor's engine type color ([Vector2], [Vector3], [Color], ...). + The script editor's engine type color ([Object], [Mesh], [Node], ...). </member> <member name="text_editor/theme/highlighting/executing_line_color" type="Color" setter="" getter=""> The script editor's color for the debugger's executing line icon (displayed in the gutter). diff --git a/doc/classes/EditorUndoRedoManager.xml b/doc/classes/EditorUndoRedoManager.xml index 0f8c69a1bb..6a66a35ce8 100644 --- a/doc/classes/EditorUndoRedoManager.xml +++ b/doc/classes/EditorUndoRedoManager.xml @@ -87,7 +87,7 @@ <return type="void" /> <param index="0" name="execute" type="bool" default="true" /> <description> - Commit the action. If [param execute] is true (default), all "do" methods/properties are called/set when this function is called. + Commits the action. If [param execute] is [code]true[/code] (default), all "do" methods/properties are called/set when this function is called. </description> </method> <method name="create_action"> diff --git a/doc/classes/GraphNode.xml b/doc/classes/GraphNode.xml index cc3acad6d6..fc8bc15b5c 100644 --- a/doc/classes/GraphNode.xml +++ b/doc/classes/GraphNode.xml @@ -154,7 +154,7 @@ <return type="bool" /> <param index="0" name="slot_index" type="int" /> <description> - Returns true if the background [StyleBox] of the slot with the given [param slot_index] is drawn. + Returns [code]true[/code] if the background [StyleBox] of the slot with the given [param slot_index] is drawn. </description> </method> <method name="is_slot_enabled_left" qualifiers="const"> diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml index 0fd84fb452..9b71a8c37f 100644 --- a/doc/classes/Image.xml +++ b/doc/classes/Image.xml @@ -510,7 +510,7 @@ <param index="1" name="lossy" type="bool" default="false" /> <param index="2" name="quality" type="float" default="0.75" /> <description> - Saves the image as a WebP (Web Picture) file to the file at [param path]. By default it will save lossless. If [param lossy] is true, the image will be saved lossy, using the [param quality] setting between 0.0 and 1.0 (inclusive). Lossless WebP offers more efficient compression than PNG. + Saves the image as a WebP (Web Picture) file to the file at [param path]. By default it will save lossless. If [param lossy] is [code]true[/code], the image will be saved lossy, using the [param quality] setting between [code]0.0[/code] and [code]1.0[/code] (inclusive). Lossless WebP offers more efficient compression than PNG. [b]Note:[/b] The WebP format is limited to a size of 16383×16383 pixels, while PNG can save larger images. </description> </method> @@ -519,7 +519,7 @@ <param index="0" name="lossy" type="bool" default="false" /> <param index="1" name="quality" type="float" default="0.75" /> <description> - Saves the image as a WebP (Web Picture) file to a byte array. By default it will save lossless. If [param lossy] is true, the image will be saved lossy, using the [param quality] setting between 0.0 and 1.0 (inclusive). Lossless WebP offers more efficient compression than PNG. + Saves the image as a WebP (Web Picture) file to a byte array. By default it will save lossless. If [param lossy] is [code]true[/code], the image will be saved lossy, using the [param quality] setting between [code]0.0[/code] and [code]1.0[/code] (inclusive). Lossless WebP offers more efficient compression than PNG. [b]Note:[/b] The WebP format is limited to a size of 16383×16383 pixels, while PNG can save larger images. </description> </method> diff --git a/doc/classes/MultiplayerPeer.xml b/doc/classes/MultiplayerPeer.xml index edb2c39e24..cec9464102 100644 --- a/doc/classes/MultiplayerPeer.xml +++ b/doc/classes/MultiplayerPeer.xml @@ -65,7 +65,7 @@ <method name="is_server_relay_supported" qualifiers="const"> <return type="bool" /> <description> - Returns true if the server can act as a relay in the current configuration (i.e. if the higher level [MultiplayerAPI] should notify connected clients of other peers, and implement a relay protocol to allow communication between them). + Returns [code]true[/code] if the server can act as a relay in the current configuration. That is, if the higher level [MultiplayerAPI] should notify connected clients of other peers, and implement a relay protocol to allow communication between them. </description> </method> <method name="poll"> diff --git a/doc/classes/NavigationServer2D.xml b/doc/classes/NavigationServer2D.xml index 7e78006240..5c19a6b355 100644 --- a/doc/classes/NavigationServer2D.xml +++ b/doc/classes/NavigationServer2D.xml @@ -133,7 +133,7 @@ <return type="bool" /> <param index="0" name="agent" type="RID" /> <description> - Returns true if the map got changed the previous frame. + Returns [code]true[/code] if the map got changed the previous frame. </description> </method> <method name="agent_set_avoidance_callback"> @@ -215,7 +215,7 @@ <param index="0" name="agent" type="RID" /> <param index="1" name="paused" type="bool" /> <description> - If [param paused] is true the specified [param agent] will not be processed, e.g. calculate avoidance velocities or receive avoidance callbacks. + If [param paused] is [code]true[/code] the specified [param agent] will not be processed, e.g. calculate avoidance velocities or receive avoidance callbacks. </description> </method> <method name="agent_set_position"> @@ -573,7 +573,7 @@ <return type="bool" /> <param index="0" name="map" type="RID" /> <description> - Returns true if the map is active. + Returns [code]true[/code] if the map is active. </description> </method> <method name="map_set_active"> @@ -707,7 +707,7 @@ <param index="0" name="obstacle" type="RID" /> <param index="1" name="paused" type="bool" /> <description> - If [param paused] is true the specified [param obstacle] will not be processed, e.g. affect avoidance velocities. + If [param paused] is [code]true[/code] the specified [param obstacle] will not be processed, e.g. affect avoidance velocities. </description> </method> <method name="obstacle_set_position"> diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml index 7e206046d6..66a286758b 100644 --- a/doc/classes/NavigationServer3D.xml +++ b/doc/classes/NavigationServer3D.xml @@ -147,7 +147,7 @@ <return type="bool" /> <param index="0" name="agent" type="RID" /> <description> - Returns true if the map got changed the previous frame. + Returns [code]true[/code] if the map got changed the previous frame. </description> </method> <method name="agent_set_avoidance_callback"> @@ -237,7 +237,7 @@ <param index="0" name="agent" type="RID" /> <param index="1" name="paused" type="bool" /> <description> - If [param paused] is true the specified [param agent] will not be processed, e.g. calculate avoidance velocities or receive avoidance callbacks. + If [param paused] is [code]true[/code] the specified [param agent] will not be processed, e.g. calculate avoidance velocities or receive avoidance callbacks. </description> </method> <method name="agent_set_position"> @@ -645,14 +645,14 @@ <return type="bool" /> <param index="0" name="map" type="RID" /> <description> - Returns true if the navigation [param map] allows navigation regions to use edge connections to connect with other navigation regions within proximity of the navigation map edge connection margin. + Returns [code]true[/code] if the navigation [param map] allows navigation regions to use edge connections to connect with other navigation regions within proximity of the navigation map edge connection margin. </description> </method> <method name="map_is_active" qualifiers="const"> <return type="bool" /> <param index="0" name="map" type="RID" /> <description> - Returns true if the map is active. + Returns [code]true[/code] if the map is active. </description> </method> <method name="map_set_active"> @@ -832,7 +832,7 @@ <param index="0" name="obstacle" type="RID" /> <param index="1" name="paused" type="bool" /> <description> - If [param paused] is true the specified [param obstacle] will not be processed, e.g. affect avoidance velocities. + If [param paused] is [code]true[/code] the specified [param obstacle] will not be processed, e.g. affect avoidance velocities. </description> </method> <method name="obstacle_set_position"> @@ -1023,7 +1023,7 @@ <return type="bool" /> <param index="0" name="region" type="RID" /> <description> - Returns true if the navigation [param region] is set to use edge connections to connect with other navigation regions within proximity of the navigation map edge connection margin. + Returns [code]true[/code] if the navigation [param region] is set to use edge connections to connect with other navigation regions within proximity of the navigation map edge connection margin. </description> </method> <method name="region_owns_point" qualifiers="const"> diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml index 2767a11e80..a130a71826 100644 --- a/doc/classes/Object.xml +++ b/doc/classes/Object.xml @@ -454,7 +454,7 @@ <return type="Variant" /> <param index="0" name="method" type="StringName" /> <description> - Calls the [param method] on the object during idle time. Always returns null, [b]not[/b] the method's result. + Calls the [param method] on the object during idle time. Always returns [code]null[/code], [b]not[/b] the method's result. Idle time happens mainly at the end of process and physics frames. In it, deferred calls will be run until there are none left, which means you can defer calls from other deferred calls and they'll still be run in the current idle time cycle. This means you should not call a method deferred from itself (or from a method called by it), as this causes infinite recursion the same way as if you had called the method directly. This method supports a variable number of arguments, so parameters can be passed as a comma separated list. [codeblocks] diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 3358e6838c..fff6c8d3bb 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -469,10 +469,10 @@ If the [code]--log-file <file>[/code] [url=$DOCS_URL/tutorials/editor/command_line_tutorial.html]command line argument[/url] is used, log rotation is always disabled. </member> <member name="debug/gdscript/warnings/assert_always_false" type="int" setter="" getter="" default="1"> - When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when an [code]assert[/code] call always evaluates to false. + When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when an [code]assert[/code] call always evaluates to [code]false[/code]. </member> <member name="debug/gdscript/warnings/assert_always_true" type="int" setter="" getter="" default="1"> - When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when an [code]assert[/code] call always evaluates to true. + When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when an [code]assert[/code] call always evaluates to [code]true[/code]. </member> <member name="debug/gdscript/warnings/confusable_capture_reassignment" type="int" setter="" getter="" default="1"> When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a local variable captured by a lambda is reassigned, since this does not modify the outer local variable. @@ -561,10 +561,10 @@ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when defining a local or member variable, signal, or enum that would have the same name as a built-in function or global class name, thus shadowing it. </member> <member name="debug/gdscript/warnings/shadowed_variable" type="int" setter="" getter="" default="1"> - When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when defining a local or member variable that would shadow a member variable that the class defines. + When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a local variable or local constant shadows a member declared in the current class. </member> <member name="debug/gdscript/warnings/shadowed_variable_base_class" type="int" setter="" getter="" default="1"> - When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when defining a local or subclass member variable that would shadow a variable that is inherited from a parent class. + When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a local variable or local constant shadows a member declared in a base class. </member> <member name="debug/gdscript/warnings/standalone_expression" type="int" setter="" getter="" default="1"> When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when calling an expression that may have no effect on the surrounding code, such as writing [code]2 + 2[/code] as a statement. @@ -3014,7 +3014,7 @@ Specify whether OpenXR should be configured for an HMD or a hand held device. </member> <member name="xr/openxr/foveation_dynamic" type="bool" setter="" getter="" default="false"> - If true and foveation is supported, will automatically adjust foveation level based on framerate up to the level set on [member xr/openxr/foveation_level]. + If [code]true[/code] and foveation is supported, will automatically adjust foveation level based on framerate up to the level set on [member xr/openxr/foveation_level]. [b]Note:[/b] Only works on the Compatibility rendering method. </member> <member name="xr/openxr/foveation_level" type="int" setter="" getter="" default=""0""> diff --git a/doc/classes/RDPipelineDepthStencilState.xml b/doc/classes/RDPipelineDepthStencilState.xml index dc1e70eb55..425890bb8d 100644 --- a/doc/classes/RDPipelineDepthStencilState.xml +++ b/doc/classes/RDPipelineDepthStencilState.xml @@ -34,10 +34,10 @@ The method used for comparing the previous and current depth values. </member> <member name="depth_range_max" type="float" setter="set_depth_range_max" getter="get_depth_range_max" default="0.0"> - The maximum depth that returns true for [member enable_depth_range]. + The maximum depth that returns [code]true[/code] for [member enable_depth_range]. </member> <member name="depth_range_min" type="float" setter="set_depth_range_min" getter="get_depth_range_min" default="0.0"> - The minimum depth that returns true for [member enable_depth_range]. + The minimum depth that returns [code]true[/code] for [member enable_depth_range]. </member> <member name="enable_depth_range" type="bool" setter="set_enable_depth_range" getter="get_enable_depth_range" default="false"> If [code]true[/code], each depth value will be tested to see if it is between [member depth_range_min] and [member depth_range_max]. If it is outside of these values, it is discarded. @@ -46,7 +46,7 @@ If [code]true[/code], enables depth testing which allows objects to be automatically occluded by other objects based on their depth. This also allows objects to be partially occluded by other objects. If [code]false[/code], objects will appear in the order they were drawn (like in Godot's 2D renderer). </member> <member name="enable_depth_write" type="bool" setter="set_enable_depth_write" getter="get_enable_depth_write" default="false"> - If [code]true[/code], writes to the depth buffer whenever the depth test returns true. Only works when enable_depth_test is also true. + If [code]true[/code], writes to the depth buffer whenever the depth test returns [code]true[/code]. Only works when enable_depth_test is also [code]true[/code]. </member> <member name="enable_stencil" type="bool" setter="set_enable_stencil" getter="get_enable_stencil" default="false"> If [code]true[/code], enables stencil testing. There are separate stencil buffers for front-facing triangles and back-facing triangles. See properties that begin with "front_op" and properties with "back_op" for each. diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index 90a0798265..284dc07fd4 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -224,7 +224,7 @@ <param index="0" name="item" type="RID" /> <param index="1" name="ignore" type="bool" /> <description> - If [param ignore] is [code]true[/code], ignore clipping on items drawn with this canvas item until this is called again with [param ignore] set to false. + If [param ignore] is [code]true[/code], ignore clipping on items drawn with this canvas item until this is called again with [param ignore] set to [code]false[/code]. </description> </method> <method name="canvas_item_add_lcd_texture_rect_region"> @@ -2957,7 +2957,7 @@ <param index="0" name="particles" type="RID" /> <param index="1" name="emitting" type="bool" /> <description> - If [code]true[/code], particles will emit over time. Setting to false does not reset the particles, but only stops their emission. Equivalent to [member GPUParticles3D.emitting]. + If [code]true[/code], particles will emit over time. Setting to [code]false[/code] does not reset the particles, but only stops their emission. Equivalent to [member GPUParticles3D.emitting]. </description> </method> <method name="particles_set_explosiveness_ratio"> diff --git a/doc/classes/ResourceLoader.xml b/doc/classes/ResourceLoader.xml index 56c3208fc3..f718ad15d8 100644 --- a/doc/classes/ResourceLoader.xml +++ b/doc/classes/ResourceLoader.xml @@ -104,7 +104,7 @@ <param index="1" name="progress" type="Array" default="[]" /> <description> Returns the status of a threaded loading operation started with [method load_threaded_request] for the resource at [param path]. See [enum ThreadLoadStatus] for possible return values. - An array variable can optionally be passed via [param progress], and will return a one-element array containing the percentage of completion of the threaded loading. + An array variable can optionally be passed via [param progress], and will return a one-element array containing the ratio of completion of the threaded loading (between [code]0.0[/code] and [code]1.0[/code]). [b]Note:[/b] The recommended way of using this method is to call it during different frames (e.g., in [method Node._process], instead of a loop). </description> </method> diff --git a/doc/classes/Shader.xml b/doc/classes/Shader.xml index 1e7f9e5ee5..3fbe1da687 100644 --- a/doc/classes/Shader.xml +++ b/doc/classes/Shader.xml @@ -31,8 +31,8 @@ <return type="Array" /> <param index="0" name="get_groups" type="bool" default="false" /> <description> - Get the list of shader uniforms that can be assigned to a [ShaderMaterial], for use with [method ShaderMaterial.set_shader_parameter] and [method ShaderMaterial.get_shader_parameter]. The parameters returned are contained in dictionaries in a similar format to the ones returned by [method Object.get_property_list]. - If argument [param get_groups] is true, parameter grouping hints will be provided. + Returns the list of shader uniforms that can be assigned to a [ShaderMaterial], for use with [method ShaderMaterial.set_shader_parameter] and [method ShaderMaterial.get_shader_parameter]. The parameters returned are contained in dictionaries in a similar format to the ones returned by [method Object.get_property_list]. + If argument [param get_groups] is [code]true[/code], parameter grouping hints are also included in the list. </description> </method> <method name="inspect_native_shader_code"> diff --git a/doc/classes/SkeletonIK3D.xml b/doc/classes/SkeletonIK3D.xml index 4858a6ce22..dbb099a22b 100644 --- a/doc/classes/SkeletonIK3D.xml +++ b/doc/classes/SkeletonIK3D.xml @@ -31,7 +31,7 @@ <method name="get_parent_skeleton" qualifiers="const"> <return type="Skeleton3D" /> <description> - Returns the parent [Skeleton3D] Node that was present when SkeletonIK entered the [SceneTree]. Returns null if the parent node was not a [Skeleton3D] Node when SkeletonIK3D entered the [SceneTree]. + Returns the parent [Skeleton3D] node that was present when SkeletonIK entered the scene tree. Returns [code]null[/code] if the parent node was not a [Skeleton3D] node when SkeletonIK3D entered the scene tree. </description> </method> <method name="is_running"> diff --git a/doc/classes/Slider.xml b/doc/classes/Slider.xml index a4ffa5c1e7..b1e78e8987 100644 --- a/doc/classes/Slider.xml +++ b/doc/classes/Slider.xml @@ -28,12 +28,12 @@ <signal name="drag_ended"> <param index="0" name="value_changed" type="bool" /> <description> - Emitted when dragging stops. If [param value_changed] is true, [member Range.value] is different from the value when you started the dragging. + Emitted when the grabber stops being dragged. If [param value_changed] is [code]true[/code], [member Range.value] is different from the value when the dragging was started. </description> </signal> <signal name="drag_started"> <description> - Emitted when dragging is started. This is emitted before the corresponding [signal Range.value_changed] signal. + Emitted when the grabber starts being dragged. This is emitted before the corresponding [signal Range.value_changed] signal. </description> </signal> </signals> diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml index 0995a5a672..4683f063f1 100644 --- a/doc/classes/TileMap.xml +++ b/doc/classes/TileMap.xml @@ -380,7 +380,7 @@ <param index="4" name="ignore_empty_terrains" type="bool" default="true" /> <description> Update all the cells in the [param cells] coordinates array so that they use the given [param terrain] for the given [param terrain_set]. If an updated cell has the same terrain as one of its neighboring cells, this function tries to join the two. This function might update neighboring tiles if needed to create correct terrain transitions. - If [param ignore_empty_terrains] is true, empty terrains will be ignored when trying to find the best fitting tile for the given terrain constraints. + If [param ignore_empty_terrains] is [code]true[/code], empty terrains will be ignored when trying to find the best fitting tile for the given terrain constraints. If [param layer] is negative, the layers are accessed from the last one. [b]Note:[/b] To work correctly, this method requires the TileMap's TileSet to have terrains set up with all required terrain combinations. Otherwise, it may produce unexpected results. </description> @@ -394,7 +394,7 @@ <param index="4" name="ignore_empty_terrains" type="bool" default="true" /> <description> Update all the cells in the [param path] coordinates array so that they use the given [param terrain] for the given [param terrain_set]. The function will also connect two successive cell in the path with the same terrain. This function might update neighboring tiles if needed to create correct terrain transitions. - If [param ignore_empty_terrains] is true, empty terrains will be ignored when trying to find the best fitting tile for the given terrain constraints. + If [param ignore_empty_terrains] is [code]true[/code], empty terrains will be ignored when trying to find the best fitting tile for the given terrain constraints. If [param layer] is negative, the layers are accessed from the last one. [b]Note:[/b] To work correctly, this method requires the TileMap's TileSet to have terrains set up with all required terrain combinations. Otherwise, it may produce unexpected results. </description> diff --git a/doc/classes/TileMapLayer.xml b/doc/classes/TileMapLayer.xml index 135f85de69..6cbec9c2aa 100644 --- a/doc/classes/TileMapLayer.xml +++ b/doc/classes/TileMapLayer.xml @@ -228,7 +228,7 @@ <param index="3" name="ignore_empty_terrains" type="bool" default="true" /> <description> Update all the cells in the [param cells] coordinates array so that they use the given [param terrain] for the given [param terrain_set]. If an updated cell has the same terrain as one of its neighboring cells, this function tries to join the two. This function might update neighboring tiles if needed to create correct terrain transitions. - If [param ignore_empty_terrains] is true, empty terrains will be ignored when trying to find the best fitting tile for the given terrain constraints. + If [param ignore_empty_terrains] is [code]true[/code], empty terrains will be ignored when trying to find the best fitting tile for the given terrain constraints. [b]Note:[/b] To work correctly, this method requires the [TileMapLayer]'s TileSet to have terrains set up with all required terrain combinations. Otherwise, it may produce unexpected results. </description> </method> @@ -240,7 +240,7 @@ <param index="3" name="ignore_empty_terrains" type="bool" default="true" /> <description> Update all the cells in the [param path] coordinates array so that they use the given [param terrain] for the given [param terrain_set]. The function will also connect two successive cell in the path with the same terrain. This function might update neighboring tiles if needed to create correct terrain transitions. - If [param ignore_empty_terrains] is true, empty terrains will be ignored when trying to find the best fitting tile for the given terrain constraints. + If [param ignore_empty_terrains] is [code]true[/code], empty terrains will be ignored when trying to find the best fitting tile for the given terrain constraints. [b]Note:[/b] To work correctly, this method requires the [TileMapLayer]'s TileSet to have terrains set up with all required terrain combinations. Otherwise, it may produce unexpected results. </description> </method> diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml index 132ecc3f92..d04a6f7316 100644 --- a/doc/classes/TreeItem.xml +++ b/doc/classes/TreeItem.xml @@ -267,7 +267,7 @@ <method name="get_next" qualifiers="const"> <return type="TreeItem" /> <description> - Returns the next sibling TreeItem in the tree or a null object if there is none. + Returns the next sibling TreeItem in the tree or a [code]null[/code] object if there is none. </description> </method> <method name="get_next_in_tree"> @@ -289,13 +289,13 @@ <method name="get_parent" qualifiers="const"> <return type="TreeItem" /> <description> - Returns the parent TreeItem or a null object if there is none. + Returns the parent TreeItem or a [code]null[/code] object if there is none. </description> </method> <method name="get_prev"> <return type="TreeItem" /> <description> - Returns the previous sibling TreeItem in the tree or a null object if there is none. + Returns the previous sibling TreeItem in the tree or a [code]null[/code] object if there is none. </description> </method> <method name="get_prev_in_tree"> diff --git a/doc/classes/VideoStreamPlayback.xml b/doc/classes/VideoStreamPlayback.xml index 8b4a7f8d29..17e29ae337 100644 --- a/doc/classes/VideoStreamPlayback.xml +++ b/doc/classes/VideoStreamPlayback.xml @@ -54,7 +54,7 @@ <method name="_play" qualifiers="virtual"> <return type="void" /> <description> - Called in response to [member VideoStreamPlayer.autoplay] or [method VideoStreamPlayer.play]. Note that manual playback may also invoke [method _stop] multiple times before this method is called. [method _is_playing] should return true once playing. + Called in response to [member VideoStreamPlayer.autoplay] or [method VideoStreamPlayer.play]. Note that manual playback may also invoke [method _stop] multiple times before this method is called. [method _is_playing] should return [code]true[/code] once playing. </description> </method> <method name="_seek" qualifiers="virtual"> @@ -81,14 +81,14 @@ <method name="_stop" qualifiers="virtual"> <return type="void" /> <description> - Stops playback. May be called multiple times before [method _play], or in response to [method VideoStreamPlayer.stop]. [method _is_playing] should return false once stopped. + Stops playback. May be called multiple times before [method _play], or in response to [method VideoStreamPlayer.stop]. [method _is_playing] should return [code]false[/code] once stopped. </description> </method> <method name="_update" qualifiers="virtual"> <return type="void" /> <param index="0" name="delta" type="float" /> <description> - Ticks video playback for [param delta] seconds. Called every frame as long as [method _is_paused] and [method _is_playing] return true. + Ticks video playback for [param delta] seconds. Called every frame as long as both [method _is_paused] and [method _is_playing] return [code]true[/code]. </description> </method> <method name="mix_audio"> diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml index 333e61d03f..c4319fd360 100644 --- a/doc/classes/Viewport.xml +++ b/doc/classes/Viewport.xml @@ -48,7 +48,7 @@ <method name="get_camera_2d" qualifiers="const"> <return type="Camera2D" /> <description> - Returns the currently active 2D camera. Returns null if there are no active cameras. + Returns the currently active 2D camera. Returns [code]null[/code] if there are no active cameras. </description> </method> <method name="get_camera_3d" qualifiers="const"> @@ -144,13 +144,13 @@ <method name="gui_get_focus_owner" qualifiers="const"> <return type="Control" /> <description> - Returns the [Control] having the focus within this viewport. If no [Control] has the focus, returns null. + Returns the currently focused [Control] within this viewport. If no [Control] is focused, returns [code]null[/code]. </description> </method> <method name="gui_get_hovered_control" qualifiers="const"> <return type="Control" /> <description> - Returns the [Control] that the mouse is currently hovering over in this viewport. If no [Control] has the cursor, returns null. + Returns the [Control] that the mouse is currently hovering over in this viewport. If no [Control] has the cursor, returns [code]null[/code]. Typically the leaf [Control] node or deepest level of the subtree which claims hover. This is very useful when used together with [method Node.is_ancestor_of] to find if the mouse is within a control tree. </description> </method> diff --git a/doc/classes/VisualShaderNodeCompare.xml b/doc/classes/VisualShaderNodeCompare.xml index b566ca62f3..9f554dacb4 100644 --- a/doc/classes/VisualShaderNodeCompare.xml +++ b/doc/classes/VisualShaderNodeCompare.xml @@ -69,10 +69,10 @@ Represents the size of the [enum Function] enum. </constant> <constant name="COND_ALL" value="0" enum="Condition"> - The result will be true if all of component in vector satisfy the comparison condition. + The result will be [code]true[/code] if all components in the vector satisfy the comparison condition. </constant> <constant name="COND_ANY" value="1" enum="Condition"> - The result will be true if any of component in vector satisfy the comparison condition. + The result will be [code]true[/code] if any component in the vector satisfies the comparison condition. </constant> <constant name="COND_MAX" value="2" enum="Condition"> Represents the size of the [enum Condition] enum. diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 3c959f0143..0138f99d50 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -1654,28 +1654,39 @@ void RasterizerCanvasGLES3::light_update_shadow(RID p_rid, int p_shadow_index, c return; } - for (int i = 0; i < 4; i++) { - glViewport((state.shadow_texture_size / 4) * i, p_shadow_index * 2, (state.shadow_texture_size / 4), 2); + Projection projection; + { + real_t fov = 90; + real_t nearp = p_near; + real_t farp = p_far; + real_t aspect = 1.0; - Projection projection; - { - real_t fov = 90; - real_t nearp = p_near; - real_t farp = p_far; - real_t aspect = 1.0; + real_t ymax = nearp * Math::tan(Math::deg_to_rad(fov * 0.5)); + real_t ymin = -ymax; + real_t xmin = ymin * aspect; + real_t xmax = ymax * aspect; - real_t ymax = nearp * Math::tan(Math::deg_to_rad(fov * 0.5)); - real_t ymin = -ymax; - real_t xmin = ymin * aspect; - real_t xmax = ymax * aspect; + projection.set_frustum(xmin, xmax, ymin, ymax, nearp, farp); + } - projection.set_frustum(xmin, xmax, ymin, ymax, nearp, farp); - } + // Precomputed: + // Vector3 cam_target = Basis::from_euler(Vector3(0, 0, Math_TAU * ((i + 3) / 4.0))).xform(Vector3(0, 1, 0)); + // projection = projection * Projection(Transform3D().looking_at(cam_targets[i], Vector3(0, 0, -1)).affine_inverse()); + const Projection projections[4] = { + projection * Projection(Vector4(0, 0, -1, 0), Vector4(1, 0, 0, 0), Vector4(0, -1, 0, 0), Vector4(0, 0, 0, 1)), - Vector3 cam_target = Basis::from_euler(Vector3(0, 0, Math_TAU * ((i + 3) / 4.0))).xform(Vector3(0, 1, 0)); + projection * Projection(Vector4(-1, 0, 0, 0), Vector4(0, 0, -1, 0), Vector4(0, -1, 0, 0), Vector4(0, 0, 0, 1)), + + projection * Projection(Vector4(0, 0, 1, 0), Vector4(-1, 0, 0, 0), Vector4(0, -1, 0, 0), Vector4(0, 0, 0, 1)), + + projection * Projection(Vector4(1, 0, 0, 0), Vector4(0, 0, 1, 0), Vector4(0, -1, 0, 0), Vector4(0, 0, 0, 1)) + + }; + + for (int i = 0; i < 4; i++) { + glViewport((state.shadow_texture_size / 4) * i, p_shadow_index * 2, (state.shadow_texture_size / 4), 2); - projection = projection * Projection(Transform3D().looking_at(cam_target, Vector3(0, 0, -1)).affine_inverse()); - shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::PROJECTION, projection, shadow_render.shader_version, variant); + shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::PROJECTION, projections[i], shadow_render.shader_version, variant); static const Vector2 directions[4] = { Vector2(1, 0), Vector2(0, 1), Vector2(-1, 0), Vector2(0, -1) }; shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::DIRECTION, directions[i].x, directions[i].y, shadow_render.shader_version, variant); diff --git a/drivers/vulkan/rendering_device_driver_vulkan.cpp b/drivers/vulkan/rendering_device_driver_vulkan.cpp index 015c0c6d2e..6eecd850f5 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.cpp +++ b/drivers/vulkan/rendering_device_driver_vulkan.cpp @@ -2611,7 +2611,10 @@ Error RenderingDeviceDriverVulkan::command_queue_execute_and_present(CommandQueu // it'll lead to very low performance in Android by entering an endless loop where it'll always resize the swap chain // every frame. - ERR_FAIL_COND_V(err != VK_SUCCESS && err != VK_SUBOPTIMAL_KHR, FAILED); + ERR_FAIL_COND_V_MSG( + err != VK_SUCCESS && err != VK_SUBOPTIMAL_KHR, + FAILED, + "QueuePresentKHR failed with error: " + get_vulkan_result(err)); } return OK; @@ -2887,21 +2890,28 @@ Error RenderingDeviceDriverVulkan::swap_chain_resize(CommandQueueID p_cmd_queue, // No swapchain yet, this is the first time we're creating it. if (!swap_chain->vk_swapchain) { - uint32_t width = surface_capabilities.currentExtent.width; - uint32_t height = surface_capabilities.currentExtent.height; + if (surface_capabilities.currentExtent.width == 0xFFFFFFFF) { + // The current extent is currently undefined, so the current surface width and height will be clamped to the surface's capabilities. + // We make sure to overwrite surface_capabilities.currentExtent.width so that the same check further below + // does not set extent.width = CLAMP( surface->width, ... ) on the first run of this function, because + // that'd be potentially unswapped. + surface_capabilities.currentExtent.width = CLAMP(surface->width, surface_capabilities.minImageExtent.width, surface_capabilities.maxImageExtent.width); + surface_capabilities.currentExtent.height = CLAMP(surface->height, surface_capabilities.minImageExtent.height, surface_capabilities.maxImageExtent.height); + } + + // We must SWAP() only once otherwise we'll keep ping-ponging between + // the right and wrong resolutions after multiple calls to swap_chain_resize(). if (surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR || surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) { // Swap to get identity width and height. - surface_capabilities.currentExtent.height = width; - surface_capabilities.currentExtent.width = height; + SWAP(surface_capabilities.currentExtent.width, surface_capabilities.currentExtent.height); } - - native_display_size = surface_capabilities.currentExtent; } VkExtent2D extent; if (surface_capabilities.currentExtent.width == 0xFFFFFFFF) { // The current extent is currently undefined, so the current surface width and height will be clamped to the surface's capabilities. + // We can only be here on the second call to swap_chain_resize(), by which time surface->width & surface->height should already be swapped if needed. extent.width = CLAMP(surface->width, surface_capabilities.minImageExtent.width, surface_capabilities.maxImageExtent.width); extent.height = CLAMP(surface->height, surface_capabilities.minImageExtent.height, surface_capabilities.maxImageExtent.height); } else { @@ -2991,7 +3001,7 @@ Error RenderingDeviceDriverVulkan::swap_chain_resize(CommandQueueID p_cmd_queue, swap_create_info.minImageCount = desired_swapchain_images; swap_create_info.imageFormat = swap_chain->format; swap_create_info.imageColorSpace = swap_chain->color_space; - swap_create_info.imageExtent = native_display_size; + swap_create_info.imageExtent = extent; swap_create_info.imageArrayLayers = 1; swap_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; swap_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; @@ -5427,6 +5437,23 @@ void RenderingDeviceDriverVulkan::print_lost_device_info() { on_device_lost(); } +inline String RenderingDeviceDriverVulkan::get_vulkan_result(VkResult err) { +#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED) + if (err == VK_ERROR_OUT_OF_HOST_MEMORY) { + return "VK_ERROR_OUT_OF_HOST_MEMORY"; + } else if (err == VK_ERROR_OUT_OF_DEVICE_MEMORY) { + return "VK_ERROR_OUT_OF_DEVICE_MEMORY"; + } else if (err == VK_ERROR_DEVICE_LOST) { + return "VK_ERROR_DEVICE_LOST"; + } else if (err == VK_ERROR_SURFACE_LOST_KHR) { + return "VK_ERROR_SURFACE_LOST_KHR"; + } else if (err == VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT) { + return "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT"; + } +#endif + return itos(err); +} + /********************/ /**** SUBMISSION ****/ /********************/ diff --git a/drivers/vulkan/rendering_device_driver_vulkan.h b/drivers/vulkan/rendering_device_driver_vulkan.h index 2b420e8feb..06cd2a31be 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.h +++ b/drivers/vulkan/rendering_device_driver_vulkan.h @@ -367,7 +367,6 @@ private: }; void _swap_chain_release(SwapChain *p_swap_chain); - VkExtent2D native_display_size; public: virtual SwapChainID swap_chain_create(RenderingContextDriver::SurfaceID p_surface) override final; @@ -656,6 +655,7 @@ public: virtual void command_insert_breadcrumb(CommandBufferID p_cmd_buffer, uint32_t p_data) override final; void print_lost_device_info(); void on_device_lost() const; + static String get_vulkan_result(VkResult err); /********************/ /**** SUBMISSION ****/ diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp index b78aad1721..c97272a571 100644 --- a/editor/debugger/script_editor_debugger.cpp +++ b/editor/debugger/script_editor_debugger.cpp @@ -1170,6 +1170,12 @@ String ScriptEditorDebugger::get_var_value(const String &p_var) const { return inspector->get_stack_variable(p_var); } +void ScriptEditorDebugger::_resources_reimported(const PackedStringArray &p_resources) { + Array msg; + msg.push_back(p_resources); + _put_msg("scene:reload_cached_files", msg); +} + int ScriptEditorDebugger::_get_node_path_cache(const NodePath &p_path) { const int *r = node_path_cache.getptr(p_path); if (r) { @@ -1818,6 +1824,7 @@ ScriptEditorDebugger::ScriptEditorDebugger() { tabs->connect("tab_changed", callable_mp(this, &ScriptEditorDebugger::_tab_changed)); InspectorDock::get_inspector_singleton()->connect("object_id_selected", callable_mp(this, &ScriptEditorDebugger::_remote_object_selected)); + EditorFileSystem::get_singleton()->connect("resources_reimported", callable_mp(this, &ScriptEditorDebugger::_resources_reimported)); { //debugger VBoxContainer *vbc = memnew(VBoxContainer); diff --git a/editor/debugger/script_editor_debugger.h b/editor/debugger/script_editor_debugger.h index 1908b1e5a7..06a968e141 100644 --- a/editor/debugger/script_editor_debugger.h +++ b/editor/debugger/script_editor_debugger.h @@ -198,6 +198,8 @@ private: void _video_mem_request(); void _video_mem_export(); + void _resources_reimported(const PackedStringArray &p_resources); + int _get_node_path_cache(const NodePath &p_path); int _get_res_path_cache(const String &p_path); diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp index 7ffbc39d75..9cf10c0ecb 100644 --- a/editor/editor_feature_profile.cpp +++ b/editor/editor_feature_profile.cpp @@ -43,37 +43,37 @@ const char *EditorFeatureProfile::feature_names[FEATURE_MAX] = { TTRC("3D Editor"), TTRC("Script Editor"), - TTRC("Game View"), TTRC("Asset Library"), TTRC("Scene Tree Editing"), TTRC("Node Dock"), TTRC("FileSystem Dock"), TTRC("Import Dock"), TTRC("History Dock"), + TTRC("Game View"), }; const char *EditorFeatureProfile::feature_descriptions[FEATURE_MAX] = { TTRC("Allows to view and edit 3D scenes."), TTRC("Allows to edit scripts using the integrated script editor."), - TTRC("Provides tools for selecting and debugging nodes at runtime."), TTRC("Provides built-in access to the Asset Library."), TTRC("Allows editing the node hierarchy in the Scene dock."), TTRC("Allows to work with signals and groups of the node selected in the Scene dock."), TTRC("Allows to browse the local file system via a dedicated dock."), TTRC("Allows to configure import settings for individual assets. Requires the FileSystem dock to function."), TTRC("Provides an overview of the editor's and each scene's undo history."), + TTRC("Provides tools for selecting and debugging nodes at runtime."), }; const char *EditorFeatureProfile::feature_identifiers[FEATURE_MAX] = { "3d", "script", - "game", "asset_lib", "scene_tree", "node_dock", "filesystem_dock", "import_dock", "history_dock", + "game", }; void EditorFeatureProfile::set_disable_class(const StringName &p_class, bool p_disabled) { diff --git a/editor/gui/editor_quick_open_dialog.cpp b/editor/gui/editor_quick_open_dialog.cpp index b8f3b259ca..0128f1f54c 100644 --- a/editor/gui/editor_quick_open_dialog.cpp +++ b/editor/gui/editor_quick_open_dialog.cpp @@ -489,6 +489,10 @@ void QuickOpenResultContainer::handle_search_box_input(const Ref<InputEvent> &p_ } void QuickOpenResultContainer::_move_selection_index(Key p_key) { + // Don't move selection if there are no results. + if (num_visible_results <= 0) { + return; + } const int max_index = num_visible_results - 1; int idx = selection_index; diff --git a/editor/import/3d/resource_importer_obj.h b/editor/import/3d/resource_importer_obj.h index faf0f336c0..9d299bc31a 100644 --- a/editor/import/3d/resource_importer_obj.h +++ b/editor/import/3d/resource_importer_obj.h @@ -63,9 +63,6 @@ public: virtual Error 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 = nullptr, Variant *r_metadata = nullptr) override; - // Threaded import can currently cause deadlocks, see GH-48265. - virtual bool can_import_threaded() const override { return false; } - ResourceImporterOBJ(); }; diff --git a/editor/import/3d/resource_importer_scene.cpp b/editor/import/3d/resource_importer_scene.cpp index d2e3b7927b..edf7aa66f0 100644 --- a/editor/import/3d/resource_importer_scene.cpp +++ b/editor/import/3d/resource_importer_scene.cpp @@ -2622,6 +2622,7 @@ Node *ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_ mesh_node->set_layer_mask(src_mesh_node->get_layer_mask()); mesh_node->set_cast_shadows_setting(src_mesh_node->get_cast_shadows_setting()); + mesh_node->set_visible(src_mesh_node->is_visible()); mesh_node->set_visibility_range_begin(src_mesh_node->get_visibility_range_begin()); mesh_node->set_visibility_range_begin_margin(src_mesh_node->get_visibility_range_begin_margin()); mesh_node->set_visibility_range_end(src_mesh_node->get_visibility_range_end()); diff --git a/editor/import/3d/resource_importer_scene.h b/editor/import/3d/resource_importer_scene.h index fe757dc2a3..daeab2ae03 100644 --- a/editor/import/3d/resource_importer_scene.h +++ b/editor/import/3d/resource_importer_scene.h @@ -304,8 +304,6 @@ public: virtual bool has_advanced_options() const override; virtual void show_advanced_options(const String &p_path) override; - virtual bool can_import_threaded() const override { return false; } - ResourceImporterScene(const String &p_scene_import_type = "PackedScene", bool p_singleton = false); ~ResourceImporterScene(); diff --git a/editor/import/3d/scene_import_settings.cpp b/editor/import/3d/scene_import_settings.cpp index 645b7fda88..945c1811d7 100644 --- a/editor/import/3d/scene_import_settings.cpp +++ b/editor/import/3d/scene_import_settings.cpp @@ -368,6 +368,7 @@ void SceneImportSettingsDialog::_fill_scene(Node *p_node, TreeItem *p_parent_ite mesh_node->set_transform(src_mesh_node->get_transform()); mesh_node->set_skin(src_mesh_node->get_skin()); mesh_node->set_skeleton_path(src_mesh_node->get_skeleton_path()); + mesh_node->set_visible(src_mesh_node->is_visible()); if (src_mesh_node->get_mesh().is_valid()) { Ref<ImporterMesh> editor_mesh = src_mesh_node->get_mesh(); mesh_node->set_mesh(editor_mesh->get_mesh()); diff --git a/editor/import/resource_importer_bitmask.h b/editor/import/resource_importer_bitmask.h index 8963c8d918..30564bf0fe 100644 --- a/editor/import/resource_importer_bitmask.h +++ b/editor/import/resource_importer_bitmask.h @@ -50,6 +50,8 @@ public: virtual bool get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const override; virtual Error 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 = nullptr, Variant *r_metadata = nullptr) override; + virtual bool can_import_threaded() const override { return true; } + ResourceImporterBitMap(); ~ResourceImporterBitMap(); }; diff --git a/editor/import/resource_importer_bmfont.h b/editor/import/resource_importer_bmfont.h index d31cd03736..48f036ff13 100644 --- a/editor/import/resource_importer_bmfont.h +++ b/editor/import/resource_importer_bmfont.h @@ -50,6 +50,8 @@ public: virtual Error 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 = nullptr, Variant *r_metadata = nullptr) override; + virtual bool can_import_threaded() const override { return true; } + ResourceImporterBMFont(); }; diff --git a/editor/import/resource_importer_csv_translation.h b/editor/import/resource_importer_csv_translation.h index c6b05eb043..9c83719ed1 100644 --- a/editor/import/resource_importer_csv_translation.h +++ b/editor/import/resource_importer_csv_translation.h @@ -51,6 +51,8 @@ public: virtual Error 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 = nullptr, Variant *r_metadata = nullptr) override; + virtual bool can_import_threaded() const override { return true; } + ResourceImporterCSVTranslation(); }; diff --git a/editor/import/resource_importer_dynamic_font.h b/editor/import/resource_importer_dynamic_font.h index de89e6b76f..7c7a16cf92 100644 --- a/editor/import/resource_importer_dynamic_font.h +++ b/editor/import/resource_importer_dynamic_font.h @@ -60,6 +60,8 @@ public: virtual Error 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 = nullptr, Variant *r_metadata = nullptr) override; + virtual bool can_import_threaded() const override { return true; } + ResourceImporterDynamicFont(); }; diff --git a/editor/import/resource_importer_image.h b/editor/import/resource_importer_image.h index 1490ab30d5..dd395009c1 100644 --- a/editor/import/resource_importer_image.h +++ b/editor/import/resource_importer_image.h @@ -52,6 +52,8 @@ public: virtual Error 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 = nullptr, Variant *r_metadata = nullptr) override; + virtual bool can_import_threaded() const override { return true; } + ResourceImporterImage(); }; diff --git a/editor/import/resource_importer_imagefont.h b/editor/import/resource_importer_imagefont.h index 065351c361..6b30a3cd6e 100644 --- a/editor/import/resource_importer_imagefont.h +++ b/editor/import/resource_importer_imagefont.h @@ -50,6 +50,8 @@ public: virtual Error 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 = nullptr, Variant *r_metadata = nullptr) override; + virtual bool can_import_threaded() const override { return true; } + ResourceImporterImageFont(); }; diff --git a/editor/import/resource_importer_layered_texture.h b/editor/import/resource_importer_layered_texture.h index 26495eed8d..d8b5bc2d14 100644 --- a/editor/import/resource_importer_layered_texture.h +++ b/editor/import/resource_importer_layered_texture.h @@ -117,6 +117,8 @@ public: virtual bool are_import_settings_valid(const String &p_path, const Dictionary &p_meta) const override; virtual String get_import_settings_string() const override; + virtual bool can_import_threaded() const override { return true; } + void set_mode(Mode p_mode) { mode = p_mode; } ResourceImporterLayeredTexture(bool p_singleton = false); diff --git a/editor/import/resource_importer_shader_file.h b/editor/import/resource_importer_shader_file.h index aefc967989..b28dea36d6 100644 --- a/editor/import/resource_importer_shader_file.h +++ b/editor/import/resource_importer_shader_file.h @@ -51,6 +51,8 @@ public: virtual Error 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 = nullptr, Variant *r_metadata = nullptr) override; + virtual bool can_import_threaded() const override { return true; } + ResourceImporterShaderFile(); }; diff --git a/editor/import/resource_importer_texture.h b/editor/import/resource_importer_texture.h index 6d74c4e2f9..6c87cd0abb 100644 --- a/editor/import/resource_importer_texture.h +++ b/editor/import/resource_importer_texture.h @@ -102,6 +102,8 @@ public: virtual Error 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 = nullptr, Variant *r_metadata = nullptr) override; + virtual bool can_import_threaded() const override { return true; } + void update_imports(); virtual bool are_import_settings_valid(const String &p_path, const Dictionary &p_meta) const override; diff --git a/editor/import/resource_importer_texture_atlas.h b/editor/import/resource_importer_texture_atlas.h index 0f2b10424c..e4ad9ac230 100644 --- a/editor/import/resource_importer_texture_atlas.h +++ b/editor/import/resource_importer_texture_atlas.h @@ -67,6 +67,8 @@ public: virtual Error 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 = nullptr, Variant *r_metadata = nullptr) override; virtual Error import_group_file(const String &p_group_file, const HashMap<String, HashMap<StringName, Variant>> &p_source_file_options, const HashMap<String, String> &p_base_paths) override; + virtual bool can_import_threaded() const override { return true; } + ResourceImporterTextureAtlas(); }; diff --git a/editor/import/resource_importer_wav.cpp b/editor/import/resource_importer_wav.cpp index 339e7921b3..2654952e8a 100644 --- a/editor/import/resource_importer_wav.cpp +++ b/editor/import/resource_importer_wav.cpp @@ -213,9 +213,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s frames = remaining_bytes; } - if (format_channels == 0) { - ERR_FAIL_COND_V(format_channels == 0, ERR_INVALID_DATA); - } + ERR_FAIL_COND_V(format_channels == 0, ERR_INVALID_DATA); frames /= format_channels; frames /= (format_bits >> 3); diff --git a/editor/import/resource_importer_wav.h b/editor/import/resource_importer_wav.h index 47af37ba41..2253756554 100644 --- a/editor/import/resource_importer_wav.h +++ b/editor/import/resource_importer_wav.h @@ -142,6 +142,8 @@ public: virtual Error 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 = nullptr, Variant *r_metadata = nullptr) override; + virtual bool can_import_threaded() const override { return true; } + ResourceImporterWAV(); }; diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp index 48dcd2e6fc..fdc222e64f 100644 --- a/editor/plugins/mesh_instance_3d_editor_plugin.cpp +++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp @@ -40,6 +40,7 @@ #include "scene/3d/physics/collision_shape_3d.h" #include "scene/3d/physics/physics_body_3d.h" #include "scene/3d/physics/static_body_3d.h" +#include "scene/gui/aspect_ratio_container.h" #include "scene/gui/box_container.h" #include "scene/gui/dialogs.h" #include "scene/gui/menu_button.h" @@ -445,10 +446,43 @@ void MeshInstance3DEditor::_debug_uv_draw() { } debug_uv->set_clip_contents(true); - debug_uv->draw_rect(Rect2(Vector2(), debug_uv->get_size()), get_theme_color(SNAME("dark_color_3"), EditorStringName(Editor))); + debug_uv->draw_rect( + Rect2(Vector2(), debug_uv->get_size()), + get_theme_color(SNAME("dark_color_3"), EditorStringName(Editor))); + + // Draw an outline to represent the UV2's beginning and end area (useful on Black OLED theme). + // Top-left coordinate needs to be `(1, 1)` to prevent `clip_contents` from clipping the top and left lines. + debug_uv->draw_rect( + Rect2(Vector2(1, 1), debug_uv->get_size() - Vector2(1, 1)), + get_theme_color(SNAME("mono_color"), EditorStringName(Editor)) * Color(1, 1, 1, 0.125), + false, + Math::round(EDSCALE)); + + for (int x = 1; x <= 7; x++) { + debug_uv->draw_line( + Vector2(debug_uv->get_size().x * 0.125 * x, 0), + Vector2(debug_uv->get_size().x * 0.125 * x, debug_uv->get_size().y), + get_theme_color(SNAME("mono_color"), EditorStringName(Editor)) * Color(1, 1, 1, 0.125), + Math::round(EDSCALE)); + } + + for (int y = 1; y <= 7; y++) { + debug_uv->draw_line( + Vector2(0, debug_uv->get_size().y * 0.125 * y), + Vector2(debug_uv->get_size().x, debug_uv->get_size().y * 0.125 * y), + get_theme_color(SNAME("mono_color"), EditorStringName(Editor)) * Color(1, 1, 1, 0.125), + Math::round(EDSCALE)); + } + debug_uv->draw_set_transform(Vector2(), 0, debug_uv->get_size()); + // Use a translucent color to allow overlapping triangles to be visible. - debug_uv->draw_multiline(uv_lines, get_theme_color(SNAME("mono_color"), EditorStringName(Editor)) * Color(1, 1, 1, 0.5)); + // Divide line width by the drawing scale set above, so that line width is consistent regardless of dialog size. + // Aspect ratio is preserved by the parent AspectRatioContainer, so we only need to check the X size which is always equal to Y. + debug_uv->draw_multiline( + uv_lines, + get_theme_color(SNAME("mono_color"), EditorStringName(Editor)) * Color(1, 1, 1, 0.5), + Math::round(EDSCALE) / debug_uv->get_size().x); } void MeshInstance3DEditor::_create_navigation_mesh() { @@ -613,10 +647,14 @@ MeshInstance3DEditor::MeshInstance3DEditor() { debug_uv_dialog = memnew(AcceptDialog); debug_uv_dialog->set_title(TTR("UV Channel Debug")); add_child(debug_uv_dialog); + + debug_uv_arc = memnew(AspectRatioContainer); + debug_uv_dialog->add_child(debug_uv_arc); + debug_uv = memnew(Control); debug_uv->set_custom_minimum_size(Size2(600, 600) * EDSCALE); debug_uv->connect(SceneStringName(draw), callable_mp(this, &MeshInstance3DEditor::_debug_uv_draw)); - debug_uv_dialog->add_child(debug_uv); + debug_uv_arc->add_child(debug_uv); navigation_mesh_dialog = memnew(ConfirmationDialog); navigation_mesh_dialog->set_title(TTR("Create NavigationMesh")); diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.h b/editor/plugins/mesh_instance_3d_editor_plugin.h index c982df9c5f..569ecd4fff 100644 --- a/editor/plugins/mesh_instance_3d_editor_plugin.h +++ b/editor/plugins/mesh_instance_3d_editor_plugin.h @@ -36,6 +36,7 @@ #include "scene/gui/option_button.h" class AcceptDialog; +class AspectRatioContainer; class ConfirmationDialog; class MenuButton; class SpinBox; @@ -79,6 +80,7 @@ class MeshInstance3DEditor : public Control { AcceptDialog *err_dialog = nullptr; AcceptDialog *debug_uv_dialog = nullptr; + AspectRatioContainer *debug_uv_arc = nullptr; Control *debug_uv = nullptr; Vector<Vector2> uv_lines; diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index b877c0b83e..5afe01025d 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -8480,7 +8480,7 @@ void Node3DEditor::clear() { } for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) { - viewports[i]->view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(Node3DEditorViewport::VIEW_AUDIO_LISTENER), i == 0); + viewports[i]->view_menu->get_popup()->set_item_checked(viewports[i]->view_menu->get_popup()->get_item_index(Node3DEditorViewport::VIEW_AUDIO_LISTENER), i == 0); viewports[i]->viewport->set_as_audio_listener_3d(i == 0); } diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 05929c5f0d..9c1befa144 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -1472,7 +1472,7 @@ void VisualShaderGraphPlugin::disconnect_nodes(VisualShader::Type p_type, int p_ if (visual_shader.is_valid() && visual_shader->get_shader_type() == p_type) { graph->disconnect_node(itos(p_from_node), p_from_port, itos(p_to_node), p_to_port); - for (const List<VisualShader::Connection>::Element *E = connections.front(); E; E = E->next()) { + for (List<VisualShader::Connection>::Element *E = connections.front(); E; E = E->next()) { if (E->get().from_node == p_from_node && E->get().from_port == p_from_port && E->get().to_node == p_to_node && E->get().to_port == p_to_port) { connections.erase(E); break; diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 19b7122a0d..87ba2e6875 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -126,7 +126,8 @@ void SceneTreeDock::input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid() && (mb->get_button_index() == MouseButton::LEFT || mb->get_button_index() == MouseButton::RIGHT)) { - if (mb->is_pressed() && scene_tree->get_rect().has_point(scene_tree->get_local_mouse_position())) { + Tree *tree = scene_tree->get_scene_tree(); + if (mb->is_pressed() && tree->get_rect().has_point(tree->get_local_mouse_position())) { tree_clicked = true; } else if (!mb->is_pressed()) { tree_clicked = false; diff --git a/methods.py b/methods.py index f023622f6c..64c3839718 100644 --- a/methods.py +++ b/methods.py @@ -90,35 +90,6 @@ def add_source_files_orig(self, sources, files, allow_gen=False): sources.append(obj) -# The section name is used for checking -# the hash table to see whether the folder -# is included in the SCU build. -# It will be something like "core/math". -def _find_scu_section_name(subdir): - section_path = os.path.abspath(subdir) + "/" - - folders = [] - folder = "" - - for i in range(8): - folder = os.path.dirname(section_path) - folder = os.path.basename(folder) - if folder == base_folder_only: - break - folders += [folder] - section_path += "../" - section_path = os.path.abspath(section_path) + "/" - - section_name = "" - for n in range(len(folders)): - # section_name += folders[len(folders) - n - 1] + " " - section_name += folders[len(folders) - n - 1] - if n != (len(folders) - 1): - section_name += "/" - - return section_name - - def add_source_files_scu(self, sources, files, allow_gen=False): if self["scu_build"] and isinstance(files, str): if "*." not in files: @@ -127,10 +98,8 @@ def add_source_files_scu(self, sources, files, allow_gen=False): # If the files are in a subdirectory, we want to create the scu gen # files inside this subdirectory. subdir = os.path.dirname(files) - if subdir != "": - subdir += "/" - - section_name = _find_scu_section_name(subdir) + subdir = subdir if subdir == "" else subdir + "/" + section_name = self.Dir(subdir).tpath # if the section name is in the hash table? # i.e. is it part of the SCU build? global _scu_folders @@ -269,34 +238,6 @@ def get_version_info(module_version_string="", silent=False): return version_info -def parse_cg_file(fname, uniforms, sizes, conditionals): - with open(fname, "r", encoding="utf-8") as fs: - line = fs.readline() - - while line: - if re.match(r"^\s*uniform", line): - res = re.match(r"uniform ([\d\w]*) ([\d\w]*)") - type = res.groups(1) - name = res.groups(2) - - uniforms.append(name) - - if type.find("texobj") != -1: - sizes.append(1) - else: - t = re.match(r"float(\d)x(\d)", type) - if t: - sizes.append(int(t.groups(1)) * int(t.groups(2))) - else: - t = re.match(r"float(\d)", type) - sizes.append(int(t.groups(1))) - - if line.find("[branch]") != -1: - conditionals.append(name) - - line = fs.readline() - - def get_cmdline_bool(option, default): """We use `ARGUMENTS.get()` to check if options were manually overridden on the command line, and SCons' _text2bool helper to convert them to booleans, otherwise they're handled as strings. diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 93d4a512a9..6241ada06a 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -5809,8 +5809,6 @@ void GDScriptAnalyzer::validate_call_arg(const List<GDScriptParser::DataType> &p #ifdef DEBUG_ENABLED void GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_identifier, const String &p_context, const bool p_in_local_scope) { const StringName &name = p_identifier->name; - GDScriptParser::DataType base = parser->current_class->get_datatype(); - GDScriptParser::ClassNode *base_class = base.class_type; { List<MethodInfo> gdscript_funcs; @@ -5838,37 +5836,53 @@ void GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_identifier } } + const GDScriptParser::DataType current_class_type = parser->current_class->get_datatype(); if (p_in_local_scope) { - while (base_class != nullptr) { + GDScriptParser::ClassNode *base_class = current_class_type.class_type; + + if (base_class != nullptr) { if (base_class->has_member(name)) { parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE, p_context, p_identifier->name, base_class->get_member(name).get_type_name(), itos(base_class->get_member(name).get_line())); return; } base_class = base_class->base_type.class_type; } + + while (base_class != nullptr) { + if (base_class->has_member(name)) { + String base_class_name = base_class->get_global_name(); + if (base_class_name.is_empty()) { + base_class_name = base_class->fqcn; + } + + parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, base_class->get_member(name).get_type_name(), itos(base_class->get_member(name).get_line()), base_class_name); + return; + } + base_class = base_class->base_type.class_type; + } } - StringName parent = base.native_type; - while (parent != StringName()) { - ERR_FAIL_COND_MSG(!class_exists(parent), "Non-existent native base class."); + StringName native_base_class = current_class_type.native_type; + while (native_base_class != StringName()) { + ERR_FAIL_COND_MSG(!class_exists(native_base_class), "Non-existent native base class."); - if (ClassDB::has_method(parent, name, true)) { - parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "method", parent); + if (ClassDB::has_method(native_base_class, name, true)) { + parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "method", native_base_class); return; - } else if (ClassDB::has_signal(parent, name, true)) { - parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "signal", parent); + } else if (ClassDB::has_signal(native_base_class, name, true)) { + parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "signal", native_base_class); return; - } else if (ClassDB::has_property(parent, name, true)) { - parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "property", parent); + } else if (ClassDB::has_property(native_base_class, name, true)) { + parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "property", native_base_class); return; - } else if (ClassDB::has_integer_constant(parent, name, true)) { - parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "constant", parent); + } else if (ClassDB::has_integer_constant(native_base_class, name, true)) { + parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "constant", native_base_class); return; - } else if (ClassDB::has_enum(parent, name, true)) { - parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "enum", parent); + } else if (ClassDB::has_enum(native_base_class, name, true)) { + parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "enum", native_base_class); return; } - parent = ClassDB::get_parent_class(parent); + native_base_class = ClassDB::get_parent_class(native_base_class); } } #endif // DEBUG_ENABLED diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp index 4ffb4bd9d1..a601cc4993 100644 --- a/modules/gdscript/gdscript_warning.cpp +++ b/modules/gdscript/gdscript_warning.cpp @@ -61,10 +61,13 @@ String GDScriptWarning::get_message() const { return vformat(R"(The signal "%s" is declared but never explicitly used in the class.)", symbols[0]); case SHADOWED_VARIABLE: CHECK_SYMBOLS(4); - return vformat(R"(The local %s "%s" is shadowing an already-declared %s at line %s.)", symbols[0], symbols[1], symbols[2], symbols[3]); + return vformat(R"(The local %s "%s" is shadowing an already-declared %s at line %s in the current class.)", symbols[0], symbols[1], symbols[2], symbols[3]); case SHADOWED_VARIABLE_BASE_CLASS: CHECK_SYMBOLS(4); - return vformat(R"(The local %s "%s" is shadowing an already-declared %s at the base class "%s".)", symbols[0], symbols[1], symbols[2], symbols[3]); + if (symbols.size() > 4) { + return vformat(R"(The local %s "%s" is shadowing an already-declared %s at line %s in the base class "%s".)", symbols[0], symbols[1], symbols[2], symbols[3], symbols[4]); + } + return vformat(R"(The local %s "%s" is shadowing an already-declared %s in the base class "%s".)", symbols[0], symbols[1], symbols[2], symbols[3]); case SHADOWED_GLOBAL_IDENTIFIER: CHECK_SYMBOLS(3); return vformat(R"(The %s "%s" has the same name as a %s.)", symbols[0], symbols[1], symbols[2]); diff --git a/modules/gdscript/gdscript_warning.h b/modules/gdscript/gdscript_warning.h index ffcf00a830..99e9b30af5 100644 --- a/modules/gdscript/gdscript_warning.h +++ b/modules/gdscript/gdscript_warning.h @@ -53,8 +53,8 @@ public: UNUSED_PRIVATE_CLASS_VARIABLE, // Class variable is declared private ("_" prefix) but never used in the class. UNUSED_PARAMETER, // Function parameter is never used. UNUSED_SIGNAL, // Signal is defined but never explicitly used in the class. - SHADOWED_VARIABLE, // Variable name shadowed by other variable in same class. - SHADOWED_VARIABLE_BASE_CLASS, // Variable name shadowed by other variable in some base class. + SHADOWED_VARIABLE, // A local variable/constant shadows a current class member. + SHADOWED_VARIABLE_BASE_CLASS, // A local variable/constant shadows a base class member. SHADOWED_GLOBAL_IDENTIFIER, // A global class or function has the same name as variable. UNREACHABLE_CODE, // Code after a return statement. UNREACHABLE_PATTERN, // Pattern in a match statement after a catch all pattern (wildcard or bind). diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/confusable_local_usage.out b/modules/gdscript/tests/scripts/analyzer/warnings/confusable_local_usage.out index 0e0d607831..cfe91e00bd 100644 --- a/modules/gdscript/tests/scripts/analyzer/warnings/confusable_local_usage.out +++ b/modules/gdscript/tests/scripts/analyzer/warnings/confusable_local_usage.out @@ -6,6 +6,6 @@ GDTEST_OK >> WARNING >> Line: 5 >> SHADOWED_VARIABLE ->> The local variable "a" is shadowing an already-declared variable at line 1. +>> The local variable "a" is shadowing an already-declared variable at line 1 in the current class. 1 2 diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/confusable_local_usage_initializer.out b/modules/gdscript/tests/scripts/analyzer/warnings/confusable_local_usage_initializer.out index 228a510490..ae0f2d8b8b 100644 --- a/modules/gdscript/tests/scripts/analyzer/warnings/confusable_local_usage_initializer.out +++ b/modules/gdscript/tests/scripts/analyzer/warnings/confusable_local_usage_initializer.out @@ -10,6 +10,6 @@ GDTEST_OK >> WARNING >> Line: 5 >> SHADOWED_VARIABLE ->> The local variable "a" is shadowing an already-declared variable at line 1. +>> The local variable "a" is shadowing an already-declared variable at line 1 in the current class. 1 2 diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/confusable_local_usage_loop.out b/modules/gdscript/tests/scripts/analyzer/warnings/confusable_local_usage_loop.out index 0d20e9f7a0..101d27df9d 100644 --- a/modules/gdscript/tests/scripts/analyzer/warnings/confusable_local_usage_loop.out +++ b/modules/gdscript/tests/scripts/analyzer/warnings/confusable_local_usage_loop.out @@ -6,7 +6,7 @@ GDTEST_OK >> WARNING >> Line: 6 >> SHADOWED_VARIABLE ->> The local variable "a" is shadowing an already-declared variable at line 1. +>> The local variable "a" is shadowing an already-declared variable at line 1 in the current class. 1 2 1 diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/lambda_shadowing_arg.out b/modules/gdscript/tests/scripts/analyzer/warnings/lambda_shadowing_arg.out index a98d80514c..5d059b9193 100644 --- a/modules/gdscript/tests/scripts/analyzer/warnings/lambda_shadowing_arg.out +++ b/modules/gdscript/tests/scripts/analyzer/warnings/lambda_shadowing_arg.out @@ -2,5 +2,5 @@ GDTEST_OK >> WARNING >> Line: 4 >> SHADOWED_VARIABLE ->> The local function parameter "shadow" is shadowing an already-declared variable at line 1. +>> The local function parameter "shadow" is shadowing an already-declared variable at line 1 in the current class. shadow diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/shadowing_base.notest.gd b/modules/gdscript/tests/scripts/analyzer/warnings/shadowing_base.notest.gd new file mode 100644 index 0000000000..5819246ded --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/warnings/shadowing_base.notest.gd @@ -0,0 +1,7 @@ +class_name ShadowingBase + +const base_const_member = 1 +var base_variable_member + +func base_function_member(): + pass diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.gd b/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.gd index 939e787ea5..6a16ae6bcc 100644 --- a/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.gd +++ b/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.gd @@ -1,4 +1,5 @@ class_name ShadowedClass +extends ShadowingBase var member: int = 0 @@ -7,6 +8,7 @@ var print_debug := 'print_debug' var print := 'print' @warning_ignore("unused_variable") +@warning_ignore("unused_local_constant") func test(): var Array := 'Array' var Node := 'Node' @@ -15,5 +17,8 @@ func test(): var member := 'member' var reference := 'reference' var ShadowedClass := 'ShadowedClass' + var base_variable_member + const base_function_member = 1 + var base_const_member print('warn') diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.out b/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.out index 8297eed4b8..075f5d3225 100644 --- a/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.out +++ b/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.out @@ -1,34 +1,46 @@ GDTEST_OK >> WARNING ->> Line: 5 +>> Line: 6 >> SHADOWED_GLOBAL_IDENTIFIER >> The variable "print_debug" has the same name as a built-in function. >> WARNING ->> Line: 11 +>> Line: 13 >> SHADOWED_GLOBAL_IDENTIFIER >> The variable "Array" has the same name as a built-in type. >> WARNING ->> Line: 12 +>> Line: 14 >> SHADOWED_GLOBAL_IDENTIFIER >> The variable "Node" has the same name as a native class. >> WARNING ->> Line: 13 +>> Line: 15 >> SHADOWED_GLOBAL_IDENTIFIER >> The variable "is_same" has the same name as a built-in function. >> WARNING ->> Line: 14 +>> Line: 16 >> SHADOWED_GLOBAL_IDENTIFIER >> The variable "sqrt" has the same name as a built-in function. >> WARNING ->> Line: 15 +>> Line: 17 >> SHADOWED_VARIABLE ->> The local variable "member" is shadowing an already-declared variable at line 3. +>> The local variable "member" is shadowing an already-declared variable at line 4 in the current class. >> WARNING ->> Line: 16 +>> Line: 18 >> SHADOWED_VARIABLE_BASE_CLASS ->> The local variable "reference" is shadowing an already-declared method at the base class "RefCounted". +>> The local variable "reference" is shadowing an already-declared method in the base class "RefCounted". >> WARNING ->> Line: 17 +>> Line: 19 >> SHADOWED_GLOBAL_IDENTIFIER >> The variable "ShadowedClass" has the same name as a global class defined in "shadowning.gd". +>> WARNING +>> Line: 20 +>> SHADOWED_VARIABLE_BASE_CLASS +>> The local variable "base_variable_member" is shadowing an already-declared variable at line 4 in the base class "ShadowingBase". +>> WARNING +>> Line: 21 +>> SHADOWED_VARIABLE_BASE_CLASS +>> The local constant "base_function_member" is shadowing an already-declared function at line 6 in the base class "ShadowingBase". +>> WARNING +>> Line: 22 +>> SHADOWED_VARIABLE_BASE_CLASS +>> The local variable "base_const_member" is shadowing an already-declared constant at line 3 in the base class "ShadowingBase". warn diff --git a/modules/gdscript/tests/scripts/parser/warnings/shadowed_constant.out b/modules/gdscript/tests/scripts/parser/warnings/shadowed_constant.out index 75fa01f928..04df229f66 100644 --- a/modules/gdscript/tests/scripts/parser/warnings/shadowed_constant.out +++ b/modules/gdscript/tests/scripts/parser/warnings/shadowed_constant.out @@ -6,4 +6,4 @@ GDTEST_OK >> WARNING >> Line: 8 >> SHADOWED_VARIABLE ->> The local constant "TEST" is shadowing an already-declared constant at line 2. +>> The local constant "TEST" is shadowing an already-declared constant at line 2 in the current class. diff --git a/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_class.out b/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_class.out index aab27e78e2..4a6964f503 100644 --- a/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_class.out +++ b/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_class.out @@ -6,4 +6,4 @@ GDTEST_OK >> WARNING >> Line: 8 >> SHADOWED_VARIABLE ->> The local variable "foo" is shadowing an already-declared variable at line 1. +>> The local variable "foo" is shadowing an already-declared variable at line 1 in the current class. diff --git a/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_function.out b/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_function.out index e3cd358126..45fb771829 100644 --- a/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_function.out +++ b/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_function.out @@ -6,4 +6,4 @@ GDTEST_OK >> WARNING >> Line: 2 >> SHADOWED_VARIABLE ->> The local variable "test" is shadowing an already-declared function at line 1. +>> The local variable "test" is shadowing an already-declared function at line 1 in the current class. diff --git a/modules/gdscript/tests/scripts/runtime/features/parameter_shadowing.out b/modules/gdscript/tests/scripts/runtime/features/parameter_shadowing.out index 5492c8f763..1650acadb5 100644 --- a/modules/gdscript/tests/scripts/runtime/features/parameter_shadowing.out +++ b/modules/gdscript/tests/scripts/runtime/features/parameter_shadowing.out @@ -2,11 +2,11 @@ GDTEST_OK >> WARNING >> Line: 5 >> SHADOWED_VARIABLE ->> The local function parameter "a" is shadowing an already-declared variable at line 3. +>> The local function parameter "a" is shadowing an already-declared variable at line 3 in the current class. >> WARNING >> Line: 15 >> SHADOWED_VARIABLE ->> The local function parameter "v" is shadowing an already-declared variable at line 13. +>> The local function parameter "v" is shadowing an already-declared variable at line 13 in the current class. a 1 b diff --git a/modules/gltf/doc_classes/GLTFAnimation.xml b/modules/gltf/doc_classes/GLTFAnimation.xml index d269145bbd..f11dea8ee8 100644 --- a/modules/gltf/doc_classes/GLTFAnimation.xml +++ b/modules/gltf/doc_classes/GLTFAnimation.xml @@ -13,7 +13,7 @@ <param index="0" name="extension_name" type="StringName" /> <description> Gets additional arbitrary data in this [GLTFAnimation] instance. This can be used to keep per-node state data in [GLTFDocumentExtension] classes, which is important because they are stateless. - The argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the glTF file), and the return value can be anything you set. If nothing was set, the return value is null. + The argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the glTF file), and the return value can be anything you set. If nothing was set, the return value is [code]null[/code]. </description> </method> <method name="set_additional_data"> diff --git a/modules/gltf/doc_classes/GLTFBufferView.xml b/modules/gltf/doc_classes/GLTFBufferView.xml index b7f499ad72..9c2ee3197f 100644 --- a/modules/gltf/doc_classes/GLTFBufferView.xml +++ b/modules/gltf/doc_classes/GLTFBufferView.xml @@ -34,10 +34,10 @@ The stride, in bytes, between interleaved data. If [code]-1[/code], this buffer view is not interleaved. </member> <member name="indices" type="bool" setter="set_indices" getter="get_indices" default="false"> - True if the GLTFBufferView's OpenGL GPU buffer type is an [code]ELEMENT_ARRAY_BUFFER[/code] used for vertex indices (integer constant [code]34963[/code]). False if the buffer type is any other value. See [url=https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_005_BuffersBufferViewsAccessors.md]Buffers, BufferViews, and Accessors[/url] for possible values. This property is set on import and used on export. + [code]true[/code] if the GLTFBufferView's OpenGL GPU buffer type is an [code]ELEMENT_ARRAY_BUFFER[/code] used for vertex indices (integer constant [code]34963[/code]). [code]false[/code] if the buffer type is any other value. See [url=https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_005_BuffersBufferViewsAccessors.md]Buffers, BufferViews, and Accessors[/url] for possible values. This property is set on import and used on export. </member> <member name="vertex_attributes" type="bool" setter="set_vertex_attributes" getter="get_vertex_attributes" default="false"> - True if the GLTFBufferView's OpenGL GPU buffer type is an [code]ARRAY_BUFFER[/code] used for vertex attributes (integer constant [code]34962[/code]). False if the buffer type is any other value. See [url=https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_005_BuffersBufferViewsAccessors.md]Buffers, BufferViews, and Accessors[/url] for possible values. This property is set on import and used on export. + [code]true[/code] if the GLTFBufferView's OpenGL GPU buffer type is an [code]ARRAY_BUFFER[/code] used for vertex attributes (integer constant [code]34962[/code]). [code]false[/code] if the buffer type is any other value. See [url=https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_005_BuffersBufferViewsAccessors.md]Buffers, BufferViews, and Accessors[/url] for possible values. This property is set on import and used on export. </member> </members> </class> diff --git a/modules/gltf/doc_classes/GLTFCamera.xml b/modules/gltf/doc_classes/GLTFCamera.xml index 9fce21659c..12334683ba 100644 --- a/modules/gltf/doc_classes/GLTFCamera.xml +++ b/modules/gltf/doc_classes/GLTFCamera.xml @@ -47,13 +47,13 @@ The distance to the near culling boundary for this camera relative to its local Z axis, in meters. This maps to glTF's [code]znear[/code] property. </member> <member name="fov" type="float" setter="set_fov" getter="get_fov" default="1.309"> - The FOV of the camera. This class and glTF define the camera FOV in radians, while Godot uses degrees. This maps to glTF's [code]yfov[/code] property. This value is only used for perspective cameras, when [member perspective] is true. + The FOV of the camera. This class and glTF define the camera FOV in radians, while Godot uses degrees. This maps to glTF's [code]yfov[/code] property. This value is only used for perspective cameras, when [member perspective] is [code]true[/code]. </member> <member name="perspective" type="bool" setter="set_perspective" getter="get_perspective" default="true"> - Whether or not the camera is in perspective mode. If false, the camera is in orthographic/orthogonal mode. This maps to glTF's camera [code]type[/code] property. See [member Camera3D.projection] and the glTF spec for more information. + If [code]true[/code], the camera is in perspective mode. Otherwise, the camera is in orthographic/orthogonal mode. This maps to glTF's camera [code]type[/code] property. See [member Camera3D.projection] and the glTF spec for more information. </member> <member name="size_mag" type="float" setter="set_size_mag" getter="get_size_mag" default="0.5"> - The size of the camera. This class and glTF define the camera size magnitude as a radius in meters, while Godot defines it as a diameter in meters. This maps to glTF's [code]ymag[/code] property. This value is only used for orthographic/orthogonal cameras, when [member perspective] is false. + The size of the camera. This class and glTF define the camera size magnitude as a radius in meters, while Godot defines it as a diameter in meters. This maps to glTF's [code]ymag[/code] property. This value is only used for orthographic/orthogonal cameras, when [member perspective] is [code]false[/code]. </member> </members> </class> diff --git a/modules/gltf/doc_classes/GLTFDocument.xml b/modules/gltf/doc_classes/GLTFDocument.xml index ffc3ab926c..47ffc624ba 100644 --- a/modules/gltf/doc_classes/GLTFDocument.xml +++ b/modules/gltf/doc_classes/GLTFDocument.xml @@ -93,7 +93,7 @@ <param index="0" name="extension" type="GLTFDocumentExtension" /> <param index="1" name="first_priority" type="bool" default="false" /> <description> - Registers the given [GLTFDocumentExtension] instance with GLTFDocument. If [param first_priority] is true, this extension will be run first. Otherwise, it will be run last. + Registers the given [GLTFDocumentExtension] instance with GLTFDocument. If [param first_priority] is [code]true[/code], this extension will be run first. Otherwise, it will be run last. [b]Note:[/b] Like GLTFDocument itself, all GLTFDocumentExtension classes must be stateless in order to function properly. If you need to store data, use the [code]set_additional_data[/code] and [code]get_additional_data[/code] methods in [GLTFState] or [GLTFNode]. </description> </method> diff --git a/modules/gltf/doc_classes/GLTFDocumentExtension.xml b/modules/gltf/doc_classes/GLTFDocumentExtension.xml index 8fcb925a48..abdbce7eeb 100644 --- a/modules/gltf/doc_classes/GLTFDocumentExtension.xml +++ b/modules/gltf/doc_classes/GLTFDocumentExtension.xml @@ -30,7 +30,7 @@ <param index="3" name="node" type="Node" /> <description> Part of the export process. This method is run after [method _get_saveable_image_formats] and before [method _export_post]. If this [GLTFDocumentExtension] is used for exporting images, this runs after [method _serialize_texture_json]. - This method can be used to modify the final JSON of each node. Data should be primarily stored in [param gltf_node] prior to serializing the JSON, but the original Godot [param node] is also provided if available. The node may be null if not available, such as when exporting glTF data not generated from a Godot scene. + This method can be used to modify the final JSON of each node. Data should be primarily stored in [param gltf_node] prior to serializing the JSON, but the original Godot [Node] is also provided if available. [param node] may be [code]null[/code] if not available, such as when exporting glTF data not generated from a Godot scene. </description> </method> <method name="_export_object_model_property" qualifiers="virtual"> @@ -43,7 +43,7 @@ <param index="5" name="target_depth" type="int" /> <description> Part of the export process. Allows GLTFDocumentExtension classes to provide mappings for properties of nodes in the Godot scene tree, to JSON pointers to glTF properties, as defined by the glTF object model. - Returns a [GLTFObjectModelProperty] instance that defines how the property should be mapped. If your extension can't handle the property, return null, or an instance without any JSON pointers (see [method GLTFObjectModelProperty.has_json_pointers]). You should use [method GLTFObjectModelProperty.set_types] to set the types, and set the JSON pointer(s) using the [member GLTFObjectModelProperty.json_pointers] property. + Returns a [GLTFObjectModelProperty] instance that defines how the property should be mapped. If your extension can't handle the property, return [code]null[/code] or an instance without any JSON pointers (see [method GLTFObjectModelProperty.has_json_pointers]). You should use [method GLTFObjectModelProperty.set_types] to set the types, and set the JSON pointer(s) using the [member GLTFObjectModelProperty.json_pointers] property. The parameters provide context for the property, including the NodePath, the Godot node, the GLTF node index, and the target object. The [param target_object] will be equal to [param godot_node] if no sub-object can be found, otherwise it will point to a sub-object. For example, if the path is [code]^"A/B/C/MeshInstance3D:mesh:surface_0/material:emission_intensity"[/code], it will get the node, then the mesh, and then the material, so [param target_object] will be the [Material] resource, and [param target_depth] will be 2 because 2 levels were traversed to get to the target. </description> </method> @@ -89,7 +89,7 @@ <description> Part of the import process. This method is run after [method _import_pre_generate] and before [method _import_node]. Runs when generating a Godot scene node from a GLTFNode. The returned node will be added to the scene tree. Multiple nodes can be generated in this step if they are added as a child of the returned node. - [b]Note:[/b] The [param scene_parent] parameter may be null if this is the single root node. + [b]Note:[/b] The [param scene_parent] parameter may be [code]null[/code] if this is the single root node. </description> </method> <method name="_get_image_file_extension" qualifiers="virtual"> @@ -130,7 +130,7 @@ <param index="2" name="partial_paths" type="NodePath[]" /> <description> Part of the import process. Allows GLTFDocumentExtension classes to provide mappings for JSON pointers to glTF properties, as defined by the glTF object model, to properties of nodes in the Godot scene tree. - Returns a [GLTFObjectModelProperty] instance that defines how the property should be mapped. If your extension can't handle the property, return null, or an instance without any NodePaths (see [method GLTFObjectModelProperty.has_node_paths]). You should use [method GLTFObjectModelProperty.set_types] to set the types, and [method GLTFObjectModelProperty.append_path_to_property] function is useful for most simple cases. + Returns a [GLTFObjectModelProperty] instance that defines how the property should be mapped. If your extension can't handle the property, return [code]null[/code] or an instance without any NodePaths (see [method GLTFObjectModelProperty.has_node_paths]). You should use [method GLTFObjectModelProperty.set_types] to set the types, and [method GLTFObjectModelProperty.append_path_to_property] function is useful for most simple cases. In many cases, [param partial_paths] will contain the start of a path, allowing the extension to complete the path. For example, for [code]/nodes/3/extensions/MY_ext/prop[/code], Godot will pass you a NodePath that leads to node 3, so the GLTFDocumentExtension class only needs to resolve the last [code]MY_ext/prop[/code] part of the path. In this example, the extension should check [code]split.size() > 4 and split[0] == "nodes" and split[2] == "extensions" and split[3] == "MY_ext"[/code] at the start of the function to check if this JSON pointer applies to it, then it can use [param partial_paths] and handle [code]split[4][/code]. </description> </method> diff --git a/modules/gltf/doc_classes/GLTFMesh.xml b/modules/gltf/doc_classes/GLTFMesh.xml index da73c20c1d..439078ffcc 100644 --- a/modules/gltf/doc_classes/GLTFMesh.xml +++ b/modules/gltf/doc_classes/GLTFMesh.xml @@ -15,7 +15,7 @@ <param index="0" name="extension_name" type="StringName" /> <description> Gets additional arbitrary data in this [GLTFMesh] instance. This can be used to keep per-node state data in [GLTFDocumentExtension] classes, which is important because they are stateless. - The argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the glTF file), and the return value can be anything you set. If nothing was set, the return value is null. + The argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the glTF file), and the return value can be anything you set. If nothing was set, the return value is [code]null[/code]. </description> </method> <method name="set_additional_data"> diff --git a/modules/gltf/doc_classes/GLTFNode.xml b/modules/gltf/doc_classes/GLTFNode.xml index eb92723a06..0fb85e4029 100644 --- a/modules/gltf/doc_classes/GLTFNode.xml +++ b/modules/gltf/doc_classes/GLTFNode.xml @@ -24,7 +24,7 @@ <param index="0" name="extension_name" type="StringName" /> <description> Gets additional arbitrary data in this [GLTFNode] instance. This can be used to keep per-node state data in [GLTFDocumentExtension] classes, which is important because they are stateless. - The argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the glTF file), and the return value can be anything you set. If nothing was set, the return value is null. + The argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the glTF file), and the return value can be anything you set. If nothing was set, the return value is [code]null[/code]. </description> </method> <method name="get_scene_node_path"> @@ -33,7 +33,7 @@ <param index="1" name="handle_skeletons" type="bool" default="true" /> <description> Returns the [NodePath] that this GLTF node will have in the Godot scene tree after being imported. This is useful when importing glTF object model pointers with [GLTFObjectModelProperty], for handling extensions such as [code]KHR_animation_pointer[/code] or [code]KHR_interactivity[/code]. - If [param handle_skeletons] is true, paths to skeleton bone glTF nodes will be resolved properly. For example, a path that would be [code]^"A/B/C/Bone1/Bone2/Bone3"[/code] if false will become [code]^"A/B/C/Skeleton3D:Bone3"[/code]. + If [param handle_skeletons] is [code]true[/code], paths to skeleton bone glTF nodes will be resolved properly. For example, a path that would be [code]^"A/B/C/Bone1/Bone2/Bone3"[/code] if [code]false[/code] will become [code]^"A/B/C/Skeleton3D:Bone3"[/code]. </description> </method> <method name="set_additional_data"> diff --git a/modules/gltf/doc_classes/GLTFObjectModelProperty.xml b/modules/gltf/doc_classes/GLTFObjectModelProperty.xml index e983269ccc..a457d94c41 100644 --- a/modules/gltf/doc_classes/GLTFObjectModelProperty.xml +++ b/modules/gltf/doc_classes/GLTFObjectModelProperty.xml @@ -81,7 +81,7 @@ Unknown or not set object model type. If the object model type is set to this value, the real type still needs to be determined. </constant> <constant name="GLTF_OBJECT_MODEL_TYPE_BOOL" value="1" enum="GLTFObjectModelType"> - Object model type "bool". Represented in the glTF JSON as a boolean, and encoded in a [GLTFAccessor] as "SCALAR". When encoded in an accessor, a value of 0 is false, and any other value is true. + Object model type "bool". Represented in the glTF JSON as a boolean, and encoded in a [GLTFAccessor] as "SCALAR". When encoded in an accessor, a value of [code]0[/code] is [code]false[/code], and any other value is [code]true[/code]. </constant> <constant name="GLTF_OBJECT_MODEL_TYPE_FLOAT" value="2" enum="GLTFObjectModelType"> Object model type "float". Represented in the glTF JSON as a number, and encoded in a [GLTFAccessor] as "SCALAR". diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml index de7ec2a4ca..376c3c89f5 100644 --- a/modules/gltf/doc_classes/GLTFState.xml +++ b/modules/gltf/doc_classes/GLTFState.xml @@ -17,7 +17,7 @@ <param index="0" name="extension_name" type="String" /> <param index="1" name="required" type="bool" /> <description> - Appends an extension to the list of extensions used by this glTF file during serialization. If [param required] is true, the extension will also be added to the list of required extensions. Do not run this in [method GLTFDocumentExtension._export_post], as that stage is too late to add extensions. The final list is sorted alphabetically. + Appends an extension to the list of extensions used by this glTF file during serialization. If [param required] is [code]true[/code], the extension will also be added to the list of required extensions. Do not run this in [method GLTFDocumentExtension._export_post], as that stage is too late to add extensions. The final list is sorted alphabetically. </description> </method> <method name="append_data_to_buffers"> @@ -25,7 +25,7 @@ <param index="0" name="data" type="PackedByteArray" /> <param index="1" name="deduplication" type="bool" /> <description> - Appends the given byte array data to the buffers and creates a [GLTFBufferView] for it. The index of the destination [GLTFBufferView] is returned. If [param deduplication] is true, the buffers will first be searched for duplicate data, otherwise new bytes will always be appended. + Appends the given byte array data to the buffers and creates a [GLTFBufferView] for it. The index of the destination [GLTFBufferView] is returned. If [param deduplication] is [code]true[/code], the buffers will first be searched for duplicate data, otherwise new bytes will always be appended. </description> </method> <method name="append_gltf_node"> @@ -35,7 +35,7 @@ <param index="2" name="parent_node_index" type="int" /> <description> Append the given [GLTFNode] to the state, and return its new index. This can be used to export one Godot node as multiple glTF nodes, or inject new glTF nodes at import time. On import, this must be called before [method GLTFDocumentExtension._generate_scene_node] finishes for the parent node. On export, this must be called before [method GLTFDocumentExtension._export_node] runs for the parent node. - The [param godot_scene_node] parameter is the Godot scene node that corresponds to this glTF node. This is highly recommended to be set to a valid node, but may be null if there is no corresponding Godot scene node. One Godot scene node may be used for multiple glTF nodes, so if exporting multiple glTF nodes for one Godot scene node, use the same Godot scene node for each. + The [param godot_scene_node] parameter is the Godot scene node that corresponds to this glTF node. This is highly recommended to be set to a valid node, but may be [code]null[/code] if there is no corresponding Godot scene node. One Godot scene node may be used for multiple glTF nodes, so if exporting multiple glTF nodes for one Godot scene node, use the same Godot scene node for each. The [param parent_node_index] parameter is the index of the parent [GLTFNode] in the state. If [code]-1[/code], the node will be a root node, otherwise the new node will be added to the parent's list of children. The index will also be written to the [member GLTFNode.parent] property of the new node. </description> </method> @@ -49,7 +49,7 @@ <param index="0" name="extension_name" type="StringName" /> <description> Gets additional arbitrary data in this [GLTFState] instance. This can be used to keep per-file state data in [GLTFDocumentExtension] classes, which is important because they are stateless. - The argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the glTF file), and the return value can be anything you set. If nothing was set, the return value is null. + The argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the glTF file), and the return value can be anything you set. If nothing was set, the return value is [code]null[/code]. </description> </method> <method name="get_animation_player"> diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp index 022d2e4477..872054ec2e 100644 --- a/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp +++ b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp @@ -88,7 +88,7 @@ void SceneExporterGLTFPlugin::_popup_gltf_export_dialog() { } _file_dialog->set_current_file(filename + String(".gltf")); // Generate and refresh the export settings. - _export_settings->generate_property_list(_gltf_document); + _export_settings->generate_property_list(_gltf_document, root); _settings_inspector->edit(nullptr); _settings_inspector->edit(_export_settings.ptr()); // Show the file dialog. diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp b/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp index 511da078d8..c14e92c3a0 100644 --- a/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp +++ b/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp @@ -129,7 +129,7 @@ String get_friendly_config_prefix(Ref<GLTFDocumentExtension> p_extension) { } // Run this before popping up the export settings, because the extensions may have changed. -void EditorSceneExporterGLTFSettings::generate_property_list(Ref<GLTFDocument> p_document) { +void EditorSceneExporterGLTFSettings::generate_property_list(Ref<GLTFDocument> p_document, Node *p_root) { _property_list.clear(); _document = p_document; String image_format_hint_string = "None,PNG,JPEG"; diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_settings.h b/modules/gltf/editor/editor_scene_exporter_gltf_settings.h index 898cddfd68..aa0e54078d 100644 --- a/modules/gltf/editor/editor_scene_exporter_gltf_settings.h +++ b/modules/gltf/editor/editor_scene_exporter_gltf_settings.h @@ -55,7 +55,7 @@ protected: bool _get_extension_setting(const String &p_name_str, Variant &r_ret) const; public: - void generate_property_list(Ref<GLTFDocument> p_document); + void generate_property_list(Ref<GLTFDocument> p_document, Node *p_root = nullptr); String get_copyright() const; void set_copyright(const String &p_copyright); diff --git a/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.cpp b/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.cpp index cde30bce18..b5edd35ad5 100644 --- a/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.cpp +++ b/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.cpp @@ -63,6 +63,7 @@ Error GLTFDocumentExtensionConvertImporterMesh::import_post(Ref<GLTFState> p_sta mesh_instance_node_3d->set_mesh(array_mesh); mesh_instance_node_3d->set_skin(importer_mesh_3d->get_skin()); mesh_instance_node_3d->set_skeleton_path(importer_mesh_3d->get_skeleton_path()); + mesh_instance_node_3d->set_visible(importer_mesh_3d->is_visible()); node->replace_by(mesh_instance_node_3d); _copy_meta(importer_mesh_3d, mesh_instance_node_3d); _copy_meta(mesh.ptr(), array_mesh.ptr()); diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 571a04936d..aa482615da 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -3482,6 +3482,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) { } } array[Mesh::ARRAY_WEIGHTS] = weights; + flags |= Mesh::ARRAY_FLAG_USE_8_BONE_WEIGHTS; } if (!indices.is_empty()) { diff --git a/modules/interactive_music/doc_classes/AudioStreamInteractive.xml b/modules/interactive_music/doc_classes/AudioStreamInteractive.xml index 17448724d1..d47d6ecde6 100644 --- a/modules/interactive_music/doc_classes/AudioStreamInteractive.xml +++ b/modules/interactive_music/doc_classes/AudioStreamInteractive.xml @@ -119,7 +119,7 @@ <param index="0" name="from_clip" type="int" /> <param index="1" name="to_clip" type="int" /> <description> - Return true if a given transition exists (was added via [method add_transition]). + Returns [code]true[/code] if a given transition exists (was added via [method add_transition]). </description> </method> <method name="is_transition_holding_previous" qualifiers="const"> diff --git a/modules/minimp3/doc_classes/ResourceImporterMP3.xml b/modules/minimp3/doc_classes/ResourceImporterMP3.xml index 72868623c7..fc0ec3682b 100644 --- a/modules/minimp3/doc_classes/ResourceImporterMP3.xml +++ b/modules/minimp3/doc_classes/ResourceImporterMP3.xml @@ -13,15 +13,15 @@ </tutorials> <members> <member name="bar_beats" type="int" setter="" getter="" default="4"> - The number of bars within a single beat in the audio track. This is only relevant for music that wishes to make use of interactive music functionality (not implemented yet), not sound effects. + The number of bars within a single beat in the audio track. This is only relevant for music that wishes to make use of interactive music functionality, not sound effects. A more convenient editor for [member bar_beats] is provided in the [b]Advanced Import Settings[/b] dialog, as it lets you preview your changes without having to reimport the audio. </member> <member name="beat_count" type="int" setter="" getter="" default="0"> - The beat count of the audio track. This is only relevant for music that wishes to make use of interactive music functionality (not implemented yet), not sound effects. + The beat count of the audio track. This is only relevant for music that wishes to make use of interactive music functionality, not sound effects. A more convenient editor for [member beat_count] is provided in the [b]Advanced Import Settings[/b] dialog, as it lets you preview your changes without having to reimport the audio. </member> <member name="bpm" type="float" setter="" getter="" default="0"> - The Beats Per Minute of the audio track. This should match the BPM measure that was used to compose the track. This is only relevant for music that wishes to make use of interactive music functionality (not implemented yet), not sound effects. + The beats per minute of the audio track. This should match the BPM measure that was used to compose the track. This is only relevant for music that wishes to make use of interactive music functionality, not sound effects. A more convenient editor for [member bpm] is provided in the [b]Advanced Import Settings[/b] dialog, as it lets you preview your changes without having to reimport the audio. </member> <member name="loop" type="bool" setter="" getter="" default="false"> diff --git a/modules/minimp3/resource_importer_mp3.h b/modules/minimp3/resource_importer_mp3.h index 2df44deaea..037756328f 100644 --- a/modules/minimp3/resource_importer_mp3.h +++ b/modules/minimp3/resource_importer_mp3.h @@ -59,6 +59,8 @@ public: virtual Error 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 = nullptr, Variant *r_metadata = nullptr) override; + virtual bool can_import_threaded() const override { return true; } + ResourceImporterMP3(); }; diff --git a/modules/navigation/3d/nav_mesh_queries_3d.cpp b/modules/navigation/3d/nav_mesh_queries_3d.cpp index 70207f86ce..5acc598d43 100644 --- a/modules/navigation/3d/nav_mesh_queries_3d.cpp +++ b/modules/navigation/3d/nav_mesh_queries_3d.cpp @@ -234,7 +234,7 @@ Vector<Vector3> NavMeshQueries3D::polygons_get_path(const LocalVector<gd::Polygo // Takes the current least_cost_poly neighbors (iterating over its edges) and compute the traveled_distance. for (const gd::Edge &edge : navigation_polys[least_cost_id].poly->edges) { // Iterate over connections in this edge, then compute the new optimized travel distance assigned to this polygon. - for (int connection_index = 0; connection_index < edge.connections.size(); connection_index++) { + for (uint32_t connection_index = 0; connection_index < edge.connections.size(); connection_index++) { const gd::Edge::Connection &connection = edge.connections[connection_index]; // Only consider the connection to another polygon if this polygon is in a region with compatible layers. diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp index 04c8a5a943..8055dd4bc8 100644 --- a/modules/navigation/nav_map.cpp +++ b/modules/navigation/nav_map.cpp @@ -426,13 +426,8 @@ void NavMap::sync() { _new_pm_polygon_count = polygon_count; - struct ConnectionPair { - gd::Edge::Connection connections[2]; - int size = 0; - }; - // Group all edges per key. - HashMap<gd::EdgeKey, ConnectionPair, gd::EdgeKey> connection_pairs_map; + connection_pairs_map.clear(); connection_pairs_map.reserve(polygons.size()); int free_edges_count = 0; // How many ConnectionPairs have only one Connection. @@ -469,7 +464,7 @@ void NavMap::sync() { } } - LocalVector<gd::Edge::Connection> free_edges; + free_edges.clear(); free_edges.reserve(free_edges_count); for (const KeyValue<gd::EdgeKey, ConnectionPair> &pair_it : connection_pairs_map) { diff --git a/modules/navigation/nav_map.h b/modules/navigation/nav_map.h index b9120c04d9..3442b78497 100644 --- a/modules/navigation/nav_map.h +++ b/modules/navigation/nav_map.h @@ -128,6 +128,14 @@ class NavMap : public NavRid { HashMap<NavRegion *, LocalVector<gd::Edge::Connection>> region_external_connections; + struct ConnectionPair { + gd::Edge::Connection connections[2]; + int size = 0; + }; + + HashMap<gd::EdgeKey, ConnectionPair, gd::EdgeKey> connection_pairs_map; + LocalVector<gd::Edge::Connection> free_edges; + public: NavMap(); ~NavMap(); diff --git a/modules/navigation/nav_utils.h b/modules/navigation/nav_utils.h index ba4c44b748..c466c82fc7 100644 --- a/modules/navigation/nav_utils.h +++ b/modules/navigation/nav_utils.h @@ -94,7 +94,7 @@ struct Edge { }; /// Connections from this edge to other polygons. - Vector<Connection> connections; + LocalVector<Connection> connections; }; struct Polygon { diff --git a/modules/openxr/doc_classes/OpenXRCompositionLayer.xml b/modules/openxr/doc_classes/OpenXRCompositionLayer.xml index 341b50065c..cfc7cd4d97 100644 --- a/modules/openxr/doc_classes/OpenXRCompositionLayer.xml +++ b/modules/openxr/doc_classes/OpenXRCompositionLayer.xml @@ -29,7 +29,7 @@ <method name="is_natively_supported" qualifiers="const"> <return type="bool" /> <description> - Returns true if the OpenXR runtime natively supports this composition layer type. + Returns [code]true[/code] if the OpenXR runtime natively supports this composition layer type. [b]Note:[/b] This will only return an accurate result after the OpenXR session has started. </description> </method> diff --git a/modules/raycast/raycast_occlusion_cull.cpp b/modules/raycast/raycast_occlusion_cull.cpp index 634c370b05..3609f5a554 100644 --- a/modules/raycast/raycast_occlusion_cull.cpp +++ b/modules/raycast/raycast_occlusion_cull.cpp @@ -90,18 +90,11 @@ void RaycastOcclusionCull::RaycastHZBuffer::update_camera_rays(const Transform3D td.camera_dir = -p_cam_transform.basis.get_column(2); td.camera_orthogonal = p_cam_orthogonal; - Projection inv_camera_matrix = p_cam_projection.inverse(); - Vector3 camera_corner_proj = Vector3(-1.0f, -1.0f, -1.0f); - Vector3 camera_corner_view = inv_camera_matrix.xform(camera_corner_proj); - td.pixel_corner = p_cam_transform.xform(camera_corner_view); - - Vector3 top_corner_proj = Vector3(-1.0f, 1.0f, -1.0f); - Vector3 top_corner_view = inv_camera_matrix.xform(top_corner_proj); - Vector3 top_corner_world = p_cam_transform.xform(top_corner_view); - - Vector3 left_corner_proj = Vector3(1.0f, -1.0f, -1.0f); - Vector3 left_corner_view = inv_camera_matrix.xform(left_corner_proj); - Vector3 left_corner_world = p_cam_transform.xform(left_corner_view); + // Calculate the world coordinates of the viewport. + Vector2 viewport_half = p_cam_projection.get_viewport_half_extents(); + td.pixel_corner = p_cam_transform.xform(Vector3(-viewport_half.x, -viewport_half.y, -p_cam_projection.get_z_near())); + Vector3 top_corner_world = p_cam_transform.xform(Vector3(-viewport_half.x, viewport_half.y, -p_cam_projection.get_z_near())); + Vector3 left_corner_world = p_cam_transform.xform(Vector3(viewport_half.x, -viewport_half.y, -p_cam_projection.get_z_near())); td.pixel_u_interp = left_corner_world - td.pixel_corner; td.pixel_v_interp = top_corner_world - td.pixel_corner; diff --git a/modules/vorbis/doc_classes/ResourceImporterOggVorbis.xml b/modules/vorbis/doc_classes/ResourceImporterOggVorbis.xml index 8ae63140f5..cede03c73a 100644 --- a/modules/vorbis/doc_classes/ResourceImporterOggVorbis.xml +++ b/modules/vorbis/doc_classes/ResourceImporterOggVorbis.xml @@ -29,15 +29,15 @@ </methods> <members> <member name="bar_beats" type="int" setter="" getter="" default="4"> - The number of bars within a single beat in the audio track. This is only relevant for music that wishes to make use of interactive music functionality (not implemented yet), not sound effects. + The number of bars within a single beat in the audio track. This is only relevant for music that wishes to make use of interactive music functionality, not sound effects. A more convenient editor for [member bar_beats] is provided in the [b]Advanced Import Settings[/b] dialog, as it lets you preview your changes without having to reimport the audio. </member> <member name="beat_count" type="int" setter="" getter="" default="0"> - The beat count of the audio track. This is only relevant for music that wishes to make use of interactive music functionality (not implemented yet), not sound effects. + The beat count of the audio track. This is only relevant for music that wishes to make use of interactive music functionality, not sound effects. A more convenient editor for [member beat_count] is provided in the [b]Advanced Import Settings[/b] dialog, as it lets you preview your changes without having to reimport the audio. </member> <member name="bpm" type="float" setter="" getter="" default="0"> - The Beats Per Minute of the audio track. This should match the BPM measure that was used to compose the track. This is only relevant for music that wishes to make use of interactive music functionality (not implemented yet), not sound effects. + The beats per minute of the audio track. This should match the BPM measure that was used to compose the track. This is only relevant for music that wishes to make use of interactive music functionality, not sound effects. A more convenient editor for [member bpm] is provided in the [b]Advanced Import Settings[/b] dialog, as it lets you preview your changes without having to reimport the audio. </member> <member name="loop" type="bool" setter="" getter="" default="false"> diff --git a/modules/vorbis/resource_importer_ogg_vorbis.h b/modules/vorbis/resource_importer_ogg_vorbis.h index 59ae3378a0..f378b80694 100644 --- a/modules/vorbis/resource_importer_ogg_vorbis.h +++ b/modules/vorbis/resource_importer_ogg_vorbis.h @@ -65,6 +65,8 @@ public: virtual Error 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 = nullptr, Variant *r_metadata = nullptr) override; + virtual bool can_import_threaded() const override { return true; } + ResourceImporterOggVorbis(); }; diff --git a/platform/SCsub b/platform/SCsub index 7c9d07f6ef..248b4b88dd 100644 --- a/platform/SCsub +++ b/platform/SCsub @@ -60,7 +60,7 @@ register_platform_apis = env.CommandNoCache( ) env.add_source_files(env.platform_sources, register_platform_apis) for platform in env.platform_apis: - env.add_source_files(env.platform_sources, f"{platform}/api/api.cpp") + env.add_source_files(env.platform_sources, f"{platform}/api/*.cpp") lib = env.add_library("platform", env.platform_sources) env.Prepend(LIBS=[lib]) diff --git a/platform/windows/detect.py b/platform/windows/detect.py index ddcd29adc9..e1109db24f 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -68,23 +68,23 @@ def can_build(): def get_mingw_bin_prefix(prefix, arch): - if not prefix: - mingw_bin_prefix = "" - elif prefix[-1] != "/": - mingw_bin_prefix = prefix + "/bin/" - else: - mingw_bin_prefix = prefix + "bin/" + bin_prefix = (os.path.normpath(os.path.join(prefix, "bin")) + os.sep) if prefix else "" + ARCH_PREFIXES = { + "x86_64": "x86_64-w64-mingw32-", + "x86_32": "i686-w64-mingw32-", + "arm32": "armv7-w64-mingw32-", + "arm64": "aarch64-w64-mingw32-", + } + arch_prefix = ARCH_PREFIXES[arch] if arch else "" + return bin_prefix + arch_prefix - if arch == "x86_64": - mingw_bin_prefix += "x86_64-w64-mingw32-" - elif arch == "x86_32": - mingw_bin_prefix += "i686-w64-mingw32-" - elif arch == "arm32": - mingw_bin_prefix += "armv7-w64-mingw32-" - elif arch == "arm64": - mingw_bin_prefix += "aarch64-w64-mingw32-" - return mingw_bin_prefix +def get_detected(env: "SConsEnvironment", tool: str) -> str: + checks = [ + get_mingw_bin_prefix(env["mingw_prefix"], env["arch"]) + tool, + get_mingw_bin_prefix(env["mingw_prefix"], "") + tool, + ] + return str(env.Detect(checks)) def detect_build_env_arch(): @@ -245,41 +245,6 @@ def get_flags(): } -def build_res_file(target, source, env: "SConsEnvironment"): - arch_aliases = { - "x86_32": "pe-i386", - "x86_64": "pe-x86-64", - "arm32": "armv7-w64-mingw32", - "arm64": "aarch64-w64-mingw32", - } - cmdbase = "windres --include-dir . --target=" + arch_aliases[env["arch"]] - - mingw_bin_prefix = get_mingw_bin_prefix(env["mingw_prefix"], env["arch"]) - - for x in range(len(source)): - ok = True - # Try prefixed executable (MinGW on Linux). - cmd = mingw_bin_prefix + cmdbase + " -i " + str(source[x]) + " -o " + str(target[x]) - try: - out = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate() - if len(out[1]): - ok = False - except Exception: - ok = False - - # Try generic executable (MSYS2). - if not ok: - cmd = cmdbase + " -i " + str(source[x]) + " -o " + str(target[x]) - try: - out = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate() - if len(out[1]): - return -1 - except Exception: - return -1 - - return 0 - - def setup_msvc_manual(env: "SConsEnvironment"): """Running from VCVARS environment""" @@ -361,6 +326,10 @@ def setup_mingw(env: "SConsEnvironment"): print_error("No valid compilers found, use MINGW_PREFIX environment variable to set MinGW path.") sys.exit(255) + env.Tool("mingw") + env.AppendUnique(CCFLAGS=env.get("ccflags", "").split()) + env.AppendUnique(RCFLAGS=env.get("rcflags", "").split()) + print("Using MinGW, arch %s" % (env["arch"])) @@ -706,6 +675,13 @@ def configure_mingw(env: "SConsEnvironment"): # https://www.scons.org/wiki/LongCmdLinesOnWin32 env.use_windows_spawn_fix() + # HACK: For some reason, Windows-native shells have their MinGW tools + # frequently fail as a result of parsing path separators incorrectly. + # For some other reason, this issue is circumvented entirely if the + # `mingw_prefix` bin is prepended to PATH. + if os.sep == "\\": + env.PrependENVPath("PATH", os.path.join(env["mingw_prefix"], "bin")) + # In case the command line to AR is too long, use a response file. env["ARCOM_ORIG"] = env["ARCOM"] env["ARCOM"] = "${TEMPFILE('$ARCOM_ORIG', '$ARCOMSTR')}" @@ -743,9 +719,6 @@ def configure_mingw(env: "SConsEnvironment"): ## Compiler configuration - if os.name != "nt": - env["PROGSUFFIX"] = env["PROGSUFFIX"] + ".exe" # for linux cross-compilation - if env["arch"] == "x86_32": if env["use_static_cpp"]: env.Append(LINKFLAGS=["-static"]) @@ -760,29 +733,31 @@ def configure_mingw(env: "SConsEnvironment"): env.Append(CCFLAGS=["-ffp-contract=off"]) - mingw_bin_prefix = get_mingw_bin_prefix(env["mingw_prefix"], env["arch"]) - if env["use_llvm"]: - env["CC"] = mingw_bin_prefix + "clang" - env["CXX"] = mingw_bin_prefix + "clang++" - if try_cmd("as --version", env["mingw_prefix"], env["arch"]): - env["AS"] = mingw_bin_prefix + "as" - env.Append(ASFLAGS=["-c"]) - if try_cmd("ar --version", env["mingw_prefix"], env["arch"]): - env["AR"] = mingw_bin_prefix + "ar" - if try_cmd("ranlib --version", env["mingw_prefix"], env["arch"]): - env["RANLIB"] = mingw_bin_prefix + "ranlib" + env["CC"] = get_detected(env, "clang") + env["CXX"] = get_detected(env, "clang++") + env["AR"] = get_detected(env, "ar") + env["RANLIB"] = get_detected(env, "ranlib") + env.Append(ASFLAGS=["-c"]) env.extra_suffix = ".llvm" + env.extra_suffix else: - env["CC"] = mingw_bin_prefix + "gcc" - env["CXX"] = mingw_bin_prefix + "g++" - if try_cmd("as --version", env["mingw_prefix"], env["arch"]): - env["AS"] = mingw_bin_prefix + "as" - ar = "ar" if os.name == "nt" else "gcc-ar" - if try_cmd(f"{ar} --version", env["mingw_prefix"], env["arch"]): - env["AR"] = mingw_bin_prefix + ar - if try_cmd("gcc-ranlib --version", env["mingw_prefix"], env["arch"]): - env["RANLIB"] = mingw_bin_prefix + "gcc-ranlib" + env["CC"] = get_detected(env, "gcc") + env["CXX"] = get_detected(env, "g++") + env["AR"] = get_detected(env, "gcc-ar" if os.name != "nt" else "ar") + env["RANLIB"] = get_detected(env, "gcc-ranlib") + + env["RC"] = get_detected(env, "windres") + ARCH_TARGETS = { + "x86_32": "pe-i386", + "x86_64": "pe-x86-64", + "arm32": "armv7-w64-mingw32", + "arm64": "aarch64-w64-mingw32", + } + env.AppendUnique(RCFLAGS=f"--target={ARCH_TARGETS[env['arch']]}") + + env["AS"] = get_detected(env, "as") + env["OBJCOPY"] = get_detected(env, "objcopy") + env["STRIP"] = get_detected(env, "strip") ## LTO @@ -924,9 +899,6 @@ def configure_mingw(env: "SConsEnvironment"): env.Append(CPPDEFINES=["MINGW_ENABLED", ("MINGW_HAS_SECURE_API", 1)]) - # resrc - env.Append(BUILDERS={"RES": env.Builder(action=build_res_file, suffix=".o", src_suffix=".rc")}) - def configure(env: "SConsEnvironment"): # Validate arch. diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index a06395ae3a..a6eab1bd29 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -5438,7 +5438,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() && ke.altgr) { + if (k->get_unicode() && ke.altgr && windows[ke.window_id].ime_active) { k->set_alt_pressed(false); k->set_ctrl_pressed(false); } @@ -5514,7 +5514,7 @@ void DisplayServerWindows::_process_key_events() { } k->set_unicode(fix_unicode(unicode)); } - if (k->get_unicode() && ke.altgr) { + if (k->get_unicode() && ke.altgr && windows[ke.window_id].ime_active) { k->set_alt_pressed(false); k->set_ctrl_pressed(false); } diff --git a/platform/windows/godot.natvis b/platform/windows/godot.natvis index 14536fa130..fc34ad3cb3 100644 --- a/platform/windows/godot.natvis +++ b/platform/windows/godot.natvis @@ -1,5 +1,15 @@ <?xml version="1.0" encoding="utf-8"?> <AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> + <Type Name="Ref<*>"> + <SmartPointer Usage="Minimal">reference</SmartPointer> + <DisplayString Condition="!reference">[empty]</DisplayString> + <DisplayString Condition="!!reference">{*reference}</DisplayString> + <Expand> + <Item Condition="!!reference" Name="[ptr]">reference</Item> + <Item Condition="!!reference" Name="[refcount]">reference->refcount.count.value</Item> + </Expand> + </Type> + <Type Name="Vector<*>"> <Expand> <Item Name="[size]">_cowdata._ptr ? (((const unsigned long long *)(_cowdata._ptr))[-1]) : 0</Item> @@ -91,6 +101,16 @@ <StringView Condition="_data && !_data->cname">_data->name,s32b</StringView> </Type> + <Type Name="HashSet<*,*,*>"> + <Expand> + <Item Name="[size]">num_elements</Item> + <ArrayItems> + <Size>num_elements</Size> + <ValuePointer>($T1 *) keys._cowdata._ptr</ValuePointer> + </ArrayItems> + </Expand> + </Type> + <Type Name="HashMapElement<*,*>"> <DisplayString>{{Key = {($T1 *) &data.key} Value = {($T2 *) &data.value}}}</DisplayString> <Expand> diff --git a/platform/windows/platform_windows_builders.py b/platform/windows/platform_windows_builders.py index 3fd9e1a581..2020e68748 100644 --- a/platform/windows/platform_windows_builders.py +++ b/platform/windows/platform_windows_builders.py @@ -2,23 +2,11 @@ import os -from detect import get_mingw_bin_prefix, try_cmd - def make_debug_mingw(target, source, env): dst = str(target[0]) # Force separate debug symbols if executable size is larger than 1.9 GB. if env["separate_debug_symbols"] or os.stat(dst).st_size >= 2040109465: - mingw_bin_prefix = get_mingw_bin_prefix(env["mingw_prefix"], env["arch"]) - if try_cmd("objcopy --version", env["mingw_prefix"], env["arch"]): - os.system(mingw_bin_prefix + "objcopy --only-keep-debug {0} {0}.debugsymbols".format(dst)) - else: - os.system("objcopy --only-keep-debug {0} {0}.debugsymbols".format(dst)) - if try_cmd("strip --version", env["mingw_prefix"], env["arch"]): - os.system(mingw_bin_prefix + "strip --strip-debug --strip-unneeded {0}".format(dst)) - else: - os.system("strip --strip-debug --strip-unneeded {0}".format(dst)) - if try_cmd("objcopy --version", env["mingw_prefix"], env["arch"]): - os.system(mingw_bin_prefix + "objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(dst)) - else: - os.system("objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(dst)) + os.system("{0} --only-keep-debug {1} {1}.debugsymbols".format(env["OBJCOPY"], dst)) + os.system("{0} --strip-debug --strip-unneeded {1}".format(env["STRIP"], dst)) + os.system("{0} --add-gnu-debuglink={1}.debugsymbols {1}".format(env["OBJCOPY"], dst)) diff --git a/scene/debugger/scene_debugger.cpp b/scene/debugger/scene_debugger.cpp index b87285ed74..1c05271daa 100644 --- a/scene/debugger/scene_debugger.cpp +++ b/scene/debugger/scene_debugger.cpp @@ -147,7 +147,6 @@ Error SceneDebugger::parse_message(void *p_user, const String &p_msg, const Arra ERR_FAIL_COND_V(p_args.is_empty(), ERR_INVALID_DATA); Transform2D transform = p_args[0]; scene_tree->get_root()->set_canvas_transform_override(transform); - runtime_node_select->_queue_selection_update(); #ifndef _3D_DISABLED @@ -164,16 +163,19 @@ Error SceneDebugger::parse_message(void *p_user, const String &p_msg, const Arra scene_tree->get_root()->set_camera_3d_override_orthogonal(size_or_fov, depth_near, depth_far); } scene_tree->get_root()->set_camera_3d_override_transform(transform); - runtime_node_select->_queue_selection_update(); #endif // _3D_DISABLED } else if (p_msg == "set_object_property") { ERR_FAIL_COND_V(p_args.size() < 3, ERR_INVALID_DATA); _set_object_property(p_args[0], p_args[1], p_args[2]); - runtime_node_select->_queue_selection_update(); + } else if (p_msg == "reload_cached_files") { + ERR_FAIL_COND_V(p_args.is_empty(), ERR_INVALID_DATA); + PackedStringArray files = p_args[0]; + reload_cached_files(files); + } else if (p_msg.begins_with("live_")) { /// Live Edit if (p_msg == "live_set_root") { ERR_FAIL_COND_V(p_args.size() < 2, ERR_INVALID_DATA); @@ -413,6 +415,15 @@ void SceneDebugger::remove_from_cache(const String &p_filename, Node *p_node) { } } +void SceneDebugger::reload_cached_files(const PackedStringArray &p_files) { + for (const String &file : p_files) { + Ref<Resource> res = ResourceCache::get_ref(file); + if (res.is_valid()) { + res->reload_from_file(); + } + } +} + /// SceneDebuggerObject SceneDebuggerObject::SceneDebuggerObject(ObjectID p_id) { id = ObjectID(); diff --git a/scene/debugger/scene_debugger.h b/scene/debugger/scene_debugger.h index f9dd6161aa..9e9f61aac5 100644 --- a/scene/debugger/scene_debugger.h +++ b/scene/debugger/scene_debugger.h @@ -67,6 +67,7 @@ public: static Error parse_message(void *p_user, const String &p_msg, const Array &p_args, bool &r_captured); static void add_to_cache(const String &p_filename, Node *p_node); static void remove_from_cache(const String &p_filename, Node *p_node); + static void reload_cached_files(const PackedStringArray &p_files); #endif }; diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 18864b1289..9eda1a256f 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -1586,6 +1586,7 @@ FileDialog::FileDialog() { vbox->add_child(hbc); tree = memnew(Tree); + tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); tree->set_hide_root(true); vbox->add_margin_child(ETR("Directories & Files:"), tree, true); diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index cb495f9d47..b1c47d858d 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -317,7 +317,7 @@ bool GraphEdit::is_node_connected(const StringName &p_from, int p_from_port, con void GraphEdit::disconnect_node(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port) { ERR_FAIL_NULL_MSG(connections_layer, "connections_layer is missing."); - for (const List<Ref<Connection>>::Element *E = connections.front(); E; E = E->next()) { + for (List<Ref<Connection>>::Element *E = connections.front(); E; E = E->next()) { if (E->get()->from_node == p_from && E->get()->from_port == p_from_port && E->get()->to_node == p_to && E->get()->to_port == p_to_port) { connection_map[p_from].erase(E->get()); connection_map[p_to].erase(E->get()); diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 9967805134..3f979f7c20 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -128,6 +128,7 @@ bool LineEdit::has_ime_text() const { void LineEdit::cancel_ime() { if (!has_ime_text()) { + _close_ime_window(); return; } ime_text = String(); @@ -140,6 +141,7 @@ void LineEdit::cancel_ime() { void LineEdit::apply_ime() { if (!has_ime_text()) { + _close_ime_window(); return; } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 7a2570f400..b1918ff23f 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -3169,6 +3169,7 @@ bool TextEdit::has_ime_text() const { void TextEdit::cancel_ime() { if (!has_ime_text()) { + _close_ime_window(); return; } ime_text = String(); @@ -3181,6 +3182,7 @@ void TextEdit::cancel_ime() { void TextEdit::apply_ime() { if (!has_ime_text()) { + _close_ime_window(); return; } diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 566bdcb915..f6e05f5796 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -5329,14 +5329,16 @@ void Tree::scroll_to_item(TreeItem *p_item, bool p_center_on_item) { int y_offset = get_item_offset(p_item); if (y_offset != -1) { - const int tbh = _get_title_button_height(); - y_offset -= tbh; + const int title_button_height = _get_title_button_height(); + y_offset -= title_button_height; const int cell_h = compute_item_height(p_item) + theme_cache.v_separation; - int screen_h = area_size.height - tbh; + int screen_h = area_size.height - title_button_height; if (p_center_on_item) { - v_scroll->set_value(y_offset - (screen_h - cell_h) / 2.0f); + // This makes sure that centering the offset doesn't overflow. + const double v_scroll_value = y_offset - MAX((screen_h - cell_h) / 2.0, 0.0); + v_scroll->set_value(v_scroll_value); } else { if (cell_h > screen_h) { // Screen size is too small, maybe it was not resized yet. v_scroll->set_value(y_offset); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 6b1ce2b4ca..315ccaeb8c 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -512,6 +512,9 @@ void register_scene_types() { GDREGISTER_CLASS(AnimationNodeStateMachine); GDREGISTER_CLASS(AnimationNodeStateMachinePlayback); + GDREGISTER_INTERNAL_CLASS(AnimationNodeStartState); + GDREGISTER_INTERNAL_CLASS(AnimationNodeEndState); + GDREGISTER_CLASS(AnimationNodeSync); GDREGISTER_CLASS(AnimationNodeStateMachineTransition); GDREGISTER_CLASS(AnimationNodeOutput); diff --git a/scene/resources/2d/tile_set.cpp b/scene/resources/2d/tile_set.cpp index 82497e9a13..54a18cf67e 100644 --- a/scene/resources/2d/tile_set.cpp +++ b/scene/resources/2d/tile_set.cpp @@ -4931,10 +4931,13 @@ void TileSetAtlasSource::_get_property_list(List<PropertyInfo> *p_list) const { } for (const KeyValue<int, TileData *> &E_alternative : E_tile.value.alternatives) { + const String formatted_key = itos(E_alternative.key); + // Add a dummy property to show the alternative exists. - tile_property_list.push_back(PropertyInfo(Variant::INT, vformat("%d", E_alternative.key), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR)); + tile_property_list.push_back(PropertyInfo(Variant::INT, formatted_key, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR)); // Get the alternative tile's properties and append them to the list of properties. + const String alternative_property_info_prefix = formatted_key + '/'; List<PropertyInfo> alternative_property_list; E_alternative.value->get_property_list(&alternative_property_list); for (PropertyInfo &alternative_property_info : alternative_property_list) { @@ -4943,14 +4946,15 @@ void TileSetAtlasSource::_get_property_list(List<PropertyInfo> *p_list) const { if (default_value.get_type() != Variant::NIL && bool(Variant::evaluate(Variant::OP_EQUAL, value, default_value))) { alternative_property_info.usage ^= PROPERTY_USAGE_STORAGE; } - alternative_property_info.name = vformat("%s/%s", vformat("%d", E_alternative.key), alternative_property_info.name); + alternative_property_info.name = alternative_property_info_prefix + alternative_property_info.name; tile_property_list.push_back(alternative_property_info); } } // Add all alternative. + const String property_info_prefix = vformat("%d:%d/", E_tile.key.x, E_tile.key.y); for (PropertyInfo &tile_property_info : tile_property_list) { - tile_property_info.name = vformat("%s/%s", vformat("%d:%d", E_tile.key.x, E_tile.key.y), tile_property_info.name); + tile_property_info.name = property_info_prefix + tile_property_info.name; p_list->push_back(tile_property_info); } } diff --git a/scene/resources/audio_stream_wav.cpp b/scene/resources/audio_stream_wav.cpp index f9787dde2e..539001bf25 100644 --- a/scene/resources/audio_stream_wav.cpp +++ b/scene/resources/audio_stream_wav.cpp @@ -624,7 +624,7 @@ Error AudioStreamWAV::save_to_wav(const String &p_path) { } String file_path = p_path; - if (!(file_path.substr(file_path.length() - 4, 4) == ".wav")) { + if (file_path.substr(file_path.length() - 4, 4).to_lower() != ".wav") { file_path += ".wav"; } diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index d6fe4385c4..bb3aad0f28 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -786,7 +786,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has Dictionary missing_resource_properties = p_node->get_meta(META_MISSING_RESOURCES, Dictionary()); for (const PropertyInfo &E : plist) { - if (!(E.usage & PROPERTY_USAGE_STORAGE)) { + if (!(E.usage & PROPERTY_USAGE_STORAGE) && !missing_resource_properties.has(E.name)) { continue; } diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 4a318a10f0..535903a1b6 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -600,7 +600,7 @@ Error ResourceLoaderText::load() { if (do_assign) { bool set_valid = true; - if (value.get_type() == Variant::OBJECT && missing_resource != nullptr) { + if (value.get_type() == Variant::OBJECT && missing_resource == nullptr && ResourceLoader::is_creating_missing_resources_if_class_unavailable_enabled()) { // If the property being set is a missing resource (and the parent is not), // then setting it will most likely not work. // Instead, save it as metadata. @@ -723,24 +723,25 @@ Error ResourceLoaderText::load() { if (error) { if (error != ERR_FILE_EOF) { _printerr(); - } else { - error = OK; - if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) { - if (!ResourceCache::has(res_path)) { - resource->set_path(res_path); - } - resource->set_as_translation_remapped(translation_remapped); - } else { - resource->set_path_cache(res_path); + return error; + } + // EOF, Done parsing. + error = OK; + if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) { + if (!ResourceCache::has(res_path)) { + resource->set_path(res_path); } + resource->set_as_translation_remapped(translation_remapped); + } else { + resource->set_path_cache(res_path); } - return error; + break; } if (!assign.is_empty()) { bool set_valid = true; - if (value.get_type() == Variant::OBJECT && missing_resource != nullptr) { + if (value.get_type() == Variant::OBJECT && missing_resource == nullptr && ResourceLoader::is_creating_missing_resources_if_class_unavailable_enabled()) { // If the property being set is a missing resource (and the parent is not), // then setting it will most likely not work. // Instead, save it as metadata. @@ -1900,7 +1901,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso #endif } - Dictionary missing_resource_properties = p_resource->get_meta(META_MISSING_RESOURCES, Dictionary()); + Dictionary missing_resource_properties = res->get_meta(META_MISSING_RESOURCES, Dictionary()); List<PropertyInfo> property_list; res->get_property_list(&property_list); @@ -1912,7 +1913,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso continue; } - if (PE->get().usage & PROPERTY_USAGE_STORAGE) { + if (PE->get().usage & PROPERTY_USAGE_STORAGE || missing_resource_properties.has(PE->get().name)) { String name = PE->get().name; Variant value; if (PE->get().usage & PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT) { diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index f1bc83eb42..847867fa4d 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -1368,7 +1368,7 @@ void VisualShader::disconnect_nodes(Type p_type, int p_from_node, int p_from_por ERR_FAIL_INDEX(p_type, TYPE_MAX); Graph *g = &graph[p_type]; - for (const List<Connection>::Element *E = g->connections.front(); E; E = E->next()) { + for (List<Connection>::Element *E = g->connections.front(); E; E = E->next()) { if (E->get().from_node == p_from_node && E->get().from_port == p_from_port && E->get().to_node == p_to_node && E->get().to_port == p_to_port) { g->connections.erase(E); g->nodes[p_from_node].next_connected_nodes.erase(p_to_node); diff --git a/scu_builders.py b/scu_builders.py index 6bf87b9163..e0bfffc320 100644 --- a/scu_builders.py +++ b/scu_builders.py @@ -259,10 +259,6 @@ def process_folder(folders, sought_exceptions=[], includes_per_scu=0, extension= def generate_scu_files(max_includes_per_scu): - print("=============================") - print("Single Compilation Unit Build") - print("=============================") - global _max_includes_per_scu _max_includes_per_scu = max_includes_per_scu diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index c4a732fef1..0dcdb90948 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -993,36 +993,43 @@ void RendererCanvasRenderRD::light_update_shadow(RID p_rid, int p_shadow_index, Vector<Color> cc; cc.push_back(Color(p_far, p_far, p_far, 1.0)); - for (int i = 0; i < 4; i++) { - //make sure it remains orthogonal, makes easy to read angle later + Projection projection; + { + real_t fov = 90; + real_t nearp = p_near; + real_t farp = p_far; + real_t aspect = 1.0; - //light.basis.scale(Vector3(to_light.elements[0].length(),to_light.elements[1].length(),1)); + real_t ymax = nearp * Math::tan(Math::deg_to_rad(fov * 0.5)); + real_t ymin = -ymax; + real_t xmin = ymin * aspect; + real_t xmax = ymax * aspect; - Rect2i rect((state.shadow_texture_size / 4) * i, p_shadow_index * 2, (state.shadow_texture_size / 4), 2); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(state.shadow_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc, 1.0, 0, rect); + projection.set_frustum(xmin, xmax, ymin, ymax, nearp, farp); + } - Projection projection; - { - real_t fov = 90; - real_t nearp = p_near; - real_t farp = p_far; - real_t aspect = 1.0; + // Precomputed: + // Vector3 cam_target = Basis::from_euler(Vector3(0, 0, Math_TAU * ((i + 3) / 4.0))).xform(Vector3(0, 1, 0)); + // projection = projection * Projection(Transform3D().looking_at(cam_targets[i], Vector3(0, 0, -1)).affine_inverse()); + const Projection projections[4] = { + projection * Projection(Vector4(0, 0, -1, 0), Vector4(1, 0, 0, 0), Vector4(0, -1, 0, 0), Vector4(0, 0, 0, 1)), - real_t ymax = nearp * Math::tan(Math::deg_to_rad(fov * 0.5)); - real_t ymin = -ymax; - real_t xmin = ymin * aspect; - real_t xmax = ymax * aspect; + projection * Projection(Vector4(-1, 0, 0, 0), Vector4(0, 0, -1, 0), Vector4(0, -1, 0, 0), Vector4(0, 0, 0, 1)), - projection.set_frustum(xmin, xmax, ymin, ymax, nearp, farp); - } + projection * Projection(Vector4(0, 0, 1, 0), Vector4(-1, 0, 0, 0), Vector4(0, -1, 0, 0), Vector4(0, 0, 0, 1)), + + projection * Projection(Vector4(1, 0, 0, 0), Vector4(0, 0, 1, 0), Vector4(0, -1, 0, 0), Vector4(0, 0, 0, 1)) + + }; - Vector3 cam_target = Basis::from_euler(Vector3(0, 0, Math_TAU * ((i + 3) / 4.0))).xform(Vector3(0, 1, 0)); - projection = projection * Projection(Transform3D().looking_at(cam_target, Vector3(0, 0, -1)).affine_inverse()); + for (int i = 0; i < 4; i++) { + Rect2i rect((state.shadow_texture_size / 4) * i, p_shadow_index * 2, (state.shadow_texture_size / 4), 2); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(state.shadow_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc, 1.0, 0, rect); ShadowRenderPushConstant push_constant; for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { - push_constant.projection[y * 4 + x] = projection.columns[y][x]; + push_constant.projection[y * 4 + x] = projections[i].columns[y][x]; } } static const Vector2 directions[4] = { Vector2(1, 0), Vector2(0, 1), Vector2(-1, 0), Vector2(0, -1) }; |