v0.2 - Animation Timeline & UI changes!

v0.2 of Pixelorama is out!
- Added animation timeline. You can add. remove. clone and change order of your frames!
- You can now import multiple images as frames.
- Ability to save individual frames, all frames as multiple files, or all frames as a single file in the form of a horizontal or vertical spritesheet!
- Different frames can have a unique amount of layers and they can be of different sizes.
- Image scaling is now functional.
- Added hints for UI elements.
- A lot of UI changes.
This commit is contained in:
OverloadedOrama 2019-09-10 01:57:46 +03:00
parent 1f80291a4b
commit 5781c42821
25 changed files with 765 additions and 183 deletions

View file

@ -1,7 +1,7 @@
extends Camera2D
var zoom_min := Vector2(0.005, 0.005)
var zoom_max := Vector2(0.8, 0.8)
var zoom_max := Vector2.ONE
var drag := false
@ -21,5 +21,11 @@ func _input(event) -> void:
# Zoom Camera
func zoom_camera(dir : int) -> void:
var zoom_margin = zoom * dir / 10
if zoom + zoom_margin > zoom_min && zoom + zoom_margin < zoom_max:
zoom += zoom_margin
#if zoom + zoom_margin > zoom_min && zoom + zoom_margin < zoom_max:
if zoom + zoom_margin > zoom_min:
zoom += zoom_margin
if zoom > zoom_max:
zoom = zoom_max
Global.zoom_level_label.text = "Zoom: x%s" % [stepify(1 / zoom.x, 0.01)]

View file

