diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..4a0547d17 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "addons/godot-gifexporter"] + path = addons/godot-gifexporter + url = https://github.com/novhack/godot-gifexporter.git diff --git a/Prefabs/Dialogs/ExportDialog.tscn b/Prefabs/Dialogs/ExportDialog.tscn index cae9a3e21..9b8b90302 100644 --- a/Prefabs/Dialogs/ExportDialog.tscn +++ b/Prefabs/Dialogs/ExportDialog.tscn @@ -1,9 +1,10 @@ -[gd_scene load_steps=2 format=2] +[gd_scene load_steps=3 format=2] [ext_resource path="res://Scripts/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 = 456.0 +margin_right = 532.0 margin_bottom = 530.0 rect_min_size = Vector2( 456, 530 ) window_title = "Export..." @@ -17,7 +18,7 @@ __meta__ = { [node name="VBoxContainer" type="VBoxContainer" parent="."] margin_left = 8.0 margin_top = 8.0 -margin_right = 448.0 +margin_right = 524.0 margin_bottom = 494.0 rect_min_size = Vector2( 330, 0 ) size_flags_vertical = 3 @@ -26,43 +27,42 @@ __meta__ = { } [node name="Tabs" type="Tabs" parent="VBoxContainer"] -margin_right = 440.0 +margin_right = 516.0 margin_bottom = 24.0 size_flags_vertical = 0 [node name="HSeparator" type="HSeparator" parent="VBoxContainer"] margin_top = 28.0 -margin_right = 440.0 +margin_right = 516.0 margin_bottom = 32.0 [node name="PreviewLabel" type="Label" parent="VBoxContainer"] margin_top = 36.0 -margin_right = 440.0 +margin_right = 516.0 margin_bottom = 50.0 text = "Preview:" [node name="PreviewScroll" type="ScrollContainer" parent="VBoxContainer"] margin_top = 54.0 -margin_right = 440.0 -margin_bottom = 358.0 +margin_right = 516.0 +margin_bottom = 274.0 size_flags_horizontal = 3 size_flags_vertical = 3 [node name="Previews" type="GridContainer" parent="VBoxContainer/PreviewScroll"] -margin_right = 440.0 -margin_bottom = 304.0 +margin_right = 516.0 +margin_bottom = 220.0 size_flags_horizontal = 3 size_flags_vertical = 3 columns = 3 [node name="FrameOptions" type="VBoxContainer" parent="VBoxContainer"] -visible = false -margin_top = 334.0 -margin_right = 440.0 -margin_bottom = 358.0 +margin_top = 278.0 +margin_right = 516.0 +margin_bottom = 302.0 [node name="FrameNumber" type="HBoxContainer" parent="VBoxContainer/FrameOptions"] -margin_right = 440.0 +margin_right = 516.0 margin_bottom = 24.0 [node name="FrameNumberLabel" type="Label" parent="VBoxContainer/FrameOptions/FrameNumber"] @@ -73,7 +73,7 @@ text = "Frame:" [node name="FrameNumber" type="SpinBox" parent="VBoxContainer/FrameOptions/FrameNumber"] margin_left = 48.0 -margin_right = 440.0 +margin_right = 516.0 margin_bottom = 24.0 rect_min_size = Vector2( 100, 0 ) size_flags_horizontal = 3 @@ -84,12 +84,12 @@ rounded = true align = 2 [node name="SpritesheetOptions" type="VBoxContainer" parent="VBoxContainer"] -margin_top = 362.0 -margin_right = 440.0 -margin_bottom = 386.0 +margin_top = 306.0 +margin_right = 516.0 +margin_bottom = 330.0 [node name="Orientation" type="HBoxContainer" parent="VBoxContainer/SpritesheetOptions"] -margin_right = 440.0 +margin_right = 516.0 margin_bottom = 24.0 alignment = 1 @@ -104,7 +104,7 @@ __meta__ = { [node name="Orientation" type="OptionButton" parent="VBoxContainer/SpritesheetOptions/Orientation"] margin_left = 81.0 -margin_right = 226.0 +margin_right = 264.0 margin_bottom = 24.0 size_flags_horizontal = 3 text = "Rows" @@ -112,15 +112,15 @@ items = [ "Rows", null, false, 0, null, "Columns", null, false, 1, null ] selected = 0 [node name="LinesCountLabel" type="Label" parent="VBoxContainer/SpritesheetOptions/Orientation"] -margin_left = 230.0 +margin_left = 268.0 margin_top = 5.0 -margin_right = 290.0 +margin_right = 328.0 margin_bottom = 19.0 text = "Columns:" [node name="LinesCount" type="SpinBox" parent="VBoxContainer/SpritesheetOptions/Orientation"] -margin_left = 294.0 -margin_right = 440.0 +margin_left = 332.0 +margin_right = 516.0 margin_bottom = 24.0 size_flags_horizontal = 3 min_value = 1.0 @@ -129,28 +129,68 @@ value = 1.0 align = 2 [node name="AnimationOptions" type="VBoxContainer" parent="VBoxContainer"] -visible = false -margin_top = 366.0 -margin_right = 440.0 +margin_top = 334.0 +margin_right = 516.0 margin_bottom = 386.0 [node name="AnimationType" type="OptionButton" parent="VBoxContainer/AnimationOptions"] -margin_right = 440.0 -margin_bottom = 20.0 +margin_right = 516.0 +margin_bottom = 24.0 +rect_min_size = Vector2( 0, 24 ) size_flags_horizontal = 3 -disabled = true text = "All frames as multiple files" -items = [ "All frames as multiple files", null, false, 0, null ] +items = [ "All frames as multiple files", null, false, 0, null, "All frames as a single file animation", null, false, 1, null ] selected = 0 +[node name="AnimatedOptions" type="HBoxContainer" parent="VBoxContainer/AnimationOptions"] +margin_top = 28.0 +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 = 82.0 +margin_bottom = 19.0 +text = "Background: " +valign = 1 + +[node name="BackgroundColor" type="ColorPickerButton" parent="VBoxContainer/AnimationOptions/AnimatedOptions"] +margin_left = 86.0 +margin_right = 265.0 +margin_bottom = 24.0 +size_flags_horizontal = 7 +color = Color( 1, 1, 1, 1 ) +edit_alpha = false + +[node name="DirectionLabel" type="Label" parent="VBoxContainer/AnimationOptions/AnimatedOptions"] +margin_left = 269.0 +margin_top = 5.0 +margin_right = 332.0 +margin_bottom = 19.0 +text = "Direction:" + +[node name="Direction" type="OptionButton" parent="VBoxContainer/AnimationOptions/AnimatedOptions"] +margin_left = 336.0 +margin_right = 516.0 +margin_bottom = 24.0 +rect_min_size = Vector2( 100, 0 ) +size_flags_horizontal = 3 +text = "Forward" +items = [ "Forward", null, false, 0, null, "Backwards", null, false, 1, null, "Ping-Pong", null, false, 2, null ] +selected = 0 +__meta__ = { +"_edit_use_anchors_": false +} + [node name="HSeparator2" type="HSeparator" parent="VBoxContainer"] margin_top = 390.0 -margin_right = 440.0 +margin_right = 516.0 margin_bottom = 394.0 [node name="Options" type="HBoxContainer" parent="VBoxContainer"] margin_top = 398.0 -margin_right = 440.0 +margin_right = 516.0 margin_bottom = 422.0 [node name="ResizeLabel" type="Label" parent="VBoxContainer/Options"] @@ -163,7 +203,7 @@ align = 2 [node name="Resize" type="SpinBox" parent="VBoxContainer/Options"] margin_left = 50.0 -margin_right = 197.0 +margin_right = 235.0 margin_bottom = 24.0 size_flags_horizontal = 3 min_value = 10.0 @@ -174,17 +214,17 @@ align = 2 suffix = "%" [node name="InterpolationLabel" type="Label" parent="VBoxContainer/Options"] -margin_left = 201.0 +margin_left = 239.0 margin_top = 5.0 -margin_right = 288.0 +margin_right = 326.0 margin_bottom = 19.0 rect_min_size = Vector2( 30, 0 ) text = "Interpolation:" align = 2 [node name="Interpolation" type="OptionButton" parent="VBoxContainer/Options"] -margin_left = 292.0 -margin_right = 440.0 +margin_left = 330.0 +margin_right = 516.0 margin_bottom = 24.0 size_flags_horizontal = 3 text = "Nearest" @@ -194,12 +234,12 @@ selected = 0 [node name="HSeparator3" type="HSeparator" parent="VBoxContainer"] margin_top = 426.0 -margin_right = 440.0 +margin_right = 516.0 margin_bottom = 430.0 [node name="Path" type="HBoxContainer" parent="VBoxContainer"] margin_top = 434.0 -margin_right = 440.0 +margin_right = 516.0 margin_bottom = 458.0 [node name="Label" type="Label" parent="VBoxContainer/Path"] @@ -211,20 +251,20 @@ text = "Path:" [node name="PathLineEdit" type="LineEdit" parent="VBoxContainer/Path"] margin_left = 36.0 -margin_right = 377.0 +margin_right = 453.0 margin_bottom = 24.0 size_flags_horizontal = 3 align = 2 [node name="PathButton" type="Button" parent="VBoxContainer/Path"] -margin_left = 381.0 -margin_right = 440.0 +margin_left = 457.0 +margin_right = 516.0 margin_bottom = 24.0 text = "Browse" [node name="File" type="HBoxContainer" parent="VBoxContainer"] margin_top = 462.0 -margin_right = 440.0 +margin_right = 516.0 margin_bottom = 486.0 [node name="Label" type="Label" parent="VBoxContainer/File"] @@ -236,19 +276,19 @@ text = "File:" [node name="FileLineEdit" type="LineEdit" parent="VBoxContainer/File"] margin_left = 34.0 -margin_right = 296.0 +margin_right = 376.0 margin_bottom = 24.0 size_flags_horizontal = 3 align = 2 [node name="FileFormat" type="OptionButton" parent="VBoxContainer/File"] -margin_left = 300.0 -margin_right = 440.0 +margin_left = 380.0 +margin_right = 516.0 margin_bottom = 24.0 rect_min_size = Vector2( 130, 0 ) disabled = true -text = ".png ; PNG Image" -items = [ ".png ; PNG Image", null, false, 0, null, ".gif ; GIF Image", null, true, 1, null ] +text = ".png; PNG Image" +items = [ ".png; PNG Image", null, false, 0, null, ".gif; GIF Image", null, false, 1, null ] selected = 0 [node name="Popups" type="Node" parent="."] @@ -265,8 +305,8 @@ window_title = "Open a Directory" resizable = true mode = 2 access = 2 -current_dir = "C:/Users/Overloaded/Dropbox/Orama Founding Members/εταιρικα αρχεια/Godot Projects/Pixelorama" -current_path = "C:/Users/Overloaded/Dropbox/Orama Founding Members/εταιρικα αρχεια/Godot Projects/Pixelorama/" +current_dir = "/home/novhack/Pixelorama" +current_path = "/home/novhack/Pixelorama/" [node name="PathValidationAlert" type="AcceptDialog" parent="Popups"] margin_left = 8.0 @@ -293,13 +333,28 @@ dialog_text = "File %s already exists. Overwrite?" __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"] +[connection signal="popup_hide" from="." to="." method="_on_ExportDialog_popup_hide"] [connection signal="tab_clicked" from="VBoxContainer/Tabs" to="." method="_on_Tabs_tab_clicked"] [connection signal="value_changed" from="VBoxContainer/FrameOptions/FrameNumber/FrameNumber" to="." method="_on_Frame_value_changed"] [connection signal="item_selected" from="VBoxContainer/SpritesheetOptions/Orientation/Orientation" to="." method="_on_Orientation_item_selected"] [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="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"] [connection signal="text_changed" from="VBoxContainer/Path/PathLineEdit" to="." method="_on_PathLineEdit_text_changed"] @@ -309,3 +364,4 @@ __meta__ = { [connection signal="dir_selected" from="Popups/PathDialog" to="." method="_on_FileDialog_dir_selected"] [connection signal="confirmed" from="Popups/FileExistsAlert" to="." method="_on_FileExistsAlert_confirmed"] [connection signal="custom_action" from="Popups/FileExistsAlert" to="." method="_on_FileExistsAlert_custom_action"] +[connection signal="timeout" from="FrameTimer" to="." method="_on_FrameTimer_timeout"] diff --git a/Scripts/AnimationTimeline.gd b/Scripts/AnimationTimeline.gd index 22f6880a4..5e9dfa7d9 100644 --- a/Scripts/AnimationTimeline.gd +++ b/Scripts/AnimationTimeline.gd @@ -9,7 +9,7 @@ onready var tag_scroll_container : ScrollContainer = $AnimationContainer/Timelin func _ready() -> void: timeline_scroll.get_h_scrollbar().connect("value_changed", self, "_h_scroll_changed") - + Global.animation_timer.wait_time = 1 / fps func _h_scroll_changed(value : float) -> void: # Let the main timeline ScrollContainer affect the tag ScrollContainer too diff --git a/Scripts/Dialogs/ExportDialog.gd b/Scripts/Dialogs/ExportDialog.gd index 337d917f9..fc45598aa 100644 --- a/Scripts/Dialogs/ExportDialog.gd +++ b/Scripts/Dialogs/ExportDialog.gd @@ -16,8 +16,11 @@ var orientation : int = Orientation.Rows var lines_count := 1 # Animation options -enum AnimationType { MultipleFiles = 0 } +enum AnimationType { MultipleFiles = 0, Animated = 1 } var animation_type : int = AnimationType.MultipleFiles +var background_color : Color = Color.white +enum AnimationDirection { Forward = 0, Backwards = 1, PingPong = 2 } +var direction : int = AnimationDirection.Forward # Options var resize := 100 @@ -26,7 +29,8 @@ var interpolation := 0 # Image.Interpolation # Export directory path and export file name var directory_path := "" var file_name := "" -var file_format := ".png" +var file_format : int = FileFormat.PNG +enum FileFormat { PNG = 0, GIF = 1} var file_exists_alert = "File %s already exists. Overwrite?" @@ -37,16 +41,21 @@ var exported_frame_number : 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 var exported_directory_path : String var exported_file_name : String -var exported_file_format : String +var exported_file_format : int # Export coroutine signal signal resume_export_function() var stop_export = false +var animated_preview_current_frame := 0 +var animated_preview_frames = [] + func _ready() -> void: $VBoxContainer/Tabs.add_tab("Frame") $VBoxContainer/Tabs.add_tab("Spritesheet") @@ -58,6 +67,7 @@ func _ready() -> void: add_button("Cancel", false, "cancel") $Popups/FileExistsAlert.add_button("Cancel Export", false, "cancel") + func show_tab() -> void: $VBoxContainer/FrameOptions.hide() $VBoxContainer/SpritesheetOptions.hide() @@ -65,6 +75,9 @@ func show_tab() -> void: match current_tab: ExportTab.Frame: + file_format = FileFormat.PNG + $VBoxContainer/File/FileFormat.selected = FileFormat.PNG + $FrameTimer.stop() if not was_exported: frame_number = Global.current_frame + 1 $VBoxContainer/FrameOptions/FrameNumber/FrameNumber.max_value = Global.canvases.size() + 1 @@ -72,6 +85,9 @@ func show_tab() -> void: process_frame() $VBoxContainer/FrameOptions.show() ExportTab.Spritesheet: + file_format = FileFormat.PNG + $VBoxContainer/File/FileFormat.selected = FileFormat.PNG + $FrameTimer.stop() if not was_exported: orientation = Orientation.Rows lines_count = int(ceil(sqrt(Global.canvases.size()))) @@ -82,7 +98,11 @@ func show_tab() -> void: process_spritesheet() $VBoxContainer/SpritesheetOptions.show() ExportTab.Animation: + set_file_format_selector() process_animation() + $VBoxContainer/AnimationOptions/AnimationType.selected = animation_type + $VBoxContainer/AnimationOptions/AnimatedOptions/BackgroundColor.color = background_color + $VBoxContainer/AnimationOptions/AnimatedOptions/Direction.selected = direction $VBoxContainer/AnimationOptions.show() set_preview() $VBoxContainer/Tabs.current_tab = current_tab @@ -161,27 +181,23 @@ func set_preview() -> void: remove_previews() if processed_images.size() == 1 and current_tab != ExportTab.Animation: $VBoxContainer/PreviewScroll/Previews.columns = 1 - add_preview(processed_images[0]) + add_image_preview(processed_images[0]) else: - $VBoxContainer/PreviewScroll/Previews.columns = ceil(sqrt(processed_images.size())) - for i in range(processed_images.size()): - add_preview(processed_images[i], i + 1) + match animation_type: + AnimationType.MultipleFiles: + $VBoxContainer/PreviewScroll/Previews.columns = ceil(sqrt(processed_images.size())) + for i in range(processed_images.size()): + add_image_preview(processed_images[i], i + 1) + AnimationType.Animated: + $VBoxContainer/PreviewScroll/Previews.columns = 1 + add_animated_preview() -func add_preview(image: Image, canvas_number: int = -1) -> void: - var container = VBoxContainer.new() - container.size_flags_horizontal = SIZE_EXPAND_FILL - container.size_flags_vertical = SIZE_EXPAND_FILL - container.rect_min_size = Vector2(0, 128) - - var preview = TextureRect.new() - preview.expand = true - preview.size_flags_horizontal = SIZE_EXPAND_FILL - preview.size_flags_vertical = SIZE_EXPAND_FILL - preview.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED +func add_image_preview(image: Image, canvas_number: int = -1) -> void: + var container = create_preview_container() + var preview = create_preview_rect() preview.texture = ImageTexture.new() preview.texture.create_from_image(image, 0) - container.add_child(preview) if canvas_number != -1: @@ -193,9 +209,46 @@ func add_preview(image: Image, canvas_number: int = -1) -> void: $VBoxContainer/PreviewScroll/Previews.add_child(container) +func add_animated_preview() -> void: + animated_preview_current_frame = processed_images.size() - 1 if direction == AnimationDirection.Backwards else 0 + animated_preview_frames = [] + + for processed_image in processed_images: + var texture = ImageTexture.new() + texture.create_from_image(processed_image, 0) + animated_preview_frames.push_back(texture) + + var container = create_preview_container() + container.name = "PreviewContainer" + var preview = create_preview_rect() + preview.name = "Preview" + preview.texture = animated_preview_frames[animated_preview_current_frame] + container.add_child(preview) + + $VBoxContainer/PreviewScroll/Previews.add_child(container) + $FrameTimer.start() + + +func create_preview_container() -> VBoxContainer: + var container = VBoxContainer.new() + container.size_flags_horizontal = SIZE_EXPAND_FILL + container.size_flags_vertical = SIZE_EXPAND_FILL + container.rect_min_size = Vector2(0, 128) + return container + + +func create_preview_rect() -> TextureRect: + var preview = TextureRect.new() + preview.expand = true + preview.size_flags_horizontal = SIZE_EXPAND_FILL + preview.size_flags_vertical = SIZE_EXPAND_FILL + preview.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED + return preview + + func remove_previews() -> void: for child in $VBoxContainer/PreviewScroll/Previews.get_children(): - child.queue_free() + child.free() func export_processed_images(ignore_overwrites : bool) -> void: @@ -209,7 +262,7 @@ func export_processed_images(ignore_overwrites : bool) -> void: var export_paths = [] for i in range(processed_images.size()): stop_export = false - var export_path = create_export_path(true if current_tab == ExportTab.Animation else false, i + 1) + var export_path = create_export_path(true if (current_tab == ExportTab.Animation && animation_type == AnimationType.MultipleFiles) else false, i + 1) # Check if the file already exists var fileCheck = File.new() if fileCheck.file_exists(export_path): @@ -224,19 +277,40 @@ func export_processed_images(ignore_overwrites : bool) -> void: # User decided to stop export 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: + break # Scale images that are to export scale_processed_images() - for i in range(processed_images.size()): - var err = processed_images[i].save_png(export_paths[i]) - if err != OK: - OS.alert("Can't save file") + 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.PingPong: + 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() + else: + for i in range(processed_images.size()): + var err = processed_images[i].save_png(export_paths[i]) + if err != OK: + OS.alert("Can't save file") # Store settings for quick export and when the dialog is opened again was_exported = true store_export_settings() - Global.file_menu.get_popup().set_item_text(5, tr("Export") + " %s" % (file_name + file_format)) + 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") hide() @@ -273,19 +347,44 @@ func create_export_path(multifile: bool, frame: int = 0) -> String: if multifile: path += "_" + String(frame) - return directory_path.plus_file(path + file_format) + return directory_path.plus_file(path + file_format_string(file_format)) func frames_divided_by_spritesheet_lines() -> int: return int(ceil(Global.canvases.size() / float(lines_count))) +func file_format_string(format_enum : int) -> String: + match format_enum: + 0: # PNG + return '.png' + 1: # GIF + return '.gif' + _: + return '' + + +func set_file_format_selector() -> void: + match animation_type: + AnimationType.MultipleFiles: + file_format = FileFormat.PNG + $VBoxContainer/File/FileFormat.selected = FileFormat.PNG + $FrameTimer.stop() + $VBoxContainer/AnimationOptions/AnimatedOptions.hide() + AnimationType.Animated: + file_format = FileFormat.GIF + $VBoxContainer/File/FileFormat.selected = FileFormat.GIF + $FrameTimer.wait_time = Global.animation_timer.wait_time + $VBoxContainer/AnimationOptions/AnimatedOptions.show() + func store_export_settings() -> void: exported_tab = current_tab exported_frame_number = frame_number 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 exported_directory_path = directory_path @@ -299,6 +398,8 @@ 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 directory_path = exported_directory_path @@ -319,7 +420,7 @@ func _on_ExportDialog_about_to_show() -> void: $VBoxContainer/Options/Interpolation.selected = interpolation $VBoxContainer/Path/PathLineEdit.text = directory_path $VBoxContainer/File/FileLineEdit.text = file_name - $VBoxContainer/File/FileFormat.text = file_format + $VBoxContainer/File/FileFormat.selected = file_format show_tab() for child in $Popups.get_children(): # Set the theme for the popups @@ -356,6 +457,28 @@ func _on_LinesCount_value_changed(value : float) -> void: set_preview() +func _on_AnimationType_item_selected(id : int) -> void: + animation_type = id + set_file_format_selector() + set_preview() + + +func _on_BackgroundColor_color_changed(color : Color) -> void: + background_color = color + + +func _on_Direction_item_selected(id : int) -> void: + direction = id + match id: + AnimationDirection.Forward: + animated_preview_current_frame = 0 + AnimationDirection.Backwards: + animated_preview_current_frame = processed_images.size() - 1 + AnimationDirection.PingPong: + animated_preview_current_frame = 0 + pingpong_direction = AnimationDirection.Forward + + func _on_Resize_value_changed(value : float) -> void: resize = value @@ -391,11 +514,7 @@ func _on_FileDialog_dir_selected(dir : String) -> void: func _on_FileFormat_item_selected(id : int) -> void: - match id: - 0: # PNG - file_format = '.png' - 1: # GIF - file_format = '.gif' + file_format = id func _on_FileExistsAlert_confirmed() -> void: @@ -412,3 +531,44 @@ func _on_FileExistsAlert_custom_action(action : String) -> void: stop_export = true emit_signal("resume_export_function") $Popups/FileExistsAlert.hide() + + +var pingpong_direction = AnimationDirection.Forward +func _on_FrameTimer_timeout() -> void: + $VBoxContainer/PreviewScroll/Previews/PreviewContainer/Preview.texture = animated_preview_frames[animated_preview_current_frame] + + match direction: + AnimationDirection.Forward: + if animated_preview_current_frame == animated_preview_frames.size() - 1: + animated_preview_current_frame = 0 + else: + animated_preview_current_frame += 1 + + AnimationDirection.Backwards: + if animated_preview_current_frame == 0: + animated_preview_current_frame = processed_images.size() - 1 + else: + animated_preview_current_frame -= 1 + + AnimationDirection.PingPong: + match pingpong_direction: + AnimationDirection.Forward: + if animated_preview_current_frame == animated_preview_frames.size() - 1: + pingpong_direction = AnimationDirection.Backwards + animated_preview_current_frame -= 1 + if animated_preview_current_frame <= 0: + animated_preview_current_frame = 0 + else: + animated_preview_current_frame += 1 + AnimationDirection.Backwards: + if animated_preview_current_frame == 0: + animated_preview_current_frame += 1 + if animated_preview_current_frame >= animated_preview_frames.size() - 1: + animated_preview_current_frame = 0 + pingpong_direction = AnimationDirection.Forward + else: + animated_preview_current_frame -= 1 + + +func _on_ExportDialog_popup_hide() -> void: + $FrameTimer.stop() diff --git a/Translations/Translations.pot b/Translations/Translations.pot index a3d5b9709..dadb4c7a7 100644 --- a/Translations/Translations.pot +++ b/Translations/Translations.pot @@ -194,6 +194,24 @@ msgstr "" msgid "All frames as multiple files" msgstr "" +msgid "All frames as a single file animation" +msgstr "" + +msgid "Background:" +msgstr "" + +msgid "Direction:" +msgstr "" + +msgid "Forward" +msgstr "" + +msgid "Backwards" +msgstr "" + +msgid "Ping-Pong" +msgstr "" + msgid "EXPORT_CURRENT_FRAME_LABEL" msgstr "" diff --git a/addons/godot-gifexporter b/addons/godot-gifexporter new file mode 160000 index 000000000..eb7be4f9a --- /dev/null +++ b/addons/godot-gifexporter @@ -0,0 +1 @@ +Subproject commit eb7be4f9a9dded53f2ce8a24ecba001da368ca5c diff --git a/project.godot b/project.godot index a94296514..224f9adfe 100644 --- a/project.godot +++ b/project.godot @@ -70,6 +70,10 @@ gdscript/warnings/return_value_discarded=false window/size/width=1280 window/size/height=720 +[editor_plugins] + +enabled=PoolStringArray( "godot-gifexporter" ) + [importer_defaults] texture={