diff options
-rw-r--r-- | doc/classes/Camera3D.xml | 6 | ||||
-rw-r--r-- | editor/connections_dialog.cpp | 2 | ||||
-rw-r--r-- | editor/editor_inspector.cpp | 3 | ||||
-rw-r--r-- | editor/editor_plugin_settings.cpp | 11 | ||||
-rw-r--r-- | editor/gui/scene_tree_editor.cpp | 26 | ||||
-rw-r--r-- | editor/node_dock.cpp | 7 | ||||
-rw-r--r-- | editor/node_dock.h | 2 | ||||
-rw-r--r-- | editor/plugins/tiles/tile_data_editors.cpp | 17 | ||||
-rw-r--r-- | editor/project_manager.cpp | 1 | ||||
-rw-r--r-- | platform/windows/display_server_windows.cpp | 2 | ||||
-rw-r--r-- | scene/3d/camera_3d.cpp | 68 | ||||
-rw-r--r-- | scene/3d/camera_3d.h | 3 | ||||
-rw-r--r-- | scene/animation/animation_node_state_machine.cpp | 10 | ||||
-rw-r--r-- | scene/main/viewport.cpp | 6 |
14 files changed, 104 insertions, 60 deletions
diff --git a/doc/classes/Camera3D.xml b/doc/classes/Camera3D.xml index 9d43b4bd26..83f1ffa08e 100644 --- a/doc/classes/Camera3D.xml +++ b/doc/classes/Camera3D.xml @@ -17,6 +17,12 @@ If this is the current camera, remove it from being current. If [param enable_next] is [code]true[/code], request to make the next camera current, if any. </description> </method> + <method name="get_camera_projection" qualifiers="const"> + <return type="Projection" /> + <description> + Returns the projection matrix that this camera uses to render to its associated viewport. The camera must be part of the scene tree to function. + </description> + </method> <method name="get_camera_rid" qualifiers="const"> <return type="RID" /> <description> diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index f4b7b14e99..3965dcd198 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -39,6 +39,7 @@ #include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "editor/gui/scene_tree_editor.h" +#include "editor/node_dock.h" #include "editor/scene_tree_dock.h" #include "plugins/script_editor_plugin.h" #include "scene/gui/button.h" @@ -1440,6 +1441,7 @@ ConnectionsDock::ConnectionsDock() { connect_button->connect("pressed", callable_mp(this, &ConnectionsDock::_connect_pressed)); connect_dialog = memnew(ConnectDialog); + connect_dialog->connect("connected", callable_mp(NodeDock::get_singleton(), &NodeDock::restore_last_valid_node), CONNECT_DEFERRED); add_child(connect_dialog); disconnect_all_dialog = memnew(ConfirmationDialog); diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index e3514b4691..367373dc17 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -3184,10 +3184,11 @@ void EditorInspector::update_tree() { if (val.enumeration == enum_name && !val.name.ends_with("_MAX")) { const String enum_value = EditorPropertyNameProcessor::get_singleton()->process_name(val.name, EditorPropertyNameProcessor::STYLE_CAPITALIZED); // Prettify the enum value display, so that "<ENUM NAME>_<VALUE>" becomes "Value". + String desc = DTR(val.description).trim_prefix("\n"); doc_info.description += vformat( "\n[b]%s:[/b] %s", enum_value.trim_prefix(EditorPropertyNameProcessor::get_singleton()->process_name(enum_name, EditorPropertyNameProcessor::STYLE_CAPITALIZED) + " "), - DTR(val.description).trim_prefix("\n")); + desc.is_empty() ? ("[i]" + TTR("No description.") + "[/i]") : desc); } } } diff --git a/editor/editor_plugin_settings.cpp b/editor/editor_plugin_settings.cpp index 1e582992d1..7f57619ac8 100644 --- a/editor/editor_plugin_settings.cpp +++ b/editor/editor_plugin_settings.cpp @@ -101,9 +101,18 @@ void EditorPluginSettings::update_plugins() { String description = cf->get_value("plugin", "description"); String scr = cf->get_value("plugin", "script"); + const PackedInt32Array boundaries = TS->string_get_word_breaks(description, "", 80); + String wrapped_description; + + for (int j = 0; j < boundaries.size(); j += 2) { + const int start = boundaries[j]; + const int end = boundaries[j + 1]; + wrapped_description += "\n" + description.substr(start, end - start + 1).rstrip("\n"); + } + TreeItem *item = plugin_list->create_item(root); item->set_text(0, name); - item->set_tooltip_text(0, TTR("Name:") + " " + name + "\n" + TTR("Path:") + " " + path + "\n" + TTR("Main Script:") + " " + scr + "\n" + TTR("Description:") + " " + description); + item->set_tooltip_text(0, TTR("Name:") + " " + name + "\n" + TTR("Path:") + " " + path + "\n" + TTR("Main Script:") + " " + scr + "\n" + TTR("Description:") + " " + wrapped_description); item->set_metadata(0, path); item->set_text(1, version); item->set_metadata(1, scr); diff --git a/editor/gui/scene_tree_editor.cpp b/editor/gui/scene_tree_editor.cpp index d1756df66c..d8c6ff54cc 100644 --- a/editor/gui/scene_tree_editor.cpp +++ b/editor/gui/scene_tree_editor.cpp @@ -374,7 +374,14 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { tooltip += String("\n" + TTR("Type:") + " " + (custom_type != StringName() ? String(custom_type) : p_node->get_class())); if (!p_node->get_editor_description().is_empty()) { - tooltip += "\n\n" + p_node->get_editor_description(); + const PackedInt32Array boundaries = TS->string_get_word_breaks(p_node->get_editor_description(), "", 80); + tooltip += "\n"; + + for (int i = 0; i < boundaries.size(); i += 2) { + const int start = boundaries[i]; + const int end = boundaries[i + 1]; + tooltip += "\n" + p_node->get_editor_description().substr(start, end - start + 1).rstrip("\n"); + } } item->set_tooltip_text(0, tooltip); @@ -1019,11 +1026,18 @@ void SceneTreeEditor::_renamed() { } } - if (n->is_unique_name_in_owner() && get_tree()->get_edited_scene_root()->get_node_or_null("%" + new_name) != nullptr) { - error->set_text(TTR("Another node already uses this unique name in the scene.")); - error->popup_centered(); - which->set_text(0, n->get_name()); - return; + if (n->is_unique_name_in_owner()) { + Node *existing = get_tree()->get_edited_scene_root()->get_node_or_null("%" + new_name); + if (existing == n) { + which->set_text(0, n->get_name()); + return; + } + if (existing != nullptr) { + error->set_text(TTR("Another node already uses this unique name in the scene.")); + error->popup_centered(); + which->set_text(0, n->get_name()); + return; + } } _rename_node(n, new_name); diff --git a/editor/node_dock.cpp b/editor/node_dock.cpp index 545769d327..ebb35eedf9 100644 --- a/editor/node_dock.cpp +++ b/editor/node_dock.cpp @@ -70,6 +70,9 @@ void NodeDock::update_lists() { void NodeDock::set_node(Node *p_node) { connections->set_node(p_node); groups->set_current(p_node); + if (p_node) { + last_valid_node = p_node; + } if (p_node) { if (connections_button->is_pressed()) { @@ -88,6 +91,10 @@ void NodeDock::set_node(Node *p_node) { } } +void NodeDock::restore_last_valid_node() { + set_node(last_valid_node); +} + NodeDock::NodeDock() { singleton = this; diff --git a/editor/node_dock.h b/editor/node_dock.h index e9dcc41d48..cc22171453 100644 --- a/editor/node_dock.h +++ b/editor/node_dock.h @@ -47,6 +47,7 @@ class NodeDock : public VBoxContainer { HBoxContainer *mode_hb = nullptr; Label *select_a_node = nullptr; + Node *last_valid_node = nullptr; private: static NodeDock *singleton; @@ -60,6 +61,7 @@ protected: public: void set_node(Node *p_node); + void restore_last_valid_node(); void show_groups(); void show_connections(); diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp index ef805e6524..7767831ea3 100644 --- a/editor/plugins/tiles/tile_data_editors.cpp +++ b/editor/plugins/tiles/tile_data_editors.cpp @@ -1185,19 +1185,18 @@ void TileDataDefaultEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2 Ref<Font> font = TileSetEditor::get_singleton()->get_theme_font(SNAME("bold"), SNAME("EditorFonts")); int font_size = TileSetEditor::get_singleton()->get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts")); String text; + // Round floating point precision to 2 digits, as tiles don't have that much space. switch (value.get_type()) { - case Variant::INT: - text = vformat("%d", value); - break; case Variant::FLOAT: text = vformat("%.2f", value); break; - case Variant::STRING: - case Variant::STRING_NAME: - text = value; + case Variant::VECTOR2: + case Variant::VECTOR3: + case Variant::VECTOR4: + text = vformat("%.2v", value); break; default: - return; + text = value.stringify(); break; } @@ -1216,8 +1215,8 @@ void TileDataDefaultEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2 } Vector2 string_size = font->get_string_size(text, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size); - p_canvas_item->draw_string_outline(font, p_transform.xform(-texture_origin) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, 1, Color(0, 0, 0, 1)); - p_canvas_item->draw_string(font, p_transform.xform(-texture_origin) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, color); + p_canvas_item->draw_string_outline(font, p_transform.xform(-texture_origin) + Vector2i(-string_size.x / 2, string_size.y / 4), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, 3, Color(0, 0, 0)); + p_canvas_item->draw_string(font, p_transform.xform(-texture_origin) + Vector2i(-string_size.x / 2, string_size.y / 4), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, color); } } diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index a86963c330..71b5ef2460 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -2504,6 +2504,7 @@ void ProjectManager::_apply_project_tags() { callable_mp((Window *)tag_manage_dialog, &Window::show).call_deferred(); // Make sure the dialog does not disappear. return; } else { + tags.sort(); cfg.set_value("application", "config/tags", tags); err = cfg.save(project_godot); if (err != OK) { diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 91f7de7f26..b0b1e1680f 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -1598,7 +1598,7 @@ void DisplayServerWindows::window_request_attention(WindowID p_window) { FLASHWINFO info; info.cbSize = sizeof(FLASHWINFO); info.hwnd = wd.hWnd; - info.dwFlags = FLASHW_TRAY; + info.dwFlags = FLASHW_ALL; info.dwTimeout = 0; info.uCount = 2; FlashWindowEx(&info); diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp index 5a4761892d..225b9b35b3 100644 --- a/scene/3d/camera_3d.cpp +++ b/scene/3d/camera_3d.cpp @@ -170,6 +170,30 @@ Transform3D Camera3D::get_camera_transform() const { return tr; } +Projection Camera3D::_get_camera_projection(real_t p_near) const { + Size2 viewport_size = get_viewport()->get_visible_rect().size; + Projection cm; + + switch (mode) { + case PROJECTION_PERSPECTIVE: { + cm.set_perspective(fov, viewport_size.aspect(), p_near, far, keep_aspect == KEEP_WIDTH); + } break; + case PROJECTION_ORTHOGONAL: { + cm.set_orthogonal(size, viewport_size.aspect(), p_near, far, keep_aspect == KEEP_WIDTH); + } break; + case PROJECTION_FRUSTUM: { + cm.set_frustum(size, viewport_size.aspect(), frustum_offset, p_near, far); + } break; + } + + return cm; +} + +Projection Camera3D::get_camera_projection() const { + ERR_FAIL_COND_V_MSG(!is_inside_tree(), Projection(), "Camera is not inside the scene tree."); + return _get_camera_projection(near); +} + void Camera3D::set_perspective(real_t p_fovy_degrees, real_t p_z_near, real_t p_z_far) { if (!force_change && fov == p_fovy_degrees && p_z_near == near && p_z_far == far && mode == PROJECTION_PERSPECTIVE) { return; @@ -286,8 +310,7 @@ Vector3 Camera3D::project_local_ray_normal(const Point2 &p_pos) const { if (mode == PROJECTION_ORTHOGONAL) { ray = Vector3(0, 0, -1); } else { - Projection cm; - cm.set_perspective(fov, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH); + Projection cm = _get_camera_projection(near); Vector2 screen_he = cm.get_viewport_half_extents(); ray = Vector3(((cpos.x / viewport_size.width) * 2.0 - 1.0) * screen_he.x, ((1.0 - (cpos.y / viewport_size.height)) * 2.0 - 1.0) * screen_he.y, -near).normalized(); } @@ -302,9 +325,7 @@ Vector3 Camera3D::project_ray_origin(const Point2 &p_pos) const { Vector2 cpos = get_viewport()->get_camera_coords(p_pos); ERR_FAIL_COND_V(viewport_size.y == 0, Vector3()); - if (mode == PROJECTION_PERSPECTIVE) { - return get_camera_transform().origin; - } else { + if (mode == PROJECTION_ORTHOGONAL) { Vector2 pos = cpos / viewport_size; real_t vsize, hsize; if (keep_aspect == KEEP_WIDTH) { @@ -321,6 +342,8 @@ Vector3 Camera3D::project_ray_origin(const Point2 &p_pos) const { ray.z = -near; ray = get_camera_transform().xform(ray); return ray; + } else { + return get_camera_transform().origin; }; }; @@ -333,15 +356,7 @@ bool Camera3D::is_position_behind(const Vector3 &p_pos) const { Vector<Vector3> Camera3D::get_near_plane_points() const { ERR_FAIL_COND_V_MSG(!is_inside_tree(), Vector<Vector3>(), "Camera is not inside scene."); - Size2 viewport_size = get_viewport()->get_visible_rect().size; - - Projection cm; - - if (mode == PROJECTION_ORTHOGONAL) { - cm.set_orthogonal(size, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH); - } else { - cm.set_perspective(fov, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH); - } + Projection cm = _get_camera_projection(near); Vector3 endpoints[8]; cm.get_endpoints(Transform3D(), endpoints); @@ -361,13 +376,7 @@ Point2 Camera3D::unproject_position(const Vector3 &p_pos) const { Size2 viewport_size = get_viewport()->get_visible_rect().size; - Projection cm; - - if (mode == PROJECTION_ORTHOGONAL) { - cm.set_orthogonal(size, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH); - } else { - cm.set_perspective(fov, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH); - } + Projection cm = _get_camera_projection(near); Plane p(get_camera_transform().xform_inv(p_pos), 1.0); @@ -389,13 +398,7 @@ Vector3 Camera3D::project_position(const Point2 &p_point, real_t p_z_depth) cons } Size2 viewport_size = get_viewport()->get_visible_rect().size; - Projection cm; - - if (mode == PROJECTION_ORTHOGONAL) { - cm.set_orthogonal(size, viewport_size.aspect(), p_z_depth, far, keep_aspect == KEEP_WIDTH); - } else { - cm.set_perspective(fov, viewport_size.aspect(), p_z_depth, far, keep_aspect == KEEP_WIDTH); - } + Projection cm = _get_camera_projection(p_z_depth); Vector2 vp_he = cm.get_viewport_half_extents(); @@ -508,6 +511,7 @@ void Camera3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_current", "enabled"), &Camera3D::set_current); ClassDB::bind_method(D_METHOD("is_current"), &Camera3D::is_current); ClassDB::bind_method(D_METHOD("get_camera_transform"), &Camera3D::get_camera_transform); + ClassDB::bind_method(D_METHOD("get_camera_projection"), &Camera3D::get_camera_projection); ClassDB::bind_method(D_METHOD("get_fov"), &Camera3D::get_fov); ClassDB::bind_method(D_METHOD("get_frustum_offset"), &Camera3D::get_frustum_offset); ClassDB::bind_method(D_METHOD("get_size"), &Camera3D::get_size); @@ -653,13 +657,7 @@ bool Camera3D::get_cull_mask_value(int p_layer_number) const { Vector<Plane> Camera3D::get_frustum() const { ERR_FAIL_COND_V(!is_inside_world(), Vector<Plane>()); - Size2 viewport_size = get_viewport()->get_visible_rect().size; - Projection cm; - if (mode == PROJECTION_PERSPECTIVE) { - cm.set_perspective(fov, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH); - } else { - cm.set_orthogonal(size, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH); - } + Projection cm = _get_camera_projection(near); return cm.get_projection_planes(get_camera_transform()); } diff --git a/scene/3d/camera_3d.h b/scene/3d/camera_3d.h index 420d0cb939..aa302ded4a 100644 --- a/scene/3d/camera_3d.h +++ b/scene/3d/camera_3d.h @@ -105,6 +105,8 @@ protected: static void _bind_methods(); + Projection _get_camera_projection(real_t p_near) const; + public: enum { NOTIFICATION_BECAME_CURRENT = 50, @@ -138,6 +140,7 @@ public: void set_frustum_offset(Vector2 p_offset); virtual Transform3D get_camera_transform() const; + virtual Projection get_camera_projection() const; virtual Vector3 project_ray_normal(const Point2 &p_pos) const; virtual Vector3 project_ray_origin(const Point2 &p_pos) const; diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index 071e2e7f37..0254419d22 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -901,18 +901,20 @@ bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationT bool is_state_changed = false; NextInfo next; - StringName transition_start = current; + Vector<StringName> transition_path; + transition_path.push_back(current); while (true) { next = _find_next(p_tree, p_state_machine); - if (next.node == transition_start) { - is_state_changed = false; - break; // Maybe infinity loop, do noting more. + if (transition_path.has(next.node)) { + WARN_PRINT_ONCE_ED("AnimationNodeStateMachinePlayback: " + base_path + "playback aborts the transition by detecting one or more looped transitions in the same frame to prevent to infinity loop. You may need to check the transition settings."); + break; // Maybe infinity loop, do nothing more. } if (!_can_transition_to_next(p_tree, p_state_machine, next, p_test_only)) { break; // Finish transition. } + transition_path.push_back(next.node); is_state_changed = true; // Setting for fading. diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index faa609d847..8609b77944 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1875,13 +1875,13 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { } if (over != gui.mouse_over) { + if (!gui.mouse_over) { + _drop_physics_mouseover(); + } _drop_mouse_over(); _gui_cancel_tooltip(); if (over) { - if (!gui.mouse_over) { - _drop_physics_mouseover(); - } _gui_call_notification(over, Control::NOTIFICATION_MOUSE_ENTER); gui.mouse_over = over; } |