1
0
Fork 0
mirror of https://github.com/Orama-Interactive/Pixelorama.git synced 2025-02-08 03:19:49 +00:00
Pixelorama/src/Canvas.gd

264 lines
10 KiB
GDScript3
Raw Normal View History

2019-08-18 09:28:38 +00:00
class_name Canvas
extends Node2D
2019-08-18 09:28:38 +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)
var current_pixel := Vector2.ZERO # pretty much same as mouse_pos, but can be accessed externally
var can_undo := true
2020-05-31 22:32:44 +00:00
var cursor_image_has_changed := false
var sprite_changed_this_frame := false # for optimization purposes
2019-08-18 09:28:38 +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:
var frame : Frame = new_empty_frame(true)
Global.current_project.frames.append(frame)
camera_zoom()
func _draw() -> void:
Global.second_viewport.get_child(0).get_node("CanvasPreview").update()
Global.small_preview_viewport.get_child(0).get_node("CanvasPreview").update()
var current_cels : Array = Global.current_project.frames[Global.current_project.current_frame].cels
var size : Vector2 = Global.current_project.size
if Global.onion_skinning:
2020-05-31 22:32:44 +00:00
onion_skinning()
# Draw current frame layers
for i in range(Global.current_project.layers.size()):
var modulate_color := Color(1, 1, 1, current_cels[i].opacity)
if Global.current_project.layers[i].visible: # if it's visible
draw_texture(current_cels[i].image_texture, location, modulate_color)
if Global.tile_mode:
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
if Global.draw_grid:
2020-05-31 22:32:44 +00:00
draw_grid(Global.grid_type)
# Draw rectangle to indicate the pixel currently being hovered on
if Global.has_focus and Global.can_draw:
Tools.draw_indicator()
func _input(event : InputEvent) -> void:
# Don't process anything below if the input isn't a mouse event, or Shift/Ctrl.
# This decreases CPU/GPU usage slightly.
if not event is InputEventMouse:
if not event is InputEventKey:
return
elif not event.scancode in [KEY_SHIFT, KEY_CONTROL]:
return
# elif not get_viewport_rect().has_point(event.position):
# return
2020-01-09 18:49:27 +00:00
current_pixel = get_local_mouse_position() + location
if Global.has_focus:
update()
sprite_changed_this_frame = false
var current_project : Project = Global.current_project
if Global.has_focus:
2020-05-31 22:32:44 +00:00
if !cursor_image_has_changed:
cursor_image_has_changed = true
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
Global.left_cursor.visible = false
Global.right_cursor.visible = false
Tools.handle_draw(current_pixel.floor(), event)
2020-05-31 22:32:44 +00:00
if sprite_changed_this_frame:
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
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
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
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
func new_empty_frame(first_time := false, single_layer := false, size := Global.current_project.size) -> Frame:
var frame := Frame.new()
for l in Global.current_project.layers: # Create as many cels as there are layers
# The sprite itself
var sprite := Image.new()
if first_time:
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")
if Global.config_cache.has_section_key("preferences", "default_fill_color"):
fill_color = Global.config_cache.get_value("preferences", "default_fill_color")
sprite.create(size.x, size.y, false, Image.FORMAT_RGBA8)
sprite.fill(fill_color)
sprite.lock()
frame.cels.append(Cel.new(sprite, 1))
if single_layer:
break
return frame
func handle_undo(action : String) -> void:
if !can_undo:
return
var frames := []
var frame_index := -1
var layer_index := -1
if Global.animation_timer.is_stopped(): # if we're not animating, store only the current canvas
frames.append(Global.current_project.frames[Global.current_project.current_frame])
frame_index = Global.current_project.current_frame
layer_index = Global.current_project.current_layer
else: # If we're animating, store all frames
frames = Global.current_project.frames
Global.current_project.undos += 1
Global.current_project.undo_redo.create_action(action)
for f in frames:
# I'm not sure why I have to unlock it, but...
# ...if I don't, it doesn't work properly
f.cels[Global.current_project.current_layer].image.unlock()
var data = f.cels[Global.current_project.current_layer].image.data
f.cels[Global.current_project.current_layer].image.lock()
Global.current_project.undo_redo.add_undo_property(f.cels[Global.current_project.current_layer].image, "data", data)
Global.current_project.undo_redo.add_undo_method(Global, "undo", frame_index, layer_index)
can_undo = false
func handle_redo(_action : String) -> void:
can_undo = true
if Global.current_project.undos < Global.current_project.undo_redo.get_version():
return
var frames := []
var frame_index := -1
var layer_index := -1
if Global.animation_timer.is_stopped():
frames.append(Global.current_project.frames[Global.current_project.current_frame])
frame_index = Global.current_project.current_frame
layer_index = Global.current_project.current_layer
else:
frames = Global.current_project.frames
for f in frames:
Global.current_project.undo_redo.add_do_property(f.cels[Global.current_project.current_layer].image, "data", f.cels[Global.current_project.current_layer].image.data)
Global.current_project.undo_redo.add_do_method(Global, "redo", frame_index, layer_index)
Global.current_project.undo_redo.commit_action()
func update_texture(layer_index : int, frame_index := -1) -> void:
if frame_index == -1:
frame_index = Global.current_project.current_frame
var current_cel : Cel = Global.current_project.frames[frame_index].cels[layer_index]
current_cel.image_texture.create_from_image(current_cel.image, 0)
var frame_texture_rect : TextureRect
frame_texture_rect = Global.find_node_by_name(Global.current_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-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):
if Global.current_project.current_frame >= i:
2020-05-31 22:32:44 +00:00
var layer_i := 0
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
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):
if Global.current_project.current_frame < Global.current_project.frames.size() - i:
2020-05-31 22:32:44 +00:00
var layer_i := 0
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
draw_texture(layer.image_texture, location, color)
2020-05-31 22:32:44 +00:00
layer_i += 1
func draw_grid(grid_type : int) -> void:
var size : Vector2 = Global.current_project.size
2020-05-31 22:32:44 +00:00
if grid_type == Global.Grid_Types.CARTESIAN || grid_type == Global.Grid_Types.ALL:
for x in range(Global.grid_width, size.x, Global.grid_width):
draw_line(Vector2(x, location.y), Vector2(x, size.y), Global.grid_color, true)
for y in range(Global.grid_height, size.y, Global.grid_height):
draw_line(Vector2(location.x, y), Vector2(size.x, y), Global.grid_color, true)
# Doesn't work properly yet
if grid_type == Global.Grid_Types.ISOMETRIC || grid_type == Global.Grid_Types.ALL:
var prev_x := 0
var prev_y := 0
for y in range(0, size.y + 1, Global.grid_width):
var yy1 = y + size.y * tan(deg2rad(26.565)) # 30 degrees
if yy1 <= (size.y + 0.01):
draw_line(Vector2(location.x, y), Vector2(size.x, yy1),Global.grid_color)
else:
var xx1 = (size.x - y) * tan(deg2rad(90 - 26.565)) # 60 degrees
draw_line(Vector2(location.x, y), Vector2(xx1, size.y), Global.grid_color)
for y in range(0, size.y + 1, Global.grid_height):
var xx2 = y * tan(deg2rad(90 - 26.565)) # 60 degrees
if xx2 <= (size.x + 0.01):
draw_line(Vector2(location.x, y), Vector2(xx2, location.y), Global.grid_color)
prev_y = location.y
else:
var distance = (xx2 - prev_x) / 2
#var yy2 = (size.y - y) * tan(deg2rad(26.565)) # 30 degrees
var yy2 = prev_y + distance
draw_line(Vector2(location.x, y), Vector2(size.x, yy2), Global.grid_color)
prev_y = yy2
prev_x = xx2
for x in range(0, size.x, Global.grid_width * 2):
if x == 0:
continue
var yy1 = (size.x - x) * tan(deg2rad(26.565)) # 30 degrees
draw_line(Vector2(x, location.y), Vector2(size.x, yy1), Global.grid_color)
for x in range(0, size.x, Global.grid_height * 2):
var yy2 = (size.x - x) * tan(deg2rad(26.565)) # 30 degrees
draw_line(Vector2(x, size.y), Vector2(size.x, size.y - yy2), Global.grid_color)