1
0
Fork 0
mirror of https://github.com/Orama-Interactive/Pixelorama.git synced 2025-03-13 06:45:17 +00:00
Pixelorama/src/Tools/LineTool.gd
Variable 67a94ccc10
[Targeted for 0.11.0][Bug FIX] Mirror preview fix (#860)
* fix mirror previews

* Fix incorredt selection resizing of selection

in mirror mode

* Fix mirror previews (selection tools)

* typo
2023-05-18 13:55:08 +03:00

239 lines
6.2 KiB
GDScript

extends "res://src/Tools/Draw.gd"
var _original_pos := Vector2.ZERO
var _start := Vector2.ZERO
var _offset := Vector2.ZERO
var _dest := Vector2.ZERO
var _drawing := false
var _displace_origin := false
var _thickness := 1
func _init() -> void:
_drawer.color_op = Drawer.ColorOp.new()
update_indicator()
func update_brush() -> void:
pass
func _on_Thickness_value_changed(value: int) -> void:
_thickness = value
update_indicator()
update_config()
save_config()
func update_indicator() -> void:
var bitmap := BitMap.new()
bitmap.create(Vector2.ONE * _thickness)
bitmap.set_bit_rect(Rect2(Vector2.ZERO, Vector2.ONE * _thickness), true)
_indicator = bitmap
_polylines = _create_polylines(_indicator)
func get_config() -> Dictionary:
var config := .get_config()
config["thickness"] = _thickness
return config
func set_config(config: Dictionary) -> void:
.set_config(config)
_thickness = config.get("thickness", _thickness)
func update_config() -> void:
.update_config()
$ThicknessSlider.value = _thickness
func _get_shape_points(_size: Vector2) -> PoolVector2Array:
return PoolVector2Array()
func _get_shape_points_filled(_size: Vector2) -> PoolVector2Array:
return PoolVector2Array()
func _input(event: InputEvent) -> void:
if _drawing:
if event.is_action_pressed("shape_displace"):
_displace_origin = true
elif event.is_action_released("shape_displace"):
_displace_origin = false
func draw_start(position: Vector2) -> void:
position = snap_position(position)
.draw_start(position)
if Input.is_action_pressed("shape_displace"):
_picking_color = true
_pick_color(position)
return
_picking_color = false
Global.canvas.selection.transform_content_confirm()
update_mask()
if Global.mirror_view:
# mirroring position is ONLY required by "Preview"
position.x = Global.current_project.size.x - position.x - 1
_original_pos = position
_start = position
_offset = position
_dest = position
_drawing = true
func draw_move(position: Vector2) -> void:
position = snap_position(position)
.draw_move(position)
if _picking_color: # Still return even if we released Alt
if Input.is_action_pressed("shape_displace"):
_pick_color(position)
return
if _drawing:
if Global.mirror_view:
# mirroring position is ONLY required by "Preview"
position.x = Global.current_project.size.x - position.x - 1
if _displace_origin:
_original_pos += position - _offset
var d := _line_angle_constraint(_original_pos, position)
_dest = d.position
if Input.is_action_pressed("shape_center"):
_start = _original_pos - (_dest - _original_pos)
else:
_start = _original_pos
cursor_text = d.text
_offset = position
func draw_end(position: Vector2) -> void:
position = snap_position(position)
.draw_end(position)
if _picking_color:
return
if _drawing:
if Global.mirror_view:
# now we revert back the coordinates from their mirror form so that line can be drawn
_original_pos.x = (Global.current_project.size.x - 1) - _original_pos.x
_start.x = (Global.current_project.size.x - 1) - _start.x
_offset.x = (Global.current_project.size.x - 1) - _offset.x
_dest.x = (Global.current_project.size.x - 1) - _dest.x
if _thickness % 2 == 0:
_original_pos.x += 1
_start.x += 1
_offset.x += 1
_dest.x += 1
_draw_shape()
_original_pos = Vector2.ZERO
_start = Vector2.ZERO
_dest = Vector2.ZERO
_drawing = false
_displace_origin = false
cursor_text = ""
func draw_preview() -> void:
if _drawing:
var canvas: CanvasItem = Global.canvas.previews
var indicator := BitMap.new()
var start := _start
if _start.x > _dest.x:
start.x = _dest.x
if _start.y > _dest.y:
start.y = _dest.y
var points := _get_points()
var t_offset := _thickness - 1
var t_offsetv := Vector2(t_offset, t_offset)
indicator.create((_dest - _start).abs() + t_offsetv * 2 + Vector2.ONE)
for point in points:
var p: Vector2 = point - start + t_offsetv
indicator.set_bit(p, 1)
canvas.draw_set_transform(start - t_offsetv, canvas.rotation, canvas.scale)
for line in _create_polylines(indicator):
canvas.draw_polyline(PoolVector2Array(line), Color.black)
canvas.draw_set_transform(canvas.position, canvas.rotation, canvas.scale)
func _draw_shape() -> void:
# var rect := _get_result_rect(origin, dest)
var points := _get_points()
prepare_undo("Draw Shape")
for point in points:
# Reset drawer every time because pixel perfect sometimes breaks the tool
_drawer.reset()
# Draw each point offsetted based on the shape's thickness
draw_tool(point)
commit_undo()
func _get_points() -> PoolVector2Array:
var array := []
var dx := int(abs(_dest.x - _start.x))
var dy := int(-abs(_dest.y - _start.y))
var err := dx + dy
var e2 := err << 1
var sx = 1 if _start.x < _dest.x else -1
var sy = 1 if _start.y < _dest.y else -1
var x = _start.x
var y = _start.y
var start := _start - Vector2.ONE * (_thickness >> 1)
var end := start + Vector2.ONE * _thickness
for yy in range(start.y, end.y):
for xx in range(start.x, end.x):
array.append(Vector2(xx, yy))
while !(x == _dest.x && y == _dest.y):
e2 = err << 1
if e2 >= dy:
err += dy
x += sx
if e2 <= dx:
err += dx
y += sy
var pos := Vector2(x, y)
start = pos - Vector2.ONE * (_thickness >> 1)
end = start + Vector2.ONE * _thickness
for yy in range(start.y, end.y):
for xx in range(start.x, end.x):
array.append(Vector2(xx, yy))
return PoolVector2Array(array)
func _line_angle_constraint(start: Vector2, end: Vector2) -> Dictionary:
var result := {}
var angle := rad2deg(end.angle_to_point(start))
var distance := start.distance_to(end)
if Input.is_action_pressed("shape_perfect"):
angle = stepify(angle, 22.5)
if step_decimals(angle) != 0:
var diff := end - start
var v := Vector2(2, 1) if abs(diff.x) > abs(diff.y) else Vector2(1, 2)
var p := diff.project(diff.sign() * v).abs().round()
var f := p.y if abs(diff.x) > abs(diff.y) else p.x
end = start + diff.sign() * v * f - diff.sign()
angle = rad2deg(atan2(sign(diff.y) * v.y, sign(diff.x) * v.x))
else:
end = start + Vector2.RIGHT.rotated(deg2rad(angle)) * distance
angle *= -1
angle += 360 if angle < 0 else 0
result.text = str(stepify(angle, 0.01)) + "°"
result.position = end.round()
return result