diff --git a/Scripts/BrushButton.gd b/Scripts/BrushButton.gd index fa93b2008..89d76900c 100644 --- a/Scripts/BrushButton.gd +++ b/Scripts/BrushButton.gd @@ -10,12 +10,13 @@ func _on_BrushButton_pressed() -> void: if Input.is_action_just_released("middle_mouse"): _on_DeleteButton_pressed() return + # Change left brush if Global.brush_type_window_position == "left": Global.current_left_brush_type = brush_type Global.custom_left_brush_index = custom_brush_index if custom_brush_index > -1: # Custom brush - if Global.current_left_tool == "Pencil": + if Global.current_left_tool == "Pencil" or Global.current_left_tool == "Bucket": Global.left_color_interpolation_container.visible = true # if hint_tooltip == "": # Global.left_brush_type_label.text = tr("Custom brush") @@ -37,7 +38,7 @@ func _on_BrushButton_pressed() -> void: Global.current_right_brush_type = brush_type Global.custom_right_brush_index = custom_brush_index if custom_brush_index > -1: - if Global.current_right_tool == "Pencil": + if Global.current_right_tool == "Pencil" or Global.current_right_tool == "Bucket": Global.right_color_interpolation_container.visible = true # if hint_tooltip == "": # Global.right_brush_type_label.text = tr("Custom brush") diff --git a/Scripts/Canvas.gd b/Scripts/Canvas.gd index f889700ac..161a76554 100644 --- a/Scripts/Canvas.gd +++ b/Scripts/Canvas.gd @@ -333,6 +333,20 @@ func _input(event : InputEvent) -> void: pencil_and_eraser(sprite, mouse_pos, Color(0, 0, 0, 0), current_mouse_button, current_action) "Bucket": if can_handle: + var brush_type = Global.Brush_Types.PIXEL + var custom_brush_image : Image + var is_custom_brush := false + if current_mouse_button == "left_mouse": + brush_type = Global.current_left_brush_type + is_custom_brush = brush_type == Global.Brush_Types.FILE or brush_type == Global.Brush_Types.CUSTOM or brush_type == Global.Brush_Types.RANDOM_FILE + if is_custom_brush: + custom_brush_image = Global.custom_left_brush_image + elif current_mouse_button == "right_mouse": + brush_type = Global.current_right_brush_type + is_custom_brush = brush_type == Global.Brush_Types.FILE or brush_type == Global.Brush_Types.CUSTOM or brush_type == Global.Brush_Types.RANDOM_FILE + if is_custom_brush: + custom_brush_image = Global.custom_right_brush_image + if fill_area == 0: # Paint the specific area of the same color var horizontal_mirror := false var vertical_mirror := false @@ -345,16 +359,28 @@ func _input(event : InputEvent) -> void: horizontal_mirror = Global.right_horizontal_mirror vertical_mirror = Global.right_vertical_mirror - flood_fill(sprite, mouse_pos, sprite.get_pixelv(mouse_pos), current_color) - if horizontal_mirror: - var pos := Vector2(mirror_x, mouse_pos.y) - flood_fill(sprite, pos, sprite.get_pixelv(pos), current_color) - if vertical_mirror: - var pos := Vector2(mouse_pos.x, mirror_y) - flood_fill(sprite, pos, sprite.get_pixelv(pos), current_color) - if horizontal_mirror && vertical_mirror: - var pos := Vector2(mirror_x, mirror_y) - flood_fill(sprite, pos, sprite.get_pixelv(pos), current_color) + if is_custom_brush: # Pattern fill + pattern_fill(sprite, mouse_pos, custom_brush_image, sprite.get_pixelv(mouse_pos)) + if horizontal_mirror: + var pos := Vector2(mirror_x, mouse_pos.y) + pattern_fill(sprite, pos, custom_brush_image, sprite.get_pixelv(mouse_pos)) + if vertical_mirror: + var pos := Vector2(mouse_pos.x, mirror_y) + pattern_fill(sprite, pos, custom_brush_image, sprite.get_pixelv(mouse_pos)) + if horizontal_mirror && vertical_mirror: + var pos := Vector2(mirror_x, mirror_y) + pattern_fill(sprite, pos, custom_brush_image, sprite.get_pixelv(mouse_pos)) + else: # Flood fill + flood_fill(sprite, mouse_pos, sprite.get_pixelv(mouse_pos), current_color) + if horizontal_mirror: + var pos := Vector2(mirror_x, mouse_pos.y) + flood_fill(sprite, pos, sprite.get_pixelv(pos), current_color) + if vertical_mirror: + var pos := Vector2(mouse_pos.x, mirror_y) + flood_fill(sprite, pos, sprite.get_pixelv(pos), current_color) + if horizontal_mirror && vertical_mirror: + var pos := Vector2(mirror_x, mirror_y) + flood_fill(sprite, pos, sprite.get_pixelv(pos), current_color) else: # Paint all pixels of the same color var pixel_color : Color = sprite.get_pixelv(mouse_pos) @@ -362,7 +388,16 @@ func _input(event : InputEvent) -> void: for yy in range(north_limit, south_limit): var c : Color = sprite.get_pixel(xx, yy) if c == pixel_color: - sprite.set_pixel(xx, yy, current_color) + if is_custom_brush: # Pattern fill + custom_brush_image.lock() + var pattern_size := custom_brush_image.get_size() + var xxx : int = int(xx) % int(pattern_size.x) + var yyy : int = int(yy) % int(pattern_size.y) + var pattern_color : Color = custom_brush_image.get_pixel(xxx, yyy) + sprite.set_pixel(xx, yy, pattern_color) + custom_brush_image.unlock() + else: + sprite.set_pixel(xx, yy, current_color) sprite_changed_this_frame = true "LightenDarken": if can_handle: @@ -589,6 +624,7 @@ func draw_brush(sprite : Image, pos : Vector2, color : Color, current_mouse_butt vertical_mirror = Global.left_vertical_mirror ld = Global.left_ld ld_amount = Global.left_ld_amount + elif current_mouse_button == "right_mouse": brush_size = Global.right_brush_size brush_type = Global.current_right_brush_type @@ -840,6 +876,44 @@ func flood_fill(sprite : Image, pos : Vector2, target_color : Color, replace_col q.append(south) sprite_changed_this_frame = true + +func pattern_fill(sprite : Image, pos : Vector2, pattern : Image, target_color : Color) -> void: + pos = pos.floor() + if !point_in_rectangle(pos, Vector2(west_limit - 1, north_limit - 1), Vector2(east_limit, south_limit)): + return + + pattern.lock() + var pattern_size := pattern.get_size() + var q = [pos] + + for n in q: + var west : Vector2 = n + var east : Vector2 = n + while west.x >= west_limit && sprite.get_pixelv(west) == target_color: + west += Vector2.LEFT + while east.x < east_limit && sprite.get_pixelv(east) == target_color: + east += Vector2.RIGHT + + for px in range(west.x + 1, east.x): + var p := Vector2(px, n.y) + var xx : int = int(px) % int(pattern_size.x) + var yy : int = int(n.y) % int(pattern_size.y) + var pattern_color : Color = pattern.get_pixel(xx, yy) + if pattern_color == target_color: + continue + sprite.set_pixelv(p, pattern_color) + + var north := p + Vector2.UP + var south := p + Vector2.DOWN + if north.y >= north_limit && sprite.get_pixelv(north) == target_color: + q.append(north) + if south.y < south_limit && sprite.get_pixelv(south) == target_color: + q.append(south) + + pattern.unlock() + + + # Algorithm based on http://members.chello.at/easyfilter/bresenham.html func plot_circle(sprite : Image, xm : int, ym : int, r : int, color : Color, fill := false) -> void: var radius := r # Used later for filling diff --git a/Scripts/Main.gd b/Scripts/Main.gd index f27f10972..2e3d0cbee 100644 --- a/Scripts/Main.gd +++ b/Scripts/Main.gd @@ -150,7 +150,7 @@ func _ready() -> void: t[0].connect("pressed", self, "_on_Tool_pressed", [t[0]]) # Checks to see if it's 3.1.x - if Engine.get_version_info().major == 3 && Engine.get_version_info().minor < 2: + if Engine.get_version_info().major == 3 and Engine.get_version_info().minor < 2: Global.left_color_picker.get_picker().move_child(Global.left_color_picker.get_picker().get_child(0), 1) Global.right_color_picker.get_picker().move_child(Global.right_color_picker.get_picker().get_child(0), 1) @@ -190,7 +190,7 @@ func _input(event : InputEvent) -> void: Global.right_cursor.position = get_global_mouse_position() + Vector2(32, 32) Global.right_cursor.texture = Global.right_cursor_tool_texture - if event is InputEventKey && (event.scancode == KEY_ENTER || event.scancode == KEY_KP_ENTER): + if event is InputEventKey and (event.scancode == KEY_ENTER or event.scancode == KEY_KP_ENTER): if get_focus_owner() is LineEdit: get_focus_owner().release_focus() @@ -308,7 +308,7 @@ func image_menu_id_pressed(id : int) -> void: var used_rect : Rect2 = Global.canvas.layers[0][0].get_used_rect() # However, if first layer is empty, loop through all layers until we find one that isn't var i := 0 - while(i < Global.canvas.layers.size() - 1 && Global.canvas.layers[i][0].get_used_rect() == Rect2(0, 0, 0, 0)): + while(i < Global.canvas.layers.size() - 1 and Global.canvas.layers[i][0].get_used_rect() == Rect2(0, 0, 0, 0)): i += 1 used_rect = Global.canvas.layers[i][0].get_used_rect() @@ -616,7 +616,7 @@ func _can_draw_false() -> void: func _on_Tool_pressed(tool_pressed : BaseButton, mouse_press := true, key_for_left := true) -> void: var current_action := tool_pressed.name - if (mouse_press && Input.is_action_just_released("left_mouse")) || (!mouse_press && key_for_left): + if (mouse_press and Input.is_action_just_released("left_mouse")) or (!mouse_press and key_for_left): Global.current_left_tool = current_action # Start from 3, so the label and checkboxes won't get invisible @@ -628,7 +628,7 @@ func _on_Tool_pressed(tool_pressed : BaseButton, mouse_press := true, key_for_le Global.left_brush_type_container.visible = true # Global.left_brush_size_container.visible = true Global.left_mirror_container.visible = true - if Global.current_left_brush_type == Global.Brush_Types.FILE || Global.current_left_brush_type == Global.Brush_Types.CUSTOM || Global.current_left_brush_type == Global.Brush_Types.RANDOM_FILE: + if Global.current_left_brush_type == Global.Brush_Types.FILE or Global.current_left_brush_type == Global.Brush_Types.CUSTOM or Global.current_left_brush_type == Global.Brush_Types.RANDOM_FILE: Global.left_color_interpolation_container.visible = true elif current_action == "Eraser": Global.left_brush_type_container.visible = true @@ -637,6 +637,8 @@ func _on_Tool_pressed(tool_pressed : BaseButton, mouse_press := true, key_for_le elif current_action == "Bucket": Global.left_fill_area_container.visible = true Global.left_mirror_container.visible = true + if Global.current_left_brush_type == Global.Brush_Types.FILE or Global.current_left_brush_type == Global.Brush_Types.CUSTOM or Global.current_left_brush_type == Global.Brush_Types.RANDOM_FILE: + Global.left_color_interpolation_container.visible = true elif current_action == "LightenDarken": # Global.left_brush_size_container.visible = true Global.left_ld_container.visible = true @@ -644,7 +646,7 @@ func _on_Tool_pressed(tool_pressed : BaseButton, mouse_press := true, key_for_le elif current_action == "ColorPicker": Global.left_colorpicker_container.visible = true - elif (mouse_press && Input.is_action_just_released("right_mouse")) || (!mouse_press && !key_for_left): + elif (mouse_press and Input.is_action_just_released("right_mouse")) or (!mouse_press and !key_for_left): Global.current_right_tool = current_action # Start from 3, so the label and checkboxes won't get invisible for i in range(3, Global.right_tool_options_container.get_child_count()): @@ -655,7 +657,7 @@ func _on_Tool_pressed(tool_pressed : BaseButton, mouse_press := true, key_for_le Global.right_brush_type_container.visible = true # Global.right_brush_size_container.visible = true Global.right_mirror_container.visible = true - if Global.current_right_brush_type == Global.Brush_Types.FILE || Global.current_right_brush_type == Global.Brush_Types.CUSTOM || Global.current_right_brush_type == Global.Brush_Types.RANDOM_FILE: + if Global.current_right_brush_type == Global.Brush_Types.FILE or Global.current_right_brush_type == Global.Brush_Types.CUSTOM or Global.current_right_brush_type == Global.Brush_Types.RANDOM_FILE: Global.right_color_interpolation_container.visible = true elif current_action == "Eraser": Global.right_brush_type_container.visible = true @@ -664,6 +666,8 @@ func _on_Tool_pressed(tool_pressed : BaseButton, mouse_press := true, key_for_le elif current_action == "Bucket": Global.right_fill_area_container.visible = true Global.right_mirror_container.visible = true + if Global.current_right_brush_type == Global.Brush_Types.FILE or Global.current_right_brush_type == Global.Brush_Types.CUSTOM or Global.current_right_brush_type == Global.Brush_Types.RANDOM_FILE: + Global.right_color_interpolation_container.visible = true elif current_action == "LightenDarken": # Global.right_brush_size_container.visible = true Global.right_ld_container.visible = true @@ -673,7 +677,7 @@ func _on_Tool_pressed(tool_pressed : BaseButton, mouse_press := true, key_for_le for t in tools: var tool_name : String = t[0].name - if tool_name == Global.current_left_tool && tool_name == Global.current_right_tool: + if tool_name == Global.current_left_tool and tool_name == Global.current_right_tool: t[0].texture_normal = load("res://Assets/Graphics/%s Themes/Tools/%s_l_r.png" % [Global.theme_type, tool_name]) elif tool_name == Global.current_left_tool: t[0].texture_normal = load("res://Assets/Graphics/%s Themes/Tools/%s_l.png" % [Global.theme_type, tool_name]) @@ -726,7 +730,7 @@ func _on_ColorDefaults_pressed() -> void: func _on_LeftColorPickerButton_color_changed(color : Color) -> void: # If the color changed while it's on full transparency, make it opaque (GH issue #54) if color.a == 0: - if previous_left_color.r != color.r || previous_left_color.g != color.g || previous_left_color.b != color.b: + if previous_left_color.r != color.r or previous_left_color.g != color.g or previous_left_color.b != color.b: Global.left_color_picker.color.a = 1 update_left_custom_brush() previous_left_color = color @@ -735,7 +739,7 @@ func _on_LeftColorPickerButton_color_changed(color : Color) -> void: func _on_RightColorPickerButton_color_changed(color : Color) -> void: # If the color changed while it's on full transparency, make it opaque (GH issue #54) if color.a == 0: - if previous_right_color.r != color.r || previous_right_color.g != color.g || previous_right_color.b != color.b: + if previous_right_color.r != color.r or previous_right_color.g != color.g or previous_right_color.b != color.b: Global.right_color_picker.color.a = 1 update_right_custom_brush() previous_right_color = color