Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto create tile for multiple atlases #79678

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 47 additions & 35 deletions editor/plugins/tiles/tile_set_atlas_source_editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1672,6 +1672,8 @@ void TileSetAtlasSourceEditor::_menu_option(int p_option) {
_update_tile_id_label();
} break;
case ADVANCED_AUTO_CREATE_TILES: {
atlases_to_auto_create_tiles.clear();
atlases_to_auto_create_tiles.append(tile_set_atlas_source);
_auto_create_tiles();
} break;
case ADVANCED_AUTO_REMOVE_TILES: {
Expand Down Expand Up @@ -2096,6 +2098,8 @@ void TileSetAtlasSourceEditor::_tile_proxy_object_changed(String p_what) {

void TileSetAtlasSourceEditor::_atlas_source_proxy_object_changed(String p_what) {
if (p_what == "texture" && !atlas_source_proxy_object->get("texture").is_null()) {
atlases_to_auto_create_tiles.clear();
atlases_to_auto_create_tiles.append(tile_set_atlas_source);
confirm_auto_create_tiles->popup_centered();
} else if (p_what == "id") {
emit_signal(SNAME("source_id_changed"), atlas_source_proxy_object->get_id());
Expand Down Expand Up @@ -2242,54 +2246,61 @@ void TileSetAtlasSourceEditor::edit(Ref<TileSet> p_tile_set, TileSetAtlasSource
_update_current_tile_data_editor();
}

void TileSetAtlasSourceEditor::init_source() {
void TileSetAtlasSourceEditor::init_new_atlases(const Vector<Ref<TileSetAtlasSource>> &p_atlases) {
tool_setup_atlas_source_button->set_pressed(true);
atlases_to_auto_create_tiles = p_atlases;
confirm_auto_create_tiles->popup_centered();
}

void TileSetAtlasSourceEditor::_auto_create_tiles() {
if (!tile_set_atlas_source) {
return;
}
for (Ref<TileSetAtlasSource> &atlas_source : atlases_to_auto_create_tiles) {
if (atlas_source.is_valid()) {
Ref<Texture2D> texture = atlas_source->get_texture();
if (texture.is_valid()) {
Vector2i margins = atlas_source->get_margins();
Vector2i separation = atlas_source->get_separation();
Vector2i texture_region_size = atlas_source->get_texture_region_size();
Size2i grid_size = atlas_source->get_atlas_grid_size();
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Create tiles in non-transparent texture regions"));
for (int y = 0; y < grid_size.y; y++) {
for (int x = 0; x < grid_size.x; x++) {
// Check if we have a tile at the coord.
Vector2i coords = Vector2i(x, y);
if (atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) {
// Check if the texture is empty at the given coords.
Rect2i region = Rect2i(margins + (coords * (texture_region_size + separation)), texture_region_size);
bool is_opaque = false;
for (int region_x = region.get_position().x; region_x < region.get_end().x; region_x++) {
for (int region_y = region.get_position().y; region_y < region.get_end().y; region_y++) {
if (texture->is_pixel_opaque(region_x, region_y)) {
is_opaque = true;
break;
}
}
if (is_opaque) {
break;
}
}

Ref<Texture2D> texture = tile_set_atlas_source->get_texture();
if (texture.is_valid()) {
Vector2i margins = tile_set_atlas_source->get_margins();
Vector2i separation = tile_set_atlas_source->get_separation();
Vector2i texture_region_size = tile_set_atlas_source->get_texture_region_size();
Size2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Create tiles in non-transparent texture regions"));
for (int y = 0; y < grid_size.y; y++) {
for (int x = 0; x < grid_size.x; x++) {
// Check if we have a tile at the coord
Vector2i coords = Vector2i(x, y);
if (tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) {
// Check if the texture is empty at the given coords.
Rect2i region = Rect2i(margins + (coords * (texture_region_size + separation)), texture_region_size);
bool is_opaque = false;
for (int region_x = region.get_position().x; region_x < region.get_end().x; region_x++) {
for (int region_y = region.get_position().y; region_y < region.get_end().y; region_y++) {
if (texture->is_pixel_opaque(region_x, region_y)) {
is_opaque = true;
break;
// If we do have opaque pixels, create a tile.
if (is_opaque) {
undo_redo->add_do_method(*atlas_source, "create_tile", coords);
undo_redo->add_undo_method(*atlas_source, "remove_tile", coords);
}
}
if (is_opaque) {
break;
}
}

// If we do have opaque pixels, create a tile.
if (is_opaque) {
undo_redo->add_do_method(tile_set_atlas_source, "create_tile", coords);
undo_redo->add_undo_method(tile_set_atlas_source, "remove_tile", coords);
}
}
undo_redo->commit_action();
}
}
undo_redo->commit_action();
}

_cancel_auto_create_tiles();
}

void TileSetAtlasSourceEditor::_cancel_auto_create_tiles() {
atlases_to_auto_create_tiles.clear();
}

void TileSetAtlasSourceEditor::_auto_remove_tiles() {
Expand Down Expand Up @@ -2644,6 +2655,7 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
confirm_auto_create_tiles->set_ok_button_text(TTR("Yes"));
confirm_auto_create_tiles->add_cancel_button()->set_text(TTR("No"));
confirm_auto_create_tiles->connect("confirmed", callable_mp(this, &TileSetAtlasSourceEditor::_auto_create_tiles));
confirm_auto_create_tiles->connect("canceled", callable_mp(this, &TileSetAtlasSourceEditor::_cancel_auto_create_tiles));
add_child(confirm_auto_create_tiles);

// Inspector plugin.
Expand Down
4 changes: 3 additions & 1 deletion editor/plugins/tiles/tile_set_atlas_source_editor.h
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,9 @@ class TileSetAtlasSourceEditor : public HSplitContainer {
// -- Misc --
void _auto_create_tiles();
void _auto_remove_tiles();
void _cancel_auto_create_tiles();
AcceptDialog *confirm_auto_create_tiles = nullptr;
Vector<Ref<TileSetAtlasSource>> atlases_to_auto_create_tiles;
Vector2i _get_drag_offset_tile_coords(const Vector2i &p_offset) const;

void _tile_set_changed();
Expand All @@ -288,7 +290,7 @@ class TileSetAtlasSourceEditor : public HSplitContainer {

public:
void edit(Ref<TileSet> p_tile_set, TileSetAtlasSource *p_tile_set_source, int p_source_id);
void init_source();
void init_new_atlases(const Vector<Ref<TileSetAtlasSource>> &p_atlases);

TileSetAtlasSourceEditor();
~TileSetAtlasSourceEditor();
Expand Down
93 changes: 40 additions & 53 deletions editor/plugins/tiles/tile_set_editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,35 +57,9 @@ void TileSetEditor::_drop_data_fw(const Point2 &p_point, const Variant &p_data,

if (p_from == sources_list) {
// Handle dropping a texture in the list of atlas resources.
int source_id = TileSet::INVALID_SOURCE;
int added = 0;
Dictionary d = p_data;
Vector<String> files = d["files"];
for (int i = 0; i < files.size(); i++) {
Ref<Texture2D> resource = ResourceLoader::load(files[i]);
if (resource.is_valid()) {
// Retrieve the id for the next created source.
source_id = tile_set->get_next_source_id();

// Actually create the new source.
Ref<TileSetAtlasSource> atlas_source = memnew(TileSetAtlasSource);
atlas_source->set_texture(resource);
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add a new atlas source"));
undo_redo->add_do_method(*tile_set, "add_source", atlas_source, source_id);
undo_redo->add_do_method(*atlas_source, "set_texture_region_size", tile_set->get_tile_size());
undo_redo->add_undo_method(*tile_set, "remove_source", source_id);
undo_redo->commit_action();
added += 1;
}
}

if (added == 1) {
tile_set_atlas_source_editor->init_source();
}

// Update the selected source (thus triggering an update).
_update_sources_list(source_id);
_load_texture_files(files);
}
}

Expand Down Expand Up @@ -126,6 +100,43 @@ bool TileSetEditor::_can_drop_data_fw(const Point2 &p_point, const Variant &p_da
return false;
}

void TileSetEditor::_load_texture_files(const Vector<String> &p_paths) {
int source_id = TileSet::INVALID_SOURCE;
Vector<Ref<TileSetAtlasSource>> atlases;

for (const String &p_path : p_paths) {
Ref<Texture2D> texture = ResourceLoader::load(p_path);

if (texture.is_null()) {
EditorNode::get_singleton()->show_warning(TTR("Invalid texture selected."));
continue;
}

// Retrieve the id for the next created source.
source_id = tile_set->get_next_source_id();

// Actually create the new source.
Ref<TileSetAtlasSource> atlas_source = memnew(TileSetAtlasSource);
atlas_source->set_texture(texture);

EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add a new atlas source"));
undo_redo->add_do_method(*tile_set, "add_source", atlas_source, source_id);
undo_redo->add_do_method(*atlas_source, "set_texture_region_size", tile_set->get_tile_size());
undo_redo->add_undo_method(*tile_set, "remove_source", source_id);
undo_redo->commit_action();

atlases.append(atlas_source);
}

if (!atlases.is_empty()) {
tile_set_atlas_source_editor->init_new_atlases(atlases);
}

// Update the selected source (thus triggering an update).
_update_sources_list(source_id);
}

void TileSetEditor::_update_sources_list(int force_selected_id) {
if (tile_set.is_null()) {
return;
Expand Down Expand Up @@ -226,30 +237,6 @@ void TileSetEditor::_update_sources_list(int force_selected_id) {
TilesEditorUtils::get_singleton()->set_sources_lists_current(sources_list->get_current());
}

void TileSetEditor::_texture_file_selected(const String &p_path) {
Ref<Texture2D> texture = ResourceLoader::load(p_path);
if (texture.is_null()) {
EditorNode::get_singleton()->show_warning(TTR("Invalid texture selected."));
return;
}

int source_id = tile_set->get_next_source_id();

Ref<TileSetAtlasSource> atlas_source = memnew(TileSetAtlasSource);
atlas_source->set_texture(texture);

// Add a new source.
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add atlas source"));
undo_redo->add_do_method(*tile_set, "add_source", atlas_source, source_id);
undo_redo->add_do_method(*atlas_source, "set_texture_region_size", tile_set->get_tile_size());
undo_redo->add_undo_method(*tile_set, "remove_source", source_id);
undo_redo->commit_action();

_update_sources_list(source_id);
tile_set_atlas_source_editor->init_source();
}

void TileSetEditor::_source_selected(int p_source_index) {
ERR_FAIL_COND(!tile_set.is_valid());

Expand Down Expand Up @@ -308,8 +295,8 @@ void TileSetEditor::_source_add_id_pressed(int p_id_pressed) {
if (!texture_file_dialog) {
texture_file_dialog = memnew(EditorFileDialog);
add_child(texture_file_dialog);
texture_file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
texture_file_dialog->connect("file_selected", callable_mp(this, &TileSetEditor::_texture_file_selected));
texture_file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILES);
texture_file_dialog->connect("files_selected", callable_mp(this, &TileSetEditor::_load_texture_files));

List<String> extensions;
ResourceLoader::get_recognized_extensions_for_type("Texture2D", &extensions);
Expand Down
2 changes: 1 addition & 1 deletion editor/plugins/tiles/tile_set_editor.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class TileSetEditor : public Control {

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;
void _load_texture_files(const Vector<String> &p_paths);

void _update_sources_list(int force_selected_id = -1);

Expand All @@ -78,7 +79,6 @@ class TileSetEditor : public Control {
MenuButton *sources_advanced_menu_button = nullptr;
ItemList *sources_list = nullptr;
Ref<Texture2D> missing_texture_texture;
void _texture_file_selected(const String &p_path);
void _source_selected(int p_source_index);
void _source_delete_pressed();
void _source_add_id_pressed(int p_id_pressed);
Expand Down
Loading