Implement TileMap patterns palette
This commit is contained in:
parent
4387f9645b
commit
1a95f893c4
18 changed files with 1163 additions and 400 deletions
|
@ -763,10 +763,10 @@
|
||||||
</method>
|
</method>
|
||||||
<method name="set_drag_forwarding">
|
<method name="set_drag_forwarding">
|
||||||
<return type="void" />
|
<return type="void" />
|
||||||
<argument index="0" name="target" type="Node" />
|
<argument index="0" name="target" type="Object" />
|
||||||
<description>
|
<description>
|
||||||
Forwards the handling of this control's drag and drop to [code]target[/code] node.
|
Forwards the handling of this control's drag and drop to [code]target[/code] object.
|
||||||
Forwarding can be implemented in the target node similar to the methods [method _get_drag_data], [method _can_drop_data], and [method _drop_data] but with two differences:
|
Forwarding can be implemented in the target object similar to the methods [method _get_drag_data], [method _can_drop_data], and [method _drop_data] but with two differences:
|
||||||
1. The function name must be suffixed with [b]_fw[/b]
|
1. The function name must be suffixed with [b]_fw[/b]
|
||||||
2. The function must take an extra argument that is the control doing the forwarding
|
2. The function must take an extra argument that is the control doing the forwarding
|
||||||
[codeblocks]
|
[codeblocks]
|
||||||
|
|
|
@ -117,6 +117,14 @@
|
||||||
Returns the neighboring cell to the one at coordinates [code]coords[/code], indentified by the [code]neighbor[/code] direction. This method takes into account the different layouts a TileMap can take.
|
Returns the neighboring cell to the one at coordinates [code]coords[/code], indentified by the [code]neighbor[/code] direction. This method takes into account the different layouts a TileMap can take.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="get_pattern">
|
||||||
|
<return type="TileMapPattern" />
|
||||||
|
<argument index="0" name="layer" type="int" />
|
||||||
|
<argument index="1" name="coords_array" type="Vector2i[]" />
|
||||||
|
<description>
|
||||||
|
Creates a new [TileMapPattern] from the given layer and set of cells.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="get_surrounding_tiles">
|
<method name="get_surrounding_tiles">
|
||||||
<return type="Vector2i[]" />
|
<return type="Vector2i[]" />
|
||||||
<argument index="0" name="coords" type="Vector2i" />
|
<argument index="0" name="coords" type="Vector2i" />
|
||||||
|
@ -151,6 +159,15 @@
|
||||||
Returns if a layer Y-sorts its tiles.
|
Returns if a layer Y-sorts its tiles.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="map_pattern">
|
||||||
|
<return type="Vector2i" />
|
||||||
|
<argument index="0" name="position_in_tilemap" type="Vector2i" />
|
||||||
|
<argument index="1" name="coords_in_pattern" type="Vector2i" />
|
||||||
|
<argument index="2" name="pattern" type="TileMapPattern" />
|
||||||
|
<description>
|
||||||
|
Returns for the given coodinate [code]coords_in_pattern[/code] in a [TileMapPattern] the corresponding cell coordinates if the pattern was pasted at the [code]position_in_tilemap[/code] coordinates (see [method set_pattern]). This mapping is required as in half-offset tile shapes, the mapping might not work by calculating [code]position_in_tile_map + coords_in_pattern[/code]
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="map_to_world" qualifiers="const">
|
<method name="map_to_world" qualifiers="const">
|
||||||
<return type="Vector2" />
|
<return type="Vector2" />
|
||||||
<argument index="0" name="map_position" type="Vector2i" />
|
<argument index="0" name="map_position" type="Vector2i" />
|
||||||
|
@ -237,6 +254,15 @@
|
||||||
Sets a layers Z-index value. This Z-index is added to each tile's Z-index value.
|
Sets a layers Z-index value. This Z-index is added to each tile's Z-index value.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="set_pattern">
|
||||||
|
<return type="void" />
|
||||||
|
<argument index="0" name="layer" type="int" />
|
||||||
|
<argument index="1" name="position" type="Vector2i" />
|
||||||
|
<argument index="2" name="pattern" type="TileMapPattern" />
|
||||||
|
<description>
|
||||||
|
Paste the given [TileMapPattern] at the given [code]position[/code] and [code]layer[/code] in the tile map.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="world_to_map" qualifiers="const">
|
<method name="world_to_map" qualifiers="const">
|
||||||
<return type="Vector2i" />
|
<return type="Vector2i" />
|
||||||
<argument index="0" name="world_position" type="Vector2" />
|
<argument index="0" name="world_position" type="Vector2" />
|
||||||
|
|
85
doc/classes/TileMapPattern.xml
Normal file
85
doc/classes/TileMapPattern.xml
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<class name="TileMapPattern" inherits="Resource" version="4.0">
|
||||||
|
<brief_description>
|
||||||
|
Holds a pattern to be copied from or pasted into [TileMap]s.
|
||||||
|
</brief_description>
|
||||||
|
<description>
|
||||||
|
This resource holds a set of cells to help bulk manipulations of [TileMap].
|
||||||
|
A pattern always start at the [code](0,0)[/code] coordinates and cannot have cells with negative coordinates.
|
||||||
|
</description>
|
||||||
|
<tutorials>
|
||||||
|
</tutorials>
|
||||||
|
<methods>
|
||||||
|
<method name="get_cell_alternative_tile" qualifiers="const">
|
||||||
|
<return type="int" />
|
||||||
|
<argument index="0" name="coords" type="Vector2i" />
|
||||||
|
<description>
|
||||||
|
Returns the tile alternative ID of the cell at [code]coords[/code].
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="get_cell_atlas_coords" qualifiers="const">
|
||||||
|
<return type="Vector2i" />
|
||||||
|
<argument index="0" name="coords" type="Vector2i" />
|
||||||
|
<description>
|
||||||
|
Returns the tile atlas coordinates ID of the cell at [code]coords[/code].
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="get_cell_source_id" qualifiers="const">
|
||||||
|
<return type="int" />
|
||||||
|
<argument index="0" name="coords" type="Vector2i" />
|
||||||
|
<description>
|
||||||
|
Returns the tile source ID of the cell at [code]coords[/code].
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="get_size" qualifiers="const">
|
||||||
|
<return type="Vector2i" />
|
||||||
|
<description>
|
||||||
|
Returns the size, in cells, of the pattern.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="get_used_cells" qualifiers="const">
|
||||||
|
<return type="Vector2i[]" />
|
||||||
|
<description>
|
||||||
|
Returns the list of used cell coordinates in the pattern.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="has_cell" qualifiers="const">
|
||||||
|
<return type="bool" />
|
||||||
|
<argument index="0" name="coords" type="Vector2i" />
|
||||||
|
<description>
|
||||||
|
Returns whether the pattern has a tile at the given coordinates.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="is_empty" qualifiers="const">
|
||||||
|
<return type="bool" />
|
||||||
|
<description>
|
||||||
|
Returns whether the pattern is empty or not.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="remove_cell">
|
||||||
|
<return type="void" />
|
||||||
|
<argument index="0" name="coords" type="Vector2i" />
|
||||||
|
<argument index="1" name="arg1" type="bool" />
|
||||||
|
<description>
|
||||||
|
Remove the cell at the given coordinates.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="set_cell">
|
||||||
|
<return type="void" />
|
||||||
|
<argument index="0" name="coords" type="Vector2i" />
|
||||||
|
<argument index="1" name="source_id" type="int" default="-1" />
|
||||||
|
<argument index="2" name="atlas_coords" type="Vector2i" default="Vector2i(-1, -1)" />
|
||||||
|
<argument index="3" name="alternative_tile" type="int" default="-1" />
|
||||||
|
<description>
|
||||||
|
Sets the tile indentifiers for the cell at coordinates [code]coords[/code]. See [method TileMap.set_cell].
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="set_size">
|
||||||
|
<return type="void" />
|
||||||
|
<argument index="0" name="size" type="Vector2i" />
|
||||||
|
<description>
|
||||||
|
Sets the size of the pattern.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
</methods>
|
||||||
|
</class>
|
|
@ -46,6 +46,14 @@
|
||||||
Occlusion layers allow assigning occlusion polygons to atlas tiles.
|
Occlusion layers allow assigning occlusion polygons to atlas tiles.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="add_pattern">
|
||||||
|
<return type="int" />
|
||||||
|
<argument index="0" name="pattern" type="TileMapPattern" />
|
||||||
|
<argument index="1" name="index" type="int" default="-1" />
|
||||||
|
<description>
|
||||||
|
Adds a [TileMapPattern] to be stored in the TileSet resouce. If provided, insert it at the given [code]index[/code].
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="add_physics_layer">
|
<method name="add_physics_layer">
|
||||||
<return type="void" />
|
<return type="void" />
|
||||||
<argument index="0" name="to_position" type="int" default="-1" />
|
<argument index="0" name="to_position" type="int" default="-1" />
|
||||||
|
@ -154,6 +162,19 @@
|
||||||
Returns the occlusion layers count.
|
Returns the occlusion layers count.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="get_pattern">
|
||||||
|
<return type="TileMapPattern" />
|
||||||
|
<argument index="0" name="index" type="int" default="-1" />
|
||||||
|
<description>
|
||||||
|
Returns the [TileMapPattern] at the given [code]index[/code].
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="get_patterns_count">
|
||||||
|
<return type="int" />
|
||||||
|
<description>
|
||||||
|
Returns the number of [TileMapPattern] this tile set handles.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="get_physics_layer_collision_layer" qualifiers="const">
|
<method name="get_physics_layer_collision_layer" qualifiers="const">
|
||||||
<return type="int" />
|
<return type="int" />
|
||||||
<argument index="0" name="layer_index" type="int" />
|
<argument index="0" name="layer_index" type="int" />
|
||||||
|
@ -374,6 +395,13 @@
|
||||||
Removes the occlusion layer at index [code]layer_index[/code]. Also updates the atlas tiles accordingly.
|
Removes the occlusion layer at index [code]layer_index[/code]. Also updates the atlas tiles accordingly.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="remove_pattern">
|
||||||
|
<return type="void" />
|
||||||
|
<argument index="0" name="index" type="int" />
|
||||||
|
<description>
|
||||||
|
Remove the [TileMapPattern] at the given index.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="remove_physics_layer">
|
<method name="remove_physics_layer">
|
||||||
<return type="void" />
|
<return type="void" />
|
||||||
<argument index="0" name="layer_index" type="int" />
|
<argument index="0" name="layer_index" type="int" />
|
||||||
|
|
|
@ -173,4 +173,22 @@ public:
|
||||||
EditorFontPreviewPlugin();
|
EditorFontPreviewPlugin();
|
||||||
~EditorFontPreviewPlugin();
|
~EditorFontPreviewPlugin();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class EditorTileMapPatternPreviewPlugin : public EditorResourcePreviewGenerator {
|
||||||
|
GDCLASS(EditorTileMapPatternPreviewPlugin, EditorResourcePreviewGenerator);
|
||||||
|
|
||||||
|
mutable SafeFlag preview_done;
|
||||||
|
|
||||||
|
void _preview_done(const Variant &p_udata);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static void _bind_methods();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual bool handles(const String &p_type) const override;
|
||||||
|
virtual Ref<Texture2D> generate(const RES &p_from, const Size2 &p_size) const override;
|
||||||
|
|
||||||
|
EditorTileMapPatternPreviewPlugin();
|
||||||
|
~EditorTileMapPatternPreviewPlugin();
|
||||||
|
};
|
||||||
#endif // EDITORPREVIEWPLUGINS_H
|
#endif // EDITORPREVIEWPLUGINS_H
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include "editor/editor_scale.h"
|
#include "editor/editor_scale.h"
|
||||||
#include "editor/plugins/canvas_item_editor_plugin.h"
|
#include "editor/plugins/canvas_item_editor_plugin.h"
|
||||||
|
|
||||||
|
#include "scene/2d/camera_2d.h"
|
||||||
#include "scene/gui/center_container.h"
|
#include "scene/gui/center_container.h"
|
||||||
#include "scene/gui/split_container.h"
|
#include "scene/gui/split_container.h"
|
||||||
|
|
||||||
|
@ -43,31 +44,11 @@
|
||||||
#include "core/math/geometry_2d.h"
|
#include "core/math/geometry_2d.h"
|
||||||
#include "core/os/keyboard.h"
|
#include "core/os/keyboard.h"
|
||||||
|
|
||||||
void TileMapEditorTilesPlugin::_notification(int p_what) {
|
|
||||||
switch (p_what) {
|
|
||||||
case NOTIFICATION_ENTER_TREE:
|
|
||||||
case NOTIFICATION_THEME_CHANGED:
|
|
||||||
select_tool_button->set_icon(get_theme_icon(SNAME("ToolSelect"), SNAME("EditorIcons")));
|
|
||||||
paint_tool_button->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
|
|
||||||
line_tool_button->set_icon(get_theme_icon(SNAME("CurveLinear"), SNAME("EditorIcons")));
|
|
||||||
rect_tool_button->set_icon(get_theme_icon(SNAME("Rectangle"), SNAME("EditorIcons")));
|
|
||||||
bucket_tool_button->set_icon(get_theme_icon(SNAME("Bucket"), SNAME("EditorIcons")));
|
|
||||||
|
|
||||||
picker_button->set_icon(get_theme_icon(SNAME("ColorPick"), SNAME("EditorIcons")));
|
|
||||||
erase_button->set_icon(get_theme_icon(SNAME("Eraser"), SNAME("EditorIcons")));
|
|
||||||
|
|
||||||
missing_atlas_texture_icon = get_theme_icon(SNAME("TileSet"), SNAME("EditorIcons"));
|
|
||||||
break;
|
|
||||||
case NOTIFICATION_VISIBILITY_CHANGED:
|
|
||||||
_stop_dragging();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TileMapEditorTilesPlugin::tile_set_changed() {
|
void TileMapEditorTilesPlugin::tile_set_changed() {
|
||||||
_update_fix_selected_and_hovered();
|
_update_fix_selected_and_hovered();
|
||||||
_update_tile_set_sources_list();
|
_update_tile_set_sources_list();
|
||||||
_update_bottom_panel();
|
_update_source_display();
|
||||||
|
_update_patterns_list();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileMapEditorTilesPlugin::_on_random_tile_checkbox_toggled(bool p_pressed) {
|
void TileMapEditorTilesPlugin::_on_random_tile_checkbox_toggled(bool p_pressed) {
|
||||||
|
@ -125,8 +106,19 @@ void TileMapEditorTilesPlugin::_update_toolbar() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Control *TileMapEditorTilesPlugin::get_toolbar() const {
|
Vector<TileMapEditorPlugin::TabData> TileMapEditorTilesPlugin::get_tabs() const {
|
||||||
return toolbar;
|
Vector<TileMapEditorPlugin::TabData> tabs;
|
||||||
|
tabs.push_back({ toolbar, tiles_bottom_panel });
|
||||||
|
tabs.push_back({ toolbar, patterns_bottom_panel });
|
||||||
|
return tabs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TileMapEditorTilesPlugin::_tab_changed() {
|
||||||
|
if (tiles_bottom_panel->is_visible_in_tree()) {
|
||||||
|
_update_selection_pattern_from_tileset_tiles_selection();
|
||||||
|
} else if (patterns_bottom_panel->is_visible_in_tree()) {
|
||||||
|
_update_selection_pattern_from_tileset_pattern_selection();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileMapEditorTilesPlugin::_update_tile_set_sources_list() {
|
void TileMapEditorTilesPlugin::_update_tile_set_sources_list() {
|
||||||
|
@ -173,7 +165,7 @@ void TileMapEditorTilesPlugin::_update_tile_set_sources_list() {
|
||||||
// Scene collection source.
|
// Scene collection source.
|
||||||
TileSetScenesCollectionSource *scene_collection_source = Object::cast_to<TileSetScenesCollectionSource>(source);
|
TileSetScenesCollectionSource *scene_collection_source = Object::cast_to<TileSetScenesCollectionSource>(source);
|
||||||
if (scene_collection_source) {
|
if (scene_collection_source) {
|
||||||
texture = get_theme_icon(SNAME("PackedScene"), SNAME("EditorIcons"));
|
texture = tiles_bottom_panel->get_theme_icon(SNAME("PackedScene"), SNAME("EditorIcons"));
|
||||||
if (item_text.is_empty()) {
|
if (item_text.is_empty()) {
|
||||||
item_text = vformat(TTR("Scene Collection Source (ID: %d)"), source_id);
|
item_text = vformat(TTR("Scene Collection Source (ID: %d)"), source_id);
|
||||||
}
|
}
|
||||||
|
@ -205,7 +197,7 @@ void TileMapEditorTilesPlugin::_update_tile_set_sources_list() {
|
||||||
TilesEditor::get_singleton()->set_sources_lists_current(sources_list->get_current());
|
TilesEditor::get_singleton()->set_sources_lists_current(sources_list->get_current());
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileMapEditorTilesPlugin::_update_bottom_panel() {
|
void TileMapEditorTilesPlugin::_update_source_display() {
|
||||||
// Update the atlas display.
|
// Update the atlas display.
|
||||||
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
|
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
|
||||||
if (!tile_map) {
|
if (!tile_map) {
|
||||||
|
@ -252,6 +244,81 @@ void TileMapEditorTilesPlugin::_update_bottom_panel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TileMapEditorTilesPlugin::_patterns_item_list_gui_input(const Ref<InputEvent> &p_event) {
|
||||||
|
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
|
||||||
|
if (!tile_map) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<TileSet> tile_set = tile_map->get_tileset();
|
||||||
|
if (!tile_set.is_valid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ED_IS_SHORTCUT("tiles_editor/paste", p_event) && p_event->is_pressed() && !p_event->is_echo()) {
|
||||||
|
select_last_pattern = true;
|
||||||
|
int new_pattern_index = tile_set->get_patterns_count();
|
||||||
|
undo_redo->create_action(TTR("Add TileSet pattern"));
|
||||||
|
undo_redo->add_do_method(*tile_set, "add_pattern", tile_map_clipboard, new_pattern_index);
|
||||||
|
undo_redo->add_undo_method(*tile_set, "remove_pattern", new_pattern_index);
|
||||||
|
undo_redo->commit_action();
|
||||||
|
patterns_item_list->accept_event();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ED_IS_SHORTCUT("tiles_editor/delete", p_event) && p_event->is_pressed() && !p_event->is_echo()) {
|
||||||
|
Vector<int> selected = patterns_item_list->get_selected_items();
|
||||||
|
undo_redo->create_action(TTR("Remove TileSet patterns"));
|
||||||
|
for (int i = 0; i < selected.size(); i++) {
|
||||||
|
int pattern_index = selected[i];
|
||||||
|
undo_redo->add_do_method(*tile_set, "remove_pattern", pattern_index);
|
||||||
|
undo_redo->add_undo_method(*tile_set, "add_pattern", tile_set->get_pattern(pattern_index), pattern_index);
|
||||||
|
}
|
||||||
|
undo_redo->commit_action();
|
||||||
|
patterns_item_list->accept_event();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TileMapEditorTilesPlugin::_pattern_preview_done(Ref<TileMapPattern> p_pattern, Ref<Texture2D> p_texture) {
|
||||||
|
// TODO optimize ?
|
||||||
|
for (int i = 0; i < patterns_item_list->get_item_count(); i++) {
|
||||||
|
if (patterns_item_list->get_item_metadata(i) == p_pattern) {
|
||||||
|
patterns_item_list->set_item_icon(i, p_texture);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TileMapEditorTilesPlugin::_update_patterns_list() {
|
||||||
|
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
|
||||||
|
if (!tile_map) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<TileSet> tile_set = tile_map->get_tileset();
|
||||||
|
if (!tile_set.is_valid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recreate the items.
|
||||||
|
patterns_item_list->clear();
|
||||||
|
for (int i = 0; i < tile_set->get_patterns_count(); i++) {
|
||||||
|
int id = patterns_item_list->add_item("");
|
||||||
|
patterns_item_list->set_item_metadata(id, tile_set->get_pattern(i));
|
||||||
|
TilesEditor::get_singleton()->queue_pattern_preview(tile_set, tile_set->get_pattern(i), callable_mp(this, &TileMapEditorTilesPlugin::_pattern_preview_done));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the label visibility.
|
||||||
|
patterns_help_label->set_visible(patterns_item_list->get_item_count() == 0);
|
||||||
|
|
||||||
|
// Added a new pattern, thus select the last one.
|
||||||
|
if (select_last_pattern) {
|
||||||
|
patterns_item_list->select(tile_set->get_patterns_count() - 1);
|
||||||
|
patterns_item_list->grab_focus();
|
||||||
|
_update_selection_pattern_from_tileset_pattern_selection();
|
||||||
|
}
|
||||||
|
select_last_pattern = false;
|
||||||
|
}
|
||||||
|
|
||||||
void TileMapEditorTilesPlugin::_update_atlas_view() {
|
void TileMapEditorTilesPlugin::_update_atlas_view() {
|
||||||
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
|
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
|
||||||
if (!tile_map) {
|
if (!tile_map) {
|
||||||
|
@ -304,7 +371,7 @@ void TileMapEditorTilesPlugin::_update_scenes_collection_view() {
|
||||||
Variant udata = i;
|
Variant udata = i;
|
||||||
EditorResourcePreview::get_singleton()->queue_edited_resource_preview(scene, this, "_scene_thumbnail_done", udata);
|
EditorResourcePreview::get_singleton()->queue_edited_resource_preview(scene, this, "_scene_thumbnail_done", udata);
|
||||||
} else {
|
} else {
|
||||||
item_index = scene_tiles_list->add_item(TTR("Tile with Invalid Scene"), get_theme_icon(SNAME("PackedScene"), SNAME("EditorIcons")));
|
item_index = scene_tiles_list->add_item(TTR("Tile with Invalid Scene"), tiles_bottom_panel->get_theme_icon(SNAME("PackedScene"), SNAME("EditorIcons")));
|
||||||
}
|
}
|
||||||
scene_tiles_list->set_item_metadata(item_index, scene_id);
|
scene_tiles_list->set_item_metadata(item_index, scene_id);
|
||||||
|
|
||||||
|
@ -360,19 +427,32 @@ void TileMapEditorTilesPlugin::_scenes_list_multi_selected(int p_index, bool p_s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_update_selection_pattern_from_tileset_selection();
|
_update_selection_pattern_from_tileset_tiles_selection();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileMapEditorTilesPlugin::_scenes_list_nothing_selected() {
|
void TileMapEditorTilesPlugin::_scenes_list_nothing_selected() {
|
||||||
scene_tiles_list->deselect_all();
|
scene_tiles_list->deselect_all();
|
||||||
tile_set_selection.clear();
|
tile_set_selection.clear();
|
||||||
tile_map_selection.clear();
|
tile_map_selection.clear();
|
||||||
selection_pattern->clear();
|
selection_pattern.instantiate();
|
||||||
_update_selection_pattern_from_tileset_selection();
|
_update_selection_pattern_from_tileset_tiles_selection();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TileMapEditorTilesPlugin::_update_theme() {
|
||||||
|
select_tool_button->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("ToolSelect"), SNAME("EditorIcons")));
|
||||||
|
paint_tool_button->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
|
||||||
|
line_tool_button->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("CurveLinear"), SNAME("EditorIcons")));
|
||||||
|
rect_tool_button->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("Rectangle"), SNAME("EditorIcons")));
|
||||||
|
bucket_tool_button->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("Bucket"), SNAME("EditorIcons")));
|
||||||
|
|
||||||
|
picker_button->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("ColorPick"), SNAME("EditorIcons")));
|
||||||
|
erase_button->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("Eraser"), SNAME("EditorIcons")));
|
||||||
|
|
||||||
|
missing_atlas_texture_icon = tiles_bottom_panel->get_theme_icon(SNAME("TileSet"), SNAME("EditorIcons"));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
|
bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
|
||||||
if (!is_visible_in_tree()) {
|
if (!(tiles_bottom_panel->is_visible_in_tree() || patterns_bottom_panel->is_visible_in_tree())) {
|
||||||
// If the bottom editor is not visible, we ignore inputs.
|
// If the bottom editor is not visible, we ignore inputs.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -400,7 +480,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
|
||||||
if (ED_IS_SHORTCUT("tiles_editor/cut", p_event) || ED_IS_SHORTCUT("tiles_editor/copy", p_event)) {
|
if (ED_IS_SHORTCUT("tiles_editor/cut", p_event) || ED_IS_SHORTCUT("tiles_editor/copy", p_event)) {
|
||||||
// Fill in the clipboard.
|
// Fill in the clipboard.
|
||||||
if (!tile_map_selection.is_empty()) {
|
if (!tile_map_selection.is_empty()) {
|
||||||
memdelete(tile_map_clipboard);
|
tile_map_clipboard.instantiate();
|
||||||
TypedArray<Vector2i> coords_array;
|
TypedArray<Vector2i> coords_array;
|
||||||
for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) {
|
for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) {
|
||||||
coords_array.push_back(E->get());
|
coords_array.push_back(E->get());
|
||||||
|
@ -633,7 +713,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
|
||||||
Vector2i tile_shape_size = tile_set->get_tile_size();
|
Vector2i tile_shape_size = tile_set->get_tile_size();
|
||||||
|
|
||||||
// Draw the selection.
|
// Draw the selection.
|
||||||
if (is_visible_in_tree() && tool_buttons_group->get_pressed_button() == select_tool_button) {
|
if ((tiles_bottom_panel->is_visible_in_tree() || patterns_bottom_panel->is_visible_in_tree()) && tool_buttons_group->get_pressed_button() == select_tool_button) {
|
||||||
// In select mode, we only draw the current selection if we are modifying it (pressing control or shift).
|
// In select mode, we only draw the current selection if we are modifying it (pressing control or shift).
|
||||||
if (drag_type == DRAG_TYPE_MOVE || (drag_type == DRAG_TYPE_SELECT && !Input::get_singleton()->is_key_pressed(KEY_CTRL) && !Input::get_singleton()->is_key_pressed(KEY_SHIFT))) {
|
if (drag_type == DRAG_TYPE_MOVE || (drag_type == DRAG_TYPE_SELECT && !Input::get_singleton()->is_key_pressed(KEY_CTRL) && !Input::get_singleton()->is_key_pressed(KEY_SHIFT))) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
|
@ -645,7 +725,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle the preview of the tiles to be placed.
|
// Handle the preview of the tiles to be placed.
|
||||||
if (is_visible_in_tree() && has_mouse) { // Only if the tilemap editor is opened and the viewport is hovered.
|
if ((tiles_bottom_panel->is_visible_in_tree() || patterns_bottom_panel->is_visible_in_tree()) && has_mouse) { // Only if the tilemap editor is opened and the viewport is hovered.
|
||||||
Map<Vector2i, TileMapCell> preview;
|
Map<Vector2i, TileMapCell> preview;
|
||||||
Rect2i drawn_grid_rect;
|
Rect2i drawn_grid_rect;
|
||||||
|
|
||||||
|
@ -679,21 +759,23 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
|
||||||
}
|
}
|
||||||
tile_map->draw_cells_outline(p_overlay, to_draw, Color(1.0, 1.0, 1.0), xform);
|
tile_map->draw_cells_outline(p_overlay, to_draw, Color(1.0, 1.0, 1.0), xform);
|
||||||
} else if (drag_type == DRAG_TYPE_MOVE) {
|
} else if (drag_type == DRAG_TYPE_MOVE) {
|
||||||
// Preview when moving.
|
if (!(patterns_item_list->is_visible_in_tree() && patterns_item_list->has_point(patterns_item_list->get_local_mouse_position()))) {
|
||||||
Vector2i top_left;
|
// Preview when moving.
|
||||||
if (!tile_map_selection.is_empty()) {
|
Vector2i top_left;
|
||||||
top_left = tile_map_selection.front()->get();
|
if (!tile_map_selection.is_empty()) {
|
||||||
}
|
top_left = tile_map_selection.front()->get();
|
||||||
for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) {
|
}
|
||||||
top_left = top_left.min(E->get());
|
for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) {
|
||||||
}
|
top_left = top_left.min(E->get());
|
||||||
Vector2i offset = drag_start_mouse_pos - tile_map->map_to_world(top_left);
|
}
|
||||||
offset = tile_map->world_to_map(drag_last_mouse_pos - offset) - tile_map->world_to_map(drag_start_mouse_pos - offset);
|
Vector2i offset = drag_start_mouse_pos - tile_map->map_to_world(top_left);
|
||||||
|
offset = tile_map->world_to_map(drag_last_mouse_pos - offset) - tile_map->world_to_map(drag_start_mouse_pos - offset);
|
||||||
|
|
||||||
TypedArray<Vector2i> selection_used_cells = selection_pattern->get_used_cells();
|
TypedArray<Vector2i> selection_used_cells = selection_pattern->get_used_cells();
|
||||||
for (int i = 0; i < selection_used_cells.size(); i++) {
|
for (int i = 0; i < selection_used_cells.size(); i++) {
|
||||||
Vector2i coords = tile_map->map_pattern(offset + top_left, selection_used_cells[i], selection_pattern);
|
Vector2i coords = tile_map->map_pattern(offset + top_left, selection_used_cells[i], selection_pattern);
|
||||||
preview[coords] = TileMapCell(selection_pattern->get_cell_source_id(selection_used_cells[i]), selection_pattern->get_cell_atlas_coords(selection_used_cells[i]), selection_pattern->get_cell_alternative_tile(selection_used_cells[i]));
|
preview[coords] = TileMapCell(selection_pattern->get_cell_source_id(selection_used_cells[i]), selection_pattern->get_cell_atlas_coords(selection_used_cells[i]), selection_pattern->get_cell_alternative_tile(selection_used_cells[i]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (drag_type == DRAG_TYPE_CLIPBOARD_PASTE) {
|
} else if (drag_type == DRAG_TYPE_CLIPBOARD_PASTE) {
|
||||||
// Preview when pasting.
|
// Preview when pasting.
|
||||||
|
@ -832,7 +914,7 @@ void TileMapEditorTilesPlugin::_mouse_exited_viewport() {
|
||||||
CanvasItemEditor::get_singleton()->update_viewport();
|
CanvasItemEditor::get_singleton()->update_viewport();
|
||||||
}
|
}
|
||||||
|
|
||||||
TileMapCell TileMapEditorTilesPlugin::_pick_random_tile(const TileMapPattern *p_pattern) {
|
TileMapCell TileMapEditorTilesPlugin::_pick_random_tile(Ref<TileMapPattern> p_pattern) {
|
||||||
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
|
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
|
||||||
if (!tile_map) {
|
if (!tile_map) {
|
||||||
return TileMapCell();
|
return TileMapCell();
|
||||||
|
@ -896,9 +978,10 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_line(Vector2 p_start_
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get or create the pattern.
|
// Get or create the pattern.
|
||||||
TileMapPattern erase_pattern;
|
Ref<TileMapPattern> erase_pattern;
|
||||||
erase_pattern.set_cell(Vector2i(0, 0), TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
|
erase_pattern.instantiate();
|
||||||
TileMapPattern *pattern = _is_erasing() ? &erase_pattern : selection_pattern;
|
erase_pattern->set_cell(Vector2i(0, 0), TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
|
||||||
|
Ref<TileMapPattern> pattern = _is_erasing() ? erase_pattern : selection_pattern;
|
||||||
|
|
||||||
Map<Vector2i, TileMapCell> output;
|
Map<Vector2i, TileMapCell> output;
|
||||||
if (!pattern->is_empty()) {
|
if (!pattern->is_empty()) {
|
||||||
|
@ -948,9 +1031,11 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_rect(Vector2i p_start
|
||||||
rect.size += Vector2i(1, 1);
|
rect.size += Vector2i(1, 1);
|
||||||
|
|
||||||
// Get or create the pattern.
|
// Get or create the pattern.
|
||||||
TileMapPattern erase_pattern;
|
Ref<TileMapPattern> erase_pattern;
|
||||||
erase_pattern.set_cell(Vector2i(0, 0), TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
|
erase_pattern.instantiate();
|
||||||
TileMapPattern *pattern = _is_erasing() ? &erase_pattern : selection_pattern;
|
erase_pattern->set_cell(Vector2i(0, 0), TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
|
||||||
|
Ref<TileMapPattern> pattern = _is_erasing() ? erase_pattern : selection_pattern;
|
||||||
|
|
||||||
Map<Vector2i, TileMapCell> err_output;
|
Map<Vector2i, TileMapCell> err_output;
|
||||||
ERR_FAIL_COND_V(pattern->is_empty(), err_output);
|
ERR_FAIL_COND_V(pattern->is_empty(), err_output);
|
||||||
|
|
||||||
|
@ -1007,9 +1092,10 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vector2i
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get or create the pattern.
|
// Get or create the pattern.
|
||||||
TileMapPattern erase_pattern;
|
Ref<TileMapPattern> erase_pattern;
|
||||||
erase_pattern.set_cell(Vector2i(0, 0), TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
|
erase_pattern.instantiate();
|
||||||
TileMapPattern *pattern = _is_erasing() ? &erase_pattern : selection_pattern;
|
erase_pattern->set_cell(Vector2i(0, 0), TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
|
||||||
|
Ref<TileMapPattern> pattern = _is_erasing() ? erase_pattern : selection_pattern;
|
||||||
|
|
||||||
if (!pattern->is_empty()) {
|
if (!pattern->is_empty()) {
|
||||||
TileMapCell source = tile_map->get_cell(tile_map_layer, p_coords);
|
TileMapCell source = tile_map->get_cell(tile_map_layer, p_coords);
|
||||||
|
@ -1153,60 +1239,80 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
|
||||||
_update_tileset_selection_from_selection_pattern();
|
_update_tileset_selection_from_selection_pattern();
|
||||||
} break;
|
} break;
|
||||||
case DRAG_TYPE_MOVE: {
|
case DRAG_TYPE_MOVE: {
|
||||||
Vector2i top_left;
|
if (patterns_item_list->is_visible_in_tree() && patterns_item_list->has_point(patterns_item_list->get_local_mouse_position())) {
|
||||||
if (!tile_map_selection.is_empty()) {
|
// Restore the cells.
|
||||||
top_left = tile_map_selection.front()->get();
|
for (KeyValue<Vector2i, TileMapCell> kv : drag_modified) {
|
||||||
}
|
tile_map->set_cell(tile_map_layer, kv.key, kv.value.source_id, kv.value.get_atlas_coords(), kv.value.alternative_tile);
|
||||||
for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) {
|
}
|
||||||
top_left = top_left.min(E->get());
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector2i offset = drag_start_mouse_pos - tile_map->map_to_world(top_left);
|
// Creating a pattern in the pattern list.
|
||||||
offset = tile_map->world_to_map(mpos - offset) - tile_map->world_to_map(drag_start_mouse_pos - offset);
|
select_last_pattern = true;
|
||||||
|
int new_pattern_index = tile_set->get_patterns_count();
|
||||||
|
undo_redo->create_action(TTR("Add TileSet pattern"));
|
||||||
|
undo_redo->add_do_method(*tile_set, "add_pattern", selection_pattern, new_pattern_index);
|
||||||
|
undo_redo->add_undo_method(*tile_set, "remove_pattern", new_pattern_index);
|
||||||
|
undo_redo->commit_action();
|
||||||
|
} else {
|
||||||
|
// Get the top-left cell.
|
||||||
|
Vector2i top_left;
|
||||||
|
if (!tile_map_selection.is_empty()) {
|
||||||
|
top_left = tile_map_selection.front()->get();
|
||||||
|
}
|
||||||
|
for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) {
|
||||||
|
top_left = top_left.min(E->get());
|
||||||
|
}
|
||||||
|
|
||||||
TypedArray<Vector2i> selection_used_cells = selection_pattern->get_used_cells();
|
// Get the offset from the mouse.
|
||||||
|
Vector2i offset = drag_start_mouse_pos - tile_map->map_to_world(top_left);
|
||||||
|
offset = tile_map->world_to_map(mpos - offset) - tile_map->world_to_map(drag_start_mouse_pos - offset);
|
||||||
|
|
||||||
Vector2i coords;
|
TypedArray<Vector2i> selection_used_cells = selection_pattern->get_used_cells();
|
||||||
Map<Vector2i, TileMapCell> cells_undo;
|
|
||||||
for (int i = 0; i < selection_used_cells.size(); i++) {
|
|
||||||
coords = tile_map->map_pattern(top_left, selection_used_cells[i], selection_pattern);
|
|
||||||
cells_undo[coords] = TileMapCell(drag_modified[coords].source_id, drag_modified[coords].get_atlas_coords(), drag_modified[coords].alternative_tile);
|
|
||||||
coords = tile_map->map_pattern(top_left + offset, selection_used_cells[i], selection_pattern);
|
|
||||||
cells_undo[coords] = TileMapCell(tile_map->get_cell_source_id(tile_map_layer, coords), tile_map->get_cell_atlas_coords(tile_map_layer, coords), tile_map->get_cell_alternative_tile(tile_map_layer, coords));
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<Vector2i, TileMapCell> cells_do;
|
// Build the list of cells to undo.
|
||||||
for (int i = 0; i < selection_used_cells.size(); i++) {
|
Vector2i coords;
|
||||||
coords = tile_map->map_pattern(top_left, selection_used_cells[i], selection_pattern);
|
Map<Vector2i, TileMapCell> cells_undo;
|
||||||
cells_do[coords] = TileMapCell();
|
for (int i = 0; i < selection_used_cells.size(); i++) {
|
||||||
}
|
coords = tile_map->map_pattern(top_left, selection_used_cells[i], selection_pattern);
|
||||||
for (int i = 0; i < selection_used_cells.size(); i++) {
|
cells_undo[coords] = TileMapCell(drag_modified[coords].source_id, drag_modified[coords].get_atlas_coords(), drag_modified[coords].alternative_tile);
|
||||||
coords = tile_map->map_pattern(top_left + offset, selection_used_cells[i], selection_pattern);
|
coords = tile_map->map_pattern(top_left + offset, selection_used_cells[i], selection_pattern);
|
||||||
cells_do[coords] = TileMapCell(selection_pattern->get_cell_source_id(selection_used_cells[i]), selection_pattern->get_cell_atlas_coords(selection_used_cells[i]), selection_pattern->get_cell_alternative_tile(selection_used_cells[i]));
|
cells_undo[coords] = TileMapCell(tile_map->get_cell_source_id(tile_map_layer, coords), tile_map->get_cell_atlas_coords(tile_map_layer, coords), tile_map->get_cell_alternative_tile(tile_map_layer, coords));
|
||||||
}
|
}
|
||||||
undo_redo->create_action(TTR("Move tiles"));
|
|
||||||
// Move the tiles.
|
|
||||||
for (const KeyValue<Vector2i, TileMapCell> &E : cells_do) {
|
|
||||||
undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
|
|
||||||
}
|
|
||||||
for (const KeyValue<Vector2i, TileMapCell> &E : cells_undo) {
|
|
||||||
undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the selection.
|
// Build the list of cells to do.
|
||||||
undo_redo->add_undo_method(this, "_set_tile_map_selection", _get_tile_map_selection());
|
Map<Vector2i, TileMapCell> cells_do;
|
||||||
tile_map_selection.clear();
|
for (int i = 0; i < selection_used_cells.size(); i++) {
|
||||||
for (int i = 0; i < selection_used_cells.size(); i++) {
|
coords = tile_map->map_pattern(top_left, selection_used_cells[i], selection_pattern);
|
||||||
coords = tile_map->map_pattern(top_left + offset, selection_used_cells[i], selection_pattern);
|
cells_do[coords] = TileMapCell();
|
||||||
tile_map_selection.insert(coords);
|
}
|
||||||
|
for (int i = 0; i < selection_used_cells.size(); i++) {
|
||||||
|
coords = tile_map->map_pattern(top_left + offset, selection_used_cells[i], selection_pattern);
|
||||||
|
cells_do[coords] = TileMapCell(selection_pattern->get_cell_source_id(selection_used_cells[i]), selection_pattern->get_cell_atlas_coords(selection_used_cells[i]), selection_pattern->get_cell_alternative_tile(selection_used_cells[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the tiles.
|
||||||
|
undo_redo->create_action(TTR("Move tiles"));
|
||||||
|
for (Map<Vector2i, TileMapCell>::Element *E = cells_do.front(); E; E = E->next()) {
|
||||||
|
undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
|
||||||
|
}
|
||||||
|
for (Map<Vector2i, TileMapCell>::Element *E = cells_undo.front(); E; E = E->next()) {
|
||||||
|
undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the selection.
|
||||||
|
undo_redo->add_undo_method(this, "_set_tile_map_selection", _get_tile_map_selection());
|
||||||
|
tile_map_selection.clear();
|
||||||
|
for (int i = 0; i < selection_used_cells.size(); i++) {
|
||||||
|
coords = tile_map->map_pattern(top_left + offset, selection_used_cells[i], selection_pattern);
|
||||||
|
tile_map_selection.insert(coords);
|
||||||
|
}
|
||||||
|
undo_redo->add_do_method(this, "_set_tile_map_selection", _get_tile_map_selection());
|
||||||
|
undo_redo->commit_action();
|
||||||
}
|
}
|
||||||
undo_redo->add_do_method(this, "_set_tile_map_selection", _get_tile_map_selection());
|
|
||||||
undo_redo->commit_action();
|
|
||||||
} break;
|
} break;
|
||||||
case DRAG_TYPE_PICK: {
|
case DRAG_TYPE_PICK: {
|
||||||
Rect2i rect = Rect2i(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(mpos) - tile_map->world_to_map(drag_start_mouse_pos)).abs();
|
Rect2i rect = Rect2i(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(mpos) - tile_map->world_to_map(drag_start_mouse_pos)).abs();
|
||||||
rect.size += Vector2i(1, 1);
|
rect.size += Vector2i(1, 1);
|
||||||
memdelete(selection_pattern);
|
|
||||||
TypedArray<Vector2i> coords_array;
|
TypedArray<Vector2i> coords_array;
|
||||||
for (int x = rect.position.x; x < rect.get_end().x; x++) {
|
for (int x = rect.position.x; x < rect.get_end().x; x++) {
|
||||||
for (int y = rect.position.y; y < rect.get_end().y; y++) {
|
for (int y = rect.position.y; y < rect.get_end().y; y++) {
|
||||||
|
@ -1216,11 +1322,10 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
selection_pattern = tile_map->get_pattern(tile_map_layer, coords_array);
|
Ref<TileMapPattern> new_selection_pattern = tile_map->get_pattern(tile_map_layer, coords_array);
|
||||||
if (!selection_pattern->is_empty()) {
|
if (!new_selection_pattern->is_empty()) {
|
||||||
|
selection_pattern = new_selection_pattern;
|
||||||
_update_tileset_selection_from_selection_pattern();
|
_update_tileset_selection_from_selection_pattern();
|
||||||
} else {
|
|
||||||
_update_selection_pattern_from_tileset_selection();
|
|
||||||
}
|
}
|
||||||
picker_button->set_pressed(false);
|
picker_button->set_pressed(false);
|
||||||
} break;
|
} break;
|
||||||
|
@ -1288,8 +1393,9 @@ void TileMapEditorTilesPlugin::_update_fix_selected_and_hovered() {
|
||||||
hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS);
|
hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS);
|
||||||
hovered_tile.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
|
hovered_tile.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
|
||||||
tile_set_selection.clear();
|
tile_set_selection.clear();
|
||||||
|
patterns_item_list->deselect_all();
|
||||||
tile_map_selection.clear();
|
tile_map_selection.clear();
|
||||||
selection_pattern->clear();
|
selection_pattern.instantiate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1299,8 +1405,9 @@ void TileMapEditorTilesPlugin::_update_fix_selected_and_hovered() {
|
||||||
hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS);
|
hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS);
|
||||||
hovered_tile.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
|
hovered_tile.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
|
||||||
tile_set_selection.clear();
|
tile_set_selection.clear();
|
||||||
|
patterns_item_list->deselect_all();
|
||||||
tile_map_selection.clear();
|
tile_map_selection.clear();
|
||||||
selection_pattern->clear();
|
selection_pattern.instantiate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1310,8 +1417,9 @@ void TileMapEditorTilesPlugin::_update_fix_selected_and_hovered() {
|
||||||
hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS);
|
hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS);
|
||||||
hovered_tile.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
|
hovered_tile.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
|
||||||
tile_set_selection.clear();
|
tile_set_selection.clear();
|
||||||
|
patterns_item_list->deselect_all();
|
||||||
tile_map_selection.clear();
|
tile_map_selection.clear();
|
||||||
selection_pattern->clear();
|
selection_pattern.instantiate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1339,8 +1447,10 @@ void TileMapEditorTilesPlugin::_update_fix_selected_and_hovered() {
|
||||||
|
|
||||||
if (!tile_map_selection.is_empty()) {
|
if (!tile_map_selection.is_empty()) {
|
||||||
_update_selection_pattern_from_tilemap_selection();
|
_update_selection_pattern_from_tilemap_selection();
|
||||||
|
} else if (tiles_bottom_panel->is_visible_in_tree()) {
|
||||||
|
_update_selection_pattern_from_tileset_tiles_selection();
|
||||||
} else {
|
} else {
|
||||||
_update_selection_pattern_from_tileset_selection();
|
_update_selection_pattern_from_tileset_pattern_selection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1373,9 +1483,14 @@ void TileMapEditorTilesPlugin::_update_selection_pattern_from_tilemap_selection(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ref<TileSet> tile_set = tile_map->get_tileset();
|
||||||
|
if (!tile_set.is_valid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ERR_FAIL_INDEX(tile_map_layer, tile_map->get_layers_count());
|
ERR_FAIL_INDEX(tile_map_layer, tile_map->get_layers_count());
|
||||||
|
|
||||||
memdelete(selection_pattern);
|
selection_pattern.instantiate();
|
||||||
|
|
||||||
TypedArray<Vector2i> coords_array;
|
TypedArray<Vector2i> coords_array;
|
||||||
for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) {
|
for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) {
|
||||||
|
@ -1384,7 +1499,7 @@ void TileMapEditorTilesPlugin::_update_selection_pattern_from_tilemap_selection(
|
||||||
selection_pattern = tile_map->get_pattern(tile_map_layer, coords_array);
|
selection_pattern = tile_map->get_pattern(tile_map_layer, coords_array);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_selection() {
|
void TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_tiles_selection() {
|
||||||
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
|
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
|
||||||
if (!tile_map) {
|
if (!tile_map) {
|
||||||
return;
|
return;
|
||||||
|
@ -1399,7 +1514,7 @@ void TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_selection(
|
||||||
tile_map_selection.clear();
|
tile_map_selection.clear();
|
||||||
|
|
||||||
// Clear the selected pattern.
|
// Clear the selected pattern.
|
||||||
selection_pattern->clear();
|
selection_pattern.instantiate();
|
||||||
|
|
||||||
// Group per source.
|
// Group per source.
|
||||||
Map<int, List<const TileMapCell *>> per_source;
|
Map<int, List<const TileMapCell *>> per_source;
|
||||||
|
@ -1457,6 +1572,30 @@ void TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_selection(
|
||||||
CanvasItemEditor::get_singleton()->update_viewport();
|
CanvasItemEditor::get_singleton()->update_viewport();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_pattern_selection() {
|
||||||
|
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
|
||||||
|
if (!tile_map) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<TileSet> tile_set = tile_map->get_tileset();
|
||||||
|
if (!tile_set.is_valid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the tilemap selection.
|
||||||
|
tile_map_selection.clear();
|
||||||
|
|
||||||
|
// Clear the selected pattern.
|
||||||
|
selection_pattern.instantiate();
|
||||||
|
|
||||||
|
if (patterns_item_list->get_selected_items().size() >= 1) {
|
||||||
|
selection_pattern = patterns_item_list->get_item_metadata(patterns_item_list->get_selected_items()[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
CanvasItemEditor::get_singleton()->update_viewport();
|
||||||
|
}
|
||||||
|
|
||||||
void TileMapEditorTilesPlugin::_update_tileset_selection_from_selection_pattern() {
|
void TileMapEditorTilesPlugin::_update_tileset_selection_from_selection_pattern() {
|
||||||
tile_set_selection.clear();
|
tile_set_selection.clear();
|
||||||
TypedArray<Vector2i> used_cells = selection_pattern->get_used_cells();
|
TypedArray<Vector2i> used_cells = selection_pattern->get_used_cells();
|
||||||
|
@ -1466,7 +1605,7 @@ void TileMapEditorTilesPlugin::_update_tileset_selection_from_selection_pattern(
|
||||||
tile_set_selection.insert(TileMapCell(selection_pattern->get_cell_source_id(coords), selection_pattern->get_cell_atlas_coords(coords), selection_pattern->get_cell_alternative_tile(coords)));
|
tile_set_selection.insert(TileMapCell(selection_pattern->get_cell_source_id(coords), selection_pattern->get_cell_atlas_coords(coords), selection_pattern->get_cell_alternative_tile(coords)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_update_bottom_panel();
|
_update_source_display();
|
||||||
tile_atlas_control->update();
|
tile_atlas_control->update();
|
||||||
alternative_tiles_control->update();
|
alternative_tiles_control->update();
|
||||||
}
|
}
|
||||||
|
@ -1616,7 +1755,7 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_gui_input(const Ref<InputEven
|
||||||
tile_set_selection.insert(TileMapCell(source_id, hovered_tile.get_atlas_coords(), 0));
|
tile_set_selection.insert(TileMapCell(source_id, hovered_tile.get_atlas_coords(), 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_update_selection_pattern_from_tileset_selection();
|
_update_selection_pattern_from_tileset_tiles_selection();
|
||||||
} else { // Released
|
} else { // Released
|
||||||
if (tile_set_dragging_selection) {
|
if (tile_set_dragging_selection) {
|
||||||
if (!mb->is_shift_pressed()) {
|
if (!mb->is_shift_pressed()) {
|
||||||
|
@ -1653,7 +1792,7 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_gui_input(const Ref<InputEven
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_update_selection_pattern_from_tileset_selection();
|
_update_selection_pattern_from_tileset_tiles_selection();
|
||||||
}
|
}
|
||||||
tile_set_dragging_selection = false;
|
tile_set_dragging_selection = false;
|
||||||
}
|
}
|
||||||
|
@ -1773,7 +1912,7 @@ void TileMapEditorTilesPlugin::_tile_alternatives_control_gui_input(const Ref<In
|
||||||
tile_set_selection.insert(TileMapCell(source_id, hovered_tile.get_atlas_coords(), hovered_tile.alternative_tile));
|
tile_set_selection.insert(TileMapCell(source_id, hovered_tile.get_atlas_coords(), hovered_tile.alternative_tile));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_update_selection_pattern_from_tileset_selection();
|
_update_selection_pattern_from_tileset_tiles_selection();
|
||||||
}
|
}
|
||||||
tile_atlas_control->update();
|
tile_atlas_control->update();
|
||||||
alternative_tiles_control->update();
|
alternative_tiles_control->update();
|
||||||
|
@ -1806,8 +1945,9 @@ void TileMapEditorTilesPlugin::edit(ObjectID p_tile_map_id, int p_tile_map_layer
|
||||||
|
|
||||||
// Clear the selection.
|
// Clear the selection.
|
||||||
tile_set_selection.clear();
|
tile_set_selection.clear();
|
||||||
|
patterns_item_list->deselect_all();
|
||||||
tile_map_selection.clear();
|
tile_map_selection.clear();
|
||||||
selection_pattern->clear();
|
selection_pattern.instantiate();
|
||||||
}
|
}
|
||||||
|
|
||||||
tile_map_layer = p_tile_map_layer;
|
tile_map_layer = p_tile_map_layer;
|
||||||
|
@ -1829,9 +1969,13 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
|
||||||
ED_SHORTCUT("tiles_editor/cancel", TTR("Cancel"), KEY_ESCAPE);
|
ED_SHORTCUT("tiles_editor/cancel", TTR("Cancel"), KEY_ESCAPE);
|
||||||
ED_SHORTCUT("tiles_editor/delete", TTR("Delete"), KEY_DELETE);
|
ED_SHORTCUT("tiles_editor/delete", TTR("Delete"), KEY_DELETE);
|
||||||
|
|
||||||
|
// --- Initialize references ---
|
||||||
|
tile_map_clipboard.instantiate();
|
||||||
|
selection_pattern.instantiate();
|
||||||
|
|
||||||
// --- Toolbar ---
|
// --- Toolbar ---
|
||||||
toolbar = memnew(HBoxContainer);
|
toolbar = memnew(HBoxContainer);
|
||||||
toolbar->set_h_size_flags(SIZE_EXPAND_FILL);
|
toolbar->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||||
|
|
||||||
HBoxContainer *tilemap_tiles_tools_buttons = memnew(HBoxContainer);
|
HBoxContainer *tilemap_tiles_tools_buttons = memnew(HBoxContainer);
|
||||||
|
|
||||||
|
@ -1942,39 +2086,44 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
|
||||||
paint_tool_button->set_pressed(true);
|
paint_tool_button->set_pressed(true);
|
||||||
_update_toolbar();
|
_update_toolbar();
|
||||||
|
|
||||||
// --- Bottom panel ---
|
// --- Bottom panel tiles ---
|
||||||
set_name("Tiles");
|
tiles_bottom_panel = memnew(VBoxContainer);
|
||||||
|
tiles_bottom_panel->connect("tree_entered", callable_mp(this, &TileMapEditorTilesPlugin::_update_theme));
|
||||||
|
tiles_bottom_panel->connect("theme_changed", callable_mp(this, &TileMapEditorTilesPlugin::_update_theme));
|
||||||
|
tiles_bottom_panel->connect("visibility_changed", callable_mp(this, &TileMapEditorTilesPlugin::_stop_dragging));
|
||||||
|
tiles_bottom_panel->connect("visibility_changed", callable_mp(this, &TileMapEditorTilesPlugin::_tab_changed));
|
||||||
|
tiles_bottom_panel->set_name(TTR("Tiles"));
|
||||||
|
|
||||||
missing_source_label = memnew(Label);
|
missing_source_label = memnew(Label);
|
||||||
missing_source_label->set_text(TTR("This TileMap's TileSet has no source configured. Edit the TileSet resource to add one."));
|
missing_source_label->set_text(TTR("This TileMap's TileSet has no source configured. Edit the TileSet resource to add one."));
|
||||||
missing_source_label->set_h_size_flags(SIZE_EXPAND_FILL);
|
missing_source_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||||
missing_source_label->set_v_size_flags(SIZE_EXPAND_FILL);
|
missing_source_label->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||||
missing_source_label->set_align(Label::ALIGN_CENTER);
|
missing_source_label->set_align(Label::ALIGN_CENTER);
|
||||||
missing_source_label->set_valign(Label::VALIGN_CENTER);
|
missing_source_label->set_valign(Label::VALIGN_CENTER);
|
||||||
missing_source_label->hide();
|
missing_source_label->hide();
|
||||||
add_child(missing_source_label);
|
tiles_bottom_panel->add_child(missing_source_label);
|
||||||
|
|
||||||
atlas_sources_split_container = memnew(HSplitContainer);
|
atlas_sources_split_container = memnew(HSplitContainer);
|
||||||
atlas_sources_split_container->set_h_size_flags(SIZE_EXPAND_FILL);
|
atlas_sources_split_container->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||||
atlas_sources_split_container->set_v_size_flags(SIZE_EXPAND_FILL);
|
atlas_sources_split_container->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||||
add_child(atlas_sources_split_container);
|
tiles_bottom_panel->add_child(atlas_sources_split_container);
|
||||||
|
|
||||||
sources_list = memnew(ItemList);
|
sources_list = memnew(ItemList);
|
||||||
sources_list->set_fixed_icon_size(Size2i(60, 60) * EDSCALE);
|
sources_list->set_fixed_icon_size(Size2i(60, 60) * EDSCALE);
|
||||||
sources_list->set_h_size_flags(SIZE_EXPAND_FILL);
|
sources_list->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||||
sources_list->set_stretch_ratio(0.25);
|
sources_list->set_stretch_ratio(0.25);
|
||||||
sources_list->set_custom_minimum_size(Size2i(70, 0) * EDSCALE);
|
sources_list->set_custom_minimum_size(Size2i(70, 0) * EDSCALE);
|
||||||
sources_list->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
|
sources_list->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
|
||||||
sources_list->connect("item_selected", callable_mp(this, &TileMapEditorTilesPlugin::_update_fix_selected_and_hovered).unbind(1));
|
sources_list->connect("item_selected", callable_mp(this, &TileMapEditorTilesPlugin::_update_fix_selected_and_hovered).unbind(1));
|
||||||
sources_list->connect("item_selected", callable_mp(this, &TileMapEditorTilesPlugin::_update_bottom_panel).unbind(1));
|
sources_list->connect("item_selected", callable_mp(this, &TileMapEditorTilesPlugin::_update_source_display).unbind(1));
|
||||||
sources_list->connect("item_selected", callable_mp(TilesEditor::get_singleton(), &TilesEditor::set_sources_lists_current));
|
sources_list->connect("item_selected", callable_mp(TilesEditor::get_singleton(), &TilesEditor::set_sources_lists_current));
|
||||||
sources_list->connect("visibility_changed", callable_mp(TilesEditor::get_singleton(), &TilesEditor::synchronize_sources_list), varray(sources_list));
|
sources_list->connect("visibility_changed", callable_mp(TilesEditor::get_singleton(), &TilesEditor::synchronize_sources_list), varray(sources_list));
|
||||||
atlas_sources_split_container->add_child(sources_list);
|
atlas_sources_split_container->add_child(sources_list);
|
||||||
|
|
||||||
// Tile atlas source.
|
// Tile atlas source.
|
||||||
tile_atlas_view = memnew(TileAtlasView);
|
tile_atlas_view = memnew(TileAtlasView);
|
||||||
tile_atlas_view->set_h_size_flags(SIZE_EXPAND_FILL);
|
tile_atlas_view->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||||
tile_atlas_view->set_v_size_flags(SIZE_EXPAND_FILL);
|
tile_atlas_view->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||||
tile_atlas_view->set_texture_grid_visible(false);
|
tile_atlas_view->set_texture_grid_visible(false);
|
||||||
tile_atlas_view->set_tile_shape_grid_visible(false);
|
tile_atlas_view->set_tile_shape_grid_visible(false);
|
||||||
tile_atlas_view->connect("transform_changed", callable_mp(TilesEditor::get_singleton(), &TilesEditor::set_atlas_view_transform));
|
tile_atlas_view->connect("transform_changed", callable_mp(TilesEditor::get_singleton(), &TilesEditor::set_atlas_view_transform));
|
||||||
|
@ -1994,8 +2143,8 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
|
||||||
|
|
||||||
// Scenes collection source.
|
// Scenes collection source.
|
||||||
scene_tiles_list = memnew(ItemList);
|
scene_tiles_list = memnew(ItemList);
|
||||||
scene_tiles_list->set_h_size_flags(SIZE_EXPAND_FILL);
|
scene_tiles_list->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||||
scene_tiles_list->set_v_size_flags(SIZE_EXPAND_FILL);
|
scene_tiles_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||||
scene_tiles_list->set_drag_forwarding(this);
|
scene_tiles_list->set_drag_forwarding(this);
|
||||||
scene_tiles_list->set_select_mode(ItemList::SELECT_MULTI);
|
scene_tiles_list->set_select_mode(ItemList::SELECT_MULTI);
|
||||||
scene_tiles_list->connect("multi_selected", callable_mp(this, &TileMapEditorTilesPlugin::_scenes_list_multi_selected));
|
scene_tiles_list->connect("multi_selected", callable_mp(this, &TileMapEditorTilesPlugin::_scenes_list_multi_selected));
|
||||||
|
@ -2006,30 +2155,42 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
|
||||||
// Invalid source label.
|
// Invalid source label.
|
||||||
invalid_source_label = memnew(Label);
|
invalid_source_label = memnew(Label);
|
||||||
invalid_source_label->set_text(TTR("Invalid source selected."));
|
invalid_source_label->set_text(TTR("Invalid source selected."));
|
||||||
invalid_source_label->set_h_size_flags(SIZE_EXPAND_FILL);
|
invalid_source_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||||
invalid_source_label->set_v_size_flags(SIZE_EXPAND_FILL);
|
invalid_source_label->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||||
invalid_source_label->set_align(Label::ALIGN_CENTER);
|
invalid_source_label->set_align(Label::ALIGN_CENTER);
|
||||||
invalid_source_label->set_valign(Label::VALIGN_CENTER);
|
invalid_source_label->set_valign(Label::VALIGN_CENTER);
|
||||||
invalid_source_label->hide();
|
invalid_source_label->hide();
|
||||||
atlas_sources_split_container->add_child(invalid_source_label);
|
atlas_sources_split_container->add_child(invalid_source_label);
|
||||||
|
|
||||||
_update_bottom_panel();
|
// --- Bottom panel patterns ---
|
||||||
|
patterns_bottom_panel = memnew(VBoxContainer);
|
||||||
|
patterns_bottom_panel->set_name(TTR("Patterns"));
|
||||||
|
patterns_bottom_panel->connect("visibility_changed", callable_mp(this, &TileMapEditorTilesPlugin::_tab_changed));
|
||||||
|
|
||||||
|
int thumbnail_size = 64;
|
||||||
|
patterns_item_list = memnew(ItemList);
|
||||||
|
patterns_item_list->set_max_columns(0);
|
||||||
|
patterns_item_list->set_icon_mode(ItemList::ICON_MODE_TOP);
|
||||||
|
patterns_item_list->set_fixed_column_width(thumbnail_size * 3 / 2);
|
||||||
|
patterns_item_list->set_max_text_lines(2);
|
||||||
|
patterns_item_list->set_fixed_icon_size(Size2(thumbnail_size, thumbnail_size));
|
||||||
|
patterns_item_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||||
|
patterns_item_list->connect("gui_input", callable_mp(this, &TileMapEditorTilesPlugin::_patterns_item_list_gui_input));
|
||||||
|
patterns_item_list->connect("item_selected", callable_mp(this, &TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_pattern_selection).unbind(1));
|
||||||
|
patterns_item_list->connect("item_activated", callable_mp(this, &TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_pattern_selection));
|
||||||
|
patterns_item_list->connect("nothing_selected", callable_mp(this, &TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_pattern_selection));
|
||||||
|
patterns_bottom_panel->add_child(patterns_item_list);
|
||||||
|
|
||||||
|
patterns_help_label = memnew(Label);
|
||||||
|
patterns_help_label->set_text(TTR("Drag and drop or paste a TileMap selection here to store a pattern."));
|
||||||
|
patterns_help_label->set_anchors_and_offsets_preset(Control::PRESET_CENTER);
|
||||||
|
patterns_item_list->add_child(patterns_help_label);
|
||||||
|
|
||||||
|
// Update.
|
||||||
|
_update_source_display();
|
||||||
}
|
}
|
||||||
|
|
||||||
TileMapEditorTilesPlugin::~TileMapEditorTilesPlugin() {
|
TileMapEditorTilesPlugin::~TileMapEditorTilesPlugin() {
|
||||||
memdelete(selection_pattern);
|
|
||||||
memdelete(tile_map_clipboard);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TileMapEditorTerrainsPlugin::_notification(int p_what) {
|
|
||||||
switch (p_what) {
|
|
||||||
case NOTIFICATION_ENTER_TREE:
|
|
||||||
case NOTIFICATION_THEME_CHANGED:
|
|
||||||
paint_tool_button->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
|
|
||||||
picker_button->set_icon(get_theme_icon(SNAME("ColorPick"), SNAME("EditorIcons")));
|
|
||||||
erase_button->set_icon(get_theme_icon(SNAME("Eraser"), SNAME("EditorIcons")));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileMapEditorTerrainsPlugin::tile_set_changed() {
|
void TileMapEditorTerrainsPlugin::tile_set_changed() {
|
||||||
|
@ -2052,8 +2213,10 @@ void TileMapEditorTerrainsPlugin::_update_toolbar() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Control *TileMapEditorTerrainsPlugin::get_toolbar() const {
|
Vector<TileMapEditorPlugin::TabData> TileMapEditorTerrainsPlugin::get_tabs() const {
|
||||||
return toolbar;
|
Vector<TileMapEditorPlugin::TabData> tabs;
|
||||||
|
tabs.push_back({ toolbar, main_vbox_container });
|
||||||
|
return tabs;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<Vector2i, TileSet::CellNeighbor> TileMapEditorTerrainsPlugin::Constraint::get_overlapping_coords_and_peering_bits() const {
|
Map<Vector2i, TileSet::CellNeighbor> TileMapEditorTerrainsPlugin::Constraint::get_overlapping_coords_and_peering_bits() const {
|
||||||
|
@ -2811,7 +2974,7 @@ void TileMapEditorTerrainsPlugin::_stop_dragging() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
|
bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
|
||||||
if (!is_visible_in_tree()) {
|
if (!main_vbox_container->is_visible_in_tree()) {
|
||||||
// If the bottom editor is not visible, we ignore inputs.
|
// If the bottom editor is not visible, we ignore inputs.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -3083,13 +3246,13 @@ void TileMapEditorTerrainsPlugin::_update_terrains_tree() {
|
||||||
TreeItem *terrain_set_tree_item = terrains_tree->create_item();
|
TreeItem *terrain_set_tree_item = terrains_tree->create_item();
|
||||||
String matches;
|
String matches;
|
||||||
if (tile_set->get_terrain_set_mode(terrain_set_index) == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
|
if (tile_set->get_terrain_set_mode(terrain_set_index) == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
|
||||||
terrain_set_tree_item->set_icon(0, get_theme_icon(SNAME("TerrainMatchCornersAndSides"), SNAME("EditorIcons")));
|
terrain_set_tree_item->set_icon(0, main_vbox_container->get_theme_icon(SNAME("TerrainMatchCornersAndSides"), SNAME("EditorIcons")));
|
||||||
matches = String(TTR("Matches Corners and Sides"));
|
matches = String(TTR("Matches Corners and Sides"));
|
||||||
} else if (tile_set->get_terrain_set_mode(terrain_set_index) == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
|
} else if (tile_set->get_terrain_set_mode(terrain_set_index) == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
|
||||||
terrain_set_tree_item->set_icon(0, get_theme_icon(SNAME("TerrainMatchCorners"), SNAME("EditorIcons")));
|
terrain_set_tree_item->set_icon(0, main_vbox_container->get_theme_icon(SNAME("TerrainMatchCorners"), SNAME("EditorIcons")));
|
||||||
matches = String(TTR("Matches Corners Only"));
|
matches = String(TTR("Matches Corners Only"));
|
||||||
} else {
|
} else {
|
||||||
terrain_set_tree_item->set_icon(0, get_theme_icon(SNAME("TerrainMatchSides"), SNAME("EditorIcons")));
|
terrain_set_tree_item->set_icon(0, main_vbox_container->get_theme_icon(SNAME("TerrainMatchSides"), SNAME("EditorIcons")));
|
||||||
matches = String(TTR("Matches Sides Only"));
|
matches = String(TTR("Matches Sides Only"));
|
||||||
}
|
}
|
||||||
terrain_set_tree_item->set_text(0, vformat("Terrain Set %d (%s)", terrain_set_index, matches));
|
terrain_set_tree_item->set_text(0, vformat("Terrain Set %d (%s)", terrain_set_index, matches));
|
||||||
|
@ -3194,6 +3357,12 @@ void TileMapEditorTerrainsPlugin::_update_tiles_list() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TileMapEditorTerrainsPlugin::_update_theme() {
|
||||||
|
paint_tool_button->set_icon(main_vbox_container->get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
|
||||||
|
picker_button->set_icon(main_vbox_container->get_theme_icon(SNAME("ColorPick"), SNAME("EditorIcons")));
|
||||||
|
erase_button->set_icon(main_vbox_container->get_theme_icon(SNAME("Eraser"), SNAME("EditorIcons")));
|
||||||
|
}
|
||||||
|
|
||||||
void TileMapEditorTerrainsPlugin::edit(ObjectID p_tile_map_id, int p_tile_map_layer) {
|
void TileMapEditorTerrainsPlugin::edit(ObjectID p_tile_map_id, int p_tile_map_layer) {
|
||||||
_stop_dragging(); // Avoids staying in a wrong drag state.
|
_stop_dragging(); // Avoids staying in a wrong drag state.
|
||||||
|
|
||||||
|
@ -3206,15 +3375,18 @@ void TileMapEditorTerrainsPlugin::edit(ObjectID p_tile_map_id, int p_tile_map_la
|
||||||
}
|
}
|
||||||
|
|
||||||
TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() {
|
TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() {
|
||||||
set_name("Terrains");
|
main_vbox_container = memnew(VBoxContainer);
|
||||||
|
main_vbox_container->connect("tree_entered", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_theme));
|
||||||
|
main_vbox_container->connect("theme_changed", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_theme));
|
||||||
|
main_vbox_container->set_name("Terrains");
|
||||||
|
|
||||||
HSplitContainer *tilemap_tab_terrains = memnew(HSplitContainer);
|
HSplitContainer *tilemap_tab_terrains = memnew(HSplitContainer);
|
||||||
tilemap_tab_terrains->set_h_size_flags(SIZE_EXPAND_FILL);
|
tilemap_tab_terrains->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||||
tilemap_tab_terrains->set_v_size_flags(SIZE_EXPAND_FILL);
|
tilemap_tab_terrains->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||||
add_child(tilemap_tab_terrains);
|
main_vbox_container->add_child(tilemap_tab_terrains);
|
||||||
|
|
||||||
terrains_tree = memnew(Tree);
|
terrains_tree = memnew(Tree);
|
||||||
terrains_tree->set_h_size_flags(SIZE_EXPAND_FILL);
|
terrains_tree->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||||
terrains_tree->set_stretch_ratio(0.25);
|
terrains_tree->set_stretch_ratio(0.25);
|
||||||
terrains_tree->set_custom_minimum_size(Size2i(70, 0) * EDSCALE);
|
terrains_tree->set_custom_minimum_size(Size2i(70, 0) * EDSCALE);
|
||||||
terrains_tree->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
|
terrains_tree->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
|
||||||
|
@ -3223,7 +3395,7 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() {
|
||||||
tilemap_tab_terrains->add_child(terrains_tree);
|
tilemap_tab_terrains->add_child(terrains_tree);
|
||||||
|
|
||||||
terrains_tile_list = memnew(ItemList);
|
terrains_tile_list = memnew(ItemList);
|
||||||
terrains_tile_list->set_h_size_flags(SIZE_EXPAND_FILL);
|
terrains_tile_list->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||||
terrains_tile_list->set_max_columns(0);
|
terrains_tile_list->set_max_columns(0);
|
||||||
terrains_tile_list->set_same_column_width(true);
|
terrains_tile_list->set_same_column_width(true);
|
||||||
terrains_tile_list->set_fixed_icon_size(Size2(30, 30) * EDSCALE);
|
terrains_tile_list->set_fixed_icon_size(Size2(30, 30) * EDSCALE);
|
||||||
|
@ -3290,7 +3462,7 @@ void TileMapEditor::_notification(int p_what) {
|
||||||
if (is_visible_in_tree() && tileset_changed_needs_update) {
|
if (is_visible_in_tree() && tileset_changed_needs_update) {
|
||||||
_update_bottom_panel();
|
_update_bottom_panel();
|
||||||
_update_layers_selection();
|
_update_layers_selection();
|
||||||
tile_map_editor_plugins[tabs->get_current_tab()]->tile_set_changed();
|
tabs_plugins[tabs_bar->get_current_tab()]->tile_set_changed();
|
||||||
CanvasItemEditor::get_singleton()->update_viewport();
|
CanvasItemEditor::get_singleton()->update_viewport();
|
||||||
tileset_changed_needs_update = false;
|
tileset_changed_needs_update = false;
|
||||||
}
|
}
|
||||||
|
@ -3414,14 +3586,11 @@ void TileMapEditor::_update_bottom_panel() {
|
||||||
|
|
||||||
// Update the visibility of controls.
|
// Update the visibility of controls.
|
||||||
missing_tileset_label->set_visible(!tile_set.is_valid());
|
missing_tileset_label->set_visible(!tile_set.is_valid());
|
||||||
if (!tile_set.is_valid()) {
|
for (unsigned int tab_index = 0; tab_index < tabs_data.size(); tab_index++) {
|
||||||
for (int i = 0; i < tile_map_editor_plugins.size(); i++) {
|
tabs_data[tab_index].panel->hide();
|
||||||
tile_map_editor_plugins[i]->hide();
|
}
|
||||||
}
|
if (tile_set.is_valid()) {
|
||||||
} else {
|
tabs_data[tabs_bar->get_current_tab()].panel->show();
|
||||||
for (int i = 0; i < tile_map_editor_plugins.size(); i++) {
|
|
||||||
tile_map_editor_plugins[i]->set_visible(i == tabs->get_current_tab());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3504,27 +3673,25 @@ void TileMapEditor::_tile_map_changed() {
|
||||||
|
|
||||||
void TileMapEditor::_tab_changed(int p_tab_id) {
|
void TileMapEditor::_tab_changed(int p_tab_id) {
|
||||||
// Make the plugin edit the correct tilemap.
|
// Make the plugin edit the correct tilemap.
|
||||||
tile_map_editor_plugins[tabs->get_current_tab()]->edit(tile_map_id, tile_map_layer);
|
tabs_plugins[tabs_bar->get_current_tab()]->edit(tile_map_id, tile_map_layer);
|
||||||
|
|
||||||
// Update toolbar.
|
// Update toolbar.
|
||||||
for (int i = 0; i < tile_map_editor_plugins.size(); i++) {
|
for (unsigned int tab_index = 0; tab_index < tabs_data.size(); tab_index++) {
|
||||||
tile_map_editor_plugins[i]->get_toolbar()->set_visible(i == p_tab_id);
|
tabs_data[tab_index].toolbar->hide();
|
||||||
}
|
}
|
||||||
|
tabs_data[p_tab_id].toolbar->show();
|
||||||
|
|
||||||
// Update visible panel.
|
// Update visible panel.
|
||||||
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
|
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
|
||||||
if (!tile_map || !tile_map->get_tileset().is_valid()) {
|
for (unsigned int tab_index = 0; tab_index < tabs_data.size(); tab_index++) {
|
||||||
for (int i = 0; i < tile_map_editor_plugins.size(); i++) {
|
tabs_data[tab_index].panel->hide();
|
||||||
tile_map_editor_plugins[i]->hide();
|
}
|
||||||
}
|
if (tile_map && tile_map->get_tileset().is_valid()) {
|
||||||
} else {
|
tabs_data[tabs_bar->get_current_tab()].panel->show();
|
||||||
for (int i = 0; i < tile_map_editor_plugins.size(); i++) {
|
|
||||||
tile_map_editor_plugins[i]->set_visible(i == tabs->get_current_tab());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Graphical update.
|
// Graphical update.
|
||||||
tile_map_editor_plugins[tabs->get_current_tab()]->update();
|
tabs_data[tabs_bar->get_current_tab()].panel->update();
|
||||||
CanvasItemEditor::get_singleton()->update_viewport();
|
CanvasItemEditor::get_singleton()->update_viewport();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3611,7 +3778,7 @@ void TileMapEditor::_update_layers_selection() {
|
||||||
layers_selection_button->set_custom_minimum_size(min_button_size);
|
layers_selection_button->set_custom_minimum_size(min_button_size);
|
||||||
layers_selection_button->update();
|
layers_selection_button->update();
|
||||||
|
|
||||||
tile_map_editor_plugins[tabs->get_current_tab()]->edit(tile_map_id, tile_map_layer);
|
tabs_plugins[tabs_bar->get_current_tab()]->edit(tile_map_id, tile_map_layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileMapEditor::_move_tile_map_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) {
|
void TileMapEditor::_move_tile_map_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) {
|
||||||
|
@ -3697,7 +3864,7 @@ bool TileMapEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return tile_map_editor_plugins[tabs->get_current_tab()]->forward_canvas_gui_input(p_event);
|
return tabs_plugins[tabs_bar->get_current_tab()]->forward_canvas_gui_input(p_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
|
void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
|
||||||
|
@ -3832,7 +3999,7 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
// Draw the plugins.
|
// Draw the plugins.
|
||||||
tile_map_editor_plugins[tabs->get_current_tab()]->forward_canvas_draw_over_viewport(p_overlay);
|
tabs_plugins[tabs_bar->get_current_tab()]->forward_canvas_draw_over_viewport(p_overlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileMapEditor::edit(TileMap *p_tile_map) {
|
void TileMapEditor::edit(TileMap *p_tile_map) {
|
||||||
|
@ -3866,7 +4033,7 @@ void TileMapEditor::edit(TileMap *p_tile_map) {
|
||||||
_update_layers_selection();
|
_update_layers_selection();
|
||||||
|
|
||||||
// Call the plugins.
|
// Call the plugins.
|
||||||
tile_map_editor_plugins[tabs->get_current_tab()]->edit(tile_map_id, tile_map_layer);
|
tabs_plugins[tabs_bar->get_current_tab()]->edit(tile_map_id, tile_map_layer);
|
||||||
|
|
||||||
_tile_map_changed();
|
_tile_map_changed();
|
||||||
}
|
}
|
||||||
|
@ -3883,24 +4050,31 @@ TileMapEditor::TileMapEditor() {
|
||||||
tile_map_editor_plugins.push_back(memnew(TileMapEditorTerrainsPlugin));
|
tile_map_editor_plugins.push_back(memnew(TileMapEditorTerrainsPlugin));
|
||||||
|
|
||||||
// Tabs.
|
// Tabs.
|
||||||
tabs = memnew(Tabs);
|
tabs_bar = memnew(Tabs);
|
||||||
tabs->set_clip_tabs(false);
|
tabs_bar->set_clip_tabs(false);
|
||||||
for (int i = 0; i < tile_map_editor_plugins.size(); i++) {
|
for (int plugin_index = 0; plugin_index < tile_map_editor_plugins.size(); plugin_index++) {
|
||||||
tabs->add_tab(tile_map_editor_plugins[i]->get_name());
|
Vector<TileMapEditorPlugin::TabData> tabs_vector = tile_map_editor_plugins[plugin_index]->get_tabs();
|
||||||
|
for (int tab_index = 0; tab_index < tabs_vector.size(); tab_index++) {
|
||||||
|
tabs_bar->add_tab(tabs_vector[tab_index].panel->get_name());
|
||||||
|
tabs_data.push_back(tabs_vector[tab_index]);
|
||||||
|
tabs_plugins.push_back(tile_map_editor_plugins[plugin_index]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tabs->connect("tab_changed", callable_mp(this, &TileMapEditor::_tab_changed));
|
tabs_bar->connect("tab_changed", callable_mp(this, &TileMapEditor::_tab_changed));
|
||||||
|
|
||||||
// --- TileMap toolbar ---
|
// --- TileMap toolbar ---
|
||||||
tile_map_toolbar = memnew(HBoxContainer);
|
tile_map_toolbar = memnew(HBoxContainer);
|
||||||
tile_map_toolbar->set_h_size_flags(SIZE_EXPAND_FILL);
|
tile_map_toolbar->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||||
|
|
||||||
// Tabs.
|
// Tabs.
|
||||||
tile_map_toolbar->add_child(tabs);
|
tile_map_toolbar->add_child(tabs_bar);
|
||||||
|
|
||||||
// Tabs toolbars.
|
// Tabs toolbars.
|
||||||
for (int i = 0; i < tile_map_editor_plugins.size(); i++) {
|
for (unsigned int tab_index = 0; tab_index < tabs_data.size(); tab_index++) {
|
||||||
tile_map_editor_plugins[i]->get_toolbar()->hide();
|
tabs_data[tab_index].toolbar->hide();
|
||||||
tile_map_toolbar->add_child(tile_map_editor_plugins[i]->get_toolbar());
|
if (!tabs_data[tab_index].toolbar->get_parent()) {
|
||||||
|
tile_map_toolbar->add_child(tabs_data[tab_index].toolbar);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wide empty separation control.
|
// Wide empty separation control.
|
||||||
|
@ -3956,11 +4130,11 @@ TileMapEditor::TileMapEditor() {
|
||||||
missing_tileset_label->hide();
|
missing_tileset_label->hide();
|
||||||
add_child(missing_tileset_label);
|
add_child(missing_tileset_label);
|
||||||
|
|
||||||
for (int i = 0; i < tile_map_editor_plugins.size(); i++) {
|
for (unsigned int tab_index = 0; tab_index < tabs_data.size(); tab_index++) {
|
||||||
add_child(tile_map_editor_plugins[i]);
|
add_child(tabs_data[tab_index].panel);
|
||||||
tile_map_editor_plugins[i]->set_h_size_flags(SIZE_EXPAND_FILL);
|
tabs_data[tab_index].panel->set_v_size_flags(SIZE_EXPAND_FILL);
|
||||||
tile_map_editor_plugins[i]->set_v_size_flags(SIZE_EXPAND_FILL);
|
tabs_data[tab_index].panel->set_visible(tab_index == 0);
|
||||||
tile_map_editor_plugins[i]->set_visible(i == 0);
|
tabs_data[tab_index].panel->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||||
}
|
}
|
||||||
|
|
||||||
_tab_changed(0);
|
_tab_changed(0);
|
||||||
|
@ -3970,4 +4144,7 @@ TileMapEditor::TileMapEditor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
TileMapEditor::~TileMapEditor() {
|
TileMapEditor::~TileMapEditor() {
|
||||||
|
for (int i = 0; i < tile_map_editor_plugins.size(); i++) {
|
||||||
|
memdelete(tile_map_editor_plugins[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,17 +33,24 @@
|
||||||
|
|
||||||
#include "tile_atlas_view.h"
|
#include "tile_atlas_view.h"
|
||||||
|
|
||||||
|
#include "core/os/thread.h"
|
||||||
#include "core/typedefs.h"
|
#include "core/typedefs.h"
|
||||||
#include "editor/editor_node.h"
|
#include "editor/editor_node.h"
|
||||||
#include "scene/2d/tile_map.h"
|
#include "scene/2d/tile_map.h"
|
||||||
#include "scene/gui/box_container.h"
|
#include "scene/gui/box_container.h"
|
||||||
#include "scene/gui/tabs.h"
|
#include "scene/gui/tabs.h"
|
||||||
|
|
||||||
class TileMapEditorPlugin : public VBoxContainer {
|
class TileMapEditorPlugin : public Object {
|
||||||
public:
|
public:
|
||||||
virtual Control *get_toolbar() const {
|
struct TabData {
|
||||||
return memnew(Control);
|
Control *toolbar;
|
||||||
|
Control *panel;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
virtual Vector<TabData> get_tabs() const {
|
||||||
|
return Vector<TabData>();
|
||||||
|
};
|
||||||
|
|
||||||
virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return false; };
|
virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return false; };
|
||||||
virtual void forward_canvas_draw_over_viewport(Control *p_overlay){};
|
virtual void forward_canvas_draw_over_viewport(Control *p_overlay){};
|
||||||
virtual void tile_set_changed(){};
|
virtual void tile_set_changed(){};
|
||||||
|
@ -106,7 +113,7 @@ private:
|
||||||
Map<Vector2i, TileMapCell> drag_modified;
|
Map<Vector2i, TileMapCell> drag_modified;
|
||||||
bool rmb_erasing = false;
|
bool rmb_erasing = false;
|
||||||
|
|
||||||
TileMapCell _pick_random_tile(const TileMapPattern *p_pattern);
|
TileMapCell _pick_random_tile(Ref<TileMapPattern> p_pattern);
|
||||||
Map<Vector2i, TileMapCell> _draw_line(Vector2 p_start_drag_mouse_pos, Vector2 p_from_mouse_pos, Vector2 p_to_mouse_pos);
|
Map<Vector2i, TileMapCell> _draw_line(Vector2 p_start_drag_mouse_pos, Vector2 p_from_mouse_pos, Vector2 p_to_mouse_pos);
|
||||||
Map<Vector2i, TileMapCell> _draw_rect(Vector2i p_start_cell, Vector2i p_end_cell);
|
Map<Vector2i, TileMapCell> _draw_rect(Vector2i p_start_cell, Vector2i p_end_cell);
|
||||||
Map<Vector2i, TileMapCell> _draw_bucket_fill(Vector2i p_coords, bool p_contiguous);
|
Map<Vector2i, TileMapCell> _draw_bucket_fill(Vector2i p_coords, bool p_contiguous);
|
||||||
|
@ -115,20 +122,25 @@ private:
|
||||||
|
|
||||||
///// Selection system. /////
|
///// Selection system. /////
|
||||||
Set<Vector2i> tile_map_selection;
|
Set<Vector2i> tile_map_selection;
|
||||||
TileMapPattern *tile_map_clipboard = memnew(TileMapPattern);
|
Ref<TileMapPattern> tile_map_clipboard;
|
||||||
TileMapPattern *selection_pattern = memnew(TileMapPattern);
|
Ref<TileMapPattern> selection_pattern;
|
||||||
void _set_tile_map_selection(const TypedArray<Vector2i> &p_selection);
|
void _set_tile_map_selection(const TypedArray<Vector2i> &p_selection);
|
||||||
TypedArray<Vector2i> _get_tile_map_selection() const;
|
TypedArray<Vector2i> _get_tile_map_selection() const;
|
||||||
|
|
||||||
Set<TileMapCell> tile_set_selection;
|
Set<TileMapCell> tile_set_selection;
|
||||||
|
|
||||||
void _update_selection_pattern_from_tilemap_selection();
|
void _update_selection_pattern_from_tilemap_selection();
|
||||||
void _update_selection_pattern_from_tileset_selection();
|
void _update_selection_pattern_from_tileset_tiles_selection();
|
||||||
|
void _update_selection_pattern_from_tileset_pattern_selection();
|
||||||
void _update_tileset_selection_from_selection_pattern();
|
void _update_tileset_selection_from_selection_pattern();
|
||||||
void _update_fix_selected_and_hovered();
|
void _update_fix_selected_and_hovered();
|
||||||
void _fix_invalid_tiles_in_tile_map_selection();
|
void _fix_invalid_tiles_in_tile_map_selection();
|
||||||
|
|
||||||
///// Bottom panel. ////.
|
///// Bottom panel common ////
|
||||||
|
void _tab_changed();
|
||||||
|
|
||||||
|
///// Bottom panel tiles ////
|
||||||
|
VBoxContainer *tiles_bottom_panel;
|
||||||
Label *missing_source_label;
|
Label *missing_source_label;
|
||||||
Label *invalid_source_label;
|
Label *invalid_source_label;
|
||||||
|
|
||||||
|
@ -137,7 +149,7 @@ private:
|
||||||
Ref<Texture2D> missing_atlas_texture_icon;
|
Ref<Texture2D> missing_atlas_texture_icon;
|
||||||
void _update_tile_set_sources_list();
|
void _update_tile_set_sources_list();
|
||||||
|
|
||||||
void _update_bottom_panel();
|
void _update_source_display();
|
||||||
|
|
||||||
// Atlas sources.
|
// Atlas sources.
|
||||||
TileMapCell hovered_tile;
|
TileMapCell hovered_tile;
|
||||||
|
@ -167,15 +179,26 @@ private:
|
||||||
void _scenes_list_multi_selected(int p_index, bool p_selected);
|
void _scenes_list_multi_selected(int p_index, bool p_selected);
|
||||||
void _scenes_list_nothing_selected();
|
void _scenes_list_nothing_selected();
|
||||||
|
|
||||||
|
///// Bottom panel patterns ////
|
||||||
|
VBoxContainer *patterns_bottom_panel;
|
||||||
|
ItemList *patterns_item_list;
|
||||||
|
Label *patterns_help_label;
|
||||||
|
void _patterns_item_list_gui_input(const Ref<InputEvent> &p_event);
|
||||||
|
void _pattern_preview_done(Ref<TileMapPattern> p_pattern, Ref<Texture2D> p_texture);
|
||||||
|
bool select_last_pattern = false;
|
||||||
|
void _update_patterns_list();
|
||||||
|
|
||||||
|
// General
|
||||||
|
void _update_theme();
|
||||||
|
|
||||||
// Update callback
|
// Update callback
|
||||||
virtual void tile_set_changed() override;
|
virtual void tile_set_changed() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void _notification(int p_what);
|
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual Control *get_toolbar() const override;
|
virtual Vector<TabData> get_tabs() const override;
|
||||||
virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override;
|
virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override;
|
||||||
virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override;
|
virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override;
|
||||||
|
|
||||||
|
@ -205,6 +228,9 @@ private:
|
||||||
|
|
||||||
void _update_toolbar();
|
void _update_toolbar();
|
||||||
|
|
||||||
|
// Main vbox.
|
||||||
|
VBoxContainer *main_vbox_container;
|
||||||
|
|
||||||
// TileMap editing.
|
// TileMap editing.
|
||||||
enum DragType {
|
enum DragType {
|
||||||
DRAG_TYPE_NONE = 0,
|
DRAG_TYPE_NONE = 0,
|
||||||
|
@ -281,16 +307,13 @@ private:
|
||||||
void _update_terrains_cache();
|
void _update_terrains_cache();
|
||||||
void _update_terrains_tree();
|
void _update_terrains_tree();
|
||||||
void _update_tiles_list();
|
void _update_tiles_list();
|
||||||
|
void _update_theme();
|
||||||
|
|
||||||
// Update callback
|
// Update callback
|
||||||
virtual void tile_set_changed() override;
|
virtual void tile_set_changed() override;
|
||||||
|
|
||||||
protected:
|
|
||||||
void _notification(int p_what);
|
|
||||||
// static void _bind_methods();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual Control *get_toolbar() const override;
|
virtual Vector<TabData> get_tabs() const override;
|
||||||
virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override;
|
virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override;
|
||||||
//virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override;
|
//virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override;
|
||||||
|
|
||||||
|
@ -328,7 +351,9 @@ private:
|
||||||
|
|
||||||
// Bottom panel.
|
// Bottom panel.
|
||||||
Label *missing_tileset_label;
|
Label *missing_tileset_label;
|
||||||
Tabs *tabs;
|
Tabs *tabs_bar;
|
||||||
|
LocalVector<TileMapEditorPlugin::TabData> tabs_data;
|
||||||
|
LocalVector<TileMapEditorPlugin *> tabs_plugins;
|
||||||
void _update_bottom_panel();
|
void _update_bottom_panel();
|
||||||
|
|
||||||
// TileMap.
|
// TileMap.
|
||||||
|
|
|
@ -156,9 +156,9 @@ void TileSetEditor::_update_sources_list(int force_selected_id) {
|
||||||
texture = atlas_source->get_texture();
|
texture = atlas_source->get_texture();
|
||||||
if (item_text.is_empty()) {
|
if (item_text.is_empty()) {
|
||||||
if (texture.is_valid()) {
|
if (texture.is_valid()) {
|
||||||
item_text = vformat("%s (id:%d)", texture->get_path().get_file(), source_id);
|
item_text = vformat("%s (ID:%d)", texture->get_path().get_file(), source_id);
|
||||||
} else {
|
} else {
|
||||||
item_text = vformat(TTR("No Texture Atlas Source (id:%d)"), source_id);
|
item_text = vformat(TTR("No Texture Atlas Source (ID:%d)"), source_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,13 +168,13 @@ void TileSetEditor::_update_sources_list(int force_selected_id) {
|
||||||
if (scene_collection_source) {
|
if (scene_collection_source) {
|
||||||
texture = get_theme_icon(SNAME("PackedScene"), SNAME("EditorIcons"));
|
texture = get_theme_icon(SNAME("PackedScene"), SNAME("EditorIcons"));
|
||||||
if (item_text.is_empty()) {
|
if (item_text.is_empty()) {
|
||||||
item_text = vformat(TTR("Scene Collection Source (id:%d)"), source_id);
|
item_text = vformat(TTR("Scene Collection Source (ID:%d)"), source_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use default if not valid.
|
// Use default if not valid.
|
||||||
if (item_text.is_empty()) {
|
if (item_text.is_empty()) {
|
||||||
item_text = vformat(TTR("Unknown Type Source (id:%d)"), source_id);
|
item_text = vformat(TTR("Unknown Type Source (ID:%d)"), source_id);
|
||||||
}
|
}
|
||||||
if (!texture.is_valid()) {
|
if (!texture.is_valid()) {
|
||||||
texture = missing_texture_texture;
|
texture = missing_texture_texture;
|
||||||
|
@ -327,6 +327,7 @@ void TileSetEditor::_notification(int p_what) {
|
||||||
tile_set->set_edited(true);
|
tile_set->set_edited(true);
|
||||||
}
|
}
|
||||||
_update_sources_list();
|
_update_sources_list();
|
||||||
|
_update_patterns_list();
|
||||||
tile_set_changed_needs_update = false;
|
tile_set_changed_needs_update = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -335,10 +336,56 @@ void TileSetEditor::_notification(int p_what) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TileSetEditor::_patterns_item_list_gui_input(const Ref<InputEvent> &p_event) {
|
||||||
|
ERR_FAIL_COND(!tile_set.is_valid());
|
||||||
|
|
||||||
|
if (ED_IS_SHORTCUT("tiles_editor/delete", p_event) && p_event->is_pressed() && !p_event->is_echo()) {
|
||||||
|
Vector<int> selected = patterns_item_list->get_selected_items();
|
||||||
|
undo_redo->create_action(TTR("Remove TileSet patterns"));
|
||||||
|
for (int i = 0; i < selected.size(); i++) {
|
||||||
|
int pattern_index = selected[i];
|
||||||
|
undo_redo->add_do_method(*tile_set, "remove_pattern", pattern_index);
|
||||||
|
undo_redo->add_undo_method(*tile_set, "add_pattern", tile_set->get_pattern(pattern_index), pattern_index);
|
||||||
|
}
|
||||||
|
undo_redo->commit_action();
|
||||||
|
patterns_item_list->accept_event();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TileSetEditor::_pattern_preview_done(Ref<TileMapPattern> p_pattern, Ref<Texture2D> p_texture) {
|
||||||
|
// TODO optimize ?
|
||||||
|
for (int i = 0; i < patterns_item_list->get_item_count(); i++) {
|
||||||
|
if (patterns_item_list->get_item_metadata(i) == p_pattern) {
|
||||||
|
patterns_item_list->set_item_icon(i, p_texture);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TileSetEditor::_update_patterns_list() {
|
||||||
|
ERR_FAIL_COND(!tile_set.is_valid());
|
||||||
|
|
||||||
|
// Recreate the items.
|
||||||
|
patterns_item_list->clear();
|
||||||
|
for (int i = 0; i < tile_set->get_patterns_count(); i++) {
|
||||||
|
int id = patterns_item_list->add_item("");
|
||||||
|
patterns_item_list->set_item_metadata(id, tile_set->get_pattern(i));
|
||||||
|
TilesEditor::get_singleton()->queue_pattern_preview(tile_set, tile_set->get_pattern(i), callable_mp(this, &TileSetEditor::_pattern_preview_done));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the label visibility.
|
||||||
|
patterns_help_label->set_visible(patterns_item_list->get_item_count() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
void TileSetEditor::_tile_set_changed() {
|
void TileSetEditor::_tile_set_changed() {
|
||||||
tile_set_changed_needs_update = true;
|
tile_set_changed_needs_update = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TileSetEditor::_tab_changed(int p_tab_changed) {
|
||||||
|
split_container->set_visible(p_tab_changed == 0);
|
||||||
|
patterns_item_list->set_visible(p_tab_changed == 1);
|
||||||
|
}
|
||||||
|
|
||||||
void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) {
|
void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) {
|
||||||
UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo);
|
UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo);
|
||||||
ERR_FAIL_COND(!undo_redo);
|
ERR_FAIL_COND(!undo_redo);
|
||||||
|
@ -582,6 +629,7 @@ void TileSetEditor::edit(Ref<TileSet> p_tile_set) {
|
||||||
if (tile_set.is_valid()) {
|
if (tile_set.is_valid()) {
|
||||||
tile_set->connect("changed", callable_mp(this, &TileSetEditor::_tile_set_changed));
|
tile_set->connect("changed", callable_mp(this, &TileSetEditor::_tile_set_changed));
|
||||||
_update_sources_list();
|
_update_sources_list();
|
||||||
|
_update_patterns_list();
|
||||||
}
|
}
|
||||||
|
|
||||||
tile_set_atlas_source_editor->hide();
|
tile_set_atlas_source_editor->hide();
|
||||||
|
@ -594,8 +642,20 @@ TileSetEditor::TileSetEditor() {
|
||||||
|
|
||||||
set_process_internal(true);
|
set_process_internal(true);
|
||||||
|
|
||||||
|
// Tabs.
|
||||||
|
tabs_bar = memnew(Tabs);
|
||||||
|
tabs_bar->set_clip_tabs(false);
|
||||||
|
tabs_bar->add_tab(TTR("Tiles"));
|
||||||
|
tabs_bar->add_tab(TTR("Patterns"));
|
||||||
|
tabs_bar->connect("tab_changed", callable_mp(this, &TileSetEditor::_tab_changed));
|
||||||
|
|
||||||
|
tile_set_toolbar = memnew(HBoxContainer);
|
||||||
|
tile_set_toolbar->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||||
|
tile_set_toolbar->add_child(tabs_bar);
|
||||||
|
|
||||||
|
//// Tiles ////
|
||||||
// Split container.
|
// Split container.
|
||||||
HSplitContainer *split_container = memnew(HSplitContainer);
|
split_container = memnew(HSplitContainer);
|
||||||
split_container->set_name(TTR("Tiles"));
|
split_container->set_name(TTR("Tiles"));
|
||||||
split_container->set_h_size_flags(SIZE_EXPAND_FILL);
|
split_container->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||||
split_container->set_v_size_flags(SIZE_EXPAND_FILL);
|
split_container->set_v_size_flags(SIZE_EXPAND_FILL);
|
||||||
|
@ -681,6 +741,24 @@ TileSetEditor::TileSetEditor() {
|
||||||
split_container_right_side->add_child(tile_set_scenes_collection_source_editor);
|
split_container_right_side->add_child(tile_set_scenes_collection_source_editor);
|
||||||
tile_set_scenes_collection_source_editor->hide();
|
tile_set_scenes_collection_source_editor->hide();
|
||||||
|
|
||||||
|
//// Patterns ////
|
||||||
|
int thumbnail_size = 64;
|
||||||
|
patterns_item_list = memnew(ItemList);
|
||||||
|
patterns_item_list->set_max_columns(0);
|
||||||
|
patterns_item_list->set_icon_mode(ItemList::ICON_MODE_TOP);
|
||||||
|
patterns_item_list->set_fixed_column_width(thumbnail_size * 3 / 2);
|
||||||
|
patterns_item_list->set_max_text_lines(2);
|
||||||
|
patterns_item_list->set_fixed_icon_size(Size2(thumbnail_size, thumbnail_size));
|
||||||
|
patterns_item_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||||
|
patterns_item_list->connect("gui_input", callable_mp(this, &TileSetEditor::_patterns_item_list_gui_input));
|
||||||
|
add_child(patterns_item_list);
|
||||||
|
patterns_item_list->hide();
|
||||||
|
|
||||||
|
patterns_help_label = memnew(Label);
|
||||||
|
patterns_help_label->set_text(TTR("Add new patterns in the TileMap editing mode."));
|
||||||
|
patterns_help_label->set_anchors_and_offsets_preset(Control::PRESET_CENTER);
|
||||||
|
patterns_item_list->add_child(patterns_help_label);
|
||||||
|
|
||||||
// Registers UndoRedo inspector callback.
|
// Registers UndoRedo inspector callback.
|
||||||
EditorNode::get_singleton()->get_editor_data().add_move_array_element_function(SNAME("TileSet"), callable_mp(this, &TileSetEditor::_move_tile_set_array_element));
|
EditorNode::get_singleton()->get_editor_data().add_move_array_element_function(SNAME("TileSet"), callable_mp(this, &TileSetEditor::_move_tile_set_array_element));
|
||||||
EditorNode::get_singleton()->get_editor_data().add_undo_redo_inspector_hook_callback(callable_mp(this, &TileSetEditor::_undo_redo_inspector_callback));
|
EditorNode::get_singleton()->get_editor_data().add_undo_redo_inspector_hook_callback(callable_mp(this, &TileSetEditor::_undo_redo_inspector_callback));
|
||||||
|
|
|
@ -46,7 +46,13 @@ class TileSetEditor : public VBoxContainer {
|
||||||
private:
|
private:
|
||||||
Ref<TileSet> tile_set;
|
Ref<TileSet> tile_set;
|
||||||
bool tile_set_changed_needs_update = false;
|
bool tile_set_changed_needs_update = false;
|
||||||
|
HSplitContainer *split_container;
|
||||||
|
|
||||||
|
// Tabs.
|
||||||
|
HBoxContainer *tile_set_toolbar;
|
||||||
|
Tabs *tabs_bar;
|
||||||
|
|
||||||
|
// Tiles.
|
||||||
Label *no_source_selected_label;
|
Label *no_source_selected_label;
|
||||||
TileSetAtlasSourceEditor *tile_set_atlas_source_editor;
|
TileSetAtlasSourceEditor *tile_set_atlas_source_editor;
|
||||||
TileSetScenesCollectionSourceEditor *tile_set_scenes_collection_source_editor;
|
TileSetScenesCollectionSourceEditor *tile_set_scenes_collection_source_editor;
|
||||||
|
@ -69,7 +75,16 @@ private:
|
||||||
AtlasMergingDialog *atlas_merging_dialog;
|
AtlasMergingDialog *atlas_merging_dialog;
|
||||||
TileProxiesManagerDialog *tile_proxies_manager_dialog;
|
TileProxiesManagerDialog *tile_proxies_manager_dialog;
|
||||||
|
|
||||||
|
// Patterns.
|
||||||
|
ItemList *patterns_item_list;
|
||||||
|
Label *patterns_help_label;
|
||||||
|
void _patterns_item_list_gui_input(const Ref<InputEvent> &p_event);
|
||||||
|
void _pattern_preview_done(Ref<TileMapPattern> p_pattern, Ref<Texture2D> p_texture);
|
||||||
|
bool select_last_pattern = false;
|
||||||
|
void _update_patterns_list();
|
||||||
|
|
||||||
void _tile_set_changed();
|
void _tile_set_changed();
|
||||||
|
void _tab_changed(int p_tab_changed);
|
||||||
|
|
||||||
void _move_tile_set_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos);
|
void _move_tile_set_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos);
|
||||||
void _undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value);
|
void _undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value);
|
||||||
|
@ -82,6 +97,8 @@ public:
|
||||||
_FORCE_INLINE_ static TileSetEditor *get_singleton() { return singleton; }
|
_FORCE_INLINE_ static TileSetEditor *get_singleton() { return singleton; }
|
||||||
|
|
||||||
void edit(Ref<TileSet> p_tile_set);
|
void edit(Ref<TileSet> p_tile_set);
|
||||||
|
Control *get_toolbar() { return tile_set_toolbar; };
|
||||||
|
|
||||||
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
|
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
|
||||||
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
|
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
|
||||||
|
|
||||||
|
|
|
@ -30,17 +30,18 @@
|
||||||
|
|
||||||
#include "tiles_editor_plugin.h"
|
#include "tiles_editor_plugin.h"
|
||||||
|
|
||||||
|
#include "core/os/mutex.h"
|
||||||
|
|
||||||
#include "editor/editor_node.h"
|
#include "editor/editor_node.h"
|
||||||
#include "editor/editor_scale.h"
|
#include "editor/editor_scale.h"
|
||||||
#include "editor/plugins/canvas_item_editor_plugin.h"
|
#include "editor/plugins/canvas_item_editor_plugin.h"
|
||||||
|
|
||||||
#include "scene/2d/tile_map.h"
|
#include "scene/2d/tile_map.h"
|
||||||
#include "scene/resources/tile_set.h"
|
|
||||||
|
|
||||||
#include "scene/gui/box_container.h"
|
#include "scene/gui/box_container.h"
|
||||||
#include "scene/gui/button.h"
|
#include "scene/gui/button.h"
|
||||||
#include "scene/gui/control.h"
|
#include "scene/gui/control.h"
|
||||||
#include "scene/gui/separator.h"
|
#include "scene/gui/separator.h"
|
||||||
|
#include "scene/resources/tile_set.h"
|
||||||
|
|
||||||
#include "tile_set_editor.h"
|
#include "tile_set_editor.h"
|
||||||
|
|
||||||
|
@ -65,6 +66,99 @@ void TilesEditor::_notification(int p_what) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TilesEditor::_pattern_preview_done(const Variant &p_udata) {
|
||||||
|
pattern_preview_done.set();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TilesEditor::_thread_func(void *ud) {
|
||||||
|
TilesEditor *te = (TilesEditor *)ud;
|
||||||
|
te->_thread();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TilesEditor::_thread() {
|
||||||
|
pattern_thread_exited.clear();
|
||||||
|
while (!pattern_thread_exit.is_set()) {
|
||||||
|
pattern_preview_sem.wait();
|
||||||
|
|
||||||
|
pattern_preview_mutex.lock();
|
||||||
|
if (pattern_preview_queue.size()) {
|
||||||
|
QueueItem item = pattern_preview_queue.front()->get();
|
||||||
|
pattern_preview_queue.pop_front();
|
||||||
|
pattern_preview_mutex.unlock();
|
||||||
|
|
||||||
|
int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
|
||||||
|
thumbnail_size *= EDSCALE;
|
||||||
|
Vector2 thumbnail_size2 = Vector2(thumbnail_size, thumbnail_size);
|
||||||
|
|
||||||
|
if (item.pattern.is_valid() && !item.pattern->is_empty()) {
|
||||||
|
// Generate the pattern preview
|
||||||
|
SubViewport *viewport = memnew(SubViewport);
|
||||||
|
viewport->set_size(thumbnail_size2);
|
||||||
|
viewport->set_disable_input(true);
|
||||||
|
viewport->set_transparent_background(true);
|
||||||
|
viewport->set_update_mode(SubViewport::UPDATE_ONCE);
|
||||||
|
|
||||||
|
TileMap *tile_map = memnew(TileMap);
|
||||||
|
tile_map->set_tileset(item.tile_set);
|
||||||
|
tile_map->set_pattern(0, Vector2(), item.pattern);
|
||||||
|
viewport->add_child(tile_map);
|
||||||
|
|
||||||
|
TypedArray<Vector2i> used_cells = tile_map->get_used_cells(0);
|
||||||
|
|
||||||
|
Rect2 encompassing_rect = Rect2();
|
||||||
|
encompassing_rect.set_position(tile_map->map_to_world(used_cells[0]));
|
||||||
|
for (int i = 0; i < used_cells.size(); i++) {
|
||||||
|
Vector2i cell = used_cells[i];
|
||||||
|
Vector2 world_pos = tile_map->map_to_world(cell);
|
||||||
|
encompassing_rect.expand_to(world_pos);
|
||||||
|
|
||||||
|
// Texture.
|
||||||
|
Ref<TileSetAtlasSource> atlas_source = tile_set->get_source(tile_map->get_cell_source_id(0, cell));
|
||||||
|
if (atlas_source.is_valid()) {
|
||||||
|
Vector2i coords = tile_map->get_cell_atlas_coords(0, cell);
|
||||||
|
int alternative = tile_map->get_cell_alternative_tile(0, cell);
|
||||||
|
|
||||||
|
Vector2 center = world_pos - atlas_source->get_tile_effective_texture_offset(coords, alternative);
|
||||||
|
encompassing_rect.expand_to(center - atlas_source->get_tile_texture_region(coords).size / 2);
|
||||||
|
encompassing_rect.expand_to(center + atlas_source->get_tile_texture_region(coords).size / 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 scale = thumbnail_size2 / MAX(encompassing_rect.size.x, encompassing_rect.size.y);
|
||||||
|
tile_map->set_scale(scale);
|
||||||
|
tile_map->set_position(-(scale * encompassing_rect.get_center()) + thumbnail_size2 / 2);
|
||||||
|
|
||||||
|
// Add the viewport at the lasst moment to avoid rendering too early.
|
||||||
|
EditorNode::get_singleton()->add_child(viewport);
|
||||||
|
|
||||||
|
pattern_preview_done.clear();
|
||||||
|
RS::get_singleton()->request_frame_drawn_callback(const_cast<TilesEditor *>(this), "_pattern_preview_done", Variant());
|
||||||
|
|
||||||
|
while (!pattern_preview_done.is_set()) {
|
||||||
|
OS::get_singleton()->delay_usec(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<Image> image = viewport->get_texture()->get_image();
|
||||||
|
Ref<ImageTexture> image_texture;
|
||||||
|
image_texture.instantiate();
|
||||||
|
image_texture->create_from_image(image);
|
||||||
|
|
||||||
|
// Find the index for the given pattern. TODO: optimize.
|
||||||
|
Variant args[] = { item.pattern, image_texture };
|
||||||
|
const Variant *args_ptr[] = { &args[0], &args[1] };
|
||||||
|
Variant r;
|
||||||
|
Callable::CallError error;
|
||||||
|
item.callback.call(args_ptr, 2, r, error);
|
||||||
|
|
||||||
|
viewport->queue_delete();
|
||||||
|
} else {
|
||||||
|
pattern_preview_mutex.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pattern_thread_exited.set();
|
||||||
|
}
|
||||||
|
|
||||||
void TilesEditor::_tile_map_changed() {
|
void TilesEditor::_tile_map_changed() {
|
||||||
tile_map_changed_needs_update = true;
|
tile_map_changed_needs_update = true;
|
||||||
}
|
}
|
||||||
|
@ -83,6 +177,7 @@ void TilesEditor::_update_editors() {
|
||||||
// Set editors visibility.
|
// Set editors visibility.
|
||||||
tilemap_toolbar->set_visible(!tileset_tilemap_switch_button->is_pressed());
|
tilemap_toolbar->set_visible(!tileset_tilemap_switch_button->is_pressed());
|
||||||
tilemap_editor->set_visible(!tileset_tilemap_switch_button->is_pressed());
|
tilemap_editor->set_visible(!tileset_tilemap_switch_button->is_pressed());
|
||||||
|
tileset_toolbar->set_visible(tileset_tilemap_switch_button->is_pressed());
|
||||||
tileset_editor->set_visible(tileset_tilemap_switch_button->is_pressed());
|
tileset_editor->set_visible(tileset_tilemap_switch_button->is_pressed());
|
||||||
|
|
||||||
// Enable/disable the switch button.
|
// Enable/disable the switch button.
|
||||||
|
@ -150,6 +245,16 @@ void TilesEditor::synchronize_atlas_view(Object *p_current) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TilesEditor::queue_pattern_preview(Ref<TileSet> p_tile_set, Ref<TileMapPattern> p_pattern, Callable p_callback) {
|
||||||
|
ERR_FAIL_COND(!p_tile_set.is_valid());
|
||||||
|
ERR_FAIL_COND(!p_pattern.is_valid());
|
||||||
|
{
|
||||||
|
MutexLock lock(pattern_preview_mutex);
|
||||||
|
pattern_preview_queue.push_back({ p_tile_set, p_pattern, p_callback });
|
||||||
|
}
|
||||||
|
pattern_preview_sem.post();
|
||||||
|
}
|
||||||
|
|
||||||
void TilesEditor::edit(Object *p_object) {
|
void TilesEditor::edit(Object *p_object) {
|
||||||
// Disconnect to changes.
|
// Disconnect to changes.
|
||||||
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
|
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
|
||||||
|
@ -192,6 +297,7 @@ void TilesEditor::edit(Object *p_object) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TilesEditor::_bind_methods() {
|
void TilesEditor::_bind_methods() {
|
||||||
|
ClassDB::bind_method(D_METHOD("_pattern_preview_done", "pattern"), &TilesEditor::_pattern_preview_done);
|
||||||
}
|
}
|
||||||
|
|
||||||
TilesEditor::TilesEditor(EditorNode *p_editor) {
|
TilesEditor::TilesEditor(EditorNode *p_editor) {
|
||||||
|
@ -229,12 +335,27 @@ TilesEditor::TilesEditor(EditorNode *p_editor) {
|
||||||
tileset_editor->hide();
|
tileset_editor->hide();
|
||||||
add_child(tileset_editor);
|
add_child(tileset_editor);
|
||||||
|
|
||||||
|
tileset_toolbar = tileset_editor->get_toolbar();
|
||||||
|
toolbar->add_child(tileset_toolbar);
|
||||||
|
|
||||||
|
// Pattern preview generation thread.
|
||||||
|
pattern_preview_thread.start(_thread_func, this);
|
||||||
|
|
||||||
// Initialization.
|
// Initialization.
|
||||||
_update_switch_button();
|
_update_switch_button();
|
||||||
_update_editors();
|
_update_editors();
|
||||||
}
|
}
|
||||||
|
|
||||||
TilesEditor::~TilesEditor() {
|
TilesEditor::~TilesEditor() {
|
||||||
|
if (pattern_preview_thread.is_started()) {
|
||||||
|
pattern_thread_exit.set();
|
||||||
|
pattern_preview_sem.post();
|
||||||
|
while (!pattern_thread_exited.is_set()) {
|
||||||
|
OS::get_singleton()->delay_usec(10000);
|
||||||
|
RenderingServer::get_singleton()->sync(); //sync pending stuff, as thread may be blocked on visual server
|
||||||
|
}
|
||||||
|
pattern_preview_thread.wait_to_finish();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -53,6 +53,7 @@ private:
|
||||||
Control *tilemap_toolbar;
|
Control *tilemap_toolbar;
|
||||||
TileMapEditor *tilemap_editor;
|
TileMapEditor *tilemap_editor;
|
||||||
|
|
||||||
|
Control *tileset_toolbar;
|
||||||
TileSetEditor *tileset_editor;
|
TileSetEditor *tileset_editor;
|
||||||
|
|
||||||
void _update_switch_button();
|
void _update_switch_button();
|
||||||
|
@ -63,6 +64,23 @@ private:
|
||||||
float atlas_view_zoom = 1.0;
|
float atlas_view_zoom = 1.0;
|
||||||
Vector2 atlas_view_scroll = Vector2();
|
Vector2 atlas_view_scroll = Vector2();
|
||||||
|
|
||||||
|
// Patterns preview generation.
|
||||||
|
struct QueueItem {
|
||||||
|
Ref<TileSet> tile_set;
|
||||||
|
Ref<TileMapPattern> pattern;
|
||||||
|
Callable callback;
|
||||||
|
};
|
||||||
|
List<QueueItem> pattern_preview_queue;
|
||||||
|
Mutex pattern_preview_mutex;
|
||||||
|
Semaphore pattern_preview_sem;
|
||||||
|
Thread pattern_preview_thread;
|
||||||
|
SafeFlag pattern_thread_exit;
|
||||||
|
SafeFlag pattern_thread_exited;
|
||||||
|
mutable SafeFlag pattern_preview_done;
|
||||||
|
void _pattern_preview_done(const Variant &p_udata);
|
||||||
|
static void _thread_func(void *ud);
|
||||||
|
void _thread();
|
||||||
|
|
||||||
void _tile_map_changed();
|
void _tile_map_changed();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -82,6 +100,9 @@ public:
|
||||||
void set_atlas_view_transform(float p_zoom, Vector2 p_scroll);
|
void set_atlas_view_transform(float p_zoom, Vector2 p_scroll);
|
||||||
void synchronize_atlas_view(Object *p_current);
|
void synchronize_atlas_view(Object *p_current);
|
||||||
|
|
||||||
|
// Pattern preview API.
|
||||||
|
void queue_pattern_preview(Ref<TileSet> p_tile_set, Ref<TileMapPattern> p_pattern, Callable p_callback);
|
||||||
|
|
||||||
void edit(Object *p_object);
|
void edit(Object *p_object);
|
||||||
|
|
||||||
TilesEditor(EditorNode *p_editor);
|
TilesEditor(EditorNode *p_editor);
|
||||||
|
|
|
@ -34,98 +34,6 @@
|
||||||
|
|
||||||
#include "servers/navigation_server_2d.h"
|
#include "servers/navigation_server_2d.h"
|
||||||
|
|
||||||
void TileMapPattern::set_cell(const Vector2i &p_coords, int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) {
|
|
||||||
ERR_FAIL_COND_MSG(p_coords.x < 0 || p_coords.y < 0, vformat("Cannot set cell with negative coords in a TileMapPattern. Wrong coords: %s", p_coords));
|
|
||||||
|
|
||||||
size = size.max(p_coords + Vector2i(1, 1));
|
|
||||||
pattern[p_coords] = TileMapCell(p_source_id, p_atlas_coords, p_alternative_tile);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TileMapPattern::has_cell(const Vector2i &p_coords) const {
|
|
||||||
return pattern.has(p_coords);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TileMapPattern::remove_cell(const Vector2i &p_coords, bool p_update_size) {
|
|
||||||
ERR_FAIL_COND(!pattern.has(p_coords));
|
|
||||||
|
|
||||||
pattern.erase(p_coords);
|
|
||||||
if (p_update_size) {
|
|
||||||
size = Vector2i();
|
|
||||||
for (const KeyValue<Vector2i, TileMapCell> &E : pattern) {
|
|
||||||
size = size.max(E.key + Vector2i(1, 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int TileMapPattern::get_cell_source_id(const Vector2i &p_coords) const {
|
|
||||||
ERR_FAIL_COND_V(!pattern.has(p_coords), TileSet::INVALID_SOURCE);
|
|
||||||
|
|
||||||
return pattern[p_coords].source_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector2i TileMapPattern::get_cell_atlas_coords(const Vector2i &p_coords) const {
|
|
||||||
ERR_FAIL_COND_V(!pattern.has(p_coords), TileSetSource::INVALID_ATLAS_COORDS);
|
|
||||||
|
|
||||||
return pattern[p_coords].get_atlas_coords();
|
|
||||||
}
|
|
||||||
|
|
||||||
int TileMapPattern::get_cell_alternative_tile(const Vector2i &p_coords) const {
|
|
||||||
ERR_FAIL_COND_V(!pattern.has(p_coords), TileSetSource::INVALID_TILE_ALTERNATIVE);
|
|
||||||
|
|
||||||
return pattern[p_coords].alternative_tile;
|
|
||||||
}
|
|
||||||
|
|
||||||
TypedArray<Vector2i> TileMapPattern::get_used_cells() const {
|
|
||||||
// Returns the cells used in the tilemap.
|
|
||||||
TypedArray<Vector2i> a;
|
|
||||||
a.resize(pattern.size());
|
|
||||||
int i = 0;
|
|
||||||
for (const KeyValue<Vector2i, TileMapCell> &E : pattern) {
|
|
||||||
Vector2i p(E.key.x, E.key.y);
|
|
||||||
a[i++] = p;
|
|
||||||
}
|
|
||||||
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector2i TileMapPattern::get_size() const {
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TileMapPattern::set_size(const Vector2i &p_size) {
|
|
||||||
for (const KeyValue<Vector2i, TileMapCell> &E : pattern) {
|
|
||||||
Vector2i coords = E.key;
|
|
||||||
if (p_size.x <= coords.x || p_size.y <= coords.y) {
|
|
||||||
ERR_FAIL_MSG(vformat("Cannot set pattern size to %s, it contains a tile at %s. Size can only be increased.", p_size, coords));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
size = p_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TileMapPattern::is_empty() const {
|
|
||||||
return pattern.is_empty();
|
|
||||||
};
|
|
||||||
|
|
||||||
void TileMapPattern::clear() {
|
|
||||||
size = Vector2i();
|
|
||||||
pattern.clear();
|
|
||||||
};
|
|
||||||
|
|
||||||
void TileMapPattern::_bind_methods() {
|
|
||||||
ClassDB::bind_method(D_METHOD("set_cell", "coords", "source_id", "atlas_coords", "alternative_tile"), &TileMapPattern::set_cell, DEFVAL(TileSet::INVALID_SOURCE), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(TileSetSource::INVALID_TILE_ALTERNATIVE));
|
|
||||||
ClassDB::bind_method(D_METHOD("has_cell", "coords"), &TileMapPattern::has_cell);
|
|
||||||
ClassDB::bind_method(D_METHOD("remove_cell", "coords"), &TileMapPattern::remove_cell);
|
|
||||||
ClassDB::bind_method(D_METHOD("get_cell_source_id", "coords"), &TileMapPattern::get_cell_source_id);
|
|
||||||
ClassDB::bind_method(D_METHOD("get_cell_atlas_coords", "coords"), &TileMapPattern::get_cell_atlas_coords);
|
|
||||||
ClassDB::bind_method(D_METHOD("get_cell_alternative_tile", "coords"), &TileMapPattern::get_cell_alternative_tile);
|
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("get_used_cells"), &TileMapPattern::get_used_cells);
|
|
||||||
ClassDB::bind_method(D_METHOD("get_size"), &TileMapPattern::get_size);
|
|
||||||
ClassDB::bind_method(D_METHOD("set_size", "size"), &TileMapPattern::set_size);
|
|
||||||
ClassDB::bind_method(D_METHOD("is_empty"), &TileMapPattern::is_empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector2i TileMap::transform_coords_layout(Vector2i p_coords, TileSet::TileOffsetAxis p_offset_axis, TileSet::TileLayout p_from_layout, TileSet::TileLayout p_to_layout) {
|
Vector2i TileMap::transform_coords_layout(Vector2i p_coords, TileSet::TileOffsetAxis p_offset_axis, TileSet::TileLayout p_from_layout, TileSet::TileLayout p_to_layout) {
|
||||||
// Transform to stacked layout.
|
// Transform to stacked layout.
|
||||||
Vector2i output = p_coords;
|
Vector2i output = p_coords;
|
||||||
|
@ -1788,11 +1696,12 @@ int TileMap::get_cell_alternative_tile(int p_layer, const Vector2i &p_coords, bo
|
||||||
return E->get().alternative_tile;
|
return E->get().alternative_tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
TileMapPattern *TileMap::get_pattern(int p_layer, TypedArray<Vector2i> p_coords_array) {
|
Ref<TileMapPattern> TileMap::get_pattern(int p_layer, TypedArray<Vector2i> p_coords_array) {
|
||||||
ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), nullptr);
|
ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), nullptr);
|
||||||
ERR_FAIL_COND_V(!tile_set.is_valid(), nullptr);
|
ERR_FAIL_COND_V(!tile_set.is_valid(), nullptr);
|
||||||
|
|
||||||
TileMapPattern *output = memnew(TileMapPattern);
|
Ref<TileMapPattern> output;
|
||||||
|
output.instantiate();
|
||||||
if (p_coords_array.is_empty()) {
|
if (p_coords_array.is_empty()) {
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
@ -1841,7 +1750,7 @@ TileMapPattern *TileMap::get_pattern(int p_layer, TypedArray<Vector2i> p_coords_
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2i TileMap::map_pattern(Vector2i p_position_in_tilemap, Vector2i p_coords_in_pattern, const TileMapPattern *p_pattern) {
|
Vector2i TileMap::map_pattern(Vector2i p_position_in_tilemap, Vector2i p_coords_in_pattern, Ref<TileMapPattern> p_pattern) {
|
||||||
ERR_FAIL_COND_V(!p_pattern->has_cell(p_coords_in_pattern), Vector2i());
|
ERR_FAIL_COND_V(!p_pattern->has_cell(p_coords_in_pattern), Vector2i());
|
||||||
|
|
||||||
Vector2i output = p_position_in_tilemap + p_coords_in_pattern;
|
Vector2i output = p_position_in_tilemap + p_coords_in_pattern;
|
||||||
|
@ -1864,7 +1773,7 @@ Vector2i TileMap::map_pattern(Vector2i p_position_in_tilemap, Vector2i p_coords_
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileMap::set_pattern(int p_layer, Vector2i p_position, const TileMapPattern *p_pattern) {
|
void TileMap::set_pattern(int p_layer, Vector2i p_position, const Ref<TileMapPattern> p_pattern) {
|
||||||
ERR_FAIL_INDEX(p_layer, (int)layers.size());
|
ERR_FAIL_INDEX(p_layer, (int)layers.size());
|
||||||
ERR_FAIL_COND(!tile_set.is_valid());
|
ERR_FAIL_COND(!tile_set.is_valid());
|
||||||
|
|
||||||
|
@ -3076,6 +2985,10 @@ void TileMap::_bind_methods() {
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("get_coords_for_body_rid", "body"), &TileMap::get_coords_for_body_rid);
|
ClassDB::bind_method(D_METHOD("get_coords_for_body_rid", "body"), &TileMap::get_coords_for_body_rid);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("get_pattern", "layer", "coords_array"), &TileMap::get_pattern);
|
||||||
|
ClassDB::bind_method(D_METHOD("map_pattern", "position_in_tilemap", "coords_in_pattern", "pattern"), &TileMap::map_pattern);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_pattern", "layer", "position", "pattern"), &TileMap::set_pattern);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("fix_invalid_tiles"), &TileMap::fix_invalid_tiles);
|
ClassDB::bind_method(D_METHOD("fix_invalid_tiles"), &TileMap::fix_invalid_tiles);
|
||||||
ClassDB::bind_method(D_METHOD("clear_layer", "layer"), &TileMap::clear_layer);
|
ClassDB::bind_method(D_METHOD("clear_layer", "layer"), &TileMap::clear_layer);
|
||||||
ClassDB::bind_method(D_METHOD("clear"), &TileMap::clear);
|
ClassDB::bind_method(D_METHOD("clear"), &TileMap::clear);
|
||||||
|
@ -3092,7 +3005,7 @@ void TileMap::_bind_methods() {
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("_update_dirty_quadrants"), &TileMap::_update_dirty_quadrants);
|
ClassDB::bind_method(D_METHOD("_update_dirty_quadrants"), &TileMap::_update_dirty_quadrants);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("_set_tile_data", "layer"), &TileMap::_set_tile_data);
|
ClassDB::bind_method(D_METHOD("_set_tile_data", "layer", "data"), &TileMap::_set_tile_data);
|
||||||
ClassDB::bind_method(D_METHOD("_get_tile_data", "layer"), &TileMap::_get_tile_data);
|
ClassDB::bind_method(D_METHOD("_get_tile_data", "layer"), &TileMap::_get_tile_data);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("_tile_set_changed_deferred_update"), &TileMap::_tile_set_changed_deferred_update);
|
ClassDB::bind_method(D_METHOD("_tile_set_changed_deferred_update"), &TileMap::_tile_set_changed_deferred_update);
|
||||||
|
|
|
@ -37,51 +37,6 @@
|
||||||
|
|
||||||
class TileSetAtlasSource;
|
class TileSetAtlasSource;
|
||||||
|
|
||||||
union TileMapCell {
|
|
||||||
struct {
|
|
||||||
int32_t source_id : 16;
|
|
||||||
int16_t coord_x : 16;
|
|
||||||
int16_t coord_y : 16;
|
|
||||||
int32_t alternative_tile : 16;
|
|
||||||
};
|
|
||||||
|
|
||||||
uint64_t _u64t;
|
|
||||||
TileMapCell(int p_source_id = -1, Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE) {
|
|
||||||
source_id = p_source_id;
|
|
||||||
set_atlas_coords(p_atlas_coords);
|
|
||||||
alternative_tile = p_alternative_tile;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector2i get_atlas_coords() const {
|
|
||||||
return Vector2i(coord_x, coord_y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_atlas_coords(const Vector2i &r_coords) {
|
|
||||||
coord_x = r_coords.x;
|
|
||||||
coord_y = r_coords.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator<(const TileMapCell &p_other) const {
|
|
||||||
if (source_id == p_other.source_id) {
|
|
||||||
if (coord_x == p_other.coord_x) {
|
|
||||||
if (coord_y == p_other.coord_y) {
|
|
||||||
return alternative_tile < p_other.alternative_tile;
|
|
||||||
} else {
|
|
||||||
return coord_y < p_other.coord_y;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return coord_x < p_other.coord_x;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return source_id < p_other.source_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(const TileMapCell &p_other) const {
|
|
||||||
return !(source_id == p_other.source_id && coord_x == p_other.coord_x && coord_y == p_other.coord_y && alternative_tile == p_other.alternative_tile);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TileMapQuadrant {
|
struct TileMapQuadrant {
|
||||||
struct CoordsWorldComparator {
|
struct CoordsWorldComparator {
|
||||||
_ALWAYS_INLINE_ bool operator()(const Vector2i &p_a, const Vector2i &p_b) const {
|
_ALWAYS_INLINE_ bool operator()(const Vector2i &p_a, const Vector2i &p_b) const {
|
||||||
|
@ -150,32 +105,6 @@ struct TileMapQuadrant {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class TileMapPattern : public Object {
|
|
||||||
GDCLASS(TileMapPattern, Object);
|
|
||||||
|
|
||||||
Vector2i size;
|
|
||||||
Map<Vector2i, TileMapCell> pattern;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
static void _bind_methods();
|
|
||||||
|
|
||||||
public:
|
|
||||||
void set_cell(const Vector2i &p_coords, int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile = 0);
|
|
||||||
bool has_cell(const Vector2i &p_coords) const;
|
|
||||||
void remove_cell(const Vector2i &p_coords, bool p_update_size = true);
|
|
||||||
int get_cell_source_id(const Vector2i &p_coords) const;
|
|
||||||
Vector2i get_cell_atlas_coords(const Vector2i &p_coords) const;
|
|
||||||
int get_cell_alternative_tile(const Vector2i &p_coords) const;
|
|
||||||
|
|
||||||
TypedArray<Vector2i> get_used_cells() const;
|
|
||||||
|
|
||||||
Vector2i get_size() const;
|
|
||||||
void set_size(const Vector2i &p_size);
|
|
||||||
bool is_empty() const;
|
|
||||||
|
|
||||||
void clear();
|
|
||||||
};
|
|
||||||
|
|
||||||
class TileMap : public Node2D {
|
class TileMap : public Node2D {
|
||||||
GDCLASS(TileMap, Node2D);
|
GDCLASS(TileMap, Node2D);
|
||||||
|
|
||||||
|
@ -349,9 +278,9 @@ public:
|
||||||
Vector2i get_cell_atlas_coords(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const;
|
Vector2i get_cell_atlas_coords(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const;
|
||||||
int get_cell_alternative_tile(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const;
|
int get_cell_alternative_tile(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const;
|
||||||
|
|
||||||
TileMapPattern *get_pattern(int p_layer, TypedArray<Vector2i> p_coords_array);
|
Ref<TileMapPattern> get_pattern(int p_layer, TypedArray<Vector2i> p_coords_array);
|
||||||
Vector2i map_pattern(Vector2i p_position_in_tilemap, Vector2i p_coords_in_pattern, const TileMapPattern *p_pattern);
|
Vector2i map_pattern(Vector2i p_position_in_tilemap, Vector2i p_coords_in_pattern, Ref<TileMapPattern> p_pattern);
|
||||||
void set_pattern(int p_layer, Vector2i p_position, const TileMapPattern *p_pattern);
|
void set_pattern(int p_layer, Vector2i p_position, const Ref<TileMapPattern> p_pattern);
|
||||||
|
|
||||||
// Not exposed to users
|
// Not exposed to users
|
||||||
TileMapCell get_cell(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const;
|
TileMapCell get_cell(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const;
|
||||||
|
|
|
@ -740,7 +740,7 @@ bool Control::has_point(const Point2 &p_point) const {
|
||||||
return Rect2(Point2(), get_size()).has_point(p_point);
|
return Rect2(Point2(), get_size()).has_point(p_point);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Control::set_drag_forwarding(Node *p_target) {
|
void Control::set_drag_forwarding(Object *p_target) {
|
||||||
if (p_target) {
|
if (p_target) {
|
||||||
data.drag_owner = p_target->get_instance_id();
|
data.drag_owner = p_target->get_instance_id();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -355,7 +355,7 @@ public:
|
||||||
virtual Size2 get_minimum_size() const;
|
virtual Size2 get_minimum_size() const;
|
||||||
virtual Size2 get_combined_minimum_size() const;
|
virtual Size2 get_combined_minimum_size() const;
|
||||||
virtual bool has_point(const Point2 &p_point) const;
|
virtual bool has_point(const Point2 &p_point) const;
|
||||||
virtual void set_drag_forwarding(Node *p_target);
|
virtual void set_drag_forwarding(Object *p_target);
|
||||||
virtual Variant get_drag_data(const Point2 &p_point);
|
virtual Variant get_drag_data(const Point2 &p_point);
|
||||||
virtual bool can_drop_data(const Point2 &p_point, const Variant &p_data) const;
|
virtual bool can_drop_data(const Point2 &p_point, const Variant &p_data) const;
|
||||||
virtual void drop_data(const Point2 &p_point, const Variant &p_data);
|
virtual void drop_data(const Point2 &p_point, const Variant &p_data);
|
||||||
|
|
|
@ -685,6 +685,7 @@ void register_scene_types() {
|
||||||
GDREGISTER_VIRTUAL_CLASS(TileSetSource);
|
GDREGISTER_VIRTUAL_CLASS(TileSetSource);
|
||||||
GDREGISTER_CLASS(TileSetAtlasSource);
|
GDREGISTER_CLASS(TileSetAtlasSource);
|
||||||
GDREGISTER_CLASS(TileSetScenesCollectionSource);
|
GDREGISTER_CLASS(TileSetScenesCollectionSource);
|
||||||
|
GDREGISTER_CLASS(TileMapPattern);
|
||||||
GDREGISTER_CLASS(TileData);
|
GDREGISTER_CLASS(TileData);
|
||||||
GDREGISTER_CLASS(TileMap);
|
GDREGISTER_CLASS(TileMap);
|
||||||
GDREGISTER_CLASS(ParallaxBackground);
|
GDREGISTER_CLASS(ParallaxBackground);
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "tile_set.h"
|
#include "tile_set.h"
|
||||||
|
|
||||||
#include "core/core_string_names.h"
|
#include "core/core_string_names.h"
|
||||||
|
#include "core/io/marshalls.h"
|
||||||
#include "core/math/geometry_2d.h"
|
#include "core/math/geometry_2d.h"
|
||||||
#include "core/templates/local_vector.h"
|
#include "core/templates/local_vector.h"
|
||||||
|
|
||||||
|
@ -39,6 +40,189 @@
|
||||||
#include "scene/resources/convex_polygon_shape_2d.h"
|
#include "scene/resources/convex_polygon_shape_2d.h"
|
||||||
#include "servers/navigation_server_2d.h"
|
#include "servers/navigation_server_2d.h"
|
||||||
|
|
||||||
|
/////////////////////////////// TileMapPattern //////////////////////////////////////
|
||||||
|
|
||||||
|
void TileMapPattern::_set_tile_data(const Vector<int> &p_data) {
|
||||||
|
int c = p_data.size();
|
||||||
|
const int *r = p_data.ptr();
|
||||||
|
|
||||||
|
int offset = 3;
|
||||||
|
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 < 12; 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]);
|
||||||
|
SWAP(local[8], local[11]);
|
||||||
|
SWAP(local[9], local[10]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int16_t x = decode_uint16(&local[0]);
|
||||||
|
int16_t y = decode_uint16(&local[2]);
|
||||||
|
uint16_t source_id = decode_uint16(&local[4]);
|
||||||
|
uint16_t atlas_coords_x = decode_uint16(&local[6]);
|
||||||
|
uint16_t atlas_coords_y = decode_uint16(&local[8]);
|
||||||
|
uint16_t alternative_tile = decode_uint16(&local[10]);
|
||||||
|
set_cell(Vector2i(x, y), source_id, Vector2i(atlas_coords_x, atlas_coords_y), alternative_tile);
|
||||||
|
}
|
||||||
|
emit_signal(SNAME("changed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<int> TileMapPattern::_get_tile_data() const {
|
||||||
|
// Export tile data to raw format
|
||||||
|
Vector<int> data;
|
||||||
|
data.resize(pattern.size() * 3);
|
||||||
|
int *w = data.ptrw();
|
||||||
|
|
||||||
|
// Save in highest format
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
for (const KeyValue<Vector2i, TileMapCell> &E : pattern) {
|
||||||
|
uint8_t *ptr = (uint8_t *)&w[idx];
|
||||||
|
encode_uint16((int16_t)(E.key.x), &ptr[0]);
|
||||||
|
encode_uint16((int16_t)(E.key.y), &ptr[2]);
|
||||||
|
encode_uint16(E.value.source_id, &ptr[4]);
|
||||||
|
encode_uint16(E.value.coord_x, &ptr[6]);
|
||||||
|
encode_uint16(E.value.coord_y, &ptr[8]);
|
||||||
|
encode_uint16(E.value.alternative_tile, &ptr[10]);
|
||||||
|
idx += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TileMapPattern::set_cell(const Vector2i &p_coords, int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) {
|
||||||
|
ERR_FAIL_COND_MSG(p_coords.x < 0 || p_coords.y < 0, vformat("Cannot set cell with negative coords in a TileMapPattern. Wrong coords: %s", p_coords));
|
||||||
|
|
||||||
|
size = size.max(p_coords + Vector2i(1, 1));
|
||||||
|
pattern[p_coords] = TileMapCell(p_source_id, p_atlas_coords, p_alternative_tile);
|
||||||
|
emit_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TileMapPattern::has_cell(const Vector2i &p_coords) const {
|
||||||
|
return pattern.has(p_coords);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TileMapPattern::remove_cell(const Vector2i &p_coords, bool p_update_size) {
|
||||||
|
ERR_FAIL_COND(!pattern.has(p_coords));
|
||||||
|
|
||||||
|
pattern.erase(p_coords);
|
||||||
|
if (p_update_size) {
|
||||||
|
size = Vector2i();
|
||||||
|
for (const KeyValue<Vector2i, TileMapCell> &E : pattern) {
|
||||||
|
size = size.max(E.key + Vector2i(1, 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emit_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
int TileMapPattern::get_cell_source_id(const Vector2i &p_coords) const {
|
||||||
|
ERR_FAIL_COND_V(!pattern.has(p_coords), TileSet::INVALID_SOURCE);
|
||||||
|
|
||||||
|
return pattern[p_coords].source_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2i TileMapPattern::get_cell_atlas_coords(const Vector2i &p_coords) const {
|
||||||
|
ERR_FAIL_COND_V(!pattern.has(p_coords), TileSetSource::INVALID_ATLAS_COORDS);
|
||||||
|
|
||||||
|
return pattern[p_coords].get_atlas_coords();
|
||||||
|
}
|
||||||
|
|
||||||
|
int TileMapPattern::get_cell_alternative_tile(const Vector2i &p_coords) const {
|
||||||
|
ERR_FAIL_COND_V(!pattern.has(p_coords), TileSetSource::INVALID_TILE_ALTERNATIVE);
|
||||||
|
|
||||||
|
return pattern[p_coords].alternative_tile;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypedArray<Vector2i> TileMapPattern::get_used_cells() const {
|
||||||
|
// Returns the cells used in the tilemap.
|
||||||
|
TypedArray<Vector2i> a;
|
||||||
|
a.resize(pattern.size());
|
||||||
|
int i = 0;
|
||||||
|
for (const KeyValue<Vector2i, TileMapCell> &E : pattern) {
|
||||||
|
Vector2i p(E.key.x, E.key.y);
|
||||||
|
a[i++] = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2i TileMapPattern::get_size() const {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TileMapPattern::set_size(const Vector2i &p_size) {
|
||||||
|
for (const KeyValue<Vector2i, TileMapCell> &E : pattern) {
|
||||||
|
Vector2i coords = E.key;
|
||||||
|
if (p_size.x <= coords.x || p_size.y <= coords.y) {
|
||||||
|
ERR_FAIL_MSG(vformat("Cannot set pattern size to %s, it contains a tile at %s. Size can only be increased.", p_size, coords));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
size = p_size;
|
||||||
|
emit_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TileMapPattern::is_empty() const {
|
||||||
|
return pattern.is_empty();
|
||||||
|
};
|
||||||
|
|
||||||
|
void TileMapPattern::clear() {
|
||||||
|
size = Vector2i();
|
||||||
|
pattern.clear();
|
||||||
|
emit_changed();
|
||||||
|
};
|
||||||
|
|
||||||
|
bool TileMapPattern::_set(const StringName &p_name, const Variant &p_value) {
|
||||||
|
if (p_name == "tile_data") {
|
||||||
|
if (p_value.is_array()) {
|
||||||
|
_set_tile_data(p_value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TileMapPattern::_get(const StringName &p_name, Variant &r_ret) const {
|
||||||
|
if (p_name == "tile_data") {
|
||||||
|
r_ret = _get_tile_data();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TileMapPattern::_get_property_list(List<PropertyInfo> *p_list) const {
|
||||||
|
p_list->push_back(PropertyInfo(Variant::OBJECT, "tile_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TileMapPattern::_bind_methods() {
|
||||||
|
ClassDB::bind_method(D_METHOD("_set_tile_data", "data"), &TileMapPattern::_set_tile_data);
|
||||||
|
ClassDB::bind_method(D_METHOD("_get_tile_data"), &TileMapPattern::_get_tile_data);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("set_cell", "coords", "source_id", "atlas_coords", "alternative_tile"), &TileMapPattern::set_cell, DEFVAL(TileSet::INVALID_SOURCE), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(TileSetSource::INVALID_TILE_ALTERNATIVE));
|
||||||
|
ClassDB::bind_method(D_METHOD("has_cell", "coords"), &TileMapPattern::has_cell);
|
||||||
|
ClassDB::bind_method(D_METHOD("remove_cell", "coords"), &TileMapPattern::remove_cell);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_cell_source_id", "coords"), &TileMapPattern::get_cell_source_id);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_cell_atlas_coords", "coords"), &TileMapPattern::get_cell_atlas_coords);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_cell_alternative_tile", "coords"), &TileMapPattern::get_cell_alternative_tile);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("get_used_cells"), &TileMapPattern::get_used_cells);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_size"), &TileMapPattern::get_size);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_size", "size"), &TileMapPattern::set_size);
|
||||||
|
ClassDB::bind_method(D_METHOD("is_empty"), &TileMapPattern::is_empty);
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////// TileSet //////////////////////////////////////
|
/////////////////////////////// TileSet //////////////////////////////////////
|
||||||
|
|
||||||
const int TileSet::INVALID_SOURCE = -1;
|
const int TileSet::INVALID_SOURCE = -1;
|
||||||
|
@ -982,6 +1166,36 @@ void TileSet::clear_tile_proxies() {
|
||||||
emit_changed();
|
emit_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int TileSet::add_pattern(Ref<TileMapPattern> p_pattern, int p_index) {
|
||||||
|
ERR_FAIL_COND_V(!p_pattern.is_valid(), -1);
|
||||||
|
ERR_FAIL_COND_V_MSG(p_pattern->is_empty(), -1, "Cannot add an empty pattern to the TileSet.");
|
||||||
|
for (unsigned int i = 0; i < patterns.size(); i++) {
|
||||||
|
ERR_FAIL_COND_V_MSG(patterns[i] == p_pattern, -1, "TileSet has already this pattern.");
|
||||||
|
}
|
||||||
|
ERR_FAIL_COND_V(p_index > (int)patterns.size(), -1);
|
||||||
|
if (p_index < 0) {
|
||||||
|
p_index = patterns.size();
|
||||||
|
}
|
||||||
|
patterns.insert(p_index, p_pattern);
|
||||||
|
emit_changed();
|
||||||
|
return p_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<TileMapPattern> TileSet::get_pattern(int p_index) {
|
||||||
|
ERR_FAIL_INDEX_V(p_index, (int)patterns.size(), Ref<TileMapPattern>());
|
||||||
|
return patterns[p_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
void TileSet::remove_pattern(int p_index) {
|
||||||
|
ERR_FAIL_INDEX(p_index, (int)patterns.size());
|
||||||
|
patterns.remove(p_index);
|
||||||
|
emit_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
int TileSet::get_patterns_count() {
|
||||||
|
return patterns.size();
|
||||||
|
}
|
||||||
|
|
||||||
Vector<Vector2> TileSet::get_tile_shape_polygon() {
|
Vector<Vector2> TileSet::get_tile_shape_polygon() {
|
||||||
Vector<Vector2> points;
|
Vector<Vector2> points;
|
||||||
if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
|
if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
|
||||||
|
@ -2483,6 +2697,12 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
} else if (components.size() == 1 && components[0].begins_with("pattern_") && components[0].trim_prefix("pattern_").is_valid_int()) {
|
||||||
|
int pattern_index = components[0].trim_prefix("pattern_").to_int();
|
||||||
|
for (int i = patterns.size(); i <= pattern_index; i++) {
|
||||||
|
add_pattern(p_value);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef DISABLE_DEPRECATED
|
#ifndef DISABLE_DEPRECATED
|
||||||
|
@ -2606,6 +2826,13 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
} else if (components.size() == 1 && components[0].begins_with("pattern_") && components[0].trim_prefix("pattern_").is_valid_int()) {
|
||||||
|
int pattern_index = components[0].trim_prefix("pattern_").to_int();
|
||||||
|
if (pattern_index < 0 || pattern_index >= (int)patterns.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
r_ret = patterns[pattern_index];
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -2686,6 +2913,11 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const {
|
||||||
p_list->push_back(PropertyInfo(Variant::ARRAY, "tile_proxies/source_level", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
|
p_list->push_back(PropertyInfo(Variant::ARRAY, "tile_proxies/source_level", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
|
||||||
p_list->push_back(PropertyInfo(Variant::ARRAY, "tile_proxies/coords_level", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
|
p_list->push_back(PropertyInfo(Variant::ARRAY, "tile_proxies/coords_level", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
|
||||||
p_list->push_back(PropertyInfo(Variant::ARRAY, "tile_proxies/alternative_level", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
|
p_list->push_back(PropertyInfo(Variant::ARRAY, "tile_proxies/alternative_level", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
|
||||||
|
|
||||||
|
// Patterns.
|
||||||
|
for (unsigned int pattern_index = 0; pattern_index < patterns.size(); pattern_index++) {
|
||||||
|
p_list->push_back(PropertyInfo(Variant::OBJECT, vformat("pattern_%d", pattern_index), PROPERTY_HINT_RESOURCE_TYPE, "TileMapPattern", PROPERTY_USAGE_NOEDITOR));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileSet::_validate_property(PropertyInfo &property) const {
|
void TileSet::_validate_property(PropertyInfo &property) const {
|
||||||
|
@ -2799,6 +3031,12 @@ void TileSet::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("cleanup_invalid_tile_proxies"), &TileSet::cleanup_invalid_tile_proxies);
|
ClassDB::bind_method(D_METHOD("cleanup_invalid_tile_proxies"), &TileSet::cleanup_invalid_tile_proxies);
|
||||||
ClassDB::bind_method(D_METHOD("clear_tile_proxies"), &TileSet::clear_tile_proxies);
|
ClassDB::bind_method(D_METHOD("clear_tile_proxies"), &TileSet::clear_tile_proxies);
|
||||||
|
|
||||||
|
// Patterns
|
||||||
|
ClassDB::bind_method(D_METHOD("add_pattern", "pattern", "index"), &TileSet::add_pattern, DEFVAL(-1));
|
||||||
|
ClassDB::bind_method(D_METHOD("get_pattern", "index"), &TileSet::get_pattern, DEFVAL(-1));
|
||||||
|
ClassDB::bind_method(D_METHOD("remove_pattern", "index"), &TileSet::remove_pattern);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_patterns_count"), &TileSet::get_patterns_count);
|
||||||
|
|
||||||
ADD_GROUP("Rendering", "");
|
ADD_GROUP("Rendering", "");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uv_clipping"), "set_uv_clipping", "is_uv_clipping");
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uv_clipping"), "set_uv_clipping", "is_uv_clipping");
|
||||||
ADD_ARRAY("occlusion_layers", "occlusion_layer_");
|
ADD_ARRAY("occlusion_layers", "occlusion_layer_");
|
||||||
|
|
|
@ -60,6 +60,84 @@ class TileSetPluginAtlasRendering;
|
||||||
class TileSetPluginAtlasPhysics;
|
class TileSetPluginAtlasPhysics;
|
||||||
class TileSetPluginAtlasNavigation;
|
class TileSetPluginAtlasNavigation;
|
||||||
|
|
||||||
|
union TileMapCell {
|
||||||
|
struct {
|
||||||
|
int32_t source_id : 16;
|
||||||
|
int16_t coord_x : 16;
|
||||||
|
int16_t coord_y : 16;
|
||||||
|
int32_t alternative_tile : 16;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint64_t _u64t;
|
||||||
|
TileMapCell(int p_source_id = -1, Vector2i p_atlas_coords = Vector2i(-1, -1), int p_alternative_tile = -1) { // default are INVALID_SOURCE, INVALID_ATLAS_COORDS, INVALID_TILE_ALTERNATIVE
|
||||||
|
source_id = p_source_id;
|
||||||
|
set_atlas_coords(p_atlas_coords);
|
||||||
|
alternative_tile = p_alternative_tile;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2i get_atlas_coords() const {
|
||||||
|
return Vector2i(coord_x, coord_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_atlas_coords(const Vector2i &r_coords) {
|
||||||
|
coord_x = r_coords.x;
|
||||||
|
coord_y = r_coords.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const TileMapCell &p_other) const {
|
||||||
|
if (source_id == p_other.source_id) {
|
||||||
|
if (coord_x == p_other.coord_x) {
|
||||||
|
if (coord_y == p_other.coord_y) {
|
||||||
|
return alternative_tile < p_other.alternative_tile;
|
||||||
|
} else {
|
||||||
|
return coord_y < p_other.coord_y;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return coord_x < p_other.coord_x;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return source_id < p_other.source_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const TileMapCell &p_other) const {
|
||||||
|
return !(source_id == p_other.source_id && coord_x == p_other.coord_x && coord_y == p_other.coord_y && alternative_tile == p_other.alternative_tile);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class TileMapPattern : public Resource {
|
||||||
|
GDCLASS(TileMapPattern, Resource);
|
||||||
|
|
||||||
|
Vector2i size;
|
||||||
|
Map<Vector2i, TileMapCell> pattern;
|
||||||
|
|
||||||
|
void _set_tile_data(const Vector<int> &p_data);
|
||||||
|
Vector<int> _get_tile_data() 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<PropertyInfo> *p_list) const;
|
||||||
|
|
||||||
|
static void _bind_methods();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void set_cell(const Vector2i &p_coords, int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile = 0);
|
||||||
|
bool has_cell(const Vector2i &p_coords) const;
|
||||||
|
void remove_cell(const Vector2i &p_coords, bool p_update_size = true);
|
||||||
|
int get_cell_source_id(const Vector2i &p_coords) const;
|
||||||
|
Vector2i get_cell_atlas_coords(const Vector2i &p_coords) const;
|
||||||
|
int get_cell_alternative_tile(const Vector2i &p_coords) const;
|
||||||
|
|
||||||
|
TypedArray<Vector2i> get_used_cells() const;
|
||||||
|
|
||||||
|
Vector2i get_size() const;
|
||||||
|
void set_size(const Vector2i &p_size);
|
||||||
|
bool is_empty() const;
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
};
|
||||||
|
|
||||||
class TileSet : public Resource {
|
class TileSet : public Resource {
|
||||||
GDCLASS(TileSet, Resource);
|
GDCLASS(TileSet, Resource);
|
||||||
|
|
||||||
|
@ -245,6 +323,8 @@ private:
|
||||||
int next_source_id = 0;
|
int next_source_id = 0;
|
||||||
// ---------------------
|
// ---------------------
|
||||||
|
|
||||||
|
LocalVector<Ref<TileMapPattern>> patterns;
|
||||||
|
|
||||||
void _compute_next_source_id();
|
void _compute_next_source_id();
|
||||||
void _source_changed();
|
void _source_changed();
|
||||||
|
|
||||||
|
@ -384,6 +464,12 @@ public:
|
||||||
void cleanup_invalid_tile_proxies();
|
void cleanup_invalid_tile_proxies();
|
||||||
void clear_tile_proxies();
|
void clear_tile_proxies();
|
||||||
|
|
||||||
|
// Patterns.
|
||||||
|
int add_pattern(Ref<TileMapPattern> p_pattern, int p_index = -1);
|
||||||
|
Ref<TileMapPattern> get_pattern(int p_index);
|
||||||
|
void remove_pattern(int p_index);
|
||||||
|
int get_patterns_count();
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
Vector<Vector2> get_tile_shape_polygon();
|
Vector<Vector2> get_tile_shape_polygon();
|
||||||
void draw_tile_shape(CanvasItem *p_canvas_item, Transform2D p_transform, Color p_color, bool p_filled = false, Ref<Texture2D> p_texture = Ref<Texture2D>());
|
void draw_tile_shape(CanvasItem *p_canvas_item, Transform2D p_transform, Color p_color, bool p_filled = false, Ref<Texture2D> p_texture = Ref<Texture2D>());
|
||||||
|
|
Loading…
Reference in a new issue