summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--SConstruct4
-rw-r--r--doc/classes/Node2D.xml27
-rw-r--r--doc/classes/RDShaderSource.xml1
-rw-r--r--doc/classes/TreeItem.xml10
-rw-r--r--drivers/gles3/storage/light_storage.cpp5
-rw-r--r--editor/connections_dialog.cpp5
-rw-r--r--editor/editor_dock_manager.cpp4
-rw-r--r--editor/editor_node.cpp116
-rw-r--r--editor/editor_node.h11
-rw-r--r--editor/gui/editor_spin_slider.cpp2
-rw-r--r--editor/import/3d/scene_import_settings.cpp66
-rw-r--r--editor/import/3d/scene_import_settings.h4
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp2
-rw-r--r--editor/plugins/path_3d_editor_plugin.cpp73
-rw-r--r--editor/plugins/path_3d_editor_plugin.h4
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.cpp61
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.h11
-rw-r--r--editor/scene_tree_dock.cpp4
-rw-r--r--editor/themes/editor_theme_manager.cpp4
-rw-r--r--platform/macos/export/export_plugin.cpp19
-rw-r--r--scene/2d/canvas_modulate.cpp2
-rw-r--r--scene/2d/light_2d.cpp2
-rw-r--r--scene/2d/light_occluder_2d.cpp2
-rw-r--r--scene/2d/navigation_link_2d.cpp2
-rw-r--r--scene/2d/parallax_layer.cpp2
-rw-r--r--scene/2d/path_2d.cpp2
-rw-r--r--scene/2d/physics/collision_object_2d.cpp2
-rw-r--r--scene/2d/physics/collision_polygon_2d.cpp2
-rw-r--r--scene/2d/physics/collision_shape_2d.cpp2
-rw-r--r--scene/2d/physics/physical_bone_2d.cpp2
-rw-r--r--scene/2d/remote_transform_2d.cpp2
-rw-r--r--scene/2d/skeleton_2d.cpp2
-rw-r--r--scene/2d/tile_map.cpp2
-rw-r--r--scene/3d/decal.cpp2
-rw-r--r--scene/3d/fog_volume.cpp2
-rw-r--r--scene/3d/gpu_particles_collision_3d.cpp2
-rw-r--r--scene/3d/lightmap_gi.cpp2
-rw-r--r--scene/3d/navigation_link_3d.cpp2
-rw-r--r--scene/3d/navigation_region_3d.cpp2
-rw-r--r--scene/3d/occluder_instance_3d.cpp2
-rw-r--r--scene/3d/path_3d.cpp2
-rw-r--r--scene/3d/physics/collision_object_3d.cpp2
-rw-r--r--scene/3d/physics/collision_polygon_3d.cpp2
-rw-r--r--scene/3d/physics/collision_shape_3d.cpp2
-rw-r--r--scene/3d/physics/vehicle_body_3d.cpp2
-rw-r--r--scene/3d/remote_transform_3d.cpp2
-rw-r--r--scene/3d/soft_body_3d.cpp2
-rw-r--r--scene/3d/visual_instance_3d.cpp2
-rw-r--r--scene/3d/voxel_gi.cpp2
-rw-r--r--scene/3d/xr_nodes.cpp6
-rw-r--r--scene/animation/animation_tree.cpp2
-rw-r--r--scene/gui/control.cpp27
-rw-r--r--scene/gui/range.cpp2
-rw-r--r--scene/gui/rich_text_label.cpp29
-rw-r--r--scene/gui/subviewport_container.cpp2
-rw-r--r--scene/gui/tree.cpp18
-rw-r--r--scene/resources/audio_stream_wav.cpp68
-rw-r--r--scene/resources/audio_stream_wav.h4
-rw-r--r--scene/resources/packed_scene.cpp19
-rw-r--r--servers/audio/audio_stream.cpp10
60 files changed, 388 insertions, 290 deletions
diff --git a/SConstruct b/SConstruct
index 5c1ccd2449..178f2d86a2 100644
--- a/SConstruct
+++ b/SConstruct
@@ -1053,7 +1053,7 @@ if env["ninja"]:
SetOption("experimental", "ninja")
env["NINJA_FILE_NAME"] = env["ninja_file"]
env["NINJA_DISABLE_AUTO_RUN"] = not env["ninja_auto_run"]
- env.Tool("ninja")
+ env.Tool("ninja", "build.ninja")
# Threads
if env["threads"]:
@@ -1116,7 +1116,7 @@ atexit.register(print_elapsed_time)
def purge_flaky_files():
- paths_to_keep = ["ninja.build"]
+ paths_to_keep = ["build.ninja"]
for build_failure in GetBuildFailures():
path = build_failure.node.path
if os.path.isfile(path) and path not in paths_to_keep:
diff --git a/doc/classes/Node2D.xml b/doc/classes/Node2D.xml
index 851290de7b..0b2dfcea03 100644
--- a/doc/classes/Node2D.xml
+++ b/doc/classes/Node2D.xml
@@ -95,43 +95,44 @@
</methods>
<members>
<member name="global_position" type="Vector2" setter="set_global_position" getter="get_global_position">
- Global position.
+ Global position. See also [member position].
</member>
<member name="global_rotation" type="float" setter="set_global_rotation" getter="get_global_rotation">
- Global rotation in radians.
+ Global rotation in radians. See also [member rotation].
</member>
<member name="global_rotation_degrees" type="float" setter="set_global_rotation_degrees" getter="get_global_rotation_degrees">
- Helper property to access [member global_rotation] in degrees instead of radians.
+ Helper property to access [member global_rotation] in degrees instead of radians. See also [member rotation_degrees].
</member>
<member name="global_scale" type="Vector2" setter="set_global_scale" getter="get_global_scale">
- Global scale.
+ Global scale. See also [member scale].
</member>
<member name="global_skew" type="float" setter="set_global_skew" getter="get_global_skew">
- Global skew in radians.
+ Global skew in radians. See also [member skew].
</member>
<member name="global_transform" type="Transform2D" setter="set_global_transform" getter="get_global_transform">
- Global [Transform2D].
+ Global [Transform2D]. See also [member transform].
</member>
<member name="position" type="Vector2" setter="set_position" getter="get_position" default="Vector2(0, 0)">
- Position, relative to the node's parent.
+ Position, relative to the node's parent. See also [member global_position].
</member>
<member name="rotation" type="float" setter="set_rotation" getter="get_rotation" default="0.0">
- Rotation in radians, relative to the node's parent.
+ Rotation in radians, relative to the node's parent. See also [member global_rotation].
[b]Note:[/b] This property is edited in the inspector in degrees. If you want to use degrees in a script, use [member rotation_degrees].
</member>
<member name="rotation_degrees" type="float" setter="set_rotation_degrees" getter="get_rotation_degrees">
- Helper property to access [member rotation] in degrees instead of radians.
+ Helper property to access [member rotation] in degrees instead of radians. See also [member global_rotation_degrees].
</member>
<member name="scale" type="Vector2" setter="set_scale" getter="get_scale" default="Vector2(1, 1)">
- The node's scale. Unscaled value: [code](1, 1)[/code].
+ The node's scale, relative to the node's parent. Unscaled value: [code](1, 1)[/code]. See also [member global_scale].
[b]Note:[/b] Negative X scales in 2D are not decomposable from the transformation matrix. Due to the way scale is represented with transformation matrices in Godot, negative scales on the X axis will be changed to negative scales on the Y axis and a rotation of 180 degrees when decomposed.
</member>
<member name="skew" type="float" setter="set_skew" getter="get_skew" default="0.0">
- Slants the node.
- [b]Note:[/b] Skew is X axis only.
+ If set to a non-zero value, slants the node in one direction or another. This can be used for pseudo-3D effects. See also [member global_skew].
+ [b]Note:[/b] Skew is performed on the X axis only, and [i]between[/i] rotation and scaling.
+ [b]Note:[/b] This property is edited in the inspector in degrees. If you want to use degrees in a script, use [code]skew = deg_to_rad(value_in_degrees)[/code].
</member>
<member name="transform" type="Transform2D" setter="set_transform" getter="get_transform">
- Local [Transform2D].
+ The node's [Transform2D], relative to the node's parent. See also [member global_transform].
</member>
</members>
</class>
diff --git a/doc/classes/RDShaderSource.xml b/doc/classes/RDShaderSource.xml
index 062c22f11f..a7b897d56e 100644
--- a/doc/classes/RDShaderSource.xml
+++ b/doc/classes/RDShaderSource.xml
@@ -23,6 +23,7 @@
<param index="1" name="source" type="String" />
<description>
Sets [param source] code for the specified shader [param stage]. Equivalent to setting one of [member source_compute], [member source_fragment], [member source_tesselation_control], [member source_tesselation_evaluation] or [member source_vertex].
+ [b]Note:[/b] If you set the compute shader source code using this method directly, remember to remove the Godot-specific hint [code]#[compute][/code].
</description>
</method>
</methods>
diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml
index 78a703c213..bd46c54990 100644
--- a/doc/classes/TreeItem.xml
+++ b/doc/classes/TreeItem.xml
@@ -19,7 +19,7 @@
<param index="3" name="disabled" type="bool" default="false" />
<param index="4" name="tooltip_text" type="String" default="&quot;&quot;" />
<description>
- Adds a button with [Texture2D] [param button] at column [param column]. The [param id] is used to identify the button in the according [signal Tree.button_clicked] signal and can be different from the buttons index. If not specified, the next available index is used, which may be retrieved by calling [method get_button_count] immediately before this method. Optionally, the button can be [param disabled] and have a [param tooltip_text].
+ Adds a button with [Texture2D] [param button] to the end of the cell at column [param column]. The [param id] is used to identify the button in the according [signal Tree.button_clicked] signal and can be different from the buttons index. If not specified, the next available index is used, which may be retrieved by calling [method get_button_count] immediately before this method. Optionally, the button can be [param disabled] and have a [param tooltip_text].
</description>
</method>
<method name="add_child">
@@ -643,7 +643,7 @@
<param index="0" name="column" type="int" />
<param index="1" name="texture" type="Texture2D" />
<description>
- Sets the given cell's icon [Texture2D]. The cell has to be in [constant CELL_MODE_ICON] mode.
+ Sets the given cell's icon [Texture2D]. If the cell is in [constant CELL_MODE_ICON] mode, the icon is displayed in the center of the cell. Otherwise, the icon is displayed before the cell's text. [constant CELL_MODE_RANGE] does not display an icon.
</description>
</method>
<method name="set_icon_max_width">
@@ -811,17 +811,17 @@
</members>
<constants>
<constant name="CELL_MODE_STRING" value="0" enum="TreeCellMode">
- Cell shows a string label. When editable, the text can be edited using a [LineEdit], or a [TextEdit] popup if [method set_edit_multiline] is used.
+ Cell shows a string label, optionally with an icon. When editable, the text can be edited using a [LineEdit], or a [TextEdit] popup if [method set_edit_multiline] is used.
</constant>
<constant name="CELL_MODE_CHECK" value="1" enum="TreeCellMode">
- Cell shows a checkbox, optionally with text. The checkbox can be pressed, released, or indeterminate (via [method set_indeterminate]). The checkbox can't be clicked unless the cell is editable.
+ Cell shows a checkbox, optionally with text and an icon. The checkbox can be pressed, released, or indeterminate (via [method set_indeterminate]). The checkbox can't be clicked unless the cell is editable.
</constant>
<constant name="CELL_MODE_RANGE" value="2" enum="TreeCellMode">
Cell shows a numeric range. When editable, it can be edited using a range slider. Use [method set_range] to set the value and [method set_range_config] to configure the range.
This cell can also be used in a text dropdown mode when you assign a text with [method set_text]. Separate options with a comma, e.g. [code]"Option1,Option2,Option3"[/code].
</constant>
<constant name="CELL_MODE_ICON" value="3" enum="TreeCellMode">
- Cell shows an icon. It can't be edited nor display text.
+ Cell shows an icon. It can't be edited nor display text. The icon is always centered within the cell.
</constant>
<constant name="CELL_MODE_CUSTOM" value="4" enum="TreeCellMode">
Cell shows as a clickable button. It will display an arrow similar to [OptionButton], but doesn't feature a dropdown (for that you can use [constant CELL_MODE_RANGE]). Clicking the button emits the [signal Tree.item_edited] signal. The button is flat by default, you can use [method set_custom_as_button] to display it with a [StyleBox].
diff --git a/drivers/gles3/storage/light_storage.cpp b/drivers/gles3/storage/light_storage.cpp
index aab1aadf02..9b976c2206 100644
--- a/drivers/gles3/storage/light_storage.cpp
+++ b/drivers/gles3/storage/light_storage.cpp
@@ -1521,6 +1521,11 @@ bool LightStorage::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_i
uint64_t min_pass = 0; // Pass of the existing one, try to use the least recently used one (LRU fashion).
for (int j = 0; j < sc; j++) {
+ if (sarr[j].owner_is_omni != is_omni) {
+ // Existing light instance type doesn't match new light instance type skip.
+ continue;
+ }
+
LightInstance *sli = light_instance_owner.get_or_null(sarr[j].owner);
if (!sli) {
// Found a released light instance.
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index 063241fd1b..5273b61f37 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -486,11 +486,6 @@ void ConnectDialog::_notification(int p_what) {
type_list->set_item_icon(i, get_editor_theme_icon(type_name));
}
- Ref<StyleBox> style = get_theme_stylebox(CoreStringName(normal), "LineEdit")->duplicate();
- if (style.is_valid()) {
- style->set_content_margin(SIDE_TOP, style->get_content_margin(SIDE_TOP) + 1.0);
- from_signal->add_theme_style_override(CoreStringName(normal), style);
- }
method_search->set_right_icon(get_editor_theme_icon("Search"));
open_method_tree->set_icon(get_editor_theme_icon("Edit"));
} break;
diff --git a/editor/editor_dock_manager.cpp b/editor/editor_dock_manager.cpp
index 75135532aa..0bdda41f26 100644
--- a/editor/editor_dock_manager.cpp
+++ b/editor/editor_dock_manager.cpp
@@ -509,7 +509,7 @@ void EditorDockManager::save_docks_to_config(Ref<ConfigFile> p_layout, const Str
}
for (int i = 0; i < hsplits.size(); i++) {
- p_layout->set_value(p_section, "dock_hsplit_" + itos(i + 1), hsplits[i]->get_split_offset());
+ p_layout->set_value(p_section, "dock_hsplit_" + itos(i + 1), int(hsplits[i]->get_split_offset() / EDSCALE));
}
FileSystemDock::get_singleton()->save_layout_to_config(p_layout, p_section);
@@ -605,7 +605,7 @@ void EditorDockManager::load_docks_from_config(Ref<ConfigFile> p_layout, const S
continue;
}
int ofs = p_layout->get_value(p_section, "dock_hsplit_" + itos(i + 1));
- hsplits[i]->set_split_offset(ofs);
+ hsplits[i]->set_split_offset(ofs * EDSCALE);
}
FileSystemDock::get_singleton()->load_layout_from_config(p_layout, p_section);
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 6899a35ded..39291138a6 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -4404,6 +4404,21 @@ bool EditorNode::is_additional_node_in_scene(Node *p_edited_scene, Node *p_reimp
return true;
}
+void EditorNode::get_scene_editor_data_for_node(Node *p_root, Node *p_node, HashMap<NodePath, SceneEditorDataEntry> &p_table) {
+ SceneEditorDataEntry new_entry;
+ new_entry.is_display_folded = p_node->is_displayed_folded();
+
+ if (p_root != p_node) {
+ new_entry.is_editable = p_root->is_editable_instance(p_node);
+ }
+
+ p_table.insert(p_root->get_path_to(p_node), new_entry);
+
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ get_scene_editor_data_for_node(p_root, p_node->get_child(i), p_table);
+ }
+}
+
void EditorNode::get_preload_scene_modification_table(
Node *p_edited_scene,
Node *p_reimported_root,
@@ -4510,7 +4525,7 @@ void EditorNode::get_preload_scene_modification_table(
void EditorNode::get_preload_modifications_reference_to_nodes(
Node *p_root,
Node *p_node,
- List<Node *> &p_excluded_nodes,
+ HashSet<Node *> &p_excluded_nodes,
List<Node *> &p_instance_list_with_children,
HashMap<NodePath, ModificationNodeEntry> &p_modification_table) {
if (!p_excluded_nodes.find(p_node)) {
@@ -5984,12 +5999,14 @@ void EditorNode::reload_scene(const String &p_path) {
scene_tabs->set_current_tab(current_tab);
}
-void EditorNode::find_all_instances_inheriting_path_in_node(Node *p_root, Node *p_node, const String &p_instance_path, List<Node *> &p_instance_list) {
+void EditorNode::find_all_instances_inheriting_path_in_node(Node *p_root, Node *p_node, const String &p_instance_path, HashSet<Node *> &p_instance_list) {
String scene_file_path = p_node->get_scene_file_path();
- // This is going to get messy...
+ bool valid_instance_found = false;
+
+ // Attempt to find all the instances matching path we're going to reload.
if (p_node->get_scene_file_path() == p_instance_path) {
- p_instance_list.push_back(p_node);
+ valid_instance_found = true;
} else {
Node *current_node = p_node;
@@ -5997,7 +6014,7 @@ void EditorNode::find_all_instances_inheriting_path_in_node(Node *p_root, Node *
while (inherited_state.is_valid()) {
String inherited_path = inherited_state->get_path();
if (inherited_path == p_instance_path) {
- p_instance_list.push_back(p_node);
+ valid_instance_found = true;
break;
}
@@ -6005,6 +6022,19 @@ void EditorNode::find_all_instances_inheriting_path_in_node(Node *p_root, Node *
}
}
+ // Instead of adding this instance directly, if its not owned by the scene, walk its ancestors
+ // and find the first node still owned by the scene. This is what we will reloading instead.
+ if (valid_instance_found) {
+ Node *current_node = p_node;
+ while (true) {
+ if (current_node->get_owner() == p_root || current_node->get_owner() == nullptr) {
+ p_instance_list.insert(current_node);
+ break;
+ }
+ current_node = current_node->get_parent();
+ }
+ }
+
for (int i = 0; i < p_node->get_child_count(); i++) {
find_all_instances_inheriting_path_in_node(p_root, p_node->get_child(i), p_instance_path, p_instance_list);
}
@@ -6023,20 +6053,20 @@ void EditorNode::preload_reimporting_with_path_in_edited_scenes(const List<Strin
Node *edited_scene_root = editor_data.get_edited_scene_root(current_scene_idx);
if (edited_scene_root) {
- SceneModificationsEntry scene_motifications;
+ SceneModificationsEntry scene_modifications;
for (const String &instance_path : p_scenes) {
if (editor_data.get_scene_path(current_scene_idx) == instance_path) {
continue;
}
- List<Node *> instance_list;
- find_all_instances_inheriting_path_in_node(edited_scene_root, edited_scene_root, instance_path, instance_list);
- if (instance_list.size() > 0) {
+ HashSet<Node *> instances_to_reimport;
+ find_all_instances_inheriting_path_in_node(edited_scene_root, edited_scene_root, instance_path, instances_to_reimport);
+ if (instances_to_reimport.size() > 0) {
editor_data.set_edited_scene(current_scene_idx);
List<Node *> instance_list_with_children;
- for (Node *original_node : instance_list) {
+ for (Node *original_node : instances_to_reimport) {
InstanceModificationsEntry instance_modifications;
// Fetching all the modified properties of the nodes reimported scene.
@@ -6044,19 +6074,19 @@ void EditorNode::preload_reimporting_with_path_in_edited_scenes(const List<Strin
instance_modifications.original_node = original_node;
instance_modifications.instance_path = instance_path;
- scene_motifications.instance_list.push_back(instance_modifications);
+ scene_modifications.instance_list.push_back(instance_modifications);
instance_list_with_children.push_back(original_node);
get_children_nodes(original_node, instance_list_with_children);
}
// Search the scene to find nodes that references the nodes will be recreated.
- get_preload_modifications_reference_to_nodes(edited_scene_root, edited_scene_root, instance_list, instance_list_with_children, scene_motifications.other_instances_modifications);
+ get_preload_modifications_reference_to_nodes(edited_scene_root, edited_scene_root, instances_to_reimport, instance_list_with_children, scene_modifications.other_instances_modifications);
}
}
- if (scene_motifications.instance_list.size() > 0) {
- scenes_modification_table[current_scene_idx] = scene_motifications;
+ if (scene_modifications.instance_list.size() > 0) {
+ scenes_modification_table[current_scene_idx] = scene_modifications;
}
}
}
@@ -6179,10 +6209,10 @@ void EditorNode::reload_instances_with_path_in_edited_scenes() {
// Instantiate early so that caches cleared on load in SceneState can be rebuilt early.
Node *instantiated_node = nullptr;
- // If we are in a inherit scene, it's easier to create a new base scene and
+ // If we are in a inherited scene, it's easier to create a new base scene and
// grab the node from there.
// When scene_path_to_node is '.' and we have scene_inherited_state, it's because
- // it's a muli-level inheritance scene. We should use
+ // it's a multi-level inheritance scene. We should use
NodePath scene_path_to_node = current_edited_scene->get_path_to(original_node);
Ref<SceneState> scene_state = current_edited_scene->get_scene_inherited_state();
if (scene_path_to_node != "." && scene_state.is_valid() && scene_state->get_path() != instance_modifications.instance_path && scene_state->find_node_by_path(scene_path_to_node) >= 0) {
@@ -6206,9 +6236,9 @@ void EditorNode::reload_instances_with_path_in_edited_scenes() {
if (!instantiated_node) {
// If no base scene was found to create the node, we will use the reimported packed scene directly.
- // But, when the current edited scene is the reimported scene, it's because it's a inherited scene
- // of the reimported scene. In that case, we will not instantiate current_packed_scene, because
- // we would reinstanciate ourself. Using the base scene is better.
+ // But, when the current edited scene is the reimported scene, it's because it's an inherited scene
+ // derived from the reimported scene. In that case, we will not instantiate current_packed_scene, because
+ // we would reinstantiate ourself. Using the base scene is better.
if (current_edited_scene == original_node) {
if (base_packed_scene.is_valid()) {
instantiated_node = base_packed_scene->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
@@ -6264,6 +6294,17 @@ void EditorNode::reload_instances_with_path_in_edited_scenes() {
// crash when reimporting scenes with animations when "Editable children" was enabled.
replace_history_reimported_nodes(original_node, instantiated_node, original_node);
+ // Reset the editable instance state.
+ HashMap<NodePath, SceneEditorDataEntry> scene_editor_data_table;
+ Node *owner = original_node->get_owner();
+ if (!owner) {
+ owner = original_node;
+ }
+
+ get_scene_editor_data_for_node(owner, original_node, scene_editor_data_table);
+
+ bool original_node_scene_instance_load_placeholder = original_node->get_scene_instance_load_placeholder();
+
// Delete all the remaining node children.
while (original_node->get_child_count()) {
Node *child = original_node->get_child(0);
@@ -6272,16 +6313,6 @@ void EditorNode::reload_instances_with_path_in_edited_scenes() {
child->queue_free();
}
- // Reset the editable instance state.
- bool is_editable = true;
- Node *owner = original_node->get_owner();
- if (owner) {
- is_editable = owner->is_editable_instance(original_node);
- }
-
- bool original_node_is_displayed_folded = original_node->is_displayed_folded();
- bool original_node_scene_instance_load_placeholder = original_node->get_scene_instance_load_placeholder();
-
// Update the name to match
instantiated_node->set_name(original_node->get_name());
@@ -6312,19 +6343,9 @@ void EditorNode::reload_instances_with_path_in_edited_scenes() {
// Mark the old node for deletion.
original_node->queue_free();
- // Restore the folded and placeholder state from the original node.
- instantiated_node->set_display_folded(original_node_is_displayed_folded);
+ // Restore the placeholder state from the original node.
instantiated_node->set_scene_instance_load_placeholder(original_node_scene_instance_load_placeholder);
- if (owner) {
- Ref<SceneState> ss_inst = owner->get_scene_instance_state();
- if (ss_inst.is_valid()) {
- ss_inst->update_instance_resource(instance_modifications.instance_path, current_packed_scene);
- }
-
- owner->set_editable_instance(instantiated_node, is_editable);
- }
-
// Attempt to re-add all the additional nodes.
for (AdditiveNodeEntry additive_node_entry : instance_modifications.addition_list) {
Node *parent_node = instantiated_node->get_node_or_null(additive_node_entry.parent);
@@ -6356,6 +6377,17 @@ void EditorNode::reload_instances_with_path_in_edited_scenes() {
}
}
+ // Restore the scene's editable instance and folded states.
+ for (HashMap<NodePath, SceneEditorDataEntry>::Iterator I = scene_editor_data_table.begin(); I; ++I) {
+ Node *node = owner->get_node_or_null(I->key);
+ if (node) {
+ if (owner != node) {
+ owner->set_editable_instance(node, I->value.is_editable);
+ }
+ node->set_display_folded(I->value.is_display_folded);
+ }
+ }
+
// Restore the selection.
if (selected_node_paths.size()) {
for (NodePath selected_node_path : selected_node_paths) {
@@ -7585,8 +7617,8 @@ EditorNode::EditorNode() {
default_layout->set_value(docks_section, "dock_split_" + itos(i + 1), 0);
}
default_layout->set_value(docks_section, "dock_hsplit_1", 0);
- default_layout->set_value(docks_section, "dock_hsplit_2", 270 * EDSCALE);
- default_layout->set_value(docks_section, "dock_hsplit_3", -270 * EDSCALE);
+ default_layout->set_value(docks_section, "dock_hsplit_2", 270);
+ default_layout->set_value(docks_section, "dock_hsplit_3", -270);
default_layout->set_value(docks_section, "dock_hsplit_4", 0);
_update_layouts_menu();
diff --git a/editor/editor_node.h b/editor/editor_node.h
index e9d2c28528..f1b50cf3fa 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -852,12 +852,19 @@ public:
HashMap<NodePath, ModificationNodeEntry> other_instances_modifications;
};
+ struct SceneEditorDataEntry {
+ bool is_editable;
+ bool is_display_folded;
+ };
+
HashMap<int, SceneModificationsEntry> scenes_modification_table;
List<String> scenes_reimported;
List<String> resources_reimported;
void update_node_from_node_modification_entry(Node *p_node, ModificationNodeEntry &p_node_modification);
+ void get_scene_editor_data_for_node(Node *p_root, Node *p_node, HashMap<NodePath, SceneEditorDataEntry> &p_table);
+
void get_preload_scene_modification_table(
Node *p_edited_scene,
Node *p_reimported_root,
@@ -866,7 +873,7 @@ public:
void get_preload_modifications_reference_to_nodes(
Node *p_root,
Node *p_node,
- List<Node *> &p_excluded_nodes,
+ HashSet<Node *> &p_excluded_nodes,
List<Node *> &p_instance_list_with_children,
HashMap<NodePath, ModificationNodeEntry> &p_modification_table);
void get_children_nodes(Node *p_node, List<Node *> &p_nodes);
@@ -927,7 +934,7 @@ public:
void reload_scene(const String &p_path);
- void find_all_instances_inheriting_path_in_node(Node *p_root, Node *p_node, const String &p_instance_path, List<Node *> &p_instance_list);
+ void find_all_instances_inheriting_path_in_node(Node *p_root, Node *p_node, const String &p_instance_path, HashSet<Node *> &p_instance_list);
void preload_reimporting_with_path_in_edited_scenes(const List<String> &p_scenes);
void reload_instances_with_path_in_edited_scenes();
diff --git a/editor/gui/editor_spin_slider.cpp b/editor/gui/editor_spin_slider.cpp
index d49d597084..a073a2338b 100644
--- a/editor/gui/editor_spin_slider.cpp
+++ b/editor/gui/editor_spin_slider.cpp
@@ -636,7 +636,7 @@ void EditorSpinSlider::_grabber_mouse_exited() {
void EditorSpinSlider::set_read_only(bool p_enable) {
read_only = p_enable;
- if (read_only && value_input) {
+ if (read_only && value_input && value_input->is_inside_tree()) {
value_input->release_focus();
}
diff --git a/editor/import/3d/scene_import_settings.cpp b/editor/import/3d/scene_import_settings.cpp
index 7ca3cb6c3a..011d0135b4 100644
--- a/editor/import/3d/scene_import_settings.cpp
+++ b/editor/import/3d/scene_import_settings.cpp
@@ -37,6 +37,7 @@
#include "editor/editor_settings.h"
#include "editor/editor_string_names.h"
#include "editor/gui/editor_file_dialog.h"
+#include "editor/plugins/skeleton_3d_editor_plugin.h"
#include "editor/themes/editor_scale.h"
#include "scene/3d/importer_mesh_instance_3d.h"
#include "scene/animation/animation_player.h"
@@ -419,7 +420,9 @@ void SceneImportSettingsDialog::_fill_scene(Node *p_node, TreeItem *p_parent_ite
animation_player->connect(SceneStringName(animation_finished), callable_mp(this, &SceneImportSettingsDialog::_animation_finished));
} else if (Object::cast_to<Skeleton3D>(p_node)) {
category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE;
- skeletons.push_back(Object::cast_to<Skeleton3D>(p_node));
+ Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_node);
+ skeleton->connect(SceneStringName(tree_entered), callable_mp(this, &SceneImportSettingsDialog::_skeleton_tree_entered).bind(skeleton));
+ skeletons.push_back(skeleton);
} else {
category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_NODE;
}
@@ -480,6 +483,31 @@ void SceneImportSettingsDialog::_fill_scene(Node *p_node, TreeItem *p_parent_ite
contents_aabb.merge_with(aabb);
}
}
+
+ Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_node);
+ if (skeleton) {
+ Ref<ArrayMesh> bones_mesh = Skeleton3DGizmoPlugin::get_bones_mesh(skeleton, -1, true);
+
+ bones_mesh_preview->set_mesh(bones_mesh);
+
+ Transform3D accum_xform;
+ Node3D *base = skeleton;
+ while (base) {
+ accum_xform = base->get_transform() * accum_xform;
+ base = Object::cast_to<Node3D>(base->get_parent());
+ }
+
+ bones_mesh_preview->set_transform(accum_xform * skeleton->get_transform());
+
+ AABB aabb = accum_xform.xform(bones_mesh->get_aabb());
+
+ if (first_aabb) {
+ contents_aabb = aabb;
+ first_aabb = false;
+ } else {
+ contents_aabb.merge_with(aabb);
+ }
+ }
}
void SceneImportSettingsDialog::_update_scene() {
@@ -795,6 +823,7 @@ void SceneImportSettingsDialog::_select(Tree *p_from, const String &p_type, cons
selecting = true;
scene_import_settings_data->hide_options = false;
+ bones_mesh_preview->hide();
if (p_type == "Node") {
node_selected->hide(); // Always hide just in case.
mesh_preview->hide();
@@ -834,6 +863,7 @@ void SceneImportSettingsDialog::_select(Tree *p_from, const String &p_type, cons
scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE;
} else if (Object::cast_to<Skeleton3D>(nd.node)) {
scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE;
+ bones_mesh_preview->show();
} else {
scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_NODE;
scene_import_settings_data->hide_options = editing_animation;
@@ -853,6 +883,8 @@ void SceneImportSettingsDialog::_select(Tree *p_from, const String &p_type, cons
scene_import_settings_data->settings = &ad.settings;
scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_ANIMATION;
+
+ _animation_update_skeleton_visibility();
} else if (p_type == "Mesh") {
node_selected->hide();
if (Object::cast_to<Node3D>(scene)) {
@@ -1055,6 +1087,11 @@ void SceneImportSettingsDialog::_animation_slider_value_changed(double p_value)
animation_player->seek(p_value * animation_map[selected_id].animation->get_length(), true);
}
+void SceneImportSettingsDialog::_skeleton_tree_entered(Skeleton3D *p_skeleton) {
+ bones_mesh_preview->set_skeleton_path(p_skeleton->get_path());
+ bones_mesh_preview->set_skin(p_skeleton->register_skin(p_skeleton->create_skin_from_rest_transforms()));
+}
+
void SceneImportSettingsDialog::_animation_finished(const StringName &p_name) {
Animation::LoopMode loop_mode = animation_loop_mode;
@@ -1080,6 +1117,14 @@ void SceneImportSettingsDialog::_animation_finished(const StringName &p_name) {
}
}
+void SceneImportSettingsDialog::_animation_update_skeleton_visibility() {
+ if (animation_toggle_skeleton_visibility->is_pressed()) {
+ bones_mesh_preview->show();
+ } else {
+ bones_mesh_preview->hide();
+ }
+}
+
void SceneImportSettingsDialog::_material_tree_selected() {
if (selecting) {
return;
@@ -1282,6 +1327,8 @@ void SceneImportSettingsDialog::_notification(int p_what) {
light_1_switch->set_icon(theme_cache.light_1_icon);
light_2_switch->set_icon(theme_cache.light_2_icon);
light_rotate_switch->set_icon(theme_cache.rotate_icon);
+
+ animation_toggle_skeleton_visibility->set_icon(get_editor_theme_icon(SNAME("Skeleton3D")));
} break;
case NOTIFICATION_PROCESS: {
@@ -1661,6 +1708,7 @@ SceneImportSettingsDialog::SceneImportSettingsDialog() {
animation_hbox->add_child(animation_stop_button);
animation_stop_button->set_flat(true);
animation_stop_button->set_focus_mode(Control::FOCUS_NONE);
+ animation_stop_button->set_tooltip_text(TTR("Selected Animation Stop"));
animation_stop_button->connect(SceneStringName(pressed), callable_mp(this, &SceneImportSettingsDialog::_stop_current_animation));
animation_slider = memnew(HSlider);
@@ -1673,6 +1721,15 @@ SceneImportSettingsDialog::SceneImportSettingsDialog() {
animation_slider->set_focus_mode(Control::FOCUS_NONE);
animation_slider->connect(SceneStringName(value_changed), callable_mp(this, &SceneImportSettingsDialog::_animation_slider_value_changed));
+ animation_toggle_skeleton_visibility = memnew(Button);
+ animation_hbox->add_child(animation_toggle_skeleton_visibility);
+ animation_toggle_skeleton_visibility->set_toggle_mode(true);
+ animation_toggle_skeleton_visibility->set_flat(true);
+ animation_toggle_skeleton_visibility->set_focus_mode(Control::FOCUS_NONE);
+ animation_toggle_skeleton_visibility->set_tooltip_text(TTR("Toggle Animation Skeleton Visibility"));
+
+ animation_toggle_skeleton_visibility->connect(SceneStringName(pressed), callable_mp(this, &SceneImportSettingsDialog::_animation_update_skeleton_visibility));
+
base_viewport->set_use_own_world_3d(true);
HBoxContainer *viewport_hbox = memnew(HBoxContainer);
@@ -1800,6 +1857,13 @@ SceneImportSettingsDialog::SceneImportSettingsDialog() {
collider_mat->set_albedo(Color(0.5, 0.5, 1.0));
}
+ {
+ bones_mesh_preview = memnew(MeshInstance3D);
+ bones_mesh_preview->set_cast_shadows_setting(GeometryInstance3D::SHADOW_CASTING_SETTING_OFF);
+ bones_mesh_preview->set_skeleton_path(NodePath());
+ base_viewport->add_child(bones_mesh_preview);
+ }
+
inspector = memnew(EditorInspector);
inspector->set_custom_minimum_size(Size2(300 * EDSCALE, 0));
inspector->connect(SNAME("property_edited"), callable_mp(this, &SceneImportSettingsDialog::_inspector_property_edited));
diff --git a/editor/import/3d/scene_import_settings.h b/editor/import/3d/scene_import_settings.h
index bbd0d2c22d..1088acf772 100644
--- a/editor/import/3d/scene_import_settings.h
+++ b/editor/import/3d/scene_import_settings.h
@@ -109,10 +109,12 @@ class SceneImportSettingsDialog : public ConfirmationDialog {
HSlider *animation_slider = nullptr;
Button *animation_play_button = nullptr;
Button *animation_stop_button = nullptr;
+ Button *animation_toggle_skeleton_visibility = nullptr;
Animation::LoopMode animation_loop_mode = Animation::LOOP_NONE;
bool animation_pingpong = false;
bool previous_import_as_skeleton = false;
bool previous_rest_as_reset = false;
+ MeshInstance3D *bones_mesh_preview = nullptr;
Ref<StandardMaterial3D> collider_mat;
@@ -187,9 +189,11 @@ class SceneImportSettingsDialog : public ConfirmationDialog {
void _reset_animation(const String &p_animation_name = "");
void _animation_slider_value_changed(double p_value);
void _animation_finished(const StringName &p_name);
+ void _animation_update_skeleton_visibility();
void _material_tree_selected();
void _mesh_tree_selected();
void _scene_tree_selected();
+ void _skeleton_tree_entered(Skeleton3D *p_skeleton);
void _cleanup();
void _on_light_1_switch_pressed();
void _on_light_2_switch_pressed();
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 4b7bf1674f..d1032470f2 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -5384,7 +5384,7 @@ CanvasItemEditor::CanvasItemEditor() {
main_menu_hbox->add_child(pivot_button);
pivot_button->set_toggle_mode(true);
pivot_button->connect(SceneStringName(pressed), callable_mp(this, &CanvasItemEditor::_button_tool_select).bind(TOOL_EDIT_PIVOT));
- pivot_button->set_tooltip_text(TTR("Click to change object's rotation pivot.") + "\n" + TTR("Shift: Set temporary rotation pivot.") + "\n" + TTR("Click this button while holding Shift to put the rotation pivot in the center of the selected nodes."));
+ pivot_button->set_tooltip_text(TTR("Click to change object's rotation pivot.") + "\n" + TTR("Shift: Set temporary rotation pivot.") + "\n" + TTR("Click this button while holding Shift to put the temporary rotation pivot in the center of the selected nodes."));
pan_button = memnew(Button);
pan_button->set_theme_type_variation("FlatButton");
diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp
index 7ba464f4e5..890035e6a6 100644
--- a/editor/plugins/path_3d_editor_plugin.cpp
+++ b/editor/plugins/path_3d_editor_plugin.cpp
@@ -687,11 +687,11 @@ void Path3DEditorPlugin::make_visible(bool p_visible) {
}
void Path3DEditorPlugin::_mode_changed(int p_mode) {
- curve_create->set_pressed(p_mode == MODE_CREATE);
- curve_edit_curve->set_pressed(p_mode == MODE_EDIT_CURVE);
- curve_edit_tilt->set_pressed(p_mode == MODE_EDIT_TILT);
- curve_edit->set_pressed(p_mode == MODE_EDIT);
- curve_del->set_pressed(p_mode == MODE_DELETE);
+ curve_create->set_pressed_no_signal(p_mode == MODE_CREATE);
+ curve_edit_curve->set_pressed_no_signal(p_mode == MODE_EDIT_CURVE);
+ curve_edit_tilt->set_pressed_no_signal(p_mode == MODE_EDIT_TILT);
+ curve_edit->set_pressed_no_signal(p_mode == MODE_EDIT);
+ curve_del->set_pressed_no_signal(p_mode == MODE_DELETE);
Node3DEditor::get_singleton()->clear_subgizmo_selection();
}
@@ -790,17 +790,14 @@ void Path3DEditorPlugin::_restore_curve_points(const PackedVector3Array &p_point
}
void Path3DEditorPlugin::_update_theme() {
- // TODO: Split the EditorPlugin instance from the UI instance and connect this properly.
- // See the 2D path editor for inspiration.
- curve_edit->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("CurveEdit"), EditorStringName(EditorIcons)));
- curve_edit_curve->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("CurveCurve"), EditorStringName(EditorIcons)));
- curve_edit_tilt->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("CurveTilt"), EditorStringName(EditorIcons)));
- curve_create->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("CurveCreate"), EditorStringName(EditorIcons)));
- curve_del->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("CurveDelete"), EditorStringName(EditorIcons)));
- curve_close->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("CurveClose"), EditorStringName(EditorIcons)));
- curve_clear_points->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Clear"), EditorStringName(EditorIcons)));
-
- create_curve_button->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Curve3D"), EditorStringName(EditorIcons)));
+ curve_edit->set_icon(topmenu_bar->get_editor_theme_icon(SNAME("CurveEdit")));
+ curve_edit_curve->set_icon(topmenu_bar->get_editor_theme_icon(SNAME("CurveCurve")));
+ curve_edit_tilt->set_icon(topmenu_bar->get_editor_theme_icon(SNAME("CurveTilt")));
+ curve_create->set_icon(topmenu_bar->get_editor_theme_icon(SNAME("CurveCreate")));
+ curve_del->set_icon(topmenu_bar->get_editor_theme_icon(SNAME("CurveDelete")));
+ curve_close->set_icon(topmenu_bar->get_editor_theme_icon(SNAME("CurveClose")));
+ curve_clear_points->set_icon(topmenu_bar->get_editor_theme_icon(SNAME("Clear")));
+ create_curve_button->set_icon(topmenu_bar->get_editor_theme_icon(SNAME("Curve3D")));
}
void Path3DEditorPlugin::_update_toolbar() {
@@ -812,42 +809,14 @@ void Path3DEditorPlugin::_update_toolbar() {
create_curve_button->set_visible(!has_curve);
}
-void Path3DEditorPlugin::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
- curve_create->connect(SceneStringName(pressed), callable_mp(this, &Path3DEditorPlugin::_mode_changed).bind(MODE_CREATE));
- curve_edit_curve->connect(SceneStringName(pressed), callable_mp(this, &Path3DEditorPlugin::_mode_changed).bind(MODE_EDIT_CURVE));
- curve_edit_tilt->connect(SceneStringName(pressed), callable_mp(this, &Path3DEditorPlugin::_mode_changed).bind(MODE_EDIT_TILT));
- curve_edit->connect(SceneStringName(pressed), callable_mp(this, &Path3DEditorPlugin::_mode_changed).bind(MODE_EDIT));
- curve_del->connect(SceneStringName(pressed), callable_mp(this, &Path3DEditorPlugin::_mode_changed).bind(MODE_DELETE));
- curve_close->connect(SceneStringName(pressed), callable_mp(this, &Path3DEditorPlugin::_close_curve));
-
- _update_theme();
- } break;
-
- case NOTIFICATION_READY: {
- // FIXME: This can trigger theme updates when the nodes that we want to update are not yet available.
- // The toolbar should be extracted to a dedicated control and theme updates should be handled through
- // the notification.
- Node3DEditor::get_singleton()->connect(SceneStringName(theme_changed), callable_mp(this, &Path3DEditorPlugin::_update_theme));
- } break;
- }
-}
-
void Path3DEditorPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_toolbar"), &Path3DEditorPlugin::_update_toolbar);
ClassDB::bind_method(D_METHOD("_clear_curve_points"), &Path3DEditorPlugin::_clear_curve_points);
ClassDB::bind_method(D_METHOD("_restore_curve_points"), &Path3DEditorPlugin::_restore_curve_points);
}
-Path3DEditorPlugin *Path3DEditorPlugin::singleton = nullptr;
-
Path3DEditorPlugin::Path3DEditorPlugin() {
- path = nullptr;
singleton = this;
- mirror_handle_angle = true;
- mirror_handle_length = true;
-
disk_size = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_settings/path3d_tilt_disk_size", 0.8);
Ref<Path3DGizmoPlugin> gizmo_plugin = memnew(Path3DGizmoPlugin(disk_size));
@@ -856,7 +825,6 @@ Path3DEditorPlugin::Path3DEditorPlugin() {
topmenu_bar = memnew(HBoxContainer);
topmenu_bar->hide();
- Node3DEditor::get_singleton()->add_control_to_menu_panel(topmenu_bar);
toolbar = memnew(HBoxContainer);
topmenu_bar->add_child(toolbar);
@@ -867,6 +835,7 @@ Path3DEditorPlugin::Path3DEditorPlugin() {
curve_edit->set_focus_mode(Control::FOCUS_NONE);
curve_edit->set_tooltip_text(TTR("Select Points") + "\n" + TTR("Shift+Click: Select multiple Points") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL) + TTR("Click: Add Point") + "\n" + TTR("Right Click: Delete Point"));
toolbar->add_child(curve_edit);
+ curve_edit->connect(SceneStringName(pressed), callable_mp(this, &Path3DEditorPlugin::_mode_changed).bind(MODE_EDIT));
curve_edit_curve = memnew(Button);
curve_edit_curve->set_theme_type_variation("FlatButton");
@@ -874,6 +843,7 @@ Path3DEditorPlugin::Path3DEditorPlugin() {
curve_edit_curve->set_focus_mode(Control::FOCUS_NONE);
curve_edit_curve->set_tooltip_text(TTR("Select Control Points") + "\n" + TTR("Shift+Click: Drag out Control Points"));
toolbar->add_child(curve_edit_curve);
+ curve_edit_curve->connect(SceneStringName(pressed), callable_mp(this, &Path3DEditorPlugin::_mode_changed).bind(MODE_EDIT_CURVE));
curve_edit_tilt = memnew(Button);
curve_edit_tilt->set_theme_type_variation("FlatButton");
@@ -881,6 +851,7 @@ Path3DEditorPlugin::Path3DEditorPlugin() {
curve_edit_tilt->set_focus_mode(Control::FOCUS_NONE);
curve_edit_tilt->set_tooltip_text(TTR("Select Tilt Handles"));
toolbar->add_child(curve_edit_tilt);
+ curve_edit_tilt->connect(SceneStringName(pressed), callable_mp(this, &Path3DEditorPlugin::_mode_changed).bind(MODE_EDIT_TILT));
curve_create = memnew(Button);
curve_create->set_theme_type_variation("FlatButton");
@@ -888,6 +859,7 @@ Path3DEditorPlugin::Path3DEditorPlugin() {
curve_create->set_focus_mode(Control::FOCUS_NONE);
curve_create->set_tooltip_text(TTR("Add Point (in empty space)") + "\n" + TTR("Split Segment (in curve)"));
toolbar->add_child(curve_create);
+ curve_create->connect(SceneStringName(pressed), callable_mp(this, &Path3DEditorPlugin::_mode_changed).bind(MODE_CREATE));
curve_del = memnew(Button);
curve_del->set_theme_type_variation("FlatButton");
@@ -895,12 +867,14 @@ Path3DEditorPlugin::Path3DEditorPlugin() {
curve_del->set_focus_mode(Control::FOCUS_NONE);
curve_del->set_tooltip_text(TTR("Delete Point"));
toolbar->add_child(curve_del);
+ curve_del->connect(SceneStringName(pressed), callable_mp(this, &Path3DEditorPlugin::_mode_changed).bind(MODE_DELETE));
curve_close = memnew(Button);
curve_close->set_theme_type_variation("FlatButton");
curve_close->set_focus_mode(Control::FOCUS_NONE);
curve_close->set_tooltip_text(TTR("Close Curve"));
toolbar->add_child(curve_close);
+ curve_close->connect(SceneStringName(pressed), callable_mp(this, &Path3DEditorPlugin::_close_curve));
curve_clear_points = memnew(Button);
curve_clear_points->set_theme_type_variation("FlatButton");
@@ -927,18 +901,17 @@ Path3DEditorPlugin::Path3DEditorPlugin() {
topmenu_bar->add_child(create_curve_button);
create_curve_button->connect(SceneStringName(pressed), callable_mp(this, &Path3DEditorPlugin::_create_curve));
- PopupMenu *menu;
- menu = handle_menu->get_popup();
+ PopupMenu *menu = handle_menu->get_popup();
menu->add_check_item(TTR("Mirror Handle Angles"));
menu->set_item_checked(HANDLE_OPTION_ANGLE, mirror_handle_angle);
menu->add_check_item(TTR("Mirror Handle Lengths"));
menu->set_item_checked(HANDLE_OPTION_LENGTH, mirror_handle_length);
menu->connect(SceneStringName(id_pressed), callable_mp(this, &Path3DEditorPlugin::_handle_option_pressed));
- curve_edit->set_pressed(true);
-}
+ curve_edit->set_pressed_no_signal(true);
-Path3DEditorPlugin::~Path3DEditorPlugin() {
+ topmenu_bar->connect(SceneStringName(theme_changed), callable_mp(this, &Path3DEditorPlugin::_update_theme));
+ Node3DEditor::get_singleton()->add_control_to_menu_panel(topmenu_bar);
}
Ref<EditorNode3DGizmo> Path3DGizmoPlugin::create_gizmo(Node3D *p_spatial) {
diff --git a/editor/plugins/path_3d_editor_plugin.h b/editor/plugins/path_3d_editor_plugin.h
index 09a7a46803..60cb7f940f 100644
--- a/editor/plugins/path_3d_editor_plugin.h
+++ b/editor/plugins/path_3d_editor_plugin.h
@@ -162,13 +162,12 @@ class Path3DEditorPlugin : public EditorPlugin {
};
protected:
- void _notification(int p_what);
static void _bind_methods();
public:
Path3D *get_edited_path() { return path; }
- static Path3DEditorPlugin *singleton;
+ inline static Path3DEditorPlugin *singleton = nullptr;
virtual EditorPlugin::AfterGUIInput forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override;
virtual String get_name() const override { return "Path3D"; }
@@ -183,7 +182,6 @@ public:
void set_handle_clicked(bool clicked) { handle_clicked = clicked; }
Path3DEditorPlugin();
- ~Path3DEditorPlugin();
};
#endif // PATH_3D_EDITOR_PLUGIN_H
diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp
index dc4d4db3f8..9fc88b3a6a 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_3d_editor_plugin.cpp
@@ -1348,16 +1348,18 @@ int Skeleton3DEditor::get_selected_bone() const {
return selected_bone;
}
+Skeleton3DGizmoPlugin::SelectionMaterials Skeleton3DGizmoPlugin::selection_materials;
+
Skeleton3DGizmoPlugin::Skeleton3DGizmoPlugin() {
- unselected_mat = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
- unselected_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- unselected_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
- unselected_mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
- unselected_mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
- unselected_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
-
- selected_mat = Ref<ShaderMaterial>(memnew(ShaderMaterial));
- selected_sh = Ref<Shader>(memnew(Shader));
+ selection_materials.unselected_mat.instantiate();
+ selection_materials.unselected_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
+ selection_materials.unselected_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
+ selection_materials.unselected_mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ selection_materials.unselected_mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
+ selection_materials.unselected_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
+
+ selection_materials.selected_mat.instantiate();
+ Ref<Shader> selected_sh = Ref<Shader>(memnew(Shader));
selected_sh->set_code(R"(
// Skeleton 3D gizmo bones shader.
@@ -1376,7 +1378,7 @@ void fragment() {
ALPHA = COLOR.a;
}
)");
- selected_mat->set_shader(selected_sh);
+ selection_materials.selected_mat->set_shader(selected_sh);
// Register properties in editor settings.
EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/skeleton", Color(1, 0.8, 0.4));
@@ -1386,6 +1388,11 @@ void fragment() {
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "editors/3d_gizmos/gizmo_settings/bone_shape", PROPERTY_HINT_ENUM, "Wire,Octahedron"));
}
+Skeleton3DGizmoPlugin::~Skeleton3DGizmoPlugin() {
+ selection_materials.unselected_mat.unref();
+ selection_materials.selected_mat.unref();
+}
+
bool Skeleton3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
return Object::cast_to<Skeleton3D>(p_spatial) != nullptr;
}
@@ -1526,6 +1533,11 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
selected = se->get_selected_bone();
}
+ Ref<ArrayMesh> m = get_bones_mesh(skeleton, selected, p_gizmo->is_selected());
+ p_gizmo->add_mesh(m, Ref<Material>(), Transform3D(), skeleton->register_skin(skeleton->create_skin_from_rest_transforms()));
+}
+
+Ref<ArrayMesh> Skeleton3DGizmoPlugin::get_bones_mesh(Skeleton3D *p_skeleton, int p_selected, bool p_is_selected) {
Color bone_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/skeleton");
Color selected_bone_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/selected_bone");
real_t bone_axis_length = EDITOR_GET("editors/3d_gizmos/gizmo_settings/bone_axis_length");
@@ -1539,11 +1551,11 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Ref<SurfaceTool> surface_tool(memnew(SurfaceTool));
surface_tool->begin(Mesh::PRIMITIVE_LINES);
- if (p_gizmo->is_selected()) {
- surface_tool->set_material(selected_mat);
+ if (p_is_selected) {
+ surface_tool->set_material(selection_materials.selected_mat);
} else {
- unselected_mat->set_albedo(bone_color);
- surface_tool->set_material(unselected_mat);
+ selection_materials.unselected_mat->set_albedo(bone_color);
+ surface_tool->set_material(selection_materials.unselected_mat);
}
LocalVector<int> bones;
@@ -1557,16 +1569,16 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
weights[0] = 1;
int current_bone_index = 0;
- Vector<int> bones_to_process = skeleton->get_parentless_bones();
+ Vector<int> bones_to_process = p_skeleton->get_parentless_bones();
while (bones_to_process.size() > current_bone_index) {
int current_bone_idx = bones_to_process[current_bone_index];
current_bone_index++;
- Color current_bone_color = (current_bone_idx == selected) ? selected_bone_color : bone_color;
+ Color current_bone_color = (current_bone_idx == p_selected) ? selected_bone_color : bone_color;
Vector<int> child_bones_vector;
- child_bones_vector = skeleton->get_bone_children(current_bone_idx);
+ child_bones_vector = p_skeleton->get_bone_children(current_bone_idx);
int child_bones_size = child_bones_vector.size();
for (int i = 0; i < child_bones_size; i++) {
@@ -1577,8 +1589,8 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
int child_bone_idx = child_bones_vector[i];
- Vector3 v0 = skeleton->get_bone_global_rest(current_bone_idx).origin;
- Vector3 v1 = skeleton->get_bone_global_rest(child_bone_idx).origin;
+ Vector3 v0 = p_skeleton->get_bone_global_rest(current_bone_idx).origin;
+ Vector3 v1 = p_skeleton->get_bone_global_rest(child_bone_idx).origin;
Vector3 d = (v1 - v0).normalized();
real_t dist = v0.distance_to(v1);
@@ -1586,7 +1598,7 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
int closest = -1;
real_t closest_d = 0.0;
for (int j = 0; j < 3; j++) {
- real_t dp = Math::abs(skeleton->get_bone_global_rest(current_bone_idx).basis[j].normalized().dot(d));
+ real_t dp = Math::abs(p_skeleton->get_bone_global_rest(current_bone_idx).basis[j].normalized().dot(d));
if (j == 0 || dp > closest_d) {
closest = j;
}
@@ -1613,7 +1625,7 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
for (int j = 0; j < 3; j++) {
Vector3 axis;
if (first == Vector3()) {
- axis = d.cross(d.cross(skeleton->get_bone_global_rest(current_bone_idx).basis[j])).normalized();
+ axis = d.cross(d.cross(p_skeleton->get_bone_global_rest(current_bone_idx).basis[j])).normalized();
first = axis;
} else {
axis = d.cross(first).normalized();
@@ -1668,7 +1680,7 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
surface_tool->add_vertex(v0);
surface_tool->set_bones(bones);
surface_tool->set_weights(weights);
- surface_tool->add_vertex(v0 + (skeleton->get_bone_global_rest(current_bone_idx).basis.inverse())[j].normalized() * dist * bone_axis_length);
+ surface_tool->add_vertex(v0 + (p_skeleton->get_bone_global_rest(current_bone_idx).basis.inverse())[j].normalized() * dist * bone_axis_length);
if (j == closest) {
continue;
@@ -1685,7 +1697,7 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
surface_tool->add_vertex(v1);
surface_tool->set_bones(bones);
surface_tool->set_weights(weights);
- surface_tool->add_vertex(v1 + (skeleton->get_bone_global_rest(child_bone_idx).basis.inverse())[j].normalized() * dist * bone_axis_length);
+ surface_tool->add_vertex(v1 + (p_skeleton->get_bone_global_rest(child_bone_idx).basis.inverse())[j].normalized() * dist * bone_axis_length);
if (j == closest) {
continue;
@@ -1698,6 +1710,5 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
}
}
- Ref<ArrayMesh> m = surface_tool->commit();
- p_gizmo->add_mesh(m, Ref<Material>(), Transform3D(), skeleton->register_skin(skeleton->create_skin_from_rest_transforms()));
+ return surface_tool->commit();
}
diff --git a/editor/plugins/skeleton_3d_editor_plugin.h b/editor/plugins/skeleton_3d_editor_plugin.h
index 0bb58aac23..d4dee1f16f 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.h
+++ b/editor/plugins/skeleton_3d_editor_plugin.h
@@ -260,11 +260,15 @@ public:
class Skeleton3DGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(Skeleton3DGizmoPlugin, EditorNode3DGizmoPlugin);
- Ref<StandardMaterial3D> unselected_mat;
- Ref<ShaderMaterial> selected_mat;
- Ref<Shader> selected_sh;
+ struct SelectionMaterials {
+ Ref<StandardMaterial3D> unselected_mat;
+ Ref<ShaderMaterial> selected_mat;
+ };
+ static SelectionMaterials selection_materials;
public:
+ static Ref<ArrayMesh> get_bones_mesh(Skeleton3D *p_skeleton, int p_selected, bool p_is_selected);
+
bool has_gizmo(Node3D *p_spatial) override;
String get_gizmo_name() const override;
int get_priority() const override;
@@ -277,6 +281,7 @@ public:
void redraw(EditorNode3DGizmo *p_gizmo) override;
Skeleton3DGizmoPlugin();
+ ~Skeleton3DGizmoPlugin();
};
#endif // SKELETON_3D_EDITOR_PLUGIN_H
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index add52ce566..2a39b11815 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -1241,6 +1241,10 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
break;
}
+ if (!_validate_no_foreign()) {
+ break;
+ }
+
List<Node *> selection = editor_selection->get_selected_node_list();
List<Node *>::Element *e = selection.front();
if (e) {
diff --git a/editor/themes/editor_theme_manager.cpp b/editor/themes/editor_theme_manager.cpp
index 119508f59b..3041857d83 100644
--- a/editor/themes/editor_theme_manager.cpp
+++ b/editor/themes/editor_theme_manager.cpp
@@ -865,7 +865,6 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the
// CheckBox.
{
Ref<StyleBoxFlat> checkbox_style = p_config.panel_container_style->duplicate();
- checkbox_style->set_content_margin_individual((p_config.increased_margin + 2) * EDSCALE, p_config.base_margin * EDSCALE, (p_config.increased_margin + 2) * EDSCALE, p_config.base_margin * EDSCALE);
p_theme->set_stylebox(CoreStringName(normal), "CheckBox", checkbox_style);
p_theme->set_stylebox(SceneStringName(pressed), "CheckBox", checkbox_style);
@@ -1165,9 +1164,6 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the
// LineEdit & TextEdit.
{
Ref<StyleBoxFlat> text_editor_style = p_config.button_style->duplicate();
- // The original button_style style has an extra 1 pixel offset that makes LineEdits not align with Buttons,
- // so this compensates for that.
- text_editor_style->set_content_margin(SIDE_TOP, text_editor_style->get_content_margin(SIDE_TOP) - 1 * EDSCALE);
// Don't round the bottom corners to make the line look sharper.
text_editor_style->set_corner_radius(CORNER_BOTTOM_LEFT, 0);
diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp
index 770871ae19..c99e9cdd0c 100644
--- a/platform/macos/export/export_plugin.cpp
+++ b/platform/macos/export/export_plugin.cpp
@@ -357,17 +357,13 @@ List<String> EditorExportPlatformMacOS::get_binary_extensions(const Ref<EditorEx
list.push_back("dmg");
#endif
list.push_back("zip");
-#ifndef WINDOWS_ENABLED
list.push_back("app");
-#endif
} else if (dist_type == 1) {
#ifdef MACOS_ENABLED
list.push_back("dmg");
#endif
list.push_back("zip");
-#ifndef WINDOWS_ENABLED
list.push_back("app");
-#endif
} else if (dist_type == 2) {
#ifdef MACOS_ENABLED
list.push_back("pkg");
@@ -1903,6 +1899,11 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
if (is_executable(file)) {
// chmod with 0755 if the file is executable.
FileAccess::set_unix_permissions(file, 0755);
+#ifndef UNIX_ENABLED
+ if (export_format == "app") {
+ add_message(EXPORT_MESSAGE_INFO, TTR("Export"), vformat(TTR("Unable to set Unix permissions for executable \"%s\". Use \"chmod +x\" to set it after transferring the exported .app to macOS or Linux."), "Contents/MacOS/" + file.get_file()));
+ }
+#endif
}
} else {
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not open \"%s\"."), file));
@@ -1928,6 +1929,11 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
if ((con_scr == 1 && p_debug) || (con_scr == 2)) {
err = _export_debug_script(p_preset, pkg_name, tmp_app_path_name.get_file() + "/Contents/MacOS/" + pkg_name, scr_path);
FileAccess::set_unix_permissions(scr_path, 0755);
+#ifndef UNIX_ENABLED
+ if (export_format == "app") {
+ add_message(EXPORT_MESSAGE_INFO, TTR("Export"), vformat(TTR("Unable to set Unix permissions for executable \"%s\". Use \"chmod +x\" to set it after transferring the exported .app to macOS or Linux."), scr_path.get_file()));
+ }
+#endif
if (err != OK) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Could not create console wrapper."));
}
@@ -2156,6 +2162,11 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
_code_sign(p_preset, tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file(), hlp_ent_path, false, true);
}
FileAccess::set_unix_permissions(tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file(), 0755);
+#ifndef UNIX_ENABLED
+ if (export_format == "app") {
+ add_message(EXPORT_MESSAGE_INFO, TTR("Export"), vformat(TTR("Unable to set Unix permissions for executable \"%s\". Use \"chmod +x\" to set it after transferring the exported .app to macOS or Linux."), "Contents/Helpers/" + hlp_path.get_file()));
+ }
+#endif
}
}
diff --git a/scene/2d/canvas_modulate.cpp b/scene/2d/canvas_modulate.cpp
index 2c5c6a1a16..dc83775c71 100644
--- a/scene/2d/canvas_modulate.cpp
+++ b/scene/2d/canvas_modulate.cpp
@@ -114,7 +114,7 @@ Color CanvasModulate::get_color() const {
}
PackedStringArray CanvasModulate::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Node2D::get_configuration_warnings();
if (is_in_canvas && is_visible_in_tree()) {
List<Node *> nodes;
diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp
index 5ce26b3ed4..50c5873781 100644
--- a/scene/2d/light_2d.cpp
+++ b/scene/2d/light_2d.cpp
@@ -417,7 +417,7 @@ Vector2 PointLight2D::get_texture_offset() const {
}
PackedStringArray PointLight2D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Node2D::get_configuration_warnings();
if (!texture.is_valid()) {
warnings.push_back(RTR("A texture with the shape of the light must be supplied to the \"Texture\" property."));
diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp
index 092c987ac0..7c3fb61d04 100644
--- a/scene/2d/light_occluder_2d.cpp
+++ b/scene/2d/light_occluder_2d.cpp
@@ -263,7 +263,7 @@ int LightOccluder2D::get_occluder_light_mask() const {
}
PackedStringArray LightOccluder2D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Node2D::get_configuration_warnings();
if (!occluder_polygon.is_valid()) {
warnings.push_back(RTR("An occluder polygon must be set (or drawn) for this occluder to take effect."));
diff --git a/scene/2d/navigation_link_2d.cpp b/scene/2d/navigation_link_2d.cpp
index 111f5a7b78..4961e18dc9 100644
--- a/scene/2d/navigation_link_2d.cpp
+++ b/scene/2d/navigation_link_2d.cpp
@@ -328,7 +328,7 @@ void NavigationLink2D::set_travel_cost(real_t p_travel_cost) {
}
PackedStringArray NavigationLink2D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Node2D::get_configuration_warnings();
if (start_position.is_equal_approx(end_position)) {
warnings.push_back(RTR("NavigationLink2D start position should be different than the end position to be useful."));
diff --git a/scene/2d/parallax_layer.cpp b/scene/2d/parallax_layer.cpp
index 023e9201fc..24f261deb6 100644
--- a/scene/2d/parallax_layer.cpp
+++ b/scene/2d/parallax_layer.cpp
@@ -133,7 +133,7 @@ void ParallaxLayer::set_base_offset_and_scale(const Point2 &p_offset, real_t p_s
}
PackedStringArray ParallaxLayer::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Node2D::get_configuration_warnings();
if (!Object::cast_to<ParallaxBackground>(get_parent())) {
warnings.push_back(RTR("ParallaxLayer node only works when set as child of a ParallaxBackground node."));
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index c3768386e9..5813ab02e3 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -288,7 +288,7 @@ void PathFollow2D::_validate_property(PropertyInfo &p_property) const {
}
PackedStringArray PathFollow2D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Node2D::get_configuration_warnings();
if (is_visible_in_tree() && is_inside_tree()) {
if (!Object::cast_to<Path2D>(get_parent())) {
diff --git a/scene/2d/physics/collision_object_2d.cpp b/scene/2d/physics/collision_object_2d.cpp
index 00b6085f0c..27ee6b883c 100644
--- a/scene/2d/physics/collision_object_2d.cpp
+++ b/scene/2d/physics/collision_object_2d.cpp
@@ -582,7 +582,7 @@ void CollisionObject2D::_update_pickable() {
}
PackedStringArray CollisionObject2D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Node2D::get_configuration_warnings();
if (shapes.is_empty()) {
warnings.push_back(RTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape2D or CollisionPolygon2D as a child to define its shape."));
diff --git a/scene/2d/physics/collision_polygon_2d.cpp b/scene/2d/physics/collision_polygon_2d.cpp
index a9b47ef4d4..b49badac1f 100644
--- a/scene/2d/physics/collision_polygon_2d.cpp
+++ b/scene/2d/physics/collision_polygon_2d.cpp
@@ -232,7 +232,7 @@ bool CollisionPolygon2D::_edit_is_selected_on_click(const Point2 &p_point, doubl
#endif
PackedStringArray CollisionPolygon2D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Node2D::get_configuration_warnings();
if (!Object::cast_to<CollisionObject2D>(get_parent())) {
warnings.push_back(RTR("CollisionPolygon2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, CharacterBody2D, etc. to give them a shape."));
diff --git a/scene/2d/physics/collision_shape_2d.cpp b/scene/2d/physics/collision_shape_2d.cpp
index 6fc29ffe63..bdd0d06b5e 100644
--- a/scene/2d/physics/collision_shape_2d.cpp
+++ b/scene/2d/physics/collision_shape_2d.cpp
@@ -174,7 +174,7 @@ bool CollisionShape2D::_edit_is_selected_on_click(const Point2 &p_point, double
}
PackedStringArray CollisionShape2D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Node2D::get_configuration_warnings();
CollisionObject2D *col_object = Object::cast_to<CollisionObject2D>(get_parent());
if (col_object == nullptr) {
diff --git a/scene/2d/physics/physical_bone_2d.cpp b/scene/2d/physics/physical_bone_2d.cpp
index 77bb8c24b8..19274c8084 100644
--- a/scene/2d/physics/physical_bone_2d.cpp
+++ b/scene/2d/physics/physical_bone_2d.cpp
@@ -107,7 +107,7 @@ void PhysicalBone2D::_find_joint_child() {
}
PackedStringArray PhysicalBone2D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = RigidBody2D::get_configuration_warnings();
if (!parent_skeleton) {
warnings.push_back(RTR("A PhysicalBone2D only works with a Skeleton2D or another PhysicalBone2D as a parent node!"));
diff --git a/scene/2d/remote_transform_2d.cpp b/scene/2d/remote_transform_2d.cpp
index 920f5720fa..1816a3409b 100644
--- a/scene/2d/remote_transform_2d.cpp
+++ b/scene/2d/remote_transform_2d.cpp
@@ -211,7 +211,7 @@ void RemoteTransform2D::force_update_cache() {
}
PackedStringArray RemoteTransform2D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Node2D::get_configuration_warnings();
if (!has_node(remote_node) || !Object::cast_to<Node2D>(get_node(remote_node))) {
warnings.push_back(RTR("Path property must point to a valid Node2D node to work."));
diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp
index f9e8c831d1..90bfb4c84c 100644
--- a/scene/2d/skeleton_2d.cpp
+++ b/scene/2d/skeleton_2d.cpp
@@ -412,7 +412,7 @@ int Bone2D::get_index_in_skeleton() const {
}
PackedStringArray Bone2D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Node2D::get_configuration_warnings();
if (!skeleton) {
if (parent_bone) {
warnings.push_back(RTR("This Bone2D chain should end at a Skeleton2D node."));
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index b10f2097da..45cfb8cf33 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -827,7 +827,7 @@ TypedArray<Vector2i> TileMap::get_surrounding_cells(const Vector2i &p_coords) {
}
PackedStringArray TileMap::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Node2D::get_configuration_warnings();
warnings.push_back(RTR("The TileMap node is deprecated as it is superseded by the use of multiple TileMapLayer nodes.\nTo convert a TileMap to a set of TileMapLayer nodes, open the TileMap bottom panel with this node selected, click the toolbox icon in the top-right corner and choose \"Extract TileMap layers as individual TileMapLayer nodes\"."));
diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp
index 485599d0fb..8702b1d3da 100644
--- a/scene/3d/decal.cpp
+++ b/scene/3d/decal.cpp
@@ -163,7 +163,7 @@ void Decal::_validate_property(PropertyInfo &p_property) const {
}
PackedStringArray Decal::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = VisualInstance3D::get_configuration_warnings();
if (OS::get_singleton()->get_current_rendering_method() == "gl_compatibility") {
warnings.push_back(RTR("Decals are only available when using the Forward+ or Mobile rendering backends."));
diff --git a/scene/3d/fog_volume.cpp b/scene/3d/fog_volume.cpp
index 54631a8dff..195074ba2f 100644
--- a/scene/3d/fog_volume.cpp
+++ b/scene/3d/fog_volume.cpp
@@ -116,7 +116,7 @@ AABB FogVolume::get_aabb() const {
}
PackedStringArray FogVolume::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = VisualInstance3D::get_configuration_warnings();
Ref<Environment> environment = get_viewport()->find_world_3d()->get_environment();
diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp
index 3a05ec9c9e..9791f23bc3 100644
--- a/scene/3d/gpu_particles_collision_3d.cpp
+++ b/scene/3d/gpu_particles_collision_3d.cpp
@@ -524,7 +524,7 @@ Ref<Image> GPUParticlesCollisionSDF3D::bake() {
}
PackedStringArray GPUParticlesCollisionSDF3D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = GPUParticlesCollision3D::get_configuration_warnings();
if (bake_mask == 0) {
warnings.push_back(RTR("The Bake Mask has no bits enabled, which means baking will not produce any collision for this GPUParticlesCollisionSDF3D.\nTo resolve this, enable at least one bit in the Bake Mask property."));
diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp
index 4048a8bd62..26a574cd26 100644
--- a/scene/3d/lightmap_gi.cpp
+++ b/scene/3d/lightmap_gi.cpp
@@ -1600,7 +1600,7 @@ Ref<CameraAttributes> LightmapGI::get_camera_attributes() const {
}
PackedStringArray LightmapGI::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = VisualInstance3D::get_configuration_warnings();
if (OS::get_singleton()->get_current_rendering_method() == "gl_compatibility") {
warnings.push_back(RTR("Lightmap can only be baked from a device that supports the RD backends. Lightmap baking may fail."));
diff --git a/scene/3d/navigation_link_3d.cpp b/scene/3d/navigation_link_3d.cpp
index bebba9a6c0..0cce21b9d0 100644
--- a/scene/3d/navigation_link_3d.cpp
+++ b/scene/3d/navigation_link_3d.cpp
@@ -453,7 +453,7 @@ void NavigationLink3D::set_travel_cost(real_t p_travel_cost) {
}
PackedStringArray NavigationLink3D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Node3D::get_configuration_warnings();
if (start_position.is_equal_approx(end_position)) {
warnings.push_back(RTR("NavigationLink3D start position should be different than the end position to be useful."));
diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp
index d7397a932d..c0c254e7ed 100644
--- a/scene/3d/navigation_region_3d.cpp
+++ b/scene/3d/navigation_region_3d.cpp
@@ -271,7 +271,7 @@ bool NavigationRegion3D::is_baking() const {
}
PackedStringArray NavigationRegion3D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Node3D::get_configuration_warnings();
if (is_visible_in_tree() && is_inside_tree()) {
if (!navigation_mesh.is_valid()) {
diff --git a/scene/3d/occluder_instance_3d.cpp b/scene/3d/occluder_instance_3d.cpp
index 6982df12f6..6d88323c76 100644
--- a/scene/3d/occluder_instance_3d.cpp
+++ b/scene/3d/occluder_instance_3d.cpp
@@ -691,7 +691,7 @@ OccluderInstance3D::BakeError OccluderInstance3D::bake_scene(Node *p_from_node,
}
PackedStringArray OccluderInstance3D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = VisualInstance3D::get_configuration_warnings();
if (!bool(GLOBAL_GET("rendering/occlusion_culling/use_occlusion_culling"))) {
warnings.push_back(RTR("Occlusion culling is disabled in the Project Settings, which means occlusion culling won't be performed in the root viewport.\nTo resolve this, open the Project Settings and enable Rendering > Occlusion Culling > Use Occlusion Culling."));
diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp
index dc030b6a0f..20d646fe1e 100644
--- a/scene/3d/path_3d.cpp
+++ b/scene/3d/path_3d.cpp
@@ -318,7 +318,7 @@ void PathFollow3D::_validate_property(PropertyInfo &p_property) const {
}
PackedStringArray PathFollow3D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Node3D::get_configuration_warnings();
if (is_visible_in_tree() && is_inside_tree()) {
if (!Object::cast_to<Path3D>(get_parent())) {
diff --git a/scene/3d/physics/collision_object_3d.cpp b/scene/3d/physics/collision_object_3d.cpp
index f11aa7012a..f0a5013ca2 100644
--- a/scene/3d/physics/collision_object_3d.cpp
+++ b/scene/3d/physics/collision_object_3d.cpp
@@ -731,7 +731,7 @@ bool CollisionObject3D::get_capture_input_on_drag() const {
}
PackedStringArray CollisionObject3D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Node3D::get_configuration_warnings();
if (shapes.is_empty()) {
warnings.push_back(RTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape3D or CollisionPolygon3D as a child to define its shape."));
diff --git a/scene/3d/physics/collision_polygon_3d.cpp b/scene/3d/physics/collision_polygon_3d.cpp
index 76cd4db779..bf8dec7b54 100644
--- a/scene/3d/physics/collision_polygon_3d.cpp
+++ b/scene/3d/physics/collision_polygon_3d.cpp
@@ -169,7 +169,7 @@ void CollisionPolygon3D::set_margin(real_t p_margin) {
}
PackedStringArray CollisionPolygon3D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Node3D::get_configuration_warnings();
if (!Object::cast_to<CollisionObject3D>(get_parent())) {
warnings.push_back(RTR("CollisionPolygon3D only serves to provide a collision shape to a CollisionObject3D derived node.\nPlease only use it as a child of Area3D, StaticBody3D, RigidBody3D, CharacterBody3D, etc. to give them a shape."));
diff --git a/scene/3d/physics/collision_shape_3d.cpp b/scene/3d/physics/collision_shape_3d.cpp
index f3492a3cf3..304fa74b06 100644
--- a/scene/3d/physics/collision_shape_3d.cpp
+++ b/scene/3d/physics/collision_shape_3d.cpp
@@ -120,7 +120,7 @@ void CollisionShape3D::resource_changed(Ref<Resource> res) {
#endif
PackedStringArray CollisionShape3D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Node3D::get_configuration_warnings();
CollisionObject3D *col_object = Object::cast_to<CollisionObject3D>(get_parent());
if (col_object == nullptr) {
diff --git a/scene/3d/physics/vehicle_body_3d.cpp b/scene/3d/physics/vehicle_body_3d.cpp
index b4c321cf5f..5073705145 100644
--- a/scene/3d/physics/vehicle_body_3d.cpp
+++ b/scene/3d/physics/vehicle_body_3d.cpp
@@ -106,7 +106,7 @@ void VehicleWheel3D::_notification(int p_what) {
}
PackedStringArray VehicleWheel3D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Node3D::get_configuration_warnings();
if (!Object::cast_to<VehicleBody3D>(get_parent())) {
warnings.push_back(RTR("VehicleWheel3D serves to provide a wheel system to a VehicleBody3D. Please use it as a child of a VehicleBody3D."));
diff --git a/scene/3d/remote_transform_3d.cpp b/scene/3d/remote_transform_3d.cpp
index e580882c46..f970879aa4 100644
--- a/scene/3d/remote_transform_3d.cpp
+++ b/scene/3d/remote_transform_3d.cpp
@@ -211,7 +211,7 @@ void RemoteTransform3D::force_update_cache() {
}
PackedStringArray RemoteTransform3D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Node3D::get_configuration_warnings();
if (!has_node(remote_node) || !Object::cast_to<Node3D>(get_node(remote_node))) {
warnings.push_back(RTR("The \"Remote Path\" property must point to a valid Node3D or Node3D-derived node to work."));
diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp
index 4fe5dd2385..7f67bde0cf 100644
--- a/scene/3d/soft_body_3d.cpp
+++ b/scene/3d/soft_body_3d.cpp
@@ -383,7 +383,7 @@ void SoftBody3D::_bind_methods() {
}
PackedStringArray SoftBody3D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = MeshInstance3D::get_configuration_warnings();
if (mesh.is_null()) {
warnings.push_back(RTR("This body will be ignored until you set a mesh."));
diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp
index 79a01450dd..a59754c8cc 100644
--- a/scene/3d/visual_instance_3d.cpp
+++ b/scene/3d/visual_instance_3d.cpp
@@ -497,7 +497,7 @@ bool GeometryInstance3D::is_ignoring_occlusion_culling() {
}
PackedStringArray GeometryInstance3D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = VisualInstance3D::get_configuration_warnings();
if (!Math::is_zero_approx(visibility_range_end) && visibility_range_end <= visibility_range_begin) {
warnings.push_back(RTR("The GeometryInstance3D visibility range's End distance is set to a non-zero value, but is lower than the Begin distance.\nThis means the GeometryInstance3D will never be visible.\nTo resolve this, set the End distance to 0 or to a value greater than the Begin distance."));
diff --git a/scene/3d/voxel_gi.cpp b/scene/3d/voxel_gi.cpp
index ffca856fba..80ff176a98 100644
--- a/scene/3d/voxel_gi.cpp
+++ b/scene/3d/voxel_gi.cpp
@@ -518,7 +518,7 @@ AABB VoxelGI::get_aabb() const {
}
PackedStringArray VoxelGI::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = VisualInstance3D::get_configuration_warnings();
if (OS::get_singleton()->get_current_rendering_method() == "gl_compatibility") {
warnings.push_back(RTR("VoxelGI nodes are not supported when using the GL Compatibility backend yet. Support will be added in a future release."));
diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp
index b71f9bc0c4..214c1f77ca 100644
--- a/scene/3d/xr_nodes.cpp
+++ b/scene/3d/xr_nodes.cpp
@@ -77,7 +77,7 @@ void XRCamera3D::_pose_changed(const Ref<XRPose> &p_pose) {
}
PackedStringArray XRCamera3D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Camera3D::get_configuration_warnings();
if (is_visible() && is_inside_tree()) {
// Warn if the node has a parent which isn't an XROrigin3D!
@@ -461,7 +461,7 @@ XRNode3D::~XRNode3D() {
}
PackedStringArray XRNode3D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Node3D::get_configuration_warnings();
if (is_visible() && is_inside_tree()) {
// Warn if the node has a parent which isn't an XROrigin3D!
@@ -644,7 +644,7 @@ Plane XRAnchor3D::get_plane() const {
Vector<XROrigin3D *> XROrigin3D::origin_nodes;
PackedStringArray XROrigin3D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Node3D::get_configuration_warnings();
if (is_visible() && is_inside_tree()) {
bool has_camera = false;
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index 867bbda4b3..19080e61de 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -681,7 +681,7 @@ uint64_t AnimationTree::get_last_process_pass() const {
}
PackedStringArray AnimationTree::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = AnimationMixer::get_configuration_warnings();
if (!root_animation_node.is_valid()) {
warnings.push_back(RTR("No root AnimationNode for the graph is set."));
}
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 15ada0021a..e030828595 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -248,7 +248,7 @@ void Control::get_argument_options(const StringName &p_function, int p_idx, List
PackedStringArray Control::get_configuration_warnings() const {
ERR_READ_THREAD_GUARD_V(PackedStringArray());
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = CanvasItem::get_configuration_warnings();
if (data.mouse_filter == MOUSE_FILTER_IGNORE && !data.tooltip.is_empty()) {
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\"."));
@@ -2356,6 +2356,24 @@ void Control::_window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, cons
points[2] = xform.xform(c->get_size());
points[3] = xform.xform(Point2(0, c->get_size().y));
+ // Tie-breaking aims to address situations where a potential focus neighbor's bounding rect
+ // is right next to the currently focused control (e.g. in BoxContainer with
+ // separation overridden to 0). This needs specific handling so that the correct
+ // focus neighbor is selected.
+
+ // Calculate centers of the potential neighbor, currently focused, and closest controls.
+ Point2 center = xform.xform(0.5 * c->get_size());
+ // We only have the points, not an actual reference.
+ Point2 p_center = 0.25 * (p_points[0] + p_points[1] + p_points[2] + p_points[3]);
+ Point2 closest_center;
+ bool should_tiebreak = false;
+ if (*r_closest != nullptr) {
+ should_tiebreak = true;
+ Control *closest = *r_closest;
+ Transform2D closest_xform = closest->get_global_transform();
+ closest_center = closest_xform.xform(0.5 * closest->get_size());
+ }
+
real_t min = 1e7;
for (int i = 0; i < 4; i++) {
@@ -2376,10 +2394,15 @@ void Control::_window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, cons
Vector2 pa, pb;
real_t d = Geometry2D::get_closest_points_between_segments(la, lb, fa, fb, pa, pb);
- //real_t d = Geometry2D::get_closest_distance_between_segments(Vector3(la.x,la.y,0),Vector3(lb.x,lb.y,0),Vector3(fa.x,fa.y,0),Vector3(fb.x,fb.y,0));
if (d < r_closest_dist) {
r_closest_dist = d;
*r_closest = c;
+ } else if (should_tiebreak && d == r_closest_dist) {
+ // Tie-break in favor of the control most aligned with p_dir.
+ if (p_dir.dot((center - p_center).normalized()) > p_dir.dot((closest_center - p_center).normalized())) {
+ r_closest_dist = d;
+ *r_closest = c;
+ }
}
}
}
diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp
index 83359653f1..d7b1a4933d 100644
--- a/scene/gui/range.cpp
+++ b/scene/gui/range.cpp
@@ -31,7 +31,7 @@
#include "range.h"
PackedStringArray Range::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Control::get_configuration_warnings();
if (shared->exp_ratio && shared->min <= 0) {
warnings.push_back(RTR("If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0."));
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 715b682342..552458245c 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -3412,6 +3412,21 @@ bool RichTextLabel::remove_paragraph(int p_paragraph, bool p_no_invalidate) {
selection.click_item = nullptr;
selection.active = false;
+ if (is_processing_internal()) {
+ bool process_enabled = false;
+ Item *it = main;
+ while (it) {
+ Vector<ItemFX *> fx_stack;
+ _fetch_item_fx_stack(it, fx_stack);
+ if (fx_stack.size()) {
+ process_enabled = true;
+ break;
+ }
+ it = _get_next_item(it, true);
+ }
+ set_process_internal(process_enabled);
+ }
+
if (p_no_invalidate) {
// Do not invalidate cache, only update vertical offsets of the paragraphs after deleted one and scrollbar.
int to_line = main->first_invalid_line.load() - 1;
@@ -3985,6 +4000,7 @@ void RichTextLabel::pop_all() {
void RichTextLabel::clear() {
_stop_thread();
+ set_process_internal(false);
MutexLock data_lock(data_mutex);
main->_clear_children();
@@ -4177,8 +4193,6 @@ void RichTextLabel::append_text(const String &p_bbcode) {
bool after_list_open_tag = false;
bool after_list_close_tag = false;
- set_process_internal(false);
-
while (pos <= p_bbcode.length()) {
int brk_pos = p_bbcode.find_char('[', pos);
@@ -5253,17 +5267,6 @@ void RichTextLabel::append_text(const String &p_bbcode) {
}
}
}
-
- Vector<ItemFX *> fx_items;
- for (Item *E : main->subitems) {
- Item *subitem = static_cast<Item *>(E);
- _fetch_item_fx_stack(subitem, fx_items);
-
- if (fx_items.size()) {
- set_process_internal(true);
- break;
- }
- }
}
void RichTextLabel::scroll_to_selection() {
diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp
index c715aceb0b..a443ae9abf 100644
--- a/scene/gui/subviewport_container.cpp
+++ b/scene/gui/subviewport_container.cpp
@@ -259,7 +259,7 @@ void SubViewportContainer::remove_child_notify(Node *p_child) {
}
PackedStringArray SubViewportContainer::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Container::get_configuration_warnings();
bool has_viewport = false;
for (int i = 0; i < get_child_count(); i++) {
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index edd25d1d5c..8871af23cb 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -3466,29 +3466,37 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
accept_event();
}
- if (!selected_item || select_mode == SELECT_ROW || selected_col > (columns.size() - 1)) {
+ if (!selected_item || selected_col > (columns.size() - 1)) {
return;
}
+
if (k.is_valid() && k->is_shift_pressed()) {
selected_item->set_collapsed_recursive(false);
- } else {
+ } else if (select_mode != SELECT_ROW) {
_go_right();
+ } else if (selected_item->get_first_child() != nullptr && selected_item->is_collapsed()) {
+ selected_item->set_collapsed(false);
+ } else {
+ _go_down();
}
} else if (p_event->is_action("ui_left") && p_event->is_pressed()) {
if (!cursor_can_exit_tree) {
accept_event();
}
- if (!selected_item || select_mode == SELECT_ROW || selected_col < 0) {
+ if (!selected_item || selected_col < 0) {
return;
}
if (k.is_valid() && k->is_shift_pressed()) {
selected_item->set_collapsed_recursive(true);
- } else {
+ } else if (select_mode != SELECT_ROW) {
_go_left();
+ } else if (selected_item->get_first_child() != nullptr && !selected_item->is_collapsed()) {
+ selected_item->set_collapsed(true);
+ } else {
+ _go_up();
}
-
} else if (p_event->is_action("ui_up") && p_event->is_pressed() && !is_command) {
if (!cursor_can_exit_tree) {
accept_event();
diff --git a/scene/resources/audio_stream_wav.cpp b/scene/resources/audio_stream_wav.cpp
index 08ebacc2b3..d0e0f0eef3 100644
--- a/scene/resources/audio_stream_wav.cpp
+++ b/scene/resources/audio_stream_wav.cpp
@@ -123,10 +123,8 @@ void AudioStreamPlaybackWAV::do_resample(const Depth *p_src, AudioFrame *p_dst,
int16_t nibble, diff, step;
p_ima_adpcm[i].last_nibble++;
- const uint8_t *src_ptr = (const uint8_t *)base->data;
- src_ptr += AudioStreamWAV::DATA_PAD;
- uint8_t nbb = src_ptr[(p_ima_adpcm[i].last_nibble >> 1) * (is_stereo ? 2 : 1) + i];
+ uint8_t nbb = p_src[(p_ima_adpcm[i].last_nibble >> 1) * (is_stereo ? 2 : 1) + i];
nibble = (p_ima_adpcm[i].last_nibble & 1) ? (nbb >> 4) : (nbb & 0xF);
step = _ima_adpcm_step_table[p_ima_adpcm[i].step_index];
@@ -184,9 +182,8 @@ void AudioStreamPlaybackWAV::do_resample(const Depth *p_src, AudioFrame *p_dst,
if (p_qoa->data_ofs != new_data_ofs) {
p_qoa->data_ofs = new_data_ofs;
- const uint8_t *src_ptr = (const uint8_t *)base->data;
- src_ptr += p_qoa->data_ofs + AudioStreamWAV::DATA_PAD;
- qoa_decode_frame(src_ptr, p_qoa->frame_len, &p_qoa->desc, p_qoa->dec, &p_qoa->dec_len);
+ const uint8_t *ofs_src = (uint8_t *)p_src + p_qoa->data_ofs;
+ qoa_decode_frame(ofs_src, p_qoa->frame_len, &p_qoa->desc, p_qoa->dec.ptr(), &p_qoa->dec_len);
}
uint32_t dec_idx = (interp_pos % QOA_FRAME_LEN) * p_qoa->desc.channels;
@@ -267,7 +264,7 @@ void AudioStreamPlaybackWAV::do_resample(const Depth *p_src, AudioFrame *p_dst,
}
int AudioStreamPlaybackWAV::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) {
- if (!base->data || !active) {
+ if (base->data.is_empty() || !active) {
for (int i = 0; i < p_frames; i++) {
p_buffer[i] = AudioFrame(0, 0);
}
@@ -324,8 +321,7 @@ int AudioStreamPlaybackWAV::mix(AudioFrame *p_buffer, float p_rate_scale, int p_
/* audio data */
- uint8_t *dataptr = (uint8_t *)base->data;
- const void *data = dataptr + AudioStreamWAV::DATA_PAD;
+ const uint8_t *data = base->data.ptr() + AudioStreamWAV::DATA_PAD;
AudioFrame *dst_buff = p_buffer;
if (format == AudioStreamWAV::FORMAT_IMA_ADPCM) {
@@ -483,11 +479,7 @@ void AudioStreamPlaybackWAV::set_sample_playback(const Ref<AudioSamplePlayback>
AudioStreamPlaybackWAV::AudioStreamPlaybackWAV() {}
-AudioStreamPlaybackWAV::~AudioStreamPlaybackWAV() {
- if (qoa.dec) {
- memfree(qoa.dec);
- }
-}
+AudioStreamPlaybackWAV::~AudioStreamPlaybackWAV() {}
/////////////////////
@@ -554,7 +546,7 @@ double AudioStreamWAV::get_length() const {
break;
case AudioStreamWAV::FORMAT_QOA:
qoa_desc desc = {};
- qoa_decode_header((uint8_t *)data + DATA_PAD, data_bytes, &desc);
+ qoa_decode_header(data.ptr() + DATA_PAD, data_bytes, &desc);
len = desc.samples * desc.channels;
break;
}
@@ -572,22 +564,16 @@ bool AudioStreamWAV::is_monophonic() const {
void AudioStreamWAV::set_data(const Vector<uint8_t> &p_data) {
AudioServer::get_singleton()->lock();
- if (data) {
- memfree(data);
- data = nullptr;
- data_bytes = 0;
- }
- int datalen = p_data.size();
- if (datalen) {
- const uint8_t *r = p_data.ptr();
- int alloc_len = datalen + DATA_PAD * 2;
- data = memalloc(alloc_len); //alloc with some padding for interpolation
- memset(data, 0, alloc_len);
- uint8_t *dataptr = (uint8_t *)data;
- memcpy(dataptr + DATA_PAD, r, datalen);
- data_bytes = datalen;
- }
+ int src_data_len = p_data.size();
+
+ data.clear();
+
+ int alloc_len = src_data_len + DATA_PAD * 2;
+ data.resize(alloc_len);
+ memset(data.ptr(), 0, alloc_len);
+ memcpy(data.ptr() + DATA_PAD, p_data.ptr(), src_data_len);
+ data_bytes = src_data_len;
AudioServer::get_singleton()->unlock();
}
@@ -595,13 +581,9 @@ void AudioStreamWAV::set_data(const Vector<uint8_t> &p_data) {
Vector<uint8_t> AudioStreamWAV::get_data() const {
Vector<uint8_t> pv;
- if (data) {
+ if (!data.is_empty()) {
pv.resize(data_bytes);
- {
- uint8_t *w = pv.ptrw();
- uint8_t *dataptr = (uint8_t *)data;
- memcpy(w, dataptr + DATA_PAD, data_bytes);
- }
+ memcpy(pv.ptrw(), data.ptr() + DATA_PAD, data_bytes);
}
return pv;
@@ -693,12 +675,12 @@ Ref<AudioStreamPlayback> AudioStreamWAV::instantiate_playback() {
sample->base = Ref<AudioStreamWAV>(this);
if (format == AudioStreamWAV::FORMAT_QOA) {
- uint32_t ffp = qoa_decode_header((uint8_t *)data + DATA_PAD, data_bytes, &sample->qoa.desc);
+ uint32_t ffp = qoa_decode_header(data.ptr() + DATA_PAD, data_bytes, &sample->qoa.desc);
ERR_FAIL_COND_V(ffp != 8, Ref<AudioStreamPlaybackWAV>());
sample->qoa.frame_len = qoa_max_frame_size(&sample->qoa.desc);
int samples_len = (sample->qoa.desc.samples > QOA_FRAME_LEN ? QOA_FRAME_LEN : sample->qoa.desc.samples);
- int alloc_len = sample->qoa.desc.channels * samples_len * sizeof(int16_t);
- sample->qoa.dec = (int16_t *)memalloc(alloc_len);
+ int dec_len = sample->qoa.desc.channels * samples_len;
+ sample->qoa.dec.resize(dec_len);
}
return sample;
@@ -780,10 +762,4 @@ void AudioStreamWAV::_bind_methods() {
AudioStreamWAV::AudioStreamWAV() {}
-AudioStreamWAV::~AudioStreamWAV() {
- if (data) {
- memfree(data);
- data = nullptr;
- data_bytes = 0;
- }
-}
+AudioStreamWAV::~AudioStreamWAV() {}
diff --git a/scene/resources/audio_stream_wav.h b/scene/resources/audio_stream_wav.h
index 47aa10e790..bc62e8883a 100644
--- a/scene/resources/audio_stream_wav.h
+++ b/scene/resources/audio_stream_wav.h
@@ -62,7 +62,7 @@ class AudioStreamPlaybackWAV : public AudioStreamPlayback {
qoa_desc desc = {};
uint32_t data_ofs = 0;
uint32_t frame_len = 0;
- int16_t *dec = nullptr;
+ LocalVector<int16_t> dec;
uint32_t dec_len = 0;
int64_t cache_pos = -1;
int16_t cache[2] = { 0, 0 };
@@ -137,7 +137,7 @@ private:
int loop_begin = 0;
int loop_end = 0;
int mix_rate = 44100;
- void *data = nullptr;
+ LocalVector<uint8_t> data;
uint32_t data_bytes = 0;
protected:
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index 62ea749465..69dc71e414 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -1354,25 +1354,6 @@ Ref<SceneState> SceneState::get_base_scene_state() const {
return Ref<SceneState>();
}
-void SceneState::update_instance_resource(String p_path, Ref<PackedScene> p_packed_scene) {
- ERR_FAIL_COND(p_packed_scene.is_null());
-
- for (const NodeData &nd : nodes) {
- if (nd.instance >= 0) {
- if (!(nd.instance & FLAG_INSTANCE_IS_PLACEHOLDER)) {
- int instance_id = nd.instance & FLAG_MASK;
- Ref<PackedScene> original_packed_scene = variants[instance_id];
- if (original_packed_scene.is_valid()) {
- if (original_packed_scene->get_path() == p_path) {
- variants.remove_at(instance_id);
- variants.insert(instance_id, p_packed_scene);
- }
- }
- }
- }
- }
-}
-
int SceneState::find_node_by_path(const NodePath &p_node) const {
ERR_FAIL_COND_V_MSG(node_path_cache.is_empty(), -1, "This operation requires the node cache to have been built.");
diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp
index e2c8686911..ece088a694 100644
--- a/servers/audio/audio_stream.cpp
+++ b/servers/audio/audio_stream.cpp
@@ -173,12 +173,12 @@ int AudioStreamPlaybackResampled::mix(AudioFrame *p_buffer, float p_rate_scale,
}
float mu2 = mu * mu;
- AudioFrame a0 = 3 * y1 - 3 * y2 + y3 - y0;
- AudioFrame a1 = 2 * y0 - 5 * y1 + 4 * y2 - y3;
- AudioFrame a2 = y2 - y0;
- AudioFrame a3 = 2 * y1;
+ float h11 = mu2 * (mu - 1);
+ float z = mu2 - h11;
+ float h01 = z - h11;
+ float h10 = mu - z;
- p_buffer[i] = (a0 * mu * mu2 + a1 * mu2 + a2 * mu + a3) / 2;
+ p_buffer[i] = y1 + (y2 - y1) * h01 + ((y2 - y0) * h10 + (y3 - y1) * h11) * 0.5;
mix_offset += mix_increment;