1
0
Fork 0
mirror of https://github.com/Orama-Interactive/Pixelorama.git synced 2025-01-31 07:29:49 +00:00

Implement a spacing option for the pencil tool (#813)

* Added Code for cursor snapping

* Added the Snap option

* typo

* Fix snapvector not updating properly

* formatting

* better snapping system

This makes the stroke snapping more accurate by preferring the snap point nearest to the cursor

* changed Snap mode to spacing

* Code Improvements

* more changes

* Update Pencil.gd

* formatting

* fix max line length

---------

Co-authored-by: Emmanouil Papadeas <35376950+OverloadedOrama@users.noreply.github.com>
This commit is contained in:
Variable 2023-02-12 20:46:47 +05:00 committed by GitHub
parent 7307743f83
commit 7f026aa371
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 136 additions and 4 deletions

View file

@ -10,6 +10,12 @@ var _cursor := Vector2.INF
var _draw_cache: PoolVector2Array = [] # for storing already drawn pixels
var _for_frame := 0 # cache for which frame?
# Only use "_spacing_mode" and "_spacing" variables (the others are set automatically)
# The _spacing_mode and _spacing values are to be CHANGED only in the tool scripts (e.g Pencil.gd)
var _spacing_mode := false # Enables spacing (continuos gaps between two strokes)
var _spacing := Vector2.ZERO # Spacing between two strokes
var _stroke_dimensions := Vector2.ONE # 2d vector containing _brush_size from Draw.gd
var _spacing_offset := Vector2.ZERO # The "INITIAL" error between position and position.snapped()
onready var color_rect: ColorRect = $ColorRect
@ -47,10 +53,11 @@ func update_config() -> void:
pass
func draw_start(_position: Vector2) -> void:
func draw_start(position: Vector2) -> void:
_draw_cache = []
is_moving = true
Global.current_project.can_undo = false
_spacing_offset = _get_spacing_offset(position)
func draw_move(position: Vector2) -> void:
@ -68,6 +75,40 @@ func draw_end(_position: Vector2) -> void:
func cursor_move(position: Vector2) -> void:
_cursor = position
if _spacing_mode and is_moving:
_cursor = get_spacing_position(position)
func get_spacing_position(position: Vector2) -> Vector2:
# spacing_factor is the distance the mouse needs to get snapped by in order
# to keep a space "_spacing" between two strokes of dimensions "_stroke_dimensions"
var spacing_factor = _stroke_dimensions + _spacing
var snap_position = position.snapped(spacing_factor) + _spacing_offset
# keeping snap_position as is would have been fine but this adds extra accuracy as to
# which snap point (from the list below) is closest to mouse and occupy THAT point
var t_c = snap_position + Vector2(0, -spacing_factor.y) # t_c is for "top centre" and so on...
var t_r = snap_position + Vector2(spacing_factor.x, -spacing_factor.y)
var t_r_r = snap_position + Vector2(2 * spacing_factor.x, -spacing_factor.y)
var m_c = snap_position
var m_r = snap_position + Vector2(spacing_factor.x, 0)
var m_r_r = snap_position + Vector2(2 * spacing_factor.x, 0)
var b_c = snap_position + Vector2(0, spacing_factor.y)
var b_r = snap_position + Vector2(spacing_factor.x, spacing_factor.y)
var b_r_r = snap_position + Vector2(2 * spacing_factor.x, spacing_factor.y)
var vec_arr := [t_c, t_r, t_r_r, m_c, m_r, m_r_r, b_c, b_r, b_r_r]
for vec in vec_arr:
if vec.distance_to(position) < snap_position.distance_to(position):
snap_position = vec
return snap_position
func _get_spacing_offset(position: Vector2) -> Vector2:
var spacing_factor = _stroke_dimensions + _spacing # spacing_factor is explained above
# since we just started drawing, the "position" is our intended location so the error
# (_spacing_offset) is measured by subtracting both quantities
return position - position.snapped(spacing_factor)
func draw_indicator(left: bool) -> void:

View file

@ -1,6 +1,7 @@
[gd_scene load_steps=2 format=2]
[gd_scene load_steps=3 format=2]
[ext_resource path="res://src/Tools/BaseTool.gd" type="Script" id=1]
[ext_resource path="res://src/UI/Nodes/ValueSlider.tscn" type="PackedScene" id=2]
[node name="ToolOptions" type="VBoxContainer"]
margin_left = 7.0
@ -23,3 +24,34 @@ theme_type_variation = "Header"
text = "Tool Name"
align = 1
autowrap = true
[node name="SpacingMode" type="CheckBox" parent="."]
visible = false
margin_top = 26.0
margin_right = 116.0
margin_bottom = 50.0
text = "Spacing"
[node name="StrokeGap" type="VBoxContainer" parent="."]
visible = false
margin_top = 26.0
margin_right = 116.0
margin_bottom = 78.0
[node name="SpacingX" parent="StrokeGap" instance=ExtResource( 2 )]
margin_right = 116.0
__meta__ = {
"_editor_description_": ""
}
prefix = "Gap X:"
suffix = "px"
[node name="SpacingY" parent="StrokeGap" instance=ExtResource( 2 )]
margin_top = 28.0
margin_right = 116.0
margin_bottom = 52.0
__meta__ = {
"_editor_description_": ""
}
prefix = "Gap Y:"
suffix = "px"

View file

@ -112,10 +112,13 @@ func update_brush() -> void:
match _brush.type:
Brushes.PIXEL:
_brush_texture.create_from_image(load("res://assets/graphics/pixel_image.png"), 0)
_stroke_dimensions = Vector2.ONE * _brush_size
Brushes.CIRCLE:
_brush_texture.create_from_image(load("res://assets/graphics/circle_9x9.png"), 0)
_stroke_dimensions = Vector2.ONE * _brush_size
Brushes.FILLED_CIRCLE:
_brush_texture.create_from_image(load("res://assets/graphics/circle_filled_9x9.png"), 0)
_stroke_dimensions = Vector2.ONE * _brush_size
Brushes.FILE, Brushes.RANDOM_FILE, Brushes.CUSTOM:
$Brush/BrushSize.suffix = "00 %" # Use a different size convention on images
if _brush.random.size() <= 1:
@ -125,6 +128,7 @@ func update_brush() -> void:
_brush_image = _create_blended_brush_image(_brush.random[random])
_brush_texture.create_from_image(_brush_image, 0)
update_mirror_brush()
_stroke_dimensions = _brush_image.get_size()
_indicator = _create_brush_indicator()
_polylines = _create_polylines(_indicator)
$Brush/Type/Texture.texture = _brush_texture
@ -277,7 +281,10 @@ func draw_fill_gap(start: Vector2, end: Vector2) -> void:
err += dx
y += sy
#coords_to_draw.append_array(_draw_tool(Vector2(x, y)))
for coord in _draw_tool(Vector2(x, y)):
var current_pixel_coord = Vector2(x, y)
if _spacing_mode:
current_pixel_coord = get_spacing_position(current_pixel_coord)
for coord in _draw_tool(current_pixel_coord):
coords_to_draw[coord] = 0
for c in coords_to_draw.keys():
_set_pixel_no_cache(c)

View file

@ -6,6 +6,7 @@ var _changed := false
var _overwrite := false
var _fill_inside := false
var _draw_points := Array()
var _old_spacing_mode := false # needed to reset spacing mode in case we change it
class PencilOp:
@ -37,6 +38,23 @@ func _on_FillInside_toggled(button_pressed):
save_config()
func _on_SpacingMode_toggled(button_pressed):
# This acts as an interface to access the intrinsic spacing_mode feature
# BaseTool holds the spacing system but for a tool to access them i recommend we do it in
# their own script
_spacing_mode = button_pressed
update_config()
save_config()
func _on_SpacingX_value_changed(value):
_spacing.x = value
func _on_SpacingY_value_changed(value):
_spacing.y = value
func _input(event: InputEvent) -> void:
var overwrite_button: CheckBox = $Overwrite
@ -54,6 +72,8 @@ func get_config() -> Dictionary:
var config := .get_config()
config["overwrite"] = _overwrite
config["fill_inside"] = _fill_inside
config["spacing_mode"] = _spacing_mode
config["spacing"] = _spacing
return config
@ -61,15 +81,22 @@ func set_config(config: Dictionary) -> void:
.set_config(config)
_overwrite = config.get("overwrite", _overwrite)
_fill_inside = config.get("fill_inside", _fill_inside)
_spacing_mode = config.get("spacing_mode", _spacing_mode)
_spacing = config.get("spacing", _spacing)
func update_config() -> void:
.update_config()
$Overwrite.pressed = _overwrite
$FillInside.pressed = _fill_inside
$SpacingMode.pressed = _spacing_mode
$StrokeGap.visible = _spacing_mode
$StrokeGap/SpacingX.value = _spacing.x
$StrokeGap/SpacingY.value = _spacing.y
func draw_start(position: Vector2) -> void:
_old_spacing_mode = _spacing_mode
position = snap_position(position)
.draw_start(position)
if Input.is_action_pressed("draw_color_picker"):
@ -93,6 +120,7 @@ func draw_start(position: Vector2) -> void:
_draw_line = Input.is_action_pressed("draw_create_line")
if _draw_line:
_spacing_mode = false # spacing mode is disabled during line mode
_line_start = position
_line_end = position
update_line_polylines(_line_start, _line_end)
@ -114,6 +142,7 @@ func draw_move(position: Vector2) -> void:
return
if _draw_line:
_spacing_mode = false # spacing mode is disabled during line mode
var d := _line_angle_constraint(_line_start, position)
_line_end = d.position
cursor_text = d.text
@ -134,6 +163,7 @@ func draw_end(position: Vector2) -> void:
return
if _draw_line:
_spacing_mode = false # spacing mode is disabled during line mode
draw_tool(_line_start)
draw_fill_gap(_line_start, _line_end)
_draw_line = false
@ -148,11 +178,16 @@ func draw_end(position: Vector2) -> void:
for y in image_size.y:
v.y = y
if Geometry.is_point_in_polygon(v, _draw_points):
if _spacing_mode:
# use of get_spacing_position() in Pencil.gd is a rare case
# (you would ONLY need _spacing_mode and _spacing in most cases)
v = get_spacing_position(v)
draw_tool(v)
commit_undo()
cursor_text = ""
update_random_image()
_spacing_mode = _old_spacing_mode
func _draw_brush_image(image: Image, src_rect: Rect2, dst: Vector2) -> void:

View file

@ -9,6 +9,9 @@ script = ExtResource( 3 )
[node name="ColorRect" parent="." index="0"]
margin_right = 128.0
[node name="Label" parent="." index="1"]
margin_right = 128.0
[node name="Brush" parent="." index="2"]
margin_right = 128.0
@ -36,10 +39,24 @@ margin_top = 90.0
margin_right = 128.0
margin_bottom = 114.0
mouse_default_cursor_shape = 2
text = "Fill inside"
text = "Fill Inside"
__meta__ = {
"_editor_description_": ""
}
[node name="SpacingMode" parent="." index="6"]
visible = true
margin_top = 118.0
margin_right = 128.0
margin_bottom = 142.0
[node name="StrokeGap" parent="." index="7"]
margin_top = 146.0
margin_right = 128.0
margin_bottom = 198.0
[connection signal="toggled" from="Overwrite" to="." method="_on_Overwrite_toggled"]
[connection signal="toggled" from="FillInside" to="." method="_on_FillInside_toggled"]
[connection signal="toggled" from="SpacingMode" to="." method="_on_SpacingMode_toggled"]
[connection signal="value_changed" from="StrokeGap/SpacingX" to="." method="_on_SpacingX_value_changed"]
[connection signal="value_changed" from="StrokeGap/SpacingY" to="." method="_on_SpacingY_value_changed"]