mirror of
https://github.com/tonytins/CozyPixelStudio.git
synced 2025-06-25 12:04:43 -04:00
Merge pull request #170 from Orama-Interactive/new-timeline
Merge the new timeline into master
This commit is contained in:
commit
65544dcfc1
16 changed files with 935 additions and 840 deletions
|
@ -23,10 +23,7 @@ func add_frame() -> void:
|
|||
Global.undo_redo.add_do_property(Global, "hidden_canvases", Global.hidden_canvases)
|
||||
Global.undo_redo.add_do_property(Global, "canvas", new_canvas)
|
||||
Global.undo_redo.add_do_property(Global, "current_frame", new_canvases.size() - 1)
|
||||
for child in Global.frame_container.get_children():
|
||||
var frame_button = child.get_node("FrameButton")
|
||||
Global.undo_redo.add_do_property(frame_button, "pressed", false)
|
||||
Global.undo_redo.add_undo_property(frame_button, "pressed", frame_button.pressed)
|
||||
|
||||
for c in Global.canvases:
|
||||
Global.undo_redo.add_do_property(c, "visible", false)
|
||||
Global.undo_redo.add_undo_property(c, "visible", c.visible)
|
||||
|
@ -39,18 +36,15 @@ func add_frame() -> void:
|
|||
|
||||
func _on_LoopAnim_pressed() -> void:
|
||||
match animation_loop:
|
||||
0:
|
||||
# Make it loop
|
||||
0: # Make it loop
|
||||
animation_loop = 1
|
||||
Global.loop_animation_button.texture_normal = load("res://Assets/Graphics/%s Themes/Timeline/Loop.png" % Global.theme_type)
|
||||
Global.loop_animation_button.hint_tooltip = "Cycle loop"
|
||||
1:
|
||||
# Make it ping-pong
|
||||
1: # Make it ping-pong
|
||||
animation_loop = 2
|
||||
Global.loop_animation_button.texture_normal = load("res://Assets/Graphics/%s Themes/Timeline/Loop_PingPong.png" % Global.theme_type)
|
||||
Global.loop_animation_button.hint_tooltip = "Ping-pong loop"
|
||||
2:
|
||||
# Make it stop
|
||||
2: # Make it stop
|
||||
animation_loop = 0
|
||||
Global.loop_animation_button.texture_normal = load("res://Assets/Graphics/%s Themes/Timeline/Loop_None.png" % Global.theme_type)
|
||||
Global.loop_animation_button.hint_tooltip = "No loop"
|
||||
|
@ -101,13 +95,13 @@ func _on_AnimationTimer_timeout() -> void:
|
|||
Global.current_frame += 1
|
||||
else:
|
||||
match animation_loop:
|
||||
0: #No loop
|
||||
0: # No loop
|
||||
Global.play_forward.pressed = false
|
||||
Global.play_backwards.pressed = false
|
||||
Global.animation_timer.stop()
|
||||
1: #Cycle loop
|
||||
1: # Cycle loop
|
||||
Global.current_frame = 0
|
||||
2: #Ping pong loop
|
||||
2: # Ping pong loop
|
||||
animation_forward = false
|
||||
_on_AnimationTimer_timeout()
|
||||
|
||||
|
@ -116,13 +110,13 @@ func _on_AnimationTimer_timeout() -> void:
|
|||
Global.current_frame -= 1
|
||||
else:
|
||||
match animation_loop:
|
||||
0: #No loop
|
||||
0: # No loop
|
||||
Global.play_backwards.pressed = false
|
||||
Global.play_forward.pressed = false
|
||||
Global.animation_timer.stop()
|
||||
1: #Cycle loop
|
||||
1: # Cycle loop
|
||||
Global.current_frame = Global.canvases.size() - 1
|
||||
2: #Ping pong loop
|
||||
2: # Ping pong loop
|
||||
animation_forward = true
|
||||
_on_AnimationTimer_timeout()
|
||||
|
||||
|
@ -142,3 +136,134 @@ func _on_FutureOnionSkinning_value_changed(value) -> void:
|
|||
func _on_BlueRedMode_toggled(button_pressed) -> void:
|
||||
Global.onion_skinning_blue_red = button_pressed
|
||||
Global.canvas.update()
|
||||
|
||||
# Layer buttons
|
||||
|
||||
func add_layer(is_new := true) -> void:
|
||||
var layer_name = null
|
||||
if !is_new: # clone layer
|
||||
layer_name = Global.layers[Global.current_layer][0] + " (" + tr("copy") + ")"
|
||||
|
||||
var new_layers : Array = Global.layers.duplicate()
|
||||
|
||||
# Store [Layer name, Layer visibility boolean, Frame container]
|
||||
new_layers.append([layer_name, true, HBoxContainer.new()])
|
||||
|
||||
Global.undos += 1
|
||||
Global.undo_redo.create_action("Add Layer")
|
||||
|
||||
for c in Global.canvases:
|
||||
var new_layer := Image.new()
|
||||
if is_new:
|
||||
new_layer.create(c.size.x, c.size.y, false, Image.FORMAT_RGBA8)
|
||||
else: # clone layer
|
||||
new_layer.copy_from(c.layers[Global.current_layer][0])
|
||||
|
||||
new_layer.lock()
|
||||
var new_layer_tex := ImageTexture.new()
|
||||
new_layer_tex.create_from_image(new_layer, 0)
|
||||
|
||||
var new_canvas_layers : Array = c.layers.duplicate()
|
||||
# Store [Image, ImageTexture, Opacity]
|
||||
new_canvas_layers.append([new_layer, new_layer_tex, 1])
|
||||
Global.undo_redo.add_do_property(c, "layers", new_canvas_layers)
|
||||
Global.undo_redo.add_undo_property(c, "layers", c.layers)
|
||||
|
||||
Global.undo_redo.add_do_property(Global, "current_layer", Global.current_layer + 1)
|
||||
Global.undo_redo.add_do_property(Global, "layers", new_layers)
|
||||
Global.undo_redo.add_undo_property(Global, "current_layer", Global.current_layer)
|
||||
Global.undo_redo.add_undo_property(Global, "layers", Global.layers)
|
||||
|
||||
Global.undo_redo.add_undo_method(Global, "undo", [Global.canvas])
|
||||
Global.undo_redo.add_do_method(Global, "redo", [Global.canvas])
|
||||
Global.undo_redo.commit_action()
|
||||
|
||||
func _on_RemoveLayer_pressed() -> void:
|
||||
var new_layers : Array = Global.layers.duplicate()
|
||||
new_layers.remove(Global.current_layer)
|
||||
Global.undos += 1
|
||||
Global.undo_redo.create_action("Remove Layer")
|
||||
if Global.current_layer > 0:
|
||||
Global.undo_redo.add_do_property(Global, "current_layer", Global.current_layer - 1)
|
||||
else:
|
||||
Global.undo_redo.add_do_property(Global, "current_layer", Global.current_layer)
|
||||
|
||||
for c in Global.canvases:
|
||||
var new_canvas_layers : Array = c.layers.duplicate()
|
||||
new_canvas_layers.remove(Global.current_layer)
|
||||
Global.undo_redo.add_do_property(c, "layers", new_canvas_layers)
|
||||
Global.undo_redo.add_undo_property(c, "layers", c.layers)
|
||||
|
||||
Global.undo_redo.add_do_property(Global, "layers", new_layers)
|
||||
Global.undo_redo.add_undo_property(Global, "current_layer", Global.current_layer)
|
||||
Global.undo_redo.add_undo_property(Global, "layers", Global.layers)
|
||||
Global.undo_redo.add_do_method(Global, "redo", [Global.canvas])
|
||||
Global.undo_redo.add_undo_method(Global, "undo", [Global.canvas])
|
||||
Global.undo_redo.commit_action()
|
||||
|
||||
func change_layer_order(rate : int) -> void:
|
||||
var change = Global.current_layer + rate
|
||||
|
||||
var new_layers : Array = Global.layers.duplicate()
|
||||
var temp = new_layers[Global.current_layer]
|
||||
new_layers[Global.current_layer] = new_layers[change]
|
||||
new_layers[change] = temp
|
||||
Global.undo_redo.create_action("Change Layer Order")
|
||||
for c in Global.canvases:
|
||||
var new_layers_canvas : Array = c.layers.duplicate()
|
||||
var temp_canvas = new_layers_canvas[Global.current_layer]
|
||||
new_layers_canvas[Global.current_layer] = new_layers_canvas[change]
|
||||
new_layers_canvas[change] = temp_canvas
|
||||
Global.undo_redo.add_do_property(c, "layers", new_layers_canvas)
|
||||
Global.undo_redo.add_undo_property(c, "layers", c.layers)
|
||||
|
||||
Global.undo_redo.add_do_property(Global, "current_layer", change)
|
||||
Global.undo_redo.add_do_property(Global, "layers", new_layers)
|
||||
Global.undo_redo.add_undo_property(Global, "layers", Global.layers)
|
||||
Global.undo_redo.add_undo_property(Global, "current_layer", Global.current_layer)
|
||||
|
||||
Global.undo_redo.add_undo_method(Global, "undo", [Global.canvas])
|
||||
Global.undo_redo.add_do_method(Global, "redo", [Global.canvas])
|
||||
Global.undo_redo.commit_action()
|
||||
|
||||
func _on_MergeDownLayer_pressed() -> void:
|
||||
var new_layers : Array = Global.layers.duplicate()
|
||||
new_layers.remove(Global.current_layer)
|
||||
|
||||
Global.undos += 1
|
||||
Global.undo_redo.create_action("Merge Layer")
|
||||
for c in Global.canvases:
|
||||
var new_layers_canvas : Array = c.layers.duplicate()
|
||||
new_layers_canvas.remove(Global.current_layer)
|
||||
var selected_layer = c.layers[Global.current_layer][0]
|
||||
if c.layers[Global.current_layer][2] < 1: # If we have layer transparency
|
||||
for xx in selected_layer.get_size().x:
|
||||
for yy in selected_layer.get_size().y:
|
||||
var pixel_color : Color = selected_layer.get_pixel(xx, yy)
|
||||
var alpha : float = pixel_color.a * c.layers[Global.current_layer][4]
|
||||
selected_layer.set_pixel(xx, yy, Color(pixel_color.r, pixel_color.g, pixel_color.b, alpha))
|
||||
|
||||
var new_layer := Image.new()
|
||||
new_layer.copy_from(c.layers[Global.current_layer - 1][0])
|
||||
new_layer.lock()
|
||||
c.blend_rect(new_layer, selected_layer, Rect2(c.position, c.size), Vector2.ZERO)
|
||||
|
||||
Global.undo_redo.add_do_property(c, "layers", new_layers_canvas)
|
||||
Global.undo_redo.add_do_property(c.layers[Global.current_layer - 1][0], "data", new_layer.data)
|
||||
Global.undo_redo.add_undo_property(c, "layers", c.layers)
|
||||
Global.undo_redo.add_undo_property(c.layers[Global.current_layer - 1][0], "data", c.layers[Global.current_layer - 1][0].data)
|
||||
|
||||
Global.undo_redo.add_do_property(Global, "current_layer", Global.current_layer - 1)
|
||||
Global.undo_redo.add_do_property(Global, "layers", new_layers)
|
||||
Global.undo_redo.add_undo_property(Global, "layers", Global.layers)
|
||||
Global.undo_redo.add_undo_property(Global, "current_layer", Global.current_layer)
|
||||
|
||||
Global.undo_redo.add_undo_method(Global, "undo", [Global.canvas])
|
||||
Global.undo_redo.add_do_method(Global, "redo", [Global.canvas])
|
||||
Global.undo_redo.commit_action()
|
||||
|
||||
func _on_OpacitySlider_value_changed(value) -> void:
|
||||
Global.canvas.layers[Global.current_layer][2] = value / 100
|
||||
Global.layer_opacity_slider.value = value
|
||||
Global.layer_opacity_spinbox.value = value
|
||||
Global.canvas.update()
|
||||
|
|
|
@ -6,9 +6,7 @@ var current_layer_index := 0
|
|||
var location := Vector2.ZERO
|
||||
var size := Vector2(64, 64)
|
||||
var fill_color := Color(0, 0, 0, 0)
|
||||
var frame := 0 setget frame_changed
|
||||
var frame_button : VBoxContainer
|
||||
var frame_texture_rect : TextureRect
|
||||
var frame := 0
|
||||
var current_pixel := Vector2.ZERO # pretty much same as mouse_pos, but can be accessed externally
|
||||
var previous_mouse_pos := Vector2.ZERO
|
||||
var previous_mouse_pos_for_lines := Vector2.ZERO
|
||||
|
@ -31,40 +29,29 @@ var pen_pressure := 1.0 # For tablet pressure sensitivity
|
|||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
# The sprite itself
|
||||
if layers.empty():
|
||||
var sprite := Image.new()
|
||||
if Global.is_default_image:
|
||||
if Global.config_cache.has_section_key("preferences", "default_width"):
|
||||
size.x = Global.config_cache.get_value("preferences", "default_width")
|
||||
if Global.config_cache.has_section_key("preferences", "default_height"):
|
||||
size.y = Global.config_cache.get_value("preferences", "default_height")
|
||||
if Global.config_cache.has_section_key("preferences", "default_fill_color"):
|
||||
fill_color = Global.config_cache.get_value("preferences", "default_fill_color")
|
||||
Global.is_default_image = !Global.is_default_image
|
||||
var fill_layers := layers.empty()
|
||||
for l in Global.layers:
|
||||
if fill_layers:
|
||||
# The sprite itself
|
||||
var sprite := Image.new()
|
||||
if Global.is_default_image:
|
||||
if Global.config_cache.has_section_key("preferences", "default_width"):
|
||||
size.x = Global.config_cache.get_value("preferences", "default_width")
|
||||
if Global.config_cache.has_section_key("preferences", "default_height"):
|
||||
size.y = Global.config_cache.get_value("preferences", "default_height")
|
||||
if Global.config_cache.has_section_key("preferences", "default_fill_color"):
|
||||
fill_color = Global.config_cache.get_value("preferences", "default_fill_color")
|
||||
Global.is_default_image = !Global.is_default_image
|
||||
|
||||
sprite.create(size.x, size.y, false, Image.FORMAT_RGBA8)
|
||||
sprite.fill(fill_color)
|
||||
sprite.lock()
|
||||
sprite.create(size.x, size.y, false, Image.FORMAT_RGBA8)
|
||||
sprite.fill(fill_color)
|
||||
sprite.lock()
|
||||
|
||||
var tex := ImageTexture.new()
|
||||
tex.create_from_image(sprite, 0)
|
||||
var tex := ImageTexture.new()
|
||||
tex.create_from_image(sprite, 0)
|
||||
|
||||
# Store [Image, ImageTexture, Layer Name, Visibity boolean, Opacity]
|
||||
layers.append([sprite, tex, tr("Layer") + " 0", true, 1])
|
||||
|
||||
generate_layer_panels()
|
||||
|
||||
frame_button = load("res://Prefabs/FrameButton.tscn").instance()
|
||||
frame_button.name = "Frame_%s" % frame
|
||||
frame_button.get_node("FrameButton").frame = frame
|
||||
frame_button.get_node("FrameButton").pressed = true
|
||||
frame_button.get_node("FrameID").text = str(frame + 1)
|
||||
frame_button.get_node("FrameID").add_color_override("font_color", Color("#3c5d75"))
|
||||
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
|
||||
# Store [Image, ImageTexture, Opacity]
|
||||
layers.append([sprite, tex, 1])
|
||||
|
||||
# Only handle camera zoom settings & offset on the first frame
|
||||
if Global.canvases[0] == self:
|
||||
|
@ -79,8 +66,8 @@ func _ready() -> void:
|
|||
|
||||
func _draw() -> void:
|
||||
draw_texture_rect(Global.transparent_background, Rect2(location, size), true) #Draw transparent background
|
||||
#Onion Skinning
|
||||
#Past
|
||||
# Onion Skinning
|
||||
# Past
|
||||
if Global.onion_skinning_past_rate > 0:
|
||||
var color : Color
|
||||
if Global.onion_skinning_blue_red:
|
||||
|
@ -89,11 +76,14 @@ func _draw() -> void:
|
|||
color = Color.white
|
||||
for i in range(1, Global.onion_skinning_past_rate + 1):
|
||||
if Global.current_frame >= i:
|
||||
for texture in Global.canvases[Global.current_frame - i].layers:
|
||||
color.a = 0.6/i
|
||||
draw_texture(texture[1], location, color)
|
||||
var layer_i := 0
|
||||
for layer in Global.canvases[Global.current_frame - i].layers:
|
||||
if Global.layers[layer_i][1]: # If it's visible
|
||||
color.a = 0.6 / i
|
||||
draw_texture(layer[1], location, color)
|
||||
layer_i += 1
|
||||
|
||||
#Future
|
||||
# Future
|
||||
if Global.onion_skinning_future_rate > 0:
|
||||
var color : Color
|
||||
if Global.onion_skinning_blue_red:
|
||||
|
@ -102,34 +92,37 @@ func _draw() -> void:
|
|||
color = Color.white
|
||||
for i in range(1, Global.onion_skinning_future_rate + 1):
|
||||
if Global.current_frame < Global.canvases.size() - i:
|
||||
for texture in Global.canvases[Global.current_frame + i].layers:
|
||||
color.a = 0.6/i
|
||||
draw_texture(texture[1], location, color)
|
||||
var layer_i := 0
|
||||
for layer in Global.canvases[Global.current_frame + i].layers:
|
||||
if Global.layers[layer_i][1]: # If it's visible
|
||||
color.a = 0.6 / i
|
||||
draw_texture(layer[1], location, color)
|
||||
layer_i += 1
|
||||
|
||||
#Draw current frame layers
|
||||
for texture in layers:
|
||||
var modulate_color := Color(1, 1, 1, texture[4])
|
||||
if texture[3]: #if it's visible
|
||||
draw_texture(texture[1], location, modulate_color)
|
||||
# Draw current frame layers
|
||||
for i in range(layers.size()):
|
||||
var modulate_color := Color(1, 1, 1, layers[i][2])
|
||||
if Global.layers[i][1]: # if it's visible
|
||||
draw_texture(layers[i][1], location, modulate_color)
|
||||
|
||||
if Global.tile_mode:
|
||||
draw_texture(texture[1], Vector2(location.x, location.y + size.y), modulate_color) #Down
|
||||
draw_texture(texture[1], Vector2(location.x - size.x, location.y + size.y), modulate_color) #Down Left
|
||||
draw_texture(texture[1], Vector2(location.x - size.x, location.y), modulate_color) #Left
|
||||
draw_texture(texture[1], location - size, modulate_color) #Up left
|
||||
draw_texture(texture[1], Vector2(location.x, location.y - size.y), modulate_color) #Up
|
||||
draw_texture(texture[1], Vector2(location.x + size.x, location.y - size.y), modulate_color) #Up right
|
||||
draw_texture(texture[1], Vector2(location.x + size.x, location.y), modulate_color) #Right
|
||||
draw_texture(texture[1], location + size, modulate_color) #Down right
|
||||
draw_texture(layers[i][1], Vector2(location.x, location.y + size.y), modulate_color) #Down
|
||||
draw_texture(layers[i][1], Vector2(location.x - size.x, location.y + size.y), modulate_color) #Down Left
|
||||
draw_texture(layers[i][1], Vector2(location.x - size.x, location.y), modulate_color) #Left
|
||||
draw_texture(layers[i][1], location - size, modulate_color) #Up left
|
||||
draw_texture(layers[i][1], Vector2(location.x, location.y - size.y), modulate_color) #Up
|
||||
draw_texture(layers[i][1], Vector2(location.x + size.x, location.y - size.y), modulate_color) #Up right
|
||||
draw_texture(layers[i][1], Vector2(location.x + size.x, location.y), modulate_color) #Right
|
||||
draw_texture(layers[i][1], location + size, modulate_color) #Down right
|
||||
|
||||
#Idea taken from flurick (on GitHub)
|
||||
# Idea taken from flurick (on GitHub)
|
||||
if Global.draw_grid:
|
||||
for x in range(0, size.x, Global.grid_width):
|
||||
draw_line(Vector2(x, location.y), Vector2(x, size.y), Global.grid_color, true)
|
||||
for y in range(0, size.y, Global.grid_height):
|
||||
draw_line(Vector2(location.x, y), Vector2(size.x, y), Global.grid_color, true)
|
||||
|
||||
#Draw rectangle to indicate the pixel currently being hovered on
|
||||
# Draw rectangle to indicate the pixel currently being hovered on
|
||||
var mouse_pos := current_pixel
|
||||
if point_in_rectangle(mouse_pos, location, location + size):
|
||||
mouse_pos = mouse_pos.floor()
|
||||
|
@ -204,6 +197,7 @@ func _input(event : InputEvent) -> void:
|
|||
pen_pressure = 1 # This causes problems with tablets though
|
||||
|
||||
sprite_changed_this_frame = false
|
||||
var sprite : Image = layers[Global.current_layer][0]
|
||||
var mouse_pos := current_pixel
|
||||
var mouse_pos_floored := mouse_pos.floor()
|
||||
var mouse_pos_ceiled := mouse_pos.ceil()
|
||||
|
@ -248,7 +242,8 @@ func _input(event : InputEvent) -> void:
|
|||
Global.cursor_position_label.text = "[%s×%s] %s, %s" % [size.x, size.y, mouse_pos_floored.x, mouse_pos_floored.y]
|
||||
if !cursor_inside_canvas:
|
||||
cursor_inside_canvas = true
|
||||
Input.set_custom_mouse_cursor(Global.cursor_image, 0, Vector2(15, 15))
|
||||
if Global.cursor_image.get_data().get_size() != Vector2.ZERO:
|
||||
Input.set_custom_mouse_cursor(Global.cursor_image, 0, Vector2(15, 15))
|
||||
if Global.show_left_tool_icon:
|
||||
Global.left_cursor.visible = true
|
||||
if Global.show_right_tool_icon:
|
||||
|
@ -292,9 +287,9 @@ func _input(event : InputEvent) -> void:
|
|||
|
||||
match current_action: # Handle current tool
|
||||
"Pencil":
|
||||
pencil_and_eraser(mouse_pos, current_color, current_mouse_button, current_action)
|
||||
pencil_and_eraser(sprite, mouse_pos, current_color, current_mouse_button, current_action)
|
||||
"Eraser":
|
||||
pencil_and_eraser(mouse_pos, Color(0, 0, 0, 0), current_mouse_button, current_action)
|
||||
pencil_and_eraser(sprite, mouse_pos, Color(0, 0, 0, 0), current_mouse_button, current_action)
|
||||
"Bucket":
|
||||
if can_handle:
|
||||
if fill_area == 0: # Paint the specific area of the same color
|
||||
|
@ -309,34 +304,34 @@ func _input(event : InputEvent) -> void:
|
|||
horizontal_mirror = Global.right_horizontal_mirror
|
||||
vertical_mirror = Global.right_vertical_mirror
|
||||
|
||||
flood_fill(mouse_pos, layers[current_layer_index][0].get_pixelv(mouse_pos), current_color)
|
||||
flood_fill(sprite, mouse_pos, sprite.get_pixelv(mouse_pos), current_color)
|
||||
if horizontal_mirror:
|
||||
var pos := Vector2(mirror_x, mouse_pos.y)
|
||||
flood_fill(pos, layers[current_layer_index][0].get_pixelv(pos), current_color)
|
||||
flood_fill(sprite, pos, sprite.get_pixelv(pos), current_color)
|
||||
if vertical_mirror:
|
||||
var pos := Vector2(mouse_pos.x, mirror_y)
|
||||
flood_fill(pos, layers[current_layer_index][0].get_pixelv(pos), current_color)
|
||||
flood_fill(sprite, pos, sprite.get_pixelv(pos), current_color)
|
||||
if horizontal_mirror && vertical_mirror:
|
||||
var pos := Vector2(mirror_x, mirror_y)
|
||||
flood_fill(pos, layers[current_layer_index][0].get_pixelv(pos), current_color)
|
||||
flood_fill(sprite, pos, sprite.get_pixelv(pos), current_color)
|
||||
|
||||
else: # Paint all pixels of the same color
|
||||
var pixel_color : Color = layers[current_layer_index][0].get_pixelv(mouse_pos)
|
||||
var pixel_color : Color = sprite.get_pixelv(mouse_pos)
|
||||
for xx in range(west_limit, east_limit):
|
||||
for yy in range(north_limit, south_limit):
|
||||
var c : Color = layers[current_layer_index][0].get_pixel(xx, yy)
|
||||
var c : Color = sprite.get_pixel(xx, yy)
|
||||
if c == pixel_color:
|
||||
layers[current_layer_index][0].set_pixel(xx, yy, current_color)
|
||||
sprite.set_pixel(xx, yy, current_color)
|
||||
sprite_changed_this_frame = true
|
||||
"LightenDarken":
|
||||
if can_handle:
|
||||
var pixel_color : Color = layers[current_layer_index][0].get_pixelv(mouse_pos)
|
||||
var pixel_color : Color = sprite.get_pixelv(mouse_pos)
|
||||
var color_changed : Color
|
||||
if ld == 0: # Lighten
|
||||
color_changed = pixel_color.lightened(ld_amount)
|
||||
else: # Darken
|
||||
color_changed = pixel_color.darkened(ld_amount)
|
||||
pencil_and_eraser(mouse_pos, color_changed, current_mouse_button, current_action)
|
||||
pencil_and_eraser(sprite, mouse_pos, color_changed, current_mouse_button, current_action)
|
||||
"RectSelect":
|
||||
# Check SelectionRectangle.gd for more code on Rectangle Selection
|
||||
if Global.can_draw && Global.has_focus:
|
||||
|
@ -363,7 +358,7 @@ func _input(event : InputEvent) -> void:
|
|||
Global.selection_rectangle.polygon[3] = Vector2(start_pos.x, end_pos.y)
|
||||
"ColorPicker":
|
||||
if can_handle:
|
||||
var pixel_color : Color = layers[current_layer_index][0].get_pixelv(mouse_pos)
|
||||
var pixel_color : Color = sprite.get_pixelv(mouse_pos)
|
||||
if color_picker_for == 0: # Pick for the left color
|
||||
Global.left_color_picker.color = pixel_color
|
||||
Global.update_left_custom_brush()
|
||||
|
@ -422,7 +417,7 @@ func _input(event : InputEvent) -> void:
|
|||
previous_mouse_pos.x = clamp(previous_mouse_pos.x, location.x, location.x + size.x)
|
||||
previous_mouse_pos.y = clamp(previous_mouse_pos.y, location.y, location.y + size.y)
|
||||
if sprite_changed_this_frame:
|
||||
update_texture(current_layer_index, (Input.is_action_just_released("left_mouse") || Input.is_action_just_released("right_mouse")))
|
||||
update_texture(Global.current_layer)
|
||||
|
||||
func camera_zoom() -> void:
|
||||
# Set camera zoom based on the sprite size
|
||||
|
@ -454,7 +449,7 @@ func handle_undo(action : String) -> void:
|
|||
var layer_index := -1
|
||||
if Global.animation_timer.is_stopped(): # if we're not animating, store only the current canvas
|
||||
canvases = [self]
|
||||
layer_index = current_layer_index
|
||||
layer_index = Global.current_layer
|
||||
else: # If we're animating, store all canvases
|
||||
canvases = Global.canvases
|
||||
Global.undos += 1
|
||||
|
@ -462,10 +457,10 @@ func handle_undo(action : String) -> void:
|
|||
for c in canvases:
|
||||
# I'm not sure why I have to unlock it, but...
|
||||
# ...if I don't, it doesn't work properly
|
||||
c.layers[c.current_layer_index][0].unlock()
|
||||
var data = c.layers[c.current_layer_index][0].data
|
||||
c.layers[c.current_layer_index][0].lock()
|
||||
Global.undo_redo.add_undo_property(c.layers[c.current_layer_index][0], "data", data)
|
||||
c.layers[Global.current_layer][0].unlock()
|
||||
var data = c.layers[Global.current_layer][0].data
|
||||
c.layers[Global.current_layer][0].lock()
|
||||
Global.undo_redo.add_undo_property(c.layers[Global.current_layer][0], "data", data)
|
||||
if action == "Rectangle Select":
|
||||
var selected_pixels = Global.selected_pixels.duplicate()
|
||||
Global.undo_redo.add_undo_property(Global.selection_rectangle, "polygon", Global.selection_rectangle.polygon)
|
||||
|
@ -483,40 +478,24 @@ func handle_redo(action : String) -> void:
|
|||
var layer_index := -1
|
||||
if Global.animation_timer.is_stopped():
|
||||
canvases = [self]
|
||||
layer_index = current_layer_index
|
||||
layer_index = Global.current_layer
|
||||
else:
|
||||
canvases = Global.canvases
|
||||
for c in canvases:
|
||||
Global.undo_redo.add_do_property(c.layers[c.current_layer_index][0], "data", c.layers[c.current_layer_index][0].data)
|
||||
Global.undo_redo.add_do_property(c.layers[Global.current_layer][0], "data", c.layers[Global.current_layer][0].data)
|
||||
if action == "Rectangle Select":
|
||||
Global.undo_redo.add_do_property(Global.selection_rectangle, "polygon", Global.selection_rectangle.polygon)
|
||||
Global.undo_redo.add_do_property(Global, "selected_pixels", Global.selected_pixels)
|
||||
Global.undo_redo.add_do_method(Global, "redo", canvases, layer_index)
|
||||
Global.undo_redo.commit_action()
|
||||
|
||||
func update_texture(layer_index : int, update_frame_tex := true) -> void:
|
||||
func update_texture(layer_index : int) -> void:
|
||||
layers[layer_index][1].create_from_image(layers[layer_index][0], 0)
|
||||
var layer_container := get_layer_container(layer_index)
|
||||
if layer_container:
|
||||
layer_container.get_child(1).get_child(0).texture = layers[layer_index][1]
|
||||
|
||||
if update_frame_tex:
|
||||
# This code is used to update the texture in the animation timeline frame button
|
||||
# but blend_rect causes major performance issues on large images
|
||||
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
|
||||
var frame_texture_rect : TextureRect
|
||||
frame_texture_rect = Global.find_node_by_name(Global.layers[layer_index][2].get_child(frame),"FrameTexture")
|
||||
frame_texture_rect.texture = layers[layer_index][1]
|
||||
|
||||
func frame_changed(value : int) -> void:
|
||||
frame = value
|
||||
if frame_button:
|
||||
frame_button.get_node("FrameButton").frame = frame
|
||||
frame_button.get_node("FrameID").text = str(frame + 1)
|
||||
|
||||
func get_layer_container(layer_index : int) -> LayerContainer:
|
||||
for container in Global.vbox_layer_container.get_children():
|
||||
|
@ -524,47 +503,24 @@ func get_layer_container(layer_index : int) -> LayerContainer:
|
|||
return container
|
||||
return null
|
||||
|
||||
func generate_layer_panels() -> void:
|
||||
for child in Global.vbox_layer_container.get_children():
|
||||
if child is LayerContainer:
|
||||
child.queue_free()
|
||||
|
||||
current_layer_index = layers.size() - 1
|
||||
if layers.size() == 1:
|
||||
Global.remove_layer_button.disabled = true
|
||||
Global.remove_layer_button.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN
|
||||
else:
|
||||
Global.remove_layer_button.disabled = false
|
||||
Global.remove_layer_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
|
||||
|
||||
for i in range(layers.size() -1, -1, -1):
|
||||
var layer_container = load("res://Prefabs/LayerContainer.tscn").instance()
|
||||
if !layers[i][2]:
|
||||
layers[i][2] = tr("Layer") + " %s" % i
|
||||
layer_container.i = i
|
||||
layer_container.get_child(1).get_child(0).texture = layers[i][1]
|
||||
layer_container.get_child(1).get_child(1).text = layers[i][2]
|
||||
layer_container.get_child(1).get_child(2).text = layers[i][2]
|
||||
Global.vbox_layer_container.add_child(layer_container)
|
||||
|
||||
func pencil_and_eraser(mouse_pos : Vector2, color : Color, current_mouse_button : String, current_action := "None") -> void:
|
||||
func pencil_and_eraser(sprite : Image, mouse_pos : Vector2, color : Color, current_mouse_button : String, current_action := "None") -> void:
|
||||
if made_line:
|
||||
return
|
||||
if is_making_line:
|
||||
fill_gaps(line_2d.points[1], previous_mouse_pos_for_lines, color, current_mouse_button, current_action)
|
||||
draw_brush(line_2d.points[1], color, current_mouse_button, current_action)
|
||||
fill_gaps(sprite, line_2d.points[1], previous_mouse_pos_for_lines, color, current_mouse_button, current_action)
|
||||
draw_brush(sprite, line_2d.points[1], color, current_mouse_button, current_action)
|
||||
made_line = true
|
||||
else:
|
||||
if point_in_rectangle(mouse_pos, location, location + size):
|
||||
mouse_inside_canvas = true
|
||||
# Draw
|
||||
draw_brush(mouse_pos, color, current_mouse_button, current_action)
|
||||
fill_gaps(mouse_pos, previous_mouse_pos, color, current_mouse_button, current_action) #Fill the gaps
|
||||
draw_brush(sprite, mouse_pos, color, current_mouse_button, current_action)
|
||||
fill_gaps(sprite, mouse_pos, previous_mouse_pos, color, current_mouse_button, current_action) # Fill the gaps
|
||||
# If mouse is not inside bounds but it used to be, fill the gaps
|
||||
elif point_in_rectangle(previous_mouse_pos, location, location + size):
|
||||
fill_gaps(mouse_pos, previous_mouse_pos, color, current_mouse_button, current_action)
|
||||
fill_gaps(sprite, mouse_pos, previous_mouse_pos, color, current_mouse_button, current_action)
|
||||
|
||||
func draw_brush(pos : Vector2, color : Color, current_mouse_button : String, current_action := "None") -> void:
|
||||
func draw_brush(sprite : Image, pos : Vector2, color : Color, current_mouse_button : String, current_action := "None") -> void:
|
||||
if Global.can_draw && Global.has_focus:
|
||||
var brush_size := 1
|
||||
var brush_type = Global.Brush_Types.PIXEL
|
||||
|
@ -635,7 +591,7 @@ func draw_brush(pos : Vector2, color : Color, current_mouse_button : String, cur
|
|||
if point_in_rectangle(Vector2(cur_pos_x, cur_pos_y), Vector2(west_limit - 1, north_limit - 1), Vector2(east_limit, south_limit)):
|
||||
var pos_floored := Vector2(cur_pos_x, cur_pos_y).floor()
|
||||
# Don't draw the same pixel over and over and don't re-lighten/darken it
|
||||
var current_pixel_color : Color = layers[current_layer_index][0].get_pixel(cur_pos_x, cur_pos_y)
|
||||
var current_pixel_color : Color = sprite.get_pixel(cur_pos_x, cur_pos_y)
|
||||
var _c := color
|
||||
if current_action == "Pencil" && color.a < 1:
|
||||
_c = blend_colors(color, current_pixel_color)
|
||||
|
@ -655,14 +611,14 @@ func draw_brush(pos : Vector2, color : Color, current_mouse_button : String, cur
|
|||
mouse_press_pressure_values.append(pen_pressure)
|
||||
else:
|
||||
mouse_press_pressure_values[saved_pixel_index] = pen_pressure
|
||||
layers[current_layer_index][0].set_pixel(cur_pos_x, cur_pos_y, _c)
|
||||
sprite.set_pixel(cur_pos_x, cur_pos_y, _c)
|
||||
sprite_changed_this_frame = true
|
||||
|
||||
# Handle mirroring
|
||||
var mirror_x := east_limit + west_limit - cur_pos_x - 1
|
||||
var mirror_y := south_limit + north_limit - cur_pos_y - 1
|
||||
if horizontal_mirror:
|
||||
current_pixel_color = layers[current_layer_index][0].get_pixel(mirror_x, cur_pos_y)
|
||||
current_pixel_color = sprite.get_pixel(mirror_x, cur_pos_y)
|
||||
if current_pixel_color != _c: # don't draw the same pixel over and over
|
||||
if current_action == "LightenDarken":
|
||||
if ld == 0: # Lighten
|
||||
|
@ -672,23 +628,24 @@ func draw_brush(pos : Vector2, color : Color, current_mouse_button : String, cur
|
|||
|
||||
mouse_press_pixels.append(pos_floored)
|
||||
mouse_press_pressure_values.append(pen_pressure)
|
||||
layers[current_layer_index][0].set_pixel(mirror_x, cur_pos_y, _c)
|
||||
sprite.set_pixel(mirror_x, cur_pos_y, _c)
|
||||
sprite_changed_this_frame = true
|
||||
|
||||
if vertical_mirror:
|
||||
current_pixel_color = layers[current_layer_index][0].get_pixel(cur_pos_x, mirror_y)
|
||||
current_pixel_color = sprite.get_pixel(cur_pos_x, mirror_y)
|
||||
if current_pixel_color != _c: # don't draw the same pixel over and over
|
||||
if current_action == "LightenDarken":
|
||||
if ld == 0: # Lighten
|
||||
_c = current_pixel_color.lightened(ld_amount)
|
||||
else:
|
||||
_c = current_pixel_color.darkened(ld_amount)
|
||||
|
||||
mouse_press_pixels.append(pos_floored)
|
||||
mouse_press_pressure_values.append(pen_pressure)
|
||||
layers[current_layer_index][0].set_pixel(cur_pos_x, mirror_y, _c)
|
||||
sprite.set_pixel(cur_pos_x, mirror_y, _c)
|
||||
sprite_changed_this_frame = true
|
||||
|
||||
if horizontal_mirror && vertical_mirror:
|
||||
current_pixel_color = layers[current_layer_index][0].get_pixel(mirror_x, mirror_y)
|
||||
current_pixel_color = sprite.get_pixel(mirror_x, mirror_y)
|
||||
if current_pixel_color != _c: # don't draw the same pixel over and over
|
||||
if current_action == "LightenDarken":
|
||||
if ld == 0: # Lighten
|
||||
|
@ -698,21 +655,21 @@ func draw_brush(pos : Vector2, color : Color, current_mouse_button : String, cur
|
|||
|
||||
mouse_press_pixels.append(pos_floored)
|
||||
mouse_press_pressure_values.append(pen_pressure)
|
||||
layers[current_layer_index][0].set_pixel(mirror_x, mirror_y, _c)
|
||||
sprite.set_pixel(mirror_x, mirror_y, _c)
|
||||
sprite_changed_this_frame = true
|
||||
|
||||
elif brush_type == Global.Brush_Types.CIRCLE || brush_type == Global.Brush_Types.FILLED_CIRCLE:
|
||||
plot_circle(layers[current_layer_index][0], pos.x, pos.y, brush_size, color, brush_type == Global.Brush_Types.FILLED_CIRCLE)
|
||||
plot_circle(sprite, pos.x, pos.y, brush_size, color, brush_type == Global.Brush_Types.FILLED_CIRCLE)
|
||||
|
||||
# Handle mirroring
|
||||
var mirror_x := east_limit + west_limit - pos.x
|
||||
var mirror_y := south_limit + north_limit - pos.y
|
||||
if horizontal_mirror:
|
||||
plot_circle(layers[current_layer_index][0], mirror_x, pos.y, brush_size, color, brush_type == Global.Brush_Types.FILLED_CIRCLE)
|
||||
plot_circle(sprite, mirror_x, pos.y, brush_size, color, brush_type == Global.Brush_Types.FILLED_CIRCLE)
|
||||
if vertical_mirror:
|
||||
plot_circle(layers[current_layer_index][0], pos.x, mirror_y, brush_size, color, brush_type == Global.Brush_Types.FILLED_CIRCLE)
|
||||
plot_circle(sprite, pos.x, mirror_y, brush_size, color, brush_type == Global.Brush_Types.FILLED_CIRCLE)
|
||||
if horizontal_mirror && vertical_mirror:
|
||||
plot_circle(layers[current_layer_index][0], mirror_x, mirror_y, brush_size, color, brush_type == Global.Brush_Types.FILLED_CIRCLE)
|
||||
plot_circle(sprite, mirror_x, mirror_y, brush_size, color, brush_type == Global.Brush_Types.FILLED_CIRCLE)
|
||||
|
||||
sprite_changed_this_frame = true
|
||||
|
||||
|
@ -755,13 +712,13 @@ func draw_brush(pos : Vector2, color : Color, current_mouse_button : String, cur
|
|||
mirror_y -= 1
|
||||
# Use custom blend function cause of godot's issue #31124
|
||||
if color.a > 0: # If it's the pencil
|
||||
blend_rect(layers[current_layer_index][0], custom_brush_image, src_rect, dst)
|
||||
blend_rect(sprite, custom_brush_image, src_rect, dst)
|
||||
if horizontal_mirror:
|
||||
blend_rect(layers[current_layer_index][0], custom_brush_image, src_rect, Vector2(mirror_x, dst.y))
|
||||
blend_rect(sprite, custom_brush_image, src_rect, Vector2(mirror_x, dst.y))
|
||||
if vertical_mirror:
|
||||
blend_rect(layers[current_layer_index][0], custom_brush_image, src_rect, Vector2(dst.x, mirror_y))
|
||||
blend_rect(sprite, custom_brush_image, src_rect, Vector2(dst.x, mirror_y))
|
||||
if horizontal_mirror && vertical_mirror:
|
||||
blend_rect(layers[current_layer_index][0], custom_brush_image, src_rect, Vector2(mirror_x, mirror_y))
|
||||
blend_rect(sprite, custom_brush_image, src_rect, Vector2(mirror_x, mirror_y))
|
||||
|
||||
else: # if it's transparent - if it's the eraser
|
||||
var custom_brush := Image.new()
|
||||
|
@ -770,15 +727,15 @@ func draw_brush(pos : Vector2, color : Color, current_mouse_button : String, cur
|
|||
custom_brush.resize(custom_brush_size.x * brush_size, custom_brush_size.y * brush_size, Image.INTERPOLATE_NEAREST)
|
||||
var custom_brush_blended = Global.blend_image_with_color(custom_brush, color, 1)
|
||||
|
||||
layers[current_layer_index][0].blit_rect_mask(custom_brush_blended, custom_brush, src_rect, dst)
|
||||
sprite.blit_rect_mask(custom_brush_blended, custom_brush, src_rect, dst)
|
||||
if horizontal_mirror:
|
||||
layers[current_layer_index][0].blit_rect_mask(custom_brush_blended, custom_brush, src_rect, Vector2(mirror_x, dst.y))
|
||||
sprite.blit_rect_mask(custom_brush_blended, custom_brush, src_rect, Vector2(mirror_x, dst.y))
|
||||
if vertical_mirror:
|
||||
layers[current_layer_index][0].blit_rect_mask(custom_brush_blended, custom_brush, src_rect, Vector2(dst.x, mirror_y))
|
||||
sprite.blit_rect_mask(custom_brush_blended, custom_brush, src_rect, Vector2(dst.x, mirror_y))
|
||||
if horizontal_mirror && vertical_mirror:
|
||||
layers[current_layer_index][0].blit_rect_mask(custom_brush_blended, custom_brush, src_rect, Vector2(mirror_x, mirror_y))
|
||||
sprite.blit_rect_mask(custom_brush_blended, custom_brush, src_rect, Vector2(mirror_x, mirror_y))
|
||||
|
||||
layers[current_layer_index][0].lock()
|
||||
sprite.lock()
|
||||
sprite_changed_this_frame = true
|
||||
|
||||
previous_mouse_pos_for_lines = pos.floor() + Vector2(0.5, 0.5)
|
||||
|
@ -789,7 +746,7 @@ func draw_brush(pos : Vector2, color : Color, current_mouse_button : String, cur
|
|||
|
||||
# Bresenham's Algorithm
|
||||
# Thanks to https://godotengine.org/qa/35276/tile-based-line-drawing-algorithm-efficiency
|
||||
func fill_gaps(mouse_pos : Vector2, prev_mouse_pos : Vector2, color : Color, current_mouse_button : String, current_action := "None") -> void:
|
||||
func fill_gaps(sprite : Image, mouse_pos : Vector2, prev_mouse_pos : Vector2, color : Color, current_mouse_button : String, current_action := "None") -> void:
|
||||
var previous_mouse_pos_floored = prev_mouse_pos.floor()
|
||||
var mouse_pos_floored = mouse_pos.floor()
|
||||
mouse_pos_floored.x = clamp(mouse_pos_floored.x, location.x - 1, location.x + size.x)
|
||||
|
@ -803,7 +760,7 @@ func fill_gaps(mouse_pos : Vector2, prev_mouse_pos : Vector2, color : Color, cur
|
|||
var x = previous_mouse_pos_floored.x
|
||||
var y = previous_mouse_pos_floored.y
|
||||
while !(x == mouse_pos_floored.x && y == mouse_pos_floored.y):
|
||||
draw_brush(Vector2(x, y), color, current_mouse_button, current_action)
|
||||
draw_brush(sprite, Vector2(x, y), color, current_mouse_button, current_action)
|
||||
e2 = err << 1
|
||||
if e2 >= dy:
|
||||
err += dy
|
||||
|
@ -813,9 +770,9 @@ func fill_gaps(mouse_pos : Vector2, prev_mouse_pos : Vector2, color : Color, cur
|
|||
y += sy
|
||||
|
||||
# Thanks to https://en.wikipedia.org/wiki/Flood_fill
|
||||
func flood_fill(pos : Vector2, target_color : Color, replace_color : Color) -> void:
|
||||
func flood_fill(sprite : Image, pos : Vector2, target_color : Color, replace_color : Color) -> void:
|
||||
pos = pos.floor()
|
||||
var pixel = layers[current_layer_index][0].get_pixelv(pos)
|
||||
var pixel = sprite.get_pixelv(pos)
|
||||
if target_color == replace_color:
|
||||
return
|
||||
elif pixel != target_color:
|
||||
|
@ -832,20 +789,20 @@ func flood_fill(pos : Vector2, target_color : Color, replace_color : Color) -> v
|
|||
break
|
||||
var west : Vector2 = n
|
||||
var east : Vector2 = n
|
||||
while west.x >= west_limit && layers[current_layer_index][0].get_pixelv(west) == target_color:
|
||||
while west.x >= west_limit && sprite.get_pixelv(west) == target_color:
|
||||
west += Vector2.LEFT
|
||||
while east.x < east_limit && layers[current_layer_index][0].get_pixelv(east) == target_color:
|
||||
while east.x < east_limit && sprite.get_pixelv(east) == target_color:
|
||||
east += Vector2.RIGHT
|
||||
for px in range(west.x + 1, east.x):
|
||||
var p := Vector2(px, n.y)
|
||||
# Draw
|
||||
layers[current_layer_index][0].set_pixelv(p, replace_color)
|
||||
replace_color = layers[current_layer_index][0].get_pixelv(p)
|
||||
sprite.set_pixelv(p, replace_color)
|
||||
replace_color = sprite.get_pixelv(p)
|
||||
var north := p + Vector2.UP
|
||||
var south := p + Vector2.DOWN
|
||||
if north.y >= north_limit && layers[current_layer_index][0].get_pixelv(north) == target_color:
|
||||
if north.y >= north_limit && sprite.get_pixelv(north) == target_color:
|
||||
q.append(north)
|
||||
if south.y < south_limit && layers[current_layer_index][0].get_pixelv(south) == target_color:
|
||||
if south.y < south_limit && sprite.get_pixelv(south) == target_color:
|
||||
q.append(south)
|
||||
sprite_changed_this_frame = true
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ func save_sprite(canvas : Canvas, path : String) -> void:
|
|||
for layer in canvas.layers:
|
||||
var img : Image = layer[0]
|
||||
img.lock()
|
||||
if layer[4] < 1: # If we have layer transparency
|
||||
if layer[2] < 1: # If we have layer transparency
|
||||
for xx in img.get_size().x:
|
||||
for yy in img.get_size().y:
|
||||
var pixel_color := img.get_pixel(xx, yy)
|
||||
|
@ -132,7 +132,7 @@ func save_spritesheet() -> void:
|
|||
for layer in canvas.layers:
|
||||
var img : Image = layer[0]
|
||||
img.lock()
|
||||
if layer[4] < 1: # If we have layer transparency
|
||||
if layer[2] < 1: # If we have layer transparency
|
||||
for xx in img.get_size().x:
|
||||
for yy in img.get_size().y:
|
||||
var pixel_color := img.get_pixel(xx, yy)
|
||||
|
|
|
@ -55,8 +55,21 @@ func _on_ImportSprites_files_selected(paths : PoolStringArray) -> void:
|
|||
image.lock()
|
||||
var tex := ImageTexture.new()
|
||||
tex.create_from_image(image, 0)
|
||||
# Store [Image, ImageTexture, Layer Name, Visibity boolean, Opacity]
|
||||
canvas.layers.append([image, tex, "Layer 0", true, 1])
|
||||
# Store [Image, ImageTexture, Opacity]
|
||||
canvas.layers.append([image, tex, 1])
|
||||
|
||||
for _i in range(1, Global.layers.size()):
|
||||
var empty_sprite := Image.new()
|
||||
empty_sprite.create(canvas.size.x, canvas.size.y, false, Image.FORMAT_RGBA8)
|
||||
empty_sprite.fill(Color(0, 0, 0, 0))
|
||||
empty_sprite.lock()
|
||||
|
||||
var empty_tex := ImageTexture.new()
|
||||
empty_tex.create_from_image(empty_sprite, 0)
|
||||
|
||||
# Store [Image, ImageTexture, Opacity]
|
||||
canvas.layers.append([empty_sprite, empty_tex, 1])
|
||||
|
||||
canvas.frame = i
|
||||
Global.canvases.append(canvas)
|
||||
Global.canvas_parent.add_child(canvas)
|
||||
|
@ -96,8 +109,20 @@ func _on_ImportSprites_files_selected(paths : PoolStringArray) -> void:
|
|||
cropped_image.lock()
|
||||
var tex := ImageTexture.new()
|
||||
tex.create_from_image(cropped_image, 0)
|
||||
# Store [Image, ImageTexture, Layer Name, Visibity boolean, Opacity]
|
||||
canvas.layers.append([cropped_image, tex, tr("Layer") + " 0", true, 1])
|
||||
# Store [Image, ImageTexture, Opacity]
|
||||
canvas.layers.append([cropped_image, tex, 1])
|
||||
for _i in range(1, Global.layers.size()):
|
||||
var empty_sprite := Image.new()
|
||||
empty_sprite.create(canvas.size.x, canvas.size.y, false, Image.FORMAT_RGBA8)
|
||||
empty_sprite.fill(Color(0, 0, 0, 0))
|
||||
empty_sprite.lock()
|
||||
|
||||
var empty_tex := ImageTexture.new()
|
||||
empty_tex.create_from_image(empty_sprite, 0)
|
||||
|
||||
# Store [Image, ImageTexture, Opacity]
|
||||
canvas.layers.append([empty_sprite, empty_tex, 1])
|
||||
|
||||
canvas.frame = i
|
||||
Global.canvases.append(canvas)
|
||||
Global.canvas_parent.add_child(canvas)
|
||||
|
@ -107,6 +132,7 @@ func _on_ImportSprites_files_selected(paths : PoolStringArray) -> void:
|
|||
|
||||
Global.canvases[Global.canvases.size() - 1].camera_zoom()
|
||||
|
||||
Global.canvases = Global.canvases # Just to call Global.canvases_changed
|
||||
Global.current_frame = i - 1
|
||||
Global.canvas = Global.canvases[Global.canvases.size() - 1]
|
||||
Global.canvas.visible = true
|
||||
|
|
|
@ -9,7 +9,7 @@ func _on_OutlineDialog_confirmed() -> void:
|
|||
var diagonal : bool = $OptionsContainer/DiagonalCheckBox.pressed
|
||||
var inside_image : bool = $OptionsContainer/InsideImageCheckBox.pressed
|
||||
|
||||
var image : Image = Global.canvas.layers[Global.canvas.current_layer_index][0]
|
||||
var image : Image = Global.canvas.layers[Global.current_layer][0]
|
||||
if image.is_invisible():
|
||||
return
|
||||
var new_image := Image.new()
|
||||
|
|
|
@ -254,8 +254,8 @@ func change_theme(ID : int) -> void:
|
|||
var disabled_file_name = button.texture_disabled.resource_path.get_file()
|
||||
button.texture_disabled = load("res://Assets/Graphics/%s Themes/%s/%s" % [Global.theme_type, button_category, disabled_file_name])
|
||||
|
||||
# Make sure the frame text gets updated
|
||||
Global.current_frame = Global.current_frame
|
||||
# Make sure the frame text gets updated
|
||||
Global.current_frame = Global.current_frame
|
||||
|
||||
func _on_GridWidthValue_value_changed(value : float) -> void:
|
||||
Global.grid_width = value
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
extends Button
|
||||
|
||||
var frame := 0
|
||||
var layer := 0
|
||||
|
||||
onready var popup_menu := $PopupMenu
|
||||
|
||||
func _ready() -> void:
|
||||
hint_tooltip = "Frame: %s, Layer: %s" % [frame, layer]
|
||||
|
||||
func _on_FrameButton_pressed() -> void:
|
||||
if Input.is_action_just_released("left_mouse"):
|
||||
Global.current_frame = frame
|
||||
Global.current_layer = layer
|
||||
elif Input.is_action_just_released("right_mouse"):
|
||||
if Global.canvases.size() == 1:
|
||||
popup_menu.set_item_disabled(0, true)
|
||||
|
@ -27,10 +32,10 @@ func _on_FrameButton_pressed() -> void:
|
|||
|
||||
func _on_PopupMenu_id_pressed(ID : int) -> void:
|
||||
match ID:
|
||||
0: #Remove Frame
|
||||
0: # Remove Frame
|
||||
remove_frame()
|
||||
|
||||
1: #Clone Layer
|
||||
1: # Clone Frame
|
||||
var canvas : Canvas = Global.canvases[frame]
|
||||
var new_canvas : Canvas = load("res://Prefabs/Canvas.tscn").instance()
|
||||
new_canvas.size = Global.canvas.size
|
||||
|
@ -41,13 +46,13 @@ func _on_PopupMenu_id_pressed(ID : int) -> void:
|
|||
var new_hidden_canvases := Global.hidden_canvases.duplicate()
|
||||
new_hidden_canvases.append(new_canvas)
|
||||
|
||||
for layer in canvas.layers: #Copy every layer
|
||||
for layer in canvas.layers: # Copy every layer
|
||||
var sprite := Image.new()
|
||||
sprite.copy_from(layer[0])
|
||||
sprite.lock()
|
||||
var tex := ImageTexture.new()
|
||||
tex.create_from_image(sprite, 0)
|
||||
new_canvas.layers.append([sprite, tex, layer[2], layer[3], layer[4]])
|
||||
new_canvas.layers.append([sprite, tex, layer[2]])
|
||||
|
||||
Global.undos += 1
|
||||
Global.undo_redo.create_action("Add Frame")
|
||||
|
@ -58,10 +63,10 @@ func _on_PopupMenu_id_pressed(ID : int) -> void:
|
|||
Global.undo_redo.add_do_property(Global, "hidden_canvases", Global.hidden_canvases)
|
||||
Global.undo_redo.add_do_property(Global, "canvas", new_canvas)
|
||||
Global.undo_redo.add_do_property(Global, "current_frame", new_canvases.size() - 1)
|
||||
for child in Global.frame_container.get_children():
|
||||
var frame_button = child.get_node("FrameButton")
|
||||
Global.undo_redo.add_do_property(frame_button, "pressed", false)
|
||||
Global.undo_redo.add_undo_property(frame_button, "pressed", frame_button.pressed)
|
||||
for i in range(Global.layers.size()):
|
||||
for child in Global.layers[i][2].get_children():
|
||||
Global.undo_redo.add_do_property(child, "pressed", false)
|
||||
Global.undo_redo.add_undo_property(child, "pressed", child.pressed)
|
||||
for c in Global.canvases:
|
||||
Global.undo_redo.add_do_property(c, "visible", false)
|
||||
Global.undo_redo.add_undo_property(c, "visible", c.visible)
|
||||
|
@ -72,9 +77,9 @@ func _on_PopupMenu_id_pressed(ID : int) -> void:
|
|||
Global.undo_redo.add_undo_property(Global, "current_frame", Global.current_frame)
|
||||
Global.undo_redo.commit_action()
|
||||
|
||||
2: #Move Left
|
||||
2: # Move Left
|
||||
change_frame_order(-1)
|
||||
3: #Move Right
|
||||
3: # Move Right
|
||||
change_frame_order(1)
|
||||
|
||||
func remove_frame() -> void:
|
||||
|
@ -121,6 +126,10 @@ func change_frame_order(rate : int) -> void:
|
|||
Global.undo_redo.add_do_property(Global.canvases[frame], "frame", change)
|
||||
Global.undo_redo.add_do_property(Global.canvases[change], "frame", frame)
|
||||
|
||||
if Global.current_frame == frame:
|
||||
Global.undo_redo.add_do_property(Global, "current_frame", change)
|
||||
Global.undo_redo.add_undo_property(Global, "current_frame", Global.current_frame)
|
||||
|
||||
Global.undo_redo.add_undo_property(Global, "canvases", Global.canvases)
|
||||
Global.undo_redo.add_undo_property(Global.canvases[frame], "frame", frame)
|
||||
Global.undo_redo.add_undo_property(Global.canvases[change], "frame", change)
|
||||
|
|
|
@ -13,12 +13,14 @@ var undos := 0 # The number of times we added undo properties
|
|||
var saved := true # Checks if the user has saved
|
||||
|
||||
# Canvas related stuff
|
||||
var canvases := [] setget canvases_changed
|
||||
var layers := [] setget layers_changed
|
||||
var current_frame := 0 setget frame_changed
|
||||
var current_layer := 0 setget layer_changed
|
||||
# warning-ignore:unused_class_variable
|
||||
var can_draw := false
|
||||
# warning-ignore:unused_class_variable
|
||||
var has_focus := false
|
||||
var canvases := []
|
||||
# warning-ignore:unused_class_variable
|
||||
var hidden_canvases := []
|
||||
var pressure_sensitivity_mode = Pressure_Sensitivity.NONE
|
||||
|
@ -223,14 +225,15 @@ var right_mirror_container : Container
|
|||
var animation_timeline : Panel
|
||||
|
||||
var animation_timer : Timer
|
||||
var frame_ids : HBoxContainer
|
||||
var current_frame_label : Label
|
||||
var loop_animation_button : BaseButton
|
||||
var play_forward : BaseButton
|
||||
var play_backwards : BaseButton
|
||||
var timeline_seconds : Control
|
||||
var frame_container : HBoxContainer
|
||||
var layers_container : VBoxContainer
|
||||
var frames_container : VBoxContainer
|
||||
|
||||
var vbox_layer_container : VBoxContainer
|
||||
var remove_layer_button : BaseButton
|
||||
var move_up_layer_button : BaseButton
|
||||
var move_down_layer_button : BaseButton
|
||||
|
@ -340,24 +343,24 @@ func _ready() -> void:
|
|||
|
||||
animation_timeline = find_node_by_name(root, "AnimationTimeline")
|
||||
|
||||
layers_container = find_node_by_name(animation_timeline, "LayersContainer")
|
||||
frames_container = find_node_by_name(animation_timeline, "FramesContainer")
|
||||
animation_timer = find_node_by_name(animation_timeline, "AnimationTimer")
|
||||
frame_ids = find_node_by_name(animation_timeline, "FrameIDs")
|
||||
current_frame_label = find_node_by_name(animation_timeline, "CurrentFrame")
|
||||
loop_animation_button = find_node_by_name(animation_timeline, "LoopAnim")
|
||||
play_forward = find_node_by_name(animation_timeline, "PlayForward")
|
||||
play_backwards = find_node_by_name(animation_timeline, "PlayBackwards")
|
||||
timeline_seconds = find_node_by_name(animation_timeline, "TimelineSeconds")
|
||||
frame_container = find_node_by_name(animation_timeline, "FrameContainer")
|
||||
|
||||
var layer_stuff_container = find_node_by_name(root, "LayerVBoxContainer")
|
||||
var layer_buttons = find_node_by_name(layer_stuff_container, "LayerButtons")
|
||||
remove_layer_button = find_node_by_name(layer_buttons, "RemoveLayer")
|
||||
move_up_layer_button = find_node_by_name(layer_buttons, "MoveUpLayer")
|
||||
move_down_layer_button = find_node_by_name(layer_buttons, "MovwDownLayer")
|
||||
merge_down_layer_button = find_node_by_name(layer_buttons, "MergeDownLayer")
|
||||
#var layer_stuff_container = find_node_by_name(animation_timeline, "LayerVBoxContainer")
|
||||
|
||||
layer_opacity_slider = find_node_by_name(layer_stuff_container, "OpacitySlider")
|
||||
layer_opacity_spinbox = find_node_by_name(layer_stuff_container, "OpacitySpinBox")
|
||||
vbox_layer_container = find_node_by_name(layer_stuff_container, "VBoxLayerContainer")
|
||||
remove_layer_button = find_node_by_name(animation_timeline, "RemoveLayer")
|
||||
move_up_layer_button = find_node_by_name(animation_timeline, "MoveUpLayer")
|
||||
move_down_layer_button = find_node_by_name(animation_timeline, "MovwDownLayer")
|
||||
merge_down_layer_button = find_node_by_name(animation_timeline, "MergeDownLayer")
|
||||
|
||||
layer_opacity_slider = find_node_by_name(animation_timeline, "OpacitySlider")
|
||||
layer_opacity_spinbox = find_node_by_name(animation_timeline, "OpacitySpinBox")
|
||||
|
||||
add_palette_button = find_node_by_name(root, "AddPalette")
|
||||
edit_palette_button = find_node_by_name(root, "EditPalette")
|
||||
|
@ -370,6 +373,9 @@ func _ready() -> void:
|
|||
|
||||
error_dialog = find_node_by_name(root, "ErrorDialog")
|
||||
|
||||
# Store [Layer name, Layer visibility boolean, Frame container]
|
||||
layers.append([tr("Layer") + " 0", true, HBoxContainer.new()])
|
||||
|
||||
# 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:
|
||||
if root.get_name() == node_name:
|
||||
|
@ -403,16 +409,8 @@ func undo(_canvases : Array, layer_index : int = -1) -> void:
|
|||
if action_name == "Scale":
|
||||
c.camera_zoom()
|
||||
|
||||
if "Layer" in action_name:
|
||||
var current_layer_index : int = _canvases[0].current_layer_index
|
||||
_canvases[0].generate_layer_panels()
|
||||
if action_name == "Change Layer Order":
|
||||
_canvases[0].current_layer_index = current_layer_index
|
||||
_canvases[0].get_layer_container(current_layer_index).changed_selection()
|
||||
|
||||
if action_name == "Add Frame":
|
||||
canvas_parent.remove_child(_canvases[0])
|
||||
frame_container.remove_child(_canvases[0].frame_button)
|
||||
# This actually means that canvases.size is one, but it hasn't been updated yet
|
||||
if canvases.size() == 2: # Stop animating
|
||||
play_forward.pressed = false
|
||||
|
@ -421,10 +419,7 @@ func undo(_canvases : Array, layer_index : int = -1) -> void:
|
|||
elif action_name == "Remove Frame":
|
||||
canvas_parent.add_child(_canvases[0])
|
||||
canvas_parent.move_child(_canvases[0], _canvases[0].frame)
|
||||
frame_container.add_child(_canvases[0].frame_button)
|
||||
frame_container.move_child(_canvases[0].frame_button, _canvases[0].frame)
|
||||
elif action_name == "Change Frame Order":
|
||||
frame_container.move_child(_canvases[0].frame_button, _canvases[0].frame)
|
||||
canvas_parent.move_child(_canvases[0], _canvases[0].frame)
|
||||
|
||||
canvas.update()
|
||||
|
@ -448,26 +443,16 @@ func redo(_canvases : Array, layer_index : int = -1) -> void:
|
|||
|
||||
if action_name == "Scale":
|
||||
c.camera_zoom()
|
||||
if "Layer" in action_name:
|
||||
var current_layer_index : int = _canvases[0].current_layer_index
|
||||
_canvases[0].generate_layer_panels()
|
||||
if action_name == "Change Layer Order":
|
||||
_canvases[0].current_layer_index = current_layer_index
|
||||
_canvases[0].get_layer_container(current_layer_index).changed_selection()
|
||||
|
||||
if action_name == "Add Frame":
|
||||
canvas_parent.add_child(_canvases[0])
|
||||
if !Global.frame_container.is_a_parent_of(_canvases[0].frame_button):
|
||||
Global.frame_container.add_child(_canvases[0].frame_button)
|
||||
elif action_name == "Remove Frame":
|
||||
canvas_parent.remove_child(_canvases[0])
|
||||
frame_container.remove_child(_canvases[0].frame_button)
|
||||
if canvases.size() == 1: # Stop animating
|
||||
play_forward.pressed = false
|
||||
play_backwards.pressed = false
|
||||
animation_timer.stop()
|
||||
elif action_name == "Change Frame Order":
|
||||
frame_container.move_child(_canvases[0].frame_button, _canvases[0].frame)
|
||||
canvas_parent.move_child(_canvases[0], _canvases[0].frame)
|
||||
|
||||
canvas.update()
|
||||
|
@ -481,28 +466,141 @@ func title_changed(value : String) -> void:
|
|||
window_title = value
|
||||
OS.set_window_title(value)
|
||||
|
||||
func canvases_changed(value : Array) -> void:
|
||||
canvases = value
|
||||
for container in frames_container.get_children():
|
||||
for button in container.get_children():
|
||||
container.remove_child(button)
|
||||
button.queue_free()
|
||||
frames_container.remove_child(container)
|
||||
|
||||
for frame_id in frame_ids.get_children():
|
||||
frame_ids.remove_child(frame_id)
|
||||
frame_id.queue_free()
|
||||
|
||||
for i in range(layers.size() - 1, -1, -1):
|
||||
frames_container.add_child(layers[i][2])
|
||||
|
||||
for j in range(canvases.size()):
|
||||
var label := Label.new()
|
||||
label.rect_min_size.x = 36
|
||||
label.align = Label.ALIGN_CENTER
|
||||
label.text = str(j + 1)
|
||||
frame_ids.add_child(label)
|
||||
|
||||
for i in range(layers.size() - 1, -1, -1):
|
||||
var frame_button = load("res://Prefabs/FrameButton.tscn").instance()
|
||||
frame_button.frame = j
|
||||
frame_button.layer = i
|
||||
frame_button.get_child(0).texture = Global.canvases[j].layers[i][1]
|
||||
|
||||
layers[i][2].add_child(frame_button)
|
||||
|
||||
func layers_changed(value : Array) -> void:
|
||||
layers = value
|
||||
|
||||
for container in layers_container.get_children():
|
||||
container.queue_free()
|
||||
|
||||
for container in frames_container.get_children():
|
||||
for button in container.get_children():
|
||||
container.remove_child(button)
|
||||
button.queue_free()
|
||||
frames_container.remove_child(container)
|
||||
|
||||
for i in range(layers.size() - 1, -1, -1):
|
||||
var layer_container = load("res://Prefabs/LayerContainer.tscn").instance()
|
||||
layer_container.i = i
|
||||
if !layers[i][0]:
|
||||
layers[i][0] = tr("Layer") + " %s" % i
|
||||
|
||||
layers_container.add_child(layer_container)
|
||||
layer_container.label.text = layers[i][0]
|
||||
layer_container.line_edit.text = layers[i][0]
|
||||
|
||||
frames_container.add_child(layers[i][2])
|
||||
for j in range(canvases.size()):
|
||||
var frame_button = load("res://Prefabs/FrameButton.tscn").instance()
|
||||
frame_button.frame = j
|
||||
frame_button.layer = i
|
||||
frame_button.get_child(0).texture = Global.canvases[j].layers[i][1]
|
||||
|
||||
layers[i][2].add_child(frame_button)
|
||||
|
||||
var layer_button = layers_container.get_child(layers_container.get_child_count() - 1 - current_layer)
|
||||
layer_button.pressed = true
|
||||
self.current_frame = current_frame # Call frame_changed to update UI
|
||||
|
||||
if layers.size() == 1:
|
||||
remove_layer_button.disabled = true
|
||||
remove_layer_button.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN
|
||||
move_up_layer_button.disabled = true
|
||||
move_up_layer_button.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN
|
||||
move_down_layer_button.disabled = true
|
||||
move_down_layer_button.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN
|
||||
merge_down_layer_button.disabled = true
|
||||
merge_down_layer_button.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN
|
||||
else:
|
||||
remove_layer_button.disabled = false
|
||||
remove_layer_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
|
||||
|
||||
func frame_changed(value : int) -> void:
|
||||
current_frame = value
|
||||
current_frame_label.text = tr("Current frame:") + " %s/%s" % [str(current_frame + 1), canvases.size()]
|
||||
|
||||
for c in canvases:
|
||||
var i := 0
|
||||
for c in canvases: # De-select all the other canvases/frames
|
||||
c.visible = false
|
||||
c.is_making_line = false
|
||||
c.line_2d.set_point_position(1, c.line_2d.points[0])
|
||||
canvas = canvases[current_frame]
|
||||
canvas.visible = true
|
||||
canvas.generate_layer_panels()
|
||||
# Make all frame buttons unpressed
|
||||
for c in canvases:
|
||||
var text_color := Color.white
|
||||
if theme_type == "Gold" || theme_type == "Light":
|
||||
text_color = Color.black
|
||||
c.frame_button.get_node("FrameButton").pressed = false
|
||||
c.frame_button.get_node("FrameID").add_color_override("font_color", text_color)
|
||||
# Make only the current frame button pressed
|
||||
canvas.frame_button.get_node("FrameButton").pressed = true
|
||||
canvas.frame_button.get_node("FrameID").add_color_override("font_color", Color("#3c5d75"))
|
||||
frame_ids.get_child(i).add_color_override("font_color", text_color)
|
||||
for layer in layers:
|
||||
if i < layer[2].get_child_count():
|
||||
layer[2].get_child(i).pressed = false
|
||||
i += 1
|
||||
|
||||
# Select the new canvas/frame
|
||||
canvas = canvases[current_frame]
|
||||
canvas.visible = true
|
||||
frame_ids.get_child(current_frame).add_color_override("font_color", Color("#3c5d75"))
|
||||
if current_frame < layers[current_layer][2].get_child_count():
|
||||
layers[current_layer][2].get_child(current_frame).pressed = true
|
||||
|
||||
func layer_changed(value : int) -> void:
|
||||
current_layer = value
|
||||
layer_opacity_slider.value = canvas.layers[current_layer][2] * 100
|
||||
layer_opacity_spinbox.value = canvas.layers[current_layer][2] * 100
|
||||
|
||||
for container in layers_container.get_children():
|
||||
container.pressed = false
|
||||
|
||||
if current_layer < layers_container.get_child_count():
|
||||
var layer_button = layers_container.get_child(layers_container.get_child_count() - 1 - current_layer)
|
||||
layer_button.pressed = true
|
||||
|
||||
if current_layer < layers.size() - 1:
|
||||
move_up_layer_button.disabled = false
|
||||
move_up_layer_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
|
||||
else:
|
||||
move_up_layer_button.disabled = true
|
||||
move_up_layer_button.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN
|
||||
|
||||
if current_layer > 0:
|
||||
move_down_layer_button.disabled = false
|
||||
move_down_layer_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
|
||||
merge_down_layer_button.disabled = false
|
||||
merge_down_layer_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
|
||||
else:
|
||||
move_down_layer_button.disabled = true
|
||||
move_down_layer_button.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN
|
||||
merge_down_layer_button.disabled = true
|
||||
merge_down_layer_button.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN
|
||||
|
||||
yield(get_tree().create_timer(0.01), "timeout")
|
||||
self.current_frame = current_frame # Call frame_changed to update UI
|
||||
|
||||
func create_brush_button(brush_img : Image, brush_type := Brush_Types.CUSTOM, hint_tooltip := "") -> void:
|
||||
var brush_container
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
class_name LayerContainer
|
||||
extends Button
|
||||
|
||||
var i
|
||||
# warning-ignore:unused_class_variable
|
||||
var currently_selected := false
|
||||
|
||||
onready var visibility_button := $VisibilityButton
|
||||
onready var label := $HBoxContainer/Label
|
||||
onready var line_edit := $HBoxContainer/LineEdit
|
||||
var i := 0
|
||||
var visibility_button : BaseButton
|
||||
var label : Label
|
||||
var line_edit : LineEdit
|
||||
|
||||
func _ready() -> void:
|
||||
changed_selection()
|
||||
if Global.canvas.layers[i][3]:
|
||||
visibility_button = Global.find_node_by_name(self, "VisibilityButton")
|
||||
label = Global.find_node_by_name(self, "Label")
|
||||
line_edit = Global.find_node_by_name(self, "LineEdit")
|
||||
|
||||
if Global.layers[i][1]:
|
||||
visibility_button.texture_normal = load("res://Assets/Graphics/%s Themes/Layers/Layer_Visible.png" % Global.theme_type)
|
||||
visibility_button.texture_hover = load("res://Assets/Graphics/%s Themes/Layers/Layer_Visible_Hover.png" % Global.theme_type)
|
||||
else:
|
||||
|
@ -23,68 +23,31 @@ func _input(event : InputEvent) -> void:
|
|||
label.visible = true
|
||||
line_edit.visible = false
|
||||
line_edit.editable = false
|
||||
var new_text : String = line_edit.text
|
||||
label.text = new_text
|
||||
Global.layers[i][0] = new_text
|
||||
|
||||
func _on_LayerContainer_pressed() -> void:
|
||||
var initially_pressed := pressed
|
||||
pressed = !pressed
|
||||
var label_initially_visible : bool = label.visible
|
||||
Global.canvas.current_layer_index = i
|
||||
changed_selection()
|
||||
if !initially_pressed:
|
||||
if label_initially_visible:
|
||||
label.visible = false
|
||||
line_edit.visible = true
|
||||
line_edit.editable = true
|
||||
line_edit.grab_focus()
|
||||
else:
|
||||
label.visible = true
|
||||
line_edit.visible = false
|
||||
line_edit.editable = false
|
||||
|
||||
func changed_selection() -> void:
|
||||
var parent := get_parent()
|
||||
for child in parent.get_children():
|
||||
if child is Button:
|
||||
child.label.visible = true
|
||||
child.line_edit.visible = false
|
||||
child.line_edit.editable = false
|
||||
if Global.canvas.current_layer_index == child.i: # The selected layer
|
||||
child.currently_selected = true
|
||||
child.pressed = true
|
||||
Global.layer_opacity_slider.value = Global.canvas.layers[child.i][4] * 100
|
||||
Global.layer_opacity_spinbox.value = Global.canvas.layers[child.i][4] * 100
|
||||
|
||||
if Global.canvas.current_layer_index < Global.canvas.layers.size() - 1:
|
||||
Global.move_up_layer_button.disabled = false
|
||||
Global.move_up_layer_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
|
||||
else:
|
||||
Global.move_up_layer_button.disabled = true
|
||||
Global.move_up_layer_button.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN
|
||||
|
||||
if Global.canvas.current_layer_index > 0:
|
||||
Global.move_down_layer_button.disabled = false
|
||||
Global.move_down_layer_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
|
||||
Global.merge_down_layer_button.disabled = false
|
||||
Global.merge_down_layer_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
|
||||
else:
|
||||
Global.move_down_layer_button.disabled = true
|
||||
Global.move_down_layer_button.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN
|
||||
Global.merge_down_layer_button.disabled = true
|
||||
Global.merge_down_layer_button.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN
|
||||
else:
|
||||
child.currently_selected = false
|
||||
child.pressed = false
|
||||
if label_initially_visible:
|
||||
label.visible = false
|
||||
line_edit.visible = true
|
||||
line_edit.editable = true
|
||||
line_edit.grab_focus()
|
||||
else:
|
||||
label.visible = true
|
||||
line_edit.visible = false
|
||||
line_edit.editable = false
|
||||
|
||||
func _on_VisibilityButton_pressed() -> void:
|
||||
if Global.canvas.layers[i][3]:
|
||||
Global.canvas.layers[i][3] = false
|
||||
if Global.layers[i][1]:
|
||||
Global.layers[i][1] = false
|
||||
visibility_button.texture_normal = load("res://Assets/Graphics/%s Themes/Layers/Layer_Invisible.png" % Global.theme_type)
|
||||
visibility_button.texture_hover = load("res://Assets/Graphics/%s Themes/Layers/Layer_Invisible_Hover.png" % Global.theme_type)
|
||||
else:
|
||||
Global.canvas.layers[i][3] = true
|
||||
Global.layers[i][1] = true
|
||||
visibility_button.texture_normal = load("res://Assets/Graphics/%s Themes/Layers/Layer_Visible.png" % Global.theme_type)
|
||||
visibility_button.texture_hover = load("res://Assets/Graphics/%s Themes/Layers/Layer_Visible_Hover.png" % Global.theme_type)
|
||||
Global.canvas.update()
|
||||
|
||||
func _on_LineEdit_text_changed(new_text : String) -> void:
|
||||
Global.canvas.layers[i][2] = new_text
|
||||
label.text = new_text
|
||||
|
|
173
Scripts/Main.gd
173
Scripts/Main.gd
|
@ -163,8 +163,9 @@ func _ready() -> void:
|
|||
|
||||
Global.window_title = "(" + tr("untitled") + ") - Pixelorama"
|
||||
|
||||
Global.canvas.layers[0][2] = tr("Layer") + " 0"
|
||||
Global.canvas.generate_layer_panels()
|
||||
Global.layers[0][0] = tr("Layer") + " 0"
|
||||
Global.layers_container.get_child(0).label.text = Global.layers[0][0]
|
||||
Global.layers_container.get_child(0).line_edit.text = Global.layers[0][0]
|
||||
|
||||
Import.import_brushes("Brushes")
|
||||
|
||||
|
@ -331,23 +332,23 @@ func image_menu_id_pressed(id : int) -> void:
|
|||
2: # Flip Horizontal
|
||||
var canvas : Canvas = Global.canvas
|
||||
canvas.handle_undo("Draw")
|
||||
canvas.layers[canvas.current_layer_index][0].unlock()
|
||||
canvas.layers[canvas.current_layer_index][0].flip_x()
|
||||
canvas.layers[canvas.current_layer_index][0].lock()
|
||||
canvas.layers[Global.current_layer][0].unlock()
|
||||
canvas.layers[Global.current_layer][0].flip_x()
|
||||
canvas.layers[Global.current_layer][0].lock()
|
||||
canvas.handle_redo("Draw")
|
||||
3: # Flip Vertical
|
||||
var canvas : Canvas = Global.canvas
|
||||
canvas.handle_undo("Draw")
|
||||
canvas.layers[canvas.current_layer_index][0].unlock()
|
||||
canvas.layers[canvas.current_layer_index][0].flip_y()
|
||||
canvas.layers[canvas.current_layer_index][0].lock()
|
||||
canvas.layers[Global.current_layer][0].unlock()
|
||||
canvas.layers[Global.current_layer][0].flip_y()
|
||||
canvas.layers[Global.current_layer][0].lock()
|
||||
canvas.handle_redo("Draw")
|
||||
4: # Rotate
|
||||
var image : Image = Global.canvas.layers[Global.canvas.current_layer_index][0]
|
||||
var image : Image = Global.canvas.layers[Global.current_layer][0]
|
||||
$RotateImage.set_sprite(image)
|
||||
$RotateImage.popup_centered()
|
||||
5: # Invert Colors
|
||||
var image : Image = Global.canvas.layers[Global.canvas.current_layer_index][0]
|
||||
var image : Image = Global.canvas.layers[Global.current_layer][0]
|
||||
Global.canvas.handle_undo("Draw")
|
||||
for xx in image.get_size().x:
|
||||
for yy in image.get_size().y:
|
||||
|
@ -357,7 +358,7 @@ func image_menu_id_pressed(id : int) -> void:
|
|||
image.set_pixel(xx, yy, px_color)
|
||||
Global.canvas.handle_redo("Draw")
|
||||
6: # Desaturation
|
||||
var image : Image = Global.canvas.layers[Global.canvas.current_layer_index][0]
|
||||
var image : Image = Global.canvas.layers[Global.current_layer][0]
|
||||
Global.canvas.handle_undo("Draw")
|
||||
for xx in image.get_size().x:
|
||||
for yy in image.get_size().y:
|
||||
|
@ -398,7 +399,18 @@ func _on_OpenSprite_file_selected(path : String) -> void:
|
|||
var version_number = float(version.substr(1, 3)) # Example, "0.6"
|
||||
if current_version_number < 0.5:
|
||||
OS.alert("File is from an older version of Pixelorama, as such it might not work properly")
|
||||
|
||||
var frame := 0
|
||||
Global.layers.clear()
|
||||
if (version_number - 0.01) > 0.6:
|
||||
var global_layer_line := file.get_line()
|
||||
while global_layer_line == ".":
|
||||
var layer_name := file.get_line()
|
||||
var layer_visibility := file.get_8()
|
||||
# Store [Layer name, Layer visibility boolean, Frame container]
|
||||
Global.layers.append([layer_name, layer_visibility, HBoxContainer.new()])
|
||||
global_layer_line = file.get_line()
|
||||
|
||||
var frame_line := file.get_line()
|
||||
clear_canvases()
|
||||
while frame_line == "--": # Load frames
|
||||
|
@ -408,9 +420,12 @@ func _on_OpenSprite_file_selected(path : String) -> void:
|
|||
var height := file.get_16()
|
||||
|
||||
var layer_line := file.get_line()
|
||||
while layer_line == "-": #Load layers
|
||||
while layer_line == "-": # Load layers
|
||||
var buffer := file.get_buffer(width * height * 4)
|
||||
var layer_name := file.get_line()
|
||||
if version_number < (0.7 - 0.01):
|
||||
var layer_name_old_version = file.get_line()
|
||||
if frame == 0:
|
||||
Global.layers.append([layer_name_old_version, true, HBoxContainer.new()])
|
||||
var layer_transparency := 1.0
|
||||
if version_number > 0.5:
|
||||
layer_transparency = file.get_float()
|
||||
|
@ -419,7 +434,7 @@ func _on_OpenSprite_file_selected(path : String) -> void:
|
|||
image.lock()
|
||||
var tex := ImageTexture.new()
|
||||
tex.create_from_image(image, 0)
|
||||
canvas.layers.append([image, tex, layer_name, true, layer_transparency])
|
||||
canvas.layers.append([image, tex, layer_transparency])
|
||||
layer_line = file.get_line()
|
||||
|
||||
var guide_line := file.get_line() # "guideline" no pun intended
|
||||
|
@ -444,7 +459,9 @@ func _on_OpenSprite_file_selected(path : String) -> void:
|
|||
frame_line = file.get_line()
|
||||
frame += 1
|
||||
|
||||
Global.canvases = Global.canvases # Just to call Global.canvases_changed
|
||||
Global.current_frame = frame - 1
|
||||
Global.layers = Global.layers # Just to call Global.layers_changed
|
||||
# Load tool options
|
||||
Global.left_color_picker.color = file.get_var()
|
||||
Global.right_color_picker.color = file.get_var()
|
||||
|
@ -452,12 +469,13 @@ func _on_OpenSprite_file_selected(path : String) -> void:
|
|||
Global.left_brush_size_edit.value = Global.left_brush_size
|
||||
Global.right_brush_size = file.get_8()
|
||||
Global.right_brush_size_edit.value = Global.right_brush_size
|
||||
var left_palette = file.get_var()
|
||||
var right_palette = file.get_var()
|
||||
for color in left_palette:
|
||||
Global.left_color_picker.get_picker().add_preset(color)
|
||||
for color in right_palette:
|
||||
Global.right_color_picker.get_picker().add_preset(color)
|
||||
if version_number < (0.7 - 0.01):
|
||||
var left_palette = file.get_var()
|
||||
var right_palette = file.get_var()
|
||||
for color in left_palette:
|
||||
Global.left_color_picker.get_picker().add_preset(color)
|
||||
for color in right_palette:
|
||||
Global.right_color_picker.get_picker().add_preset(color)
|
||||
|
||||
# Load custom brushes
|
||||
Global.custom_brushes.resize(Global.brushes_from_files)
|
||||
|
@ -496,18 +514,24 @@ func _on_SaveSprite_file_selected(path : String) -> void:
|
|||
var err := file.open(path, File.WRITE)
|
||||
if err == OK:
|
||||
file.store_line(ProjectSettings.get_setting("application/config/Version"))
|
||||
|
||||
for layer in Global.layers: # Store Global layers
|
||||
file.store_line(".")
|
||||
file.store_line(layer[0]) # Layer name
|
||||
file.store_8(layer[1]) # Layer visibility
|
||||
file.store_line("END_GLOBAL_LAYERS")
|
||||
|
||||
for canvas in Global.canvases: # Store frames
|
||||
file.store_line("--")
|
||||
file.store_16(canvas.size.x)
|
||||
file.store_16(canvas.size.y)
|
||||
for layer in canvas.layers: # Store layers
|
||||
for layer in canvas.layers: # Store canvas layers
|
||||
file.store_line("-")
|
||||
file.store_buffer(layer[0].get_data())
|
||||
file.store_line(layer[2]) # Layer name
|
||||
file.store_float(layer[4]) # Layer transparency
|
||||
file.store_float(layer[2]) # Layer transparency
|
||||
file.store_line("END_LAYERS")
|
||||
|
||||
for child in canvas.get_children(): #Store guides
|
||||
for child in canvas.get_children(): # Store guides
|
||||
if child is Guide:
|
||||
file.store_line("|")
|
||||
file.store_8(child.type)
|
||||
|
@ -521,19 +545,15 @@ func _on_SaveSprite_file_selected(path : String) -> void:
|
|||
file.store_line("END_FRAMES")
|
||||
|
||||
# Save tool options
|
||||
var left_color: Color = Global.left_color_picker.color
|
||||
var right_color: Color = Global.right_color_picker.color
|
||||
var left_brush_size: int = Global.left_brush_size
|
||||
var right_brush_size: int = Global.right_brush_size
|
||||
var left_palette: PoolColorArray = Global.left_color_picker.get_picker().get_presets()
|
||||
var right_palette: PoolColorArray = Global.right_color_picker.get_picker().get_presets()
|
||||
var left_color : Color = Global.left_color_picker.color
|
||||
var right_color : Color = Global.right_color_picker.color
|
||||
var left_brush_size : int = Global.left_brush_size
|
||||
var right_brush_size : int = Global.right_brush_size
|
||||
file.store_var(left_color)
|
||||
file.store_var(right_color)
|
||||
file.store_8(left_brush_size)
|
||||
file.store_8(right_brush_size)
|
||||
file.store_var(left_palette)
|
||||
file.store_var(right_palette)
|
||||
#Save custom brushes
|
||||
# Save custom brushes
|
||||
for i in range(Global.brushes_from_files, Global.custom_brushes.size()):
|
||||
var brush = Global.custom_brushes[i]
|
||||
file.store_line("/")
|
||||
|
@ -551,11 +571,6 @@ func _on_SaveSprite_file_selected(path : String) -> void:
|
|||
_on_QuitDialog_confirmed()
|
||||
|
||||
func clear_canvases() -> 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()
|
||||
|
@ -687,86 +702,6 @@ func _on_RightBrushSizeEdit_value_changed(value) -> void:
|
|||
Global.right_brush_size = new_size
|
||||
update_right_custom_brush()
|
||||
|
||||
func add_layer(is_new := true) -> void:
|
||||
var new_layer := Image.new()
|
||||
var layer_name = null
|
||||
if is_new:
|
||||
new_layer.create(Global.canvas.size.x, Global.canvas.size.y, false, Image.FORMAT_RGBA8)
|
||||
else: # clone layer
|
||||
new_layer.copy_from(Global.canvas.layers[Global.canvas.current_layer_index][0])
|
||||
layer_name = Global.canvas.layers[Global.canvas.current_layer_index][2] + " (" + tr("copy") + ")"
|
||||
new_layer.lock()
|
||||
var new_layer_tex := ImageTexture.new()
|
||||
new_layer_tex.create_from_image(new_layer, 0)
|
||||
|
||||
var new_layers: Array = Global.canvas.layers.duplicate()
|
||||
# Store [Image, ImageTexture, Layer Name, Visibity boolean, Opacity]
|
||||
new_layers.append([new_layer, new_layer_tex, layer_name, true, 1])
|
||||
Global.undos += 1
|
||||
Global.undo_redo.create_action("Add Layer")
|
||||
Global.undo_redo.add_do_property(Global.canvas, "layers", new_layers)
|
||||
Global.undo_redo.add_undo_property(Global.canvas, "layers", Global.canvas.layers)
|
||||
|
||||
Global.undo_redo.add_undo_method(Global, "undo", [Global.canvas])
|
||||
Global.undo_redo.add_do_method(Global, "redo", [Global.canvas])
|
||||
Global.undo_redo.commit_action()
|
||||
|
||||
func _on_RemoveLayerButton_pressed() -> void:
|
||||
var new_layers: Array = Global.canvas.layers.duplicate()
|
||||
new_layers.remove(Global.canvas.current_layer_index)
|
||||
Global.undos += 1
|
||||
Global.undo_redo.create_action("Remove Layer")
|
||||
Global.undo_redo.add_do_property(Global.canvas, "layers", new_layers)
|
||||
Global.undo_redo.add_undo_property(Global.canvas, "layers", Global.canvas.layers)
|
||||
|
||||
Global.undo_redo.add_undo_method(Global, "undo", [Global.canvas])
|
||||
Global.undo_redo.add_do_method(Global, "redo", [Global.canvas])
|
||||
Global.undo_redo.commit_action()
|
||||
|
||||
func change_layer_order(rate : int) -> void:
|
||||
var change = Global.canvas.current_layer_index + rate
|
||||
|
||||
var new_layers: Array = Global.canvas.layers.duplicate()
|
||||
var temp = new_layers[Global.canvas.current_layer_index]
|
||||
new_layers[Global.canvas.current_layer_index] = new_layers[change]
|
||||
new_layers[change] = temp
|
||||
Global.undo_redo.create_action("Change Layer Order")
|
||||
Global.undo_redo.add_do_property(Global.canvas, "layers", new_layers)
|
||||
Global.undo_redo.add_do_property(Global.canvas, "current_layer_index", change)
|
||||
Global.undo_redo.add_undo_property(Global.canvas, "layers", Global.canvas.layers)
|
||||
Global.undo_redo.add_undo_property(Global.canvas, "current_layer_index", Global.canvas.current_layer_index)
|
||||
|
||||
Global.undo_redo.add_undo_method(Global, "undo", [Global.canvas])
|
||||
Global.undo_redo.add_do_method(Global, "redo", [Global.canvas])
|
||||
Global.undo_redo.commit_action()
|
||||
|
||||
func _on_MergeLayer_pressed() -> void:
|
||||
var new_layers: Array = Global.canvas.layers.duplicate()
|
||||
new_layers.remove(Global.canvas.current_layer_index)
|
||||
var selected_layer = Global.canvas.layers[Global.canvas.current_layer_index][0]
|
||||
if Global.canvas.layers[Global.canvas.current_layer_index][4] < 1: # If we have layer transparency
|
||||
for xx in selected_layer.get_size().x:
|
||||
for yy in selected_layer.get_size().y:
|
||||
var pixel_color : Color = selected_layer.get_pixel(xx, yy)
|
||||
var alpha : float = pixel_color.a * Global.canvas.layers[Global.canvas.current_layer_index][4]
|
||||
selected_layer.set_pixel(xx, yy, Color(pixel_color.r, pixel_color.g, pixel_color.b, alpha))
|
||||
|
||||
var new_layer := Image.new()
|
||||
new_layer.copy_from(Global.canvas.layers[Global.canvas.current_layer_index - 1][0])
|
||||
new_layer.lock()
|
||||
|
||||
Global.canvas.blend_rect(new_layer, selected_layer, Rect2(Global.canvas.position, Global.canvas.size), Vector2.ZERO)
|
||||
|
||||
Global.undos += 1
|
||||
Global.undo_redo.create_action("Merge Layer")
|
||||
Global.undo_redo.add_do_property(Global.canvas, "layers", new_layers)
|
||||
Global.undo_redo.add_do_property(Global.canvas.layers[Global.canvas.current_layer_index - 1][0], "data", new_layer.data)
|
||||
Global.undo_redo.add_undo_property(Global.canvas, "layers", Global.canvas.layers)
|
||||
Global.undo_redo.add_undo_property(Global.canvas.layers[Global.canvas.current_layer_index - 1][0], "data", Global.canvas.layers[Global.canvas.current_layer_index - 1][0].data)
|
||||
|
||||
Global.undo_redo.add_undo_method(Global, "undo", [Global.canvas])
|
||||
Global.undo_redo.add_do_method(Global, "redo", [Global.canvas])
|
||||
Global.undo_redo.commit_action()
|
||||
|
||||
func _on_ColorSwitch_pressed() -> void:
|
||||
var temp: Color = Global.left_color_picker.color
|
||||
|
@ -853,7 +788,7 @@ func _on_RightVerticalMirroring_toggled(button_pressed) -> void:
|
|||
Global.right_vertical_mirror = button_pressed
|
||||
|
||||
func _on_OpacitySlider_value_changed(value) -> void:
|
||||
Global.canvas.layers[Global.canvas.current_layer_index][4] = value / 100
|
||||
Global.canvas.layers[Global.current_layer][4] = value / 100
|
||||
Global.layer_opacity_slider.value = value
|
||||
Global.layer_opacity_spinbox.value = value
|
||||
Global.canvas.update()
|
||||
|
|
|
@ -23,7 +23,7 @@ func _process(delta : float) -> void:
|
|||
var mouse_pos_floored := mouse_pos.floor()
|
||||
var start_pos := polygon[0]
|
||||
var end_pos := polygon[2]
|
||||
var current_layer_index: int = Global.canvas.current_layer_index
|
||||
var current_layer_index : int = Global.current_layer
|
||||
var layer : Image = Global.canvas.layers[current_layer_index][0]
|
||||
|
||||
if end_pos == start_pos:
|
||||
|
@ -59,7 +59,7 @@ func _process(delta : float) -> void:
|
|||
layer.set_pixelv(curr_px, Color(0, 0, 0, 0))
|
||||
else: # If part of selection is outside canvas
|
||||
orig_colors.append(Color(0, 0, 0, 0))
|
||||
Global.canvas.update_texture(Global.canvas.current_layer_index)
|
||||
Global.canvas.update_texture(current_layer_index)
|
||||
tex.create_from_image(img, 0)
|
||||
update()
|
||||
|
||||
|
@ -90,7 +90,7 @@ func _process(delta : float) -> void:
|
|||
var px = polygon[0] + Global.selected_pixels[i] - Global.selected_pixels[0]
|
||||
if point_in_rectangle(px, Global.canvas.location - Vector2.ONE, Global.canvas.size):
|
||||
layer.set_pixelv(px, orig_colors[i])
|
||||
Global.canvas.update_texture(Global.canvas.current_layer_index)
|
||||
Global.canvas.update_texture(current_layer_index)
|
||||
img.fill(Color(0, 0, 0, 0))
|
||||
tex.create_from_image(img, 0)
|
||||
update()
|
||||
|
@ -136,8 +136,6 @@ func _process(delta : float) -> void:
|
|||
layer.set_pixel(xx, yy, Color(0, 0, 0, 0))
|
||||
Global.canvas.handle_redo("Draw")
|
||||
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
if img.get_size() == polygon[2] - polygon[0]:
|
||||
draw_texture(tex, polygon[0], Color(1, 1, 1, 0.5))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue