Skip to content

Commit

Permalink
Fix regression where intersecting selections was not working
Browse files Browse the repository at this point in the history
Regression from e14a506
  • Loading branch information
OverloadedOrama committed Apr 13, 2024
1 parent 5f43a3e commit e4afcc2
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 40 deletions.
7 changes: 4 additions & 3 deletions src/Tools/SelectionTools/EllipseSelect.gd
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func draw_preview() -> void:
var canvas: Node2D = Global.canvas.previews
var position := canvas.position
var scale := canvas.scale
var temp_rect = _rect
var temp_rect := _rect
if Global.mirror_view:
position.x = position.x + Global.current_project.size.x
temp_rect.position.x = Global.current_project.size.x - temp_rect.position.x
Expand Down Expand Up @@ -113,8 +113,9 @@ func apply_selection(_position: Vector2) -> void:


func set_ellipse(selection_map: SelectionMap, position: Vector2) -> void:
var project: Project = Global.current_project
var bitmap_size: Vector2 = selection_map.get_size()
var previous_selection_map := SelectionMap.new() # Used for intersect
previous_selection_map.copy_from(selection_map)
if _intersect:
selection_map.clear()
var points := _get_shape_points_filled(_rect.size)
Expand All @@ -123,7 +124,7 @@ func set_ellipse(selection_map: SelectionMap, position: Vector2) -> void:
if pos.x < 0 or pos.y < 0 or pos.x >= bitmap_size.x or pos.y >= bitmap_size.y:
continue
if _intersect:
if project.selection_map.is_pixel_selected(pos):
if previous_selection_map.is_pixel_selected(pos):
selection_map.select_pixel(pos, true)
else:
selection_map.select_pixel(pos, !_subtract)
Expand Down
21 changes: 14 additions & 7 deletions src/Tools/SelectionTools/Lasso.gd
Original file line number Diff line number Diff line change
Expand Up @@ -77,21 +77,26 @@ func apply_selection(_position) -> void:
.apply_selection(_position)
var project: 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, _draw_points)
lasso_selection(project.selection_map, previous_selection_map, _draw_points)

# Handle mirroring
if Tools.horizontal_mirror:
lasso_selection(project.selection_map, mirror_array(_draw_points, true, false))
var mirror_x := mirror_array(_draw_points, true, false)
lasso_selection(project.selection_map, previous_selection_map, mirror_x)
if Tools.vertical_mirror:
lasso_selection(project.selection_map, mirror_array(_draw_points, true, true))
var mirror_xy := mirror_array(_draw_points, true, true)
lasso_selection(project.selection_map, previous_selection_map, mirror_xy)
if Tools.vertical_mirror:
lasso_selection(project.selection_map, mirror_array(_draw_points, false, true))
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:
Expand All @@ -103,14 +108,16 @@ func apply_selection(_position) -> void:
_last_position = Vector2.INF


func lasso_selection(selection_map: SelectionMap, points: PoolVector2Array) -> void:
func lasso_selection(
selection_map: SelectionMap, previous_selection_map: SelectionMap, points: PoolVector2Array
) -> void:
var project: Project = Global.current_project
var size := selection_map.get_size()
for point in points:
if point.x < 0 or point.y < 0 or point.x >= size.x or point.y >= size.y:
continue
if _intersect:
if project.selection_map.is_pixel_selected(point):
if previous_selection_map.is_pixel_selected(point):
selection_map.select_pixel(point, true)
else:
selection_map.select_pixel(point, !_subtract)
Expand All @@ -123,7 +130,7 @@ func lasso_selection(selection_map: SelectionMap, points: PoolVector2Array) -> v
v.y = y
if Geometry.is_point_in_polygon(v, points):
if _intersect:
if project.selection_map.is_pixel_selected(v):
if previous_selection_map.is_pixel_selected(v):
selection_map.select_pixel(v, true)
else:
selection_map.select_pixel(v, !_subtract)
Expand Down
30 changes: 16 additions & 14 deletions src/Tools/SelectionTools/MagicWand.gd
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,31 @@ func apply_selection(position: Vector2) -> void:
var size: Vector2 = project.size
if position.x < 0 or position.y < 0 or position.x >= size.x or position.y >= size.y:
return
var previous_selection_map := SelectionMap.new() # Used for intersect
previous_selection_map.copy_from(project.selection_map)
if !_add and !_subtract and !_intersect:
Global.canvas.selection.clear_selection()

if _intersect:
project.selection_map.clear()

