Skip to content

Commit

Permalink
Fix a memory leak coming from the Layer class
Browse files Browse the repository at this point in the history
Removed the "frame_container" property from Layer.gd, which used to hold a reference to a node, leading to orphan nodes being created and never freed. Memory management seems to be working okay now. Previously, every time the user made a change, memory kept going up and never coming down. Now, data that can never be recovered, like undo data that have been rewritten in history, are also removed from memory.
  • Loading branch information
OverloadedOrama committed Dec 23, 2021
1 parent 6a78351 commit 4832690
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 131 deletions.
9 changes: 1 addition & 8 deletions src/Autoload/OpenSave.gd
Expand Up @@ -170,14 +170,7 @@ func open_old_pxo_file(file: File, new_project: Project, first_line: String) ->
var layer_new_cels_linked := file.get_8()
linked_cels.append(file.get_var())

var l := Layer.new(
layer_name,
layer_visibility,
layer_lock,
HBoxContainer.new(),
layer_new_cels_linked,
[]
)
var l := Layer.new(layer_name, layer_visibility, layer_lock, layer_new_cels_linked, [])
new_project.layers.append(l)
global_layer_line = file.get_line()

Expand Down
9 changes: 1 addition & 8 deletions src/Classes/Layer.gd
Expand Up @@ -5,23 +5,16 @@ extends Reference
var name := ""
var visible := true
var locked := false
var frame_container: HBoxContainer
var new_cels_linked := false
var linked_cels := [] # Array of Frames


func _init(
_name := "",
_visible := true,
_locked := false,
_frame_container := HBoxContainer.new(),
_new_cels_linked := false,
_linked_cels := []
_name := "", _visible := true, _locked := false, _new_cels_linked := false, _linked_cels := []
) -> void:
name = _name
visible = _visible
locked = _locked
frame_container = _frame_container
new_cels_linked = _new_cels_linked
linked_cels = _linked_cels

Expand Down
81 changes: 49 additions & 32 deletions src/Classes/Project.gd
Expand Up @@ -85,8 +85,6 @@ func _init(_frames := [], _name := tr("untitled"), _size := Vector2(64, 64)) ->


func remove() -> void:
for layer in layers:
layer.frame_container.queue_free()
undo_redo.free()
for guide in guides:
guide.queue_free()
Expand Down Expand Up @@ -160,7 +158,8 @@ func change_project() -> void:
layer_container.label.text = layers[i].name
layer_container.line_edit.text = layers[i].name

Global.frames_container.add_child(layers[i].frame_container)
var layer_cel_container := HBoxContainer.new()
Global.frames_container.add_child(layer_cel_container)
for j in range(frames.size()): # Create Cel buttons
var cel_button = cel_button_node.instance()
cel_button.frame = j
Expand All @@ -169,7 +168,7 @@ func change_project() -> void:
if j == current_frame and i == current_layer:
cel_button.pressed = true

layers[i].frame_container.add_child(cel_button)
layer_cel_container.add_child(cel_button)

for j in range(frames.size()): # Create frame ID labels
var button: Button = frame_button_node.instance()
Expand Down Expand Up @@ -335,7 +334,6 @@ func serialize() -> Dictionary:
cel_data.append(
{
"opacity": cel.opacity,
# "image_data" : cel.image.get_data()
}
)
frame_data.append({"cels": cel_data, "duration": frame.duration})
Expand Down Expand Up @@ -402,7 +400,6 @@ func deserialize(dict: Dictionary) -> void:
saved_layer.name,
saved_layer.visible,
saved_layer.locked,
HBoxContainer.new(),
saved_layer.new_cels_linked,
linked_cels
)
Expand Down Expand Up @@ -463,7 +460,15 @@ func _frames_changed(value: Array) -> void:
frame_id.queue_free()

for i in range(layers.size() - 1, -1, -1):
Global.frames_container.add_child(layers[i].frame_container)
var layer_cel_container := HBoxContainer.new()
layer_cel_container.name = "FRAMESS " + str(i)
Global.frames_container.add_child(layer_cel_container)
for j in range(frames.size()):
var cel_button = cel_button_node.instance()
cel_button.frame = j
cel_button.layer = i
cel_button.get_child(0).texture = frames[j].cels[i].image_texture
layer_cel_container.add_child(cel_button)

