Skip to content

Commit

Permalink
Linked Cel Refactor and Timeline Refactor Tweaks (#764)
Browse files Browse the repository at this point in the history
* Updated PixelLayerButton's LinkButton's hint_tooltip to be more accurate

* Don't automatically link the current frame's cel when enabling new_cels_linked on a layer

* Mostly added new system

* renamed link group to link set

* Enable drag and drop of linked cels on the same layer

* formatted CelButton.gd

* serialize/deserialize

* Copy frames w/ new linked cels system. Removed copy_cel from layer classes

* Removed commented out code from AnimationTimeline.copy_frames

* Removed Project.duplicate_layers

* Removed unlink_cel in favour of using null with link cel (as the first part of that method was the same)

* Disabled show_behind_parent on PixelCelButton's LinkedIndicator, as it wasn't enough to improve visibility of selection

* Moved BaseLayer.copy out of the Methods to Override section

* Added optional texture param to Cel's set_content method (needed for use when deserializing, and otherwise helpful

* set textures with set_content where needed

* open_image_as_spritesheet_layer new_cels_linked part updated

* clone layer with linked cels implemented. Removed copy_all_cels from layer classes

* weaked how copied layers names are updated

* Merge layers works with new linked cels now

* Fixed texture on cel buttons not being updated on button setup

* fixed bug where using set_content with new image texture would result in an empty texture

* Open old .pxo with new linked cels

* simplified backwards compatiblity

* removed linked_cels

* better linked cels backwards compatibility

* Removed some old TODO comments

* fixed linked_cels conversion bug when linked_cels is empty

* Added undo for linking the previous cel when creating new cels with new_cels_linked enabled

* Removed TODOs

* Cleaned up some method variable naming

* Cleaned up deserialization

* combined matching for loops

* Inlined BaseLayer.copy() where its used

* gdformat

* Fixed Translations,pot

Co-authored-by: MrTriPie <MrTriPie>
  • Loading branch information
mrtripie authored Oct 16, 2022
1 parent 9230f35 commit 637662d
Show file tree
Hide file tree
Showing 13 changed files with 291 additions and 293 deletions.
8 changes: 4 additions & 4 deletions Translations/Translations.pot
Original file line number Diff line number Diff line change
Expand Up @@ -1543,10 +1543,10 @@ msgstr ""
msgid "Add Frame Tag"
msgstr ""

msgid "Link Cel"
msgid "Link Cels to"
msgstr ""

msgid "Unlink Cel"
msgid "Unlink Cels"
msgstr ""

msgid "Frame Properties"
Expand Down Expand Up @@ -1600,8 +1600,8 @@ msgstr ""
msgid "Frame: %s, Layer: %s"
msgstr ""

msgid "Enable/disable cel linking\n\n"
"Linked cels are being shared across multiple frames"
msgid "Enable/disable automatic linking of new cels when creating new frames\n\n"
"Linked cels share content across multiple frames"
msgstr ""

msgid "Expand/collapse group"
Expand Down
61 changes: 32 additions & 29 deletions src/Autoload/OpenSave.gd
Original file line number Diff line number Diff line change
Expand Up @@ -191,20 +191,22 @@ func open_old_pxo_file(file: File, new_project: Project, first_line: String) ->

var frame := 0

var linked_cels := []
var layer_dicts := []
if file_major_version >= 0 and file_minor_version > 6:
var global_layer_line := file.get_line()
while global_layer_line == ".":
var layer_dict := {
"name": file.get_line(),
"visible": file.get_8(),
"locked": file.get_8(),
"new_cels_linked": file.get_8(),
"linked_cels": []
}
linked_cels.append(file.get_var())
layer_dicts.append(
{
"name": file.get_line(),
"visible": file.get_8(),
"locked": file.get_8(),
"new_cels_linked": file.get_8(),
"link_sets": []
}
)
layer_dicts[-1]["link_sets"].append(file.get_var())
var l := PixelLayer.new(new_project)
l.deserialize(layer_dict)
l.index = new_project.layers.size()
new_project.layers.append(l)
global_layer_line = file.get_line()

Expand All @@ -222,20 +224,14 @@ func open_old_pxo_file(file: File, new_project: Project, first_line: String) ->
var layer_name_old_version = file.get_line()
if frame == 0:
var l := PixelLayer.new(new_project, layer_name_old_version)
l.index = layer_i
new_project.layers.append(l)
var cel_opacity := 1.0
if file_major_version >= 0 and file_minor_version > 5:
cel_opacity = file.get_float()
var image := Image.new()
image.create_from_data(width, height, false, Image.FORMAT_RGBA8, buffer)
frame_class.cels.append(PixelCel.new(image, cel_opacity))
if file_major_version >= 0 and file_minor_version >= 7:
if frame in linked_cels[layer_i]:
var linked_cel: PixelCel = new_project.layers[layer_i].linked_cels[0].cels[layer_i]
new_project.layers[layer_i].linked_cels.append(frame_class)
frame_class.cels[layer_i].image = linked_cel.image
frame_class.cels[layer_i].image_texture = linked_cel.image_texture

layer_i += 1
layer_line = file.get_line()

Expand All @@ -260,6 +256,10 @@ func open_old_pxo_file(file: File, new_project: Project, first_line: String) ->
frame_line = file.get_line()
frame += 1

for layer_i in new_project.layers.size():
# Now that we have the layers, frames, and cels, deserialize layer data
new_project.layers[layer_i].deserialize(layer_dicts[layer_i])

if new_guides:
var guide_line := file.get_line() # "guideline" no pun intended
while guide_line == "|": # Load guides
Expand Down Expand Up @@ -460,27 +460,32 @@ func open_image_as_spritesheet_layer(
# Initialize undo mechanism
project.undos += 1
project.undo_redo.create_action("Add Spritesheet Layer")
var new_layers: Array = project.layers.duplicate() # Used for updating linked_cels lists

# Create new frames (if needed)
var new_frames_size = max(project.frames.size(), start_frame + (vertical * horizontal))
var frames := []
var frame_indices: Array
var frame_indices := []
if new_frames_size > project.frames.size():
var required_frames = new_frames_size - project.frames.size()
frame_indices = range(
project.current_frame + 1, project.current_frame + required_frames + 1
)
for i in required_frames:
var new_frame := Frame.new()
for l_i in range(project.layers.size()): # Create as many cels as there are layers
new_frame.cels.append(project.layers[l_i].new_empty_cel())
if new_layers[l_i].get("new_cels_linked"):
new_layers[l_i].linked_cels.append(new_frame)
new_frame.cels[l_i].set_content(
new_layers[l_i].linked_cels[0].cels[l_i].get_content()
)
new_frame.cels[l_i].image_texture = new_layers[l_i].linked_cels[0].cels[l_i].image_texture
for l in range(project.layers.size()): # Create as many cels as there are layers
new_frame.cels.append(project.layers[l].new_empty_cel())
if project.layers[l].new_cels_linked:
var prev_cel: BaseCel = project.frames[project.current_frame].cels[l]
if prev_cel.link_set == null:
prev_cel.link_set = []
project.undo_redo.add_do_method(
project.layers[l], "link_cel", prev_cel, prev_cel.link_set
)
project.undo_redo.add_undo_method(
project.layers[l], "link_cel", prev_cel, null
)
new_frame.cels[l].set_content(prev_cel.get_content(), prev_cel.image_texture)
new_frame.cels[l].link_set = prev_cel.link_set
frames.append(new_frame)

# Create new layer for spritesheet
Expand All @@ -504,14 +509,12 @@ func open_image_as_spritesheet_layer(
project.undo_redo.add_do_property(project, "current_frame", new_frames_size - 1)
project.undo_redo.add_do_property(project, "current_layer", project.layers.size())
project.undo_redo.add_do_method(project, "add_frames", frames, frame_indices)
project.undo_redo.add_do_property(project, "layers", new_layers)
project.undo_redo.add_do_method(project, "add_layers", [layer], [project.layers.size()], [cels])
project.undo_redo.add_do_method(Global, "undo_or_redo", false)

project.undo_redo.add_undo_property(project, "current_layer", project.current_layer)
project.undo_redo.add_undo_property(project, "current_frame", project.current_frame)
project.undo_redo.add_undo_method(project, "remove_layers", [project.layers.size()])
project.undo_redo.add_undo_property(project, "layers", project.layers)
project.undo_redo.add_undo_method(project, "remove_frames", frame_indices)
project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
project.undo_redo.commit_action()
Expand Down
3 changes: 2 additions & 1 deletion src/Classes/BaseCel.gd
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ extends Reference

var opacity: float
var image_texture: ImageTexture
var link_set = null # The linked cel array this cel is in, or null if its not linked

# Methods to Override:

Expand All @@ -16,7 +17,7 @@ func get_content():
return null


func set_content(_content) -> void:
func set_content(_content, _texture: ImageTexture = null) -> void:
return


Expand Down
64 changes: 43 additions & 21 deletions src/Classes/BaseLayer.gd
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ extends Reference
# Base class for layer properties. Different layer types extend from this class.

var name := ""
var visible := true
var locked := false
var parent: BaseLayer
var project
var index: int
var parent: BaseLayer
var visible := true
var locked := false
var new_cels_linked := false
var cel_link_sets := [] # 2D Array of Cels (Each Array inside this represents a "link set")


# Returns true if this is a direct or indirect parent of layer
Expand Down Expand Up @@ -81,17 +83,43 @@ func get_layer_path() -> String:
return name


# Links a cel to link_set if its an array, or unlinks if null. Just handles changing cel_link_sets
# and cel.link_set. Content/image_texture are handled seperately for undo/redo related reasons
func link_cel(cel: BaseCel, link_set = null) -> void:
# Erase from the cel's current link_set
if cel.link_set != null:
cel.link_set.erase(cel)
if cel.link_set.empty():
cel_link_sets.erase(cel.link_set)
# Add to link_set
cel.link_set = link_set
if link_set != null:
link_set.append(cel)
if not cel_link_sets.has(link_set):
cel_link_sets.append(link_set)


# Methods to Override:


func serialize() -> Dictionary:
assert(index == project.layers.find(self))
return {
var dict := {
"name": name,
"visible": visible,
"locked": locked,
"parent": parent.index if is_instance_valid(parent) else -1
}
if not cel_link_sets.empty():
var cels := [] # Cels array for easy finding of the frame index for link_set saving
for frame in project.frames:
cels.append(frame.cels[index])
dict["link_sets"] = []
for link_set in cel_link_sets:
dict["link_sets"].append([])
for cel in link_set:
dict["link_sets"][-1].append(cels.find(cel))
return dict


func deserialize(dict: Dictionary) -> void:
Expand All @@ -100,29 +128,23 @@ func deserialize(dict: Dictionary) -> void:
locked = dict.locked
if dict.get("parent", -1) != -1:
parent = project.layers[dict.parent]


func copy() -> BaseLayer:
var copy = get_script().new(project)
copy.project = project
copy.index = index
copy.deserialize(serialize())
return copy
if dict.has("linked_cels") and not dict["linked_cels"].empty():
dict["link_sets"] = [dict["linked_cels"]] # Convert old linked_cels to link_sets
if dict.has("link_sets"):
for serialized_link_set in dict["link_sets"]:
var link_set := []
for linked_cel_index in serialized_link_set:
var linked_cel: BaseCel = project.frames[linked_cel_index].cels[index]
link_set.append(linked_cel)
linked_cel.link_set = link_set
linked_cel.set_content(link_set[0].get_content(), link_set[0].image_texture)
cel_link_sets.append(link_set)


func new_empty_cel() -> BaseCel:
return null


func copy_cel(_frame: int, _linked: bool) -> BaseCel:
return null


# Used to copy all cels with cel linking properly set up between this set of copies:
func copy_all_cels() -> Array:
return []


func set_name_to_default(number: int) -> void:
name = tr("Layer") + " %s" % number

Expand Down
13 changes: 0 additions & 13 deletions src/Classes/GroupLayer.gd
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,6 @@ func new_empty_cel() -> BaseCel:
return GroupCel.new()


func copy_cel(frame_index: int, _linked: bool) -> BaseCel:
var cel: GroupCel = project.frames[frame_index].cels[index]
return GroupCel.new(cel.opacity)


func copy_all_cels() -> Array:
var cels := []
for frame in project.frames:
var cel: GroupCel = frame.cels[index]
cels.append(GroupCel.new(cel.opacity))
return cels


func set_name_to_default(number: int) -> void:
name = tr("Group") + " %s" % number

Expand Down
10 changes: 7 additions & 3 deletions src/Classes/PixelCel.gd
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,14 @@ func get_content():
return image


func set_content(content) -> void:
func set_content(content, texture: ImageTexture = null) -> void:
image = content
image_texture.create_from_image(image, 0)
if is_instance_valid(texture):
image_texture = texture
if image_texture.get_size() != image.get_size():
image_texture.create_from_image(image, 0)
else:
image_texture.create_from_image(image, 0)


func create_empty_content():
Expand Down Expand Up @@ -65,5 +70,4 @@ func load_image_data_from_pxo(file: File, project_size: Vector2) -> void:

func instantiate_cel_button() -> Node:
var cel_button = Global.pixel_cel_button_node.instance()
cel_button.get_child(0).texture = image_texture
return cel_button
45 changes: 0 additions & 45 deletions src/Classes/PixelLayer.gd
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ class_name PixelLayer
extends BaseLayer
# A class for standard pixel layer properties.

var new_cels_linked := false
var linked_cels := [] # Array of Frames


func _init(_project, _name := "") -> void:
project = _project
Expand All @@ -18,62 +15,20 @@ func serialize() -> Dictionary:
var dict = .serialize()
dict["type"] = Global.LayerTypes.PIXEL
dict["new_cels_linked"] = new_cels_linked
dict["linked_cels"] = []
for cel in linked_cels:
dict.linked_cels.append(project.frames.find(cel))
return dict


func deserialize(dict: Dictionary) -> void:
.deserialize(dict)
new_cels_linked = dict.new_cels_linked

for linked_cel_number in dict.linked_cels:
linked_cels.append(project.frames[linked_cel_number])
var linked_cel: PixelCel = project.frames[linked_cel_number].cels[index]
linked_cel.image = linked_cels[0].cels[index].image
linked_cel.image_texture = linked_cels[0].cels[index].image_texture


func new_empty_cel() -> BaseCel:
var image := Image.new()
image.create(project.size.x, project.size.y, false, Image.FORMAT_RGBA8)
return PixelCel.new(image)


func copy_cel(frame_index: int, linked: bool) -> BaseCel:
if linked and not linked_cels.empty():
var cel: PixelCel = linked_cels[0].cels[index]
return PixelCel.new(cel.image, cel.opacity, cel.image_texture)
else:
var cel: PixelCel = project.frames[frame_index].cels[index]
var copy_image := Image.new()
copy_image.copy_from(cel.image)
return PixelCel.new(copy_image, cel.opacity)


func copy_all_cels() -> Array:
var cels := []

var linked_image: Image
var linked_texture: ImageTexture
if not linked_cels.empty():
var cel: PixelCel = linked_cels[0].cels[index]
linked_image = Image.new()
linked_image.copy_from(cel.image)
linked_texture = ImageTexture.new()

for frame in project.frames:
var cel: PixelCel = frame.cels[index]
if linked_cels.has(frame):
cels.append(PixelCel.new(linked_image, cel.opacity, linked_texture))
else:
var copy_image := Image.new()
copy_image.copy_from(cel.image)
cels.append(PixelCel.new(copy_image, cel.opacity))
return cels


func can_layer_get_drawn() -> bool:
return is_visible_in_hierarchy() && !is_locked_in_hierarchy()

Expand Down
Loading

0 comments on commit 637662d

Please sign in to comment.