mirror of
https://github.com/Orama-Interactive/Pixelorama.git
synced 2025-02-21 13:03:13 +00:00
The time they take to complete now depends on the size of the selection, rather than checking all of the pixels of the entire canvas.
158 lines
5.1 KiB
GDScript
158 lines
5.1 KiB
GDScript
extends BaseSelectionTool
|
|
|
|
var _last_position := Vector2.INF
|
|
var _draw_points: Array[Vector2i] = []
|
|
|
|
|
|
func draw_start(pos: Vector2i) -> void:
|
|
pos = snap_position(pos)
|
|
super.draw_start(pos)
|
|
if !_move:
|
|
_draw_points.append(pos)
|
|
_last_position = pos
|
|
|
|
|
|
func draw_move(pos_i: Vector2i) -> void:
|
|
if selection_node.arrow_key_move:
|
|
return
|
|
var pos := _get_stabilized_position(pos_i)
|
|
pos = snap_position(pos)
|
|
super.draw_move(pos)
|
|
if !_move:
|
|
append_gap(_last_position, pos)
|
|
_last_position = pos
|
|
_draw_points.append(Vector2i(pos))
|
|
_offset = pos
|
|
|
|
|
|
func draw_end(pos: Vector2i) -> void:
|
|
if selection_node.arrow_key_move:
|
|
return
|
|
pos = snap_position(pos)
|
|
super.draw_end(pos)
|
|
|
|
|
|
func draw_preview() -> void:
|
|
var canvas := Global.canvas.previews_sprite
|
|
if _last_position != Vector2.INF and !_move:
|
|
var image := Image.create(
|
|
Global.current_project.size.x, Global.current_project.size.y, false, Image.FORMAT_LA8
|
|
)
|
|
for point in _draw_points:
|
|
var draw_point := point
|
|
if Global.mirror_view: # This fixes previewing in mirror mode
|
|
draw_point.x = image.get_width() - draw_point.x - 1
|
|
if Rect2i(Vector2i.ZERO, image.get_size()).has_point(draw_point):
|
|
image.set_pixelv(draw_point, Color.WHITE)
|
|
|
|
# Handle mirroring
|
|
if Tools.horizontal_mirror:
|
|
for point in mirror_array(_draw_points, true, false):
|
|
var draw_point := point
|
|
if Global.mirror_view: # This fixes previewing in mirror mode
|
|
draw_point.x = image.get_width() - draw_point.x - 1
|
|
if Rect2i(Vector2i.ZERO, image.get_size()).has_point(draw_point):
|
|
image.set_pixelv(draw_point, Color.WHITE)
|
|
if Tools.vertical_mirror:
|
|
for point in mirror_array(_draw_points, true, true):
|
|
var draw_point := point
|
|
if Global.mirror_view: # This fixes previewing in mirror mode
|
|
draw_point.x = image.get_width() - draw_point.x - 1
|
|
if Rect2i(Vector2i.ZERO, image.get_size()).has_point(draw_point):
|
|
image.set_pixelv(draw_point, Color.WHITE)
|
|
if Tools.vertical_mirror:
|
|
for point in mirror_array(_draw_points, false, true):
|
|
var draw_point := point
|
|
if Global.mirror_view: # This fixes previewing in mirror mode
|
|
draw_point.x = image.get_width() - draw_point.x - 1
|
|
if Rect2i(Vector2i.ZERO, image.get_size()).has_point(draw_point):
|
|
image.set_pixelv(draw_point, Color.WHITE)
|
|
var texture := ImageTexture.create_from_image(image)
|
|
canvas.texture = texture
|
|
else:
|
|
canvas.texture = null
|
|
|
|
|
|
func apply_selection(_position) -> void:
|
|
super.apply_selection(_position)
|
|
var project := Global.current_project
|
|
var cleared := false
|
|
var previous_selection_map := SelectionMap.new() # Used for intersect
|
|
previous_selection_map.copy_from(project.selection_map)
|
|
if !_add and !_subtract and !_intersect:
|
|
cleared = true
|
|
Global.canvas.selection.clear_selection()
|
|
if _draw_points.size() > 3:
|
|
if _intersect:
|
|
project.selection_map.clear()
|
|
lasso_selection(project.selection_map, previous_selection_map, _draw_points)
|
|
|
|
# Handle mirroring
|
|
if Tools.horizontal_mirror:
|
|
var mirror_x := mirror_array(_draw_points, true, false)
|
|
lasso_selection(project.selection_map, previous_selection_map, mirror_x)
|
|
if Tools.vertical_mirror:
|
|
var mirror_xy := mirror_array(_draw_points, true, true)
|
|
lasso_selection(project.selection_map, previous_selection_map, mirror_xy)
|
|
if Tools.vertical_mirror:
|
|
var mirror_y := mirror_array(_draw_points, false, true)
|
|
lasso_selection(project.selection_map, previous_selection_map, mirror_y)
|
|
|
|
Global.canvas.selection.big_bounding_rectangle = project.selection_map.get_used_rect()
|
|
else:
|
|
if !cleared:
|
|
Global.canvas.selection.clear_selection()
|
|
|
|
Global.canvas.selection.commit_undo("Select", undo_data)
|
|
_draw_points.clear()
|
|
_last_position = Vector2.INF
|
|
|
|
|
|
func lasso_selection(
|
|
selection_map: SelectionMap, previous_selection_map: SelectionMap, points: Array[Vector2i]
|
|
) -> void:
|
|
var selection_size := selection_map.get_size()
|
|
var bounding_rect := Rect2i(points[0], Vector2i.ZERO)
|
|
for point in points:
|
|
if point.x < 0 or point.y < 0 or point.x >= selection_size.x or point.y >= selection_size.y:
|
|
continue
|
|
bounding_rect = bounding_rect.expand(point)
|
|
if _intersect:
|
|
if previous_selection_map.is_pixel_selected(point):
|
|
selection_map.select_pixel(point, true)
|
|
else:
|
|
selection_map.select_pixel(point, !_subtract)
|
|
|
|
var v := Vector2i()
|
|
for x in bounding_rect.size.x:
|
|
v.x = x + bounding_rect.position.x
|
|
for y in bounding_rect.size.y:
|
|
v.y = y + bounding_rect.position.y
|
|
if Geometry2D.is_point_in_polygon(v, points):
|
|
if _intersect:
|
|
if previous_selection_map.is_pixel_selected(v):
|
|
selection_map.select_pixel(v, true)
|
|
else:
|
|
selection_map.select_pixel(v, !_subtract)
|
|
|
|
|
|
# Bresenham's Algorithm
|
|
# Thanks to https://godotengine.org/qa/35276/tile-based-line-drawing-algorithm-efficiency
|
|
func append_gap(start: Vector2i, end: Vector2i) -> void:
|
|
var dx := absi(end.x - start.x)
|
|
var dy := -absi(end.y - start.y)
|
|
var err := dx + dy
|
|
var e2 := err << 1
|
|
var sx := 1 if start.x < end.x else -1
|
|
var sy := 1 if start.y < end.y else -1
|
|
var x := start.x
|
|
var y := start.y
|
|
while !(x == end.x && y == end.y):
|
|
e2 = err << 1
|
|
if e2 >= dy:
|
|
err += dy
|
|
x += sx
|
|
if e2 <= dx:
|
|
err += dx
|
|
y += sy
|
|
_draw_points.append(Vector2i(x, y))
|