mirror of
https://github.com/tonytins/CozyPixelStudio.git
synced 2025-06-25 05:24:43 -04:00
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:
parent
1f80291a4b
commit
5781c42821
25 changed files with 765 additions and 183 deletions
|
@ -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)]
|
|
@ -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
8
Scripts/FrameButton.gd
Normal 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()
|
|
@ -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
|
376
Scripts/Main.gd
376
Scripts/Main.gd
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue