diff options
Diffstat (limited to 'editor')
-rw-r--r-- | editor/editor_plugin.cpp | 2 | ||||
-rw-r--r-- | editor/editor_themes.cpp | 10 | ||||
-rw-r--r-- | editor/import/editor_import_plugin.cpp | 2 | ||||
-rw-r--r-- | editor/import/resource_importer_obj.cpp | 8 | ||||
-rw-r--r-- | editor/plugins/animation_blend_tree_editor_plugin.cpp | 1 | ||||
-rw-r--r-- | editor/plugins/animation_state_machine_editor.cpp | 4 | ||||
-rw-r--r-- | editor/plugins/tile_map_editor_plugin.cpp | 2 | ||||
-rw-r--r-- | editor/plugins/tile_set_editor_plugin.cpp | 681 | ||||
-rw-r--r-- | editor/plugins/tile_set_editor_plugin.h | 11 |
9 files changed, 466 insertions, 255 deletions
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index 403db4b8ba..ff8cce8057 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -273,7 +273,7 @@ void EditorInterface::_bind_methods() { ClassDB::bind_method(D_METHOD("get_resource_filesystem"), &EditorInterface::get_resource_file_system); ClassDB::bind_method(D_METHOD("get_editor_viewport"), &EditorInterface::get_editor_viewport); ClassDB::bind_method(D_METHOD("make_mesh_previews", "meshes", "preview_size"), &EditorInterface::_make_mesh_previews); - ClassDB::bind_method(D_METHOD("select_file", "p_file"), &EditorInterface::select_file); + ClassDB::bind_method(D_METHOD("select_file", "file"), &EditorInterface::select_file); ClassDB::bind_method(D_METHOD("get_selected_path"), &EditorInterface::get_selected_path); ClassDB::bind_method(D_METHOD("set_plugin_enabled", "plugin", "enabled"), &EditorInterface::set_plugin_enabled); diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index eacf2ee1b4..8a2206d06c 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -994,6 +994,14 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { graphsbposition->set_draw_center(false); graphsbposition->set_border_color_all(error_color); graphsbposition->set_shadow_color(error_color * Color(1.0, 1.0, 1.0, 0.2)); + Ref<StyleBoxFlat> smgraphsb = make_flat_stylebox(Color(mv, mv, mv, 0.7), gn_margin_side, 24, gn_margin_side, 5); + smgraphsb->set_border_width_all(border_width); + smgraphsb->set_border_color_all(Color(mv2, mv2, mv2, 0.9)); + Ref<StyleBoxFlat> smgraphsbselected = make_flat_stylebox(Color(mv, mv, mv, 0.9), gn_margin_side, 24, gn_margin_side, 5); + smgraphsbselected->set_border_width_all(border_width); + smgraphsbselected->set_border_color_all(Color(accent_color.r, accent_color.g, accent_color.b, 0.9)); + smgraphsbselected->set_shadow_size(8 * EDSCALE); + smgraphsbselected->set_shadow_color(shadow_color); if (use_gn_headers) { graphsb->set_border_width(MARGIN_TOP, 24 * EDSCALE); @@ -1008,6 +1016,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_stylebox("commentfocus", "GraphNode", graphsbcommentselected); theme->set_stylebox("breakpoint", "GraphNode", graphsbbreakpoint); theme->set_stylebox("position", "GraphNode", graphsbposition); + theme->set_stylebox("state_machine_frame", "GraphNode", smgraphsb); + theme->set_stylebox("state_machine_selectedframe", "GraphNode", smgraphsbselected); Color default_node_color = Color(mv2, mv2, mv2); theme->set_color("title_color", "GraphNode", default_node_color); diff --git a/editor/import/editor_import_plugin.cpp b/editor/import/editor_import_plugin.cpp index c1c1183692..fbb5bf9342 100644 --- a/editor/import/editor_import_plugin.cpp +++ b/editor/import/editor_import_plugin.cpp @@ -165,5 +165,5 @@ void EditorImportPlugin::_bind_methods() { ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::REAL, "get_priority")); ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::INT, "get_import_order")); ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "get_option_visibility", PropertyInfo(Variant::STRING, "option"), PropertyInfo(Variant::DICTIONARY, "options"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::INT, "import", PropertyInfo(Variant::STRING, "source_file"), PropertyInfo(Variant::STRING, "save_path"), PropertyInfo(Variant::DICTIONARY, "options"), PropertyInfo(Variant::ARRAY, "r_platform_variants"), PropertyInfo(Variant::ARRAY, "r_gen_files"))); + ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::INT, "import", PropertyInfo(Variant::STRING, "source_file"), PropertyInfo(Variant::STRING, "save_path"), PropertyInfo(Variant::DICTIONARY, "options"), PropertyInfo(Variant::ARRAY, "platform_variants"), PropertyInfo(Variant::ARRAY, "gen_files"))); } diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index c237d2e854..ae118e3e01 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -45,6 +45,7 @@ uint32_t EditorOBJImporter::get_import_flags() const { static Error _parse_material_library(const String &p_path, Map<String, Ref<SpatialMaterial> > &material_map, List<String> *r_missing_deps) { FileAccessRef f = FileAccess::open(p_path, FileAccess::READ); + ERR_EXPLAIN(vformat("Couldn't open MTL file '%s', it may not exist or not be readable.", p_path)); ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); Ref<SpatialMaterial> current; @@ -206,7 +207,7 @@ static Error _parse_material_library(const String &p_path, Map<String, Ref<Spati static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p_single_mesh, bool p_generate_tangents, bool p_optimize, Vector3 p_scale_mesh, List<String> *r_missing_deps) { FileAccessRef f = FileAccess::open(p_path, FileAccess::READ); - + ERR_EXPLAIN(vformat("Couldn't open OBJ file '%s', it may not exist or not be readable.", p_path)); ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); Ref<ArrayMesh> mesh; @@ -217,11 +218,6 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p bool flip_faces = false; int mesh_flags = p_optimize ? Mesh::ARRAY_COMPRESS_DEFAULT : 0; - //bool flip_faces = p_options["force/flip_faces"]; - //bool force_smooth = p_options["force/smooth_shading"]; - //bool weld_vertices = p_options["force/weld_vertices"]; - //float weld_tolerance = p_options["force/weld_tolerance"]; - Vector<Vector3> vertices; Vector<Vector3> normals; Vector<Vector2> uvs; diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index 1e5a116f47..2dbf349271 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -134,6 +134,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() { node->set_offset(blend_tree->get_node_position(E->get()) * EDSCALE); node->set_title(agnode->get_caption()); + node->set_human_readable_collision_renaming(false); node->set_name(E->get()); int base = 0; diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index ee30294fe7..427b4eebee 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -572,8 +572,8 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); - Ref<StyleBox> style = get_stylebox("frame", "GraphNode"); - Ref<StyleBox> style_selected = get_stylebox("selectedframe", "GraphNode"); + Ref<StyleBox> style = get_stylebox("state_machine_frame", "GraphNode"); + Ref<StyleBox> style_selected = get_stylebox("state_machine_selectedframe", "GraphNode"); Ref<Font> font = get_font("title_font", "GraphNode"); Color font_color = get_color("title_color", "GraphNode"); diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index c9367edec6..b56c0bbc1b 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -517,7 +517,7 @@ void TileMapEditor::_update_palette() { manual_palette->show(); } - if (tileset->tile_get_tile_mode(sel_tile) == TileSet::AUTO_TILE) { + if (sel_tile != TileMap::INVALID_CELL && tileset->tile_get_tile_mode(sel_tile) == TileSet::AUTO_TILE) { manual_button->show(); } else { manual_button->hide(); diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index e5551d385b..297cf6754c 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -165,6 +165,11 @@ void TileSetEditor::_import_scene(Node *p_scene, Ref<TileSet> p_library, bool p_ _import_node(p_scene, p_library); } +void TileSetEditor::_undo_redo_import_scene(Node *p_scene, bool p_merge) { + + _import_scene(p_scene, tileset, p_merge); +} + Error TileSetEditor::update_library_file(Node *p_base_scene, Ref<TileSet> ml, bool p_merge) { _import_scene(p_base_scene, ml, p_merge); @@ -173,6 +178,7 @@ Error TileSetEditor::update_library_file(Node *p_base_scene, Ref<TileSet> ml, bo void TileSetEditor::_bind_methods() { + ClassDB::bind_method("_undo_redo_import_scene", &TileSetEditor::_undo_redo_import_scene); ClassDB::bind_method("_on_tileset_toolbar_button_pressed", &TileSetEditor::_on_tileset_toolbar_button_pressed); ClassDB::bind_method("_on_textures_added", &TileSetEditor::_on_textures_added); ClassDB::bind_method("_on_tileset_toolbar_confirm", &TileSetEditor::_on_tileset_toolbar_confirm); @@ -190,9 +196,16 @@ void TileSetEditor::_bind_methods() { ClassDB::bind_method("_set_snap_step", &TileSetEditor::_set_snap_step); ClassDB::bind_method("_set_snap_off", &TileSetEditor::_set_snap_off); ClassDB::bind_method("_set_snap_sep", &TileSetEditor::_set_snap_sep); + ClassDB::bind_method("_validate_current_tile_id", &TileSetEditor::_validate_current_tile_id); ClassDB::bind_method("_zoom_in", &TileSetEditor::_zoom_in); ClassDB::bind_method("_zoom_out", &TileSetEditor::_zoom_out); ClassDB::bind_method("_zoom_reset", &TileSetEditor::_zoom_reset); + ClassDB::bind_method("_select_edited_shape_coord", &TileSetEditor::_select_edited_shape_coord); + + ClassDB::bind_method("edit", &TileSetEditor::edit); + ClassDB::bind_method("add_texture", &TileSetEditor::add_texture); + ClassDB::bind_method("remove_texture", &TileSetEditor::remove_texture); + ClassDB::bind_method("update_texture_list_icon", &TileSetEditor::update_texture_list_icon); } void TileSetEditor::_notification(int p_what) { @@ -244,6 +257,7 @@ void TileSetEditor::_notification(int p_what) { TileSetEditor::TileSetEditor(EditorNode *p_editor) { editor = p_editor; + undo_redo = editor->get_undo_redo(); current_tile = -1; VBoxContainer *left_container = memnew(VBoxContainer); @@ -375,19 +389,6 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { tools[SHAPE_DELETE]->connect("pressed", this, "_on_tool_clicked", varray(SHAPE_DELETE)); toolbar->add_child(tools[SHAPE_DELETE]); - separator_grid = memnew(VSeparator); - toolbar->add_child(separator_grid); - tools[SHAPE_KEEP_INSIDE_TILE] = memnew(ToolButton); - tools[SHAPE_KEEP_INSIDE_TILE]->set_toggle_mode(true); - tools[SHAPE_KEEP_INSIDE_TILE]->set_pressed(true); - tools[SHAPE_KEEP_INSIDE_TILE]->set_tooltip(TTR("Keep polygon inside region Rect.")); - toolbar->add_child(tools[SHAPE_KEEP_INSIDE_TILE]); - tools[TOOL_GRID_SNAP] = memnew(ToolButton); - tools[TOOL_GRID_SNAP]->set_toggle_mode(true); - tools[TOOL_GRID_SNAP]->set_tooltip(TTR("Enable snap and show grid (configurable via the Inspector).")); - tools[TOOL_GRID_SNAP]->connect("toggled", this, "_on_grid_snap_toggled"); - toolbar->add_child(tools[TOOL_GRID_SNAP]); - spin_priority = memnew(SpinBox); spin_priority->set_min(1); spin_priority->set_max(255); @@ -406,6 +407,19 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { spin_z_index->hide(); toolbar->add_child(spin_z_index); + separator_grid = memnew(VSeparator); + toolbar->add_child(separator_grid); + tools[SHAPE_KEEP_INSIDE_TILE] = memnew(ToolButton); + tools[SHAPE_KEEP_INSIDE_TILE]->set_toggle_mode(true); + tools[SHAPE_KEEP_INSIDE_TILE]->set_pressed(true); + tools[SHAPE_KEEP_INSIDE_TILE]->set_tooltip(TTR("Keep polygon inside region Rect.")); + toolbar->add_child(tools[SHAPE_KEEP_INSIDE_TILE]); + tools[TOOL_GRID_SNAP] = memnew(ToolButton); + tools[TOOL_GRID_SNAP]->set_toggle_mode(true); + tools[TOOL_GRID_SNAP]->set_tooltip(TTR("Enable snap and show grid (configurable via the Inspector).")); + tools[TOOL_GRID_SNAP]->connect("toggled", this, "_on_grid_snap_toggled"); + toolbar->add_child(tools[TOOL_GRID_SNAP]); + Control *separator = memnew(Control); separator->set_h_size_flags(SIZE_EXPAND_FILL); toolbar->add_child(separator); @@ -481,7 +495,7 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { //--------------- helper = memnew(TilesetEditorContext(this)); - tile_names_opacity = 0; + tile_names_visible = false; // config scale max_scale = 10.0f; @@ -502,7 +516,7 @@ void TileSetEditor::_on_tileset_toolbar_button_pressed(int p_index) { } break; case TOOL_TILESET_REMOVE_TEXTURE: { if (get_current_texture().is_valid()) { - cd->set_text(TTR("Remove selected texture and ALL TILES which use it?")); + cd->set_text(TTR("Remove selected texture? This will remove all tiles which use it.")); cd->popup_centered(Size2(300, 60)); } else { err_dialog->set_text(TTR("You haven't selected a texture to remove.")); @@ -511,7 +525,7 @@ void TileSetEditor::_on_tileset_toolbar_button_pressed(int p_index) { } break; case TOOL_TILESET_CREATE_SCENE: { - cd->set_text(TTR("Create from scene?")); + cd->set_text(TTR("Create from scene? This will overwrite all current tiles.")); cd->popup_centered(Size2(300, 60)); } break; case TOOL_TILESET_MERGE_SCENE: { @@ -528,14 +542,18 @@ void TileSetEditor::_on_tileset_toolbar_confirm() { RID current_rid = get_current_texture()->get_rid(); List<int> ids; tileset->get_tile_list(&ids); + + undo_redo->create_action(TTR("Remove Texture")); for (List<int>::Element *E = ids.front(); E; E = E->next()) { if (tileset->tile_get_texture(E->get())->get_rid() == current_rid) { - tileset->remove_tile(E->get()); + undo_redo->add_do_method(tileset.ptr(), "remove_tile", E->get()); + _undo_tile_removal(E->get()); } } - texture_list->remove_item(texture_list->find_metadata(current_rid)); - texture_map.erase(current_rid); - _on_texture_list_selected(-1); + undo_redo->add_do_method(this, "remove_texture", get_current_texture()); + undo_redo->add_undo_method(this, "add_texture", get_current_texture()); + undo_redo->add_undo_method(this, "update_texture_list_icon"); + undo_redo->commit_action(); } break; case TOOL_TILESET_MERGE_SCENE: case TOOL_TILESET_CREATE_SCENE: { @@ -544,9 +562,19 @@ void TileSetEditor::_on_tileset_toolbar_confirm() { Node *scene = en->get_edited_scene(); if (!scene) break; - _import_scene(scene, tileset, option == TOOL_TILESET_MERGE_SCENE); - edit(tileset); + List<int> ids; + tileset->get_tile_list(&ids); + + undo_redo->create_action(TTR(option == TOOL_TILESET_MERGE_SCENE ? "Merge Tileset from Scene" : "Create Tileset from Scene")); + undo_redo->add_do_method(this, "_undo_redo_import_scene", scene, option == TOOL_TILESET_MERGE_SCENE); + undo_redo->add_undo_method(tileset.ptr(), "clear"); + for (List<int>::Element *E = ids.front(); E; E = E->next()) { + _undo_tile_removal(E->get()); + } + undo_redo->add_do_method(this, "edit", tileset); + undo_redo->add_undo_method(this, "edit", tileset); + undo_redo->commit_action(); } break; } } @@ -580,9 +608,7 @@ void TileSetEditor::_on_textures_added(const PoolStringArray &p_paths) { if (texture_map.has(t->get_rid())) { invalid_count++; } else { - texture_list->add_item(t->get_path().get_file()); - texture_map.insert(t->get_rid(), t); - texture_list->set_item_metadata(texture_list->get_item_count() - 1, t->get_rid()); + add_texture(t); } } @@ -631,8 +657,8 @@ void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) { spin_z_index->hide(); } break; case EDITMODE_COLLISION: - case EDITMODE_NAVIGATION: - case EDITMODE_OCCLUSION: { + case EDITMODE_OCCLUSION: + case EDITMODE_NAVIGATION: { tools[TOOL_SELECT]->show(); separator_bitmask->hide(); @@ -653,7 +679,7 @@ void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) { spin_priority->hide(); spin_z_index->hide(); - select_coord(edited_shape_coord); + _select_edited_shape_coord(); } break; case EDITMODE_BITMASK: { tools[TOOL_SELECT]->show(); @@ -667,9 +693,7 @@ void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) { separator_delete->hide(); tools[SHAPE_DELETE]->hide(); - separator_grid->hide(); tools[SHAPE_KEEP_INSIDE_TILE]->hide(); - tools[TOOL_GRID_SNAP]->hide(); tools[TOOL_SELECT]->set_pressed(true); tools[TOOL_SELECT]->set_tooltip(TTR("LMB: Set bit on.\nRMB: Set bit off.\nClick on another Tile to edit it.")); @@ -905,17 +929,16 @@ void TileSetEditor::_on_workspace_draw() { } void TileSetEditor::_on_workspace_process() { - float a = tile_names_opacity; - if (Input::get_singleton()->is_key_pressed(KEY_ALT) || tools[VISIBLE_INFO]->is_pressed()) { - a += get_tree()->get_idle_process_time() * 2; - } else { - a -= get_tree()->get_idle_process_time() * 2; - } - a = CLAMP(a, 0, 1); - if (a != tile_names_opacity) + if (Input::get_singleton()->is_key_pressed(KEY_ALT) || tools[VISIBLE_INFO]->is_pressed()) { + if (!tile_names_visible) { + tile_names_visible = true; + workspace_overlay->update(); + } + } else if (tile_names_visible) { + tile_names_visible = false; workspace_overlay->update(); - tile_names_opacity = a; + } } void TileSetEditor::_on_workspace_overlay_draw() { @@ -927,7 +950,7 @@ void TileSetEditor::_on_workspace_overlay_draw() { const Color COLOR_SINGLE = Color(0.988281, 0.909323, 0.266373); const Color COLOR_ATLAS = Color(0.78653, 0.812835, 0.832031); - if (tile_names_opacity > 0) { + if (tile_names_visible) { RID current_texture_rid = get_current_texture()->get_rid(); List<int> *tiles = new List<int>(); tileset->get_tile_list(tiles); @@ -944,13 +967,12 @@ void TileSetEditor::_on_workspace_overlay_draw() { c = COLOR_AUTOTILE; else if (tileset->tile_get_tile_mode(t_id) == TileSet::ATLAS_TILE) c = COLOR_ATLAS; - c.a = tile_names_opacity; String tile_id_name = String::num(t_id, 0) + ": " + tileset->tile_get_name(t_id); Ref<Font> font = get_font("font", "Label"); region.set_size(font->get_string_size(tile_id_name)); workspace_overlay->draw_rect(region, c); region.position.y += region.size.y - 2; - c = Color(0.1, 0.1, 0.1, tile_names_opacity); + c = Color(0.1, 0.1, 0.1); workspace_overlay->draw_string(font, region.position, tile_id_name, c); } } @@ -968,7 +990,6 @@ void TileSetEditor::_on_workspace_overlay_draw() { } } -#define MIN_DISTANCE_SQUARED 6 void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { if (tileset.is_null() || !get_current_texture().is_valid()) @@ -1047,29 +1068,49 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { edited_region.position -= WORKSPACE_MARGIN; if (!edited_region.has_no_area()) { if (get_current_tile() >= 0 && workspace_mode == WORKSPACE_EDIT) { - tileset->tile_set_region(get_current_tile(), edited_region); + undo_redo->create_action(TTR("Set Tile Region")); + undo_redo->add_do_method(tileset.ptr(), "tile_set_region", get_current_tile(), edited_region); + undo_redo->add_undo_method(tileset.ptr(), "tile_set_region", get_current_tile(), tileset->tile_get_region(get_current_tile())); + edited_region = Rect2(); + undo_redo->add_do_method(workspace, "update"); + undo_redo->add_undo_method(workspace, "update"); + undo_redo->add_do_method(workspace_overlay, "update"); + undo_redo->add_undo_method(workspace_overlay, "update"); + undo_redo->commit_action(); } else { int t_id = tileset->get_last_unused_tile_id(); - tileset->create_tile(t_id); - tileset->tile_set_texture(t_id, get_current_texture()); - tileset->tile_set_region(t_id, edited_region); - tileset->tile_set_name(t_id, get_current_texture()->get_path().get_file() + " " + String::num(t_id, 0)); + undo_redo->create_action(TTR("Create Tile")); + undo_redo->add_do_method(tileset.ptr(), "create_tile", t_id); + undo_redo->add_undo_method(tileset.ptr(), "remove_tile", t_id); + undo_redo->add_undo_method(this, "_validate_current_tile_id"); + undo_redo->add_do_method(tileset.ptr(), "tile_set_texture", t_id, get_current_texture()); + undo_redo->add_do_method(tileset.ptr(), "tile_set_region", t_id, edited_region); + undo_redo->add_do_method(tileset.ptr(), "tile_set_name", t_id, get_current_texture()->get_path().get_file() + " " + String::num(t_id, 0)); if (workspace_mode != WORKSPACE_CREATE_SINGLE) { - tileset->autotile_set_size(t_id, snap_step); - tileset->autotile_set_spacing(t_id, snap_separation.x); - tileset->tile_set_tile_mode(t_id, workspace_mode == WORKSPACE_CREATE_AUTOTILE ? TileSet::AUTO_TILE : TileSet::ATLAS_TILE); + undo_redo->add_do_method(tileset.ptr(), "autotile_set_size", t_id, snap_step); + undo_redo->add_do_method(tileset.ptr(), "autotile_set_spacing", t_id, snap_separation.x); + undo_redo->add_do_method(tileset.ptr(), "tile_set_tile_mode", t_id, workspace_mode == WORKSPACE_CREATE_AUTOTILE ? TileSet::AUTO_TILE : TileSet::ATLAS_TILE); } - set_current_tile(t_id); tool_workspacemode[WORKSPACE_EDIT]->set_pressed(true); tool_editmode[EDITMODE_COLLISION]->set_pressed(true); edit_mode = EDITMODE_COLLISION; + edited_region = Rect2(); + + undo_redo->add_do_method(workspace, "update"); + undo_redo->add_undo_method(workspace, "update"); + undo_redo->add_do_method(workspace_overlay, "update"); + undo_redo->add_undo_method(workspace_overlay, "update"); + undo_redo->commit_action(); + + set_current_tile(t_id); _on_workspace_mode_changed(WORKSPACE_EDIT); } + } else { + edited_region = Rect2(); + workspace->update(); + workspace_overlay->update(); } - edited_region = Rect2(); - workspace->update(); - workspace_overlay->update(); return; } } else if (mm.is_valid()) { @@ -1082,8 +1123,8 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { } } } - if (workspace_mode == WORKSPACE_EDIT) { + if (workspace_mode == WORKSPACE_EDIT) { if (get_current_tile() >= 0) { int spacing = tileset->autotile_get_spacing(get_current_tile()); Vector2 size = tileset->autotile_get_size(get_current_tile()); @@ -1092,13 +1133,12 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { if (mb.is_valid()) { if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && current_tile_region.has_point(mb->get_position())) { Vector2 coord((int)((mb->get_position().x - current_tile_region.position.x) / (spacing + size.x)), (int)((mb->get_position().y - current_tile_region.position.y) / (spacing + size.y))); - tileset->autotile_set_icon_coordinate(get_current_tile(), coord); - Rect2 region = tileset->tile_get_region(get_current_tile()); - region.size = size; - coord.x *= (spacing + size.x); - coord.y *= (spacing + size.y); - region.position += coord; - workspace->update(); + undo_redo->create_action(TTR("Set Tile Icon")); + undo_redo->add_do_method(tileset.ptr(), "autotile_set_icon_coordinate", get_current_tile(), coord); + undo_redo->add_undo_method(tileset.ptr(), "autotile_set_icon_coordinate", get_current_tile(), tileset->autotile_get_icon_coordinate(get_current_tile())); + undo_redo->add_do_method(workspace, "update"); + undo_redo->add_undo_method(workspace, "update"); + undo_redo->commit_action(); } } } break; @@ -1156,14 +1196,22 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { } } } - uint16_t mask = tileset->autotile_get_bitmask(get_current_tile(), coord); + + uint16_t old_mask = tileset->autotile_get_bitmask(get_current_tile(), coord); + uint16_t new_mask = old_mask; if (erasing) { - mask &= ~bit; + new_mask &= ~bit; } else { - mask |= bit; + new_mask |= bit; + } + if (old_mask != new_mask) { + undo_redo->create_action(TTR("Edit Tile Bitmask")); + undo_redo->add_do_method(tileset.ptr(), "autotile_set_bitmask", get_current_tile(), coord, new_mask); + undo_redo->add_undo_method(tileset.ptr(), "autotile_set_bitmask", get_current_tile(), coord, old_mask); + undo_redo->add_do_method(workspace, "update"); + undo_redo->add_undo_method(workspace, "update"); + undo_redo->commit_action(); } - tileset->autotile_set_bitmask(get_current_tile(), coord, mask); - workspace->update(); } } else { if ((erasing && mb->get_button_index() == BUTTON_RIGHT) || (!erasing && mb->get_button_index() == BUTTON_LEFT)) { @@ -1219,14 +1267,22 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { } } } - uint16_t mask = tileset->autotile_get_bitmask(get_current_tile(), coord); + + uint16_t old_mask = tileset->autotile_get_bitmask(get_current_tile(), coord); + uint16_t new_mask = old_mask; if (erasing) { - mask &= ~bit; + new_mask &= ~bit; } else { - mask |= bit; + new_mask |= bit; + } + if (old_mask != new_mask) { + undo_redo->create_action(TTR("Edit Tile Bitmask")); + undo_redo->add_do_method(tileset.ptr(), "autotile_set_bitmask", get_current_tile(), coord, new_mask); + undo_redo->add_undo_method(tileset.ptr(), "autotile_set_bitmask", get_current_tile(), coord, old_mask); + undo_redo->add_do_method(workspace, "update"); + undo_redo->add_undo_method(workspace, "update"); + undo_redo->commit_action(); } - tileset->autotile_set_bitmask(get_current_tile(), coord, mask); - workspace->update(); } } } break; @@ -1241,13 +1297,14 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { shape_anchor.x *= (size.x + spacing); shape_anchor.y *= (size.y + spacing); } + const real_t grab_threshold = EDITOR_GET("editors/poly_editor/point_grab_radius"); shape_anchor += current_tile_region.position; if (tools[TOOL_SELECT]->is_pressed()) { if (mb.is_valid()) { if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { if (edit_mode != EDITMODE_PRIORITY && current_shape.size() > 0) { for (int i = 0; i < current_shape.size(); i++) { - if ((current_shape[i] - mb->get_position()).length_squared() <= MIN_DISTANCE_SQUARED) { + if ((current_shape[i] - mb->get_position()).length_squared() <= grab_threshold) { dragging_point = i; workspace->update(); return; @@ -1258,20 +1315,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { Vector2 coord((int)((mb->get_position().x - current_tile_region.position.x) / (spacing + size.x)), (int)((mb->get_position().y - current_tile_region.position.y) / (spacing + size.y))); if (edited_shape_coord != coord) { edited_shape_coord = coord; - edited_occlusion_shape = tileset->autotile_get_light_occluder(get_current_tile(), edited_shape_coord); - edited_navigation_shape = tileset->autotile_get_navigation_polygon(get_current_tile(), edited_shape_coord); - Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(get_current_tile()); - bool found_collision_shape = false; - for (int i = 0; i < sd.size(); i++) { - if (sd[i].autotile_coord == coord) { - edited_collision_shape = sd[i].shape; - found_collision_shape = true; - break; - } - } - if (!found_collision_shape) - edited_collision_shape = Ref<ConvexPolygonShape2D>(NULL); - select_coord(edited_shape_coord); + _select_edited_shape_coord(); } } workspace->update(); @@ -1290,9 +1334,12 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { points.push_back(p - shape_anchor); } - edited_collision_shape->set_points(points); - - workspace->update(); + undo_redo->create_action(TTR("Edit Collision Polygon")); + undo_redo->add_do_method(edited_collision_shape.ptr(), "set_points", points); + undo_redo->add_undo_method(edited_collision_shape.ptr(), "set_points", edited_collision_shape->get_points()); + undo_redo->add_do_method(this, "_select_edited_shape_coord"); + undo_redo->add_undo_method(this, "_select_edited_shape_coord"); + undo_redo->commit_action(); } } else if (edit_mode == EDITMODE_OCCLUSION) { if (dragging_point >= 0) { @@ -1307,9 +1354,13 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { } w = PoolVector<Vector2>::Write(); - edited_occlusion_shape->set_polygon(polygon); - workspace->update(); + undo_redo->create_action(TTR("Edit Occlusion Polygon")); + undo_redo->add_do_method(edited_occlusion_shape.ptr(), "set_polygon", polygon); + undo_redo->add_undo_method(edited_occlusion_shape.ptr(), "set_polygon", edited_occlusion_shape->get_polygon()); + undo_redo->add_do_method(this, "_select_edited_shape_coord"); + undo_redo->add_undo_method(this, "_select_edited_shape_coord"); + undo_redo->commit_action(); } } else if (edit_mode == EDITMODE_NAVIGATION) { if (dragging_point >= 0) { @@ -1326,10 +1377,15 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { } w = PoolVector<Vector2>::Write(); - edited_navigation_shape->set_vertices(polygon); - edited_navigation_shape->add_polygon(indices); - workspace->update(); + undo_redo->create_action(TTR("Edit Navigation Polygon")); + undo_redo->add_do_method(edited_navigation_shape.ptr(), "set_vertices", polygon); + undo_redo->add_undo_method(edited_navigation_shape.ptr(), "set_vertices", edited_navigation_shape->get_vertices()); + undo_redo->add_do_method(edited_navigation_shape.ptr(), "add_polygon", indices); + undo_redo->add_undo_method(edited_navigation_shape.ptr(), "add_polygon", edited_navigation_shape->get_polygon(0)); + undo_redo->add_do_method(this, "_select_edited_shape_coord"); + undo_redo->add_undo_method(this, "_select_edited_shape_coord"); + undo_redo->commit_action(); } } } @@ -1340,14 +1396,13 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { } } } else if (tools[SHAPE_NEW_POLYGON]->is_pressed()) { - if (mb.is_valid()) { if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { Vector2 pos = mb->get_position(); pos = snap_point(pos); if (creating_shape) { if (current_shape.size() > 0) { - if ((pos - current_shape[0]).length_squared() <= MIN_DISTANCE_SQUARED) { + if ((pos - current_shape[0]).length_squared() <= grab_threshold) { if (current_shape.size() > 2) { close_shape(shape_anchor); workspace->update(); @@ -1358,60 +1413,16 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { current_shape.push_back(pos); workspace->update(); } else { - int t_id = get_current_tile(); - if (t_id >= 0) { - if (edit_mode == EDITMODE_COLLISION) { - Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(t_id); - for (int i = 0; i < sd.size(); i++) { - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE || sd[i].autotile_coord == edited_shape_coord) { - Ref<ConvexPolygonShape2D> shape = sd[i].shape; - - if (!shape.is_null()) { - sd.remove(i); - tileset->tile_set_shapes(get_current_tile(), sd); - edited_collision_shape = Ref<Shape2D>(); - workspace->update(); - } - break; - } - } - } else if (edit_mode == EDITMODE_OCCLUSION) { - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) { - Map<Vector2, Ref<OccluderPolygon2D> > map = tileset->autotile_get_light_oclusion_map(t_id); - for (Map<Vector2, Ref<OccluderPolygon2D> >::Element *E = map.front(); E; E = E->next()) { - if (E->key() == edited_shape_coord) { - tileset->autotile_set_light_occluder(get_current_tile(), Ref<OccluderPolygon2D>(), edited_shape_coord); - break; - } - } - } else - tileset->tile_set_light_occluder(t_id, Ref<OccluderPolygon2D>()); - - edited_occlusion_shape = Ref<OccluderPolygon2D>(); - workspace->update(); - } else if (edit_mode == EDITMODE_NAVIGATION) { - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) { - Map<Vector2, Ref<NavigationPolygon> > map = tileset->autotile_get_navigation_map(t_id); - for (Map<Vector2, Ref<NavigationPolygon> >::Element *E = map.front(); E; E = E->next()) { - if (E->key() == edited_shape_coord) { - tileset->autotile_set_navigation_polygon(t_id, Ref<NavigationPolygon>(), edited_shape_coord); - break; - } - } - } else - tileset->tile_set_navigation_polygon(t_id, Ref<NavigationPolygon>()); - edited_navigation_shape = Ref<NavigationPolygon>(); - workspace->update(); - } - } - creating_shape = true; current_shape.resize(0); current_shape.push_back(snap_point(pos)); + workspace->update(); } - } else if (mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT && current_shape.size() > 2) { + } else if (mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) { if (creating_shape) { - close_shape(shape_anchor); + creating_shape = false; + _select_edited_shape_coord(); + workspace->update(); } } } else if (mm.is_valid()) { @@ -1431,14 +1442,27 @@ void TileSetEditor::_on_tool_clicked(int p_tool) { if (p_tool == BITMASK_COPY) { bitmask_map_copy = tileset->autotile_get_bitmask_map(get_current_tile()); } else if (p_tool == BITMASK_PASTE) { - tileset->autotile_clear_bitmask_map(get_current_tile()); + undo_redo->create_action(TTR("Paste Tile Bitmask")); + undo_redo->add_do_method(tileset.ptr(), "autotile_clear_bitmask_map", get_current_tile()); + undo_redo->add_undo_method(tileset.ptr(), "autotile_clear_bitmask_map", get_current_tile()); for (Map<Vector2, uint16_t>::Element *E = bitmask_map_copy.front(); E; E = E->next()) { - tileset->autotile_set_bitmask(get_current_tile(), E->key(), E->value()); + undo_redo->add_do_method(tileset.ptr(), "autotile_set_bitmask", get_current_tile(), E->key(), E->value()); } - workspace->update(); + for (Map<Vector2, uint16_t>::Element *E = tileset->autotile_get_bitmask_map(get_current_tile()).front(); E; E = E->next()) { + undo_redo->add_undo_method(tileset.ptr(), "autotile_set_bitmask", get_current_tile(), E->key(), E->value()); + } + undo_redo->add_do_method(workspace, "update"); + undo_redo->add_undo_method(workspace, "update"); + undo_redo->commit_action(); } else if (p_tool == BITMASK_CLEAR) { - tileset->autotile_clear_bitmask_map(get_current_tile()); - workspace->update(); + undo_redo->create_action(TTR("Clear Tile Bitmask")); + undo_redo->add_do_method(tileset.ptr(), "autotile_clear_bitmask_map", get_current_tile()); + for (Map<Vector2, uint16_t>::Element *E = tileset->autotile_get_bitmask_map(get_current_tile()).front(); E; E = E->next()) { + undo_redo->add_undo_method(tileset.ptr(), "autotile_set_bitmask", get_current_tile(), E->key(), E->value()); + } + undo_redo->add_do_method(workspace, "update"); + undo_redo->add_undo_method(workspace, "update"); + undo_redo->commit_action(); } else if (p_tool == SHAPE_DELETE) { if (creating_shape) { creating_shape = false; @@ -1447,11 +1471,17 @@ void TileSetEditor::_on_tool_clicked(int p_tool) { } else { switch (edit_mode) { case EDITMODE_REGION: { - if (workspace_mode == WORKSPACE_EDIT && get_current_tile() >= 0) { - tileset->remove_tile(get_current_tile()); - set_current_tile(-1); - workspace->update(); - workspace_overlay->update(); + int t_id = get_current_tile(); + if (workspace_mode == WORKSPACE_EDIT && t_id >= 0) { + undo_redo->create_action(TTR("Remove Tile")); + undo_redo->add_do_method(tileset.ptr(), "remove_tile", t_id); + _undo_tile_removal(t_id); + undo_redo->add_do_method(this, "_validate_current_tile_id"); + undo_redo->add_do_method(workspace, "update"); + undo_redo->add_undo_method(workspace, "update"); + undo_redo->add_do_method(workspace_overlay, "update"); + undo_redo->add_undo_method(workspace_overlay, "update"); + undo_redo->commit_action(); } tool_workspacemode[WORKSPACE_EDIT]->set_pressed(true); workspace_mode = WORKSPACE_EDIT; @@ -1459,37 +1489,50 @@ void TileSetEditor::_on_tool_clicked(int p_tool) { } break; case EDITMODE_COLLISION: { if (!edited_collision_shape.is_null()) { - Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(get_current_tile()); - int index = -1; + // Necessary to get the version that returns a Array instead of a Vector. + Array sd = tileset->call("tile_get_shapes", get_current_tile()); for (int i = 0; i < sd.size(); i++) { - if (sd[i].shape == edited_collision_shape) { - index = i; + if (sd[i].get("shape") == edited_collision_shape) { + undo_redo->create_action(TTR("Remove Collision Polygon")); + undo_redo->add_undo_method(tileset.ptr(), "tile_set_shapes", get_current_tile(), sd.duplicate()); + sd.remove(i); + undo_redo->add_do_method(tileset.ptr(), "tile_set_shapes", get_current_tile(), sd); + undo_redo->add_do_method(this, "_select_edited_shape_coord"); + undo_redo->add_undo_method(this, "_select_edited_shape_coord"); + undo_redo->commit_action(); break; } } - if (index >= 0) { - sd.remove(index); - tileset->tile_set_shapes(get_current_tile(), sd); - edited_collision_shape = Ref<Shape2D>(); - current_shape.resize(0); - workspace->update(); + } + } break; + case EDITMODE_OCCLUSION: { + if (!edited_occlusion_shape.is_null()) { + undo_redo->create_action(TTR("Remove Occlusion Polygon")); + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { + undo_redo->add_do_method(tileset.ptr(), "tile_set_light_occluder", get_current_tile(), Ref<OccluderPolygon2D>()); + undo_redo->add_undo_method(tileset.ptr(), "tile_set_light_occluder", get_current_tile(), tileset->tile_get_light_occluder(get_current_tile())); + } else { + undo_redo->add_do_method(tileset.ptr(), "autotile_set_light_occluder", get_current_tile(), Ref<OccluderPolygon2D>(), edited_shape_coord); + undo_redo->add_undo_method(tileset.ptr(), "autotile_set_light_occluder", get_current_tile(), tileset->autotile_get_light_occluder(get_current_tile(), edited_shape_coord), edited_shape_coord); } + undo_redo->add_do_method(this, "_select_edited_shape_coord"); + undo_redo->add_undo_method(this, "_select_edited_shape_coord"); + undo_redo->commit_action(); } } break; case EDITMODE_NAVIGATION: { if (!edited_navigation_shape.is_null()) { - tileset->autotile_set_navigation_polygon(get_current_tile(), Ref<NavigationPolygon>(), edited_shape_coord); - edited_navigation_shape = Ref<NavigationPolygon>(); - current_shape.resize(0); - workspace->update(); - } - } break; - case EDITMODE_OCCLUSION: { - if (!edited_occlusion_shape.is_null()) { - tileset->autotile_set_light_occluder(get_current_tile(), Ref<OccluderPolygon2D>(), edited_shape_coord); - edited_occlusion_shape = Ref<OccluderPolygon2D>(); - current_shape.resize(0); - workspace->update(); + undo_redo->create_action(TTR("Remove Navigation Polygon")); + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { + undo_redo->add_do_method(tileset.ptr(), "tile_set_navigation_polygon", get_current_tile(), Ref<NavigationPolygon>()); + undo_redo->add_undo_method(tileset.ptr(), "tile_set_navigation_polygon", get_current_tile(), tileset->tile_get_navigation_polygon(get_current_tile())); + } else { + undo_redo->add_do_method(tileset.ptr(), "autotile_set_navigation_polygon", get_current_tile(), Ref<NavigationPolygon>(), edited_shape_coord); + undo_redo->add_undo_method(tileset.ptr(), "autotile_set_navigation_polygon", get_current_tile(), tileset->autotile_get_navigation_polygon(get_current_tile(), edited_shape_coord), edited_shape_coord); + } + undo_redo->add_do_method(this, "_select_edited_shape_coord"); + undo_redo->add_undo_method(this, "_select_edited_shape_coord"); + undo_redo->commit_action(); } } break; default: {} @@ -1506,13 +1549,27 @@ void TileSetEditor::_on_tool_clicked(int p_tool) { } void TileSetEditor::_on_priority_changed(float val) { - tileset->autotile_set_subtile_priority(get_current_tile(), edited_shape_coord, (int)val); - workspace->update(); + if ((int)val == tileset->autotile_get_subtile_priority(get_current_tile(), edited_shape_coord)) + return; + + undo_redo->create_action(TTR("Edit Tile Priority")); + undo_redo->add_do_method(tileset.ptr(), "autotile_set_subtile_priority", get_current_tile(), edited_shape_coord, (int)val); + undo_redo->add_undo_method(tileset.ptr(), "autotile_set_subtile_priority", get_current_tile(), edited_shape_coord, tileset->autotile_get_subtile_priority(get_current_tile(), edited_shape_coord)); + undo_redo->add_do_method(workspace, "update"); + undo_redo->add_undo_method(workspace, "update"); + undo_redo->commit_action(); } void TileSetEditor::_on_z_index_changed(float val) { - tileset->autotile_set_z_index(get_current_tile(), edited_shape_coord, (int)val); - workspace->update(); + if ((int)val == tileset->autotile_get_z_index(get_current_tile(), edited_shape_coord)) + return; + + undo_redo->create_action(TTR("Edit Tile Z Index")); + undo_redo->add_do_method(tileset.ptr(), "autotile_set_z_index", get_current_tile(), edited_shape_coord, (int)val); + undo_redo->add_undo_method(tileset.ptr(), "autotile_set_z_index", get_current_tile(), edited_shape_coord, tileset->autotile_get_z_index(get_current_tile(), edited_shape_coord)); + undo_redo->add_do_method(workspace, "update"); + undo_redo->add_undo_method(workspace, "update"); + undo_redo->commit_action(); } void TileSetEditor::_on_grid_snap_toggled(bool p_val) { @@ -1538,6 +1595,63 @@ void TileSetEditor::_set_snap_sep(Vector2 p_val) { workspace->update(); } +void TileSetEditor::_validate_current_tile_id() { + if (get_current_tile() >= 0 && !tileset->has_tile(get_current_tile())) + set_current_tile(-1); +} + +void TileSetEditor::_select_edited_shape_coord() { + select_coord(edited_shape_coord); +} + +void TileSetEditor::_undo_tile_removal(int p_id) { + undo_redo->add_undo_method(tileset.ptr(), "create_tile", p_id); + undo_redo->add_undo_method(tileset.ptr(), "tile_set_name", p_id, tileset->tile_get_name(p_id)); + undo_redo->add_undo_method(tileset.ptr(), "tile_set_normal_map", p_id, tileset->tile_get_normal_map(p_id)); + undo_redo->add_undo_method(tileset.ptr(), "tile_set_texture_offset", p_id, tileset->tile_get_texture_offset(p_id)); + undo_redo->add_undo_method(tileset.ptr(), "tile_set_material", p_id, tileset->tile_get_material(p_id)); + undo_redo->add_undo_method(tileset.ptr(), "tile_set_modulate", p_id, tileset->tile_get_modulate(p_id)); + undo_redo->add_undo_method(tileset.ptr(), "tile_set_occluder_offset", p_id, tileset->tile_get_occluder_offset(p_id)); + undo_redo->add_undo_method(tileset.ptr(), "tile_set_navigation_polygon_offset", p_id, tileset->tile_get_navigation_polygon_offset(p_id)); + undo_redo->add_undo_method(tileset.ptr(), "tile_set_shape_offset", p_id, 0, tileset->tile_get_shape_offset(p_id, 0)); + undo_redo->add_undo_method(tileset.ptr(), "tile_set_shape_transform", p_id, 0, tileset->tile_get_shape_transform(p_id, 0)); + undo_redo->add_undo_method(tileset.ptr(), "tile_set_z_index", p_id, tileset->tile_get_z_index(p_id)); + undo_redo->add_undo_method(tileset.ptr(), "tile_set_texture", p_id, tileset->tile_get_texture(p_id)); + undo_redo->add_undo_method(tileset.ptr(), "tile_set_region", p_id, tileset->tile_get_region(p_id)); + // Necessary to get the version that returns a Array instead of a Vector. + undo_redo->add_undo_method(tileset.ptr(), "tile_set_shapes", p_id, tileset->call("tile_get_shapes", p_id)); + if (tileset->tile_get_tile_mode(p_id) == TileSet::SINGLE_TILE) { + undo_redo->add_undo_method(tileset.ptr(), "tile_set_light_occluder", p_id, tileset->tile_get_light_occluder(p_id)); + undo_redo->add_undo_method(tileset.ptr(), "tile_set_navigation_polygon", p_id, tileset->tile_get_navigation_polygon(p_id)); + } else { + Map<Vector2, Ref<OccluderPolygon2D> > oclusion_map = tileset->autotile_get_light_oclusion_map(p_id); + for (Map<Vector2, Ref<OccluderPolygon2D> >::Element *E = oclusion_map.front(); E; E = E->next()) { + undo_redo->add_undo_method(tileset.ptr(), "autotile_set_light_occluder", p_id, E->value(), E->key()); + } + Map<Vector2, Ref<NavigationPolygon> > navigation_map = tileset->autotile_get_navigation_map(p_id); + for (Map<Vector2, Ref<NavigationPolygon> >::Element *E = navigation_map.front(); E; E = E->next()) { + undo_redo->add_undo_method(tileset.ptr(), "autotile_set_navigation_polygon", p_id, E->value(), E->key()); + } + Map<Vector2, uint16_t> bitmask_map = tileset->autotile_get_bitmask_map(p_id); + for (Map<Vector2, uint16_t>::Element *E = bitmask_map.front(); E; E = E->next()) { + undo_redo->add_undo_method(tileset.ptr(), "autotile_set_bitmask", p_id, E->key(), E->value()); + } + Map<Vector2, int> priority_map = tileset->autotile_get_priority_map(p_id); + for (Map<Vector2, int>::Element *E = priority_map.front(); E; E = E->next()) { + undo_redo->add_undo_method(tileset.ptr(), "autotile_set_subtile_priority", p_id, E->key(), E->value()); + } + undo_redo->add_undo_method(tileset.ptr(), "autotile_set_icon_coordinate", p_id, tileset->autotile_get_icon_coordinate(p_id)); + Map<Vector2, int> z_map = tileset->autotile_get_z_index_map(p_id); + for (Map<Vector2, int>::Element *E = z_map.front(); E; E = E->next()) { + undo_redo->add_undo_method(tileset.ptr(), "autotile_set_z_index", p_id, E->key(), E->value()); + } + undo_redo->add_undo_method(tileset.ptr(), "tile_set_tile_mode", p_id, tileset->tile_get_tile_mode(p_id)); + undo_redo->add_undo_method(tileset.ptr(), "autotile_set_size", p_id, tileset->autotile_get_size(p_id)); + undo_redo->add_undo_method(tileset.ptr(), "autotile_set_spacing", p_id, tileset->autotile_get_spacing(p_id)); + undo_redo->add_undo_method(tileset.ptr(), "autotile_set_bitmask_mode", p_id, tileset->autotile_get_bitmask_mode(p_id)); + } +} + void TileSetEditor::_zoom_in() { float scale = workspace->get_scale().x; if (scale < max_scale) { @@ -1548,7 +1662,6 @@ void TileSetEditor::_zoom_in() { } } void TileSetEditor::_zoom_out() { - float scale = workspace->get_scale().x; if (scale > min_scale) { scale /= scale_ratio; @@ -1773,7 +1886,7 @@ void TileSetEditor::draw_polygon_shapes() { } Vector<Vector2> polygon; Vector<Color> colors; - if (shape == edited_collision_shape && current_shape.size() > 2) { + if (!creating_shape && shape == edited_collision_shape && current_shape.size() > 2) { for (int j = 0; j < current_shape.size(); j++) { polygon.push_back(current_shape[j]); colors.push_back(c_bg); @@ -1787,11 +1900,14 @@ void TileSetEditor::draw_polygon_shapes() { if (polygon.size() > 2) { workspace->draw_polygon(polygon, colors); } + if (coord == edited_shape_coord || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { - for (int j = 0; j < shape->get_points().size() - 1; j++) { - workspace->draw_line(shape->get_points()[j] + anchor, shape->get_points()[j + 1] + anchor, c_border, 1, true); + if (!creating_shape) { + for (int j = 0; j < polygon.size() - 1; j++) { + workspace->draw_line(polygon[j], polygon[j + 1], c_border, 1, true); + } + workspace->draw_line(polygon[polygon.size() - 1], polygon[0], c_border, 1, true); } - if (shape == edited_collision_shape) { draw_handles = true; } @@ -1810,16 +1926,25 @@ void TileSetEditor::draw_polygon_shapes() { Vector<Color> colors; Vector2 anchor = WORKSPACE_MARGIN; anchor += tileset->tile_get_region(get_current_tile()).position; - for (int j = 0; j < shape->get_polygon().size(); j++) { - polygon.push_back(shape->get_polygon()[j] + anchor); - colors.push_back(c_bg); + if (!creating_shape && shape == edited_occlusion_shape && current_shape.size() > 2) { + for (int j = 0; j < current_shape.size(); j++) { + polygon.push_back(current_shape[j]); + colors.push_back(c_bg); + } + } else { + for (int j = 0; j < shape->get_polygon().size(); j++) { + polygon.push_back(shape->get_polygon()[j] + anchor); + colors.push_back(c_bg); + } } workspace->draw_polygon(polygon, colors); - for (int j = 0; j < shape->get_polygon().size() - 1; j++) { - workspace->draw_line(shape->get_polygon()[j] + anchor, shape->get_polygon()[j + 1] + anchor, c_border, 1, true); + if (!creating_shape) { + for (int j = 0; j < polygon.size() - 1; j++) { + workspace->draw_line(polygon[j], polygon[j + 1], c_border, 1, true); + } + workspace->draw_line(polygon[polygon.size() - 1], polygon[0], c_border, 1, true); } - workspace->draw_line(shape->get_polygon()[shape->get_polygon().size() - 1] + anchor, shape->get_polygon()[0] + anchor, c_border, 1, true); if (shape == edited_occlusion_shape) { draw_handles = true; } @@ -1848,7 +1973,7 @@ void TileSetEditor::draw_polygon_shapes() { } Vector<Vector2> polygon; Vector<Color> colors; - if (shape == edited_occlusion_shape && current_shape.size() > 2) { + if (!creating_shape && shape == edited_occlusion_shape && current_shape.size() > 2) { for (int j = 0; j < current_shape.size(); j++) { polygon.push_back(current_shape[j]); colors.push_back(c_bg); @@ -1860,11 +1985,14 @@ void TileSetEditor::draw_polygon_shapes() { } } workspace->draw_polygon(polygon, colors); + if (coord == edited_shape_coord) { - for (int j = 0; j < shape->get_polygon().size() - 1; j++) { - workspace->draw_line(shape->get_polygon()[j] + anchor, shape->get_polygon()[j + 1] + anchor, c_border, 1, true); + if (!creating_shape) { + for (int j = 0; j < polygon.size() - 1; j++) { + workspace->draw_line(polygon[j], polygon[j + 1], c_border, 1, true); + } + workspace->draw_line(polygon[polygon.size() - 1], polygon[0], c_border, 1, true); } - workspace->draw_line(shape->get_polygon()[shape->get_polygon().size() - 1] + anchor, shape->get_polygon()[0] + anchor, c_border, 1, true); if (shape == edited_occlusion_shape) { draw_handles = true; } @@ -1885,24 +2013,30 @@ void TileSetEditor::draw_polygon_shapes() { Vector<Color> colors; Vector2 anchor = WORKSPACE_MARGIN; anchor += tileset->tile_get_region(get_current_tile()).position; - PoolVector<Vector2> vertices = shape->get_vertices(); - for (int j = 0; j < shape->get_polygon(0).size(); j++) { - polygon.push_back(vertices[shape->get_polygon(0)[j]] + anchor); - colors.push_back(c_bg); + if (!creating_shape && shape == edited_navigation_shape && current_shape.size() > 2) { + for (int j = 0; j < current_shape.size(); j++) { + polygon.push_back(current_shape[j]); + colors.push_back(c_bg); + } + } else { + PoolVector<Vector2> vertices = shape->get_vertices(); + for (int j = 0; j < shape->get_polygon(0).size(); j++) { + polygon.push_back(vertices[shape->get_polygon(0)[j]] + anchor); + colors.push_back(c_bg); + } } workspace->draw_polygon(polygon, colors); - if (shape->get_polygon_count() > 0) { - PoolVector<Vector2> vertices = shape->get_vertices(); - for (int j = 0; j < shape->get_polygon(0).size() - 1; j++) { - workspace->draw_line(vertices[shape->get_polygon(0)[j]] + anchor, vertices[shape->get_polygon(0)[j + 1]] + anchor, c_border, 1, true); - } - if (shape == edited_navigation_shape) { - draw_handles = true; + if (!creating_shape) { + for (int j = 0; j < polygon.size() - 1; j++) { + workspace->draw_line(polygon[j], polygon[j + 1], c_border, 1, true); } + workspace->draw_line(polygon[polygon.size() - 1], polygon[0], c_border, 1, true); + } + if (shape == edited_navigation_shape) { + draw_handles = true; } } - } else { Map<Vector2, Ref<NavigationPolygon> > map = tileset->autotile_get_navigation_map(t_id); for (Map<Vector2, Ref<NavigationPolygon> >::Element *E = map.front(); E; E = E->next()) { @@ -1927,12 +2061,12 @@ void TileSetEditor::draw_polygon_shapes() { } Vector<Vector2> polygon; Vector<Color> colors; - if (shape == edited_navigation_shape && current_shape.size() > 2) { + if (!creating_shape && shape == edited_navigation_shape && current_shape.size() > 2) { for (int j = 0; j < current_shape.size(); j++) { polygon.push_back(current_shape[j]); colors.push_back(c_bg); } - } else if (shape->get_polygon_count() > 0) { + } else { PoolVector<Vector2> vertices = shape->get_vertices(); for (int j = 0; j < shape->get_polygon(0).size(); j++) { polygon.push_back(vertices[shape->get_polygon(0)[j]] + anchor); @@ -1940,15 +2074,16 @@ void TileSetEditor::draw_polygon_shapes() { } } workspace->draw_polygon(polygon, colors); + if (coord == edited_shape_coord) { - if (shape->get_polygon_count() > 0) { - PoolVector<Vector2> vertices = shape->get_vertices(); - for (int j = 0; j < shape->get_polygon(0).size() - 1; j++) { - workspace->draw_line(vertices[shape->get_polygon(0)[j]] + anchor, vertices[shape->get_polygon(0)[j + 1]] + anchor, c_border, 1, true); - } - if (shape == edited_navigation_shape) { - draw_handles = true; + if (!creating_shape) { + for (int j = 0; j < polygon.size() - 1; j++) { + workspace->draw_line(polygon[j], polygon[j + 1], c_border, 1, true); } + workspace->draw_line(polygon[polygon.size() - 1], polygon[0], c_border, 1, true); + } + if (shape == edited_navigation_shape) { + draw_handles = true; } } } @@ -1957,11 +2092,13 @@ void TileSetEditor::draw_polygon_shapes() { } break; default: {} } + if (creating_shape) { for (int j = 0; j < current_shape.size() - 1; j++) { workspace->draw_line(current_shape[j], current_shape[j + 1], Color(0, 1, 1), 1, true); } workspace->draw_line(current_shape[current_shape.size() - 1], snap_point(workspace->get_local_mouse_position()), Color(0, 1, 1), 1, true); + draw_handles = true; } } @@ -1990,16 +2127,29 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) { shape->set_points(segments); + undo_redo->create_action(TTR("Create Collision Polygon")); + // Necessary to get the version that returns a Array instead of a Vector. + Array sd = tileset->call("tile_get_shapes", get_current_tile()); + undo_redo->add_undo_method(tileset.ptr(), "tile_set_shapes", get_current_tile(), sd.duplicate()); + for (int i = 0; i < sd.size(); i++) { + if (sd[i].get("shape") == edited_collision_shape) { + sd.remove(i); + break; + } + } + undo_redo->add_do_method(tileset.ptr(), "tile_set_shapes", get_current_tile(), sd); if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) - tileset->tile_add_shape(get_current_tile(), shape, Transform2D(), false, edited_shape_coord); + undo_redo->add_do_method(tileset.ptr(), "tile_add_shape", get_current_tile(), shape, Transform2D(), false, edited_shape_coord); else - tileset->tile_add_shape(get_current_tile(), shape, Transform2D()); - - edited_collision_shape = shape; + undo_redo->add_do_method(tileset.ptr(), "tile_add_shape", get_current_tile(), shape, Transform2D()); + tools[TOOL_SELECT]->set_pressed(true); + undo_redo->add_do_method(this, "_select_edited_shape_coord"); + undo_redo->add_undo_method(this, "_select_edited_shape_coord"); + undo_redo->commit_action(); + } else { + tools[TOOL_SELECT]->set_pressed(true); + workspace->update(); } - - tools[TOOL_SELECT]->set_pressed(true); - workspace->update(); } else if (edit_mode == EDITMODE_OCCLUSION) { Ref<OccluderPolygon2D> shape = memnew(OccluderPolygon2D); @@ -2014,13 +2164,18 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) { w = PoolVector<Vector2>::Write(); shape->set_polygon(polygon); - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) - tileset->autotile_set_light_occluder(get_current_tile(), shape, edited_shape_coord); - else - tileset->tile_set_light_occluder(get_current_tile(), shape); - edited_occlusion_shape = shape; + undo_redo->create_action(TTR("Create Occlusion Polygon")); + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) { + undo_redo->add_do_method(tileset.ptr(), "autotile_set_light_occluder", get_current_tile(), shape, edited_shape_coord); + undo_redo->add_undo_method(tileset.ptr(), "autotile_set_light_occluder", get_current_tile(), tileset->autotile_get_light_occluder(get_current_tile(), edited_shape_coord), edited_shape_coord); + } else { + undo_redo->add_do_method(tileset.ptr(), "tile_set_light_occluder", get_current_tile(), shape); + undo_redo->add_undo_method(tileset.ptr(), "tile_set_light_occluder", get_current_tile(), tileset->tile_get_light_occluder(get_current_tile())); + } tools[TOOL_SELECT]->set_pressed(true); - workspace->update(); + undo_redo->add_do_method(this, "_select_edited_shape_coord"); + undo_redo->add_undo_method(this, "_select_edited_shape_coord"); + undo_redo->commit_action(); } else if (edit_mode == EDITMODE_NAVIGATION) { Ref<NavigationPolygon> shape = memnew(NavigationPolygon); @@ -2038,13 +2193,18 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) { shape->set_vertices(polygon); shape->add_polygon(indices); - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) - tileset->autotile_set_navigation_polygon(get_current_tile(), shape, edited_shape_coord); - else - tileset->tile_set_navigation_polygon(get_current_tile(), shape); - edited_navigation_shape = shape; + undo_redo->create_action(TTR("Create Navigation Polygon")); + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) { + undo_redo->add_do_method(tileset.ptr(), "autotile_set_navigation_polygon", get_current_tile(), shape, edited_shape_coord); + undo_redo->add_undo_method(tileset.ptr(), "autotile_set_navigation_polygon", get_current_tile(), tileset->autotile_get_navigation_polygon(get_current_tile(), edited_shape_coord), edited_shape_coord); + } else { + undo_redo->add_do_method(tileset.ptr(), "tile_set_navigation_polygon", get_current_tile(), shape); + undo_redo->add_undo_method(tileset.ptr(), "tile_set_navigation_polygon", get_current_tile(), tileset->tile_get_navigation_polygon(get_current_tile())); + } tools[TOOL_SELECT]->set_pressed(true); - workspace->update(); + undo_redo->add_do_method(this, "_select_edited_shape_coord"); + undo_redo->add_undo_method(this, "_select_edited_shape_coord"); + undo_redo->commit_action(); } tileset->_change_notify(""); } @@ -2089,6 +2249,23 @@ void TileSetEditor::select_coord(const Vector2 &coord) { } } } else { + Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(get_current_tile()); + bool found_collision_shape = false; + for (int i = 0; i < sd.size(); i++) { + if (sd[i].autotile_coord == coord) { + if (edited_collision_shape != sd[i].shape) + edited_collision_shape = sd[i].shape; + found_collision_shape = true; + break; + } + } + if (!found_collision_shape) + edited_collision_shape = Ref<ConvexPolygonShape2D>(NULL); + if (edited_occlusion_shape != tileset->autotile_get_light_occluder(get_current_tile(), coord)) + edited_occlusion_shape = tileset->autotile_get_light_occluder(get_current_tile(), coord); + if (edited_navigation_shape != tileset->autotile_get_navigation_polygon(get_current_tile(), coord)) + edited_navigation_shape = tileset->autotile_get_navigation_polygon(get_current_tile(), coord); + int spacing = tileset->autotile_get_spacing(get_current_tile()); Vector2 size = tileset->autotile_get_size(get_current_tile()); Vector2 shape_anchor = coord; @@ -2159,6 +2336,24 @@ Vector2 TileSetEditor::snap_point(const Vector2 &point) { return p; } +void TileSetEditor::add_texture(Ref<Texture> p_texture) { + texture_list->add_item(p_texture->get_path().get_file()); + texture_map.insert(p_texture->get_rid(), p_texture); + texture_list->set_item_metadata(texture_list->get_item_count() - 1, p_texture->get_rid()); +} + +void TileSetEditor::remove_texture(Ref<Texture> p_texture) { + texture_list->remove_item(texture_list->find_metadata(p_texture->get_rid())); + texture_map.erase(p_texture->get_rid()); + + _validate_current_tile_id(); + + if (!get_current_texture().is_valid()) { + _on_texture_list_selected(-1); + workspace_overlay->update(); + } +} + void TileSetEditor::update_texture_list() { Ref<Texture> selected_texture = get_current_texture(); @@ -2175,9 +2370,7 @@ void TileSetEditor::update_texture_list() { } if (!texture_map.has(tileset->tile_get_texture(E->get())->get_rid())) { - texture_list->add_item(tileset->tile_get_texture(E->get())->get_path().get_file()); - texture_map.insert(tileset->tile_get_texture(E->get())->get_rid(), tileset->tile_get_texture(E->get())); - texture_list->set_item_metadata(texture_list->get_item_count() - 1, tileset->tile_get_texture(E->get())->get_rid()); + add_texture(tileset->tile_get_texture(E->get())); } } for (int i = 0; i < ids_to_remove.size(); i++) { @@ -2191,7 +2384,9 @@ void TileSetEditor::update_texture_list() { } else if (get_current_texture().is_valid()) { _on_texture_list_selected(texture_list->find_metadata(get_current_texture()->get_rid())); } else { + _validate_current_tile_id(); _on_texture_list_selected(-1); + workspace_overlay->update(); } update_texture_list_icon(); helper->_change_notify(""); @@ -2267,7 +2462,7 @@ void TileSetEditor::update_workspace_tile_mode() { if (edit_mode == EDITMODE_ICON) select_coord(tileset->autotile_get_icon_coordinate(get_current_tile())); else - select_coord(edited_shape_coord); + _select_edited_shape_coord(); } else if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) { if (tool_editmode[EDITMODE_PRIORITY]->is_pressed() || tool_editmode[EDITMODE_BITMASK]->is_pressed()) { tool_editmode[EDITMODE_COLLISION]->set_pressed(true); @@ -2276,7 +2471,7 @@ void TileSetEditor::update_workspace_tile_mode() { if (edit_mode == EDITMODE_ICON) select_coord(tileset->autotile_get_icon_coordinate(get_current_tile())); else - select_coord(edited_shape_coord); + _select_edited_shape_coord(); tool_editmode[EDITMODE_BITMASK]->hide(); tool_editmode[EDITMODE_PRIORITY]->hide(); diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h index 276e23f9ee..e4e01750bd 100644 --- a/editor/plugins/tile_set_editor_plugin.h +++ b/editor/plugins/tile_set_editor_plugin.h @@ -94,6 +94,7 @@ class TileSetEditor : public HSplitContainer { Ref<TileSet> tileset; TilesetEditorContext *helper; EditorNode *editor; + UndoRedo *undo_redo; ConfirmationDialog *cd; AcceptDialog *err_dialog; @@ -107,7 +108,7 @@ class TileSetEditor : public HSplitContainer { bool creating_shape; int dragging_point; - float tile_names_opacity; + bool tile_names_visible; Vector2 region_from; Rect2 edited_region; bool draw_edited_region; @@ -151,10 +152,14 @@ class TileSetEditor : public HSplitContainer { void update_texture_list(); void update_texture_list_icon(); + void add_texture(Ref<Texture> p_texture); + void remove_texture(Ref<Texture> p_texture); + Ref<Texture> get_current_texture(); static void _import_node(Node *p_node, Ref<TileSet> p_library); static void _import_scene(Node *p_scene, Ref<TileSet> p_library, bool p_merge); + void _undo_redo_import_scene(Node *p_scene, bool p_merge); protected: static void _bind_methods(); @@ -186,6 +191,10 @@ private: void _set_snap_off(Vector2 p_val); void _set_snap_sep(Vector2 p_val); + void _validate_current_tile_id(); + void _select_edited_shape_coord(); + void _undo_tile_removal(int p_id); + void _zoom_in(); void _zoom_out(); void _zoom_reset(); |