2019-08-18 09:28:38 +00:00
|
|
|
class_name Canvas
|
2020-02-10 22:06:24 +00:00
|
|
|
extends Node2D
|
2019-08-18 09:28:38 +00:00
|
|
|
|
2020-05-01 17:47:10 +00:00
|
|
|
|
2019-08-18 09:28:38 +00:00
|
|
|
var location := Vector2.ZERO
|
2020-01-10 19:47:44 +00:00
|
|
|
var fill_color := Color(0, 0, 0, 0)
|
2019-12-28 13:14:54 +00:00
|
|
|
var current_pixel := Vector2.ZERO # pretty much same as mouse_pos, but can be accessed externally
|
2019-12-26 19:36:56 +00:00
|
|
|
var can_undo := true
|
2020-05-31 22:32:44 +00:00
|
|
|
var cursor_image_has_changed := false
|
2019-12-28 13:14:54 +00:00
|
|
|
var sprite_changed_this_frame := false # for optimization purposes
|
2019-08-18 09:28:38 +00:00
|
|
|
|
2020-08-17 19:54:33 +00:00
|
|
|
onready var grid = $Grid
|
2020-08-18 13:35:05 +00:00
|
|
|
onready var indicators = $Indicators
|
2020-08-17 19:54:33 +00:00
|
|
|
|
2020-04-27 15:09:54 +00:00
|
|
|
|
2019-08-18 09:28:38 +00:00
|
|
|
# Called when the node enters the scene tree for the first time.
|
|
|
|
func _ready() -> void:
|
2020-06-02 23:14:24 +00:00
|
|
|
var frame : Frame = new_empty_frame(true)
|
2020-06-04 18:05:36 +00:00
|
|
|
Global.current_project.frames.append(frame)
|
2020-07-21 21:11:33 +00:00
|
|
|
yield(get_tree().create_timer(0.2), "timeout")
|
2020-06-02 23:14:24 +00:00
|
|
|
camera_zoom()
|
2020-01-15 20:31:02 +00:00
|
|
|
|
2020-05-01 17:47:10 +00:00
|
|
|
|
2020-02-10 22:06:24 +00:00
|
|
|
func _draw() -> void:
|
2020-06-11 23:27:21 +00:00
|
|
|
Global.second_viewport.get_child(0).get_node("CanvasPreview").update()
|
|
|
|
Global.small_preview_viewport.get_child(0).get_node("CanvasPreview").update()
|
2020-06-04 18:05:36 +00:00
|
|
|
var current_cels : Array = Global.current_project.frames[Global.current_project.current_frame].cels
|
2020-06-04 20:20:20 +00:00
|
|
|
var size : Vector2 = Global.current_project.size
|
2020-03-26 18:56:30 +00:00
|
|
|
if Global.onion_skinning:
|
2020-05-31 22:32:44 +00:00
|
|
|
onion_skinning()
|
2020-02-10 22:06:24 +00:00
|
|
|
|
2020-01-18 19:06:47 +00:00
|
|
|
# Draw current frame layers
|
2020-06-04 18:05:36 +00:00
|
|
|
for i in range(Global.current_project.layers.size()):
|
2020-06-02 23:14:24 +00:00
|
|
|
var modulate_color := Color(1, 1, 1, current_cels[i].opacity)
|
2020-06-04 18:05:36 +00:00
|
|
|
if Global.current_project.layers[i].visible: # if it's visible
|
2020-06-02 23:14:24 +00:00
|
|
|
draw_texture(current_cels[i].image_texture, location, modulate_color)
|
2020-02-10 22:06:24 +00:00
|
|
|
|
|
|
|
if Global.tile_mode:
|
2020-06-02 23:14:24 +00:00
|
|
|
draw_texture(current_cels[i].image_texture, Vector2(location.x, location.y + size.y), modulate_color) # Down
|
|
|
|
draw_texture(current_cels[i].image_texture, Vector2(location.x - size.x, location.y + size.y), modulate_color) # Down Left
|
|
|
|
draw_texture(current_cels[i].image_texture, Vector2(location.x - size.x, location.y), modulate_color) # Left
|
|
|
|
draw_texture(current_cels[i].image_texture, location - size, modulate_color) # Up left
|
|
|
|
draw_texture(current_cels[i].image_texture, Vector2(location.x, location.y - size.y), modulate_color) # Up
|
|
|
|
draw_texture(current_cels[i].image_texture, Vector2(location.x + size.x, location.y - size.y), modulate_color) # Up right
|
|
|
|
draw_texture(current_cels[i].image_texture, Vector2(location.x + size.x, location.y), modulate_color) # Right
|
|
|
|
draw_texture(current_cels[i].image_texture, location + size, modulate_color) # Down right
|
2020-01-18 19:06:47 +00:00
|
|
|
|
2019-11-19 21:23:43 +00:00
|
|
|
|
2019-12-27 15:12:19 +00:00
|
|
|
func _input(event : InputEvent) -> void:
|
2019-12-27 15:38:43 +00:00
|
|
|
# Don't process anything below if the input isn't a mouse event, or Shift/Ctrl.
|
2019-12-27 15:12:19 +00:00
|
|
|
# This decreases CPU/GPU usage slightly.
|
|
|
|
if not event is InputEventMouse:
|
2020-07-09 12:22:17 +00:00
|
|
|
if not event is InputEventKey:
|
2019-12-27 15:38:43 +00:00
|
|
|
return
|
2020-07-09 12:22:17 +00:00
|
|
|
elif not event.scancode in [KEY_SHIFT, KEY_CONTROL]:
|
|
|
|
return
|
|
|
|
# elif not get_viewport_rect().has_point(event.position):
|
|
|
|
# return
|
2020-02-11 16:42:23 +00:00
|
|
|
|
2020-01-09 18:49:27 +00:00
|
|
|
current_pixel = get_local_mouse_position() + location
|
2020-01-15 23:38:44 +00:00
|
|
|
|
2020-01-15 20:47:56 +00:00
|
|
|
if Global.has_focus:
|
2019-12-26 19:36:56 +00:00
|
|
|
update()
|
2019-12-27 15:38:43 +00:00
|
|
|
|
|
|
|
sprite_changed_this_frame = false
|
2020-06-05 13:06:59 +00:00
|
|
|
|
2020-07-09 12:22:17 +00:00
|
|
|
var current_project : Project = Global.current_project
|
2019-10-29 21:22:38 +00:00
|
|
|
|
2020-05-30 22:07:08 +00:00
|
|
|
if Global.has_focus:
|
2020-05-31 22:32:44 +00:00
|
|
|
if !cursor_image_has_changed:
|
|
|
|
cursor_image_has_changed = true
|
2020-01-15 20:47:56 +00:00
|
|
|
if Global.show_left_tool_icon:
|
|
|
|
Global.left_cursor.visible = true
|
|
|
|
if Global.show_right_tool_icon:
|
|
|
|
Global.right_cursor.visible = true
|
|
|
|
else:
|
2020-05-31 22:32:44 +00:00
|
|
|
if cursor_image_has_changed:
|
|
|
|
cursor_image_has_changed = false
|
2020-01-15 20:47:56 +00:00
|
|
|
Global.left_cursor.visible = false
|
|
|
|
Global.right_cursor.visible = false
|
2019-10-29 21:22:38 +00:00
|
|
|
|
2020-07-09 12:22:17 +00:00
|
|
|
Tools.handle_draw(current_pixel.floor(), event)
|
|
|
|
|
2020-05-31 22:32:44 +00:00
|
|
|
if sprite_changed_this_frame:
|
2020-06-05 13:06:59 +00:00
|
|
|
update_texture(current_project.current_layer)
|
2020-05-31 22:32:44 +00:00
|
|
|
|
|
|
|
|
|
|
|
func camera_zoom() -> void:
|
|
|
|
# Set camera zoom based on the sprite size
|
2020-06-04 20:20:20 +00:00
|
|
|
var bigger_canvas_axis = max(Global.current_project.size.x, Global.current_project.size.y)
|
2020-05-31 22:32:44 +00:00
|
|
|
var zoom_max := Vector2(bigger_canvas_axis, bigger_canvas_axis) * 0.01
|
2020-06-05 18:03:34 +00:00
|
|
|
var cameras = [Global.camera, Global.camera2, Global.camera_preview]
|
|
|
|
for camera in cameras:
|
|
|
|
if zoom_max > Vector2.ONE:
|
|
|
|
camera.zoom_max = zoom_max
|
|
|
|
else:
|
|
|
|
camera.zoom_max = Vector2.ONE
|
2020-05-31 22:32:44 +00:00
|
|
|
|
2020-08-01 21:59:00 +00:00
|
|
|
if camera == Global.camera_preview:
|
|
|
|
Global.preview_zoom_slider.max_value = -camera.zoom_min.x
|
|
|
|
Global.preview_zoom_slider.min_value = -camera.zoom_max.x
|
|
|
|
|
2020-06-05 18:03:34 +00:00
|
|
|
camera.fit_to_frame(Global.current_project.size)
|
|
|
|
camera.save_values_to_project()
|
2020-05-31 22:32:44 +00:00
|
|
|
|
|
|
|
Global.transparent_checker._ready() # To update the rect size
|
|
|
|
|
|
|
|
|
2020-06-09 15:44:08 +00:00
|
|
|
func new_empty_frame(first_time := false, single_layer := false, size := Global.current_project.size) -> Frame:
|
2020-06-02 23:14:24 +00:00
|
|
|
var frame := Frame.new()
|
2020-06-05 15:19:05 +00:00
|
|
|
for l in Global.current_project.layers: # Create as many cels as there are layers
|
2020-06-02 23:14:24 +00:00
|
|
|
# The sprite itself
|
|
|
|
var sprite := Image.new()
|
|
|
|
if first_time:
|
2020-06-04 20:20:20 +00:00
|
|
|
if Global.config_cache.has_section_key("preferences", "default_image_width"):
|
|
|
|
Global.current_project.size.x = Global.config_cache.get_value("preferences", "default_image_width")
|
|
|
|
if Global.config_cache.has_section_key("preferences", "default_image_height"):
|
|
|
|
Global.current_project.size.y = Global.config_cache.get_value("preferences", "default_image_height")
|
2020-06-02 23:14:24 +00:00
|
|
|
if Global.config_cache.has_section_key("preferences", "default_fill_color"):
|
|
|
|
fill_color = Global.config_cache.get_value("preferences", "default_fill_color")
|
2020-06-09 15:44:08 +00:00
|
|
|
sprite.create(size.x, size.y, false, Image.FORMAT_RGBA8)
|
2020-06-02 23:14:24 +00:00
|
|
|
sprite.fill(fill_color)
|
|
|
|
sprite.lock()
|
|
|
|
frame.cels.append(Cel.new(sprite, 1))
|
|
|
|
|
2020-06-05 15:19:05 +00:00
|
|
|
if single_layer:
|
|
|
|
break
|
|
|
|
|
2020-06-02 23:14:24 +00:00
|
|
|
return frame
|
|
|
|
|
|
|
|
|
2020-07-24 00:22:12 +00:00
|
|
|
func handle_undo(action : String, project : Project = Global.current_project, layer_index := -2, frame_index := -2) -> void:
|
2019-12-26 19:36:56 +00:00
|
|
|
if !can_undo:
|
|
|
|
return
|
2020-07-24 00:22:12 +00:00
|
|
|
|
|
|
|
if layer_index <= -2:
|
|
|
|
layer_index = project.current_layer
|
|
|
|
if frame_index <= -2:
|
|
|
|
frame_index = project.current_frame
|
|
|
|
|
|
|
|
var cels := []
|
2020-06-02 23:14:24 +00:00
|
|
|
var frames := []
|
2020-07-24 00:22:12 +00:00
|
|
|
var layers := []
|
|
|
|
if frame_index == -1:
|
|
|
|
frames = project.frames
|
|
|
|
else:
|
|
|
|
frames.append(project.frames[frame_index])
|
|
|
|
|
|
|
|
if layer_index == -1:
|
|
|
|
layers = project.layers
|
|
|
|
else:
|
|
|
|
layers.append(project.layers[layer_index])
|
|
|
|
|
2020-06-02 23:14:24 +00:00
|
|
|
for f in frames:
|
2020-07-24 00:22:12 +00:00
|
|
|
for l in layers:
|
|
|
|
var index = project.layers.find(l)
|
|
|
|
cels.append(f.cels[index])
|
|
|
|
|
|
|
|
project.undos += 1
|
|
|
|
project.undo_redo.create_action(action)
|
|
|
|
for cel in cels:
|
|
|
|
# If we don't unlock the image, it doesn't work properly
|
|
|
|
cel.image.unlock()
|
|
|
|
var data = cel.image.data
|
|
|
|
cel.image.lock()
|
|
|
|
project.undo_redo.add_undo_property(cel.image, "data", data)
|
2020-07-24 00:41:10 +00:00
|
|
|
project.undo_redo.add_undo_method(Global, "undo", frame_index, layer_index, project)
|
2019-10-29 21:22:38 +00:00
|
|
|
|
2019-12-26 19:36:56 +00:00
|
|
|
can_undo = false
|
|
|
|
|
2020-05-01 17:47:10 +00:00
|
|
|
|
2020-07-24 00:22:12 +00:00
|
|
|
func handle_redo(_action : String, project : Project = Global.current_project, layer_index := -2, frame_index := -2) -> void:
|
2020-02-11 18:05:37 +00:00
|
|
|
can_undo = true
|
2020-07-24 00:22:12 +00:00
|
|
|
if project.undos < project.undo_redo.get_version():
|
2019-10-31 23:41:02 +00:00
|
|
|
return
|
2020-07-24 00:22:12 +00:00
|
|
|
|
|
|
|
if layer_index <= -2:
|
|
|
|
layer_index = project.current_layer
|
|
|
|
if frame_index <= -2:
|
|
|
|
frame_index = project.current_frame
|
|
|
|
|
|
|
|
var cels := []
|
2020-06-02 23:14:24 +00:00
|
|
|
var frames := []
|
2020-07-24 00:22:12 +00:00
|
|
|
var layers := []
|
|
|
|
if frame_index == -1:
|
|
|
|
frames = project.frames
|
|
|
|
else:
|
|
|
|
frames.append(project.frames[frame_index])
|
|
|
|
|
|
|
|
if layer_index == -1:
|
|
|
|
layers = project.layers
|
2019-11-05 16:19:41 +00:00
|
|
|
else:
|
2020-07-24 00:22:12 +00:00
|
|
|
layers.append(project.layers[layer_index])
|
|
|
|
|
2020-06-02 23:14:24 +00:00
|
|
|
for f in frames:
|
2020-07-24 00:22:12 +00:00
|
|
|
for l in layers:
|
|
|
|
var index = project.layers.find(l)
|
|
|
|
cels.append(f.cels[index])
|
|
|
|
|
|
|
|
for cel in cels:
|
|
|
|
project.undo_redo.add_do_property(cel.image, "data", cel.image.data)
|
2020-07-24 00:41:10 +00:00
|
|
|
project.undo_redo.add_do_method(Global, "redo", frame_index, layer_index, project)
|
2020-07-24 00:22:12 +00:00
|
|
|
project.undo_redo.commit_action()
|
2019-10-29 21:22:38 +00:00
|
|
|
|
2020-05-01 17:47:10 +00:00
|
|
|
|
2020-07-24 00:41:10 +00:00
|
|
|
func update_texture(layer_index : int, frame_index := -1, project : Project = Global.current_project) -> void:
|
2020-06-02 23:14:24 +00:00
|
|
|
if frame_index == -1:
|
2020-07-24 00:41:10 +00:00
|
|
|
frame_index = project.current_frame
|
|
|
|
var current_cel : Cel = project.frames[frame_index].cels[layer_index]
|
2020-06-02 23:14:24 +00:00
|
|
|
current_cel.image_texture.create_from_image(current_cel.image, 0)
|
2020-03-04 23:53:48 +00:00
|
|
|
|
2020-07-24 00:41:10 +00:00
|
|
|
if project == Global.current_project:
|
|
|
|
var frame_texture_rect : TextureRect
|
|
|
|
frame_texture_rect = Global.find_node_by_name(project.layers[layer_index].frame_container.get_child(frame_index), "CelTexture")
|
|
|
|
frame_texture_rect.texture = current_cel.image_texture
|
2019-08-18 09:28:38 +00:00
|
|
|
|
2020-05-01 17:47:10 +00:00
|
|
|
|
2020-05-31 22:32:44 +00:00
|
|
|
func onion_skinning() -> void:
|
|
|
|
# Past
|
|
|
|
if Global.onion_skinning_past_rate > 0:
|
|
|
|
var color : Color
|
|
|
|
if Global.onion_skinning_blue_red:
|
|
|
|
color = Color.blue
|
|
|
|
else:
|
|
|
|
color = Color.white
|
|
|
|
for i in range(1, Global.onion_skinning_past_rate + 1):
|
2020-06-04 18:05:36 +00:00
|
|
|
if Global.current_project.current_frame >= i:
|
2020-05-31 22:32:44 +00:00
|
|
|
var layer_i := 0
|
2020-06-04 18:05:36 +00:00
|
|
|
for layer in Global.current_project.frames[Global.current_project.current_frame - i].cels:
|
|
|
|
if Global.current_project.layers[layer_i].visible:
|
2020-05-31 22:32:44 +00:00
|
|
|
color.a = 0.6 / i
|
2020-06-01 15:50:31 +00:00
|
|
|
draw_texture(layer.image_texture, location, color)
|
2020-05-31 22:32:44 +00:00
|
|
|
layer_i += 1
|
|
|
|
|
|
|
|
# Future
|
|
|
|
if Global.onion_skinning_future_rate > 0:
|
|
|
|
var color : Color
|
|
|
|
if Global.onion_skinning_blue_red:
|
|
|
|
color = Color.red
|
|
|
|
else:
|
|
|
|
color = Color.white
|
|
|
|
for i in range(1, Global.onion_skinning_future_rate + 1):
|
2020-06-04 18:05:36 +00:00
|
|
|
if Global.current_project.current_frame < Global.current_project.frames.size() - i:
|
2020-05-31 22:32:44 +00:00
|
|
|
var layer_i := 0
|
2020-06-04 18:05:36 +00:00
|
|
|
for layer in Global.current_project.frames[Global.current_project.current_frame + i].cels:
|
|
|
|
if Global.current_project.layers[layer_i].visible:
|
2020-05-31 22:32:44 +00:00
|
|
|
color.a = 0.6 / i
|
2020-06-01 15:50:31 +00:00
|
|
|
draw_texture(layer.image_texture, location, color)
|
2020-05-31 22:32:44 +00:00
|
|
|
layer_i += 1
|