diff options
234 files changed, 2082 insertions, 1282 deletions
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index 7aaa9a46b7..d0de39a79d 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -1200,6 +1200,7 @@ ProjectSettings::ProjectSettings() { // Initialization of engine variables should be done in the setup() method, // so that the values can be overridden from project.godot or project.binary. + CRASH_COND_MSG(singleton != nullptr, "Instantiating a new ProjectSettings singleton is not supported."); singleton = this; GLOBAL_DEF_BASIC("application/config/name", ""); diff --git a/core/io/resource.cpp b/core/io/resource.cpp index ab30fb1ca3..be75ad7e25 100644 --- a/core/io/resource.cpp +++ b/core/io/resource.cpp @@ -436,7 +436,7 @@ void Resource::_bind_methods() { ADD_GROUP("Resource", "resource_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "resource_local_to_scene"), "set_local_to_scene", "is_local_to_scene"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "resource_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_path", "get_path"); - ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "resource_name"), "set_name", "get_name"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "resource_name"), "set_name", "get_name"); MethodInfo get_rid_bind("_get_rid"); get_rid_bind.return_val.type = Variant::RID; diff --git a/core/object/worker_thread_pool.cpp b/core/object/worker_thread_pool.cpp index 9b3dc6833e..0218a4c8f6 100644 --- a/core/object/worker_thread_pool.cpp +++ b/core/object/worker_thread_pool.cpp @@ -402,7 +402,9 @@ void WorkerThreadPool::wait_for_group_task_completion(GroupID p_group) { } } - groups.erase(p_group); // Threads do not access this, so safe to erase here. + task_mutex.lock(); // This mutex is needed when Physics 2D and/or 3D is selected to run on a separate thread. + groups.erase(p_group); + task_mutex.unlock(); } void WorkerThreadPool::init(int p_thread_count, bool p_use_native_threads_low_priority, float p_low_priority_task_ratio) { diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp index d2e4d752a4..17d41ca95e 100644 --- a/core/variant/variant_parser.cpp +++ b/core/variant/variant_parser.cpp @@ -1283,7 +1283,7 @@ Error VariantParser::_parse_dictionary(Dictionary &object, Stream *p_stream, int Variant v; err = parse_value(token, v, p_stream, line, r_err_str, p_res_parser); - if (err) { + if (err && err != ERR_FILE_MISSING_DEPENDENCIES) { return err; } object[key] = v; diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml index af8d9c416f..80e0c81509 100644 --- a/doc/classes/Animation.xml +++ b/doc/classes/Animation.xml @@ -251,15 +251,6 @@ Returns the amount of tracks in the animation. </description> </method> - <method name="method_track_get_key_indices" qualifiers="const"> - <return type="PackedInt32Array" /> - <param index="0" name="track_idx" type="int" /> - <param index="1" name="time_sec" type="float" /> - <param index="2" name="delta" type="float" /> - <description> - Returns all the key indices of a method track, given a position and delta time. - </description> - </method> <method name="method_track_get_name" qualifiers="const"> <return type="StringName" /> <param index="0" name="track_idx" type="int" /> @@ -523,15 +514,6 @@ Swaps the track [param track_idx]'s index position with the track [param with_idx]. </description> </method> - <method name="value_track_get_key_indices" qualifiers="const"> - <return type="PackedInt32Array" /> - <param index="0" name="track_idx" type="int" /> - <param index="1" name="time_sec" type="float" /> - <param index="2" name="delta" type="float" /> - <description> - Returns all the key indices of a value track, given a position and delta time. - </description> - </method> <method name="value_track_get_update_mode" qualifiers="const"> <return type="int" enum="Animation.UpdateMode" /> <param index="0" name="track_idx" type="int" /> diff --git a/doc/classes/AnimationNode.xml b/doc/classes/AnimationNode.xml index b856b5f208..915fbf53cd 100644 --- a/doc/classes/AnimationNode.xml +++ b/doc/classes/AnimationNode.xml @@ -53,7 +53,7 @@ <return type="float" /> <param index="0" name="time" type="float" /> <param index="1" name="seek" type="bool" /> - <param index="2" name="seek_root" type="bool" /> + <param index="2" name="is_external_seeking" type="bool" /> <description> When inheriting from [AnimationRootNode], implement this virtual method to run some code when this node is processed. The [param time] parameter is a relative delta, unless [param seek] is [code]true[/code], in which case it is absolute. Here, call the [method blend_input], [method blend_node] or [method blend_animation] functions. You can also use [method get_parameter] and [method set_parameter] to modify local memory. @@ -73,7 +73,7 @@ <param index="1" name="time" type="float" /> <param index="2" name="delta" type="float" /> <param index="3" name="seeked" type="bool" /> - <param index="4" name="seek_root" type="bool" /> + <param index="4" name="is_external_seeking" type="bool" /> <param index="5" name="blend" type="float" /> <param index="6" name="pingponged" type="int" default="0" /> <description> @@ -85,7 +85,7 @@ <param index="0" name="input_index" type="int" /> <param index="1" name="time" type="float" /> <param index="2" name="seek" type="bool" /> - <param index="3" name="seek_root" type="bool" /> + <param index="3" name="is_external_seeking" type="bool" /> <param index="4" name="blend" type="float" /> <param index="5" name="filter" type="int" enum="AnimationNode.FilterAction" default="0" /> <param index="6" name="sync" type="bool" default="true" /> @@ -99,7 +99,7 @@ <param index="1" name="node" type="AnimationNode" /> <param index="2" name="time" type="float" /> <param index="3" name="seek" type="bool" /> - <param index="4" name="seek_root" type="bool" /> + <param index="4" name="is_external_seeking" type="bool" /> <param index="5" name="blend" type="float" /> <param index="6" name="filter" type="int" enum="AnimationNode.FilterAction" default="0" /> <param index="7" name="sync" type="bool" default="true" /> diff --git a/doc/classes/AnimationTree.xml b/doc/classes/AnimationTree.xml index 27797b00b5..21f4b37741 100644 --- a/doc/classes/AnimationTree.xml +++ b/doc/classes/AnimationTree.xml @@ -19,10 +19,66 @@ Manually advance the animations by the specified time (in seconds). </description> </method> - <method name="get_root_motion_transform" qualifiers="const"> - <return type="Transform3D" /> + <method name="get_root_motion_position" qualifiers="const"> + <return type="Vector3" /> <description> - Retrieve the motion of the [member root_motion_track] as a [Transform3D] that can be used elsewhere. If [member root_motion_track] is not a path to a track of type [constant Animation.TYPE_POSITION_3D], [constant Animation.TYPE_SCALE_3D] or [constant Animation.TYPE_ROTATION_3D], returns an identity transformation. See also [member root_motion_track] and [RootMotionView]. + Retrieve the motion of position with the [member root_motion_track] as a [Vector3] that can be used elsewhere. + If [member root_motion_track] is not a path to a track of type [constant Animation.TYPE_POSITION_3D], returns [code]Vector3(0, 0, 0)[/code]. + See also [member root_motion_track] and [RootMotionView]. + The most basic example is applying position to [CharacterBody3D]: + [codeblocks] + [gdscript] + var current_rotation: Quaternion + + func _process(delta): + if Input.is_action_just_pressed("animate"): + current_rotation = get_quaternion() + state_machine.travel("Animate") + var velocity: Vector3 = current_rotation * animation_tree.get_root_motion_position() / delta + set_velocity(velocity) + move_and_slide() + [/gdscript] + [/codeblocks] + </description> + </method> + <method name="get_root_motion_rotation" qualifiers="const"> + <return type="Quaternion" /> + <description> + Retrieve the motion of rotation with the [member root_motion_track] as a [Quaternion] that can be used elsewhere. + If [member root_motion_track] is not a path to a track of type [constant Animation.TYPE_ROTATION_3D], returns [code]Quaternion(0, 0, 0, 1)[/code]. + See also [member root_motion_track] and [RootMotionView]. + The most basic example is applying rotation to [CharacterBody3D]: + [codeblocks] + [gdscript] + func _process(delta): + if Input.is_action_just_pressed("animate"): + state_machine.travel("Animate") + set_quaternion(get_quaternion() * animation_tree.get_root_motion_rotation()) + [/gdscript] + [/codeblocks] + </description> + </method> + <method name="get_root_motion_scale" qualifiers="const"> + <return type="Vector3" /> + <description> + Retrieve the motion of scale with the [member root_motion_track] as a [Vector3] that can be used elsewhere. + If [member root_motion_track] is not a path to a track of type [constant Animation.TYPE_SCALE_3D], returns [code]Vector3(0, 0, 0)[/code]. + See also [member root_motion_track] and [RootMotionView]. + The most basic example is applying scale to [CharacterBody3D]: + [codeblocks] + [gdscript] + var current_scale: Vector3 = Vector3(1, 1, 1) + var scale_accum: Vector3 = Vector3(1, 1, 1) + + func _process(delta): + if Input.is_action_just_pressed("animate"): + current_scale = get_scale() + scale_accum = Vector3(1, 1, 1) + state_machine.travel("Animate") + scale_accum += animation_tree.get_root_motion_scale() + set_scale(current_scale * scale_accum) + [/gdscript] + [/codeblocks] </description> </method> <method name="rename_parameter"> @@ -48,7 +104,7 @@ </member> <member name="root_motion_track" type="NodePath" setter="set_root_motion_track" getter="get_root_motion_track" default="NodePath("")"> The path to the Animation track used for root motion. Paths must be valid scene-tree paths to a node, and must be specified starting from the parent node of the node that will reproduce the animation. To specify a track that controls properties or bones, append its name after the path, separated by [code]":"[/code]. For example, [code]"character/skeleton:ankle"[/code] or [code]"character/mesh:transform/local"[/code]. - If the track has type [constant Animation.TYPE_POSITION_3D], [constant Animation.TYPE_ROTATION_3D] or [constant Animation.TYPE_SCALE_3D] the transformation will be cancelled visually, and the animation will appear to stay in place. See also [method get_root_motion_transform] and [RootMotionView]. + If the track has type [constant Animation.TYPE_POSITION_3D], [constant Animation.TYPE_ROTATION_3D] or [constant Animation.TYPE_SCALE_3D] the transformation will be cancelled visually, and the animation will appear to stay in place. See also [method get_root_motion_position], [method get_root_motion_rotation], [method get_root_motion_scale] and [RootMotionView]. </member> <member name="tree_root" type="AnimationNode" setter="set_tree_root" getter="get_tree_root"> The root animation node of this [AnimationTree]. See [AnimationNode]. diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml index 50bbbc71a0..499d53e63c 100644 --- a/doc/classes/CanvasItem.xml +++ b/doc/classes/CanvasItem.xml @@ -510,7 +510,7 @@ <method name="move_to_front"> <return type="void" /> <description> - Moves this node to display on top of its siblings. This has more use in [Control], as [Node2D] can be ordered with [member Node2D.z_index]. + Moves this node to display on top of its siblings. Internally, the node is moved to the bottom of parent's children list. The method has no effect on nodes without a parent. </description> </method> @@ -587,6 +587,17 @@ If [code]true[/code], this [CanvasItem] is drawn. The node is only visible if all of its antecedents are visible as well (in other words, [method is_visible_in_tree] must return [code]true[/code]). [b]Note:[/b] For controls that inherit [Popup], the correct way to make them visible is to call one of the multiple [code]popup*()[/code] functions instead. </member> + <member name="y_sort_enabled" type="bool" setter="set_y_sort_enabled" getter="is_y_sort_enabled" default="false"> + If [code]true[/code], child nodes with the lowest Y position are drawn before those with a higher Y position. If [code]false[/code], Y-sorting is disabled. Y-sorting only affects children that inherit from [CanvasItem]. + You can nest nodes with Y-sorting. Child Y-sorted nodes are sorted in the same space as the parent Y-sort. This feature allows you to organize a scene better or divide it into multiple ones without changing your scene tree. + </member> + <member name="z_as_relative" type="bool" setter="set_z_as_relative" getter="is_z_relative" default="true"> + If [code]true[/code], the node's Z index is relative to its parent's Z index. If this node's Z index is 2 and its parent's effective Z index is 3, then this node's effective Z index will be 2 + 3 = 5. + </member> + <member name="z_index" type="int" setter="set_z_index" getter="get_z_index" default="0"> + Z index. Controls the order in which the nodes render. A node with a higher Z index will display in front of others. Must be between [constant RenderingServer.CANVAS_ITEM_Z_MIN] and [constant RenderingServer.CANVAS_ITEM_Z_MAX] (inclusive). + [b]Note:[/b] Changing the Z index of a [Control] only affects the drawing order, not the order in which input events are handled. This can be useful to implement certain UI animations, e.g. a menu where hovered items are scaled and should overlap others. + </member> </members> <signals> <signal name="draw"> diff --git a/doc/classes/DirectionalLight2D.xml b/doc/classes/DirectionalLight2D.xml index 7a54980c19..f825a9e082 100644 --- a/doc/classes/DirectionalLight2D.xml +++ b/doc/classes/DirectionalLight2D.xml @@ -1,19 +1,20 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="DirectionalLight2D" inherits="Light2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> - Directional light from a distance. + Directional 2D light from a distance. </brief_description> <description> A directional light is a type of [Light2D] node that models an infinite number of parallel rays covering the entire scene. It is used for lights with strong intensity that are located far away from the scene (for example: to model sunlight or moonlight). </description> <tutorials> + <link title="2D lights and shadows">$DOCS_URL/tutorials/2d/2d_lights_and_shadows.html</link> </tutorials> <members> <member name="height" type="float" setter="set_height" getter="get_height" default="0.0"> The height of the light. Used with 2D normal mapping. Ranges from 0 (parallel to the plane) to 1 (perpendicular to the plane). </member> <member name="max_distance" type="float" setter="set_max_distance" getter="get_max_distance" default="10000.0"> - Maximum distance this light covers. Increasing this value will make directional shadows visible from further away, at the cost of lower overall shadow detail and performance (due to more objects being included in shadow rendering). + The maximum distance from the camera center objects can be before their shadows are culled (in pixels). Decreasing this value can prevent objects located outside the camera from casting shadows (while also improving performance). [member Camera2D.zoom] is not taken into account by [member max_distance], which means that at higher zoom values, shadows will appear to fade out sooner when zooming onto a given point. </member> </members> </class> diff --git a/doc/classes/EditorSceneFormatImporter.xml b/doc/classes/EditorSceneFormatImporter.xml index 6de9c2c5dc..db93cab14c 100644 --- a/doc/classes/EditorSceneFormatImporter.xml +++ b/doc/classes/EditorSceneFormatImporter.xml @@ -39,7 +39,6 @@ <param index="0" name="path" type="String" /> <param index="1" name="flags" type="int" /> <param index="2" name="options" type="Dictionary" /> - <param index="3" name="bake_fps" type="int" /> <description> </description> </method> diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index 07457387a0..865faa13ae 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -592,6 +592,9 @@ <member name="interface/theme/custom_theme" type="String" setter="" getter=""> The custom theme resource to use for the editor. Must be a Godot theme resource in [code].tres[/code] or [code].res[/code] format. </member> + <member name="interface/theme/draw_extra_borders" type="bool" setter="" getter=""> + If [code]true[/code], draws additional borders around interactive UI elements in the editor. This is automatically enabled when using the [b]Black (OLED)[/b] theme preset, as this theme preset uses a fully black background. + </member> <member name="interface/theme/icon_and_font_color" type="int" setter="" getter=""> The icon and font color scheme to use in the editor. - [b]Auto[/b] determines the color scheme to use automatically based on [member interface/theme/base_color]. diff --git a/doc/classes/Light2D.xml b/doc/classes/Light2D.xml index 00815758a1..062d532464 100644 --- a/doc/classes/Light2D.xml +++ b/doc/classes/Light2D.xml @@ -4,8 +4,7 @@ Casts light in a 2D environment. </brief_description> <description> - Casts light in a 2D environment. Light is defined by a (usually grayscale) texture, a color, an energy value, a mode (see constants), and various other parameters (range and shadows-related). - [b]Note:[/b] Light2D can also be used as a mask. + Casts light in a 2D environment. A light is defined as a color, an energy value, a mode (see constants), and various other parameters (range and shadows-related). </description> <tutorials> <link title="2D lights and shadows">$DOCS_URL/tutorials/2d/2d_lights_and_shadows.html</link> @@ -14,12 +13,14 @@ <method name="get_height" qualifiers="const"> <return type="float" /> <description> + Returns the light's height, which is used in 2D normal mapping. See [member PointLight2D.height] and [member DirectionalLight2D.height]. </description> </method> <method name="set_height"> <return type="void" /> <param index="0" name="height" type="float" /> <description> + Sets the light's height, which is used in 2D normal mapping. See [member PointLight2D.height] and [member DirectionalLight2D.height]. </description> </method> </methods> @@ -64,7 +65,7 @@ Shadow filter type. See [enum ShadowFilter] for possible values. </member> <member name="shadow_filter_smooth" type="float" setter="set_shadow_smooth" getter="get_shadow_smooth" default="0.0"> - Smoothing value for shadows. + Smoothing value for shadows. Higher values will result in softer shadows, at the cost of visible streaks that can appear in shadow rendering. [member shadow_filter_smooth] only has an effect if [member shadow_filter] is [constant SHADOW_FILTER_PCF5] or [constant SHADOW_FILTER_PCF13]. </member> <member name="shadow_item_cull_mask" type="int" setter="set_item_shadow_cull_mask" getter="get_item_shadow_cull_mask" default="1"> The shadow mask. Used with [LightOccluder2D] to cast shadows. Only occluders with a matching light mask will cast shadows. @@ -72,13 +73,13 @@ </members> <constants> <constant name="SHADOW_FILTER_NONE" value="0" enum="ShadowFilter"> - No filter applies to the shadow map. See [member shadow_filter]. + No filter applies to the shadow map. This provides hard shadow edges and is the fastest to render. See [member shadow_filter]. </constant> <constant name="SHADOW_FILTER_PCF5" value="1" enum="ShadowFilter"> - Percentage closer filtering (5 samples) applies to the shadow map. See [member shadow_filter]. + Percentage closer filtering (5 samples) applies to the shadow map. This is slower compared to hard shadow rendering. See [member shadow_filter]. </constant> <constant name="SHADOW_FILTER_PCF13" value="2" enum="ShadowFilter"> - Percentage closer filtering (13 samples) applies to the shadow map. See [member shadow_filter]. + Percentage closer filtering (13 samples) applies to the shadow map. This is the slowest shadow filtereing mode, and should be used sparingly. See [member shadow_filter]. </constant> <constant name="BLEND_MODE_ADD" value="0" enum="BlendMode"> Adds the value of pixels corresponding to the Light2D to the values of pixels under it. This is the common behavior of a light. diff --git a/doc/classes/Mesh.xml b/doc/classes/Mesh.xml index 640fa9efec..4d3fb7ed5c 100644 --- a/doc/classes/Mesh.xml +++ b/doc/classes/Mesh.xml @@ -97,7 +97,7 @@ </description> </method> <method name="create_convex_shape" qualifiers="const"> - <return type="Shape3D" /> + <return type="ConvexPolygonShape3D" /> <param index="0" name="clean" type="bool" default="true" /> <param index="1" name="simplify" type="bool" default="false" /> <description> @@ -115,7 +115,7 @@ </description> </method> <method name="create_trimesh_shape" qualifiers="const"> - <return type="Shape3D" /> + <return type="ConcavePolygonShape3D" /> <description> Calculate a [ConcavePolygonShape3D] from the mesh. </description> diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index 0368f29a13..24df5977f9 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -384,8 +384,11 @@ <method name="get_path_to" qualifiers="const"> <return type="NodePath" /> <param index="0" name="node" type="Node" /> + <param index="1" name="use_unique_path" type="bool" default="false" /> <description> Returns the relative [NodePath] from this node to the specified [param node]. Both nodes must be in the same scene or the function will fail. + If [param use_unique_path] is [code]true[/code], returns the shortest path considering unique node. + [b]Note:[/b] If you get a relative path which starts from a unique node, the path may be longer than a normal relative path due to the addition of the unique node's name. </description> </method> <method name="get_physics_process_delta_time" qualifiers="const"> diff --git a/doc/classes/Node2D.xml b/doc/classes/Node2D.xml index 054ab532af..26efe37dce 100644 --- a/doc/classes/Node2D.xml +++ b/doc/classes/Node2D.xml @@ -125,15 +125,5 @@ <member name="transform" type="Transform2D" setter="set_transform" getter="get_transform"> Local [Transform2D]. </member> - <member name="y_sort_enabled" type="bool" setter="set_y_sort_enabled" getter="is_y_sort_enabled" default="false"> - If [code]true[/code], child nodes with the lowest Y position are drawn before those with a higher Y position. If [code]false[/code], Y-sorting is disabled. Y-sorting only affects children that inherit from [CanvasItem]. - You can nest nodes with Y-sorting. Child Y-sorted nodes are sorted in the same space as the parent Y-sort. This feature allows you to organize a scene better or divide it into multiple ones without changing your scene tree. - </member> - <member name="z_as_relative" type="bool" setter="set_z_as_relative" getter="is_z_relative" default="true"> - If [code]true[/code], the node's Z index is relative to its parent's Z index. If this node's Z index is 2 and its parent's effective Z index is 3, then this node's effective Z index will be 2 + 3 = 5. - </member> - <member name="z_index" type="int" setter="set_z_index" getter="get_z_index" default="0"> - Z index. Controls the order in which the nodes render. A node with a higher Z index will display in front of others. Must be between [constant RenderingServer.CANVAS_ITEM_Z_MIN] and [constant RenderingServer.CANVAS_ITEM_Z_MAX] (inclusive). - </member> </members> </class> diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index ea9b83d2aa..610f77e3d8 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -182,10 +182,12 @@ <method name="get_cmdline_user_args"> <return type="PackedStringArray" /> <description> - Similar to [method get_cmdline_args], but this returns the user arguments (any argument passed after the double dash [code]--[/code] argument). These are left untouched by Godot for the user. + Similar to [method get_cmdline_args], but this returns the user arguments (any argument passed after the double dash [code]--[/code] or double plus [code]++[/code] argument). These are left untouched by Godot for the user. [code]++[/code] can be used in situations where [code]--[/code] is intercepted by another program (such as [code]startx[/code]). For example, in the command line below, [code]--fullscreen[/code] will not be returned in [method get_cmdline_user_args] and [code]--level 1[/code] will only be returned in [method get_cmdline_user_args]: [codeblock] godot --fullscreen -- --level 1 + # Or: + godot --fullscreen ++ --level 1 [/codeblock] </description> </method> diff --git a/doc/classes/PointLight2D.xml b/doc/classes/PointLight2D.xml index 89cabbd428..0c51a78e49 100644 --- a/doc/classes/PointLight2D.xml +++ b/doc/classes/PointLight2D.xml @@ -1,10 +1,13 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="PointLight2D" inherits="Light2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> + Positional 2D light source. </brief_description> <description> + Casts light in a 2D environment. This light's shape is defined by a (usually grayscale) texture </description> <tutorials> + <link title="2D lights and shadows">$DOCS_URL/tutorials/2d/2d_lights_and_shadows.html</link> </tutorials> <members> <member name="height" type="float" setter="set_height" getter="get_height" default="0.0"> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index b6f92c2c40..1f0a8d91fa 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -2266,7 +2266,20 @@ Set the default Variable Rate Shading (VRS) mode for the main viewport. See [member Viewport.vrs_mode] to change this at runtime, and [enum Viewport.VRSMode] for possible values. </member> <member name="rendering/vrs/texture" type="String" setter="" getter="" default=""""> - If [member rendering/vrs/mode] is set to texture, this is the path to default texture loaded as the VRS image. + If [member rendering/vrs/mode] is set to [b]Texture[/b], this is the path to default texture loaded as the VRS image. + The texture [i]must[/i] use a lossless compression format so that colors can be matched precisely. The following VRS densities are mapped to various colors, with brighter colors representing a lower level of shading precision: + [codeblock] + - 1x1 = rgb(0, 0, 0) - #000000 + - 1x2 = rgb(0, 85, 0) - #005500 + - 2x1 = rgb(85, 0, 0) - #550000 + - 2x2 = rgb(85, 85, 0) - #555500 + - 2x4 = rgb(85, 170, 0) - #55aa00 + - 4x2 = rgb(170, 85, 0) - #aa5500 + - 4x4 = rgb(170, 170, 0) - #aaaa00 + - 4x8 = rgb(170, 255, 0) - #aaff00 - Not supported on most hardware + - 8x4 = rgb(255, 170, 0) - #ffaa00 - Not supported on most hardware + - 8x8 = rgb(255, 255, 0) - #ffff00 - Not supported on most hardware + [/codeblock] </member> <member name="threading/worker_pool/low_priority_thread_ratio" type="float" setter="" getter="" default="0.3"> </member> diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml index 78013a8f4b..236d34383f 100644 --- a/doc/classes/Viewport.xml +++ b/doc/classes/Viewport.xml @@ -343,6 +343,19 @@ </member> <member name="vrs_texture" type="Texture2D" setter="set_vrs_texture" getter="get_vrs_texture"> Texture to use when [member vrs_mode] is set to [constant Viewport.VRS_TEXTURE]. + The texture [i]must[/i] use a lossless compression format so that colors can be matched precisely. The following VRS densities are mapped to various colors, with brighter colors representing a lower level of shading precision: + [codeblock] + - 1x1 = rgb(0, 0, 0) - #000000 + - 1x2 = rgb(0, 85, 0) - #005500 + - 2x1 = rgb(85, 0, 0) - #550000 + - 2x2 = rgb(85, 85, 0) - #555500 + - 2x4 = rgb(85, 170, 0) - #55aa00 + - 4x2 = rgb(170, 85, 0) - #aa5500 + - 4x4 = rgb(170, 170, 0) - #aaaa00 + - 4x8 = rgb(170, 255, 0) - #aaff00 - Not supported on most hardware + - 8x4 = rgb(255, 170, 0) - #ffaa00 - Not supported on most hardware + - 8x8 = rgb(255, 255, 0) - #ffff00 - Not supported on most hardware + [/codeblock] </member> <member name="world_2d" type="World2D" setter="set_world_2d" getter="get_world_2d"> The custom [World2D] which can be used as 2D environment source. diff --git a/drivers/gles3/shaders/stdlib_inc.glsl b/drivers/gles3/shaders/stdlib_inc.glsl index d5051760d7..d819940b1d 100644 --- a/drivers/gles3/shaders/stdlib_inc.glsl +++ b/drivers/gles3/shaders/stdlib_inc.glsl @@ -38,7 +38,6 @@ vec2 unpackSnorm2x16(uint p) { vec2 v = vec2(float(p & uint(0xffff)), float(p >> uint(16))); return clamp((v - 32767.0) * vec2(0.00003051851), vec2(-1.0), vec2(1.0)); } -#endif uint packUnorm4x8(vec4 v) { uvec4 uv = uvec4(round(clamp(v, vec4(0.0), vec4(1.0)) * 255.0)); @@ -58,3 +57,5 @@ vec4 unpackSnorm4x8(uint p) { vec4 v = vec4(float(p & uint(0xff)), float((p >> uint(8)) & uint(0xff)), float((p >> uint(16)) & uint(0xff)), float(p >> uint(24))); return clamp((v - vec4(127.0)) * vec4(0.00787401574), vec4(-1.0), vec4(1.0)); } + +#endif diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 161706489f..b02a100784 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -565,7 +565,7 @@ String OS_Unix::get_executable_path() const { WARN_PRINT("MAXPATHLEN is too small"); } - String path(resolved_path); + String path = String::utf8(resolved_path); delete[] resolved_path; return path; diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp index a7a07a41ac..7ffec0835b 100644 --- a/editor/animation_bezier_editor.cpp +++ b/editor/animation_bezier_editor.cpp @@ -32,6 +32,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "scene/gui/view_panner.h" #include "scene/resources/text_line.h" diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 7aa06e6398..7c403b7523 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -35,10 +35,13 @@ #include "editor/animation_bezier_editor.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" +#include "editor/inspector_dock.h" #include "editor/plugins/animation_player_editor_plugin.h" #include "scene/animation/animation_player.h" #include "scene/animation/tween.h" +#include "scene/gui/grid_container.h" #include "scene/gui/separator.h" #include "scene/gui/view_panner.h" #include "scene/main/window.h" @@ -1751,7 +1754,9 @@ void AnimationTimelineEdit::update_values() { length->set_step(1); length->set_tooltip_text(TTR("Animation length (frames)")); time_icon->set_tooltip_text(TTR("Animation length (frames)")); - track_edit->editor->_update_key_edit(); + if (track_edit) { + track_edit->editor->_update_key_edit(); + } } else { length->set_value(animation->get_length()); length->set_step(0.001); @@ -3849,7 +3854,7 @@ void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_ } // Let's build a node path. - String path = root->get_path_to(p_node); + String path = root->get_path_to(p_node, true); if (!p_sub.is_empty()) { path += ":" + p_sub; } @@ -3889,7 +3894,7 @@ bool AnimationTrackEditor::has_track(Node3D *p_node, const String &p_sub, const } // Let's build a node path. - String path = root->get_path_to(p_node); + String path = root->get_path_to(p_node, true); if (!p_sub.is_empty()) { path += ":" + p_sub; } @@ -3937,11 +3942,10 @@ void AnimationTrackEditor::_insert_animation_key(NodePath p_path, const Variant void AnimationTrackEditor::insert_node_value_key(Node *p_node, const String &p_property, const Variant &p_value, bool p_only_if_exists) { ERR_FAIL_COND(!root); - // Let's build a node path. + // Let's build a node path. Node *node = p_node; - - String path = root->get_path_to(node); + String path = root->get_path_to(node, true); if (Object::cast_to<AnimationPlayer>(node) && p_property == "current_animation") { if (node == AnimationPlayerEditor::get_singleton()->get_player()) { @@ -4035,14 +4039,13 @@ void AnimationTrackEditor::insert_value_key(const String &p_property, const Vari EditorSelectionHistory *history = EditorNode::get_singleton()->get_editor_selection_history(); ERR_FAIL_COND(!root); - // Let's build a node path. ERR_FAIL_COND(history->get_path_size() == 0); Object *obj = ObjectDB::get_instance(history->get_path_object(0)); ERR_FAIL_COND(!Object::cast_to<Node>(obj)); + // Let's build a node path. Node *node = Object::cast_to<Node>(obj); - - String path = root->get_path_to(node); + String path = root->get_path_to(node, true); if (Object::cast_to<AnimationPlayer>(node) && p_property == "current_animation") { if (node == AnimationPlayerEditor::get_singleton()->get_player()) { @@ -4826,7 +4829,7 @@ void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) { ERR_FAIL_COND(!root); Node *node = get_node(p_path); ERR_FAIL_COND(!node); - NodePath path_to = root->get_path_to(node); + NodePath path_to = root->get_path_to(node, true); if (adding_track_type == Animation::TYPE_BLEND_SHAPE && !node->is_class("MeshInstance3D")) { EditorNode::get_singleton()->show_warning(TTR("Blend Shape tracks only apply to MeshInstance3D nodes.")); diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index e907d5a281..65cb083ac7 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -2002,23 +2002,14 @@ void CodeTextEditor::goto_next_bookmark() { return; } - text_editor->remove_secondary_carets(); - int line = text_editor->get_caret_line(); - if (line >= (int)bmarks[bmarks.size() - 1]) { - text_editor->unfold_line(bmarks[0]); - text_editor->set_caret_line(bmarks[0]); - text_editor->center_viewport_to_caret(); - } else { - for (int i = 0; i < bmarks.size(); i++) { - int bmark_line = bmarks[i]; - if (bmark_line > line) { - text_editor->unfold_line(bmark_line); - text_editor->set_caret_line(bmark_line); - text_editor->center_viewport_to_caret(); - return; - } + int current_line = text_editor->get_caret_line(); + int bmark_idx = 0; + if (current_line < (int)bmarks[bmarks.size() - 1]) { + while (bmark_idx < bmarks.size() && bmarks[bmark_idx] <= current_line) { + bmark_idx++; } } + goto_line_centered(bmarks[bmark_idx]); } void CodeTextEditor::goto_prev_bookmark() { @@ -2027,23 +2018,14 @@ void CodeTextEditor::goto_prev_bookmark() { return; } - text_editor->remove_secondary_carets(); - int line = text_editor->get_caret_line(); - if (line <= (int)bmarks[0]) { - text_editor->unfold_line(bmarks[bmarks.size() - 1]); - text_editor->set_caret_line(bmarks[bmarks.size() - 1]); - text_editor->center_viewport_to_caret(); - } else { - for (int i = bmarks.size() - 1; i >= 0; i--) { - int bmark_line = bmarks[i]; - if (bmark_line < line) { - text_editor->unfold_line(bmark_line); - text_editor->set_caret_line(bmark_line); - text_editor->center_viewport_to_caret(); - return; - } + int current_line = text_editor->get_caret_line(); + int bmark_idx = bmarks.size() - 1; + if (current_line > (int)bmarks[0]) { + while (bmark_idx >= 0 && bmarks[bmark_idx] >= current_line) { + bmark_idx--; } } + goto_line_centered(bmarks[bmark_idx]); } void CodeTextEditor::remove_all_bookmarks() { diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index ed2044c117..2bd77bf99c 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -31,6 +31,7 @@ #include "connections_dialog.h" #include "editor/doc_tools.h" +#include "editor/editor_help.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp index 1ec94aeae4..610f467faa 100644 --- a/editor/debugger/editor_debugger_node.cpp +++ b/editor/debugger/editor_debugger_node.cpp @@ -35,6 +35,8 @@ #include "editor/debugger/script_editor_debugger.h" #include "editor/editor_log.h" #include "editor/editor_node.h" +#include "editor/editor_settings.h" +#include "editor/inspector_dock.h" #include "editor/plugins/editor_debugger_plugin.h" #include "editor/plugins/script_editor_plugin.h" #include "editor/scene_tree_dock.h" diff --git a/editor/debugger/editor_debugger_tree.cpp b/editor/debugger/editor_debugger_tree.cpp index 4168efda26..8b31781c5e 100644 --- a/editor/debugger/editor_debugger_tree.cpp +++ b/editor/debugger/editor_debugger_tree.cpp @@ -34,6 +34,7 @@ #include "editor/editor_node.h" #include "editor/scene_tree_dock.h" #include "scene/debugger/scene_debugger.h" +#include "scene/gui/texture_rect.h" #include "scene/resources/packed_scene.h" #include "servers/display_server.h" diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp index d419e16b12..deca638f3b 100644 --- a/editor/debugger/script_editor_debugger.cpp +++ b/editor/debugger/script_editor_debugger.cpp @@ -46,6 +46,7 @@ #include "editor/editor_property_name_processor.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/inspector_dock.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "editor/plugins/editor_debugger_plugin.h" #include "editor/plugins/node_3d_editor_plugin.h" @@ -53,6 +54,7 @@ #include "scene/3d/camera_3d.h" #include "scene/debugger/scene_debugger.h" #include "scene/gui/dialogs.h" +#include "scene/gui/grid_container.h" #include "scene/gui/label.h" #include "scene/gui/line_edit.h" #include "scene/gui/margin_container.h" diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp index 24116a8053..a040d918df 100644 --- a/editor/editor_audio_buses.cpp +++ b/editor/editor_audio_buses.cpp @@ -40,6 +40,7 @@ #include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "filesystem_dock.h" +#include "scene/gui/separator.h" #include "scene/resources/font.h" #include "servers/audio_server.h" diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index 8cb1dfd24e..41b3d45a1f 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -541,8 +541,6 @@ void EditorAutoloadSettings::update_autoload() { info.node->queue_free(); info.node = nullptr; } - - ProjectSettings::get_singleton()->remove_autoload(info.name); } // Load new/changed autoloads @@ -567,12 +565,6 @@ void EditorAutoloadSettings::update_autoload() { } } - ProjectSettings::AutoloadInfo prop_info; - prop_info.name = info->name; - prop_info.path = info->path; - prop_info.is_singleton = info->is_singleton; - ProjectSettings::get_singleton()->add_autoload(prop_info); - if (!info->in_editor && !info->is_singleton) { // No reason to keep this node memdelete(info->node); diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index 48be0c9c00..f15b874c45 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -945,11 +945,11 @@ StringName EditorData::script_class_get_base(const String &p_class) const { Variant EditorData::script_class_instance(const String &p_class) { if (ScriptServer::is_global_class(p_class)) { - Variant obj = ClassDB::instantiate(ScriptServer::get_global_class_native_base(p_class)); - if (obj) { - Ref<Script> script = script_class_load_script(p_class); - if (script.is_valid()) { - ((Object *)obj)->set_script(script); + Ref<Script> script = script_class_load_script(p_class); + if (script.is_valid()) { + Object *obj = ClassDB::instantiate(script->get_instance_base_type()); + if (obj) { + obj->set_script(script); } return obj; } diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp index 49fb16a095..7080cdbdd5 100644 --- a/editor/editor_feature_profile.cpp +++ b/editor/editor_feature_profile.cpp @@ -309,7 +309,11 @@ void EditorFeatureProfile::_bind_methods() { BIND_ENUM_CONSTANT(FEATURE_MAX); } -EditorFeatureProfile::EditorFeatureProfile() {} +EditorFeatureProfile::EditorFeatureProfile() { + for (int i = 0; i < FEATURE_MAX; i++) { + features_disabled[i] = false; + } +} ////////////////////////// @@ -746,6 +750,8 @@ void EditorFeatureProfileManager::_update_selected_profile() { class_list->clear(); String profile = _get_selected_profile(); + profile_actions[PROFILE_SET]->set_disabled(profile == current_profile); + if (profile.is_empty()) { //nothing selected, nothing edited property_list->clear(); edited.unref(); diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp index ee02916a5f..55c512f77d 100644 --- a/editor/editor_file_dialog.cpp +++ b/editor/editor_file_dialog.cpp @@ -34,7 +34,6 @@ #include "core/io/file_access.h" #include "core/os/keyboard.h" #include "core/os/os.h" -#include "core/string/print_string.h" #include "dependency_editor.h" #include "editor/editor_file_system.h" #include "editor/editor_node.h" @@ -44,6 +43,10 @@ #include "scene/gui/center_container.h" #include "scene/gui/label.h" #include "scene/gui/margin_container.h" +#include "scene/gui/option_button.h" +#include "scene/gui/separator.h" +#include "scene/gui/split_container.h" +#include "scene/gui/texture_rect.h" #include "servers/display_server.h" EditorFileDialog::GetIconFunc EditorFileDialog::get_icon_func = nullptr; diff --git a/editor/editor_file_dialog.h b/editor/editor_file_dialog.h index 2e7302aaf9..40073326a1 100644 --- a/editor/editor_file_dialog.h +++ b/editor/editor_file_dialog.h @@ -32,17 +32,14 @@ #define EDITOR_FILE_DIALOG_H #include "core/io/dir_access.h" -#include "editor/plugins/editor_preview_plugins.h" -#include "scene/gui/box_container.h" #include "scene/gui/dialogs.h" -#include "scene/gui/item_list.h" -#include "scene/gui/line_edit.h" -#include "scene/gui/option_button.h" -#include "scene/gui/separator.h" -#include "scene/gui/split_container.h" -#include "scene/gui/texture_rect.h" class DependencyRemoveDialog; +class HSplitContainer; +class ItemList; +class OptionButton; +class PopupMenu; +class TextureRect; class EditorFileDialog : public ConfirmationDialog { GDCLASS(EditorFileDialog, ConfirmationDialog); diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index ce06631fdd..5d137ce290 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -39,6 +39,7 @@ #include "core/object/worker_thread_pool.h" #include "core/os/os.h" #include "core/variant/variant_parser.h" +#include "editor/editor_help.h" #include "editor/editor_node.h" #include "editor/editor_paths.h" #include "editor/editor_resource_preview.h" @@ -619,7 +620,12 @@ bool EditorFileSystem::_update_scan_actions() { if (_test_for_reimport(full_path, false)) { //must reimport reimports.push_back(full_path); - reimports.append_array(_get_dependencies(full_path)); + Vector<String> dependencies = _get_dependencies(full_path); + for (const String &dependency_path : dependencies) { + if (import_extensions.has(dependency_path.get_extension())) { + reimports.push_back(dependency_path); + } + } } else { //must not reimport, all was good //update modified times, to avoid reimport diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 676e4b0b33..6bd67fbcb9 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -39,6 +39,7 @@ #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/plugins/script_editor_plugin.h" +#include "scene/gui/line_edit.h" #define CONTRIBUTE_URL vformat("%s/community/contributing/updating_the_class_reference.html", VERSION_DOCS_URL) diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 4822aab7d4..a5397a8e6a 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -30,9 +30,7 @@ #include "editor_inspector.h" -#include "array_property_edit.h" #include "core/os/keyboard.h" -#include "dictionary_property_edit.h" #include "editor/doc_tools.h" #include "editor/editor_feature_profile.h" #include "editor/editor_node.h" @@ -40,9 +38,11 @@ #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" +#include "editor/inspector_dock.h" #include "editor/plugins/script_editor_plugin.h" #include "multi_node_edit.h" -#include "scene/gui/center_container.h" +#include "scene/gui/spin_box.h" +#include "scene/gui/texture_rect.h" #include "scene/property_utils.h" #include "scene/resources/packed_scene.h" @@ -660,6 +660,7 @@ void EditorProperty::gui_input(const Ref<InputEvent> &p_event) { } if (keying_rect.has_point(mpos)) { + accept_event(); emit_signal(SNAME("property_keyed"), property, use_keying_next()); if (use_keying_next()) { @@ -683,10 +684,12 @@ void EditorProperty::gui_input(const Ref<InputEvent> &p_event) { } } if (delete_rect.has_point(mpos)) { + accept_event(); emit_signal(SNAME("property_deleted"), property); } if (revert_rect.has_point(mpos)) { + accept_event(); bool is_valid_revert = false; Variant revert_value = EditorPropertyRevert::get_property_revert_value(object, property, &is_valid_revert); ERR_FAIL_COND(!is_valid_revert); @@ -695,11 +698,13 @@ void EditorProperty::gui_input(const Ref<InputEvent> &p_event) { } if (check_rect.has_point(mpos)) { + accept_event(); checked = !checked; queue_redraw(); emit_signal(SNAME("property_checked"), property, checked); } } else if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) { + accept_event(); _update_popup(); menu->set_position(get_screen_position() + get_local_mouse_position()); menu->reset_size(); @@ -1482,6 +1487,8 @@ void EditorInspectorSection::gui_input(const Ref<InputEvent> &p_event) { return; } + accept_event(); + bool should_unfold = !object->editor_is_section_unfolded(section); if (should_unfold) { unfold(); @@ -1680,6 +1687,7 @@ void EditorInspectorArray::_panel_gui_input(Ref<InputEvent> p_event, int p_index Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid()) { if (movable && mb->get_button_index() == MouseButton::RIGHT) { + array_elements[p_index].panel->accept_event(); popup_array_index_pressed = begin_array_index + p_index; rmb_popup->set_item_disabled(OPTION_MOVE_UP, popup_array_index_pressed == 0); rmb_popup->set_item_disabled(OPTION_MOVE_DOWN, popup_array_index_pressed == count - 1); diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h index 1b93b19845..41651494ce 100644 --- a/editor/editor_inspector.h +++ b/editor/editor_inspector.h @@ -33,14 +33,17 @@ #include "editor_property_name_processor.h" #include "scene/gui/box_container.h" -#include "scene/gui/button.h" -#include "scene/gui/dialogs.h" -#include "scene/gui/line_edit.h" -#include "scene/gui/option_button.h" -#include "scene/gui/panel_container.h" #include "scene/gui/scroll_container.h" -#include "scene/gui/spin_box.h" -#include "scene/gui/texture_rect.h" + +class AcceptDialog; +class Button; +class ConfirmationDialog; +class LineEdit; +class OptionButton; +class PanelContainer; +class PopupMenu; +class SpinBox; +class TextureRect; class EditorPropertyRevert { public: diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 2f6481704a..d00a64f796 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -37,7 +37,6 @@ #include "core/io/image_loader.h" #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" -#include "core/io/stream_peer_tls.h" #include "core/object/class_db.h" #include "core/object/message_queue.h" #include "core/os/keyboard.h" @@ -47,10 +46,7 @@ #include "core/string/translation.h" #include "core/version.h" #include "main/main.h" -#include "scene/3d/importer_mesh_instance_3d.h" -#include "scene/gui/center_container.h" #include "scene/gui/color_picker.h" -#include "scene/gui/control.h" #include "scene/gui/dialogs.h" #include "scene/gui/file_dialog.h" #include "scene/gui/link_button.h" @@ -61,17 +57,13 @@ #include "scene/gui/split_container.h" #include "scene/gui/tab_bar.h" #include "scene/gui/tab_container.h" -#include "scene/gui/texture_progress_bar.h" #include "scene/main/window.h" #include "scene/resources/packed_scene.h" #include "servers/display_server.h" -#include "servers/navigation_server_2d.h" #include "servers/navigation_server_3d.h" #include "servers/physics_server_2d.h" -#include "servers/rendering/rendering_device.h" #include "editor/audio_stream_preview.h" -#include "editor/debugger/debug_adapter/debug_adapter_server.h" #include "editor/debugger/editor_debugger_node.h" #include "editor/dependency_editor.h" #include "editor/editor_about.h" @@ -90,12 +82,13 @@ #include "editor/editor_plugin.h" #include "editor/editor_properties.h" #include "editor/editor_property_name_processor.h" +#include "editor/editor_quick_open.h" +#include "editor/editor_resource_preview.h" #include "editor/editor_run.h" #include "editor/editor_run_native.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/editor_settings_dialog.h" -#include "editor/editor_spin_slider.h" #include "editor/editor_themes.h" #include "editor/editor_toaster.h" #include "editor/editor_translation_parser.h" @@ -108,7 +101,6 @@ #include "editor/import/audio_stream_import_settings.h" #include "editor/import/dynamic_font_import_settings.h" #include "editor/import/editor_import_collada.h" -#include "editor/import/editor_import_plugin.h" #include "editor/import/resource_importer_bitmask.h" #include "editor/import/resource_importer_bmfont.h" #include "editor/import/resource_importer_csv_translation.h" @@ -123,6 +115,7 @@ #include "editor/import/resource_importer_wav.h" #include "editor/import/scene_import_settings.h" #include "editor/import_dock.h" +#include "editor/inspector_dock.h" #include "editor/multi_node_edit.h" #include "editor/node_dock.h" #include "editor/plugin_config_dialog.h" @@ -130,6 +123,7 @@ #include "editor/plugins/asset_library_editor_plugin.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "editor/plugins/debugger_editor_plugin.h" +#include "editor/plugins/editor_preview_plugins.h" #include "editor/plugins/editor_resource_conversion_plugin.h" #include "editor/plugins/gdextension_export_plugin.h" #include "editor/plugins/material_editor_plugin.h" @@ -1200,6 +1194,10 @@ void EditorNode::edit_node(Node *p_node) { push_item(p_node); } +void EditorNode::edit_resource(const Ref<Resource> &p_resource) { + InspectorDock::get_singleton()->edit_resource(p_resource); +} + void EditorNode::save_resource_in_path(const Ref<Resource> &p_resource, const String &p_path) { editor_data.apply_changes_in_editors(); int flg = 0; @@ -3358,7 +3356,9 @@ void EditorNode::add_editor_plugin(EditorPlugin *p_editor, bool p_config_changed void EditorNode::remove_editor_plugin(EditorPlugin *p_editor, bool p_config_changed) { if (p_editor->has_main_screen()) { - for (int i = 0; i < singleton->main_editor_buttons.size(); i++) { + // Remove the main editor button and update the bindings of + // all buttons behind it to point to the correct main window. + for (int i = singleton->main_editor_buttons.size() - 1; i >= 0; i--) { if (p_editor->get_name() == singleton->main_editor_buttons[i]->get_text()) { if (singleton->main_editor_buttons[i]->is_pressed()) { singleton->editor_select(EDITOR_SCRIPT); @@ -3368,6 +3368,9 @@ void EditorNode::remove_editor_plugin(EditorPlugin *p_editor, bool p_config_chan singleton->main_editor_buttons.remove_at(i); break; + } else { + singleton->main_editor_buttons[i]->disconnect("pressed", callable_mp(singleton, &EditorNode::editor_select)); + singleton->main_editor_buttons[i]->connect("pressed", callable_mp(singleton, &EditorNode::editor_select).bind(i - 1)); } } @@ -5879,10 +5882,6 @@ void EditorNode::_feature_profile_changed() { node_tabs->set_tab_hidden(node_tabs->get_tab_idx_from_control(NodeDock::get_singleton()), false); fs_tabs->set_tab_hidden(fs_tabs->get_tab_idx_from_control(FileSystemDock::get_singleton()), false); history_tabs->set_tab_hidden(history_tabs->get_tab_idx_from_control(history_dock), false); - history_dock->set_visible(true); - ImportDock::get_singleton()->set_visible(true); - NodeDock::get_singleton()->set_visible(true); - FileSystemDock::get_singleton()->set_visible(true); main_editor_buttons[EDITOR_3D]->set_visible(true); main_editor_buttons[EDITOR_SCRIPT]->set_visible(true); if (AssetLibraryEditorPlugin::is_available()) { diff --git a/editor/editor_node.h b/editor/editor_node.h index ff0338a794..c430662c7f 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -32,12 +32,13 @@ #define EDITOR_NODE_H #include "core/templates/safe_refcount.h" +#include "editor/editor_data.h" #include "editor/editor_folding.h" #include "editor/editor_native_shader_source_visualizer.h" +#include "editor/editor_plugin.h" #include "editor/editor_run.h" #include "editor/editor_title_bar.h" #include "editor/export/editor_export.h" -#include "editor/inspector_dock.h" typedef void (*EditorNodeInitCallback)(); typedef void (*EditorPluginInitializeCallback)(); @@ -46,8 +47,8 @@ typedef bool (*EditorBuildCallback)(); class AcceptDialog; class AudioStreamPreviewGenerator; class BackgroundProgress; -class Button; class CenterContainer; +class CheckBox; class ColorPicker; class ConfirmationDialog; class Control; @@ -59,18 +60,19 @@ class EditorCommandPalette; class EditorExport; class EditorExtensionManager; class EditorFeatureProfileManager; +class EditorFileDialog; class EditorFileServer; class EditorFolding; class EditorInspector; class EditorLayoutsDialog; class EditorLog; -class EditorPlugin; class EditorPluginList; class EditorQuickOpen; class EditorResourcePreview; class EditorResourceConversionPlugin; class EditorRun; class EditorRunNative; +class EditorSelectionHistory; class EditorSettingsDialog; class EditorToaster; class EditorUndoRedoManager; @@ -84,6 +86,7 @@ class LinkButton; class MenuBar; class MenuButton; class NodeDock; +class OptionButton; class OrphanResourcesDialog; class Panel; class PanelContainer; @@ -98,7 +101,9 @@ class ScriptCreateDialog; class SubViewport; class TabBar; class TabContainer; +class TextureRect; class TextureProgressBar; +class Tree; class VSplitContainer; class Window; class EditorBuildProfileManager; @@ -775,7 +780,7 @@ public: bool is_movie_maker_enabled() const; void edit_node(Node *p_node); - void edit_resource(const Ref<Resource> &p_resource) { InspectorDock::get_singleton()->edit_resource(p_resource); }; + void edit_resource(const Ref<Resource> &p_resource); void save_resource_in_path(const Ref<Resource> &p_resource, const String &p_path); void save_resource(const Ref<Resource> &p_resource); diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index e11bc3c252..f9c8b722c4 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -42,6 +42,7 @@ #include "editor/filesystem_dock.h" #include "editor/import/editor_import_plugin.h" #include "editor/import/resource_importer_scene.h" +#include "editor/inspector_dock.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "editor/plugins/editor_debugger_plugin.h" #include "editor/plugins/node_3d_editor_plugin.h" diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 8c53f576ac..fb3bf46c05 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -32,16 +32,22 @@ #include "core/config/project_settings.h" #include "core/core_string_names.h" +#include "editor/create_dialog.h" #include "editor/editor_file_dialog.h" #include "editor/editor_node.h" #include "editor/editor_properties_array_dict.h" -#include "editor/editor_resource_preview.h" +#include "editor/editor_resource_picker.h" #include "editor/editor_scale.h" -#include "editor/filesystem_dock.h" +#include "editor/editor_settings.h" +#include "editor/inspector_dock.h" +#include "editor/plugins/script_editor_plugin.h" #include "editor/project_settings_editor.h" +#include "editor/property_selector.h" +#include "editor/scene_tree_editor.h" #include "scene/2d/gpu_particles_2d.h" #include "scene/3d/fog_volume.h" #include "scene/3d/gpu_particles_3d.h" +#include "scene/gui/color_picker.h" #include "scene/main/window.h" #include "scene/resources/font.h" #include "scene/resources/mesh.h" diff --git a/editor/editor_properties.h b/editor/editor_properties.h index ad36e01544..f38e33d9e3 100644 --- a/editor/editor_properties.h +++ b/editor/editor_properties.h @@ -31,15 +31,19 @@ #ifndef EDITOR_PROPERTIES_H #define EDITOR_PROPERTIES_H -#include "editor/create_dialog.h" #include "editor/editor_inspector.h" -#include "editor/editor_locale_dialog.h" -#include "editor/editor_resource_picker.h" -#include "editor/editor_spin_slider.h" -#include "editor/property_selector.h" -#include "editor/scene_tree_editor.h" -#include "scene/gui/color_picker.h" -#include "scene/gui/line_edit.h" + +class CheckBox; +class ColorPickerButton; +class CreateDialog; +class EditorFileDialog; +class EditorLocaleDialog; +class EditorResourcePicker; +class EditorSpinSlider; +class PropertySelector; +class SceneTreeDialog; +class TextEdit; +class TextureButton; class EditorPropertyNil : public EditorProperty { GDCLASS(EditorPropertyNil, EditorProperty); diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index 659221ee0b..edda6c5d7b 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -34,6 +34,7 @@ #include "core/io/marshalls.h" #include "editor/editor_properties.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/inspector_dock.h" bool EditorPropertyArrayObject::_set(const StringName &p_name, const Variant &p_value) { @@ -692,6 +693,8 @@ void EditorPropertyArray::_reorder_button_up() { reorder_mouse_y_delta = 0.0f; Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); + + ERR_FAIL_NULL(reorder_selected_button); reorder_selected_button->warp_mouse(reorder_selected_button->get_size() / 2.0f); reorder_selected_element_hbox = nullptr; diff --git a/editor/editor_run.h b/editor/editor_run.h index 4cbc6838e4..935e32ee2a 100644 --- a/editor/editor_run.h +++ b/editor/editor_run.h @@ -32,7 +32,7 @@ #define EDITOR_RUN_H #include "core/os/os.h" -#include "scene/main/node.h" + class EditorRun { public: enum Status { diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index bc186c7a16..c44fe04442 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -452,11 +452,12 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/inspector/show_low_level_opentype_features", false, "") // Theme - EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_ENUM, "interface/theme/preset", "Default", "Default,Breeze Dark,Godot 2,Gray,Light,Solarized (Dark),Solarized (Light),Custom") + EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_ENUM, "interface/theme/preset", "Default", "Default,Breeze Dark,Godot 2,Gray,Light,Solarized (Dark),Solarized (Light),Black (OLED),Custom") EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/theme/icon_and_font_color", 0, "Auto,Dark,Light") EDITOR_SETTING(Variant::COLOR, PROPERTY_HINT_NONE, "interface/theme/base_color", Color(0.2, 0.23, 0.31), "") EDITOR_SETTING(Variant::COLOR, PROPERTY_HINT_NONE, "interface/theme/accent_color", Color(0.41, 0.61, 0.91), "") EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/theme/contrast", 0.3, "-1,1,0.01") + EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/theme/draw_extra_borders", false, "") EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/theme/icon_saturation", 1.0, "0,2,0.01") EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/theme/relationship_line_opacity", 0.1, "0.00,1,0.01") EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "interface/theme/border_size", 0, "0,2,1") diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp index b1b54fd717..6c11572d10 100644 --- a/editor/editor_settings_dialog.cpp +++ b/editor/editor_settings_dialog.cpp @@ -61,7 +61,7 @@ void EditorSettingsDialog::_settings_changed() { void EditorSettingsDialog::_settings_property_edited(const String &p_name) { String full_name = inspector->get_full_item_path(p_name); - if (full_name == "interface/theme/accent_color" || full_name == "interface/theme/base_color" || full_name == "interface/theme/contrast") { + if (full_name == "interface/theme/accent_color" || full_name == "interface/theme/base_color" || full_name == "interface/theme/contrast" || full_name == "interface/theme/draw_extra_borders") { EditorSettings::get_singleton()->set_manually("interface/theme/preset", "Custom"); // set preset to Custom } else if (full_name.begins_with("text_editor/theme/highlighting")) { EditorSettings::get_singleton()->set_manually("text_editor/theme/color_theme", "Custom"); diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index df28b2e6ab..96834f4a6c 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -393,6 +393,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { Color accent_color = EDITOR_GET("interface/theme/accent_color"); Color base_color = EDITOR_GET("interface/theme/base_color"); float contrast = EDITOR_GET("interface/theme/contrast"); + bool draw_extra_borders = EDITOR_GET("interface/theme/draw_extra_borders"); float icon_saturation = EDITOR_GET("interface/theme/icon_saturation"); float relationship_line_opacity = EDITOR_GET("interface/theme/relationship_line_opacity"); @@ -404,6 +405,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { Color preset_accent_color; Color preset_base_color; float preset_contrast = 0; + bool preset_draw_extra_borders = false; const float default_contrast = 0.3; @@ -440,6 +442,12 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { preset_base_color = Color(0.89, 0.86, 0.79); // A negative contrast rate looks better for light themes, since it better follows the natural order of UI "elevation". preset_contrast = -0.08; + } else if (preset == "Black (OLED)") { + preset_accent_color = Color(0.45, 0.75, 1.0); + preset_base_color = Color(0, 0, 0); + // The contrast rate value is irrelevant on a fully black theme. + preset_contrast = 0.0; + preset_draw_extra_borders = true; } else { // Default preset_accent_color = Color(0.44, 0.73, 0.98); preset_base_color = Color(0.21, 0.24, 0.29); @@ -450,15 +458,18 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { accent_color = preset_accent_color; base_color = preset_base_color; contrast = preset_contrast; + draw_extra_borders = preset_draw_extra_borders; EditorSettings::get_singleton()->set_initial_value("interface/theme/accent_color", accent_color); EditorSettings::get_singleton()->set_initial_value("interface/theme/base_color", base_color); EditorSettings::get_singleton()->set_initial_value("interface/theme/contrast", contrast); + EditorSettings::get_singleton()->set_initial_value("interface/theme/draw_extra_borders", draw_extra_borders); } EditorSettings::get_singleton()->set_manually("interface/theme/preset", preset); EditorSettings::get_singleton()->set_manually("interface/theme/accent_color", accent_color); EditorSettings::get_singleton()->set_manually("interface/theme/base_color", base_color); EditorSettings::get_singleton()->set_manually("interface/theme/contrast", contrast); + EditorSettings::get_singleton()->set_manually("interface/theme/draw_extra_borders", draw_extra_borders); // Colors bool dark_theme = EditorSettings::get_singleton()->is_dark_theme(); @@ -477,6 +488,10 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { const Color dark_color_2 = base_color.lerp(Color(0, 0, 0, 1), contrast * 1.5).clamp(); const Color dark_color_3 = base_color.lerp(Color(0, 0, 0, 1), contrast * 2).clamp(); + // Only used when the Draw Extra Borders editor setting is enabled. + const Color extra_border_color_1 = Color(0.5, 0.5, 0.5); + const Color extra_border_color_2 = dark_theme ? Color(0.3, 0.3, 0.3) : Color(0.7, 0.7, 0.7); + const Color background_color = dark_color_2; // White (dark theme) or black (light theme), will be used to generate the rest of the colors @@ -489,7 +504,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { const Color font_hover_color = mono_color.lerp(base_color, 0.125); const Color font_focus_color = mono_color.lerp(base_color, 0.125); const Color font_hover_pressed_color = font_hover_color.lerp(accent_color, 0.74); - const Color font_disabled_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.3); + const Color font_disabled_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.35); const Color font_readonly_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.65); const Color font_placeholder_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.6); const Color selection_color = accent_color * Color(1, 1, 1, 0.4); @@ -634,10 +649,19 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { Ref<StyleBoxFlat> style_widget = style_default->duplicate(); style_widget->set_default_margin_individual(widget_default_margin.x, widget_default_margin.y, widget_default_margin.x, widget_default_margin.y); style_widget->set_bg_color(dark_color_1); - style_widget->set_border_color(dark_color_2); + if (draw_extra_borders) { + style_widget->set_border_width_all(Math::round(EDSCALE)); + style_widget->set_border_color(extra_border_color_1); + } else { + style_widget->set_border_color(dark_color_2); + } Ref<StyleBoxFlat> style_widget_disabled = style_widget->duplicate(); - style_widget_disabled->set_border_color(disabled_color); + if (draw_extra_borders) { + style_widget_disabled->set_border_color(extra_border_color_2); + } else { + style_widget_disabled->set_border_color(disabled_color); + } style_widget_disabled->set_bg_color(disabled_bg_color); Ref<StyleBoxFlat> style_widget_focus = style_widget->duplicate(); @@ -650,7 +674,11 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { Ref<StyleBoxFlat> style_widget_hover = style_widget->duplicate(); style_widget_hover->set_bg_color(mono_color * Color(1, 1, 1, 0.11)); - style_widget_hover->set_border_color(mono_color * Color(1, 1, 1, 0.05)); + if (draw_extra_borders) { + style_widget_hover->set_border_color(extra_border_color_1); + } else { + style_widget_hover->set_border_color(mono_color * Color(1, 1, 1, 0.05)); + } // Style for windows, popups, etc.. Ref<StyleBoxFlat> style_popup = style_default->duplicate(); @@ -991,7 +1019,11 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { style_popup_menu->set_default_margin_individual(EDSCALE, 2 * EDSCALE, EDSCALE, 2 * EDSCALE); // Always display a border for PopupMenus so they can be distinguished from their background. style_popup_menu->set_border_width_all(EDSCALE); - style_popup_menu->set_border_color(dark_color_2); + if (draw_extra_borders) { + style_popup_menu->set_border_color(extra_border_color_2); + } else { + style_popup_menu->set_border_color(dark_color_2); + } theme->set_stylebox("panel", "PopupMenu", style_popup_menu); Ref<StyleBoxFlat> style_menu_hover = style_widget_hover->duplicate(); @@ -1111,7 +1143,13 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { Ref<StyleBoxFlat> style_tree_bg = style_default->duplicate(); // Make Trees easier to distinguish from other controls by using a darker background color. style_tree_bg->set_bg_color(dark_color_1.lerp(dark_color_2, 0.5)); - style_tree_bg->set_border_color(dark_color_3); + if (draw_extra_borders) { + style_tree_bg->set_border_width_all(Math::round(EDSCALE)); + style_tree_bg->set_border_color(extra_border_color_2); + } else { + style_tree_bg->set_border_color(dark_color_3); + } + theme->set_stylebox("panel", "Tree", style_tree_bg); // Tree @@ -1207,8 +1245,14 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // ItemList Ref<StyleBoxFlat> style_itemlist_bg = style_default->duplicate(); style_itemlist_bg->set_bg_color(dark_color_1); - style_itemlist_bg->set_border_width_all(border_width); - style_itemlist_bg->set_border_color(dark_color_3); + + if (draw_extra_borders) { + style_itemlist_bg->set_border_width_all(Math::round(EDSCALE)); + style_itemlist_bg->set_border_color(extra_border_color_2); + } else { + style_itemlist_bg->set_border_width_all(border_width); + style_itemlist_bg->set_border_color(dark_color_3); + } Ref<StyleBoxFlat> style_itemlist_cursor = style_default->duplicate(); style_itemlist_cursor->set_draw_center(false); @@ -1326,14 +1370,21 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // The original style_widget style has an extra 1 pixel offset that makes LineEdits not align with Buttons, // so this compensates for that. style_line_edit->set_default_margin(SIDE_TOP, style_line_edit->get_default_margin(SIDE_TOP) - 1 * EDSCALE); - // Add a bottom line to make LineEdits more visible, especially in sectioned inspectors - // such as the Project Settings. - style_line_edit->set_border_width(SIDE_BOTTOM, Math::round(2 * EDSCALE)); - style_line_edit->set_border_color(dark_color_2); + // Don't round the bottom corner to make the line look sharper. style_tab_selected->set_corner_radius(CORNER_BOTTOM_LEFT, 0); style_tab_selected->set_corner_radius(CORNER_BOTTOM_RIGHT, 0); + if (draw_extra_borders) { + style_line_edit->set_border_width_all(Math::round(EDSCALE)); + style_line_edit->set_border_color(extra_border_color_1); + } else { + // Add a bottom line to make LineEdits more visible, especially in sectioned inspectors + // such as the Project Settings. + style_line_edit->set_border_width(SIDE_BOTTOM, Math::round(2 * EDSCALE)); + style_line_edit->set_border_color(dark_color_2); + } + Ref<StyleBoxFlat> style_line_edit_disabled = style_line_edit->duplicate(); style_line_edit_disabled->set_border_color(disabled_color); style_line_edit_disabled->set_bg_color(disabled_bg_color); diff --git a/editor/export/export_template_manager.cpp b/editor/export/export_template_manager.cpp index 9ebf4d795a..84766a5bef 100644 --- a/editor/export/export_template_manager.cpp +++ b/editor/export/export_template_manager.cpp @@ -40,6 +40,7 @@ #include "editor/editor_settings.h" #include "editor/progress_dialog.h" #include "scene/gui/file_dialog.h" +#include "scene/gui/menu_button.h" #include "scene/gui/separator.h" #include "scene/gui/tree.h" #include "scene/main/http_request.h" diff --git a/editor/export/project_export.cpp b/editor/export/project_export.cpp index 6ff3539708..f5c5aafb5d 100644 --- a/editor/export/project_export.cpp +++ b/editor/export/project_export.cpp @@ -37,9 +37,16 @@ #include "editor/editor_node.h" #include "editor/editor_properties.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/export/editor_export.h" +#include "scene/gui/check_box.h" #include "scene/gui/check_button.h" +#include "scene/gui/item_list.h" #include "scene/gui/link_button.h" +#include "scene/gui/menu_button.h" +#include "scene/gui/option_button.h" +#include "scene/gui/split_container.h" +#include "scene/gui/texture_rect.h" #include "scene/gui/tree.h" void ProjectExportDialog::_theme_changed() { diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp index 6890a46193..c335655d4e 100644 --- a/editor/import/editor_import_collada.cpp +++ b/editor/import/editor_import_collada.cpp @@ -65,7 +65,7 @@ struct ColladaImport { bool force_make_tangents = false; bool apply_mesh_xform_to_vertices = true; bool use_mesh_builtin_materials = false; - float bake_fps = 15; + float bake_fps = 30; HashMap<String, NodeMap> node_map; //map from collada node to engine node HashMap<String, String> node_name_map; //map from collada node to engine node @@ -1760,7 +1760,7 @@ void EditorSceneFormatImporterCollada::get_extensions(List<String> *r_extensions r_extensions->push_back("dae"); } -Node *EditorSceneFormatImporterCollada::import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { +Node *EditorSceneFormatImporterCollada::import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err) { if (r_err) { *r_err = OK; } @@ -1771,7 +1771,7 @@ Node *EditorSceneFormatImporterCollada::import_scene(const String &p_path, uint3 } state.use_mesh_builtin_materials = true; - state.bake_fps = p_bake_fps; + state.bake_fps = (float)p_options["animation/fps"]; Error err = state.load(p_path, flags, p_flags & EditorSceneFormatImporter::IMPORT_GENERATE_TANGENT_ARRAYS, false); diff --git a/editor/import/editor_import_collada.h b/editor/import/editor_import_collada.h index a75b0a903f..ec30c91c1b 100644 --- a/editor/import/editor_import_collada.h +++ b/editor/import/editor_import_collada.h @@ -39,7 +39,7 @@ class EditorSceneFormatImporterCollada : public EditorSceneFormatImporter { public: virtual uint32_t get_import_flags() const override; virtual void get_extensions(List<String> *r_extensions) const override; - virtual Node *import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps = nullptr, Error *r_err = nullptr) override; + virtual Node *import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps = nullptr, Error *r_err = nullptr) override; EditorSceneFormatImporterCollada(); }; diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index fe70fd58b5..f19b4dbe56 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -422,7 +422,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_ return OK; } -Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { +Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err) { List<Ref<Mesh>> meshes; Error err = _parse_obj(p_path, meshes, false, p_flags & IMPORT_GENERATE_TANGENT_ARRAYS, false, Vector3(1, 1, 1), Vector3(0, 0, 0), r_missing_deps); diff --git a/editor/import/resource_importer_obj.h b/editor/import/resource_importer_obj.h index 4dfac90fa1..121d8e6d36 100644 --- a/editor/import/resource_importer_obj.h +++ b/editor/import/resource_importer_obj.h @@ -39,7 +39,7 @@ class EditorOBJImporter : public EditorSceneFormatImporter { public: virtual uint32_t get_import_flags() const override; virtual void get_extensions(List<String> *r_extensions) const override; - virtual Node *import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override; + virtual Node *import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err = nullptr) override; EditorOBJImporter(); }; diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index f7a3ce2679..a9ce6e9f88 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -74,13 +74,13 @@ void EditorSceneFormatImporter::get_extensions(List<String> *r_extensions) const ERR_FAIL(); } -Node *EditorSceneFormatImporter::import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { +Node *EditorSceneFormatImporter::import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err) { Dictionary options_dict; for (const KeyValue<StringName, Variant> &elem : p_options) { options_dict[elem.key] = elem.value; } Object *ret = nullptr; - if (GDVIRTUAL_CALL(_import_scene, p_path, p_flags, options_dict, p_bake_fps, ret)) { + if (GDVIRTUAL_CALL(_import_scene, p_path, p_flags, options_dict, ret)) { return Object::cast_to<Node>(ret); } @@ -100,7 +100,7 @@ Variant EditorSceneFormatImporter::get_option_visibility(const String &p_path, b void EditorSceneFormatImporter::_bind_methods() { GDVIRTUAL_BIND(_get_import_flags); GDVIRTUAL_BIND(_get_extensions); - GDVIRTUAL_BIND(_import_scene, "path", "flags", "options", "bake_fps"); + GDVIRTUAL_BIND(_import_scene, "path", "flags", "options"); GDVIRTUAL_BIND(_get_import_options, "path"); GDVIRTUAL_BIND(_get_option_visibility, "path", "for_animation", "option"); @@ -355,7 +355,7 @@ static void _pre_gen_shape_list(Ref<ImporterMesh> &mesh, Vector<Ref<Shape3D>> &r ERR_FAIL_NULL_MSG(mesh, "Cannot generate shape list with null mesh value"); ERR_FAIL_NULL_MSG(mesh->get_mesh(), "Cannot generate shape list with null mesh value"); if (!p_convex) { - Ref<Shape3D> shape = mesh->create_trimesh_shape(); + Ref<ConcavePolygonShape3D> shape = mesh->create_trimesh_shape(); r_shape_list.push_back(shape); } else { Vector<Ref<Shape3D>> cd; @@ -1864,6 +1864,7 @@ void ResourceImporterScene::get_import_options(const String &p_path, List<Import r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "skins/use_named_skins"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 30)); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/trimming"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "import_script/path", PROPERTY_HINT_FILE, script_ext_hint), "")); r_options->push_back(ImportOption(PropertyInfo(Variant::DICTIONARY, "_subresources", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), Dictionary())); @@ -2281,13 +2282,8 @@ Node *ResourceImporterScene::pre_import(const String &p_source_file, const HashM ERR_FAIL_COND_V(!importer.is_valid(), nullptr); - int bake_fps = 30; - if (p_options.has(SNAME("animation/fps"))) { - bake_fps = p_options[SNAME("animation/fps")]; - } - Error err = OK; - Node *scene = importer->import_scene(p_source_file, EditorSceneFormatImporter::IMPORT_ANIMATION | EditorSceneFormatImporter::IMPORT_GENERATE_TANGENT_ARRAYS, p_options, bake_fps, nullptr, &err); + Node *scene = importer->import_scene(p_source_file, EditorSceneFormatImporter::IMPORT_ANIMATION | EditorSceneFormatImporter::IMPORT_GENERATE_TANGENT_ARRAYS, p_options, nullptr, &err); if (!scene || err != OK) { return nullptr; } @@ -2326,8 +2322,6 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p ERR_FAIL_COND_V(!importer.is_valid(), ERR_FILE_UNRECOGNIZED); - float fps = p_options["animation/fps"]; - int import_flags = 0; if (animation_importer) { @@ -2350,7 +2344,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p Error err = OK; List<String> missing_deps; // for now, not much will be done with this - Node *scene = importer->import_scene(src_path, import_flags, p_options, fps, &missing_deps, &err); + Node *scene = importer->import_scene(src_path, import_flags, p_options, &missing_deps, &err); if (!scene || err != OK) { return err; } @@ -2398,6 +2392,10 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p post_importer_plugins.write[i]->pre_process(scene, p_options); } + float fps = 30; + if (p_options.has(SNAME("animation/fps"))) { + fps = (float)p_options[SNAME("animation/fps")]; + } _pre_fix_animations(scene, scene, node_data, animation_data, fps); _post_fix_node(scene, scene, collision_map, occluder_arrays, scanned_meshes, node_data, material_data, animation_data, fps); _post_fix_animations(scene, scene, node_data, animation_data, fps); @@ -2612,7 +2610,7 @@ void EditorSceneFormatImporterESCN::get_extensions(List<String> *r_extensions) c r_extensions->push_back("escn"); } -Node *EditorSceneFormatImporterESCN::import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { +Node *EditorSceneFormatImporterESCN::import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err) { Error error; Ref<PackedScene> ps = ResourceFormatLoaderText::singleton->load(p_path, p_path, &error); ERR_FAIL_COND_V_MSG(!ps.is_valid(), nullptr, "Cannot load scene as text resource from path '" + p_path + "'."); diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h index 5f64330453..678251372b 100644 --- a/editor/import/resource_importer_scene.h +++ b/editor/import/resource_importer_scene.h @@ -53,12 +53,12 @@ class EditorSceneFormatImporter : public RefCounted { protected: static void _bind_methods(); - Node *import_scene_wrapper(const String &p_path, uint32_t p_flags, Dictionary p_options, int p_bake_fps); - Ref<Animation> import_animation_wrapper(const String &p_path, uint32_t p_flags, Dictionary p_options, int p_bake_fps); + Node *import_scene_wrapper(const String &p_path, uint32_t p_flags, Dictionary p_options); + Ref<Animation> import_animation_wrapper(const String &p_path, uint32_t p_flags, Dictionary p_options); GDVIRTUAL0RC(int, _get_import_flags) GDVIRTUAL0RC(Vector<String>, _get_extensions) - GDVIRTUAL4R(Object *, _import_scene, String, uint32_t, Dictionary, uint32_t) + GDVIRTUAL3R(Object *, _import_scene, String, uint32_t, Dictionary) GDVIRTUAL1(_get_import_options, String) GDVIRTUAL3RC(Variant, _get_option_visibility, String, bool, String) @@ -74,7 +74,7 @@ public: virtual uint32_t get_import_flags() const; virtual void get_extensions(List<String> *r_extensions) const; - virtual Node *import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr); + virtual Node *import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err = nullptr); virtual void get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options); virtual Variant get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option, const HashMap<StringName, Variant> &p_options); @@ -310,7 +310,7 @@ class EditorSceneFormatImporterESCN : public EditorSceneFormatImporter { public: virtual uint32_t get_import_flags() const override; virtual void get_extensions(List<String> *r_extensions) const override; - virtual Node *import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override; + virtual Node *import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err = nullptr) override; }; template <class M> diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp index 03c801c42b..e64b80abbd 100644 --- a/editor/plugins/animation_blend_space_1d_editor.cpp +++ b/editor/plugins/animation_blend_space_1d_editor.cpp @@ -37,6 +37,8 @@ #include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "scene/animation/animation_blend_tree.h" +#include "scene/gui/check_box.h" +#include "scene/gui/panel_container.h" StringName AnimationNodeBlendSpace1DEditor::get_blend_position_path() const { StringName path = AnimationTreeEditor::get_singleton()->get_base_path() + "blend_position"; diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp index f27fd0cded..4d8e972883 100644 --- a/editor/plugins/animation_blend_space_2d_editor.cpp +++ b/editor/plugins/animation_blend_space_2d_editor.cpp @@ -42,9 +42,12 @@ #include "editor/editor_undo_redo_manager.h" #include "scene/animation/animation_blend_tree.h" #include "scene/animation/animation_player.h" +#include "scene/gui/check_box.h" #include "scene/gui/grid_container.h" #include "scene/gui/menu_button.h" +#include "scene/gui/option_button.h" #include "scene/gui/panel.h" +#include "scene/gui/panel_container.h" #include "scene/main/window.h" bool AnimationNodeBlendSpace2DEditor::can_edit(const Ref<AnimationNode> &p_node) { diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index 9da6e15e75..0f67663948 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -41,9 +41,11 @@ #include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "scene/animation/animation_player.h" +#include "scene/gui/check_box.h" #include "scene/gui/menu_button.h" #include "scene/gui/panel.h" #include "scene/gui/progress_bar.h" +#include "scene/gui/separator.h" #include "scene/gui/view_panner.h" #include "scene/main/window.h" diff --git a/editor/plugins/animation_library_editor.cpp b/editor/plugins/animation_library_editor.cpp index e377366c0d..10b5271fc8 100644 --- a/editor/plugins/animation_library_editor.cpp +++ b/editor/plugins/animation_library_editor.cpp @@ -32,6 +32,7 @@ #include "editor/editor_file_dialog.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" void AnimationLibraryEditor::set_animation_player(Object *p_player) { diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 85739d0d8f..f8ebd377d1 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -40,9 +40,11 @@ #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" +#include "editor/inspector_dock.h" #include "editor/plugins/canvas_item_editor_plugin.h" // For onion skinning. #include "editor/plugins/node_3d_editor_plugin.h" // For onion skinning. #include "editor/scene_tree_dock.h" +#include "scene/gui/separator.h" #include "scene/main/window.h" #include "scene/resources/animation.h" #include "scene/scene_string_names.h" diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index bd34d3808d..ef9477abea 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -43,7 +43,10 @@ #include "scene/animation/animation_blend_tree.h" #include "scene/animation/animation_player.h" #include "scene/gui/menu_button.h" +#include "scene/gui/option_button.h" #include "scene/gui/panel.h" +#include "scene/gui/panel_container.h" +#include "scene/gui/separator.h" #include "scene/gui/tree.h" #include "scene/main/viewport.h" #include "scene/main/window.h" diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 72bee901bf..7c3ecd5d4e 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -41,6 +41,7 @@ #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/project_settings_editor.h" +#include "scene/gui/menu_button.h" static inline void setup_http_request(HTTPRequest *request) { request->set_use_threads(EDITOR_DEF("asset_library/use_threads", true)); diff --git a/editor/plugins/bit_map_editor_plugin.cpp b/editor/plugins/bit_map_editor_plugin.cpp index 657c5a36b6..8d9b3147a9 100644 --- a/editor/plugins/bit_map_editor_plugin.cpp +++ b/editor/plugins/bit_map_editor_plugin.cpp @@ -31,6 +31,8 @@ #include "bit_map_editor_plugin.h" #include "editor/editor_scale.h" +#include "scene/gui/label.h" +#include "scene/gui/texture_rect.h" void BitMapEditor::setup(const Ref<BitMap> &p_bitmap) { texture_rect->set_texture(ImageTexture::create_from_image(p_bitmap->convert_to_image())); diff --git a/editor/plugins/bone_map_editor_plugin.cpp b/editor/plugins/bone_map_editor_plugin.cpp index 9ceedb18b3..4bf11f0627 100644 --- a/editor/plugins/bone_map_editor_plugin.cpp +++ b/editor/plugins/bone_map_editor_plugin.cpp @@ -31,10 +31,14 @@ #include "bone_map_editor_plugin.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/import/post_import_plugin_skeleton_renamer.h" #include "editor/import/post_import_plugin_skeleton_rest_fixer.h" #include "editor/import/post_import_plugin_skeleton_track_organizer.h" #include "editor/import/scene_import_settings.h" +#include "scene/gui/aspect_ratio_container.h" +#include "scene/gui/separator.h" +#include "scene/gui/texture_rect.h" void BoneMapperButton::fetch_textures() { if (selected) { diff --git a/editor/plugins/bone_map_editor_plugin.h b/editor/plugins/bone_map_editor_plugin.h index 16e5403978..e6a35d1120 100644 --- a/editor/plugins/bone_map_editor_plugin.h +++ b/editor/plugins/bone_map_editor_plugin.h @@ -41,11 +41,14 @@ #endif #include "scene/3d/skeleton_3d.h" +#include "scene/gui/box_container.h" #include "scene/gui/color_rect.h" #include "scene/gui/dialogs.h" #include "scene/resources/bone_map.h" #include "scene/resources/texture.h" +class AspectRatioContainer; + class BoneMapperButton : public TextureButton { GDCLASS(BoneMapperButton, TextureButton); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 0fe77ec400..c08c9a83a7 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -32,15 +32,14 @@ #include "core/config/project_settings.h" #include "core/input/input.h" -#include "core/math/geometry_2d.h" #include "core/os/keyboard.h" -#include "core/string/print_string.h" #include "editor/debugger/editor_debugger_node.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/editor_toaster.h" #include "editor/editor_undo_redo_manager.h" +#include "editor/editor_zoom_widget.h" #include "editor/plugins/animation_player_editor_plugin.h" #include "editor/plugins/script_editor_plugin.h" #include "editor/scene_tree_dock.h" @@ -55,6 +54,7 @@ #include "scene/gui/grid_container.h" #include "scene/gui/nine_patch_rect.h" #include "scene/gui/separator.h" +#include "scene/gui/split_container.h" #include "scene/gui/subviewport_container.h" #include "scene/gui/view_panner.h" #include "scene/main/canvas_layer.h" @@ -5596,7 +5596,7 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String & // make visible for certain node type if (Object::cast_to<Control>(child)) { Size2 texture_size = texture->get_size(); - undo_redo->add_do_property(child, "rect_size", texture_size); + undo_redo->add_do_property(child, "size", texture_size); } else if (Object::cast_to<Polygon2D>(child)) { Size2 texture_size = texture->get_size(); Vector<Vector2> list = { @@ -5612,6 +5612,11 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String & Transform2D xform = canvas_item_editor->get_canvas_transform(); Point2 target_position = xform.affine_inverse().xform(p_point); + // Adjust position for Control and TouchScreenButton + if (Object::cast_to<Control>(child) || Object::cast_to<TouchScreenButton>(child)) { + target_position -= texture->get_size() / 2; + } + // there's nothing to be used as source position so snapping will work as absolute if enabled target_position = canvas_item_editor->snap_point(target_position); undo_redo->add_do_method(child, "set_global_position", target_position); diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index cc98aa8c51..9c7d0fbe6f 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -32,22 +32,21 @@ #define CANVAS_ITEM_EDITOR_PLUGIN_H #include "editor/editor_plugin.h" -#include "editor/editor_zoom_widget.h" +#include "scene/gui/base_button.h" #include "scene/gui/box_container.h" -#include "scene/gui/check_box.h" -#include "scene/gui/label.h" -#include "scene/gui/panel_container.h" -#include "scene/gui/spin_box.h" -#include "scene/gui/split_container.h" -#include "scene/gui/texture_rect.h" -#include "scene/main/canvas_item.h" class AcceptDialog; +class CanvasItemEditorViewport; class ConfirmationDialog; class EditorData; -class CanvasItemEditorViewport; +class EditorZoomWidget; +class HScrollBar; +class HSplitContainer; class MenuButton; +class PanelContainer; class ViewPanner; +class VScrollBar; +class VSplitContainer; class CanvasItemEditorSelectedItem : public Object { GDCLASS(CanvasItemEditorSelectedItem, Object); diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp index 891a22cc71..36b51e0e0c 100644 --- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp @@ -35,7 +35,11 @@ #include "editor/editor_file_dialog.h" #include "editor/editor_node.h" #include "scene/2d/cpu_particles_2d.h" +#include "scene/gui/check_box.h" +#include "scene/gui/menu_button.h" +#include "scene/gui/option_button.h" #include "scene/gui/separator.h" +#include "scene/gui/spin_box.h" #include "scene/resources/particle_process_material.h" void CPUParticles2DEditorPlugin::edit(Object *p_object) { diff --git a/editor/plugins/font_config_plugin.cpp b/editor/plugins/font_config_plugin.cpp index 33992314b0..4370d013be 100644 --- a/editor/plugins/font_config_plugin.cpp +++ b/editor/plugins/font_config_plugin.cpp @@ -31,6 +31,7 @@ #include "font_config_plugin.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/import/dynamic_font_import_settings.h" /*************************************************************************/ diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.cpp b/editor/plugins/gpu_particles_2d_editor_plugin.cpp index 87381b3221..0fa3efba9a 100644 --- a/editor/plugins/gpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_2d_editor_plugin.cpp @@ -37,6 +37,7 @@ #include "editor/editor_undo_redo_manager.h" #include "editor/scene_tree_dock.h" #include "scene/2d/cpu_particles_2d.h" +#include "scene/gui/menu_button.h" #include "scene/gui/separator.h" #include "scene/resources/particle_process_material.h" diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp index db3a46d1f1..b2878244d0 100644 --- a/editor/plugins/gpu_particles_3d_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp @@ -36,6 +36,8 @@ #include "editor/plugins/node_3d_editor_plugin.h" #include "editor/scene_tree_dock.h" #include "scene/3d/cpu_particles_3d.h" +#include "scene/3d/mesh_instance_3d.h" +#include "scene/gui/menu_button.h" #include "scene/resources/particle_process_material.h" bool GPUParticles3DEditorBase::_generate(Vector<Vector3> &points, Vector<Vector3> &normals) { diff --git a/editor/plugins/material_editor_plugin.h b/editor/plugins/material_editor_plugin.h index 076fd5e537..7d7d41785b 100644 --- a/editor/plugins/material_editor_plugin.h +++ b/editor/plugins/material_editor_plugin.h @@ -41,7 +41,9 @@ #include "scene/resources/material.h" #include "scene/resources/primitive_meshes.h" +class SubViewport; class SubViewportContainer; +class TextureButton; class MaterialEditor : public Control { GDCLASS(MaterialEditor, Control); diff --git a/editor/plugins/mesh_editor_plugin.cpp b/editor/plugins/mesh_editor_plugin.cpp index 57dc92a9ee..79fbf19f89 100644 --- a/editor/plugins/mesh_editor_plugin.cpp +++ b/editor/plugins/mesh_editor_plugin.cpp @@ -32,6 +32,8 @@ #include "core/config/project_settings.h" #include "editor/editor_scale.h" +#include "scene/gui/texture_button.h" +#include "scene/main/viewport.h" void MeshEditor::gui_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); diff --git a/editor/plugins/mesh_editor_plugin.h b/editor/plugins/mesh_editor_plugin.h index b8d6562c5c..8eecc909b6 100644 --- a/editor/plugins/mesh_editor_plugin.h +++ b/editor/plugins/mesh_editor_plugin.h @@ -40,6 +40,9 @@ #include "scene/resources/camera_attributes.h" #include "scene/resources/material.h" +class SubViewport; +class TextureButton; + class MeshEditor : public SubViewportContainer { GDCLASS(MeshEditor, SubViewportContainer); diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp index 68fbce771a..57e8046f32 100644 --- a/editor/plugins/mesh_instance_3d_editor_plugin.cpp +++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp @@ -38,6 +38,9 @@ #include "scene/3d/navigation_region_3d.h" #include "scene/3d/physics_body_3d.h" #include "scene/gui/box_container.h" +#include "scene/gui/menu_button.h" +#include "scene/resources/concave_polygon_shape_3d.h" +#include "scene/resources/convex_polygon_shape_3d.h" void MeshInstance3DEditor::_node_removed(Node *p_node) { if (p_node == node) { @@ -66,7 +69,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { List<Node *> selection = editor_selection->get_selected_node_list(); if (selection.is_empty()) { - Ref<Shape3D> shape = mesh->create_trimesh_shape(); + Ref<ConcavePolygonShape3D> shape = mesh->create_trimesh_shape(); if (shape.is_null()) { err_dialog->set_text(TTR("Couldn't create a Trimesh collision shape.")); err_dialog->popup_centered(); @@ -105,7 +108,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { continue; } - Ref<Shape3D> shape = m->create_trimesh_shape(); + Ref<ConcavePolygonShape3D> shape = m->create_trimesh_shape(); if (shape.is_null()) { continue; } @@ -137,7 +140,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { return; } - Ref<Shape3D> shape = mesh->create_trimesh_shape(); + Ref<ConcavePolygonShape3D> shape = mesh->create_trimesh_shape(); if (shape.is_null()) { return; } @@ -171,7 +174,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { bool simplify = (p_option == MENU_OPTION_CREATE_SIMPLIFIED_CONVEX_COLLISION_SHAPE); - Ref<Shape3D> shape = mesh->create_convex_shape(true, simplify); + Ref<ConvexPolygonShape3D> shape = mesh->create_convex_shape(true, simplify); if (shape.is_null()) { err_dialog->set_text(TTR("Couldn't create a single convex collision shape.")); diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp index 6654b03a0d..4a8e5d9979 100644 --- a/editor/plugins/mesh_library_editor_plugin.cpp +++ b/editor/plugins/mesh_library_editor_plugin.cpp @@ -33,11 +33,13 @@ #include "editor/editor_file_dialog.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" +#include "editor/inspector_dock.h" #include "main/main.h" #include "node_3d_editor_plugin.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/3d/navigation_region_3d.h" #include "scene/3d/physics_body_3d.h" +#include "scene/gui/menu_button.h" #include "scene/main/window.h" #include "scene/resources/packed_scene.h" diff --git a/editor/plugins/multimesh_editor_plugin.cpp b/editor/plugins/multimesh_editor_plugin.cpp index b0e206b020..40fac060cd 100644 --- a/editor/plugins/multimesh_editor_plugin.cpp +++ b/editor/plugins/multimesh_editor_plugin.cpp @@ -35,6 +35,8 @@ #include "node_3d_editor_plugin.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/gui/box_container.h" +#include "scene/gui/menu_button.h" +#include "scene/gui/option_button.h" void MultiMeshEditor::_node_removed(Node *p_node) { if (p_node == node) { diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index ca6d65bd57..df1fd52b69 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -36,14 +36,12 @@ #include "core/math/math_funcs.h" #include "core/math/projection.h" #include "core/os/keyboard.h" -#include "core/templates/sort_array.h" #include "editor/debugger/editor_debugger_node.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "editor/plugins/animation_player_editor_plugin.h" #include "editor/plugins/node_3d_editor_gizmos.h" -#include "editor/plugins/script_editor_plugin.h" #include "editor/scene_tree_dock.h" #include "scene/3d/camera_3d.h" #include "scene/3d/collision_shape_3d.h" @@ -54,9 +52,12 @@ #include "scene/3d/visual_instance_3d.h" #include "scene/3d/world_environment.h" #include "scene/gui/center_container.h" +#include "scene/gui/color_picker.h" #include "scene/gui/flow_container.h" +#include "scene/gui/split_container.h" #include "scene/gui/subviewport_container.h" #include "scene/resources/packed_scene.h" +#include "scene/resources/sky_material.h" #include "scene/resources/surface_tool.h" constexpr real_t DISTANCE_DEFAULT = 4; diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index a8d3bfb70c..b7ac718182 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -33,31 +33,29 @@ #include "editor/editor_plugin.h" #include "editor/editor_scale.h" -#include "editor/editor_spin_slider.h" #include "editor/plugins/node_3d_editor_gizmos.h" -#include "scene/3d/camera_3d.h" -#include "scene/3d/light_3d.h" -#include "scene/3d/visual_instance_3d.h" -#include "scene/3d/world_environment.h" #include "scene/gui/box_container.h" -#include "scene/gui/color_picker.h" -#include "scene/gui/panel_container.h" +#include "scene/gui/button.h" #include "scene/gui/spin_box.h" -#include "scene/gui/split_container.h" -#include "scene/resources/environment.h" -#include "scene/resources/fog_material.h" -#include "scene/resources/sky_material.h" class AcceptDialog; class CheckBox; +class ColorPickerButton; class ConfirmationDialog; +class DirectionalLight3D; class EditorData; +class EditorSpinSlider; +class HSplitContainer; +class LineEdit; class MenuButton; class Node3DEditor; class Node3DEditorViewport; class OptionButton; +class PanelContainer; +class ProceduralSkyMaterial; +class SubViewport; class SubViewportContainer; -class DirectionalLight3D; +class VSplitContainer; class WorldEnvironment; class ViewportRotationControl : public Control { diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp index 133a7e5327..3204cc8d0f 100644 --- a/editor/plugins/path_2d_editor_plugin.cpp +++ b/editor/plugins/path_2d_editor_plugin.cpp @@ -37,6 +37,7 @@ #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" +#include "scene/gui/menu_button.h" void Path2DEditor::_notification(int p_what) { switch (p_what) { diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp index d7953bf4e0..5a7b0321b7 100644 --- a/editor/plugins/path_3d_editor_plugin.cpp +++ b/editor/plugins/path_3d_editor_plugin.cpp @@ -37,6 +37,7 @@ #include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "node_3d_editor_plugin.h" +#include "scene/gui/menu_button.h" #include "scene/resources/curve.h" static bool _is_in_handle(int p_id, int p_num_points) { diff --git a/editor/plugins/physical_bone_3d_editor_plugin.cpp b/editor/plugins/physical_bone_3d_editor_plugin.cpp index 9dc89133c4..2b59e4cf08 100644 --- a/editor/plugins/physical_bone_3d_editor_plugin.cpp +++ b/editor/plugins/physical_bone_3d_editor_plugin.cpp @@ -31,6 +31,7 @@ #include "physical_bone_3d_editor_plugin.h" #include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/gui/separator.h" void PhysicalBone3DEditor::_bind_methods() { } diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index 6218c887fb..a19a42f951 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -38,10 +38,14 @@ #include "editor/editor_undo_redo_manager.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "scene/2d/skeleton_2d.h" +#include "scene/gui/check_box.h" #include "scene/gui/menu_button.h" #include "scene/gui/scroll_container.h" #include "scene/gui/separator.h" #include "scene/gui/slider.h" +#include "scene/gui/spin_box.h" +#include "scene/gui/split_container.h" +#include "scene/gui/texture_rect.h" #include "scene/gui/view_panner.h" Node2D *Polygon2DEditor::_get_node() const { diff --git a/editor/plugins/polygon_3d_editor_plugin.cpp b/editor/plugins/polygon_3d_editor_plugin.cpp index 1cd4804b79..dde44d31fa 100644 --- a/editor/plugins/polygon_3d_editor_plugin.cpp +++ b/editor/plugins/polygon_3d_editor_plugin.cpp @@ -41,6 +41,7 @@ #include "editor/editor_undo_redo_manager.h" #include "node_3d_editor_plugin.h" #include "scene/3d/camera_3d.h" +#include "scene/gui/separator.h" void Polygon3DEditor::_notification(int p_what) { switch (p_what) { diff --git a/editor/plugins/root_motion_editor_plugin.cpp b/editor/plugins/root_motion_editor_plugin.cpp index 596b2c0edb..93a64a8f3d 100644 --- a/editor/plugins/root_motion_editor_plugin.cpp +++ b/editor/plugins/root_motion_editor_plugin.cpp @@ -32,6 +32,7 @@ #include "editor/editor_node.h" #include "scene/animation/animation_player.h" #include "scene/animation/animation_tree.h" +#include "scene/gui/tree.h" #include "scene/main/window.h" void EditorPropertyRootMotion::_confirmed() { diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 4ff3919e9b..bb5491fcb5 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -40,6 +40,7 @@ #include "editor/debugger/editor_debugger_node.h" #include "editor/debugger/script_editor_debugger.h" #include "editor/editor_file_dialog.h" +#include "editor/editor_help_search.h" #include "editor/editor_node.h" #include "editor/editor_paths.h" #include "editor/editor_run_script.h" @@ -47,6 +48,7 @@ #include "editor/editor_settings.h" #include "editor/filesystem_dock.h" #include "editor/find_in_files.h" +#include "editor/inspector_dock.h" #include "editor/node_dock.h" #include "editor/plugins/shader_editor_plugin.h" #include "editor/plugins/text_shader_editor.h" diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index 3f84ded0a2..213fbdc22a 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -31,24 +31,22 @@ #ifndef SCRIPT_EDITOR_PLUGIN_H #define SCRIPT_EDITOR_PLUGIN_H -#include "core/object/script_language.h" -#include "editor/code_editor.h" -#include "editor/editor_help.h" -#include "editor/editor_help_search.h" #include "editor/editor_plugin.h" -#include "editor/script_create_dialog.h" -#include "scene/gui/item_list.h" -#include "scene/gui/line_edit.h" -#include "scene/gui/menu_button.h" -#include "scene/gui/split_container.h" -#include "scene/gui/tab_container.h" -#include "scene/gui/text_edit.h" -#include "scene/gui/tree.h" -#include "scene/main/timer.h" +#include "scene/gui/dialogs.h" +#include "scene/gui/panel_container.h" +#include "scene/resources/syntax_highlighter.h" #include "scene/resources/text_file.h" class EditorFileDialog; +class EditorHelpSearch; +class FindReplaceBar; +class HSplitContainer; +class ItemList; +class MenuButton; +class TabContainer; class TextureRect; +class Tree; +class VSplitContainer; class EditorSyntaxHighlighter : public SyntaxHighlighter { GDCLASS(EditorSyntaxHighlighter, SyntaxHighlighter) diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 4e66dc3d7e..747fdfd041 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -38,6 +38,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "scene/gui/split_container.h" void ConnectionInfoDialog::ok_pressed() { } diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index 5fd12674b3..cbc4153e12 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -31,10 +31,14 @@ #ifndef SCRIPT_TEXT_EDITOR_H #define SCRIPT_TEXT_EDITOR_H +#include "script_editor_plugin.h" + +#include "editor/code_editor.h" #include "scene/gui/color_picker.h" #include "scene/gui/dialogs.h" #include "scene/gui/tree.h" -#include "script_editor_plugin.h" + +class RichTextLabel; class ConnectionInfoDialog : public AcceptDialog { GDCLASS(ConnectionInfoDialog, AcceptDialog); diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index 2f80e41dd4..fbc94c70f8 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -34,9 +34,12 @@ #include "editor/editor_scale.h" #include "editor/editor_undo_redo_manager.h" #include "editor/filesystem_dock.h" +#include "editor/inspector_dock.h" #include "editor/plugins/text_shader_editor.h" #include "editor/plugins/visual_shader_editor_plugin.h" #include "editor/shader_create_dialog.h" +#include "scene/gui/item_list.h" +#include "scene/gui/texture_rect.h" void ShaderEditorPlugin::_update_shader_list() { shader_list->clear(); diff --git a/editor/plugins/shader_file_editor_plugin.cpp b/editor/plugins/shader_file_editor_plugin.cpp index dd644cb369..4e33c421ae 100644 --- a/editor/plugins/shader_file_editor_plugin.cpp +++ b/editor/plugins/shader_file_editor_plugin.cpp @@ -37,6 +37,8 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "scene/gui/item_list.h" +#include "scene/gui/split_container.h" #include "servers/display_server.h" #include "servers/rendering/shader_types.h" diff --git a/editor/plugins/skeleton_2d_editor_plugin.cpp b/editor/plugins/skeleton_2d_editor_plugin.cpp index dbad81d743..5ae21a430d 100644 --- a/editor/plugins/skeleton_2d_editor_plugin.cpp +++ b/editor/plugins/skeleton_2d_editor_plugin.cpp @@ -35,6 +35,7 @@ #include "editor/editor_undo_redo_manager.h" #include "scene/2d/mesh_instance_2d.h" #include "scene/gui/box_container.h" +#include "scene/gui/menu_button.h" #include "thirdparty/misc/clipper.hpp" void Skeleton2DEditor::_node_removed(Node *p_node) { diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp index 8e80d0d5d8..e8bbfd1b91 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -34,6 +34,7 @@ #include "editor/editor_node.h" #include "editor/editor_properties.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "editor/plugins/animation_player_editor_plugin.h" #include "node_3d_editor_plugin.h" @@ -41,6 +42,7 @@ #include "scene/3d/joint_3d.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/3d/physics_body_3d.h" +#include "scene/gui/separator.h" #include "scene/resources/capsule_shape_3d.h" #include "scene/resources/skeleton_profile.h" #include "scene/resources/sphere_shape_3d.h" diff --git a/editor/plugins/skeleton_3d_editor_plugin.h b/editor/plugins/skeleton_3d_editor_plugin.h index 273bdeaac8..8ef61861d0 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.h +++ b/editor/plugins/skeleton_3d_editor_plugin.h @@ -45,6 +45,9 @@ class Joint; class PhysicalBone3D; class Skeleton3DEditorPlugin; class Button; +class Tree; +class TreeItem; +class VSeparator; class BoneTransformEditor : public VBoxContainer { GDCLASS(BoneTransformEditor, VBoxContainer); diff --git a/editor/plugins/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp index b78b70cd5c..110ad7cac0 100644 --- a/editor/plugins/sprite_2d_editor_plugin.cpp +++ b/editor/plugins/sprite_2d_editor_plugin.cpp @@ -41,6 +41,7 @@ #include "scene/2d/mesh_instance_2d.h" #include "scene/2d/polygon_2d.h" #include "scene/gui/box_container.h" +#include "scene/gui/menu_button.h" #include "thirdparty/misc/clipper.hpp" void Sprite2DEditor::_node_removed(Node *p_node) { diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp index 6924cb58bf..64e899b121 100644 --- a/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/editor/plugins/sprite_frames_editor_plugin.cpp @@ -34,6 +34,7 @@ #include "core/io/resource_loader.h" #include "core/os/keyboard.h" #include "editor/editor_file_dialog.h" +#include "editor/editor_file_system.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" @@ -43,6 +44,7 @@ #include "scene/gui/center_container.h" #include "scene/gui/margin_container.h" #include "scene/gui/panel_container.h" +#include "scene/gui/separator.h" static void _draw_shadowed_line(Control *p_control, const Point2 &p_from, const Size2 &p_size, const Size2 &p_shadow_offset, Color p_color, Color p_shadow_color) { p_control->draw_line(p_from, p_from + p_size, p_color); diff --git a/editor/plugins/style_box_editor_plugin.cpp b/editor/plugins/style_box_editor_plugin.cpp index 16a6a48df9..afc54a2b83 100644 --- a/editor/plugins/style_box_editor_plugin.cpp +++ b/editor/plugins/style_box_editor_plugin.cpp @@ -31,6 +31,7 @@ #include "style_box_editor_plugin.h" #include "editor/editor_scale.h" +#include "scene/gui/texture_button.h" bool StyleBoxPreview::grid_preview_enabled = true; diff --git a/editor/plugins/style_box_editor_plugin.h b/editor/plugins/style_box_editor_plugin.h index a072745d8f..d5351d3f34 100644 --- a/editor/plugins/style_box_editor_plugin.h +++ b/editor/plugins/style_box_editor_plugin.h @@ -37,6 +37,8 @@ #include "scene/gui/texture_rect.h" #include "scene/resources/style_box.h" +class TextureButton; + class StyleBoxPreview : public VBoxContainer { GDCLASS(StyleBoxPreview, VBoxContainer); diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp index 03cff74bdb..baf5e363f8 100644 --- a/editor/plugins/text_editor.cpp +++ b/editor/plugins/text_editor.cpp @@ -33,6 +33,7 @@ #include "core/os/keyboard.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" +#include "scene/gui/menu_button.h" void TextEditor::add_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) { ERR_FAIL_COND(p_highlighter.is_null()); diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h index 486a0f2c23..9f2132bc0b 100644 --- a/editor/plugins/text_editor.h +++ b/editor/plugins/text_editor.h @@ -33,6 +33,8 @@ #include "script_editor_plugin.h" +#include "editor/code_editor.h" + class TextEditor : public ScriptEditorBase { GDCLASS(TextEditor, ScriptEditorBase); diff --git a/editor/plugins/texture_3d_editor_plugin.cpp b/editor/plugins/texture_3d_editor_plugin.cpp index 4b2f28658a..bdea12c2cb 100644 --- a/editor/plugins/texture_3d_editor_plugin.cpp +++ b/editor/plugins/texture_3d_editor_plugin.cpp @@ -30,6 +30,8 @@ #include "texture_3d_editor_plugin.h" +#include "scene/gui/label.h" + void Texture3DEditor::_texture_rect_draw() { texture_rect->draw_rect(Rect2(Point2(), texture_rect->get_size()), Color(1, 1, 1, 1)); } diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp index 4aed7a92a2..5783912c96 100644 --- a/editor/plugins/texture_editor_plugin.cpp +++ b/editor/plugins/texture_editor_plugin.cpp @@ -30,6 +30,8 @@ #include "texture_editor_plugin.h" #include "editor/editor_scale.h" +#include "scene/gui/label.h" +#include "scene/gui/texture_rect.h" TextureRect *TexturePreview::get_texture_display() { return texture_display; diff --git a/editor/plugins/texture_layered_editor_plugin.cpp b/editor/plugins/texture_layered_editor_plugin.cpp index b0a174c1bc..479e84682b 100644 --- a/editor/plugins/texture_layered_editor_plugin.cpp +++ b/editor/plugins/texture_layered_editor_plugin.cpp @@ -30,6 +30,8 @@ #include "texture_layered_editor_plugin.h" +#include "scene/gui/label.h" + void TextureLayeredEditor::gui_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index 2e84a4fac9..fdfa3f8d0a 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -38,7 +38,9 @@ #include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "scene/gui/check_box.h" +#include "scene/gui/option_button.h" #include "scene/gui/separator.h" +#include "scene/gui/spin_box.h" #include "scene/gui/view_panner.h" #include "scene/resources/texture.h" diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h index 310de19cc5..90a5b20e14 100644 --- a/editor/plugins/texture_region_editor_plugin.h +++ b/editor/plugins/texture_region_editor_plugin.h @@ -36,6 +36,7 @@ #include "editor/editor_plugin.h" #include "scene/2d/sprite_2d.h" #include "scene/3d/sprite_3d.h" +#include "scene/gui/dialogs.h" #include "scene/gui/nine_patch_rect.h" #include "scene/resources/style_box.h" #include "scene/resources/texture.h" diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index 5d02e4e437..135b218768 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -38,6 +38,8 @@ #include "editor/editor_undo_redo_manager.h" #include "editor/progress_dialog.h" #include "scene/gui/color_picker.h" +#include "scene/gui/panel_container.h" +#include "scene/gui/split_container.h" #include "scene/theme/theme_db.h" void ThemeItemImportTree::_update_items_tree() { diff --git a/editor/plugins/theme_editor_preview.cpp b/editor/plugins/theme_editor_preview.cpp index fdd8a80ad3..082b21bbe5 100644 --- a/editor/plugins/theme_editor_preview.cpp +++ b/editor/plugins/theme_editor_preview.cpp @@ -36,9 +36,12 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "scene/gui/button.h" +#include "scene/gui/check_box.h" #include "scene/gui/check_button.h" #include "scene/gui/color_picker.h" #include "scene/gui/progress_bar.h" +#include "scene/gui/text_edit.h" +#include "scene/gui/tree.h" #include "scene/resources/packed_scene.h" #include "scene/theme/theme_db.h" diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp index 44b8ff05d1..993f606f2f 100644 --- a/editor/plugins/tiles/tile_data_editors.cpp +++ b/editor/plugins/tiles/tile_data_editors.cpp @@ -38,8 +38,13 @@ #include "editor/editor_node.h" #include "editor/editor_properties.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" +#include "scene/gui/menu_button.h" +#include "scene/gui/option_button.h" +#include "scene/gui/separator.h" + #ifdef DEBUG_ENABLED #include "servers/navigation_server_3d.h" #endif // DEBUG_ENABLED @@ -851,6 +856,7 @@ GenericTilePolygonEditor::GenericTilePolygonEditor() { void TileDataDefaultEditor::_property_value_changed(StringName p_property, Variant p_value, StringName p_field) { ERR_FAIL_COND(!dummy_object); dummy_object->set(p_property, p_value); + emit_signal(SNAME("needs_redraw")); } Variant TileDataDefaultEditor::_get_painted_value() { diff --git a/editor/plugins/tiles/tile_data_editors.h b/editor/plugins/tiles/tile_data_editors.h index 98d337b4cf..e98e1d6701 100644 --- a/editor/plugins/tiles/tile_data_editors.h +++ b/editor/plugins/tiles/tile_data_editors.h @@ -39,6 +39,9 @@ #include "scene/gui/control.h" #include "scene/gui/label.h" +class MenuButton; +class EditorUndoRedoManager; + class TileDataEditor : public VBoxContainer { GDCLASS(TileDataEditor, VBoxContainer); diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp index eb7c93872e..e622a0817a 100644 --- a/editor/plugins/tiles/tile_map_editor.cpp +++ b/editor/plugins/tiles/tile_map_editor.cpp @@ -35,6 +35,7 @@ #include "editor/editor_node.h" #include "editor/editor_resource_preview.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "editor/plugins/canvas_item_editor_plugin.h" diff --git a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp index 50350de97e..7058b28e68 100644 --- a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp +++ b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp @@ -32,7 +32,9 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" +#include "scene/gui/separator.h" void TileProxiesManagerDialog::_right_clicked(int p_item, Vector2 p_local_mouse_pos, Object *p_item_list, MouseButton p_mouse_button_index) { if (p_mouse_button_index != MouseButton::RIGHT) { diff --git a/editor/plugins/tiles/tile_proxies_manager_dialog.h b/editor/plugins/tiles/tile_proxies_manager_dialog.h index d0f1933882..e2363eb809 100644 --- a/editor/plugins/tiles/tile_proxies_manager_dialog.h +++ b/editor/plugins/tiles/tile_proxies_manager_dialog.h @@ -36,6 +36,8 @@ #include "scene/gui/dialogs.h" #include "scene/gui/item_list.h" +class EditorUndoRedoManager; + class TileProxiesManagerDialog : public ConfirmationDialog { GDCLASS(TileProxiesManagerDialog, ConfirmationDialog); diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp index 8e69abd7ff..ae7570e161 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp @@ -35,10 +35,10 @@ #include "editor/editor_inspector.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "editor/progress_dialog.h" -#include "editor/editor_node.h" #include "scene/gui/box_container.h" #include "scene/gui/button.h" #include "scene/gui/control.h" @@ -152,7 +152,7 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_set(const StringName &p_na // ID and size related properties. if (tiles.size() == 1) { - const Vector2i &coords = tiles.front()->get().tile; + const Vector2i coords = tiles.front()->get().tile; const int &alternative = tiles.front()->get().alternative; if (alternative == 0) { @@ -543,11 +543,13 @@ void TileSetAtlasSourceEditor::_update_source_inspector() { void TileSetAtlasSourceEditor::_update_fix_selected_and_hovered_tiles() { // Fix selected. - for (RBSet<TileSelection>::Element *E = selection.front(); E; E = E->next()) { + for (RBSet<TileSelection>::Element *E = selection.front(); E;) { + RBSet<TileSelection>::Element *N = E->next(); TileSelection selected = E->get(); if (!tile_set_atlas_source->has_tile(selected.tile) || !tile_set_atlas_source->has_alternative_tile(selected.tile, selected.alternative)) { selection.erase(E); } + E = N; } // Fix hovered. diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.h b/editor/plugins/tiles/tile_set_atlas_source_editor.h index 8e217e359f..14e120e2a3 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.h +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.h @@ -37,7 +37,10 @@ #include "scene/gui/split_container.h" #include "scene/resources/tile_set.h" +class Popup; class TileSet; +class Tree; +class VSeparator; class TileSetAtlasSourceEditor : public HBoxContainer { GDCLASS(TileSetAtlasSourceEditor, HBoxContainer); diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp index dccff80512..b24c5059b0 100644 --- a/editor/plugins/tiles/tile_set_editor.cpp +++ b/editor/plugins/tiles/tile_set_editor.cpp @@ -36,6 +36,7 @@ #include "editor/editor_file_system.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "scene/gui/box_container.h" diff --git a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp index 3b711a568e..a14aad6652 100644 --- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp @@ -38,6 +38,7 @@ #include "editor/editor_undo_redo_manager.h" #include "scene/gui/item_list.h" +#include "scene/gui/split_container.h" #include "core/core_string_names.h" diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp index 4239e2c981..5d93f58f34 100644 --- a/editor/plugins/tiles/tiles_editor_plugin.cpp +++ b/editor/plugins/tiles/tiles_editor_plugin.cpp @@ -30,10 +30,13 @@ #include "tiles_editor_plugin.h" +#include "tile_set_editor.h" + #include "core/os/mutex.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "scene/2d/tile_map.h" @@ -43,8 +46,6 @@ #include "scene/gui/separator.h" #include "scene/resources/tile_set.h" -#include "tile_set_editor.h" - TilesEditorPlugin *TilesEditorPlugin::singleton = nullptr; void TilesEditorPlugin::_preview_frame_started() { diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp index 4fdfaed50e..86aa897c78 100644 --- a/editor/plugins/version_control_editor_plugin.cpp +++ b/editor/plugins/version_control_editor_plugin.cpp @@ -38,6 +38,7 @@ #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/filesystem_dock.h" +#include "editor/plugins/script_editor_plugin.h" #include "scene/gui/separator.h" #define CHECK_PLUGIN_INITIALIZED() \ diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index a51396d712..f32e0bdfa2 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -32,31 +32,31 @@ #include "core/config/project_settings.h" #include "core/core_string_names.h" -#include "core/input/input.h" #include "core/io/resource_loader.h" #include "core/math/math_defs.h" #include "core/os/keyboard.h" -#include "editor/editor_log.h" #include "editor/editor_node.h" #include "editor/editor_properties.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" +#include "editor/inspector_dock.h" #include "editor/plugins/curve_editor_plugin.h" #include "editor/plugins/shader_editor_plugin.h" -#include "scene/animation/animation_player.h" #include "scene/gui/button.h" +#include "scene/gui/check_box.h" #include "scene/gui/code_edit.h" #include "scene/gui/graph_edit.h" #include "scene/gui/menu_button.h" -#include "scene/gui/panel.h" +#include "scene/gui/option_button.h" #include "scene/gui/popup.h" #include "scene/gui/rich_text_label.h" +#include "scene/gui/separator.h" #include "scene/gui/tree.h" #include "scene/gui/view_panner.h" #include "scene/main/window.h" #include "scene/resources/visual_shader_nodes.h" #include "scene/resources/visual_shader_particle_nodes.h" -#include "scene/resources/visual_shader_sdf_nodes.h" #include "servers/display_server.h" #include "servers/rendering/shader_types.h" diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index e9d6257f81..8afad9f668 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -34,11 +34,17 @@ #include "editor/editor_plugin.h" #include "editor/editor_properties.h" #include "editor/plugins/editor_resource_conversion_plugin.h" +#include "scene/resources/syntax_highlighter.h" #include "scene/resources/visual_shader.h" +class CodeEdit; class CurveEditor; class GraphEdit; class GraphNode; +class MenuButton; +class PopupPanel; +class RichTextLabel; +class Tree; class VisualShaderEditor; diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 02d59921bf..249504b6e8 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -49,6 +49,7 @@ #include "editor/editor_vcs_interface.h" #include "main/main.h" #include "scene/gui/center_container.h" +#include "scene/gui/check_box.h" #include "scene/gui/line_edit.h" #include "scene/gui/margin_container.h" #include "scene/gui/panel_container.h" @@ -435,17 +436,17 @@ private: return; } - ProjectSettings *current = memnew(ProjectSettings); - - int err = current->setup(dir2, ""); + // Load project.godot as ConfigFile to set the new name. + ConfigFile cfg; + String project_godot = dir2.path_join("project.godot"); + Error err = cfg.load(project_godot); if (err != OK) { - set_message(vformat(TTR("Couldn't load project.godot in project path (error %d). It may be missing or corrupted."), err), MESSAGE_ERROR); + set_message(vformat(TTR("Couldn't load project at '%s' (error %d). It may be missing or corrupted."), project_godot, err), MESSAGE_ERROR); } else { - ProjectSettings::CustomMap edited_settings; - edited_settings["application/config/name"] = project_name->get_text().strip_edges(); - - if (current->save_custom(dir2.path_join("project.godot"), edited_settings, Vector<String>(), true) != OK) { - set_message(TTR("Couldn't edit project.godot in project path."), MESSAGE_ERROR); + cfg.set_value("application", "config/name", project_name->get_text().strip_edges()); + err = cfg.save(project_godot); + if (err != OK) { + set_message(vformat(TTR("Couldn't save project at '%s' (error %d)."), project_godot, err), MESSAGE_ERROR); } } @@ -693,18 +694,19 @@ public: default_files_container->hide(); get_ok_button()->set_disabled(false); - ProjectSettings *current = memnew(ProjectSettings); - - int err = current->setup(project_path->get_text(), ""); + // Fetch current name from project.godot to prefill the text input. + ConfigFile cfg; + String project_godot = project_path->get_text().path_join("project.godot"); + Error err = cfg.load(project_godot); if (err != OK) { - set_message(vformat(TTR("Couldn't load project.godot in project path (error %d). It may be missing or corrupted."), err), MESSAGE_ERROR); + set_message(vformat(TTR("Couldn't load project at '%s' (error %d). It may be missing or corrupted."), project_godot, err), MESSAGE_ERROR); status_rect->show(); msg->show(); get_ok_button()->set_disabled(true); - } else if (current->has_setting("application/config/name")) { - String proj = current->get("application/config/name"); - project_name->set_text(proj); - _text_changed(proj); + } else { + String cur_name = cfg.get_value("application", "config/name", ""); + project_name->set_text(cur_name); + _text_changed(cur_name); } project_name->call_deferred(SNAME("grab_focus")); @@ -1251,7 +1253,6 @@ void ProjectList::migrate_config() { if (FileAccess::exists(_config_path)) { return; } - print_line("Migrating legacy project list"); List<PropertyInfo> properties; EditorSettings::get_singleton()->get_property_list(&properties); @@ -1264,6 +1265,8 @@ void ProjectList::migrate_config() { } String path = EDITOR_GET(property_key); + print_line("Migrating legacy project '" + path + "'."); + String favoriteKey = "favorite_projects/" + property_key.get_slice("/", 1); bool favorite = EditorSettings::get_singleton()->has_setting(favoriteKey); add_project(path, favorite); diff --git a/editor/project_manager.h b/editor/project_manager.h index 7c05429dde..de4db2944f 100644 --- a/editor/project_manager.h +++ b/editor/project_manager.h @@ -38,6 +38,7 @@ #include "scene/gui/scroll_container.h" #include "scene/gui/tree.h" +class CheckBox; class ProjectDialog; class ProjectList; diff --git a/editor/register_editor_types.cpp b/editor/register_editor_types.cpp index d3097a694e..f301ff5c6b 100644 --- a/editor/register_editor_types.cpp +++ b/editor/register_editor_types.cpp @@ -30,8 +30,6 @@ #include "register_editor_types.h" -#include "core/extension/native_extension_manager.h" - #include "editor/animation_track_editor.h" #include "editor/debugger/debug_adapter/debug_adapter_server.h" #include "editor/editor_command_palette.h" @@ -43,6 +41,7 @@ #include "editor/editor_resource_picker.h" #include "editor/editor_resource_preview.h" #include "editor/editor_run_script.h" +#include "editor/editor_settings.h" #include "editor/editor_translation_parser.h" #include "editor/editor_undo_redo_manager.h" #include "editor/filesystem_dock.h" diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp index 74c123d942..40683e2938 100644 --- a/editor/rename_dialog.cpp +++ b/editor/rename_dialog.cpp @@ -42,6 +42,7 @@ #include "modules/regex/regex.h" #include "plugins/script_editor_plugin.h" #include "scene/gui/control.h" +#include "scene/gui/grid_container.h" #include "scene/gui/label.h" #include "scene/gui/separator.h" #include "scene/gui/tab_container.h" diff --git a/editor/reparent_dialog.cpp b/editor/reparent_dialog.cpp index 75098b25b1..37712d4197 100644 --- a/editor/reparent_dialog.cpp +++ b/editor/reparent_dialog.cpp @@ -33,6 +33,7 @@ #include "core/string/print_string.h" #include "scene/gui/box_container.h" #include "scene/gui/label.h" +#include "scene/gui/tree.h" void ReparentDialog::_notification(int p_what) { switch (p_what) { diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 9c3ef4cecc..0ebd8e610a 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -41,14 +41,17 @@ #include "editor/editor_file_dialog.h" #include "editor/editor_node.h" #include "editor/editor_paths.h" +#include "editor/editor_quick_open.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" +#include "editor/inspector_dock.h" #include "editor/multi_node_edit.h" #include "editor/plugins/animation_player_editor_plugin.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "editor/plugins/node_3d_editor_plugin.h" #include "editor/plugins/script_editor_plugin.h" +#include "editor/reparent_dialog.h" #include "editor/shader_create_dialog.h" #include "scene/main/window.h" #include "scene/property_utils.h" @@ -1153,11 +1156,13 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { if (TOOL_CREATE_FAVORITE == p_tool) { String name = selected_favorite_root.get_slicec(' ', 0); if (ScriptServer::is_global_class(name)) { - new_node = Object::cast_to<Node>(ClassDB::instantiate(ScriptServer::get_global_class_native_base(name))); Ref<Script> scr = ResourceLoader::load(ScriptServer::get_global_class_path(name), "Script"); - if (new_node && scr.is_valid()) { - new_node->set_script(scr); - new_node->set_name(name); + if (scr.is_valid()) { + new_node = Object::cast_to<Node>(ClassDB::instantiate(scr->get_instance_base_type())); + if (new_node) { + new_node->set_script(scr); + new_node->set_name(name); + } } } else { new_node = Object::cast_to<Node>(ClassDB::instantiate(selected_favorite_root)); diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h index 6ec9d31ca8..ac368e1aab 100644 --- a/editor/scene_tree_dock.h +++ b/editor/scene_tree_dock.h @@ -31,21 +31,17 @@ #ifndef SCENE_TREE_DOCK_H #define SCENE_TREE_DOCK_H -#include "editor/create_dialog.h" +#include "scene_tree_editor.h" + #include "editor/editor_data.h" -#include "editor/editor_quick_open.h" -#include "editor/groups_editor.h" -#include "editor/reparent_dialog.h" #include "editor/script_create_dialog.h" -#include "scene/animation/animation_player.h" #include "scene/gui/box_container.h" -#include "scene/gui/button.h" -#include "scene/gui/control.h" -#include "scene/gui/label.h" -#include "scene/gui/popup_menu.h" -#include "scene/gui/tree.h" -#include "scene_tree_editor.h" +#include "scene/resources/animation.h" +class EditorQuickOpen; +class MenuButton; +class ReparentDialog; +class ShaderCreateDialog; class TextureRect; #include "modules/modules_enabled.gen.h" // For regex. @@ -53,8 +49,6 @@ class TextureRect; class RenameDialog; #endif // MODULE_REGEX_ENABLED -class ShaderCreateDialog; - class SceneTreeDock : public VBoxContainer { GDCLASS(SceneTreeDock, VBoxContainer); diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index 46d3502a24..092ef30678 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -32,10 +32,10 @@ #include "core/config/project_settings.h" #include "core/object/message_queue.h" -#include "core/string/print_string.h" #include "editor/editor_file_system.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "editor/node_dock.h" #include "editor/plugins/animation_player_editor_plugin.h" diff --git a/editor/scene_tree_editor.h b/editor/scene_tree_editor.h index 33ef5dbcb3..c1afcf0f45 100644 --- a/editor/scene_tree_editor.h +++ b/editor/scene_tree_editor.h @@ -32,8 +32,6 @@ #define SCENE_TREE_EDITOR_H #include "editor/editor_data.h" -#include "editor/editor_settings.h" -#include "scene/gui/button.h" #include "scene/gui/dialogs.h" #include "scene/gui/tree.h" diff --git a/main/main.cpp b/main/main.cpp index 460c73ceee..2d0843a331 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -318,7 +318,7 @@ void Main::print_help(const char *p_binary) { OS::get_singleton()->print("\n"); OS::get_singleton()->print("Run options:\n"); - OS::get_singleton()->print(" -- Separator for user-provided arguments. Following arguments are not used by the engine, but can be read from `OS.get_cmdline_user_args()`.\n"); + OS::get_singleton()->print(" --, ++ Separator for user-provided arguments. Following arguments are not used by the engine, but can be read from `OS.get_cmdline_user_args()`.\n"); #ifdef TOOLS_ENABLED OS::get_singleton()->print(" -e, --editor Start the editor instead of running the scene.\n"); OS::get_singleton()->print(" -p, --project-manager Start the project manager, even if a project is auto-detected.\n"); @@ -1288,7 +1288,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph goto error; } - } else if (I->get() == "--") { + } else if (I->get() == "--" || I->get() == "++") { adding_user_args = true; } else { main_args.push_back(I->get()); @@ -1540,6 +1540,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph if (rendering_driver.is_empty() && rendering_method.is_empty() && project_manager) { rendering_driver = "opengl3"; rendering_method = "gl_compatibility"; + default_renderer_mobile = "gl_compatibility"; } #endif if (renderer_hints.is_empty()) { @@ -2660,7 +2661,11 @@ bool Main::start() { if (!editor && !ClassDB::class_exists(main_loop_type) && ScriptServer::is_global_class(main_loop_type)) { String script_path = ScriptServer::get_global_class_path(main_loop_type); Ref<Script> script_res = ResourceLoader::load(script_path); - StringName script_base = ScriptServer::get_global_class_native_base(main_loop_type); + if (script_res.is_null()) { + OS::get_singleton()->alert("Error: Could not load MainLoop script type: " + main_loop_type); + ERR_FAIL_V_MSG(false, vformat("Could not load global class %s.", main_loop_type)); + } + StringName script_base = script_res->get_instance_base_type(); Object *obj = ClassDB::instantiate(script_base); MainLoop *script_loop = Object::cast_to<MainLoop>(obj); if (!script_loop) { diff --git a/misc/dist/html/full-size.html b/misc/dist/html/full-size.html index 6ae3e5cc73..6710cb1533 100644 --- a/misc/dist/html/full-size.html +++ b/misc/dist/html/full-size.html @@ -215,7 +215,7 @@ const engine = new Engine(GODOT_CONFIG); const missing = Engine.getMissingFeatures(); if (missing.length !== 0) { - const missingMsg = 'Warning!\nThe following features required to run Godot projects on the Web are missing:\n'; + const missingMsg = 'Error\nThe following features required to run Godot projects on the Web are missing:\n'; displayFailureNotice(missingMsg + missing.join('\n')); } else { setStatusMode('indeterminate'); diff --git a/misc/dist/icon_console.svg b/misc/dist/icon_console.svg new file mode 100644 index 0000000000..d486482f3b --- /dev/null +++ b/misc/dist/icon_console.svg @@ -0,0 +1,120 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + width="1024" + height="1024" + id="svg3030" + version="1.1" + inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)" + sodipodi:docname="icon_console.svg" + inkscape:export-filename="/home/akien/Projects/godot/godot.git/icon.png" + inkscape:export-xdpi="24" + inkscape:export-ydpi="24" + xml:space="preserve" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"><defs + id="defs3032" /><sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="0.28259086" + inkscape:cx="955.44491" + inkscape:cy="1380.0871" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:window-width="3840" + inkscape:window-height="2054" + inkscape:window-x="-11" + inkscape:window-y="594" + inkscape:window-maximized="1" + inkscape:document-rotation="0" + inkscape:showpageshadow="0" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1" /><metadata + id="metadata3035"><rdf:RDF><cc:Work + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(0,-98.519719)"><g + inkscape:label="Layer 1" + id="layer1-6" + transform="translate(1.7750003e-7,-2.4372979)"><g + id="g78-0" + transform="matrix(4.162611,0,0,-4.162611,919.24059,771.67186)" + style="stroke-width:0.320312"><path + d="m 0,0 c 0,0 -0.325,1.994 -0.515,1.976 l -36.182,-3.491 c -2.879,-0.278 -5.115,-2.574 -5.317,-5.459 l -0.994,-14.247 -27.992,-1.997 -1.904,12.912 c -0.424,2.872 -2.932,5.037 -5.835,5.037 h -38.188 c -2.902,0 -5.41,-2.165 -5.834,-5.037 l -1.905,-12.912 -27.992,1.997 -0.994,14.247 c -0.202,2.886 -2.438,5.182 -5.317,5.46 l -36.2,3.49 c -0.187,0.018 -0.324,-1.978 -0.511,-1.978 l -0.049,-7.83 30.658,-4.944 1.004,-14.374 c 0.203,-2.91 2.551,-5.263 5.463,-5.472 l 38.551,-2.75 c 0.146,-0.01 0.29,-0.016 0.434,-0.016 2.897,0 5.401,2.166 5.825,5.038 l 1.959,13.286 h 28.005 l 1.959,-13.286 c 0.423,-2.871 2.93,-5.037 5.831,-5.037 0.142,0 0.284,0.005 0.423,0.015 l 38.556,2.75 c 2.911,0.209 5.26,2.562 5.463,5.472 l 1.003,14.374 30.645,4.966 z" + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.320312" + id="path80-3" + inkscape:connector-curvature="0" /></g><g + id="g82-3-2" + transform="matrix(4.162611,0,0,-4.162611,104.69892,525.90697)" + style="stroke-width:0.320312"><path + d="m 0,0 v -47.514 -6.035 -5.492 c 0.108,-0.001 0.216,-0.005 0.323,-0.015 l 36.196,-3.49 c 1.896,-0.183 3.382,-1.709 3.514,-3.609 l 1.116,-15.978 31.574,-2.253 2.175,14.747 c 0.282,1.912 1.922,3.329 3.856,3.329 h 38.188 c 1.933,0 3.573,-1.417 3.855,-3.329 l 2.175,-14.747 31.575,2.253 1.115,15.978 c 0.133,1.9 1.618,3.425 3.514,3.609 l 36.182,3.49 c 0.107,0.01 0.214,0.014 0.322,0.015 v 4.711 l 0.015,0.005 V 0 c 5.09692,6.4164715 9.92323,13.494208 13.621,19.449 -5.651,9.62 -12.575,18.217 -19.976,26.182 -6.864,-3.455 -13.531,-7.369 -19.828,-11.534 -3.151,3.132 -6.7,5.694 -10.186,8.372 -3.425,2.751 -7.285,4.768 -10.946,7.118 1.09,8.117 1.629,16.108 1.846,24.448 -9.446,4.754 -19.519,7.906 -29.708,10.17 -4.068,-6.837 -7.788,-14.241 -11.028,-21.479 -3.842,0.642 -7.702,0.88 -11.567,0.926 v 0.006 c -0.027,0 -0.052,-0.006 -0.075,-0.006 -0.024,0 -0.049,0.006 -0.073,0.006 V 63.652 C 93.903,63.606 90.046,63.368 86.203,62.726 82.965,69.964 79.247,77.368 75.173,84.205 64.989,81.941 54.915,78.789 45.47,74.035 45.686,65.695 46.225,57.704 47.318,49.587 43.65,47.237 39.795,45.22 36.369,42.469 32.888,39.791 29.333,37.229 26.181,34.097 19.884,38.262 13.219,42.176 6.353,45.631 -1.048,37.666 -7.968,29.069 -13.621,19.449 -9.1783421,12.475308 -4.4130298,5.4661124 0,0 Z" + style="fill:#478cbf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.320312" + id="path84-6-6" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccccccccsssscccccccccccccccccccsccccccccccc" /></g><g + id="g86-7-9" + transform="matrix(4.162611,0,0,-4.162611,784.07144,817.24284)" + style="stroke-width:0.320312"><path + d="m 0,0 -1.121,-16.063 c -0.135,-1.936 -1.675,-3.477 -3.611,-3.616 l -38.555,-2.751 c -0.094,-0.007 -0.188,-0.01 -0.281,-0.01 -1.916,0 -3.569,1.406 -3.852,3.33 l -2.211,14.994 H -81.09 l -2.211,-14.994 c -0.297,-2.018 -2.101,-3.469 -4.133,-3.32 l -38.555,2.751 c -1.936,0.139 -3.476,1.68 -3.611,3.616 L -130.721,0 -163.268,3.138 c 0.015,-3.498 0.06,-7.33 0.06,-8.093 0,-34.374 43.605,-50.896 97.781,-51.086 h 0.066 0.067 c 54.176,0.19 97.766,16.712 97.766,51.086 0,0.777 0.047,4.593 0.063,8.093 z" + style="fill:#478cbf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.320312" + id="path88-5-4" + inkscape:connector-curvature="0" /></g><g + id="g90-3-1" + transform="matrix(4.162611,0,0,-4.162611,389.21484,625.67104)" + style="stroke-width:0.320312"><path + d="m 0,0 c 0,-12.052 -9.765,-21.815 -21.813,-21.815 -12.042,0 -21.81,9.763 -21.81,21.815 0,12.044 9.768,21.802 21.81,21.802 C -9.765,21.802 0,12.044 0,0" + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.320312" + id="path92-5-3" + inkscape:connector-curvature="0" /></g><g + id="g94-6-7" + transform="matrix(4.162611,0,0,-4.162611,367.36686,631.05679)" + style="stroke-width:0.320312"><path + d="m 0,0 c 0,-7.994 -6.479,-14.473 -14.479,-14.473 -7.996,0 -14.479,6.479 -14.479,14.473 0,7.994 6.483,14.479 14.479,14.479 C -6.479,14.479 0,7.994 0,0" + style="fill:#414042;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.320312" + id="path96-2-8" + inkscape:connector-curvature="0" /></g><g + id="g98-9-8" + transform="matrix(4.162611,0,0,-4.162611,511.99336,724.73954)" + style="stroke-width:0.320312"><path + d="m 0,0 c -3.878,0 -7.021,2.858 -7.021,6.381 v 20.081 c 0,3.52 3.143,6.381 7.021,6.381 3.878,0 7.028,-2.861 7.028,-6.381 V 6.381 C 7.028,2.858 3.878,0 0,0" + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.320312" + id="path100-1-3" + inkscape:connector-curvature="0" /></g><g + id="g102-2-8" + transform="matrix(4.162611,0,0,-4.162611,634.78706,625.67104)" + style="stroke-width:0.320312"><path + d="m 0,0 c 0,-12.052 9.765,-21.815 21.815,-21.815 12.041,0 21.808,9.763 21.808,21.815 0,12.044 -9.767,21.802 -21.808,21.802 C 9.765,21.802 0,12.044 0,0" + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.320312" + id="path104-7-1" + inkscape:connector-curvature="0" /></g><g + id="g106-0-5" + transform="matrix(4.162611,0,0,-4.162611,656.64056,631.05679)" + style="stroke-width:0.320312"><path + d="m 0,0 c 0,-7.994 6.477,-14.473 14.471,-14.473 8.002,0 14.479,6.479 14.479,14.473 0,7.994 -6.477,14.479 -14.479,14.479 C 6.477,14.479 0,7.994 0,0" + style="fill:#414042;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.320312" + id="path108-9-3" + inkscape:connector-curvature="0" /></g></g><path + id="path581" + style="fill:#414042;fill-opacity:1;stroke-width:20;stroke:#ffffff;stroke-opacity:1;stroke-dasharray:none" + d="m 559.63672,752.49433 c -9.61602,0 -17.48438,7.86834 -17.48438,17.48437 v 295.125 c 0,9.6161 7.86836,17.4844 17.48438,17.4844 h 384.64062 c 9.61603,0 17.48438,-7.8683 17.48438,-17.4844 v -295.125 c 0,-9.61603 -7.86835,-17.48437 -17.48438,-17.48437 z" + sodipodi:nodetypes="sccssccss" /><path + id="path10" + style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:10.7638" + d="m 604.19435,828.87215 -19.37462,19.37464 c -5.38188,4.3055 -5.38188,11.84096 0,17.22283 l 66.73589,66.73469 -66.73589,66.73589 c -5.38188,5.3819 -5.38188,12.9161 0,17.2216 l 19.37462,19.3747 c 5.38188,5.3818 12.91613,5.3818 17.22163,0 l 75.33586,-75.33592 19.38547,-19.38425 c 5.46258,-5.17192 5.07049,-13.02396 0,-17.22284 l -19.37462,-19.37462 -75.34671,-75.34672 c -4.96088,-4.18442 -12.91229,-4.15049 -17.22163,0 z" + sodipodi:nodetypes="ccccscsccccccc" /><path + d="M 917.91967,991.872 H 760.9701 c -5.88562,0 -9.80935,3.9237 -9.80935,9.8093 v 29.4281 c 0,5.8856 3.92373,9.8093 9.80935,9.8093 h 156.94957 c 5.88561,0 9.80934,-3.9237 9.80934,-9.8093 v -29.4281 c 0,-5.8856 -3.92373,-9.8093 -9.80934,-9.8093 z" + fill="url(#paint5_linear)" + id="path25" + style="fill:#ffffff;fill-opacity:1;stroke-width:9.80938" /></g></svg> diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index a6840b54b8..95e577c140 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -494,8 +494,8 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type result = ref->get_parser()->head->get_datatype(); } else { result.kind = GDScriptParser::DataType::SCRIPT; - result.native_type = ScriptServer::get_global_class_native_base(first); result.script_type = ResourceLoader::load(path, "Script"); + result.native_type = result.script_type->get_instance_base_type(); result.script_path = path; result.is_constant = true; result.is_meta_type = false; @@ -2733,21 +2733,13 @@ GDScriptParser::DataType GDScriptAnalyzer::make_global_class_meta_type(const Str return type; } - type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; - type.kind = GDScriptParser::DataType::CLASS; - type.builtin_type = Variant::OBJECT; - type.native_type = ScriptServer::get_global_class_native_base(p_class_name); - type.class_type = ref->get_parser()->head; - type.script_path = ref->get_parser()->script_path; - type.is_constant = true; - type.is_meta_type = true; - return type; + return ref->get_parser()->head->get_datatype(); } else { type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; type.kind = GDScriptParser::DataType::SCRIPT; type.builtin_type = Variant::OBJECT; - type.native_type = ScriptServer::get_global_class_native_base(p_class_name); type.script_type = ResourceLoader::load(path, "Script"); + type.native_type = type.script_type->get_instance_base_type(); type.script_path = path; type.is_constant = true; type.is_meta_type = true; diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp index 2e7263b652..021504f242 100644 --- a/modules/gdscript/gdscript_cache.cpp +++ b/modules/gdscript/gdscript_cache.cpp @@ -260,7 +260,7 @@ Ref<GDScript> GDScriptCache::get_full_script(const String &p_path, Error &r_erro Ref<GDScript> script; r_error = OK; if (singleton->full_gdscript_cache.has(p_path)) { - script = Ref<GDScript>(singleton->full_gdscript_cache[p_path]); + script = singleton->full_gdscript_cache[p_path]; if (!p_update_from_disk) { return script; } @@ -360,7 +360,6 @@ Ref<PackedScene> GDScriptCache::get_packed_scene(const String &p_path, Error &r_ singleton->packed_scene_cache[p_path] = scene; singleton->packed_scene_dependencies[p_path].insert(p_owner); - scene->recreate_state(); scene->reload_from_file(); return scene; } diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index f0ceb42f89..103eb60da9 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -2284,7 +2284,7 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri _set_error(vformat(R"(Could not find class "%s" in "%s".)", base->fully_qualified_name, base->path), nullptr); return ERR_COMPILATION_FAILED; } - ERR_FAIL_COND_V(!base->is_valid(), ERR_BUG); + ERR_FAIL_COND_V(!base->is_valid() && !base->reloading, ERR_BUG); } p_script->base = base; diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 7628bffd22..c02ee99a86 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -3265,15 +3265,6 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co } } - // Need special checks for assert and preload as they are technically - // keywords, so are not registered in GDScriptUtilityFunctions. - if (GDScriptUtilityFunctions::function_exists(p_symbol) || "assert" == p_symbol || "preload" == p_symbol) { - r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_METHOD; - r_result.class_name = "@GDScript"; - r_result.class_member = p_symbol; - return OK; - } - if ("PI" == p_symbol || "TAU" == p_symbol || "INF" == p_symbol || "NAN" == p_symbol) { r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT; r_result.class_name = "@GDScript"; @@ -3283,11 +3274,24 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co GDScriptParser parser; parser.parse(p_code, p_path, true); - GDScriptAnalyzer analyzer(&parser); - analyzer.analyze(); GDScriptParser::CompletionContext context = parser.get_completion_context(); + // Allows class functions with the names like built-ins to be handled properly. + if (context.type != GDScriptParser::COMPLETION_ATTRIBUTE) { + // Need special checks for assert and preload as they are technically + // keywords, so are not registered in GDScriptUtilityFunctions. + if (GDScriptUtilityFunctions::function_exists(p_symbol) || "assert" == p_symbol || "preload" == p_symbol) { + r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_METHOD; + r_result.class_name = "@GDScript"; + r_result.class_member = p_symbol; + return OK; + } + } + + GDScriptAnalyzer analyzer(&parser); + analyzer.analyze(); + if (context.current_class && context.current_class->extends.size() > 0) { bool success = false; ClassDB::get_integer_constant(context.current_class->extends[0], p_symbol, &success); diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 7074520a34..f8fe015c6b 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -3785,15 +3785,14 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node } break; case GDScriptParser::DataType::CLASS: - // Can assume type is a global GDScript class. if (ClassDB::is_parent_class(export_type.native_type, SNAME("Resource"))) { variable->export_info.type = Variant::OBJECT; variable->export_info.hint = PROPERTY_HINT_RESOURCE_TYPE; - variable->export_info.hint_string = export_type.class_type->identifier->name; + variable->export_info.hint_string = export_type.to_string(); } else if (ClassDB::is_parent_class(export_type.native_type, SNAME("Node"))) { variable->export_info.type = Variant::OBJECT; variable->export_info.hint = PROPERTY_HINT_NODE_TYPE; - variable->export_info.hint_string = export_type.class_type->identifier->name; + variable->export_info.hint_string = export_type.to_string(); } else { push_error(R"(Export type can only be built-in, a resource, a node or an enum.)", variable); return false; @@ -3802,16 +3801,19 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node break; case GDScriptParser::DataType::SCRIPT: { StringName class_name; - if (export_type.script_type != nullptr && export_type.script_type.is_valid()) { + StringName native_base; + if (export_type.script_type.is_valid()) { class_name = export_type.script_type->get_language()->get_global_class_name(export_type.script_type->get_path()); + native_base = export_type.script_type->get_instance_base_type(); } if (class_name == StringName()) { Ref<Script> script = ResourceLoader::load(export_type.script_path, SNAME("Script")); if (script.is_valid()) { class_name = script->get_language()->get_global_class_name(export_type.script_path); + native_base = script->get_instance_base_type(); } } - if (class_name != StringName() && ClassDB::is_parent_class(ScriptServer::get_global_class_native_base(class_name), SNAME("Resource"))) { + if (class_name != StringName() && native_base != StringName() && ClassDB::is_parent_class(native_base, SNAME("Resource"))) { variable->export_info.type = Variant::OBJECT; variable->export_info.hint = PROPERTY_HINT_RESOURCE_TYPE; variable->export_info.hint_string = class_name; diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp index 39f4c976a4..551973140d 100644 --- a/modules/gdscript/language_server/gdscript_language_protocol.cpp +++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp @@ -32,6 +32,7 @@ #include "core/config/project_settings.h" #include "editor/doc_tools.h" +#include "editor/editor_help.h" #include "editor/editor_log.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" diff --git a/modules/gltf/doc_classes/GLTFDocument.xml b/modules/gltf/doc_classes/GLTFDocument.xml index 588015de62..f313f4b28f 100644 --- a/modules/gltf/doc_classes/GLTFDocument.xml +++ b/modules/gltf/doc_classes/GLTFDocument.xml @@ -14,7 +14,6 @@ <param index="1" name="base_path" type="String" /> <param index="2" name="state" type="GLTFState" /> <param index="3" name="flags" type="int" default="0" /> - <param index="4" name="bake_fps" type="int" default="30" /> <description> Takes a [PackedByteArray] defining a gLTF and returns a [GLTFState] object through the [param state] parameter. [b]Note:[/b] The [param base_path] tells [method append_from_buffer] where to find dependencies and can be empty. @@ -25,8 +24,7 @@ <param index="0" name="path" type="String" /> <param index="1" name="state" type="GLTFState" /> <param index="2" name="flags" type="int" default="0" /> - <param index="3" name="bake_fps" type="int" default="30" /> - <param index="4" name="base_path" type="String" default="""" /> + <param index="3" name="base_path" type="String" default="""" /> <description> Takes a path to a gLTF file and returns a [GLTFState] object through the [param state] parameter. [b]Note:[/b] The [param base_path] tells [method append_from_file] where to find dependencies and can be empty. @@ -37,7 +35,6 @@ <param index="0" name="node" type="Node" /> <param index="1" name="state" type="GLTFState" /> <param index="2" name="flags" type="int" default="0" /> - <param index="3" name="bake_fps" type="int" default="30" /> <description> Takes a Godot Engine scene node and returns a [GLTFState] object through the [param state] parameter. </description> @@ -52,7 +49,8 @@ <method name="generate_scene"> <return type="Node" /> <param index="0" name="state" type="GLTFState" /> - <param index="1" name="bake_fps" type="int" default="30" /> + <param index="1" name="bake_fps" type="float" default="30" /> + <param index="2" name="trimming" type="bool" default="false" /> <description> Takes a [GLTFState] object through the [param state] parameter and returns a Godot Engine scene node. </description> diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp index 95db1c0965..0c0b134bd1 100644 --- a/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp +++ b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp @@ -85,7 +85,7 @@ void SceneExporterGLTFPlugin::_gltf2_dialog_action(String p_file) { state.instantiate(); int32_t flags = 0; flags |= EditorSceneFormatImporter::IMPORT_USE_NAMED_SKIN_BINDS; - Error err = doc->append_from_scene(root, state, flags, 30.0f); + Error err = doc->append_from_scene(root, state, flags); if (err != OK) { ERR_PRINT(vformat("glTF2 save scene error %s.", itos(err))); } diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp index 20c9508474..7007ea5d13 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.cpp +++ b/modules/gltf/editor/editor_scene_importer_blend.cpp @@ -41,6 +41,7 @@ #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "main/main.h" +#include "scene/gui/line_edit.h" #include "scene/main/node.h" #include "scene/resources/animation.h" @@ -58,7 +59,7 @@ void EditorSceneFormatImporterBlend::get_extensions(List<String> *r_extensions) } Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_t p_flags, - const HashMap<StringName, Variant> &p_options, int p_bake_fps, + const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err) { // Get global paths for source and sink. @@ -227,14 +228,14 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_ if (p_options.has(SNAME("blender/materials/unpack_enabled")) && p_options[SNAME("blender/materials/unpack_enabled")]) { base_dir = sink.get_base_dir(); } - Error err = gltf->append_from_file(sink.get_basename() + ".gltf", state, p_flags, p_bake_fps, base_dir); + Error err = gltf->append_from_file(sink.get_basename() + ".gltf", state, p_flags, base_dir); if (err != OK) { if (r_err) { *r_err = FAILED; } return nullptr; } - return gltf->generate_scene(state, p_bake_fps); + return gltf->generate_scene(state, (float)p_options["animation/fps"], (bool)p_options["animation/trimming"]); } Variant EditorSceneFormatImporterBlend::get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option, diff --git a/modules/gltf/editor/editor_scene_importer_blend.h b/modules/gltf/editor/editor_scene_importer_blend.h index a1485ff82e..fe687f19fc 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.h +++ b/modules/gltf/editor/editor_scene_importer_blend.h @@ -66,7 +66,7 @@ public: virtual uint32_t get_import_flags() const override; virtual void get_extensions(List<String> *r_extensions) const override; virtual Node *import_scene(const String &p_path, uint32_t p_flags, - const HashMap<StringName, Variant> &p_options, int p_bake_fps, + const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err = nullptr) override; virtual void get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options) override; diff --git a/modules/gltf/editor/editor_scene_importer_fbx.cpp b/modules/gltf/editor/editor_scene_importer_fbx.cpp index 017a44cccf..14f2117413 100644 --- a/modules/gltf/editor/editor_scene_importer_fbx.cpp +++ b/modules/gltf/editor/editor_scene_importer_fbx.cpp @@ -49,7 +49,7 @@ void EditorSceneFormatImporterFBX::get_extensions(List<String> *r_extensions) co } Node *EditorSceneFormatImporterFBX::import_scene(const String &p_path, uint32_t p_flags, - const HashMap<StringName, Variant> &p_options, int p_bake_fps, + const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err) { // Get global paths for source and sink. @@ -95,14 +95,14 @@ Node *EditorSceneFormatImporterFBX::import_scene(const String &p_path, uint32_t Ref<GLTFState> state; state.instantiate(); print_verbose(vformat("glTF path: %s", sink)); - Error err = gltf->append_from_file(sink, state, p_flags, p_bake_fps); + Error err = gltf->append_from_file(sink, state, p_flags); if (err != OK) { if (r_err) { *r_err = FAILED; } return nullptr; } - return gltf->generate_scene(state, p_bake_fps); + return gltf->generate_scene(state, (float)p_options["animation/fps"], (bool)p_options["animation/trimming"]); } Variant EditorSceneFormatImporterFBX::get_option_visibility(const String &p_path, bool p_for_animation, diff --git a/modules/gltf/editor/editor_scene_importer_fbx.h b/modules/gltf/editor/editor_scene_importer_fbx.h index b0039b1c8f..6bf9f3e033 100644 --- a/modules/gltf/editor/editor_scene_importer_fbx.h +++ b/modules/gltf/editor/editor_scene_importer_fbx.h @@ -45,7 +45,7 @@ public: virtual uint32_t get_import_flags() const override; virtual void get_extensions(List<String> *r_extensions) const override; virtual Node *import_scene(const String &p_path, uint32_t p_flags, - const HashMap<StringName, Variant> &p_options, int p_bake_fps, + const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err = nullptr) override; virtual void get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options) override; diff --git a/modules/gltf/editor/editor_scene_importer_gltf.cpp b/modules/gltf/editor/editor_scene_importer_gltf.cpp index 161808aade..3cf49a3046 100644 --- a/modules/gltf/editor/editor_scene_importer_gltf.cpp +++ b/modules/gltf/editor/editor_scene_importer_gltf.cpp @@ -47,13 +47,13 @@ void EditorSceneFormatImporterGLTF::get_extensions(List<String> *r_extensions) c } Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path, uint32_t p_flags, - const HashMap<StringName, Variant> &p_options, int p_bake_fps, + const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err) { Ref<GLTFDocument> doc; doc.instantiate(); Ref<GLTFState> state; state.instantiate(); - Error err = doc->append_from_file(p_path, state, p_flags, p_bake_fps); + Error err = doc->append_from_file(p_path, state, p_flags); if (err != OK) { if (r_err) { *r_err = err; @@ -63,7 +63,7 @@ Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path, uint32_t if (p_options.has("animation/import")) { state->set_create_animations(bool(p_options["animation/import"])); } - return doc->generate_scene(state, p_bake_fps); + return doc->generate_scene(state, (float)p_options["animation/fps"], (bool)p_options["animation/trimming"]); } #endif // TOOLS_ENABLED diff --git a/modules/gltf/editor/editor_scene_importer_gltf.h b/modules/gltf/editor/editor_scene_importer_gltf.h index edca038532..c0582b26c1 100644 --- a/modules/gltf/editor/editor_scene_importer_gltf.h +++ b/modules/gltf/editor/editor_scene_importer_gltf.h @@ -45,7 +45,7 @@ public: virtual uint32_t get_import_flags() const override; virtual void get_extensions(List<String> *r_extensions) const override; virtual Node *import_scene(const String &p_path, uint32_t p_flags, - const HashMap<StringName, Variant> &p_options, int p_bake_fps, + const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err = nullptr) override; }; diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index eb8f7e5ebc..735e35ac1e 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -5860,7 +5860,7 @@ T GLTFDocument::_interpolate_track(const Vector<real_t> &p_times, const Vector<T ERR_FAIL_V(p_values[0]); } -void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, const GLTFAnimationIndex index, const int bake_fps) { +void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, const GLTFAnimationIndex index, const float bake_fps, const bool trimming) { Ref<GLTFAnimation> anim = state->animations[index]; String anim_name = anim->get_name(); @@ -5877,7 +5877,8 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, animation->set_loop_mode(Animation::LOOP_LINEAR); } - float length = 0.0; + double anim_start = trimming ? INFINITY : 0.0; + double anim_end = 0.0; for (const KeyValue<int, GLTFAnimation::Track> &track_i : anim->get_tracks()) { const GLTFAnimation::Track &track = track_i.value; @@ -5907,19 +5908,40 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, transform_node_path = node_path; } - for (int i = 0; i < track.rotation_track.times.size(); i++) { - length = MAX(length, track.rotation_track.times[i]); - } - for (int i = 0; i < track.position_track.times.size(); i++) { - length = MAX(length, track.position_track.times[i]); - } - for (int i = 0; i < track.scale_track.times.size(); i++) { - length = MAX(length, track.scale_track.times[i]); - } - - for (int i = 0; i < track.weight_tracks.size(); i++) { - for (int j = 0; j < track.weight_tracks[i].times.size(); j++) { - length = MAX(length, track.weight_tracks[i].times[j]); + if (trimming) { + for (int i = 0; i < track.rotation_track.times.size(); i++) { + anim_start = MIN(anim_start, track.rotation_track.times[i]); + anim_end = MAX(anim_end, track.rotation_track.times[i]); + } + for (int i = 0; i < track.position_track.times.size(); i++) { + anim_start = MIN(anim_start, track.position_track.times[i]); + anim_end = MAX(anim_end, track.position_track.times[i]); + } + for (int i = 0; i < track.scale_track.times.size(); i++) { + anim_start = MIN(anim_start, track.scale_track.times[i]); + anim_end = MAX(anim_end, track.scale_track.times[i]); + } + for (int i = 0; i < track.weight_tracks.size(); i++) { + for (int j = 0; j < track.weight_tracks[i].times.size(); j++) { + anim_start = MIN(anim_start, track.weight_tracks[i].times[j]); + anim_end = MAX(anim_end, track.weight_tracks[i].times[j]); + } + } + } else { + // If you don't use trimming and the first key time is not at 0.0, fake keys will be inserted. + for (int i = 0; i < track.rotation_track.times.size(); i++) { + anim_end = MAX(anim_end, track.rotation_track.times[i]); + } + for (int i = 0; i < track.position_track.times.size(); i++) { + anim_end = MAX(anim_end, track.position_track.times[i]); + } + for (int i = 0; i < track.scale_track.times.size(); i++) { + anim_end = MAX(anim_end, track.scale_track.times[i]); + } + for (int i = 0; i < track.weight_tracks.size(); i++) { + for (int j = 0; j < track.weight_tracks[i].times.size(); j++) { + anim_end = MAX(anim_end, track.weight_tracks[i].times[j]); + } } } @@ -5988,10 +6010,8 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, } } - //first determine animation length - const double increment = 1.0 / bake_fps; - double time = 0.0; + double time = anim_start; Vector3 base_pos; Quaternion base_rot; @@ -6017,26 +6037,26 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, if (position_idx >= 0) { pos = _interpolate_track<Vector3>(track.position_track.times, track.position_track.values, time, track.position_track.interpolation); - animation->position_track_insert_key(position_idx, time, pos); + animation->position_track_insert_key(position_idx, time - anim_start, pos); } if (rotation_idx >= 0) { rot = _interpolate_track<Quaternion>(track.rotation_track.times, track.rotation_track.values, time, track.rotation_track.interpolation); - animation->rotation_track_insert_key(rotation_idx, time, rot); + animation->rotation_track_insert_key(rotation_idx, time - anim_start, rot); } if (scale_idx >= 0) { scale = _interpolate_track<Vector3>(track.scale_track.times, track.scale_track.values, time, track.scale_track.interpolation); - animation->scale_track_insert_key(scale_idx, time, scale); + animation->scale_track_insert_key(scale_idx, time - anim_start, scale); } if (last) { break; } time += increment; - if (time >= length) { + if (time >= anim_end) { last = true; - time = length; + time = anim_end; } } } @@ -6071,21 +6091,21 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, bool last = false; while (true) { real_t blend = _interpolate_track<real_t>(track.weight_tracks[i].times, track.weight_tracks[i].values, time, gltf_interp); - animation->blend_shape_track_insert_key(track_idx, time, blend); + animation->blend_shape_track_insert_key(track_idx, time - anim_start, blend); if (last) { break; } time += increment; - if (time >= length) { + if (time >= anim_end) { last = true; - time = length; + time = anim_end; } } } } } - animation->set_length(length); + animation->set_length(anim_end - anim_start); Ref<AnimationLibrary> library; if (!ap->has_animation_library("")) { @@ -6585,7 +6605,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, } } -Error GLTFDocument::_parse(Ref<GLTFState> state, String p_path, Ref<FileAccess> f, int p_bake_fps) { +Error GLTFDocument::_parse(Ref<GLTFState> state, String p_path, Ref<FileAccess> f) { Error err; if (f.is_null()) { return FAILED; @@ -6636,7 +6656,7 @@ Error GLTFDocument::_parse(Ref<GLTFState> state, String p_path, Ref<FileAccess> } } - err = _parse_gltf_state(state, p_path, p_bake_fps); + err = _parse_gltf_state(state, p_path); ERR_FAIL_COND_V(err != OK, err); return OK; @@ -6754,14 +6774,14 @@ Error GLTFDocument::_serialize_file(Ref<GLTFState> state, const String p_path) { } void GLTFDocument::_bind_methods() { - ClassDB::bind_method(D_METHOD("append_from_file", "path", "state", "flags", "bake_fps", "base_path"), - &GLTFDocument::append_from_file, DEFVAL(0), DEFVAL(30), DEFVAL(String())); - ClassDB::bind_method(D_METHOD("append_from_buffer", "bytes", "base_path", "state", "flags", "bake_fps"), - &GLTFDocument::append_from_buffer, DEFVAL(0), DEFVAL(30)); - ClassDB::bind_method(D_METHOD("append_from_scene", "node", "state", "flags", "bake_fps"), - &GLTFDocument::append_from_scene, DEFVAL(0), DEFVAL(30)); - ClassDB::bind_method(D_METHOD("generate_scene", "state", "bake_fps"), - &GLTFDocument::generate_scene, DEFVAL(30)); + ClassDB::bind_method(D_METHOD("append_from_file", "path", "state", "flags", "base_path"), + &GLTFDocument::append_from_file, DEFVAL(0), DEFVAL(String())); + ClassDB::bind_method(D_METHOD("append_from_buffer", "bytes", "base_path", "state", "flags"), + &GLTFDocument::append_from_buffer, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("append_from_scene", "node", "state", "flags"), + &GLTFDocument::append_from_scene, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("generate_scene", "state", "bake_fps", "trimming"), + &GLTFDocument::generate_scene, DEFVAL(30), DEFVAL(false)); ClassDB::bind_method(D_METHOD("generate_buffer", "state"), &GLTFDocument::generate_buffer); ClassDB::bind_method(D_METHOD("write_to_filesystem", "state", "path"), @@ -6870,7 +6890,7 @@ Error GLTFDocument::write_to_filesystem(Ref<GLTFState> state, const String &p_pa return OK; } -Node *GLTFDocument::generate_scene(Ref<GLTFState> state, int32_t p_bake_fps) { +Node *GLTFDocument::generate_scene(Ref<GLTFState> state, float p_bake_fps, bool p_trimming) { ERR_FAIL_NULL_V(state, nullptr); ERR_FAIL_INDEX_V(0, state->root_nodes.size(), nullptr); Error err = OK; @@ -6884,7 +6904,7 @@ Node *GLTFDocument::generate_scene(Ref<GLTFState> state, int32_t p_bake_fps) { root->add_child(ap, true); ap->set_owner(root); for (int i = 0; i < state->animations.size(); i++) { - _import_animation(state, ap, i, p_bake_fps); + _import_animation(state, ap, i, p_bake_fps, p_trimming); } } for (KeyValue<GLTFNodeIndex, Node *> E : state->scene_nodes) { @@ -6910,7 +6930,7 @@ Node *GLTFDocument::generate_scene(Ref<GLTFState> state, int32_t p_bake_fps) { return root; } -Error GLTFDocument::append_from_scene(Node *p_node, Ref<GLTFState> state, uint32_t p_flags, int32_t p_bake_fps) { +Error GLTFDocument::append_from_scene(Node *p_node, Ref<GLTFState> state, uint32_t p_flags) { ERR_FAIL_COND_V(state.is_null(), FAILED); state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS; state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS; @@ -6930,7 +6950,7 @@ Error GLTFDocument::append_from_scene(Node *p_node, Ref<GLTFState> state, uint32 return OK; } -Error GLTFDocument::append_from_buffer(PackedByteArray p_bytes, String p_base_path, Ref<GLTFState> state, uint32_t p_flags, int32_t p_bake_fps) { +Error GLTFDocument::append_from_buffer(PackedByteArray p_bytes, String p_base_path, Ref<GLTFState> state, uint32_t p_flags) { ERR_FAIL_COND_V(state.is_null(), FAILED); // TODO Add missing texture and missing .bin file paths to r_missing_deps 2021-09-10 fire Error err = FAILED; @@ -6941,7 +6961,7 @@ Error GLTFDocument::append_from_buffer(PackedByteArray p_bytes, String p_base_pa file_access.instantiate(); file_access->open_custom(p_bytes.ptr(), p_bytes.size()); state->base_path = p_base_path.get_base_dir(); - err = _parse(state, state->base_path, file_access, p_bake_fps); + err = _parse(state, state->base_path, file_access); ERR_FAIL_COND_V(err != OK, err); for (Ref<GLTFDocumentExtension> ext : document_extensions) { ERR_CONTINUE(ext.is_null()); @@ -6951,7 +6971,7 @@ Error GLTFDocument::append_from_buffer(PackedByteArray p_bytes, String p_base_pa return OK; } -Error GLTFDocument::_parse_gltf_state(Ref<GLTFState> state, const String &p_search_path, float p_bake_fps) { +Error GLTFDocument::_parse_gltf_state(Ref<GLTFState> state, const String &p_search_path) { Error err; /* PARSE EXTENSIONS */ @@ -7047,7 +7067,7 @@ Error GLTFDocument::_parse_gltf_state(Ref<GLTFState> state, const String &p_sear return OK; } -Error GLTFDocument::append_from_file(String p_path, Ref<GLTFState> r_state, uint32_t p_flags, int32_t p_bake_fps, String p_base_path) { +Error GLTFDocument::append_from_file(String p_path, Ref<GLTFState> r_state, uint32_t p_flags, String p_base_path) { // TODO Add missing texture and missing .bin file paths to r_missing_deps 2021-09-10 fire if (r_state == Ref<GLTFState>()) { r_state.instantiate(); @@ -7064,7 +7084,7 @@ Error GLTFDocument::append_from_file(String p_path, Ref<GLTFState> r_state, uint base_path = p_path.get_base_dir(); } r_state->base_path = base_path; - err = _parse(r_state, base_path, f, p_bake_fps); + err = _parse(r_state, base_path, f); ERR_FAIL_COND_V(err != OK, err); for (Ref<GLTFDocumentExtension> ext : document_extensions) { ERR_CONTINUE(ext.is_null()); diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h index 5a0e4ff498..6eb38354a2 100644 --- a/modules/gltf/gltf_document.h +++ b/modules/gltf/gltf_document.h @@ -292,17 +292,17 @@ private: static float get_max_component(const Color &p_color); public: - Error append_from_file(String p_path, Ref<GLTFState> r_state, uint32_t p_flags = 0, int32_t p_bake_fps = 30, String p_base_path = String()); - Error append_from_buffer(PackedByteArray p_bytes, String p_base_path, Ref<GLTFState> r_state, uint32_t p_flags = 0, int32_t p_bake_fps = 30); - Error append_from_scene(Node *p_node, Ref<GLTFState> r_state, uint32_t p_flags = 0, int32_t p_bake_fps = 30); + Error append_from_file(String p_path, Ref<GLTFState> r_state, uint32_t p_flags = 0, String p_base_path = String()); + Error append_from_buffer(PackedByteArray p_bytes, String p_base_path, Ref<GLTFState> r_state, uint32_t p_flags = 0); + Error append_from_scene(Node *p_node, Ref<GLTFState> r_state, uint32_t p_flags = 0); public: - Node *generate_scene(Ref<GLTFState> state, int32_t p_bake_fps = 30.0f); + Node *generate_scene(Ref<GLTFState> state, float p_bake_fps = 30.0f, bool p_trimming = false); PackedByteArray generate_buffer(Ref<GLTFState> state); Error write_to_filesystem(Ref<GLTFState> state, const String &p_path); public: - Error _parse_gltf_state(Ref<GLTFState> state, const String &p_search_path, float p_bake_fps); + Error _parse_gltf_state(Ref<GLTFState> state, const String &p_search_path); Error _parse_gltf_extensions(Ref<GLTFState> state); void _process_mesh_instances(Ref<GLTFState> state, Node *scene_root); void _generate_scene_node(Ref<GLTFState> state, Node *scene_parent, @@ -310,7 +310,7 @@ public: const GLTFNodeIndex node_index); void _generate_skeleton_bone_node(Ref<GLTFState> state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index); void _import_animation(Ref<GLTFState> state, AnimationPlayer *ap, - const GLTFAnimationIndex index, const int bake_fps); + const GLTFAnimationIndex index, const float bake_fps, const bool trimming); void _convert_mesh_instances(Ref<GLTFState> state); GLTFCameraIndex _convert_camera(Ref<GLTFState> state, Camera3D *p_camera); void _convert_light_to_gltf(Light3D *light, Ref<GLTFState> state, Ref<GLTFNode> gltf_node); @@ -368,7 +368,7 @@ public: void _convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, String p_animation_track_name); Error _serialize(Ref<GLTFState> state, const String &p_path); - Error _parse(Ref<GLTFState> state, String p_path, Ref<FileAccess> f, int p_bake_fps); + Error _parse(Ref<GLTFState> state, String p_path, Ref<FileAccess> f); }; #endif // GLTF_DOCUMENT_H diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp index c8aedc8b92..89ef9ddd90 100644 --- a/modules/gridmap/editor/grid_map_editor_plugin.cpp +++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp @@ -40,6 +40,8 @@ #include "editor/editor_undo_redo_manager.h" #include "editor/plugins/node_3d_editor_plugin.h" #include "scene/3d/camera_3d.h" +#include "scene/gui/menu_button.h" +#include "scene/gui/separator.h" #include "scene/main/window.h" void GridMapEditor::_node_removed(Node *p_node) { diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index a4bffc1e3c..cfb9a0fbfb 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -46,6 +46,7 @@ #include "editor/editor_internal_calls.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" +#include "editor/inspector_dock.h" #include "editor/node_dock.h" #include "editor/script_templates/templates.gen.h" #endif diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs index e3b7ac297d..1b9f63c22d 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs @@ -474,6 +474,11 @@ namespace Godot.Collections } } + internal interface IGenericGodotArray + { + public Array UnderlyingArray { get; } + } + /// <summary> /// Typed wrapper around Godot's Array class, an array of Variant /// typed elements allocated in the engine in C++. Useful when @@ -487,7 +492,8 @@ namespace Godot.Collections IList<T>, IReadOnlyList<T>, ICollection<T>, - IEnumerable<T> + IEnumerable<T>, + IGenericGodotArray { private static godot_variant ToVariantFunc(in Array<T> godotArray) => VariantUtils.CreateFromArray(godotArray); @@ -503,6 +509,8 @@ namespace Godot.Collections private readonly Array _underlyingArray; + Array IGenericGodotArray.UnderlyingArray => _underlyingArray; + internal ref godot_array.movable NativeValue { [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs index f14790a218..cf25e1f0ae 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs @@ -344,6 +344,11 @@ namespace Godot.Collections } } + internal interface IGenericGodotDictionary + { + public Dictionary UnderlyingDictionary { get; } + } + /// <summary> /// Typed wrapper around Godot's Dictionary class, a dictionary of Variant /// typed elements allocated in the engine in C++. Useful when @@ -354,7 +359,8 @@ namespace Godot.Collections /// <typeparam name="TValue">The type of the dictionary's values.</typeparam> public class Dictionary<[MustBeVariant] TKey, [MustBeVariant] TValue> : IDictionary<TKey, TValue>, - IReadOnlyDictionary<TKey, TValue> + IReadOnlyDictionary<TKey, TValue>, + IGenericGodotDictionary { private static godot_variant ToVariantFunc(in Dictionary<TKey, TValue> godotDictionary) => VariantUtils.CreateFromDictionary(godotDictionary); @@ -370,6 +376,8 @@ namespace Godot.Collections private readonly Dictionary _underlyingDict; + Dictionary IGenericGodotDictionary.UnderlyingDictionary => _underlyingDict; + internal ref godot_dictionary.movable NativeValue { [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs index 649661ee06..d2a80d0e92 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs @@ -293,6 +293,10 @@ namespace Godot.NativeInterop return VariantUtils.CreateFromDictionary(godotDictionary); case Collections.Array godotArray: return VariantUtils.CreateFromArray(godotArray); + case Collections.IGenericGodotDictionary godotDictionary: + return VariantUtils.CreateFromDictionary(godotDictionary.UnderlyingDictionary); + case Collections.IGenericGodotArray godotArray: + return VariantUtils.CreateFromArray(godotArray.UnderlyingArray); case Variant variant: return NativeFuncs.godotsharp_variant_new_copy((godot_variant)variant.NativeVar); } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs index b30b6a0752..c7deb6423b 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs @@ -414,21 +414,6 @@ namespace Godot.NativeInterop // StringExtensions - public static partial void godotsharp_string_md5_buffer(in godot_string p_self, - out godot_packed_byte_array r_md5_buffer); - - public static partial void godotsharp_string_md5_text(in godot_string p_self, out godot_string r_md5_text); - - public static partial int godotsharp_string_rfind(in godot_string p_self, in godot_string p_what, int p_from); - - public static partial int godotsharp_string_rfindn(in godot_string p_self, in godot_string p_what, int p_from); - - public static partial void godotsharp_string_sha256_buffer(in godot_string p_self, - out godot_packed_byte_array r_sha256_buffer); - - public static partial void godotsharp_string_sha256_text(in godot_string p_self, - out godot_string r_sha256_text); - public static partial void godotsharp_string_simplify_path(in godot_string p_self, out godot_string r_simplified_path); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs index f511233fcc..d4329d78c1 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.IO; using System.Security; +using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using Godot.NativeInterop; @@ -67,30 +69,13 @@ namespace Godot } /// <summary> - /// If the string is a path to a file, return the path to the file without the extension. - /// </summary> - /// <seealso cref="GetExtension(string)"/> - /// <seealso cref="GetBaseDir(string)"/> - /// <seealso cref="GetFile(string)"/> - /// <param name="instance">The path to a file.</param> - /// <returns>The path to the file without the extension.</returns> - public static string GetBaseName(this string instance) - { - int index = instance.LastIndexOf('.'); - - if (index > 0) - return instance.Substring(0, index); - - return instance; - } - - /// <summary> /// Returns <see langword="true"/> if the strings begins /// with the given string <paramref name="text"/>. /// </summary> /// <param name="instance">The string to check.</param> /// <param name="text">The beginning string.</param> /// <returns>If the string begins with the given string.</returns> + [Obsolete("Use string.StartsWith instead.")] public static bool BeginsWith(this string instance, string text) { return instance.StartsWith(text); @@ -144,15 +129,15 @@ namespace Godot } /// <summary> - /// Returns the amount of substrings <paramref name="what"/> in the string. + /// Returns the number of occurrences of substring <paramref name="what"/> in the string. /// </summary> /// <param name="instance">The string where the substring will be searched.</param> /// <param name="what">The substring that will be counted.</param> - /// <param name="caseSensitive">If the search is case sensitive.</param> /// <param name="from">Index to start searching from.</param> /// <param name="to">Index to stop searching at.</param> - /// <returns>Amount of substrings in the string.</returns> - public static int Count(this string instance, string what, bool caseSensitive = true, int from = 0, int to = 0) + /// <param name="caseSensitive">If the search is case sensitive.</param> + /// <returns>Number of occurrences of the substring in the string.</returns> + public static int Count(this string instance, string what, int from = 0, int to = 0, bool caseSensitive = true) { if (what.Length == 0) { @@ -211,6 +196,82 @@ namespace Godot } /// <summary> + /// Returns the number of occurrences of substring <paramref name="what"/> (ignoring case) + /// between <paramref name="from"/> and <paramref name="to"/> positions. If <paramref name="from"/> + /// and <paramref name="to"/> equals 0 the whole string will be used. If only <paramref name="to"/> + /// equals 0 the remained substring will be used. + /// </summary> + /// <param name="instance">The string where the substring will be searched.</param> + /// <param name="what">The substring that will be counted.</param> + /// <param name="from">Index to start searching from.</param> + /// <param name="to">Index to stop searching at.</param> + /// <returns>Number of occurrences of the substring in the string.</returns> + public static int CountN(this string instance, string what, int from = 0, int to = 0) + { + return instance.Count(what, from, to, caseSensitive: false); + } + + /// <summary> + /// Returns a copy of the string with indentation (leading tabs and spaces) removed. + /// See also <see cref="Indent"/> to add indentation. + /// </summary> + /// <param name="instance">The string to remove the indentation from.</param> + /// <returns>The string with the indentation removed.</returns> + public static string Dedent(this string instance) + { + var sb = new StringBuilder(); + string indent = ""; + bool hasIndent = false; + bool hasText = false; + int lineStart = 0; + int indentStop = -1; + + for (int i = 0; i < instance.Length; i++) + { + char c = instance[i]; + if (c == '\n') + { + if (hasText) + { + sb.Append(instance.Substring(indentStop, i - indentStop)); + } + sb.Append('\n'); + hasText = false; + lineStart = i + 1; + indentStop = -1; + } + else if (!hasText) + { + if (c > 32) + { + hasText = true; + if (!hasIndent) + { + hasIndent = true; + indent = instance.Substring(lineStart, i - lineStart); + indentStop = i; + } + } + if (hasIndent && indentStop < 0) + { + int j = i - lineStart; + if (j >= indent.Length || c != indent[j]) + { + indentStop = i; + } + } + } + } + + if (hasText) + { + sb.Append(instance.Substring(indentStop, instance.Length - indentStop)); + } + + return sb.ToString(); + } + + /// <summary> /// Returns a copy of the string with special characters escaped using the C language standard. /// </summary> /// <param name="instance">The string to escape.</param> @@ -443,29 +504,6 @@ namespace Godot } /// <summary> - /// Returns <see langword="true"/> if the strings ends - /// with the given string <paramref name="text"/>. - /// </summary> - /// <param name="instance">The string to check.</param> - /// <param name="text">The ending string.</param> - /// <returns>If the string ends with the given string.</returns> - public static bool EndsWith(this string instance, string text) - { - return instance.EndsWith(text); - } - - /// <summary> - /// Erase <paramref name="chars"/> characters from the string starting from <paramref name="pos"/>. - /// </summary> - /// <param name="instance">The string to modify.</param> - /// <param name="pos">Starting position from which to erase.</param> - /// <param name="chars">Amount of characters to erase.</param> - public static void Erase(this StringBuilder instance, int pos, int chars) - { - instance.Remove(pos, chars); - } - - /// <summary> /// Returns the extension without the leading period character (<c>.</c>) /// if the string is a valid file name or path. If the string does not contain /// an extension, returns an empty string instead. @@ -489,7 +527,7 @@ namespace Godot /// <returns>The extension of the file or an empty string.</returns> public static string GetExtension(this string instance) { - int pos = instance.FindLast("."); + int pos = instance.RFind("."); if (pos < 0) return instance; @@ -498,12 +536,16 @@ namespace Godot } /// <summary> - /// Find the first occurrence of a substring. Optionally, the search starting position can be passed. + /// Returns the index of the first occurrence of the specified string in this instance, + /// or <c>-1</c>. Optionally, the starting search index can be specified, continuing + /// to the end of the string. + /// Note: If you just want to know whether a string contains a substring, use the + /// <see cref="string.Contains(string)"/> method. /// </summary> /// <seealso cref="Find(string, char, int, bool)"/> - /// <seealso cref="FindLast(string, string, bool)"/> - /// <seealso cref="FindLast(string, string, int, bool)"/> /// <seealso cref="FindN(string, string, int)"/> + /// <seealso cref="RFind(string, string, int, bool)"/> + /// <seealso cref="RFindN(string, string, int)"/> /// <param name="instance">The string that will be searched.</param> /// <param name="what">The substring to find.</param> /// <param name="from">The search starting position.</param> @@ -519,9 +561,9 @@ namespace Godot /// Find the first occurrence of a char. Optionally, the search starting position can be passed. /// </summary> /// <seealso cref="Find(string, string, int, bool)"/> - /// <seealso cref="FindLast(string, string, bool)"/> - /// <seealso cref="FindLast(string, string, int, bool)"/> /// <seealso cref="FindN(string, string, int)"/> + /// <seealso cref="RFind(string, string, int, bool)"/> + /// <seealso cref="RFindN(string, string, int)"/> /// <param name="instance">The string that will be searched.</param> /// <param name="what">The substring to find.</param> /// <param name="from">The search starting position.</param> @@ -529,50 +571,21 @@ namespace Godot /// <returns>The first instance of the char, or -1 if not found.</returns> public static int Find(this string instance, char what, int from = 0, bool caseSensitive = true) { - // TODO: Could be more efficient if we get a char version of `IndexOf`. - // See https://github.com/dotnet/runtime/issues/44116 - return instance.IndexOf(what.ToString(), from, - caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase); - } + if (caseSensitive) + return instance.IndexOf(what, from); - /// <summary>Find the last occurrence of a substring.</summary> - /// <seealso cref="Find(string, string, int, bool)"/> - /// <seealso cref="Find(string, char, int, bool)"/> - /// <seealso cref="FindLast(string, string, int, bool)"/> - /// <seealso cref="FindN(string, string, int)"/> - /// <param name="instance">The string that will be searched.</param> - /// <param name="what">The substring to find.</param> - /// <param name="caseSensitive">If <see langword="true"/>, the search is case sensitive.</param> - /// <returns>The starting position of the substring, or -1 if not found.</returns> - public static int FindLast(this string instance, string what, bool caseSensitive = true) - { - return instance.FindLast(what, instance.Length - 1, caseSensitive); - } - - /// <summary>Find the last occurrence of a substring specifying the search starting position.</summary> - /// <seealso cref="Find(string, string, int, bool)"/> - /// <seealso cref="Find(string, char, int, bool)"/> - /// <seealso cref="FindLast(string, string, bool)"/> - /// <seealso cref="FindN(string, string, int)"/> - /// <param name="instance">The string that will be searched.</param> - /// <param name="what">The substring to find.</param> - /// <param name="from">The search starting position.</param> - /// <param name="caseSensitive">If <see langword="true"/>, the search is case sensitive.</param> - /// <returns>The starting position of the substring, or -1 if not found.</returns> - public static int FindLast(this string instance, string what, int from, bool caseSensitive = true) - { - return instance.LastIndexOf(what, from, - caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase); + return CultureInfo.InvariantCulture.CompareInfo.IndexOf(instance, what, from, CompareOptions.OrdinalIgnoreCase); } /// <summary> - /// Find the first occurrence of a substring but search as case-insensitive. - /// Optionally, the search starting position can be passed. + /// Returns the index of the first case-insensitive occurrence of the specified string in this instance, + /// or <c>-1</c>. Optionally, the starting search index can be specified, continuing + /// to the end of the string. /// </summary> /// <seealso cref="Find(string, string, int, bool)"/> /// <seealso cref="Find(string, char, int, bool)"/> - /// <seealso cref="FindLast(string, string, bool)"/> - /// <seealso cref="FindLast(string, string, int, bool)"/> + /// <seealso cref="RFind(string, string, int, bool)"/> + /// <seealso cref="RFindN(string, string, int)"/> /// <param name="instance">The string that will be searched.</param> /// <param name="what">The substring to find.</param> /// <param name="from">The search starting position.</param> @@ -616,7 +629,7 @@ namespace Godot } } - int sep = Mathf.Max(rs.FindLast("/"), rs.FindLast("\\")); + int sep = Mathf.Max(rs.RFind("/"), rs.RFind("\\")); if (sep == -1) return directory; @@ -625,6 +638,24 @@ namespace Godot } /// <summary> + /// If the string is a path to a file, return the path to the file without the extension. + /// </summary> + /// <seealso cref="GetExtension(string)"/> + /// <seealso cref="GetBaseDir(string)"/> + /// <seealso cref="GetFile(string)"/> + /// <param name="instance">The path to a file.</param> + /// <returns>The path to the file without the extension.</returns> + public static string GetBaseName(this string instance) + { + int index = instance.RFind("."); + + if (index > 0) + return instance.Substring(0, index); + + return instance; + } + + /// <summary> /// If the string is a path to a file, return the file and ignore the base directory. /// </summary> /// <seealso cref="GetBaseName(string)"/> @@ -634,7 +665,7 @@ namespace Godot /// <returns>The file name.</returns> public static string GetFile(this string instance) { - int sep = Mathf.Max(instance.FindLast("/"), instance.FindLast("\\")); + int sep = Mathf.Max(instance.RFind("/"), instance.RFind("\\")); if (sep == -1) return instance; @@ -643,8 +674,8 @@ namespace Godot } /// <summary> - /// Converts the given byte array of ASCII encoded text to a string. - /// Faster alternative to <see cref="GetStringFromUTF8"/> if the + /// Converts ASCII encoded array to string. + /// Fast alternative to <see cref="GetStringFromUTF8"/> if the /// content is ASCII-only. Unlike the UTF-8 function this function /// maps every byte to a character in the array. Multibyte sequences /// will not be interpreted correctly. For parsing user input always @@ -658,13 +689,35 @@ namespace Godot } /// <summary> - /// Converts the given byte array of UTF-8 encoded text to a string. + /// Converts UTF-16 encoded array to string using the little endian byte order. + /// </summary> + /// <param name="bytes">A byte array of UTF-16 characters.</param> + /// <returns>A string created from the bytes.</returns> + public static string GetStringFromUTF16(this byte[] bytes) + { + return Encoding.Unicode.GetString(bytes); + } + + /// <summary> + /// Converts UTF-32 encoded array to string using the little endian byte order. + /// </summary> + /// <param name="bytes">A byte array of UTF-32 characters.</param> + /// <returns>A string created from the bytes.</returns> + public static string GetStringFromUTF32(this byte[] bytes) + { + return Encoding.UTF32.GetString(bytes); + } + + /// <summary> + /// Converts UTF-8 encoded array to string. /// Slower than <see cref="GetStringFromASCII"/> but supports UTF-8 /// encoded data. Use this function if you are unsure about the /// source of the data. For user input this function /// should always be preferred. /// </summary> - /// <param name="bytes">A byte array of UTF-8 characters (a character may take up multiple bytes).</param> + /// <param name="bytes"> + /// A byte array of UTF-8 characters (a character may take up multiple bytes). + /// </param> /// <returns>A string created from the bytes.</returns> public static string GetStringFromUTF8(this byte[] bytes) { @@ -766,18 +819,44 @@ namespace Godot } /// <summary> - /// Inserts a substring at a given position. + /// Returns a copy of the string with lines indented with <paramref name="prefix"/>. + /// For example, the string can be indented with two tabs using <c>"\t\t"</c>, + /// or four spaces using <c>" "</c>. The prefix can be any string so it can + /// also be used to comment out strings with e.g. <c>"// </c>. + /// See also <see cref="Dedent"/> to remove indentation. + /// Note: Empty lines are kept empty. /// </summary> - /// <param name="instance">The string to modify.</param> - /// <param name="pos">Position at which to insert the substring.</param> - /// <param name="what">Substring to insert.</param> - /// <returns> - /// The string with <paramref name="what"/> inserted at the given - /// position <paramref name="pos"/>. - /// </returns> - public static string Insert(this string instance, int pos, string what) + /// <param name="instance">The string to add indentation to.</param> + /// <param name="prefix">The string to use as indentation.</param> + /// <returns>The string with indentation added.</returns> + public static string Indent(this string instance, string prefix) { - return instance.Insert(pos, what); + var sb = new StringBuilder(); + int lineStart = 0; + + for (int i = 0; i < instance.Length; i++) + { + char c = instance[i]; + if (c == '\n') + { + if (i == lineStart) + { + sb.Append(c); // Leave empty lines empty. + } + else + { + sb.Append(prefix); + sb.Append(instance.Substring(lineStart, i - lineStart + 1)); + } + lineStart = i + 1; + } + } + if (lineStart != instance.Length) + { + sb.Append(prefix); + sb.Append(instance.Substring(lineStart)); + } + return sb.ToString(); } /// <summary> @@ -873,19 +952,94 @@ namespace Godot return instance.IsSubsequenceOf(text, caseSensitive: false); } + private static readonly char[] _invalidFileNameCharacters = { ':', '/', '\\', '?', '*', '"', '|', '%', '<', '>' }; + + /// <summary> + /// Returns <see langword="true"/> if this string is free from characters that + /// aren't allowed in file names. + /// </summary> + /// <param name="instance">The string to check.</param> + /// <returns>If the string contains a valid file name.</returns> + public static bool IsValidFileName(this string instance) + { + var stripped = instance.Trim(); + if (instance != stripped) + return false; + + if (string.IsNullOrEmpty(stripped)) + return false; + + return instance.IndexOfAny(_invalidFileNameCharacters) == -1; + } + /// <summary> - /// Check whether the string contains a valid <see langword="float"/>. + /// Returns <see langword="true"/> if this string contains a valid <see langword="float"/>. + /// This is inclusive of integers, and also supports exponents. /// </summary> + /// <example> + /// <code> + /// GD.Print("1.7".IsValidFloat()) // Prints "True" + /// GD.Print("24".IsValidFloat()) // Prints "True" + /// GD.Print("7e3".IsValidFloat()) // Prints "True" + /// GD.Print("Hello".IsValidFloat()) // Prints "False" + /// </code> + /// </example> /// <param name="instance">The string to check.</param> /// <returns>If the string contains a valid floating point number.</returns> public static bool IsValidFloat(this string instance) { - float f; - return float.TryParse(instance, out f); + return float.TryParse(instance, out _); + } + + /// <summary> + /// Returns <see langword="true"/> if this string contains a valid hexadecimal number. + /// If <paramref name="withPrefix"/> is <see langword="true"/>, then a validity of the + /// hexadecimal number is determined by <c>0x</c> prefix, for instance: <c>0xDEADC0DE</c>. + /// </summary> + /// <param name="instance">The string to check.</param> + /// <param name="withPrefix">If the string must contain the <c>0x</c> prefix to be valid.</param> + /// <returns>If the string contains a valid hexadecimal number.</returns> + public static bool IsValidHexNumber(this string instance, bool withPrefix = false) + { + if (string.IsNullOrEmpty(instance)) + return false; + + int from = 0; + if (instance.Length != 1 && instance[0] == '+' || instance[0] == '-') + { + from++; + } + + if (withPrefix) + { + if (instance.Length < 3) + return false; + if (instance[from] != '0' || instance[from + 1] != 'x') + return false; + from += 2; + } + + for (int i = from; i < instance.Length; i++) + { + char c = instance[i]; + if (IsHexDigit(c)) + continue; + + return false; + } + + return true; + + static bool IsHexDigit(char c) + { + return char.IsDigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); + } } /// <summary> - /// Check whether the string contains a valid color in HTML notation. + /// Returns <see langword="true"/> if this string contains a valid color in hexadecimal + /// HTML notation. Other HTML notations such as named colors or <c>hsl()</c> aren't + /// considered valid by this method and will return <see langword="false"/>. /// </summary> /// <param name="instance">The string to check.</param> /// <returns>If the string contains a valid HTML color.</returns> @@ -895,10 +1049,17 @@ namespace Godot } /// <summary> - /// Check whether the string is a valid identifier. As is common in - /// programming languages, a valid identifier may contain only letters, - /// digits and underscores (_) and the first character may not be a digit. + /// Returns <see langword="true"/> if this string is a valid identifier. + /// A valid identifier may contain only letters, digits and underscores (<c>_</c>) + /// and the first character may not be a digit. /// </summary> + /// <example> + /// <code> + /// GD.Print("good_ident_1".IsValidIdentifier()) // Prints "True" + /// GD.Print("1st_bad_ident".IsValidIdentifier()) // Prints "False" + /// GD.Print("bad_ident_#2".IsValidIdentifier()) // Prints "False" + /// </code> + /// </example> /// <param name="instance">The string to check.</param> /// <returns>If the string contains a valid identifier.</returns> public static bool IsValidIdentifier(this string instance) @@ -926,38 +1087,73 @@ namespace Godot } /// <summary> - /// Check whether the string contains a valid integer. + /// Returns <see langword="true"/> if this string contains a valid <see langword="int"/>. /// </summary> + /// <example> + /// <code> + /// GD.Print("7".IsValidInt()) // Prints "True" + /// GD.Print("14.6".IsValidInt()) // Prints "False" + /// GD.Print("L".IsValidInt()) // Prints "False" + /// GD.Print("+3".IsValidInt()) // Prints "True" + /// GD.Print("-12".IsValidInt()) // Prints "True" + /// </code> + /// </example> /// <param name="instance">The string to check.</param> /// <returns>If the string contains a valid integer.</returns> - public static bool IsValidInteger(this string instance) + public static bool IsValidInt(this string instance) { - int f; - return int.TryParse(instance, out f); + return int.TryParse(instance, out _); } /// <summary> - /// Check whether the string contains a valid IP address. + /// Returns <see langword="true"/> if this string contains only a well-formatted + /// IPv4 or IPv6 address. This method considers reserved IP addresses such as + /// <c>0.0.0.0</c> as valid. /// </summary> /// <param name="instance">The string to check.</param> /// <returns>If the string contains a valid IP address.</returns> public static bool IsValidIPAddress(this string instance) { - // TODO: Support IPv6 addresses - string[] ip = instance.Split("."); + if (instance.Contains(':')) + { + string[] ip = instance.Split(':'); - if (ip.Length != 4) - return false; + for (int i = 0; i < ip.Length; i++) + { + string n = ip[i]; + if (n.Length == 0) + continue; + + if (n.IsValidHexNumber(withPrefix: false)) + { + long nint = n.HexToInt(); + if (nint < 0 || nint > 0xffff) + return false; - for (int i = 0; i < ip.Length; i++) + continue; + } + + if (!n.IsValidIPAddress()) + return false; + } + } + else { - string n = ip[i]; - if (!n.IsValidInteger()) - return false; + string[] ip = instance.Split('.'); - int val = n.ToInt(); - if (val < 0 || val > 255) + if (ip.Length != 4) return false; + + for (int i = 0; i < ip.Length; i++) + { + string n = ip[i]; + if (!n.IsValidInt()) + return false; + + int val = n.ToInt(); + if (val < 0 || val > 255) + return false; + } } return true; @@ -1003,41 +1199,20 @@ namespace Godot } /// <summary> - /// Returns the length of the string in characters. - /// </summary> - /// <param name="instance">The string to check.</param> - /// <returns>The length of the string.</returns> - public static int Length(this string instance) - { - return instance.Length; - } - - /// <summary> /// Returns a copy of the string with characters removed from the left. + /// The <paramref name="chars"/> argument is a string specifying the set of characters + /// to be removed. + /// Note: The <paramref name="chars"/> is not a prefix. See <see cref="TrimPrefix"/> + /// method that will remove a single prefix string rather than a set of characters. /// </summary> /// <seealso cref="RStrip(string, string)"/> /// <param name="instance">The string to remove characters from.</param> /// <param name="chars">The characters to be removed.</param> /// <returns>A copy of the string with characters removed from the left.</returns> + [Obsolete("Use string.TrimStart instead.")] public static string LStrip(this string instance, string chars) { - int len = instance.Length; - int beg; - - for (beg = 0; beg < len; beg++) - { - if (chars.Find(instance[beg]) == -1) - { - break; - } - } - - if (beg == 0) - { - return instance; - } - - return instance.Substr(beg, len - beg); + return instance.TrimStart(chars.ToCharArray()); } /// <summary> @@ -1117,10 +1292,9 @@ namespace Godot /// <returns>The MD5 hash of the string.</returns> public static byte[] MD5Buffer(this string instance) { - using godot_string instanceStr = Marshaling.ConvertStringToNative(instance); - NativeFuncs.godotsharp_string_md5_buffer(instanceStr, out var md5Buffer); - using (md5Buffer) - return Marshaling.ConvertNativePackedByteArrayToSystemArray(md5Buffer); +#pragma warning disable CA5351 // Do Not Use Broken Cryptographic Algorithms + return MD5.HashData(Encoding.UTF8.GetBytes(instance)); +#pragma warning restore CA5351 } /// <summary> @@ -1131,10 +1305,7 @@ namespace Godot /// <returns>The MD5 hash of the string.</returns> public static string MD5Text(this string instance) { - using godot_string instanceStr = Marshaling.ConvertStringToNative(instance); - NativeFuncs.godotsharp_string_md5_text(instanceStr, out var md5Text); - using (md5Text) - return Marshaling.ConvertStringToManaged(md5Text); + return instance.MD5Buffer().HexEncode(); } /// <summary> @@ -1151,17 +1322,6 @@ namespace Godot } /// <summary> - /// Returns the character code at position <paramref name="at"/>. - /// </summary> - /// <param name="instance">The string to check.</param> - /// <param name="at">The position int the string for the character to check.</param> - /// <returns>The character code.</returns> - public static int OrdAt(this string instance, int at) - { - return instance[at]; - } - - /// <summary> /// Format a number to have an exact number of <paramref name="digits"/> /// after the decimal point. /// </summary> @@ -1282,34 +1442,47 @@ namespace Godot } /// <summary> - /// Perform a search for a substring, but start from the end of the string instead of the beginning. + /// Returns the index of the last occurrence of the specified string in this instance, + /// or <c>-1</c>. Optionally, the starting search index can be specified, continuing to + /// the beginning of the string. /// </summary> + /// <seealso cref="Find(string, string, int, bool)"/> + /// <seealso cref="Find(string, char, int, bool)"/> + /// <seealso cref="FindN(string, string, int)"/> /// <seealso cref="RFindN(string, string, int)"/> /// <param name="instance">The string that will be searched.</param> /// <param name="what">The substring to search in the string.</param> /// <param name="from">The position at which to start searching.</param> + /// <param name="caseSensitive">If <see langword="true"/>, the search is case sensitive.</param> /// <returns>The position at which the substring was found, or -1 if not found.</returns> - public static int RFind(this string instance, string what, int from = -1) + public static int RFind(this string instance, string what, int from = -1, bool caseSensitive = true) { - using godot_string instanceStr = Marshaling.ConvertStringToNative(instance); - using godot_string whatStr = Marshaling.ConvertStringToNative(instance); - return NativeFuncs.godotsharp_string_rfind(instanceStr, whatStr, from); + if (from == -1) + from = instance.Length - 1; + + return instance.LastIndexOf(what, from, + caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase); } /// <summary> - /// Perform a search for a substring, but start from the end of the string instead of the beginning. - /// Also search case-insensitive. + /// Returns the index of the last case-insensitive occurrence of the specified string in this instance, + /// or <c>-1</c>. Optionally, the starting search index can be specified, continuing to + /// the beginning of the string. /// </summary> - /// <seealso cref="RFind(string, string, int)"/> + /// <seealso cref="Find(string, string, int, bool)"/> + /// <seealso cref="Find(string, char, int, bool)"/> + /// <seealso cref="FindN(string, string, int)"/> + /// <seealso cref="RFind(string, string, int, bool)"/> /// <param name="instance">The string that will be searched.</param> /// <param name="what">The substring to search in the string.</param> /// <param name="from">The position at which to start searching.</param> /// <returns>The position at which the substring was found, or -1 if not found.</returns> public static int RFindN(this string instance, string what, int from = -1) { - using godot_string instanceStr = Marshaling.ConvertStringToNative(instance); - using godot_string whatStr = Marshaling.ConvertStringToNative(instance); - return NativeFuncs.godotsharp_string_rfindn(instanceStr, whatStr, from); + if (from == -1) + from = instance.Length - 1; + + return instance.LastIndexOf(what, from, StringComparison.OrdinalIgnoreCase); } /// <summary> @@ -1332,30 +1505,43 @@ namespace Godot /// <summary> /// Returns a copy of the string with characters removed from the right. + /// The <paramref name="chars"/> argument is a string specifying the set of characters + /// to be removed. + /// Note: The <paramref name="chars"/> is not a suffix. See <see cref="TrimSuffix"/> + /// method that will remove a single suffix string rather than a set of characters. /// </summary> /// <seealso cref="LStrip(string, string)"/> /// <param name="instance">The string to remove characters from.</param> /// <param name="chars">The characters to be removed.</param> /// <returns>A copy of the string with characters removed from the right.</returns> + [Obsolete("Use string.TrimEnd instead.")] public static string RStrip(this string instance, string chars) { - int len = instance.Length; - int end; - - for (end = len - 1; end >= 0; end--) - { - if (chars.Find(instance[end]) == -1) - { - break; - } - } + return instance.TrimEnd(chars.ToCharArray()); + } - if (end == len - 1) - { - return instance; - } + /// <summary> + /// Returns the SHA-1 hash of the string as an array of bytes. + /// </summary> + /// <seealso cref="SHA1Text(string)"/> + /// <param name="instance">The string to hash.</param> + /// <returns>The SHA-1 hash of the string.</returns> + public static byte[] SHA1Buffer(this string instance) + { +#pragma warning disable CA5350 // Do Not Use Weak Cryptographic Algorithms + return SHA1.HashData(Encoding.UTF8.GetBytes(instance)); +#pragma warning restore CA5350 + } - return instance.Substr(0, end + 1); + /// <summary> + /// Returns the SHA-1 hash of the string as a string. + /// </summary> + /// <seealso cref="SHA1Buffer(string)"/> + /// <param name="instance">The string to hash.</param> + /// <returns>The SHA-1 hash of the string.</returns> + public static string SHA1Text(this string instance) + { + return instance.SHA1Buffer().HexEncode(); } /// <summary> @@ -1366,10 +1552,7 @@ namespace Godot /// <returns>The SHA-256 hash of the string.</returns> public static byte[] SHA256Buffer(this string instance) { - using godot_string instanceStr = Marshaling.ConvertStringToNative(instance); - NativeFuncs.godotsharp_string_sha256_buffer(instanceStr, out var sha256Buffer); - using (sha256Buffer) - return Marshaling.ConvertNativePackedByteArrayToSystemArray(sha256Buffer); + return SHA256.HashData(Encoding.UTF8.GetBytes(instance)); } /// <summary> @@ -1380,10 +1563,7 @@ namespace Godot /// <returns>The SHA-256 hash of the string.</returns> public static string SHA256Text(this string instance) { - using godot_string instanceStr = Marshaling.ConvertStringToNative(instance); - NativeFuncs.godotsharp_string_sha256_text(instanceStr, out var sha256Text); - using (sha256Text) - return Marshaling.ConvertStringToManaged(sha256Text); + return instance.SHA256Buffer().HexEncode(); } /// <summary> @@ -1455,7 +1635,7 @@ namespace Godot /// <returns>The array of strings split from the string.</returns> public static string[] Split(this string instance, string divisor, bool allowEmpty = true) { - return instance.Split(new[] { divisor }, + return instance.Split(divisor, allowEmpty ? StringSplitOptions.None : StringSplitOptions.RemoveEmptyEntries); } @@ -1503,8 +1683,10 @@ namespace Godot }; /// <summary> - /// Returns a copy of the string stripped of any non-printable character at the beginning and the end. - /// The optional arguments are used to toggle stripping on the left and right edges respectively. + /// Returns a copy of the string stripped of any non-printable character + /// (including tabulations, spaces and line breaks) at the beginning and the end. + /// The optional arguments are used to toggle stripping on the left and right + /// edges respectively. /// </summary> /// <param name="instance">The string to strip.</param> /// <param name="left">If the left side should be stripped.</param> @@ -1522,6 +1704,30 @@ namespace Godot return instance.TrimEnd(_nonPrintable); } + + /// <summary> + /// Returns a copy of the string stripped of any escape character. + /// These include all non-printable control characters of the first page + /// of the ASCII table (< 32), such as tabulation (<c>\t</c>) and + /// newline (<c>\n</c> and <c>\r</c>) characters, but not spaces. + /// </summary> + /// <param name="instance">The string to strip.</param> + /// <returns>The string stripped of any escape characters.</returns> + public static string StripEscapes(this string instance) + { + var sb = new StringBuilder(); + for (int i = 0; i < instance.Length; i++) + { + // Escape characters on first page of the ASCII table, before 32 (Space). + if (instance[i] < 32) + continue; + + sb.Append(instance[i]); + } + + return sb.ToString(); + } + /// <summary> /// Returns part of the string from the position <paramref name="from"/>, with length <paramref name="len"/>. /// </summary> @@ -1539,13 +1745,15 @@ namespace Godot /// <summary> /// Converts the String (which is a character array) to PackedByteArray (which is an array of bytes). - /// The conversion is speeded up in comparison to <see cref="ToUTF8(string)"/> with the assumption - /// that all the characters the String contains are only ASCII characters. + /// The conversion is faster compared to <see cref="ToUTF8Buffer(string)"/>, + /// as this method assumes that all the characters in the String are ASCII characters. /// </summary> - /// <seealso cref="ToUTF8(string)"/> + /// <seealso cref="ToUTF8Buffer(string)"/> + /// <seealso cref="ToUTF16Buffer(string)"/> + /// <seealso cref="ToUTF32Buffer(string)"/> /// <param name="instance">The string to convert.</param> /// <returns>The string as ASCII encoded bytes.</returns> - public static byte[] ToAscii(this string instance) + public static byte[] ToASCIIBuffer(this string instance) { return Encoding.ASCII.GetBytes(instance); } @@ -1573,41 +1781,76 @@ namespace Godot } /// <summary> - /// Returns the string converted to lowercase. + /// Converts the string (which is an array of characters) to an UTF-16 encoded array of bytes. /// </summary> - /// <seealso cref="ToUpper(string)"/> + /// <seealso cref="ToASCIIBuffer(string)"/> + /// <seealso cref="ToUTF32Buffer(string)"/> + /// <seealso cref="ToUTF8Buffer(string)"/> /// <param name="instance">The string to convert.</param> - /// <returns>The string converted to lowercase.</returns> - public static string ToLower(this string instance) + /// <returns>The string as UTF-16 encoded bytes.</returns> + public static byte[] ToUTF16Buffer(this string instance) { - return instance.ToLower(); + return Encoding.Unicode.GetBytes(instance); } /// <summary> - /// Returns the string converted to uppercase. + /// Converts the string (which is an array of characters) to an UTF-32 encoded array of bytes. /// </summary> - /// <seealso cref="ToLower(string)"/> + /// <seealso cref="ToASCIIBuffer(string)"/> + /// <seealso cref="ToUTF16Buffer(string)"/> + /// <seealso cref="ToUTF8Buffer(string)"/> /// <param name="instance">The string to convert.</param> - /// <returns>The string converted to uppercase.</returns> - public static string ToUpper(this string instance) + /// <returns>The string as UTF-32 encoded bytes.</returns> + public static byte[] ToUTF32Buffer(this string instance) { - return instance.ToUpper(); + return Encoding.UTF32.GetBytes(instance); } /// <summary> - /// Converts the String (which is an array of characters) to PackedByteArray (which is an array of bytes). - /// The conversion is a bit slower than <see cref="ToAscii(string)"/>, but supports all UTF-8 characters. - /// Therefore, you should prefer this function over <see cref="ToAscii(string)"/>. + /// Converts the string (which is an array of characters) to an UTF-8 encoded array of bytes. + /// The conversion is a bit slower than <see cref="ToASCIIBuffer(string)"/>, + /// but supports all UTF-8 characters. Therefore, you should prefer this function + /// over <see cref="ToASCIIBuffer(string)"/>. /// </summary> - /// <seealso cref="ToAscii(string)"/> + /// <seealso cref="ToASCIIBuffer(string)"/> + /// <seealso cref="ToUTF16Buffer(string)"/> + /// <seealso cref="ToUTF32Buffer(string)"/> /// <param name="instance">The string to convert.</param> /// <returns>The string as UTF-8 encoded bytes.</returns> - public static byte[] ToUTF8(this string instance) + public static byte[] ToUTF8Buffer(this string instance) { return Encoding.UTF8.GetBytes(instance); } /// <summary> + /// Removes a given string from the start if it starts with it or leaves the string unchanged. + /// </summary> + /// <param name="instance">The string to remove the prefix from.</param> + /// <param name="prefix">The string to remove from the start.</param> + /// <returns>A copy of the string with the prefix string removed from the start.</returns> + public static string TrimPrefix(this string instance, string prefix) + { + if (instance.StartsWith(prefix)) + return instance.Substring(prefix.Length); + + return instance; + } + + /// <summary> + /// Removes a given string from the end if it ends with it or leaves the string unchanged. + /// </summary> + /// <param name="instance">The string to remove the suffix from.</param> + /// <param name="suffix">The string to remove from the end.</param> + /// <returns>A copy of the string with the suffix string removed from the end.</returns> + public static string TrimSuffix(this string instance, string suffix) + { + if (instance.EndsWith(suffix)) + return instance.Substring(0, instance.Length - suffix.Length); + + return instance; + } + + /// <summary> /// Decodes a string in URL encoded format. This is meant to /// decode parameters in a URL when receiving an HTTP request. /// This mostly wraps around <see cref="Uri.UnescapeDataString"/>, @@ -1634,6 +1877,25 @@ namespace Godot return Uri.EscapeDataString(instance); } + private const string _uniqueNodePrefix = "%"; + private static readonly string[] _invalidNodeNameCharacters = { ".", ":", "@", "/", "\"", _uniqueNodePrefix }; + + /// <summary> + /// Removes any characters from the string that are prohibited in + /// <see cref="Node"/> names (<c>.</c> <c>:</c> <c>@</c> <c>/</c> <c>"</c>). + /// </summary> + /// <param name="instance">The string to sanitize.</param> + /// <returns>The string sanitized as a valid node name.</returns> + public static string ValidateNodeName(this string instance) + { + string name = instance.Replace(_invalidNodeNameCharacters[0], ""); + for (int i = 1; i < _invalidNodeNameCharacters.Length; i++) + { + name = name.Replace(_invalidNodeNameCharacters[i], ""); + } + return name; + } + /// <summary> /// Returns a copy of the string with special characters escaped using the XML standard. /// </summary> diff --git a/modules/mono/glue/runtime_interop.cpp b/modules/mono/glue/runtime_interop.cpp index e20a88076a..338e5a0147 100644 --- a/modules/mono/glue/runtime_interop.cpp +++ b/modules/mono/glue/runtime_interop.cpp @@ -1067,30 +1067,6 @@ void godotsharp_dictionary_to_string(const Dictionary *p_self, String *r_str) { *r_str = Variant(*p_self).operator String(); } -void godotsharp_string_md5_buffer(const String *p_self, PackedByteArray *r_md5_buffer) { - memnew_placement(r_md5_buffer, PackedByteArray(p_self->md5_buffer())); -} - -void godotsharp_string_md5_text(const String *p_self, String *r_md5_text) { - memnew_placement(r_md5_text, String(p_self->md5_text())); -} - -int32_t godotsharp_string_rfind(const String *p_self, const String *p_what, int32_t p_from) { - return p_self->rfind(*p_what, p_from); -} - -int32_t godotsharp_string_rfindn(const String *p_self, const String *p_what, int32_t p_from) { - return p_self->rfindn(*p_what, p_from); -} - -void godotsharp_string_sha256_buffer(const String *p_self, PackedByteArray *r_sha256_buffer) { - memnew_placement(r_sha256_buffer, PackedByteArray(p_self->sha256_buffer())); -} - -void godotsharp_string_sha256_text(const String *p_self, String *r_sha256_text) { - memnew_placement(r_sha256_text, String(p_self->sha256_text())); -} - void godotsharp_string_simplify_path(const String *p_self, String *r_simplified_path) { memnew_placement(r_simplified_path, String(p_self->simplify_path())); } @@ -1473,12 +1449,6 @@ static const void *unmanaged_callbacks[]{ (void *)godotsharp_dictionary_duplicate, (void *)godotsharp_dictionary_remove_key, (void *)godotsharp_dictionary_to_string, - (void *)godotsharp_string_md5_buffer, - (void *)godotsharp_string_md5_text, - (void *)godotsharp_string_rfind, - (void *)godotsharp_string_rfindn, - (void *)godotsharp_string_sha256_buffer, - (void *)godotsharp_string_sha256_text, (void *)godotsharp_string_simplify_path, (void *)godotsharp_string_to_camel_case, (void *)godotsharp_string_to_pascal_case, diff --git a/modules/noise/editor/noise_editor_plugin.cpp b/modules/noise/editor/noise_editor_plugin.cpp index 47f5f8f819..a8e376e142 100644 --- a/modules/noise/editor/noise_editor_plugin.cpp +++ b/modules/noise/editor/noise_editor_plugin.cpp @@ -34,6 +34,7 @@ #include "editor/editor_inspector.h" #include "editor/editor_scale.h" +#include "scene/gui/button.h" #include "scene/gui/texture_rect.h" #include "modules/noise/noise.h" diff --git a/modules/openxr/extensions/openxr_opengl_extension.cpp b/modules/openxr/extensions/openxr_opengl_extension.cpp index 569030cc11..234c5f8391 100644 --- a/modules/openxr/extensions/openxr_opengl_extension.cpp +++ b/modules/openxr/extensions/openxr_opengl_extension.cpp @@ -138,7 +138,7 @@ void *OpenXROpenGLExtension::set_session_create_and_get_next_pointer(void *p_nex graphics_binding_gl.display = eglGetCurrentDisplay(); graphics_binding_gl.config = (EGLConfig)0; // https://github.com/KhronosGroup/OpenXR-SDK-Source/blob/master/src/tests/hello_xr/graphicsplugin_opengles.cpp#L122 - graphics_binding_gl.context = eglGetCurrentContext(); + graphics_binding_gl.context = (void *)display_server->window_get_native_handle(DisplayServer::OPENGL_CONTEXT); #else graphics_binding_gl.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR; graphics_binding_gl.next = p_next_pointer; diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index d6580ebfa6..59d3865acd 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -51,7 +51,7 @@ #define XR_USE_GRAPHICS_API_VULKAN #endif #ifdef GLES3_ENABLED -#ifdef ANDROID +#ifdef ANDROID_ENABLED #define XR_USE_GRAPHICS_API_OPENGL_ES #include <EGL/egl.h> #include <EGL/eglext.h> @@ -59,7 +59,7 @@ #include <GLES3/gl3ext.h> #else #define XR_USE_GRAPHICS_API_OPENGL -#endif // ANDROID +#endif // ANDROID_ENABLED #ifdef X11_ENABLED #include OPENGL_INCLUDE_H #define GL_GLEXT_PROTOTYPES 1 diff --git a/platform/android/detect.py b/platform/android/detect.py index 57a8d34d0e..d4d6154472 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -161,7 +161,6 @@ def configure(env: "Environment"): "-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden -fno-strict-aliasing".split() ) ) - env.Append(CPPDEFINES=["GLES_ENABLED"]) if get_min_sdk_version(env["ndk_platform"]) >= 24: env.Append(CPPDEFINES=[("_FILE_OFFSET_BITS", 64)]) @@ -184,9 +183,13 @@ def configure(env: "Environment"): env.Prepend(CPPPATH=["#platform/android"]) env.Append(CPPDEFINES=["ANDROID_ENABLED", "UNIX_ENABLED"]) - env.Append(LIBS=["OpenSLES", "EGL", "GLESv2", "android", "log", "z", "dl"]) + env.Append(LIBS=["OpenSLES", "EGL", "android", "log", "z", "dl"]) if env["vulkan"]: env.Append(CPPDEFINES=["VULKAN_ENABLED"]) if not env["use_volk"]: env.Append(LIBS=["vulkan"]) + + if env["opengl3"]: + env.Append(CPPDEFINES=["GLES3_ENABLED"]) + env.Append(LIBS=["GLESv3"]) diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp index 967f5c7dae..f76f3844e9 100644 --- a/platform/android/display_server_android.cpp +++ b/platform/android/display_server_android.cpp @@ -41,6 +41,10 @@ #include "platform/android/vulkan/vulkan_context_android.h" #include "servers/rendering/renderer_rd/renderer_compositor_rd.h" #endif +#ifdef GLES3_ENABLED +#include "drivers/gles3/rasterizer_gles3.h" +#include <EGL/egl.h> +#endif DisplayServerAndroid *DisplayServerAndroid::get_singleton() { return static_cast<DisplayServerAndroid *>(DisplayServer::get_singleton()); @@ -323,7 +327,7 @@ int64_t DisplayServerAndroid::window_get_native_handle(HandleType p_handle_type, } #ifdef GLES3_ENABLED case OPENGL_CONTEXT: { - return eglGetCurrentContext(); + return reinterpret_cast<int64_t>(eglGetCurrentContext()); } #endif default: { @@ -449,6 +453,14 @@ DisplayServer *DisplayServerAndroid::create_func(const String &p_rendering_drive DisplayServer *ds = memnew(DisplayServerAndroid(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, r_error)); if (r_error != OK) { OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan versions.", "Unable to initialize Video driver"); + if (p_rendering_driver == "vulkan") { + OS::get_singleton()->alert("Your video card driver does not support the selected Vulkan version.\n" + "Please try exporting your game using the gl_compatibility renderer.", + "Unable to initialize Video driver"); + } else { + OS::get_singleton()->alert("Your video card driver does not support OpenGL ES 3.0.", + "Unable to initialize Video driver"); + } } return ds; } @@ -493,28 +505,11 @@ void DisplayServerAndroid::notify_surface_changed(int p_width, int p_height) { DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) { rendering_driver = p_rendering_driver; - // TODO: rendering_driver is broken, change when different drivers are supported again - rendering_driver = "vulkan"; - keep_screen_on = GLOBAL_GET("display/window/energy_saving/keep_screen_on"); #if defined(GLES3_ENABLED) if (rendering_driver == "opengl3") { - bool gl_initialization_error = false; - - if (RasterizerGLES3::is_viable() == OK) { - RasterizerGLES3::register_config(); - RasterizerGLES3::make_current(); - } else { - gl_initialization_error = true; - } - - if (gl_initialization_error) { - OS::get_singleton()->alert("Your device does not support any of the supported OpenGL versions.\n" - "Please try updating your Android version.", - "Unable to initialize video driver"); - return; - } + RasterizerGLES3::make_current(); } #endif @@ -619,11 +614,11 @@ MouseButton DisplayServerAndroid::mouse_get_button_state() const { return (MouseButton)Input::get_singleton()->get_mouse_button_mask(); } -void DisplayServerAndroid::cursor_set_shape(DisplayServer::CursorShape p_shape) { +void DisplayServerAndroid::_cursor_set_shape_helper(CursorShape p_shape, bool force) { if (!OS_Android::get_singleton()->get_godot_java()->get_godot_view()->can_update_pointer_icon()) { return; } - if (cursor_shape == p_shape) { + if (cursor_shape == p_shape && !force) { return; } @@ -634,10 +629,23 @@ void DisplayServerAndroid::cursor_set_shape(DisplayServer::CursorShape p_shape) } } +void DisplayServerAndroid::cursor_set_shape(DisplayServer::CursorShape p_shape) { + _cursor_set_shape_helper(p_shape); +} + DisplayServer::CursorShape DisplayServerAndroid::cursor_get_shape() const { return cursor_shape; } +void DisplayServerAndroid::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { + String cursor_path = p_cursor.is_valid() ? p_cursor->get_path() : ""; + if (!cursor_path.is_empty()) { + cursor_path = ProjectSettings::get_singleton()->globalize_path(cursor_path); + } + OS_Android::get_singleton()->get_godot_java()->get_godot_view()->configure_pointer_icon(android_cursors[cursor_shape], cursor_path, p_hotspot); + _cursor_set_shape_helper(p_shape, true); +} + void DisplayServerAndroid::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { #if defined(VULKAN_ENABLED) context_vulkan->set_vsync_mode(p_window, p_vsync_mode); @@ -651,3 +659,23 @@ DisplayServer::VSyncMode DisplayServerAndroid::window_get_vsync_mode(WindowID p_ return DisplayServer::VSYNC_ENABLED; #endif } + +void DisplayServerAndroid::reset_swap_buffers_flag() { + swap_buffers_flag = false; +} + +bool DisplayServerAndroid::should_swap_buffers() const { + return swap_buffers_flag; +} + +void DisplayServerAndroid::swap_buffers() { + swap_buffers_flag = true; +} + +void DisplayServerAndroid::set_native_icon(const String &p_filename) { + // NOT SUPPORTED +} + +void DisplayServerAndroid::set_icon(const Ref<Image> &p_icon) { + // NOT SUPPORTED +} diff --git a/platform/android/display_server_android.h b/platform/android/display_server_android.h index a6bc88e048..c7f4d8046f 100644 --- a/platform/android/display_server_android.h +++ b/platform/android/display_server_android.h @@ -66,6 +66,7 @@ class DisplayServerAndroid : public DisplayServer { MouseMode mouse_mode = MouseMode::MOUSE_MODE_VISIBLE; bool keep_screen_on; + bool swap_buffers_flag; CursorShape cursor_shape = CursorShape::CURSOR_ARROW; @@ -188,8 +189,10 @@ public: void process_magnetometer(const Vector3 &p_magnetometer); void process_gyroscope(const Vector3 &p_gyroscope); + void _cursor_set_shape_helper(CursorShape p_shape, bool force = false); virtual void cursor_set_shape(CursorShape p_shape) override; virtual CursorShape cursor_get_shape() const override; + virtual void cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) override; virtual void mouse_set_mode(MouseMode p_mode) override; virtual MouseMode mouse_get_mode() const override; @@ -204,6 +207,13 @@ public: virtual Point2i mouse_get_position() const override; virtual MouseButton mouse_get_button_state() const override; + void reset_swap_buffers_flag(); + bool should_swap_buffers() const; + virtual void swap_buffers() override; + + virtual void set_native_icon(const String &p_filename) override; + virtual void set_icon(const Ref<Image> &p_icon) override; + DisplayServerAndroid(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error); ~DisplayServerAndroid(); }; diff --git a/platform/android/java/app/AndroidManifest.xml b/platform/android/java/app/AndroidManifest.xml index 2d4c4763a2..1db135826a 100644 --- a/platform/android/java/app/AndroidManifest.xml +++ b/platform/android/java/app/AndroidManifest.xml @@ -13,7 +13,7 @@ android:xlargeScreens="true" /> <uses-feature - android:glEsVersion="0x00020000" + android:glEsVersion="0x00030000" android:required="true" /> <application diff --git a/platform/android/java/editor/src/main/AndroidManifest.xml b/platform/android/java/editor/src/main/AndroidManifest.xml index 6aa5f06f31..f3ddaafd0e 100644 --- a/platform/android/java/editor/src/main/AndroidManifest.xml +++ b/platform/android/java/editor/src/main/AndroidManifest.xml @@ -11,7 +11,7 @@ android:xlargeScreens="true" /> <uses-feature - android:glEsVersion="0x00020000" + android:glEsVersion="0x00030000" android:required="true" /> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java index a002a37ab9..3487e5019c 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java @@ -175,6 +175,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC public GodotIO io; public GodotNetUtils netUtils; public GodotTTS tts; + DirectoryAccessHandler directoryAccessHandler; public interface ResultCallback { void callback(int requestCode, int resultCode, Intent data); @@ -488,7 +489,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC netUtils = new GodotNetUtils(activity); tts = new GodotTTS(activity); Context context = getContext(); - DirectoryAccessHandler directoryAccessHandler = new DirectoryAccessHandler(context); + directoryAccessHandler = new DirectoryAccessHandler(context); FileAccessHandler fileAccessHandler = new FileAccessHandler(context); mSensorManager = (SensorManager)activity.getSystemService(Context.SENSOR_SERVICE); mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java index 3dfc37f6b0..f8d937521b 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java @@ -43,8 +43,13 @@ import org.godotengine.godot.xr.regular.RegularFallbackConfigChooser; import android.annotation.SuppressLint; import android.content.Context; +import android.content.res.AssetManager; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.PixelFormat; import android.os.Build; +import android.text.TextUtils; +import android.util.SparseArray; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.PointerIcon; @@ -52,6 +57,8 @@ import android.view.SurfaceView; import androidx.annotation.Keep; +import java.io.InputStream; + /** * A simple GLSurfaceView sub-class that demonstrate how to perform * OpenGL ES 2.0 rendering into a GL Surface. Note the following important @@ -61,7 +68,7 @@ import androidx.annotation.Keep; * See ContextFactory class definition below. * * - The class must use a custom EGLConfigChooser to be able to select - * an EGLConfig that supports 2.0. This is done by providing a config + * an EGLConfig that supports 3.0. This is done by providing a config * specification to eglChooseConfig() that has the attribute * EGL10.ELG_RENDERABLE_TYPE containing the EGL_OPENGL_ES2_BIT flag * set. See ConfigChooser class definition below. @@ -74,6 +81,7 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView private final Godot godot; private final GodotInputHandler inputHandler; private final GodotRenderer godotRenderer; + private final SparseArray<PointerIcon> customPointerIcons = new SparseArray<>(); public GodotGLRenderView(Context context, Godot godot, XRMode xrMode, boolean p_use_debug_opengl) { super(context); @@ -169,12 +177,49 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView } /** + * Used to configure the PointerIcon for the given type. + * + * Called from JNI + */ + @Keep + @Override + public void configurePointerIcon(int pointerType, String imagePath, float hotSpotX, float hotSpotY) { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { + try { + Bitmap bitmap = null; + if (!TextUtils.isEmpty(imagePath)) { + if (godot.directoryAccessHandler.filesystemFileExists(imagePath)) { + // Try to load the bitmap from the file system + bitmap = BitmapFactory.decodeFile(imagePath); + } else if (godot.directoryAccessHandler.assetsFileExists(imagePath)) { + // Try to load the bitmap from the assets directory + AssetManager am = getContext().getAssets(); + InputStream imageInputStream = am.open(imagePath); + bitmap = BitmapFactory.decodeStream(imageInputStream); + } + } + + PointerIcon customPointerIcon = PointerIcon.create(bitmap, hotSpotX, hotSpotY); + customPointerIcons.put(pointerType, customPointerIcon); + } catch (Exception e) { + // Reset the custom pointer icon + customPointerIcons.delete(pointerType); + } + } + } + + /** * called from JNI to change pointer icon */ @Keep + @Override public void setPointerIcon(int pointerType) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - setPointerIcon(PointerIcon.getSystemIcon(getContext(), pointerType)); + PointerIcon pointerIcon = customPointerIcons.get(pointerType); + if (pointerIcon == null) { + pointerIcon = PointerIcon.getSystemIcon(getContext(), pointerType); + } + setPointerIcon(pointerIcon); } } diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java index cb63fd885f..ab74ba037d 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java @@ -48,5 +48,7 @@ public interface GodotRenderView { GodotInputHandler getInputHandler(); + void configurePointerIcon(int pointerType, String imagePath, float hotSpotX, float hotSpotY); + void setPointerIcon(int pointerType); } diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java index 0becf00d93..56bc7f9e76 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java @@ -36,7 +36,12 @@ import org.godotengine.godot.vulkan.VkSurfaceView; import android.annotation.SuppressLint; import android.content.Context; +import android.content.res.AssetManager; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.os.Build; +import android.text.TextUtils; +import android.util.SparseArray; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.PointerIcon; @@ -44,10 +49,13 @@ import android.view.SurfaceView; import androidx.annotation.Keep; +import java.io.InputStream; + public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderView { private final Godot godot; private final GodotInputHandler mInputHandler; private final VkRenderer mRenderer; + private final SparseArray<PointerIcon> customPointerIcons = new SparseArray<>(); public GodotVulkanRenderView(Context context, Godot godot) { super(context); @@ -143,12 +151,49 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV } /** + * Used to configure the PointerIcon for the given type. + * + * Called from JNI + */ + @Keep + @Override + public void configurePointerIcon(int pointerType, String imagePath, float hotSpotX, float hotSpotY) { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { + try { + Bitmap bitmap = null; + if (!TextUtils.isEmpty(imagePath)) { + if (godot.directoryAccessHandler.filesystemFileExists(imagePath)) { + // Try to load the bitmap from the file system + bitmap = BitmapFactory.decodeFile(imagePath); + } else if (godot.directoryAccessHandler.assetsFileExists(imagePath)) { + // Try to load the bitmap from the assets directory + AssetManager am = getContext().getAssets(); + InputStream imageInputStream = am.open(imagePath); + bitmap = BitmapFactory.decodeStream(imageInputStream); + } + } + + PointerIcon customPointerIcon = PointerIcon.create(bitmap, hotSpotX, hotSpotY); + customPointerIcons.put(pointerType, customPointerIcon); + } catch (Exception e) { + // Reset the custom pointer icon + customPointerIcons.delete(pointerType); + } + } + } + + /** * called from JNI to change pointer icon */ @Keep + @Override public void setPointerIcon(int pointerType) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - setPointerIcon(PointerIcon.getSystemIcon(getContext(), pointerType)); + PointerIcon pointerIcon = customPointerIcons.get(pointerType); + if (pointerIcon == null) { + pointerIcon = PointerIcon.getSystemIcon(getContext(), pointerType); + } + setPointerIcon(pointerIcon); } } diff --git a/platform/android/java/lib/src/org/godotengine/godot/io/directory/DirectoryAccessHandler.kt b/platform/android/java/lib/src/org/godotengine/godot/io/directory/DirectoryAccessHandler.kt index fedcf4843f..6bc317415f 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/io/directory/DirectoryAccessHandler.kt +++ b/platform/android/java/lib/src/org/godotengine/godot/io/directory/DirectoryAccessHandler.kt @@ -79,6 +79,9 @@ class DirectoryAccessHandler(context: Context) { private val assetsDirAccess = AssetsDirectoryAccess(context) private val fileSystemDirAccess = FilesystemDirectoryAccess(context) + fun assetsFileExists(assetsPath: String) = assetsDirAccess.fileExists(assetsPath) + fun filesystemFileExists(path: String) = fileSystemDirAccess.fileExists(path) + private fun hasDirId(accessType: AccessType, dirId: Int): Boolean { return when (accessType) { ACCESS_RESOURCES -> assetsDirAccess.hasDirId(dirId) diff --git a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularConfigChooser.java b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularConfigChooser.java index 445238b1c2..9834fdfb88 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularConfigChooser.java +++ b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularConfigChooser.java @@ -45,20 +45,18 @@ public class RegularConfigChooser implements GLSurfaceView.EGLConfigChooser { private int[] mValue = new int[1]; - // FIXME: Add support for Vulkan. - - /* This EGL config specification is used to specify 2.0 rendering. + /* This EGL config specification is used to specify 3.0 rendering. * We use a minimum size of 4 bits for red/green/blue, but will * perform actual matching in chooseConfig() below. */ private static int EGL_OPENGL_ES2_BIT = 4; - private static int[] s_configAttribs2 = { + private static int[] s_configAttribs = { EGL10.EGL_RED_SIZE, 4, EGL10.EGL_GREEN_SIZE, 4, EGL10.EGL_BLUE_SIZE, 4, - // EGL10.EGL_DEPTH_SIZE, 16, + // EGL10.EGL_DEPTH_SIZE, 16, // EGL10.EGL_STENCIL_SIZE, EGL10.EGL_DONT_CARE, - EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, //apparently there is no EGL_OPENGL_ES3_BIT EGL10.EGL_NONE }; @@ -75,7 +73,7 @@ public class RegularConfigChooser implements GLSurfaceView.EGLConfigChooser { /* Get the number of minimally matching EGL configurations */ int[] num_config = new int[1]; - egl.eglChooseConfig(display, s_configAttribs2, null, 0, num_config); + egl.eglChooseConfig(display, s_configAttribs, null, 0, num_config); int numConfigs = num_config[0]; @@ -86,7 +84,7 @@ public class RegularConfigChooser implements GLSurfaceView.EGLConfigChooser { /* Allocate then read the array of minimally matching EGL configs */ EGLConfig[] configs = new EGLConfig[numConfigs]; - egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs, num_config); + egl.eglChooseConfig(display, s_configAttribs, configs, numConfigs, num_config); if (GLUtils.DEBUG) { GLUtils.printConfigs(egl, display, configs); diff --git a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java index 5d62723170..8fb86bf6d0 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java +++ b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java @@ -52,17 +52,16 @@ public class RegularContextFactory implements GLSurfaceView.EGLContextFactory { private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098; public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) { - // FIXME: Add support for Vulkan. - Log.w(TAG, "creating OpenGL ES 2.0 context :"); + Log.w(TAG, "creating OpenGL ES 3.0 context :"); GLUtils.checkEglError(TAG, "Before eglCreateContext", egl); EGLContext context; if (GLUtils.use_debug_opengl) { - int[] attrib_list2 = { EGL_CONTEXT_CLIENT_VERSION, 2, _EGL_CONTEXT_FLAGS_KHR, _EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR, EGL10.EGL_NONE }; - context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list2); + int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 3, _EGL_CONTEXT_FLAGS_KHR, _EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR, EGL10.EGL_NONE }; + context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); } else { - int[] attrib_list2 = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE }; - context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list2); + int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL10.EGL_NONE }; + context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); } GLUtils.checkEglError(TAG, "After eglCreateContext", egl); return context; diff --git a/platform/android/java/nativeSrcsConfigs/CMakeLists.txt b/platform/android/java/nativeSrcsConfigs/CMakeLists.txt index 711f7cd502..1325063a57 100644 --- a/platform/android/java/nativeSrcsConfigs/CMakeLists.txt +++ b/platform/android/java/nativeSrcsConfigs/CMakeLists.txt @@ -17,4 +17,4 @@ target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC ${GODOT_ROOT_DIR}) -add_definitions(-DUNIX_ENABLED -DVULKAN_ENABLED -DANDROID_ENABLED) +add_definitions(-DUNIX_ENABLED -DVULKAN_ENABLED -DANDROID_ENABLED -DGLES3_ENABLED) diff --git a/platform/android/java_godot_view_wrapper.cpp b/platform/android/java_godot_view_wrapper.cpp index 378a467772..23cfc5f2e6 100644 --- a/platform/android/java_godot_view_wrapper.cpp +++ b/platform/android/java_godot_view_wrapper.cpp @@ -42,6 +42,7 @@ GodotJavaViewWrapper::GodotJavaViewWrapper(jobject godot_view) { int android_device_api_level = android_get_device_api_level(); if (android_device_api_level >= __ANDROID_API_N__) { + _configure_pointer_icon = env->GetMethodID(_cls, "configurePointerIcon", "(ILjava/lang/String;FF)V"); _set_pointer_icon = env->GetMethodID(_cls, "setPointerIcon", "(I)V"); } if (android_device_api_level >= __ANDROID_API_O__) { @@ -51,7 +52,7 @@ GodotJavaViewWrapper::GodotJavaViewWrapper(jobject godot_view) { } bool GodotJavaViewWrapper::can_update_pointer_icon() const { - return _set_pointer_icon != nullptr; + return _configure_pointer_icon != nullptr && _set_pointer_icon != nullptr; } bool GodotJavaViewWrapper::can_capture_pointer() const { @@ -76,6 +77,16 @@ void GodotJavaViewWrapper::release_pointer_capture() { } } +void GodotJavaViewWrapper::configure_pointer_icon(int pointer_type, const String &image_path, const Vector2 &p_hotspot) { + if (_configure_pointer_icon != nullptr) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_NULL(env); + + jstring jImagePath = env->NewStringUTF(image_path.utf8().get_data()); + env->CallVoidMethod(_godot_view, _configure_pointer_icon, pointer_type, jImagePath, p_hotspot.x, p_hotspot.y); + } +} + void GodotJavaViewWrapper::set_pointer_icon(int pointer_type) { if (_set_pointer_icon != nullptr) { JNIEnv *env = get_jni_env(); diff --git a/platform/android/java_godot_view_wrapper.h b/platform/android/java_godot_view_wrapper.h index b398c73cac..b58a6607ce 100644 --- a/platform/android/java_godot_view_wrapper.h +++ b/platform/android/java_godot_view_wrapper.h @@ -31,6 +31,7 @@ #ifndef JAVA_GODOT_VIEW_WRAPPER_H #define JAVA_GODOT_VIEW_WRAPPER_H +#include "core/math/vector2.h" #include <android/log.h> #include <jni.h> @@ -45,6 +46,8 @@ private: jmethodID _request_pointer_capture = 0; jmethodID _release_pointer_capture = 0; + + jmethodID _configure_pointer_icon = 0; jmethodID _set_pointer_icon = 0; public: @@ -55,6 +58,8 @@ public: void request_pointer_capture(); void release_pointer_capture(); + + void configure_pointer_icon(int pointer_type, const String &image_path, const Vector2 &p_hotspot); void set_pointer_icon(int pointer_type); ~GodotJavaViewWrapper(); diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 97fa90b1d2..4f81e4bccd 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -268,12 +268,16 @@ bool OS_Android::main_loop_iterate(bool *r_should_swap_buffers) { if (!main_loop) { return false; } + DisplayServerAndroid::get_singleton()->reset_swap_buffers_flag(); DisplayServerAndroid::get_singleton()->process_events(); uint64_t current_frames_drawn = Engine::get_singleton()->get_frames_drawn(); bool exit = Main::iteration(); if (r_should_swap_buffers) { - *r_should_swap_buffers = !is_in_low_processor_usage_mode() || RenderingServer::get_singleton()->has_changed() || current_frames_drawn != Engine::get_singleton()->get_frames_drawn(); + *r_should_swap_buffers = !is_in_low_processor_usage_mode() || + DisplayServerAndroid::get_singleton()->should_swap_buffers() || + RenderingServer::get_singleton()->has_changed() || + current_frames_drawn != Engine::get_singleton()->get_frames_drawn(); } return exit; @@ -474,7 +478,6 @@ OS_Android::OS_Android(GodotJavaWrapper *p_godot_java, GodotIOJavaWrapper *p_god #if defined(GLES3_ENABLED) gl_extensions = nullptr; - use_gl2 = false; #endif #if defined(VULKAN_ENABLED) diff --git a/platform/ios/app_delegate.mm b/platform/ios/app_delegate.mm index fb183d52d4..3ebd530585 100644 --- a/platform/ios/app_delegate.mm +++ b/platform/ios/app_delegate.mm @@ -45,7 +45,7 @@ extern int gargc; extern char **gargv; -extern int ios_main(int, char **, String, String); +extern int ios_main(int, char **); extern void ios_finish(); @implementation AppDelegate @@ -66,12 +66,7 @@ static ViewController *mainViewController = nil; // Create a full-screen window self.window = [[UIWindow alloc] initWithFrame:windowBounds]; - NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); - NSString *documentsDirectory = [paths objectAtIndex:0]; - paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); - NSString *cacheDirectory = [paths objectAtIndex:0]; - - int err = ios_main(gargc, gargv, String::utf8([documentsDirectory UTF8String]), String::utf8([cacheDirectory UTF8String])); + int err = ios_main(gargc, gargv); if (err != 0) { // bail, things did not go very well for us, should probably output a message on screen with our error code... diff --git a/platform/ios/godot_ios.mm b/platform/ios/godot_ios.mm index 5f3e786b8a..abe7c59ce2 100644 --- a/platform/ios/godot_ios.mm +++ b/platform/ios/godot_ios.mm @@ -38,10 +38,6 @@ static OS_IOS *os = nullptr; -int add_path(int, char **); -int add_cmdline(int, char **); -int ios_main(int, char **, String); - int add_path(int p_argc, char **p_args) { NSString *str = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"godot_path"]; if (!str) { @@ -74,7 +70,7 @@ int add_cmdline(int p_argc, char **p_args) { return p_argc; } -int ios_main(int argc, char **argv, String data_dir, String cache_dir) { +int ios_main(int argc, char **argv) { size_t len = strlen(argv[0]); while (len--) { @@ -95,7 +91,7 @@ int ios_main(int argc, char **argv, String data_dir, String cache_dir) { char cwd[512]; getcwd(cwd, sizeof(cwd)); printf("cwd %s\n", cwd); - os = new OS_IOS(data_dir, cache_dir); + os = new OS_IOS(); // We must override main when testing is enabled TEST_MAIN_OVERRIDE diff --git a/platform/ios/os_ios.h b/platform/ios/os_ios.h index 400040875f..3560de7486 100644 --- a/platform/ios/os_ios.h +++ b/platform/ios/os_ios.h @@ -71,9 +71,6 @@ private: virtual void finalize() override; - String user_data_dir; - String cache_dir; - bool is_focused = false; void deinitialize_modules(); @@ -81,7 +78,7 @@ private: public: static OS_IOS *get_singleton(); - OS_IOS(String p_data_dir, String p_cache_dir); + OS_IOS(); ~OS_IOS(); void initialize_modules(); @@ -106,7 +103,6 @@ public: virtual Error shell_open(String p_uri) override; - void set_user_data_dir(String p_dir); virtual String get_user_data_dir() const override; virtual String get_cache_path() const override; diff --git a/platform/ios/os_ios.mm b/platform/ios/os_ios.mm index b6b94d2f5e..9a8cfc2593 100644 --- a/platform/ios/os_ios.mm +++ b/platform/ios/os_ios.mm @@ -90,7 +90,7 @@ OS_IOS *OS_IOS::get_singleton() { return (OS_IOS *)OS::get_singleton(); } -OS_IOS::OS_IOS(String p_data_dir, String p_cache_dir) { +OS_IOS::OS_IOS() { for (int i = 0; i < ios_init_callbacks_count; ++i) { ios_init_callbacks[i](); } @@ -101,11 +101,6 @@ OS_IOS::OS_IOS(String p_data_dir, String p_cache_dir) { main_loop = nullptr; - // can't call set_data_dir from here, since it requires DirAccess - // which is initialized in initialize_core - user_data_dir = p_data_dir; - cache_dir = p_cache_dir; - Vector<Logger *> loggers; loggers.push_back(memnew(SyslogLogger)); #ifdef DEBUG_ENABLED @@ -130,8 +125,6 @@ void OS_IOS::alert(const String &p_alert, const String &p_title) { void OS_IOS::initialize_core() { OS_Unix::initialize_core(); - - set_user_data_dir(user_data_dir); } void OS_IOS::initialize() { @@ -273,18 +266,26 @@ Error OS_IOS::shell_open(String p_uri) { return OK; } -void OS_IOS::set_user_data_dir(String p_dir) { - Ref<DirAccess> da = DirAccess::open(p_dir); - user_data_dir = da->get_current_dir(); - printf("setting data dir to %s from %s\n", user_data_dir.utf8().get_data(), p_dir.utf8().get_data()); -} - String OS_IOS::get_user_data_dir() const { - return user_data_dir; + static String ret; + if (ret.is_empty()) { + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + if (paths && [paths count] >= 1) { + ret.parse_utf8([[paths firstObject] UTF8String]); + } + } + return ret; } String OS_IOS::get_cache_path() const { - return cache_dir; + static String ret; + if (ret.is_empty()) { + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); + if (paths && [paths count] >= 1) { + ret.parse_utf8([[paths firstObject] UTF8String]); + } + } + return ret; } String OS_IOS::get_locale() const { diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm index 3aff5b8b7e..a3bee13f69 100644 --- a/platform/macos/display_server_macos.mm +++ b/platform/macos/display_server_macos.mm @@ -2348,9 +2348,6 @@ void DisplayServerMacOS::reparent_check(WindowID p_window) { if (parent_screen == screen) { if (![[wd_parent.window_object childWindows] containsObject:wd.window_object]) { - if (wd.exclusive) { - ERR_FAIL_COND_MSG([[wd_parent.window_object childWindows] count] > 0, "Transient parent has another exclusive child."); - } [wd.window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; [wd_parent.window_object addChildWindow:wd.window_object ordered:NSWindowAbove]; } @@ -2369,9 +2366,6 @@ void DisplayServerMacOS::reparent_check(WindowID p_window) { if (child_screen == screen) { if (![[wd.window_object childWindows] containsObject:wd_child.window_object]) { - if (wd_child.exclusive) { - ERR_FAIL_COND_MSG([[wd.window_object childWindows] count] > 0, "Transient parent has another exclusive child."); - } if (wd_child.fullscreen) { [wd_child.window_object toggleFullScreen:nil]; } diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp index 5860a4f0ae..5e71d10a3f 100644 --- a/platform/macos/export/export_plugin.cpp +++ b/platform/macos/export/export_plugin.cpp @@ -1834,8 +1834,8 @@ bool EditorExportPlatformMacOS::has_valid_project_configuration(const Ref<Editor if (p_preset->get("notarization/apple_id_name") != "") { if (p_preset->get("notarization/apple_id_password") == "") { err += TTR("Notarization: Apple ID password not specified.") + "\n"; + valid = false; } - valid = false; } if (p_preset->get("notarization/api_uuid") != "") { if (p_preset->get("notarization/api_key") == "") { diff --git a/platform/web/js/engine/features.js b/platform/web/js/engine/features.js index f91a4eff81..b7c6c9d445 100644 --- a/platform/web/js/engine/features.js +++ b/platform/web/js/engine/features.js @@ -76,19 +76,19 @@ const Features = { // eslint-disable-line no-unused-vars getMissingFeatures: function () { const missing = []; if (!Features.isWebGLAvailable(2)) { - missing.push('WebGL2'); + missing.push('WebGL2 - Check web browser configuration and hardware support'); } if (!Features.isFetchAvailable()) { - missing.push('Fetch'); + missing.push('Fetch - Check web browser version'); } if (!Features.isSecureContext()) { - missing.push('Secure Context'); + missing.push('Secure Context - Check web server configuration (use HTTPS)'); } if (!Features.isCrossOriginIsolated()) { - missing.push('Cross Origin Isolation'); + missing.push('Cross Origin Isolation - Check web server configuration (send correct headers)'); } if (!Features.isSharedArrayBufferAvailable()) { - missing.push('SharedArrayBuffer'); + missing.push('SharedArrayBuffer - Check web server configuration (send correct headers)'); } // Audio is normally optional since we have a dummy fallback. return missing; diff --git a/platform/windows/crash_handler_windows.cpp b/platform/windows/crash_handler_windows.cpp index b501ee78db..7ba66750cf 100644 --- a/platform/windows/crash_handler_windows.cpp +++ b/platform/windows/crash_handler_windows.cpp @@ -157,7 +157,7 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) { return EXCEPTION_CONTINUE_SEARCH; } - SymSetOptions(SymGetOptions() | SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); + SymSetOptions(SymGetOptions() | SYMOPT_LOAD_LINES | SYMOPT_UNDNAME | SYMOPT_EXACT_SYMBOLS); EnumProcessModules(process, &module_handles[0], module_handles.size() * sizeof(HMODULE), &cbNeeded); module_handles.resize(cbNeeded / sizeof(HMODULE)); EnumProcessModules(process, &module_handles[0], module_handles.size() * sizeof(HMODULE), &cbNeeded); diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 0b878feb7f..29482213d8 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -3919,6 +3919,8 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win WindowID main_window = _create_window(p_mode, p_vsync_mode, 0, Rect2i(window_position, p_resolution)); ERR_FAIL_COND_MSG(main_window == INVALID_WINDOW_ID, "Failed to create main window."); + joypad = new JoypadWindows(&windows[MAIN_WINDOW_ID].hWnd); + for (int i = 0; i < WINDOW_FLAG_MAX; i++) { if (p_flags & (1 << i)) { window_set_flag(WindowFlags(i), true, main_window); @@ -3958,8 +3960,6 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win _update_real_mouse_position(MAIN_WINDOW_ID); - joypad = new JoypadWindows(&windows[MAIN_WINDOW_ID].hWnd); - r_error = OK; static_cast<OS_Windows *>(OS::get_singleton())->set_main_window(windows[MAIN_WINDOW_ID].hWnd); diff --git a/platform/windows/godot.ico b/platform/windows/godot.ico Binary files differindex 25830ffdc6..f0bb68225d 100644 --- a/platform/windows/godot.ico +++ b/platform/windows/godot.ico diff --git a/platform/windows/godot_console.ico b/platform/windows/godot_console.ico Binary files differnew file mode 100644 index 0000000000..1d27e3d6ae --- /dev/null +++ b/platform/windows/godot_console.ico diff --git a/platform/windows/godot_res_wrap.rc b/platform/windows/godot_res_wrap.rc index 9877ff6075..9dd29afe51 100644 --- a/platform/windows/godot_res_wrap.rc +++ b/platform/windows/godot_res_wrap.rc @@ -4,7 +4,7 @@ #define _MKSTR(m_x) _STR(m_x) #endif -GODOT_ICON ICON platform/windows/godot.ico +GODOT_ICON ICON platform/windows/godot_console.ico 1 VERSIONINFO FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,0 diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index 6e8ecb13b1..13d371042b 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -296,7 +296,9 @@ void NavigationPolygon::make_polygons_from_outlines() { TPPLPartition tpart; if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { //failed! - ERR_PRINT("NavigationPolygon: Convex partition failed!"); + ERR_PRINT("NavigationPolygon: Convex partition failed! Failed to convert outlines to a valid NavigationMesh." + "\nNavigationPolygon outlines can not overlap vertices or edges inside same outline or with other outlines or have any intersections." + "\nAdd the outmost and largest outline first. To add holes inside this outline add the smaller outlines with opposite winding order."); return; } diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp index 2518069b78..4788a1b813 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -30,6 +30,8 @@ #include "node_2d.h" +#include "scene/main/viewport.h" + #ifdef TOOLS_ENABLED Dictionary Node2D::_edit_get_state() const { Dictionary state; @@ -326,29 +328,6 @@ void Node2D::set_global_transform(const Transform2D &p_transform) { } } -void Node2D::set_z_index(int p_z) { - ERR_FAIL_COND(p_z < RS::CANVAS_ITEM_Z_MIN); - ERR_FAIL_COND(p_z > RS::CANVAS_ITEM_Z_MAX); - z_index = p_z; - RS::get_singleton()->canvas_item_set_z_index(get_canvas_item(), z_index); -} - -void Node2D::set_z_as_relative(bool p_enabled) { - if (z_relative == p_enabled) { - return; - } - z_relative = p_enabled; - RS::get_singleton()->canvas_item_set_z_as_relative_to_parent(get_canvas_item(), p_enabled); -} - -bool Node2D::is_z_relative() const { - return z_relative; -} - -int Node2D::get_z_index() const { - return z_index; -} - Transform2D Node2D::get_relative_transform_to_parent(const Node *p_parent) const { if (p_parent == this) { return Transform2D(); @@ -380,13 +359,14 @@ Point2 Node2D::to_global(Point2 p_local) const { return get_global_transform().xform(p_local); } -void Node2D::set_y_sort_enabled(bool p_enabled) { - y_sort_enabled = p_enabled; - RS::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(), y_sort_enabled); -} - -bool Node2D::is_y_sort_enabled() const { - return y_sort_enabled; +void Node2D::_notification(int p_notification) { + switch (p_notification) { + case NOTIFICATION_MOVED_IN_PARENT: { + if (get_viewport()) { + get_viewport()->gui_set_root_order_dirty(); + } + } break; + } } void Node2D::_bind_methods() { @@ -425,15 +405,6 @@ void Node2D::_bind_methods() { ClassDB::bind_method(D_METHOD("to_local", "global_point"), &Node2D::to_local); ClassDB::bind_method(D_METHOD("to_global", "local_point"), &Node2D::to_global); - ClassDB::bind_method(D_METHOD("set_z_index", "z_index"), &Node2D::set_z_index); - ClassDB::bind_method(D_METHOD("get_z_index"), &Node2D::get_z_index); - - ClassDB::bind_method(D_METHOD("set_z_as_relative", "enable"), &Node2D::set_z_as_relative); - ClassDB::bind_method(D_METHOD("is_z_relative"), &Node2D::is_z_relative); - - ClassDB::bind_method(D_METHOD("set_y_sort_enabled", "enabled"), &Node2D::set_y_sort_enabled); - ClassDB::bind_method(D_METHOD("is_y_sort_enabled"), &Node2D::is_y_sort_enabled); - ClassDB::bind_method(D_METHOD("get_relative_transform_to_parent", "parent"), &Node2D::get_relative_transform_to_parent); ADD_GROUP("Transform", ""); @@ -448,9 +419,4 @@ void Node2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_scale", "get_global_scale"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "global_skew", PROPERTY_HINT_NONE, "radians", PROPERTY_USAGE_NONE), "set_global_skew", "get_global_skew"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "global_transform", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NONE), "set_global_transform", "get_global_transform"); - - ADD_GROUP("Ordering", ""); - ADD_PROPERTY(PropertyInfo(Variant::INT, "z_index", PROPERTY_HINT_RANGE, itos(RS::CANVAS_ITEM_Z_MIN) + "," + itos(RS::CANVAS_ITEM_Z_MAX) + ",1"), "set_z_index", "get_z_index"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "z_as_relative"), "set_z_as_relative", "is_z_relative"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "y_sort_enabled"), "set_y_sort_enabled", "is_y_sort_enabled"); } diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h index 0d8a31e6bb..76707dc422 100644 --- a/scene/2d/node_2d.h +++ b/scene/2d/node_2d.h @@ -40,9 +40,6 @@ class Node2D : public CanvasItem { real_t rotation = 0.0; Size2 scale = Vector2(1, 1); real_t skew = 0.0; - int z_index = 0; - bool z_relative = true; - bool y_sort_enabled = false; Transform2D transform; @@ -53,6 +50,7 @@ class Node2D : public CanvasItem { void _update_xform_values(); protected: + void _notification(int p_notification); static void _bind_methods(); public: @@ -102,21 +100,12 @@ public: void set_global_skew(const real_t p_radians); void set_global_scale(const Size2 &p_scale); - void set_z_index(int p_z); - int get_z_index() const; - void look_at(const Vector2 &p_pos); real_t get_angle_to(const Vector2 &p_pos) const; Point2 to_local(Point2 p_global) const; Point2 to_global(Point2 p_local) const; - void set_z_as_relative(bool p_enabled); - bool is_z_relative() const; - - virtual void set_y_sort_enabled(bool p_enabled); - virtual bool is_y_sort_enabled() const; - Transform2D get_relative_transform_to_parent(const Node *p_parent) const; Transform2D get_transform() const override; diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp index ca23fe03a2..66546092f2 100644 --- a/scene/3d/collision_object_3d.cpp +++ b/scene/3d/collision_object_3d.cpp @@ -30,6 +30,7 @@ #include "collision_object_3d.h" +#include "scene/resources/shape_3d.h" #include "scene/scene_string_names.h" void CollisionObject3D::_notification(int p_what) { diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp index 2c5df48b75..476820b1c4 100644 --- a/scene/3d/gpu_particles_collision_3d.cpp +++ b/scene/3d/gpu_particles_collision_3d.cpp @@ -347,7 +347,9 @@ void GPUParticlesCollisionSDF3D::_compute_sdf(ComputeSDFParams *params) { WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &GPUParticlesCollisionSDF3D::_compute_sdf_z, params, params->size.z); while (!WorkerThreadPool::get_singleton()->is_group_task_completed(group_task)) { OS::get_singleton()->delay_usec(10000); - bake_step_function(WorkerThreadPool::get_singleton()->get_group_processed_element_count(group_task) * 100 / params->size.z, "Baking SDF"); + if (bake_step_function) { + bake_step_function(WorkerThreadPool::get_singleton()->get_group_processed_element_count(group_task) * 100 / params->size.z, "Baking SDF"); + } } WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task); } diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp index d4f60503c2..04d164ba88 100644 --- a/scene/3d/mesh_instance_3d.cpp +++ b/scene/3d/mesh_instance_3d.cpp @@ -33,6 +33,8 @@ #include "collision_shape_3d.h" #include "core/core_string_names.h" #include "physics_body_3d.h" +#include "scene/resources/concave_polygon_shape_3d.h" +#include "scene/resources/convex_polygon_shape_3d.h" bool MeshInstance3D::_set(const StringName &p_name, const Variant &p_value) { //this is not _too_ bad performance wise, really. it only arrives here if the property was not set anywhere else. @@ -224,7 +226,7 @@ Node *MeshInstance3D::create_trimesh_collision_node() { return nullptr; } - Ref<Shape3D> shape = mesh->create_trimesh_shape(); + Ref<ConcavePolygonShape3D> shape = mesh->create_trimesh_shape(); if (shape.is_null()) { return nullptr; } @@ -254,7 +256,7 @@ Node *MeshInstance3D::create_convex_collision_node(bool p_clean, bool p_simplify return nullptr; } - Ref<Shape3D> shape = mesh->create_convex_shape(p_clean, p_simplify); + Ref<ConvexPolygonShape3D> shape = mesh->create_convex_shape(p_clean, p_simplify); if (shape.is_null()) { return nullptr; } diff --git a/scene/3d/spring_arm_3d.cpp b/scene/3d/spring_arm_3d.cpp index f855fce318..6d8ce06524 100644 --- a/scene/3d/spring_arm_3d.cpp +++ b/scene/3d/spring_arm_3d.cpp @@ -31,6 +31,7 @@ #include "spring_arm_3d.h" #include "scene/3d/camera_3d.h" +#include "scene/resources/shape_3d.h" void SpringArm3D::_notification(int p_what) { switch (p_what) { diff --git a/scene/animation/animation_blend_space_1d.cpp b/scene/animation/animation_blend_space_1d.cpp index 3153572517..4b325ee464 100644 --- a/scene/animation/animation_blend_space_1d.cpp +++ b/scene/animation/animation_blend_space_1d.cpp @@ -230,14 +230,14 @@ void AnimationNodeBlendSpace1D::_add_blend_point(int p_index, const Ref<Animatio } } -double AnimationNodeBlendSpace1D::process(double p_time, bool p_seek, bool p_seek_root) { +double AnimationNodeBlendSpace1D::process(double p_time, bool p_seek, bool p_is_external_seeking) { if (blend_points_used == 0) { return 0.0; } if (blend_points_used == 1) { // only one point available, just play that animation - return blend_node(blend_points[0].name, blend_points[0].node, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, true); + return blend_node(blend_points[0].name, blend_points[0].node, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true); } double blend_pos = get_parameter(blend_position); @@ -307,10 +307,10 @@ double AnimationNodeBlendSpace1D::process(double p_time, bool p_seek, bool p_see for (int i = 0; i < blend_points_used; i++) { if (i == point_lower || i == point_higher) { - double remaining = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, weights[i], FILTER_IGNORE, true); + double remaining = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, weights[i], FILTER_IGNORE, true); max_time_remaining = MAX(max_time_remaining, remaining); } else if (sync) { - blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, true); + blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true); } } diff --git a/scene/animation/animation_blend_space_1d.h b/scene/animation/animation_blend_space_1d.h index 1876ccebc7..30cfe52c8e 100644 --- a/scene/animation/animation_blend_space_1d.h +++ b/scene/animation/animation_blend_space_1d.h @@ -98,7 +98,7 @@ public: void set_use_sync(bool p_sync); bool is_using_sync() const; - double process(double p_time, bool p_seek, bool p_seek_root) override; + double process(double p_time, bool p_seek, bool p_is_external_seeking) override; String get_caption() const override; Ref<AnimationNode> get_child_by_name(const StringName &p_name) override; diff --git a/scene/animation/animation_blend_space_2d.cpp b/scene/animation/animation_blend_space_2d.cpp index b376f668ad..4e20429ac9 100644 --- a/scene/animation/animation_blend_space_2d.cpp +++ b/scene/animation/animation_blend_space_2d.cpp @@ -432,7 +432,7 @@ void AnimationNodeBlendSpace2D::_blend_triangle(const Vector2 &p_pos, const Vect r_weights[2] = w; } -double AnimationNodeBlendSpace2D::process(double p_time, bool p_seek, bool p_seek_root) { +double AnimationNodeBlendSpace2D::process(double p_time, bool p_seek, bool p_is_external_seeking) { _update_triangles(); Vector2 blend_pos = get_parameter(blend_position); @@ -502,7 +502,7 @@ double AnimationNodeBlendSpace2D::process(double p_time, bool p_seek, bool p_see for (int j = 0; j < 3; j++) { if (i == triangle_points[j]) { //blend with the given weight - double t = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, blend_weights[j], FILTER_IGNORE, true); + double t = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, blend_weights[j], FILTER_IGNORE, true); if (first || t < mind) { mind = t; first = false; @@ -513,7 +513,7 @@ double AnimationNodeBlendSpace2D::process(double p_time, bool p_seek, bool p_see } if (sync && !found) { - blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, true); + blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true); } } } else { @@ -538,22 +538,22 @@ double AnimationNodeBlendSpace2D::process(double p_time, bool p_seek, bool p_see na_n->set_backward(na_c->is_backward()); } //see how much animation remains - from = cur_length_internal - blend_node(blend_points[cur_closest].name, blend_points[cur_closest].node, p_time, false, p_seek_root, 0.0, FILTER_IGNORE, true); + from = cur_length_internal - blend_node(blend_points[cur_closest].name, blend_points[cur_closest].node, p_time, false, p_is_external_seeking, 0.0, FILTER_IGNORE, true); } - mind = blend_node(blend_points[new_closest].name, blend_points[new_closest].node, from, true, p_seek_root, 1.0, FILTER_IGNORE, true); + mind = blend_node(blend_points[new_closest].name, blend_points[new_closest].node, from, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true); cur_length_internal = from + mind; cur_closest = new_closest; } else { - mind = blend_node(blend_points[cur_closest].name, blend_points[cur_closest].node, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, true); + mind = blend_node(blend_points[cur_closest].name, blend_points[cur_closest].node, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true); } if (sync) { for (int i = 0; i < blend_points_used; i++) { if (i != cur_closest) { - blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, true); + blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true); } } } diff --git a/scene/animation/animation_blend_space_2d.h b/scene/animation/animation_blend_space_2d.h index 250189f202..41854f73a4 100644 --- a/scene/animation/animation_blend_space_2d.h +++ b/scene/animation/animation_blend_space_2d.h @@ -128,7 +128,7 @@ public: void set_y_label(const String &p_label); String get_y_label() const; - virtual double process(double p_time, bool p_seek, bool p_seek_root) override; + virtual double process(double p_time, bool p_seek, bool p_is_external_seeking) override; virtual String get_caption() const override; Vector2 get_closest_point(const Vector2 &p_point); diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index 846c102e3f..015b5b27e3 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -64,7 +64,7 @@ void AnimationNodeAnimation::_validate_property(PropertyInfo &p_property) const } } -double AnimationNodeAnimation::process(double p_time, bool p_seek, bool p_seek_root) { +double AnimationNodeAnimation::process(double p_time, bool p_seek, bool p_is_external_seeking) { AnimationPlayer *ap = state->player; ERR_FAIL_COND_V(!ap, 0); @@ -115,12 +115,13 @@ double AnimationNodeAnimation::process(double p_time, bool p_seek, bool p_seek_r } cur_time = Math::pingpong(cur_time, anim_size); } + } else if (anim->get_loop_mode() == Animation::LOOP_LINEAR) { + if (!Math::is_zero_approx(anim_size)) { + cur_time = Math::fposmod(cur_time, anim_size); + } + backward = false; } else { - if (anim->get_loop_mode() == Animation::LOOP_LINEAR) { - if (!Math::is_zero_approx(anim_size)) { - cur_time = Math::fposmod(cur_time, anim_size); - } - } else if (cur_time < 0) { + if (cur_time < 0) { step += cur_time; cur_time = 0; } else if (cur_time > anim_size) { @@ -128,12 +129,25 @@ double AnimationNodeAnimation::process(double p_time, bool p_seek, bool p_seek_r cur_time = anim_size; } backward = false; + + // If ended, don't progress animation. So set delta to 0. + if (p_time > 0) { + if (play_mode == PLAY_MODE_FORWARD) { + if (prev_time >= anim_size) { + step = 0; + } + } else { + if (prev_time <= 0) { + step = 0; + } + } + } } if (play_mode == PLAY_MODE_FORWARD) { - blend_animation(animation, cur_time, step, p_seek, p_seek_root, 1.0, pingponged); + blend_animation(animation, cur_time, step, p_seek, p_is_external_seeking, 1.0, pingponged); } else { - blend_animation(animation, anim_size - cur_time, -step, p_seek, p_seek_root, 1.0, pingponged); + blend_animation(animation, anim_size - cur_time, -step, p_seek, p_is_external_seeking, 1.0, pingponged); } set_parameter(time, cur_time); @@ -273,7 +287,7 @@ bool AnimationNodeOneShot::has_filter() const { return true; } -double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_seek_root) { +double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_is_external_seeking) { bool cur_active = get_parameter(active); bool cur_prev_active = get_parameter(prev_active); double cur_time = get_parameter(time); @@ -296,7 +310,7 @@ double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_seek_roo } if (!cur_active) { - return blend_input(0, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, sync); + return blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync); } } @@ -333,12 +347,12 @@ double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_seek_roo double main_rem; if (mix == MIX_MODE_ADD) { - main_rem = blend_input(0, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, sync); + main_rem = blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync); } else { - main_rem = blend_input(0, p_time, p_seek, p_seek_root, 1.0 - blend, FILTER_BLEND, sync); + main_rem = blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0 - blend, FILTER_BLEND, sync); } - double os_rem = blend_input(1, os_seek ? cur_time : p_time, os_seek, p_seek_root, blend, FILTER_PASS, true); + double os_rem = blend_input(1, os_seek ? cur_time : p_time, os_seek, p_is_external_seeking, blend, FILTER_PASS, true); if (do_start) { cur_remaining = os_rem; @@ -420,10 +434,10 @@ bool AnimationNodeAdd2::has_filter() const { return true; } -double AnimationNodeAdd2::process(double p_time, bool p_seek, bool p_seek_root) { +double AnimationNodeAdd2::process(double p_time, bool p_seek, bool p_is_external_seeking) { double amount = get_parameter(add_amount); - double rem0 = blend_input(0, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, sync); - blend_input(1, p_time, p_seek, p_seek_root, amount, FILTER_PASS, sync); + double rem0 = blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync); + blend_input(1, p_time, p_seek, p_is_external_seeking, amount, FILTER_PASS, sync); return rem0; } @@ -454,11 +468,11 @@ bool AnimationNodeAdd3::has_filter() const { return true; } -double AnimationNodeAdd3::process(double p_time, bool p_seek, bool p_seek_root) { +double AnimationNodeAdd3::process(double p_time, bool p_seek, bool p_is_external_seeking) { double amount = get_parameter(add_amount); - blend_input(0, p_time, p_seek, p_seek_root, MAX(0, -amount), FILTER_PASS, sync); - double rem0 = blend_input(1, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, sync); - blend_input(2, p_time, p_seek, p_seek_root, MAX(0, amount), FILTER_PASS, sync); + blend_input(0, p_time, p_seek, p_is_external_seeking, MAX(0, -amount), FILTER_PASS, sync); + double rem0 = blend_input(1, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync); + blend_input(2, p_time, p_seek, p_is_external_seeking, MAX(0, amount), FILTER_PASS, sync); return rem0; } @@ -486,11 +500,11 @@ String AnimationNodeBlend2::get_caption() const { return "Blend2"; } -double AnimationNodeBlend2::process(double p_time, bool p_seek, bool p_seek_root) { +double AnimationNodeBlend2::process(double p_time, bool p_seek, bool p_is_external_seeking) { double amount = get_parameter(blend_amount); - double rem0 = blend_input(0, p_time, p_seek, p_seek_root, 1.0 - amount, FILTER_BLEND, sync); - double rem1 = blend_input(1, p_time, p_seek, p_seek_root, amount, FILTER_PASS, sync); + double rem0 = blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0 - amount, FILTER_BLEND, sync); + double rem1 = blend_input(1, p_time, p_seek, p_is_external_seeking, amount, FILTER_PASS, sync); return amount > 0.5 ? rem1 : rem0; //hacky but good enough } @@ -521,11 +535,11 @@ String AnimationNodeBlend3::get_caption() const { return "Blend3"; } -double AnimationNodeBlend3::process(double p_time, bool p_seek, bool p_seek_root) { +double AnimationNodeBlend3::process(double p_time, bool p_seek, bool p_is_external_seeking) { double amount = get_parameter(blend_amount); - double rem0 = blend_input(0, p_time, p_seek, p_seek_root, MAX(0, -amount), FILTER_IGNORE, sync); - double rem1 = blend_input(1, p_time, p_seek, p_seek_root, 1.0 - ABS(amount), FILTER_IGNORE, sync); - double rem2 = blend_input(2, p_time, p_seek, p_seek_root, MAX(0, amount), FILTER_IGNORE, sync); + double rem0 = blend_input(0, p_time, p_seek, p_is_external_seeking, MAX(0, -amount), FILTER_IGNORE, sync); + double rem1 = blend_input(1, p_time, p_seek, p_is_external_seeking, 1.0 - ABS(amount), FILTER_IGNORE, sync); + double rem2 = blend_input(2, p_time, p_seek, p_is_external_seeking, MAX(0, amount), FILTER_IGNORE, sync); return amount > 0.5 ? rem2 : (amount < -0.5 ? rem0 : rem1); //hacky but good enough } @@ -553,12 +567,12 @@ String AnimationNodeTimeScale::get_caption() const { return "TimeScale"; } -double AnimationNodeTimeScale::process(double p_time, bool p_seek, bool p_seek_root) { +double AnimationNodeTimeScale::process(double p_time, bool p_seek, bool p_is_external_seeking) { double cur_scale = get_parameter(scale); if (p_seek) { - return blend_input(0, p_time, true, p_seek_root, 1.0, FILTER_IGNORE, true); + return blend_input(0, p_time, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true); } else { - return blend_input(0, p_time * cur_scale, false, p_seek_root, 1.0, FILTER_IGNORE, true); + return blend_input(0, p_time * cur_scale, false, p_is_external_seeking, 1.0, FILTER_IGNORE, true); } } @@ -583,16 +597,16 @@ String AnimationNodeTimeSeek::get_caption() const { return "Seek"; } -double AnimationNodeTimeSeek::process(double p_time, bool p_seek, bool p_seek_root) { +double AnimationNodeTimeSeek::process(double p_time, bool p_seek, bool p_is_external_seeking) { double cur_seek_pos = get_parameter(seek_pos); if (p_seek) { - return blend_input(0, p_time, true, p_seek_root, 1.0, FILTER_IGNORE, true); + return blend_input(0, p_time, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true); } else if (cur_seek_pos >= 0) { double ret = blend_input(0, cur_seek_pos, true, true, 1.0, FILTER_IGNORE, true); set_parameter(seek_pos, -1.0); //reset return ret; } else { - return blend_input(0, p_time, false, p_seek_root, 1.0, FILTER_IGNORE, true); + return blend_input(0, p_time, false, p_is_external_seeking, 1.0, FILTER_IGNORE, true); } } @@ -700,7 +714,7 @@ bool AnimationNodeTransition::is_from_start() const { return from_start; } -double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_root) { +double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_external_seeking) { int cur_current = get_parameter(current); int cur_prev = get_parameter(prev); int cur_prev_current = get_parameter(prev_current); @@ -729,14 +743,14 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_ if (sync) { for (int i = 0; i < enabled_inputs; i++) { if (i != cur_current && i != cur_prev) { - blend_input(i, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, true); + blend_input(i, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true); } } } if (cur_prev < 0) { // process current animation, check for transition - rem = blend_input(cur_current, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, true); + rem = blend_input(cur_current, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true); if (p_seek) { cur_time = p_time; @@ -756,17 +770,16 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_ } if (from_start && !p_seek && switched) { //just switched, seek to start of current - - rem = blend_input(cur_current, 0, true, p_seek_root, 1.0 - blend, FILTER_IGNORE, true); + rem = blend_input(cur_current, 0, true, p_is_external_seeking, 1.0 - blend, FILTER_IGNORE, true); } else { - rem = blend_input(cur_current, p_time, p_seek, p_seek_root, 1.0 - blend, FILTER_IGNORE, true); + rem = blend_input(cur_current, p_time, p_seek, p_is_external_seeking, 1.0 - blend, FILTER_IGNORE, true); } if (p_seek) { - blend_input(cur_prev, p_time, true, p_seek_root, blend, FILTER_IGNORE, true); + blend_input(cur_prev, p_time, true, p_is_external_seeking, blend, FILTER_IGNORE, true); cur_time = p_time; } else { - blend_input(cur_prev, p_time, false, p_seek_root, blend, FILTER_IGNORE, true); + blend_input(cur_prev, p_time, false, p_is_external_seeking, blend, FILTER_IGNORE, true); cur_time += p_time; cur_prev_xfading -= p_time; if (cur_prev_xfading < 0) { @@ -835,8 +848,8 @@ String AnimationNodeOutput::get_caption() const { return "Output"; } -double AnimationNodeOutput::process(double p_time, bool p_seek, bool p_seek_root) { - return blend_input(0, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, true); +double AnimationNodeOutput::process(double p_time, bool p_seek, bool p_is_external_seeking) { + return blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true); } AnimationNodeOutput::AnimationNodeOutput() { @@ -1048,9 +1061,9 @@ String AnimationNodeBlendTree::get_caption() const { return "BlendTree"; } -double AnimationNodeBlendTree::process(double p_time, bool p_seek, bool p_seek_root) { +double AnimationNodeBlendTree::process(double p_time, bool p_seek, bool p_is_external_seeking) { Ref<AnimationNodeOutput> output = nodes[SceneStringNames::get_singleton()->output].node; - return _blend_node("output", nodes[SceneStringNames::get_singleton()->output].connections, this, output, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, true); + return _blend_node("output", nodes[SceneStringNames::get_singleton()->output].connections, this, output, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true); } void AnimationNodeBlendTree::get_node_list(List<StringName> *r_list) { diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h index 1c31718259..52bf67b8f5 100644 --- a/scene/animation/animation_blend_tree.h +++ b/scene/animation/animation_blend_tree.h @@ -53,7 +53,7 @@ public: static Vector<String> (*get_editable_animation_list)(); virtual String get_caption() const override; - virtual double process(double p_time, bool p_seek, bool p_seek_root) override; + virtual double process(double p_time, bool p_seek, bool p_is_external_seeking) override; void set_animation(const StringName &p_name); StringName get_animation() const; @@ -72,7 +72,7 @@ protected: private: PlayMode play_mode = PLAY_MODE_FORWARD; - bool backward = false; + bool backward = false; // Only used by pingpong animation. }; VARIANT_ENUM_CAST(AnimationNodeAnimation::PlayMode) @@ -148,7 +148,7 @@ public: MixMode get_mix_mode() const; virtual bool has_filter() const override; - virtual double process(double p_time, bool p_seek, bool p_seek_root) override; + virtual double process(double p_time, bool p_seek, bool p_is_external_seeking) override; AnimationNodeOneShot(); }; @@ -170,7 +170,7 @@ public: virtual String get_caption() const override; virtual bool has_filter() const override; - virtual double process(double p_time, bool p_seek, bool p_seek_root) override; + virtual double process(double p_time, bool p_seek, bool p_is_external_seeking) override; AnimationNodeAdd2(); }; @@ -190,7 +190,7 @@ public: virtual String get_caption() const override; virtual bool has_filter() const override; - virtual double process(double p_time, bool p_seek, bool p_seek_root) override; + virtual double process(double p_time, bool p_seek, bool p_is_external_seeking) override; AnimationNodeAdd3(); }; @@ -208,7 +208,7 @@ public: virtual Variant get_parameter_default_value(const StringName &p_parameter) const override; virtual String get_caption() const override; - virtual double process(double p_time, bool p_seek, bool p_seek_root) override; + virtual double process(double p_time, bool p_seek, bool p_is_external_seeking) override; virtual bool has_filter() const override; AnimationNodeBlend2(); @@ -228,7 +228,7 @@ public: virtual String get_caption() const override; - double process(double p_time, bool p_seek, bool p_seek_root) override; + double process(double p_time, bool p_seek, bool p_is_external_seeking) override; AnimationNodeBlend3(); }; @@ -246,7 +246,7 @@ public: virtual String get_caption() const override; - double process(double p_time, bool p_seek, bool p_seek_root) override; + double process(double p_time, bool p_seek, bool p_is_external_seeking) override; AnimationNodeTimeScale(); }; @@ -265,7 +265,7 @@ public: virtual String get_caption() const override; - double process(double p_time, bool p_seek, bool p_seek_root) override; + double process(double p_time, bool p_seek, bool p_is_external_seeking) override; AnimationNodeTimeSeek(); }; @@ -331,7 +331,7 @@ public: void set_from_start(bool p_from_start); bool is_from_start() const; - double process(double p_time, bool p_seek, bool p_seek_root) override; + double process(double p_time, bool p_seek, bool p_is_external_seeking) override; AnimationNodeTransition(); }; @@ -341,7 +341,7 @@ class AnimationNodeOutput : public AnimationNode { public: virtual String get_caption() const override; - virtual double process(double p_time, bool p_seek, bool p_seek_root) override; + virtual double process(double p_time, bool p_seek, bool p_is_external_seeking) override; AnimationNodeOutput(); }; @@ -410,7 +410,7 @@ public: void get_node_connections(List<NodeConnection> *r_connections) const; virtual String get_caption() const override; - virtual double process(double p_time, bool p_seek, bool p_seek_root) override; + virtual double process(double p_time, bool p_seek, bool p_is_external_seeking) override; void get_node_list(List<StringName> *r_list); diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index 8291df8036..360f16de02 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -332,11 +332,11 @@ bool AnimationNodeStateMachinePlayback::_travel(AnimationNodeStateMachine *p_sta return true; } -double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_seek_root) { +double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_is_external_seeking) { if (p_time == -1) { Ref<AnimationNodeStateMachine> anodesm = p_state_machine->states[current].node; if (anodesm.is_valid()) { - p_state_machine->blend_node(current, p_state_machine->states[current].node, -1, p_seek, p_seek_root, 0, AnimationNode::FILTER_IGNORE, true); + p_state_machine->blend_node(current, p_state_machine->states[current].node, -1, p_seek, p_is_external_seeking, 0, AnimationNode::FILTER_IGNORE, true); } playing = false; return 0; @@ -405,7 +405,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s current = p_state_machine->start_node; } - len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_seek_root, 1.0, AnimationNode::FILTER_IGNORE, true); + len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_is_external_seeking, 1.0, AnimationNode::FILTER_IGNORE, true); pos_current = 0; } @@ -433,10 +433,10 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s if (current_curve.is_valid()) { fade_blend = current_curve->sample(fade_blend); } - float rem = p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_seek_root, fade_blend, AnimationNode::FILTER_IGNORE, true); + float rem = p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_is_external_seeking, fade_blend, AnimationNode::FILTER_IGNORE, true); if (fading_from != StringName()) { - p_state_machine->blend_node(fading_from, p_state_machine->states[fading_from].node, p_time, p_seek, p_seek_root, 1.0 - fade_blend, AnimationNode::FILTER_IGNORE, true); + p_state_machine->blend_node(fading_from, p_state_machine->states[fading_from].node, p_time, p_seek, p_is_external_seeking, 1.0 - fade_blend, AnimationNode::FILTER_IGNORE, true); } //guess playback position @@ -593,19 +593,19 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s { // if the current node is a state machine, update the "playing" variable to false by passing -1 in p_time Ref<AnimationNodeStateMachine> anodesm = p_state_machine->states[current].node; if (anodesm.is_valid()) { - p_state_machine->blend_node(current, p_state_machine->states[current].node, -1, p_seek, p_seek_root, 0, AnimationNode::FILTER_IGNORE, true); + p_state_machine->blend_node(current, p_state_machine->states[current].node, -1, p_seek, p_is_external_seeking, 0, AnimationNode::FILTER_IGNORE, true); } } current = next; if (switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_SYNC) { - len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_seek_root, 0, AnimationNode::FILTER_IGNORE, true); + len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_is_external_seeking, 0, AnimationNode::FILTER_IGNORE, true); pos_current = MIN(pos_current, len_current); - p_state_machine->blend_node(current, p_state_machine->states[current].node, pos_current, true, p_seek_root, 0, AnimationNode::FILTER_IGNORE, true); + p_state_machine->blend_node(current, p_state_machine->states[current].node, pos_current, true, p_is_external_seeking, 0, AnimationNode::FILTER_IGNORE, true); } else { - len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_seek_root, 0, AnimationNode::FILTER_IGNORE, true); + len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_is_external_seeking, 0, AnimationNode::FILTER_IGNORE, true); pos_current = 0; } @@ -1133,11 +1133,11 @@ Vector2 AnimationNodeStateMachine::get_graph_offset() const { return graph_offset; } -double AnimationNodeStateMachine::process(double p_time, bool p_seek, bool p_seek_root) { +double AnimationNodeStateMachine::process(double p_time, bool p_seek, bool p_is_external_seeking) { Ref<AnimationNodeStateMachinePlayback> playback_new = get_parameter(playback); ERR_FAIL_COND_V(playback_new.is_null(), 0.0); - return playback_new->process(this, p_time, p_seek, p_seek_root); + return playback_new->process(this, p_time, p_seek, p_is_external_seeking); } String AnimationNodeStateMachine::get_caption() const { diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h index cdb4c7528a..0dfe5a3a43 100644 --- a/scene/animation/animation_node_state_machine.h +++ b/scene/animation/animation_node_state_machine.h @@ -133,7 +133,7 @@ class AnimationNodeStateMachinePlayback : public Resource { bool _travel(AnimationNodeStateMachine *p_state_machine, const StringName &p_travel); - double process(AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_seek_root); + double process(AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_is_external_seeking); bool _check_advance_condition(const Ref<AnimationNodeStateMachine> p_state_machine, const Ref<AnimationNodeStateMachineTransition> p_transition) const; @@ -239,7 +239,7 @@ public: void set_graph_offset(const Vector2 &p_offset); Vector2 get_graph_offset() const; - virtual double process(double p_time, bool p_seek, bool p_seek_root) override; + virtual double process(double p_time, bool p_seek, bool p_is_external_seeking) override; virtual String get_caption() const override; virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name) override; diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 85bc4e9814..45eeff71f2 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -683,7 +683,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double } else if (p_is_current && p_delta != 0) { List<int> indices; - a->value_track_get_key_indices(i, p_time, p_delta, &indices, p_pingponged); + a->track_get_key_indices_in_range(i, p_time, p_delta, &indices, p_pingponged); for (int &F : indices) { Variant value = a->track_get_key_value(i, F); @@ -742,8 +742,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double } List<int> indices; - - a->method_track_get_key_indices(i, p_time, p_delta, &indices, p_pingponged); + a->track_get_key_indices_in_range(i, p_time, p_delta, &indices, p_pingponged); for (int &E : indices) { StringName method = a->method_track_get_name(i, E); diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index 99d450fa5b..50165773d0 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -86,7 +86,7 @@ void AnimationNode::get_child_nodes(List<ChildNode> *r_child_nodes) { } } -void AnimationNode::blend_animation(const StringName &p_animation, double p_time, double p_delta, bool p_seeked, bool p_seek_root, real_t p_blend, int p_pingponged) { +void AnimationNode::blend_animation(const StringName &p_animation, double p_time, double p_delta, bool p_seeked, bool p_is_external_seeking, real_t p_blend, int p_pingponged) { ERR_FAIL_COND(!state); ERR_FAIL_COND(!state->player->has_animation(p_animation)); @@ -113,18 +113,18 @@ void AnimationNode::blend_animation(const StringName &p_animation, double p_time anim_state.animation = animation; anim_state.seeked = p_seeked; anim_state.pingponged = p_pingponged; - anim_state.seek_root = p_seek_root; + anim_state.is_external_seeking = p_is_external_seeking; state->animation_states.push_back(anim_state); } -double AnimationNode::_pre_process(const StringName &p_base_path, AnimationNode *p_parent, State *p_state, double p_time, bool p_seek, bool p_seek_root, const Vector<StringName> &p_connections) { +double AnimationNode::_pre_process(const StringName &p_base_path, AnimationNode *p_parent, State *p_state, double p_time, bool p_seek, bool p_is_external_seeking, const Vector<StringName> &p_connections) { base_path = p_base_path; parent = p_parent; connections = p_connections; state = p_state; - double t = process(p_time, p_seek, p_seek_root); + double t = process(p_time, p_seek, p_is_external_seeking); state = nullptr; parent = nullptr; @@ -148,7 +148,7 @@ void AnimationNode::make_invalid(const String &p_reason) { state->invalid_reasons += String::utf8("• ") + p_reason; } -double AnimationNode::blend_input(int p_input, double p_time, bool p_seek, bool p_seek_root, real_t p_blend, FilterAction p_filter, bool p_sync) { +double AnimationNode::blend_input(int p_input, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter, bool p_sync) { ERR_FAIL_INDEX_V(p_input, inputs.size(), 0); ERR_FAIL_COND_V(!state, 0); @@ -167,7 +167,7 @@ double AnimationNode::blend_input(int p_input, double p_time, bool p_seek, bool //inputs.write[p_input].last_pass = state->last_pass; real_t activity = 0.0; - double ret = _blend_node(node_name, blend_tree->get_node_connection_array(node_name), nullptr, node, p_time, p_seek, p_seek_root, p_blend, p_filter, p_sync, &activity); + double ret = _blend_node(node_name, blend_tree->get_node_connection_array(node_name), nullptr, node, p_time, p_seek, p_is_external_seeking, p_blend, p_filter, p_sync, &activity); Vector<AnimationTree::Activity> *activity_ptr = state->tree->input_activity_map.getptr(base_path); @@ -178,11 +178,11 @@ double AnimationNode::blend_input(int p_input, double p_time, bool p_seek, bool return ret; } -double AnimationNode::blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_seek_root, real_t p_blend, FilterAction p_filter, bool p_sync) { - return _blend_node(p_sub_path, Vector<StringName>(), this, p_node, p_time, p_seek, p_seek_root, p_blend, p_filter, p_sync); +double AnimationNode::blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter, bool p_sync) { + return _blend_node(p_sub_path, Vector<StringName>(), this, p_node, p_time, p_seek, p_is_external_seeking, p_blend, p_filter, p_sync); } -double AnimationNode::_blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_seek_root, real_t p_blend, FilterAction p_filter, bool p_sync, real_t *r_max) { +double AnimationNode::_blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter, bool p_sync, real_t *r_max) { ERR_FAIL_COND_V(!p_node.is_valid(), 0); ERR_FAIL_COND_V(!state, 0); @@ -292,9 +292,9 @@ double AnimationNode::_blend_node(const StringName &p_subpath, const Vector<Stri // This process, which depends on p_sync is needed to process sync correctly in the case of // that a synced AnimationNodeSync exists under the un-synced AnimationNodeSync. if (!p_seek && !p_sync && !any_valid) { - return p_node->_pre_process(new_path, new_parent, state, 0, p_seek, p_seek_root, p_connections); + return p_node->_pre_process(new_path, new_parent, state, 0, p_seek, p_is_external_seeking, p_connections); } - return p_node->_pre_process(new_path, new_parent, state, p_time, p_seek, p_seek_root, p_connections); + return p_node->_pre_process(new_path, new_parent, state, p_time, p_seek, p_is_external_seeking, p_connections); } int AnimationNode::get_input_count() const { @@ -335,9 +335,9 @@ void AnimationNode::remove_input(int p_index) { emit_changed(); } -double AnimationNode::process(double p_time, bool p_seek, bool p_seek_root) { +double AnimationNode::process(double p_time, bool p_seek, bool p_is_external_seeking) { double ret = 0; - GDVIRTUAL_CALL(_process, p_time, p_seek, p_seek_root, ret); + GDVIRTUAL_CALL(_process, p_time, p_seek, p_is_external_seeking, ret); return ret; } @@ -413,9 +413,9 @@ void AnimationNode::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_filters", "filters"), &AnimationNode::_set_filters); ClassDB::bind_method(D_METHOD("_get_filters"), &AnimationNode::_get_filters); - ClassDB::bind_method(D_METHOD("blend_animation", "animation", "time", "delta", "seeked", "seek_root", "blend", "pingponged"), &AnimationNode::blend_animation, DEFVAL(0)); - ClassDB::bind_method(D_METHOD("blend_node", "name", "node", "time", "seek", "seek_root", "blend", "filter", "sync"), &AnimationNode::blend_node, DEFVAL(FILTER_IGNORE), DEFVAL(true)); - ClassDB::bind_method(D_METHOD("blend_input", "input_index", "time", "seek", "seek_root", "blend", "filter", "sync"), &AnimationNode::blend_input, DEFVAL(FILTER_IGNORE), DEFVAL(true)); + ClassDB::bind_method(D_METHOD("blend_animation", "animation", "time", "delta", "seeked", "is_external_seeking", "blend", "pingponged"), &AnimationNode::blend_animation, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("blend_node", "name", "node", "time", "seek", "is_external_seeking", "blend", "filter", "sync"), &AnimationNode::blend_node, DEFVAL(FILTER_IGNORE), DEFVAL(true)); + ClassDB::bind_method(D_METHOD("blend_input", "input_index", "time", "seek", "is_external_seeking", "blend", "filter", "sync"), &AnimationNode::blend_input, DEFVAL(FILTER_IGNORE), DEFVAL(true)); ClassDB::bind_method(D_METHOD("set_parameter", "name", "value"), &AnimationNode::set_parameter); ClassDB::bind_method(D_METHOD("get_parameter", "name"), &AnimationNode::get_parameter); @@ -427,7 +427,7 @@ void AnimationNode::_bind_methods() { GDVIRTUAL_BIND(_get_parameter_list); GDVIRTUAL_BIND(_get_child_by_name, "name"); GDVIRTUAL_BIND(_get_parameter_default_value, "parameter"); - GDVIRTUAL_BIND(_process, "time", "seek", "seek_root"); + GDVIRTUAL_BIND(_process, "time", "seek", "is_external_seeking"); GDVIRTUAL_BIND(_get_caption); GDVIRTUAL_BIND(_has_filter); @@ -800,9 +800,18 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) { } } else if (track_cache_type == Animation::TYPE_VALUE) { // If it has at least one angle interpolation, it also uses angle interpolation for blending. - TrackCacheValue *track_value = memnew(TrackCacheValue); + TrackCacheValue *track_value = static_cast<TrackCacheValue *>(track); + bool was_discrete = track_value->is_discrete; + bool was_using_angle = track_value->is_using_angle; track_value->is_discrete |= anim->value_track_get_update_mode(i) == Animation::UPDATE_DISCRETE || anim->value_track_get_update_mode(i) == Animation::UPDATE_TRIGGER; track_value->is_using_angle |= anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_LINEAR_ANGLE || anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_CUBIC_ANGLE; + + if (was_discrete != track_value->is_discrete) { + WARN_PRINT_ONCE("Tracks with different update modes are blended. Blending prioritizes Discrete/Trigger mode, so other update mode tracks will not be blended."); + } + if (was_using_angle != track_value->is_using_angle) { + WARN_PRINT_ONCE("Tracks for rotation with different interpolation types are blended. Blending prioritizes angle interpolation, so the blending result uses the shortest path referenced to the initial (RESET animation) value."); + } } track->setup_pass = setup_pass; @@ -874,7 +883,9 @@ void AnimationTree::_process_graph(double p_delta) { _update_properties(); //if properties need updating, update them //check all tracks, see if they need modification - root_motion_transform = Transform3D(); + root_motion_position = Vector3(0, 0, 0); + root_motion_rotation = Quaternion(0, 0, 0, 1); + root_motion_scale = Vector3(0, 0, 0); if (!root.is_valid()) { ERR_PRINT("AnimationTree: root AnimationNode is not set, disabling playback."); @@ -973,7 +984,7 @@ void AnimationTree::_process_graph(double p_delta) { if (track->root_motion) { t->loc = Vector3(0, 0, 0); t->rot = Quaternion(0, 0, 0, 1); - t->scale = Vector3(0, 0, 0); + t->scale = Vector3(1, 1, 1); } else { t->loc = t->init_loc; t->rot = t->init_rot; @@ -1009,9 +1020,10 @@ void AnimationTree::_process_graph(double p_delta) { real_t weight = as.blend; bool seeked = as.seeked; int pingponged = as.pingponged; + bool is_external_seeking = as.is_external_seeking; #ifndef _3D_DISABLED bool backward = signbit(delta); // This flag is required only for the root motion since it calculates the difference between the previous and current frames. - bool calc_root = !seeked || as.seek_root; + bool calc_root = !seeked || is_external_seeking; #endif // _3D_DISABLED for (int i = 0; i < a->get_track_count(); i++) { @@ -1370,7 +1382,7 @@ void AnimationTree::_process_graph(double p_delta) { } } else { if (seeked) { - int idx = a->track_find_key(i, time); + int idx = a->track_find_key(i, time, !is_external_seeking); if (idx < 0) { continue; } @@ -1379,7 +1391,7 @@ void AnimationTree::_process_graph(double p_delta) { t->object->set_indexed(t->subpath, value); } else { List<int> indices; - a->value_track_get_key_indices(i, time, delta, &indices, pingponged); + a->track_get_key_indices_in_range(i, time, delta, &indices, pingponged); for (int &F : indices) { Variant value = a->track_get_key_value(i, F); value = _post_process_key_value(a, i, value, t->object); @@ -1393,7 +1405,7 @@ void AnimationTree::_process_graph(double p_delta) { TrackCacheMethod *t = static_cast<TrackCacheMethod *>(track); if (seeked) { - int idx = a->track_find_key(i, time); + int idx = a->track_find_key(i, time, !is_external_seeking); if (idx < 0) { continue; } @@ -1404,7 +1416,7 @@ void AnimationTree::_process_graph(double p_delta) { } } else { List<int> indices; - a->method_track_get_key_indices(i, time, delta, &indices, pingponged); + a->track_get_key_indices_in_range(i, time, delta, &indices, pingponged); for (int &F : indices) { StringName method = a->method_track_get_name(i, F); Vector<Variant> params = a->method_track_get_params(i, F); @@ -1427,7 +1439,7 @@ void AnimationTree::_process_graph(double p_delta) { if (seeked) { //find whatever should be playing - int idx = a->track_find_key(i, time); + int idx = a->track_find_key(i, time, !is_external_seeking); if (idx < 0) { continue; } @@ -1540,7 +1552,7 @@ void AnimationTree::_process_graph(double p_delta) { if (seeked) { //seek - int idx = a->track_find_key(i, time); + int idx = a->track_find_key(i, time, !is_external_seeking); if (idx < 0) { continue; } @@ -1618,11 +1630,9 @@ void AnimationTree::_process_graph(double p_delta) { TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track); if (t->root_motion) { - Transform3D xform; - xform.origin = t->loc; - xform.basis.set_quaternion_scale(t->rot, Vector3(1, 1, 1) + t->scale); - - root_motion_transform = xform; + root_motion_position = root_motion_rotation.xform_inv(t->loc); + root_motion_rotation = t->rot; + root_motion_scale = t->scale - Vector3(1, 1, 1); } else if (t->skeleton && t->bone_idx >= 0) { if (t->loc_used) { @@ -1835,8 +1845,16 @@ NodePath AnimationTree::get_root_motion_track() const { return root_motion_track; } -Transform3D AnimationTree::get_root_motion_transform() const { - return root_motion_transform; +Vector3 AnimationTree::get_root_motion_position() const { + return root_motion_position; +} + +Quaternion AnimationTree::get_root_motion_rotation() const { + return root_motion_rotation; +} + +Vector3 AnimationTree::get_root_motion_scale() const { + return root_motion_scale; } void AnimationTree::_tree_changed() { @@ -1994,7 +2012,9 @@ void AnimationTree::_bind_methods() { ClassDB::bind_method(D_METHOD("set_root_motion_track", "path"), &AnimationTree::set_root_motion_track); ClassDB::bind_method(D_METHOD("get_root_motion_track"), &AnimationTree::get_root_motion_track); - ClassDB::bind_method(D_METHOD("get_root_motion_transform"), &AnimationTree::get_root_motion_transform); + ClassDB::bind_method(D_METHOD("get_root_motion_position"), &AnimationTree::get_root_motion_position); + ClassDB::bind_method(D_METHOD("get_root_motion_rotation"), &AnimationTree::get_root_motion_rotation); + ClassDB::bind_method(D_METHOD("get_root_motion_scale"), &AnimationTree::get_root_motion_scale); ClassDB::bind_method(D_METHOD("_update_properties"), &AnimationTree::_update_properties); diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h index 84d0a8190a..a4b0f992dc 100644 --- a/scene/animation/animation_tree.h +++ b/scene/animation/animation_tree.h @@ -68,7 +68,7 @@ public: const Vector<real_t> *track_blends = nullptr; real_t blend = 0.0; bool seeked = false; - bool seek_root = false; + bool is_external_seeking = false; int pingponged = 0; }; @@ -86,7 +86,7 @@ public: Vector<real_t> blends; State *state = nullptr; - double _pre_process(const StringName &p_base_path, AnimationNode *p_parent, State *p_state, double p_time, bool p_seek, bool p_seek_root, const Vector<StringName> &p_connections); + double _pre_process(const StringName &p_base_path, AnimationNode *p_parent, State *p_state, double p_time, bool p_seek, bool p_is_external_seeking, const Vector<StringName> &p_connections); //all this is temporary StringName base_path; @@ -99,12 +99,12 @@ public: Array _get_filters() const; void _set_filters(const Array &p_filters); friend class AnimationNodeBlendTree; - double _blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_seek_root, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true, real_t *r_max = nullptr); + double _blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true, real_t *r_max = nullptr); protected: - void blend_animation(const StringName &p_animation, double p_time, double p_delta, bool p_seeked, bool p_seek_root, real_t p_blend, int p_pingponged = 0); - double blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_seek_root, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true); - double blend_input(int p_input, double p_time, bool p_seek, bool p_seek_root, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true); + void blend_animation(const StringName &p_animation, double p_time, double p_delta, bool p_seeked, bool p_is_external_seeking, real_t p_blend, int p_pingponged = 0); + double blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true); + double blend_input(int p_input, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true); void make_invalid(const String &p_reason); AnimationTree *get_animation_tree() const; @@ -135,7 +135,7 @@ public: virtual void get_child_nodes(List<ChildNode> *r_child_nodes); - virtual double process(double p_time, bool p_seek, bool p_seek_root); + virtual double process(double p_time, bool p_seek, bool p_is_external_seeking); virtual String get_caption() const; int get_input_count() const; @@ -294,7 +294,9 @@ private: bool started = true; NodePath root_motion_track; - Transform3D root_motion_transform; + Vector3 root_motion_position = Vector3(0, 0, 0); + Quaternion root_motion_rotation = Quaternion(0, 0, 0, 1); + Vector3 root_motion_scale = Vector3(0, 0, 0); friend class AnimationNode; bool properties_dirty = true; @@ -350,7 +352,9 @@ public: void set_root_motion_track(const NodePath &p_track); NodePath get_root_motion_track() const; - Transform3D get_root_motion_transform() const; + Vector3 get_root_motion_position() const; + Quaternion get_root_motion_rotation() const; + Vector3 get_root_motion_scale() const; real_t get_connection_activity(const StringName &p_path, int p_connection) const; void advance(double p_time); diff --git a/scene/animation/root_motion_view.cpp b/scene/animation/root_motion_view.cpp index 47f08219a9..a6ccb4a576 100644 --- a/scene/animation/root_motion_view.cpp +++ b/scene/animation/root_motion_view.cpp @@ -103,7 +103,8 @@ void RootMotionView::_notification(int p_what) { set_physics_process_internal(false); } - transform = tree->get_root_motion_transform(); + transform.origin = tree->get_root_motion_position(); + transform.basis = tree->get_root_motion_rotation(); // Scale is meaningless. } } @@ -113,9 +114,8 @@ void RootMotionView::_notification(int p_what) { first = false; - transform.orthonormalize(); //don't want scale, too imprecise - - accumulated = accumulated * transform; + accumulated.origin += transform.origin; + accumulated.basis *= transform.basis; accumulated.origin.x = Math::fposmod(accumulated.origin.x, cell_size); if (zero_y) { accumulated.origin.y = 0; diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 4e76f72921..5ce17abf18 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -220,6 +220,10 @@ PackedStringArray Control::get_configuration_warnings() const { warnings.push_back(RTR("The Hint Tooltip won't be displayed as the control's Mouse Filter is set to \"Ignore\". To solve this, set the Mouse Filter to \"Stop\" or \"Pass\".")); } + if (get_z_index() != 0) { + warnings.push_back(RTR("Changing the Z index of a control only affects the drawing order, not the input event handling order.")); + } + return warnings; } @@ -2935,7 +2939,7 @@ void Control::_notification(int p_notification) { queue_redraw(); if (data.RI) { - get_viewport()->_gui_set_root_order_dirty(); + get_viewport()->gui_set_root_order_dirty(); } } break; diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index 7bcd4721fc..2563fa5914 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -450,6 +450,39 @@ void CanvasItem::item_rect_changed(bool p_size_changed) { emit_signal(SceneStringNames::get_singleton()->item_rect_changed); } +void CanvasItem::set_z_index(int p_z) { + ERR_FAIL_COND(p_z < RS::CANVAS_ITEM_Z_MIN); + ERR_FAIL_COND(p_z > RS::CANVAS_ITEM_Z_MAX); + z_index = p_z; + RS::get_singleton()->canvas_item_set_z_index(canvas_item, z_index); + update_configuration_warnings(); +} + +void CanvasItem::set_z_as_relative(bool p_enabled) { + if (z_relative == p_enabled) { + return; + } + z_relative = p_enabled; + RS::get_singleton()->canvas_item_set_z_as_relative_to_parent(canvas_item, p_enabled); +} + +bool CanvasItem::is_z_relative() const { + return z_relative; +} + +int CanvasItem::get_z_index() const { + return z_index; +} + +void CanvasItem::set_y_sort_enabled(bool p_enabled) { + y_sort_enabled = p_enabled; + RS::get_singleton()->canvas_item_set_sort_children_by_y(canvas_item, y_sort_enabled); +} + +bool CanvasItem::is_y_sort_enabled() const { + return y_sort_enabled; +} + void CanvasItem::draw_dashed_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width, real_t p_dash) { ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); @@ -913,9 +946,19 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("set_modulate", "modulate"), &CanvasItem::set_modulate); ClassDB::bind_method(D_METHOD("get_modulate"), &CanvasItem::get_modulate); + ClassDB::bind_method(D_METHOD("set_self_modulate", "self_modulate"), &CanvasItem::set_self_modulate); ClassDB::bind_method(D_METHOD("get_self_modulate"), &CanvasItem::get_self_modulate); + ClassDB::bind_method(D_METHOD("set_z_index", "z_index"), &Node2D::set_z_index); + ClassDB::bind_method(D_METHOD("get_z_index"), &Node2D::get_z_index); + + ClassDB::bind_method(D_METHOD("set_z_as_relative", "enable"), &Node2D::set_z_as_relative); + ClassDB::bind_method(D_METHOD("is_z_relative"), &Node2D::is_z_relative); + + ClassDB::bind_method(D_METHOD("set_y_sort_enabled", "enabled"), &Node2D::set_y_sort_enabled); + ClassDB::bind_method(D_METHOD("is_y_sort_enabled"), &Node2D::is_y_sort_enabled); + ClassDB::bind_method(D_METHOD("set_draw_behind_parent", "enable"), &CanvasItem::set_draw_behind_parent); ClassDB::bind_method(D_METHOD("is_draw_behind_parent_enabled"), &CanvasItem::is_draw_behind_parent_enabled); @@ -1005,6 +1048,11 @@ void CanvasItem::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_light_mask", "get_light_mask"); ADD_PROPERTY(PropertyInfo(Variant::INT, "visibility_layer", PROPERTY_HINT_LAYERS_2D_RENDER), "set_visibility_layer", "get_visibility_layer"); + ADD_GROUP("Ordering", ""); + ADD_PROPERTY(PropertyInfo(Variant::INT, "z_index", PROPERTY_HINT_RANGE, itos(RS::CANVAS_ITEM_Z_MIN) + "," + itos(RS::CANVAS_ITEM_Z_MAX) + ",1"), "set_z_index", "get_z_index"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "z_as_relative"), "set_z_as_relative", "is_z_relative"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "y_sort_enabled"), "set_y_sort_enabled", "is_y_sort_enabled"); + ADD_GROUP("Texture", "texture_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Inherit,Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Anisotropic,Linear Mipmap Anisotropic"), "set_texture_filter", "get_texture_filter"); ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_repeat", PROPERTY_HINT_ENUM, "Inherit,Disabled,Enabled,Mirror"), "set_texture_repeat", "get_texture_repeat"); diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h index 4e78a175dc..4ace982825 100644 --- a/scene/main/canvas_item.h +++ b/scene/main/canvas_item.h @@ -91,6 +91,10 @@ private: int light_mask = 1; uint32_t visibility_layer = 1; + int z_index = 0; + bool z_relative = true; + bool y_sort_enabled = false; + Window *window = nullptr; bool visible = true; bool parent_visible_in_tree = false; @@ -230,6 +234,17 @@ public: void set_visibility_layer_bit(uint32_t p_visibility_layer, bool p_enable); bool get_visibility_layer_bit(uint32_t p_visibility_layer) const; + /* ORDERING */ + + void set_z_index(int p_z); + int get_z_index() const; + + void set_z_as_relative(bool p_enabled); + bool is_z_relative() const; + + virtual void set_y_sort_enabled(bool p_enabled); + virtual bool is_y_sort_enabled() const; + /* DRAWING API */ void draw_dashed_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width = 1.0, real_t p_dash = 2.0); diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp index be5788739b..5fde18721a 100644 --- a/scene/main/canvas_layer.cpp +++ b/scene/main/canvas_layer.cpp @@ -38,7 +38,7 @@ void CanvasLayer::set_layer(int p_xform) { layer = p_xform; if (viewport.is_valid()) { RenderingServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_index()); - vp->_gui_set_root_order_dirty(); + vp->gui_set_root_order_dirty(); } } diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 90b996e06b..680c4cd7e4 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -1660,7 +1660,7 @@ Node *Node::find_common_parent_with(const Node *p_node) const { return const_cast<Node *>(common_parent); } -NodePath Node::get_path_to(const Node *p_node) const { +NodePath Node::get_path_to(const Node *p_node, bool p_use_unique_path) const { ERR_FAIL_NULL_V(p_node, NodePath()); if (this == p_node) { @@ -1690,20 +1690,58 @@ NodePath Node::get_path_to(const Node *p_node) const { visited.clear(); Vector<StringName> path; + StringName up = String(".."); - n = p_node; + if (p_use_unique_path) { + n = p_node; - while (n != common_parent) { - path.push_back(n->get_name()); - n = n->data.parent; - } + bool is_detected = false; + while (n != common_parent) { + if (n->is_unique_name_in_owner() && n->get_owner() == get_owner()) { + path.push_back(UNIQUE_NODE_PREFIX + String(n->get_name())); + is_detected = true; + break; + } + path.push_back(n->get_name()); + n = n->data.parent; + } - n = this; - StringName up = String(".."); + if (!is_detected) { + n = this; - while (n != common_parent) { - path.push_back(up); - n = n->data.parent; + String detected_name; + int up_count = 0; + while (n != common_parent) { + if (n->is_unique_name_in_owner() && n->get_owner() == get_owner()) { + detected_name = n->get_name(); + up_count = 0; + } + up_count++; + n = n->data.parent; + } + + for (int i = 0; i < up_count; i++) { + path.push_back(up); + } + + if (!detected_name.is_empty()) { + path.push_back(UNIQUE_NODE_PREFIX + detected_name); + } + } + } else { + n = p_node; + + while (n != common_parent) { + path.push_back(n->get_name()); + n = n->data.parent; + } + + n = this; + + while (n != common_parent) { + path.push_back(up); + n = n->data.parent; + } } path.reverse(); @@ -2765,7 +2803,7 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("is_ancestor_of", "node"), &Node::is_ancestor_of); ClassDB::bind_method(D_METHOD("is_greater_than", "node"), &Node::is_greater_than); ClassDB::bind_method(D_METHOD("get_path"), &Node::get_path); - ClassDB::bind_method(D_METHOD("get_path_to", "node"), &Node::get_path_to); + ClassDB::bind_method(D_METHOD("get_path_to", "node", "use_unique_path"), &Node::get_path_to, DEFVAL(false)); ClassDB::bind_method(D_METHOD("add_to_group", "group", "persistent"), &Node::add_to_group, DEFVAL(false)); ClassDB::bind_method(D_METHOD("remove_from_group", "group"), &Node::remove_from_group); ClassDB::bind_method(D_METHOD("is_in_group", "group"), &Node::is_in_group); diff --git a/scene/main/node.h b/scene/main/node.h index e07fb003d4..574f5063e8 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -331,7 +331,7 @@ public: bool is_greater_than(const Node *p_node) const; NodePath get_path() const; - NodePath get_path_to(const Node *p_node) const; + NodePath get_path_to(const Node *p_node, bool p_use_unique_path = false) const; Node *find_common_parent_with(const Node *p_node) const; void add_to_group(const StringName &p_identifier, bool p_persistent = false); diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 41eefe0f85..ceb5b76ff2 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -1447,7 +1447,7 @@ SceneTree::SceneTree() { ProjectSettings::get_singleton()->set_custom_property_info("rendering/vrs/texture", PropertyInfo(Variant::STRING, "rendering/vrs/texture", - PROPERTY_HINT_FILE, "*.png")); + PROPERTY_HINT_FILE, "*.bmp,*.png,*.tga,*.webp")); if (vrs_mode == 1 && !vrs_texture_path.is_empty()) { Ref<Image> vrs_image; vrs_image.instantiate(); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index f58bf868ad..7430a0a835 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -2097,7 +2097,7 @@ List<Control *>::Element *Viewport::_gui_add_root_control(Control *p_control) { return gui.roots.push_back(p_control); } -void Viewport::_gui_set_root_order_dirty() { +void Viewport::gui_set_root_order_dirty() { gui.roots_order_dirty = true; } diff --git a/scene/main/viewport.h b/scene/main/viewport.h index dc69ec24d8..5659ee4000 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -456,8 +456,6 @@ private: void _update_canvas_items(Node *p_node); - void _gui_set_root_order_dirty(); - friend class Window; void _sub_window_update_order(); @@ -514,6 +512,8 @@ public: Transform2D get_final_transform() const; + void gui_set_root_order_dirty(); + void set_transparent_background(bool p_enable); bool has_transparent_background() const; diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index da73a479ce..ed9a709382 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -2705,106 +2705,6 @@ Variant Animation::value_track_interpolate(int p_track, double p_time) const { return Variant(); } -void Animation::_value_track_get_key_indices_in_range(const ValueTrack *vt, double from_time, double to_time, List<int> *p_indices) const { - if (from_time != length && to_time == length) { - to_time = length + CMP_EPSILON; //include a little more if at the end - } - int to = _find(vt->values, to_time); - - if (to >= 0 && from_time == to_time && vt->values[to].time == from_time) { - //find exact (0 delta), return if found - p_indices->push_back(to); - return; - } - // can't really send the events == time, will be sent in the next frame. - // if event>=len then it will probably never be requested by the anim player. - - if (to >= 0 && vt->values[to].time >= to_time) { - to--; - } - - if (to < 0) { - return; // not bother - } - - int from = _find(vt->values, from_time); - - // position in the right first event.+ - if (from < 0 || vt->values[from].time < from_time) { - from++; - } - - int max = vt->values.size(); - - for (int i = from; i <= to; i++) { - ERR_CONTINUE(i < 0 || i >= max); // shouldn't happen - p_indices->push_back(i); - } -} - -void Animation::value_track_get_key_indices(int p_track, double p_time, double p_delta, List<int> *p_indices, int p_pingponged) const { - ERR_FAIL_INDEX(p_track, tracks.size()); - Track *t = tracks[p_track]; - ERR_FAIL_COND(t->type != TYPE_VALUE); - - ValueTrack *vt = static_cast<ValueTrack *>(t); - - double from_time = p_time - p_delta; - double to_time = p_time; - - if (from_time > to_time) { - SWAP(from_time, to_time); - } - - switch (loop_mode) { - case LOOP_NONE: { - if (from_time < 0) { - from_time = 0; - } - if (from_time > length) { - from_time = length; - } - - if (to_time < 0) { - to_time = 0; - } - if (to_time > length) { - to_time = length; - } - } break; - case LOOP_LINEAR: { - from_time = Math::fposmod(from_time, length); - to_time = Math::fposmod(to_time, length); - - if (from_time > to_time) { - // handle loop by splitting - _value_track_get_key_indices_in_range(vt, from_time, length, p_indices); - _value_track_get_key_indices_in_range(vt, 0, to_time, p_indices); - return; - } - } break; - case LOOP_PINGPONG: { - from_time = Math::pingpong(from_time, length); - to_time = Math::pingpong(to_time, length); - - if (p_pingponged == -1) { - // handle loop by splitting - _value_track_get_key_indices_in_range(vt, 0, from_time, p_indices); - _value_track_get_key_indices_in_range(vt, 0, to_time, p_indices); - return; - } - if (p_pingponged == 1) { - // handle loop by splitting - _value_track_get_key_indices_in_range(vt, from_time, length, p_indices); - _value_track_get_key_indices_in_range(vt, to_time, length, p_indices); - return; - } - } break; - } - - _value_track_get_key_indices_in_range(vt, from_time, to_time, p_indices); -} - void Animation::value_track_set_update_mode(int p_track, UpdateMode p_mode) { ERR_FAIL_INDEX(p_track, tracks.size()); Track *t = tracks[p_track]; @@ -2827,7 +2727,7 @@ Animation::UpdateMode Animation::value_track_get_update_mode(int p_track) const template <class T> void Animation::_track_get_key_indices_in_range(const Vector<T> &p_array, double from_time, double to_time, List<int> *p_indices) const { - if (from_time != length && to_time == length) { + if (to_time == length) { to_time = length + CMP_EPSILON; //include a little more if at the end } @@ -2861,6 +2761,11 @@ void Animation::_track_get_key_indices_in_range(const Vector<T> &p_array, double void Animation::track_get_key_indices_in_range(int p_track, double p_time, double p_delta, List<int> *p_indices, int p_pingponged) const { ERR_FAIL_INDEX(p_track, tracks.size()); + + if (p_delta == 0) { + return; // Prevent to get key continuously. + } + const Track *t = tracks[p_track]; double from_time = p_time - p_delta; @@ -2977,86 +2882,88 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl if ((int)Math::floor(abs(p_delta) / length) % 2 == 0) { if (p_pingponged == -1) { // handle loop by splitting + to_time = MAX(CMP_EPSILON, to_time); // To avoid overlapping keys at the turnaround point, one of the point will needs to be shifted slightly. switch (t->type) { case TYPE_POSITION_3D: { const PositionTrack *tt = static_cast<const PositionTrack *>(t); if (tt->compressed_track >= 0) { _get_compressed_key_indices_in_range<3>(tt->compressed_track, 0, from_time, p_indices); - _get_compressed_key_indices_in_range<3>(tt->compressed_track, 0, to_time, p_indices); + _get_compressed_key_indices_in_range<3>(tt->compressed_track, CMP_EPSILON, to_time, p_indices); } else { _track_get_key_indices_in_range(tt->positions, 0, from_time, p_indices); - _track_get_key_indices_in_range(tt->positions, 0, to_time, p_indices); + _track_get_key_indices_in_range(tt->positions, CMP_EPSILON, to_time, p_indices); } } break; case TYPE_ROTATION_3D: { const RotationTrack *rt = static_cast<const RotationTrack *>(t); if (rt->compressed_track >= 0) { _get_compressed_key_indices_in_range<3>(rt->compressed_track, 0, from_time, p_indices); - _get_compressed_key_indices_in_range<3>(rt->compressed_track, 0, to_time, p_indices); + _get_compressed_key_indices_in_range<3>(rt->compressed_track, CMP_EPSILON, to_time, p_indices); } else { _track_get_key_indices_in_range(rt->rotations, 0, from_time, p_indices); - _track_get_key_indices_in_range(rt->rotations, 0, to_time, p_indices); + _track_get_key_indices_in_range(rt->rotations, CMP_EPSILON, to_time, p_indices); } } break; case TYPE_SCALE_3D: { const ScaleTrack *st = static_cast<const ScaleTrack *>(t); if (st->compressed_track >= 0) { _get_compressed_key_indices_in_range<3>(st->compressed_track, 0, from_time, p_indices); - _get_compressed_key_indices_in_range<3>(st->compressed_track, 0, to_time, p_indices); + _get_compressed_key_indices_in_range<3>(st->compressed_track, CMP_EPSILON, to_time, p_indices); } else { _track_get_key_indices_in_range(st->scales, 0, from_time, p_indices); - _track_get_key_indices_in_range(st->scales, 0, to_time, p_indices); + _track_get_key_indices_in_range(st->scales, CMP_EPSILON, to_time, p_indices); } } break; case TYPE_BLEND_SHAPE: { const BlendShapeTrack *bst = static_cast<const BlendShapeTrack *>(t); if (bst->compressed_track >= 0) { _get_compressed_key_indices_in_range<1>(bst->compressed_track, 0, from_time, p_indices); - _get_compressed_key_indices_in_range<1>(bst->compressed_track, 0, to_time, p_indices); + _get_compressed_key_indices_in_range<1>(bst->compressed_track, CMP_EPSILON, to_time, p_indices); } else { _track_get_key_indices_in_range(bst->blend_shapes, 0, from_time, p_indices); - _track_get_key_indices_in_range(bst->blend_shapes, 0, to_time, p_indices); + _track_get_key_indices_in_range(bst->blend_shapes, CMP_EPSILON, to_time, p_indices); } } break; case TYPE_VALUE: { const ValueTrack *vt = static_cast<const ValueTrack *>(t); _track_get_key_indices_in_range(vt->values, 0, from_time, p_indices); - _track_get_key_indices_in_range(vt->values, 0, to_time, p_indices); + _track_get_key_indices_in_range(vt->values, CMP_EPSILON, to_time, p_indices); } break; case TYPE_METHOD: { const MethodTrack *mt = static_cast<const MethodTrack *>(t); _track_get_key_indices_in_range(mt->methods, 0, from_time, p_indices); - _track_get_key_indices_in_range(mt->methods, 0, to_time, p_indices); + _track_get_key_indices_in_range(mt->methods, CMP_EPSILON, to_time, p_indices); } break; case TYPE_BEZIER: { const BezierTrack *bz = static_cast<const BezierTrack *>(t); _track_get_key_indices_in_range(bz->values, 0, from_time, p_indices); - _track_get_key_indices_in_range(bz->values, 0, to_time, p_indices); + _track_get_key_indices_in_range(bz->values, CMP_EPSILON, to_time, p_indices); } break; case TYPE_AUDIO: { const AudioTrack *ad = static_cast<const AudioTrack *>(t); _track_get_key_indices_in_range(ad->values, 0, from_time, p_indices); - _track_get_key_indices_in_range(ad->values, 0, to_time, p_indices); + _track_get_key_indices_in_range(ad->values, CMP_EPSILON, to_time, p_indices); } break; case TYPE_ANIMATION: { const AnimationTrack *an = static_cast<const AnimationTrack *>(t); _track_get_key_indices_in_range(an->values, 0, from_time, p_indices); - _track_get_key_indices_in_range(an->values, 0, to_time, p_indices); + _track_get_key_indices_in_range(an->values, CMP_EPSILON, to_time, p_indices); } break; } return; } if (p_pingponged == 1) { // handle loop by splitting + to_time = MIN(length - CMP_EPSILON, to_time); switch (t->type) { case TYPE_POSITION_3D: { const PositionTrack *tt = static_cast<const PositionTrack *>(t); if (tt->compressed_track >= 0) { _get_compressed_key_indices_in_range<3>(tt->compressed_track, from_time, length, p_indices); - _get_compressed_key_indices_in_range<3>(tt->compressed_track, to_time, length, p_indices); + _get_compressed_key_indices_in_range<3>(tt->compressed_track, to_time, length - CMP_EPSILON, p_indices); } else { _track_get_key_indices_in_range(tt->positions, from_time, length, p_indices); - _track_get_key_indices_in_range(tt->positions, to_time, length, p_indices); + _track_get_key_indices_in_range(tt->positions, to_time, length - CMP_EPSILON, p_indices); } } break; case TYPE_ROTATION_3D: { @@ -3066,7 +2973,7 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl _get_compressed_key_indices_in_range<3>(rt->compressed_track, to_time, length, p_indices); } else { _track_get_key_indices_in_range(rt->rotations, from_time, length, p_indices); - _track_get_key_indices_in_range(rt->rotations, to_time, length, p_indices); + _track_get_key_indices_in_range(rt->rotations, to_time, length - CMP_EPSILON, p_indices); } } break; case TYPE_SCALE_3D: { @@ -3076,43 +2983,43 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl _get_compressed_key_indices_in_range<3>(st->compressed_track, to_time, length, p_indices); } else { _track_get_key_indices_in_range(st->scales, from_time, length, p_indices); - _track_get_key_indices_in_range(st->scales, to_time, length, p_indices); + _track_get_key_indices_in_range(st->scales, to_time, length - CMP_EPSILON, p_indices); } } break; case TYPE_BLEND_SHAPE: { const BlendShapeTrack *bst = static_cast<const BlendShapeTrack *>(t); if (bst->compressed_track >= 0) { _get_compressed_key_indices_in_range<1>(bst->compressed_track, from_time, length, p_indices); - _get_compressed_key_indices_in_range<1>(bst->compressed_track, to_time, length, p_indices); + _get_compressed_key_indices_in_range<1>(bst->compressed_track, to_time, length - CMP_EPSILON, p_indices); } else { _track_get_key_indices_in_range(bst->blend_shapes, from_time, length, p_indices); - _track_get_key_indices_in_range(bst->blend_shapes, to_time, length, p_indices); + _track_get_key_indices_in_range(bst->blend_shapes, to_time, length - CMP_EPSILON, p_indices); } } break; case TYPE_VALUE: { const ValueTrack *vt = static_cast<const ValueTrack *>(t); _track_get_key_indices_in_range(vt->values, from_time, length, p_indices); - _track_get_key_indices_in_range(vt->values, to_time, length, p_indices); + _track_get_key_indices_in_range(vt->values, to_time, length - CMP_EPSILON, p_indices); } break; case TYPE_METHOD: { const MethodTrack *mt = static_cast<const MethodTrack *>(t); _track_get_key_indices_in_range(mt->methods, from_time, length, p_indices); - _track_get_key_indices_in_range(mt->methods, to_time, length, p_indices); + _track_get_key_indices_in_range(mt->methods, to_time, length - CMP_EPSILON, p_indices); } break; case TYPE_BEZIER: { const BezierTrack *bz = static_cast<const BezierTrack *>(t); _track_get_key_indices_in_range(bz->values, from_time, length, p_indices); - _track_get_key_indices_in_range(bz->values, to_time, length, p_indices); + _track_get_key_indices_in_range(bz->values, to_time, length - CMP_EPSILON, p_indices); } break; case TYPE_AUDIO: { const AudioTrack *ad = static_cast<const AudioTrack *>(t); _track_get_key_indices_in_range(ad->values, from_time, length, p_indices); - _track_get_key_indices_in_range(ad->values, to_time, length, p_indices); + _track_get_key_indices_in_range(ad->values, to_time, length - CMP_EPSILON, p_indices); } break; case TYPE_ANIMATION: { const AnimationTrack *an = static_cast<const AnimationTrack *>(t); _track_get_key_indices_in_range(an->values, from_time, length, p_indices); - _track_get_key_indices_in_range(an->values, to_time, length, p_indices); + _track_get_key_indices_in_range(an->values, to_time, length - CMP_EPSILON, p_indices); } break; } return; @@ -3177,110 +3084,6 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl } } -void Animation::_method_track_get_key_indices_in_range(const MethodTrack *mt, double from_time, double to_time, List<int> *p_indices) const { - if (from_time != length && to_time == length) { - to_time = length + CMP_EPSILON; //include a little more if at the end - } - - int to = _find(mt->methods, to_time); - - // can't really send the events == time, will be sent in the next frame. - // if event>=len then it will probably never be requested by the anim player. - - if (to >= 0 && mt->methods[to].time >= to_time) { - to--; - } - - if (to < 0) { - return; // not bother - } - - int from = _find(mt->methods, from_time); - - // position in the right first event.+ - if (from < 0 || mt->methods[from].time < from_time) { - from++; - } - - int max = mt->methods.size(); - - for (int i = from; i <= to; i++) { - ERR_CONTINUE(i < 0 || i >= max); // shouldn't happen - p_indices->push_back(i); - } -} - -void Animation::method_track_get_key_indices(int p_track, double p_time, double p_delta, List<int> *p_indices, int p_pingponged) const { - ERR_FAIL_INDEX(p_track, tracks.size()); - Track *t = tracks[p_track]; - ERR_FAIL_COND(t->type != TYPE_METHOD); - - MethodTrack *mt = static_cast<MethodTrack *>(t); - - double from_time = p_time - p_delta; - double to_time = p_time; - - if (from_time > to_time) { - SWAP(from_time, to_time); - } - - switch (loop_mode) { - case LOOP_NONE: { - if (from_time < 0) { - from_time = 0; - } - if (from_time > length) { - from_time = length; - } - - if (to_time < 0) { - to_time = 0; - } - if (to_time > length) { - to_time = length; - } - } break; - case LOOP_LINEAR: { - if (from_time > length || from_time < 0) { - from_time = Math::fposmod(from_time, length); - } - if (to_time > length || to_time < 0) { - to_time = Math::fposmod(to_time, length); - } - - if (from_time > to_time) { - // handle loop by splitting - _method_track_get_key_indices_in_range(mt, from_time, length, p_indices); - _method_track_get_key_indices_in_range(mt, 0, to_time, p_indices); - return; - } - } break; - case LOOP_PINGPONG: { - if (from_time > length || from_time < 0) { - from_time = Math::pingpong(from_time, length); - } - if (to_time > length || to_time < 0) { - to_time = Math::pingpong(to_time, length); - } - - if (p_pingponged == -1) { - _method_track_get_key_indices_in_range(mt, 0, from_time, p_indices); - _method_track_get_key_indices_in_range(mt, 0, to_time, p_indices); - return; - } - if (p_pingponged == 1) { - _method_track_get_key_indices_in_range(mt, from_time, length, p_indices); - _method_track_get_key_indices_in_range(mt, to_time, length, p_indices); - return; - } - } break; - default: - break; - } - - _method_track_get_key_indices_in_range(mt, from_time, to_time, p_indices); -} - Vector<Variant> Animation::method_track_get_params(int p_track, int p_key_idx) const { ERR_FAIL_INDEX_V(p_track, tracks.size(), Vector<Variant>()); Track *t = tracks[p_track]; @@ -3941,10 +3744,8 @@ void Animation::_bind_methods() { ClassDB::bind_method(D_METHOD("value_track_set_update_mode", "track_idx", "mode"), &Animation::value_track_set_update_mode); ClassDB::bind_method(D_METHOD("value_track_get_update_mode", "track_idx"), &Animation::value_track_get_update_mode); - ClassDB::bind_method(D_METHOD("value_track_get_key_indices", "track_idx", "time_sec", "delta"), &Animation::_value_track_get_key_indices); ClassDB::bind_method(D_METHOD("value_track_interpolate", "track_idx", "time_sec"), &Animation::value_track_interpolate); - ClassDB::bind_method(D_METHOD("method_track_get_key_indices", "track_idx", "time_sec", "delta"), &Animation::_method_track_get_key_indices); ClassDB::bind_method(D_METHOD("method_track_get_name", "track_idx", "key_idx"), &Animation::method_track_get_name); ClassDB::bind_method(D_METHOD("method_track_get_params", "track_idx", "key_idx"), &Animation::method_track_get_params); diff --git a/scene/resources/animation.h b/scene/resources/animation.h index 49c8fa4c22..6c1ca3cd05 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -252,9 +252,6 @@ private: template <class T> _FORCE_INLINE_ void _track_get_key_indices_in_range(const Vector<T> &p_array, double from_time, double to_time, List<int> *p_indices) const; - _FORCE_INLINE_ void _value_track_get_key_indices_in_range(const ValueTrack *vt, double from_time, double to_time, List<int> *p_indices) const; - _FORCE_INLINE_ void _method_track_get_key_indices_in_range(const MethodTrack *mt, double from_time, double to_time, List<int> *p_indices) const; - double length = 1.0; real_t step = 0.1; LoopMode loop_mode = LOOP_NONE; @@ -345,27 +342,6 @@ private: // bind helpers private: - Vector<int> _value_track_get_key_indices(int p_track, double p_time, double p_delta) const { - List<int> idxs; - value_track_get_key_indices(p_track, p_time, p_delta, &idxs); - Vector<int> idxr; - - for (int &E : idxs) { - idxr.push_back(E); - } - return idxr; - } - Vector<int> _method_track_get_key_indices(int p_track, double p_time, double p_delta) const { - List<int> idxs; - method_track_get_key_indices(p_track, p_time, p_delta, &idxs); - Vector<int> idxr; - - for (int &E : idxs) { - idxr.push_back(E); - } - return idxr; - } - bool _float_track_optimize_key(const TKey<float> t0, const TKey<float> t1, const TKey<float> t2, real_t p_allowed_velocity_err, real_t p_allowed_precision_error); bool _vector2_track_optimize_key(const TKey<Vector2> t0, const TKey<Vector2> t1, const TKey<Vector2> t2, real_t p_alowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error); bool _vector3_track_optimize_key(const TKey<Vector3> t0, const TKey<Vector3> t1, const TKey<Vector3> t2, real_t p_alowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error); @@ -470,11 +446,9 @@ public: bool track_get_interpolation_loop_wrap(int p_track) const; Variant value_track_interpolate(int p_track, double p_time) const; - void value_track_get_key_indices(int p_track, double p_time, double p_delta, List<int> *p_indices, int p_pingponged = 0) const; void value_track_set_update_mode(int p_track, UpdateMode p_mode); UpdateMode value_track_get_update_mode(int p_track) const; - void method_track_get_key_indices(int p_track, double p_time, double p_delta, List<int> *p_indices, int p_pingponged = 0) const; Vector<Variant> method_track_get_params(int p_track, int p_key_idx) const; StringName method_track_get_name(int p_track, int p_key_idx) const; diff --git a/scene/resources/importer_mesh.cpp b/scene/resources/importer_mesh.cpp index cec5569345..d1278f9340 100644 --- a/scene/resources/importer_mesh.cpp +++ b/scene/resources/importer_mesh.cpp @@ -971,10 +971,10 @@ Vector<Ref<Shape3D>> ImporterMesh::convex_decompose(const Mesh::ConvexDecomposit return ret; } -Ref<Shape3D> ImporterMesh::create_trimesh_shape() const { +Ref<ConcavePolygonShape3D> ImporterMesh::create_trimesh_shape() const { Vector<Face3> faces = get_faces(); if (faces.size() == 0) { - return Ref<Shape3D>(); + return Ref<ConcavePolygonShape3D>(); } Vector<Vector3> face_points; diff --git a/scene/resources/importer_mesh.h b/scene/resources/importer_mesh.h index 088a77edd1..bbd6498fcf 100644 --- a/scene/resources/importer_mesh.h +++ b/scene/resources/importer_mesh.h @@ -119,7 +119,7 @@ public: Vector<Face3> get_faces() const; Vector<Ref<Shape3D>> convex_decompose(const Mesh::ConvexDecompositionSettings &p_settings) const; - Ref<Shape3D> create_trimesh_shape() const; + Ref<ConcavePolygonShape3D> create_trimesh_shape() const; Ref<NavigationMesh> create_navigation_mesh(); Error lightmap_unwrap_cached(const Transform3D &p_base_transform, float p_texel_size, const Vector<uint8_t> &p_src_cache, Vector<uint8_t> &r_dst_cache); diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index d1e300e057..4f68a6f69b 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -388,7 +388,7 @@ Vector<Face3> Mesh::get_surface_faces(int p_surface) const { return Vector<Face3>(); } -Ref<Shape3D> Mesh::create_convex_shape(bool p_clean, bool p_simplify) const { +Ref<ConvexPolygonShape3D> Mesh::create_convex_shape(bool p_clean, bool p_simplify) const { if (p_simplify) { ConvexDecompositionSettings settings; settings.max_convex_hulls = 1; @@ -425,10 +425,10 @@ Ref<Shape3D> Mesh::create_convex_shape(bool p_clean, bool p_simplify) const { return shape; } -Ref<Shape3D> Mesh::create_trimesh_shape() const { +Ref<ConcavePolygonShape3D> Mesh::create_trimesh_shape() const { Vector<Face3> faces = get_faces(); if (faces.size() == 0) { - return Ref<Shape3D>(); + return Ref<ConcavePolygonShape3D>(); } Vector<Vector3> face_points; diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index 5ed4164117..6f995280e8 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -35,9 +35,12 @@ #include "core/math/face3.h" #include "core/math/triangle_mesh.h" #include "scene/resources/material.h" -#include "scene/resources/shape_3d.h" #include "servers/rendering_server.h" +class ConcavePolygonShape3D; +class ConvexPolygonShape3D; +class Shape3D; + class Mesh : public Resource { GDCLASS(Mesh, Resource); @@ -211,8 +214,8 @@ public: static ConvexDecompositionFunc convex_decomposition_function; Vector<Ref<Shape3D>> convex_decompose(const ConvexDecompositionSettings &p_settings) const; - Ref<Shape3D> create_convex_shape(bool p_clean = true, bool p_simplify = false) const; - Ref<Shape3D> create_trimesh_shape() const; + Ref<ConvexPolygonShape3D> create_convex_shape(bool p_clean = true, bool p_simplify = false) const; + Ref<ConcavePolygonShape3D> create_trimesh_shape() const; virtual int get_builtin_bind_pose_count() const; virtual Transform3D get_builtin_bind_pose(int p_index) const; diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index f46faa1013..f4b7f3d0b2 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -1005,6 +1005,37 @@ void SceneState::clear() { base_scene_idx = -1; } +Error SceneState::copy_from(const Ref<SceneState> &p_scene_state) { + ERR_FAIL_COND_V(p_scene_state.is_null(), ERR_INVALID_PARAMETER); + + clear(); + + for (const StringName &E : p_scene_state->names) { + names.append(E); + } + for (const Variant &E : p_scene_state->variants) { + variants.append(E); + } + for (const SceneState::NodeData &E : p_scene_state->nodes) { + nodes.append(E); + } + for (const SceneState::ConnectionData &E : p_scene_state->connections) { + connections.append(E); + } + for (KeyValue<NodePath, int> &E : p_scene_state->node_path_cache) { + node_path_cache.insert(E.key, E.value); + } + for (const NodePath &E : p_scene_state->node_paths) { + node_paths.append(E); + } + for (const NodePath &E : p_scene_state->editable_instances) { + editable_instances.append(E); + } + base_scene_idx = p_scene_state->base_scene_idx; + + return OK; +} + Ref<SceneState> SceneState::get_base_scene_state() const { if (base_scene_idx >= 0) { Ref<PackedScene> ps = variants[base_scene_idx]; @@ -1737,6 +1768,28 @@ void PackedScene::clear() { state->clear(); } +void PackedScene::reload_from_file() { + String path = get_path(); + if (!path.is_resource_file()) { + return; + } + + Ref<PackedScene> s = ResourceLoader::load(ResourceLoader::path_remap(path), get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE); + if (!s.is_valid()) { + return; + } + + // Backup the loaded_state + Ref<SceneState> loaded_state = s->get_state(); + // This assigns a new state to s->state + // We do this because of the next step + s->recreate_state(); + // This has a side-effect to clear s->state + copy_from(s); + // Then, we copy the backed-up loaded_state to state + state->copy_from(loaded_state); +} + bool PackedScene::can_instantiate() const { return state->can_instantiate(); } diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h index a30ec54d85..ad1f50cd39 100644 --- a/scene/resources/packed_scene.h +++ b/scene/resources/packed_scene.h @@ -143,6 +143,7 @@ public: String get_path() const; void clear(); + Error copy_from(const Ref<SceneState> &p_scene_state); bool can_instantiate() const; Node *instantiate(GenEditState p_edit_state) const; @@ -235,6 +236,8 @@ public: void recreate_state(); void replace_state(Ref<SceneState> p_by); + virtual void reload_from_file() override; + virtual void set_path(const String &p_path, bool p_take_over = false) override; #ifdef TOOLS_ENABLED virtual void set_last_modified_time(uint64_t p_time) override { diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 8b2b7e118c..354373ef3c 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -144,6 +144,7 @@ Error ResourceLoaderText::_parse_ext_resource(VariantParser::Stream *p_stream, R } String id = token.value; + Error err = OK; if (!ignore_resource_parsing) { if (!ext_resources.has(id)) { @@ -163,7 +164,7 @@ Error ResourceLoaderText::_parse_ext_resource(VariantParser::Stream *p_stream, R error = ERR_FILE_MISSING_DEPENDENCIES; error_text = "[ext_resource] referenced nonexistent resource at: " + path; _printerr(); - return error; + err = error; } else { ResourceLoader::notify_dependency_error(local_path, path, type); } @@ -175,7 +176,7 @@ Error ResourceLoaderText::_parse_ext_resource(VariantParser::Stream *p_stream, R error = ERR_FILE_MISSING_DEPENDENCIES; error_text = "[ext_resource] referenced non-loaded resource at: " + path; _printerr(); - return error; + err = error; } } else { r_res = Ref<Resource>(); @@ -187,7 +188,7 @@ Error ResourceLoaderText::_parse_ext_resource(VariantParser::Stream *p_stream, R return ERR_PARSE_ERROR; } - return OK; + return err; } Ref<PackedScene> ResourceLoaderText::_parse_node_tag(VariantParser::ResourceParser &parser) { diff --git a/scene/theme/theme_db.cpp b/scene/theme/theme_db.cpp index 1025d40b05..0268a685fe 100644 --- a/scene/theme/theme_db.cpp +++ b/scene/theme/theme_db.cpp @@ -49,7 +49,7 @@ void ThemeDB::initialize_theme() { ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom", PropertyInfo(Variant::STRING, "gui/theme/custom", PROPERTY_HINT_FILE, "*.tres,*.res,*.theme", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); String font_path = GLOBAL_DEF_RST("gui/theme/custom_font", ""); - ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom_font", PropertyInfo(Variant::STRING, "gui/theme/custom_font", PROPERTY_HINT_FILE, "*.tres,*.res", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); + ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom_font", PropertyInfo(Variant::STRING, "gui/theme/custom_font", PROPERTY_HINT_FILE, "*.tres,*.res,*.otf,*.ttf,*.woff,*.woff2,*.fnt,*.font,*.pfb,*.pfm", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); TextServer::FontAntialiasing font_antialiasing = (TextServer::FontAntialiasing)(int)GLOBAL_DEF_RST("gui/theme/default_font_antialiasing", 1); ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_font_antialiasing", PropertyInfo(Variant::INT, "gui/theme/default_font_antialiasing", PROPERTY_HINT_ENUM, "None,Grayscale,LCD Subpixel", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); diff --git a/thirdparty/README.md b/thirdparty/README.md index ad290880e6..a75ceda7d3 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -44,7 +44,7 @@ Files extracted from upstream source: ## certs - Upstream: Mozilla, via https://github.com/bagder/ca-bundle -- Version: git (7f33e7eb8472dbcf31fdcf50cd216c89a282825d, 2022) +- Version: git (b2f7415648411b6fd7c298c6c92d6552f0165f60, 2022) - License: MPL 2.0 @@ -591,7 +591,7 @@ in 10.40, it can be found in the `patches` folder. ## recastnavigation - Upstream: https://github.com/recastnavigation/recastnavigation -- Version: git (5a870d427e47abd4a8e4ce58a95582ec049434d5, 2022) +- Version: git (4fef0446609b23d6ac180ed822817571525528a1, 2022) - License: zlib Files extracted from upstream source: diff --git a/thirdparty/certs/ca-certificates.crt b/thirdparty/certs/ca-certificates.crt index 036f630d5b..5ed6adf574 100644 --- a/thirdparty/certs/ca-certificates.crt +++ b/thirdparty/certs/ca-certificates.crt @@ -1,7 +1,7 @@ ## ## Bundle of CA Root Certificates ## -## Certificate data from Mozilla as of: Tue Jul 19 14:20:01 2022 GMT +## Certificate data from Mozilla as of: Fri Oct 21 16:14:43 2022 GMT ## ## This is a bundle of X.509 certificates of public Certificate Authorities ## (CA). These were automatically extracted from Mozilla's root certificates @@ -14,7 +14,7 @@ ## Just configure this file as the SSLCACertificateFile. ## ## Conversion done with mk-ca-bundle.pl version 1.29. -## SHA256: 9bf3799611fb58197f61d45e71ce3dc19f30e7dd73731915872ce5108a7bb066 +## SHA256: 3ff8bd209b5f2e739b9f2b96eacb694a774114685b02978257824f37ff528f71 ## @@ -3458,3 +3458,49 @@ zPUwHQYDVR0OBBYEFP+CMXI++cRmbK04ntGwUYilkMz1MA4GA1UdDwEB/wQEAwIBBjAKBggqhkjO PQQDAwNpADBmAjEA5gVYaWHlLcoNy/EZCL3W/VGSGn5jVASQkZo1kTmZ+gepZpO6yGjUij/67W4W Aie3AjEA3VoXK3YdZUKWpqxdinlW2Iob35reX8dQj7FbcQwm32pAAOwzkSFxvmjkI6TZraE3 -----END CERTIFICATE----- + +Security Communication RootCA3 +============================== +-----BEGIN CERTIFICATE----- +MIIFfzCCA2egAwIBAgIJAOF8N0D9G/5nMA0GCSqGSIb3DQEBDAUAMF0xCzAJBgNVBAYTAkpQMSUw +IwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMScwJQYDVQQDEx5TZWN1cml0eSBD +b21tdW5pY2F0aW9uIFJvb3RDQTMwHhcNMTYwNjE2MDYxNzE2WhcNMzgwMTE4MDYxNzE2WjBdMQsw +CQYDVQQGEwJKUDElMCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UE +AxMeU2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EzMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEA48lySfcw3gl8qUCBWNO0Ot26YQ+TUG5pPDXC7ltzkBtnTCHsXzW7OT4rCmDvu20r +hvtxosis5FaU+cmvsXLUIKx00rgVrVH+hXShuRD+BYD5UpOzQD11EKzAlrenfna84xtSGc4RHwsE +NPXY9Wk8d/Nk9A2qhd7gCVAEF5aEt8iKvE1y/By7z/MGTfmfZPd+pmaGNXHIEYBMwXFAWB6+oHP2 +/D5Q4eAvJj1+XCO1eXDe+uDRpdYMQXF79+qMHIjH7Iv10S9VlkZ8WjtYO/u62C21Jdp6Ts9EriGm +npjKIG58u4iFW/vAEGK78vknR+/RiTlDxN/e4UG/VHMgly1s2vPUB6PmudhvrvyMGS7TZ2crldtY +XLVqAvO4g160a75BflcJdURQVc1aEWEhCmHCqYj9E7wtiS/NYeCVvsq1e+F7NGcLH7YMx3weGVPK +p7FKFSBWFHA9K4IsD50VHUeAR/94mQ4xr28+j+2GaR57GIgUssL8gjMunEst+3A7caoreyYn8xrC +3PsXuKHqy6C0rtOUfnrQq8PsOC0RLoi/1D+tEjtCrI8Cbn3M0V9hvqG8OmpI6iZVIhZdXw3/JzOf +GAN0iltSIEdrRU0id4xVJ/CvHozJgyJUt5rQT9nO/NkuHJYosQLTA70lUhw0Zk8jq/R3gpYd0Vcw +CBEF/VfR2ccCAwEAAaNCMEAwHQYDVR0OBBYEFGQUfPxYchamCik0FW8qy7z8r6irMA4GA1UdDwEB +/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBDAUAA4ICAQDcAiMI4u8hOscNtybS +YpOnpSNyByCCYN8Y11StaSWSntkUz5m5UoHPrmyKO1o5yGwBQ8IibQLwYs1OY0PAFNr0Y/Dq9HHu +Tofjcan0yVflLl8cebsjqodEV+m9NU1Bu0soo5iyG9kLFwfl9+qd9XbXv8S2gVj/yP9kaWJ5rW4O +H3/uHWnlt3Jxs/6lATWUVCvAUm2PVcTJ0rjLyjQIUYWg9by0F1jqClx6vWPGOi//lkkZhOpn2ASx +YfQAW0q3nHE3GYV5v4GwxxMOdnE+OoAGrgYWp421wsTL/0ClXI2lyTrtcoHKXJg80jQDdwj98ClZ +XSEIx2C/pHF7uNkegr4Jr2VvKKu/S7XuPghHJ6APbw+LP6yVGPO5DtxnVW5inkYO0QR4ynKudtml ++LLfiAlhi+8kTtFZP1rUPcmTPCtk9YENFpb3ksP+MW/oKjJ0DvRMmEoYDjBU1cXrvMUVnuiZIesn +KwkK2/HmcBhWuwzkvvnoEKQTkrgc4NtnHVMDpCKn3F2SEDzq//wbEBrD2NCcnWXL0CsnMQMeNuE9 +dnUM/0Umud1RvCPHX9jYhxBAEg09ODfnRDwYwFMJZI//1ZqmfHAuc1Uh6N//g7kdPjIe1qZ9LPFm +6Vwdp6POXiUyK+OVrCoHzrQoeIY8LaadTdJ0MN1kURXbg4NR16/9M51NZg== +-----END CERTIFICATE----- + +Security Communication ECC RootCA1 +================================== +-----BEGIN CERTIFICATE----- +MIICODCCAb6gAwIBAgIJANZdm7N4gS7rMAoGCCqGSM49BAMDMGExCzAJBgNVBAYTAkpQMSUwIwYD +VQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMSswKQYDVQQDEyJTZWN1cml0eSBDb21t +dW5pY2F0aW9uIEVDQyBSb290Q0ExMB4XDTE2MDYxNjA1MTUyOFoXDTM4MDExODA1MTUyOFowYTEL +MAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKzApBgNV +BAMTIlNlY3VyaXR5IENvbW11bmljYXRpb24gRUNDIFJvb3RDQTEwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAASkpW9gAwPDvTH00xecK4R1rOX9PVdu12O/5gSJko6BnOPpR27KkBLIE+CnnfdldB9sELLo +5OnvbYUymUSxXv3MdhDYW72ixvnWQuRXdtyQwjWpS4g8EkdtXP9JTxpKULGjQjBAMB0GA1UdDgQW +BBSGHOf+LaVKiwj+KBH6vqNm+GBZLzAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAK +BggqhkjOPQQDAwNoADBlAjAVXUI9/Lbu9zuxNuie9sRGKEkz0FhDKmMpzE2xtHqiuQ04pV1IKv3L +snNdo4gIxwwCMQDAqy0Obe0YottT6SXbVQjgUMzfRGEWgqtJsLKB7HOHeLRMsmIbEvoWTSVLY70e +N9k= +-----END CERTIFICATE----- diff --git a/thirdparty/recastnavigation/Recast/Include/Recast.h b/thirdparty/recastnavigation/Recast/Include/Recast.h index 4d557389b5..246376bbee 100644 --- a/thirdparty/recastnavigation/Recast/Include/Recast.h +++ b/thirdparty/recastnavigation/Recast/Include/Recast.h @@ -22,13 +22,16 @@ /// The value of PI used by Recast. static const float RC_PI = 3.14159265f; +/// Used to ignore unused function parameters and silence any compiler warnings. +template<class T> void rcIgnoreUnused(const T&) { } + /// Recast log categories. /// @see rcContext enum rcLogCategory { RC_LOG_PROGRESS = 1, ///< A progress log entry. RC_LOG_WARNING, ///< A warning log entry. - RC_LOG_ERROR, ///< An error log entry. + RC_LOG_ERROR ///< An error log entry. }; /// Recast performance timer categories. @@ -101,7 +104,6 @@ enum rcTimerLabel class rcContext { public: - /// Contructor. /// @param[in] state TRUE if the logging and performance timers should be enabled. [Default: true] inline rcContext(bool state = true) : m_logEnabled(state), m_timerEnabled(state) {} @@ -140,31 +142,30 @@ public: inline int getAccumulatedTime(const rcTimerLabel label) const { return m_timerEnabled ? doGetAccumulatedTime(label) : -1; } protected: - /// Clears all log entries. - virtual void doResetLog() {} + virtual void doResetLog(); /// Logs a message. /// @param[in] category The category of the message. /// @param[in] msg The formatted message. /// @param[in] len The length of the formatted message. - virtual void doLog(const rcLogCategory /*category*/, const char* /*msg*/, const int /*len*/) {} + virtual void doLog(const rcLogCategory category, const char* msg, const int len) { rcIgnoreUnused(category); rcIgnoreUnused(msg); rcIgnoreUnused(len); } /// Clears all timers. (Resets all to unused.) virtual void doResetTimers() {} /// Starts the specified performance timer. /// @param[in] label The category of timer. - virtual void doStartTimer(const rcTimerLabel /*label*/) {} + virtual void doStartTimer(const rcTimerLabel label) { rcIgnoreUnused(label); } /// Stops the specified performance timer. /// @param[in] label The category of the timer. - virtual void doStopTimer(const rcTimerLabel /*label*/) {} + virtual void doStopTimer(const rcTimerLabel label) { rcIgnoreUnused(label); } /// Returns the total accumulated time of the specified performance timer. /// @param[in] label The category of the timer. /// @return The accumulated time of the timer, or -1 if timers are disabled or the timer has never been started. - virtual int doGetAccumulatedTime(const rcTimerLabel /*label*/) const { return -1; } + virtual int doGetAccumulatedTime(const rcTimerLabel label) const { rcIgnoreUnused(label); return -1; } /// True if logging is enabled. bool m_logEnabled; @@ -564,7 +565,7 @@ static const int RC_AREA_BORDER = 0x20000; enum rcBuildContoursFlags { RC_CONTOUR_TESS_WALL_EDGES = 0x01, ///< Tessellate solid (impassable) edges during contour simplification. - RC_CONTOUR_TESS_AREA_EDGES = 0x02, ///< Tessellate edges between areas during contour simplification. + RC_CONTOUR_TESS_AREA_EDGES = 0x02 ///< Tessellate edges between areas during contour simplification. }; /// Applied to the region id field of contour vertices in order to extract the region id. @@ -595,11 +596,6 @@ static const int RC_NOT_CONNECTED = 0x3f; /// @name General helper functions /// @{ -/// Used to ignore a function parameter. VS complains about unused parameters -/// and this silences the warning. -/// @param [in] _ Unused parameter -template<class T> void rcIgnoreUnused(const T&) { } - /// Swaps the values of the two parameters. /// @param[in,out] a Value A /// @param[in,out] b Value B @@ -996,6 +992,7 @@ void rcMarkConvexPolyArea(rcContext* ctx, const float* verts, const int nverts, /// @ingroup recast /// @param[in] verts The vertices of the polygon [Form: (x, y, z) * @p nverts] /// @param[in] nverts The number of vertices in the polygon. +/// @param[in] offset How much to offset the polygon by. [Units: wu] /// @param[out] outVerts The offset vertices (should hold up to 2 * @p nverts) [Form: (x, y, z) * return value] /// @param[in] maxOutVerts The max number of vertices that can be stored to @p outVerts. /// @returns Number of vertices in the offset polygon or 0 if too few vertices in @p outVerts. diff --git a/thirdparty/recastnavigation/Recast/Include/RecastAlloc.h b/thirdparty/recastnavigation/Recast/Include/RecastAlloc.h index 071278d659..8b166d736d 100644 --- a/thirdparty/recastnavigation/Recast/Include/RecastAlloc.h +++ b/thirdparty/recastnavigation/Recast/Include/RecastAlloc.h @@ -112,7 +112,7 @@ class rcVectorBase { typedef rcSizeType size_type; typedef T value_type; - rcVectorBase() : m_size(0), m_cap(0), m_data(0) {}; + rcVectorBase() : m_size(0), m_cap(0), m_data(0) {} rcVectorBase(const rcVectorBase<T, H>& other) : m_size(0), m_cap(0), m_data(0) { assign(other.begin(), other.end()); } explicit rcVectorBase(rcSizeType count) : m_size(0), m_cap(0), m_data(0) { resize(count); } rcVectorBase(rcSizeType count, const T& value) : m_size(0), m_cap(0), m_data(0) { resize(count, value); } @@ -142,8 +142,8 @@ class rcVectorBase { const T& front() const { rcAssert(m_size); return m_data[0]; } T& front() { rcAssert(m_size); return m_data[0]; } - const T& back() const { rcAssert(m_size); return m_data[m_size - 1]; }; - T& back() { rcAssert(m_size); return m_data[m_size - 1]; }; + const T& back() const { rcAssert(m_size); return m_data[m_size - 1]; } + T& back() { rcAssert(m_size); return m_data[m_size - 1]; } const T* data() const { return m_data; } T* data() { return m_data; } diff --git a/thirdparty/recastnavigation/Recast/Source/Recast.cpp b/thirdparty/recastnavigation/Recast/Source/Recast.cpp index 1b71710cdc..4cf145c981 100644 --- a/thirdparty/recastnavigation/Recast/Source/Recast.cpp +++ b/thirdparty/recastnavigation/Recast/Source/Recast.cpp @@ -94,6 +94,11 @@ void rcContext::log(const rcLogCategory category, const char* format, ...) doLog(category, msg, len); } +void rcContext::doResetLog() +{ + // Defined out of line to fix the weak v-tables warning +} + rcHeightfield* rcAllocHeightfield() { return rcNew<rcHeightfield>(RC_ALLOC_PERM); diff --git a/thirdparty/recastnavigation/Recast/Source/RecastMesh.cpp b/thirdparty/recastnavigation/Recast/Source/RecastMesh.cpp index e99eaebb79..ea09ee1de0 100644 --- a/thirdparty/recastnavigation/Recast/Source/RecastMesh.cpp +++ b/thirdparty/recastnavigation/Recast/Source/RecastMesh.cpp @@ -566,7 +566,6 @@ static bool canRemoveVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned sho const int nvp = mesh.nvp; // Count number of polygons to remove. - int numRemovedVerts = 0; int numTouchedVerts = 0; int numRemainingEdges = 0; for (int i = 0; i < mesh.npolys; ++i) @@ -586,7 +585,6 @@ static bool canRemoveVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned sho } if (numRemoved) { - numRemovedVerts += numRemoved; numRemainingEdges += numVerts-(numRemoved+1); } } diff --git a/thirdparty/recastnavigation/Recast/Source/RecastMeshDetail.cpp b/thirdparty/recastnavigation/Recast/Source/RecastMeshDetail.cpp index 1999200c1a..40bfc9b4bc 100644 --- a/thirdparty/recastnavigation/Recast/Source/RecastMeshDetail.cpp +++ b/thirdparty/recastnavigation/Recast/Source/RecastMeshDetail.cpp @@ -284,7 +284,7 @@ static unsigned short getHeight(const float fx, const float fy, const float fz, enum EdgeValues { EV_UNDEF = -1, - EV_HULL = -2, + EV_HULL = -2 }; static int findEdge(const int* edges, int nedges, int s, int t) diff --git a/thirdparty/recastnavigation/Recast/Source/RecastRasterization.cpp b/thirdparty/recastnavigation/Recast/Source/RecastRasterization.cpp index a4cef74909..673550e79e 100644 --- a/thirdparty/recastnavigation/Recast/Source/RecastRasterization.cpp +++ b/thirdparty/recastnavigation/Recast/Source/RecastRasterization.cpp @@ -264,7 +264,8 @@ static bool rasterizeTri(const float* v0, const float* v1, const float* v2, // Calculate the footprint of the triangle on the grid's y-axis int y0 = (int)((tmin[2] - bmin[2])*ics); int y1 = (int)((tmax[2] - bmin[2])*ics); - y0 = rcClamp(y0, 0, h-1); + // use -1 rather than 0 to cut the polygon properly at the start of the tile + y0 = rcClamp(y0, -1, h-1); y1 = rcClamp(y1, 0, h-1); // Clip the triangle into all grid cells it touches. @@ -283,7 +284,7 @@ static bool rasterizeTri(const float* v0, const float* v1, const float* v2, dividePoly(in, nvIn, inrow, &nvrow, p1, &nvIn, cz+cs, 2); rcSwap(in, p1); if (nvrow < 3) continue; - + if (y < 0) continue; // find the horizontal bounds in the row float minX = inrow[0], maxX = inrow[0]; for (int i=1; i<nvrow; ++i) @@ -293,7 +294,10 @@ static bool rasterizeTri(const float* v0, const float* v1, const float* v2, } int x0 = (int)((minX - bmin[0])*ics); int x1 = (int)((maxX - bmin[0])*ics); - x0 = rcClamp(x0, 0, w-1); + if (x1 < 0 || x0 >= w) { + continue; + } + x0 = rcClamp(x0, -1, w-1); x1 = rcClamp(x1, 0, w-1); int nv, nv2 = nvrow; @@ -305,7 +309,7 @@ static bool rasterizeTri(const float* v0, const float* v1, const float* v2, dividePoly(inrow, nv2, p1, &nv, p2, &nv2, cx+cs, 0); rcSwap(inrow, p2); if (nv < 3) continue; - + if (x < 0) continue; // Calculate min and max of the span. float smin = p1[1], smax = p1[1]; for (int i = 1; i < nv; ++i) |