diff --git a/src/Shaders/ColorSelect.gdshader b/src/Shaders/ColorSelect.gdshader index bcb6f8432..0fcbae627 100644 --- a/src/Shaders/ColorSelect.gdshader +++ b/src/Shaders/ColorSelect.gdshader @@ -1,7 +1,7 @@ shader_type canvas_item; render_mode unshaded; -uniform sampler2D selection : hint_default_black; +uniform sampler2D selection : filter_nearest, hint_default_black; uniform vec4 color; uniform float similarity_percent : hint_range(0.0, 100.0); uniform int operation = 0; // 0 = add, 1 = subtract, 2 = intersect diff --git a/src/Tools/SelectionTools/EllipseSelect.gd b/src/Tools/SelectionTools/EllipseSelect.gd index 0df67e9b0..1680c30de 100644 --- a/src/Tools/SelectionTools/EllipseSelect.gd +++ b/src/Tools/SelectionTools/EllipseSelect.gd @@ -92,8 +92,9 @@ func apply_selection(_position: Vector2i) -> void: func set_ellipse(selection_map: SelectionMap, pos: Vector2i) -> void: - var project := Global.current_project var bitmap_size := 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 := DrawingAlgos.get_ellipse_points_filled(Vector2.ZERO, _rect.size) @@ -102,7 +103,7 @@ func set_ellipse(selection_map: SelectionMap, pos: Vector2i) -> void: if fill_p.x < 0 or fill_p.y < 0 or fill_p.x >= bitmap_size.x or fill_p.y >= bitmap_size.y: continue if _intersect: - if project.selection_map.is_pixel_selected(fill_p): + if previous_selection_map.is_pixel_selected(fill_p): selection_map.select_pixel(fill_p, true) else: selection_map.select_pixel(fill_p, !_subtract) diff --git a/src/Tools/SelectionTools/Lasso.gd b/src/Tools/SelectionTools/Lasso.gd index 933f50374..a404865a7 100644 --- a/src/Tools/SelectionTools/Lasso.gd +++ b/src/Tools/SelectionTools/Lasso.gd @@ -76,21 +76,26 @@ 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, _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: @@ -102,14 +107,16 @@ func apply_selection(_position) -> void: _last_position = Vector2.INF -func lasso_selection(selection_map: SelectionMap, points: Array[Vector2i]) -> void: +func lasso_selection( + selection_map: SelectionMap, previous_selection_map: SelectionMap, points: Array[Vector2i] +) -> void: var project := Global.current_project var selection_size := selection_map.get_size() 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 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) @@ -122,7 +129,7 @@ func lasso_selection(selection_map: SelectionMap, points: Array[Vector2i]) -> vo v.y = y if Geometry2D.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) diff --git a/src/Tools/SelectionTools/MagicWand.gd b/src/Tools/SelectionTools/MagicWand.gd index 5b6cf8074..43945deae 100644 --- a/src/Tools/SelectionTools/MagicWand.gd +++ b/src/Tools/SelectionTools/MagicWand.gd @@ -24,18 +24,19 @@ func apply_selection(pos: Vector2i) -> void: var project := Global.current_project if pos.x < 0 or pos.y < 0 or pos.x >= project.size.x or pos.y >= project.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()) - _flood_fill(pos, cel_image, project.selection_map) + _flood_fill(pos, cel_image, project.selection_map, previous_selection_map) # Handle mirroring for mirror_pos in Tools.get_mirrored_positions(pos): - _flood_fill(mirror_pos, cel_image, project.selection_map) + _flood_fill(mirror_pos, cel_image, project.selection_map, previous_selection_map) Global.canvas.selection.big_bounding_rectangle = project.selection_map.get_used_rect() Global.canvas.selection.commit_undo("Select", undo_data) @@ -119,7 +120,9 @@ func _check_flooded_segment( return ret -func _flood_fill(pos: Vector2i, image: Image, selection_map: SelectionMap) -> void: +func _flood_fill( + pos: Vector2i, 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 := Global.current_project @@ -130,7 +133,7 @@ func _flood_fill(pos: Vector2i, image: Image, selection_map: SelectionMap) -> vo _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( @@ -162,18 +165,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(Vector2i(px, p.y), selection_map) + _set_bit(Vector2i(px, p.y), selection_map, previous_selection_map) -func _set_bit(p: Vector2i, selection_map: SelectionMap) -> void: - var project := Global.current_project +func _set_bit(p: Vector2i, 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) diff --git a/src/Tools/SelectionTools/PaintSelect.gd b/src/Tools/SelectionTools/PaintSelect.gd index a2fc98df8..a86661ab8 100644 --- a/src/Tools/SelectionTools/PaintSelect.gd +++ b/src/Tools/SelectionTools/PaintSelect.gd @@ -104,6 +104,8 @@ func apply_selection(pos: Vector2i) -> void: super.apply_selection(pos) 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() @@ -111,15 +113,18 @@ func apply_selection(pos: Vector2i) -> void: 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: @@ -131,14 +136,15 @@ func apply_selection(pos: Vector2i) -> void: _last_position = Vector2.INF -func paint_selection(selection_map: SelectionMap, points: Array[Vector2i]) -> void: - var project := Global.current_project +func paint_selection( + selection_map: SelectionMap, previous_selection_map: SelectionMap, points: Array[Vector2i] +) -> void: var selection_size := selection_map.get_size() 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 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) diff --git a/src/Tools/SelectionTools/PolygonSelect.gd b/src/Tools/SelectionTools/PolygonSelect.gd index 7de01760f..c271f5420 100644 --- a/src/Tools/SelectionTools/PolygonSelect.gd +++ b/src/Tools/SelectionTools/PolygonSelect.gd @@ -115,21 +115,26 @@ func apply_selection(pos: Vector2i) -> void: return 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, _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: @@ -143,14 +148,16 @@ func apply_selection(pos: Vector2i) -> void: Global.canvas.previews.queue_redraw() -func lasso_selection(selection_map: SelectionMap, points: Array[Vector2i]) -> void: +func lasso_selection( + selection_map: SelectionMap, previous_selection_map: SelectionMap, points: Array[Vector2i] +) -> void: var project := Global.current_project var selection_size := selection_map.get_size() 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 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) @@ -163,7 +170,7 @@ func lasso_selection(selection_map: SelectionMap, points: Array[Vector2i]) -> vo v.y = y if Geometry2D.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) diff --git a/src/UI/Canvas/Selection.gd b/src/UI/Canvas/Selection.gd index 0b8bd2682..607373106 100644 --- a/src/UI/Canvas/Selection.gd +++ b/src/UI/Canvas/Selection.gd @@ -421,14 +421,16 @@ func select_rect(rect: Rect2i, operation := 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() + 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 := Vector2i(x, y) - if !Rect2i(Vector2i.ZERO, project.selection_map.get_size()).has_point(pos): + if !Rect2i(Vector2i.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()