@ -4,20 +4,18 @@ class_name Canvas
var layers := []
var current_layer_index := 0
var trans_background : ImageTexture
var current_sprite : Image
var location := Vector2.ZERO
var size := Vector2(64, 64)
var frame := 0
var frame_button : VBoxContainer
var frame_texture_rect : TextureRect
var previous_mouse_pos := Vector2.ZERO
var mouse_inside_canvas := false #used for undo
var sprite_changed_this_frame := false #for optimization purposes
var left_square_indicator_visible := true
var right_square_indicator_visible := false
var left_brush_size := 1
var right_brush_size := 1
var is_making_line := false
var line_2d : Line2D
var draw_grid := false
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
@ -27,24 +25,29 @@ func _ready() -> void:
trans_background.create_from_image(load("res://Transparent Background.png"), 0)
#The sprite itself
if !current_sprite:
current_sprite = Image.new()
current_sprite.create(size.x, size.y, false, Image.FORMAT_RGBA8)
if layers.empty():
var sprite := Image.new()
sprite.create(size.x, size.y, false, Image.FORMAT_RGBA8)
current_sprite.lock()
var tex := ImageTexture.new()
tex.create_from_image(current_sprite, 0)
#Store [Image, ImageTexture, Layer Name, Visibity boolean]
layers.append([current_sprite, tex, "Layer 0", true])
sprite.lock()
var tex := ImageTexture.new()
tex.create_from_image(sprite, 0)
#Store [Image, ImageTexture, Layer Name, Visibity boolean]
layers.append([sprite, tex, "Layer 0", true])
generate_layer_panels()
#Set camera offset to the center of canvas
$"../Camera2D".offset = size / 2
#Set camera zoom based on the sprite size
var bigger = max(size.x, size.y)
$"../Camera2D".zoom_max = Vector2(bigger, bigger) * 0.01
$"../Camera2D".zoom = Vector2(bigger, bigger) * 0.002
frame_button = load("res://FrameButton.tscn").instance()
frame_button.name = "Frame_%s" % frame
frame_button.get_node("FrameButton").frame = frame
frame_button.get_node("FrameID").text = str(frame)
Global.frame_container.add_child(frame_button)
frame_texture_rect = Global.find_node_by_name(frame_button, "FrameTexture")
frame_texture_rect.texture = layers[0][1] #ImageTexture current_layer_index
camera_zoom()
# warning-ignore:unused_argument
func _process(delta) -> void:
@ -60,11 +63,16 @@ func _process(delta) -> void:
current_mouse_button = "R"
current_action = Global.current_right_tool
if visible:
if !point_in_rectangle(mouse_pos, location, location + size):
if !Input.is_mouse_button_pressed(BUTTON_LEFT) && !Input.is_mouse_button_pressed(BUTTON_RIGHT):
if mouse_inside_canvas:
mouse_inside_canvas = false
Global.cursor_position_label.text = "[%sx%s]" % [size.x, size.y]
else:
var mouse_pos_floored := mouse_pos.floor()
Global.cursor_position_label.text = "[%sx%s] %s, %s" % [size.x, size.y, mouse_pos_floored.x, mouse_pos_floored.y]
if !point_in_rectangle(mouse_pos, location, location + size):
if !Input.is_mouse_button_pressed(BUTTON_LEFT) && !Input.is_mouse_button_pressed(BUTTON_RIGHT):
if mouse_inside_canvas:
mouse_inside_canvas = false
match current_action:
"Pencil":
var current_color : Color
@ -76,7 +84,7 @@ func _process(delta) -> void:
"Eraser":
pencil_and_eraser(mouse_pos, Color(0, 0, 0, 0), current_mouse_button)
"Fill":
if point_in_rectangle(mouse_pos, location, location + size) && Global.can_draw && Global.has_focus:
if point_in_rectangle(mouse_pos, location, location + size) && Global.can_draw && Global.has_focus && Global.current_frame == frame:
var current_color : Color
if current_mouse_button == "L":
current_color = Global.left_color_picker.color
@ -94,9 +102,18 @@ func _process(delta) -> void:
if sprite_changed_this_frame:
update_texture(current_layer_index)
func update_texture(layer_index : int):
func update_texture(layer_index : int) -> void:
layers[layer_index][1].create_from_image(layers[layer_index][0], 0)
get_layer_container(layer_index).get_child(0).get_child(1).texture = layers[layer_index][1]
var whole_image := Image.new()
whole_image.create(size.x, size.y, false, Image.FORMAT_RGBA8)
for layer in layers:
whole_image.blend_rect(layer[0], Rect2(position, size), Vector2.ZERO)
layer[0].lock()
var whole_image_texture := ImageTexture.new()
whole_image_texture.create_from_image(whole_image, 0)
frame_texture_rect.texture = whole_image_texture
func get_layer_container(layer_index : int) -> PanelContainer:
for container in Global.vbox_layer_container.get_children():
@ -112,7 +129,7 @@ func _draw() -> void:
draw_texture(texture[1], location)
#Idea taken from flurick (on GitHub)
if draw_grid:
if Global.draw_grid:
for x in size.x:
draw_line(Vector2(x, location.y), Vector2(x, size.y), Color.black, true)
for y in size.y:
@ -122,14 +139,14 @@ func _draw() -> void:
var mouse_pos := get_local_mouse_position() - location
if point_in_rectangle(mouse_pos, location, location + size):
mouse_pos = mouse_pos.floor()
if left_square_indicator_visible:
var start_pos_x = mouse_pos.x - (left_brush_size >> 1)
var start_pos_y = mouse_pos.y - (left_brush_size >> 1)
draw_rect(Rect2(start_pos_x, start_pos_y, left_brush_size, left_brush_size), Color.blue, false)
if right_square_indicator_visible:
var start_pos_x = mouse_pos.x - (right_brush_size >> 1)
var start_pos_y = mouse_pos.y - (right_brush_size >> 1)
draw_rect(Rect2(start_pos_x, start_pos_y, right_brush_size, right_brush_size), Color.red, false)
if Global.left_square_indicator_visible:
var start_pos_x = mouse_pos.x - (Global.left_brush_size >> 1)
var start_pos_y = mouse_pos.y - (Global.left_brush_size >> 1)
draw_rect(Rect2(start_pos_x, start_pos_y, Global.left_brush_size, Global.left_brush_size), Color.blue, false)
if Global.right_square_indicator_visible:
var start_pos_x = mouse_pos.x - (Global.right_brush_size >> 1)
var start_pos_y = mouse_pos.y - (Global.right_brush_size >> 1)
draw_rect(Rect2(start_pos_x, start_pos_y, Global.right_brush_size, Global.right_brush_size), Color.red, false)
func generate_layer_panels() -> void:
for child in Global.vbox_layer_container.get_children():
@ -155,6 +172,19 @@ func generate_layer_panels() -> void:
layer_container.get_child(0).get_child(1).texture = layers[i][1]
Global.vbox_layer_container.add_child(layer_container)
func camera_zoom() -> void:
#Set camera offset to the center of canvas
Global.camera.offset = size / 2
#Set camera zoom based on the sprite size
var bigger = max(size.x, size.y)
var zoom_max := Vector2(bigger, bigger) * 0.01
if zoom_max > Vector2.ONE:
Global.camera.zoom_max = zoom_max
else:
Global.camera.zoom_max = Vector2.ONE
Global.camera.zoom = Vector2(bigger, bigger) * 0.002
Global.zoom_level_label.text = "Zoom: x%s" % [stepify(1 / $"../Camera2D".zoom.x, 0.01)]
func pencil_and_eraser(mouse_pos : Vector2, color : Color, current_mouse_button : String) -> void:
if Input.is_key_pressed(KEY_SHIFT):
if !is_making_line:
@ -168,9 +198,9 @@ func pencil_and_eraser(mouse_pos : Vector2, color : Color, current_mouse_button
else:
var brush_size := 1
if current_mouse_button == "L":
brush_size = left_brush_size
brush_size = Global.left_brush_size
elif current_mouse_button == "R":
brush_size = right_brush_size
brush_size = Global.right_brush_size
if is_making_line:
fill_gaps(mouse_pos, color, brush_size)
@ -187,7 +217,7 @@ func pencil_and_eraser(mouse_pos : Vector2, color : Color, current_mouse_button
fill_gaps(mouse_pos, color, brush_size)
func draw_pixel(pos : Vector2, color : Color, brush_size : int) -> void:
if Global.can_draw && Global.has_focus:
if Global.can_draw && Global.has_focus && Global.current_frame == frame:
var start_pos_x = pos.x - (brush_size >> 1)
var start_pos_y = pos.y - (brush_size >> 1)
for cur_pos_x in range(start_pos_x, start_pos_x + brush_size):

8
Scripts/FrameButton.gd Normal file
View file

@ -0,0 +1,8 @@
extends Button
var frame := 0
func _on_FrameButton_pressed() -> void:
Global.current_frame = frame
#print(len(Global.canvases))
Global.change_frame()

View file

@ -1,22 +1,44 @@
extends Node
# warning-ignore:unused_class_variable
var current_frame := 0
# warning-ignore:unused_class_variable
var can_draw := false
# warning-ignore:unused_class_variable
var has_focus := true
# warning-ignore:unused_class_variable
var draw_grid := false
var canvases := []
var canvas : Canvas
var canvas_parent
var canvas_parent : Node
# warning-ignore:unused_class_variable
var left_square_indicator_visible := true
# warning-ignore:unused_class_variable
var right_square_indicator_visible := false
# warning-ignore:unused_class_variable
var left_brush_size := 1
# warning-ignore:unused_class_variable
var right_brush_size := 1
var camera : Camera2D
var left_color_picker : ColorPickerButton
var right_color_picker : ColorPickerButton
var file_menu : MenuButton
var edit_menu : MenuButton
var left_indicator : Sprite
var right_indicator : Sprite
var play_forward : Button
var play_backwards : Button
var frame_container : HBoxContainer
var remove_frame_button : Button
var move_left_frame_button : Button
var move_right_frame_button : Button
var vbox_layer_container : VBoxContainer
var remove_layer_button : Button
var move_up_layer_button : Button
var move_down_layer_button : Button
var merge_down_layer_button : Button
var cursor_position_label : Label
var zoom_level_label : Label
# warning-ignore:unused_class_variable
var current_left_tool := "Pencil"
# warning-ignore:unused_class_variable
@ -25,18 +47,28 @@ var current_right_tool := "Eraser"
func _ready() -> void:
var root = get_tree().get_root()
canvas = find_node_by_name(root, "Canvas")
canvases.append(canvas)
canvas_parent = canvas.get_parent()
camera = find_node_by_name(canvas_parent, "Camera2D")
left_color_picker = find_node_by_name(root, "LeftColorPickerButton")
right_color_picker = find_node_by_name(root, "RightColorPickerButton")
file_menu = find_node_by_name(root, "FileMenu")
edit_menu = find_node_by_name(root, "EditMenu")
left_indicator = find_node_by_name(root, "LeftIndicator")
right_indicator = find_node_by_name(root, "RightIndicator")
play_forward = find_node_by_name(root, "PlayForward")
play_backwards = find_node_by_name(root, "PlayBackwards")
frame_container = find_node_by_name(root, "FrameContainer")
remove_frame_button = find_node_by_name(root, "RemoveFrame")
move_left_frame_button = find_node_by_name(root, "MoveFrameLeft")
move_right_frame_button = find_node_by_name(root, "MoveFrameRight")
vbox_layer_container = find_node_by_name(root, "VBoxLayerContainer")
remove_layer_button = find_node_by_name(root, "RemoveLayerButton")
move_up_layer_button = find_node_by_name(root, "MoveUpLayer")
move_down_layer_button = find_node_by_name(root, "MoveDownLayer")
merge_down_layer_button = find_node_by_name(root, "MergeDownLayer")
cursor_position_label = find_node_by_name(root, "CursorPosition")
zoom_level_label = find_node_by_name(root, "ZoomLevel")
#Thanks to https://godotengine.org/qa/17524/how-to-find-an-instanced-scene-by-its-name
func find_node_by_name(root, node_name) -> Node:
@ -48,4 +80,27 @@ func find_node_by_name(root, node_name) -> Node:
var found = find_node_by_name(child, node_name)
if found:
return found
return null
return null
func change_frame() -> void:
for c in canvases:
c.visible = false
canvas = canvases[current_frame]
canvas.visible = true
canvas.generate_layer_panels()
handle_layer_order_buttons()
func handle_layer_order_buttons() -> void:
if current_frame == 0:
move_left_frame_button.disabled = true
move_left_frame_button.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN
else:
move_left_frame_button.disabled = false
move_left_frame_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
if current_frame == canvases.size() - 1:
move_right_frame_button.disabled = true
move_right_frame_button.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN
else:
move_right_frame_button.disabled = false
move_right_frame_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND

View file

@ -5,21 +5,30 @@ var opensprite_file_selected := false
var pencil_tool
var eraser_tool
var fill_tool
var export_all_frames : CheckButton
var export_as_single_file : CheckButton
var export_vertical_spritesheet : CheckButton
var fps := 1.0
var animation_loop := false
var animation_forward := true
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
var file_menu_items := {
"New..." : KEY_MASK_CTRL + KEY_N,
#The import and export key shortcuts will change,
#and they will be bound to Open and Save/Save as once I
#make a custom file for Pixelorama projects
"Import..." : KEY_MASK_CTRL + KEY_O,
"Export..." : KEY_MASK_CTRL + KEY_S,
"Export as..." : KEY_MASK_SHIFT + KEY_MASK_CTRL + KEY_S,
"Quit" : KEY_MASK_CTRL + KEY_Q
}
var edit_menu_items := {
"Scale Image" : 0,
"Show Grid" : KEY_MASK_CTRL + KEY_G
#"Undo" : KEY_MASK_CTRL + KEY_Z,
#"Redo" : KEY_MASK_SHIFT + KEY_MASK_CTRL + KEY_Z,
#"Scale Image" : 0
}
var file_menu : PopupMenu = Global.file_menu.get_popup()
var edit_menu : PopupMenu = Global.edit_menu.get_popup()
@ -42,6 +51,16 @@ func _ready() -> void:
eraser_tool.connect("pressed", self, "_on_Tool_pressed", [eraser_tool])
fill_tool.connect("pressed", self, "_on_Tool_pressed", [fill_tool])
export_all_frames = CheckButton.new()
export_all_frames.text = "Export all frames?"
export_as_single_file = CheckButton.new()
export_as_single_file.text = "Export frames as a single file?"
export_vertical_spritesheet = CheckButton.new()
export_vertical_spritesheet.text = "Vertical spritesheet?"
$SaveSprite.get_vbox().add_child(export_all_frames)
$SaveSprite.get_vbox().add_child(export_as_single_file)
$SaveSprite.get_vbox().add_child(export_vertical_spritesheet)
func _input(event):
#Handle tool shortcuts
if event.is_action_pressed("right_pencil_tool"):
@ -57,6 +76,7 @@ func _input(event):
elif event.is_action_pressed("left_fill_tool"):
_on_Tool_pressed(fill_tool, false, true)
func file_menu_id_pressed(id : int) -> void:
match id:
0: #New
@ -71,7 +91,7 @@ func file_menu_id_pressed(id : int) -> void:
$SaveSprite.popup_centered()
Global.can_draw = false
else:
save_sprite()
export_project()
3: #Export as
$SaveSprite.popup_centered()
Global.can_draw = false
@ -80,58 +100,165 @@ func file_menu_id_pressed(id : int) -> void:
func edit_menu_id_pressed(id : int) -> void:
match id:
0: #Show grid
Global.canvas.draw_grid = !Global.canvas.draw_grid
0: #Scale Image
$ScaleImage.popup_centered()
Global.can_draw = false
1: #Show grid
Global.draw_grid = !Global.draw_grid
func _on_CreateNewImage_confirmed() -> void:
var width = float($CreateNewImage/VBoxContainer/WidthCont/LineEdit.text)
var height = float($CreateNewImage/VBoxContainer/HeightCont/LineEdit.text)
width = clamp(width, 1, 16384)
height = clamp(height, 1, 16384)
var width = float($CreateNewImage/VBoxContainer/WidthCont/WidthValue.value)
var height = float($CreateNewImage/VBoxContainer/HeightCont/HeightValue.value)
new_canvas(Vector2(width, height).floor())
func _on_OpenSprite_file_selected(path : String) -> void:
var image = Image.new()
var err = image.load(path)
if err == OK:
opensprite_file_selected = true
new_canvas(image.get_size(), image)
else:
OS.alert("Can't load file")
#func _on_OpenSprite_file_selected(path : String) -> void:
# var image = Image.new()
# var err = image.load(path)
# if err == OK:
# opensprite_file_selected = true
# new_canvas(image.get_size(), image)
# else:
# OS.alert("Can't load file")
func new_canvas(size : Vector2, sprite : Image = null) -> void:
var left_indicator_visible = Global.canvas.left_square_indicator_visible
var right_indicator_visible = Global.canvas.right_square_indicator_visible
var left_brush_size = Global.canvas.left_brush_size
var right_brush_size = Global.canvas.right_brush_size
func _on_OpenSprite_files_selected(paths) -> void:
for child in Global.vbox_layer_container.get_children():
if child is PanelContainer:
child.queue_free()
Global.canvas.queue_free()
for child in Global.frame_container.get_children():
child.queue_free()
for child in Global.canvas_parent.get_children():
if child is Canvas:
child.queue_free()
Global.canvases.clear()
#Find the biggest image and let it handle the camera zoom options
var max_size : Vector2
var biggest_canvas : Canvas
var i := 0
for path in paths:
var image = Image.new()
var err = image.load(path)
if err == OK:
opensprite_file_selected = true
var canvas : Canvas = load("res://Canvas.tscn").instance()
canvas.size = image.get_size()
image.convert(Image.FORMAT_RGBA8)
image.lock()
var tex := ImageTexture.new()
tex.create_from_image(image, 0)
#Store [Image, ImageTexture, Layer Name, Visibity boolean]
canvas.layers.append([image, tex, "Layer 0", true])
canvas.frame = i
Global.canvas_parent.add_child(canvas)
Global.canvases.append(canvas)
canvas.visible = false
if i == 0:
max_size = canvas.size
biggest_canvas = canvas
else:
if canvas.size > max_size:
biggest_canvas = canvas
else:
OS.alert("Can't load file")
i += 1
Global.current_frame = i - 1
Global.canvas = Global.canvases[Global.canvases.size() - 1]
Global.canvas.visible = true
Global.handle_layer_order_buttons()
biggest_canvas.camera_zoom()
if i > 1:
Global.remove_frame_button.disabled = false
Global.remove_frame_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
else:
Global.remove_frame_button.disabled = true
Global.remove_frame_button.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN
func new_canvas(size : Vector2, sprite : Image = null) -> void:
for child in Global.vbox_layer_container.get_children():
if child is PanelContainer:
child.queue_free()
for child in Global.frame_container.get_children():
child.queue_free()
for child in Global.canvas_parent.get_children():
if child is Canvas:
child.queue_free()
Global.canvases.clear()
Global.canvas = load("res://Canvas.tscn").instance()
Global.canvas.size = size
Global.canvas.left_square_indicator_visible = left_indicator_visible
Global.canvas.right_square_indicator_visible = right_indicator_visible
Global.canvas.left_brush_size = left_brush_size
Global.canvas.right_brush_size = right_brush_size
if sprite:
Global.canvas.current_sprite = sprite
Global.canvas.current_sprite.convert(Image.FORMAT_RGBA8)
# if sprite:
# var layer0 := sprite
# layer0.convert(Image.FORMAT_RGBA8)
# var tex := ImageTexture.new()
# tex.create_from_image(layer0, 0)
# #Store [Image, ImageTexture, Layer Name, Visibity boolean]
# Global.canvas.layers.append([layer0, tex, "Layer 0", true])
Global.canvas_parent.add_child(Global.canvas)
Global.canvases.append(Global.canvas)
Global.current_frame = 0
Global.remove_frame_button.disabled = true
Global.remove_frame_button.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN
func _on_SaveSprite_file_selected(path : String) -> void:
current_path = path
save_sprite()
export_project()
func save_sprite() -> void:
func export_project() -> void:
if export_all_frames.pressed:
if !export_as_single_file.pressed:
var i := 0
for canvas in Global.canvases:
var path := "%s_%s" % [current_path, str(i)]
path = path.replace(".png", "")
path = "%s.png" % path
save_sprite(canvas, path)
i += 1
else:
save_spritesheet()
else:
save_sprite(Global.canvas, current_path)
func save_sprite(canvas : Canvas, path : String) -> void:
var whole_image := Image.new()
whole_image.create(Global.canvas.size.x, Global.canvas.size.y, false, Image.FORMAT_RGBA8)
for layer in Global.canvas.layers:
whole_image.blend_rect(layer[0], Rect2(Global.canvas.position, Global.canvas.size), Vector2.ZERO)
whole_image.create(canvas.size.x, canvas.size.y, false, Image.FORMAT_RGBA8)
for layer in canvas.layers:
whole_image.blend_rect(layer[0], Rect2(canvas.position, canvas.size), Vector2.ZERO)
layer[0].lock()
#var err = Global.canvas.current_sprite.save_png(current_path)
var err = whole_image.save_png(path)
if err != OK:
OS.alert("Can't save file")
func save_spritesheet() -> void:
var width
var height
if export_vertical_spritesheet.pressed:
width = Global.canvas.size.x
height = 0
for canvas in Global.canvases:
height += canvas.size.y
if canvas.size.x > width:
width = canvas.size.x
else:
width = 0
height = Global.canvas.size.y
for canvas in Global.canvases:
width += canvas.size.x
if canvas.size.y > height:
height = canvas.size.y
var whole_image := Image.new()
whole_image.create(width, height, false, Image.FORMAT_RGBA8)
var dst := Vector2.ZERO
for canvas in Global.canvases:
for layer in canvas.layers:
whole_image.blend_rect(layer[0], Rect2(canvas.position, canvas.size), dst)
layer[0].lock()
if export_vertical_spritesheet.pressed:
dst += Vector2(0, canvas.size.y)
else:
dst += Vector2(canvas.size.x, 0)
var err = whole_image.save_png(current_path)
if err != OK:
OS.alert("Can't save file")
@ -163,22 +290,19 @@ func _on_Tool_pressed(tool_pressed : BaseButton, mouse_press := true, key_for_le
Global.right_indicator.get_parent().remove_child(Global.right_indicator)
tool_pressed.add_child(Global.right_indicator)
func _on_ScaleImage_confirmed() -> void:
var width = float($ScaleImage/VBoxContainer/WidthCont/LineEdit.text)
var height = float($ScaleImage/VBoxContainer/HeightCont/LineEdit.text)
width = clamp(width, 1, 16384)
height = clamp(height, 1, 16384)
#var sprites := []
var width = float($ScaleImage/VBoxContainer/WidthCont/WidthValue.value)
var height = float($ScaleImage/VBoxContainer/HeightCont/HeightValue.value)
for i in range(Global.canvas.layers.size() - 1, -1, -1):
var sprite = Image.new()
sprite = Global.canvas.layers[i][1].get_data()
sprite.resize(width, height)
sprite.resize(width, height, $ScaleImage/VBoxContainer/InterpolationContainer/InterpolationType.selected)
Global.canvas.layers[i][0] = sprite
Global.canvas.layers[i][0].lock()
Global.canvas.update_texture(i)
Global.canvas.size = Vector2(width, height).floor()
Global.canvas.camera_zoom()
func add_layer(is_new := true) -> void:
var new_layer := Image.new()
@ -226,16 +350,164 @@ func _on_MergeLayer_pressed() -> void:
Global.canvas.update_texture(Global.canvas.current_layer_index - 1)
_on_RemoveLayerButton_pressed()
func _on_LeftIndicatorCheckbox_toggled(button_pressed):
Global.canvas.left_square_indicator_visible = button_pressed
func _on_LeftIndicatorCheckbox_toggled(button_pressed) -> void:
Global.left_square_indicator_visible = button_pressed
func _on_RightIndicatorCheckbox_toggled(button_pressed):
Global.canvas.right_square_indicator_visible = button_pressed
func _on_RightIndicatorCheckbox_toggled(button_pressed) -> void:
Global.right_square_indicator_visible = button_pressed
func _on_LeftBrushSizeEdit_value_changed(value):
func _on_LeftBrushSizeEdit_value_changed(value) -> void:
var new_size = int(value)
Global.canvas.left_brush_size = new_size
Global.left_brush_size = new_size
func _on_RightBrushSizeEdit_value_changed(value):
func _on_RightBrushSizeEdit_value_changed(value) -> void:
var new_size = int(value)
Global.canvas.right_brush_size = new_size
Global.right_brush_size = new_size
func _on_AddFrame_pressed() -> void:
var canvas = load("res://Canvas.tscn").instance()
canvas.size = Global.canvas.size
Global.current_frame = Global.canvases.size()
canvas.frame = Global.current_frame
for canvas in Global.canvases:
canvas.visible = false
Global.canvases.append(canvas)
Global.canvas = canvas
Global.canvas_parent.add_child(canvas)
Global.remove_frame_button.disabled = false
Global.remove_frame_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
Global.move_left_frame_button.disabled = false
Global.move_left_frame_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
func _on_RemoveFrame_pressed() -> void:
Global.canvas.frame_button.queue_free()
Global.canvas.queue_free()
Global.canvases.remove(Global.current_frame)
for canvas in Global.canvases:
if canvas.frame > Global.current_frame:
canvas.frame -= 1
canvas.frame_button.get_node("FrameButton").frame = canvas.frame
canvas.frame_button.get_node("FrameID").text = str(canvas.frame)
if Global.current_frame > 0:
Global.current_frame -= 1
if len(Global.canvases) == 1:
Global.remove_frame_button.disabled = true
Global.remove_frame_button.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN
Global.canvas = Global.canvases[Global.current_frame]
Global.canvas.visible = true
Global.canvas.generate_layer_panels()
Global.handle_layer_order_buttons()
func _on_CloneFrame_pressed() -> void:
var canvas = load("res://Canvas.tscn").instance()
canvas.size = Global.canvas.size
#canvas.layers = Global.canvas.layers.duplicate(true)
for layer in Global.canvas.layers:
var sprite := Image.new()
sprite.copy_from(layer[0])
sprite.lock()
var tex := ImageTexture.new()
tex.create_from_image(sprite, 0)
canvas.layers.append([sprite, tex, layer[2], layer[3]])
Global.current_frame = Global.canvases.size()
canvas.frame = Global.current_frame
for canvas in Global.canvases:
canvas.visible = false
Global.canvases.append(canvas)
Global.canvas = canvas
Global.canvas_parent.add_child(canvas)
Global.remove_frame_button.disabled = false
Global.remove_frame_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
Global.move_left_frame_button.disabled = false
Global.move_left_frame_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
func _on_MoveFrameLeft_pressed() -> void:
change_frame_order(-1)
func _on_MoveFrameRight_pressed() -> void:
change_frame_order(1)
func change_frame_order(rate : int) -> void:
var frame_button = Global.frame_container.get_node("Frame_%s" % Global.current_frame)
var change = Global.current_frame + rate
var temp = Global.canvases[Global.current_frame]
Global.canvases[Global.current_frame] = Global.canvases[change]
Global.canvases[change] = temp
#Clear frame button names first, to avoid duplicates like two Frame_0s
for canvas in Global.canvases:
canvas.frame_button.name = "frame"
for canvas in Global.canvases:
canvas.frame = Global.canvases.find(canvas)
canvas.frame_button.name = "Frame_%s" % canvas.frame
canvas.frame_button.get_node("FrameButton").frame = canvas.frame
canvas.frame_button.get_node("FrameID").text = str(canvas.frame)
Global.current_frame = change
Global.frame_container.move_child(frame_button, Global.current_frame)
Global.canvas_parent.move_child(Global.canvas, Global.current_frame)
#Global.canvas.generate_layer_panels()
Global.handle_layer_order_buttons()
func _on_PlayForward_toggled(button_pressed) -> void:
Global.play_backwards.pressed = false
Global.play_backwards.text = "Play Backwards"
if button_pressed:
Global.play_forward.text = "Stop"
$AnimationTimer.wait_time = 1 / fps
$AnimationTimer.start()
animation_forward = true
else:
Global.play_forward.text = "Play Forward"
$AnimationTimer.stop()
func _on_PlayBackwards_toggled(button_pressed) -> void:
Global.play_forward.pressed = false
Global.play_forward.text = "Play Forward"
if button_pressed:
Global.play_backwards.text = "Stop"
$AnimationTimer.wait_time = 1 / fps
$AnimationTimer.start()
animation_forward = false
else:
Global.play_backwards.text = "Play Backwards"
$AnimationTimer.stop()
func _on_AnimationTimer_timeout() -> void:
if animation_forward:
if Global.current_frame < Global.canvases.size() - 1:
Global.current_frame += 1
else:
if animation_loop:
Global.current_frame = 0
else:
Global.play_forward.pressed = false
Global.play_forward.text = "Play Forward"
$AnimationTimer.stop()
else:
if Global.current_frame > 0:
Global.current_frame -= 1
else:
if animation_loop:
Global.current_frame = Global.canvases.size() - 1
else:
Global.play_backwards.pressed = false
Global.play_backwards.text = "Play Backwards"
$AnimationTimer.stop()
Global.change_frame()
func _on_FPSValue_value_changed(value) -> void:
fps = float(value)
$AnimationTimer.wait_time = 1 / fps
func _on_LoopAnim_toggled(button_pressed) -> void:
animation_loop = button_pressed