diff --git a/assets/graphics/blue_themes/tools/magicwand.png b/assets/graphics/blue_themes/tools/magicwand.png new file mode 100644 index 000000000..70db804cf Binary files /dev/null and b/assets/graphics/blue_themes/tools/magicwand.png differ diff --git a/assets/graphics/blue_themes/tools/magicwand.png.import b/assets/graphics/blue_themes/tools/magicwand.png.import new file mode 100644 index 000000000..650e63dfd --- /dev/null +++ b/assets/graphics/blue_themes/tools/magicwand.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/magicwand.png-3075f7068af0c6e2ea80b52a2b42e0f3.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/graphics/blue_themes/tools/magicwand.png" +dest_files=[ "res://.import/magicwand.png-3075f7068af0c6e2ea80b52a2b42e0f3.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=false +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/assets/graphics/cursor_icons/magicwand_cursor.png b/assets/graphics/cursor_icons/magicwand_cursor.png new file mode 100644 index 000000000..fcf4c789b Binary files /dev/null and b/assets/graphics/cursor_icons/magicwand_cursor.png differ diff --git a/assets/graphics/cursor_icons/magicwand_cursor.png.import b/assets/graphics/cursor_icons/magicwand_cursor.png.import new file mode 100644 index 000000000..07c8de051 --- /dev/null +++ b/assets/graphics/cursor_icons/magicwand_cursor.png.import @@ -0,0 +1,13 @@ +[remap] + +importer="image" +type="Image" +path="res://.import/magicwand_cursor.png-101895aac3a0f59e7ab4bec0b6974cb2.image" + +[deps] + +source_file="res://assets/graphics/cursor_icons/magicwand_cursor.png" +dest_files=[ "res://.import/magicwand_cursor.png-101895aac3a0f59e7ab4bec0b6974cb2.image" ] + +[params] + diff --git a/assets/graphics/dark_themes/tools/magicwand.png b/assets/graphics/dark_themes/tools/magicwand.png new file mode 100644 index 000000000..70db804cf Binary files /dev/null and b/assets/graphics/dark_themes/tools/magicwand.png differ diff --git a/assets/graphics/dark_themes/tools/magicwand.png.import b/assets/graphics/dark_themes/tools/magicwand.png.import new file mode 100644 index 000000000..3e2810e6f --- /dev/null +++ b/assets/graphics/dark_themes/tools/magicwand.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/magicwand.png-3cccd2fa02877ce6a56ea4b20b6ea2d1.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/graphics/dark_themes/tools/magicwand.png" +dest_files=[ "res://.import/magicwand.png-3cccd2fa02877ce6a56ea4b20b6ea2d1.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=false +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/assets/graphics/light_themes/tools/magicwand.png b/assets/graphics/light_themes/tools/magicwand.png new file mode 100644 index 000000000..edf0681b6 Binary files /dev/null and b/assets/graphics/light_themes/tools/magicwand.png differ diff --git a/assets/graphics/light_themes/tools/magicwand.png.import b/assets/graphics/light_themes/tools/magicwand.png.import new file mode 100644 index 000000000..9c9f4b4bd --- /dev/null +++ b/assets/graphics/light_themes/tools/magicwand.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/magicwand.png-c29d8e73c331c766685584cb6eb33062.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/graphics/light_themes/tools/magicwand.png" +dest_files=[ "res://.import/magicwand.png-c29d8e73c331c766685584cb6eb33062.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=false +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/project.godot b/project.godot index f2060b1a1..7977f5254 100644 --- a/project.godot +++ b/project.godot @@ -518,6 +518,16 @@ right_color_select_tool={ "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":true,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":87,"unicode":0,"echo":false,"script":null) ] } +left_magic_wand_tool={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":81,"unicode":0,"echo":false,"script":null) + ] +} +right_magic_wand_tool={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":true,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":81,"unicode":0,"echo":false,"script":null) + ] +} [locale] diff --git a/src/Autoload/Global.gd b/src/Autoload/Global.gd index 004149632..9da113270 100644 --- a/src/Autoload/Global.gd +++ b/src/Autoload/Global.gd @@ -486,6 +486,13 @@ Press %s to move the content""") % [InputMap.get_action_list("left_rectangle_sel %s for right mouse button""") % [InputMap.get_action_list("left_color_select_tool")[0].as_text(), InputMap.get_action_list("right_color_select_tool")[0].as_text()] + var magic_wand : BaseButton = tool_buttons.find_node("MagicWand") + magic_wand.hint_tooltip = tr("""Magic Wand + +%s for left mouse button +%s for right mouse button""") % [InputMap.get_action_list("left_magic_wand_tool")[0].as_text(), InputMap.get_action_list("right_magic_wand_tool")[0].as_text()] + + var move_select : BaseButton = tool_buttons.find_node("Move") move_select.hint_tooltip = tr("""Move diff --git a/src/Autoload/Tools.gd b/src/Autoload/Tools.gd index 6650db65e..d9fbc7fc0 100644 --- a/src/Autoload/Tools.gd +++ b/src/Autoload/Tools.gd @@ -41,6 +41,7 @@ signal color_changed(color, button) var _tools = { "RectSelect" : "res://src/Tools/RectSelect.tscn", "ColorSelect" : "res://src/Tools/ColorSelect.tscn", + "MagicWand" : "res://src/Tools/MagicWand.tscn", "Move" : "res://src/Tools/Move.tscn", "Zoom" : "res://src/Tools/Zoom.tscn", "Pan" : "res://src/Tools/Pan.tscn", diff --git a/src/Tools/ColorSelect.gd b/src/Tools/ColorSelect.gd index 89eccdb08..8fccdb70e 100644 --- a/src/Tools/ColorSelect.gd +++ b/src/Tools/ColorSelect.gd @@ -14,14 +14,16 @@ func draw_move(_position : Vector2) -> void: func draw_end(position : Vector2) -> void: - var subtract_from_selection : bool = Tools.control var project : Project = Global.current_project if position.x < 0 or position.y < 0: return if position.x > project.size.x - 1 or position.y > project.size.y - 1: return + + var subtract_from_selection : bool = Tools.control if !Tools.shift and !subtract_from_selection: Global.canvas.selection.clear_selection() + var selection_bitmap_copy : BitMap = project.selection_bitmap.duplicate() var cel_image := Image.new() cel_image.copy_from(project.frames[project.current_frame].cels[project.current_layer].image) diff --git a/src/Tools/MagicWand.gd b/src/Tools/MagicWand.gd new file mode 100644 index 000000000..a0a6e9bcb --- /dev/null +++ b/src/Tools/MagicWand.gd @@ -0,0 +1,60 @@ +extends BaseTool + + +var undo_data : Dictionary + + +func draw_start(_position : Vector2) -> void: + Global.canvas.selection.move_content_confirm() + undo_data = Global.canvas.selection._get_undo_data(false) + + +func draw_move(_position : Vector2) -> void: + pass + + +func draw_end(position : Vector2) -> void: + var project : Project = Global.current_project + if position.x < 0 or position.y < 0: + return + if position.x > project.size.x - 1 or position.y > project.size.y - 1: + return + + var subtract_from_selection : bool = Tools.control + if !Tools.shift and !subtract_from_selection: + Global.canvas.selection.clear_selection() + + var selection_bitmap_copy : BitMap = project.selection_bitmap.duplicate() + var cel_image := Image.new() + cel_image.copy_from(project.frames[project.current_frame].cels[project.current_layer].image) + cel_image.lock() + var color := cel_image.get_pixelv(position) + + # Flood fill logic + var processed := BitMap.new() + processed.create(cel_image.get_size()) + var q = [position] + for n in q: + if processed.get_bit(n): + continue + var west : Vector2 = n + var east : Vector2 = n + while west.x >= 0 && cel_image.get_pixelv(west).is_equal_approx(color): + west += Vector2.LEFT + while east.x < project.size.x && cel_image.get_pixelv(east).is_equal_approx(color): + east += Vector2.RIGHT + for px in range(west.x + 1, east.x): + var p := Vector2(px, n.y) + selection_bitmap_copy.set_bit(p, !subtract_from_selection) + processed.set_bit(p, true) + var north := p + Vector2.UP + var south := p + Vector2.DOWN + if north.y >= 0 && cel_image.get_pixelv(north).is_equal_approx(color): + q.append(north) + if south.y < project.size.y && cel_image.get_pixelv(south).is_equal_approx(color): + q.append(south) + + cel_image.unlock() + project.selection_bitmap = selection_bitmap_copy + Global.canvas.selection.big_bounding_rectangle = project.get_selection_rectangle(project.selection_bitmap) + Global.canvas.selection.commit_undo("Rectangle Select", undo_data) diff --git a/src/Tools/MagicWand.tscn b/src/Tools/MagicWand.tscn new file mode 100644 index 000000000..6505fba02 --- /dev/null +++ b/src/Tools/MagicWand.tscn @@ -0,0 +1,20 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://src/Tools/BaseTool.tscn" type="PackedScene" id=1] +[ext_resource path="res://src/Tools/MagicWand.gd" type="Script" id=2] + +[node name="ToolOptions" instance=ExtResource( 1 )] +script = ExtResource( 2 ) + +[node name="PixelPerfect" parent="." index="1"] +visible = false + +[node name="EmptySpacer" parent="." index="2"] +visible = false +margin_top = 18.0 +margin_bottom = 30.0 + +[node name="Mirror" parent="." index="3"] +visible = false +margin_top = 18.0 +margin_bottom = 35.0 diff --git a/src/UI/ToolButtons.gd b/src/UI/ToolButtons.gd index 8aedda64a..d49733be8 100644 --- a/src/UI/ToolButtons.gd +++ b/src/UI/ToolButtons.gd @@ -5,6 +5,7 @@ extends VBoxContainer onready var tools := [ [$RectSelect, "rectangle_select"], [$ColorSelect, "color_select"], + [$MagicWand, "magic_wand"], [$Move, "move"], [$Zoom, "zoom"], [$Pan, "pan"], diff --git a/src/UI/UI.tscn b/src/UI/UI.tscn index 49f351652..a342842ff 100644 --- a/src/UI/UI.tscn +++ b/src/UI/UI.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=32 format=2] +[gd_scene load_steps=33 format=2] [ext_resource path="res://src/UI/ToolButtons.gd" type="Script" id=1] [ext_resource path="res://src/UI/Canvas/CanvasPreview.tscn" type="PackedScene" id=2] @@ -28,6 +28,7 @@ [ext_resource path="res://assets/graphics/dark_themes/tools/move.png" type="Texture" id=26] [ext_resource path="res://assets/graphics/tool_backgrounds/r.png" type="Texture" id=27] [ext_resource path="res://assets/graphics/dark_themes/tools/colorselect.png" type="Texture" id=28] +[ext_resource path="res://assets/graphics/dark_themes/tools/magicwand.png" type="Texture" id=29] [sub_resource type="ShaderMaterial" id=1] shader = ExtResource( 9 ) @@ -91,7 +92,7 @@ __meta__ = { margin_left = 7.0 margin_top = 7.0 margin_right = 39.0 -margin_bottom = 435.0 +margin_bottom = 471.0 size_flags_horizontal = 4 size_flags_vertical = 0 script = ExtResource( 1 ) @@ -148,7 +149,7 @@ __meta__ = { "_edit_use_anchors_": false } -[node name="Move" type="Button" parent="ToolPanel/PanelContainer/ToolButtons" groups=[ +[node name="MagicWand" type="Button" parent="ToolPanel/PanelContainer/ToolButtons" groups=[ "UIButtons", ]] margin_top = 72.0 @@ -158,6 +159,31 @@ rect_min_size = Vector2( 32, 32 ) mouse_default_cursor_shape = 2 button_mask = 3 +[node name="Background" type="TextureRect" parent="ToolPanel/PanelContainer/ToolButtons/MagicWand"] +margin_right = 32.0 +margin_bottom = 32.0 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="ToolIcon" type="TextureRect" parent="ToolPanel/PanelContainer/ToolButtons/MagicWand"] +margin_right = 32.0 +margin_bottom = 32.0 +texture = ExtResource( 29 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Move" type="Button" parent="ToolPanel/PanelContainer/ToolButtons" groups=[ +"UIButtons", +]] +margin_top = 108.0 +margin_right = 32.0 +margin_bottom = 140.0 +rect_min_size = Vector2( 32, 32 ) +mouse_default_cursor_shape = 2 +button_mask = 3 + [node name="Background" type="TextureRect" parent="ToolPanel/PanelContainer/ToolButtons/Move"] margin_right = 32.0 margin_bottom = 32.0 @@ -176,9 +202,9 @@ __meta__ = { [node name="Zoom" type="Button" parent="ToolPanel/PanelContainer/ToolButtons" groups=[ "UIButtons", ]] -margin_top = 108.0 +margin_top = 144.0 margin_right = 32.0 -margin_bottom = 140.0 +margin_bottom = 176.0 rect_min_size = Vector2( 32, 32 ) mouse_default_cursor_shape = 2 button_mask = 3 @@ -201,9 +227,9 @@ __meta__ = { [node name="Pan" type="Button" parent="ToolPanel/PanelContainer/ToolButtons" groups=[ "UIButtons", ]] -margin_top = 144.0 +margin_top = 180.0 margin_right = 32.0 -margin_bottom = 176.0 +margin_bottom = 212.0 rect_min_size = Vector2( 32, 32 ) mouse_default_cursor_shape = 2 button_mask = 3 @@ -226,9 +252,9 @@ __meta__ = { [node name="ColorPicker" type="Button" parent="ToolPanel/PanelContainer/ToolButtons" groups=[ "UIButtons", ]] -margin_top = 180.0 +margin_top = 216.0 margin_right = 32.0 -margin_bottom = 212.0 +margin_bottom = 248.0 rect_min_size = Vector2( 32, 32 ) mouse_default_cursor_shape = 2 button_mask = 3 @@ -251,9 +277,9 @@ __meta__ = { [node name="Pencil" type="Button" parent="ToolPanel/PanelContainer/ToolButtons" groups=[ "UIButtons", ]] -margin_top = 216.0 +margin_top = 252.0 margin_right = 32.0 -margin_bottom = 248.0 +margin_bottom = 284.0 rect_min_size = Vector2( 32, 32 ) mouse_default_cursor_shape = 2 button_mask = 3 @@ -277,9 +303,9 @@ __meta__ = { [node name="Eraser" type="Button" parent="ToolPanel/PanelContainer/ToolButtons" groups=[ "UIButtons", ]] -margin_top = 252.0 +margin_top = 288.0 margin_right = 32.0 -margin_bottom = 284.0 +margin_bottom = 320.0 rect_min_size = Vector2( 32, 32 ) mouse_default_cursor_shape = 2 button_mask = 3 @@ -303,9 +329,9 @@ __meta__ = { [node name="Bucket" type="Button" parent="ToolPanel/PanelContainer/ToolButtons" groups=[ "UIButtons", ]] -margin_top = 288.0 +margin_top = 324.0 margin_right = 32.0 -margin_bottom = 320.0 +margin_bottom = 356.0 rect_min_size = Vector2( 32, 32 ) mouse_default_cursor_shape = 2 button_mask = 3 @@ -328,9 +354,9 @@ __meta__ = { [node name="LightenDarken" type="Button" parent="ToolPanel/PanelContainer/ToolButtons" groups=[ "UIButtons", ]] -margin_top = 324.0 +margin_top = 360.0 margin_right = 32.0 -margin_bottom = 356.0 +margin_bottom = 392.0 rect_min_size = Vector2( 32, 32 ) mouse_default_cursor_shape = 2 button_mask = 3 @@ -353,9 +379,9 @@ __meta__ = { [node name="RectangleTool" type="Button" parent="ToolPanel/PanelContainer/ToolButtons" groups=[ "UIButtons", ]] -margin_top = 360.0 +margin_top = 396.0 margin_right = 32.0 -margin_bottom = 392.0 +margin_bottom = 428.0 rect_min_size = Vector2( 32, 32 ) mouse_default_cursor_shape = 2 button_mask = 3 @@ -378,9 +404,9 @@ __meta__ = { [node name="EllipseTool" type="Button" parent="ToolPanel/PanelContainer/ToolButtons" groups=[ "UIButtons", ]] -margin_top = 396.0 +margin_top = 432.0 margin_right = 32.0 -margin_bottom = 428.0 +margin_bottom = 464.0 rect_min_size = Vector2( 32, 32 ) mouse_default_cursor_shape = 2 button_mask = 3