From e14a506d2c17aa803e5c15ea48585cfc0d669acf Mon Sep 17 00:00:00 2001 From: Emmanouil Papadeas Date: Fri, 17 Nov 2023 19:41:09 +0200 Subject: [PATCH] [Undo/Redo] Compress SelectionMaps stored in memory, get rid of a lot of selection_map_copy instances --- src/Autoload/DrawingAlgos.gd | 8 +- src/Tools/SelectionTools/ColorSelect.gd | 4 +- src/Tools/SelectionTools/EllipseSelect.gd | 11 +-- src/Tools/SelectionTools/Lasso.gd | 13 ++- src/Tools/SelectionTools/MagicWand.gd | 13 ++- src/Tools/SelectionTools/PaintSelect.gd | 13 ++- src/Tools/SelectionTools/PolygonSelect.gd | 13 ++- src/Tools/SelectionTools/SelectionTool.gd | 13 +-- src/UI/Canvas/Selection.gd | 80 ++++++------------- .../Dialogs/ImageEffects/FlipImageDialog.gd | 18 ++--- 10 files changed, 59 insertions(+), 127 deletions(-) diff --git a/src/Autoload/DrawingAlgos.gd b/src/Autoload/DrawingAlgos.gd index 96faace65..65bded586 100644 --- a/src/Autoload/DrawingAlgos.gd +++ b/src/Autoload/DrawingAlgos.gd @@ -550,10 +550,6 @@ func general_do_scale(width: int, height: int) -> void: var x_ratio = project.size.x / width var y_ratio = project.size.y / height - var selection_map_copy := SelectionMap.new() - selection_map_copy.copy_from(project.selection_map) - selection_map_copy.crop(size.x, size.y) - var new_x_symmetry_point = project.x_symmetry_point / x_ratio var new_y_symmetry_point = project.y_symmetry_point / y_ratio var new_x_symmetry_axis_points = project.x_symmetry_axis.points @@ -566,7 +562,7 @@ func general_do_scale(width: int, height: int) -> void: project.undos += 1 project.undo_redo.create_action("Scale") project.undo_redo.add_do_property(project, "size", size) - project.undo_redo.add_do_property(project, "selection_map", selection_map_copy) + project.undo_redo.add_do_method(project.selection_map, "crop", size.x, size.y) project.undo_redo.add_do_property(project, "x_symmetry_point", new_x_symmetry_point) project.undo_redo.add_do_property(project, "y_symmetry_point", new_y_symmetry_point) project.undo_redo.add_do_property(project.x_symmetry_axis, "points", new_x_symmetry_axis_points) @@ -576,7 +572,7 @@ func general_do_scale(width: int, height: int) -> void: func general_undo_scale() -> void: var project: Project = Global.current_project project.undo_redo.add_undo_property(project, "size", project.size) - project.undo_redo.add_undo_property(project, "selection_map", project.selection_map) + project.undo_redo.add_undo_method(project.selection_map, "crop", project.size.x, project.size.y) project.undo_redo.add_undo_property(project, "x_symmetry_point", project.x_symmetry_point) project.undo_redo.add_undo_property(project, "y_symmetry_point", project.y_symmetry_point) project.undo_redo.add_undo_property( diff --git a/src/Tools/SelectionTools/ColorSelect.gd b/src/Tools/SelectionTools/ColorSelect.gd index d829c867a..7534d7117 100644 --- a/src/Tools/SelectionTools/ColorSelect.gd +++ b/src/Tools/SelectionTools/ColorSelect.gd @@ -52,8 +52,6 @@ func apply_selection(position: Vector2) -> void: gen.generate_image(cel_image, shader, params, project.size) cel_image.convert(Image.FORMAT_LA8) - var selection_map_copy := SelectionMap.new() - selection_map_copy.copy_from(cel_image) - project.selection_map = selection_map_copy + project.selection_map.copy_from(cel_image) Global.canvas.selection.big_bounding_rectangle = project.selection_map.get_used_rect() Global.canvas.selection.commit_undo("Select", undo_data) diff --git a/src/Tools/SelectionTools/EllipseSelect.gd b/src/Tools/SelectionTools/EllipseSelect.gd index 8ca87de46..2895febc7 100644 --- a/src/Tools/SelectionTools/EllipseSelect.gd +++ b/src/Tools/SelectionTools/EllipseSelect.gd @@ -77,9 +77,7 @@ func apply_selection(_position: Vector2) -> void: Global.canvas.selection.commit_undo("Select", undo_data) if _rect.size != Vector2.ZERO: - var selection_map_copy := SelectionMap.new() - selection_map_copy.copy_from(project.selection_map) - set_ellipse(selection_map_copy, _rect.position) + set_ellipse(project.selection_map, _rect.position) # Handle mirroring if Tools.horizontal_mirror: @@ -90,7 +88,7 @@ func apply_selection(_position: Vector2) -> void: + 1 ) mirror_x_rect.end.x = Global.current_project.x_symmetry_point - _rect.end.x + 1 - set_ellipse(selection_map_copy, mirror_x_rect.abs().position) + set_ellipse(project.selection_map, mirror_x_rect.abs().position) if Tools.vertical_mirror: var mirror_xy_rect := mirror_x_rect mirror_xy_rect.position.y = ( @@ -99,7 +97,7 @@ func apply_selection(_position: Vector2) -> void: + 1 ) mirror_xy_rect.end.y = Global.current_project.y_symmetry_point - _rect.end.y + 1 - set_ellipse(selection_map_copy, mirror_xy_rect.abs().position) + set_ellipse(project.selection_map, mirror_xy_rect.abs().position) if Tools.vertical_mirror: var mirror_y_rect := _rect mirror_y_rect.position.y = ( @@ -108,9 +106,8 @@ func apply_selection(_position: Vector2) -> void: + 1 ) mirror_y_rect.end.y = Global.current_project.y_symmetry_point - _rect.end.y + 1 - set_ellipse(selection_map_copy, mirror_y_rect.abs().position) + set_ellipse(project.selection_map, mirror_y_rect.abs().position) - project.selection_map = selection_map_copy Global.canvas.selection.big_bounding_rectangle = project.selection_map.get_used_rect() Global.canvas.selection.commit_undo("Select", undo_data) diff --git a/src/Tools/SelectionTools/Lasso.gd b/src/Tools/SelectionTools/Lasso.gd index e4146dc02..38908ae49 100644 --- a/src/Tools/SelectionTools/Lasso.gd +++ b/src/Tools/SelectionTools/Lasso.gd @@ -81,21 +81,18 @@ func apply_selection(_position) -> void: cleared = true Global.canvas.selection.clear_selection() if _draw_points.size() > 3: - var selection_map_copy := SelectionMap.new() - selection_map_copy.copy_from(project.selection_map) if _intersect: - selection_map_copy.clear() - lasso_selection(selection_map_copy, _draw_points) + project.selection_map.clear() + lasso_selection(project.selection_map, _draw_points) # Handle mirroring if Tools.horizontal_mirror: - lasso_selection(selection_map_copy, mirror_array(_draw_points, true, false)) + lasso_selection(project.selection_map, mirror_array(_draw_points, true, false)) if Tools.vertical_mirror: - lasso_selection(selection_map_copy, mirror_array(_draw_points, true, true)) + lasso_selection(project.selection_map, mirror_array(_draw_points, true, true)) if Tools.vertical_mirror: - lasso_selection(selection_map_copy, mirror_array(_draw_points, false, true)) + lasso_selection(project.selection_map, mirror_array(_draw_points, false, true)) - project.selection_map = selection_map_copy Global.canvas.selection.big_bounding_rectangle = project.selection_map.get_used_rect() else: if !cleared: diff --git a/src/Tools/SelectionTools/MagicWand.gd b/src/Tools/SelectionTools/MagicWand.gd index 2bfc9abae..4f8e0ebc1 100644 --- a/src/Tools/SelectionTools/MagicWand.gd +++ b/src/Tools/SelectionTools/MagicWand.gd @@ -15,31 +15,28 @@ func apply_selection(position: Vector2) -> void: if !_add and !_subtract and !_intersect: Global.canvas.selection.clear_selection() - var selection_map_copy := SelectionMap.new() - selection_map_copy.copy_from(project.selection_map) if _intersect: - selection_map_copy.clear() + project.selection_map.clear() var cel_image := Image.new() cel_image.copy_from(_get_draw_image()) cel_image.lock() - _flood_fill(position, cel_image, selection_map_copy) + _flood_fill(position, cel_image, project.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, selection_map_copy) + _flood_fill(mirror_x, cel_image, project.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, selection_map_copy) + _flood_fill(mirror_xy, cel_image, project.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, selection_map_copy) + _flood_fill(mirror_y, cel_image, project.selection_map) cel_image.unlock() - project.selection_map = selection_map_copy Global.canvas.selection.big_bounding_rectangle = project.selection_map.get_used_rect() Global.canvas.selection.commit_undo("Select", undo_data) diff --git a/src/Tools/SelectionTools/PaintSelect.gd b/src/Tools/SelectionTools/PaintSelect.gd index 52bb70a65..a889169c6 100644 --- a/src/Tools/SelectionTools/PaintSelect.gd +++ b/src/Tools/SelectionTools/PaintSelect.gd @@ -110,21 +110,18 @@ func apply_selection(_position) -> void: Global.canvas.selection.clear_selection() # This is paint selection so we've done >= 1 nstead of > 1 if _draw_points.size() >= 1: - var selection_map_copy := SelectionMap.new() - selection_map_copy.copy_from(project.selection_map) if _intersect: - selection_map_copy.clear() - paint_selection(selection_map_copy, _draw_points) + project.selection_map.clear() + paint_selection(project.selection_map, _draw_points) # Handle mirroring if Tools.horizontal_mirror: - paint_selection(selection_map_copy, mirror_array(_draw_points, true, false)) + paint_selection(project.selection_map, mirror_array(_draw_points, true, false)) if Tools.vertical_mirror: - paint_selection(selection_map_copy, mirror_array(_draw_points, true, true)) + paint_selection(project.selection_map, mirror_array(_draw_points, true, true)) if Tools.vertical_mirror: - paint_selection(selection_map_copy, mirror_array(_draw_points, false, true)) + paint_selection(project.selection_map, mirror_array(_draw_points, false, true)) - project.selection_map = selection_map_copy Global.canvas.selection.big_bounding_rectangle = project.selection_map.get_used_rect() else: if !cleared: diff --git a/src/Tools/SelectionTools/PolygonSelect.gd b/src/Tools/SelectionTools/PolygonSelect.gd index 9603ba9a8..ac1db8123 100644 --- a/src/Tools/SelectionTools/PolygonSelect.gd +++ b/src/Tools/SelectionTools/PolygonSelect.gd @@ -119,21 +119,18 @@ func apply_selection(_position) -> void: cleared = true Global.canvas.selection.clear_selection() if _draw_points.size() > 3: - var selection_map_copy := SelectionMap.new() - selection_map_copy.copy_from(project.selection_map) if _intersect: - selection_map_copy.clear() - lasso_selection(selection_map_copy, _draw_points) + project.selection_map.clear() + lasso_selection(project.selection_map, _draw_points) # Handle mirroring if Tools.horizontal_mirror: - lasso_selection(selection_map_copy, mirror_array(_draw_points, true, false)) + lasso_selection(project.selection_map, mirror_array(_draw_points, true, false)) if Tools.vertical_mirror: - lasso_selection(selection_map_copy, mirror_array(_draw_points, true, true)) + lasso_selection(project.selection_map, mirror_array(_draw_points, true, true)) if Tools.vertical_mirror: - lasso_selection(selection_map_copy, mirror_array(_draw_points, false, true)) + lasso_selection(project.selection_map, mirror_array(_draw_points, false, true)) - project.selection_map = selection_map_copy Global.canvas.selection.big_bounding_rectangle = project.selection_map.get_used_rect() else: if !cleared: diff --git a/src/Tools/SelectionTools/SelectionTool.gd b/src/Tools/SelectionTools/SelectionTool.gd index d3f125592..9f4d25612 100644 --- a/src/Tools/SelectionTools/SelectionTool.gd +++ b/src/Tools/SelectionTools/SelectionTool.gd @@ -113,12 +113,7 @@ func draw_start(position: Vector2) -> void: Rect2(Vector2.ZERO, project.selection_map.get_size()), selection_node.big_bounding_rectangle.position ) - - var selection_map_copy := SelectionMap.new() - selection_map_copy.copy_from(project.selection_map) - selection_map_copy.move_bitmap_values(project) - - project.selection_map = selection_map_copy + project.selection_map.move_bitmap_values(project) selection_node.commit_undo("Move Selection", selection_node.undo_data) selection_node.undo_data = selection_node.get_undo_data(true) else: @@ -239,11 +234,7 @@ func _on_Position_value_changed(value: Vector2) -> void: undo_data = selection_node.get_undo_data(false) timer.start() selection_node.big_bounding_rectangle.position = value - - var selection_map_copy := SelectionMap.new() - selection_map_copy.copy_from(project.selection_map) - selection_map_copy.move_bitmap_values(project) - project.selection_map = selection_map_copy + project.selection_map.move_bitmap_values(project) project.selection_map_changed() diff --git a/src/UI/Canvas/Selection.gd b/src/UI/Canvas/Selection.gd index 3c670998b..929dbe399 100644 --- a/src/UI/Canvas/Selection.gd +++ b/src/UI/Canvas/Selection.gd @@ -377,9 +377,8 @@ func _resize_rect(pos: Vector2, dir: Vector2) -> void: func resize_selection() -> void: var size := big_bounding_rectangle.size.abs() - var selection_map: SelectionMap = Global.current_project.selection_map if is_moving_content: - selection_map = original_bitmap + Global.current_project.selection_map.copy_from(original_bitmap) preview_image.copy_from(original_preview_image) preview_image.resize(size.x, size.y, Image.INTERPOLATE_NEAREST) if temp_rect.size.x < 0: @@ -388,12 +387,9 @@ func resize_selection() -> void: preview_image.flip_y() preview_image_texture.create_from_image(preview_image, 0) - var selection_map_copy := SelectionMap.new() - selection_map_copy.copy_from(selection_map) - selection_map_copy.resize_bitmap_values( + Global.current_project.selection_map.resize_bitmap_values( Global.current_project, size, temp_rect.size.x < 0, temp_rect.size.y < 0 ) - Global.current_project.selection_map = selection_map_copy Global.current_project.selection_map_changed() update() Global.canvas.update() @@ -436,8 +432,6 @@ func _gizmo_rotate() -> void: # Does not work properly yet func select_rect(rect: Rect2, operation: int = SelectionOperation.ADD) -> void: var project: Project = Global.current_project - var selection_map_copy := SelectionMap.new() - selection_map_copy.copy_from(project.selection_map) # Used only if the selection is outside of the canvas boundaries, # on the left and/or above (negative coords) var offset_position := Vector2.ZERO @@ -450,27 +444,28 @@ func select_rect(rect: Rect2, operation: int = SelectionOperation.ADD) -> void: if offset_position != Vector2.ZERO: big_bounding_rectangle.position -= offset_position - selection_map_copy.move_bitmap_values(project) + project.selection_map.move_bitmap_values(project) if operation == SelectionOperation.ADD: - selection_map_copy.fill_rect(rect, Color(1, 1, 1, 1)) + project.selection_map.fill_rect(rect, Color(1, 1, 1, 1)) elif operation == SelectionOperation.SUBTRACT: - selection_map_copy.fill_rect(rect, Color(0)) + project.selection_map.fill_rect(rect, Color(0)) elif operation == SelectionOperation.INTERSECT: - selection_map_copy.clear() + 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, selection_map_copy.get_size()).has_point(pos): + if !Rect2(Vector2.ZERO, project.selection_map.get_size()).has_point(pos): continue - selection_map_copy.select_pixel(pos, project.selection_map.is_pixel_selected(pos)) - big_bounding_rectangle = selection_map_copy.get_used_rect() + project.selection_map.select_pixel( + pos, project.selection_map.is_pixel_selected(pos) + ) + big_bounding_rectangle = project.selection_map.get_used_rect() if offset_position != Vector2.ZERO: big_bounding_rectangle.position += offset_position - selection_map_copy.move_bitmap_values(project) + project.selection_map.move_bitmap_values(project) - project.selection_map = selection_map_copy self.big_bounding_rectangle = big_bounding_rectangle # call getter method @@ -488,10 +483,7 @@ func move_borders(move: Vector2) -> void: func move_borders_end() -> void: - var selection_map_copy := SelectionMap.new() - selection_map_copy.copy_from(Global.current_project.selection_map) - selection_map_copy.move_bitmap_values(Global.current_project) - Global.current_project.selection_map = selection_map_copy + Global.current_project.selection_map.move_bitmap_values(Global.current_project) if not is_moving_content: commit_undo("Select", undo_data) else: @@ -547,10 +539,7 @@ func transform_content_confirm() -> void: Rect2(Vector2.ZERO, project.selection_map.get_size()), big_bounding_rectangle.position ) - var selection_map_copy := SelectionMap.new() - selection_map_copy.copy_from(project.selection_map) - selection_map_copy.move_bitmap_values(project) - project.selection_map = selection_map_copy + project.selection_map.move_bitmap_values(project) commit_undo("Move Selection", undo_data) original_preview_image = Image.new() @@ -570,7 +559,7 @@ func transform_content_cancel() -> void: is_moving_content = false self.big_bounding_rectangle = original_big_bounding_rectangle - project.selection_map = original_bitmap + project.selection_map.copy_from(original_bitmap) project.selection_map_changed() preview_image = original_preview_image for cel in _get_selected_draw_cels(): @@ -602,13 +591,12 @@ func commit_undo(action: String, undo_data_tmp: Dictionary) -> void: project.undos += 1 project.undo_redo.create_action(action) - project.undo_redo.add_do_property(project, "selection_map", redo_data["selection_map"]) + Global.undo_redo_compress_images(redo_data, undo_data_tmp, project) project.undo_redo.add_do_property( self, "big_bounding_rectangle", redo_data["big_bounding_rectangle"] ) project.undo_redo.add_do_property(project, "selection_offset", redo_data["outline_offset"]) - project.undo_redo.add_undo_property(project, "selection_map", undo_data_tmp["selection_map"]) project.undo_redo.add_undo_property( self, "big_bounding_rectangle", undo_data_tmp["big_bounding_rectangle"] ) @@ -616,16 +604,6 @@ func commit_undo(action: String, undo_data_tmp: Dictionary) -> void: project, "selection_offset", undo_data_tmp["outline_offset"] ) - if undo_data_tmp["undo_image"]: - for image in redo_data: - if not image is Image: - continue - project.undo_redo.add_do_property(image, "data", redo_data[image]) - image.unlock() - for image in undo_data_tmp: - if not image is Image: - continue - project.undo_redo.add_undo_property(image, "data", undo_data_tmp[image]) project.undo_redo.add_do_method(Global, "undo_or_redo", false) project.undo_redo.add_do_method(project, "selection_map_changed") project.undo_redo.add_undo_method(Global, "undo_or_redo", true) @@ -638,7 +616,7 @@ func commit_undo(action: String, undo_data_tmp: Dictionary) -> void: func get_undo_data(undo_image: bool) -> Dictionary: var data := {} var project: Project = Global.current_project - data["selection_map"] = project.selection_map + data[project.selection_map] = project.selection_map.data data["big_bounding_rectangle"] = big_bounding_rectangle data["outline_offset"] = Global.current_project.selection_offset data["undo_image"] = undo_image @@ -702,10 +680,8 @@ func copy() -> void: else: if is_moving_content: to_copy.copy_from(preview_image) - var selection_map_copy := SelectionMap.new() - selection_map_copy.copy_from(project.selection_map) - selection_map_copy.move_bitmap_values(project, false) - cl_selection_map = selection_map_copy + project.selection_map.move_bitmap_values(project, false) + cl_selection_map = project.selection_map else: to_copy = image.get_rect(big_bounding_rectangle) to_copy.lock() @@ -776,7 +752,7 @@ func paste(in_place := false) -> void: max(clip_map.get_size().y, project.selection_map.get_size().y) ) - project.selection_map = clip_map + project.selection_map.copy_from(clip_map) project.selection_map.crop(max_size.x, max_size.y) project.selection_offset = clipboard.selection_offset big_bounding_rectangle = clipboard.big_bounding_rectangle @@ -899,13 +875,10 @@ func invert() -> void: transform_content_confirm() var project: Project = Global.current_project var undo_data_tmp := get_undo_data(false) - var selection_map_copy := SelectionMap.new() - selection_map_copy.copy_from(project.selection_map) - selection_map_copy.crop(project.size.x, project.size.y) - selection_map_copy.invert() - project.selection_map = selection_map_copy + project.selection_map.crop(project.size.x, project.size.y) + project.selection_map.invert() project.selection_map_changed() - self.big_bounding_rectangle = selection_map_copy.get_used_rect() + self.big_bounding_rectangle = project.selection_map.get_used_rect() project.selection_offset = Vector2.ZERO commit_undo("Select", undo_data_tmp) @@ -916,11 +889,8 @@ func clear_selection(use_undo := false) -> void: return transform_content_confirm() var undo_data_tmp := get_undo_data(false) - var selection_map_copy := SelectionMap.new() - selection_map_copy.copy_from(project.selection_map) - selection_map_copy.crop(project.size.x, project.size.y) - selection_map_copy.clear() - project.selection_map = selection_map_copy + project.selection_map.crop(project.size.x, project.size.y) + project.selection_map.clear() self.big_bounding_rectangle = Rect2() project.selection_offset = Vector2.ZERO diff --git a/src/UI/Dialogs/ImageEffects/FlipImageDialog.gd b/src/UI/Dialogs/ImageEffects/FlipImageDialog.gd index 4040e91ee..08e26a4a5 100644 --- a/src/UI/Dialogs/ImageEffects/FlipImageDialog.gd +++ b/src/UI/Dialogs/ImageEffects/FlipImageDialog.gd @@ -57,9 +57,7 @@ func _commit_undo(action: String, undo_data: Dictionary, project: Project) -> vo project.undo_redo.create_action(action) Global.undo_redo_compress_images(redo_data, undo_data, project) if redo_data.has("outline_offset"): - project.undo_redo.add_do_property(project, "selection_map", redo_data["selection_map"]) project.undo_redo.add_do_property(project, "selection_offset", redo_data["outline_offset"]) - project.undo_redo.add_undo_property(project, "selection_map", undo_data["selection_map"]) project.undo_redo.add_undo_property( project, "selection_offset", undo_data["outline_offset"] ) @@ -74,9 +72,7 @@ func _get_undo_data(project: Project) -> Dictionary: var affect_selection := selection_checkbox.pressed and project.has_selection var data := {} if affect_selection: - var bitmap_image := SelectionMap.new() - bitmap_image.copy_from(project.selection_map) - data["selection_map"] = bitmap_image + data[project.selection_map] = project.selection_map.data data["outline_offset"] = project.selection_offset var images := _get_selected_draw_images(project) @@ -89,21 +85,17 @@ func _get_undo_data(project: Project) -> Dictionary: func _flip_selection(project: Project = Global.current_project) -> void: if !(selection_checkbox.pressed and project.has_selection): return - - var bitmap_image := SelectionMap.new() - bitmap_image.copy_from(project.selection_map) - var selection_rect := bitmap_image.get_used_rect() - var smaller_bitmap_image := bitmap_image.get_rect(selection_rect) + var selection_rect := project.selection_map.get_used_rect() + var smaller_bitmap_image := project.selection_map.get_rect(selection_rect) if flip_h.pressed: smaller_bitmap_image.flip_x() if flip_v.pressed: smaller_bitmap_image.flip_y() - bitmap_image.fill(Color(0, 0, 0, 0)) - bitmap_image.blend_rect( + project.selection_map.fill(Color(0, 0, 0, 0)) + project.selection_map.blend_rect( smaller_bitmap_image, Rect2(Vector2.ZERO, smaller_bitmap_image.get_size()), selection_rect.position ) - project.selection_map = bitmap_image