var cel_image := Image.new()
cel_image.copy_from(_get_draw_image())
cel_image.lock()
_flood_fill(position, cel_image, project.selection_map)
_flood_fill(position, cel_image, project.selection_map, previous_selection_map)

# Handle mirroring
if Tools.horizontal_mirror:
var mirror_x := position
mirror_x.x = Global.current_project.x_symmetry_point - position.x
_flood_fill(mirror_x, cel_image, project.selection_map)
_flood_fill(mirror_x, cel_image, project.selection_map, previous_selection_map)
if Tools.vertical_mirror:
var mirror_xy := mirror_x
mirror_xy.y = Global.current_project.y_symmetry_point - position.y
_flood_fill(mirror_xy, cel_image, project.selection_map)
_flood_fill(mirror_xy, cel_image, project.selection_map, previous_selection_map)
if Tools.vertical_mirror:
var mirror_y := position
mirror_y.y = Global.current_project.y_symmetry_point - position.y
_flood_fill(mirror_y, cel_image, project.selection_map)
_flood_fill(mirror_y, cel_image, project.selection_map, previous_selection_map)
cel_image.unlock()
Global.canvas.selection.big_bounding_rectangle = project.selection_map.get_used_rect()
Global.canvas.selection.commit_undo("Select", undo_data)
Expand Down Expand Up @@ -127,18 +128,20 @@ func _check_flooded_segment(
return ret


func _flood_fill(position: Vector2, image: Image, selection_map: SelectionMap) -> void:
func _flood_fill(
pos: Vector2, image: Image, selection_map: SelectionMap, previous_selection_map: SelectionMap
) -> void:
# implements the floodfill routine by Shawn Hargreaves
# from https://www1.udel.edu/CIS/software/dist/allegro-4.2.1/src/flood.c
var project: Project = Global.current_project
var color: Color = image.get_pixelv(position)
var color: Color = image.get_pixelv(pos)
# init flood data structures
_allegro_flood_segments = []
_allegro_image_segments = []
_compute_segments_for_image(position, project, image, color)
_compute_segments_for_image(pos, project, image, color)
# now actually color the image: since we have already checked a few things for the points
# we'll process here, we're going to skip a bunch of safety checks to speed things up.
_select_segments(selection_map)
_select_segments(selection_map, previous_selection_map)


func _compute_segments_for_image(
Expand Down Expand Up @@ -170,18 +173,17 @@ func _compute_segments_for_image(
done = false


func _select_segments(selection_map: SelectionMap) -> void:
func _select_segments(selection_map: SelectionMap, previous_selection_map: SelectionMap) -> void:
# short circuit for flat colors
for c in _allegro_image_segments.size():
var p = _allegro_image_segments[c]
for px in range(p.left_position, p.right_position + 1):
# We don't have to check again whether the point being processed is within the bounds
_set_bit(Vector2(px, p.y), selection_map)
_set_bit(Vector2(px, p.y), selection_map, previous_selection_map)


func _set_bit(p: Vector2, selection_map: SelectionMap) -> void:
var project: Project = Global.current_project
func _set_bit(p: Vector2, selection_map: SelectionMap, prev_selection_map: SelectionMap) -> void:
if _intersect:
selection_map.select_pixel(p, project.selection_map.is_pixel_selected(p))
selection_map.select_pixel(p, prev_selection_map.is_pixel_selected(p))
else:
selection_map.select_pixel(p, !_subtract)
20 changes: 13 additions & 7 deletions src/Tools/SelectionTools/PaintSelect.gd
Original file line number Diff line number Diff line change
Expand Up @@ -105,22 +105,27 @@ func apply_selection(_position) -> void:
.apply_selection(_position)
var project: 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()
# This is paint selection so we've done >= 1 nstead of > 1
if _draw_points.size() >= 1:
if _intersect:
project.selection_map.clear()
paint_selection(project.selection_map, _draw_points)
paint_selection(project.selection_map, previous_selection_map, _draw_points)

# Handle mirroring
if Tools.horizontal_mirror:
paint_selection(project.selection_map, mirror_array(_draw_points, true, false))
var mirror_x := mirror_array(_draw_points, true, false)
paint_selection(project.selection_map, previous_selection_map, mirror_x)
if Tools.vertical_mirror:
paint_selection(project.selection_map, mirror_array(_draw_points, true, true))
var mirror_xy := mirror_array(_draw_points, true, true)
paint_selection(project.selection_map, previous_selection_map, mirror_xy)
if Tools.vertical_mirror:
paint_selection(project.selection_map, mirror_array(_draw_points, false, true))
var mirror_y := mirror_array(_draw_points, false, true)
paint_selection(project.selection_map, previous_selection_map, mirror_y)

Global.canvas.selection.big_bounding_rectangle = project.selection_map.get_used_rect()
else:
Expand All @@ -132,14 +137,15 @@ func apply_selection(_position) -> void:
_last_position = Vector2.INF


func paint_selection(selection_map: SelectionMap, points: PoolVector2Array) -> void:
var project: Project = Global.current_project
func paint_selection(
selection_map: SelectionMap, previous_selection_map: SelectionMap, points: PoolVector2Array
) -> void:
var size := selection_map.get_size()
for point in points:
if point.x < 0 or point.y < 0 or point.x >= size.x or point.y >= size.y:
continue
if _intersect:
if project.selection_map.is_pixel_selected(point):
if previous_selection_map.is_pixel_selected(point):
selection_map.select_pixel(point, true)
else:
selection_map.select_pixel(point, !_subtract)
Expand Down
21 changes: 14 additions & 7 deletions src/Tools/SelectionTools/PolygonSelect.gd
Original file line number Diff line number Diff line change
Expand Up @@ -115,21 +115,26 @@ func apply_selection(_position) -> void:
return
var project: 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, _draw_points)
lasso_selection(project.selection_map, previous_selection_map, _draw_points)

# Handle mirroring
if Tools.horizontal_mirror:
lasso_selection(project.selection_map, mirror_array(_draw_points, true, false))
var mirror_x := mirror_array(_draw_points, true, false)
lasso_selection(project.selection_map, previous_selection_map, mirror_x)
if Tools.vertical_mirror:
lasso_selection(project.selection_map, mirror_array(_draw_points, true, true))
var mirror_xy := mirror_array(_draw_points, true, true)
lasso_selection(project.selection_map, previous_selection_map, mirror_xy)
if Tools.vertical_mirror:
lasso_selection(project.selection_map, mirror_array(_draw_points, false, true))
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:
Expand All @@ -143,14 +148,16 @@ func apply_selection(_position) -> void:
Global.canvas.previews.update()


func lasso_selection(selection_map: SelectionMap, points: PoolVector2Array) -> void:
func lasso_selection(
selection_map: SelectionMap, previous_selection_map: SelectionMap, points: PoolVector2Array
) -> void:
var project: Project = Global.current_project
var size := selection_map.get_size()
for point in points:
if point.x < 0 or point.y < 0 or point.x >= size.x or point.y >= size.y:
continue
if _intersect:
if project.selection_map.is_pixel_selected(point):
if previous_selection_map.is_pixel_selected(point):
selection_map.select_pixel(point, true)
else:
selection_map.select_pixel(point, !_subtract)
Expand All @@ -163,7 +170,7 @@ func lasso_selection(selection_map: SelectionMap, points: PoolVector2Array) -> v
v.y = y
if Geometry.is_point_in_polygon(v, points):
if _intersect:
if project.selection_map.is_pixel_selected(v):
if previous_selection_map.is_pixel_selected(v):
selection_map.select_pixel(v, true)
else:
selection_map.select_pixel(v, !_subtract)
Expand Down
6 changes: 4 additions & 2 deletions src/UI/Canvas/Selection.gd
Original file line number Diff line number Diff line change
Expand Up @@ -451,14 +451,16 @@ func select_rect(rect: Rect2, operation: int = SelectionOperation.ADD) -> void:
elif operation == SelectionOperation.SUBTRACT:
project.selection_map.fill_rect(rect, Color(0))
elif operation == SelectionOperation.INTERSECT:
var previous_selection_map := SelectionMap.new() # Used for intersect
previous_selection_map.copy_from(project.selection_map)
project.selection_map.clear()
for x in range(rect.position.x, rect.end.x):
for y in range(rect.position.y, rect.end.y):
var pos := Vector2(x, y)
if !Rect2(Vector2.ZERO, project.selection_map.get_size()).has_point(pos):
if !Rect2(Vector2.ZERO, previous_selection_map.get_size()).has_point(pos):
continue
project.selection_map.select_pixel(
pos, project.selection_map.is_pixel_selected(pos)
pos, previous_selection_map.is_pixel_selected(pos)
)
big_bounding_rectangle = project.selection_map.get_used_rect()

Expand Down

0 comments on commit e4afcc2

Please sign in to comment.