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:
parent
7307743f83
commit
7f026aa371
|
@ -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:
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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"]
|
||||
|
|
Loading…
Reference in a new issue