1
0
Fork 0
mirror of https://github.com/Orama-Interactive/Pixelorama.git synced 2025-01-31 07:29:49 +00:00

Spritesheet Animation Canvas Preview (#835)

* spritesheet preview

* formatting
This commit is contained in:
Variable 2023-03-23 18:25:33 +05:00 committed by GitHub
parent 4e7d5d34cf
commit 2ad1391ca1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 320 additions and 80 deletions

View file

@ -1,58 +1,119 @@
extends Node2D extends Node2D
enum Mode { TIMELINE, SPRITESHEET }
var mode = Mode.TIMELINE
var h_frames: int = 1
var v_frames: int = 1
var start_sprite_sheet_frame: int = 1
var end_sprite_sheet_frame: int = 1
var sprite_frames = []
var frame: int = 0 var frame: int = 0
onready var animation_timer: Timer = $AnimationTimer onready var animation_timer: Timer = $AnimationTimer
func _draw() -> void: func _draw() -> void:
var current_project: Project = Global.current_project var current_project: Project = Global.current_project
if frame >= current_project.frames.size(): var texture_to_draw := ImageTexture.new()
frame = current_project.current_frame var modulate_color := Color.white
match mode:
Mode.TIMELINE:
if frame >= current_project.frames.size():
frame = current_project.current_frame
$AnimationTimer.wait_time = ( $AnimationTimer.wait_time = (
current_project.frames[frame].duration current_project.frames[frame].duration
* (1 / Global.current_project.fps) * (1 / Global.current_project.fps)
) )
if animation_timer.is_stopped(): if animation_timer.is_stopped():
frame = current_project.current_frame frame = current_project.current_frame
var current_cels: Array = current_project.frames[frame].cels var current_cels: Array = current_project.frames[frame].cels
# Draw current frame layers # Draw current frame layers
for i in range(current_cels.size()): for i in range(current_cels.size()):
if current_cels[i] is GroupCel: if current_cels[i] is GroupCel:
continue continue
var modulate_color := Color(1, 1, 1, current_cels[i].opacity) modulate_color = Color(1, 1, 1, current_cels[i].opacity)
if ( if (
i < current_project.layers.size() i < current_project.layers.size()
and current_project.layers[i].is_visible_in_hierarchy() and current_project.layers[i].is_visible_in_hierarchy()
): ):
draw_texture(current_cels[i].image_texture, Vector2.ZERO, modulate_color) texture_to_draw = current_cels[i].image_texture
Mode.SPRITESHEET:
var target_frame = current_project.frames[current_project.current_frame]
var frame_image = Image.new()
frame_image.create(
current_project.size.x, current_project.size.y, false, Image.FORMAT_RGBA8
)
Export.blend_all_layers(frame_image, target_frame)
sprite_frames = split_spritesheet(frame_image, h_frames, v_frames)
# limit start and end
if end_sprite_sheet_frame > sprite_frames.size():
end_sprite_sheet_frame = sprite_frames.size()
if start_sprite_sheet_frame < 0:
start_sprite_sheet_frame = 0
# reset frame if required
if frame >= end_sprite_sheet_frame:
frame = start_sprite_sheet_frame - 1
texture_to_draw = sprite_frames[frame]
var rect = Rect2(Vector2.ZERO, texture_to_draw.get_data().get_size())
get_parent().get_node("TransparentChecker").fit_rect(rect)
draw_texture(texture_to_draw, Vector2.ZERO, modulate_color)
func _on_AnimationTimer_timeout() -> void: func _on_AnimationTimer_timeout() -> void:
var first_frame := 0 match mode:
var last_frame: int = Global.current_project.frames.size() - 1 Mode.TIMELINE:
var current_project: Project = Global.current_project var first_frame := 0
var last_frame: int = Global.current_project.frames.size() - 1
var current_project: Project = Global.current_project
if Global.play_only_tags: if Global.play_only_tags:
for tag in current_project.animation_tags: for tag in current_project.animation_tags:
if ( if (
current_project.current_frame + 1 >= tag.from current_project.current_frame + 1 >= tag.from
&& current_project.current_frame + 1 <= tag.to && current_project.current_frame + 1 <= tag.to
): ):
first_frame = tag.from - 1 first_frame = tag.from - 1
last_frame = min(current_project.frames.size() - 1, tag.to - 1) last_frame = min(current_project.frames.size() - 1, tag.to - 1)
if frame < last_frame: if frame < last_frame:
frame += 1 frame += 1
else: else:
frame = first_frame frame = first_frame
$AnimationTimer.wait_time = (
Global.current_project.frames[frame].duration
* (1 / Global.current_project.fps)
)
Mode.SPRITESHEET:
frame += 1
$AnimationTimer.wait_time = (1 / Global.current_project.fps)
$AnimationTimer.set_one_shot(true) $AnimationTimer.set_one_shot(true)
$AnimationTimer.wait_time = (
Global.current_project.frames[frame].duration
* (1 / Global.current_project.fps)
)
$AnimationTimer.start() $AnimationTimer.start()
update() update()
func split_spritesheet(image: Image, horiz: int, vert: int) -> Array:
var result = []
horiz = min(horiz, image.get_size().x)
vert = min(vert, image.get_size().y)
var frame_width := image.get_size().x / horiz
var frame_height := image.get_size().y / vert
for yy in range(vert):
for xx in range(horiz):
var tex := ImageTexture.new()
var cropped_image := Image.new()
cropped_image = image.get_rect(
Rect2(frame_width * xx, frame_height * yy, frame_width, frame_height)
)
cropped_image.convert(Image.FORMAT_RGBA8)
tex.create_from_image(cropped_image, 0)
result.append(tex)
return result

View file

@ -6,4 +6,5 @@
script = ExtResource( 1 ) script = ExtResource( 1 )
[node name="AnimationTimer" type="Timer" parent="."] [node name="AnimationTimer" type="Timer" parent="."]
[connection signal="timeout" from="AnimationTimer" to="." method="_on_AnimationTimer_timeout"] [connection signal="timeout" from="AnimationTimer" to="." method="_on_AnimationTimer_timeout"]

View file

@ -1,8 +1,13 @@
extends PanelContainer extends PanelContainer
onready var canvas_preview = $HBoxContainer/PreviewViewportContainer/Viewport/CanvasPreview onready var canvas_preview: Node2D = $"%CanvasPreview"
onready var camera: Camera2D = $HBoxContainer/PreviewViewportContainer/Viewport/CameraPreview onready var camera: Camera2D = $"%CameraPreview"
onready var play_button: Button = $HBoxContainer/VBoxContainer/PlayButton onready var play_button: Button = $"%PlayButton"
onready var h_frames: SpinBox = $"%HFrames"
onready var v_frames: SpinBox = $"%VFrames"
onready var start: SpinBox = $"%Start"
onready var end: SpinBox = $"%End"
func _on_PreviewZoomSlider_value_changed(value: float) -> void: func _on_PreviewZoomSlider_value_changed(value: float) -> void:
@ -13,11 +18,55 @@ func _on_PreviewZoomSlider_value_changed(value: float) -> void:
func _on_PlayButton_toggled(button_pressed: bool) -> void: func _on_PlayButton_toggled(button_pressed: bool) -> void:
if button_pressed: if button_pressed:
if Global.current_project.frames.size() <= 1: if canvas_preview.mode == canvas_preview.Mode.TIMELINE:
play_button.pressed = false if Global.current_project.frames.size() <= 1:
return play_button.pressed = false
return
else:
if start.value == end.value:
play_button.pressed = false
return
canvas_preview.animation_timer.start() canvas_preview.animation_timer.start()
Global.change_button_texturerect(play_button.get_child(0), "pause.png") Global.change_button_texturerect(play_button.get_child(0), "pause.png")
else: else:
canvas_preview.animation_timer.stop() canvas_preview.animation_timer.stop()
Global.change_button_texturerect(play_button.get_child(0), "play.png") Global.change_button_texturerect(play_button.get_child(0), "play.png")
func _on_OptionButton_item_selected(index: int) -> void:
play_button.pressed = false
canvas_preview.mode = index
$VBox/Animation/VBoxContainer/Options.visible = bool(index == 1)
canvas_preview.update()
func _on_HFrames_value_changed(value: float) -> void:
canvas_preview.h_frames = value
var frames = canvas_preview.h_frames * canvas_preview.v_frames
start.max_value = frames
end.max_value = frames
canvas_preview.update()
func _on_VFrames_value_changed(value: float) -> void:
canvas_preview.v_frames = value
var frames = canvas_preview.h_frames * canvas_preview.v_frames
start.max_value = frames
end.max_value = frames
canvas_preview.update()
func _on_Start_value_changed(value: float) -> void:
canvas_preview.frame = value - 1
canvas_preview.start_sprite_sheet_frame = value
if end.value < value:
end.value = value
canvas_preview.update()
func _on_End_value_changed(value: float) -> void:
canvas_preview.end_sprite_sheet_frame = value
if start.value > value:
start.value = value
canvas_preview.frame = value - 1
canvas_preview.update()

View file

@ -1,4 +1,4 @@
[gd_scene load_steps=8 format=2] [gd_scene load_steps=9 format=2]
[ext_resource path="res://src/UI/Nodes/TransparentChecker.tscn" type="PackedScene" id=1] [ext_resource path="res://src/UI/Nodes/TransparentChecker.tscn" type="PackedScene" id=1]
[ext_resource path="res://src/Shaders/TransparentChecker.shader" type="Shader" id=2] [ext_resource path="res://src/Shaders/TransparentChecker.shader" type="Shader" id=2]
@ -6,6 +6,7 @@
[ext_resource path="res://src/UI/CanvasPreviewContainer/CanvasPreviewContainer.gd" type="Script" id=4] [ext_resource path="res://src/UI/CanvasPreviewContainer/CanvasPreviewContainer.gd" type="Script" id=4]
[ext_resource path="res://src/UI/Canvas/CanvasPreview.tscn" type="PackedScene" id=5] [ext_resource path="res://src/UI/Canvas/CanvasPreview.tscn" type="PackedScene" id=5]
[ext_resource path="res://assets/graphics/timeline/play.png" type="Texture" id=6] [ext_resource path="res://assets/graphics/timeline/play.png" type="Texture" id=6]
[ext_resource path="res://src/UI/Nodes/CollapsibleContainer.tscn" type="PackedScene" id=7]
[sub_resource type="ShaderMaterial" id=1] [sub_resource type="ShaderMaterial" id=1]
shader = ExtResource( 2 ) shader = ExtResource( 2 )
@ -25,52 +26,89 @@ margin_bottom = 174.0
rect_min_size = Vector2( 0, 90 ) rect_min_size = Vector2( 0, 90 )
script = ExtResource( 4 ) script = ExtResource( 4 )
[node name="HBoxContainer" type="HBoxContainer" parent="."] [node name="VBox" type="VBoxContainer" parent="."]
margin_left = 7.0 margin_left = 7.0
margin_top = 7.0 margin_top = 7.0
margin_right = 321.0 margin_right = 321.0
margin_bottom = 167.0 margin_bottom = 167.0
[node name="VBoxContainer" type="VBoxContainer" parent="HBoxContainer"] [node name="HBox" type="HBoxContainer" parent="VBox"]
margin_right = 20.0 margin_right = 314.0
margin_bottom = 160.0 margin_bottom = 136.0
size_flags_vertical = 3
[node name="Label" type="Label" parent="HBoxContainer/VBoxContainer"] [node name="VBoxContainer" type="VBoxContainer" parent="VBox/HBox"]
margin_left = 6.0 margin_right = 16.0
margin_right = 14.0 margin_bottom = 136.0
[node name="Label" type="Label" parent="VBox/HBox/VBoxContainer"]
margin_left = 4.0
margin_right = 12.0
margin_bottom = 14.0 margin_bottom = 14.0
size_flags_horizontal = 4 size_flags_horizontal = 4
text = "+" text = "+"
align = 1 align = 1
[node name="PreviewZoomSlider" type="VSlider" parent="HBoxContainer/VBoxContainer"] [node name="PreviewZoomSlider" type="VSlider" parent="VBox/HBox/VBoxContainer"]
margin_left = 2.0
margin_top = 18.0 margin_top = 18.0
margin_right = 18.0 margin_right = 16.0
margin_bottom = 118.0 margin_bottom = 118.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
size_flags_horizontal = 4 size_flags_horizontal = 4
size_flags_vertical = 3 size_flags_vertical = 3
step = 0.01 step = 0.01
[node name="Label2" type="Label" parent="HBoxContainer/VBoxContainer"] [node name="Label2" type="Label" parent="VBox/HBox/VBoxContainer"]
margin_left = 7.0 margin_left = 5.0
margin_top = 122.0 margin_top = 122.0
margin_right = 12.0 margin_right = 10.0
margin_bottom = 136.0 margin_bottom = 136.0
size_flags_horizontal = 4 size_flags_horizontal = 4
text = "-" text = "-"
align = 1 align = 1
[node name="PlayButton" type="Button" parent="HBoxContainer/VBoxContainer" groups=["UIButtons"]] [node name="PreviewViewportContainer" type="ViewportContainer" parent="VBox/HBox"]
margin_left = 20.0
margin_right = 314.0
margin_bottom = 136.0
size_flags_horizontal = 3
size_flags_vertical = 3
stretch = true
[node name="Viewport" type="Viewport" parent="VBox/HBox/PreviewViewportContainer"]
size = Vector2( 294, 136 )
transparent_bg = true
handle_input_locally = false
render_target_update_mode = 3
[node name="TransparentChecker" parent="VBox/HBox/PreviewViewportContainer/Viewport" instance=ExtResource( 1 )]
material = SubResource( 1 )
[node name="CanvasPreview" parent="VBox/HBox/PreviewViewportContainer/Viewport" instance=ExtResource( 5 )]
unique_name_in_owner = true
[node name="CameraPreview" type="Camera2D" parent="VBox/HBox/PreviewViewportContainer/Viewport"]
unique_name_in_owner = true
offset = Vector2( 32, 32 )
current = true
zoom = Vector2( 0.15, 0.15 )
script = ExtResource( 3 )
[node name="Animation" type="HBoxContainer" parent="VBox"]
margin_top = 140.0 margin_top = 140.0
margin_right = 20.0 margin_right = 314.0
margin_bottom = 160.0 margin_bottom = 160.0
[node name="PlayButton" type="Button" parent="VBox/Animation" groups=["UIButtons"]]
unique_name_in_owner = true
margin_right = 20.0
margin_bottom = 20.0
rect_min_size = Vector2( 20, 0 ) rect_min_size = Vector2( 20, 0 )
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
size_flags_vertical = 0
toggle_mode = true toggle_mode = true
[node name="TextureRect" type="TextureRect" parent="HBoxContainer/VBoxContainer/PlayButton"] [node name="TextureRect" type="TextureRect" parent="VBox/Animation/PlayButton"]
anchor_left = 0.5 anchor_left = 0.5
anchor_top = 0.5 anchor_top = 0.5
anchor_right = 0.5 anchor_right = 0.5
@ -85,30 +123,121 @@ __meta__ = {
"_edit_use_anchors_": false "_edit_use_anchors_": false
} }
[node name="PreviewViewportContainer" type="ViewportContainer" parent="HBoxContainer"] [node name="VBoxContainer" type="VBoxContainer" parent="VBox/Animation"]
margin_left = 24.0 margin_left = 24.0
margin_right = 314.0 margin_right = 314.0
margin_bottom = 160.0 margin_bottom = 20.0
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 3
stretch = true
[node name="Viewport" type="Viewport" parent="HBoxContainer/PreviewViewportContainer"] [node name="Mode" type="HBoxContainer" parent="VBox/Animation/VBoxContainer"]
size = Vector2( 290, 160 ) margin_right = 290.0
transparent_bg = true margin_bottom = 20.0
handle_input_locally = false
render_target_update_mode = 3
[node name="TransparentChecker" parent="HBoxContainer/PreviewViewportContainer/Viewport" instance=ExtResource( 1 )] [node name="Label" type="Label" parent="VBox/Animation/VBoxContainer/Mode"]
material = SubResource( 1 ) margin_top = 3.0
margin_right = 114.0
margin_bottom = 17.0
text = "Animation Mode: "
[node name="CanvasPreview" parent="HBoxContainer/PreviewViewportContainer/Viewport" instance=ExtResource( 5 )] [node name="OptionButton" type="OptionButton" parent="VBox/Animation/VBoxContainer/Mode"]
margin_left = 118.0
margin_right = 290.0
margin_bottom = 20.0
size_flags_horizontal = 3
text = "Timeline Frames"
clip_text = true
align = 1
items = [ "Timeline Frames", null, false, 0, null, "Current Frame (As Spritesheet)", null, false, 1, null ]
selected = 0
[node name="CameraPreview" type="Camera2D" parent="HBoxContainer/PreviewViewportContainer/Viewport"] [node name="Options" parent="VBox/Animation/VBoxContainer" instance=ExtResource( 7 )]
offset = Vector2( 32, 32 ) visible = false
current = true margin_top = 24.0
zoom = Vector2( 0.15, 0.15 ) margin_right = 290.0
script = ExtResource( 3 ) margin_bottom = 44.0
text = "Spritesheet Options"
[connection signal="value_changed" from="HBoxContainer/VBoxContainer/PreviewZoomSlider" to="." method="_on_PreviewZoomSlider_value_changed"] [node name="GridContainer" type="GridContainer" parent="VBox/Animation/VBoxContainer/Options"]
[connection signal="toggled" from="HBoxContainer/VBoxContainer/PlayButton" to="." method="_on_PlayButton_toggled"] visible = false
margin_right = 290.0
margin_bottom = 52.0
columns = 4
[node name="Label" type="Label" parent="VBox/Animation/VBoxContainer/Options/GridContainer"]
margin_top = 5.0
margin_right = 65.0
margin_bottom = 19.0
text = "HFrames: "
align = 2
[node name="HFrames" type="SpinBox" parent="VBox/Animation/VBoxContainer/Options/GridContainer"]
unique_name_in_owner = true
margin_left = 69.0
margin_right = 143.0
margin_bottom = 24.0
min_value = 1.0
value = 1.0
allow_greater = true
[node name="Label2" type="Label" parent="VBox/Animation/VBoxContainer/Options/GridContainer"]
margin_left = 147.0
margin_top = 5.0
margin_right = 210.0
margin_bottom = 19.0
text = "VFrames: "
align = 2
[node name="VFrames" type="SpinBox" parent="VBox/Animation/VBoxContainer/Options/GridContainer"]
unique_name_in_owner = true
margin_left = 214.0
margin_right = 288.0
margin_bottom = 24.0
min_value = 1.0
value = 1.0
allow_greater = true
__meta__ = {
"_editor_description_": ""
}
[node name="Label3" type="Label" parent="VBox/Animation/VBoxContainer/Options/GridContainer"]
margin_top = 33.0
margin_right = 65.0
margin_bottom = 47.0
text = "Start: "
align = 2
[node name="Start" type="SpinBox" parent="VBox/Animation/VBoxContainer/Options/GridContainer"]
unique_name_in_owner = true
margin_left = 69.0
margin_top = 28.0
margin_right = 143.0
margin_bottom = 52.0
min_value = 1.0
max_value = 1.0
value = 1.0
[node name="Label4" type="Label" parent="VBox/Animation/VBoxContainer/Options/GridContainer"]
margin_left = 147.0
margin_top = 33.0
margin_right = 210.0
margin_bottom = 47.0
text = "End: "
align = 2
[node name="End" type="SpinBox" parent="VBox/Animation/VBoxContainer/Options/GridContainer"]
unique_name_in_owner = true
margin_left = 214.0
margin_top = 28.0
margin_right = 288.0
margin_bottom = 52.0
min_value = 1.0
max_value = 1.0
value = 1.0
[connection signal="value_changed" from="VBox/HBox/VBoxContainer/PreviewZoomSlider" to="." method="_on_PreviewZoomSlider_value_changed"]
[connection signal="toggled" from="VBox/Animation/PlayButton" to="." method="_on_PlayButton_toggled"]
[connection signal="item_selected" from="VBox/Animation/VBoxContainer/Mode/OptionButton" to="." method="_on_OptionButton_item_selected"]
[connection signal="value_changed" from="VBox/Animation/VBoxContainer/Options/GridContainer/HFrames" to="." method="_on_HFrames_value_changed"]
[connection signal="value_changed" from="VBox/Animation/VBoxContainer/Options/GridContainer/VFrames" to="." method="_on_VFrames_value_changed"]
[connection signal="value_changed" from="VBox/Animation/VBoxContainer/Options/GridContainer/Start" to="." method="_on_Start_value_changed"]
[connection signal="value_changed" from="VBox/Animation/VBoxContainer/Options/GridContainer/End" to="." method="_on_End_value_changed"]