diff --git a/src/Classes/ImageEffect.gd b/src/Classes/ImageEffect.gd index f50aef337..d1cf3c12e 100644 --- a/src/Classes/ImageEffect.gd +++ b/src/Classes/ImageEffect.gd @@ -157,10 +157,11 @@ func display_animate_dialog() -> void: func _commit_undo(action: String, undo_data: Dictionary, project: Project) -> void: + project.update_tilesets(undo_data) var redo_data := _get_undo_data(project) project.undos += 1 project.undo_redo.create_action(action) - Global.undo_redo_compress_images(redo_data, undo_data, project) + project.deserialize_cel_undo_data(redo_data, undo_data) project.undo_redo.add_do_method(Global.undo_or_redo.bind(false, -1, -1, project)) project.undo_redo.add_undo_method(Global.undo_or_redo.bind(true, -1, -1, project)) project.undo_redo.commit_action() @@ -168,24 +169,22 @@ func _commit_undo(action: String, undo_data: Dictionary, project: Project) -> vo func _get_undo_data(project: Project) -> Dictionary: var data := {} - var images := _get_selected_draw_images(project) - for image in images: - image.add_data_to_dictionary(data) + project.serialize_cel_undo_data(_get_selected_draw_cels(project), data) return data -func _get_selected_draw_images(project: Project) -> Array[ImageExtended]: - var images: Array[ImageExtended] = [] +func _get_selected_draw_cels(project: Project) -> Array[BaseCel]: + var images: Array[BaseCel] = [] if affect == SELECTED_CELS: for cel_index in project.selected_cels: var cel: BaseCel = project.frames[cel_index[0]].cels[cel_index[1]] if cel is PixelCel: - images.append(cel.get_image()) + images.append(cel) else: for frame in project.frames: for cel in frame.cels: if cel is PixelCel: - images.append(cel.get_image()) + images.append(cel) return images diff --git a/src/Classes/Project.gd b/src/Classes/Project.gd index 317369523..35143700c 100644 --- a/src/Classes/Project.gd +++ b/src/Classes/Project.gd @@ -651,6 +651,26 @@ func get_all_pixel_cels() -> Array[PixelCel]: return cels +func serialize_cel_undo_data(cels: Array[BaseCel], data: Dictionary) -> void: + for cel in cels: + if not cel is PixelCel: + continue + var image := (cel as PixelCel).get_image() + image.add_data_to_dictionary(data) + if cel is CelTileMap: + data[cel] = (cel as CelTileMap).serialize_undo_data() + + +func deserialize_cel_undo_data(redo_data: Dictionary, undo_data: Dictionary) -> void: + Global.undo_redo_compress_images(redo_data, undo_data, self) + for cel in redo_data: + if cel is CelTileMap: + (cel as CelTileMap).deserialize_undo_data(redo_data[cel], undo_redo, false) + for cel in undo_data: + if cel is CelTileMap: + (cel as CelTileMap).deserialize_undo_data(undo_data[cel], undo_redo, true) + + ## Re-order layers to take each cel's z-index into account. If all z-indexes are 0, ## then the order of drawing is the same as the order of the layers itself. func order_layers(frame_index := current_frame) -> void: @@ -954,3 +974,9 @@ func reorder_reference_image(from: int, to: int) -> void: func add_tileset(tileset: TileSetCustom) -> void: tilesets.append(tileset) + + +func update_tilesets(cel_dictionary: Dictionary) -> void: + for cel in cel_dictionary: + if cel is CelTileMap: + (cel as CelTileMap).update_tileset() diff --git a/src/Tools/BaseDraw.gd b/src/Tools/BaseDraw.gd index 5fa176d47..fb14fa909 100644 --- a/src/Tools/BaseDraw.gd +++ b/src/Tools/BaseDraw.gd @@ -272,11 +272,9 @@ func prepare_undo(action: String) -> void: func commit_undo() -> void: - for cel in _undo_data: - if cel is CelTileMap: - (cel as CelTileMap).update_tileset() - var redo_data := _get_undo_data() var project := Global.current_project + project.update_tilesets(_undo_data) + var redo_data := _get_undo_data() var frame := -1 var layer := -1 if Global.animation_timeline.animation_timer.is_stopped() and project.selected_cels.size() == 1: @@ -284,13 +282,7 @@ func commit_undo() -> void: layer = project.current_layer project.undos += 1 - Global.undo_redo_compress_images(redo_data, _undo_data, project) - for cel in redo_data: - if cel is CelTileMap: - (cel as CelTileMap).deserialize_undo_data(redo_data[cel], project.undo_redo, false) - for cel in _undo_data: - if cel is CelTileMap: - (cel as CelTileMap).deserialize_undo_data(_undo_data[cel], project.undo_redo, true) + project.deserialize_cel_undo_data(redo_data, _undo_data) project.undo_redo.add_do_method(Global.undo_or_redo.bind(false, frame, layer)) project.undo_redo.add_undo_method(Global.undo_or_redo.bind(true, frame, layer)) project.undo_redo.commit_action() @@ -766,13 +758,7 @@ func _get_undo_data() -> Dictionary: if not cel is PixelCel: continue cels.append(cel) - for cel in cels: - if not cel is PixelCel: - continue - var image := (cel as PixelCel).get_image() - image.add_data_to_dictionary(data) - if cel is CelTileMap: - data[cel] = (cel as CelTileMap).serialize_undo_data() + project.serialize_cel_undo_data(cels, data) return data diff --git a/src/Tools/BaseTool.gd b/src/Tools/BaseTool.gd index 33975e8e6..6a2e5f33e 100644 --- a/src/Tools/BaseTool.gd +++ b/src/Tools/BaseTool.gd @@ -344,6 +344,17 @@ func _get_draw_image() -> ImageExtended: return Global.current_project.get_current_cel().get_image() +func _get_selected_draw_cels() -> Array[BaseCel]: + var cels: Array[BaseCel] + var project := Global.current_project + for cel_index in project.selected_cels: + var cel: BaseCel = project.frames[cel_index[0]].cels[cel_index[1]] + if not cel is PixelCel: + continue + cels.append(cel) + return cels + + func _get_selected_draw_images() -> Array[ImageExtended]: var images: Array[ImageExtended] = [] var project := Global.current_project diff --git a/src/Tools/DesignTools/Bucket.gd b/src/Tools/DesignTools/Bucket.gd index 801b4e634..6712e6be3 100644 --- a/src/Tools/DesignTools/Bucket.gd +++ b/src/Tools/DesignTools/Bucket.gd @@ -494,8 +494,9 @@ func _set_pixel_pattern(image: ImageExtended, x: int, y: int, pattern_size: Vect func commit_undo() -> void: - var redo_data := _get_undo_data() var project := Global.current_project + project.update_tilesets(_undo_data) + var redo_data := _get_undo_data() var frame := -1 var layer := -1 if Global.animation_timeline.animation_timer.is_stopped() and project.selected_cels.size() == 1: @@ -504,7 +505,7 @@ func commit_undo() -> void: project.undos += 1 project.undo_redo.create_action("Draw") - Global.undo_redo_compress_images(redo_data, _undo_data, project) + project.deserialize_cel_undo_data(redo_data, _undo_data) project.undo_redo.add_do_method(Global.undo_or_redo.bind(false, frame, layer)) project.undo_redo.add_undo_method(Global.undo_or_redo.bind(true, frame, layer)) project.undo_redo.commit_action() @@ -514,14 +515,13 @@ func commit_undo() -> void: func _get_undo_data() -> Dictionary: var data := {} if Global.animation_timeline.animation_timer.is_stopped(): - var images := _get_selected_draw_images() - for image in images: - image.add_data_to_dictionary(data) + Global.current_project.serialize_cel_undo_data(_get_selected_draw_cels(), data) else: + var cels: Array[BaseCel] for frame in Global.current_project.frames: var cel := frame.cels[Global.current_project.current_layer] if not cel is PixelCel: continue - var image := (cel as PixelCel).get_image() - image.add_data_to_dictionary(data) + cels.append(cel) + Global.current_project.serialize_cel_undo_data(cels, data) return data diff --git a/src/Tools/UtilityTools/Move.gd b/src/Tools/UtilityTools/Move.gd index 476ae025e..dc0635ddd 100644 --- a/src/Tools/UtilityTools/Move.gd +++ b/src/Tools/UtilityTools/Move.gd @@ -130,8 +130,9 @@ func _snap_position(pos: Vector2) -> Vector2: func _commit_undo(action: String) -> void: - var redo_data := _get_undo_data() var project := Global.current_project + project.update_tilesets(_undo_data) + var redo_data := _get_undo_data() var frame := -1 var layer := -1 if Global.animation_timeline.animation_timer.is_stopped() and project.selected_cels.size() == 1: @@ -140,7 +141,7 @@ func _commit_undo(action: String) -> void: project.undos += 1 project.undo_redo.create_action(action) - Global.undo_redo_compress_images(redo_data, _undo_data, project) + project.deserialize_cel_undo_data(redo_data, _undo_data) project.undo_redo.add_do_method(Global.undo_or_redo.bind(false, frame, layer)) project.undo_redo.add_undo_method(Global.undo_or_redo.bind(true, frame, layer)) project.undo_redo.commit_action() @@ -158,9 +159,5 @@ func _get_undo_data() -> Dictionary: for frame in project.frames: var cel := frame.cels[project.current_layer] cels.append(cel) - for cel in cels: - if not cel is PixelCel: - continue - var image := (cel as PixelCel).get_image() - image.add_data_to_dictionary(data) + project.serialize_cel_undo_data(cels, data) return data diff --git a/src/Tools/UtilityTools/Text.gd b/src/Tools/UtilityTools/Text.gd index b3ce7a3e2..f7bfc1173 100644 --- a/src/Tools/UtilityTools/Text.gd +++ b/src/Tools/UtilityTools/Text.gd @@ -161,8 +161,9 @@ func text_to_pixels() -> void: func commit_undo(action: String, undo_data: Dictionary) -> void: - var redo_data := _get_undo_data() var project := Global.current_project + project.update_tilesets(undo_data) + var redo_data := _get_undo_data() var frame := -1 var layer := -1 if Global.animation_timeline.animation_timer.is_stopped() and project.selected_cels.size() == 1: @@ -171,7 +172,7 @@ func commit_undo(action: String, undo_data: Dictionary) -> void: project.undos += 1 project.undo_redo.create_action(action) - Global.undo_redo_compress_images(redo_data, undo_data, project) + project.deserialize_cel_undo_data(redo_data, undo_data) project.undo_redo.add_do_method(Global.undo_or_redo.bind(false, frame, layer)) project.undo_redo.add_undo_method(Global.undo_or_redo.bind(true, frame, layer)) project.undo_redo.commit_action() @@ -179,9 +180,7 @@ func commit_undo(action: String, undo_data: Dictionary) -> void: func _get_undo_data() -> Dictionary: var data := {} - var images := _get_selected_draw_images() - for image in images: - image.add_data_to_dictionary(data) + Global.current_project.serialize_cel_undo_data(_get_selected_draw_cels(), data) return data diff --git a/src/UI/Canvas/Selection.gd b/src/UI/Canvas/Selection.gd index f28fd7cd7..ba3fa0986 100644 --- a/src/UI/Canvas/Selection.gd +++ b/src/UI/Canvas/Selection.gd @@ -568,12 +568,12 @@ func commit_undo(action: String, undo_data_tmp: Dictionary) -> void: if !undo_data_tmp: print("No undo data found!") return - var redo_data := get_undo_data(undo_data_tmp["undo_image"]) var project := Global.current_project - + project.update_tilesets(undo_data_tmp) + var redo_data := get_undo_data(undo_data_tmp["undo_image"]) project.undos += 1 project.undo_redo.create_action(action) - Global.undo_redo_compress_images(redo_data, undo_data_tmp, project) + project.deserialize_cel_undo_data(redo_data, undo_data_tmp) project.undo_redo.add_do_property( self, "big_bounding_rectangle", redo_data["big_bounding_rectangle"] ) @@ -604,15 +604,14 @@ func get_undo_data(undo_image: bool) -> Dictionary: data["undo_image"] = undo_image if undo_image: - var images := _get_selected_draw_images() - for image in images: - image.add_data_to_dictionary(data) - + Global.current_project.serialize_cel_undo_data(_get_selected_draw_cels(), data) return data -func _get_selected_draw_cels() -> Array[PixelCel]: - var cels: Array[PixelCel] = [] +# TODO: Change BaseCel to PixelCel if Godot ever fixes issues +# with typed arrays being cast into other types. +func _get_selected_draw_cels() -> Array[BaseCel]: + var cels: Array[BaseCel] = [] var project := Global.current_project for cel_index in project.selected_cels: var cel: BaseCel = project.frames[cel_index[0]].cels[cel_index[1]] diff --git a/src/UI/Dialogs/ImageEffects/FlipImageDialog.gd b/src/UI/Dialogs/ImageEffects/FlipImageDialog.gd index aa4f81248..b5633d258 100644 --- a/src/UI/Dialogs/ImageEffects/FlipImageDialog.gd +++ b/src/UI/Dialogs/ImageEffects/FlipImageDialog.gd @@ -47,11 +47,11 @@ func _flip_image(cel: Image, affect_selection: bool, project: Project) -> void: func _commit_undo(action: String, undo_data: Dictionary, project: Project) -> void: _flip_selection(project) - + project.update_tilesets(undo_data) var redo_data := _get_undo_data(project) project.undos += 1 project.undo_redo.create_action(action) - Global.undo_redo_compress_images(redo_data, undo_data, project) + project.deserialize_cel_undo_data(redo_data, undo_data) if redo_data.has("outline_offset"): project.undo_redo.add_do_property(project, "selection_offset", redo_data["outline_offset"]) project.undo_redo.add_undo_property( @@ -66,14 +66,10 @@ func _commit_undo(action: String, undo_data: Dictionary, project: Project) -> vo func _get_undo_data(project: Project) -> Dictionary: var affect_selection := selection_checkbox.button_pressed and project.has_selection - var data := {} + var data := super._get_undo_data(project) if affect_selection: data[project.selection_map] = project.selection_map.data data["outline_offset"] = project.selection_offset - - var images := _get_selected_draw_images(project) - for image in images: - data[image] = image.data return data diff --git a/src/UI/Timeline/LayerEffects/LayerEffectsSettings.gd b/src/UI/Timeline/LayerEffects/LayerEffectsSettings.gd index 09c9ff5b4..9560a8ffa 100644 --- a/src/UI/Timeline/LayerEffects/LayerEffectsSettings.gd +++ b/src/UI/Timeline/LayerEffects/LayerEffectsSettings.gd @@ -149,34 +149,37 @@ func _delete_effect(effect: LayerEffect) -> void: func _apply_effect(layer: BaseLayer, effect: LayerEffect) -> void: + var project := Global.current_project var index := layer.effects.find(effect) var redo_data := {} var undo_data := {} - for frame in Global.current_project.frames: + for frame in project.frames: var cel := frame.cels[layer.index] - var new_image := ImageExtended.new() var cel_image := cel.get_image() + if cel is CelTileMap: + undo_data[cel] = (cel as CelTileMap).serialize_undo_data() if cel_image is ImageExtended: - new_image.is_indexed = cel_image.is_indexed - new_image.copy_from_custom(cel_image) - var image_size := new_image.get_size() - var shader_image_effect := ShaderImageEffect.new() - shader_image_effect.generate_image(new_image, effect.shader, effect.params, image_size) - if cel_image is ImageExtended: - redo_data[cel_image.indices_image] = new_image.indices_image.data undo_data[cel_image.indices_image] = cel_image.indices_image.data - redo_data[cel_image] = new_image.data undo_data[cel_image] = cel_image.data - Global.current_project.undos += 1 - Global.current_project.undo_redo.create_action("Apply layer effect") - Global.undo_redo_compress_images(redo_data, undo_data) - Global.current_project.undo_redo.add_do_method(func(): layer.effects.erase(effect)) - Global.current_project.undo_redo.add_do_method(Global.canvas.queue_redraw) - Global.current_project.undo_redo.add_do_method(Global.undo_or_redo.bind(false)) - Global.current_project.undo_redo.add_undo_method(func(): layer.effects.insert(index, effect)) - Global.current_project.undo_redo.add_undo_method(Global.canvas.queue_redraw) - Global.current_project.undo_redo.add_undo_method(Global.undo_or_redo.bind(true)) - Global.current_project.undo_redo.commit_action() + var image_size := cel_image.get_size() + var shader_image_effect := ShaderImageEffect.new() + shader_image_effect.generate_image(cel_image, effect.shader, effect.params, image_size) + if cel is CelTileMap: + (cel as CelTileMap).update_tileset() + redo_data[cel] = (cel as CelTileMap).serialize_undo_data() + if cel_image is ImageExtended: + redo_data[cel_image.indices_image] = cel_image.indices_image.data + redo_data[cel_image] = cel_image.data + project.undos += 1 + project.undo_redo.create_action("Apply layer effect") + project.deserialize_cel_undo_data(redo_data, undo_data) + project.undo_redo.add_do_method(func(): layer.effects.erase(effect)) + project.undo_redo.add_do_method(Global.canvas.queue_redraw) + project.undo_redo.add_do_method(Global.undo_or_redo.bind(false)) + project.undo_redo.add_undo_method(func(): layer.effects.insert(index, effect)) + project.undo_redo.add_undo_method(Global.canvas.queue_redraw) + project.undo_redo.add_undo_method(Global.undo_or_redo.bind(true)) + project.undo_redo.commit_action() effect_container.get_child(index).queue_free() diff --git a/src/UI/TopMenuContainer/TopMenuContainer.gd b/src/UI/TopMenuContainer/TopMenuContainer.gd index 622921701..3e4ea7882 100644 --- a/src/UI/TopMenuContainer/TopMenuContainer.gd +++ b/src/UI/TopMenuContainer/TopMenuContainer.gd @@ -722,21 +722,25 @@ func _color_mode_submenu_id_pressed(id: ColorModes) -> void: var old_color_mode := project.color_mode var redo_data := {} var undo_data := {} + var pixel_cels: Array[BaseCel] + # We need to do it this way because Godot + # doesn't like casting typed arrays into other types. for cel in project.get_all_pixel_cels(): - cel.get_image().add_data_to_dictionary(undo_data) + pixel_cels.append(cel) + project.serialize_cel_undo_data(pixel_cels, undo_data) # Change the color mode directly before undo/redo in order to affect the images, # so we can store them as redo data. if id == ColorModes.RGBA: project.color_mode = Image.FORMAT_RGBA8 else: project.color_mode = Project.INDEXED_MODE - for cel in project.get_all_pixel_cels(): - cel.get_image().add_data_to_dictionary(redo_data) + project.update_tilesets(undo_data) + project.serialize_cel_undo_data(pixel_cels, redo_data) project.undo_redo.create_action("Change color mode") project.undos += 1 project.undo_redo.add_do_property(project, "color_mode", project.color_mode) project.undo_redo.add_undo_property(project, "color_mode", old_color_mode) - Global.undo_redo_compress_images(redo_data, undo_data, project) + project.deserialize_cel_undo_data(redo_data, undo_data) project.undo_redo.add_do_method(_check_color_mode_submenu_item.bind(project)) project.undo_redo.add_undo_method(_check_color_mode_submenu_item.bind(project)) project.undo_redo.add_do_method(Global.undo_or_redo.bind(false))