diff --git a/src/Tools/BaseTool.gd b/src/Tools/BaseTool.gd index 3f98ff7c4..1b8384f16 100644 --- a/src/Tools/BaseTool.gd +++ b/src/Tools/BaseTool.gd @@ -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: diff --git a/src/Tools/BaseTool.tscn b/src/Tools/BaseTool.tscn index f275a2ac1..342d9e65d 100644 --- a/src/Tools/BaseTool.tscn +++ b/src/Tools/BaseTool.tscn @@ -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" diff --git a/src/Tools/Draw.gd b/src/Tools/Draw.gd index cb7e0ce2a..4a5acfa64 100644 --- a/src/Tools/Draw.gd +++ b/src/Tools/Draw.gd @@ -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) diff --git a/src/Tools/Pencil.gd b/src/Tools/Pencil.gd index ef070bf6b..a677c5f7c 100644 --- a/src/Tools/Pencil.gd +++ b/src/Tools/Pencil.gd @@ -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: diff --git a/src/Tools/Pencil.tscn b/src/Tools/Pencil.tscn index 3b03957b7..97471507c 100644 --- a/src/Tools/Pencil.tscn +++ b/src/Tools/Pencil.tscn @@ -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"]