From eccd1452faa0c9389b52ea4435a908d6d542e515 Mon Sep 17 00:00:00 2001 From: Sofox Date: Sun, 11 Aug 2024 16:38:41 +0100 Subject: [PATCH] Enable SpriteFramesEditor to guess the amount of rows and columns of a sprite sheet when loading it for the first time --- .../plugins/sprite_frames_editor_plugin.cpp | 90 ++++++++++++++++++- editor/plugins/sprite_frames_editor_plugin.h | 3 + 2 files changed, 89 insertions(+), 4 deletions(-) diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp index 48087e3166a..ff5aca6cb0b 100644 --- a/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/editor/plugins/sprite_frames_editor_plugin.cpp @@ -504,6 +504,82 @@ void SpriteFramesEditor::_update_show_settings() { } } +void SpriteFramesEditor::_auto_slice_sprite_sheet() { + if (updating_split_settings) { + return; + } + updating_split_settings = true; + + const Size2i size = split_sheet_preview->get_texture()->get_size(); + + const Size2i split_sheet = _estimate_sprite_sheet_size(split_sheet_preview->get_texture()); + split_sheet_h->set_value(split_sheet.x); + split_sheet_v->set_value(split_sheet.y); + split_sheet_size_x->set_value(size.x / split_sheet.x); + split_sheet_size_y->set_value(size.y / split_sheet.y); + split_sheet_sep_x->set_value(0); + split_sheet_sep_y->set_value(0); + split_sheet_offset_x->set_value(0); + split_sheet_offset_y->set_value(0); + + updating_split_settings = false; + + frames_selected.clear(); + selected_count = 0; + last_frame_selected = -1; + split_sheet_preview->queue_redraw(); +} + +bool SpriteFramesEditor::_matches_background_color(const Color &p_background_color, const Color &p_pixel_color) { + if ((p_background_color.a == 0 && p_pixel_color.a == 0) || p_background_color.is_equal_approx(p_pixel_color)) { + return true; + } + + Color d = p_background_color - p_pixel_color; + // 0.04f is the threshold for how much a colour can deviate from background colour and still be considered a match. Arrived at through experimentation, can be tweaked. + return (d.r * d.r) + (d.g * d.g) + (d.b * d.b) + (d.a * d.a) < 0.04f; +} + +Size2i SpriteFramesEditor::_estimate_sprite_sheet_size(const Ref p_texture) { + Ref image = p_texture->get_image(); + Size2i size = p_texture->get_size(); + + Color assumed_background_color = image->get_pixel(0, 0); + Size2i sheet_size; + + bool previous_line_background = true; + for (int x = 0; x < size.x; x++) { + int y = 0; + while (y < size.y && _matches_background_color(assumed_background_color, image->get_pixel(x, y))) { + y++; + } + bool current_line_background = (y == size.y); + if (previous_line_background && !current_line_background) { + sheet_size.x++; + } + previous_line_background = current_line_background; + } + + previous_line_background = true; + for (int y = 0; y < size.y; y++) { + int x = 0; + while (x < size.x && _matches_background_color(assumed_background_color, image->get_pixel(x, y))) { + x++; + } + bool current_line_background = (x == size.x); + if (previous_line_background && !current_line_background) { + sheet_size.y++; + } + previous_line_background = current_line_background; + } + + if (sheet_size == Size2i(0, 0) || sheet_size == Size2i(1, 1)) { + sheet_size = Size2i(4, 4); + } + + return sheet_size; +} + void SpriteFramesEditor::_prepare_sprite_sheet(const String &p_file) { Ref texture = ResourceLoader::load(p_file); if (texture.is_null()) { @@ -530,10 +606,11 @@ void SpriteFramesEditor::_prepare_sprite_sheet(const String &p_file) { // Different texture, reset to 4x4. dominant_param = PARAM_FRAME_COUNT; updating_split_settings = true; - split_sheet_h->set_value(4); - split_sheet_v->set_value(4); - split_sheet_size_x->set_value(size.x / 4); - split_sheet_size_y->set_value(size.y / 4); + const Size2i split_sheet = Size2i(4, 4); + split_sheet_h->set_value(split_sheet.x); + split_sheet_v->set_value(split_sheet.y); + split_sheet_size_x->set_value(size.x / split_sheet.x); + split_sheet_size_y->set_value(size.y / split_sheet.y); split_sheet_sep_x->set_value(0); split_sheet_sep_y->set_value(0); split_sheet_offset_x->set_value(0); @@ -2290,6 +2367,11 @@ SpriteFramesEditor::SpriteFramesEditor() { split_sheet_offset_hb->add_child(split_sheet_offset_vb); split_sheet_settings_vb->add_child(split_sheet_offset_hb); + Button *auto_slice = memnew(Button); + auto_slice->set_text(TTR("Auto Slice")); + auto_slice->connect(SceneStringName(pressed), callable_mp(this, &SpriteFramesEditor::_auto_slice_sprite_sheet)); + split_sheet_settings_vb->add_child(auto_slice); + split_sheet_hb->add_child(split_sheet_settings_vb); file_split_sheet = memnew(EditorFileDialog); diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h index 9b6aaf98fe0..d6345a3ac8a 100644 --- a/editor/plugins/sprite_frames_editor_plugin.h +++ b/editor/plugins/sprite_frames_editor_plugin.h @@ -234,6 +234,9 @@ class SpriteFramesEditor : public HSplitContainer { void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); void _open_sprite_sheet(); + void _auto_slice_sprite_sheet(); + bool _matches_background_color(const Color &p_background_color, const Color &p_pixel_color); + Size2i _estimate_sprite_sheet_size(const Ref p_texture); void _prepare_sprite_sheet(const String &p_file); int _sheet_preview_position_to_frame_index(const Vector2 &p_position); void _sheet_preview_draw();