for j in range(frames.size()):
var button: Button = frame_button_node.instance()
Expand All @@ -472,14 +477,6 @@ func _frames_changed(value: Array) -> void:
button.text = str(j + 1)
Global.frame_ids.add_child(button)

for i in range(layers.size() - 1, -1, -1):
var cel_button = cel_button_node.instance()
cel_button.frame = j
cel_button.layer = i
cel_button.get_child(0).texture = frames[j].cels[i].image_texture

layers[i].frame_container.add_child(cel_button)

_set_timeline_first_and_last_frames()


Expand All @@ -497,23 +494,24 @@ func _layers_changed(value: Array) -> void:
_remove_cel_buttons()

for i in range(layers.size() - 1, -1, -1):
var layer_container = layer_button_node.instance()
layer_container.layer = i
var layer_button: LayerButton = layer_button_node.instance()
layer_button.layer = i
if layers[i].name == "":
layers[i].name = tr("Layer") + " %s" % i

Global.layers_container.add_child(layer_container)
layer_container.label.text = layers[i].name
layer_container.line_edit.text = layers[i].name
Global.layers_container.add_child(layer_button)
layer_button.label.text = layers[i].name
layer_button.line_edit.text = layers[i].name

Global.frames_container.add_child(layers[i].frame_container)
var layer_cel_container := HBoxContainer.new()
layer_cel_container.name = "LAYERSSS " + str(i)
Global.frames_container.add_child(layer_cel_container)
for j in range(frames.size()):
var cel_button = cel_button_node.instance()
cel_button.frame = j
cel_button.layer = i
cel_button.get_child(0).texture = frames[j].cels[i].image_texture

layers[i].frame_container.add_child(cel_button)
layer_cel_container.add_child(cel_button)

var layer_button = Global.layers_container.get_child(
Global.layers_container.get_child_count() - 1 - current_layer
Expand All @@ -525,10 +523,8 @@ func _layers_changed(value: Array) -> void:

func _remove_cel_buttons() -> void:
for container in Global.frames_container.get_children():
for button in container.get_children():
container.remove_child(button)
button.queue_free()
Global.frames_container.remove_child(container)
container.queue_free()


func _frame_changed(value: int) -> void:
Expand All @@ -544,9 +540,9 @@ func _frame_changed(value: int) -> void:
):
text_color = Color.black
Global.frame_ids.get_child(i).add_color_override("font_color", text_color)
for layer in layers: # De-select all the other frames
if i < layer.frame_container.get_child_count():
layer.frame_container.get_child(i).pressed = false
for container in Global.frames_container.get_children(): # De-select all the other frames
if i < container.get_child_count():
container.get_child(i).pressed = false

if selected_cels.empty():
selected_cels.append([current_frame, current_layer])
Expand All @@ -558,9 +554,13 @@ func _frame_changed(value: int) -> void:
Global.frame_ids.get_child(current_frame_tmp).add_color_override(
"font_color", Global.control.theme.get_color("Selected Color", "Label")
)
if layers:
if current_frame_tmp < layers[current_layer_tmp].frame_container.get_child_count():
var fbutton = layers[current_layer_tmp].frame_container.get_child(current_frame_tmp)
var container_child_count: int = Global.frames_container.get_child_count()
if current_layer_tmp < container_child_count:
var container = Global.frames_container.get_child(
container_child_count - 1 - current_layer_tmp
)
if current_frame_tmp < container.get_child_count():
var fbutton = container.get_child(current_frame_tmp)
fbutton.pressed = true

Global.disable_button(Global.remove_frame_button, frames.size() == 1)
Expand Down Expand Up @@ -704,6 +704,23 @@ func is_empty() -> bool:
)


func duplicate_layers() -> Array:
var new_layers: Array = layers.duplicate()
# Loop through the array to create new classes for each element, so that they
# won't be the same as the original array's classes. Needed for undo/redo to work properly.
for i in new_layers.size():
var new_linked_cels = new_layers[i].linked_cels.duplicate()
new_layers[i] = Layer.new(
new_layers[i].name,
new_layers[i].visible,
new_layers[i].locked,
new_layers[i].new_cels_linked,
new_linked_cels
)

