1
0
Fork 0
mirror of https://github.com/Orama-Interactive/Pixelorama.git synced 2025-01-19 01: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
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
onready var animation_timer: Timer = $AnimationTimer
func _draw() -> void:
var current_project: Project = Global.current_project
if frame >= current_project.frames.size():
frame = current_project.current_frame
var texture_to_draw := ImageTexture.new()
var modulate_color := Color.white
match mode:
Mode.TIMELINE:
if frame >= current_project.frames.size():
frame = current_project.current_frame
$AnimationTimer.wait_time = (
current_project.frames[frame].duration
* (1 / Global.current_project.fps)
)
$AnimationTimer.wait_time = (
current_project.frames[frame].duration
* (1 / Global.current_project.fps)
)
if animation_timer.is_stopped():
frame = current_project.current_frame
var current_cels: Array = current_project.frames[frame].cels
if animation_timer.is_stopped():
frame = current_project.current_frame
var current_cels: Array = current_project.frames[frame].cels
# Draw current frame layers
for i in range(current_cels.size()):
if current_cels[i] is GroupCel:
continue
var modulate_color := Color(1, 1, 1, current_cels[i].opacity)
if (
i < current_project.layers.size()
and current_project.layers[i].is_visible_in_hierarchy()
):
draw_texture(current_cels[i].image_texture, Vector2.ZERO, modulate_color)
# Draw current frame layers
for i in range(current_cels.size()):
if current_cels[i] is GroupCel:
continue
modulate_color = Color(1, 1, 1, current_cels[i].opacity)
if (
i < current_project.layers.size()
and current_project.layers[i].is_visible_in_hierarchy()
):
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:
var first_frame := 0
var last_frame: int = Global.current_project.frames.size() - 1
var current_project: Project = Global.current_project
match mode:
Mode.TIMELINE:
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:
for tag in current_project.animation_tags:
if (
current_project.current_frame + 1 >= tag.from
&& current_project.current_frame + 1 <= tag.to
):
first_frame = tag.from - 1
last_frame = min(current_project.frames.size() - 1, tag.to - 1)
if Global.play_only_tags:
for tag in current_project.animation_tags:
if (
current_project.current_frame + 1 >= tag.from
&& current_project.current_frame + 1 <= tag.to
):
first_frame = tag.from - 1
last_frame = min(current_project.frames.size() - 1, tag.to - 1)
if frame < last_frame:
frame += 1
else:
frame = first_frame
if frame < last_frame:
frame += 1
else:
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.wait_time = (
Global.current_project.frames[frame].duration
* (1 / Global.current_project.fps)
)
$AnimationTimer.start()
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 )
[node name="AnimationTimer" type="Timer" parent="."]
[connection signal="timeout" from="AnimationTimer" to="." method="_on_AnimationTimer_timeout"]

View file

