diff options
55 files changed, 298 insertions, 176 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/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/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/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..8287671578 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"> @@ -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 4d8ea28bc6..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. @@ -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/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/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/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/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/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/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/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/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/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/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/tree.cpp b/scene/gui/tree.cpp index aab6f672f0..cfd93a5317 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -5362,14 +5362,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/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/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) }; |