1
0
Fork 0
mirror of https://github.com/Orama-Interactive/Pixelorama.git synced 2025-01-18 17:19:50 +00:00

Pattern filling - Partially addresses #130

If the user chooses a brush that is not the pixel or a circle brush and uses the bucket tool, the brush image is used as a pattern that fills the area.
This commit is contained in:
OverloadedOrama 2020-03-28 05:15:09 +02:00
parent 61c4ea7aa1
commit e072b95727
3 changed files with 102 additions and 23 deletions

View file

@ -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")

View file

@ -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,6 +359,18 @@ func _input(event : InputEvent) -> void:
horizontal_mirror = Global.right_horizontal_mirror
vertical_mirror = Global.right_vertical_mirror
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)
@ -362,6 +388,15 @@ 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:
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":
@ -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

View file

@ -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