diff options
Diffstat (limited to 'editor')
| -rw-r--r-- | editor/animation_editor.cpp | 25 | ||||
| -rw-r--r-- | editor/editor_plugin.cpp | 5 | ||||
| -rw-r--r-- | editor/editor_settings.cpp | 2 | ||||
| -rw-r--r-- | editor/filesystem_dock.cpp | 104 | ||||
| -rw-r--r-- | editor/filesystem_dock.h | 6 | ||||
| -rw-r--r-- | editor/import/resource_importer_scene.cpp | 173 | ||||
| -rw-r--r-- | editor/import/resource_importer_scene.h | 15 | ||||
| -rw-r--r-- | editor/plugins/asset_library_editor_plugin.cpp | 8 | ||||
| -rw-r--r-- | editor/plugins/asset_library_editor_plugin.h | 1 | ||||
| -rw-r--r-- | editor/plugins/canvas_item_editor_plugin.cpp | 60 | ||||
| -rw-r--r-- | editor/plugins/canvas_item_editor_plugin.h | 1 | ||||
| -rw-r--r-- | editor/plugins/mesh_instance_editor_plugin.cpp | 145 | ||||
| -rw-r--r-- | editor/plugins/mesh_instance_editor_plugin.h | 10 | ||||
| -rw-r--r-- | editor/plugins/script_text_editor.cpp | 25 | ||||
| -rw-r--r-- | editor/plugins/script_text_editor.h | 3 | ||||
| -rw-r--r-- | editor/plugins/tile_set_editor_plugin.cpp | 2 | ||||
| -rw-r--r-- | editor/property_editor.cpp | 60 | ||||
| -rw-r--r-- | editor/property_selector.cpp | 18 |
18 files changed, 491 insertions, 172 deletions
diff --git a/editor/animation_editor.cpp b/editor/animation_editor.cpp index 1d70f8ba55..c6757ba98f 100644 --- a/editor/animation_editor.cpp +++ b/editor/animation_editor.cpp @@ -1124,6 +1124,8 @@ void AnimationKeyEditor::_track_editor_draw() { Ref<Texture> add_key_icon = get_icon("TrackAddKey", "EditorIcons"); Ref<Texture> add_key_icon_hl = get_icon("TrackAddKeyHl", "EditorIcons"); Ref<Texture> down_icon = get_icon("select_arrow", "Tree"); + Ref<Texture> checked = get_icon("checked", "Tree"); + Ref<Texture> unchecked = get_icon("unchecked", "Tree"); Ref<Texture> wrap_icon[2] = { get_icon("InterpWrapClamp", "EditorIcons"), @@ -1170,6 +1172,7 @@ void AnimationKeyEditor::_track_editor_draw() { v_scroll->set_page(fit); } + int left_check_ofs = checked->get_width(); int settings_limit = size.width - right_separator_ofs; int name_limit = settings_limit * name_column_ratio; @@ -1332,6 +1335,7 @@ void AnimationKeyEditor::_track_editor_draw() { valid_type = obj->get_static_property_type_indexed(leftover_path, &prop_exists); } + // Draw background color of the whole track if (/*mouse_over.over!=MouseOver::OVER_NONE &&*/ idx == mouse_over.track) { Color sepc = hover_color; te->draw_rect(Rect2(ofs + Point2(0, y), Size2(size.width, h - 1)), sepc); @@ -1343,14 +1347,20 @@ void AnimationKeyEditor::_track_editor_draw() { te->draw_rect(Rect2(ofs + Point2(0, y), Size2(size.width - 1, h - 1)), tc); } - te->draw_texture(type_icon[animation->track_get_type(idx)], ofs + Point2(0, y + (h - type_icon[0]->get_height()) / 2).floor()); + // Draw track enabled state check box + Ref<Texture> check_box = animation->track_is_enabled(idx) ? checked : unchecked; + te->draw_texture(check_box, ofs + Point2(0, y + (h - checked->get_height()) / 2).floor()); + + // Draw track type glyph and node path + te->draw_texture(type_icon[animation->track_get_type(idx)], ofs + Point2(left_check_ofs + sep, y + (h - type_icon[0]->get_height()) / 2).floor()); NodePath np = animation->track_get_path(idx); Node *n = root ? root->get_node(np) : (Node *)NULL; Color ncol = color; if (n && editor_selection->is_selected(n)) ncol = track_select_color; - te->draw_string(font, Point2(ofs + Point2(type_icon[0]->get_width() + sep, y + font->get_ascent() + (sep / 2))).floor(), np, ncol, name_limit - (type_icon[0]->get_width() + sep) - 5); + te->draw_string(font, Point2(ofs + Point2(left_check_ofs + sep + type_icon[0]->get_width() + sep, y + font->get_ascent() + (sep / 2))).floor(), np, ncol, name_limit - (type_icon[0]->get_width() + sep) - 5); + // Draw separator line below track area if (!obj) te->draw_line(ofs + Point2(0, y + h / 2), ofs + Point2(name_limit, y + h / 2), invalid_path_color); @@ -1798,6 +1808,7 @@ void AnimationKeyEditor::_track_editor_gui_input(const Ref<InputEvent> &p_input) Ref<Texture> down_icon = get_icon("select_arrow", "Tree"); Ref<Texture> hsize_icon = get_icon("Hsize", "EditorIcons"); Ref<Texture> add_key_icon = get_icon("TrackAddKey", "EditorIcons"); + Ref<Texture> check_icon = get_icon("checked", "Tree"); Ref<Texture> wrap_icon[2] = { get_icon("InterpWrapClamp", "EditorIcons"), @@ -1832,6 +1843,7 @@ void AnimationKeyEditor::_track_editor_gui_input(const Ref<InputEvent> &p_input) v_scroll->set_page(fit); } + int left_check_ofs = check_icon->get_width(); int settings_limit = size.width - right_separator_ofs; int name_limit = settings_limit * name_column_ratio; @@ -2092,7 +2104,12 @@ void AnimationKeyEditor::_track_editor_gui_input(const Ref<InputEvent> &p_input) return; } - if (mpos.x < name_limit - (type_icon[0]->get_width() / 2.0)) { + if (mpos.x < left_check_ofs) { + // Checkbox on the very left to enable/disable tracks. + + animation->track_set_enabled(idx, !animation->track_is_enabled(idx)); + + } else if (mpos.x < name_limit - (type_icon[0]->get_width() / 2.0)) { //name column // area @@ -2103,7 +2120,7 @@ void AnimationKeyEditor::_track_editor_gui_input(const Ref<InputEvent> &p_input) return; } - Rect2 area(ofs.x, ofs.y + ((int(mpos.y) / h) + 1) * h, name_limit, h); + Rect2 area(ofs.x + left_check_ofs + sep, ofs.y + ((int(mpos.y) / h) + 1) * h, name_limit - left_check_ofs - sep, h); track_name->set_text(animation->track_get_path(idx)); track_name->set_position(te->get_global_position() + area.position); track_name->set_size(area.size); diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index a39e4d6efb..5c4c2b694f 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -565,12 +565,12 @@ void EditorPlugin::save_global_state() {} void EditorPlugin::add_import_plugin(const Ref<EditorImportPlugin> &p_importer) { ResourceFormatImporter::get_singleton()->add_importer(p_importer); - EditorFileSystem::get_singleton()->scan(); + EditorFileSystem::get_singleton()->call_deferred("scan"); } void EditorPlugin::remove_import_plugin(const Ref<EditorImportPlugin> &p_importer) { ResourceFormatImporter::get_singleton()->remove_importer(p_importer); - EditorFileSystem::get_singleton()->scan(); + EditorFileSystem::get_singleton()->call_deferred("scan"); } void EditorPlugin::add_export_plugin(const Ref<EditorExportPlugin> &p_exporter) { @@ -587,7 +587,6 @@ void EditorPlugin::add_scene_import_plugin(const Ref<EditorSceneImporter> &p_imp void EditorPlugin::remove_scene_import_plugin(const Ref<EditorSceneImporter> &p_importer) { ResourceImporterScene::get_singleton()->remove_importer(p_importer); - } void EditorPlugin::set_window_layout(Ref<ConfigFile> p_layout) { diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 04e09abcea..d199b27b83 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -348,7 +348,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("text_editor/files/autosave_interval_secs", 0); _initial_set("text_editor/cursor/block_caret", false); - _initial_set("text_editor/cursor/caret_blink", false); + _initial_set("text_editor/cursor/caret_blink", true); _initial_set("text_editor/cursor/caret_blink_speed", 0.65); hints["text_editor/cursor/caret_blink_speed"] = PropertyInfo(Variant::REAL, "text_editor/cursor/caret_blink_speed", PROPERTY_HINT_RANGE, "0.1, 10, 0.1"); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index ca6571fdda..9ece36ea80 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -806,6 +806,39 @@ void FileSystemDock::_try_move_item(const FileOrFolder &p_item, const String &p_ memdelete(da); } +void FileSystemDock::_try_duplicate_item(const FileOrFolder &p_item, const String &p_new_path) const { + //Ensure folder paths end with "/" + String old_path = (p_item.is_file || p_item.path.ends_with("/")) ? p_item.path : (p_item.path + "/"); + String new_path = (p_item.is_file || p_new_path.ends_with("/")) ? p_new_path : (p_new_path + "/"); + + if (new_path == old_path) { + return; + } else if (old_path == "res://") { + EditorNode::get_singleton()->add_io_error(TTR("Cannot move/rename resources root.")); + return; + } else if (!p_item.is_file && new_path.begins_with(old_path)) { + //This check doesn't erroneously catch renaming to a longer name as folder paths always end with "/" + EditorNode::get_singleton()->add_io_error(TTR("Cannot move a folder into itself.\n") + old_path + "\n"); + return; + } + + DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + print_line("Duplicating " + old_path + " -> " + new_path); + Error err = da->copy(old_path, new_path); + if (err == OK) { + //Move/Rename any corresponding import settings too + if (p_item.is_file && FileAccess::exists(old_path + ".import")) { + err = da->copy(old_path + ".import", new_path + ".import"); + if (err != OK) { + EditorNode::get_singleton()->add_io_error(TTR("Error duplicating:\n") + old_path + ".import\n"); + } + } + } else { + EditorNode::get_singleton()->add_io_error(TTR("Error duplicating:\n") + old_path + "\n"); + } + memdelete(da); +} + void FileSystemDock::_update_dependencies_after_move(const Map<String, String> &p_renames) const { //The following code assumes that the following holds: // 1) EditorFileSystem contains the old paths/folder structure from before the rename/move. @@ -888,6 +921,39 @@ void FileSystemDock::_rename_operation_confirm() { _rescan(); } +void FileSystemDock::_duplicate_operation_confirm() { + + String new_name = duplicate_dialog_text->get_text().strip_edges(); + if (new_name.length() == 0) { + EditorNode::get_singleton()->show_warning(TTR("No name provided.")); + return; + } else if (new_name.find("/") != -1 || new_name.find("\\") != -1 || new_name.find(":") != -1) { + EditorNode::get_singleton()->show_warning(TTR("Name contains invalid characters.")); + return; + } + + String old_path = to_duplicate.path.ends_with("/") ? to_duplicate.path.substr(0, to_duplicate.path.length() - 1) : to_rename.path; + String new_path = old_path.get_base_dir().plus_file(new_name); + if (old_path == new_path) { + return; + } + + //Present a more user friendly warning for name conflict + DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + if (da->file_exists(new_path) || da->dir_exists(new_path)) { + EditorNode::get_singleton()->show_warning(TTR("A file or folder with this name already exists.")); + memdelete(da); + return; + } + memdelete(da); + + _try_duplicate_item(to_duplicate, new_name); + + //Rescan everything + print_line("call rescan!"); + _rescan(); +} + void FileSystemDock::_move_operation_confirm(const String &p_to_path) { Map<String, String> renames; @@ -1003,6 +1069,27 @@ void FileSystemDock::_file_option(int p_option) { //2) warn } } break; + case FILE_DUPLICATE: { + int idx = files->get_current(); + if (idx < 0 || idx >= files->get_item_count()) + break; + + to_duplicate.path = files->get_item_metadata(idx); + to_duplicate.is_file = !to_duplicate.path.ends_with("/"); + if (to_duplicate.is_file) { + String name = to_duplicate.path.get_file(); + duplicate_dialog->set_title(TTR("Duplicating file:") + " " + name); + duplicate_dialog_text->set_text(name); + duplicate_dialog_text->select(0, name.find_last(".")); + } else { + String name = to_duplicate.path.substr(0, to_duplicate.path.length() - 1).get_file(); + duplicate_dialog->set_title(TTR("Duplicating folder:") + " " + name); + duplicate_dialog_text->set_text(name); + duplicate_dialog_text->select(0, name.length()); + } + duplicate_dialog->popup_centered_minsize(Size2(250, 80) * EDSCALE); + duplicate_dialog_text->grab_focus(); + } break; case FILE_INFO: { } break; @@ -1441,10 +1528,14 @@ void FileSystemDock::_files_list_rmb_select(int p_item, const Vector2 &p_pos) { if (!all_files_scenes && filenames.size() == 1) { file_options->add_item(TTR("Open"), FILE_OPEN); file_options->add_separator(); + } + + if (filenames.size() == 1) { file_options->add_item(TTR("Edit Dependencies.."), FILE_DEPENDENCIES); file_options->add_item(TTR("View Owners.."), FILE_OWNERS); file_options->add_separator(); } + } else if (all_folders && foldernames.size() > 0) { file_options->add_item(TTR("Open"), FILE_OPEN); file_options->add_separator(); @@ -1455,6 +1546,7 @@ void FileSystemDock::_files_list_rmb_select(int p_item, const Vector2 &p_pos) { if (num_items == 1) { file_options->add_item(TTR("Copy Path"), FILE_COPY_PATH); file_options->add_item(TTR("Rename.."), FILE_RENAME); + file_options->add_item(TTR("Duplicate.."), FILE_DUPLICATE); } file_options->add_item(TTR("Move To.."), FILE_MOVE); file_options->add_item(TTR("Delete"), FILE_REMOVE); @@ -1566,6 +1658,7 @@ void FileSystemDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_make_dir_confirm"), &FileSystemDock::_make_dir_confirm); ClassDB::bind_method(D_METHOD("_move_operation_confirm"), &FileSystemDock::_move_operation_confirm); ClassDB::bind_method(D_METHOD("_rename_operation_confirm"), &FileSystemDock::_rename_operation_confirm); + ClassDB::bind_method(D_METHOD("_duplicate_operation_confirm"), &FileSystemDock::_duplicate_operation_confirm); ClassDB::bind_method(D_METHOD("_search_changed"), &FileSystemDock::_search_changed); @@ -1739,6 +1832,17 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) { rename_dialog->register_text_enter(rename_dialog_text); rename_dialog->connect("confirmed", this, "_rename_operation_confirm"); + duplicate_dialog = memnew(ConfirmationDialog); + VBoxContainer *duplicate_dialog_vb = memnew(VBoxContainer); + duplicate_dialog->add_child(duplicate_dialog_vb); + + duplicate_dialog_text = memnew(LineEdit); + duplicate_dialog_vb->add_margin_child(TTR("Name:"), duplicate_dialog_text); + duplicate_dialog->get_ok()->set_text(TTR("Duplicate")); + add_child(duplicate_dialog); + duplicate_dialog->register_text_enter(duplicate_dialog_text); + duplicate_dialog->connect("confirmed", this, "_duplicate_operation_confirm"); + make_dir_dialog = memnew(ConfirmationDialog); make_dir_dialog->set_title(TTR("Create Folder")); VBoxContainer *make_folder_dialog_vb = memnew(VBoxContainer); diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index b004b1974d..bc8d835ba1 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -70,6 +70,7 @@ private: FILE_MOVE, FILE_RENAME, FILE_REMOVE, + FILE_DUPLICATE, FILE_REIMPORT, FILE_INFO, FILE_NEW_FOLDER, @@ -120,6 +121,8 @@ private: EditorDirDialog *move_dialog; ConfirmationDialog *rename_dialog; LineEdit *rename_dialog_text; + ConfirmationDialog *duplicate_dialog; + LineEdit *duplicate_dialog_text; ConfirmationDialog *make_dir_dialog; LineEdit *make_dir_dialog_text; @@ -136,6 +139,7 @@ private: is_file(p_is_file) {} }; FileOrFolder to_rename; + FileOrFolder to_duplicate; Vector<FileOrFolder> to_move; Vector<String> history; @@ -172,10 +176,12 @@ private: void _get_all_files_in_dir(EditorFileSystemDirectory *efsd, Vector<String> &files) const; void _find_remaps(EditorFileSystemDirectory *efsd, const Map<String, String> &renames, Vector<String> &to_remaps) const; void _try_move_item(const FileOrFolder &p_item, const String &p_new_path, Map<String, String> &p_renames) const; + void _try_duplicate_item(const FileOrFolder &p_item, const String &p_new_path) const; void _update_dependencies_after_move(const Map<String, String> &p_renames) const; void _make_dir_confirm(); void _rename_operation_confirm(); + void _duplicate_operation_confirm(); void _move_operation_confirm(const String &p_to_path); void _file_option(int p_option); diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index 4ef8ec48a0..08d2897250 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -47,8 +47,6 @@ #include "scene/resources/ray_shape.h" #include "scene/resources/sphere_shape.h" - - uint32_t EditorSceneImporter::get_import_flags() const { if (get_script_instance()) { @@ -60,80 +58,73 @@ uint32_t EditorSceneImporter::get_import_flags() const { void EditorSceneImporter::get_extensions(List<String> *r_extensions) const { if (get_script_instance()) { - Array arr= get_script_instance()->call("_get_extensions"); - for(int i=0;i<arr.size();i++) { + Array arr = get_script_instance()->call("_get_extensions"); + for (int i = 0; i < arr.size(); i++) { r_extensions->push_back(arr[i]); } return; } ERR_FAIL(); - } Node *EditorSceneImporter::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { if (get_script_instance()) { - return get_script_instance()->call("_import_scene",p_path,p_flags,p_bake_fps); + return get_script_instance()->call("_import_scene", p_path, p_flags, p_bake_fps); } ERR_FAIL_V(NULL); - } -Ref<Animation> EditorSceneImporter::import_animation(const String &p_path, uint32_t p_flags,int p_bake_fps) { +Ref<Animation> EditorSceneImporter::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) { if (get_script_instance()) { - return get_script_instance()->call("_import_animation",p_path,p_flags); + return get_script_instance()->call("_import_animation", p_path, p_flags); } ERR_FAIL_V(NULL); - } //for documenters, these functions are useful when an importer calls an external conversion helper (like, fbx2gltf), //and you want to load the resulting file -Node* EditorSceneImporter::import_scene_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps) { - - return ResourceImporterScene::get_singleton()->import_scene_from_other_importer(this,p_path,p_flags,p_bake_fps); +Node *EditorSceneImporter::import_scene_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps) { + return ResourceImporterScene::get_singleton()->import_scene_from_other_importer(this, p_path, p_flags, p_bake_fps); } Ref<Animation> EditorSceneImporter::import_animation_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps) { - return ResourceImporterScene::get_singleton()->import_animation_from_other_importer(this,p_path,p_flags,p_bake_fps); - + return ResourceImporterScene::get_singleton()->import_animation_from_other_importer(this, p_path, p_flags, p_bake_fps); } void EditorSceneImporter::_bind_methods() { - ClassDB::bind_method(D_METHOD("import_scene_from_other_importer","path","flags","bake_fps"),&EditorSceneImporter::import_scene_from_other_importer); - ClassDB::bind_method(D_METHOD("import_animation_from_other_importer","path","flags","bake_fps"),&EditorSceneImporter::import_animation_from_other_importer); + ClassDB::bind_method(D_METHOD("import_scene_from_other_importer", "path", "flags", "bake_fps"), &EditorSceneImporter::import_scene_from_other_importer); + ClassDB::bind_method(D_METHOD("import_animation_from_other_importer", "path", "flags", "bake_fps"), &EditorSceneImporter::import_animation_from_other_importer); BIND_VMETHOD(MethodInfo(Variant::INT, "_get_import_flags")); BIND_VMETHOD(MethodInfo(Variant::ARRAY, "_get_extensions")); - MethodInfo mi = MethodInfo(Variant::OBJECT, "_import_scene",PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "flags"), PropertyInfo(Variant::INT, "bake_fps")); - mi.return_val.class_name="Node"; + MethodInfo mi = MethodInfo(Variant::OBJECT, "_import_scene", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "flags"), PropertyInfo(Variant::INT, "bake_fps")); + mi.return_val.class_name = "Node"; BIND_VMETHOD(mi); - mi = MethodInfo(Variant::OBJECT, "_import_animation",PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "flags"), PropertyInfo(Variant::INT, "bake_fps")); - mi.return_val.class_name="Animation"; + mi = MethodInfo(Variant::OBJECT, "_import_animation", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "flags"), PropertyInfo(Variant::INT, "bake_fps")); + mi.return_val.class_name = "Animation"; BIND_VMETHOD(mi); - BIND_CONSTANT( IMPORT_SCENE ); - BIND_CONSTANT( IMPORT_ANIMATION ); - BIND_CONSTANT( IMPORT_ANIMATION_DETECT_LOOP ); - BIND_CONSTANT( IMPORT_ANIMATION_OPTIMIZE ); - BIND_CONSTANT( IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS ); - BIND_CONSTANT( IMPORT_ANIMATION_KEEP_VALUE_TRACKS ); - BIND_CONSTANT( IMPORT_GENERATE_TANGENT_ARRAYS ); - BIND_CONSTANT( IMPORT_FAIL_ON_MISSING_DEPENDENCIES ); - BIND_CONSTANT( IMPORT_MATERIALS_IN_INSTANCES ); - BIND_CONSTANT( IMPORT_USE_COMPRESSION ); - + BIND_CONSTANT(IMPORT_SCENE); + BIND_CONSTANT(IMPORT_ANIMATION); + BIND_CONSTANT(IMPORT_ANIMATION_DETECT_LOOP); + BIND_CONSTANT(IMPORT_ANIMATION_OPTIMIZE); + BIND_CONSTANT(IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS); + BIND_CONSTANT(IMPORT_ANIMATION_KEEP_VALUE_TRACKS); + BIND_CONSTANT(IMPORT_GENERATE_TANGENT_ARRAYS); + BIND_CONSTANT(IMPORT_FAIL_ON_MISSING_DEPENDENCIES); + BIND_CONSTANT(IMPORT_MATERIALS_IN_INSTANCES); + BIND_CONSTANT(IMPORT_USE_COMPRESSION); } - ///////////////////////////////// void EditorScenePostImport::_bind_methods() { @@ -201,6 +192,10 @@ bool ResourceImporterScene::get_option_visibility(const String &p_option, const return false; } + if (p_option == "meshes/lightmap_texel_size" && int(p_options["meshes/light_baking"]) < 2) { + return false; + } + return true; } @@ -961,6 +956,36 @@ static String _make_extname(const String &p_str) { return ext_name; } +void ResourceImporterScene::_find_meshes(Node *p_node, Map<Ref<ArrayMesh>, Transform> &meshes) { + + List<PropertyInfo> pi; + p_node->get_property_list(&pi); + + MeshInstance *mi = Object::cast_to<MeshInstance>(p_node); + + if (mi) { + + Ref<ArrayMesh> mesh = mi->get_mesh(); + + if (mesh.is_valid() && !meshes.has(mesh)) { + Spatial *s = mi; + while (s->get_parent_spatial()) { + s = s->get_parent_spatial(); + } + + if (s == mi) { + meshes[mesh] = s->get_transform(); + } else { + meshes[mesh] = s->get_transform() * mi->get_relative_transform(s); + } + } + } + for (int i = 0; i < p_node->get_child_count(); i++) { + + _find_meshes(p_node->get_child(i), meshes); + } +} + void ResourceImporterScene::_make_external_resources(Node *p_node, const String &p_base_path, bool p_make_animations, bool p_keep_animations, bool p_make_materials, bool p_keep_materials, bool p_make_meshes, Map<Ref<Animation>, Ref<Animation> > &p_animations, Map<Ref<Material>, Ref<Material> > &p_materials, Map<Ref<ArrayMesh>, Ref<ArrayMesh> > &p_meshes) { List<PropertyInfo> pi; @@ -1140,7 +1165,8 @@ void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, in r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/compress"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/ensure_tangents"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/storage", PROPERTY_HINT_ENUM, "Built-In,Files"), meshes_out ? 1 : 0)); - r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/light_baking", PROPERTY_HINT_ENUM, "Disabled,Enable"), 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/light_baking", PROPERTY_HINT_ENUM, "Disabled,Enable,Gen Lightmaps"), 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "meshes/lightmap_texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.05)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "external_files/store_in_subdir"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 15)); @@ -1171,17 +1197,16 @@ void ResourceImporterScene::_replace_owner(Node *p_node, Node *p_scene, Node *p_ Node *n = p_node->get_child(i); _replace_owner(n, p_scene, p_new_owner); } - } -Node* ResourceImporterScene::import_scene_from_other_importer(EditorSceneImporter *p_exception,const String &p_path, uint32_t p_flags, int p_bake_fps) { +Node *ResourceImporterScene::import_scene_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps) { Ref<EditorSceneImporter> importer; String ext = p_path.get_extension().to_lower(); for (Set<Ref<EditorSceneImporter> >::Element *E = importers.front(); E; E = E->next()) { - if (E->get().ptr()==p_exception) + if (E->get().ptr() == p_exception) continue; List<String> extensions; E->get()->get_extensions(&extensions); @@ -1199,42 +1224,41 @@ Node* ResourceImporterScene::import_scene_from_other_importer(EditorSceneImporte break; } - ERR_FAIL_COND_V(!importer.is_valid(),NULL); + ERR_FAIL_COND_V(!importer.is_valid(), NULL); List<String> missing; Error err; - return importer->import_scene(p_path,p_flags,p_bake_fps,&missing,&err); + return importer->import_scene(p_path, p_flags, p_bake_fps, &missing, &err); } -Ref<Animation> ResourceImporterScene::import_animation_from_other_importer(EditorSceneImporter *p_exception,const String &p_path, uint32_t p_flags, int p_bake_fps) { - +Ref<Animation> ResourceImporterScene::import_animation_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps) { - Ref<EditorSceneImporter> importer; - String ext = p_path.get_extension().to_lower(); + Ref<EditorSceneImporter> importer; + String ext = p_path.get_extension().to_lower(); - for (Set<Ref<EditorSceneImporter> >::Element *E = importers.front(); E; E = E->next()) { + for (Set<Ref<EditorSceneImporter> >::Element *E = importers.front(); E; E = E->next()) { - if (E->get().ptr()==p_exception) - continue; - List<String> extensions; - E->get()->get_extensions(&extensions); + if (E->get().ptr() == p_exception) + continue; + List<String> extensions; + E->get()->get_extensions(&extensions); - for (List<String>::Element *F = extensions.front(); F; F = F->next()) { + for (List<String>::Element *F = extensions.front(); F; F = F->next()) { - if (F->get().to_lower() == ext) { + if (F->get().to_lower() == ext) { - importer = E->get(); - break; - } - } + importer = E->get(); + break; + } + } - if (importer.is_valid()) - break; - } + if (importer.is_valid()) + break; + } - ERR_FAIL_COND_V(!importer.is_valid(),NULL); + ERR_FAIL_COND_V(!importer.is_valid(), NULL); - return importer->import_animation(p_path,p_flags,p_bake_fps); + return importer->import_animation(p_path, p_flags, p_bake_fps); } Error ResourceImporterScene::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files) { @@ -1371,6 +1395,37 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p } } + if (light_bake_mode == 2 /* || generate LOD */) { + + Map<Ref<ArrayMesh>, Transform> meshes; + _find_meshes(scene, meshes); + + if (light_bake_mode == 2) { + + float texel_size = p_options["meshes/lightmap_texel_size"]; + texel_size = MAX(0.001, texel_size); + + EditorProgress progress("gen_lightmaps", TTR("Generating Lightmaps"), meshes.size()); + int step = 0; + for (Map<Ref<ArrayMesh>, Transform>::Element *E = meshes.front(); E; E = E->next()) { + + Ref<ArrayMesh> mesh = E->key(); + String name = mesh->get_name(); + if (name == "") { //should not happen but.. + name = "Mesh " + itos(step); + } + + progress.step(TTR("Generating for Mesh: ") + name + " (" + itos(step) + "/" + itos(meshes.size()) + ")", step); + + Error err = mesh->lightmap_unwrap(E->get(), texel_size); + if (err != OK) { + EditorNode::add_io_error("Mesh '" + name + "' failed lightmap generation. Please fix geometry."); + } + step++; + } + } + } + if (external_animations || external_materials || external_meshes) { Map<Ref<Animation>, Ref<Animation> > anim_map; Map<Ref<Material>, Ref<Material> > mat_map; diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h index fc6ce05fa4..933585a48c 100644 --- a/editor/import/resource_importer_scene.h +++ b/editor/import/resource_importer_scene.h @@ -40,13 +40,13 @@ class Material; class EditorSceneImporter : public Reference { GDCLASS(EditorSceneImporter, Reference); -protected: +protected: static void _bind_methods(); - - Node* import_scene_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps); + Node *import_scene_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps); Ref<Animation> import_animation_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps); + public: enum ImportFlags { IMPORT_SCENE = 1, @@ -62,11 +62,10 @@ public: }; - virtual uint32_t get_import_flags() const; virtual void get_extensions(List<String> *r_extensions) const; virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = NULL); - virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags,int p_bake_fps); + virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps); EditorSceneImporter() {} }; @@ -136,6 +135,8 @@ public: virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const; virtual int get_import_order() const { return 100; } //after everything + void _find_meshes(Node *p_node, Map<Ref<ArrayMesh>, Transform> &meshes); + void _make_external_resources(Node *p_node, const String &p_base_path, bool p_make_animations, bool p_keep_animations, bool p_make_materials, bool p_keep_materials, bool p_make_meshes, Map<Ref<Animation>, Ref<Animation> > &p_animations, Map<Ref<Material>, Ref<Material> > &p_materials, Map<Ref<ArrayMesh>, Ref<ArrayMesh> > &p_meshes); Node *_fix_node(Node *p_node, Node *p_root, Map<Ref<ArrayMesh>, Ref<Shape> > &collision_map, LightBakeMode p_light_bake_mode); @@ -147,8 +148,8 @@ public: virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL); - Node* import_scene_from_other_importer(EditorSceneImporter *p_exception,const String &p_path, uint32_t p_flags, int p_bake_fps); - Ref<Animation> import_animation_from_other_importer(EditorSceneImporter *p_exception,const String &p_path, uint32_t p_flags, int p_bake_fps); + Node *import_scene_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps); + Ref<Animation> import_animation_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps); ResourceImporterScene(); }; diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index eee54f3cd2..3ab8f318a7 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -915,6 +915,11 @@ void EditorAssetLibrary::_search(int p_page) { _api_request("asset", REQUESTING_SEARCH, args); } +void EditorAssetLibrary::_search_text_entered(const String &p_text) { + + _search(); +} + HBoxContainer *EditorAssetLibrary::_make_pages(int p_page, int p_page_count, int p_page_len, int p_total_items, int p_current_items) { HBoxContainer *hbc = memnew(HBoxContainer); @@ -1280,6 +1285,7 @@ void EditorAssetLibrary::_bind_methods() { ClassDB::bind_method("_select_category", &EditorAssetLibrary::_select_category); ClassDB::bind_method("_image_request_completed", &EditorAssetLibrary::_image_request_completed); ClassDB::bind_method("_search", &EditorAssetLibrary::_search, DEFVAL(0)); + ClassDB::bind_method("_search_text_entered", &EditorAssetLibrary::_search_text_entered); ClassDB::bind_method("_install_asset", &EditorAssetLibrary::_install_asset); ClassDB::bind_method("_manage_plugins", &EditorAssetLibrary::_manage_plugins); ClassDB::bind_method("_asset_open", &EditorAssetLibrary::_asset_open); @@ -1309,7 +1315,7 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { filter = memnew(LineEdit); search_hb->add_child(filter); filter->set_h_size_flags(SIZE_EXPAND_FILL); - filter->connect("text_entered", this, "_search"); + filter->connect("text_entered", this, "_search_text_entered"); search = memnew(Button(TTR("Search"))); search->connect("pressed", this, "_search"); search_hb->add_child(search); diff --git a/editor/plugins/asset_library_editor_plugin.h b/editor/plugins/asset_library_editor_plugin.h index 90d597e70a..5536fbb2ec 100644 --- a/editor/plugins/asset_library_editor_plugin.h +++ b/editor/plugins/asset_library_editor_plugin.h @@ -284,6 +284,7 @@ class EditorAssetLibrary : public PanelContainer { void _search(int p_page = 0); void _rerun_search(int p_ignore); + void _search_text_entered(const String &p_text = ""); void _api_request(const String &p_request, RequestType p_request_type, const String &p_arguments = ""); void _http_request_completed(int p_status, int p_code, const PoolStringArray &headers, const PoolByteArray &p_data); void _http_download_completed(int p_status, int p_code, const PoolStringArray &headers, const PoolByteArray &p_data); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 8eee9c7e7c..150c184e90 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -4342,6 +4342,9 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { drag = DRAG_NONE; bone_last_frame = 0; additive_selection = false; + + // Update the menus checkboxes + call_deferred("set_state", get_state()); } CanvasItemEditor *CanvasItemEditor::singleton = NULL; @@ -4486,15 +4489,24 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String & Ref<Texture> texture = Ref<Texture>(Object::cast_to<Texture>(ResourceCache::get(path))); Size2 texture_size = texture->get_size(); - editor_data->get_undo_redo().add_do_method(parent, "add_child", child); - editor_data->get_undo_redo().add_do_method(child, "set_owner", editor->get_edited_scene()); - editor_data->get_undo_redo().add_do_reference(child); - editor_data->get_undo_redo().add_undo_method(parent, "remove_child", child); + if (parent) { + editor_data->get_undo_redo().add_do_method(parent, "add_child", child); + editor_data->get_undo_redo().add_do_method(child, "set_owner", editor->get_edited_scene()); + editor_data->get_undo_redo().add_do_reference(child); + editor_data->get_undo_redo().add_undo_method(parent, "remove_child", child); + } else { // if we haven't parent, lets try to make a child as a parent. + editor_data->get_undo_redo().add_do_method(editor, "set_edited_scene", child); + editor_data->get_undo_redo().add_do_method(child, "set_owner", editor->get_edited_scene()); + editor_data->get_undo_redo().add_do_reference(child); + editor_data->get_undo_redo().add_undo_method(editor, "set_edited_scene", (Object *)NULL); + } - String new_name = parent->validate_child_name(child); - ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger(); - editor_data->get_undo_redo().add_do_method(sed, "live_debug_create_node", editor->get_edited_scene()->get_path_to(parent), child->get_class(), new_name); - editor_data->get_undo_redo().add_undo_method(sed, "live_debug_remove_node", NodePath(String(editor->get_edited_scene()->get_path_to(parent)) + "/" + new_name)); + if (parent) { + String new_name = parent->validate_child_name(child); + ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger(); + editor_data->get_undo_redo().add_do_method(sed, "live_debug_create_node", editor->get_edited_scene()->get_path_to(parent), child->get_class(), new_name); + editor_data->get_undo_redo().add_undo_method(sed, "live_debug_remove_node", NodePath(String(editor->get_edited_scene()->get_path_to(parent)) + "/" + new_name)); + } // handle with different property for texture String property = "texture"; @@ -4527,8 +4539,8 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String & } // locate at preview position - Point2 pos; - if (parent->has_method("get_global_position")) { + Point2 pos = Point2(0, 0); + if (parent && parent->has_method("get_global_position")) { pos = parent->call("get_global_position"); } Transform2D trans = canvas->get_canvas_transform(); @@ -4689,6 +4701,18 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian return false; } +void CanvasItemEditorViewport::_show_resource_type_selector() { + List<BaseButton *> btn_list; + button_group->get_buttons(&btn_list); + + for (int i = 0; i < btn_list.size(); i++) { + CheckBox *check = Object::cast_to<CheckBox>(btn_list[i]); + check->set_pressed(check->get_text() == default_type); + } + selector->set_title(vformat(TTR("Add %s"), default_type)); + selector->popup_centered_minsize(); +} + void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p_data) { bool is_shift = Input::get_singleton()->is_key_pressed(KEY_SHIFT); bool is_alt = Input::get_singleton()->is_key_pressed(KEY_ALT); @@ -4705,10 +4729,8 @@ void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p if (root_node) { list.push_back(root_node); } else { - accept->get_ok()->set_text(TTR("OK :(")); - accept->set_text(TTR("No parent to instance a child at.")); - accept->popup_centered_minsize(); - _remove_preview(); + drop_pos = p_point; + _show_resource_type_selector(); return; } } @@ -4727,15 +4749,7 @@ void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p drop_pos = p_point; if (is_alt) { - List<BaseButton *> btn_list; - button_group->get_buttons(&btn_list); - - for (int i = 0; i < btn_list.size(); i++) { - CheckBox *check = Object::cast_to<CheckBox>(btn_list[i]); - check->set_pressed(check->get_text() == default_type); - } - selector->set_title(vformat(TTR("Add %s"), default_type)); - selector->popup_centered_minsize(); + _show_resource_type_selector(); } else { _perform_drop_data(); } diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index 457833e1a7..4be09a16e9 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -578,6 +578,7 @@ class CanvasItemEditorViewport : public Control { void _create_nodes(Node *parent, Node *child, String &path, const Point2 &p_point); bool _create_instance(Node *parent, String &path, const Point2 &p_point); void _perform_drop_data(); + void _show_resource_type_selector(); static void _bind_methods(); diff --git a/editor/plugins/mesh_instance_editor_plugin.cpp b/editor/plugins/mesh_instance_editor_plugin.cpp index 84fc0cecf2..9d116349c0 100644 --- a/editor/plugins/mesh_instance_editor_plugin.cpp +++ b/editor/plugins/mesh_instance_editor_plugin.cpp @@ -195,7 +195,139 @@ void MeshInstanceEditor::_menu_option(int p_option) { outline_dialog->popup_centered(Vector2(200, 90)); } break; + case MENU_OPTION_CREATE_UV2: { + + Ref<ArrayMesh> mesh = node->get_mesh(); + if (!mesh.is_valid()) { + err_dialog->set_text(TTR("Contained Mesh is not of type ArrayMesh.")); + err_dialog->popup_centered_minsize(); + return; + } + + Error err = mesh->lightmap_unwrap(node->get_global_transform()); + if (err != OK) { + err_dialog->set_text(TTR("UV Unwrap failed, mesh may not be manifold?")); + err_dialog->popup_centered_minsize(); + return; + } + + } break; + case MENU_OPTION_DEBUG_UV1: { + Ref<Mesh> mesh = node->get_mesh(); + if (!mesh.is_valid()) { + err_dialog->set_text(TTR("No mesh to debug.")); + err_dialog->popup_centered_minsize(); + return; + } + _create_uv_lines(0); + } break; + case MENU_OPTION_DEBUG_UV2: { + Ref<Mesh> mesh = node->get_mesh(); + if (!mesh.is_valid()) { + err_dialog->set_text(TTR("No mesh to debug.")); + err_dialog->popup_centered_minsize(); + return; + } + _create_uv_lines(1); + } break; + } +} + +struct MeshInstanceEditorEdgeSort { + + Vector2 a; + Vector2 b; + + bool operator<(const MeshInstanceEditorEdgeSort &p_b) const { + if (a == p_b.a) + return b < p_b.b; + else + return a < p_b.a; + } + + MeshInstanceEditorEdgeSort() {} + MeshInstanceEditorEdgeSort(const Vector2 &p_a, const Vector2 &p_b) { + if (p_a < p_b) { + a = p_a; + b = p_b; + } else { + b = p_a; + a = p_b; + } + } +}; + +void MeshInstanceEditor::_create_uv_lines(int p_layer) { + + Ref<Mesh> mesh = node->get_mesh(); + ERR_FAIL_COND(!mesh.is_valid()); + + Set<MeshInstanceEditorEdgeSort> edges; + uv_lines.clear(); + for (int i = 0; i < mesh->get_surface_count(); i++) { + if (mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) + continue; + Array a = mesh->surface_get_arrays(i); + + PoolVector<Vector2> uv = a[p_layer == 0 ? Mesh::ARRAY_TEX_UV : Mesh::ARRAY_TEX_UV2]; + if (uv.size() == 0) { + err_dialog->set_text(TTR("Model has no UV in this layer")); + err_dialog->popup_centered_minsize(); + return; + } + + PoolVector<Vector2>::Read r = uv.read(); + + PoolVector<int> indices = a[Mesh::ARRAY_INDEX]; + PoolVector<int>::Read ri; + + int ic; + bool use_indices; + + if (indices.size()) { + ic = indices.size(); + ri = indices.read(); + use_indices = true; + } else { + ic = uv.size(); + use_indices = false; + } + + for (int j = 0; j < ic; j += 3) { + + for (int k = 0; k < 3; k++) { + + MeshInstanceEditorEdgeSort edge; + if (use_indices) { + edge.a = r[ri[j + k]]; + edge.b = r[ri[j + ((k + 1) % 3)]]; + } else { + edge.a = r[j + k]; + edge.b = r[j + ((k + 1) % 3)]; + } + + if (edges.has(edge)) + continue; + + uv_lines.push_back(edge.a); + uv_lines.push_back(edge.b); + edges.insert(edge); + } + } } + + debug_uv_dialog->popup_centered_minsize(); +} + +void MeshInstanceEditor::_debug_uv_draw() { + + if (uv_lines.size() == 0) + return; + + debug_uv->set_clip_contents(true); + debug_uv->draw_rect(Rect2(Vector2(), debug_uv->get_size()), Color(0.2, 0.2, 0.0)); + debug_uv->draw_set_transform(Vector2(), 0, debug_uv->get_size()); + debug_uv->draw_multiline(uv_lines, Color(1.0, 0.8, 0.7)); } void MeshInstanceEditor::_create_outline_mesh() { @@ -244,6 +376,7 @@ void MeshInstanceEditor::_bind_methods() { ClassDB::bind_method("_menu_option", &MeshInstanceEditor::_menu_option); ClassDB::bind_method("_create_outline_mesh", &MeshInstanceEditor::_create_outline_mesh); + ClassDB::bind_method("_debug_uv_draw", &MeshInstanceEditor::_debug_uv_draw); } MeshInstanceEditor::MeshInstanceEditor() { @@ -263,6 +396,10 @@ MeshInstanceEditor::MeshInstanceEditor() { options->get_popup()->add_item(TTR("Create Navigation Mesh"), MENU_OPTION_CREATE_NAVMESH); options->get_popup()->add_separator(); options->get_popup()->add_item(TTR("Create Outline Mesh.."), MENU_OPTION_CREATE_OUTLINE_MESH); + options->get_popup()->add_separator(); + options->get_popup()->add_item(TTR("View UV1"), MENU_OPTION_DEBUG_UV1); + options->get_popup()->add_item(TTR("View UV2"), MENU_OPTION_DEBUG_UV2); + options->get_popup()->add_item(TTR("Unwrap UV2 for Lightmap/AO"), MENU_OPTION_CREATE_UV2); options->get_popup()->connect("id_pressed", this, "_menu_option"); @@ -286,6 +423,14 @@ MeshInstanceEditor::MeshInstanceEditor() { err_dialog = memnew(AcceptDialog); add_child(err_dialog); + + debug_uv_dialog = memnew(AcceptDialog); + debug_uv_dialog->set_title("UV Channel Debug"); + add_child(debug_uv_dialog); + debug_uv = memnew(Control); + debug_uv->set_custom_minimum_size(Size2(600, 600) * EDSCALE); + debug_uv->connect("draw", this, "_debug_uv_draw"); + debug_uv_dialog->add_child(debug_uv); } void MeshInstanceEditorPlugin::edit(Object *p_object) { diff --git a/editor/plugins/mesh_instance_editor_plugin.h b/editor/plugins/mesh_instance_editor_plugin.h index fa851458ce..68c149f98a 100644 --- a/editor/plugins/mesh_instance_editor_plugin.h +++ b/editor/plugins/mesh_instance_editor_plugin.h @@ -47,6 +47,9 @@ class MeshInstanceEditor : public Node { MENU_OPTION_CREATE_CONVEX_COLLISION_SHAPE, MENU_OPTION_CREATE_NAVMESH, MENU_OPTION_CREATE_OUTLINE_MESH, + MENU_OPTION_CREATE_UV2, + MENU_OPTION_DEBUG_UV1, + MENU_OPTION_DEBUG_UV2, }; MeshInstance *node; @@ -58,11 +61,18 @@ class MeshInstanceEditor : public Node { AcceptDialog *err_dialog; + AcceptDialog *debug_uv_dialog; + Control *debug_uv; + Vector<Vector2> uv_lines; + void _menu_option(int p_option); void _create_outline_mesh(); + void _create_uv_lines(int p_layer); friend class MeshInstanceEditorPlugin; + void _debug_uv_draw(); + protected: void _node_removed(Node *p_node); static void _bind_methods(); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 6a869aaadb..95f2739927 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -1015,14 +1015,9 @@ void ScriptTextEditor::_edit_option(int p_op) { tx->end_complex_operation(); tx->update(); } break; - case EDIT_FOLD_LINE: { + case EDIT_TOGGLE_FOLD_LINE: { - tx->fold_line(tx->cursor_get_line()); - tx->update(); - } break; - case EDIT_UNFOLD_LINE: { - - tx->unfold_line(tx->cursor_get_line()); + tx->toggle_fold_line(tx->cursor_get_line()); tx->update(); } break; case EDIT_FOLD_ALL_LINES: { @@ -1517,13 +1512,9 @@ void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_right"), EDIT_INDENT_RIGHT); context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT); } - if (p_can_fold) { - // can fold - context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_line"), EDIT_FOLD_LINE); - } else if (p_is_folded) { - // can unfold - context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_line"), EDIT_UNFOLD_LINE); - } + if (p_can_fold || p_is_folded) + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE); + if (p_color) { context_menu->add_separator(); context_menu->add_item(TTR("Pick Color"), EDIT_PICK_COLOR); @@ -1587,9 +1578,8 @@ ScriptTextEditor::ScriptTextEditor() { edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/delete_line"), EDIT_DELETE_LINE); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/clone_down"), EDIT_CLONE_DOWN); - edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_line"), EDIT_FOLD_LINE); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_all_lines"), EDIT_FOLD_ALL_LINES); - edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_line"), EDIT_UNFOLD_LINE); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_all_lines"), EDIT_UNFOLD_ALL_LINES); edit_menu->get_popup()->add_separator(); #ifdef OSX_ENABLED @@ -1668,8 +1658,7 @@ void ScriptTextEditor::register_editor() { ED_SHORTCUT("script_text_editor/indent_right", TTR("Indent Right"), 0); ED_SHORTCUT("script_text_editor/toggle_comment", TTR("Toggle Comment"), KEY_MASK_CMD | KEY_K); ED_SHORTCUT("script_text_editor/clone_down", TTR("Clone Down"), KEY_MASK_CMD | KEY_B); - ED_SHORTCUT("script_text_editor/fold_line", TTR("Fold Line"), KEY_MASK_ALT | KEY_LEFT); - ED_SHORTCUT("script_text_editor/unfold_line", TTR("Unfold Line"), KEY_MASK_ALT | KEY_RIGHT); + ED_SHORTCUT("script_text_editor/toggle_fold_line", TTR("Fold/Unfold Line"), KEY_MASK_ALT | KEY_F); ED_SHORTCUT("script_text_editor/fold_all_lines", TTR("Fold All Lines"), 0); ED_SHORTCUT("script_text_editor/unfold_all_lines", TTR("Unfold All Lines"), 0); #ifdef OSX_ENABLED diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index 722015ef3e..e3b81e7c3f 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -91,8 +91,7 @@ class ScriptTextEditor : public ScriptEditorBase { EDIT_TO_UPPERCASE, EDIT_TO_LOWERCASE, EDIT_CAPITALIZE, - EDIT_FOLD_LINE, - EDIT_UNFOLD_LINE, + EDIT_TOGGLE_FOLD_LINE, EDIT_FOLD_ALL_LINES, EDIT_UNFOLD_ALL_LINES, SEARCH_FIND, diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index eb2faa1ab1..b8c57fd959 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -343,7 +343,7 @@ AutotileEditor::AutotileEditor(EditorNode *p_editor) { split->add_child(property_editor); helper = memnew(AutotileEditorHelper(this)); - property_editor->edit(helper); + property_editor->call_deferred("edit", helper); // Editor diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp index eed1efaf9c..1d709b250a 100644 --- a/editor/property_editor.cpp +++ b/editor/property_editor.cpp @@ -430,24 +430,19 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: } else if (hint == PROPERTY_HINT_LAYERS_2D_PHYSICS || hint == PROPERTY_HINT_LAYERS_2D_RENDER || hint == PROPERTY_HINT_LAYERS_3D_PHYSICS || hint == PROPERTY_HINT_LAYERS_3D_RENDER) { - String title; String basename; switch (hint) { case PROPERTY_HINT_LAYERS_2D_RENDER: basename = "layer_names/2d_render"; - title = "2D Render Layers"; break; case PROPERTY_HINT_LAYERS_2D_PHYSICS: basename = "layer_names/2d_physics"; - title = "2D Physics Layers"; break; case PROPERTY_HINT_LAYERS_3D_RENDER: basename = "layer_names/3d_render"; - title = "3D Render Layers"; break; case PROPERTY_HINT_LAYERS_3D_PHYSICS: basename = "layer_names/3d_physics"; - title = "3D Physics Layers"; break; } @@ -469,11 +464,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: show(); - value_label[0]->set_text(title); - value_label[0]->show(); - value_label[0]->set_position(Vector2(4, 4) * EDSCALE); - - checks20gc->set_position(Vector2(4, 4) * EDSCALE + Vector2(0, value_label[0]->get_size().height + 4 * EDSCALE)); + checks20gc->set_position(Vector2(4, 4) * EDSCALE); checks20gc->set_size(checks20gc->get_minimum_size()); set_size(Vector2(4, 4) * EDSCALE + checks20gc->get_position() + checks20gc->get_size()); @@ -656,7 +647,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: } } - if (type) + if (type != Variant::NIL) property_select->select_property_from_basic_type(type, v); updating = false; @@ -2811,13 +2802,12 @@ void PropertyEditor::update_tree() { TreeItem *sep = tree->create_item(root); current_category = sep; String type = p.name; - //* + if (has_icon(type, "EditorIcons")) sep->set_icon(0, get_icon(type, "EditorIcons")); else sep->set_icon(0, get_icon("Object", "EditorIcons")); - //*/ sep->set_text(0, type); sep->set_expand_right(0, true); sep->set_selectable(0, false); @@ -2943,38 +2933,36 @@ void PropertyEditor::update_tree() { } if (use_doc_hints) { - StringName setter; - StringName type; - if (ClassDB::get_setter_and_type_for_property(obj->get_class_name(), p.name, type, setter)) { - String descr; - bool found = false; - Map<StringName, Map<StringName, String> >::Element *E = descr_cache.find(type); - if (E) { + StringName classname = obj->get_class_name(); + StringName propname = p.name; + String descr; + bool found = false; - Map<StringName, String>::Element *F = E->get().find(setter); - if (F) { - found = true; - descr = F->get(); - } + Map<StringName, Map<StringName, String> >::Element *E = descr_cache.find(classname); + if (E) { + Map<StringName, String>::Element *F = E->get().find(propname); + if (F) { + found = true; + descr = F->get(); } - if (!found) { + } - DocData *dd = EditorHelp::get_doc_data(); - Map<String, DocData::ClassDoc>::Element *E = dd->class_list.find(type); - if (E) { - for (int i = 0; i < E->get().methods.size(); i++) { - if (E->get().methods[i].name == setter.operator String()) { - descr = E->get().methods[i].description.strip_edges().word_wrap(80); - } + if (!found) { + DocData *dd = EditorHelp::get_doc_data(); + Map<String, DocData::ClassDoc>::Element *E = dd->class_list.find(classname); + if (E) { + for (int i = 0; i < E->get().properties.size(); i++) { + if (E->get().properties[i].name == propname.operator String()) { + descr = E->get().properties[i].description.strip_edges().word_wrap(80); } } - - descr_cache[type][setter] = descr; } - item->set_tooltip(0, TTR("Property:") + " " + p.name + "\n\n" + descr); + descr_cache[classname][propname] = descr; } + + item->set_tooltip(0, TTR("Property:") + " " + p.name + "\n\n" + descr); } Dictionary d; diff --git a/editor/property_selector.cpp b/editor/property_selector.cpp index 86de7c56e1..77b73e4635 100644 --- a/editor/property_selector.cpp +++ b/editor/property_selector.cpp @@ -363,23 +363,6 @@ void PropertySelector::_item_selected() { at_class = ClassDB::get_parent_class(at_class); } - - if (text == String()) { - - StringName setter; - StringName type; - if (ClassDB::get_setter_and_type_for_property(class_type, name, type, setter)) { - Map<String, DocData::ClassDoc>::Element *E = dd->class_list.find(type); - if (E) { - for (int i = 0; i < E->get().methods.size(); i++) { - if (E->get().methods[i].name == setter.operator String()) { - text = E->get().methods[i].description; - } - } - } - } - } - } else { String at_class = class_type; @@ -516,6 +499,7 @@ void PropertySelector::select_property_from_script(const Ref<Script> &p_script, search_box->grab_focus(); _update_search(); } + void PropertySelector::select_property_from_basic_type(Variant::Type p_type, const String &p_current) { ERR_FAIL_COND(p_type == Variant::NIL); |