diff options
Diffstat (limited to 'editor/editor_node.cpp')
-rw-r--r-- | editor/editor_node.cpp | 233 |
1 files changed, 191 insertions, 42 deletions
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index bb34a45938..454170647f 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -85,6 +85,7 @@ #include "editor/editor_settings.h" #include "editor/editor_spin_slider.h" #include "editor/editor_themes.h" +#include "editor/editor_translation_parser.h" #include "editor/export_template_manager.h" #include "editor/filesystem_dock.h" #include "editor/import/editor_import_collada.h" @@ -103,7 +104,6 @@ #include "editor/import_dock.h" #include "editor/multi_node_edit.h" #include "editor/node_dock.h" -#include "editor/pane_drag.h" #include "editor/plugin_config_dialog.h" #include "editor/plugins/animation_blend_space_1d_editor.h" #include "editor/plugins/animation_blend_space_2d_editor.h" @@ -138,6 +138,7 @@ #include "editor/plugins/multimesh_editor_plugin.h" #include "editor/plugins/navigation_polygon_editor_plugin.h" #include "editor/plugins/node_3d_editor_plugin.h" +#include "editor/plugins/packed_scene_translation_parser_plugin.h" #include "editor/plugins/path_2d_editor_plugin.h" #include "editor/plugins/path_3d_editor_plugin.h" #include "editor/plugins/physical_bone_3d_editor_plugin.h" @@ -178,6 +179,111 @@ EditorNode *EditorNode::singleton = nullptr; +void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vector<String> &r_filenames) { + // Keep track of a list of "index sets," i.e. sets of indices + // within disambiguated_scene_names which contain the same name. + Vector<Set<int>> index_sets; + Map<String, int> scene_name_to_set_index; + for (int i = 0; i < r_filenames.size(); i++) { + String scene_name = r_filenames[i]; + if (!scene_name_to_set_index.has(scene_name)) { + index_sets.append(Set<int>()); + scene_name_to_set_index.insert(r_filenames[i], index_sets.size() - 1); + } + index_sets.write[scene_name_to_set_index[scene_name]].insert(i); + } + + // For each index set with a size > 1, we need to disambiguate + for (int i = 0; i < index_sets.size(); i++) { + Set<int> iset = index_sets[i]; + while (iset.size() > 1) { + // Append the parent folder to each scene name + for (Set<int>::Element *E = iset.front(); E; E = E->next()) { + int set_idx = E->get(); + String scene_name = r_filenames[set_idx]; + String full_path = p_full_paths[set_idx]; + + // Get rid of file extensions and res:// prefixes + if (scene_name.rfind(".") >= 0) { + scene_name = scene_name.substr(0, scene_name.rfind(".")); + } + if (full_path.begins_with("res://")) { + full_path = full_path.substr(6); + } + if (full_path.rfind(".") >= 0) { + full_path = full_path.substr(0, full_path.rfind(".")); + } + + int scene_name_size = scene_name.size(); + int full_path_size = full_path.size(); + int difference = full_path_size - scene_name_size; + + // Find just the parent folder of the current path and append it. + // If the current name is foo.tscn, and the full path is /some/folder/foo.tscn + // then slash_idx is the second '/', so that we select just "folder", and + // append that to yield "folder/foo.tscn". + if (difference > 0) { + String parent = full_path.substr(0, difference); + int slash_idx = parent.rfind("/"); + slash_idx = parent.rfind("/", slash_idx - 1); + parent = slash_idx >= 0 ? parent.substr(slash_idx + 1) : parent; + r_filenames.write[set_idx] = parent + r_filenames[set_idx]; + } + } + + // Loop back through scene names and remove non-ambiguous names + bool can_proceed = false; + Set<int>::Element *E = iset.front(); + while (E) { + String scene_name = r_filenames[E->get()]; + bool duplicate_found = false; + for (Set<int>::Element *F = iset.front(); F; F = F->next()) { + if (E->get() == F->get()) { + continue; + } + String other_scene_name = r_filenames[F->get()]; + if (other_scene_name == scene_name) { + duplicate_found = true; + break; + } + } + + Set<int>::Element *to_erase = duplicate_found ? nullptr : E; + + // We need to check that we could actually append anymore names + // if we wanted to for disambiguation. If we can't, then we have + // to abort even with ambiguous names. We clean the full path + // and the scene name first to remove extensions so that this + // comparison actually works. + String path = p_full_paths[E->get()]; + if (path.begins_with("res://")) { + path = path.substr(6); + } + if (path.rfind(".") >= 0) { + path = path.substr(0, path.rfind(".")); + } + if (scene_name.rfind(".") >= 0) { + scene_name = scene_name.substr(0, scene_name.rfind(".")); + } + + // We can proceed iff the full path is longer than the scene name, + // meaning that there is at least one more parent folder we can + // tack onto the name. + can_proceed = can_proceed || (path.size() - scene_name.size()) >= 1; + + E = E->next(); + if (to_erase) { + iset.erase(to_erase); + } + } + + if (!can_proceed) { + break; + } + } + } +} + void EditorNode::_update_scene_tabs() { bool show_rb = EditorSettings::get_singleton()->get("interface/scene_tabs/show_script_button"); @@ -185,6 +291,16 @@ void EditorNode::_update_scene_tabs() { DisplayServer::get_singleton()->global_menu_clear("_dock"); } + // Get all scene names, which may be ambiguous + Vector<String> disambiguated_scene_names; + Vector<String> full_path_names; + for (int i = 0; i < editor_data.get_edited_scene_count(); i++) { + disambiguated_scene_names.append(editor_data.get_scene_title(i)); + full_path_names.append(editor_data.get_scene_path(i)); + } + + disambiguate_filenames(full_path_names, disambiguated_scene_names); + scene_tabs->clear_tabs(); Ref<Texture2D> script_icon = gui_base->get_theme_icon("Script", "EditorIcons"); for (int i = 0; i < editor_data.get_edited_scene_count(); i++) { @@ -196,7 +312,7 @@ void EditorNode::_update_scene_tabs() { int current = editor_data.get_edited_scene(); bool unsaved = (i == current) ? saved_version != editor_data.get_undo_redo().get_version() : editor_data.get_scene_version(i) != 0; - scene_tabs->add_tab(editor_data.get_scene_title(i) + (unsaved ? "(*)" : ""), icon); + scene_tabs->add_tab(disambiguated_scene_names[i] + (unsaved ? "(*)" : ""), icon); if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_GLOBAL_MENU)) { DisplayServer::get_singleton()->global_menu_add_item("_dock", editor_data.get_scene_title(i) + (unsaved ? "(*)" : ""), callable_mp(this, &EditorNode::_global_menu_scene), i); @@ -360,7 +476,7 @@ void EditorNode::_notification(int p_what) { bool dof_jitter = GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_use_jitter"); RS::get_singleton()->camera_effects_set_dof_blur_quality(dof_quality, dof_jitter); RS::get_singleton()->environment_set_ssao_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/quality/ssao/quality"))), GLOBAL_GET("rendering/quality/ssao/half_size")); - RS::get_singleton()->screen_space_roughness_limiter_set_active(GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter"), GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_curve")); + RS::get_singleton()->screen_space_roughness_limiter_set_active(GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_enabled"), GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_amount"), GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_limit")); bool glow_bicubic = int(GLOBAL_GET("rendering/quality/glow/upscale_mode")) > 0; RS::get_singleton()->environment_glow_set_use_bicubic_upscale(glow_bicubic); RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::EnvironmentSSRRoughnessQuality(int(GLOBAL_GET("rendering/quality/screen_space_reflection/roughness_quality"))); @@ -376,6 +492,12 @@ void EditorNode::_notification(int p_what) { RS::get_singleton()->directional_shadow_quality_set(directional_shadow_quality); float probe_update_speed = GLOBAL_GET("rendering/lightmapper/probe_capture_update_speed"); RS::get_singleton()->lightmap_set_probe_capture_update_speed(probe_update_speed); + RS::EnvironmentSDFGIFramesToConverge frames_to_converge = RS::EnvironmentSDFGIFramesToConverge(int(GLOBAL_GET("rendering/sdfgi/frames_to_converge"))); + RS::get_singleton()->environment_set_sdfgi_frames_to_converge(frames_to_converge); + RS::EnvironmentSDFGIRayCount ray_count = RS::EnvironmentSDFGIRayCount(int(GLOBAL_GET("rendering/sdfgi/probe_ray_count"))); + RS::get_singleton()->environment_set_sdfgi_ray_count(ray_count); + RS::GIProbeQuality gi_probe_quality = RS::GIProbeQuality(int(GLOBAL_GET("rendering/quality/gi_probes/quality"))); + RS::get_singleton()->gi_probe_set_quality(gi_probe_quality); } ResourceImporterTexture::get_singleton()->update_imports(); @@ -429,14 +551,14 @@ void EditorNode::_notification(int p_what) { /* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */ } break; - case NOTIFICATION_WM_FOCUS_IN: { + case NOTIFICATION_APPLICATION_FOCUS_IN: { // Restore the original FPS cap after focusing back on the editor OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(int(EDITOR_GET("interface/editor/low_processor_mode_sleep_usec"))); EditorFileSystem::get_singleton()->scan_changes(); } break; - case NOTIFICATION_WM_FOCUS_OUT: { + case NOTIFICATION_APPLICATION_FOCUS_OUT: { // Set a low FPS cap to decrease CPU/GPU usage while the editor is unfocused OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(int(EDITOR_GET("interface/editor/unfocused_low_processor_mode_sleep_usec"))); } break; @@ -1103,20 +1225,25 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) { _find_node_types(editor_data.get_edited_scene_root(), c2d, c3d); - bool is2d; - if (c3d < c2d) { - is2d = true; - } else { - is2d = false; - } save.step(TTR("Creating Thumbnail"), 1); //current view? Ref<Image> img; - if (is2d) { + // If neither 3D or 2D nodes are present, make a 1x1 black texture. + // We cannot fallback on the 2D editor, because it may not have been used yet, + // which would result in an invalid texture. + if (c3d == 0 && c2d == 0) { + img.instance(); + img->create(1, 1, 0, Image::FORMAT_RGB8); + } else if (c3d < c2d) { img = scene_root->get_texture()->get_data(); } else { - img = Node3DEditor::get_singleton()->get_editor_viewport(0)->get_viewport_node()->get_texture()->get_data(); + // The 3D editor may be disabled as a feature, but scenes can still be opened. + // This check prevents the preview from regenerating in case those scenes are then saved. + Ref<EditorFeatureProfile> profile = feature_profile_manager->get_current_profile(); + if (!profile->is_feature_disabled(EditorFeatureProfile::FEATURE_3D)) { + img = Node3DEditor::get_singleton()->get_editor_viewport(0)->get_viewport_node()->get_texture()->get_data(); + } } if (img.is_valid()) { @@ -1921,7 +2048,6 @@ void EditorNode::_run(bool p_current, const String &p_custom) { play_custom_scene_button->set_pressed(false); play_custom_scene_button->set_icon(gui_base->get_theme_icon("PlayCustom", "EditorIcons")); - String main_scene; String run_filename; String args; bool skip_breakpoints; @@ -2342,8 +2468,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } break; case RUN_PLAY: { - _menu_option_confirm(RUN_STOP, true); - _run(false); + run_play(); } break; case RUN_PLAY_CUSTOM_SCENE: { @@ -2354,8 +2479,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { play_custom_scene_button->set_pressed(false); } else { String last_custom_scene = run_custom_filename; - _menu_option_confirm(RUN_STOP, true); - _run(false, last_custom_scene); + run_play_custom(last_custom_scene); } } break; @@ -2395,9 +2519,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } break; case RUN_PLAY_SCENE: { - _save_default_environment(); - _menu_option_confirm(RUN_STOP, true); - _run(true); + run_play_current(); } break; case RUN_SCENE_SETTINGS: { @@ -3405,10 +3527,14 @@ void EditorNode::_update_recent_scenes() { void EditorNode::_quick_opened() { Vector<String> files = quick_open->get_selected_files(); + bool open_scene_dialog = quick_open->get_base_type() == "PackedScene"; for (int i = 0; i < files.size(); i++) { String res_path = files[i]; - if (quick_open->get_base_type() == "PackedScene") { + List<String> scene_extensions; + ResourceLoader::get_recognized_extensions_for_type("PackedScene", &scene_extensions); + + if (open_scene_dialog || scene_extensions.find(files[i].get_extension())) { open_request(res_path); } else { load_resource(res_path); @@ -3464,6 +3590,7 @@ void EditorNode::register_editor_types() { ResourceSaver::set_timestamp_on_save(true); ClassDB::register_class<EditorPlugin>(); + ClassDB::register_class<EditorTranslationParserPlugin>(); ClassDB::register_class<EditorImportPlugin>(); ClassDB::register_class<EditorScript>(); ClassDB::register_class<EditorSelection>(); @@ -3637,22 +3764,14 @@ Ref<Texture2D> EditorNode::get_object_icon(const Object *p_object, const String Ref<Texture2D> EditorNode::get_class_icon(const String &p_class, const String &p_fallback) const { ERR_FAIL_COND_V_MSG(p_class.empty(), nullptr, "Class name cannot be empty."); - if (gui_base->has_theme_icon(p_class, "EditorIcons")) { - return gui_base->get_theme_icon(p_class, "EditorIcons"); - } - if (ScriptServer::is_global_class(p_class)) { - String icon_path = EditorNode::get_editor_data().script_class_get_icon_path(p_class); - Ref<ImageTexture> icon = _load_custom_class_icon(icon_path); - if (icon.is_valid()) { - return icon; - } - - Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(p_class), "Script"); + Ref<ImageTexture> icon; + Ref<Script> script = EditorNode::get_editor_data().script_class_load_script(p_class); + StringName name = p_class; while (script.is_valid()) { - String current_icon_path; - script->get_language()->get_global_class_name(script->get_path(), nullptr, ¤t_icon_path); + name = EditorNode::get_editor_data().script_class_get_name(script->get_path()); + String current_icon_path = EditorNode::get_editor_data().script_class_get_icon_path(name); icon = _load_custom_class_icon(current_icon_path); if (icon.is_valid()) { return icon; @@ -3661,10 +3780,8 @@ Ref<Texture2D> EditorNode::get_class_icon(const String &p_class, const String &p } if (icon.is_null()) { - icon = gui_base->get_theme_icon(ScriptServer::get_global_class_base(p_class), "EditorIcons"); + icon = gui_base->get_theme_icon(ScriptServer::get_global_class_base(name), "EditorIcons"); } - - return icon; } const Map<String, Vector<EditorData::CustomType>> &p_map = EditorNode::get_editor_data().get_custom_types(); @@ -3679,6 +3796,10 @@ Ref<Texture2D> EditorNode::get_class_icon(const String &p_class, const String &p } } + if (gui_base->has_theme_icon(p_class, "EditorIcons")) { + return gui_base->get_theme_icon(p_class, "EditorIcons"); + } + if (p_fallback.length() && gui_base->has_theme_icon(p_fallback, "EditorIcons")) { return gui_base->get_theme_icon(p_fallback, "EditorIcons"); } @@ -4157,7 +4278,6 @@ void EditorNode::_update_dock_slots_visibility() { } right_hsplit->hide(); - bottom_panel->hide(); } else { for (int i = 0; i < DOCK_SLOT_MAX; i++) { int tabs_visible = 0; @@ -4187,7 +4307,6 @@ void EditorNode::_update_dock_slots_visibility() { dock_slot[i]->set_current_tab(0); } } - bottom_panel->show(); if (right_l_vsplit->is_visible() || right_r_vsplit->is_visible()) { right_hsplit->show(); @@ -4405,10 +4524,35 @@ void EditorNode::run_play() { _run(false); } +void EditorNode::run_play_current() { + _save_default_environment(); + _menu_option_confirm(RUN_STOP, true); + _run(true); +} + +void EditorNode::run_play_custom(const String &p_custom) { + _menu_option_confirm(RUN_STOP, true); + _run(false, p_custom); +} + void EditorNode::run_stop() { _menu_option_confirm(RUN_STOP, false); } +bool EditorNode::is_run_playing() const { + EditorRun::Status status = editor_run.get_status(); + return (status == EditorRun::STATUS_PLAY || status == EditorRun::STATUS_PAUSED); +} + +String EditorNode::get_run_playing_scene() const { + String run_filename = editor_run.get_running_scene(); + if (run_filename == "" && is_run_playing()) { + run_filename = GLOBAL_DEF("application/run/main_scene", ""); // Must be the main scene then. + } + + return run_filename; +} + int EditorNode::get_current_tab() { return scene_tabs->get_current_tab(); } @@ -5401,10 +5545,10 @@ EditorNode::EditorNode() { switch (display_scale) { case 0: { // Try applying a suitable display scale automatically - const int screen = DisplayServer::get_singleton()->window_get_current_screen(); #ifdef OSX_ENABLED - editor_set_scale(DisplayServer::get_singleton()->screen_get_scale(screen)); + editor_set_scale(DisplayServer::get_singleton()->screen_get_max_scale()); #else + const int screen = DisplayServer::get_singleton()->window_get_current_screen(); editor_set_scale(DisplayServer::get_singleton()->screen_get_dpi(screen) >= 192 && DisplayServer::get_singleton()->screen_get_size(screen).x > 2000 ? 2.0 : 1.0); #endif } break; @@ -6488,6 +6632,7 @@ EditorNode::EditorNode() { } resource_preview->add_preview_generator(Ref<EditorTexturePreviewPlugin>(memnew(EditorTexturePreviewPlugin))); + resource_preview->add_preview_generator(Ref<EditorImagePreviewPlugin>(memnew(EditorImagePreviewPlugin))); resource_preview->add_preview_generator(Ref<EditorPackedScenePreviewPlugin>(memnew(EditorPackedScenePreviewPlugin))); resource_preview->add_preview_generator(Ref<EditorMaterialPreviewPlugin>(memnew(EditorMaterialPreviewPlugin))); resource_preview->add_preview_generator(Ref<EditorScriptPreviewPlugin>(memnew(EditorScriptPreviewPlugin))); @@ -6539,6 +6684,10 @@ EditorNode::EditorNode() { EditorExport::get_singleton()->add_export_plugin(export_text_to_binary_plugin); + Ref<PackedSceneEditorTranslationParserPlugin> packed_scene_translation_parser_plugin; + packed_scene_translation_parser_plugin.instance(); + EditorTranslationParser::get_singleton()->add_parser(packed_scene_translation_parser_plugin, EditorTranslationParser::STANDARD); + _edit_current(); current = nullptr; saving_resource = Ref<Resource>(); |