mirror of
https://github.com/Orama-Interactive/Pixelorama.git
synced 2025-01-18 17:19:50 +00:00
Pixel Perfect mode for brush, eraser and lighten/darken (#222)
* Add pixel perfect mode for pencil and eraser * Add Pixel Perfect for left and right tools Co-authored-by: Dávid Gábor Bodor <david.gabor.bodr@gmail.com>
This commit is contained in:
parent
0bed558e31
commit
1ccd5dde7a
36
Main.tscn
36
Main.tscn
|
@ -637,6 +637,23 @@ value = 1.0
|
|||
allow_greater = true
|
||||
ticks_on_borders = true
|
||||
|
||||
[node name="LeftBrushPixelPerfectMode" type="VBoxContainer" parent="MenuAndUI/UI/RightPanel/PreviewAndPalettes/ToolAndPaletteVSplit/ColorAndToolOptions/ScrollContainer/ToolOptions/LeftToolOptions"]
|
||||
margin_top = 71.0
|
||||
margin_right = 160.0
|
||||
margin_bottom = 87.0
|
||||
alignment = 1
|
||||
|
||||
[node name="LeftPixelPerfectMode" type="CheckBox" parent="MenuAndUI/UI/RightPanel/PreviewAndPalettes/ToolAndPaletteVSplit/ColorAndToolOptions/ScrollContainer/ToolOptions/LeftToolOptions/LeftBrushPixelPerfectMode"]
|
||||
margin_left = 36.0
|
||||
margin_right = 123.0
|
||||
margin_bottom = 16.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
size_flags_horizontal = 4
|
||||
pressed = true
|
||||
text = "Pixel Perfect"
|
||||
align = 1
|
||||
|
||||
[node name="LeftColorInterpolation" type="VBoxContainer" parent="MenuAndUI/UI/RightPanel/PreviewAndPalettes/ToolAndPaletteVSplit/ColorAndToolOptions/ScrollContainer/ToolOptions/LeftToolOptions"]
|
||||
visible = false
|
||||
margin_top = 75.0
|
||||
|
@ -1031,6 +1048,23 @@ value = 1.0
|
|||
allow_greater = true
|
||||
ticks_on_borders = true
|
||||
|
||||
[node name="RightBrushPixelPerfectMode" type="VBoxContainer" parent="MenuAndUI/UI/RightPanel/PreviewAndPalettes/ToolAndPaletteVSplit/ColorAndToolOptions/ScrollContainer/ToolOptions/RightToolOptions"]
|
||||
margin_top = 71.0
|
||||
margin_right = 160.0
|
||||
margin_bottom = 87.0
|
||||
alignment = 1
|
||||
|
||||
[node name="RightPixelPerfectMode" type="CheckBox" parent="MenuAndUI/UI/RightPanel/PreviewAndPalettes/ToolAndPaletteVSplit/ColorAndToolOptions/ScrollContainer/ToolOptions/RightToolOptions/RightBrushPixelPerfectMode"]
|
||||
margin_left = 36.0
|
||||
margin_right = 123.0
|
||||
margin_bottom = 16.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
size_flags_horizontal = 4
|
||||
pressed = true
|
||||
text = "Pixel Perfect"
|
||||
align = 1
|
||||
|
||||
[node name="RightColorInterpolation" type="VBoxContainer" parent="MenuAndUI/UI/RightPanel/PreviewAndPalettes/ToolAndPaletteVSplit/ColorAndToolOptions/ScrollContainer/ToolOptions/RightToolOptions"]
|
||||
visible = false
|
||||
margin_top = 75.0
|
||||
|
@ -1658,6 +1692,7 @@ visible = false
|
|||
[connection signal="pressed" from="MenuAndUI/UI/RightPanel/PreviewAndPalettes/ToolAndPaletteVSplit/ColorAndToolOptions/ScrollContainer/ToolOptions/LeftToolOptions/LeftBrushType/LeftBrushTypeButton" to="." method="_on_LeftBrushTypeButton_pressed"]
|
||||
[connection signal="value_changed" from="MenuAndUI/UI/RightPanel/PreviewAndPalettes/ToolAndPaletteVSplit/ColorAndToolOptions/ScrollContainer/ToolOptions/LeftToolOptions/LeftBrushType/LeftBrushSizeEdit" to="." method="_on_LeftBrushSizeEdit_value_changed"]
|
||||
[connection signal="value_changed" from="MenuAndUI/UI/RightPanel/PreviewAndPalettes/ToolAndPaletteVSplit/ColorAndToolOptions/ScrollContainer/ToolOptions/LeftToolOptions/LeftBrushSizeSlider" to="." method="_on_LeftBrushSizeEdit_value_changed"]
|
||||
[connection signal="toggled" from="MenuAndUI/UI/RightPanel/PreviewAndPalettes/ToolAndPaletteVSplit/ColorAndToolOptions/ScrollContainer/ToolOptions/LeftToolOptions/LeftBrushPixelPerfectMode/LeftPixelPerfectMode" to="." method="_on_LeftPixelPerfectMode_toggled"]
|
||||
[connection signal="value_changed" from="MenuAndUI/UI/RightPanel/PreviewAndPalettes/ToolAndPaletteVSplit/ColorAndToolOptions/ScrollContainer/ToolOptions/LeftToolOptions/LeftColorInterpolation/LeftInterpolateFactor" to="." method="_on_LeftInterpolateFactor_value_changed"]
|
||||
[connection signal="value_changed" from="MenuAndUI/UI/RightPanel/PreviewAndPalettes/ToolAndPaletteVSplit/ColorAndToolOptions/ScrollContainer/ToolOptions/LeftToolOptions/LeftColorInterpolation/LeftInterpolateSlider" to="." method="_on_LeftInterpolateFactor_value_changed"]
|
||||
[connection signal="item_selected" from="MenuAndUI/UI/RightPanel/PreviewAndPalettes/ToolAndPaletteVSplit/ColorAndToolOptions/ScrollContainer/ToolOptions/LeftToolOptions/LeftFillArea/LeftFillAreaOptions" to="." method="_on_LeftFillAreaOptions_item_selected"]
|
||||
|
@ -1677,6 +1712,7 @@ visible = false
|
|||
[connection signal="pressed" from="MenuAndUI/UI/RightPanel/PreviewAndPalettes/ToolAndPaletteVSplit/ColorAndToolOptions/ScrollContainer/ToolOptions/RightToolOptions/RightBrushType/RightBrushTypeButton" to="." method="_on_RightBrushTypeButton_pressed"]
|
||||
[connection signal="value_changed" from="MenuAndUI/UI/RightPanel/PreviewAndPalettes/ToolAndPaletteVSplit/ColorAndToolOptions/ScrollContainer/ToolOptions/RightToolOptions/RightBrushType/RightBrushSizeEdit" to="." method="_on_RightBrushSizeEdit_value_changed"]
|
||||
[connection signal="value_changed" from="MenuAndUI/UI/RightPanel/PreviewAndPalettes/ToolAndPaletteVSplit/ColorAndToolOptions/ScrollContainer/ToolOptions/RightToolOptions/RightBrushSizeSlider" to="." method="_on_RightBrushSizeEdit_value_changed"]
|
||||
[connection signal="toggled" from="MenuAndUI/UI/RightPanel/PreviewAndPalettes/ToolAndPaletteVSplit/ColorAndToolOptions/ScrollContainer/ToolOptions/RightToolOptions/RightBrushPixelPerfectMode/RightPixelPerfectMode" to="." method="_on_RightPixelPerfectMode_toggled"]
|
||||
[connection signal="value_changed" from="MenuAndUI/UI/RightPanel/PreviewAndPalettes/ToolAndPaletteVSplit/ColorAndToolOptions/ScrollContainer/ToolOptions/RightToolOptions/RightColorInterpolation/RightInterpolateFactor" to="." method="_on_RightInterpolateFactor_value_changed"]
|
||||
[connection signal="value_changed" from="MenuAndUI/UI/RightPanel/PreviewAndPalettes/ToolAndPaletteVSplit/ColorAndToolOptions/ScrollContainer/ToolOptions/RightToolOptions/RightColorInterpolation/RightInterpolateSlider" to="." method="_on_RightInterpolateFactor_value_changed"]
|
||||
[connection signal="item_selected" from="MenuAndUI/UI/RightPanel/PreviewAndPalettes/ToolAndPaletteVSplit/ColorAndToolOptions/ScrollContainer/ToolOptions/RightToolOptions/RightFillArea/RightFillAreaOptions" to="." method="_on_RightFillAreaOptions_item_selected"]
|
||||
|
|
|
@ -27,6 +27,17 @@ var is_making_selection := "None"
|
|||
var line_2d : Line2D
|
||||
var pen_pressure := 1.0 # For tablet pressure sensitivity
|
||||
|
||||
const Drawer = preload("Drawers.gd").Drawer
|
||||
const SimpleDrawer = preload("Drawers.gd").SimpleDrawer
|
||||
const PixelPerfectDrawer = preload("Drawers.gd").PixelPerfectDrawer
|
||||
|
||||
var pixel_perfect_drawer := PixelPerfectDrawer.new()
|
||||
var pixel_perfect_drawer_h_mirror := PixelPerfectDrawer.new()
|
||||
var pixel_perfect_drawer_v_mirror := PixelPerfectDrawer.new()
|
||||
var pixel_perfect_drawer_hv_mirror := PixelPerfectDrawer.new()
|
||||
var simple_drawer := SimpleDrawer.new()
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
var fill_layers := layers.empty()
|
||||
|
@ -219,6 +230,10 @@ func _input(event : InputEvent) -> void:
|
|||
made_line = false
|
||||
mouse_press_pixels.clear()
|
||||
mouse_press_pressure_values.clear()
|
||||
pixel_perfect_drawer.reset()
|
||||
pixel_perfect_drawer_h_mirror.reset()
|
||||
pixel_perfect_drawer_v_mirror.reset()
|
||||
pixel_perfect_drawer_hv_mirror.reset()
|
||||
can_undo = true
|
||||
|
||||
current_pixel = get_local_mouse_position() + location
|
||||
|
@ -610,8 +625,11 @@ func draw_brush(sprite : Image, pos : Vector2, color : Color, current_mouse_butt
|
|||
var brush_type = Global.Brush_Types.PIXEL
|
||||
var brush_index := -1
|
||||
var custom_brush_image : Image
|
||||
|
||||
var horizontal_mirror := false
|
||||
var vertical_mirror := false
|
||||
var pixel_perfect := false
|
||||
|
||||
var ld := 0
|
||||
var ld_amount := 0.1
|
||||
if Global.pressure_sensitivity_mode == Global.Pressure_Sensitivity.ALPHA:
|
||||
|
@ -637,6 +655,7 @@ func draw_brush(sprite : Image, pos : Vector2, color : Color, current_mouse_butt
|
|||
|
||||
horizontal_mirror = Global.left_horizontal_mirror
|
||||
vertical_mirror = Global.left_vertical_mirror
|
||||
pixel_perfect = Global.left_pixel_perfect
|
||||
ld = Global.left_ld
|
||||
ld_amount = Global.left_ld_amount
|
||||
|
||||
|
@ -658,6 +677,7 @@ func draw_brush(sprite : Image, pos : Vector2, color : Color, current_mouse_butt
|
|||
|
||||
horizontal_mirror = Global.right_horizontal_mirror
|
||||
vertical_mirror = Global.right_vertical_mirror
|
||||
pixel_perfect = Global.right_pixel_perfect
|
||||
ld = Global.right_ld
|
||||
ld_amount = Global.right_ld_amount
|
||||
|
||||
|
@ -667,6 +687,11 @@ func draw_brush(sprite : Image, pos : Vector2, color : Color, current_mouse_butt
|
|||
var end_pos_y
|
||||
|
||||
if brush_type == Global.Brush_Types.PIXEL || current_action == "LightenDarken":
|
||||
var drawer = pixel_perfect_drawer if pixel_perfect else simple_drawer
|
||||
var drawer_v_mirror = pixel_perfect_drawer_v_mirror if pixel_perfect else simple_drawer
|
||||
var drawer_h_mirror = pixel_perfect_drawer_h_mirror if pixel_perfect else simple_drawer
|
||||
var drawer_hv_mirror = pixel_perfect_drawer_hv_mirror if pixel_perfect else simple_drawer
|
||||
|
||||
start_pos_x = pos.x - (brush_size >> 1)
|
||||
start_pos_y = pos.y - (brush_size >> 1)
|
||||
end_pos_x = start_pos_x + brush_size
|
||||
|
@ -696,7 +721,8 @@ func draw_brush(sprite : Image, pos : Vector2, color : Color, current_mouse_butt
|
|||
mouse_press_pressure_values.append(pen_pressure)
|
||||
else:
|
||||
mouse_press_pressure_values[saved_pixel_index] = pen_pressure
|
||||
sprite.set_pixel(cur_pos_x, cur_pos_y, _c)
|
||||
drawer.set_pixel(sprite, Vector2(cur_pos_x, cur_pos_y), _c)
|
||||
|
||||
sprite_changed_this_frame = true
|
||||
|
||||
# Handle mirroring
|
||||
|
@ -713,7 +739,7 @@ func draw_brush(sprite : Image, pos : Vector2, color : Color, current_mouse_butt
|
|||
|
||||
mouse_press_pixels.append(pos_floored)
|
||||
mouse_press_pressure_values.append(pen_pressure)
|
||||
sprite.set_pixel(mirror_x, cur_pos_y, _c)
|
||||
drawer_h_mirror.set_pixel(sprite, Vector2(mirror_x, cur_pos_y), _c)
|
||||
sprite_changed_this_frame = true
|
||||
|
||||
if vertical_mirror:
|
||||
|
@ -726,7 +752,7 @@ func draw_brush(sprite : Image, pos : Vector2, color : Color, current_mouse_butt
|
|||
_c = current_pixel_color.darkened(ld_amount)
|
||||
mouse_press_pixels.append(pos_floored)
|
||||
mouse_press_pressure_values.append(pen_pressure)
|
||||
sprite.set_pixel(cur_pos_x, mirror_y, _c)
|
||||
drawer_v_mirror.set_pixel(sprite, Vector2(cur_pos_x, mirror_y), _c)
|
||||
sprite_changed_this_frame = true
|
||||
|
||||
if horizontal_mirror && vertical_mirror:
|
||||
|
@ -740,7 +766,7 @@ func draw_brush(sprite : Image, pos : Vector2, color : Color, current_mouse_butt
|
|||
|
||||
mouse_press_pixels.append(pos_floored)
|
||||
mouse_press_pressure_values.append(pen_pressure)
|
||||
sprite.set_pixel(mirror_x, mirror_y, _c)
|
||||
drawer_hv_mirror.set_pixel(sprite, Vector2(mirror_x, mirror_y), _c)
|
||||
sprite_changed_this_frame = true
|
||||
|
||||
elif brush_type == Global.Brush_Types.CIRCLE || brush_type == Global.Brush_Types.FILLED_CIRCLE:
|
||||
|
|
37
Scripts/Drawers.gd
Normal file
37
Scripts/Drawers.gd
Normal file
|
@ -0,0 +1,37 @@
|
|||
class Drawer:
|
||||
func reset() -> void:
|
||||
pass
|
||||
|
||||
func set_pixel(sprite: Image, pos: Vector2, new_color: Color) -> void:
|
||||
pass
|
||||
|
||||
|
||||
class SimpleDrawer extends Drawer:
|
||||
func reset() -> void:
|
||||
pass
|
||||
|
||||
func set_pixel(sprite: Image, pos: Vector2, new_color: Color) -> void:
|
||||
sprite.set_pixel(pos.x, pos.y, new_color)
|
||||
|
||||
|
||||
class PixelPerfectDrawer extends Drawer:
|
||||
const neighbours = [Vector2(0, 1), Vector2(1, 0), Vector2(-1, 0), Vector2(0, -1)]
|
||||
const corners = [Vector2(1, 1), Vector2(-1, -1), Vector2(-1, 1), Vector2(1, -1)]
|
||||
var last_pixels = [null, null]
|
||||
|
||||
func reset():
|
||||
last_pixels = [null, null]
|
||||
|
||||
func set_pixel(sprite: Image, pos: Vector2, new_color: Color) -> void:
|
||||
last_pixels.push_back([pos, sprite.get_pixel(pos.x, pos.y)])
|
||||
sprite.set_pixel(pos.x, pos.y, new_color)
|
||||
|
||||
var corner = last_pixels.pop_front()
|
||||
var neighbour = last_pixels[0]
|
||||
|
||||
if corner == null or neighbour == null:
|
||||
return
|
||||
|
||||
if pos - corner[0] in corners and pos - neighbour[0] in neighbours:
|
||||
sprite.set_pixel(neighbour[0].x, neighbour[0].y, neighbour[1])
|
||||
last_pixels[0] = corner
|
|
@ -105,6 +105,9 @@ var left_vertical_mirror := false
|
|||
var right_horizontal_mirror := false
|
||||
var right_vertical_mirror := false
|
||||
|
||||
var left_pixel_perfect := true
|
||||
var right_pixel_perfect := true
|
||||
|
||||
# View menu options
|
||||
var tile_mode := false
|
||||
var draw_grid := false
|
||||
|
@ -195,6 +198,9 @@ var left_brush_size_slider : HSlider
|
|||
var right_brush_size_edit : SpinBox
|
||||
var right_brush_size_slider : HSlider
|
||||
|
||||
var left_pixel_perfect_container : VBoxContainer
|
||||
var right_pixel_perfect_container : VBoxContainer
|
||||
|
||||
var left_color_interpolation_container : Container
|
||||
var right_color_interpolation_container : Container
|
||||
var left_interpolate_spinbox : SpinBox
|
||||
|
@ -324,6 +330,9 @@ func _ready() -> void:
|
|||
right_brush_size_edit = find_node_by_name(root, "RightBrushSizeEdit")
|
||||
right_brush_size_slider = find_node_by_name(root, "RightBrushSizeSlider")
|
||||
|
||||
left_pixel_perfect_container = find_node_by_name(root, "LeftBrushPixelPerfectMode")
|
||||
right_pixel_perfect_container = find_node_by_name(root, "RightBrushPixelPerfectMode")
|
||||
|
||||
left_color_interpolation_container = find_node_by_name(root, "LeftColorInterpolation")
|
||||
right_color_interpolation_container = find_node_by_name(root, "RightColorInterpolation")
|
||||
left_interpolate_spinbox = find_node_by_name(root, "LeftInterpolateFactor")
|
||||
|
|
|
@ -495,12 +495,14 @@ func _on_Tool_pressed(tool_pressed : BaseButton, mouse_press := true, key_for_le
|
|||
if current_action == "Pencil":
|
||||
Global.left_brush_type_container.visible = true
|
||||
Global.left_brush_size_slider.visible = true
|
||||
Global.left_pixel_perfect_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 == "Eraser":
|
||||
Global.left_brush_type_container.visible = true
|
||||
Global.left_brush_size_slider.visible = true
|
||||
Global.left_pixel_perfect_container.visible = true
|
||||
Global.left_mirror_container.visible = true
|
||||
elif current_action == "Bucket":
|
||||
Global.left_fill_area_container.visible = true
|
||||
|
@ -508,6 +510,7 @@ func _on_Tool_pressed(tool_pressed : BaseButton, mouse_press := true, key_for_le
|
|||
elif current_action == "LightenDarken":
|
||||
Global.left_brush_type_container.visible = true
|
||||
Global.left_brush_size_slider.visible = true
|
||||
Global.left_pixel_perfect_container.visible = true
|
||||
Global.left_ld_container.visible = true
|
||||
Global.left_mirror_container.visible = true
|
||||
elif current_action == "ColorPicker":
|
||||
|
@ -527,12 +530,14 @@ func _on_Tool_pressed(tool_pressed : BaseButton, mouse_press := true, key_for_le
|
|||
if current_action == "Pencil":
|
||||
Global.right_brush_type_container.visible = true
|
||||
Global.right_brush_size_slider.visible = true
|
||||
Global.right_pixel_perfect_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 == "Eraser":
|
||||
Global.right_brush_type_container.visible = true
|
||||
Global.right_brush_size_slider.visible = true
|
||||
Global.right_pixel_perfect_container.visible = true
|
||||
Global.right_mirror_container.visible = true
|
||||
elif current_action == "Bucket":
|
||||
Global.right_fill_area_container.visible = true
|
||||
|
@ -540,6 +545,7 @@ func _on_Tool_pressed(tool_pressed : BaseButton, mouse_press := true, key_for_le
|
|||
elif current_action == "LightenDarken":
|
||||
Global.right_brush_type_container.visible = true
|
||||
Global.right_brush_size_slider.visible = true
|
||||
Global.right_pixel_perfect_container.visible = true
|
||||
Global.right_ld_container.visible = true
|
||||
Global.right_mirror_container.visible = true
|
||||
elif current_action == "ColorPicker":
|
||||
|
@ -784,3 +790,11 @@ func _on_QuitDialog_confirmed() -> void:
|
|||
modulate = Color(0.5, 0.5, 0.5)
|
||||
|
||||
get_tree().quit()
|
||||
|
||||
|
||||
func _on_LeftPixelPerfectMode_toggled(button_pressed) -> void:
|
||||
Global.left_pixel_perfect = button_pressed
|
||||
|
||||
|
||||
func _on_RightPixelPerfectMode_toggled(button_pressed) -> void:
|
||||
Global.right_pixel_perfect = button_pressed
|
||||
|
|
Loading…
Reference in a new issue