mirror of
https://github.com/tonytins/CozyPixelStudio.git
synced 2025-06-25 07:04:43 -04:00
Replace godot-gifexporter with godot-gdgifexporter (#295)
Add exporting in a separate thread and a progress bar Remove background color option from gif export
This commit is contained in:
parent
e4aa17b01c
commit
f3bce3857a
16 changed files with 1073 additions and 80 deletions
|
@ -1,5 +1,9 @@
|
|||
extends Node
|
||||
|
||||
# Gif exporter
|
||||
const gifexporter = preload("res://addons/gdgifexporter/gifexporter.gd")
|
||||
var quantization = preload("res://addons/gdgifexporter/quantization/median_cut.gd").new()
|
||||
|
||||
enum ExportTab { FRAME = 0, SPRITESHEET = 1, ANIMATION = 2 }
|
||||
var current_tab : int = ExportTab.FRAME
|
||||
|
||||
|
@ -20,7 +24,6 @@ var lines_count := 1
|
|||
# Animation options
|
||||
enum AnimationType { MULTIPLE_FILES = 0, ANIMATED = 1 }
|
||||
var animation_type : int = AnimationType.MULTIPLE_FILES
|
||||
var background_color : Color = Color.white
|
||||
enum AnimationDirection { FORWARD = 0, BACKWARDS = 1, PING_PONG = 2 }
|
||||
var direction : int = AnimationDirection.FORWARD
|
||||
|
||||
|
@ -43,7 +46,6 @@ var exported_frame_current_tag : int
|
|||
var exported_orientation : int
|
||||
var exported_lines_count : int
|
||||
var exported_animation_type : int
|
||||
var exported_background_color : Color
|
||||
var exported_direction : int
|
||||
var exported_resize : int
|
||||
var exported_interpolation : int
|
||||
|
@ -56,6 +58,16 @@ var stop_export = false
|
|||
|
||||
var file_exists_alert = "File %s already exists. Overwrite?"
|
||||
|
||||
# Export progress variables
|
||||
var export_progress_fraction := 0.0
|
||||
var export_progress := 0.0
|
||||
onready var gif_export_thread := Thread.new()
|
||||
|
||||
|
||||
func _exit_tree():
|
||||
if gif_export_thread.is_active():
|
||||
gif_export_thread.wait_to_finish()
|
||||
|
||||
|
||||
func process_frame() -> void:
|
||||
var frame = Global.current_project.frames[frame_number - 1]
|
||||
|
@ -127,18 +139,18 @@ func process_animation() -> void:
|
|||
processed_images.append(image)
|
||||
|
||||
|
||||
func export_processed_images(ignore_overwrites: bool, path_validation_alert_popup: AcceptDialog, file_exists_alert_popup: AcceptDialog, export_dialog: AcceptDialog ) -> bool:
|
||||
func export_processed_images(ignore_overwrites: bool, export_dialog: AcceptDialog ) -> bool:
|
||||
# Stop export if directory path or file name are not valid
|
||||
var dir = Directory.new()
|
||||
if not dir.dir_exists(directory_path) or not file_name.is_valid_filename():
|
||||
path_validation_alert_popup.popup_centered()
|
||||
export_dialog.open_path_validation_alert_popup()
|
||||
return false
|
||||
|
||||
# Check export paths
|
||||
var export_paths = []
|
||||
for i in range(processed_images.size()):
|
||||
stop_export = false
|
||||
var multiple_files := true if (current_tab == ExportTab.ANIMATION && animation_type == AnimationType.MULTIPLE_FILES) else false
|
||||
var multiple_files := true if (current_tab == ExportTab.ANIMATION and animation_type == AnimationType.MULTIPLE_FILES) else false
|
||||
var export_path = create_export_path(multiple_files, i + 1)
|
||||
# If user want to create new directory for each animation tag then check if directories exist and create them if not
|
||||
if multiple_files and new_dir_for_each_frame_tag:
|
||||
|
@ -152,8 +164,7 @@ func export_processed_images(ignore_overwrites: bool, path_validation_alert_popu
|
|||
# Ask user if he want's to overwrite the file
|
||||
if not was_exported or (was_exported and not ignore_overwrites):
|
||||
# Overwrite existing file?
|
||||
file_exists_alert_popup.dialog_text = file_exists_alert % export_path
|
||||
file_exists_alert_popup.popup_centered()
|
||||
export_dialog.open_file_exists_alert_popup(file_exists_alert % export_path)
|
||||
# Stops the function until the user decides if he want's to overwrite
|
||||
yield(export_dialog, "resume_export_function")
|
||||
if stop_export:
|
||||
|
@ -161,29 +172,16 @@ func export_processed_images(ignore_overwrites: bool, path_validation_alert_popu
|
|||
return
|
||||
export_paths.append(export_path)
|
||||
# Only get one export path if single file animated image is exported
|
||||
if current_tab == ExportTab.ANIMATION && animation_type == AnimationType.ANIMATED:
|
||||
if current_tab == ExportTab.ANIMATION and animation_type == AnimationType.ANIMATED:
|
||||
break
|
||||
|
||||
# Scale images that are to export
|
||||
scale_processed_images()
|
||||
|
||||
if current_tab == ExportTab.ANIMATION && animation_type == AnimationType.ANIMATED:
|
||||
var frame_delay_in_ms = Global.animation_timer.wait_time * 100
|
||||
|
||||
$GifExporter.begin_export(export_paths[0], processed_images[0].get_width(), processed_images[0].get_height(), frame_delay_in_ms, 0)
|
||||
match direction:
|
||||
AnimationDirection.FORWARD:
|
||||
for i in range(processed_images.size()):
|
||||
$GifExporter.write_frame(processed_images[i], background_color, frame_delay_in_ms)
|
||||
AnimationDirection.BACKWARDS:
|
||||
for i in range(processed_images.size() - 1, -1, -1):
|
||||
$GifExporter.write_frame(processed_images[i], background_color, frame_delay_in_ms)
|
||||
AnimationDirection.PING_PONG:
|
||||
for i in range(0, processed_images.size()):
|
||||
$GifExporter.write_frame(processed_images[i], background_color, frame_delay_in_ms)
|
||||
for i in range(processed_images.size() - 2, 0, -1):
|
||||
$GifExporter.write_frame(processed_images[i], background_color, frame_delay_in_ms)
|
||||
$GifExporter.end_export()
|
||||
if current_tab == ExportTab.ANIMATION and animation_type == AnimationType.ANIMATED:
|
||||
if gif_export_thread.is_active():
|
||||
gif_export_thread.wait_to_finish()
|
||||
gif_export_thread.start(self, "export_gif", {"export_dialog": export_dialog, "export_paths": export_paths})
|
||||
else:
|
||||
for i in range(processed_images.size()):
|
||||
if OS.get_name() == "HTML5":
|
||||
|
@ -197,10 +195,54 @@ func export_processed_images(ignore_overwrites: bool, path_validation_alert_popu
|
|||
was_exported = true
|
||||
store_export_settings()
|
||||
Global.file_menu.get_popup().set_item_text(5, tr("Export") + " %s" % (file_name + file_format_string(file_format)))
|
||||
Global.notification_label("File(s) exported")
|
||||
|
||||
# Only show when not exporting gif - gif export finishes in thread
|
||||
if not (current_tab == ExportTab.ANIMATION and animation_type == AnimationType.ANIMATED):
|
||||
Global.notification_label("File(s) exported")
|
||||
return true
|
||||
|
||||
|
||||
func export_gif(args: Dictionary) -> void:
|
||||
# Export progress popup
|
||||
export_progress_fraction = 100 / processed_images.size() # one fraction per each frame, one fraction for write to disk
|
||||
export_progress = 0.0
|
||||
args["export_dialog"].set_export_progress_bar(export_progress)
|
||||
args["export_dialog"].toggle_export_progress_popup(true)
|
||||
|
||||
# Export and save gif
|
||||
var exporter = gifexporter.new(processed_images[0].get_width(), processed_images[0].get_height())
|
||||
match direction:
|
||||
AnimationDirection.FORWARD:
|
||||
for i in range(processed_images.size()):
|
||||
write_frame_to_gif(processed_images[i], Global.animation_timer.wait_time, exporter, args["export_dialog"])
|
||||
AnimationDirection.BACKWARDS:
|
||||
for i in range(processed_images.size() - 1, -1, -1):
|
||||
write_frame_to_gif(processed_images[i], Global.animation_timer.wait_time, exporter, args["export_dialog"])
|
||||
AnimationDirection.PING_PONG:
|
||||
export_progress_fraction = 100 / (processed_images.size() * 2)
|
||||
for i in range(0, processed_images.size()):
|
||||
write_frame_to_gif(processed_images[i], Global.animation_timer.wait_time, exporter, args["export_dialog"])
|
||||
for i in range(processed_images.size() - 2, 0, -1):
|
||||
write_frame_to_gif(processed_images[i], Global.animation_timer.wait_time, exporter, args["export_dialog"])
|
||||
var file: File = File.new()
|
||||
|
||||
file.open(args["export_paths"][0], File.WRITE)
|
||||
file.store_buffer(exporter.export_file_data())
|
||||
file.close()
|
||||
args["export_dialog"].toggle_export_progress_popup(false)
|
||||
Global.notification_label("File(s) exported")
|
||||
|
||||
|
||||
func write_frame_to_gif(image: Image, wait_time: float, exporter: Node, export_dialog: Node) -> void:
|
||||
exporter.write_frame(image, wait_time, quantization)
|
||||
increase_export_progress(export_dialog)
|
||||
|
||||
|
||||
func increase_export_progress(export_dialog: Node) -> void:
|
||||
export_progress += export_progress_fraction
|
||||
export_dialog.set_export_progress_bar(export_progress)
|
||||
|
||||
|
||||
func scale_processed_images() -> void:
|
||||
for processed_image in processed_images:
|
||||
if resize != 100:
|
||||
|
@ -288,7 +330,6 @@ func store_export_settings() -> void:
|
|||
exported_orientation = orientation
|
||||
exported_lines_count = lines_count
|
||||
exported_animation_type = animation_type
|
||||
exported_background_color = background_color
|
||||
exported_direction = direction
|
||||
exported_resize = resize
|
||||
exported_interpolation = interpolation
|
||||
|
@ -305,7 +346,6 @@ func restore_previous_export_settings() -> void:
|
|||
orientation = exported_orientation
|
||||
lines_count = exported_lines_count
|
||||
animation_type = exported_animation_type
|
||||
background_color = exported_background_color
|
||||
direction = exported_direction
|
||||
resize = exported_resize
|
||||
interpolation = exported_interpolation
|
||||
|
|
|
@ -11,8 +11,12 @@ onready var popups = $Popups
|
|||
onready var file_exists_alert_popup = $Popups/FileExistsAlert
|
||||
onready var path_validation_alert_popup = $Popups/PathValidationAlert
|
||||
onready var path_dialog_popup = $Popups/PathDialog
|
||||
onready var export_progress_popup = $Popups/ExportProgressBar
|
||||
onready var export_progress_bar = $Popups/ExportProgressBar/MarginContainer/ProgressBar
|
||||
|
||||
onready var animation_options_multiple_animations_directories = $VBoxContainer/AnimationOptions/MultipleAnimationsDirectories
|
||||
onready var previews = $VBoxContainer/PreviewScroll/Previews
|
||||
onready var frame_timer = $FrameTimer
|
||||
|
||||
onready var frame_options = $VBoxContainer/FrameOptions
|
||||
onready var frame_options_frame_number = $VBoxContainer/FrameOptions/FrameNumber/FrameNumber
|
||||
|
@ -26,10 +30,8 @@ onready var spritesheet_options_lines_count_label = $VBoxContainer/SpritesheetOp
|
|||
onready var animation_options = $VBoxContainer/AnimationOptions
|
||||
onready var animation_options_animation_type = $VBoxContainer/AnimationOptions/AnimationType
|
||||
onready var animation_options_animation_options = $VBoxContainer/AnimationOptions/AnimatedOptions
|
||||
onready var animation_options_background_color = $VBoxContainer/AnimationOptions/AnimatedOptions/BackgroundColor
|
||||
onready var animation_options_direction = $VBoxContainer/AnimationOptions/AnimatedOptions/Direction
|
||||
|
||||
onready var frame_timer = $FrameTimer
|
||||
|
||||
onready var options_resize = $VBoxContainer/Options/Resize
|
||||
onready var options_interpolation = $VBoxContainer/Options/Interpolation
|
||||
|
@ -38,8 +40,6 @@ onready var path_line_edit = $VBoxContainer/Path/PathLineEdit
|
|||
onready var file_line_edit = $VBoxContainer/File/FileLineEdit
|
||||
onready var file_file_format = $VBoxContainer/File/FileFormat
|
||||
|
||||
onready var animation_options_multiple_animations_directories = $VBoxContainer/AnimationOptions/MultipleAnimationsDirectories
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
tabs.add_tab("Frame")
|
||||
|
@ -52,10 +52,8 @@ func _ready() -> void:
|
|||
add_button("Cancel", false, "cancel")
|
||||
file_exists_alert_popup.add_button("Cancel Export", false, "cancel")
|
||||
|
||||
# Disable GIF export for unsupported platforms
|
||||
if not $GifExporter.is_platform_supported():
|
||||
animation_options_animation_type.selected = Export.AnimationType.MULTIPLE_FILES
|
||||
animation_options_animation_type.disabled = true
|
||||
# Remove close button from export progress bar
|
||||
export_progress_popup.get_close_button().hide()
|
||||
|
||||
|
||||
func show_tab() -> void:
|
||||
|
@ -95,7 +93,6 @@ func show_tab() -> void:
|
|||
set_file_format_selector()
|
||||
Export.process_animation()
|
||||
animation_options_animation_type.selected = Export.animation_type
|
||||
animation_options_background_color.color = Export.background_color
|
||||
animation_options_direction.selected = Export.direction
|
||||
animation_options.show()
|
||||
set_preview()
|
||||
|
@ -111,7 +108,7 @@ func external_export() -> void:
|
|||
Export.process_spritesheet()
|
||||
Export.ExportTab.ANIMATION:
|
||||
Export.process_animation()
|
||||
if Export.export_processed_images(true, path_validation_alert_popup, file_exists_alert_popup, self):
|
||||
if Export.export_processed_images(true, self):
|
||||
hide()
|
||||
|
||||
|
||||
|
@ -216,6 +213,26 @@ func create_frame_tag_list() -> void:
|
|||
spritesheet_options_frames.add_item(item.name)
|
||||
|
||||
|
||||
func open_path_validation_alert_popup() -> void:
|
||||
path_validation_alert_popup.popup_centered()
|
||||
|
||||
|
||||
func open_file_exists_alert_popup(dialog_text: String) -> void:
|
||||
file_exists_alert_popup.dialog_text = dialog_text
|
||||
file_exists_alert_popup.popup_centered()
|
||||
|
||||
|
||||
func toggle_export_progress_popup(open: bool) -> void:
|
||||
if open:
|
||||
export_progress_popup.popup_centered()
|
||||
else:
|
||||
export_progress_popup.hide()
|
||||
|
||||
|
||||
func set_export_progress_bar(value: float) -> void:
|
||||
export_progress_bar.value = value
|
||||
|
||||
|
||||
func _on_ExportDialog_about_to_show() -> void:
|
||||
# If export already occured - fill the dialog with previous export settings
|
||||
if Export.was_exported:
|
||||
|
@ -278,10 +295,6 @@ func _on_AnimationType_item_selected(id : int) -> void:
|
|||
set_preview()
|
||||
|
||||
|
||||
func _on_BackgroundColor_color_changed(color : Color) -> void:
|
||||
Export.background_color = color
|
||||
|
||||
|
||||
func _on_Direction_item_selected(id : int) -> void:
|
||||
Export.direction = id
|
||||
match id:
|
||||
|
@ -303,7 +316,7 @@ func _on_Interpolation_item_selected(id: int) -> void:
|
|||
|
||||
|
||||
func _on_ExportDialog_confirmed() -> void:
|
||||
if Export.export_processed_images(false, path_validation_alert_popup, file_exists_alert_popup, self):
|
||||
if Export.export_processed_images(false, self):
|
||||
hide()
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
[gd_scene load_steps=3 format=2]
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://src/UI/Dialogs/ExportDialog.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/godot-gifexporter/src/GifExporter.gd" type="Script" id=2]
|
||||
|
||||
[node name="ExportDialog" type="AcceptDialog"]
|
||||
margin_right = 532.0
|
||||
|
@ -183,31 +182,14 @@ margin_right = 516.0
|
|||
margin_bottom = 52.0
|
||||
rect_min_size = Vector2( 0, 24 )
|
||||
|
||||
[node name="BackgroundColorLabel" type="Label" parent="VBoxContainer/AnimationOptions/AnimatedOptions"]
|
||||
margin_top = 5.0
|
||||
margin_right = 78.0
|
||||
margin_bottom = 19.0
|
||||
text = "Background:"
|
||||
valign = 1
|
||||
|
||||
[node name="BackgroundColor" type="ColorPickerButton" parent="VBoxContainer/AnimationOptions/AnimatedOptions"]
|
||||
margin_left = 82.0
|
||||
margin_right = 263.0
|
||||
margin_bottom = 24.0
|
||||
mouse_default_cursor_shape = 2
|
||||
size_flags_horizontal = 7
|
||||
color = Color( 1, 1, 1, 1 )
|
||||
edit_alpha = false
|
||||
|
||||
[node name="DirectionLabel" type="Label" parent="VBoxContainer/AnimationOptions/AnimatedOptions"]
|
||||
margin_left = 267.0
|
||||
margin_top = 5.0
|
||||
margin_right = 330.0
|
||||
margin_right = 63.0
|
||||
margin_bottom = 19.0
|
||||
text = "Direction:"
|
||||
|
||||
[node name="Direction" type="OptionButton" parent="VBoxContainer/AnimationOptions/AnimatedOptions"]
|
||||
margin_left = 334.0
|
||||
margin_left = 67.0
|
||||
margin_right = 516.0
|
||||
margin_bottom = 24.0
|
||||
rect_min_size = Vector2( 100, 0 )
|
||||
|
@ -365,10 +347,10 @@ __meta__ = {
|
|||
}
|
||||
|
||||
[node name="FileExistsAlert" type="AcceptDialog" parent="Popups"]
|
||||
margin_left = 8.0
|
||||
margin_top = 180.0
|
||||
margin_right = 448.0
|
||||
margin_bottom = 280.0
|
||||
margin_left = 10.5227
|
||||
margin_top = 176.636
|
||||
margin_right = 450.523
|
||||
margin_bottom = 276.636
|
||||
size_flags_horizontal = 0
|
||||
size_flags_vertical = 0
|
||||
window_title = "Alarm!"
|
||||
|
@ -378,16 +360,41 @@ __meta__ = {
|
|||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="ExportProgressBar" type="WindowDialog" parent="Popups"]
|
||||
margin_left = 63.0
|
||||
margin_top = 215.0
|
||||
margin_right = 402.0
|
||||
margin_bottom = 256.0
|
||||
popup_exclusive = true
|
||||
window_title = "Exporting in progress..."
|
||||
__meta__ = {
|
||||
"_edit_group_": true,
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="Popups/ExportProgressBar"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = 5.0
|
||||
margin_top = 5.0
|
||||
margin_right = -5.0
|
||||
margin_bottom = -5.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="ProgressBar" type="ProgressBar" parent="Popups/ExportProgressBar/MarginContainer"]
|
||||
margin_right = 329.0
|
||||
margin_bottom = 14.0
|
||||
size_flags_horizontal = 3
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="FrameTimer" type="Timer" parent="."]
|
||||
__meta__ = {
|
||||
"_editor_description_": "Timer to advance animation frames in animation preview."
|
||||
}
|
||||
|
||||
[node name="GifExporter" type="Node" parent="."]
|
||||
script = ExtResource( 2 )
|
||||
__meta__ = {
|
||||
"_editor_description_": ""
|
||||
}
|
||||
[connection signal="about_to_show" from="." to="." method="_on_ExportDialog_about_to_show"]
|
||||
[connection signal="confirmed" from="." to="." method="_on_ExportDialog_confirmed"]
|
||||
[connection signal="custom_action" from="." to="." method="_on_ExportDialog_custom_action"]
|
||||
|
@ -399,7 +406,6 @@ __meta__ = {
|
|||
[connection signal="value_changed" from="VBoxContainer/SpritesheetOptions/Orientation/LinesCount" to="." method="_on_LinesCount_value_changed"]
|
||||
[connection signal="item_selected" from="VBoxContainer/AnimationOptions/AnimationType" to="." method="_on_AnimationType_item_selected"]
|
||||
[connection signal="toggled" from="VBoxContainer/AnimationOptions/MultipleAnimationsDirectories" to="." method="_on_MultipleAnimationsDirectories_toggled"]
|
||||
[connection signal="color_changed" from="VBoxContainer/AnimationOptions/AnimatedOptions/BackgroundColor" to="." method="_on_BackgroundColor_color_changed"]
|
||||
[connection signal="item_selected" from="VBoxContainer/AnimationOptions/AnimatedOptions/Direction" to="." method="_on_Direction_item_selected"]
|
||||
[connection signal="value_changed" from="VBoxContainer/Options/Resize" to="." method="_on_Resize_value_changed"]
|
||||
[connection signal="item_selected" from="VBoxContainer/Options/Interpolation" to="." method="_on_Interpolation_item_selected"]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue