diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index ea5ac6914..b5b1c501c 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -150,8 +150,6 @@ #include "editor/plugins/texture_editor_plugin.h" #include "editor/plugins/texture_region_editor_plugin.h" #include "editor/plugins/theme_editor_plugin.h" -#include "editor/plugins/tile_map_editor_plugin.h" -#include "editor/plugins/tile_set_editor_plugin.h" #include "editor/plugins/viewport_preview_editor_plugin.h" #include "editor/progress_dialog.h" #include "editor/project_export.h" @@ -1707,29 +1705,6 @@ void EditorNode::_dialog_action(String p_file) { } } break; - case FILE_EXPORT_TILESET: { - Ref tileset; - if (FileAccess::exists(p_file) && file_export_lib_merge->is_pressed()) { - tileset = ResourceLoader::load(p_file, "TileSet"); - - if (tileset.is_null()) { - show_accept(TTR("Can't load TileSet for merging!"), TTR("OK")); - return; - } - - } else { - tileset = Ref(memnew(TileSet)); - } - - TileSetEditor::update_library_file(editor_data.get_edited_scene_root(), tileset, true); - - Error err = ResourceSaver::save(p_file, tileset); - if (err) { - show_accept(TTR("Error saving TileSet!"), TTR("OK")); - return; - } - } break; - case RESOURCE_SAVE: case RESOURCE_SAVE_AS: { ERR_FAIL_COND(saving_resource.is_null()); @@ -2390,26 +2365,6 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { project_export->popup_export(); } break; - case FILE_EXPORT_TILESET: { - //Make sure that the scene has a root before trying to convert to tileset - if (!editor_data.get_edited_scene_root()) { - show_accept(TTR("This operation can't be done without a root node."), TTR("OK")); - break; - } - - List extensions; - Ref ml(memnew(TileSet)); - ResourceSaver::get_recognized_extensions(ml, &extensions); - file_export_lib->clear_filters(); - for (List::Element *E = extensions.front(); E; E = E->next()) { - file_export_lib->add_filter("*." + E->get()); - } - - file_export_lib->popup_centered_ratio(); - file_export_lib->set_title(TTR("Export Tile Set")); - - } break; - case FILE_IMPORT_SUBSCENE: { if (!editor_data.get_edited_scene_root()) { show_accept(TTR("This operation can't be done without a selected node."), TTR("OK")); @@ -5821,7 +5776,7 @@ EditorNode::EditorNode() { EDITOR_DEF("interface/inspector/horizontal_vector2_editing", false); EDITOR_DEF("interface/inspector/horizontal_vector_types_editing", true); EDITOR_DEF("interface/inspector/open_resources_in_current_inspector", true); - EDITOR_DEF("interface/inspector/resources_to_open_in_new_inspector", "Script,TileSet"); + EDITOR_DEF("interface/inspector/resources_to_open_in_new_inspector", "Script"); EDITOR_DEF("interface/inspector/default_color_picker_mode", 0); EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "interface/inspector/default_color_picker_mode", PROPERTY_HINT_ENUM, "RGB,HSV,RAW", PROPERTY_USAGE_DEFAULT)); EDITOR_DEF("run/auto_save/save_before_running", true); @@ -6153,7 +6108,6 @@ EditorNode::EditorNode() { pm_export->set_name("Export"); p->add_child(pm_export); p->add_submenu_item(TTR("Convert To..."), "Export"); - pm_export->add_shortcut(ED_SHORTCUT("editor/convert_to_TileSet", TTR("TileSet...")), FILE_EXPORT_TILESET); pm_export->connect("id_pressed", this, "_menu_option"); p->add_separator(); @@ -6752,8 +6706,6 @@ EditorNode::EditorNode() { add_editor_plugin(memnew(ItemListEditorPlugin(this))); add_editor_plugin(memnew(Polygon3DEditorPlugin(this))); add_editor_plugin(memnew(CollisionPolygon2DEditorPlugin(this))); - add_editor_plugin(memnew(TileSetEditorPlugin(this))); - add_editor_plugin(memnew(TileMapEditorPlugin(this))); add_editor_plugin(memnew(SpriteFramesEditorPlugin(this))); add_editor_plugin(memnew(TextureRegionEditorPlugin(this))); add_editor_plugin(memnew(RoomManagerEditorPlugin(this))); diff --git a/editor/editor_node.h b/editor/editor_node.h index d5d541ecc..3d6292c5a 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -130,7 +130,6 @@ private: FILE_EXPORT_PROJECT, FILE_INSTALL_ANDROID_SOURCE, FILE_EXPLORE_ANDROID_BUILD_TEMPLATES, - FILE_EXPORT_TILESET, FILE_SAVE_OPTIMIZED, FILE_OPEN_RECENT, FILE_OPEN_OLD_SCENE, diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp deleted file mode 100644 index c566afedc..000000000 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ /dev/null @@ -1,2280 +0,0 @@ -/*************************************************************************/ -/* tile_map_editor_plugin.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "tile_map_editor_plugin.h" - -#include "canvas_item_editor_plugin.h" -#include "core/math/math_funcs.h" -#include "core/os/input.h" -#include "core/os/keyboard.h" -#include "editor/editor_scale.h" -#include "editor/editor_settings.h" -#include "scene/gui/split_container.h" - -static float _lerp_fade(int total, int fade, float position) { - if (position < fade) { - return Math::inverse_lerp(0, fade, position); - } else if (position > (total - fade)) { - return Math::inverse_lerp(total, total - fade, position); - } - return 1.0; -} - -void TileMapEditor::_node_removed(Node *p_node) { - if (p_node == node) { - node = nullptr; - } -} - -void TileMapEditor::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_PROCESS: { - if (bucket_queue.size()) { - CanvasItemEditor::get_singleton()->update_viewport(); - } - - } break; - - case NOTIFICATION_ENTER_TREE: { - get_tree()->connect("node_removed", this, "_node_removed"); - FALLTHROUGH; - } - - case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { - if (is_visible_in_tree()) { - _update_palette(); - } - - paint_button->set_icon(get_icon("Edit", "EditorIcons")); - bucket_fill_button->set_icon(get_icon("Bucket", "EditorIcons")); - picker_button->set_icon(get_icon("ColorPick", "EditorIcons")); - select_button->set_icon(get_icon("ToolSelect", "EditorIcons")); - - rotate_left_button->set_icon(get_icon("RotateLeft", "EditorIcons")); - rotate_right_button->set_icon(get_icon("RotateRight", "EditorIcons")); - flip_horizontal_button->set_icon(get_icon("MirrorX", "EditorIcons")); - flip_vertical_button->set_icon(get_icon("MirrorY", "EditorIcons")); - clear_transform_button->set_icon(get_icon("Clear", "EditorIcons")); - - search_box->set_right_icon(get_icon("Search", "EditorIcons")); - search_box->set_clear_button_enabled(true); - - PopupMenu *p = options->get_popup(); - p->set_item_icon(p->get_item_index(OPTION_CUT), get_icon("ActionCut", "EditorIcons")); - p->set_item_icon(p->get_item_index(OPTION_COPY), get_icon("Duplicate", "EditorIcons")); - p->set_item_icon(p->get_item_index(OPTION_ERASE_SELECTION), get_icon("Remove", "EditorIcons")); - - } break; - - case NOTIFICATION_EXIT_TREE: { - get_tree()->disconnect("node_removed", this, "_node_removed"); - } break; - - case NOTIFICATION_WM_FOCUS_OUT: { - if (tool == TOOL_PAINTING) { - Vector ids = get_selected_tiles(); - - if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) { - _set_cell(over_tile, ids, flip_h, flip_v, transpose); - _finish_undo(); - - paint_undo.clear(); - } - - tool = TOOL_NONE; - _update_button_tool(); - } - - // set flag to ignore over_tile on refocus - refocus_over_tile = true; - } break; - } -} - -void TileMapEditor::_update_button_tool() { - ToolButton *tb[4] = { paint_button, bucket_fill_button, picker_button, select_button }; - // Unpress all buttons - for (int i = 0; i < 4; i++) { - tb[i]->set_pressed(false); - } - - // Press the good button - switch (tool) { - case TOOL_NONE: - case TOOL_PAINTING: { - paint_button->set_pressed(true); - } break; - case TOOL_BUCKET: { - bucket_fill_button->set_pressed(true); - } break; - case TOOL_PICKING: { - picker_button->set_pressed(true); - } break; - case TOOL_SELECTING: { - select_button->set_pressed(true); - } break; - default: - break; - } - - if (tool != TOOL_PICKING) { - last_tool = tool; - } -} - -void TileMapEditor::_button_tool_select(int p_tool) { - tool = (Tool)p_tool; - _update_button_tool(); - switch (tool) { - case TOOL_SELECTING: { - selection_active = false; - } break; - default: - break; - } - CanvasItemEditor::get_singleton()->update_viewport(); -} - -void TileMapEditor::_menu_option(int p_option) { - switch (p_option) { - case OPTION_COPY: { - _update_copydata(); - - if (selection_active) { - tool = TOOL_PASTING; - - CanvasItemEditor::get_singleton()->update_viewport(); - } - } break; - case OPTION_ERASE_SELECTION: { - if (!selection_active) { - return; - } - - _start_undo(TTR("Erase Selection")); - _erase_selection(); - _finish_undo(); - - selection_active = false; - copydata.clear(); - - CanvasItemEditor::get_singleton()->update_viewport(); - } break; - case OPTION_FIX_INVALID: { - undo_redo->create_action(TTR("Fix Invalid Tiles")); - undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); - node->fix_invalid_tiles(); - undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); - undo_redo->commit_action(); - - } break; - case OPTION_CUT: { - if (selection_active) { - _update_copydata(); - - _start_undo(TTR("Cut Selection")); - _erase_selection(); - _finish_undo(); - - selection_active = false; - - tool = TOOL_PASTING; - - CanvasItemEditor::get_singleton()->update_viewport(); - } - } break; - } - _update_button_tool(); -} - -void TileMapEditor::_palette_selected(int index) { - _update_palette(); -} - -void TileMapEditor::_palette_multi_selected(int index, bool selected) { - _update_palette(); -} - -void TileMapEditor::_palette_input(const Ref &p_event) { - const Ref mb = p_event; - - // Zoom in/out using Ctrl + mouse wheel. - if (mb.is_valid() && mb->is_pressed() && mb->get_command()) { - if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_UP) { - size_slider->set_value(size_slider->get_value() + 0.2); - } - - if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_DOWN) { - size_slider->set_value(size_slider->get_value() - 0.2); - } - } -} - -void TileMapEditor::_canvas_mouse_enter() { - mouse_over = true; - CanvasItemEditor::get_singleton()->update_viewport(); -} - -void TileMapEditor::_canvas_mouse_exit() { - mouse_over = false; - CanvasItemEditor::get_singleton()->update_viewport(); -} - -Vector TileMapEditor::get_selected_tiles() const { - Vector items = palette->get_selected_items(); - - if (items.size() == 0) { - items.push_back(TileMap::INVALID_CELL); - return items; - } - - for (int i = items.size() - 1; i >= 0; i--) { - items.write[i] = palette->get_item_metadata(items[i]); - } - return items; -} - -void TileMapEditor::set_selected_tiles(Vector p_tiles) { - palette->unselect_all(); - - for (int i = p_tiles.size() - 1; i >= 0; i--) { - int idx = palette->find_metadata(p_tiles[i]); - - if (idx >= 0) { - palette->select(idx, false); - } - } - - palette->ensure_current_is_visible(); -} - -Dictionary TileMapEditor::_create_cell_dictionary(int tile, bool flip_x, bool flip_y, bool transpose, Vector2 autotile_coord) { - Dictionary cell; - - cell["id"] = tile; - cell["flip_h"] = flip_x; - cell["flip_y"] = flip_y; - cell["transpose"] = transpose; - cell["auto_coord"] = autotile_coord; - - return cell; -} - -void TileMapEditor::_create_set_cell_undo_redo(const Vector2 &p_vec, const CellOp &p_cell_old, const CellOp &p_cell_new) { - Dictionary cell_old = _create_cell_dictionary(p_cell_old.idx, p_cell_old.xf, p_cell_old.yf, p_cell_old.tr, p_cell_old.ac); - Dictionary cell_new = _create_cell_dictionary(p_cell_new.idx, p_cell_new.xf, p_cell_new.yf, p_cell_new.tr, p_cell_new.ac); - - undo_redo->add_undo_method(node, "_set_celld", p_vec, cell_old); - undo_redo->add_do_method(node, "_set_celld", p_vec, cell_new); -} - -void TileMapEditor::_start_undo(const String &p_action) { - undo_data.clear(); - undo_redo->create_action(p_action); -} - -void TileMapEditor::_finish_undo() { - if (undo_data.size()) { - for (Map::Element *E = undo_data.front(); E; E = E->next()) { - _create_set_cell_undo_redo(E->key(), E->get(), _get_op_from_cell(E->key())); - } - - undo_data.clear(); - } - - undo_redo->commit_action(); -} - -void TileMapEditor::_set_cell(const Point2i &p_pos, Vector p_values, bool p_flip_h, bool p_flip_v, bool p_transpose, const Point2i &p_autotile_coord) { - ERR_FAIL_COND(!node); - - if (p_values.size() == 0) { - return; - } - - int p_value = p_values[Math::rand() % p_values.size()]; - int prev_val = node->get_cell(p_pos.x, p_pos.y); - - bool prev_flip_h = node->is_cell_x_flipped(p_pos.x, p_pos.y); - bool prev_flip_v = node->is_cell_y_flipped(p_pos.x, p_pos.y); - bool prev_transpose = node->is_cell_transposed(p_pos.x, p_pos.y); - Vector2 prev_position = node->get_cell_autotile_coord(p_pos.x, p_pos.y); - - Vector2 position; - int current = manual_palette->get_current(); - if (current != -1) { - if (tool != TOOL_PASTING) { - position = manual_palette->get_item_metadata(current); - } else { - position = p_autotile_coord; - } - } else { - // If there is no manual tile selected, that either means that - // autotiling is enabled, or the given tile is not autotiling. Either - // way, the coordinate of the tile does not matter, so assigning it to - // the coordinate of the existing tile works fine. - position = prev_position; - } - - if (p_value == prev_val && p_flip_h == prev_flip_h && p_flip_v == prev_flip_v && p_transpose == prev_transpose && prev_position == position) { - return; // Check that it's actually different. - } - - for (int y = p_pos.y - 1; y <= p_pos.y + 1; y++) { - for (int x = p_pos.x - 1; x <= p_pos.x + 1; x++) { - Point2i p = Point2i(x, y); - if (!undo_data.has(p)) { - undo_data[p] = _get_op_from_cell(p); - } - } - } - - node->_set_celld(p_pos, _create_cell_dictionary(p_value, p_flip_h, p_flip_v, p_transpose, p_autotile_coord)); - - if (tool == TOOL_PASTING) { - return; - } - - if (manual_autotile || (p_value != -1 && node->get_tileset()->has_tile(p_value) && node->get_tileset()->tile_get_tile_mode(p_value) == TileSet::ATLAS_TILE)) { - if (current != -1) { - node->set_cell_autotile_coord(p_pos.x, p_pos.y, position); - } else if (node->get_tileset()->tile_get_tile_mode(p_value) == TileSet::ATLAS_TILE && priority_atlastile) { - // BIND_CENTER is used to indicate that bitmask should not update for this tile cell. - node->get_tileset()->autotile_set_bitmask(p_value, Vector2(p_pos.x, p_pos.y), TileSet::BIND_CENTER); - node->update_cell_bitmask(p_pos.x, p_pos.y); - } - } else { - node->update_bitmask_area(Point2(p_pos)); - } -} - -void TileMapEditor::_manual_toggled(bool p_enabled) { - manual_autotile = p_enabled; - _update_palette(); -} - -void TileMapEditor::_priority_toggled(bool p_enabled) { - priority_atlastile = p_enabled; - _update_palette(); -} - -void TileMapEditor::_text_entered(const String &p_text) { - canvas_item_editor_viewport->grab_focus(); -} - -void TileMapEditor::_text_changed(const String &p_text) { - _update_palette(); -} - -void TileMapEditor::_sbox_input(const Ref &p_ie) { - Ref k = p_ie; - - if (k.is_valid() && (k->get_scancode() == KEY_UP || k->get_scancode() == KEY_DOWN || k->get_scancode() == KEY_PAGEUP || k->get_scancode() == KEY_PAGEDOWN)) { - palette->call("_gui_input", k); - search_box->accept_event(); - } -} - -// Implementation detail of TileMapEditor::_update_palette(); -// In modern C++ this could have been inside its body. -namespace { -struct _PaletteEntry { - int id; - String name; - - bool operator<(const _PaletteEntry &p_rhs) const { - // Natural no case comparison will compare strings based on CharType - // order (except digits) and on numbers that start on the same position. - return name.naturalnocasecmp_to(p_rhs.name) < 0; - } -}; -} // namespace - -void TileMapEditor::_update_palette() { - if (!node) { - return; - } - - // Update the clear button. - clear_transform_button->set_disabled(!flip_h && !flip_v && !transpose); - - // Update the palette. - Vector selected = get_selected_tiles(); - int selected_single = palette->get_current(); - int selected_manual = manual_palette->get_current(); - palette->clear(); - manual_palette->clear(); - manual_palette->hide(); - - Ref tileset = node->get_tileset(); - if (tileset.is_null()) { - search_box->set_text(""); - search_box->set_editable(false); - info_message->show(); - return; - } - - search_box->set_editable(true); - info_message->hide(); - - List tiles; - tileset->get_tile_list(&tiles); - if (tiles.empty()) { - return; - } - - float min_size = EDITOR_GET("editors/tile_map/preview_size"); - min_size *= EDSCALE; - int hseparation = EDITOR_GET("editors/tile_map/palette_item_hseparation"); - bool show_tile_names = bool(EDITOR_GET("editors/tile_map/show_tile_names")); - bool show_tile_ids = bool(EDITOR_GET("editors/tile_map/show_tile_ids")); - bool sort_by_name = bool(EDITOR_GET("editors/tile_map/sort_tiles_by_name")); - - palette->add_constant_override("hseparation", hseparation * EDSCALE); - - palette->set_fixed_icon_size(Size2(min_size, min_size)); - palette->set_fixed_column_width(min_size * MAX(size_slider->get_value(), 1)); - palette->set_same_column_width(true); - manual_palette->set_fixed_icon_size(Size2(min_size, min_size)); - manual_palette->set_same_column_width(true); - - String filter = search_box->get_text().strip_edges(); - - Vector<_PaletteEntry> entries; - - for (List::Element *E = tiles.front(); E; E = E->next()) { - String name = tileset->tile_get_name(E->get()); - - if (name != "") { - if (show_tile_ids) { - if (sort_by_name) { - name = name + " - " + itos(E->get()); - } else { - name = itos(E->get()) + " - " + name; - } - } - } else { - name = "#" + itos(E->get()); - } - - if (filter != "" && !filter.is_subsequence_ofi(name)) { - continue; - } - - const _PaletteEntry entry = { E->get(), name }; - entries.push_back(entry); - } - - if (sort_by_name) { - entries.sort(); - } - - for (int i = 0; i < entries.size(); i++) { - if (show_tile_names) { - palette->add_item(entries[i].name); - } else { - palette->add_item(String()); - } - - Ref tex = tileset->tile_get_texture(entries[i].id); - - if (tex.is_valid()) { - Rect2 region = tileset->tile_get_region(entries[i].id); - - if (tileset->tile_get_tile_mode(entries[i].id) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(entries[i].id) == TileSet::ATLAS_TILE) { - int spacing = tileset->autotile_get_spacing(entries[i].id); - region.size = tileset->autotile_get_size(entries[i].id); - region.position += (region.size + Vector2(spacing, spacing)) * tileset->autotile_get_icon_coordinate(entries[i].id); - } - - // Transpose and flip. - palette->set_item_icon_transposed(palette->get_item_count() - 1, transpose); - if (flip_h) { - region.size.x = -region.size.x; - } - if (flip_v) { - region.size.y = -region.size.y; - } - - // Set region. - if (region.size != Size2()) { - palette->set_item_icon_region(palette->get_item_count() - 1, region); - } - - // Set icon. - palette->set_item_icon(palette->get_item_count() - 1, tex); - - // Modulation. - Color color = tileset->tile_get_modulate(entries[i].id); - palette->set_item_icon_modulate(palette->get_item_count() - 1, color); - } - - palette->set_item_metadata(palette->get_item_count() - 1, entries[i].id); - } - - int sel_tile = selected.get(0); - if (selected.get(0) != TileMap::INVALID_CELL) { - set_selected_tiles(selected); - sel_tile = selected.get(Math::rand() % selected.size()); - } else if (palette->get_item_count() > 0) { - palette->select(0); - sel_tile = palette->get_selected_items().get(0); - } - - if (sel_tile != TileMap::INVALID_CELL && tileset->has_tile(sel_tile) && ((manual_autotile && tileset->tile_get_tile_mode(sel_tile) == TileSet::AUTO_TILE) || (!priority_atlastile && tileset->tile_get_tile_mode(sel_tile) == TileSet::ATLAS_TILE))) { - const Map &tiles2 = tileset->autotile_get_bitmask_map(sel_tile); - - Vector entries2; - for (const Map::Element *E = tiles2.front(); E; E = E->next()) { - entries2.push_back(E->key()); - } - // Sort tiles in row-major order. - struct SwapComparator { - _FORCE_INLINE_ bool operator()(const Vector2 &v_l, const Vector2 &v_r) const { - return v_l.y != v_r.y ? v_l.y < v_r.y : v_l.x < v_r.x; - } - }; - entries2.sort_custom(); - - Ref tex = tileset->tile_get_texture(sel_tile); - Color modulate = tileset->tile_get_modulate(sel_tile); - - for (int i = 0; i < entries2.size(); i++) { - manual_palette->add_item(String()); - - if (tex.is_valid()) { - Rect2 region = tileset->tile_get_region(sel_tile); - int spacing = tileset->autotile_get_spacing(sel_tile); - region.size = tileset->autotile_get_size(sel_tile); // !! - region.position += (region.size + Vector2(spacing, spacing)) * entries2[i]; - - if (!region.has_no_area()) { - manual_palette->set_item_icon_region(manual_palette->get_item_count() - 1, region); - } - - manual_palette->set_item_icon(manual_palette->get_item_count() - 1, tex); - manual_palette->set_item_icon_modulate(manual_palette->get_item_count() - 1, modulate); - } - - manual_palette->set_item_metadata(manual_palette->get_item_count() - 1, entries2[i]); - } - } - - if (manual_palette->get_item_count() > 0) { - // Only show the manual palette if at least tile exists in it. - if (selected_manual == -1 || selected_single != palette->get_current()) { - selected_manual = 0; - } - if (selected_manual < manual_palette->get_item_count()) { - manual_palette->set_current(selected_manual); - } - manual_palette->show(); - } - - if (sel_tile != TileMap::INVALID_CELL && tileset->has_tile(sel_tile) && tileset->tile_get_tile_mode(sel_tile) == TileSet::AUTO_TILE) { - manual_button->show(); - priority_button->hide(); - } else { - manual_button->hide(); - priority_button->show(); - } -} - -void TileMapEditor::_pick_tile(const Point2 &p_pos) { - int id = node->get_cell(p_pos.x, p_pos.y); - - if (id == TileMap::INVALID_CELL || !node->get_tileset()->has_tile(id)) { - return; - } - - if (search_box->get_text() != "") { - search_box->set_text(""); - _update_palette(); - } - - flip_h = node->is_cell_x_flipped(p_pos.x, p_pos.y); - flip_v = node->is_cell_y_flipped(p_pos.x, p_pos.y); - transpose = node->is_cell_transposed(p_pos.x, p_pos.y); - autotile_coord = node->get_cell_autotile_coord(p_pos.x, p_pos.y); - - Vector selected; - selected.push_back(id); - set_selected_tiles(selected); - _update_palette(); - - if ((manual_autotile && node->get_tileset()->tile_get_tile_mode(id) == TileSet::AUTO_TILE) || (!priority_atlastile && node->get_tileset()->tile_get_tile_mode(id) == TileSet::ATLAS_TILE)) { - manual_palette->select(manual_palette->find_metadata((Point2)autotile_coord)); - } - - CanvasItemEditor::get_singleton()->update_viewport(); -} - -PoolVector TileMapEditor::_bucket_fill(const Point2i &p_start, bool erase, bool preview) { - int prev_id = node->get_cell(p_start.x, p_start.y); - Vector ids; - ids.push_back(TileMap::INVALID_CELL); - if (!erase) { - ids = get_selected_tiles(); - - if (ids.size() == 0 || ids[0] == TileMap::INVALID_CELL) { - return PoolVector(); - } - } else if (prev_id == TileMap::INVALID_CELL) { - return PoolVector(); - } - - // Check if the tile variation is the same - if (ids.size() == 1 && ids[0] == prev_id) { - int current = manual_palette->get_current(); - if (current == -1) { - // Same ID, no variation selected, nothing to change - return PoolVector(); - } - Vector2 prev_autotile_coord = node->get_cell_autotile_coord(p_start.x, p_start.y); - Vector2 autotile_coord = manual_palette->get_item_metadata(current); - if (autotile_coord == prev_autotile_coord) { - // Same ID and variation, nothing to change - return PoolVector(); - } - } - - Rect2i r = node->get_used_rect(); - - int area = r.get_area(); - if (preview) { - // Test if we can re-use the result from preview bucket fill - bool invalidate_cache = false; - // Area changed - if (r != bucket_cache_rect) { - _clear_bucket_cache(); - } - // Cache grid is not initialized - if (bucket_cache_visited == nullptr) { - bucket_cache_visited = new bool[area]; - invalidate_cache = true; - } - // Tile ID changed or position wasn't visited by the previous fill - const int loc = (p_start.x - r.position.x) + (p_start.y - r.position.y) * r.get_size().x; - const bool in_range = 0 <= loc && loc < area; - if (prev_id != bucket_cache_tile || (in_range && !bucket_cache_visited[loc])) { - invalidate_cache = true; - } - if (invalidate_cache) { - for (int i = 0; i < area; ++i) { - bucket_cache_visited[i] = false; - } - bucket_cache = PoolVector(); - bucket_cache_tile = prev_id; - bucket_cache_rect = r; - bucket_queue.clear(); - } - } - - PoolVector points; - Vector non_preview_cache; - int count = 0; - int limit = 0; - - if (preview) { - limit = 1024; - } else { - bucket_queue.clear(); - } - - bucket_queue.push_back(p_start); - - while (bucket_queue.size()) { - Point2i n = bucket_queue.front()->get(); - bucket_queue.pop_front(); - - if (!r.has_point(n)) { - continue; - } - - if (node->get_cell(n.x, n.y) == prev_id) { - if (preview) { - int loc = (n.x - r.position.x) + (n.y - r.position.y) * r.get_size().x; - if (bucket_cache_visited[loc]) { - continue; - } - bucket_cache_visited[loc] = true; - bucket_cache.push_back(n); - } else { - if (non_preview_cache.find(n) >= 0) { - continue; - } - points.push_back(n); - non_preview_cache.push_back(n); - } - - bucket_queue.push_back(Point2i(n.x, n.y + 1)); - bucket_queue.push_back(Point2i(n.x, n.y - 1)); - bucket_queue.push_back(Point2i(n.x + 1, n.y)); - bucket_queue.push_back(Point2i(n.x - 1, n.y)); - count++; - } - - if (limit > 0 && count >= limit) { - break; - } - } - - return preview ? bucket_cache : points; -} - -void TileMapEditor::_fill_points(const PoolVector &p_points, const Dictionary &p_op) { - int len = p_points.size(); - PoolVector::Read pr = p_points.read(); - - Vector ids = p_op["id"]; - bool xf = p_op["flip_h"]; - bool yf = p_op["flip_v"]; - bool tr = p_op["transpose"]; - - for (int i = 0; i < len; i++) { - _set_cell(pr[i], ids, xf, yf, tr); - node->make_bitmask_area_dirty(pr[i]); - } - if (!manual_autotile) { - node->update_dirty_bitmask(); - } -} - -void TileMapEditor::_erase_points(const PoolVector &p_points) { - int len = p_points.size(); - PoolVector::Read pr = p_points.read(); - - for (int i = 0; i < len; i++) { - _set_cell(pr[i], invalid_cell); - } -} - -void TileMapEditor::_select(const Point2i &p_from, const Point2i &p_to) { - Point2i begin = p_from; - Point2i end = p_to; - - if (begin.x > end.x) { - SWAP(begin.x, end.x); - } - if (begin.y > end.y) { - SWAP(begin.y, end.y); - } - - rectangle.position = begin; - rectangle.size = end - begin; - - CanvasItemEditor::get_singleton()->update_viewport(); -} - -void TileMapEditor::_erase_selection() { - if (!selection_active) { - return; - } - - for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) { - for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) { - _set_cell(Point2i(j, i), invalid_cell, false, false, false); - } - } -} - -void TileMapEditor::_draw_grid(Control *p_viewport, const Rect2 &p_rect) const { - if (!EDITOR_GET("editors/tile_map/display_grid")) { - return; - } - - const Transform2D cell_xf = node->get_cell_transform(); - const Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * node->get_global_transform(); - - // Fade the grid when the rendered cell size is relatively small. - const float cell_area = xform.xform(Rect2(Point2(), node->get_cell_size())).get_area(); - const float distance_fade = MIN(Math::inverse_lerp(4.0f, 64.0f, cell_area), 1.0f); - if (distance_fade <= 0) { - return; - } - const Color grid_color = Color(EDITOR_GET("editors/tile_map/grid_color")) * Color(1, 1, 1, distance_fade); - const Color axis_color = Color(EDITOR_GET("editors/tile_map/axis_color")) * Color(1, 1, 1, distance_fade); - - const int fade = 5; - const Rect2i si = p_rect.grow(fade); - - // When zoomed in, it's useful to clip the rendering. - Rect2i clipped; - { - const Transform2D xform_inv = xform.affine_inverse(); - const Size2 screen_size = p_viewport->get_size(); - Rect2 rect; - rect.position = node->world_to_map(xform_inv.xform(Vector2())); - rect.expand_to(node->world_to_map(xform_inv.xform(Vector2(0, screen_size.height))) + Vector2(0, 1)); - rect.expand_to(node->world_to_map(xform_inv.xform(Vector2(screen_size.width, 0))) + Vector2(1, 0)); - rect.expand_to(node->world_to_map(xform_inv.xform(screen_size)) + Vector2(1, 1)); - if (node->get_half_offset() != TileMap::HALF_OFFSET_DISABLED) { - rect.grow_by(1); // So it won't matter whether corners are on an odd or even row/column. - } - clipped = rect.clip(si); - } - clipped.position -= si.position; // Relative to the fade rect, in grid unit. - const Point2i clipped_end = clipped.position + clipped.size; - - if (clipped.has_no_area()) { - return; - } - - Vector points; - Vector colors; - - // Vertical lines. - if (node->get_half_offset() != TileMap::HALF_OFFSET_X && node->get_half_offset() != TileMap::HALF_OFFSET_NEGATIVE_X) { - points.resize(4); - colors.resize(4); - - for (int x = clipped.position.x; x <= clipped_end.x; x++) { - points.write[0] = xform.xform(node->map_to_world(si.position + Vector2(x, 0))); - points.write[1] = xform.xform(node->map_to_world(si.position + Vector2(x, fade))); - points.write[2] = xform.xform(node->map_to_world(si.position + Vector2(x, si.size.y - fade))); - points.write[3] = xform.xform(node->map_to_world(si.position + Vector2(x, si.size.y))); - - const Color color = (x + si.position.x == 0) ? axis_color : grid_color; - const float line_opacity = _lerp_fade(si.size.x, fade, x); - - colors.write[0] = Color(color.r, color.g, color.b, 0.0); - colors.write[1] = Color(color.r, color.g, color.b, color.a * line_opacity); - colors.write[2] = Color(color.r, color.g, color.b, color.a * line_opacity); - colors.write[3] = Color(color.r, color.g, color.b, 0.0); - - p_viewport->draw_polyline_colors(points, colors, 1); - } - } else { - const float half_offset = node->get_half_offset() == TileMap::HALF_OFFSET_X ? 0.5 : -0.5; - const int cell_count = clipped.size.y; - points.resize(cell_count * 2); - colors.resize(cell_count * 2); - - for (int x = clipped.position.x; x <= clipped_end.x; x++) { - const Color color = (x + si.position.x == 0) ? axis_color : grid_color; - const float line_opacity = _lerp_fade(si.size.x, fade, x); - - for (int y = clipped.position.y; y < clipped_end.y; y++) { - Vector2 ofs; - if (ABS(si.position.y + y) & 1) { - ofs = cell_xf[0] * half_offset; - } - const int index = (y - clipped.position.y) * 2; - points.write[index + 0] = xform.xform(ofs + node->map_to_world(si.position + Vector2(x, y), true)); - points.write[index + 1] = xform.xform(ofs + node->map_to_world(si.position + Vector2(x, y + 1), true)); - colors.write[index + 0] = Color(color.r, color.g, color.b, color.a * line_opacity * _lerp_fade(si.size.y, fade, y)); - colors.write[index + 1] = Color(color.r, color.g, color.b, color.a * line_opacity * _lerp_fade(si.size.y, fade, y + 1)); - } - p_viewport->draw_multiline_colors(points, colors, 1); - } - } - - // Horizontal lines. - if (node->get_half_offset() != TileMap::HALF_OFFSET_Y && node->get_half_offset() != TileMap::HALF_OFFSET_NEGATIVE_Y) { - points.resize(4); - colors.resize(4); - - for (int y = clipped.position.y; y <= clipped_end.y; y++) { - points.write[0] = xform.xform(node->map_to_world(si.position + Vector2(0, y))); - points.write[1] = xform.xform(node->map_to_world(si.position + Vector2(fade, y))); - points.write[2] = xform.xform(node->map_to_world(si.position + Vector2(si.size.x - fade, y))); - points.write[3] = xform.xform(node->map_to_world(si.position + Vector2(si.size.x, y))); - - const Color color = (y + si.position.y == 0) ? axis_color : grid_color; - const float line_opacity = _lerp_fade(si.size.y, fade, y); - - colors.write[0] = Color(color.r, color.g, color.b, 0.0); - colors.write[1] = Color(color.r, color.g, color.b, color.a * line_opacity); - colors.write[2] = Color(color.r, color.g, color.b, color.a * line_opacity); - colors.write[3] = Color(color.r, color.g, color.b, 0.0); - - p_viewport->draw_polyline_colors(points, colors, 1); - } - } else { - const float half_offset = node->get_half_offset() == TileMap::HALF_OFFSET_Y ? 0.5 : -0.5; - const int cell_count = clipped.size.x; - points.resize(cell_count * 2); - colors.resize(cell_count * 2); - - for (int y = clipped.position.y; y <= clipped_end.y; y++) { - const Color color = (y + si.position.y == 0) ? axis_color : grid_color; - const float line_opacity = _lerp_fade(si.size.y, fade, y); - - for (int x = clipped.position.x; x < clipped_end.x; x++) { - Vector2 ofs; - if (ABS(si.position.x + x) & 1) { - ofs = cell_xf[1] * half_offset; - } - const int index = (x - clipped.position.x) * 2; - points.write[index + 0] = xform.xform(ofs + node->map_to_world(si.position + Vector2(x, y), true)); - points.write[index + 1] = xform.xform(ofs + node->map_to_world(si.position + Vector2(x + 1, y), true)); - colors.write[index + 0] = Color(color.r, color.g, color.b, color.a * line_opacity * _lerp_fade(si.size.x, fade, x)); - colors.write[index + 1] = Color(color.r, color.g, color.b, color.a * line_opacity * _lerp_fade(si.size.x, fade, x + 1)); - } - p_viewport->draw_multiline_colors(points, colors, 1); - } - } -} - -void TileMapEditor::_draw_cell(Control *p_viewport, int p_cell, const Point2i &p_point, bool p_flip_h, bool p_flip_v, bool p_transpose, const Point2i &p_autotile_coord, const Transform2D &p_xform) { - if (!node->get_tileset()->has_tile(p_cell)) { - return; - } - - Ref t = node->get_tileset()->tile_get_texture(p_cell); - if (t.is_null()) { - return; - } - - Vector2 tile_ofs = node->get_tileset()->tile_get_texture_offset(p_cell); - - Rect2 r = node->get_tileset()->tile_get_region(p_cell); - if (node->get_tileset()->tile_get_tile_mode(p_cell) == TileSet::AUTO_TILE || node->get_tileset()->tile_get_tile_mode(p_cell) == TileSet::ATLAS_TILE) { - Vector2 offset; - if (tool != TOOL_PASTING) { - int selected = manual_palette->get_current(); - if ((manual_autotile || (node->get_tileset()->tile_get_tile_mode(p_cell) == TileSet::ATLAS_TILE && !priority_atlastile)) && selected != -1) { - offset = manual_palette->get_item_metadata(selected); - } else { - offset = node->get_tileset()->autotile_get_icon_coordinate(p_cell); - } - } else { - offset = p_autotile_coord; - } - - int spacing = node->get_tileset()->autotile_get_spacing(p_cell); - r.size = node->get_tileset()->autotile_get_size(p_cell); - r.position += (r.size + Vector2(spacing, spacing)) * offset; - } - Size2 cell_size = node->get_cell_size(); - bool centered_texture = node->is_centered_textures_enabled(); - bool compatibility_mode_enabled = node->is_compatibility_mode_enabled(); - Rect2 rect = Rect2(); - rect.position = node->map_to_world(p_point) + node->get_cell_draw_offset(); - - if (r.has_no_area()) { - rect.size = t->get_size(); - } else { - rect.size = r.size; - } - - if (compatibility_mode_enabled && !centered_texture) { - if (rect.size.y > rect.size.x) { - if ((p_flip_h && (p_flip_v || p_transpose)) || (p_flip_v && !p_transpose)) { - tile_ofs.y += rect.size.y - rect.size.x; - } - } else if (rect.size.y < rect.size.x) { - if ((p_flip_v && (p_flip_h || p_transpose)) || (p_flip_h && !p_transpose)) { - tile_ofs.x += rect.size.x - rect.size.y; - } - } - } - - if (p_transpose) { - SWAP(tile_ofs.x, tile_ofs.y); - if (centered_texture) { - rect.position.x += cell_size.x / 2 - rect.size.y / 2; - rect.position.y += cell_size.y / 2 - rect.size.x / 2; - } - } else if (centered_texture) { - rect.position += cell_size / 2 - rect.size / 2; - } - - if (p_flip_h) { - rect.size.x *= -1.0; - tile_ofs.x *= -1.0; - } - - if (p_flip_v) { - rect.size.y *= -1.0; - tile_ofs.y *= -1.0; - } - - if (compatibility_mode_enabled && !centered_texture) { - if (node->get_tile_origin() == TileMap::TILE_ORIGIN_TOP_LEFT) { - rect.position += tile_ofs; - } else if (node->get_tile_origin() == TileMap::TILE_ORIGIN_BOTTOM_LEFT) { - rect.position += tile_ofs; - - if (p_transpose) { - if (p_flip_h) { - rect.position.x -= cell_size.x; - } else { - rect.position.x += cell_size.x; - } - } else { - if (p_flip_v) { - rect.position.y -= cell_size.y; - } else { - rect.position.y += cell_size.y; - } - } - - } else if (node->get_tile_origin() == TileMap::TILE_ORIGIN_CENTER) { - rect.position += tile_ofs; - - if (p_flip_h) { - rect.position.x -= cell_size.x / 2; - } else { - rect.position.x += cell_size.x / 2; - } - - if (p_flip_v) { - rect.position.y -= cell_size.y / 2; - } else { - rect.position.y += cell_size.y / 2; - } - } - } else { - rect.position += tile_ofs; - } - - Color modulate = node->get_tileset()->tile_get_modulate(p_cell); - modulate.a = 0.5; - - Transform2D old_transform = p_viewport->get_viewport_transform(); - p_viewport->draw_set_transform_matrix(p_xform); // Take into account TileMap transformation when displaying cell - if (r.has_no_area()) { - p_viewport->draw_texture_rect(t, rect, false, modulate, p_transpose); - } else { - p_viewport->draw_texture_rect_region(t, rect, r, modulate, p_transpose); - } - p_viewport->draw_set_transform_matrix(old_transform); -} - -void TileMapEditor::_draw_fill_preview(Control *p_viewport, int p_cell, const Point2i &p_point, bool p_flip_h, bool p_flip_v, bool p_transpose, const Point2i &p_autotile_coord, const Transform2D &p_xform) { - PoolVector points = _bucket_fill(p_point, false, true); - PoolVector::Read pr = points.read(); - int len = points.size(); - - for (int i = 0; i < len; ++i) { - _draw_cell(p_viewport, p_cell, pr[i], p_flip_h, p_flip_v, p_transpose, p_autotile_coord, p_xform); - } -} - -void TileMapEditor::_clear_bucket_cache() { - if (bucket_cache_visited) { - delete[] bucket_cache_visited; - bucket_cache_visited = nullptr; - } -} - -void TileMapEditor::_update_copydata() { - copydata.clear(); - - if (!selection_active) { - return; - } - - for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) { - for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) { - TileData tcd; - - tcd.cell = node->get_cell(j, i); - if (tcd.cell != TileMap::INVALID_CELL) { - tcd.pos = Point2i(j, i); - tcd.flip_h = node->is_cell_x_flipped(j, i); - tcd.flip_v = node->is_cell_y_flipped(j, i); - tcd.transpose = node->is_cell_transposed(j, i); - tcd.autotile_coord = node->get_cell_autotile_coord(j, i); - - copydata.push_back(tcd); - } - } - } -} - -static inline Vector line(int x0, int x1, int y0, int y1) { - Vector points; - - float dx = ABS(x1 - x0); - float dy = ABS(y1 - y0); - - int x = x0; - int y = y0; - - int sx = x0 > x1 ? -1 : 1; - int sy = y0 > y1 ? -1 : 1; - - if (dx > dy) { - float err = dx / 2; - - for (; x != x1; x += sx) { - points.push_back(Vector2(x, y)); - - err -= dy; - if (err < 0) { - y += sy; - err += dx; - } - } - } else { - float err = dy / 2; - - for (; y != y1; y += sy) { - points.push_back(Vector2(x, y)); - - err -= dx; - if (err < 0) { - x += sx; - err += dy; - } - } - } - - points.push_back(Vector2(x, y)); - - return points; -} - -bool TileMapEditor::forward_gui_input(const Ref &p_event) { - if (!node || !node->get_tileset().is_valid() || !node->is_visible_in_tree() || CanvasItemEditor::get_singleton()->get_current_tool() != CanvasItemEditor::TOOL_SELECT) { - return false; - } - - Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * node->get_global_transform(); - Transform2D xform_inv = xform.affine_inverse(); - - Ref mb = p_event; - - if (mb.is_valid()) { - if (mb->get_button_index() == BUTTON_LEFT) { - if (mb->is_pressed()) { - if (Input::get_singleton()->is_key_pressed(KEY_SPACE)) { - return false; // Drag. - } - - if (tool == TOOL_NONE) { - if (mb->get_shift()) { - if (mb->get_command()) { - tool = TOOL_RECTANGLE_PAINT; - } else { - tool = TOOL_LINE_PAINT; - } - - selection_active = false; - rectangle_begin = over_tile; - - _update_button_tool(); - return true; - } - - if (mb->get_command()) { - tool = TOOL_PICKING; - _pick_tile(over_tile); - _update_button_tool(); - - return true; - } - - tool = TOOL_PAINTING; - _update_button_tool(); - } - - if (tool == TOOL_PAINTING) { - Vector ids = get_selected_tiles(); - - if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) { - tool = TOOL_PAINTING; - - _start_undo(TTR("Paint TileMap")); - } - } else if (tool == TOOL_PICKING) { - _pick_tile(over_tile); - } else if (tool == TOOL_SELECTING) { - selection_active = true; - rectangle_begin = over_tile; - } - - _update_button_tool(); - return true; - - } else { - // Mousebutton was released. - if (tool != TOOL_NONE) { - if (tool == TOOL_PAINTING) { - Vector ids = get_selected_tiles(); - - if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) { - _set_cell(over_tile, ids, flip_h, flip_v, transpose); - _finish_undo(); - - paint_undo.clear(); - } - } else if (tool == TOOL_LINE_PAINT) { - Vector ids = get_selected_tiles(); - - if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) { - _start_undo(TTR("Line Draw")); - for (Map::Element *E = paint_undo.front(); E; E = E->next()) { - _set_cell(E->key(), ids, flip_h, flip_v, transpose); - } - _finish_undo(); - - paint_undo.clear(); - - CanvasItemEditor::get_singleton()->update_viewport(); - } - } else if (tool == TOOL_RECTANGLE_PAINT) { - Vector ids = get_selected_tiles(); - - if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) { - _start_undo(TTR("Rectangle Paint")); - for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) { - for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) { - _set_cell(Point2i(j, i), ids, flip_h, flip_v, transpose); - } - } - _finish_undo(); - - CanvasItemEditor::get_singleton()->update_viewport(); - } - } else if (tool == TOOL_PASTING) { - Point2 ofs = over_tile - rectangle.position; - Vector ids; - - _start_undo(TTR("Paste")); - ids.push_back(0); - for (List::Element *E = copydata.front(); E; E = E->next()) { - ids.write[0] = E->get().cell; - _set_cell(E->get().pos + ofs, ids, E->get().flip_h, E->get().flip_v, E->get().transpose, E->get().autotile_coord); - } - _finish_undo(); - - CanvasItemEditor::get_singleton()->update_viewport(); - - return true; // We want to keep the Pasting tool. - } else if (tool == TOOL_SELECTING) { - CanvasItemEditor::get_singleton()->update_viewport(); - - } else if (tool == TOOL_BUCKET) { - PoolVector points = _bucket_fill(over_tile); - - if (points.size() == 0) { - return false; - } - - _start_undo(TTR("Bucket Fill")); - - Dictionary op; - op["id"] = get_selected_tiles(); - op["flip_h"] = flip_h; - op["flip_v"] = flip_v; - op["transpose"] = transpose; - - _fill_points(points, op); - - _finish_undo(); - - // So the fill preview is cleared right after the click. - CanvasItemEditor::get_singleton()->update_viewport(); - - // We want to keep the bucket-tool active. - return true; - } - - tool = TOOL_NONE; - _update_button_tool(); - - return true; - } - } - } else if (mb->get_button_index() == BUTTON_RIGHT) { - if (mb->is_pressed()) { - if (tool == TOOL_SELECTING || selection_active) { - tool = TOOL_NONE; - selection_active = false; - - CanvasItemEditor::get_singleton()->update_viewport(); - - _update_button_tool(); - return true; - } - - if (tool == TOOL_PASTING) { - tool = TOOL_NONE; - copydata.clear(); - - CanvasItemEditor::get_singleton()->update_viewport(); - - _update_button_tool(); - return true; - } - - if (tool == TOOL_NONE) { - paint_undo.clear(); - - Point2 local = node->world_to_map(xform_inv.xform(mb->get_position())); - - _start_undo(TTR("Erase TileMap")); - - if (mb->get_shift()) { - if (mb->get_command()) { - tool = TOOL_RECTANGLE_ERASE; - } else { - tool = TOOL_LINE_ERASE; - } - - selection_active = false; - rectangle_begin = local; - } else { - tool = TOOL_ERASING; - - _set_cell(local, invalid_cell); - } - - _update_button_tool(); - return true; - } - - } else { - if (tool == TOOL_ERASING || tool == TOOL_RECTANGLE_ERASE || tool == TOOL_LINE_ERASE) { - _finish_undo(); - - if (tool == TOOL_RECTANGLE_ERASE || tool == TOOL_LINE_ERASE) { - CanvasItemEditor::get_singleton()->update_viewport(); - } - - tool = TOOL_NONE; - - _update_button_tool(); - return true; - - } else if (tool == TOOL_BUCKET) { - Vector ids; - ids.push_back(node->get_cell(over_tile.x, over_tile.y)); - Dictionary pop; - pop["id"] = ids; - pop["flip_h"] = node->is_cell_x_flipped(over_tile.x, over_tile.y); - pop["flip_v"] = node->is_cell_y_flipped(over_tile.x, over_tile.y); - pop["transpose"] = node->is_cell_transposed(over_tile.x, over_tile.y); - - PoolVector points = _bucket_fill(over_tile, true); - - if (points.size() == 0) { - return false; - } - - undo_redo->create_action(TTR("Bucket Fill")); - - undo_redo->add_do_method(this, "_erase_points", points); - undo_redo->add_undo_method(this, "_fill_points", points, pop); - - undo_redo->commit_action(); - } - } - } - } - - Ref mm = p_event; - - if (mm.is_valid()) { - Point2i new_over_tile = node->world_to_map(xform_inv.xform(mm->get_position())); - Point2i old_over_tile = over_tile; - - if (new_over_tile != over_tile) { - over_tile = new_over_tile; - CanvasItemEditor::get_singleton()->update_viewport(); - } - - if (refocus_over_tile) { - // editor lost focus; forget last tile position - old_over_tile = new_over_tile; - refocus_over_tile = false; - } - - int tile_under = node->get_cell(over_tile.x, over_tile.y); - String tile_name = "none"; - - if (node->get_tileset()->has_tile(tile_under)) { - tile_name = node->get_tileset()->tile_get_name(tile_under); - } - tile_info->show(); - tile_info->set_text(String::num(over_tile.x) + ", " + String::num(over_tile.y) + " [" + tile_name + "]"); - - if (tool == TOOL_PAINTING) { - // Paint using bresenham line to prevent holes in painting if the user moves fast. - - Vector points = line(old_over_tile.x, over_tile.x, old_over_tile.y, over_tile.y); - Vector ids = get_selected_tiles(); - - for (int i = 0; i < points.size(); ++i) { - Point2i pos = points[i]; - - if (!paint_undo.has(pos)) { - paint_undo[pos] = _get_op_from_cell(pos); - } - - _set_cell(pos, ids, flip_h, flip_v, transpose); - } - - return true; - } - - if (tool == TOOL_ERASING) { - // Erase using bresenham line to prevent holes in painting if the user moves fast. - - Vector points = line(old_over_tile.x, over_tile.x, old_over_tile.y, over_tile.y); - - for (int i = 0; i < points.size(); ++i) { - Point2i pos = points[i]; - - _set_cell(pos, invalid_cell); - } - - return true; - } - - if (tool == TOOL_SELECTING) { - _select(rectangle_begin, over_tile); - - return true; - } - - if (tool == TOOL_LINE_PAINT || tool == TOOL_LINE_ERASE) { - Vector ids = get_selected_tiles(); - Vector tmp_cell; - bool erasing = (tool == TOOL_LINE_ERASE); - - tmp_cell.push_back(0); - if (erasing && paint_undo.size()) { - for (Map::Element *E = paint_undo.front(); E; E = E->next()) { - tmp_cell.write[0] = E->get().idx; - _set_cell(E->key(), tmp_cell, E->get().xf, E->get().yf, E->get().tr); - } - } - - paint_undo.clear(); - - if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) { - Vector points = line(rectangle_begin.x, over_tile.x, rectangle_begin.y, over_tile.y); - - for (int i = 0; i < points.size(); i++) { - paint_undo[points[i]] = _get_op_from_cell(points[i]); - - if (erasing) { - _set_cell(points[i], invalid_cell); - } - } - - CanvasItemEditor::get_singleton()->update_viewport(); - } - - return true; - } - if (tool == TOOL_RECTANGLE_PAINT || tool == TOOL_RECTANGLE_ERASE) { - Vector tmp_cell; - tmp_cell.push_back(0); - - _select(rectangle_begin, over_tile); - - if (tool == TOOL_RECTANGLE_ERASE) { - if (paint_undo.size()) { - for (Map::Element *E = paint_undo.front(); E; E = E->next()) { - tmp_cell.write[0] = E->get().idx; - _set_cell(E->key(), tmp_cell, E->get().xf, E->get().yf, E->get().tr); - } - } - - paint_undo.clear(); - - for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) { - for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) { - Point2i tile = Point2i(j, i); - paint_undo[tile] = _get_op_from_cell(tile); - - _set_cell(tile, invalid_cell); - } - } - } - - return true; - } - if (tool == TOOL_PICKING && Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT)) { - _pick_tile(over_tile); - - return true; - } - } - - Ref k = p_event; - - if (k.is_valid() && k->is_pressed()) { - if (last_tool == TOOL_NONE && tool == TOOL_PICKING && k->get_scancode() == KEY_SHIFT && k->get_command()) { - // trying to draw a rectangle with the painting tool, so change to the correct tool - tool = last_tool; - - CanvasItemEditor::get_singleton()->update_viewport(); - _update_button_tool(); - } - - if (k->get_scancode() == KEY_ESCAPE) { - if (tool == TOOL_PASTING) { - copydata.clear(); - } else if (tool == TOOL_SELECTING || selection_active) { - selection_active = false; - } - - tool = TOOL_NONE; - - CanvasItemEditor::get_singleton()->update_viewport(); - - _update_button_tool(); - return true; - } - - if (!mouse_over) { - // Editor shortcuts should not fire if mouse not in viewport. - return false; - } - - if (ED_IS_SHORTCUT("tile_map_editor/paint_tile", p_event)) { - // NOTE: We do not set tool = TOOL_PAINTING as this begins painting - // immediately without pressing the left mouse button first. - tool = TOOL_NONE; - CanvasItemEditor::get_singleton()->update_viewport(); - - _update_button_tool(); - return true; - } - if (ED_IS_SHORTCUT("tile_map_editor/bucket_fill", p_event)) { - tool = TOOL_BUCKET; - CanvasItemEditor::get_singleton()->update_viewport(); - - _update_button_tool(); - return true; - } - if (ED_IS_SHORTCUT("tile_map_editor/erase_selection", p_event)) { - _menu_option(OPTION_ERASE_SELECTION); - - _update_button_tool(); - return true; - } - if (ED_IS_SHORTCUT("tile_map_editor/select", p_event)) { - tool = TOOL_SELECTING; - selection_active = false; - - CanvasItemEditor::get_singleton()->update_viewport(); - - _update_button_tool(); - return true; - } - if (ED_IS_SHORTCUT("tile_map_editor/copy_selection", p_event)) { - _update_copydata(); - - if (selection_active) { - tool = TOOL_PASTING; - - CanvasItemEditor::get_singleton()->update_viewport(); - - _update_button_tool(); - return true; - } - } - if (ED_IS_SHORTCUT("tile_map_editor/cut_selection", p_event)) { - if (selection_active) { - _update_copydata(); - - _start_undo(TTR("Cut Selection")); - _erase_selection(); - _finish_undo(); - - selection_active = false; - - tool = TOOL_PASTING; - - CanvasItemEditor::get_singleton()->update_viewport(); - _update_button_tool(); - return true; - } - } - if (ED_IS_SHORTCUT("tile_map_editor/find_tile", p_event)) { - search_box->select_all(); - search_box->grab_focus(); - - return true; - } - if (ED_IS_SHORTCUT("tile_map_editor/rotate_left", p_event)) { - _rotate(-1); - CanvasItemEditor::get_singleton()->update_viewport(); - return true; - } - if (ED_IS_SHORTCUT("tile_map_editor/rotate_right", p_event)) { - _rotate(1); - CanvasItemEditor::get_singleton()->update_viewport(); - return true; - } - if (ED_IS_SHORTCUT("tile_map_editor/flip_horizontal", p_event)) { - _flip_horizontal(); - CanvasItemEditor::get_singleton()->update_viewport(); - return true; - } - if (ED_IS_SHORTCUT("tile_map_editor/flip_vertical", p_event)) { - _flip_vertical(); - CanvasItemEditor::get_singleton()->update_viewport(); - return true; - } - if (ED_IS_SHORTCUT("tile_map_editor/clear_transform", p_event)) { - _clear_transform(); - CanvasItemEditor::get_singleton()->update_viewport(); - return true; - } - if (ED_IS_SHORTCUT("tile_map_editor/transpose", p_event)) { - transpose = !transpose; - _update_palette(); - CanvasItemEditor::get_singleton()->update_viewport(); - return true; - } - } else if (k.is_valid()) { // Release event. - - if (tool == TOOL_NONE) { - if (k->get_scancode() == KEY_SHIFT && k->get_command()) { - tool = TOOL_PICKING; - _update_button_tool(); - } - } else if (tool == TOOL_PICKING) { -#ifdef APPLE_STYLE_KEYS - if (k->get_scancode() == KEY_META) { -#else - if (k->get_scancode() == KEY_CONTROL) { -#endif - // Go back to that last tool if KEY_CONTROL was released. - tool = last_tool; - - CanvasItemEditor::get_singleton()->update_viewport(); - _update_button_tool(); - } - } - } - return false; -} - -void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { - if (!node || CanvasItemEditor::get_singleton()->get_current_tool() != CanvasItemEditor::TOOL_SELECT) { - return; - } - - _draw_grid(p_overlay, node->get_used_rect()); - - const Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * node->get_global_transform(); - const Transform2D cell_xf = node->get_cell_transform(); - - if (selection_active) { - Vector points; - points.push_back(xform.xform(node->map_to_world((rectangle.position)))); - points.push_back(xform.xform(node->map_to_world((rectangle.position + Point2(rectangle.size.x + 1, 0))))); - points.push_back(xform.xform(node->map_to_world((rectangle.position + Point2(rectangle.size.x + 1, rectangle.size.y + 1))))); - points.push_back(xform.xform(node->map_to_world((rectangle.position + Point2(0, rectangle.size.y + 1))))); - - p_overlay->draw_colored_polygon(points, Color(0.2, 0.8, 1, 0.4)); - } - - if (mouse_over && node->get_tileset().is_valid()) { - Vector2 endpoints[4] = { - node->map_to_world(over_tile, true), - node->map_to_world((over_tile + Point2(1, 0)), true), - node->map_to_world((over_tile + Point2(1, 1)), true), - node->map_to_world((over_tile + Point2(0, 1)), true) - }; - - for (int i = 0; i < 4; i++) { - if (node->get_half_offset() == TileMap::HALF_OFFSET_X && ABS(over_tile.y) & 1) { - endpoints[i] += cell_xf[0] * 0.5; - } - if (node->get_half_offset() == TileMap::HALF_OFFSET_NEGATIVE_X && ABS(over_tile.y) & 1) { - endpoints[i] += cell_xf[0] * -0.5; - } - if (node->get_half_offset() == TileMap::HALF_OFFSET_Y && ABS(over_tile.x) & 1) { - endpoints[i] += cell_xf[1] * 0.5; - } - if (node->get_half_offset() == TileMap::HALF_OFFSET_NEGATIVE_Y && ABS(over_tile.x) & 1) { - endpoints[i] += cell_xf[1] * -0.5; - } - endpoints[i] = xform.xform(endpoints[i]); - } - Color col; - if (node->get_cell(over_tile.x, over_tile.y) != TileMap::INVALID_CELL) { - col = Color(0.2, 0.8, 1.0, 0.8); - } else { - col = Color(1.0, 0.4, 0.2, 0.8); - } - - for (int i = 0; i < 4; i++) { - p_overlay->draw_line(endpoints[i], endpoints[(i + 1) % 4], col, 2); - } - - bool bucket_preview = EditorSettings::get_singleton()->get("editors/tile_map/bucket_fill_preview"); - if (tool == TOOL_SELECTING || tool == TOOL_PICKING || !bucket_preview) { - return; - } - - if (tool == TOOL_LINE_PAINT) { - if (paint_undo.empty()) { - return; - } - - Vector ids = get_selected_tiles(); - - if (ids.size() == 1 && ids[0] == TileMap::INVALID_CELL) { - return; - } - - // Making a Rect2i that encloses all the cells in paint_undo. - // I wonder if there is a cleaner way to do it. - const Point2i first_pos = paint_undo.front()->key(); - int left = first_pos.x; - int right = first_pos.x; - int top = first_pos.y; - int bottom = first_pos.y; - for (Map::Element *E = paint_undo.front()->next(); E; E = E->next()) { - const Point2i &pos = E->key(); - left = MIN(pos.x, left); - right = MAX(pos.x, right); - top = MIN(pos.y, top); - bottom = MAX(pos.y, bottom); - } - _draw_grid(p_overlay, Rect2i(left, top, right - left + 1, bottom - top + 1)); - - for (Map::Element *E = paint_undo.front(); E; E = E->next()) { - _draw_cell(p_overlay, ids[0], E->key(), flip_h, flip_v, transpose, autotile_coord, xform); - } - - } else if (tool == TOOL_RECTANGLE_PAINT) { - Vector ids = get_selected_tiles(); - - if (ids.size() == 1 && ids[0] == TileMap::INVALID_CELL) { - return; - } - - _draw_grid(p_overlay, rectangle); - - for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) { - for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) { - _draw_cell(p_overlay, ids[0], Point2i(j, i), flip_h, flip_v, transpose, autotile_coord, xform); - } - } - } else if (tool == TOOL_PASTING) { - if (copydata.empty()) { - return; - } - - Ref ts = node->get_tileset(); - - if (ts.is_null()) { - return; - } - - Point2 ofs = over_tile - rectangle.position; - - for (List::Element *E = copydata.front(); E; E = E->next()) { - if (!ts->has_tile(E->get().cell)) { - continue; - } - - TileData tcd = E->get(); - - _draw_cell(p_overlay, tcd.cell, tcd.pos + ofs, tcd.flip_h, tcd.flip_v, tcd.transpose, tcd.autotile_coord, xform); - } - - Rect2i duplicate = rectangle; - duplicate.position = over_tile; - - Vector points; - points.push_back(xform.xform(node->map_to_world(duplicate.position))); - points.push_back(xform.xform(node->map_to_world((duplicate.position + Point2(duplicate.size.x + 1, 0))))); - points.push_back(xform.xform(node->map_to_world((duplicate.position + Point2(duplicate.size.x + 1, duplicate.size.y + 1))))); - points.push_back(xform.xform(node->map_to_world((duplicate.position + Point2(0, duplicate.size.y + 1))))); - - p_overlay->draw_colored_polygon(points, Color(0.2, 1.0, 0.8, 0.2)); - - } else if (tool == TOOL_BUCKET) { - Vector tiles = get_selected_tiles(); - _draw_fill_preview(p_overlay, tiles[0], over_tile, flip_h, flip_v, transpose, autotile_coord, xform); - - } else { - Vector st = get_selected_tiles(); - - if (st.size() == 1 && st[0] == TileMap::INVALID_CELL) { - return; - } - - _draw_grid(p_overlay, Rect2(over_tile, Size2(1, 1))); - _draw_cell(p_overlay, st[0], over_tile, flip_h, flip_v, transpose, autotile_coord, xform); - } - } -} - -void TileMapEditor::edit(Node *p_tile_map) { - search_box->set_text(""); - - if (!canvas_item_editor_viewport) { - canvas_item_editor_viewport = CanvasItemEditor::get_singleton()->get_viewport_control(); - } - - if (node && node->is_connected("settings_changed", this, "_tileset_settings_changed")) { - node->disconnect("settings_changed", this, "_tileset_settings_changed"); - } - - if (p_tile_map) { - node = Object::cast_to(p_tile_map); - if (!canvas_item_editor_viewport->is_connected("mouse_entered", this, "_canvas_mouse_enter")) { - canvas_item_editor_viewport->connect("mouse_entered", this, "_canvas_mouse_enter"); - } - if (!canvas_item_editor_viewport->is_connected("mouse_exited", this, "_canvas_mouse_exit")) { - canvas_item_editor_viewport->connect("mouse_exited", this, "_canvas_mouse_exit"); - } - - _update_palette(); - - } else { - node = nullptr; - - if (canvas_item_editor_viewport->is_connected("mouse_entered", this, "_canvas_mouse_enter")) { - canvas_item_editor_viewport->disconnect("mouse_entered", this, "_canvas_mouse_enter"); - } - if (canvas_item_editor_viewport->is_connected("mouse_exited", this, "_canvas_mouse_exit")) { - canvas_item_editor_viewport->disconnect("mouse_exited", this, "_canvas_mouse_exit"); - } - - _update_palette(); - } - - if (node && !node->is_connected("settings_changed", this, "_tileset_settings_changed")) { - node->connect("settings_changed", this, "_tileset_settings_changed"); - } - - _clear_bucket_cache(); -} - -void TileMapEditor::_tileset_settings_changed() { - _update_palette(); - CanvasItemEditor::get_singleton()->update_viewport(); -} - -void TileMapEditor::_icon_size_changed(float p_value) { - if (node) { - palette->set_icon_scale(p_value); - manual_palette->set_icon_scale(p_value); - _update_palette(); - } -} - -void TileMapEditor::_bind_methods() { - ClassDB::bind_method(D_METHOD("_manual_toggled"), &TileMapEditor::_manual_toggled); - ClassDB::bind_method(D_METHOD("_priority_toggled"), &TileMapEditor::_priority_toggled); - ClassDB::bind_method(D_METHOD("_text_entered"), &TileMapEditor::_text_entered); - ClassDB::bind_method(D_METHOD("_text_changed"), &TileMapEditor::_text_changed); - ClassDB::bind_method(D_METHOD("_sbox_input"), &TileMapEditor::_sbox_input); - ClassDB::bind_method(D_METHOD("_button_tool_select"), &TileMapEditor::_button_tool_select); - ClassDB::bind_method(D_METHOD("_menu_option"), &TileMapEditor::_menu_option); - ClassDB::bind_method(D_METHOD("_canvas_mouse_enter"), &TileMapEditor::_canvas_mouse_enter); - ClassDB::bind_method(D_METHOD("_canvas_mouse_exit"), &TileMapEditor::_canvas_mouse_exit); - ClassDB::bind_method(D_METHOD("_tileset_settings_changed"), &TileMapEditor::_tileset_settings_changed); - ClassDB::bind_method(D_METHOD("_rotate"), &TileMapEditor::_rotate); - ClassDB::bind_method(D_METHOD("_flip_horizontal"), &TileMapEditor::_flip_horizontal); - ClassDB::bind_method(D_METHOD("_flip_vertical"), &TileMapEditor::_flip_vertical); - ClassDB::bind_method(D_METHOD("_clear_transform"), &TileMapEditor::_clear_transform); - ClassDB::bind_method(D_METHOD("_palette_selected"), &TileMapEditor::_palette_selected); - ClassDB::bind_method(D_METHOD("_palette_multi_selected"), &TileMapEditor::_palette_multi_selected); - ClassDB::bind_method(D_METHOD("_palette_input"), &TileMapEditor::_palette_input); - - ClassDB::bind_method(D_METHOD("_fill_points"), &TileMapEditor::_fill_points); - ClassDB::bind_method(D_METHOD("_erase_points"), &TileMapEditor::_erase_points); - - ClassDB::bind_method(D_METHOD("_icon_size_changed"), &TileMapEditor::_icon_size_changed); - ClassDB::bind_method(D_METHOD("_node_removed"), &TileMapEditor::_node_removed); -} - -TileMapEditor::CellOp TileMapEditor::_get_op_from_cell(const Point2i &p_pos) { - CellOp op; - op.idx = node->get_cell(p_pos.x, p_pos.y); - if (op.idx != TileMap::INVALID_CELL) { - if (node->is_cell_x_flipped(p_pos.x, p_pos.y)) { - op.xf = true; - } - if (node->is_cell_y_flipped(p_pos.x, p_pos.y)) { - op.yf = true; - } - if (node->is_cell_transposed(p_pos.x, p_pos.y)) { - op.tr = true; - } - op.ac = node->get_cell_autotile_coord(p_pos.x, p_pos.y); - } - return op; -} - -void TileMapEditor::_rotate(int steps) { - const bool normal_rotation_matrix[][3] = { - { false, false, false }, - { true, true, false }, - { false, true, true }, - { true, false, true } - }; - - const bool mirrored_rotation_matrix[][3] = { - { false, true, false }, - { true, true, true }, - { false, false, true }, - { true, false, false } - }; - - if (transpose ^ flip_h ^ flip_v) { - // Odd number of flags activated = mirrored rotation - for (int i = 0; i < 4; i++) { - if (transpose == mirrored_rotation_matrix[i][0] && - flip_h == mirrored_rotation_matrix[i][1] && - flip_v == mirrored_rotation_matrix[i][2]) { - int new_id = Math::wrapi(i + steps, 0, 4); - transpose = mirrored_rotation_matrix[new_id][0]; - flip_h = mirrored_rotation_matrix[new_id][1]; - flip_v = mirrored_rotation_matrix[new_id][2]; - break; - } - } - } else { - // Even number of flags activated = normal rotation - for (int i = 0; i < 4; i++) { - if (transpose == normal_rotation_matrix[i][0] && - flip_h == normal_rotation_matrix[i][1] && - flip_v == normal_rotation_matrix[i][2]) { - int new_id = Math::wrapi(i + steps, 0, 4); - transpose = normal_rotation_matrix[new_id][0]; - flip_h = normal_rotation_matrix[new_id][1]; - flip_v = normal_rotation_matrix[new_id][2]; - break; - } - } - } - - _update_palette(); -} - -void TileMapEditor::_flip_horizontal() { - flip_h = !flip_h; - _update_palette(); -} - -void TileMapEditor::_flip_vertical() { - flip_v = !flip_v; - _update_palette(); -} - -void TileMapEditor::_clear_transform() { - transpose = false; - flip_h = false; - flip_v = false; - _update_palette(); -} - -TileMapEditor::TileMapEditor(EditorNode *p_editor) { - node = nullptr; - manual_autotile = false; - priority_atlastile = false; - manual_position = Vector2(0, 0); - canvas_item_editor_viewport = nullptr; - editor = p_editor; - undo_redo = EditorNode::get_undo_redo(); - - tool = TOOL_NONE; - selection_active = false; - mouse_over = false; - - flip_h = false; - flip_v = false; - transpose = false; - - bucket_cache_tile = -1; - bucket_cache_visited = nullptr; - - invalid_cell.resize(1); - invalid_cell.write[0] = TileMap::INVALID_CELL; - - ED_SHORTCUT("tile_map_editor/erase_selection", TTR("Erase Selection"), KEY_DELETE); - ED_SHORTCUT("tile_map_editor/find_tile", TTR("Find Tile"), KEY_MASK_CMD + KEY_F); - ED_SHORTCUT("tile_map_editor/transpose", TTR("Transpose"), KEY_T); - - HBoxContainer *tool_hb = memnew(HBoxContainer); - add_child(tool_hb); - - manual_button = memnew(CheckBox); - manual_button->set_text(TTR("Disable Autotile")); - manual_button->connect("toggled", this, "_manual_toggled"); - add_child(manual_button); - - priority_button = memnew(CheckBox); - priority_button->set_text(TTR("Enable Priority")); - priority_button->connect("toggled", this, "_priority_toggled"); - add_child(priority_button); - - search_box = memnew(LineEdit); - search_box->set_placeholder(TTR("Filter tiles")); - search_box->set_h_size_flags(SIZE_EXPAND_FILL); - search_box->connect("text_entered", this, "_text_entered"); - search_box->connect("text_changed", this, "_text_changed"); - search_box->connect("gui_input", this, "_sbox_input"); - add_child(search_box); - - size_slider = memnew(HSlider); - size_slider->set_h_size_flags(SIZE_EXPAND_FILL); - size_slider->set_min(0.1f); - size_slider->set_max(4.0f); - size_slider->set_step(0.1f); - size_slider->set_value(1.0f); - size_slider->connect("value_changed", this, "_icon_size_changed"); - add_child(size_slider); - - int mw = EDITOR_GET("editors/tile_map/palette_min_width"); - - VSplitContainer *palette_container = memnew(VSplitContainer); - palette_container->set_v_size_flags(SIZE_EXPAND_FILL); - palette_container->set_custom_minimum_size(Size2(mw, 0)); - add_child(palette_container); - - // Add tile palette. - palette = memnew(ItemList); - palette->set_h_size_flags(SIZE_EXPAND_FILL); - palette->set_v_size_flags(SIZE_EXPAND_FILL); - palette->set_max_columns(0); - palette->set_icon_mode(ItemList::ICON_MODE_TOP); - palette->set_max_text_lines(2); - palette->set_select_mode(ItemList::SELECT_MULTI); - palette->add_constant_override("vseparation", 8 * EDSCALE); - palette->connect("item_selected", this, "_palette_selected"); - palette->connect("multi_selected", this, "_palette_multi_selected"); - palette->connect("gui_input", this, "_palette_input"); - palette_container->add_child(palette); - - // Add message for when no texture is selected. - info_message = memnew(Label); - info_message->set_text(TTR("Give a TileSet resource to this TileMap to use its tiles.")); - info_message->set_valign(Label::VALIGN_CENTER); - info_message->set_align(Label::ALIGN_CENTER); - info_message->set_autowrap(true); - info_message->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); - info_message->set_anchors_and_margins_preset(PRESET_WIDE, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); - palette->add_child(info_message); - - // Add autotile override palette. - manual_palette = memnew(ItemList); - manual_palette->set_h_size_flags(SIZE_EXPAND_FILL); - manual_palette->set_v_size_flags(SIZE_EXPAND_FILL); - manual_palette->set_max_columns(0); - manual_palette->set_icon_mode(ItemList::ICON_MODE_TOP); - manual_palette->set_max_text_lines(2); - manual_palette->hide(); - palette_container->add_child(manual_palette); - - // Add menu items. - toolbar = memnew(HBoxContainer); - toolbar->hide(); - CanvasItemEditor::get_singleton()->add_control_to_menu_panel(toolbar); - - toolbar->add_child(memnew(VSeparator)); - - // Tools. - paint_button = memnew(ToolButton); - paint_button->set_shortcut(ED_SHORTCUT("tile_map_editor/paint_tile", TTR("Paint Tile"), KEY_P)); -#ifdef OSX_ENABLED - paint_button->set_tooltip(TTR("Shift+LMB: Line Draw\nShift+Command+LMB: Rectangle Paint")); -#else - paint_button->set_tooltip(TTR("Shift+LMB: Line Draw\nShift+Ctrl+LMB: Rectangle Paint")); -#endif - paint_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_NONE)); - paint_button->set_toggle_mode(true); - toolbar->add_child(paint_button); - - bucket_fill_button = memnew(ToolButton); - bucket_fill_button->set_shortcut(ED_SHORTCUT("tile_map_editor/bucket_fill", TTR("Bucket Fill"), KEY_B)); - bucket_fill_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_BUCKET)); - bucket_fill_button->set_toggle_mode(true); - toolbar->add_child(bucket_fill_button); - - picker_button = memnew(ToolButton); - picker_button->set_shortcut(ED_SHORTCUT("tile_map_editor/pick_tile", TTR("Pick Tile"), KEY_I)); - picker_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_PICKING)); - picker_button->set_toggle_mode(true); - toolbar->add_child(picker_button); - - select_button = memnew(ToolButton); - select_button->set_shortcut(ED_SHORTCUT("tile_map_editor/select", TTR("Select"), KEY_M)); - select_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_SELECTING)); - select_button->set_toggle_mode(true); - toolbar->add_child(select_button); - - _update_button_tool(); - - // Container to the right of the toolbar. - toolbar_right = memnew(HBoxContainer); - toolbar_right->hide(); - toolbar_right->set_h_size_flags(SIZE_EXPAND_FILL); - toolbar_right->set_alignment(BoxContainer::ALIGN_END); - CanvasItemEditor::get_singleton()->add_control_to_menu_panel(toolbar_right); - - // Tile position. - tile_info = memnew(Label); - tile_info->set_modulate(Color(1, 1, 1, 0.8)); - tile_info->set_mouse_filter(MOUSE_FILTER_IGNORE); - tile_info->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("main", "EditorFonts")); - tile_info->add_color_override("font_color", Color(1, 1, 1, 0.8)); // Overlay has a fixed dark background. - // The tile info is only displayed after a tile has been hovered. - tile_info->hide(); - CanvasItemEditor::get_singleton()->add_control_to_info_overlay(tile_info); - - // Menu. - options = memnew(MenuButton); - options->set_text("TileMap"); - options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("TileMap", "EditorIcons")); - options->set_process_unhandled_key_input(false); - toolbar_right->add_child(options); - - PopupMenu *p = options->get_popup(); - p->add_shortcut(ED_SHORTCUT("tile_map_editor/cut_selection", TTR("Cut Selection"), KEY_MASK_CMD + KEY_X), OPTION_CUT); - p->add_shortcut(ED_SHORTCUT("tile_map_editor/copy_selection", TTR("Copy Selection"), KEY_MASK_CMD + KEY_C), OPTION_COPY); - p->add_shortcut(ED_GET_SHORTCUT("tile_map_editor/erase_selection"), OPTION_ERASE_SELECTION); - p->add_separator(); - p->add_item(TTR("Fix Invalid Tiles"), OPTION_FIX_INVALID); - p->connect("id_pressed", this, "_menu_option"); - - rotate_left_button = memnew(ToolButton); - rotate_left_button->set_tooltip(TTR("Rotate Left")); - rotate_left_button->set_focus_mode(FOCUS_NONE); - rotate_left_button->connect("pressed", this, "_rotate", varray(-1)); - rotate_left_button->set_shortcut(ED_SHORTCUT("tile_map_editor/rotate_left", TTR("Rotate Left"), KEY_A)); - tool_hb->add_child(rotate_left_button); - - rotate_right_button = memnew(ToolButton); - rotate_right_button->set_tooltip(TTR("Rotate Right")); - rotate_right_button->set_focus_mode(FOCUS_NONE); - rotate_right_button->connect("pressed", this, "_rotate", varray(1)); - rotate_right_button->set_shortcut(ED_SHORTCUT("tile_map_editor/rotate_right", TTR("Rotate Right"), KEY_S)); - tool_hb->add_child(rotate_right_button); - - flip_horizontal_button = memnew(ToolButton); - flip_horizontal_button->set_tooltip(TTR("Flip Horizontally")); - flip_horizontal_button->set_focus_mode(FOCUS_NONE); - flip_horizontal_button->connect("pressed", this, "_flip_horizontal"); - flip_horizontal_button->set_shortcut(ED_SHORTCUT("tile_map_editor/flip_horizontal", TTR("Flip Horizontally"), KEY_X)); - tool_hb->add_child(flip_horizontal_button); - - flip_vertical_button = memnew(ToolButton); - flip_vertical_button->set_tooltip(TTR("Flip Vertically")); - flip_vertical_button->set_focus_mode(FOCUS_NONE); - flip_vertical_button->connect("pressed", this, "_flip_vertical"); - flip_vertical_button->set_shortcut(ED_SHORTCUT("tile_map_editor/flip_vertical", TTR("Flip Vertically"), KEY_Z)); - tool_hb->add_child(flip_vertical_button); - - clear_transform_button = memnew(ToolButton); - clear_transform_button->set_tooltip(TTR("Clear Transform")); - clear_transform_button->set_focus_mode(FOCUS_NONE); - clear_transform_button->connect("pressed", this, "_clear_transform"); - clear_transform_button->set_shortcut(ED_SHORTCUT("tile_map_editor/clear_transform", TTR("Clear Transform"), KEY_W)); - tool_hb->add_child(clear_transform_button); - - clear_transform_button->set_disabled(true); -} - -TileMapEditor::~TileMapEditor() { - _clear_bucket_cache(); - copydata.clear(); -} - -/////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////// - -void TileMapEditorPlugin::_notification(int p_what) { - if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { - switch ((int)EditorSettings::get_singleton()->get("editors/tile_map/editor_side")) { - case 0: { // Left. - CanvasItemEditor::get_singleton()->move_control_to_left_panel(tile_map_editor); - } break; - case 1: { // Right. - CanvasItemEditor::get_singleton()->move_control_to_right_panel(tile_map_editor); - } break; - } - } -} - -void TileMapEditorPlugin::edit(Object *p_object) { - tile_map_editor->edit(Object::cast_to(p_object)); -} - -bool TileMapEditorPlugin::handles(Object *p_object) const { - return p_object->is_class("TileMap"); -} - -void TileMapEditorPlugin::make_visible(bool p_visible) { - if (p_visible) { - tile_map_editor->show(); - tile_map_editor->get_toolbar()->show(); - tile_map_editor->get_toolbar_right()->show(); - // `tile_info` isn't shown here, as it's displayed after a tile has been hovered. - // Otherwise, a translucent black rectangle would be visible as there would be an - // empty Label in the CanvasItemEditor's info overlay. - - // Change to TOOL_SELECT when TileMap node is selected, to prevent accidental movement. - CanvasItemEditor::get_singleton()->set_current_tool(CanvasItemEditor::TOOL_SELECT); - } else { - tile_map_editor->hide(); - tile_map_editor->get_toolbar()->hide(); - tile_map_editor->get_toolbar_right()->hide(); - tile_map_editor->get_tile_info()->hide(); - tile_map_editor->edit(nullptr); - } -} - -TileMapEditorPlugin::TileMapEditorPlugin(EditorNode *p_node) { - EDITOR_DEF("editors/tile_map/preview_size", 64); - EDITOR_DEF("editors/tile_map/palette_min_width", 80); - EDITOR_DEF("editors/tile_map/palette_item_hseparation", 8); - EDITOR_DEF("editors/tile_map/show_tile_names", true); - EDITOR_DEF("editors/tile_map/show_tile_ids", false); - EDITOR_DEF("editors/tile_map/sort_tiles_by_name", true); - EDITOR_DEF("editors/tile_map/bucket_fill_preview", true); - EDITOR_DEF("editors/tile_map/editor_side", 1); - EDITOR_DEF("editors/tile_map/display_grid", true); - EDITOR_DEF("editors/tile_map/grid_color", Color(1, 0.3, 0.1, 0.2)); - EDITOR_DEF("editors/tile_map/axis_color", Color(1, 0.8, 0.2, 0.5)); - EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "editors/tile_map/editor_side", PROPERTY_HINT_ENUM, "Left,Right")); - - tile_map_editor = memnew(TileMapEditor(p_node)); - switch ((int)EditorSettings::get_singleton()->get("editors/tile_map/editor_side")) { - case 0: { // Left. - CanvasItemEditor::get_singleton()->add_control_to_left_panel(tile_map_editor); - } break; - case 1: { // Right. - CanvasItemEditor::get_singleton()->add_control_to_right_panel(tile_map_editor); - } break; - } - tile_map_editor->hide(); -} - -TileMapEditorPlugin::~TileMapEditorPlugin() { -} diff --git a/editor/plugins/tile_map_editor_plugin.h b/editor/plugins/tile_map_editor_plugin.h deleted file mode 100644 index 1baea8b93..000000000 --- a/editor/plugins/tile_map_editor_plugin.h +++ /dev/null @@ -1,256 +0,0 @@ -/*************************************************************************/ -/* tile_map_editor_plugin.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef TILE_MAP_EDITOR_PLUGIN_H -#define TILE_MAP_EDITOR_PLUGIN_H - -#include "editor/editor_node.h" -#include "editor/editor_plugin.h" - -#include "scene/2d/tile_map.h" -#include "scene/gui/check_box.h" -#include "scene/gui/label.h" -#include "scene/gui/line_edit.h" -#include "scene/gui/menu_button.h" -#include "scene/gui/tool_button.h" - -class TileMapEditor : public VBoxContainer { - GDCLASS(TileMapEditor, VBoxContainer); - - enum Tool { - - TOOL_NONE, - TOOL_PAINTING, - TOOL_ERASING, - TOOL_RECTANGLE_PAINT, - TOOL_RECTANGLE_ERASE, - TOOL_LINE_PAINT, - TOOL_LINE_ERASE, - TOOL_SELECTING, - TOOL_BUCKET, - TOOL_PICKING, - TOOL_PASTING - }; - - enum Options { - - OPTION_COPY, - OPTION_ERASE_SELECTION, - OPTION_FIX_INVALID, - OPTION_CUT - }; - - TileMap *node; - bool manual_autotile; - bool priority_atlastile; - Vector2 manual_position; - - EditorNode *editor; - UndoRedo *undo_redo; - Control *canvas_item_editor_viewport; - - LineEdit *search_box; - HSlider *size_slider; - ItemList *palette; - ItemList *manual_palette; - - Label *info_message; - - HBoxContainer *toolbar; - HBoxContainer *toolbar_right; - - Label *tile_info; - MenuButton *options; - - ToolButton *paint_button; - ToolButton *bucket_fill_button; - ToolButton *picker_button; - ToolButton *select_button; - - ToolButton *flip_horizontal_button; - ToolButton *flip_vertical_button; - ToolButton *rotate_left_button; - ToolButton *rotate_right_button; - ToolButton *clear_transform_button; - - CheckBox *manual_button; - CheckBox *priority_button; - - Tool tool; - Tool last_tool; - - bool selection_active; - bool mouse_over; - - bool flip_h; - bool flip_v; - bool transpose; - Point2i autotile_coord; - - Point2i rectangle_begin; - Rect2i rectangle; - - Point2i over_tile; - bool refocus_over_tile; - - bool *bucket_cache_visited; - Rect2i bucket_cache_rect; - int bucket_cache_tile; - PoolVector bucket_cache; - List bucket_queue; - - struct CellOp { - int idx; - bool xf; - bool yf; - bool tr; - Vector2 ac; - - CellOp() : - idx(TileMap::INVALID_CELL), - xf(false), - yf(false), - tr(false) {} - }; - - Map paint_undo; - - struct TileData { - Point2i pos; - int cell; - bool flip_h; - bool flip_v; - bool transpose; - Point2i autotile_coord; - - TileData() : - cell(TileMap::INVALID_CELL), - flip_h(false), - flip_v(false), - transpose(false) {} - }; - - List copydata; - - Map undo_data; - Vector invalid_cell; - - void _pick_tile(const Point2 &p_pos); - - PoolVector _bucket_fill(const Point2i &p_start, bool erase = false, bool preview = false); - - void _fill_points(const PoolVector &p_points, const Dictionary &p_op); - void _erase_points(const PoolVector &p_points); - - void _select(const Point2i &p_from, const Point2i &p_to); - void _erase_selection(); - - void _draw_grid(Control *p_viewport, const Rect2 &p_rect) const; - void _draw_cell(Control *p_viewport, int p_cell, const Point2i &p_point, bool p_flip_h, bool p_flip_v, bool p_transpose, const Point2i &p_autotile_coord, const Transform2D &p_xform); - void _draw_fill_preview(Control *p_viewport, int p_cell, const Point2i &p_point, bool p_flip_h, bool p_flip_v, bool p_transpose, const Point2i &p_autotile_coord, const Transform2D &p_xform); - void _clear_bucket_cache(); - - void _update_copydata(); - - Vector get_selected_tiles() const; - void set_selected_tiles(Vector p_tile); - - void _manual_toggled(bool p_enabled); - void _priority_toggled(bool p_enabled); - void _text_entered(const String &p_text); - void _text_changed(const String &p_text); - void _sbox_input(const Ref &p_ie); - void _update_palette(); - void _update_button_tool(); - void _button_tool_select(int p_tool); - void _menu_option(int p_option); - void _palette_selected(int index); - void _palette_multi_selected(int index, bool selected); - void _palette_input(const Ref &p_event); - - Dictionary _create_cell_dictionary(int tile, bool flip_x, bool flip_y, bool transpose, Vector2 autotile_coord); - void _start_undo(const String &p_action); - void _finish_undo(); - void _create_set_cell_undo_redo(const Vector2 &p_vec, const CellOp &p_cell_old, const CellOp &p_cell_new); - void _set_cell(const Point2i &p_pos, Vector p_values, bool p_flip_h = false, bool p_flip_v = false, bool p_transpose = false, const Point2i &p_autotile_coord = Point2()); - - void _canvas_mouse_enter(); - void _canvas_mouse_exit(); - void _tileset_settings_changed(); - void _icon_size_changed(float p_value); - - void _clear_transform(); - void _flip_horizontal(); - void _flip_vertical(); - void _rotate(int steps); - -protected: - void _notification(int p_what); - void _node_removed(Node *p_node); - static void _bind_methods(); - CellOp _get_op_from_cell(const Point2i &p_pos); - -public: - HBoxContainer *get_toolbar() const { return toolbar; } - HBoxContainer *get_toolbar_right() const { return toolbar_right; } - Label *get_tile_info() const { return tile_info; } - - bool forward_gui_input(const Ref &p_event); - void forward_canvas_draw_over_viewport(Control *p_overlay); - - void edit(Node *p_tile_map); - - TileMapEditor(EditorNode *p_editor); - ~TileMapEditor(); -}; - -class TileMapEditorPlugin : public EditorPlugin { - GDCLASS(TileMapEditorPlugin, EditorPlugin); - - TileMapEditor *tile_map_editor; - -protected: - void _notification(int p_what); - -public: - virtual bool forward_canvas_gui_input(const Ref &p_event) { return tile_map_editor->forward_gui_input(p_event); } - virtual void forward_canvas_draw_over_viewport(Control *p_overlay) { tile_map_editor->forward_canvas_draw_over_viewport(p_overlay); } - - virtual String get_name() const { return "TileMap"; } - bool has_main_screen() const { return false; } - virtual void edit(Object *p_object); - virtual bool handles(Object *p_object) const; - virtual void make_visible(bool p_visible); - - TileMapEditorPlugin(EditorNode *p_node); - ~TileMapEditorPlugin(); -}; - -#endif // TILE_MAP_EDITOR_PLUGIN_H diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp deleted file mode 100644 index 9a5268b15..000000000 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ /dev/null @@ -1,3672 +0,0 @@ -/*************************************************************************/ -/* tile_set_editor_plugin.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "tile_set_editor_plugin.h" - -#include "core/os/input.h" -#include "core/os/keyboard.h" -#include "editor/editor_scale.h" -#include "editor/plugins/canvas_item_editor_plugin.h" -#include "scene/2d/physics_body_2d.h" -#include "scene/2d/sprite.h" - -void TileSetEditor::edit(const Ref &p_tileset) { - tileset = p_tileset; - tileset->add_change_receptor(this); - - texture_list->clear(); - texture_map.clear(); - update_texture_list(); -} - -void TileSetEditor::_import_node(Node *p_node, Ref p_library) { - for (int i = 0; i < p_node->get_child_count(); i++) { - Node *child = p_node->get_child(i); - - if (!Object::cast_to(child)) { - if (child->get_child_count() > 0) { - _import_node(child, p_library); - } - - continue; - } - - Sprite *mi = Object::cast_to(child); - Ref texture = mi->get_texture(); - Ref normal_map = mi->get_normal_map(); - Ref material = mi->get_material(); - - if (texture.is_null()) { - continue; - } - - int id = p_library->find_tile_by_name(mi->get_name()); - if (id < 0) { - id = p_library->get_last_unused_tile_id(); - p_library->create_tile(id); - p_library->tile_set_name(id, mi->get_name()); - } - - p_library->tile_set_texture(id, texture); - p_library->tile_set_normal_map(id, normal_map); - p_library->tile_set_material(id, material); - - p_library->tile_set_modulate(id, mi->get_modulate()); - - Vector2 phys_offset; - Size2 s; - - if (mi->is_region()) { - s = mi->get_region_rect().size; - p_library->tile_set_region(id, mi->get_region_rect()); - } else { - const int frame = mi->get_frame(); - const int hframes = mi->get_hframes(); - s = texture->get_size() / Size2(hframes, mi->get_vframes()); - p_library->tile_set_region(id, Rect2(Vector2(frame % hframes, frame / hframes) * s, s)); - } - - if (mi->is_centered()) { - phys_offset += -s / 2; - } - - Vector collisions; - Ref nav_poly; - Ref occluder; - bool found_collisions = false; - - for (int j = 0; j < mi->get_child_count(); j++) { - Node *child2 = mi->get_child(j); - - if (Object::cast_to(child2)) { - nav_poly = Object::cast_to(child2)->get_navigation_polygon(); - } - - if (Object::cast_to(child2)) { - occluder = Object::cast_to(child2)->get_occluder_polygon(); - } - - if (!Object::cast_to(child2)) { - continue; - } - - found_collisions = true; - - StaticBody2D *sb = Object::cast_to(child2); - - List shapes; - sb->get_shape_owners(&shapes); - - for (List::Element *E = shapes.front(); E; E = E->next()) { - if (sb->is_shape_owner_disabled(E->get())) { - continue; - } - - Transform2D shape_transform = sb->get_transform() * sb->shape_owner_get_transform(E->get()); - bool one_way = sb->is_shape_owner_one_way_collision_enabled(E->get()); - - shape_transform[2] -= phys_offset; - - for (int k = 0; k < sb->shape_owner_get_shape_count(E->get()); k++) { - Ref shape = sb->shape_owner_get_shape(E->get(), k); - TileSet::ShapeData shape_data; - shape_data.shape = shape; - shape_data.shape_transform = shape_transform; - shape_data.one_way_collision = one_way; - collisions.push_back(shape_data); - } - } - } - - if (found_collisions) { - p_library->tile_set_shapes(id, collisions); - } - - p_library->tile_set_texture_offset(id, mi->get_offset()); - p_library->tile_set_navigation_polygon(id, nav_poly); - p_library->tile_set_light_occluder(id, occluder); - p_library->tile_set_occluder_offset(id, -phys_offset); - p_library->tile_set_navigation_polygon_offset(id, -phys_offset); - p_library->tile_set_z_index(id, mi->get_z_index()); - } -} - -void TileSetEditor::_import_scene(Node *p_scene, Ref p_library, bool p_merge) { - if (!p_merge) { - p_library->clear(); - } - - _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 ml, bool p_merge) { - _import_scene(p_base_scene, ml, p_merge); - return OK; -} - -Variant TileSetEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) { - return false; -} - -bool TileSetEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const { - Dictionary d = p_data; - - if (!d.has("type")) { - return false; - } - - if (d.has("from") && (Object *)(d["from"]) == texture_list) { - return false; - } - - if (String(d["type"]) == "resource" && d.has("resource")) { - RES r = d["resource"]; - - Ref texture = r; - - if (texture.is_valid()) { - return true; - } - } - - if (String(d["type"]) == "files") { - Vector files = d["files"]; - - if (files.size() == 0) { - return false; - } - - for (int i = 0; i < files.size(); i++) { - String file = files[i]; - String ftype = EditorFileSystem::get_singleton()->get_file_type(file); - - if (!ClassDB::is_parent_class(ftype, "Texture")) { - return false; - } - } - - return true; - } - return false; -} - -void TileSetEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) { - if (!can_drop_data_fw(p_point, p_data, p_from)) { - return; - } - - Dictionary d = p_data; - - if (!d.has("type")) { - return; - } - - if (String(d["type"]) == "resource" && d.has("resource")) { - RES r = d["resource"]; - - Ref texture = r; - - if (texture.is_valid()) { - add_texture(texture); - } - - if (texture_list->get_item_count() > 0) { - update_texture_list_icon(); - texture_list->select(texture_list->get_item_count() - 1); - _on_texture_list_selected(texture_list->get_item_count() - 1); - } - } - - if (String(d["type"]) == "files") { - PoolVector files = d["files"]; - - _on_textures_added(files); - } -} - -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); - ClassDB::bind_method("_on_texture_list_selected", &TileSetEditor::_on_texture_list_selected); - ClassDB::bind_method("_on_edit_mode_changed", &TileSetEditor::_on_edit_mode_changed); - ClassDB::bind_method("_on_scroll_container_input", &TileSetEditor::_on_scroll_container_input); - ClassDB::bind_method("_on_workspace_mode_changed", &TileSetEditor::_on_workspace_mode_changed); - ClassDB::bind_method("_on_workspace_overlay_draw", &TileSetEditor::_on_workspace_overlay_draw); - ClassDB::bind_method("_on_workspace_process", &TileSetEditor::_on_workspace_process); - ClassDB::bind_method("_on_workspace_draw", &TileSetEditor::_on_workspace_draw); - ClassDB::bind_method("_on_workspace_input", &TileSetEditor::_on_workspace_input); - ClassDB::bind_method("_on_tool_clicked", &TileSetEditor::_on_tool_clicked); - ClassDB::bind_method("_on_priority_changed", &TileSetEditor::_on_priority_changed); - ClassDB::bind_method("_on_z_index_changed", &TileSetEditor::_on_z_index_changed); - ClassDB::bind_method("_on_grid_snap_toggled", &TileSetEditor::_on_grid_snap_toggled); - 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("_sort_tiles", &TileSetEditor::_sort_tiles); - - ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &TileSetEditor::get_drag_data_fw); - ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &TileSetEditor::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("drop_data_fw"), &TileSetEditor::drop_data_fw); - - 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); - ClassDB::bind_method("update_workspace_minsize", &TileSetEditor::update_workspace_minsize); -} - -void TileSetEditor::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_READY: { - add_constant_override("autohide", 1); // Fixes the dragger always showing up. - } break; - case NOTIFICATION_ENTER_TREE: - case NOTIFICATION_THEME_CHANGED: { - tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]->set_icon(get_icon("ToolAddNode", "EditorIcons")); - tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]->set_icon(get_icon("Remove", "EditorIcons")); - tileset_toolbar_tools->set_icon(get_icon("Tools", "EditorIcons")); - - tool_workspacemode[WORKSPACE_EDIT]->set_icon(get_icon("Edit", "EditorIcons")); - tool_workspacemode[WORKSPACE_CREATE_SINGLE]->set_icon(get_icon("AddSingleTile", "EditorIcons")); - tool_workspacemode[WORKSPACE_CREATE_AUTOTILE]->set_icon(get_icon("AddAutotile", "EditorIcons")); - tool_workspacemode[WORKSPACE_CREATE_ATLAS]->set_icon(get_icon("AddAtlasTile", "EditorIcons")); - - tools[TOOL_SELECT]->set_icon(get_icon("ToolSelect", "EditorIcons")); - tools[BITMASK_COPY]->set_icon(get_icon("Duplicate", "EditorIcons")); - tools[BITMASK_PASTE]->set_icon(get_icon("Override", "EditorIcons")); - tools[BITMASK_CLEAR]->set_icon(get_icon("Clear", "EditorIcons")); - tools[SHAPE_NEW_POLYGON]->set_icon(get_icon("CollisionPolygon2D", "EditorIcons")); - tools[SHAPE_NEW_RECTANGLE]->set_icon(get_icon("CollisionShape2D", "EditorIcons")); - tools[SELECT_PREVIOUS]->set_icon(get_icon("ArrowLeft", "EditorIcons")); - tools[SELECT_NEXT]->set_icon(get_icon("ArrowRight", "EditorIcons")); - tools[SHAPE_DELETE]->set_icon(get_icon("Remove", "EditorIcons")); - tools[SHAPE_KEEP_INSIDE_TILE]->set_icon(get_icon("Snap", "EditorIcons")); - tools[TOOL_GRID_SNAP]->set_icon(get_icon("SnapGrid", "EditorIcons")); - tools[ZOOM_OUT]->set_icon(get_icon("ZoomLess", "EditorIcons")); - tools[ZOOM_1]->set_icon(get_icon("ZoomReset", "EditorIcons")); - tools[ZOOM_IN]->set_icon(get_icon("ZoomMore", "EditorIcons")); - tools[VISIBLE_INFO]->set_icon(get_icon("InformationSign", "EditorIcons")); - _update_toggle_shape_button(); - - tool_editmode[EDITMODE_REGION]->set_icon(get_icon("RegionEdit", "EditorIcons")); - tool_editmode[EDITMODE_COLLISION]->set_icon(get_icon("StaticBody2D", "EditorIcons")); - tool_editmode[EDITMODE_OCCLUSION]->set_icon(get_icon("LightOccluder2D", "EditorIcons")); - tool_editmode[EDITMODE_NAVIGATION]->set_icon(get_icon("Navigation2D", "EditorIcons")); - tool_editmode[EDITMODE_BITMASK]->set_icon(get_icon("PackedDataContainer", "EditorIcons")); - tool_editmode[EDITMODE_PRIORITY]->set_icon(get_icon("MaterialPreviewLight1", "EditorIcons")); - tool_editmode[EDITMODE_ICON]->set_icon(get_icon("LargeTexture", "EditorIcons")); - tool_editmode[EDITMODE_Z_INDEX]->set_icon(get_icon("Sort", "EditorIcons")); - - scroll->add_style_override("bg", get_stylebox("bg", "Tree")); - } break; - } -} - -TileSetEditor::TileSetEditor(EditorNode *p_editor) { - editor = p_editor; - undo_redo = EditorNode::get_undo_redo(); - current_tile = -1; - - VBoxContainer *left_container = memnew(VBoxContainer); - add_child(left_container); - - texture_list = memnew(ItemList); - left_container->add_child(texture_list); - texture_list->set_v_size_flags(SIZE_EXPAND_FILL); - texture_list->set_custom_minimum_size(Size2(200, 0)); - texture_list->connect("item_selected", this, "_on_texture_list_selected"); - texture_list->set_drag_forwarding(this); - - HBoxContainer *tileset_toolbar_container = memnew(HBoxContainer); - left_container->add_child(tileset_toolbar_container); - - tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE] = memnew(ToolButton); - tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]->connect("pressed", this, "_on_tileset_toolbar_button_pressed", varray(TOOL_TILESET_ADD_TEXTURE)); - tileset_toolbar_container->add_child(tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]); - tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]->set_tooltip(TTR("Add Texture(s) to TileSet.")); - - tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE] = memnew(ToolButton); - tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]->connect("pressed", this, "_on_tileset_toolbar_button_pressed", varray(TOOL_TILESET_REMOVE_TEXTURE)); - tileset_toolbar_container->add_child(tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]); - tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]->set_tooltip(TTR("Remove selected Texture from TileSet.")); - - Control *toolbar_separator = memnew(Control); - toolbar_separator->set_h_size_flags(Control::SIZE_EXPAND_FILL); - tileset_toolbar_container->add_child(toolbar_separator); - - tileset_toolbar_tools = memnew(MenuButton); - tileset_toolbar_tools->set_text(TTR("Tools")); - tileset_toolbar_tools->get_popup()->add_item(TTR("Create from Scene"), TOOL_TILESET_CREATE_SCENE); - tileset_toolbar_tools->get_popup()->add_item(TTR("Merge from Scene"), TOOL_TILESET_MERGE_SCENE); - - tileset_toolbar_tools->get_popup()->connect("id_pressed", this, "_on_tileset_toolbar_button_pressed"); - tileset_toolbar_container->add_child(tileset_toolbar_tools); - - //--------------- - VBoxContainer *right_container = memnew(VBoxContainer); - right_container->set_v_size_flags(SIZE_EXPAND_FILL); - add_child(right_container); - - dragging_point = -1; - creating_shape = false; - snap_step = Vector2(32, 32); - snap_offset = WORKSPACE_MARGIN; - - set_custom_minimum_size(Size2(0, 150)); - - VBoxContainer *main_vb = memnew(VBoxContainer); - right_container->add_child(main_vb); - main_vb->set_v_size_flags(SIZE_EXPAND_FILL); - - HBoxContainer *tool_hb = memnew(HBoxContainer); - Ref g(memnew(ButtonGroup)); - - String workspace_label[WORKSPACE_MODE_MAX] = { - TTR("Edit"), - TTR("New Single Tile"), - TTR("New Autotile"), - TTR("New Atlas") - }; - for (int i = 0; i < (int)WORKSPACE_MODE_MAX; i++) { - tool_workspacemode[i] = memnew(Button); - tool_workspacemode[i]->set_text(workspace_label[i]); - tool_workspacemode[i]->set_toggle_mode(true); - tool_workspacemode[i]->set_button_group(g); - tool_workspacemode[i]->connect("pressed", this, "_on_workspace_mode_changed", varray(i)); - tool_hb->add_child(tool_workspacemode[i]); - } - - Control *spacer = memnew(Control); - spacer->set_h_size_flags(Control::SIZE_EXPAND_FILL); - tool_hb->add_child(spacer); - tool_hb->move_child(spacer, WORKSPACE_CREATE_SINGLE); - - tools[SELECT_NEXT] = memnew(ToolButton); - tool_hb->add_child(tools[SELECT_NEXT]); - tool_hb->move_child(tools[SELECT_NEXT], WORKSPACE_CREATE_SINGLE); - tools[SELECT_NEXT]->set_shortcut(ED_SHORTCUT("tileset_editor/next_shape", TTR("Next Coordinate"), KEY_PAGEDOWN)); - tools[SELECT_NEXT]->connect("pressed", this, "_on_tool_clicked", varray(SELECT_NEXT)); - tools[SELECT_NEXT]->set_tooltip(TTR("Select the next shape, subtile, or Tile.")); - tools[SELECT_PREVIOUS] = memnew(ToolButton); - tool_hb->add_child(tools[SELECT_PREVIOUS]); - tool_hb->move_child(tools[SELECT_PREVIOUS], WORKSPACE_CREATE_SINGLE); - tools[SELECT_PREVIOUS]->set_shortcut(ED_SHORTCUT("tileset_editor/previous_shape", TTR("Previous Coordinate"), KEY_PAGEUP)); - tools[SELECT_PREVIOUS]->set_tooltip(TTR("Select the previous shape, subtile, or Tile.")); - tools[SELECT_PREVIOUS]->connect("pressed", this, "_on_tool_clicked", varray(SELECT_PREVIOUS)); - - VSeparator *separator_shape_selection = memnew(VSeparator); - tool_hb->add_child(separator_shape_selection); - tool_hb->move_child(separator_shape_selection, WORKSPACE_CREATE_SINGLE); - - tool_workspacemode[WORKSPACE_EDIT]->set_pressed(true); - workspace_mode = WORKSPACE_EDIT; - - main_vb->add_child(tool_hb); - main_vb->add_child(memnew(HSeparator)); - - tool_hb = memnew(HBoxContainer); - - g = Ref(memnew(ButtonGroup)); - String label[EDITMODE_MAX] = { - TTR("Region"), - TTR("Collision"), - TTR("Occlusion"), - TTR("Navigation"), - TTR("Bitmask"), - TTR("Priority"), - TTR("Icon"), - TTR("Z Index") - }; - for (int i = 0; i < (int)EDITMODE_MAX; i++) { - tool_editmode[i] = memnew(Button); - tool_editmode[i]->set_text(label[i]); - tool_editmode[i]->set_toggle_mode(true); - tool_editmode[i]->set_button_group(g); - tool_editmode[i]->connect("pressed", this, "_on_edit_mode_changed", varray(i)); - tool_hb->add_child(tool_editmode[i]); - } - tool_editmode[EDITMODE_COLLISION]->set_pressed(true); - edit_mode = EDITMODE_COLLISION; - - tool_editmode[EDITMODE_REGION]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_region", TTR("Region Mode"), KEY_1)); - tool_editmode[EDITMODE_COLLISION]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_collision", TTR("Collision Mode"), KEY_2)); - tool_editmode[EDITMODE_OCCLUSION]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_occlusion", TTR("Occlusion Mode"), KEY_3)); - tool_editmode[EDITMODE_NAVIGATION]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_navigation", TTR("Navigation Mode"), KEY_4)); - tool_editmode[EDITMODE_BITMASK]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_bitmask", TTR("Bitmask Mode"), KEY_5)); - tool_editmode[EDITMODE_PRIORITY]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_priority", TTR("Priority Mode"), KEY_6)); - tool_editmode[EDITMODE_ICON]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_icon", TTR("Icon Mode"), KEY_7)); - tool_editmode[EDITMODE_Z_INDEX]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_z_index", TTR("Z Index Mode"), KEY_8)); - - main_vb->add_child(tool_hb); - separator_editmode = memnew(HSeparator); - main_vb->add_child(separator_editmode); - - toolbar = memnew(HBoxContainer); - Ref tg(memnew(ButtonGroup)); - - tools[TOOL_SELECT] = memnew(ToolButton); - toolbar->add_child(tools[TOOL_SELECT]); - tools[TOOL_SELECT]->set_toggle_mode(true); - tools[TOOL_SELECT]->set_button_group(tg); - tools[TOOL_SELECT]->set_pressed(true); - tools[TOOL_SELECT]->connect("pressed", this, "_on_tool_clicked", varray(TOOL_SELECT)); - - separator_bitmask = memnew(VSeparator); - toolbar->add_child(separator_bitmask); - tools[BITMASK_COPY] = memnew(ToolButton); - tools[BITMASK_COPY]->set_tooltip(TTR("Copy bitmask.")); - tools[BITMASK_COPY]->connect("pressed", this, "_on_tool_clicked", varray(BITMASK_COPY)); - toolbar->add_child(tools[BITMASK_COPY]); - tools[BITMASK_PASTE] = memnew(ToolButton); - tools[BITMASK_PASTE]->set_tooltip(TTR("Paste bitmask.")); - tools[BITMASK_PASTE]->connect("pressed", this, "_on_tool_clicked", varray(BITMASK_PASTE)); - toolbar->add_child(tools[BITMASK_PASTE]); - tools[BITMASK_CLEAR] = memnew(ToolButton); - tools[BITMASK_CLEAR]->set_tooltip(TTR("Erase bitmask.")); - tools[BITMASK_CLEAR]->connect("pressed", this, "_on_tool_clicked", varray(BITMASK_CLEAR)); - toolbar->add_child(tools[BITMASK_CLEAR]); - - tools[SHAPE_NEW_RECTANGLE] = memnew(ToolButton); - toolbar->add_child(tools[SHAPE_NEW_RECTANGLE]); - tools[SHAPE_NEW_RECTANGLE]->set_toggle_mode(true); - tools[SHAPE_NEW_RECTANGLE]->set_button_group(tg); - tools[SHAPE_NEW_RECTANGLE]->set_tooltip(TTR("Create a new rectangle.")); - tools[SHAPE_NEW_RECTANGLE]->connect("pressed", this, "_on_tool_clicked", varray(SHAPE_NEW_RECTANGLE)); - tools[SHAPE_NEW_RECTANGLE]->set_shortcut(ED_SHORTCUT("tileset_editor/shape_new_rectangle", TTR("New Rectangle"), KEY_MASK_SHIFT | KEY_R)); - - tools[SHAPE_NEW_POLYGON] = memnew(ToolButton); - toolbar->add_child(tools[SHAPE_NEW_POLYGON]); - tools[SHAPE_NEW_POLYGON]->set_toggle_mode(true); - tools[SHAPE_NEW_POLYGON]->set_button_group(tg); - tools[SHAPE_NEW_POLYGON]->set_tooltip(TTR("Create a new polygon.")); - tools[SHAPE_NEW_POLYGON]->connect("pressed", this, "_on_tool_clicked", varray(SHAPE_NEW_POLYGON)); - tools[SHAPE_NEW_POLYGON]->set_shortcut(ED_SHORTCUT("tileset_editor/shape_new_polygon", TTR("New Polygon"), KEY_MASK_SHIFT | KEY_P)); - - separator_shape_toggle = memnew(VSeparator); - toolbar->add_child(separator_shape_toggle); - tools[SHAPE_TOGGLE_TYPE] = memnew(ToolButton); - tools[SHAPE_TOGGLE_TYPE]->connect("pressed", this, "_on_tool_clicked", varray(SHAPE_TOGGLE_TYPE)); - toolbar->add_child(tools[SHAPE_TOGGLE_TYPE]); - - separator_delete = memnew(VSeparator); - toolbar->add_child(separator_delete); - tools[SHAPE_DELETE] = memnew(ToolButton); - tools[SHAPE_DELETE]->connect("pressed", this, "_on_tool_clicked", varray(SHAPE_DELETE)); - tools[SHAPE_DELETE]->set_shortcut(ED_SHORTCUT("tileset_editor/shape_delete", TTR("Delete Selected Shape"), KEY_MASK_SHIFT | KEY_BACKSPACE)); - toolbar->add_child(tools[SHAPE_DELETE]); - - spin_priority = memnew(SpinBox); - spin_priority->set_min(1); - spin_priority->set_max(255); - spin_priority->set_step(1); - spin_priority->set_custom_minimum_size(Size2(100, 0)); - spin_priority->connect("value_changed", this, "_on_priority_changed"); - spin_priority->hide(); - toolbar->add_child(spin_priority); - - spin_z_index = memnew(SpinBox); - spin_z_index->set_min(VS::CANVAS_ITEM_Z_MIN); - spin_z_index->set_max(VS::CANVAS_ITEM_Z_MAX); - spin_z_index->set_step(1); - spin_z_index->set_custom_minimum_size(Size2(100, 0)); - spin_z_index->connect("value_changed", this, "_on_z_index_changed"); - 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); - - tools[ZOOM_OUT] = memnew(ToolButton); - tools[ZOOM_OUT]->connect("pressed", this, "_zoom_out"); - toolbar->add_child(tools[ZOOM_OUT]); - tools[ZOOM_OUT]->set_tooltip(TTR("Zoom Out")); - tools[ZOOM_1] = memnew(ToolButton); - tools[ZOOM_1]->connect("pressed", this, "_zoom_reset"); - toolbar->add_child(tools[ZOOM_1]); - tools[ZOOM_1]->set_tooltip(TTR("Zoom Reset")); - tools[ZOOM_IN] = memnew(ToolButton); - tools[ZOOM_IN]->connect("pressed", this, "_zoom_in"); - toolbar->add_child(tools[ZOOM_IN]); - tools[ZOOM_IN]->set_tooltip(TTR("Zoom In")); - - tools[VISIBLE_INFO] = memnew(ToolButton); - tools[VISIBLE_INFO]->set_toggle_mode(true); - tools[VISIBLE_INFO]->set_tooltip(TTR("Display Tile Names (Hold Alt Key)")); - toolbar->add_child(tools[VISIBLE_INFO]); - - main_vb->add_child(toolbar); - - scroll = memnew(ScrollContainer); - main_vb->add_child(scroll); - scroll->set_v_size_flags(SIZE_EXPAND_FILL); - scroll->connect("gui_input", this, "_on_scroll_container_input"); - scroll->set_clip_contents(true); - - empty_message = memnew(Label); - empty_message->set_text(TTR("Add or select a texture on the left panel to edit the tiles bound to it.")); - empty_message->set_valign(Label::VALIGN_CENTER); - empty_message->set_align(Label::ALIGN_CENTER); - empty_message->set_autowrap(true); - empty_message->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); - empty_message->set_v_size_flags(SIZE_EXPAND_FILL); - main_vb->add_child(empty_message); - - workspace_container = memnew(Control); - scroll->add_child(workspace_container); - - workspace_overlay = memnew(Control); - workspace_overlay->connect("draw", this, "_on_workspace_overlay_draw"); - workspace_container->add_child(workspace_overlay); - - workspace = memnew(Control); - workspace->set_focus_mode(FOCUS_ALL); - workspace->connect("draw", this, "_on_workspace_draw"); - workspace->connect("gui_input", this, "_on_workspace_input"); - workspace->set_draw_behind_parent(true); - workspace_overlay->add_child(workspace); - - preview = memnew(Sprite); - workspace->add_child(preview); - preview->set_centered(false); - preview->set_draw_behind_parent(true); - preview->set_position(WORKSPACE_MARGIN); - - //--------------- - cd = memnew(ConfirmationDialog); - add_child(cd); - cd->connect("confirmed", this, "_on_tileset_toolbar_confirm"); - - //--------------- - err_dialog = memnew(AcceptDialog); - add_child(err_dialog); - - //--------------- - texture_dialog = memnew(EditorFileDialog); - texture_dialog->set_access(EditorFileDialog::ACCESS_RESOURCES); - texture_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILES); - texture_dialog->clear_filters(); - List extensions; - - ResourceLoader::get_recognized_extensions_for_type("Texture", &extensions); - for (List::Element *E = extensions.front(); E; E = E->next()) { - texture_dialog->add_filter("*." + E->get() + " ; " + E->get().to_upper()); - } - add_child(texture_dialog); - texture_dialog->connect("files_selected", this, "_on_textures_added"); - - //--------------- - helper = memnew(TilesetEditorContext(this)); - tile_names_visible = false; - - // Config scale. - max_scale = 16.0f; - min_scale = 0.01f; - scale_ratio = 1.2f; -} - -TileSetEditor::~TileSetEditor() { - if (helper) { - memdelete(helper); - } -} - -void TileSetEditor::_on_tileset_toolbar_button_pressed(int p_index) { - option = p_index; - switch (option) { - case TOOL_TILESET_ADD_TEXTURE: { - texture_dialog->popup_centered_ratio(); - } break; - case TOOL_TILESET_REMOVE_TEXTURE: { - if (get_current_texture().is_valid()) { - 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.")); - err_dialog->popup_centered(Size2(300, 60)); - } - } break; - case TOOL_TILESET_CREATE_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: { - cd->set_text(TTR("Merge from scene?")); - cd->popup_centered(Size2(300, 60)); - } break; - } -} - -void TileSetEditor::_on_tileset_toolbar_confirm() { - switch (option) { - case TOOL_TILESET_REMOVE_TEXTURE: { - String current_texture_path = get_current_texture()->get_path(); - List ids; - tileset->get_tile_list(&ids); - - undo_redo->create_action(TTR("Remove Texture")); - for (List::Element *E = ids.front(); E; E = E->next()) { - if (tileset->tile_get_texture(E->get())->get_path() == current_texture_path) { - undo_redo->add_do_method(tileset.ptr(), "remove_tile", E->get()); - _undo_tile_removal(E->get()); - } - } - 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: { - EditorNode *en = editor; - Node *scene = en->get_edited_scene(); - if (!scene) { - break; - } - - List 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::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; - } -} - -void TileSetEditor::_on_texture_list_selected(int p_index) { - if (get_current_texture().is_valid()) { - current_item_index = p_index; - preview->set_texture(get_current_texture()); - update_workspace_tile_mode(); - update_workspace_minsize(); - } else { - current_item_index = -1; - preview->set_texture(nullptr); - workspace->set_custom_minimum_size(Size2i()); - update_workspace_tile_mode(); - } - - set_current_tile(-1); - workspace->update(); -} - -void TileSetEditor::_on_textures_added(const PoolStringArray &p_paths) { - int invalid_count = 0; - for (int i = 0; i < p_paths.size(); i++) { - Ref t = Ref(ResourceLoader::load(p_paths[i])); - - ERR_CONTINUE_MSG(!t.is_valid(), "'" + p_paths[i] + "' is not a valid texture."); - - if (texture_map.has(t->get_path())) { - invalid_count++; - } else { - add_texture(t); - } - } - - if (texture_list->get_item_count() > 0) { - update_texture_list_icon(); - texture_list->select(texture_list->get_item_count() - 1); - _on_texture_list_selected(texture_list->get_item_count() - 1); - } - - if (invalid_count > 0) { - err_dialog->set_text(vformat(TTR("%s file(s) were not added because was already on the list."), String::num(invalid_count, 0))); - err_dialog->popup_centered(Size2(300, 60)); - } -} - -void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) { - draw_handles = false; - creating_shape = false; - edit_mode = (EditMode)p_edit_mode; - switch (edit_mode) { - case EDITMODE_REGION: { - tools[TOOL_SELECT]->show(); - - separator_bitmask->hide(); - tools[BITMASK_COPY]->hide(); - tools[BITMASK_PASTE]->hide(); - tools[BITMASK_CLEAR]->hide(); - tools[SHAPE_NEW_POLYGON]->hide(); - tools[SHAPE_NEW_RECTANGLE]->hide(); - - if (workspace_mode == WORKSPACE_EDIT) { - separator_delete->show(); - tools[SHAPE_DELETE]->show(); - } else { - separator_delete->hide(); - tools[SHAPE_DELETE]->hide(); - } - - separator_grid->show(); - tools[SHAPE_KEEP_INSIDE_TILE]->hide(); - tools[TOOL_GRID_SNAP]->show(); - - tools[TOOL_SELECT]->set_pressed(true); - tools[TOOL_SELECT]->set_tooltip(TTR("Drag handles to edit Rect.\nClick on another Tile to edit it.")); - tools[SHAPE_DELETE]->set_tooltip(TTR("Delete selected Rect.")); - spin_priority->hide(); - spin_z_index->hide(); - } break; - case EDITMODE_COLLISION: - case EDITMODE_OCCLUSION: - case EDITMODE_NAVIGATION: { - tools[TOOL_SELECT]->show(); - - separator_bitmask->hide(); - tools[BITMASK_COPY]->hide(); - tools[BITMASK_PASTE]->hide(); - tools[BITMASK_CLEAR]->hide(); - tools[SHAPE_NEW_POLYGON]->show(); - tools[SHAPE_NEW_RECTANGLE]->show(); - - separator_delete->show(); - tools[SHAPE_DELETE]->show(); - - separator_grid->show(); - tools[SHAPE_KEEP_INSIDE_TILE]->show(); - tools[TOOL_GRID_SNAP]->show(); - - tools[TOOL_SELECT]->set_tooltip(TTR("Select current edited sub-tile.\nClick on another Tile to edit it.")); - tools[SHAPE_DELETE]->set_tooltip(TTR("Delete polygon.")); - spin_priority->hide(); - spin_z_index->hide(); - - _select_edited_shape_coord(); - } break; - case EDITMODE_BITMASK: { - tools[TOOL_SELECT]->show(); - - separator_bitmask->show(); - tools[BITMASK_COPY]->show(); - tools[BITMASK_PASTE]->show(); - tools[BITMASK_CLEAR]->show(); - tools[SHAPE_NEW_POLYGON]->hide(); - tools[SHAPE_NEW_RECTANGLE]->hide(); - - separator_delete->hide(); - tools[SHAPE_DELETE]->hide(); - - tools[SHAPE_KEEP_INSIDE_TILE]->hide(); - - tools[TOOL_SELECT]->set_pressed(true); - tools[TOOL_SELECT]->set_tooltip(TTR("LMB: Set bit on.\nRMB: Set bit off.\nShift+LMB: Set wildcard bit.\nClick on another Tile to edit it.")); - spin_priority->hide(); - } break; - case EDITMODE_Z_INDEX: - case EDITMODE_PRIORITY: - case EDITMODE_ICON: { - tools[TOOL_SELECT]->show(); - - separator_bitmask->hide(); - tools[BITMASK_COPY]->hide(); - tools[BITMASK_PASTE]->hide(); - tools[BITMASK_CLEAR]->hide(); - tools[SHAPE_NEW_POLYGON]->hide(); - tools[SHAPE_NEW_RECTANGLE]->hide(); - - separator_delete->hide(); - tools[SHAPE_DELETE]->hide(); - - separator_grid->show(); - tools[SHAPE_KEEP_INSIDE_TILE]->hide(); - tools[TOOL_GRID_SNAP]->show(); - - if (edit_mode == EDITMODE_ICON) { - tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to use as icon, this will be also used on invalid autotile bindings.\nClick on another Tile to edit it.")); - spin_priority->hide(); - spin_z_index->hide(); - } else if (edit_mode == EDITMODE_PRIORITY) { - tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to change its priority.\nClick on another Tile to edit it.")); - spin_priority->show(); - spin_z_index->hide(); - } else { - tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to change its z index.\nClick on another Tile to edit it.")); - spin_priority->hide(); - spin_z_index->show(); - } - } break; - default: { - } - } - _update_toggle_shape_button(); - workspace->update(); -} - -void TileSetEditor::_on_workspace_mode_changed(int p_workspace_mode) { - workspace_mode = (WorkspaceMode)p_workspace_mode; - if (p_workspace_mode == WORKSPACE_EDIT) { - update_workspace_tile_mode(); - } else { - for (int i = 0; i < EDITMODE_MAX; i++) { - tool_editmode[i]->hide(); - } - tool_editmode[EDITMODE_REGION]->show(); - tool_editmode[EDITMODE_REGION]->set_pressed(true); - _on_edit_mode_changed(EDITMODE_REGION); - separator_editmode->show(); - } -} - -void TileSetEditor::_on_workspace_draw() { - if (tileset.is_null() || !get_current_texture().is_valid()) { - return; - } - - const Color COLOR_AUTOTILE = Color(0.3, 0.6, 1); - const Color COLOR_SINGLE = Color(1, 1, 0.3); - const Color COLOR_ATLAS = Color(0.8, 0.8, 0.8); - const Color COLOR_SUBDIVISION = Color(0.3, 0.7, 0.6); - - draw_handles = false; - - draw_highlight_current_tile(); - - draw_grid_snap(); - if (get_current_tile() >= 0) { - int spacing = tileset->autotile_get_spacing(get_current_tile()); - Vector2 size = tileset->autotile_get_size(get_current_tile()); - Rect2i region = tileset->tile_get_region(get_current_tile()); - - switch (edit_mode) { - case EDITMODE_ICON: { - Vector2 coord = tileset->autotile_get_icon_coordinate(get_current_tile()); - draw_highlight_subtile(coord); - } break; - case EDITMODE_BITMASK: { - Color c(1, 0, 0, 0.5); - Color ci(0.3, 0.6, 1, 0.5); - for (int x = 0; x < region.size.x / (spacing + size.x); x++) { - for (int y = 0; y < region.size.y / (spacing + size.y); y++) { - Vector2 coord(x, y); - Point2 anchor(coord.x * (spacing + size.x), coord.y * (spacing + size.y)); - anchor += WORKSPACE_MARGIN; - anchor += region.position; - uint32_t mask = tileset->autotile_get_bitmask(get_current_tile(), coord); - if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) { - if (mask & TileSet::BIND_IGNORE_TOPLEFT) { - workspace->draw_rect(Rect2(anchor, size / 4), ci); - workspace->draw_rect(Rect2(anchor + size / 4, size / 4), ci); - } else if (mask & TileSet::BIND_TOPLEFT) { - workspace->draw_rect(Rect2(anchor, size / 2), c); - } - if (mask & TileSet::BIND_IGNORE_TOPRIGHT) { - workspace->draw_rect(Rect2(anchor + Vector2(size.x / 2, 0), size / 4), ci); - workspace->draw_rect(Rect2(anchor + Vector2(size.x * 3 / 4, size.y / 4), size / 4), ci); - } else if (mask & TileSet::BIND_TOPRIGHT) { - workspace->draw_rect(Rect2(anchor + Vector2(size.x / 2, 0), size / 2), c); - } - if (mask & TileSet::BIND_IGNORE_BOTTOMLEFT) { - workspace->draw_rect(Rect2(anchor + Vector2(0, size.y / 2), size / 4), ci); - workspace->draw_rect(Rect2(anchor + Vector2(size.x / 4, size.y * 3 / 4), size / 4), ci); - } else if (mask & TileSet::BIND_BOTTOMLEFT) { - workspace->draw_rect(Rect2(anchor + Vector2(0, size.y / 2), size / 2), c); - } - if (mask & TileSet::BIND_IGNORE_BOTTOMRIGHT) { - workspace->draw_rect(Rect2(anchor + size / 2, size / 4), ci); - workspace->draw_rect(Rect2(anchor + size * 3 / 4, size / 4), ci); - } else if (mask & TileSet::BIND_BOTTOMRIGHT) { - workspace->draw_rect(Rect2(anchor + size / 2, size / 2), c); - } - } else { - if (mask & TileSet::BIND_IGNORE_TOPLEFT) { - workspace->draw_rect(Rect2(anchor, size / 6), ci); - workspace->draw_rect(Rect2(anchor + size / 6, size / 6), ci); - } else if (mask & TileSet::BIND_TOPLEFT) { - workspace->draw_rect(Rect2(anchor, size / 3), c); - } - if (mask & TileSet::BIND_IGNORE_TOP) { - workspace->draw_rect(Rect2(anchor + Vector2(size.x / 3, 0), size / 6), ci); - workspace->draw_rect(Rect2(anchor + Vector2(size.x / 2, size.y / 6), size / 6), ci); - } else if (mask & TileSet::BIND_TOP) { - workspace->draw_rect(Rect2(anchor + Vector2(size.x / 3, 0), size / 3), c); - } - if (mask & TileSet::BIND_IGNORE_TOPRIGHT) { - workspace->draw_rect(Rect2(anchor + Vector2(size.x * 4 / 6, 0), size / 6), ci); - workspace->draw_rect(Rect2(anchor + Vector2(size.x * 5 / 6, size.y / 6), size / 6), ci); - } else if (mask & TileSet::BIND_TOPRIGHT) { - workspace->draw_rect(Rect2(anchor + Vector2((size.x / 3) * 2, 0), size / 3), c); - } - if (mask & TileSet::BIND_IGNORE_LEFT) { - workspace->draw_rect(Rect2(anchor + Vector2(0, size.y / 3), size / 6), ci); - workspace->draw_rect(Rect2(anchor + Vector2(size.x / 6, size.y / 2), size / 6), ci); - } else if (mask & TileSet::BIND_LEFT) { - workspace->draw_rect(Rect2(anchor + Vector2(0, size.y / 3), size / 3), c); - } - if (mask & TileSet::BIND_IGNORE_CENTER) { - workspace->draw_rect(Rect2(anchor + size / 3, size / 6), ci); - workspace->draw_rect(Rect2(anchor + size / 2, size / 6), ci); - } else if (mask & TileSet::BIND_CENTER) { - workspace->draw_rect(Rect2(anchor + Vector2(size.x / 3, size.y / 3), size / 3), c); - } - if (mask & TileSet::BIND_IGNORE_RIGHT) { - workspace->draw_rect(Rect2(anchor + Vector2(size.x * 4 / 6, size.y / 3), size / 6), ci); - workspace->draw_rect(Rect2(anchor + Vector2(size.x * 5 / 6, size.y / 2), size / 6), ci); - } else if (mask & TileSet::BIND_RIGHT) { - workspace->draw_rect(Rect2(anchor + Vector2((size.x / 3) * 2, size.y / 3), size / 3), c); - } - if (mask & TileSet::BIND_IGNORE_BOTTOMLEFT) { - workspace->draw_rect(Rect2(anchor + Vector2(0, size.y * 4 / 6), size / 6), ci); - workspace->draw_rect(Rect2(anchor + Vector2(size.x / 6, size.y * 5 / 6), size / 6), ci); - } else if (mask & TileSet::BIND_BOTTOMLEFT) { - workspace->draw_rect(Rect2(anchor + Vector2(0, (size.y / 3) * 2), size / 3), c); - } - if (mask & TileSet::BIND_IGNORE_BOTTOM) { - workspace->draw_rect(Rect2(anchor + Vector2(size.x / 3, size.y * 4 / 6), size / 6), ci); - workspace->draw_rect(Rect2(anchor + Vector2(size.x / 2, size.y * 5 / 6), size / 6), ci); - } else if (mask & TileSet::BIND_BOTTOM) { - workspace->draw_rect(Rect2(anchor + Vector2(size.x / 3, (size.y / 3) * 2), size / 3), c); - } - if (mask & TileSet::BIND_IGNORE_BOTTOMRIGHT) { - workspace->draw_rect(Rect2(anchor + size * 4 / 6, size / 6), ci); - workspace->draw_rect(Rect2(anchor + size * 5 / 6, size / 6), ci); - } else if (mask & TileSet::BIND_BOTTOMRIGHT) { - workspace->draw_rect(Rect2(anchor + (size / 3) * 2, size / 3), c); - } - } - } - } - } break; - case EDITMODE_COLLISION: - case EDITMODE_OCCLUSION: - case 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) { - draw_highlight_subtile(edited_shape_coord); - } - draw_polygon_shapes(); - draw_grid_snap(); - } break; - case EDITMODE_PRIORITY: { - spin_priority->set_value(tileset->autotile_get_subtile_priority(get_current_tile(), edited_shape_coord)); - uint32_t mask = tileset->autotile_get_bitmask(get_current_tile(), edited_shape_coord); - Vector queue_others; - int total = 0; - for (Map::Element *E = tileset->autotile_get_bitmask_map(get_current_tile()).front(); E; E = E->next()) { - if (E->value() == mask) { - total += tileset->autotile_get_subtile_priority(get_current_tile(), E->key()); - if (E->key() != edited_shape_coord) { - queue_others.push_back(E->key()); - } - } - } - spin_priority->set_suffix(" / " + String::num(total, 0)); - draw_highlight_subtile(edited_shape_coord, queue_others); - } break; - case EDITMODE_Z_INDEX: { - spin_z_index->set_value(tileset->autotile_get_z_index(get_current_tile(), edited_shape_coord)); - draw_highlight_subtile(edited_shape_coord); - } break; - default: { - } - } - } - - String current_texture_path = get_current_texture()->get_path(); - List tiles; - tileset->get_tile_list(&tiles); - for (List::Element *E = tiles.front(); E; E = E->next()) { - int t_id = E->get(); - if (tileset->tile_get_texture(t_id)->get_path() == current_texture_path && (t_id != get_current_tile() || edit_mode != EDITMODE_REGION || workspace_mode != WORKSPACE_EDIT)) { - Rect2i region = tileset->tile_get_region(t_id); - region.position += WORKSPACE_MARGIN; - Color c; - if (tileset->tile_get_tile_mode(t_id) == TileSet::SINGLE_TILE) { - c = COLOR_SINGLE; - } else if (tileset->tile_get_tile_mode(t_id) == TileSet::AUTO_TILE) { - c = COLOR_AUTOTILE; - } else if (tileset->tile_get_tile_mode(t_id) == TileSet::ATLAS_TILE) { - c = COLOR_ATLAS; - } - draw_tile_subdivision(t_id, COLOR_SUBDIVISION); - workspace->draw_rect(region, c, false); - } - } - - if (edit_mode == EDITMODE_REGION) { - if (workspace_mode != WORKSPACE_EDIT) { - Rect2i region = edited_region; - Color c; - if (workspace_mode == WORKSPACE_CREATE_SINGLE) { - c = COLOR_SINGLE; - } else if (workspace_mode == WORKSPACE_CREATE_AUTOTILE) { - c = COLOR_AUTOTILE; - } else if (workspace_mode == WORKSPACE_CREATE_ATLAS) { - c = COLOR_ATLAS; - } - workspace->draw_rect(region, c, false); - draw_edited_region_subdivision(); - } else { - int t_id = get_current_tile(); - if (t_id < 0) { - return; - } - - Rect2i region; - if (draw_edited_region) { - region = edited_region; - } else { - region = tileset->tile_get_region(t_id); - region.position += WORKSPACE_MARGIN; - } - - if (draw_edited_region) { - draw_edited_region_subdivision(); - } else { - draw_tile_subdivision(t_id, COLOR_SUBDIVISION); - } - - Color c; - if (tileset->tile_get_tile_mode(t_id) == TileSet::SINGLE_TILE) { - c = COLOR_SINGLE; - } else if (tileset->tile_get_tile_mode(t_id) == TileSet::AUTO_TILE) { - c = COLOR_AUTOTILE; - } else if (tileset->tile_get_tile_mode(t_id) == TileSet::ATLAS_TILE) { - c = COLOR_ATLAS; - } - workspace->draw_rect(region, c, false); - } - } - - workspace_overlay->update(); -} - -void TileSetEditor::_on_workspace_process() { - 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(); - } -} - -void TileSetEditor::_on_workspace_overlay_draw() { - if (!tileset.is_valid() || !get_current_texture().is_valid()) { - return; - } - - const Color COLOR_AUTOTILE = Color(0.266373, 0.565288, 0.988281); - 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_visible) { - String current_texture_path = get_current_texture()->get_path(); - List tiles; - tileset->get_tile_list(&tiles); - for (List::Element *E = tiles.front(); E; E = E->next()) { - int t_id = E->get(); - if (tileset->tile_get_texture(t_id)->get_path() != current_texture_path) { - continue; - } - - Rect2 region = tileset->tile_get_region(t_id); - region.position += WORKSPACE_MARGIN; - region.position *= workspace->get_scale().x; - Color c; - if (tileset->tile_get_tile_mode(t_id) == TileSet::SINGLE_TILE) { - c = COLOR_SINGLE; - } else if (tileset->tile_get_tile_mode(t_id) == TileSet::AUTO_TILE) { - c = COLOR_AUTOTILE; - } else if (tileset->tile_get_tile_mode(t_id) == TileSet::ATLAS_TILE) { - c = COLOR_ATLAS; - } - String tile_id_name = String::num(t_id, 0) + ": " + tileset->tile_get_name(t_id); - Ref 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); - workspace_overlay->draw_string(font, region.position, tile_id_name, c); - } - } - - int t_id = get_current_tile(); - if (t_id < 0) { - return; - } - - Ref handle = get_icon("EditorHandle", "EditorIcons"); - if (draw_handles) { - for (int i = 0; i < current_shape.size(); i++) { - workspace_overlay->draw_texture(handle, current_shape[i] * workspace->get_scale().x - handle->get_size() * 0.5); - } - } -} - -int TileSetEditor::get_grabbed_point(const Vector2 &p_mouse_pos, real_t p_grab_threshold) { - Transform2D xform = workspace->get_transform(); - - int grabbed_point = -1; - real_t min_distance = 1e10; - - for (int i = 0; i < current_shape.size(); i++) { - const real_t distance = xform.xform(current_shape[i]).distance_to(xform.xform(p_mouse_pos)); - if (distance < p_grab_threshold && distance < min_distance) { - min_distance = distance; - grabbed_point = i; - } - } - - return grabbed_point; -} - -bool TileSetEditor::is_within_grabbing_distance_of_first_point(const Vector2 &p_pos, real_t p_grab_threshold) { - Transform2D xform = workspace->get_transform(); - - const real_t distance = xform.xform(current_shape[0]).distance_to(xform.xform(p_pos)); - - return distance < p_grab_threshold; -} - -void TileSetEditor::_on_scroll_container_input(const Ref &p_event) { - const Ref mb = p_event; - - if (mb.is_valid()) { - // Zoom in/out using Ctrl + mouse wheel. This is done on the ScrollContainer - // to allow performing this action anywhere, even if the cursor isn't - // hovering the texture in the workspace. - if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed() && mb->get_control()) { - _zoom_on_position(scale_ratio, mb->get_position()); - // Don't scroll up after zooming in. - accept_event(); - } else if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->get_control()) { - _zoom_on_position(1 / scale_ratio, mb->get_position()); - // Don't scroll down after zooming out. - accept_event(); - } - } -} - -void TileSetEditor::_on_workspace_input(const Ref &p_ie) { - if (tileset.is_null() || !get_current_texture().is_valid()) { - return; - } - - static bool dragging; - static bool erasing; - static bool alternative; - draw_edited_region = false; - - Rect2 current_tile_region = Rect2(); - if (get_current_tile() >= 0) { - current_tile_region = tileset->tile_get_region(get_current_tile()); - } - current_tile_region.position += WORKSPACE_MARGIN; - - const Ref mb = p_ie; - const Ref mm = p_ie; - - if (mb.is_valid()) { - if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && !creating_shape) { - if (!current_tile_region.has_point(mb->get_position())) { - String current_texture_path = get_current_texture()->get_path(); - List tiles; - tileset->get_tile_list(&tiles); - for (List::Element *E = tiles.front(); E; E = E->next()) { - int t_id = E->get(); - if (tileset->tile_get_texture(t_id)->get_path() == current_texture_path) { - Rect2 r = tileset->tile_get_region(t_id); - r.position += WORKSPACE_MARGIN; - if (r.has_point(mb->get_position())) { - set_current_tile(t_id); - workspace->update(); - workspace_overlay->update(); - return; - } - } - } - } - } - } - // Drag Middle Mouse - if (mm.is_valid()) { - if (mm->get_button_mask() & BUTTON_MASK_MIDDLE) { - Vector2 dragged(mm->get_relative().x, mm->get_relative().y); - scroll->set_h_scroll(scroll->get_h_scroll() - dragged.x * workspace->get_scale().x); - scroll->set_v_scroll(scroll->get_v_scroll() - dragged.y * workspace->get_scale().x); - } - } - - if (edit_mode == EDITMODE_REGION) { - if (mb.is_valid()) { - if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { - if (get_current_tile() >= 0 || workspace_mode != WORKSPACE_EDIT) { - dragging = true; - region_from = mb->get_position(); - edited_region = Rect2(region_from, Size2()); - workspace->update(); - workspace_overlay->update(); - return; - } - } else if (dragging && mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) { - dragging = false; - edited_region = Rect2(); - workspace->update(); - workspace_overlay->update(); - return; - } else if (dragging && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { - dragging = false; - update_edited_region(mb->get_position()); - edited_region.position -= WORKSPACE_MARGIN; - if (!edited_region.has_no_area()) { - if (get_current_tile() >= 0 && workspace_mode == WORKSPACE_EDIT) { - 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())); - - Size2 tile_workspace_size = edited_region.position + edited_region.size + WORKSPACE_MARGIN * 2; - Size2 workspace_minsize = workspace->get_custom_minimum_size(); - // If the new region is bigger, just directly change the workspace size to avoid checking all other tiles. - if (tile_workspace_size.x > workspace_minsize.x || tile_workspace_size.y > workspace_minsize.y) { - Size2 max_workspace_size = Size2(MAX(tile_workspace_size.x, workspace_minsize.x), MAX(tile_workspace_size.y, workspace_minsize.y)); - undo_redo->add_do_method(workspace, "set_custom_minimum_size", max_workspace_size); - undo_redo->add_undo_method(workspace, "set_custom_minimum_size", workspace_minsize); - undo_redo->add_do_method(workspace_container, "set_custom_minimum_size", max_workspace_size); - undo_redo->add_undo_method(workspace_container, "set_custom_minimum_size", workspace_minsize); - undo_redo->add_do_method(workspace_overlay, "set_custom_minimum_size", max_workspace_size); - undo_redo->add_undo_method(workspace_overlay, "set_custom_minimum_size", workspace_minsize); - } else if (workspace_minsize.x > get_current_texture()->get_size().x + WORKSPACE_MARGIN.x * 2 || workspace_minsize.y > get_current_texture()->get_size().y + WORKSPACE_MARGIN.y * 2) { - undo_redo->add_do_method(this, "update_workspace_minsize"); - undo_redo->add_undo_method(this, "update_workspace_minsize"); - } - - 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(); - 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) { - 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); - } - - tool_workspacemode[WORKSPACE_EDIT]->set_pressed(true); - tool_editmode[EDITMODE_COLLISION]->set_pressed(true); - edit_mode = EDITMODE_COLLISION; - - Size2 tile_workspace_size = edited_region.position + edited_region.size + WORKSPACE_MARGIN * 2; - Size2 workspace_minsize = workspace->get_custom_minimum_size(); - if (tile_workspace_size.x > workspace_minsize.x || tile_workspace_size.y > workspace_minsize.y) { - Size2 new_workspace_minsize = Size2(MAX(tile_workspace_size.x, workspace_minsize.x), MAX(tile_workspace_size.y, workspace_minsize.y)); - undo_redo->add_do_method(workspace, "set_custom_minimum_size", new_workspace_minsize); - undo_redo->add_undo_method(workspace, "set_custom_minimum_size", workspace_minsize); - undo_redo->add_do_method(workspace_container, "set_custom_minimum_size", new_workspace_minsize); - undo_redo->add_undo_method(workspace_container, "set_custom_minimum_size", workspace_minsize); - undo_redo->add_do_method(workspace_overlay, "set_custom_minimum_size", new_workspace_minsize); - undo_redo->add_undo_method(workspace_overlay, "set_custom_minimum_size", workspace_minsize); - } - - 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(); - } - return; - } - } else if (mm.is_valid()) { - if (dragging) { - update_edited_region(mm->get_position()); - draw_edited_region = true; - workspace->update(); - workspace_overlay->update(); - return; - } - } - } - - 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()); - switch (edit_mode) { - case EDITMODE_ICON: { - 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))); - 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; - case EDITMODE_BITMASK: { - if (mb.is_valid()) { - if (mb->is_pressed()) { - if (dragging) { - return; - } - if ((mb->get_button_index() == BUTTON_RIGHT || mb->get_button_index() == BUTTON_LEFT) && current_tile_region.has_point(mb->get_position())) { - dragging = true; - erasing = (mb->get_button_index() == BUTTON_RIGHT); - alternative = Input::get_singleton()->is_key_pressed(KEY_SHIFT); - 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))); - Vector2 pos(coord.x * (spacing + size.x), coord.y * (spacing + size.y)); - pos = mb->get_position() - (pos + current_tile_region.position); - uint32_t bit = 0; - if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) { - if (pos.x < size.x / 2) { - if (pos.y < size.y / 2) { - bit = TileSet::BIND_TOPLEFT; - } else { - bit = TileSet::BIND_BOTTOMLEFT; - } - } else { - if (pos.y < size.y / 2) { - bit = TileSet::BIND_TOPRIGHT; - } else { - bit = TileSet::BIND_BOTTOMRIGHT; - } - } - } else { - if (pos.x < size.x / 3) { - if (pos.y < size.y / 3) { - bit = TileSet::BIND_TOPLEFT; - } else if (pos.y > (size.y / 3) * 2) { - bit = TileSet::BIND_BOTTOMLEFT; - } else { - bit = TileSet::BIND_LEFT; - } - } else if (pos.x > (size.x / 3) * 2) { - if (pos.y < size.y / 3) { - bit = TileSet::BIND_TOPRIGHT; - } else if (pos.y > (size.y / 3) * 2) { - bit = TileSet::BIND_BOTTOMRIGHT; - } else { - bit = TileSet::BIND_RIGHT; - } - } else { - if (pos.y < size.y / 3) { - bit = TileSet::BIND_TOP; - } else if (pos.y > (size.y / 3) * 2) { - bit = TileSet::BIND_BOTTOM; - } else { - bit = TileSet::BIND_CENTER; - } - } - } - - uint32_t old_mask = tileset->autotile_get_bitmask(get_current_tile(), coord); - uint32_t new_mask = old_mask; - if (alternative) { - new_mask &= ~bit; - new_mask |= (bit << 16); - } else if (erasing) { - new_mask &= ~bit; - new_mask &= ~(bit << 16); - } else { - new_mask |= bit; - new_mask &= ~(bit << 16); - } - - 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(); - } - } - } else { - if ((erasing && mb->get_button_index() == BUTTON_RIGHT) || (!erasing && mb->get_button_index() == BUTTON_LEFT)) { - dragging = false; - erasing = false; - alternative = false; - } - } - } - if (mm.is_valid()) { - if (dragging && current_tile_region.has_point(mm->get_position())) { - Vector2 coord((int)((mm->get_position().x - current_tile_region.position.x) / (spacing + size.x)), (int)((mm->get_position().y - current_tile_region.position.y) / (spacing + size.y))); - Vector2 pos(coord.x * (spacing + size.x), coord.y * (spacing + size.y)); - pos = mm->get_position() - (pos + current_tile_region.position); - uint32_t bit = 0; - if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) { - if (pos.x < size.x / 2) { - if (pos.y < size.y / 2) { - bit = TileSet::BIND_TOPLEFT; - } else { - bit = TileSet::BIND_BOTTOMLEFT; - } - } else { - if (pos.y < size.y / 2) { - bit = TileSet::BIND_TOPRIGHT; - } else { - bit = TileSet::BIND_BOTTOMRIGHT; - } - } - } else { - if (pos.x < size.x / 3) { - if (pos.y < size.y / 3) { - bit = TileSet::BIND_TOPLEFT; - } else if (pos.y > (size.y / 3) * 2) { - bit = TileSet::BIND_BOTTOMLEFT; - } else { - bit = TileSet::BIND_LEFT; - } - } else if (pos.x > (size.x / 3) * 2) { - if (pos.y < size.y / 3) { - bit = TileSet::BIND_TOPRIGHT; - } else if (pos.y > (size.y / 3) * 2) { - bit = TileSet::BIND_BOTTOMRIGHT; - } else { - bit = TileSet::BIND_RIGHT; - } - } else { - if (pos.y < size.y / 3) { - bit = TileSet::BIND_TOP; - } else if (pos.y > (size.y / 3) * 2) { - bit = TileSet::BIND_BOTTOM; - } else { - bit = TileSet::BIND_CENTER; - } - } - } - - uint32_t old_mask = tileset->autotile_get_bitmask(get_current_tile(), coord); - uint32_t new_mask = old_mask; - if (alternative) { - new_mask &= ~bit; - new_mask |= (bit << 16); - } else if (erasing) { - new_mask &= ~bit; - new_mask &= ~(bit << 16); - } else { - new_mask |= bit; - new_mask &= ~(bit << 16); - } - 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(); - } - } - } - } break; - case EDITMODE_COLLISION: - case EDITMODE_OCCLUSION: - case EDITMODE_NAVIGATION: - case EDITMODE_PRIORITY: - case EDITMODE_Z_INDEX: { - Vector2 shape_anchor = Vector2(0, 0); - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) { - shape_anchor = edited_shape_coord; - 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) { - int grabbed_point = get_grabbed_point(mb->get_position(), grab_threshold); - - if (grabbed_point >= 0) { - dragging_point = grabbed_point; - workspace->update(); - return; - } - } - if ((tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) && 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))); - if (edited_shape_coord != coord) { - edited_shape_coord = coord; - _select_edited_shape_coord(); - } - } - workspace->update(); - } else if (!mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { - if (edit_mode == EDITMODE_COLLISION) { - if (dragging_point >= 0) { - dragging_point = -1; - - Vector points; - - for (int i = 0; i < current_shape.size(); i++) { - Vector2 p = current_shape[i]; - if (tools[TOOL_GRID_SNAP]->is_pressed() || tools[SHAPE_KEEP_INSIDE_TILE]->is_pressed()) { - p = snap_point(p); - } - points.push_back(p - shape_anchor); - } - - undo_redo->create_action(TTR("Edit Collision Polygon")); - _set_edited_shape_points(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) { - dragging_point = -1; - - PoolVector polygon; - polygon.resize(current_shape.size()); - PoolVector::Write w = polygon.write(); - - for (int i = 0; i < current_shape.size(); i++) { - w[i] = current_shape[i] - shape_anchor; - } - - w.release(); - - 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) { - dragging_point = -1; - - PoolVector polygon; - Vector indices; - polygon.resize(current_shape.size()); - PoolVector::Write w = polygon.write(); - - for (int i = 0; i < current_shape.size(); i++) { - w[i] = current_shape[i] - shape_anchor; - indices.push_back(i); - } - - w.release(); - - 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(), "clear_polygons"); - undo_redo->add_undo_method(edited_navigation_shape.ptr(), "clear_polygons"); - 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(); - } - } - } - } else if (mm.is_valid()) { - if (dragging_point >= 0) { - current_shape.set(dragging_point, snap_point(mm->get_position())); - workspace->update(); - } - } - } 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() > 2) { - if (is_within_grabbing_distance_of_first_point(mb->get_position(), grab_threshold)) { - close_shape(shape_anchor); - workspace->update(); - return; - } - } - current_shape.push_back(pos); - workspace->update(); - } else { - creating_shape = true; - _set_edited_collision_shape(Ref()); - current_shape.resize(0); - current_shape.push_back(snap_point(pos)); - workspace->update(); - } - } else if (mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) { - if (creating_shape) { - creating_shape = false; - _select_edited_shape_coord(); - workspace->update(); - } - } - } else if (mm.is_valid()) { - if (creating_shape) { - workspace->update(); - } - } - } else if (tools[SHAPE_NEW_RECTANGLE]->is_pressed()) { - if (mb.is_valid()) { - if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { - _set_edited_collision_shape(Ref()); - current_shape.resize(0); - Vector2 pos = mb->get_position(); - pos = snap_point(pos); - current_shape.push_back(pos); - current_shape.push_back(pos); - current_shape.push_back(pos); - current_shape.push_back(pos); - creating_shape = true; - workspace->update(); - return; - } else if (mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) { - if (creating_shape) { - creating_shape = false; - _select_edited_shape_coord(); - workspace->update(); - } - } else if (!mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { - if (creating_shape) { - // if the first two corners are within grabbing distance of one another, expand the rect to fill the tile - if (is_within_grabbing_distance_of_first_point(current_shape[1], grab_threshold)) { - current_shape.set(0, snap_point(shape_anchor)); - current_shape.set(1, snap_point(shape_anchor + Vector2(current_tile_region.size.x, 0))); - current_shape.set(2, snap_point(shape_anchor + current_tile_region.size)); - current_shape.set(3, snap_point(shape_anchor + Vector2(0, current_tile_region.size.y))); - } - - close_shape(shape_anchor); - workspace->update(); - return; - } - } - } else if (mm.is_valid()) { - if (creating_shape) { - Vector2 pos = mm->get_position(); - pos = snap_point(pos); - Vector2 p = current_shape[2]; - current_shape.set(3, snap_point(Vector2(pos.x, p.y))); - current_shape.set(0, snap_point(pos)); - current_shape.set(1, snap_point(Vector2(p.x, pos.y))); - workspace->update(); - } - } - } - } break; - default: { - } - } - } - } -} - -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) { - 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::Element *E = bitmask_map_copy.front(); E; E = E->next()) { - undo_redo->add_do_method(tileset.ptr(), "autotile_set_bitmask", get_current_tile(), E->key(), E->value()); - } - for (Map::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) { - undo_redo->create_action(TTR("Clear Tile Bitmask")); - undo_redo->add_do_method(tileset.ptr(), "autotile_clear_bitmask_map", get_current_tile()); - for (Map::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_TOGGLE_TYPE) { - if (edited_collision_shape.is_valid()) { - Ref convex = edited_collision_shape; - Ref concave = edited_collision_shape; - Ref previous_shape = edited_collision_shape; - Array sd = tileset->call("tile_get_shapes", get_current_tile()); - - if (convex.is_valid()) { - // Make concave. - undo_redo->create_action(TTR("Make Polygon Concave")); - Ref _concave = memnew(ConcavePolygonShape2D); - edited_collision_shape = _concave; - _set_edited_shape_points(_get_collision_shape_points(convex)); - } else if (concave.is_valid()) { - // Make convex. - undo_redo->create_action(TTR("Make Polygon Convex")); - Ref _convex = memnew(ConvexPolygonShape2D); - edited_collision_shape = _convex; - _set_edited_shape_points(_get_collision_shape_points(concave)); - } - for (int i = 0; i < sd.size(); i++) { - if (sd[i].get("shape") == previous_shape) { - undo_redo->add_undo_method(tileset.ptr(), "tile_set_shapes", get_current_tile(), sd.duplicate()); - 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) { - undo_redo->add_do_method(tileset.ptr(), "tile_add_shape", get_current_tile(), edited_collision_shape, Transform2D(), false, edited_shape_coord); - } else { - undo_redo->add_do_method(tileset.ptr(), "tile_add_shape", get_current_tile(), edited_collision_shape, Transform2D()); - } - undo_redo->add_do_method(this, "_select_edited_shape_coord"); - undo_redo->add_undo_method(this, "_select_edited_shape_coord"); - undo_redo->commit_action(); - - _update_toggle_shape_button(); - workspace->update(); - workspace_container->update(); - helper->_change_notify(""); - } - } else if (p_tool == SELECT_NEXT) { - _select_next_shape(); - } else if (p_tool == SELECT_PREVIOUS) { - _select_previous_shape(); - } else if (p_tool == SHAPE_DELETE) { - if (creating_shape) { - creating_shape = false; - current_shape.resize(0); - workspace->update(); - } else { - switch (edit_mode) { - case EDITMODE_REGION: { - 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"); - - Rect2 tile_region = tileset->tile_get_region(get_current_tile()); - Size2 tile_workspace_size = tile_region.position + tile_region.size; - if (tile_workspace_size.x > get_current_texture()->get_size().x || tile_workspace_size.y > get_current_texture()->get_size().y) { - undo_redo->add_do_method(this, "update_workspace_minsize"); - undo_redo->add_undo_method(this, "update_workspace_minsize"); - } - - 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; - update_workspace_tile_mode(); - } break; - case EDITMODE_COLLISION: { - if (!edited_collision_shape.is_null()) { - // 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].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; - } - } - } - } 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()); - 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(), 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()) { - 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()); - 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(), 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: { - } - } - } - } else if (p_tool == TOOL_SELECT || p_tool == SHAPE_NEW_POLYGON || p_tool == SHAPE_NEW_RECTANGLE) { - if (creating_shape) { - // Cancel Creation - creating_shape = false; - current_shape.resize(0); - workspace->update(); - } - } -} - -void TileSetEditor::_on_priority_changed(float val) { - 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) { - 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) { - helper->set_snap_options_visible(p_val); - workspace->update(); -} - -Vector TileSetEditor::_get_collision_shape_points(const Ref &p_shape) { - Ref convex = p_shape; - Ref concave = p_shape; - if (convex.is_valid()) { - return convex->get_points(); - } else if (concave.is_valid()) { - Vector points; - for (int i = 0; i < concave->get_segments().size(); i += 2) { - points.push_back(concave->get_segments()[i]); - } - return points; - } else { - return Vector(); - } -} - -Vector TileSetEditor::_get_edited_shape_points() { - return _get_collision_shape_points(edited_collision_shape); -} - -void TileSetEditor::_set_edited_shape_points(const Vector &points) { - Ref convex = edited_collision_shape; - Ref concave = edited_collision_shape; - if (convex.is_valid()) { - undo_redo->add_do_method(convex.ptr(), "set_points", points); - undo_redo->add_undo_method(convex.ptr(), "set_points", _get_edited_shape_points()); - } else if (concave.is_valid() && points.size() > 1) { - PoolVector2Array segments; - for (int i = 0; i < points.size() - 1; i++) { - segments.push_back(points[i]); - segments.push_back(points[i + 1]); - } - segments.push_back(points[points.size() - 1]); - segments.push_back(points[0]); - undo_redo->add_do_method(concave.ptr(), "set_segments", segments); - undo_redo->add_undo_method(concave.ptr(), "set_segments", concave->get_segments()); - } -} - -void TileSetEditor::_update_tile_data() { - current_tile_data.clear(); - if (get_current_tile() < 0) { - return; - } - - Vector sd = tileset->tile_get_shapes(get_current_tile()); - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { - SubtileData data; - for (int i = 0; i < sd.size(); i++) { - data.collisions.push_back(sd[i].shape); - } - data.navigation_shape = tileset->tile_get_navigation_polygon(get_current_tile()); - data.occlusion_shape = tileset->tile_get_light_occluder(get_current_tile()); - current_tile_data[Vector2i()] = data; - } else { - Vector2 cell_count = _get_subtiles_count(get_current_tile()); - for (int y = 0; y < cell_count.y; y++) { - for (int x = 0; x < cell_count.x; x++) { - SubtileData data; - Vector2i coord(x, y); - for (int i = 0; i < sd.size(); i++) { - if (sd[i].autotile_coord == coord) { - data.collisions.push_back(sd[i].shape); - } - } - data.navigation_shape = tileset->autotile_get_navigation_polygon(get_current_tile(), coord); - data.occlusion_shape = tileset->tile_get_light_occluder(get_current_tile()); - current_tile_data[coord] = data; - } - } - } -} - -void TileSetEditor::_update_toggle_shape_button() { - Ref convex = edited_collision_shape; - Ref concave = edited_collision_shape; - separator_shape_toggle->show(); - tools[SHAPE_TOGGLE_TYPE]->show(); - if (edit_mode != EDITMODE_COLLISION || !edited_collision_shape.is_valid()) { - separator_shape_toggle->hide(); - tools[SHAPE_TOGGLE_TYPE]->hide(); - } else if (concave.is_valid()) { - tools[SHAPE_TOGGLE_TYPE]->set_icon(get_icon("ConvexPolygonShape2D", "EditorIcons")); - tools[SHAPE_TOGGLE_TYPE]->set_text(TTR("Make Convex")); - } else if (convex.is_valid()) { - tools[SHAPE_TOGGLE_TYPE]->set_icon(get_icon("ConcavePolygonShape2D", "EditorIcons")); - tools[SHAPE_TOGGLE_TYPE]->set_text(TTR("Make Concave")); - } else { - // Shouldn't happen - separator_shape_toggle->hide(); - tools[SHAPE_TOGGLE_TYPE]->hide(); - } -} - -void TileSetEditor::_select_next_tile() { - Array tiles = _get_tiles_in_current_texture(true); - if (tiles.size() == 0) { - set_current_tile(-1); - } else if (get_current_tile() == -1) { - set_current_tile(tiles[0]); - } else { - int index = tiles.find(get_current_tile()); - if (index < 0) { - set_current_tile(tiles[0]); - } else if (index == tiles.size() - 1) { - set_current_tile(tiles[0]); - } else { - set_current_tile(tiles[index + 1]); - } - } - if (get_current_tile() == -1) { - return; - } else if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { - return; - } else { - switch (edit_mode) { - case EDITMODE_COLLISION: - case EDITMODE_OCCLUSION: - case EDITMODE_NAVIGATION: - case EDITMODE_PRIORITY: - case EDITMODE_Z_INDEX: { - edited_shape_coord = Vector2(); - _select_edited_shape_coord(); - } break; - default: { - } - } - } -} - -void TileSetEditor::_select_previous_tile() { - Array tiles = _get_tiles_in_current_texture(true); - if (tiles.size() == 0) { - set_current_tile(-1); - } else if (get_current_tile() == -1) { - set_current_tile(tiles[tiles.size() - 1]); - } else { - int index = tiles.find(get_current_tile()); - if (index <= 0) { - set_current_tile(tiles[tiles.size() - 1]); - } else { - set_current_tile(tiles[index - 1]); - } - } - if (get_current_tile() == -1) { - return; - } else if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { - return; - } else { - switch (edit_mode) { - case EDITMODE_COLLISION: - case EDITMODE_OCCLUSION: - case EDITMODE_NAVIGATION: - case EDITMODE_PRIORITY: - case EDITMODE_Z_INDEX: { - edited_shape_coord = _get_subtiles_count(get_current_tile()) - Vector2(1, 1); - _select_edited_shape_coord(); - } break; - default: { - } - } - } -} - -Array TileSetEditor::_get_tiles_in_current_texture(bool sorted) { - Array a; - List all_tiles; - if (!get_current_texture().is_valid()) { - return a; - } - tileset->get_tile_list(&all_tiles); - for (int i = 0; i < all_tiles.size(); i++) { - if (tileset->tile_get_texture(all_tiles[i]) == get_current_texture()) { - a.push_back(all_tiles[i]); - } - } - if (sorted) { - a.sort_custom(this, "_sort_tiles"); - } - return a; -} - -bool TileSetEditor::_sort_tiles(Variant p_a, Variant p_b) { - int a = p_a; - int b = p_b; - - Vector2 pos_a = tileset->tile_get_region(a).position; - Vector2 pos_b = tileset->tile_get_region(b).position; - if (pos_a.y < pos_b.y) { - return true; - - } else if (pos_a.y == pos_b.y) { - return (pos_a.x < pos_b.x); - } else { - return false; - } -} - -Vector2 TileSetEditor::_get_subtiles_count(int p_tile_id) { - const int spacing = tileset->autotile_get_spacing(p_tile_id); - const Vector2 region_size = tileset->tile_get_region(p_tile_id).size; - const Vector2 subtile_size = tileset->autotile_get_size(p_tile_id); - // In case of not perfect fit the last row/column is allowed to exceed the tile region. - // The return value is the biggest integer-only `(m, n)` satisfying the formula: - // (m, n) * subtile_size + (m - 1, n - 1) * spacing < region_size + subtile_size - Vector2 mn = Vector2(1, 1) + (region_size / (subtile_size + Vector2(spacing, spacing))); - return mn == mn.floor() ? mn.floor() - Vector2(1, 1) : mn.floor(); -} - -void TileSetEditor::_select_next_subtile() { - if (get_current_tile() == -1) { - _select_next_tile(); - return; - } - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { - _select_next_tile(); - } else if (edit_mode == EDITMODE_REGION || edit_mode == EDITMODE_BITMASK || edit_mode == EDITMODE_ICON) { - _select_next_tile(); - } else { - Vector2 cell_count = _get_subtiles_count(get_current_tile()); - if (edited_shape_coord.x >= cell_count.x - 1 && edited_shape_coord.y >= cell_count.y - 1) { - _select_next_tile(); - } else { - edited_shape_coord.x++; - if (edited_shape_coord.x > cell_count.x - 1) { - edited_shape_coord.x = 0; - edited_shape_coord.y++; - } - _select_edited_shape_coord(); - } - } -} - -void TileSetEditor::_select_previous_subtile() { - if (get_current_tile() == -1) { - _select_previous_tile(); - return; - } - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { - _select_previous_tile(); - } else if (edit_mode == EDITMODE_REGION || edit_mode == EDITMODE_BITMASK || edit_mode == EDITMODE_ICON) { - _select_previous_tile(); - } else { - Vector2 cell_count = _get_subtiles_count(get_current_tile()); - if (edited_shape_coord.x <= 0 && edited_shape_coord.y <= 0) { - _select_previous_tile(); - } else { - edited_shape_coord.x--; - if (edited_shape_coord.x < 0) { - edited_shape_coord.x = cell_count.x - 1; - edited_shape_coord.y--; - } - _select_edited_shape_coord(); - } - } -} - -void TileSetEditor::_select_next_shape() { - if (get_current_tile() == -1) { - _select_next_subtile(); - } else if (edit_mode != EDITMODE_COLLISION) { - _select_next_subtile(); - } else { - Vector2i edited_coord = Vector2i(); - if (tileset->tile_get_tile_mode(get_current_tile()) != TileSet::SINGLE_TILE) { - edited_coord = Vector2i(edited_shape_coord); - } - SubtileData data = current_tile_data[edited_coord]; - if (data.collisions.size() == 0) { - _select_next_subtile(); - } else { - int index = data.collisions.find(edited_collision_shape); - if (index < 0) { - _set_edited_collision_shape(data.collisions[0]); - } else if (index == data.collisions.size() - 1) { - _select_next_subtile(); - } else { - _set_edited_collision_shape(data.collisions[index + 1]); - } - } - current_shape.resize(0); - Rect2 current_tile_region = tileset->tile_get_region(get_current_tile()); - current_tile_region.position += WORKSPACE_MARGIN; - - int spacing = tileset->autotile_get_spacing(get_current_tile()); - Vector2 size = tileset->autotile_get_size(get_current_tile()); - Vector2 shape_anchor = edited_shape_coord; - shape_anchor.x *= (size.x + spacing); - shape_anchor.y *= (size.y + spacing); - current_tile_region.position += shape_anchor; - - if (edited_collision_shape.is_valid()) { - for (int i = 0; i < _get_edited_shape_points().size(); i++) { - current_shape.push_back(_get_edited_shape_points()[i] + current_tile_region.position); - } - } - workspace->update(); - workspace_container->update(); - helper->_change_notify(""); - } -} - -void TileSetEditor::_select_previous_shape() { - if (get_current_tile() == -1) { - _select_previous_subtile(); - if (get_current_tile() != -1 && edit_mode == EDITMODE_COLLISION) { - SubtileData data = current_tile_data[Vector2i(edited_shape_coord)]; - if (data.collisions.size() > 1) { - _set_edited_collision_shape(data.collisions[data.collisions.size() - 1]); - } - } else { - return; - } - } else if (edit_mode != EDITMODE_COLLISION) { - _select_previous_subtile(); - } else { - Vector2i edited_coord = Vector2i(); - if (tileset->tile_get_tile_mode(get_current_tile()) != TileSet::SINGLE_TILE) { - edited_coord = Vector2i(edited_shape_coord); - } - SubtileData data = current_tile_data[edited_coord]; - if (data.collisions.size() == 0) { - _select_previous_subtile(); - data = current_tile_data[Vector2i(edited_shape_coord)]; - if (data.collisions.size() > 1) { - _set_edited_collision_shape(data.collisions[data.collisions.size() - 1]); - } - } else { - int index = data.collisions.find(edited_collision_shape); - if (index < 0) { - _set_edited_collision_shape(data.collisions[data.collisions.size() - 1]); - } else if (index == 0) { - _select_previous_subtile(); - data = current_tile_data[Vector2i(edited_shape_coord)]; - if (data.collisions.size() > 1) { - _set_edited_collision_shape(data.collisions[data.collisions.size() - 1]); - } - } else { - _set_edited_collision_shape(data.collisions[index - 1]); - } - } - - current_shape.resize(0); - Rect2 current_tile_region = tileset->tile_get_region(get_current_tile()); - current_tile_region.position += WORKSPACE_MARGIN; - - int spacing = tileset->autotile_get_spacing(get_current_tile()); - Vector2 size = tileset->autotile_get_size(get_current_tile()); - Vector2 shape_anchor = edited_shape_coord; - shape_anchor.x *= (size.x + spacing); - shape_anchor.y *= (size.y + spacing); - current_tile_region.position += shape_anchor; - - if (edited_collision_shape.is_valid()) { - for (int i = 0; i < _get_edited_shape_points().size(); i++) { - current_shape.push_back(_get_edited_shape_points()[i] + current_tile_region.position); - } - } - workspace->update(); - workspace_container->update(); - helper->_change_notify(""); - } -} - -void TileSetEditor::_set_edited_collision_shape(const Ref &p_shape) { - edited_collision_shape = p_shape; - _update_toggle_shape_button(); -} - -void TileSetEditor::_set_snap_step(Vector2 p_val) { - snap_step.x = CLAMP(p_val.x, 1, 1024); - snap_step.y = CLAMP(p_val.y, 1, 1024); - workspace->update(); -} - -void TileSetEditor::_set_snap_off(Vector2 p_val) { - snap_offset.x = CLAMP(p_val.x, 0, 1024 + WORKSPACE_MARGIN.x); - snap_offset.y = CLAMP(p_val.y, 0, 1024 + WORKSPACE_MARGIN.y); - workspace->update(); -} - -void TileSetEditor::_set_snap_sep(Vector2 p_val) { - snap_separation.x = CLAMP(p_val.x, 0, 1024); - snap_separation.y = CLAMP(p_val.y, 0, 1024); - 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> oclusion_map = tileset->autotile_get_light_oclusion_map(p_id); - for (Map>::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> navigation_map = tileset->autotile_get_navigation_map(p_id); - for (Map>::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 bitmask_map = tileset->autotile_get_bitmask_map(p_id); - for (Map::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 priority_map = tileset->autotile_get_priority_map(p_id); - for (Map::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 z_map = tileset->autotile_get_z_index_map(p_id); - for (Map::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() { - _zoom_on_position(scale_ratio, Vector2()); -} - -void TileSetEditor::_zoom_out() { - _zoom_on_position(1 / scale_ratio, Vector2()); -} - -void TileSetEditor::_zoom_reset() { - workspace->set_scale(Vector2(1, 1)); - workspace_container->set_custom_minimum_size(workspace->get_rect().size); - workspace_overlay->set_custom_minimum_size(workspace->get_rect().size); -} - -void TileSetEditor::_zoom_on_position(float p_zoom, const Vector2 &p_position) { - const float old_scale = workspace->get_scale().x; - const float new_scale = CLAMP(old_scale * p_zoom, min_scale, max_scale); - - workspace->set_scale(Vector2(new_scale, new_scale)); - workspace_container->set_custom_minimum_size(workspace->get_rect().size * new_scale); - workspace_overlay->set_custom_minimum_size(workspace->get_rect().size * new_scale); - - Vector2 offset = Vector2(scroll->get_h_scroll(), scroll->get_v_scroll()); - offset = (offset + p_position) / old_scale * new_scale - p_position; - scroll->set_h_scroll(offset.x); - scroll->set_v_scroll(offset.y); -} - -void TileSetEditor::draw_highlight_current_tile() { - Color shadow_color = Color(0.3, 0.3, 0.3, 0.3); - if ((workspace_mode == WORKSPACE_EDIT && get_current_tile() >= 0) || !edited_region.has_no_area()) { - Rect2 region; - if (edited_region.has_no_area()) { - region = tileset->tile_get_region(get_current_tile()); - region.position += WORKSPACE_MARGIN; - } else { - region = edited_region; - } - - if (region.position.y >= 0) { - workspace->draw_rect(Rect2(0, 0, workspace->get_rect().size.x, region.position.y), shadow_color); - } - if (region.position.x >= 0) { - workspace->draw_rect(Rect2(0, MAX(0, region.position.y), region.position.x, MIN(workspace->get_rect().size.y - region.position.y, MIN(region.size.y, region.position.y + region.size.y))), shadow_color); - } - if (region.position.x + region.size.x <= workspace->get_rect().size.x) { - workspace->draw_rect(Rect2(region.position.x + region.size.x, MAX(0, region.position.y), workspace->get_rect().size.x - region.position.x - region.size.x, MIN(workspace->get_rect().size.y - region.position.y, MIN(region.size.y, region.position.y + region.size.y))), shadow_color); - } - if (region.position.y + region.size.y <= workspace->get_rect().size.y) { - workspace->draw_rect(Rect2(0, region.position.y + region.size.y, workspace->get_rect().size.x, workspace->get_rect().size.y - region.size.y - region.position.y), shadow_color); - } - } else { - workspace->draw_rect(Rect2(Point2(0, 0), workspace->get_rect().size), shadow_color); - } -} - -void TileSetEditor::draw_highlight_subtile(Vector2 coord, const Vector &other_highlighted) { - Color shadow_color = Color(0.3, 0.3, 0.3, 0.3); - Vector2 size = tileset->autotile_get_size(get_current_tile()); - int spacing = tileset->autotile_get_spacing(get_current_tile()); - Rect2 region = tileset->tile_get_region(get_current_tile()); - coord.x *= (size.x + spacing); - coord.y *= (size.y + spacing); - coord += region.position; - coord += WORKSPACE_MARGIN; - - if (coord.y >= 0) { - workspace->draw_rect(Rect2(0, 0, workspace->get_rect().size.x, coord.y), shadow_color); - } - if (coord.x >= 0) { - workspace->draw_rect(Rect2(0, MAX(0, coord.y), coord.x, MIN(workspace->get_rect().size.y - coord.y, MIN(size.y, coord.y + size.y))), shadow_color); - } - if (coord.x + size.x <= workspace->get_rect().size.x) { - workspace->draw_rect(Rect2(coord.x + size.x, MAX(0, coord.y), workspace->get_rect().size.x - coord.x - size.x, MIN(workspace->get_rect().size.y - coord.y, MIN(size.y, coord.y + size.y))), shadow_color); - } - if (coord.y + size.y <= workspace->get_rect().size.y) { - workspace->draw_rect(Rect2(0, coord.y + size.y, workspace->get_rect().size.x, workspace->get_rect().size.y - size.y - coord.y), shadow_color); - } - - coord += Vector2(1, 1) / workspace->get_scale().x; - workspace->draw_rect(Rect2(coord, size - Vector2(2, 2) / workspace->get_scale().x), Color(1, 0, 0), false); - for (int i = 0; i < other_highlighted.size(); i++) { - coord = other_highlighted[i]; - coord.x *= (size.x + spacing); - coord.y *= (size.y + spacing); - coord += region.position; - coord += WORKSPACE_MARGIN; - coord += Vector2(1, 1) / workspace->get_scale().x; - workspace->draw_rect(Rect2(coord, size - Vector2(2, 2) / workspace->get_scale().x), Color(1, 0.5, 0.5), false); - } -} - -void TileSetEditor::draw_tile_subdivision(int p_id, Color p_color) const { - Color c = p_color; - if (tileset->tile_get_tile_mode(p_id) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(p_id) == TileSet::ATLAS_TILE) { - Rect2 region = tileset->tile_get_region(p_id); - Size2 size = tileset->autotile_get_size(p_id); - int spacing = tileset->autotile_get_spacing(p_id); - float j = size.x; - - while (j < region.size.x) { - if (spacing <= 0) { - workspace->draw_line(region.position + WORKSPACE_MARGIN + Point2(j, 0), region.position + WORKSPACE_MARGIN + Point2(j, region.size.y), c); - } else { - workspace->draw_rect(Rect2(region.position + WORKSPACE_MARGIN + Point2(j, 0), Size2(spacing, region.size.y)), c); - } - j += spacing + size.x; - } - j = size.y; - while (j < region.size.y) { - if (spacing <= 0) { - workspace->draw_line(region.position + WORKSPACE_MARGIN + Point2(0, j), region.position + WORKSPACE_MARGIN + Point2(region.size.x, j), c); - } else { - workspace->draw_rect(Rect2(region.position + WORKSPACE_MARGIN + Point2(0, j), Size2(region.size.x, spacing)), c); - } - j += spacing + size.y; - } - } -} - -void TileSetEditor::draw_edited_region_subdivision() const { - Color c = Color(0.3, 0.7, 0.6); - Rect2 region = edited_region; - Size2 size; - int spacing; - bool draw; - - if (workspace_mode == WORKSPACE_EDIT) { - int p_id = get_current_tile(); - size = tileset->autotile_get_size(p_id); - spacing = tileset->autotile_get_spacing(p_id); - draw = tileset->tile_get_tile_mode(p_id) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(p_id) == TileSet::ATLAS_TILE; - } else { - size = snap_step; - spacing = snap_separation.x; - draw = workspace_mode != WORKSPACE_CREATE_SINGLE; - } - - if (draw) { - float j = size.x; - while (j < region.size.x) { - if (spacing <= 0) { - workspace->draw_line(region.position + Point2(j, 0), region.position + Point2(j, region.size.y), c); - } else { - workspace->draw_rect(Rect2(region.position + Point2(j, 0), Size2(spacing, region.size.y)), c); - } - j += spacing + size.x; - } - j = size.y; - while (j < region.size.y) { - if (spacing <= 0) { - workspace->draw_line(region.position + Point2(0, j), region.position + Point2(region.size.x, j), c); - } else { - workspace->draw_rect(Rect2(region.position + Point2(0, j), Size2(region.size.x, spacing)), c); - } - j += spacing + size.y; - } - } -} - -void TileSetEditor::draw_grid_snap() { - if (tools[TOOL_GRID_SNAP]->is_pressed()) { - Color grid_color = Color(0.4, 0, 1); - Size2 s = workspace->get_size(); - - int width_count = Math::floor((s.width - WORKSPACE_MARGIN.x) / (snap_step.x + snap_separation.x)); - int height_count = Math::floor((s.height - WORKSPACE_MARGIN.y) / (snap_step.y + snap_separation.y)); - - int last_p = 0; - if (snap_step.x != 0) { - for (int i = 0; i <= width_count; i++) { - if (i == 0 && snap_offset.x != 0) { - last_p = snap_offset.x; - } - if (snap_separation.x != 0) { - if (i != 0) { - workspace->draw_rect(Rect2(last_p, 0, snap_separation.x, s.height), grid_color); - last_p += snap_separation.x; - } else { - workspace->draw_rect(Rect2(last_p, 0, -snap_separation.x, s.height), grid_color); - } - } else { - workspace->draw_line(Point2(last_p, 0), Point2(last_p, s.height), grid_color); - } - last_p += snap_step.x; - } - } - last_p = 0; - if (snap_step.y != 0) { - for (int i = 0; i <= height_count; i++) { - if (i == 0 && snap_offset.y != 0) { - last_p = snap_offset.y; - } - if (snap_separation.y != 0) { - if (i != 0) { - workspace->draw_rect(Rect2(0, last_p, s.width, snap_separation.y), grid_color); - last_p += snap_separation.y; - } else { - workspace->draw_rect(Rect2(0, last_p, s.width, -snap_separation.y), grid_color); - } - } else { - workspace->draw_line(Point2(0, last_p), Point2(s.width, last_p), grid_color); - } - last_p += snap_step.y; - } - } - } -} - -void TileSetEditor::draw_polygon_shapes() { - int t_id = get_current_tile(); - if (t_id < 0) { - return; - } - - switch (edit_mode) { - case EDITMODE_COLLISION: { - Vector sd = tileset->tile_get_shapes(t_id); - for (int i = 0; i < sd.size(); i++) { - Vector2 coord = Vector2(0, 0); - Vector2 anchor = Vector2(0, 0); - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) { - coord = sd[i].autotile_coord; - anchor = tileset->autotile_get_size(t_id); - anchor.x += tileset->autotile_get_spacing(t_id); - anchor.y += tileset->autotile_get_spacing(t_id); - anchor.x *= coord.x; - anchor.y *= coord.y; - } - anchor += WORKSPACE_MARGIN; - anchor += tileset->tile_get_region(t_id).position; - Ref shape = sd[i].shape; - if (shape.is_valid()) { - Color c_bg; - Color c_border; - Ref convex = shape; - bool is_convex = convex.is_valid(); - if ((tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE || coord == edited_shape_coord) && sd[i].shape == edited_collision_shape) { - if (is_convex) { - c_bg = Color(0, 1, 1, 0.5); - c_border = Color(0, 1, 1); - } else { - c_bg = Color(0.8, 0, 1, 0.5); - c_border = Color(0.8, 0, 1); - } - } else { - if (is_convex) { - c_bg = Color(0.9, 0.7, 0.07, 0.5); - c_border = Color(0.9, 0.7, 0.07, 1); - - } else { - c_bg = Color(0.9, 0.45, 0.075, 0.5); - c_border = Color(0.9, 0.45, 0.075); - } - } - Vector polygon; - Vector colors; - 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); - } - } else { - for (int j = 0; j < _get_collision_shape_points(shape).size(); j++) { - polygon.push_back(_get_collision_shape_points(shape)[j] + anchor); - colors.push_back(c_bg); - } - } - - if (polygon.size() < 3) { - continue; - } - - workspace->draw_polygon(polygon, colors); - - if (coord == edited_shape_coord || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { - if (!creating_shape && polygon.size() > 1) { - 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; - } - } - } - } - } break; - case EDITMODE_OCCLUSION: { - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { - Ref shape = edited_occlusion_shape; - if (shape.is_valid()) { - Color c_bg = Color(0, 1, 1, 0.5); - Color c_border = Color(0, 1, 1); - - Vector polygon; - Vector colors; - Vector2 anchor = WORKSPACE_MARGIN; - anchor += tileset->tile_get_region(get_current_tile()).position; - 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); - - if (!creating_shape && polygon.size() > 1) { - 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_occlusion_shape) { - draw_handles = true; - } - } - } else { - Map> map = tileset->autotile_get_light_oclusion_map(t_id); - for (Map>::Element *E = map.front(); E; E = E->next()) { - Vector2 coord = E->key(); - Vector2 anchor = tileset->autotile_get_size(t_id); - anchor.x += tileset->autotile_get_spacing(t_id); - anchor.y += tileset->autotile_get_spacing(t_id); - anchor.x *= coord.x; - anchor.y *= coord.y; - anchor += WORKSPACE_MARGIN; - anchor += tileset->tile_get_region(t_id).position; - Ref shape = E->value(); - if (shape.is_valid()) { - Color c_bg; - Color c_border; - if (coord == edited_shape_coord && shape == edited_occlusion_shape) { - c_bg = Color(0, 1, 1, 0.5); - c_border = Color(0, 1, 1); - } else { - c_bg = Color(0.9, 0.7, 0.07, 0.5); - c_border = Color(0.9, 0.7, 0.07, 1); - } - Vector polygon; - Vector colors; - 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); - - if (coord == edited_shape_coord) { - if (!creating_shape && polygon.size() > 1) { - 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_occlusion_shape) { - draw_handles = true; - } - } - } - } - } - } break; - case EDITMODE_NAVIGATION: { - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { - Ref shape = edited_navigation_shape; - - if (shape.is_valid()) { - Color c_bg = Color(0, 1, 1, 0.5); - Color c_border = Color(0, 1, 1); - - Vector polygon; - Vector colors; - Vector2 anchor = WORKSPACE_MARGIN; - anchor += tileset->tile_get_region(get_current_tile()).position; - 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 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 (!creating_shape && polygon.size() > 1) { - 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> map = tileset->autotile_get_navigation_map(t_id); - for (Map>::Element *E = map.front(); E; E = E->next()) { - Vector2 coord = E->key(); - Vector2 anchor = tileset->autotile_get_size(t_id); - anchor.x += tileset->autotile_get_spacing(t_id); - anchor.y += tileset->autotile_get_spacing(t_id); - anchor.x *= coord.x; - anchor.y *= coord.y; - anchor += WORKSPACE_MARGIN; - anchor += tileset->tile_get_region(t_id).position; - Ref shape = E->value(); - if (shape.is_valid()) { - Color c_bg; - Color c_border; - if (coord == edited_shape_coord && shape == edited_navigation_shape) { - c_bg = Color(0, 1, 1, 0.5); - c_border = Color(0, 1, 1); - } else { - c_bg = Color(0.9, 0.7, 0.07, 0.5); - c_border = Color(0.9, 0.7, 0.07, 1); - } - Vector polygon; - Vector colors; - 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 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 (coord == edited_shape_coord) { - if (!creating_shape && polygon.size() > 1) { - 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; - } - } - } - } - } - } break; - default: { - } - } - - if (creating_shape && current_shape.size() > 1) { - 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; - } -} - -void TileSetEditor::close_shape(const Vector2 &shape_anchor) { - creating_shape = false; - - if (edit_mode == EDITMODE_COLLISION) { - if (current_shape.size() >= 3) { - Ref shape = memnew(ConvexPolygonShape2D); - - Vector points; - float p_total = 0; - - for (int i = 0; i < current_shape.size(); i++) { - points.push_back(current_shape[i] - shape_anchor); - - if (i != current_shape.size() - 1) { - p_total += ((current_shape[i + 1].x - current_shape[i].x) * (-current_shape[i + 1].y + (-current_shape[i].y))); - } else { - p_total += ((current_shape[0].x - current_shape[i].x) * (-current_shape[0].y + (-current_shape[i].y))); - } - } - - if (p_total < 0) { - points.invert(); - } - - shape->set_points(points); - - 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) { - undo_redo->add_do_method(tileset.ptr(), "tile_add_shape", get_current_tile(), shape, Transform2D(), false, edited_shape_coord); - } else { - 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(); - } - } else if (edit_mode == EDITMODE_OCCLUSION) { - Ref shape = memnew(OccluderPolygon2D); - - PoolVector polygon; - polygon.resize(current_shape.size()); - PoolVector::Write w = polygon.write(); - - for (int i = 0; i < current_shape.size(); i++) { - w[i] = current_shape[i] - shape_anchor; - } - - w.release(); - shape->set_polygon(polygon); - - 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); - 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 shape = memnew(NavigationPolygon); - - PoolVector polygon; - Vector indices; - polygon.resize(current_shape.size()); - PoolVector::Write w = polygon.write(); - - for (int i = 0; i < current_shape.size(); i++) { - w[i] = current_shape[i] - shape_anchor; - indices.push_back(i); - } - - w.release(); - shape->set_vertices(polygon); - shape->add_polygon(indices); - - 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); - 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(""); -} - -void TileSetEditor::select_coord(const Vector2 &coord) { - _update_tile_data(); - current_shape = PoolVector2Array(); - if (get_current_tile() == -1) { - return; - } - Rect2 current_tile_region = tileset->tile_get_region(get_current_tile()); - current_tile_region.position += WORKSPACE_MARGIN; - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { - if (edited_collision_shape != tileset->tile_get_shape(get_current_tile(), 0)) { - _set_edited_collision_shape(tileset->tile_get_shape(get_current_tile(), 0)); - } - if (edited_occlusion_shape != tileset->tile_get_light_occluder(get_current_tile())) { - edited_occlusion_shape = tileset->tile_get_light_occluder(get_current_tile()); - } - if (edited_navigation_shape != tileset->tile_get_navigation_polygon(get_current_tile())) { - edited_navigation_shape = tileset->tile_get_navigation_polygon(get_current_tile()); - } - - if (edit_mode == EDITMODE_COLLISION) { - current_shape.resize(0); - if (edited_collision_shape.is_valid()) { - for (int i = 0; i < _get_edited_shape_points().size(); i++) { - current_shape.push_back(_get_edited_shape_points()[i] + current_tile_region.position); - } - } - } else if (edit_mode == EDITMODE_OCCLUSION) { - current_shape.resize(0); - if (edited_occlusion_shape.is_valid()) { - for (int i = 0; i < edited_occlusion_shape->get_polygon().size(); i++) { - current_shape.push_back(edited_occlusion_shape->get_polygon()[i] + current_tile_region.position); - } - } - } else if (edit_mode == EDITMODE_NAVIGATION) { - current_shape.resize(0); - if (edited_navigation_shape.is_valid()) { - if (edited_navigation_shape->get_polygon_count() > 0) { - PoolVector vertices = edited_navigation_shape->get_vertices(); - for (int i = 0; i < edited_navigation_shape->get_polygon(0).size(); i++) { - current_shape.push_back(vertices[edited_navigation_shape->get_polygon(0)[i]] + current_tile_region.position); - } - } - } - } - } else { - Vector 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) { - _set_edited_collision_shape(sd[i].shape); - } - found_collision_shape = true; - break; - } - } - if (!found_collision_shape) { - _set_edited_collision_shape(Ref(nullptr)); - } - 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; - shape_anchor.x *= (size.x + spacing); - shape_anchor.y *= (size.y + spacing); - shape_anchor += current_tile_region.position; - if (edit_mode == EDITMODE_COLLISION) { - current_shape.resize(0); - if (edited_collision_shape.is_valid()) { - for (int j = 0; j < _get_edited_shape_points().size(); j++) { - current_shape.push_back(_get_edited_shape_points()[j] + shape_anchor); - } - } - } else if (edit_mode == EDITMODE_OCCLUSION) { - current_shape.resize(0); - if (edited_occlusion_shape.is_valid()) { - for (int i = 0; i < edited_occlusion_shape->get_polygon().size(); i++) { - current_shape.push_back(edited_occlusion_shape->get_polygon()[i] + shape_anchor); - } - } - } else if (edit_mode == EDITMODE_NAVIGATION) { - current_shape.resize(0); - if (edited_navigation_shape.is_valid()) { - if (edited_navigation_shape->get_polygon_count() > 0) { - PoolVector vertices = edited_navigation_shape->get_vertices(); - for (int i = 0; i < edited_navigation_shape->get_polygon(0).size(); i++) { - current_shape.push_back(vertices[edited_navigation_shape->get_polygon(0)[i]] + shape_anchor); - } - } - } - } - } - workspace->update(); - workspace_container->update(); - helper->_change_notify(""); -} - -Vector2 TileSetEditor::snap_point(const Vector2 &point) { - Vector2 p = point; - Vector2 coord = edited_shape_coord; - Vector2 tile_size = tileset->autotile_get_size(get_current_tile()); - int spacing = tileset->autotile_get_spacing(get_current_tile()); - Vector2 anchor = coord; - anchor.x *= (tile_size.x + spacing); - anchor.y *= (tile_size.y + spacing); - anchor += tileset->tile_get_region(get_current_tile()).position; - anchor += WORKSPACE_MARGIN; - Rect2 region(anchor, tile_size); - Rect2 tile_region(tileset->tile_get_region(get_current_tile()).position + WORKSPACE_MARGIN, tileset->tile_get_region(get_current_tile()).size); - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { - region.position = tileset->tile_get_region(get_current_tile()).position + WORKSPACE_MARGIN; - region.size = tileset->tile_get_region(get_current_tile()).size; - } - - if (tools[TOOL_GRID_SNAP]->is_pressed()) { - p.x = Math::snap_scalar_separation(snap_offset.x, snap_step.x, p.x, snap_separation.x); - p.y = Math::snap_scalar_separation(snap_offset.y, snap_step.y, p.y, snap_separation.y); - } - - if (tools[SHAPE_KEEP_INSIDE_TILE]->is_pressed()) { - if (p.x < region.position.x) { - p.x = region.position.x; - } - if (p.y < region.position.y) { - p.y = region.position.y; - } - if (p.x > region.position.x + region.size.x) { - p.x = region.position.x + region.size.x; - } - if (p.y > region.position.y + region.size.y) { - p.y = region.position.y + region.size.y; - } - } - - if (p.x < tile_region.position.x) { - p.x = tile_region.position.x; - } - if (p.y < tile_region.position.y) { - p.y = tile_region.position.y; - } - if (p.x > (tile_region.position.x + tile_region.size.x)) { - p.x = (tile_region.position.x + tile_region.size.x); - } - if (p.y > (tile_region.position.y + tile_region.size.y)) { - p.y = (tile_region.position.y + tile_region.size.y); - } - - return p; -} - -void TileSetEditor::add_texture(Ref p_texture) { - texture_list->add_item(p_texture->get_path().get_file()); - texture_map.insert(p_texture->get_path(), p_texture); - texture_list->set_item_metadata(texture_list->get_item_count() - 1, p_texture->get_path()); -} - -void TileSetEditor::remove_texture(Ref p_texture) { - texture_list->remove_item(texture_list->find_metadata(p_texture->get_path())); - texture_map.erase(p_texture->get_path()); - - _validate_current_tile_id(); - - if (!get_current_texture().is_valid()) { - _on_texture_list_selected(-1); - workspace_overlay->update(); - } -} - -void TileSetEditor::update_texture_list() { - Ref selected_texture = get_current_texture(); - - helper->set_tileset(tileset); - - List ids; - tileset->get_tile_list(&ids); - Vector ids_to_remove; - for (List::Element *E = ids.front(); E; E = E->next()) { - // Clear tiles referencing gone textures (user has been already given the chance to fix broken deps) - if (!tileset->tile_get_texture(E->get()).is_valid()) { - ids_to_remove.push_back(E->get()); - ERR_CONTINUE(!tileset->tile_get_texture(E->get()).is_valid()); - } - - if (!texture_map.has(tileset->tile_get_texture(E->get())->get_path())) { - add_texture(tileset->tile_get_texture(E->get())); - } - } - for (int i = 0; i < ids_to_remove.size(); i++) { - tileset->remove_tile(ids_to_remove[i]); - } - - if (texture_list->get_item_count() > 0 && selected_texture.is_valid()) { - texture_list->select(texture_list->find_metadata(selected_texture->get_path())); - if (texture_list->get_selected_items().size() > 0) { - _on_texture_list_selected(texture_list->get_selected_items()[0]); - } - } else if (get_current_texture().is_valid()) { - _on_texture_list_selected(texture_list->find_metadata(get_current_texture()->get_path())); - } else { - _validate_current_tile_id(); - _on_texture_list_selected(-1); - workspace_overlay->update(); - } - update_texture_list_icon(); - helper->_change_notify(""); -} - -void TileSetEditor::update_texture_list_icon() { - for (int current_idx = 0; current_idx < texture_list->get_item_count(); current_idx++) { - String path = texture_list->get_item_metadata(current_idx); - texture_list->set_item_icon(current_idx, texture_map[path]); - Size2 texture_size = texture_map[path]->get_size(); - texture_list->set_item_icon_region(current_idx, Rect2(0, 0, MIN(texture_size.x, 150), MIN(texture_size.y, 100))); - } - texture_list->update(); -} - -void TileSetEditor::update_workspace_tile_mode() { - if (!get_current_texture().is_valid()) { - tool_workspacemode[WORKSPACE_EDIT]->set_pressed(true); - workspace_mode = WORKSPACE_EDIT; - for (int i = 1; i < WORKSPACE_MODE_MAX; i++) { - tool_workspacemode[i]->set_disabled(true); - } - tools[SELECT_NEXT]->set_disabled(true); - tools[SELECT_PREVIOUS]->set_disabled(true); - - tools[ZOOM_OUT]->hide(); - tools[ZOOM_1]->hide(); - tools[ZOOM_IN]->hide(); - tools[VISIBLE_INFO]->hide(); - - scroll->hide(); - empty_message->show(); - } else { - for (int i = 1; i < WORKSPACE_MODE_MAX; i++) { - tool_workspacemode[i]->set_disabled(false); - } - tools[SELECT_NEXT]->set_disabled(false); - tools[SELECT_PREVIOUS]->set_disabled(false); - - tools[ZOOM_OUT]->show(); - tools[ZOOM_1]->show(); - tools[ZOOM_IN]->show(); - tools[VISIBLE_INFO]->show(); - - scroll->show(); - empty_message->hide(); - } - - if (workspace_mode != WORKSPACE_EDIT) { - for (int i = 0; i < EDITMODE_MAX; i++) { - tool_editmode[i]->hide(); - } - tool_editmode[EDITMODE_REGION]->show(); - tool_editmode[EDITMODE_REGION]->set_pressed(true); - _on_edit_mode_changed(EDITMODE_REGION); - separator_editmode->show(); - return; - } - - if (get_current_tile() < 0) { - for (int i = 0; i < EDITMODE_MAX; i++) { - tool_editmode[i]->hide(); - } - for (int i = TOOL_SELECT; i < ZOOM_OUT; i++) { - tools[i]->hide(); - } - - separator_editmode->hide(); - separator_bitmask->hide(); - separator_delete->hide(); - separator_grid->hide(); - return; - } - - for (int i = 0; i < EDITMODE_MAX; i++) { - tool_editmode[i]->show(); - } - separator_editmode->show(); - - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { - if (tool_editmode[EDITMODE_ICON]->is_pressed() || tool_editmode[EDITMODE_PRIORITY]->is_pressed() || tool_editmode[EDITMODE_BITMASK]->is_pressed() || tool_editmode[EDITMODE_Z_INDEX]->is_pressed()) { - tool_editmode[EDITMODE_COLLISION]->set_pressed(true); - edit_mode = EDITMODE_COLLISION; - } - select_coord(Vector2(0, 0)); - - tool_editmode[EDITMODE_ICON]->hide(); - tool_editmode[EDITMODE_BITMASK]->hide(); - tool_editmode[EDITMODE_PRIORITY]->hide(); - tool_editmode[EDITMODE_Z_INDEX]->hide(); - } else if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) { - if (edit_mode == EDITMODE_ICON) { - select_coord(tileset->autotile_get_icon_coordinate(get_current_tile())); - } else { - _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); - edit_mode = EDITMODE_COLLISION; - } - if (edit_mode == EDITMODE_ICON) { - select_coord(tileset->autotile_get_icon_coordinate(get_current_tile())); - } else { - _select_edited_shape_coord(); - } - - tool_editmode[EDITMODE_BITMASK]->hide(); - } - _on_edit_mode_changed(edit_mode); -} - -void TileSetEditor::update_workspace_minsize() { - Size2 workspace_min_size = get_current_texture()->get_size(); - String current_texture_path = get_current_texture()->get_path(); - List tiles; - tileset->get_tile_list(&tiles); - for (List::Element *E = tiles.front(); E; E = E->next()) { - if (tileset->tile_get_texture(E->get())->get_path() != current_texture_path) { - continue; - } - - Rect2i region = tileset->tile_get_region(E->get()); - if (region.position.x + region.size.x > workspace_min_size.x) { - workspace_min_size.x = region.position.x + region.size.x; - } - if (region.position.y + region.size.y > workspace_min_size.y) { - workspace_min_size.y = region.position.y + region.size.y; - } - } - - workspace_container->set_custom_minimum_size(workspace_min_size * workspace->get_scale() + WORKSPACE_MARGIN * 2); - workspace_overlay->set_custom_minimum_size(workspace_min_size * workspace->get_scale() + WORKSPACE_MARGIN * 2); - // Make sure workspace size is initialized last (otherwise it might be incorrect). - workspace->call_deferred("set_custom_minimum_size", workspace_min_size + WORKSPACE_MARGIN * 2); -} - -void TileSetEditor::update_edited_region(const Vector2 &end_point) { - edited_region = Rect2(region_from, Size2()); - if (tools[TOOL_GRID_SNAP]->is_pressed()) { - Vector2 grid_coord; - grid_coord = ((region_from - snap_offset) / (snap_step + snap_separation)).floor(); - grid_coord *= (snap_step + snap_separation); - grid_coord += snap_offset; - edited_region.expand_to(grid_coord); - grid_coord += snap_step; - edited_region.expand_to(grid_coord); - - grid_coord = ((end_point - snap_offset) / (snap_step + snap_separation)).floor(); - grid_coord *= (snap_step + snap_separation); - grid_coord += snap_offset; - edited_region.expand_to(grid_coord); - grid_coord += snap_step; - edited_region.expand_to(grid_coord); - } else { - edited_region.expand_to(end_point); - } -} - -int TileSetEditor::get_current_tile() const { - return current_tile; -} - -void TileSetEditor::set_current_tile(int p_id) { - if (current_tile != p_id) { - current_tile = p_id; - helper->_change_notify(""); - select_coord(Vector2(0, 0)); - update_workspace_tile_mode(); - if (p_id == -1) { - editor->get_inspector()->edit(tileset.ptr()); - } else { - editor->get_inspector()->edit(helper); - } - } -} - -Ref TileSetEditor::get_current_texture() { - if (texture_list->get_selected_items().size() == 0) { - return Ref(); - } else { - return texture_map[texture_list->get_item_metadata(texture_list->get_selected_items()[0])]; - } -} - -void TilesetEditorContext::set_tileset(const Ref &p_tileset) { - tileset = p_tileset; -} - -void TilesetEditorContext::set_snap_options_visible(bool p_visible) { - snap_options_visible = p_visible; - _change_notify(""); -} - -bool TilesetEditorContext::_set(const StringName &p_name, const Variant &p_value) { - String name = p_name.operator String(); - - if (name == "options_offset") { - Vector2 snap = p_value; - tileset_editor->_set_snap_off(snap + WORKSPACE_MARGIN); - return true; - } else if (name == "options_step") { - Vector2 snap = p_value; - tileset_editor->_set_snap_step(snap); - return true; - } else if (name == "options_separation") { - Vector2 snap = p_value; - tileset_editor->_set_snap_sep(snap); - return true; - } else if (p_name.operator String().left(5) == "tile_") { - String name2 = p_name.operator String().right(5); - bool v = false; - - if (tileset_editor->get_current_tile() < 0 || tileset.is_null()) { - return false; - } - - if (name2 == "autotile_bitmask_mode") { - tileset->set(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/bitmask_mode", p_value, &v); - } else if (name2 == "subtile_size") { - tileset->set(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/tile_size", p_value, &v); - } else if (name2 == "subtile_spacing") { - tileset->set(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/spacing", p_value, &v); - } else { - tileset->set(String::num(tileset_editor->get_current_tile(), 0) + "/" + name2, p_value, &v); - } - if (v) { - tileset->_change_notify(""); - tileset_editor->workspace->update(); - tileset_editor->workspace_overlay->update(); - } - return v; - } else if (name == "tileset_script") { - tileset->set_script(p_value); - return true; - } else if (name == "selected_collision_one_way") { - Vector sd = tileset->tile_get_shapes(tileset_editor->get_current_tile()); - for (int index = 0; index < sd.size(); index++) { - if (sd[index].shape == tileset_editor->edited_collision_shape) { - tileset->tile_set_shape_one_way(tileset_editor->get_current_tile(), index, p_value); - return true; - } - } - return false; - } else if (name == "selected_collision_one_way_margin") { - Vector sd = tileset->tile_get_shapes(tileset_editor->get_current_tile()); - for (int index = 0; index < sd.size(); index++) { - if (sd[index].shape == tileset_editor->edited_collision_shape) { - tileset->tile_set_shape_one_way_margin(tileset_editor->get_current_tile(), index, p_value); - return true; - } - } - return false; - } - - tileset_editor->err_dialog->set_text(TTR("This property can't be changed.")); - tileset_editor->err_dialog->popup_centered(Size2(300, 60)); - return false; -} - -bool TilesetEditorContext::_get(const StringName &p_name, Variant &r_ret) const { - String name = p_name.operator String(); - bool v = false; - - if (name == "options_offset") { - r_ret = tileset_editor->snap_offset - WORKSPACE_MARGIN; - v = true; - } else if (name == "options_step") { - r_ret = tileset_editor->snap_step; - v = true; - } else if (name == "options_separation") { - r_ret = tileset_editor->snap_separation; - v = true; - } else if (name.left(5) == "tile_") { - name = name.right(5); - - if (tileset_editor->get_current_tile() < 0 || tileset.is_null()) { - return false; - } - if (!tileset->has_tile(tileset_editor->get_current_tile())) { - return false; - } - - if (name == "autotile_bitmask_mode") { - r_ret = tileset->get(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/bitmask_mode", &v); - } else if (name == "subtile_size") { - r_ret = tileset->get(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/tile_size", &v); - } else if (name == "subtile_spacing") { - r_ret = tileset->get(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/spacing", &v); - } else { - r_ret = tileset->get(String::num(tileset_editor->get_current_tile(), 0) + "/" + name, &v); - } - return v; - } else if (name == "selected_collision") { - r_ret = tileset_editor->edited_collision_shape; - v = true; - } else if (name == "selected_collision_one_way") { - Vector sd = tileset->tile_get_shapes(tileset_editor->get_current_tile()); - for (int index = 0; index < sd.size(); index++) { - if (sd[index].shape == tileset_editor->edited_collision_shape) { - r_ret = sd[index].one_way_collision; - v = true; - break; - } - } - } else if (name == "selected_collision_one_way_margin") { - Vector sd = tileset->tile_get_shapes(tileset_editor->get_current_tile()); - for (int index = 0; index < sd.size(); index++) { - if (sd[index].shape == tileset_editor->edited_collision_shape) { - r_ret = sd[index].one_way_collision_margin; - v = true; - break; - } - } - } else if (name == "selected_navigation") { - r_ret = tileset_editor->edited_navigation_shape; - v = true; - } else if (name == "selected_occlusion") { - r_ret = tileset_editor->edited_occlusion_shape; - v = true; - } else if (name == "tileset_script") { - r_ret = tileset->get_script(); - v = true; - } - return v; -} - -void TilesetEditorContext::_get_property_list(List *p_list) const { - if (snap_options_visible) { - p_list->push_back(PropertyInfo(Variant::NIL, "Snap Options", PROPERTY_HINT_NONE, "options_", PROPERTY_USAGE_GROUP)); - p_list->push_back(PropertyInfo(Variant::VECTOR2, "options_offset")); - p_list->push_back(PropertyInfo(Variant::VECTOR2, "options_step")); - p_list->push_back(PropertyInfo(Variant::VECTOR2, "options_separation")); - } - if (tileset_editor->get_current_tile() >= 0 && !tileset.is_null()) { - int id = tileset_editor->get_current_tile(); - p_list->push_back(PropertyInfo(Variant::NIL, "Selected Tile", PROPERTY_HINT_NONE, "tile_", PROPERTY_USAGE_GROUP)); - p_list->push_back(PropertyInfo(Variant::STRING, "tile_name")); - p_list->push_back(PropertyInfo(Variant::OBJECT, "tile_normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture")); - p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_tex_offset")); - p_list->push_back(PropertyInfo(Variant::OBJECT, "tile_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial")); - p_list->push_back(PropertyInfo(Variant::COLOR, "tile_modulate")); - p_list->push_back(PropertyInfo(Variant::INT, "tile_tile_mode", PROPERTY_HINT_ENUM, "SINGLE_TILE,AUTO_TILE,ATLAS_TILE")); - if (tileset->tile_get_tile_mode(id) == TileSet::AUTO_TILE) { - p_list->push_back(PropertyInfo(Variant::INT, "tile_autotile_bitmask_mode", PROPERTY_HINT_ENUM, "2x2,3x3 (minimal),3x3")); - p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_subtile_size")); - p_list->push_back(PropertyInfo(Variant::INT, "tile_subtile_spacing", PROPERTY_HINT_RANGE, "0, 1024, 1")); - } else if (tileset->tile_get_tile_mode(id) == TileSet::ATLAS_TILE) { - p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_subtile_size")); - p_list->push_back(PropertyInfo(Variant::INT, "tile_subtile_spacing", PROPERTY_HINT_RANGE, "0, 1024, 1")); - } - p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_occluder_offset")); - p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_navigation_offset")); - p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_shape_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); - p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_shape_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); - p_list->push_back(PropertyInfo(Variant::INT, "tile_z_index", PROPERTY_HINT_RANGE, itos(VS::CANVAS_ITEM_Z_MIN) + "," + itos(VS::CANVAS_ITEM_Z_MAX) + ",1")); - } - if (tileset_editor->edit_mode == TileSetEditor::EDITMODE_COLLISION && tileset_editor->edited_collision_shape.is_valid()) { - p_list->push_back(PropertyInfo(Variant::OBJECT, "selected_collision", PROPERTY_HINT_RESOURCE_TYPE, tileset_editor->edited_collision_shape->get_class())); - if (tileset_editor->edited_collision_shape.is_valid()) { - p_list->push_back(PropertyInfo(Variant::BOOL, "selected_collision_one_way", PROPERTY_HINT_NONE)); - p_list->push_back(PropertyInfo(Variant::REAL, "selected_collision_one_way_margin", PROPERTY_HINT_NONE)); - } - } - if (tileset_editor->edit_mode == TileSetEditor::EDITMODE_NAVIGATION && tileset_editor->edited_navigation_shape.is_valid()) { - p_list->push_back(PropertyInfo(Variant::OBJECT, "selected_navigation", PROPERTY_HINT_RESOURCE_TYPE, tileset_editor->edited_navigation_shape->get_class())); - } - if (tileset_editor->edit_mode == TileSetEditor::EDITMODE_OCCLUSION && tileset_editor->edited_occlusion_shape.is_valid()) { - p_list->push_back(PropertyInfo(Variant::OBJECT, "selected_occlusion", PROPERTY_HINT_RESOURCE_TYPE, tileset_editor->edited_occlusion_shape->get_class())); - } - if (!tileset.is_null()) { - p_list->push_back(PropertyInfo(Variant::OBJECT, "tileset_script", PROPERTY_HINT_RESOURCE_TYPE, "Script")); - } -} - -void TilesetEditorContext::_bind_methods() { - ClassDB::bind_method("_hide_script_from_inspector", &TilesetEditorContext::_hide_script_from_inspector); -} - -TilesetEditorContext::TilesetEditorContext(TileSetEditor *p_tileset_editor) { - tileset_editor = p_tileset_editor; - snap_options_visible = false; -} - -void TileSetEditorPlugin::edit(Object *p_node) { - if (Object::cast_to(p_node)) { - tileset_editor->edit(Object::cast_to(p_node)); - } -} - -bool TileSetEditorPlugin::handles(Object *p_node) const { - return p_node->is_class("TileSet") || p_node->is_class("TilesetEditorContext"); -} - -void TileSetEditorPlugin::make_visible(bool p_visible) { - if (p_visible) { - tileset_editor_button->show(); - editor->make_bottom_panel_item_visible(tileset_editor); - if (!get_tree()->is_connected("idle_frame", tileset_editor, "_on_workspace_process")) { - get_tree()->connect("idle_frame", tileset_editor, "_on_workspace_process"); - } - } else { - editor->hide_bottom_panel(); - tileset_editor_button->hide(); - if (get_tree()->is_connected("idle_frame", tileset_editor, "_on_workspace_process")) { - get_tree()->disconnect("idle_frame", tileset_editor, "_on_workspace_process"); - } - } -} - -Dictionary TileSetEditorPlugin::get_state() const { - Dictionary state; - state["snap_offset"] = tileset_editor->snap_offset; - state["snap_step"] = tileset_editor->snap_step; - state["snap_separation"] = tileset_editor->snap_separation; - state["snap_enabled"] = tileset_editor->tools[TileSetEditor::TOOL_GRID_SNAP]->is_pressed(); - state["keep_inside_tile"] = tileset_editor->tools[TileSetEditor::SHAPE_KEEP_INSIDE_TILE]->is_pressed(); - state["show_information"] = tileset_editor->tools[TileSetEditor::VISIBLE_INFO]->is_pressed(); - return state; -} - -void TileSetEditorPlugin::set_state(const Dictionary &p_state) { - Dictionary state = p_state; - if (state.has("snap_step")) { - tileset_editor->_set_snap_step(state["snap_step"]); - } - - if (state.has("snap_offset")) { - tileset_editor->_set_snap_off(state["snap_offset"]); - } - - if (state.has("snap_separation")) { - tileset_editor->_set_snap_sep(state["snap_separation"]); - } - - if (state.has("snap_enabled")) { - tileset_editor->tools[TileSetEditor::TOOL_GRID_SNAP]->set_pressed(state["snap_enabled"]); - if (tileset_editor->helper) { - tileset_editor->_on_grid_snap_toggled(state["snap_enabled"]); - } - } - - if (state.has("keep_inside_tile")) { - tileset_editor->tools[TileSetEditor::SHAPE_KEEP_INSIDE_TILE]->set_pressed(state["keep_inside_tile"]); - } - - if (state.has("show_information")) { - tileset_editor->tools[TileSetEditor::VISIBLE_INFO]->set_pressed(state["show_information"]); - } -} - -TileSetEditorPlugin::TileSetEditorPlugin(EditorNode *p_node) { - editor = p_node; - tileset_editor = memnew(TileSetEditor(p_node)); - - tileset_editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE); - tileset_editor->hide(); - - tileset_editor_button = p_node->add_bottom_panel_item(TTR("TileSet"), tileset_editor); - tileset_editor_button->hide(); -} diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h deleted file mode 100644 index 87b4b3e73..000000000 --- a/editor/plugins/tile_set_editor_plugin.h +++ /dev/null @@ -1,298 +0,0 @@ -/*************************************************************************/ -/* tile_set_editor_plugin.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef TILE_SET_EDITOR_PLUGIN_H -#define TILE_SET_EDITOR_PLUGIN_H - -#include "editor/editor_node.h" -#include "scene/2d/sprite.h" -#include "scene/resources/concave_polygon_shape_2d.h" -#include "scene/resources/convex_polygon_shape_2d.h" -#include "scene/resources/tile_set.h" - -#define WORKSPACE_MARGIN Vector2(10, 10) -class TilesetEditorContext; - -class TileSetEditor : public HSplitContainer { - friend class TileSetEditorPlugin; - friend class TilesetEditorContext; - - GDCLASS(TileSetEditor, HSplitContainer); - - enum TextureToolButtons { - TOOL_TILESET_ADD_TEXTURE, - TOOL_TILESET_REMOVE_TEXTURE, - TOOL_TILESET_CREATE_SCENE, - TOOL_TILESET_MERGE_SCENE, - TOOL_TILESET_MAX - }; - - enum WorkspaceMode { - WORKSPACE_EDIT, - WORKSPACE_CREATE_SINGLE, - WORKSPACE_CREATE_AUTOTILE, - WORKSPACE_CREATE_ATLAS, - WORKSPACE_MODE_MAX - }; - - enum EditMode { - EDITMODE_REGION, - EDITMODE_COLLISION, - EDITMODE_OCCLUSION, - EDITMODE_NAVIGATION, - EDITMODE_BITMASK, - EDITMODE_PRIORITY, - EDITMODE_ICON, - EDITMODE_Z_INDEX, - EDITMODE_MAX - }; - - enum TileSetTools { - SELECT_PREVIOUS, - SELECT_NEXT, - TOOL_SELECT, - BITMASK_COPY, - BITMASK_PASTE, - BITMASK_CLEAR, - SHAPE_NEW_POLYGON, - SHAPE_NEW_RECTANGLE, - SHAPE_TOGGLE_TYPE, - SHAPE_DELETE, - SHAPE_KEEP_INSIDE_TILE, - TOOL_GRID_SNAP, - ZOOM_OUT, - ZOOM_1, - ZOOM_IN, - VISIBLE_INFO, - TOOL_MAX - }; - - struct SubtileData { - Array collisions; - Ref occlusion_shape; - Ref navigation_shape; - }; - - Ref tileset; - TilesetEditorContext *helper; - EditorNode *editor; - UndoRedo *undo_redo; - - ConfirmationDialog *cd; - AcceptDialog *err_dialog; - EditorFileDialog *texture_dialog; - - ItemList *texture_list; - int option; - ToolButton *tileset_toolbar_buttons[TOOL_TILESET_MAX]; - MenuButton *tileset_toolbar_tools; - Map> texture_map; - - bool creating_shape; - int dragging_point; - bool tile_names_visible; - Vector2 region_from; - Rect2 edited_region; - bool draw_edited_region; - Vector2 edited_shape_coord; - PoolVector2Array current_shape; - Map current_tile_data; - Map bitmask_map_copy; - - Vector2 snap_step; - Vector2 snap_offset; - Vector2 snap_separation; - - Ref edited_collision_shape; - Ref edited_occlusion_shape; - Ref edited_navigation_shape; - - int current_item_index; - Sprite *preview; - ScrollContainer *scroll; - Label *empty_message; - Control *workspace_container; - bool draw_handles; - Control *workspace_overlay; - Control *workspace; - Button *tool_workspacemode[WORKSPACE_MODE_MAX]; - Button *tool_editmode[EDITMODE_MAX]; - HSeparator *separator_editmode; - HBoxContainer *toolbar; - ToolButton *tools[TOOL_MAX]; - VSeparator *separator_shape_toggle; - VSeparator *separator_bitmask; - VSeparator *separator_delete; - VSeparator *separator_grid; - SpinBox *spin_priority; - SpinBox *spin_z_index; - WorkspaceMode workspace_mode; - EditMode edit_mode; - int current_tile; - - float max_scale; - float min_scale; - float scale_ratio; - - void update_texture_list(); - void update_texture_list_icon(); - - void add_texture(Ref p_texture); - void remove_texture(Ref p_texture); - - Ref get_current_texture(); - - static void _import_node(Node *p_node, Ref p_library); - static void _import_scene(Node *p_scene, Ref p_library, bool p_merge); - void _undo_redo_import_scene(Node *p_scene, bool p_merge); - - Variant get_drag_data_fw(const Point2 &p_point, Control *p_from); - bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; - void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); - -protected: - static void _bind_methods(); - void _notification(int p_what); - -public: - void edit(const Ref &p_tileset); - static Error update_library_file(Node *p_base_scene, Ref ml, bool p_merge = true); - - TileSetEditor(EditorNode *p_editor); - ~TileSetEditor(); - -private: - void _on_tileset_toolbar_button_pressed(int p_index); - void _on_tileset_toolbar_confirm(); - void _on_texture_list_selected(int p_index); - void _on_textures_added(const PoolStringArray &p_paths); - void _on_edit_mode_changed(int p_edit_mode); - void _on_workspace_mode_changed(int p_workspace_mode); - void _on_workspace_overlay_draw(); - void _on_workspace_draw(); - void _on_workspace_process(); - void _on_scroll_container_input(const Ref &p_event); - void _on_workspace_input(const Ref &p_ie); - void _on_tool_clicked(int p_tool); - void _on_priority_changed(float val); - void _on_z_index_changed(float val); - void _on_grid_snap_toggled(bool p_val); - Vector _get_collision_shape_points(const Ref &p_shape); - Vector _get_edited_shape_points(); - void _set_edited_shape_points(const Vector &points); - void _update_tile_data(); - void _update_toggle_shape_button(); - void _select_next_tile(); - void _select_previous_tile(); - Array _get_tiles_in_current_texture(bool sorted = false); - bool _sort_tiles(Variant p_a, Variant p_b); - Vector2 _get_subtiles_count(int p_tile_id); - void _select_next_subtile(); - void _select_previous_subtile(); - void _select_next_shape(); - void _select_previous_shape(); - void _set_edited_collision_shape(const Ref &p_shape); - void _set_snap_step(Vector2 p_val); - 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(); - void _zoom_on_position(float p_zoom, const Vector2 &p_position); - - void draw_highlight_current_tile(); - void draw_highlight_subtile(Vector2 coord, const Vector &other_highlighted = Vector()); - void draw_tile_subdivision(int p_id, Color p_color) const; - void draw_edited_region_subdivision() const; - void draw_grid_snap(); - void draw_polygon_shapes(); - void close_shape(const Vector2 &shape_anchor); - void select_coord(const Vector2 &coord); - Vector2 snap_point(const Vector2 &point); - void update_workspace_tile_mode(); - void update_workspace_minsize(); - void update_edited_region(const Vector2 &end_point); - int get_grabbed_point(const Vector2 &p_mouse_pos, real_t grab_threshold); - bool is_within_grabbing_distance_of_first_point(const Vector2 &p_pos, real_t p_grab_threshold); - - int get_current_tile() const; - void set_current_tile(int p_id); -}; - -class TilesetEditorContext : public Object { - friend class TileSetEditor; - GDCLASS(TilesetEditorContext, Object); - - Ref tileset; - TileSetEditor *tileset_editor; - bool snap_options_visible; - -public: - bool _hide_script_from_inspector() { return true; } - void set_tileset(const Ref &p_tileset); - -private: - void set_snap_options_visible(bool p_visible); - -protected: - bool _set(const StringName &p_name, const Variant &p_value); - bool _get(const StringName &p_name, Variant &r_ret) const; - void _get_property_list(List *p_list) const; - static void _bind_methods(); - -public: - TilesetEditorContext(TileSetEditor *p_tileset_editor); -}; - -class TileSetEditorPlugin : public EditorPlugin { - GDCLASS(TileSetEditorPlugin, EditorPlugin); - - TileSetEditor *tileset_editor; - Button *tileset_editor_button; - EditorNode *editor; - -public: - virtual String get_name() const { return "TileSet"; } - bool has_main_screen() const { return false; } - virtual void edit(Object *p_node); - virtual bool handles(Object *p_node) const; - virtual void make_visible(bool p_visible); - void set_state(const Dictionary &p_state); - Dictionary get_state() const; - - TileSetEditorPlugin(EditorNode *p_node); -}; - -#endif // TILE_SET_EDITOR_PLUGIN_H diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp deleted file mode 100644 index 3111706b9..000000000 --- a/scene/2d/tile_map.cpp +++ /dev/null @@ -1,1938 +0,0 @@ -/*************************************************************************/ -/* tile_map.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "tile_map.h" - -#include "collision_object_2d.h" -#include "core/io/marshalls.h" -#include "core/method_bind_ext.gen.inc" -#include "core/os/os.h" -#include "scene/2d/area_2d.h" -#include "servers/navigation_2d_server.h" -#include "servers/physics_2d_server.h" - -int TileMap::_get_quadrant_size() const { - if (y_sort_mode) { - return 1; - } else { - return quadrant_size; - } -} - -void TileMap::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_ENTER_TREE: { - Node2D *c = this; - while (c) { - navigation = Object::cast_to(c); - if (navigation) { - break; - } - - c = Object::cast_to(c->get_parent()); - } - - if (use_parent) { - _clear_quadrants(); - collision_parent = Object::cast_to(get_parent()); - } - - pending_update = true; - _recreate_quadrants(); - update_dirty_quadrants(); - RID space = get_world_2d()->get_space(); - _update_quadrant_transform(); - _update_quadrant_space(space); - update_configuration_warning(); - - } break; - - case NOTIFICATION_EXIT_TREE: { - _update_quadrant_space(RID()); - for (Map::Element *E = quadrant_map.front(); E; E = E->next()) { - Quadrant &q = E->get(); - if (navigation) { - for (Map::Element *F = q.navpoly_ids.front(); F; F = F->next()) { - Navigation2DServer::get_singleton()->region_set_map(F->get().region, RID()); - } - q.navpoly_ids.clear(); - } - - if (collision_parent) { - collision_parent->remove_shape_owner(q.shape_owner_id); - q.shape_owner_id = -1; - } - - for (Map::Element *F = q.occluder_instances.front(); F; F = F->next()) { - if (F->get().id.is_valid()) { - VS::get_singleton()->free(F->get().id); - } - } - q.occluder_instances.clear(); - } - - collision_parent = nullptr; - navigation = nullptr; - - } break; - - case NOTIFICATION_TRANSFORM_CHANGED: { - //move stuff - _update_quadrant_transform(); - - } break; - case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { - if (use_parent) { - _recreate_quadrants(); - } - - } break; - - case NOTIFICATION_VISIBILITY_CHANGED: { - for (Map::Element *E = quadrant_map.front(); E; E = E->next()) { - for (Map::Element *F = E->get().occluder_instances.front(); F; F = F->next()) { - VS::get_singleton()->canvas_light_occluder_set_enabled(F->get().id, is_visible()); - } - } - - } break; - } -} - -void TileMap::_update_quadrant_space(const RID &p_space) { - if (!use_parent) { - for (Map::Element *E = quadrant_map.front(); E; E = E->next()) { - Quadrant &q = E->get(); - Physics2DServer::get_singleton()->body_set_space(q.body, p_space); - } - } -} - -void TileMap::_update_quadrant_transform() { - if (!is_inside_tree()) { - return; - } - - Transform2D global_transform = get_global_transform(); - - Transform2D local_transform; - if (collision_parent) { - local_transform = get_transform(); - } - - Transform2D nav_rel; - if (navigation) { - nav_rel = get_relative_transform_to_parent(navigation); - } - - for (Map::Element *E = quadrant_map.front(); E; E = E->next()) { - Quadrant &q = E->get(); - Transform2D xform; - xform.set_origin(q.pos); - - if (!use_parent) { - xform = global_transform * xform; - Physics2DServer::get_singleton()->body_set_state(q.body, Physics2DServer::BODY_STATE_TRANSFORM, xform); - } - - if (navigation) { - for (Map::Element *F = q.navpoly_ids.front(); F; F = F->next()) { - Navigation2DServer::get_singleton()->region_set_transform(F->get().region, nav_rel * F->get().xform); - } - } - - for (Map::Element *F = q.occluder_instances.front(); F; F = F->next()) { - VS::get_singleton()->canvas_light_occluder_set_transform(F->get().id, global_transform * F->get().xform); - } - } -} - -void TileMap::set_tileset(const Ref &p_tileset) { - if (tile_set.is_valid()) { - tile_set->disconnect("changed", this, "_recreate_quadrants"); - tile_set->remove_change_receptor(this); - } - - _clear_quadrants(); - tile_set = p_tileset; - - if (tile_set.is_valid()) { - tile_set->connect("changed", this, "_recreate_quadrants"); - tile_set->add_change_receptor(this); - } else { - clear(); - } - - _recreate_quadrants(); - emit_signal("settings_changed"); -} - -Ref TileMap::get_tileset() const { - return tile_set; -} - -void TileMap::set_cell_size(Size2 p_size) { - ERR_FAIL_COND(p_size.x < 1 || p_size.y < 1); - - _clear_quadrants(); - cell_size = p_size; - _recreate_quadrants(); - emit_signal("settings_changed"); -} - -Size2 TileMap::get_cell_size() const { - return cell_size; -} - -void TileMap::set_quadrant_size(int p_size) { - ERR_FAIL_COND_MSG(p_size < 1, "Quadrant size cannot be smaller than 1."); - - _clear_quadrants(); - quadrant_size = p_size; - _recreate_quadrants(); - emit_signal("settings_changed"); -} - -int TileMap::get_quadrant_size() const { - return quadrant_size; -} - -void TileMap::_fix_cell_transform(Transform2D &xform, const Cell &p_cell, const Vector2 &p_offset, const Size2 &p_sc) { - Size2 s = p_sc; - Vector2 offset = p_offset; - - if (compatibility_mode && !centered_textures) { - if (tile_origin == TILE_ORIGIN_BOTTOM_LEFT) { - offset.y += cell_size.y; - } else if (tile_origin == TILE_ORIGIN_CENTER) { - offset += cell_size / 2; - } - - if (s.y > s.x) { - if ((p_cell.flip_h && (p_cell.flip_v || p_cell.transpose)) || (p_cell.flip_v && !p_cell.transpose)) { - offset.y += s.y - s.x; - } - } else if (s.y < s.x) { - if ((p_cell.flip_v && (p_cell.flip_h || p_cell.transpose)) || (p_cell.flip_h && !p_cell.transpose)) { - offset.x += s.x - s.y; - } - } - } - - if (p_cell.transpose) { - SWAP(xform.elements[0].x, xform.elements[0].y); - SWAP(xform.elements[1].x, xform.elements[1].y); - SWAP(offset.x, offset.y); - SWAP(s.x, s.y); - } - - if (p_cell.flip_h) { - xform.elements[0].x = -xform.elements[0].x; - xform.elements[1].x = -xform.elements[1].x; - if (compatibility_mode && !centered_textures) { - if (tile_origin == TILE_ORIGIN_TOP_LEFT || tile_origin == TILE_ORIGIN_BOTTOM_LEFT) { - offset.x = s.x - offset.x; - } else if (tile_origin == TILE_ORIGIN_CENTER) { - offset.x = s.x - offset.x / 2; - } - } else { - offset.x = s.x - offset.x; - } - } - - if (p_cell.flip_v) { - xform.elements[0].y = -xform.elements[0].y; - xform.elements[1].y = -xform.elements[1].y; - if (compatibility_mode && !centered_textures) { - if (tile_origin == TILE_ORIGIN_TOP_LEFT) { - offset.y = s.y - offset.y; - } else if (tile_origin == TILE_ORIGIN_BOTTOM_LEFT) { - offset.y += s.y; - } else if (tile_origin == TILE_ORIGIN_CENTER) { - offset.y += s.y; - } - } else { - offset.y = s.y - offset.y; - } - } - - if (centered_textures) { - offset += cell_size / 2 - s / 2; - } - xform.elements[2] += offset; -} - -void TileMap::_add_shape(int &shape_idx, const Quadrant &p_q, const Ref &p_shape, const TileSet::ShapeData &p_shape_data, const Transform2D &p_xform, const Vector2 &p_metadata) { - Physics2DServer *ps = Physics2DServer::get_singleton(); - - if (!use_parent) { - ps->body_add_shape(p_q.body, p_shape->get_rid(), p_xform); - ps->body_set_shape_metadata(p_q.body, shape_idx, p_metadata); - ps->body_set_shape_as_one_way_collision(p_q.body, shape_idx, p_shape_data.one_way_collision, p_shape_data.one_way_collision_margin); - - } else if (collision_parent) { - Transform2D xform = p_xform; - xform.set_origin(xform.get_origin() + p_q.pos); - - collision_parent->shape_owner_add_shape(p_q.shape_owner_id, p_shape); - - int real_index = collision_parent->shape_owner_get_shape_index(p_q.shape_owner_id, shape_idx); - RID rid = collision_parent->get_rid(); - - if (Object::cast_to(collision_parent) != nullptr) { - ps->area_set_shape_transform(rid, real_index, get_transform() * xform); - } else { - ps->body_set_shape_transform(rid, real_index, get_transform() * xform); - ps->body_set_shape_metadata(rid, real_index, p_metadata); - ps->body_set_shape_as_one_way_collision(rid, real_index, p_shape_data.one_way_collision, p_shape_data.one_way_collision_margin); - } - } - shape_idx++; -} - -void TileMap::update_dirty_quadrants() { - if (!pending_update) { - return; - } - if (!is_inside_tree() || !tile_set.is_valid()) { - pending_update = false; - return; - } - - VisualServer *vs = VisualServer::get_singleton(); - Physics2DServer *ps = Physics2DServer::get_singleton(); - Vector2 tofs = get_cell_draw_offset(); - Transform2D nav_rel; - if (navigation) { - nav_rel = get_relative_transform_to_parent(navigation); - } - - Vector2 qofs; - - SceneTree *st = SceneTree::get_singleton(); - Color debug_collision_color; - Color debug_navigation_color; - - bool debug_shapes = false; - if (st) { - if (Engine::get_singleton()->is_editor_hint()) { - debug_shapes = show_collision; - } else { - debug_shapes = st->is_debugging_collisions_hint(); - } - - if (debug_shapes) { - debug_collision_color = st->get_debug_collisions_color(); - } - } - - bool debug_navigation = st && st->is_debugging_navigation_hint(); - if (debug_navigation) { - debug_navigation_color = st->get_debug_navigation_color(); - } - - while (dirty_quadrant_list.first()) { - Quadrant &q = *dirty_quadrant_list.first()->self(); - - for (List::Element *E = q.canvas_items.front(); E; E = E->next()) { - if (E->get().is_valid()) { - vs->free(E->get()); - } - } - q.canvas_items.clear(); - - if (!use_parent) { - ps->body_clear_shapes(q.body); - } else if (collision_parent) { - collision_parent->shape_owner_clear_shapes(q.shape_owner_id); - } - int shape_idx = 0; - - if (navigation) { - for (Map::Element *E = q.navpoly_ids.front(); E; E = E->next()) { - Navigation2DServer::get_singleton()->region_set_map(E->get().region, RID()); - } - q.navpoly_ids.clear(); - } - - for (Map::Element *E = q.occluder_instances.front(); E; E = E->next()) { - if (E->get().id.is_valid()) { - VS::get_singleton()->free(E->get().id); - } - } - q.occluder_instances.clear(); - Ref prev_material; - int prev_z_index = 0; - RID prev_canvas_item; - RID prev_debug_canvas_item; - - for (int i = 0; i < q.cells.size(); i++) { - Map::Element *E = tile_map.find(q.cells[i]); - Cell &c = E->get(); - //moment of truth - if (!tile_set->has_tile(c.id)) { - continue; - } - Ref tex = tile_set->tile_get_texture(c.id); - Vector2 tile_ofs = tile_set->tile_get_texture_offset(c.id); - - Vector2 wofs = _map_to_world(E->key().x, E->key().y); - Vector2 offset = wofs - q.pos + tofs; - - if (!tex.is_valid()) { - continue; - } - - Ref mat = tile_set->tile_get_material(c.id); - int z_index = tile_set->tile_get_z_index(c.id); - - if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE || tile_set->tile_get_tile_mode(c.id) == TileSet::ATLAS_TILE) { - z_index += tile_set->autotile_get_z_index(c.id, Vector2(c.autotile_coord_x, c.autotile_coord_y)); - } - - RID canvas_item; - RID debug_canvas_item; - - if (prev_canvas_item == RID() || prev_material != mat || prev_z_index != z_index) { - canvas_item = RID_PRIME(vs->canvas_item_create()); - if (mat.is_valid()) { - vs->canvas_item_set_material(canvas_item, mat->get_rid()); - } - vs->canvas_item_set_parent(canvas_item, get_canvas_item()); - _update_item_material_state(canvas_item); - Transform2D xform; - xform.set_origin(q.pos); - vs->canvas_item_set_transform(canvas_item, xform); - vs->canvas_item_set_light_mask(canvas_item, get_light_mask()); - vs->canvas_item_set_z_index(canvas_item, z_index); - - q.canvas_items.push_back(canvas_item); - - if (debug_shapes) { - debug_canvas_item = RID_PRIME(vs->canvas_item_create()); - vs->canvas_item_set_parent(debug_canvas_item, canvas_item); - vs->canvas_item_set_z_as_relative_to_parent(debug_canvas_item, false); - vs->canvas_item_set_z_index(debug_canvas_item, VS::CANVAS_ITEM_Z_MAX - 1); - q.canvas_items.push_back(debug_canvas_item); - prev_debug_canvas_item = debug_canvas_item; - } - - prev_canvas_item = canvas_item; - prev_material = mat; - prev_z_index = z_index; - - } else { - canvas_item = prev_canvas_item; - if (debug_shapes) { - debug_canvas_item = prev_debug_canvas_item; - } - } - - Rect2 r = tile_set->tile_get_region(c.id); - if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE || tile_set->tile_get_tile_mode(c.id) == TileSet::ATLAS_TILE) { - int spacing = tile_set->autotile_get_spacing(c.id); - r.size = tile_set->autotile_get_size(c.id); - r.position += (r.size + Vector2(spacing, spacing)) * Vector2(c.autotile_coord_x, c.autotile_coord_y); - } - - Size2 s; - if (r == Rect2()) { - s = tex->get_size(); - } else { - s = r.size; - } - - Rect2 rect; - rect.position = offset.floor(); - rect.size = s; - rect.size.x += fp_adjust; - rect.size.y += fp_adjust; - - if (compatibility_mode && !centered_textures) { - if (rect.size.y > rect.size.x) { - if ((c.flip_h && (c.flip_v || c.transpose)) || (c.flip_v && !c.transpose)) { - tile_ofs.y += rect.size.y - rect.size.x; - } - } else if (rect.size.y < rect.size.x) { - if ((c.flip_v && (c.flip_h || c.transpose)) || (c.flip_h && !c.transpose)) { - tile_ofs.x += rect.size.x - rect.size.y; - } - } - } - - if (c.transpose) { - SWAP(tile_ofs.x, tile_ofs.y); - if (centered_textures) { - rect.position.x += cell_size.x / 2 - rect.size.y / 2; - rect.position.y += cell_size.y / 2 - rect.size.x / 2; - } - } else if (centered_textures) { - rect.position += cell_size / 2 - rect.size / 2; - } - - if (c.flip_h) { - rect.size.x = -rect.size.x; - tile_ofs.x = -tile_ofs.x; - } - - if (c.flip_v) { - rect.size.y = -rect.size.y; - tile_ofs.y = -tile_ofs.y; - } - - if (compatibility_mode && !centered_textures) { - if (tile_origin == TILE_ORIGIN_TOP_LEFT) { - rect.position += tile_ofs; - - } else if (tile_origin == TILE_ORIGIN_BOTTOM_LEFT) { - rect.position += tile_ofs; - - if (c.transpose) { - if (c.flip_h) { - rect.position.x -= cell_size.x; - } else { - rect.position.x += cell_size.x; - } - } else { - if (c.flip_v) { - rect.position.y -= cell_size.y; - } else { - rect.position.y += cell_size.y; - } - } - - } else if (tile_origin == TILE_ORIGIN_CENTER) { - rect.position += tile_ofs; - - if (c.flip_h) { - rect.position.x -= cell_size.x / 2; - } else { - rect.position.x += cell_size.x / 2; - } - - if (c.flip_v) { - rect.position.y -= cell_size.y / 2; - } else { - rect.position.y += cell_size.y / 2; - } - } - } else { - rect.position += tile_ofs; - } - - Ref normal_map = tile_set->tile_get_normal_map(c.id); - Color modulate = tile_set->tile_get_modulate(c.id); - Color self_modulate = get_self_modulate(); - modulate = Color(modulate.r * self_modulate.r, modulate.g * self_modulate.g, - modulate.b * self_modulate.b, modulate.a * self_modulate.a); - if (r == Rect2()) { - tex->draw_rect(canvas_item, rect, false, modulate, c.transpose, normal_map); - } else { - tex->draw_rect_region(canvas_item, rect, r, modulate, c.transpose, normal_map, clip_uv); - } - - Vector shapes = tile_set->tile_get_shapes(c.id); - - for (int j = 0; j < shapes.size(); j++) { - Ref shape = shapes[j].shape; - if (shape.is_valid()) { - if (tile_set->tile_get_tile_mode(c.id) == TileSet::SINGLE_TILE || (shapes[j].autotile_coord.x == c.autotile_coord_x && shapes[j].autotile_coord.y == c.autotile_coord_y)) { - Transform2D xform; - xform.set_origin(offset.floor()); - - Vector2 shape_ofs = shapes[j].shape_transform.get_origin(); - - _fix_cell_transform(xform, c, shape_ofs, s); - - xform *= shapes[j].shape_transform.untranslated(); - - if (debug_canvas_item.is_valid()) { - vs->canvas_item_add_set_transform(debug_canvas_item, xform); - shape->draw(debug_canvas_item, debug_collision_color); - } - - if (shape->has_meta("decomposed")) { - Array _shapes = shape->get_meta("decomposed"); - for (int k = 0; k < _shapes.size(); k++) { - Ref convex = _shapes[k]; - if (convex.is_valid()) { - _add_shape(shape_idx, q, convex, shapes[j], xform, Vector2(E->key().x, E->key().y)); -#ifdef DEBUG_ENABLED - } else { - print_error("The TileSet assigned to the TileMap " + get_name() + " has an invalid convex shape."); -#endif - } - } - } else { - _add_shape(shape_idx, q, shape, shapes[j], xform, Vector2(E->key().x, E->key().y)); - } - } - } - } - - if (debug_canvas_item.is_valid()) { - vs->canvas_item_add_set_transform(debug_canvas_item, Transform2D()); - } - - if (navigation) { - Ref navpoly; - Vector2 npoly_ofs; - if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE || tile_set->tile_get_tile_mode(c.id) == TileSet::ATLAS_TILE) { - navpoly = tile_set->autotile_get_navigation_polygon(c.id, Vector2(c.autotile_coord_x, c.autotile_coord_y)); - npoly_ofs = Vector2(); - } else { - navpoly = tile_set->tile_get_navigation_polygon(c.id); - npoly_ofs = tile_set->tile_get_navigation_polygon_offset(c.id); - } - - if (navpoly.is_valid()) { - Transform2D xform; - xform.set_origin(offset.floor() + q.pos); - _fix_cell_transform(xform, c, npoly_ofs, s); - - RID region = Navigation2DServer::get_singleton()->region_create(); - Navigation2DServer::get_singleton()->region_set_map(region, navigation->get_rid()); - Navigation2DServer::get_singleton()->region_set_transform(region, nav_rel * xform); - Navigation2DServer::get_singleton()->region_set_navpoly(region, navpoly); - - Quadrant::NavPoly np; - np.region = region; - np.xform = xform; - q.navpoly_ids[E->key()] = np; - - if (debug_navigation) { - RID debug_navigation_item = RID_PRIME(vs->canvas_item_create()); - vs->canvas_item_set_parent(debug_navigation_item, canvas_item); - vs->canvas_item_set_z_as_relative_to_parent(debug_navigation_item, false); - vs->canvas_item_set_z_index(debug_navigation_item, VS::CANVAS_ITEM_Z_MAX - 2); // Display one below collision debug - - if (debug_navigation_item.is_valid()) { - PoolVector navigation_polygon_vertices = navpoly->get_vertices(); - int vsize = navigation_polygon_vertices.size(); - - if (vsize > 2) { - Vector colors; - Vector vertices; - vertices.resize(vsize); - colors.resize(vsize); - { - PoolVector::Read vr = navigation_polygon_vertices.read(); - for (int j = 0; j < vsize; j++) { - vertices.write[j] = vr[j]; - colors.write[j] = debug_navigation_color; - } - } - - Vector indices; - - for (int j = 0; j < navpoly->get_polygon_count(); j++) { - Vector polygon = navpoly->get_polygon(j); - - for (int k = 2; k < polygon.size(); k++) { - int kofs[3] = { 0, k - 1, k }; - for (int l = 0; l < 3; l++) { - int idx = polygon[kofs[l]]; - ERR_FAIL_INDEX(idx, vsize); - indices.push_back(idx); - } - } - } - Transform2D navxform; - navxform.set_origin(offset.floor()); - _fix_cell_transform(navxform, c, npoly_ofs, s); - - vs->canvas_item_set_transform(debug_navigation_item, navxform); - vs->canvas_item_add_triangle_array(debug_navigation_item, indices, vertices, colors); - } - } - } - } - } - - Ref occluder; - if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE || tile_set->tile_get_tile_mode(c.id) == TileSet::ATLAS_TILE) { - occluder = tile_set->autotile_get_light_occluder(c.id, Vector2(c.autotile_coord_x, c.autotile_coord_y)); - } else { - occluder = tile_set->tile_get_light_occluder(c.id); - } - if (occluder.is_valid()) { - Vector2 occluder_ofs = tile_set->tile_get_occluder_offset(c.id); - Transform2D xform; - xform.set_origin(offset.floor() + q.pos); - _fix_cell_transform(xform, c, occluder_ofs, s); - - RID orid = RID_PRIME(VS::get_singleton()->canvas_light_occluder_create()); - VS::get_singleton()->canvas_light_occluder_set_transform(orid, get_global_transform() * xform); - VS::get_singleton()->canvas_light_occluder_set_polygon(orid, occluder->get_rid()); - VS::get_singleton()->canvas_light_occluder_attach_to_canvas(orid, get_canvas()); - VS::get_singleton()->canvas_light_occluder_set_light_mask(orid, occluder_light_mask); - VS::get_singleton()->canvas_light_occluder_set_enabled(orid, is_visible()); - Quadrant::Occluder oc; - oc.xform = xform; - oc.id = orid; - q.occluder_instances[E->key()] = oc; - } - } - - dirty_quadrant_list.remove(dirty_quadrant_list.first()); - quadrant_order_dirty = true; - } - - pending_update = false; - - if (quadrant_order_dirty) { - int index = -(int64_t)0x80000000; //always must be drawn below children - for (Map::Element *E = quadrant_map.front(); E; E = E->next()) { - Quadrant &q = E->get(); - for (List::Element *F = q.canvas_items.front(); F; F = F->next()) { - VS::get_singleton()->canvas_item_set_draw_index(F->get(), index++); - } - } - - quadrant_order_dirty = false; - } - - _recompute_rect_cache(); -} - -void TileMap::_recompute_rect_cache() { -#ifdef DEBUG_ENABLED - - if (!rect_cache_dirty) { - return; - } - - Rect2 r_total; - for (Map::Element *E = quadrant_map.front(); E; E = E->next()) { - Rect2 r; - r.position = _map_to_world(E->key().x * _get_quadrant_size(), E->key().y * _get_quadrant_size()); - r.expand_to(_map_to_world(E->key().x * _get_quadrant_size() + _get_quadrant_size(), E->key().y * _get_quadrant_size())); - r.expand_to(_map_to_world(E->key().x * _get_quadrant_size() + _get_quadrant_size(), E->key().y * _get_quadrant_size() + _get_quadrant_size())); - r.expand_to(_map_to_world(E->key().x * _get_quadrant_size(), E->key().y * _get_quadrant_size() + _get_quadrant_size())); - if (E == quadrant_map.front()) { - r_total = r; - } else { - r_total = r_total.merge(r); - } - } - - rect_cache = r_total; - - item_rect_changed(); - - rect_cache_dirty = false; -#endif -} - -Map::Element *TileMap::_create_quadrant(const PosKey &p_qk) { - Transform2D xform; - //xform.set_origin(Point2(p_qk.x,p_qk.y)*cell_size*quadrant_size); - Quadrant q; - q.pos = _map_to_world(p_qk.x * _get_quadrant_size(), p_qk.y * _get_quadrant_size()); - q.pos += get_cell_draw_offset(); - if (tile_origin == TILE_ORIGIN_CENTER) { - q.pos += cell_size / 2; - } else if (tile_origin == TILE_ORIGIN_BOTTOM_LEFT) { - q.pos.y += cell_size.y; - } - - xform.set_origin(q.pos); - //q.canvas_item = VisualServer::get_singleton()->canvas_item_create(); - if (!use_parent) { - q.body = RID_PRIME(Physics2DServer::get_singleton()->body_create()); - Physics2DServer::get_singleton()->body_set_mode(q.body, use_kinematic ? Physics2DServer::BODY_MODE_KINEMATIC : Physics2DServer::BODY_MODE_STATIC); - - Physics2DServer::get_singleton()->body_attach_object_instance_id(q.body, get_instance_id()); - Physics2DServer::get_singleton()->body_set_collision_layer(q.body, collision_layer); - Physics2DServer::get_singleton()->body_set_collision_mask(q.body, collision_mask); - Physics2DServer::get_singleton()->body_set_param(q.body, Physics2DServer::BODY_PARAM_FRICTION, friction); - Physics2DServer::get_singleton()->body_set_param(q.body, Physics2DServer::BODY_PARAM_BOUNCE, bounce); - - if (is_inside_tree()) { - xform = get_global_transform() * xform; - RID space = get_world_2d()->get_space(); - Physics2DServer::get_singleton()->body_set_space(q.body, space); - } - - Physics2DServer::get_singleton()->body_set_state(q.body, Physics2DServer::BODY_STATE_TRANSFORM, xform); - } else if (collision_parent) { - xform = get_transform() * xform; - q.shape_owner_id = collision_parent->create_shape_owner(this); - } else { - q.shape_owner_id = -1; - } - - rect_cache_dirty = true; - quadrant_order_dirty = true; - return quadrant_map.insert(p_qk, q); -} - -void TileMap::_erase_quadrant(Map::Element *Q) { - Quadrant &q = Q->get(); - if (!use_parent) { - if (q.body.is_valid()) { - Physics2DServer::get_singleton()->free(q.body); - q.body = RID(); - } - } else if (collision_parent) { - collision_parent->remove_shape_owner(q.shape_owner_id); - } - - for (List::Element *E = q.canvas_items.front(); E; E = E->next()) { - if (E->get().is_valid()) { - VisualServer::get_singleton()->free(E->get()); - } - } - q.canvas_items.clear(); - if (q.dirty_list.in_list()) { - dirty_quadrant_list.remove(&q.dirty_list); - } - - if (navigation) { - for (Map::Element *E = q.navpoly_ids.front(); E; E = E->next()) { - Navigation2DServer::get_singleton()->region_set_map(E->get().region, RID()); - } - q.navpoly_ids.clear(); - } - - for (Map::Element *E = q.occluder_instances.front(); E; E = E->next()) { - if (E->get().id.is_valid()) { - VS::get_singleton()->free(E->get().id); - } - } - q.occluder_instances.clear(); - - quadrant_map.erase(Q); - rect_cache_dirty = true; -} - -void TileMap::_make_quadrant_dirty(Map::Element *Q, bool update) { - Quadrant &q = Q->get(); - if (!q.dirty_list.in_list()) { - dirty_quadrant_list.add(&q.dirty_list); - } - - if (pending_update) { - return; - } - pending_update = true; - if (!is_inside_tree()) { - return; - } - - if (update) { - call_deferred("update_dirty_quadrants"); - } -} - -void TileMap::set_cellv(const Vector2 &p_pos, int p_tile, bool p_flip_x, bool p_flip_y, bool p_transpose, Vector2 p_autotile_coord) { - set_cell(p_pos.x, p_pos.y, p_tile, p_flip_x, p_flip_y, p_transpose, p_autotile_coord); -} - -void TileMap::_set_celld(const Vector2 &p_pos, const Dictionary &p_data) { - Variant v_pos_x = p_pos.x, v_pos_y = p_pos.y, v_tile = p_data["id"], v_flip_h = p_data["flip_h"], v_flip_v = p_data["flip_y"], v_transpose = p_data["transpose"], v_autotile_coord = p_data["auto_coord"]; - const Variant *args[7] = { &v_pos_x, &v_pos_y, &v_tile, &v_flip_h, &v_flip_v, &v_transpose, &v_autotile_coord }; - Variant::CallError ce; - call("set_cell", args, 7, ce); -} - -void TileMap::set_cell(int p_x, int p_y, int p_tile, bool p_flip_x, bool p_flip_y, bool p_transpose, Vector2 p_autotile_coord) { - PosKey pk(p_x, p_y); - - Map::Element *E = tile_map.find(pk); - if (!E && p_tile == INVALID_CELL) { - return; //nothing to do - } - - PosKey qk = pk.to_quadrant(_get_quadrant_size()); - if (p_tile == INVALID_CELL) { - //erase existing - tile_map.erase(pk); - Map::Element *Q = quadrant_map.find(qk); - ERR_FAIL_COND(!Q); - Quadrant &q = Q->get(); - q.cells.erase(pk); - if (q.cells.size() == 0) { - _erase_quadrant(Q); - } else { - _make_quadrant_dirty(Q); - } - - used_size_cache_dirty = true; - return; - } - - Map::Element *Q = quadrant_map.find(qk); - - if (!E) { - E = tile_map.insert(pk, Cell()); - if (!Q) { - Q = _create_quadrant(qk); - } - Quadrant &q = Q->get(); - q.cells.insert(pk); - } else { - ERR_FAIL_COND(!Q); // quadrant should exist... - - if (E->get().id == p_tile && E->get().flip_h == p_flip_x && E->get().flip_v == p_flip_y && E->get().transpose == p_transpose && E->get().autotile_coord_x == (uint16_t)p_autotile_coord.x && E->get().autotile_coord_y == (uint16_t)p_autotile_coord.y) { - return; //nothing changed - } - } - - Cell &c = E->get(); - - c.id = p_tile; - c.flip_h = p_flip_x; - c.flip_v = p_flip_y; - c.transpose = p_transpose; - c.autotile_coord_x = (uint16_t)p_autotile_coord.x; - c.autotile_coord_y = (uint16_t)p_autotile_coord.y; - - _make_quadrant_dirty(Q); - used_size_cache_dirty = true; -} - -int TileMap::get_cellv(const Vector2 &p_pos) const { - return get_cell(p_pos.x, p_pos.y); -} - -void TileMap::make_bitmask_area_dirty(const Vector2 &p_pos) { - for (int x = p_pos.x - 1; x <= p_pos.x + 1; x++) { - for (int y = p_pos.y - 1; y <= p_pos.y + 1; y++) { - PosKey p(x, y); - if (dirty_bitmask.find(p) == nullptr) { - dirty_bitmask.push_back(p); - } - } - } -} - -void TileMap::update_bitmask_area(const Vector2 &p_pos) { - for (int x = p_pos.x - 1; x <= p_pos.x + 1; x++) { - for (int y = p_pos.y - 1; y <= p_pos.y + 1; y++) { - update_cell_bitmask(x, y); - } - } -} - -void TileMap::update_bitmask_region(const Vector2 &p_start, const Vector2 &p_end) { - if ((p_end.x < p_start.x || p_end.y < p_start.y) || (p_end.x == p_start.x && p_end.y == p_start.y)) { - Array a = get_used_cells(); - for (int i = 0; i < a.size(); i++) { - Vector2 vector = (Vector2)a[i]; - update_cell_bitmask(vector.x, vector.y); - } - return; - } - for (int x = p_start.x - 1; x <= p_end.x + 1; x++) { - for (int y = p_start.y - 1; y <= p_end.y + 1; y++) { - update_cell_bitmask(x, y); - } - } -} - -void TileMap::update_cell_bitmask(int p_x, int p_y) { - ERR_FAIL_COND_MSG(tile_set.is_null(), "Cannot update cell bitmask if Tileset is not open."); - PosKey p(p_x, p_y); - Map::Element *E = tile_map.find(p); - if (E != nullptr) { - int id = get_cell(p_x, p_y); - if (!tile_set->has_tile(id)) { - return; - } - if (tile_set->tile_get_tile_mode(id) == TileSet::AUTO_TILE) { - uint16_t mask = 0; - if (tile_set->autotile_get_bitmask_mode(id) == TileSet::BITMASK_2X2) { - if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y))) { - mask |= TileSet::BIND_TOPLEFT; - } - if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y))) { - mask |= TileSet::BIND_TOPRIGHT; - } - if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y))) { - mask |= TileSet::BIND_BOTTOMLEFT; - } - if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y))) { - mask |= TileSet::BIND_BOTTOMRIGHT; - } - } else { - if (tile_set->autotile_get_bitmask_mode(id) == TileSet::BITMASK_3X3_MINIMAL) { - if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y))) { - mask |= TileSet::BIND_TOPLEFT; - } - if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y))) { - mask |= TileSet::BIND_TOPRIGHT; - } - if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y))) { - mask |= TileSet::BIND_BOTTOMLEFT; - } - if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y))) { - mask |= TileSet::BIND_BOTTOMRIGHT; - } - } else { - if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y - 1))) { - mask |= TileSet::BIND_TOPLEFT; - } - if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y - 1))) { - mask |= TileSet::BIND_TOPRIGHT; - } - if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y + 1))) { - mask |= TileSet::BIND_BOTTOMLEFT; - } - if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y + 1))) { - mask |= TileSet::BIND_BOTTOMRIGHT; - } - } - if (tile_set->is_tile_bound(id, get_cell(p_x, p_y - 1))) { - mask |= TileSet::BIND_TOP; - } - if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y))) { - mask |= TileSet::BIND_LEFT; - } - mask |= TileSet::BIND_CENTER; - if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y))) { - mask |= TileSet::BIND_RIGHT; - } - if (tile_set->is_tile_bound(id, get_cell(p_x, p_y + 1))) { - mask |= TileSet::BIND_BOTTOM; - } - } - Vector2 coord = tile_set->autotile_get_subtile_for_bitmask(id, mask, this, Vector2(p_x, p_y)); - E->get().autotile_coord_x = (int)coord.x; - E->get().autotile_coord_y = (int)coord.y; - - PosKey qk = p.to_quadrant(_get_quadrant_size()); - Map::Element *Q = quadrant_map.find(qk); - _make_quadrant_dirty(Q); - - } else if (tile_set->tile_get_tile_mode(id) == TileSet::SINGLE_TILE) { - E->get().autotile_coord_x = 0; - E->get().autotile_coord_y = 0; - } else if (tile_set->tile_get_tile_mode(id) == TileSet::ATLAS_TILE) { - if (tile_set->autotile_get_bitmask(id, Vector2(p_x, p_y)) == TileSet::BIND_CENTER) { - Vector2 coord = tile_set->atlastile_get_subtile_by_priority(id, this, Vector2(p_x, p_y)); - - E->get().autotile_coord_x = (int)coord.x; - E->get().autotile_coord_y = (int)coord.y; - } - } - } -} - -void TileMap::update_dirty_bitmask() { - while (dirty_bitmask.size() > 0) { - update_cell_bitmask(dirty_bitmask[0].x, dirty_bitmask[0].y); - dirty_bitmask.pop_front(); - } -} - -void TileMap::fix_invalid_tiles() { - ERR_FAIL_COND_MSG(tile_set.is_null(), "Cannot fix invalid tiles if Tileset is not open."); - - Map temp_tile_map = tile_map; - for (Map::Element *E = temp_tile_map.front(); E; E = E->next()) { - if (!tile_set->has_tile(get_cell(E->key().x, E->key().y))) { - set_cell(E->key().x, E->key().y, INVALID_CELL); - } - } -} - -int TileMap::get_cell(int p_x, int p_y) const { - PosKey pk(p_x, p_y); - - const Map::Element *E = tile_map.find(pk); - - if (!E) { - return INVALID_CELL; - } - - return E->get().id; -} -bool TileMap::is_cell_x_flipped(int p_x, int p_y) const { - PosKey pk(p_x, p_y); - - const Map::Element *E = tile_map.find(pk); - - if (!E) { - return false; - } - - return E->get().flip_h; -} -bool TileMap::is_cell_y_flipped(int p_x, int p_y) const { - PosKey pk(p_x, p_y); - - const Map::Element *E = tile_map.find(pk); - - if (!E) { - return false; - } - - return E->get().flip_v; -} -bool TileMap::is_cell_transposed(int p_x, int p_y) const { - PosKey pk(p_x, p_y); - - const Map::Element *E = tile_map.find(pk); - - if (!E) { - return false; - } - - return E->get().transpose; -} - -void TileMap::set_cell_autotile_coord(int p_x, int p_y, const Vector2 &p_coord) { - PosKey pk(p_x, p_y); - - const Map::Element *E = tile_map.find(pk); - - if (!E) { - return; - } - - Cell c = E->get(); - c.autotile_coord_x = p_coord.x; - c.autotile_coord_y = p_coord.y; - tile_map[pk] = c; - - PosKey qk = pk.to_quadrant(_get_quadrant_size()); - Map::Element *Q = quadrant_map.find(qk); - - if (!Q) { - return; - } - - _make_quadrant_dirty(Q); -} - -Vector2 TileMap::get_cell_autotile_coord(int p_x, int p_y) const { - PosKey pk(p_x, p_y); - - const Map::Element *E = tile_map.find(pk); - - if (!E) { - return Vector2(); - } - - return Vector2(E->get().autotile_coord_x, E->get().autotile_coord_y); -} - -void TileMap::_recreate_quadrants() { - _clear_quadrants(); - - for (Map::Element *E = tile_map.front(); E; E = E->next()) { - PosKey qk = PosKey(E->key().x, E->key().y).to_quadrant(_get_quadrant_size()); - - Map::Element *Q = quadrant_map.find(qk); - if (!Q) { - Q = _create_quadrant(qk); - dirty_quadrant_list.add(&Q->get().dirty_list); - } - - Q->get().cells.insert(E->key()); - _make_quadrant_dirty(Q, false); - } - update_dirty_quadrants(); -} - -void TileMap::_clear_quadrants() { - while (quadrant_map.size()) { - _erase_quadrant(quadrant_map.front()); - } -} - -void TileMap::set_material(const Ref &p_material) { - CanvasItem::set_material(p_material); - _update_all_items_material_state(); -} - -void TileMap::set_use_parent_material(bool p_use_parent_material) { - CanvasItem::set_use_parent_material(p_use_parent_material); - _update_all_items_material_state(); -} - -void TileMap::_update_all_items_material_state() { - for (Map::Element *E = quadrant_map.front(); E; E = E->next()) { - Quadrant &q = E->get(); - for (List::Element *F = q.canvas_items.front(); F; F = F->next()) { - _update_item_material_state(F->get()); - } - } -} - -void TileMap::_update_item_material_state(const RID &p_canvas_item) { - VS::get_singleton()->canvas_item_set_use_parent_material(p_canvas_item, get_use_parent_material() || get_material().is_valid()); -} - -void TileMap::clear() { - _clear_quadrants(); - tile_map.clear(); - used_size_cache_dirty = true; -} - -void TileMap::_set_tile_data(const PoolVector &p_data) { - ERR_FAIL_COND(format > FORMAT_2); - - int c = p_data.size(); - PoolVector::Read r = p_data.read(); - - int offset = (format == FORMAT_2) ? 3 : 2; - ERR_FAIL_COND_MSG(c % offset != 0, "Corrupted tile data."); - - clear(); - for (int i = 0; i < c; i += offset) { - const uint8_t *ptr = (const uint8_t *)&r[i]; - uint8_t local[12]; - for (int j = 0; j < ((format == FORMAT_2) ? 12 : 8); j++) { - local[j] = ptr[j]; - } - -#ifdef BIG_ENDIAN_ENABLED - - SWAP(local[0], local[3]); - SWAP(local[1], local[2]); - SWAP(local[4], local[7]); - SWAP(local[5], local[6]); - //TODO: ask someone to check this... - if (FORMAT == FORMAT_2) { - SWAP(local[8], local[11]); - SWAP(local[9], local[10]); - } -#endif - - uint16_t x = decode_uint16(&local[0]); - uint16_t y = decode_uint16(&local[2]); - uint32_t v = decode_uint32(&local[4]); - bool flip_h = v & (1 << 29); - bool flip_v = v & (1 << 30); - bool transpose = v & (1 << 31); - v &= (1 << 29) - 1; - int16_t coord_x = 0; - int16_t coord_y = 0; - if (format == FORMAT_2) { - coord_x = decode_uint16(&local[8]); - coord_y = decode_uint16(&local[10]); - } - - set_cell(x, y, v, flip_h, flip_v, transpose, Vector2(coord_x, coord_y)); - } -} - -PoolVector TileMap::_get_tile_data() const { - PoolVector data; - data.resize(tile_map.size() * 3); - PoolVector::Write w = data.write(); - - // Save in highest format - - int idx = 0; - for (const Map::Element *E = tile_map.front(); E; E = E->next()) { - uint8_t *ptr = (uint8_t *)&w[idx]; - encode_uint16(E->key().x, &ptr[0]); - encode_uint16(E->key().y, &ptr[2]); - uint32_t val = E->get().id; - if (E->get().flip_h) { - val |= (1 << 29); - } - if (E->get().flip_v) { - val |= (1 << 30); - } - if (E->get().transpose) { - val |= (1 << 31); - } - encode_uint32(val, &ptr[4]); - encode_uint16(E->get().autotile_coord_x, &ptr[8]); - encode_uint16(E->get().autotile_coord_y, &ptr[10]); - idx += 3; - } - - w.release(); - - return data; -} - -#ifdef TOOLS_ENABLED -Rect2 TileMap::_edit_get_rect() const { - if (pending_update) { - const_cast(this)->update_dirty_quadrants(); - } else { - const_cast(this)->_recompute_rect_cache(); - } - return rect_cache; -} -#endif - -void TileMap::set_collision_layer(uint32_t p_layer) { - collision_layer = p_layer; - if (!use_parent) { - for (Map::Element *E = quadrant_map.front(); E; E = E->next()) { - Quadrant &q = E->get(); - Physics2DServer::get_singleton()->body_set_collision_layer(q.body, collision_layer); - } - } -} - -void TileMap::set_collision_mask(uint32_t p_mask) { - collision_mask = p_mask; - if (!use_parent) { - for (Map::Element *E = quadrant_map.front(); E; E = E->next()) { - Quadrant &q = E->get(); - Physics2DServer::get_singleton()->body_set_collision_mask(q.body, collision_mask); - } - } -} - -void TileMap::set_collision_layer_bit(int p_bit, bool p_value) { - ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive."); - uint32_t layer = get_collision_layer(); - if (p_value) { - layer |= 1 << p_bit; - } else { - layer &= ~(1 << p_bit); - } - set_collision_layer(layer); -} - -void TileMap::set_collision_mask_bit(int p_bit, bool p_value) { - ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive."); - uint32_t mask = get_collision_mask(); - if (p_value) { - mask |= 1 << p_bit; - } else { - mask &= ~(1 << p_bit); - } - set_collision_mask(mask); -} - -bool TileMap::get_collision_use_kinematic() const { - return use_kinematic; -} - -void TileMap::set_collision_use_kinematic(bool p_use_kinematic) { - _clear_quadrants(); - use_kinematic = p_use_kinematic; - _recreate_quadrants(); -} - -bool TileMap::get_collision_use_parent() const { - return use_parent; -} - -void TileMap::set_collision_use_parent(bool p_use_parent) { - if (use_parent == p_use_parent) { - return; - } - - _clear_quadrants(); - - use_parent = p_use_parent; - set_notify_local_transform(use_parent); - - if (use_parent && is_inside_tree()) { - collision_parent = Object::cast_to(get_parent()); - } else { - collision_parent = nullptr; - } - - _recreate_quadrants(); - _change_notify(); - update_configuration_warning(); -} - -void TileMap::set_collision_friction(float p_friction) { - friction = p_friction; - if (!use_parent) { - for (Map::Element *E = quadrant_map.front(); E; E = E->next()) { - Quadrant &q = E->get(); - Physics2DServer::get_singleton()->body_set_param(q.body, Physics2DServer::BODY_PARAM_FRICTION, p_friction); - } - } -} - -float TileMap::get_collision_friction() const { - return friction; -} - -void TileMap::set_collision_bounce(float p_bounce) { - bounce = p_bounce; - if (!use_parent) { - for (Map::Element *E = quadrant_map.front(); E; E = E->next()) { - Quadrant &q = E->get(); - Physics2DServer::get_singleton()->body_set_param(q.body, Physics2DServer::BODY_PARAM_BOUNCE, p_bounce); - } - } -} -float TileMap::get_collision_bounce() const { - return bounce; -} - -uint32_t TileMap::get_collision_layer() const { - return collision_layer; -} - -uint32_t TileMap::get_collision_mask() const { - return collision_mask; -} - -bool TileMap::get_collision_layer_bit(int p_bit) const { - ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision layer bit must be between 0 and 31 inclusive."); - return get_collision_layer() & (1 << p_bit); -} - -bool TileMap::get_collision_mask_bit(int p_bit) const { - ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive."); - return get_collision_mask() & (1 << p_bit); -} - -void TileMap::set_mode(Mode p_mode) { - _clear_quadrants(); - mode = p_mode; - _recreate_quadrants(); - emit_signal("settings_changed"); -} - -TileMap::Mode TileMap::get_mode() const { - return mode; -} - -void TileMap::set_half_offset(HalfOffset p_half_offset) { - _clear_quadrants(); - half_offset = p_half_offset; - _recreate_quadrants(); - emit_signal("settings_changed"); -} - -void TileMap::set_tile_origin(TileOrigin p_tile_origin) { - _clear_quadrants(); - tile_origin = p_tile_origin; - _recreate_quadrants(); - emit_signal("settings_changed"); -} - -TileMap::TileOrigin TileMap::get_tile_origin() const { - return tile_origin; -} - -Vector2 TileMap::get_cell_draw_offset() const { - switch (mode) { - case MODE_SQUARE: { - return Vector2(); - } break; - case MODE_ISOMETRIC: { - return Vector2(-cell_size.x * 0.5, 0); - - } break; - case MODE_CUSTOM: { - Vector2 min; - min.x = MIN(custom_transform[0].x, min.x); - min.y = MIN(custom_transform[0].y, min.y); - min.x = MIN(custom_transform[1].x, min.x); - min.y = MIN(custom_transform[1].y, min.y); - return min; - } break; - } - - return Vector2(); -} - -TileMap::HalfOffset TileMap::get_half_offset() const { - return half_offset; -} - -Transform2D TileMap::get_cell_transform() const { - switch (mode) { - case MODE_SQUARE: { - Transform2D m; - m[0] *= cell_size.x; - m[1] *= cell_size.y; - return m; - } break; - case MODE_ISOMETRIC: { - //isometric only makes sense when y is positive in both x and y vectors, otherwise - //the drawing of tiles will overlap - Transform2D m; - m[0] = Vector2(cell_size.x * 0.5, cell_size.y * 0.5); - m[1] = Vector2(-cell_size.x * 0.5, cell_size.y * 0.5); - return m; - - } break; - case MODE_CUSTOM: { - return custom_transform; - } break; - } - - return Transform2D(); -} - -void TileMap::set_custom_transform(const Transform2D &p_xform) { - _clear_quadrants(); - custom_transform = p_xform; - _recreate_quadrants(); - emit_signal("settings_changed"); -} - -Transform2D TileMap::get_custom_transform() const { - return custom_transform; -} - -Vector2 TileMap::_map_to_world(int p_x, int p_y, bool p_ignore_ofs) const { - Vector2 ret = get_cell_transform().xform(Vector2(p_x, p_y)); - if (!p_ignore_ofs) { - switch (half_offset) { - case HALF_OFFSET_X: - case HALF_OFFSET_NEGATIVE_X: { - if (ABS(p_y) & 1) { - ret += get_cell_transform()[0] * (half_offset == HALF_OFFSET_X ? 0.5 : -0.5); - } - } break; - case HALF_OFFSET_Y: - case HALF_OFFSET_NEGATIVE_Y: { - if (ABS(p_x) & 1) { - ret += get_cell_transform()[1] * (half_offset == HALF_OFFSET_Y ? 0.5 : -0.5); - } - } break; - case HALF_OFFSET_DISABLED: { - // Nothing to do. - } - } - } - return ret; -} - -bool TileMap::_set(const StringName &p_name, const Variant &p_value) { - if (p_name == "format") { - if (p_value.get_type() == Variant::INT) { - format = (DataFormat)(p_value.operator int64_t()); // Set format used for loading - return true; - } - } else if (p_name == "tile_data") { - if (p_value.is_array()) { - _set_tile_data(p_value); - return true; - } - return false; - } - return false; -} - -bool TileMap::_get(const StringName &p_name, Variant &r_ret) const { - if (p_name == "format") { - r_ret = FORMAT_2; // When saving, always save highest format - return true; - } else if (p_name == "tile_data") { - r_ret = _get_tile_data(); - return true; - } - return false; -} - -void TileMap::_get_property_list(List *p_list) const { - PropertyInfo p(Variant::INT, "format", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL); - p_list->push_back(p); - - p = PropertyInfo(Variant::OBJECT, "tile_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL); - p_list->push_back(p); -} - -void TileMap::_validate_property(PropertyInfo &property) const { - if (use_parent && property.name != "collision_use_parent" && property.name.begins_with("collision_")) { - property.usage = PROPERTY_USAGE_NOEDITOR; - } -} - -Vector2 TileMap::map_to_world(const Vector2 &p_pos, bool p_ignore_ofs) const { - return _map_to_world(p_pos.x, p_pos.y, p_ignore_ofs); -} - -Vector2 TileMap::world_to_map(const Vector2 &p_pos) const { - Vector2 ret = get_cell_transform().affine_inverse().xform(p_pos); - - // Account for precision errors on the border (GH-23250). - // 0.00005 is 5*CMP_EPSILON, results would start being unpredictable if - // cell size is > 15,000, but we can hardly have more precision anyway with - // floating point. - ret += Vector2(0.00005, 0.00005); - - switch (half_offset) { - case HALF_OFFSET_X: { - if (int(floor(ret.y)) & 1) { - ret.x -= 0.5; - } - } break; - case HALF_OFFSET_NEGATIVE_X: { - if (int(floor(ret.y)) & 1) { - ret.x += 0.5; - } - } break; - case HALF_OFFSET_Y: { - if (int(floor(ret.x)) & 1) { - ret.y -= 0.5; - } - } break; - case HALF_OFFSET_NEGATIVE_Y: { - if (int(floor(ret.x)) & 1) { - ret.y += 0.5; - } - } break; - case HALF_OFFSET_DISABLED: { - // Nothing to do. - } - } - - return ret.floor(); -} - -void TileMap::set_y_sort_mode(bool p_enable) { - _clear_quadrants(); - y_sort_mode = p_enable; - VS::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(), y_sort_mode); - _recreate_quadrants(); - emit_signal("settings_changed"); -} - -bool TileMap::is_y_sort_mode_enabled() const { - return y_sort_mode; -} - -void TileMap::set_compatibility_mode(bool p_enable) { - _clear_quadrants(); - compatibility_mode = p_enable; - _recreate_quadrants(); - emit_signal("settings_changed"); -} - -bool TileMap::is_compatibility_mode_enabled() const { - return compatibility_mode; -} - -void TileMap::set_centered_textures(bool p_enable) { - _clear_quadrants(); - centered_textures = p_enable; - _recreate_quadrants(); - emit_signal("settings_changed"); -} - -bool TileMap::is_centered_textures_enabled() const { - return centered_textures; -} - -Array TileMap::get_used_cells() const { - Array a; - a.resize(tile_map.size()); - int i = 0; - for (Map::Element *E = tile_map.front(); E; E = E->next()) { - Vector2 p(E->key().x, E->key().y); - a[i++] = p; - } - - return a; -} - -Array TileMap::get_used_cells_by_id(int p_id) const { - Array a; - for (Map::Element *E = tile_map.front(); E; E = E->next()) { - if (E->value().id == p_id) { - Vector2 p(E->key().x, E->key().y); - a.push_back(p); - } - } - - return a; -} - -Rect2 TileMap::get_used_rect() { // Not const because of cache - - if (used_size_cache_dirty) { - if (tile_map.size() > 0) { - used_size_cache = Rect2(tile_map.front()->key().x, tile_map.front()->key().y, 0, 0); - - for (Map::Element *E = tile_map.front(); E; E = E->next()) { - used_size_cache.expand_to(Vector2(E->key().x, E->key().y)); - } - - used_size_cache.size += Vector2(1, 1); - } else { - used_size_cache = Rect2(); - } - - used_size_cache_dirty = false; - } - - return used_size_cache; -} - -void TileMap::set_occluder_light_mask(int p_mask) { - occluder_light_mask = p_mask; - for (Map::Element *E = quadrant_map.front(); E; E = E->next()) { - for (Map::Element *F = E->get().occluder_instances.front(); F; F = F->next()) { - VisualServer::get_singleton()->canvas_light_occluder_set_light_mask(F->get().id, occluder_light_mask); - } - } -} - -int TileMap::get_occluder_light_mask() const { - return occluder_light_mask; -} - -void TileMap::set_light_mask(int p_light_mask) { - CanvasItem::set_light_mask(p_light_mask); - for (Map::Element *E = quadrant_map.front(); E; E = E->next()) { - for (List::Element *F = E->get().canvas_items.front(); F; F = F->next()) { - VisualServer::get_singleton()->canvas_item_set_light_mask(F->get(), get_light_mask()); - } - } -} - -void TileMap::set_clip_uv(bool p_enable) { - if (clip_uv == p_enable) { - return; - } - - _clear_quadrants(); - clip_uv = p_enable; - _recreate_quadrants(); -} - -bool TileMap::get_clip_uv() const { - return clip_uv; -} - -String TileMap::get_configuration_warning() const { - String warning = Node2D::get_configuration_warning(); - - if (use_parent && !collision_parent) { - if (!warning.empty()) { - warning += "\n\n"; - } - return TTR("TileMap with Use Parent on needs a parent CollisionObject2D to give shapes to. Please use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."); - } - - return warning; -} - -void TileMap::set_show_collision(bool p_value) { - show_collision = p_value; - _recreate_quadrants(); -} - -bool TileMap::is_show_collision_enabled() const { - return show_collision; -} - -void TileMap::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_tileset", "tileset"), &TileMap::set_tileset); - ClassDB::bind_method(D_METHOD("get_tileset"), &TileMap::get_tileset); - - ClassDB::bind_method(D_METHOD("set_mode", "mode"), &TileMap::set_mode); - ClassDB::bind_method(D_METHOD("get_mode"), &TileMap::get_mode); - - ClassDB::bind_method(D_METHOD("set_half_offset", "half_offset"), &TileMap::set_half_offset); - ClassDB::bind_method(D_METHOD("get_half_offset"), &TileMap::get_half_offset); - - ClassDB::bind_method(D_METHOD("set_custom_transform", "custom_transform"), &TileMap::set_custom_transform); - ClassDB::bind_method(D_METHOD("get_custom_transform"), &TileMap::get_custom_transform); - - ClassDB::bind_method(D_METHOD("set_cell_size", "size"), &TileMap::set_cell_size); - ClassDB::bind_method(D_METHOD("get_cell_size"), &TileMap::get_cell_size); - - ClassDB::bind_method(D_METHOD("_set_old_cell_size", "size"), &TileMap::_set_old_cell_size); - ClassDB::bind_method(D_METHOD("_get_old_cell_size"), &TileMap::_get_old_cell_size); - - ClassDB::bind_method(D_METHOD("set_quadrant_size", "size"), &TileMap::set_quadrant_size); - ClassDB::bind_method(D_METHOD("get_quadrant_size"), &TileMap::get_quadrant_size); - - ClassDB::bind_method(D_METHOD("set_tile_origin", "origin"), &TileMap::set_tile_origin); - ClassDB::bind_method(D_METHOD("get_tile_origin"), &TileMap::get_tile_origin); - - ClassDB::bind_method(D_METHOD("set_clip_uv", "enable"), &TileMap::set_clip_uv); - ClassDB::bind_method(D_METHOD("get_clip_uv"), &TileMap::get_clip_uv); - - ClassDB::bind_method(D_METHOD("set_y_sort_mode", "enable"), &TileMap::set_y_sort_mode); - ClassDB::bind_method(D_METHOD("is_y_sort_mode_enabled"), &TileMap::is_y_sort_mode_enabled); - - ClassDB::bind_method(D_METHOD("set_compatibility_mode", "enable"), &TileMap::set_compatibility_mode); - ClassDB::bind_method(D_METHOD("is_compatibility_mode_enabled"), &TileMap::is_compatibility_mode_enabled); - - ClassDB::bind_method(D_METHOD("set_show_collision", "enable"), &TileMap::set_show_collision); - ClassDB::bind_method(D_METHOD("is_show_collision_enabled"), &TileMap::is_show_collision_enabled); - - ClassDB::bind_method(D_METHOD("set_centered_textures", "enable"), &TileMap::set_centered_textures); - ClassDB::bind_method(D_METHOD("is_centered_textures_enabled"), &TileMap::is_centered_textures_enabled); - - ClassDB::bind_method(D_METHOD("set_collision_use_kinematic", "use_kinematic"), &TileMap::set_collision_use_kinematic); - ClassDB::bind_method(D_METHOD("get_collision_use_kinematic"), &TileMap::get_collision_use_kinematic); - - ClassDB::bind_method(D_METHOD("set_collision_use_parent", "use_parent"), &TileMap::set_collision_use_parent); - ClassDB::bind_method(D_METHOD("get_collision_use_parent"), &TileMap::get_collision_use_parent); - - ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &TileMap::set_collision_layer); - ClassDB::bind_method(D_METHOD("get_collision_layer"), &TileMap::get_collision_layer); - - ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &TileMap::set_collision_mask); - ClassDB::bind_method(D_METHOD("get_collision_mask"), &TileMap::get_collision_mask); - - ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &TileMap::set_collision_layer_bit); - ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &TileMap::get_collision_layer_bit); - - ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &TileMap::set_collision_mask_bit); - ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &TileMap::get_collision_mask_bit); - - ClassDB::bind_method(D_METHOD("set_collision_friction", "value"), &TileMap::set_collision_friction); - ClassDB::bind_method(D_METHOD("get_collision_friction"), &TileMap::get_collision_friction); - - ClassDB::bind_method(D_METHOD("set_collision_bounce", "value"), &TileMap::set_collision_bounce); - ClassDB::bind_method(D_METHOD("get_collision_bounce"), &TileMap::get_collision_bounce); - - ClassDB::bind_method(D_METHOD("set_occluder_light_mask", "mask"), &TileMap::set_occluder_light_mask); - ClassDB::bind_method(D_METHOD("get_occluder_light_mask"), &TileMap::get_occluder_light_mask); - - ClassDB::bind_method(D_METHOD("set_cell", "x", "y", "tile", "flip_x", "flip_y", "transpose", "autotile_coord"), &TileMap::set_cell, DEFVAL(false), DEFVAL(false), DEFVAL(false), DEFVAL(Vector2())); - ClassDB::bind_method(D_METHOD("set_cellv", "position", "tile", "flip_x", "flip_y", "transpose", "autotile_coord"), &TileMap::set_cellv, DEFVAL(false), DEFVAL(false), DEFVAL(false), DEFVAL(Vector2())); - ClassDB::bind_method(D_METHOD("_set_celld", "position", "data"), &TileMap::_set_celld); - ClassDB::bind_method(D_METHOD("get_cell", "x", "y"), &TileMap::get_cell); - ClassDB::bind_method(D_METHOD("get_cellv", "position"), &TileMap::get_cellv); - ClassDB::bind_method(D_METHOD("is_cell_x_flipped", "x", "y"), &TileMap::is_cell_x_flipped); - ClassDB::bind_method(D_METHOD("is_cell_y_flipped", "x", "y"), &TileMap::is_cell_y_flipped); - ClassDB::bind_method(D_METHOD("is_cell_transposed", "x", "y"), &TileMap::is_cell_transposed); - - ClassDB::bind_method(D_METHOD("get_cell_autotile_coord", "x", "y"), &TileMap::get_cell_autotile_coord); - - ClassDB::bind_method(D_METHOD("fix_invalid_tiles"), &TileMap::fix_invalid_tiles); - ClassDB::bind_method(D_METHOD("clear"), &TileMap::clear); - - ClassDB::bind_method(D_METHOD("get_used_cells"), &TileMap::get_used_cells); - ClassDB::bind_method(D_METHOD("get_used_cells_by_id", "id"), &TileMap::get_used_cells_by_id); - ClassDB::bind_method(D_METHOD("get_used_rect"), &TileMap::get_used_rect); - - ClassDB::bind_method(D_METHOD("map_to_world", "map_position", "ignore_half_ofs"), &TileMap::map_to_world, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("world_to_map", "world_position"), &TileMap::world_to_map); - - ClassDB::bind_method(D_METHOD("_clear_quadrants"), &TileMap::_clear_quadrants); - ClassDB::bind_method(D_METHOD("_recreate_quadrants"), &TileMap::_recreate_quadrants); - ClassDB::bind_method(D_METHOD("update_dirty_quadrants"), &TileMap::update_dirty_quadrants); - - ClassDB::bind_method(D_METHOD("update_bitmask_area", "position"), &TileMap::update_bitmask_area); - ClassDB::bind_method(D_METHOD("update_bitmask_region", "start", "end"), &TileMap::update_bitmask_region, DEFVAL(Vector2()), DEFVAL(Vector2())); - - ClassDB::bind_method(D_METHOD("_set_tile_data"), &TileMap::_set_tile_data); - ClassDB::bind_method(D_METHOD("_get_tile_data"), &TileMap::_get_tile_data); - - ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Square,Isometric,Custom"), "set_mode", "get_mode"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tile_set", PROPERTY_HINT_RESOURCE_TYPE, "TileSet"), "set_tileset", "get_tileset"); - - ADD_GROUP("Cell", "cell_"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "cell_size", PROPERTY_HINT_RANGE, "1,8192,1"), "set_cell_size", "get_cell_size"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_quadrant_size", PROPERTY_HINT_RANGE, "1,128,1"), "set_quadrant_size", "get_quadrant_size"); - ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "cell_custom_transform"), "set_custom_transform", "get_custom_transform"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_half_offset", PROPERTY_HINT_ENUM, "Offset X,Offset Y,Disabled,Offset Negative X,Offset Negative Y"), "set_half_offset", "get_half_offset"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_tile_origin", PROPERTY_HINT_ENUM, "Top Left,Center,Bottom Left"), "set_tile_origin", "get_tile_origin"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cell_y_sort"), "set_y_sort_mode", "is_y_sort_mode_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_collision"), "set_show_collision", "is_show_collision_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "compatibility_mode"), "set_compatibility_mode", "is_compatibility_mode_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered_textures"), "set_centered_textures", "is_centered_textures_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cell_clip_uv"), "set_clip_uv", "get_clip_uv"); - - ADD_GROUP("Collision", "collision_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision_use_parent", PROPERTY_HINT_NONE, ""), "set_collision_use_parent", "get_collision_use_parent"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision_use_kinematic", PROPERTY_HINT_NONE, ""), "set_collision_use_kinematic", "get_collision_use_kinematic"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "collision_friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_collision_friction", "get_collision_friction"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "collision_bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_collision_bounce", "get_collision_bounce"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask"); - - ADD_GROUP("Occluder", "occluder_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "occluder_light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_occluder_light_mask", "get_occluder_light_mask"); - - ADD_PROPERTY_DEFAULT("format", FORMAT_1); - - ADD_SIGNAL(MethodInfo("settings_changed")); - - BIND_CONSTANT(INVALID_CELL); - - BIND_ENUM_CONSTANT(MODE_SQUARE); - BIND_ENUM_CONSTANT(MODE_ISOMETRIC); - BIND_ENUM_CONSTANT(MODE_CUSTOM); - - BIND_ENUM_CONSTANT(HALF_OFFSET_X); - BIND_ENUM_CONSTANT(HALF_OFFSET_Y); - BIND_ENUM_CONSTANT(HALF_OFFSET_DISABLED); - BIND_ENUM_CONSTANT(HALF_OFFSET_NEGATIVE_X); - BIND_ENUM_CONSTANT(HALF_OFFSET_NEGATIVE_Y); - - BIND_ENUM_CONSTANT(TILE_ORIGIN_TOP_LEFT); - BIND_ENUM_CONSTANT(TILE_ORIGIN_CENTER); - BIND_ENUM_CONSTANT(TILE_ORIGIN_BOTTOM_LEFT); -} - -void TileMap::_changed_callback(Object *p_changed, const char *p_prop) { - if (tile_set.is_valid() && tile_set.ptr() == p_changed) { - emit_signal("settings_changed"); - } -} - -TileMap::TileMap() { - rect_cache_dirty = true; - used_size_cache_dirty = true; - pending_update = false; - quadrant_order_dirty = false; - quadrant_size = 16; - cell_size = Size2(64, 64); - custom_transform = Transform2D(64, 0, 0, 64, 0, 0); - collision_layer = 1; - collision_mask = 1; - friction = 1; - bounce = 0; - mode = MODE_SQUARE; - half_offset = HALF_OFFSET_DISABLED; - use_parent = false; - collision_parent = nullptr; - use_kinematic = false; - navigation = nullptr; - y_sort_mode = false; - compatibility_mode = false; - centered_textures = false; - occluder_light_mask = 1; - clip_uv = false; - format = FORMAT_1; // Assume lowest possible format if none is present - - fp_adjust = 0.00001; - tile_origin = TILE_ORIGIN_TOP_LEFT; - set_notify_transform(true); - set_notify_local_transform(false); -} - -TileMap::~TileMap() { - if (tile_set.is_valid()) { - tile_set->remove_change_receptor(this); - } - - clear(); -} diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h deleted file mode 100644 index c42a7c81c..000000000 --- a/scene/2d/tile_map.h +++ /dev/null @@ -1,360 +0,0 @@ -/*************************************************************************/ -/* tile_map.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef TILE_MAP_H -#define TILE_MAP_H - -#include "core/self_list.h" -#include "core/vset.h" -#include "scene/2d/navigation_2d.h" -#include "scene/2d/node_2d.h" -#include "scene/resources/tile_set.h" - -class CollisionObject2D; - -class TileMap : public Node2D { - GDCLASS(TileMap, Node2D); - -public: - enum Mode { - MODE_SQUARE, - MODE_ISOMETRIC, - MODE_CUSTOM - }; - - enum HalfOffset { - HALF_OFFSET_X, - HALF_OFFSET_Y, - HALF_OFFSET_DISABLED, - HALF_OFFSET_NEGATIVE_X, - HALF_OFFSET_NEGATIVE_Y, - }; - - enum TileOrigin { - TILE_ORIGIN_TOP_LEFT, - TILE_ORIGIN_CENTER, - TILE_ORIGIN_BOTTOM_LEFT - }; - -private: - enum DataFormat { - FORMAT_1 = 0, - FORMAT_2 - }; - - Ref tile_set; - Size2i cell_size; - int quadrant_size; - Mode mode; - Transform2D custom_transform; - HalfOffset half_offset; - bool use_parent; - CollisionObject2D *collision_parent; - bool use_kinematic; - Navigation2D *navigation; - bool show_collision = false; - - union PosKey { - struct { - int16_t x; - int16_t y; - }; - uint32_t key; - - //using a more precise comparison so the regions can be sorted later - bool operator<(const PosKey &p_k) const { return (y == p_k.y) ? x < p_k.x : y < p_k.y; } - - bool operator==(const PosKey &p_k) const { return (y == p_k.y && x == p_k.x); } - - PosKey to_quadrant(const int &p_quadrant_size) const { - // rounding down, instead of simply rounding towards zero (truncating) - return PosKey( - x > 0 ? x / p_quadrant_size : (x - (p_quadrant_size - 1)) / p_quadrant_size, - y > 0 ? y / p_quadrant_size : (y - (p_quadrant_size - 1)) / p_quadrant_size); - } - - PosKey(int16_t p_x, int16_t p_y) { - x = p_x; - y = p_y; - } - PosKey() { - x = 0; - y = 0; - } - }; - - union Cell { - struct { - int32_t id : 24; - bool flip_h : 1; - bool flip_v : 1; - bool transpose : 1; - int16_t autotile_coord_x : 16; - int16_t autotile_coord_y : 16; - }; - - uint64_t _u64t; - Cell() { _u64t = 0; } - }; - - Map tile_map; - List dirty_bitmask; - - struct Quadrant { - Vector2 pos; - List canvas_items; - RID body; - uint32_t shape_owner_id; - - SelfList dirty_list; - - struct NavPoly { - RID region; - Transform2D xform; - }; - - struct Occluder { - RID id; - Transform2D xform; - }; - - Map navpoly_ids; - Map occluder_instances; - - VSet cells; - - void operator=(const Quadrant &q) { - pos = q.pos; - canvas_items = q.canvas_items; - body = q.body; - shape_owner_id = q.shape_owner_id; - cells = q.cells; - navpoly_ids = q.navpoly_ids; - occluder_instances = q.occluder_instances; - } - Quadrant(const Quadrant &q) : - dirty_list(this) { - pos = q.pos; - canvas_items = q.canvas_items; - body = q.body; - shape_owner_id = q.shape_owner_id; - cells = q.cells; - occluder_instances = q.occluder_instances; - navpoly_ids = q.navpoly_ids; - } - Quadrant() : - dirty_list(this) {} - }; - - Map quadrant_map; - - SelfList::List dirty_quadrant_list; - - bool pending_update; - - Rect2 rect_cache; - bool rect_cache_dirty; - Rect2 used_size_cache; - bool used_size_cache_dirty; - bool quadrant_order_dirty; - bool y_sort_mode; - bool compatibility_mode; - bool centered_textures; - bool clip_uv; - float fp_adjust; - float friction; - float bounce; - uint32_t collision_layer; - uint32_t collision_mask; - mutable DataFormat format; - - TileOrigin tile_origin; - - int occluder_light_mask; - - void _fix_cell_transform(Transform2D &xform, const Cell &p_cell, const Vector2 &p_offset, const Size2 &p_sc); - - void _add_shape(int &shape_idx, const Quadrant &p_q, const Ref &p_shape, const TileSet::ShapeData &p_shape_data, const Transform2D &p_xform, const Vector2 &p_metadata); - - Map::Element *_create_quadrant(const PosKey &p_qk); - void _erase_quadrant(Map::Element *Q); - void _make_quadrant_dirty(Map::Element *Q, bool update = true); - void _recreate_quadrants(); - void _clear_quadrants(); - void _update_quadrant_space(const RID &p_space); - void _update_quadrant_transform(); - void _recompute_rect_cache(); - - void _update_all_items_material_state(); - _FORCE_INLINE_ void _update_item_material_state(const RID &p_canvas_item); - - _FORCE_INLINE_ int _get_quadrant_size() const; - - void _set_tile_data(const PoolVector &p_data); - PoolVector _get_tile_data() const; - - void _set_old_cell_size(int p_size) { set_cell_size(Size2(p_size, p_size)); } - int _get_old_cell_size() const { return cell_size.x; } - - _FORCE_INLINE_ Vector2 _map_to_world(int p_x, int p_y, bool p_ignore_ofs = false) const; - -protected: - bool _set(const StringName &p_name, const Variant &p_value); - bool _get(const StringName &p_name, Variant &r_ret) const; - void _get_property_list(List *p_list) const; - - void _notification(int p_what); - static void _bind_methods(); - - virtual void _validate_property(PropertyInfo &property) const; - virtual void _changed_callback(Object *p_changed, const char *p_prop); - -public: - enum { - INVALID_CELL = -1 - }; - -#ifdef TOOLS_ENABLED - virtual Rect2 _edit_get_rect() const; -#endif - - void set_tileset(const Ref &p_tileset); - Ref get_tileset() const; - - void set_cell_size(Size2 p_size); - Size2 get_cell_size() const; - - void set_quadrant_size(int p_size); - int get_quadrant_size() const; - - void set_cell(int p_x, int p_y, int p_tile, bool p_flip_x = false, bool p_flip_y = false, bool p_transpose = false, Vector2 p_autotile_coord = Vector2()); - int get_cell(int p_x, int p_y) const; - bool is_cell_x_flipped(int p_x, int p_y) const; - bool is_cell_y_flipped(int p_x, int p_y) const; - bool is_cell_transposed(int p_x, int p_y) const; - void set_cell_autotile_coord(int p_x, int p_y, const Vector2 &p_coord); - Vector2 get_cell_autotile_coord(int p_x, int p_y) const; - - void _set_celld(const Vector2 &p_pos, const Dictionary &p_data); - void set_cellv(const Vector2 &p_pos, int p_tile, bool p_flip_x = false, bool p_flip_y = false, bool p_transpose = false, Vector2 p_autotile_coord = Vector2()); - int get_cellv(const Vector2 &p_pos) const; - - void make_bitmask_area_dirty(const Vector2 &p_pos); - void update_bitmask_area(const Vector2 &p_pos); - void update_bitmask_region(const Vector2 &p_start = Vector2(), const Vector2 &p_end = Vector2()); - void update_cell_bitmask(int p_x, int p_y); - void update_dirty_bitmask(); - - void update_dirty_quadrants(); - - void set_show_collision(bool p_value); - bool is_show_collision_enabled() const; - - void set_collision_layer(uint32_t p_layer); - uint32_t get_collision_layer() const; - - void set_collision_mask(uint32_t p_mask); - uint32_t get_collision_mask() const; - - void set_collision_layer_bit(int p_bit, bool p_value); - bool get_collision_layer_bit(int p_bit) const; - - void set_collision_mask_bit(int p_bit, bool p_value); - bool get_collision_mask_bit(int p_bit) const; - - void set_collision_use_kinematic(bool p_use_kinematic); - bool get_collision_use_kinematic() const; - - void set_collision_use_parent(bool p_use_parent); - bool get_collision_use_parent() const; - - void set_collision_friction(float p_friction); - float get_collision_friction() const; - - void set_collision_bounce(float p_bounce); - float get_collision_bounce() const; - - void set_mode(Mode p_mode); - Mode get_mode() const; - - void set_half_offset(HalfOffset p_half_offset); - HalfOffset get_half_offset() const; - - void set_tile_origin(TileOrigin p_tile_origin); - TileOrigin get_tile_origin() const; - - void set_custom_transform(const Transform2D &p_xform); - Transform2D get_custom_transform() const; - - Transform2D get_cell_transform() const; - Vector2 get_cell_draw_offset() const; - - Vector2 map_to_world(const Vector2 &p_pos, bool p_ignore_ofs = false) const; - Vector2 world_to_map(const Vector2 &p_pos) const; - - void set_y_sort_mode(bool p_enable); - bool is_y_sort_mode_enabled() const; - - void set_compatibility_mode(bool p_enable); - bool is_compatibility_mode_enabled() const; - - void set_centered_textures(bool p_enable); - bool is_centered_textures_enabled() const; - - Array get_used_cells() const; - Array get_used_cells_by_id(int p_id) const; - Rect2 get_used_rect(); // Not const because of cache - - void set_occluder_light_mask(int p_mask); - int get_occluder_light_mask() const; - - virtual void set_light_mask(int p_light_mask); - - virtual void set_material(const Ref &p_material); - - virtual void set_use_parent_material(bool p_use_parent_material); - - void set_clip_uv(bool p_enable); - bool get_clip_uv() const; - - String get_configuration_warning() const; - - void fix_invalid_tiles(); - void clear(); - - TileMap(); - ~TileMap(); -}; - -VARIANT_ENUM_CAST(TileMap::Mode); -VARIANT_ENUM_CAST(TileMap::HalfOffset); -VARIANT_ENUM_CAST(TileMap::TileOrigin); - -#endif // TILE_MAP_H diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 9b622eaa4..51cc9d318 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -63,7 +63,6 @@ #include "scene/2d/remote_transform_2d.h" #include "scene/2d/skeleton_2d.h" #include "scene/2d/sprite.h" -#include "scene/2d/tile_map.h" #include "scene/2d/touch_screen_button.h" #include "scene/2d/visibility_notifier_2d.h" #include "scene/2d/y_sort.h" @@ -167,7 +166,6 @@ #include "scene/resources/surface_tool.h" #include "scene/resources/text_file.h" #include "scene/resources/texture.h" -#include "scene/resources/tile_set.h" #include "scene/resources/video_stream.h" #include "scene/resources/world.h" #include "scene/resources/world_2d.h" @@ -545,8 +543,6 @@ void register_scene_types() { ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); - ClassDB::register_class(); - ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp deleted file mode 100644 index e46dc36e1..000000000 --- a/scene/resources/tile_set.cpp +++ /dev/null @@ -1,1197 +0,0 @@ -/*************************************************************************/ -/* tile_set.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "tile_set.h" -#include "core/array.h" -#include "core/engine.h" - -bool TileSet::_set(const StringName &p_name, const Variant &p_value) { - String n = p_name; - int slash = n.find("/"); - if (slash == -1) { - return false; - } - int id = String::to_int(n.c_str(), slash); - - if (!tile_map.has(id)) { - create_tile(id); - } - String what = n.substr(slash + 1, n.length()); - - if (what == "name") { - tile_set_name(id, p_value); - } else if (what == "texture") { - tile_set_texture(id, p_value); - } else if (what == "normal_map") { - tile_set_normal_map(id, p_value); - } else if (what == "tex_offset") { - tile_set_texture_offset(id, p_value); - } else if (what == "material") { - tile_set_material(id, p_value); - } else if (what == "modulate") { - tile_set_modulate(id, p_value); - } else if (what == "region") { - tile_set_region(id, p_value); - } else if (what == "tile_mode") { - tile_set_tile_mode(id, (TileMode)((int)p_value)); - } else if (what == "is_autotile") { - // backward compatibility for Godot 3.0.x - // autotile used to be a bool, it's now an enum - bool is_autotile = p_value; - if (is_autotile) { - tile_set_tile_mode(id, AUTO_TILE); - } - } else if (what.left(9) == "autotile/") { - what = what.right(9); - if (what == "bitmask_mode") { - autotile_set_bitmask_mode(id, (BitmaskMode)((int)p_value)); - } else if (what == "icon_coordinate") { - autotile_set_icon_coordinate(id, p_value); - } else if (what == "tile_size") { - autotile_set_size(id, p_value); - } else if (what == "spacing") { - autotile_set_spacing(id, p_value); - } else if (what == "bitmask_flags") { - tile_map[id].autotile_data.flags.clear(); - if (p_value.is_array()) { - Array p = p_value; - Vector2 last_coord; - while (p.size() > 0) { - if (p[0].get_type() == Variant::VECTOR2) { - last_coord = p[0]; - } else if (p[0].get_type() == Variant::INT) { - autotile_set_bitmask(id, last_coord, p[0]); - } - p.pop_front(); - } - } - } else if (what == "occluder_map") { - tile_map[id].autotile_data.occluder_map.clear(); - Array p = p_value; - Vector2 last_coord; - while (p.size() > 0) { - if (p[0].get_type() == Variant::VECTOR2) { - last_coord = p[0]; - } else if (p[0].get_type() == Variant::OBJECT) { - autotile_set_light_occluder(id, p[0], last_coord); - } - p.pop_front(); - } - } else if (what == "navpoly_map") { - tile_map[id].autotile_data.navpoly_map.clear(); - Array p = p_value; - Vector2 last_coord; - while (p.size() > 0) { - if (p[0].get_type() == Variant::VECTOR2) { - last_coord = p[0]; - } else if (p[0].get_type() == Variant::OBJECT) { - autotile_set_navigation_polygon(id, p[0], last_coord); - } - p.pop_front(); - } - } else if (what == "priority_map") { - tile_map[id].autotile_data.priority_map.clear(); - Array p = p_value; - Vector3 val; - Vector2 v; - int priority; - while (p.size() > 0) { - val = p[0]; - if (val.z > 1) { - v.x = val.x; - v.y = val.y; - priority = (int)val.z; - tile_map[id].autotile_data.priority_map[v] = priority; - } - p.pop_front(); - } - } else if (what == "z_index_map") { - tile_map[id].autotile_data.z_index_map.clear(); - Array p = p_value; - Vector3 val; - Vector2 v; - int z_index; - while (p.size() > 0) { - val = p[0]; - if (val.z != 0) { - v.x = val.x; - v.y = val.y; - z_index = (int)val.z; - tile_map[id].autotile_data.z_index_map[v] = z_index; - } - p.pop_front(); - } - } - } else if (what == "shape") { - if (tile_get_shape_count(id) > 0) { - for (int i = 0; i < tile_get_shape_count(id); i++) { - tile_set_shape(id, i, p_value); - } - } else { - tile_set_shape(id, 0, p_value); - } - } else if (what == "shape_offset") { - if (tile_get_shape_count(id) > 0) { - for (int i = 0; i < tile_get_shape_count(id); i++) { - tile_set_shape_offset(id, i, p_value); - } - } else { - tile_set_shape_offset(id, 0, p_value); - } - } else if (what == "shape_transform") { - if (tile_get_shape_count(id) > 0) { - for (int i = 0; i < tile_get_shape_count(id); i++) { - tile_set_shape_transform(id, i, p_value); - } - } else { - tile_set_shape_transform(id, 0, p_value); - } - } else if (what == "shape_one_way") { - if (tile_get_shape_count(id) > 0) { - for (int i = 0; i < tile_get_shape_count(id); i++) { - tile_set_shape_one_way(id, i, p_value); - } - } else { - tile_set_shape_one_way(id, 0, p_value); - } - } else if (what == "shape_one_way_margin") { - if (tile_get_shape_count(id) > 0) { - for (int i = 0; i < tile_get_shape_count(id); i++) { - tile_set_shape_one_way_margin(id, i, p_value); - } - } else { - tile_set_shape_one_way_margin(id, 0, p_value); - } - } else if (what == "shapes") { - _tile_set_shapes(id, p_value); - } else if (what == "occluder") { - tile_set_light_occluder(id, p_value); - } else if (what == "occluder_offset") { - tile_set_occluder_offset(id, p_value); - } else if (what == "navigation") { - tile_set_navigation_polygon(id, p_value); - } else if (what == "navigation_offset") { - tile_set_navigation_polygon_offset(id, p_value); - } else if (what == "z_index") { - tile_set_z_index(id, p_value); - } else { - return false; - } - - return true; -} - -bool TileSet::_get(const StringName &p_name, Variant &r_ret) const { - String n = p_name; - int slash = n.find("/"); - if (slash == -1) { - return false; - } - int id = String::to_int(n.c_str(), slash); - - ERR_FAIL_COND_V(!tile_map.has(id), false); - - String what = n.substr(slash + 1, n.length()); - - if (what == "name") { - r_ret = tile_get_name(id); - } else if (what == "texture") { - r_ret = tile_get_texture(id); - } else if (what == "normal_map") { - r_ret = tile_get_normal_map(id); - } else if (what == "tex_offset") { - r_ret = tile_get_texture_offset(id); - } else if (what == "material") { - r_ret = tile_get_material(id); - } else if (what == "modulate") { - r_ret = tile_get_modulate(id); - } else if (what == "region") { - r_ret = tile_get_region(id); - } else if (what == "tile_mode") { - r_ret = tile_get_tile_mode(id); - } else if (what.left(9) == "autotile/") { - what = what.right(9); - if (what == "bitmask_mode") { - r_ret = autotile_get_bitmask_mode(id); - } else if (what == "icon_coordinate") { - r_ret = autotile_get_icon_coordinate(id); - } else if (what == "tile_size") { - r_ret = autotile_get_size(id); - } else if (what == "spacing") { - r_ret = autotile_get_spacing(id); - } else if (what == "bitmask_flags") { - Array p; - for (Map::Element *E = tile_map[id].autotile_data.flags.front(); E; E = E->next()) { - p.push_back(E->key()); - p.push_back(E->value()); - } - r_ret = p; - } else if (what == "occluder_map") { - Array p; - for (Map>::Element *E = tile_map[id].autotile_data.occluder_map.front(); E; E = E->next()) { - p.push_back(E->key()); - p.push_back(E->value()); - } - r_ret = p; - } else if (what == "navpoly_map") { - Array p; - for (Map>::Element *E = tile_map[id].autotile_data.navpoly_map.front(); E; E = E->next()) { - p.push_back(E->key()); - p.push_back(E->value()); - } - r_ret = p; - } else if (what == "priority_map") { - Array p; - Vector3 v; - for (Map::Element *E = tile_map[id].autotile_data.priority_map.front(); E; E = E->next()) { - if (E->value() > 1) { - //Don't save default value - v.x = E->key().x; - v.y = E->key().y; - v.z = E->value(); - p.push_back(v); - } - } - r_ret = p; - } else if (what == "z_index_map") { - Array p; - Vector3 v; - for (Map::Element *E = tile_map[id].autotile_data.z_index_map.front(); E; E = E->next()) { - if (E->value() != 0) { - //Don't save default value - v.x = E->key().x; - v.y = E->key().y; - v.z = E->value(); - p.push_back(v); - } - } - r_ret = p; - } - } else if (what == "shape") { - r_ret = tile_get_shape(id, 0); - } else if (what == "shape_offset") { - r_ret = tile_get_shape_offset(id, 0); - } else if (what == "shape_transform") { - r_ret = tile_get_shape_transform(id, 0); - } else if (what == "shape_one_way") { - r_ret = tile_get_shape_one_way(id, 0); - } else if (what == "shape_one_way_margin") { - r_ret = tile_get_shape_one_way_margin(id, 0); - } else if (what == "shapes") { - r_ret = _tile_get_shapes(id); - } else if (what == "occluder") { - r_ret = tile_get_light_occluder(id); - } else if (what == "occluder_offset") { - r_ret = tile_get_occluder_offset(id); - } else if (what == "navigation") { - r_ret = tile_get_navigation_polygon(id); - } else if (what == "navigation_offset") { - r_ret = tile_get_navigation_polygon_offset(id); - } else if (what == "z_index") { - r_ret = tile_get_z_index(id); - } else { - return false; - } - - return true; -} - -void TileSet::_get_property_list(List *p_list) const { - for (Map::Element *E = tile_map.front(); E; E = E->next()) { - int id = E->key(); - String pre = itos(id) + "/"; - p_list->push_back(PropertyInfo(Variant::STRING, pre + "name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); - p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture", PROPERTY_USAGE_NOEDITOR)); - p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture", PROPERTY_USAGE_NOEDITOR)); - p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "tex_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); - p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial", PROPERTY_USAGE_NOEDITOR)); - p_list->push_back(PropertyInfo(Variant::COLOR, pre + "modulate", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); - p_list->push_back(PropertyInfo(Variant::RECT2, pre + "region", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); - p_list->push_back(PropertyInfo(Variant::INT, pre + "tile_mode", PROPERTY_HINT_ENUM, "SINGLE_TILE,AUTO_TILE,ATLAS_TILE", PROPERTY_USAGE_NOEDITOR)); - if (tile_get_tile_mode(id) == AUTO_TILE) { - p_list->push_back(PropertyInfo(Variant::INT, pre + "autotile/bitmask_mode", PROPERTY_HINT_ENUM, "2X2,3X3 (minimal),3X3", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); - p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/bitmask_flags", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); - p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "autotile/icon_coordinate", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); - p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "autotile/tile_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); - p_list->push_back(PropertyInfo(Variant::INT, pre + "autotile/spacing", PROPERTY_HINT_RANGE, "0,256,1", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); - p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/occluder_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); - p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/navpoly_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); - p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/priority_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); - p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/z_index_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); - } else if (tile_get_tile_mode(id) == ATLAS_TILE) { - p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "autotile/icon_coordinate", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); - p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "autotile/tile_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); - p_list->push_back(PropertyInfo(Variant::INT, pre + "autotile/spacing", PROPERTY_HINT_RANGE, "0,256,1", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); - p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/occluder_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); - p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/navpoly_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); - p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/priority_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); - p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/z_index_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); - } - p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "occluder_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); - p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "occluder", PROPERTY_HINT_RESOURCE_TYPE, "OccluderPolygon2D", PROPERTY_USAGE_NOEDITOR)); - p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "navigation_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); - p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "navigation", PROPERTY_HINT_RESOURCE_TYPE, "NavigationPolygon", PROPERTY_USAGE_NOEDITOR)); - p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "shape_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); - p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "shape_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); - p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D", PROPERTY_USAGE_NOEDITOR)); - p_list->push_back(PropertyInfo(Variant::BOOL, pre + "shape_one_way", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); - p_list->push_back(PropertyInfo(Variant::REAL, pre + "shape_one_way_margin", PROPERTY_HINT_RANGE, "0,128,0.01", PROPERTY_USAGE_NOEDITOR)); - p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "shapes", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); - p_list->push_back(PropertyInfo(Variant::INT, pre + "z_index", PROPERTY_HINT_RANGE, itos(VS::CANVAS_ITEM_Z_MIN) + "," + itos(VS::CANVAS_ITEM_Z_MAX) + ",1", PROPERTY_USAGE_NOEDITOR)); - } -} - -void TileSet::create_tile(int p_id) { - ERR_FAIL_COND_MSG(tile_map.has(p_id), vformat("The TileSet already has a tile with ID '%d'.", p_id)); - tile_map[p_id] = TileData(); - tile_map[p_id].autotile_data = AutotileData(); - _change_notify(""); - emit_changed(); -} - -void TileSet::autotile_set_bitmask_mode(int p_id, BitmaskMode p_mode) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - tile_map[p_id].autotile_data.bitmask_mode = p_mode; - _change_notify(""); - emit_changed(); -} - -TileSet::BitmaskMode TileSet::autotile_get_bitmask_mode(int p_id) const { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), BITMASK_2X2, vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - return tile_map[p_id].autotile_data.bitmask_mode; -} - -void TileSet::tile_set_texture(int p_id, const Ref &p_texture) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - tile_map[p_id].texture = p_texture; - emit_changed(); - _change_notify("texture"); -} - -Ref TileSet::tile_get_texture(int p_id) const { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), Ref(), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - return tile_map[p_id].texture; -} - -void TileSet::tile_set_normal_map(int p_id, const Ref &p_normal_map) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - tile_map[p_id].normal_map = p_normal_map; - emit_changed(); -} - -Ref TileSet::tile_get_normal_map(int p_id) const { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), Ref(), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - return tile_map[p_id].normal_map; -} - -void TileSet::tile_set_material(int p_id, const Ref &p_material) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - tile_map[p_id].material = p_material; - emit_changed(); -} - -Ref TileSet::tile_get_material(int p_id) const { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), Ref(), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - return tile_map[p_id].material; -} - -void TileSet::tile_set_modulate(int p_id, const Color &p_modulate) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - tile_map[p_id].modulate = p_modulate; - emit_changed(); - _change_notify("modulate"); -} - -Color TileSet::tile_get_modulate(int p_id) const { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), Color(1, 1, 1), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - return tile_map[p_id].modulate; -} - -void TileSet::tile_set_texture_offset(int p_id, const Vector2 &p_offset) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - tile_map[p_id].offset = p_offset; - emit_changed(); -} - -Vector2 TileSet::tile_get_texture_offset(int p_id) const { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), Vector2(), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - return tile_map[p_id].offset; -} - -void TileSet::tile_set_region(int p_id, const Rect2 &p_region) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - tile_map[p_id].region = p_region; - emit_changed(); - _change_notify("region"); -} - -Rect2 TileSet::tile_get_region(int p_id) const { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), Rect2(), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - return tile_map[p_id].region; -} - -void TileSet::tile_set_tile_mode(int p_id, TileMode p_tile_mode) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - tile_map[p_id].tile_mode = p_tile_mode; - emit_changed(); - _change_notify("tile_mode"); -} - -TileSet::TileMode TileSet::tile_get_tile_mode(int p_id) const { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), SINGLE_TILE, vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - return tile_map[p_id].tile_mode; -} - -void TileSet::autotile_set_icon_coordinate(int p_id, Vector2 coord) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - tile_map[p_id].autotile_data.icon_coord = coord; - emit_changed(); -} - -Vector2 TileSet::autotile_get_icon_coordinate(int p_id) const { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), Vector2(), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - return tile_map[p_id].autotile_data.icon_coord; -} - -void TileSet::autotile_set_spacing(int p_id, int p_spacing) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - ERR_FAIL_COND(p_spacing < 0); - tile_map[p_id].autotile_data.spacing = p_spacing; - emit_changed(); -} - -int TileSet::autotile_get_spacing(int p_id) const { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), 0, vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - return tile_map[p_id].autotile_data.spacing; -} - -void TileSet::autotile_set_size(int p_id, Size2 p_size) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - ERR_FAIL_COND(p_size.x <= 0 || p_size.y <= 0); - tile_map[p_id].autotile_data.size = p_size; -} - -Size2 TileSet::autotile_get_size(int p_id) const { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), Size2(), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - return tile_map[p_id].autotile_data.size; -} - -void TileSet::autotile_clear_bitmask_map(int p_id) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - tile_map[p_id].autotile_data.flags.clear(); -} - -void TileSet::autotile_set_subtile_priority(int p_id, const Vector2 &p_coord, int p_priority) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - ERR_FAIL_COND(p_priority <= 0); - tile_map[p_id].autotile_data.priority_map[p_coord] = p_priority; -} - -int TileSet::autotile_get_subtile_priority(int p_id, const Vector2 &p_coord) { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), 1, vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - if (tile_map[p_id].autotile_data.priority_map.has(p_coord)) { - return tile_map[p_id].autotile_data.priority_map[p_coord]; - } - //When not custom priority set return the default value - return 1; -} - -const Map &TileSet::autotile_get_priority_map(int p_id) const { - static Map dummy; - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), dummy, vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - return tile_map[p_id].autotile_data.priority_map; -} - -void TileSet::autotile_set_z_index(int p_id, const Vector2 &p_coord, int p_z_index) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - tile_map[p_id].autotile_data.z_index_map[p_coord] = p_z_index; - emit_changed(); -} - -int TileSet::autotile_get_z_index(int p_id, const Vector2 &p_coord) { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), 1, vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - if (tile_map[p_id].autotile_data.z_index_map.has(p_coord)) { - return tile_map[p_id].autotile_data.z_index_map[p_coord]; - } - //When not custom z index set return the default value - return 0; -} - -const Map &TileSet::autotile_get_z_index_map(int p_id) const { - static Map dummy; - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), dummy, vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - return tile_map[p_id].autotile_data.z_index_map; -} - -void TileSet::autotile_set_bitmask(int p_id, Vector2 p_coord, uint32_t p_flag) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - if (p_flag == 0) { - if (tile_map[p_id].autotile_data.flags.has(p_coord)) { - tile_map[p_id].autotile_data.flags.erase(p_coord); - } - } else { - tile_map[p_id].autotile_data.flags[p_coord] = p_flag; - } -} - -uint32_t TileSet::autotile_get_bitmask(int p_id, Vector2 p_coord) { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), 0, vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - if (!tile_map[p_id].autotile_data.flags.has(p_coord)) { - return 0; - } - return tile_map[p_id].autotile_data.flags[p_coord]; -} - -const Map &TileSet::autotile_get_bitmask_map(int p_id) { - static Map dummy; - static Map dummy_atlas; - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), dummy, vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - if (tile_get_tile_mode(p_id) == ATLAS_TILE) { - dummy_atlas = Map(); - Rect2 region = tile_get_region(p_id); - Size2 size = autotile_get_size(p_id); - float spacing = autotile_get_spacing(p_id); - for (int x = 0; x < (region.size.x / (size.x + spacing)); x++) { - for (int y = 0; y < (region.size.y / (size.y + spacing)); y++) { - dummy_atlas.insert(Vector2(x, y), 0); - } - } - return dummy_atlas; - } else { - return tile_map[p_id].autotile_data.flags; - } -} - -Vector2 TileSet::autotile_get_subtile_for_bitmask(int p_id, uint16_t p_bitmask, const Node *p_tilemap_node, const Vector2 &p_tile_location) { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), Vector2(), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - //First try to forward selection to script - if (p_tilemap_node->get_class_name() == "TileMap") { - if (get_script_instance() != nullptr) { - if (get_script_instance()->has_method("_forward_subtile_selection")) { - Variant ret = get_script_instance()->call("_forward_subtile_selection", p_id, p_bitmask, p_tilemap_node, p_tile_location); - if (ret.get_type() == Variant::VECTOR2) { - return ret; - } - } - } - } - - List coords; - List priorities; - uint32_t priority_sum = 0; - uint32_t mask; - uint16_t mask_; - uint16_t mask_ignore; - for (Map::Element *E = tile_map[p_id].autotile_data.flags.front(); E; E = E->next()) { - mask = E->get(); - if (tile_map[p_id].autotile_data.bitmask_mode == BITMASK_2X2) { - mask |= (BIND_IGNORE_TOP | BIND_IGNORE_LEFT | BIND_IGNORE_CENTER | BIND_IGNORE_RIGHT | BIND_IGNORE_BOTTOM); - } - - mask_ = mask & 0xFFFF; - mask_ignore = mask >> 16; - - if (((mask_ & (~mask_ignore)) == (p_bitmask & (~mask_ignore))) && (((~mask_) | mask_ignore) == ((~p_bitmask) | mask_ignore))) { - uint32_t priority = autotile_get_subtile_priority(p_id, E->key()); - priority_sum += priority; - priorities.push_back(priority); - coords.push_back(E->key()); - } - } - - if (coords.size() == 0) { - return autotile_get_icon_coordinate(p_id); - } else { - uint32_t picked_value = Math::rand() % priority_sum; - uint32_t upper_bound; - uint32_t lower_bound = 0; - Vector2 result = coords.front()->get(); - List::Element *coords_E = coords.front(); - List::Element *priorities_E = priorities.front(); - while (priorities_E) { - upper_bound = lower_bound + priorities_E->get(); - if (lower_bound <= picked_value && picked_value < upper_bound) { - result = coords_E->get(); - break; - } - lower_bound = upper_bound; - priorities_E = priorities_E->next(); - coords_E = coords_E->next(); - } - - return result; - } -} - -Vector2 TileSet::atlastile_get_subtile_by_priority(int p_id, const Node *p_tilemap_node, const Vector2 &p_tile_location) { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), Vector2(), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - //First try to forward selection to script - if (get_script_instance() != nullptr) { - if (get_script_instance()->has_method("_forward_atlas_subtile_selection")) { - Variant ret = get_script_instance()->call("_forward_atlas_subtile_selection", p_id, p_tilemap_node, p_tile_location); - if (ret.get_type() == Variant::VECTOR2) { - return ret; - } - } - } - - const Vector2 spacing(autotile_get_spacing(p_id), autotile_get_spacing(p_id)); - const Vector2 coord = tile_get_region(p_id).size / (autotile_get_size(p_id) + spacing); - - List coords; - for (int x = 0; x < coord.x; x++) { - for (int y = 0; y < coord.y; y++) { - for (int i = 0; i < autotile_get_subtile_priority(p_id, Vector2(x, y)); i++) { - coords.push_back(Vector2(x, y)); - } - } - } - if (coords.size() == 0) { - return autotile_get_icon_coordinate(p_id); - } else { - return coords[Math::random(0, (int)coords.size())]; - } -} - -void TileSet::tile_set_name(int p_id, const String &p_name) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - tile_map[p_id].name = p_name; - emit_changed(); - _change_notify("name"); -} - -String TileSet::tile_get_name(int p_id) const { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), String(), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - return tile_map[p_id].name; -} - -void TileSet::tile_clear_shapes(int p_id) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - tile_map[p_id].shapes_data.clear(); -} - -void TileSet::tile_add_shape(int p_id, const Ref &p_shape, const Transform2D &p_transform, bool p_one_way, const Vector2 &p_autotile_coord) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - - ShapeData new_data = ShapeData(); - new_data.shape = p_shape; - new_data.shape_transform = p_transform; - new_data.one_way_collision = p_one_way; - new_data.autotile_coord = p_autotile_coord; - - tile_map[p_id].shapes_data.push_back(new_data); -} - -int TileSet::tile_get_shape_count(int p_id) const { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), 0, vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - return tile_map[p_id].shapes_data.size(); -} - -void TileSet::tile_set_shape(int p_id, int p_shape_id, const Ref &p_shape) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - ERR_FAIL_COND(p_shape_id < 0); - - if (p_shape_id >= tile_map[p_id].shapes_data.size()) { - tile_map[p_id].shapes_data.resize(p_shape_id + 1); - } - tile_map[p_id].shapes_data.write[p_shape_id].shape = p_shape; - _decompose_convex_shape(p_shape); - emit_changed(); -} - -Ref TileSet::tile_get_shape(int p_id, int p_shape_id) const { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), Ref(), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - ERR_FAIL_COND_V(p_shape_id < 0, Ref()); - - if (p_shape_id < tile_map[p_id].shapes_data.size()) { - return tile_map[p_id].shapes_data[p_shape_id].shape; - } - - return Ref(); -} - -void TileSet::tile_set_shape_transform(int p_id, int p_shape_id, const Transform2D &p_offset) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - ERR_FAIL_COND(p_shape_id < 0); - - if (p_shape_id >= tile_map[p_id].shapes_data.size()) { - tile_map[p_id].shapes_data.resize(p_shape_id + 1); - } - tile_map[p_id].shapes_data.write[p_shape_id].shape_transform = p_offset; - emit_changed(); -} - -Transform2D TileSet::tile_get_shape_transform(int p_id, int p_shape_id) const { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), Transform2D(), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - ERR_FAIL_COND_V(p_shape_id < 0, Transform2D()); - - if (p_shape_id < tile_map[p_id].shapes_data.size()) { - return tile_map[p_id].shapes_data[p_shape_id].shape_transform; - } - - return Transform2D(); -} - -void TileSet::tile_set_shape_offset(int p_id, int p_shape_id, const Vector2 &p_offset) { - Transform2D transform = tile_get_shape_transform(p_id, p_shape_id); - transform.set_origin(p_offset); - tile_set_shape_transform(p_id, p_shape_id, transform); -} - -Vector2 TileSet::tile_get_shape_offset(int p_id, int p_shape_id) const { - return tile_get_shape_transform(p_id, p_shape_id).get_origin(); -} - -void TileSet::tile_set_shape_one_way(int p_id, int p_shape_id, const bool p_one_way) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - ERR_FAIL_COND(p_shape_id < 0); - - if (p_shape_id >= tile_map[p_id].shapes_data.size()) { - tile_map[p_id].shapes_data.resize(p_shape_id + 1); - } - tile_map[p_id].shapes_data.write[p_shape_id].one_way_collision = p_one_way; - emit_changed(); -} - -bool TileSet::tile_get_shape_one_way(int p_id, int p_shape_id) const { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), false, vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - ERR_FAIL_COND_V(p_shape_id < 0, false); - - if (p_shape_id < tile_map[p_id].shapes_data.size()) { - return tile_map[p_id].shapes_data[p_shape_id].one_way_collision; - } - - return false; -} - -void TileSet::tile_set_shape_one_way_margin(int p_id, int p_shape_id, float p_margin) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - ERR_FAIL_COND(p_shape_id < 0); - - if (p_shape_id >= tile_map[p_id].shapes_data.size()) { - tile_map[p_id].shapes_data.resize(p_shape_id + 1); - } - tile_map[p_id].shapes_data.write[p_shape_id].one_way_collision_margin = p_margin; - emit_changed(); -} - -float TileSet::tile_get_shape_one_way_margin(int p_id, int p_shape_id) const { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), 0, vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - ERR_FAIL_COND_V(p_shape_id < 0, 0); - - if (p_shape_id < tile_map[p_id].shapes_data.size()) { - return tile_map[p_id].shapes_data[p_shape_id].one_way_collision_margin; - } - - return 0; -} - -void TileSet::tile_set_light_occluder(int p_id, const Ref &p_light_occluder) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - tile_map[p_id].occluder = p_light_occluder; -} - -Ref TileSet::tile_get_light_occluder(int p_id) const { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), Ref(), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - return tile_map[p_id].occluder; -} - -void TileSet::autotile_set_light_occluder(int p_id, const Ref &p_light_occluder, const Vector2 &p_coord) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - if (p_light_occluder.is_null()) { - if (tile_map[p_id].autotile_data.occluder_map.has(p_coord)) { - tile_map[p_id].autotile_data.occluder_map.erase(p_coord); - } - } else { - tile_map[p_id].autotile_data.occluder_map[p_coord] = p_light_occluder; - } -} - -Ref TileSet::autotile_get_light_occluder(int p_id, const Vector2 &p_coord) const { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), Ref(), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - - if (!tile_map[p_id].autotile_data.occluder_map.has(p_coord)) { - return Ref(); - } else { - return tile_map[p_id].autotile_data.occluder_map[p_coord]; - } -} - -void TileSet::tile_set_navigation_polygon_offset(int p_id, const Vector2 &p_offset) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - tile_map[p_id].navigation_polygon_offset = p_offset; -} - -Vector2 TileSet::tile_get_navigation_polygon_offset(int p_id) const { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), Vector2(), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - return tile_map[p_id].navigation_polygon_offset; -} - -void TileSet::tile_set_navigation_polygon(int p_id, const Ref &p_navigation_polygon) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - tile_map[p_id].navigation_polygon = p_navigation_polygon; -} - -Ref TileSet::tile_get_navigation_polygon(int p_id) const { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), Ref(), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - return tile_map[p_id].navigation_polygon; -} - -const Map> &TileSet::autotile_get_light_oclusion_map(int p_id) const { - static Map> dummy; - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), dummy, vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - return tile_map[p_id].autotile_data.occluder_map; -} - -void TileSet::autotile_set_navigation_polygon(int p_id, const Ref &p_navigation_polygon, const Vector2 &p_coord) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - if (p_navigation_polygon.is_null()) { - if (tile_map[p_id].autotile_data.navpoly_map.has(p_coord)) { - tile_map[p_id].autotile_data.navpoly_map.erase(p_coord); - } - } else { - tile_map[p_id].autotile_data.navpoly_map[p_coord] = p_navigation_polygon; - } -} - -Ref TileSet::autotile_get_navigation_polygon(int p_id, const Vector2 &p_coord) const { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), Ref(), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - if (!tile_map[p_id].autotile_data.navpoly_map.has(p_coord)) { - return Ref(); - } else { - return tile_map[p_id].autotile_data.navpoly_map[p_coord]; - } -} - -const Map> &TileSet::autotile_get_navigation_map(int p_id) const { - static Map> dummy; - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), dummy, vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - return tile_map[p_id].autotile_data.navpoly_map; -} - -void TileSet::tile_set_occluder_offset(int p_id, const Vector2 &p_offset) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - tile_map[p_id].occluder_offset = p_offset; -} - -Vector2 TileSet::tile_get_occluder_offset(int p_id) const { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), Vector2(), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - return tile_map[p_id].occluder_offset; -} - -void TileSet::tile_set_shapes(int p_id, const Vector &p_shapes) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - tile_map[p_id].shapes_data = p_shapes; - for (int i = 0; i < p_shapes.size(); i++) { - _decompose_convex_shape(p_shapes[i].shape); - } - emit_changed(); -} - -Vector TileSet::tile_get_shapes(int p_id) const { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), Vector(), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - - return tile_map[p_id].shapes_data; -} - -int TileSet::tile_get_z_index(int p_id) const { - ERR_FAIL_COND_V_MSG(!tile_map.has(p_id), 0, vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - return tile_map[p_id].z_index; -} - -void TileSet::tile_set_z_index(int p_id, int p_z_index) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - tile_map[p_id].z_index = p_z_index; - emit_changed(); -} - -void TileSet::_tile_set_shapes(int p_id, const Array &p_shapes) { - ERR_FAIL_COND(!tile_map.has(p_id)); - Vector shapes_data; - Transform2D default_transform = tile_get_shape_transform(p_id, 0); - bool default_one_way = tile_get_shape_one_way(p_id, 0); - Vector2 default_autotile_coord = Vector2(); - for (int i = 0; i < p_shapes.size(); i++) { - ShapeData s = ShapeData(); - - if (p_shapes[i].get_type() == Variant::OBJECT) { - Ref shape = p_shapes[i]; - if (shape.is_null()) { - continue; - } - - s.shape = shape; - s.shape_transform = default_transform; - s.one_way_collision = default_one_way; - s.autotile_coord = default_autotile_coord; - } else if (p_shapes[i].get_type() == Variant::DICTIONARY) { - Dictionary d = p_shapes[i]; - - if (d.has("shape") && d["shape"].get_type() == Variant::OBJECT) { - s.shape = d["shape"]; - _decompose_convex_shape(s.shape); - } else { - continue; - } - - if (d.has("shape_transform") && d["shape_transform"].get_type() == Variant::TRANSFORM2D) { - s.shape_transform = d["shape_transform"]; - } else if (d.has("shape_offset") && d["shape_offset"].get_type() == Variant::VECTOR2) { - s.shape_transform = Transform2D(0, (Vector2)d["shape_offset"]); - } else { - s.shape_transform = default_transform; - } - - if (d.has("one_way") && d["one_way"].get_type() == Variant::BOOL) { - s.one_way_collision = d["one_way"]; - } else { - s.one_way_collision = default_one_way; - } - - if (d.has("one_way_margin") && d["one_way_margin"].is_num()) { - s.one_way_collision_margin = d["one_way_margin"]; - } else { - s.one_way_collision_margin = 1.0; - } - - if (d.has("autotile_coord") && d["autotile_coord"].get_type() == Variant::VECTOR2) { - s.autotile_coord = d["autotile_coord"]; - } else { - s.autotile_coord = default_autotile_coord; - } - - } else { - ERR_CONTINUE_MSG(true, "Expected an array of objects or dictionaries for tile_set_shapes."); - } - - shapes_data.push_back(s); - } - - tile_map[p_id].shapes_data = shapes_data; - emit_changed(); -} - -Array TileSet::_tile_get_shapes(int p_id) const { - ERR_FAIL_COND_V(!tile_map.has(p_id), Array()); - Array arr; - - Vector data = tile_map[p_id].shapes_data; - for (int i = 0; i < data.size(); i++) { - Dictionary shape_data; - shape_data["shape"] = data[i].shape; - shape_data["shape_transform"] = data[i].shape_transform; - shape_data["one_way"] = data[i].one_way_collision; - shape_data["one_way_margin"] = data[i].one_way_collision_margin; - shape_data["autotile_coord"] = data[i].autotile_coord; - arr.push_back(shape_data); - } - - return arr; -} - -Array TileSet::_get_tiles_ids() const { - Array arr; - - for (Map::Element *E = tile_map.front(); E; E = E->next()) { - arr.push_back(E->key()); - } - - return arr; -} - -void TileSet::_decompose_convex_shape(Ref p_shape) { - if (Engine::get_singleton()->is_editor_hint()) { - return; - } - Ref convex = p_shape; - if (!convex.is_valid()) { - return; - } - Vector> decomp = Geometry::decompose_polygon_in_convex(convex->get_points()); - if (decomp.size() > 1) { - Array sub_shapes; - for (int i = 0; i < decomp.size(); i++) { - Ref _convex = memnew(ConvexPolygonShape2D); - _convex->set_points(decomp[i]); - sub_shapes.append(_convex); - } - convex->set_meta("decomposed", sub_shapes); - } else { - convex->set_meta("decomposed", Variant()); - } -} - -void TileSet::get_tile_list(List *p_tiles) const { - for (Map::Element *E = tile_map.front(); E; E = E->next()) { - p_tiles->push_back(E->key()); - } -} - -bool TileSet::has_tile(int p_id) const { - return tile_map.has(p_id); -} - -bool TileSet::is_tile_bound(int p_drawn_id, int p_neighbor_id) { - if (p_drawn_id == p_neighbor_id) { - return true; - } else if (get_script_instance() != nullptr) { - if (get_script_instance()->has_method("_is_tile_bound")) { - Variant ret = get_script_instance()->call("_is_tile_bound", p_drawn_id, p_neighbor_id); - if (ret.get_type() == Variant::BOOL) { - return ret; - } - } - } - return false; -} - -void TileSet::remove_tile(int p_id) { - ERR_FAIL_COND_MSG(!tile_map.has(p_id), vformat("The TileSet doesn't have a tile with ID '%d'.", p_id)); - tile_map.erase(p_id); - _change_notify(""); - emit_changed(); -} - -int TileSet::get_last_unused_tile_id() const { - if (tile_map.size()) { - return tile_map.back()->key() + 1; - } else { - return 0; - } -} - -int TileSet::find_tile_by_name(const String &p_name) const { - for (Map::Element *E = tile_map.front(); E; E = E->next()) { - if (p_name == E->get().name) { - return E->key(); - } - } - return -1; -} - -void TileSet::clear() { - tile_map.clear(); - _change_notify(""); - emit_changed(); -} - -void TileSet::_bind_methods() { - ClassDB::bind_method(D_METHOD("create_tile", "id"), &TileSet::create_tile); - ClassDB::bind_method(D_METHOD("autotile_clear_bitmask_map", "id"), &TileSet::autotile_clear_bitmask_map); - ClassDB::bind_method(D_METHOD("autotile_set_icon_coordinate", "id", "coord"), &TileSet::autotile_set_icon_coordinate); - ClassDB::bind_method(D_METHOD("autotile_get_icon_coordinate", "id"), &TileSet::autotile_get_icon_coordinate); - ClassDB::bind_method(D_METHOD("autotile_set_subtile_priority", "id", "coord", "priority"), &TileSet::autotile_set_subtile_priority); - ClassDB::bind_method(D_METHOD("autotile_get_subtile_priority", "id", "coord"), &TileSet::autotile_get_subtile_priority); - ClassDB::bind_method(D_METHOD("autotile_set_z_index", "id", "coord", "z_index"), &TileSet::autotile_set_z_index); - ClassDB::bind_method(D_METHOD("autotile_get_z_index", "id", "coord"), &TileSet::autotile_get_z_index); - ClassDB::bind_method(D_METHOD("autotile_set_light_occluder", "id", "light_occluder", "coord"), &TileSet::autotile_set_light_occluder); - ClassDB::bind_method(D_METHOD("autotile_get_light_occluder", "id", "coord"), &TileSet::autotile_get_light_occluder); - ClassDB::bind_method(D_METHOD("autotile_set_navigation_polygon", "id", "navigation_polygon", "coord"), &TileSet::autotile_set_navigation_polygon); - ClassDB::bind_method(D_METHOD("autotile_get_navigation_polygon", "id", "coord"), &TileSet::autotile_get_navigation_polygon); - ClassDB::bind_method(D_METHOD("autotile_set_bitmask", "id", "bitmask", "flag"), &TileSet::autotile_set_bitmask); - ClassDB::bind_method(D_METHOD("autotile_get_bitmask", "id", "coord"), &TileSet::autotile_get_bitmask); - ClassDB::bind_method(D_METHOD("autotile_set_bitmask_mode", "id", "mode"), &TileSet::autotile_set_bitmask_mode); - ClassDB::bind_method(D_METHOD("autotile_get_bitmask_mode", "id"), &TileSet::autotile_get_bitmask_mode); - ClassDB::bind_method(D_METHOD("autotile_set_spacing", "id", "spacing"), &TileSet::autotile_set_spacing); - ClassDB::bind_method(D_METHOD("autotile_get_spacing", "id"), &TileSet::autotile_get_spacing); - ClassDB::bind_method(D_METHOD("autotile_set_size", "id", "size"), &TileSet::autotile_set_size); - ClassDB::bind_method(D_METHOD("autotile_get_size", "id"), &TileSet::autotile_get_size); - ClassDB::bind_method(D_METHOD("tile_set_name", "id", "name"), &TileSet::tile_set_name); - ClassDB::bind_method(D_METHOD("tile_get_name", "id"), &TileSet::tile_get_name); - ClassDB::bind_method(D_METHOD("tile_set_texture", "id", "texture"), &TileSet::tile_set_texture); - ClassDB::bind_method(D_METHOD("tile_get_texture", "id"), &TileSet::tile_get_texture); - ClassDB::bind_method(D_METHOD("tile_set_normal_map", "id", "normal_map"), &TileSet::tile_set_normal_map); - ClassDB::bind_method(D_METHOD("tile_get_normal_map", "id"), &TileSet::tile_get_normal_map); - ClassDB::bind_method(D_METHOD("tile_set_material", "id", "material"), &TileSet::tile_set_material); - ClassDB::bind_method(D_METHOD("tile_get_material", "id"), &TileSet::tile_get_material); - ClassDB::bind_method(D_METHOD("tile_set_modulate", "id", "color"), &TileSet::tile_set_modulate); - ClassDB::bind_method(D_METHOD("tile_get_modulate", "id"), &TileSet::tile_get_modulate); - ClassDB::bind_method(D_METHOD("tile_set_texture_offset", "id", "texture_offset"), &TileSet::tile_set_texture_offset); - ClassDB::bind_method(D_METHOD("tile_get_texture_offset", "id"), &TileSet::tile_get_texture_offset); - ClassDB::bind_method(D_METHOD("tile_set_region", "id", "region"), &TileSet::tile_set_region); - ClassDB::bind_method(D_METHOD("tile_get_region", "id"), &TileSet::tile_get_region); - ClassDB::bind_method(D_METHOD("tile_set_shape", "id", "shape_id", "shape"), &TileSet::tile_set_shape); - ClassDB::bind_method(D_METHOD("tile_get_shape", "id", "shape_id"), &TileSet::tile_get_shape); - ClassDB::bind_method(D_METHOD("tile_set_shape_offset", "id", "shape_id", "shape_offset"), &TileSet::tile_set_shape_offset); - ClassDB::bind_method(D_METHOD("tile_get_shape_offset", "id", "shape_id"), &TileSet::tile_get_shape_offset); - ClassDB::bind_method(D_METHOD("tile_set_shape_transform", "id", "shape_id", "shape_transform"), &TileSet::tile_set_shape_transform); - ClassDB::bind_method(D_METHOD("tile_get_shape_transform", "id", "shape_id"), &TileSet::tile_get_shape_transform); - ClassDB::bind_method(D_METHOD("tile_set_shape_one_way", "id", "shape_id", "one_way"), &TileSet::tile_set_shape_one_way); - ClassDB::bind_method(D_METHOD("tile_get_shape_one_way", "id", "shape_id"), &TileSet::tile_get_shape_one_way); - ClassDB::bind_method(D_METHOD("tile_set_shape_one_way_margin", "id", "shape_id", "one_way"), &TileSet::tile_set_shape_one_way_margin); - ClassDB::bind_method(D_METHOD("tile_get_shape_one_way_margin", "id", "shape_id"), &TileSet::tile_get_shape_one_way_margin); - ClassDB::bind_method(D_METHOD("tile_add_shape", "id", "shape", "shape_transform", "one_way", "autotile_coord"), &TileSet::tile_add_shape, DEFVAL(false), DEFVAL(Vector2())); - ClassDB::bind_method(D_METHOD("tile_get_shape_count", "id"), &TileSet::tile_get_shape_count); - ClassDB::bind_method(D_METHOD("tile_set_shapes", "id", "shapes"), &TileSet::_tile_set_shapes); - ClassDB::bind_method(D_METHOD("tile_get_shapes", "id"), &TileSet::_tile_get_shapes); - ClassDB::bind_method(D_METHOD("tile_set_tile_mode", "id", "tilemode"), &TileSet::tile_set_tile_mode); - ClassDB::bind_method(D_METHOD("tile_get_tile_mode", "id"), &TileSet::tile_get_tile_mode); - ClassDB::bind_method(D_METHOD("tile_set_navigation_polygon", "id", "navigation_polygon"), &TileSet::tile_set_navigation_polygon); - ClassDB::bind_method(D_METHOD("tile_get_navigation_polygon", "id"), &TileSet::tile_get_navigation_polygon); - ClassDB::bind_method(D_METHOD("tile_set_navigation_polygon_offset", "id", "navigation_polygon_offset"), &TileSet::tile_set_navigation_polygon_offset); - ClassDB::bind_method(D_METHOD("tile_get_navigation_polygon_offset", "id"), &TileSet::tile_get_navigation_polygon_offset); - ClassDB::bind_method(D_METHOD("tile_set_light_occluder", "id", "light_occluder"), &TileSet::tile_set_light_occluder); - ClassDB::bind_method(D_METHOD("tile_get_light_occluder", "id"), &TileSet::tile_get_light_occluder); - ClassDB::bind_method(D_METHOD("tile_set_occluder_offset", "id", "occluder_offset"), &TileSet::tile_set_occluder_offset); - ClassDB::bind_method(D_METHOD("tile_get_occluder_offset", "id"), &TileSet::tile_get_occluder_offset); - ClassDB::bind_method(D_METHOD("tile_set_z_index", "id", "z_index"), &TileSet::tile_set_z_index); - ClassDB::bind_method(D_METHOD("tile_get_z_index", "id"), &TileSet::tile_get_z_index); - - ClassDB::bind_method(D_METHOD("remove_tile", "id"), &TileSet::remove_tile); - ClassDB::bind_method(D_METHOD("clear"), &TileSet::clear); - ClassDB::bind_method(D_METHOD("get_last_unused_tile_id"), &TileSet::get_last_unused_tile_id); - ClassDB::bind_method(D_METHOD("find_tile_by_name", "name"), &TileSet::find_tile_by_name); - ClassDB::bind_method(D_METHOD("get_tiles_ids"), &TileSet::_get_tiles_ids); - - BIND_VMETHOD(MethodInfo(Variant::BOOL, "_is_tile_bound", PropertyInfo(Variant::INT, "drawn_id"), PropertyInfo(Variant::INT, "neighbor_id"))); - BIND_VMETHOD(MethodInfo(Variant::VECTOR2, "_forward_subtile_selection", PropertyInfo(Variant::INT, "autotile_id"), PropertyInfo(Variant::INT, "bitmask"), PropertyInfo(Variant::OBJECT, "tilemap", PROPERTY_HINT_NONE, "TileMap"), PropertyInfo(Variant::VECTOR2, "tile_location"))); - BIND_VMETHOD(MethodInfo(Variant::VECTOR2, "_forward_atlas_subtile_selection", PropertyInfo(Variant::INT, "atlastile_id"), PropertyInfo(Variant::OBJECT, "tilemap", PROPERTY_HINT_NONE, "TileMap"), PropertyInfo(Variant::VECTOR2, "tile_location"))); - - BIND_ENUM_CONSTANT(BITMASK_2X2); - BIND_ENUM_CONSTANT(BITMASK_3X3_MINIMAL); - BIND_ENUM_CONSTANT(BITMASK_3X3); - - BIND_ENUM_CONSTANT(BIND_TOPLEFT); - BIND_ENUM_CONSTANT(BIND_TOP); - BIND_ENUM_CONSTANT(BIND_TOPRIGHT); - BIND_ENUM_CONSTANT(BIND_LEFT); - BIND_ENUM_CONSTANT(BIND_CENTER); - BIND_ENUM_CONSTANT(BIND_RIGHT); - BIND_ENUM_CONSTANT(BIND_BOTTOMLEFT); - BIND_ENUM_CONSTANT(BIND_BOTTOM); - BIND_ENUM_CONSTANT(BIND_BOTTOMRIGHT); - - BIND_ENUM_CONSTANT(SINGLE_TILE); - BIND_ENUM_CONSTANT(AUTO_TILE); - BIND_ENUM_CONSTANT(ATLAS_TILE); -} - -TileSet::TileSet() { -} diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h deleted file mode 100644 index 7d294b5f5..000000000 --- a/scene/resources/tile_set.h +++ /dev/null @@ -1,269 +0,0 @@ -/*************************************************************************/ -/* tile_set.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef TILE_SET_H -#define TILE_SET_H - -#include "core/array.h" -#include "core/resource.h" -#include "scene/2d/light_occluder_2d.h" -#include "scene/2d/navigation_polygon.h" -#include "scene/resources/convex_polygon_shape_2d.h" -#include "scene/resources/shape_2d.h" -#include "scene/resources/texture.h" - -class TileSet : public Resource { - GDCLASS(TileSet, Resource); - -public: - struct ShapeData { - Ref shape; - Transform2D shape_transform; - Vector2 autotile_coord; - bool one_way_collision; - float one_way_collision_margin; - - ShapeData() { - one_way_collision = false; - one_way_collision_margin = 1.0; - } - }; - - enum BitmaskMode { - BITMASK_2X2, - BITMASK_3X3_MINIMAL, - BITMASK_3X3 - }; - - enum AutotileBindings { - BIND_TOPLEFT = 1, - BIND_TOP = 2, - BIND_TOPRIGHT = 4, - BIND_LEFT = 8, - BIND_CENTER = 16, - BIND_RIGHT = 32, - BIND_BOTTOMLEFT = 64, - BIND_BOTTOM = 128, - BIND_BOTTOMRIGHT = 256, - - BIND_IGNORE_TOPLEFT = 1 << 16, - BIND_IGNORE_TOP = 1 << 17, - BIND_IGNORE_TOPRIGHT = 1 << 18, - BIND_IGNORE_LEFT = 1 << 19, - BIND_IGNORE_CENTER = 1 << 20, - BIND_IGNORE_RIGHT = 1 << 21, - BIND_IGNORE_BOTTOMLEFT = 1 << 22, - BIND_IGNORE_BOTTOM = 1 << 23, - BIND_IGNORE_BOTTOMRIGHT = 1 << 24 - }; - - enum TileMode { - SINGLE_TILE, - AUTO_TILE, - ATLAS_TILE - }; - - struct AutotileData { - BitmaskMode bitmask_mode; - Size2 size; - int spacing; - Vector2 icon_coord; - Map flags; - Map> occluder_map; - Map> navpoly_map; - Map priority_map; - Map z_index_map; - - // Default size to prevent invalid value - explicit AutotileData() : - bitmask_mode(BITMASK_2X2), - size(64, 64), - spacing(0), - icon_coord(0, 0) {} - }; - -private: - struct TileData { - String name; - Ref texture; - Ref normal_map; - Vector2 offset; - Rect2i region; - Vector shapes_data; - Vector2 occluder_offset; - Ref occluder; - Vector2 navigation_polygon_offset; - Ref navigation_polygon; - Ref material; - TileMode tile_mode; - Color modulate; - AutotileData autotile_data; - int z_index; - - // Default modulate for back-compat - explicit TileData() : - tile_mode(SINGLE_TILE), - modulate(1, 1, 1), - z_index(0) {} - }; - - Map tile_map; - -protected: - bool _set(const StringName &p_name, const Variant &p_value); - bool _get(const StringName &p_name, Variant &r_ret) const; - void _get_property_list(List *p_list) const; - void _tile_set_shapes(int p_id, const Array &p_shapes); - Array _tile_get_shapes(int p_id) const; - Array _get_tiles_ids() const; - void _decompose_convex_shape(Ref p_shape); - - static void _bind_methods(); - -public: - void create_tile(int p_id); - - void autotile_set_bitmask_mode(int p_id, BitmaskMode p_mode); - BitmaskMode autotile_get_bitmask_mode(int p_id) const; - - void tile_set_name(int p_id, const String &p_name); - String tile_get_name(int p_id) const; - - void tile_set_texture(int p_id, const Ref &p_texture); - Ref tile_get_texture(int p_id) const; - - void tile_set_normal_map(int p_id, const Ref &p_normal_map); - Ref tile_get_normal_map(int p_id) const; - - void tile_set_texture_offset(int p_id, const Vector2 &p_offset); - Vector2 tile_get_texture_offset(int p_id) const; - - void tile_set_region(int p_id, const Rect2 &p_region); - Rect2 tile_get_region(int p_id) const; - - void tile_set_tile_mode(int p_id, TileMode p_tile_mode); - TileMode tile_get_tile_mode(int p_id) const; - - void autotile_set_icon_coordinate(int p_id, Vector2 coord); - Vector2 autotile_get_icon_coordinate(int p_id) const; - - void autotile_set_spacing(int p_id, int p_spacing); - int autotile_get_spacing(int p_id) const; - - void autotile_set_size(int p_id, Size2 p_size); - Size2 autotile_get_size(int p_id) const; - - void autotile_clear_bitmask_map(int p_id); - void autotile_set_subtile_priority(int p_id, const Vector2 &p_coord, int p_priority); - int autotile_get_subtile_priority(int p_id, const Vector2 &p_coord); - const Map &autotile_get_priority_map(int p_id) const; - - void autotile_set_z_index(int p_id, const Vector2 &p_coord, int p_z_index); - int autotile_get_z_index(int p_id, const Vector2 &p_coord); - const Map &autotile_get_z_index_map(int p_id) const; - - void autotile_set_bitmask(int p_id, Vector2 p_coord, uint32_t p_flag); - uint32_t autotile_get_bitmask(int p_id, Vector2 p_coord); - const Map &autotile_get_bitmask_map(int p_id); - Vector2 autotile_get_subtile_for_bitmask(int p_id, uint16_t p_bitmask, const Node *p_tilemap_node = nullptr, const Vector2 &p_tile_location = Vector2()); - Vector2 atlastile_get_subtile_by_priority(int p_id, const Node *p_tilemap_node = nullptr, const Vector2 &p_tile_location = Vector2()); - - void tile_set_shape(int p_id, int p_shape_id, const Ref &p_shape); - Ref tile_get_shape(int p_id, int p_shape_id) const; - - void tile_set_shape_transform(int p_id, int p_shape_id, const Transform2D &p_offset); - Transform2D tile_get_shape_transform(int p_id, int p_shape_id) const; - - void tile_set_shape_offset(int p_id, int p_shape_id, const Vector2 &p_offset); - Vector2 tile_get_shape_offset(int p_id, int p_shape_id) const; - - void tile_set_shape_one_way(int p_id, int p_shape_id, bool p_one_way); - bool tile_get_shape_one_way(int p_id, int p_shape_id) const; - - void tile_set_shape_one_way_margin(int p_id, int p_shape_id, float p_margin); - float tile_get_shape_one_way_margin(int p_id, int p_shape_id) const; - - void tile_clear_shapes(int p_id); - void tile_add_shape(int p_id, const Ref &p_shape, const Transform2D &p_transform, bool p_one_way = false, const Vector2 &p_autotile_coord = Vector2()); - int tile_get_shape_count(int p_id) const; - - void tile_set_shapes(int p_id, const Vector &p_shapes); - Vector tile_get_shapes(int p_id) const; - - void tile_set_material(int p_id, const Ref &p_material); - Ref tile_get_material(int p_id) const; - - void tile_set_modulate(int p_id, const Color &p_modulate); - Color tile_get_modulate(int p_id) const; - - void tile_set_occluder_offset(int p_id, const Vector2 &p_offset); - Vector2 tile_get_occluder_offset(int p_id) const; - - void tile_set_light_occluder(int p_id, const Ref &p_light_occluder); - Ref tile_get_light_occluder(int p_id) const; - - void autotile_set_light_occluder(int p_id, const Ref &p_light_occluder, const Vector2 &p_coord); - Ref autotile_get_light_occluder(int p_id, const Vector2 &p_coord) const; - const Map> &autotile_get_light_oclusion_map(int p_id) const; - - void tile_set_navigation_polygon_offset(int p_id, const Vector2 &p_offset); - Vector2 tile_get_navigation_polygon_offset(int p_id) const; - - void tile_set_navigation_polygon(int p_id, const Ref &p_navigation_polygon); - Ref tile_get_navigation_polygon(int p_id) const; - - void autotile_set_navigation_polygon(int p_id, const Ref &p_navigation_polygon, const Vector2 &p_coord); - Ref autotile_get_navigation_polygon(int p_id, const Vector2 &p_coord) const; - const Map> &autotile_get_navigation_map(int p_id) const; - - void tile_set_z_index(int p_id, int p_z_index); - int tile_get_z_index(int p_id) const; - - void remove_tile(int p_id); - - bool has_tile(int p_id) const; - - bool is_tile_bound(int p_drawn_id, int p_neighbor_id); - - int find_tile_by_name(const String &p_name) const; - void get_tile_list(List *p_tiles) const; - - void clear(); - - int get_last_unused_tile_id() const; - - TileSet(); -}; - -VARIANT_ENUM_CAST(TileSet::AutotileBindings); -VARIANT_ENUM_CAST(TileSet::BitmaskMode); -VARIANT_ENUM_CAST(TileSet::TileMode); - -#endif // TILE_SET_H