@ -1,8 +1,13 @@
extends PanelContainer
onready var canvas_preview = $HBoxContainer/PreviewViewportContainer/Viewport/CanvasPreview
onready var camera: Camera2D = $HBoxContainer/PreviewViewportContainer/Viewport/CameraPreview
onready var play_button: Button = $HBoxContainer/VBoxContainer/PlayButton
onready var canvas_preview: Node2D = $"%CanvasPreview"
onready var camera: Camera2D = $"%CameraPreview"
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:
@ -13,11 +18,55 @@ func _on_PreviewZoomSlider_value_changed(value: float) -> void:
func _on_PlayButton_toggled(button_pressed: bool) -> void:
if button_pressed:
if Global.current_project.frames.size() <= 1:
play_button.pressed = false
return
if canvas_preview.mode == canvas_preview.Mode.TIMELINE:
if Global.current_project.frames.size() <= 1:
play_button.pressed = false
return
else:
if start.value == end.value:
play_button.pressed = false
return
canvas_preview.animation_timer.start()
Global.change_button_texturerect(play_button.get_child(0), "pause.png")
else:
canvas_preview.animation_timer.stop()
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/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/Canvas/CanvasPreview.tscn" type="PackedScene" id=5]
[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]
shader = ExtResource( 2 )
@ -25,52 +26,89 @@ margin_bottom = 174.0
rect_min_size = Vector2( 0, 90 )
script = ExtResource( 4 )
[node name="HBoxContainer" type="HBoxContainer" parent="."]
[node name="VBox" type="VBoxContainer" parent="."]
margin_left = 7.0
margin_top = 7.0
margin_right = 321.0
margin_bottom = 167.0
[node name="VBoxContainer" type="VBoxContainer" parent="HBoxContainer"]
margin_right = 20.0
margin_bottom = 160.0
[node name="HBox" type="HBoxContainer" parent="VBox"]
margin_right = 314.0
margin_bottom = 136.0
size_flags_vertical = 3
[node name="Label" type="Label" parent="HBoxContainer/VBoxContainer"]
margin_left = 6.0
margin_right = 14.0
[node name="VBoxContainer" type="VBoxContainer" parent="VBox/HBox"]
margin_right = 16.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
size_flags_horizontal = 4
text = "+"
align = 1
[node name="PreviewZoomSlider" type="VSlider" parent="HBoxContainer/VBoxContainer"]
margin_left = 2.0
[node name="PreviewZoomSlider" type="VSlider" parent="VBox/HBox/VBoxContainer"]
margin_top = 18.0
margin_right = 18.0
margin_right = 16.0
margin_bottom = 118.0
mouse_default_cursor_shape = 2
size_flags_horizontal = 4
size_flags_vertical = 3
step = 0.01
[node name="Label2" type="Label" parent="HBoxContainer/VBoxContainer"]
margin_left = 7.0
[node name="Label2" type="Label" parent="VBox/HBox/VBoxContainer"]
margin_left = 5.0
margin_top = 122.0
margin_right = 12.0
margin_right = 10.0
margin_bottom = 136.0
size_flags_horizontal = 4
text = "-"
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_right = 20.0
margin_right = 314.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 )
mouse_default_cursor_shape = 2
size_flags_vertical = 0
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_top = 0.5
anchor_right = 0.5
@ -85,30 +123,121 @@ __meta__ = {
"_edit_use_anchors_": false
}
[node name="PreviewViewportContainer" type="ViewportContainer" parent="HBoxContainer"]
[node name="VBoxContainer" type="VBoxContainer" parent="VBox/Animation"]
margin_left = 24.0
margin_right = 314.0
margin_bottom = 160.0
margin_bottom = 20.0
size_flags_horizontal = 3
size_flags_vertical = 3
stretch = true
[node name="Viewport" type="Viewport" parent="HBoxContainer/PreviewViewportContainer"]
size = Vector2( 290, 160 )
transparent_bg = true
handle_input_locally = false
render_target_update_mode = 3
[node name="Mode" type="HBoxContainer" parent="VBox/Animation/VBoxContainer"]
margin_right = 290.0
margin_bottom = 20.0
[node name="TransparentChecker" parent="HBoxContainer/PreviewViewportContainer/Viewport" instance=ExtResource( 1 )]
material = SubResource( 1 )
[node name="Label" type="Label" parent="VBox/Animation/VBoxContainer/Mode"]
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"]
offset = Vector2( 32, 32 )
current = true
zoom = Vector2( 0.15, 0.15 )
script = ExtResource( 3 )
[node name="Options" parent="VBox/Animation/VBoxContainer" instance=ExtResource( 7 )]
visible = false
margin_top = 24.0
margin_right = 290.0
margin_bottom = 44.0
text = "Spritesheet Options"
[connection signal="value_changed" from="HBoxContainer/VBoxContainer/PreviewZoomSlider" to="." method="_on_PreviewZoomSlider_value_changed"]
[connection signal="toggled" from="HBoxContainer/VBoxContainer/PlayButton" to="." method="_on_PlayButton_toggled"]
[node name="GridContainer" type="GridContainer" parent="VBox/Animation/VBoxContainer/Options"]
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"]