return new_layers


func can_pixel_get_drawn(
pixel: Vector2,
bitmap: BitMap = selection_bitmap,
Expand Down
14 changes: 9 additions & 5 deletions src/UI/Canvas/Canvas.gd
Expand Up @@ -112,10 +112,12 @@ func update_texture(layer_i: int, frame_i := -1, project: Project = Global.curre
current_cel.image_texture.create_from_image(current_cel.image, 0)

if project == Global.current_project:
var frame_button = project.layers[layer_i].frame_container.get_child(frame_i)
var frame_texture_rect: TextureRect
frame_texture_rect = frame_button.find_node("CelTexture")
frame_texture_rect.texture = current_cel.image_texture
var container_index = Global.frames_container.get_child_count() - 1 - layer_i
var layer_cel_container = Global.frames_container.get_child(container_index)
var cel_button = layer_cel_container.get_child(frame_i)
var cel_texture_rect: TextureRect
cel_texture_rect = cel_button.find_node("CelTexture")
cel_texture_rect.texture = current_cel.image_texture


func update_selected_cels_textures(project: Project = Global.current_project) -> void:
Expand All @@ -127,7 +129,9 @@ func update_selected_cels_textures(project: Project = Global.current_project) ->
current_cel.image_texture.create_from_image(current_cel.image, 0)

if project == Global.current_project:
var cel_button = project.layers[layer_index].frame_container.get_child(frame_index)
var container_index = Global.frames_container.get_child_count() - 1 - layer_index
var layer_cel_container = Global.frames_container.get_child(container_index)
var cel_button = layer_cel_container.get_child(frame_index)
var cel_texture_rect: TextureRect = cel_button.find_node("CelTexture")
cel_texture_rect.texture = current_cel.image_texture

Expand Down
61 changes: 6 additions & 55 deletions src/UI/Timeline/AnimationTimeline.gd
Expand Up @@ -54,8 +54,8 @@ func cel_size_changed(value: int) -> void:
for layer_button in Global.layers_container.get_children():
layer_button.rect_min_size.y = cel_size
layer_button.rect_size.y = cel_size
for layer in Global.current_project.layers:
for cel_button in layer.frame_container.get_children():
for container in Global.frames_container.get_children():
for cel_button in container.get_children():
cel_button.rect_min_size.x = cel_size
cel_button.rect_min_size.y = cel_size
cel_button.rect_size.x = cel_size
Expand Down Expand Up @@ -83,20 +83,8 @@ func add_frame() -> void:
var project: Project = Global.current_project
var frame: Frame = project.new_empty_frame()
var new_frames: Array = project.frames.duplicate()
var new_layers: Array = project.layers.duplicate()
var new_layers: Array = project.duplicate_layers()
new_frames.insert(project.current_frame + 1, frame)
# Loop through the array to create new classes for each element, so that they
# won't be the same as the original array's classes. Needed for undo/redo to work properly.
for i in new_layers.size():
var new_linked_cels = new_layers[i].linked_cels.duplicate()
new_layers[i] = Layer.new(
new_layers[i].name,
new_layers[i].visible,
new_layers[i].locked,
new_layers[i].frame_container,
new_layers[i].new_cels_linked,
new_linked_cels
)

for l_i in range(new_layers.size()):
if new_layers[l_i].new_cels_linked: # If the link button is pressed
Expand Down Expand Up @@ -161,19 +149,7 @@ func delete_frame(frame := -1) -> void:
# Check if one of the cels of the frame is linked
# if they are, unlink them too
# this prevents removed cels being kept in linked memory
var new_layers: Array = Global.current_project.layers.duplicate()
# Loop through the array to create new classes for each element, so that they
# won't be the same as the original array's classes. Needed for undo/redo to work properly.
for i in new_layers.size():
var new_linked_cels = new_layers[i].linked_cels.duplicate()
new_layers[i] = Layer.new(
new_layers[i].name,
new_layers[i].visible,
new_layers[i].locked,
new_layers[i].frame_container,
new_layers[i].new_cels_linked,
new_linked_cels
)
var new_layers: Array = Global.current_project.duplicate_layers()

for layer in new_layers:
for linked in layer.linked_cels:
Expand Down Expand Up @@ -221,7 +197,7 @@ func copy_frame(frame := -1) -> void:

var new_frame := Frame.new()
var new_frames := Global.current_project.frames.duplicate()
var new_layers: Array = Global.current_project.layers.duplicate()
var new_layers: Array = Global.current_project.duplicate_layers()
new_frames.insert(frame + 1, new_frame)

for cel in Global.current_project.frames[frame].cels: # Copy every cel
Expand All @@ -231,19 +207,6 @@ func copy_frame(frame := -1) -> void:
sprite_texture.create_from_image(sprite, 0)
new_frame.cels.append(Cel.new(sprite, cel.opacity, sprite_texture))

# Loop through the array to create new classes for each element, so that they
# won't be the same as the original array's classes. Needed for undo/redo to work properly.
for i in new_layers.size():
var new_linked_cels = new_layers[i].linked_cels.duplicate()
new_layers[i] = Layer.new(
new_layers[i].name,
new_layers[i].visible,
new_layers[i].locked,
new_layers[i].frame_container,
new_layers[i].new_cels_linked,
new_linked_cels
)

for l_i in range(new_layers.size()):
if new_layers[l_i].new_cels_linked: # If the link button is pressed
new_layers[l_i].linked_cels.append(new_frame)
Expand Down Expand Up @@ -651,19 +614,7 @@ func change_layer_order(rate: int) -> void:


func _on_MergeDownLayer_pressed() -> void:
var new_layers: Array = Global.current_project.layers.duplicate()
# Loop through the array to create new classes for each element, so that they
# won't be the same as the original array's classes. Needed for undo/redo to work properly.
for i in new_layers.size():
var new_linked_cels = new_layers[i].linked_cels.duplicate()
new_layers[i] = Layer.new(
new_layers[i].name,
new_layers[i].visible,
new_layers[i].locked,
new_layers[i].frame_container,
new_layers[i].new_cels_linked,
new_linked_cels
)
var new_layers: Array = Global.current_project.duplicate_layers()

Global.current_project.undos += 1
Global.current_project.undo_redo.create_action("Merge Layer")
Expand Down
14 changes: 1 addition & 13 deletions src/UI/Timeline/CelButton.gd
Expand Up @@ -105,19 +105,7 @@ func _on_PopupMenu_id_pressed(id: int) -> void:
MenuOptions.LINK:
var f: Frame = Global.current_project.frames[frame]
var cel_index: int = Global.current_project.layers[layer].linked_cels.find(f)
var new_layers: Array = Global.current_project.layers.duplicate()
# Loop through the array to create new classes for each element, so that they
# won't be the same as the original array's classes. Needed for undo/redo to work properly.
for i in new_layers.size():
var new_linked_cels: Array = new_layers[i].linked_cels.duplicate()
new_layers[i] = Layer.new(
new_layers[i].name,
new_layers[i].visible,
new_layers[i].locked,
new_layers[i].frame_container,
new_layers[i].new_cels_linked,
new_linked_cels
)
var new_layers: Array = Global.current_project.duplicate_layers()
var new_cels: Array = f.cels.duplicate()
for i in new_cels.size():
new_cels[i] = Cel.new(
Expand Down
3 changes: 2 additions & 1 deletion src/UI/Timeline/LayerButton.gd
Expand Up @@ -116,7 +116,8 @@ func _on_LinkButton_pressed() -> void:
layer_class.linked_cels.append(
Global.current_project.frames[Global.current_project.current_frame]
)
layer_class.frame_container.get_child(Global.current_project.current_frame).button_setup()
var container = Global.frames_container.get_child(Global.current_project.current_layer)
container.get_child(Global.current_project.current_frame).button_setup()

Global.current_project.layers = Global.current_project.layers # Call the setter

Expand Down

0 comments on commit 4832690

Please sign in to comment.