1
0
Fork 0
mirror of https://github.com/Orama-Interactive/Pixelorama.git synced 2025-01-18 17:19:50 +00:00

v0.2 - Animation Timeline & UI changes!

v0.2 of Pixelorama is out!
- Added animation timeline. You can add. remove. clone and change order of your frames!
- You can now import multiple images as frames.
- Ability to save individual frames, all frames as multiple files, or all frames as a single file in the form of a horizontal or vertical spritesheet!
- Different frames can have a unique amount of layers and they can be of different sizes.
- Image scaling is now functional.
- Added hints for UI elements.
- A lot of UI changes.
This commit is contained in:
OverloadedOrama 2019-09-10 01:57:46 +03:00
parent 1f80291a4b
commit 5781c42821
25 changed files with 765 additions and 183 deletions

1
.gitignore vendored
View file

@ -1 +1,2 @@
Scripts/Old/ Scripts/Old/
Assets/Graphics/Tools/

View file

@ -1,3 +0,0 @@
source_md5="b8469a8d2b9b7f33cde9c50c882514d3"
dest_md5="611bf34048e600d74fb53c849097c026"

View file

@ -1,3 +0,0 @@
source_md5="3f3e12abce4c2177df141c708b02c3cc"
dest_md5="5bb71e82d18a6514c7bec6e2f2996585"

View file

@ -1,3 +0,0 @@
source_md5="90f1e764a9d0303186411784568ef237"
dest_md5="b40997122ed6d10d1612023e114c7315"

View file

@ -1,3 +0,0 @@
source_md5="90f1e764a9d0303186411784568ef237"
dest_md5="5d2507d2ac9dd6d7f8b781cd64e5e4b6"

View file

@ -1,3 +0,0 @@
source_md5="6861c2574df688e89c30a4d2c3ff0512"
dest_md5="5eaa4f1834b413cd6fba1a5e73afdea5"

View file

@ -1,3 +0,0 @@
source_md5="327bd47a99785cc67d3b563e11e15386"
dest_md5="f762a141beffeb685bedf56872c571fc"

View file

@ -1,3 +0,0 @@
source_md5="3b9968d48bb94408d74340e812e4a715"
dest_md5="2d008139a38b2c0df1d773b0eb202d2f"

View file

@ -1,3 +0,0 @@
source_md5="d0ec0d56b87c9a8c60688d6af9d226a0"
dest_md5="605f5c73c93dc2a072713c6f3fcd0563"

View file

@ -1,3 +0,0 @@
source_md5="1afa25ff3984b4aa5d235e151ea745f2"
dest_md5="3331184ae61337c572353772eeedb37b"

View file

@ -1,3 +0,0 @@
source_md5="8cc6a8f03f20c923403c7d96eb234a23"
dest_md5="b99e77f302c757ba661cafd4fec3bab0"

View file

@ -1,3 +0,0 @@
source_md5="16bf0d760b5c4ff30efd2a7ddb10c5a7"
dest_md5="c9a9e4d828f496f7c9371c42dd41c332"

View file

@ -1,3 +0,0 @@
source_md5="702bfdd94a8185490af255dd080e549d"
dest_md5="0944e37fba7b57fbcd1c1b699eddb31f"

34
FrameButton.tscn Normal file
View file

@ -0,0 +1,34 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://Scripts/FrameButton.gd" type="Script" id=1]
[node name="Frame" type="VBoxContainer"]
margin_right = 32.0
margin_bottom = 50.0
[node name="FrameButton" type="Button" parent="."]
margin_right = 36.0
margin_bottom = 36.0
rect_min_size = Vector2( 36, 36 )
mouse_default_cursor_shape = 2
size_flags_horizontal = 0
size_flags_vertical = 0
script = ExtResource( 1 )
[node name="FrameTexture" type="TextureRect" parent="FrameButton"]
margin_left = 2.0
margin_top = 2.0
margin_right = 34.0
margin_bottom = 34.0
rect_min_size = Vector2( 32, 32 )
size_flags_horizontal = 0
size_flags_vertical = 0
expand = true
[node name="FrameID" type="Label" parent="."]
margin_top = 40.0
margin_right = 36.0
margin_bottom = 54.0
text = "0"
align = 1
[connection signal="pressed" from="FrameButton" to="FrameButton" method="_on_FrameButton_pressed"]

308
Main.tscn
View file

@ -211,27 +211,163 @@ min_value = 1.0
value = 1.0 value = 1.0
suffix = "px" suffix = "px"
[node name="ViewportContainer" type="ViewportContainer" parent="UI"] [node name="CanvasAndTimeline" type="VBoxContainer" parent="UI"]
editor/display_folded = true
margin_left = 324.0 margin_left = 324.0
margin_right = 860.0 margin_right = 860.0
margin_bottom = 600.0 margin_bottom = 600.0
size_flags_horizontal = 3
[node name="ViewportContainer" type="ViewportContainer" parent="UI/CanvasAndTimeline"]
margin_right = 536.0
margin_bottom = 448.0
mouse_default_cursor_shape = 3 mouse_default_cursor_shape = 3
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 3
stretch = true stretch = true
[node name="Viewport" type="Viewport" parent="UI/ViewportContainer"] [node name="Viewport" type="Viewport" parent="UI/CanvasAndTimeline/ViewportContainer"]
size = Vector2( 536, 600 ) size = Vector2( 536, 448 )
handle_input_locally = false handle_input_locally = false
render_target_update_mode = 3 render_target_update_mode = 3
[node name="Canvas" parent="UI/ViewportContainer/Viewport" instance=ExtResource( 5 )] [node name="Canvas" parent="UI/CanvasAndTimeline/ViewportContainer/Viewport" instance=ExtResource( 5 )]
[node name="Camera2D" type="Camera2D" parent="UI/ViewportContainer/Viewport"] [node name="Camera2D" type="Camera2D" parent="UI/CanvasAndTimeline/ViewportContainer/Viewport"]
current = true current = true
zoom = Vector2( 0.15, 0.15 ) zoom = Vector2( 0.15, 0.15 )
script = ExtResource( 6 ) script = ExtResource( 6 )
[node name="AnimationTimeline" type="Panel" parent="UI/CanvasAndTimeline"]
margin_top = 452.0
margin_right = 536.0
margin_bottom = 600.0
rect_min_size = Vector2( 0, 148 )
size_flags_horizontal = 3
[node name="TimelineContainer" type="VBoxContainer" parent="UI/CanvasAndTimeline/AnimationTimeline"]
anchor_right = 1.0
anchor_bottom = 1.0
size_flags_horizontal = 3
[node name="ButtonContainer" type="CenterContainer" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer"]
margin_right = 536.0
margin_bottom = 40.0
[node name="AnimationButtons" type="HBoxContainer" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/ButtonContainer"]
margin_left = 69.0
margin_right = 467.0
margin_bottom = 40.0
[node name="LoopAnim" type="CheckButton" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/ButtonContainer/AnimationButtons"]
margin_right = 111.0
margin_bottom = 40.0
hint_tooltip = "Should the animation loop (play again after it reached the end)?"
mouse_default_cursor_shape = 2
text = "Loop"
[node name="PlayBackwards" type="Button" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/ButtonContainer/AnimationButtons"]
margin_left = 115.0
margin_right = 224.0
margin_bottom = 40.0
hint_tooltip = "Play the animation backwards (from end to beggining)"
mouse_default_cursor_shape = 2
toggle_mode = true
text = "Play Backwards"
[node name="PlayForward" type="Button" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/ButtonContainer/AnimationButtons"]
margin_left = 228.0
margin_right = 320.0
margin_bottom = 40.0
hint_tooltip = "Play the animation forward (from beggining to end)"
mouse_default_cursor_shape = 2
size_flags_horizontal = 0
toggle_mode = true
text = "Play Forward"
[node name="FPSValue" type="SpinBox" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/ButtonContainer/AnimationButtons"]
margin_left = 324.0
margin_right = 398.0
margin_bottom = 40.0
hint_tooltip = "How many frames per second should the animation preview be? The more FPS, the faster the animation plays."
mouse_default_cursor_shape = 2
min_value = 1.0
value = 1.0
suffix = "FPS"
[node name="HSeparator" type="HSeparator" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer"]
margin_top = 44.0
margin_right = 536.0
margin_bottom = 48.0
[node name="CenterContainer" type="CenterContainer" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer"]
margin_top = 52.0
margin_right = 536.0
margin_bottom = 72.0
[node name="FrameButtons" type="HBoxContainer" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/CenterContainer"]
margin_left = 209.0
margin_right = 326.0
margin_bottom = 20.0
[node name="AddFrame" type="Button" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/CenterContainer/FrameButtons"]
margin_right = 20.0
margin_bottom = 20.0
hint_tooltip = "Add a new frame"
mouse_default_cursor_shape = 2
size_flags_horizontal = 0
text = "+"
[node name="RemoveFrame" type="Button" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/CenterContainer/FrameButtons"]
margin_left = 24.0
margin_right = 41.0
margin_bottom = 20.0
hint_tooltip = "Remove selected frame"
mouse_default_cursor_shape = 8
disabled = true
text = "-"
[node name="MoveFrameLeft" type="Button" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/CenterContainer/FrameButtons"]
margin_left = 45.0
margin_right = 65.0
margin_bottom = 20.0
hint_tooltip = "Move selected frame to the left"
mouse_default_cursor_shape = 8
disabled = true
text = "<"
[node name="MoveFrameRight" type="Button" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/CenterContainer/FrameButtons"]
margin_left = 69.0
margin_right = 89.0
margin_bottom = 20.0
hint_tooltip = "Move selected frame to the right"
mouse_default_cursor_shape = 8
disabled = true
text = ">"
[node name="CloneFrame" type="Button" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/CenterContainer/FrameButtons"]
margin_left = 93.0
margin_right = 117.0
margin_bottom = 20.0
hint_tooltip = "Clone current frame"
mouse_default_cursor_shape = 2
size_flags_horizontal = 0
text = "Cl"
[node name="HSeparator2" type="HSeparator" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer"]
margin_top = 76.0
margin_right = 536.0
margin_bottom = 80.0
[node name="ScrollContainer" type="ScrollContainer" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer"]
margin_top = 84.0
margin_right = 536.0
margin_bottom = 148.0
size_flags_horizontal = 3
size_flags_vertical = 3
scroll_vertical_enabled = false
[node name="FrameContainer" type="HBoxContainer" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/ScrollContainer"]
[node name="LayerPanel" type="Panel" parent="UI"] [node name="LayerPanel" type="Panel" parent="UI"]
editor/display_folded = true editor/display_folded = true
margin_left = 864.0 margin_left = 864.0
@ -239,19 +375,22 @@ margin_right = 1024.0
margin_bottom = 600.0 margin_bottom = 600.0
rect_min_size = Vector2( 160, 0 ) rect_min_size = Vector2( 160, 0 )
[node name="ScrollContainer" type="ScrollContainer" parent="UI/LayerPanel"] [node name="LayersAndMisc" type="VBoxContainer" parent="UI/LayerPanel"]
editor/display_folded = true anchor_right = 1.0
anchor_bottom = 1.0
[node name="ScrollContainer" type="ScrollContainer" parent="UI/LayerPanel/LayersAndMisc"]
margin_right = 160.0 margin_right = 160.0
margin_bottom = 600.0 margin_bottom = 538.0
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 3 size_flags_vertical = 3
[node name="VBoxLayerContainer" type="VBoxContainer" parent="UI/LayerPanel/ScrollContainer"] [node name="VBoxLayerContainer" type="VBoxContainer" parent="UI/LayerPanel/LayersAndMisc/ScrollContainer"]
margin_right = 160.0 margin_right = 160.0
margin_bottom = 38.0 margin_bottom = 38.0
size_flags_horizontal = 3 size_flags_horizontal = 3
[node name="LayerLabel" type="Label" parent="UI/LayerPanel/ScrollContainer/VBoxLayerContainer"] [node name="LayerLabel" type="Label" parent="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer"]
margin_right = 160.0 margin_right = 160.0
margin_bottom = 14.0 margin_bottom = 14.0
size_flags_horizontal = 3 size_flags_horizontal = 3
@ -259,19 +398,25 @@ size_flags_vertical = 0
text = "Layers" text = "Layers"
align = 1 align = 1
[node name="HBoxContainer" type="HBoxContainer" parent="UI/LayerPanel/ScrollContainer/VBoxLayerContainer"] [node name="CenterContainer" type="CenterContainer" parent="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer"]
editor/display_folded = true
margin_top = 18.0 margin_top = 18.0
margin_right = 160.0 margin_right = 160.0
margin_bottom = 38.0 margin_bottom = 38.0
[node name="AddLayerButton" type="Button" parent="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer"] [node name="LayerButtons" type="HBoxContainer" parent="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer/CenterContainer"]
margin_left = 7.0
margin_right = 153.0
margin_bottom = 20.0
[node name="AddLayerButton" type="Button" parent="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer/CenterContainer/LayerButtons"]
margin_right = 20.0 margin_right = 20.0
margin_bottom = 20.0 margin_bottom = 20.0
hint_tooltip = "Create a new layer" hint_tooltip = "Create a new layer"
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
text = "+" text = "+"
[node name="RemoveLayerButton" type="Button" parent="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer"] [node name="RemoveLayerButton" type="Button" parent="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer/CenterContainer/LayerButtons"]
margin_left = 24.0 margin_left = 24.0
margin_right = 44.0 margin_right = 44.0
margin_bottom = 20.0 margin_bottom = 20.0
@ -280,7 +425,7 @@ mouse_default_cursor_shape = 8
disabled = true disabled = true
text = "X" text = "X"
[node name="MoveUpLayer" type="Button" parent="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer"] [node name="MoveUpLayer" type="Button" parent="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer/CenterContainer/LayerButtons"]
margin_left = 48.0 margin_left = 48.0
margin_right = 67.0 margin_right = 67.0
margin_bottom = 20.0 margin_bottom = 20.0
@ -289,7 +434,7 @@ mouse_default_cursor_shape = 8
disabled = true disabled = true
text = "^" text = "^"
[node name="MoveDownLayer" type="Button" parent="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer"] [node name="MoveDownLayer" type="Button" parent="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer/CenterContainer/LayerButtons"]
margin_left = 71.0 margin_left = 71.0
margin_right = 90.0 margin_right = 90.0
margin_bottom = 20.0 margin_bottom = 20.0
@ -298,7 +443,7 @@ mouse_default_cursor_shape = 8
disabled = true disabled = true
text = "v" text = "v"
[node name="CloneLayer" type="Button" parent="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer"] [node name="CloneLayer" type="Button" parent="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer/CenterContainer/LayerButtons"]
margin_left = 94.0 margin_left = 94.0
margin_right = 118.0 margin_right = 118.0
margin_bottom = 20.0 margin_bottom = 20.0
@ -306,7 +451,7 @@ hint_tooltip = "Clone current layer"
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
text = "Cl" text = "Cl"
[node name="MergeDownLayer" type="Button" parent="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer"] [node name="MergeDownLayer" type="Button" parent="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer/CenterContainer/LayerButtons"]
margin_left = 122.0 margin_left = 122.0
margin_right = 146.0 margin_right = 146.0
margin_bottom = 20.0 margin_bottom = 20.0
@ -315,6 +460,28 @@ mouse_default_cursor_shape = 8
disabled = true disabled = true
text = "M" text = "M"
[node name="HSeparator" type="HSeparator" parent="UI/LayerPanel/LayersAndMisc"]
margin_top = 542.0
margin_right = 160.0
margin_bottom = 546.0
[node name="CursorPosition" type="Label" parent="UI/LayerPanel/LayersAndMisc"]
margin_top = 550.0
margin_right = 160.0
margin_bottom = 564.0
text = "[64x64]"
[node name="ZoomLevel" type="Label" parent="UI/LayerPanel/LayersAndMisc"]
margin_top = 568.0
margin_right = 160.0
margin_bottom = 582.0
text = "Zoom: x7.81"
[node name="EmptyLabel" type="Label" parent="UI/LayerPanel/LayersAndMisc"]
margin_top = 586.0
margin_right = 160.0
margin_bottom = 600.0
[node name="CreateNewImage" type="ConfirmationDialog" parent="."] [node name="CreateNewImage" type="ConfirmationDialog" parent="."]
editor/display_folded = true editor/display_folded = true
margin_right = 200.0 margin_right = 200.0
@ -342,11 +509,14 @@ margin_right = 46.0
margin_bottom = 19.0 margin_bottom = 19.0
text = "Width: " text = "Width: "
[node name="LineEdit" type="LineEdit" parent="CreateNewImage/VBoxContainer/WidthCont"] [node name="WidthValue" type="SpinBox" parent="CreateNewImage/VBoxContainer/WidthCont"]
margin_left = 50.0 margin_left = 50.0
margin_right = 108.0 margin_right = 124.0
margin_bottom = 24.0 margin_bottom = 24.0
text = "64" min_value = 1.0
max_value = 16384.0
value = 64.0
suffix = "px"
[node name="HeightCont" type="HBoxContainer" parent="CreateNewImage/VBoxContainer"] [node name="HeightCont" type="HBoxContainer" parent="CreateNewImage/VBoxContainer"]
margin_top = 46.0 margin_top = 46.0
@ -359,18 +529,21 @@ margin_right = 46.0
margin_bottom = 19.0 margin_bottom = 19.0
text = "Height:" text = "Height:"
[node name="LineEdit" type="LineEdit" parent="CreateNewImage/VBoxContainer/HeightCont"] [node name="HeightValue" type="SpinBox" parent="CreateNewImage/VBoxContainer/HeightCont"]
margin_left = 50.0 margin_left = 50.0
margin_right = 108.0 margin_right = 124.0
margin_bottom = 24.0 margin_bottom = 24.0
text = "64" min_value = 1.0
max_value = 16384.0
value = 64.0
suffix = "px"
[node name="OpenSprite" type="FileDialog" parent="."] [node name="OpenSprite" type="FileDialog" parent="."]
margin_right = 515.0 margin_right = 515.0
margin_bottom = 348.0 margin_bottom = 348.0
window_title = "Open a File" window_title = "Open File(s)"
resizable = true resizable = true
mode = 0 mode = 1
access = 2 access = 2
filters = PoolStringArray( "*jpg, *.png ; JPG, PNG Images" ) filters = PoolStringArray( "*jpg, *.png ; JPG, PNG Images" )
current_dir = "C:/Users/Overloaded/Dropbox/Orama Founding Members/εταιρικα αρχεια/Godot Projects/Pixelorama" current_dir = "C:/Users/Overloaded/Dropbox/Orama Founding Members/εταιρικα αρχεια/Godot Projects/Pixelorama"
@ -385,7 +558,7 @@ margin_left = -512.0
margin_top = -300.0 margin_top = -300.0
margin_right = 3.0 margin_right = 3.0
margin_bottom = 48.0 margin_bottom = 48.0
window_title = "Create a new image" window_title = "Export sprite"
resizable = true resizable = true
access = 2 access = 2
filters = PoolStringArray( "*.png ; PNG Image" ) filters = PoolStringArray( "*.png ; PNG Image" )
@ -393,24 +566,25 @@ current_dir = "C:/Users/Overloaded/Dropbox/Orama Founding Members/εταιρικ
current_path = "C:/Users/Overloaded/Dropbox/Orama Founding Members/εταιρικα αρχεια/Godot Projects/Pixelorama/" current_path = "C:/Users/Overloaded/Dropbox/Orama Founding Members/εταιρικα αρχεια/Godot Projects/Pixelorama/"
[node name="ScaleImage" type="ConfirmationDialog" parent="."] [node name="ScaleImage" type="ConfirmationDialog" parent="."]
editor/display_folded = true visible = true
margin_right = 200.0 margin_right = 200.0
margin_bottom = 114.0 margin_bottom = 114.0
[node name="VBoxContainer" type="VBoxContainer" parent="ScaleImage"] [node name="VBoxContainer" type="VBoxContainer" parent="ScaleImage"]
margin_left = 8.0 margin_left = 8.0
margin_top = 8.0 margin_top = 8.0
margin_right = 192.0 margin_right = 257.0
margin_bottom = 78.0 margin_bottom = 102.0
[node name="ImageSize" type="Label" parent="ScaleImage/VBoxContainer"] [node name="ImageSize" type="Label" parent="ScaleImage/VBoxContainer"]
margin_right = 184.0 margin_right = 249.0
margin_bottom = 14.0 margin_bottom = 14.0
text = "Image Size" text = "Image Size"
[node name="WidthCont" type="HBoxContainer" parent="ScaleImage/VBoxContainer"] [node name="WidthCont" type="HBoxContainer" parent="ScaleImage/VBoxContainer"]
editor/display_folded = true
margin_top = 18.0 margin_top = 18.0
margin_right = 184.0 margin_right = 249.0
margin_bottom = 42.0 margin_bottom = 42.0
[node name="WidthLabel" type="Label" parent="ScaleImage/VBoxContainer/WidthCont"] [node name="WidthLabel" type="Label" parent="ScaleImage/VBoxContainer/WidthCont"]
@ -419,15 +593,19 @@ margin_right = 46.0
margin_bottom = 19.0 margin_bottom = 19.0
text = "Width: " text = "Width: "
[node name="LineEdit" type="LineEdit" parent="ScaleImage/VBoxContainer/WidthCont"] [node name="WidthValue" type="SpinBox" parent="ScaleImage/VBoxContainer/WidthCont"]
margin_left = 50.0 margin_left = 50.0
margin_right = 108.0 margin_right = 124.0
margin_bottom = 24.0 margin_bottom = 24.0
text = "64" min_value = 1.0
max_value = 16384.0
value = 64.0
suffix = "px"
[node name="HeightCont" type="HBoxContainer" parent="ScaleImage/VBoxContainer"] [node name="HeightCont" type="HBoxContainer" parent="ScaleImage/VBoxContainer"]
editor/display_folded = true
margin_top = 46.0 margin_top = 46.0
margin_right = 184.0 margin_right = 249.0
margin_bottom = 70.0 margin_bottom = 70.0
[node name="Height" type="Label" parent="ScaleImage/VBoxContainer/HeightCont"] [node name="Height" type="Label" parent="ScaleImage/VBoxContainer/HeightCont"]
@ -436,11 +614,35 @@ margin_right = 46.0
margin_bottom = 19.0 margin_bottom = 19.0
text = "Height:" text = "Height:"
[node name="LineEdit" type="LineEdit" parent="ScaleImage/VBoxContainer/HeightCont"] [node name="HeightValue" type="SpinBox" parent="ScaleImage/VBoxContainer/HeightCont"]
margin_left = 50.0 margin_left = 50.0
margin_right = 108.0 margin_right = 124.0
margin_bottom = 24.0 margin_bottom = 24.0
text = "64" min_value = 1.0
max_value = 16384.0
value = 64.0
suffix = "px"
[node name="InterpolationContainer" type="HBoxContainer" parent="ScaleImage/VBoxContainer"]
margin_top = 74.0
margin_right = 249.0
margin_bottom = 94.0
[node name="InterpolationLabel" type="Label" parent="ScaleImage/VBoxContainer/InterpolationContainer"]
margin_top = 3.0
margin_right = 87.0
margin_bottom = 17.0
text = "Interpolation:"
[node name="InterpolationType" type="OptionButton" parent="ScaleImage/VBoxContainer/InterpolationContainer"]
margin_left = 91.0
margin_right = 249.0
margin_bottom = 20.0
text = "Interpolation Type"
items = [ "Nearest", null, false, 0, null, "Bilinear", null, false, 1, null, "Cubic", null, false, 2, null, "Trilinear", null, false, 3, null ]
selected = 0
[node name="AnimationTimer" type="Timer" parent="."]
[connection signal="toggled" from="UI/ToolPanel/Tools/ToolOptions/LeftToolOptions/LeftIndicatorCheckbox" to="." method="_on_LeftIndicatorCheckbox_toggled"] [connection signal="toggled" from="UI/ToolPanel/Tools/ToolOptions/LeftToolOptions/LeftIndicatorCheckbox" to="." method="_on_LeftIndicatorCheckbox_toggled"]
[connection signal="popup_closed" from="UI/ToolPanel/Tools/ToolOptions/LeftToolOptions/LeftColorPickerButton" to="." method="_can_draw_true"] [connection signal="popup_closed" from="UI/ToolPanel/Tools/ToolOptions/LeftToolOptions/LeftColorPickerButton" to="." method="_can_draw_true"]
[connection signal="pressed" from="UI/ToolPanel/Tools/ToolOptions/LeftToolOptions/LeftColorPickerButton" to="." method="_can_draw_false"] [connection signal="pressed" from="UI/ToolPanel/Tools/ToolOptions/LeftToolOptions/LeftColorPickerButton" to="." method="_can_draw_false"]
@ -449,19 +651,29 @@ text = "64"
[connection signal="popup_closed" from="UI/ToolPanel/Tools/ToolOptions/RightToolOptions/RightColorPickerButton" to="." method="_can_draw_true"] [connection signal="popup_closed" from="UI/ToolPanel/Tools/ToolOptions/RightToolOptions/RightColorPickerButton" to="." method="_can_draw_true"]
[connection signal="pressed" from="UI/ToolPanel/Tools/ToolOptions/RightToolOptions/RightColorPickerButton" to="." method="_can_draw_false"] [connection signal="pressed" from="UI/ToolPanel/Tools/ToolOptions/RightToolOptions/RightColorPickerButton" to="." method="_can_draw_false"]
[connection signal="value_changed" from="UI/ToolPanel/Tools/ToolOptions/RightToolOptions/BrushSize/RightBrushSizeEdit" to="." method="_on_RightBrushSizeEdit_value_changed"] [connection signal="value_changed" from="UI/ToolPanel/Tools/ToolOptions/RightToolOptions/BrushSize/RightBrushSizeEdit" to="." method="_on_RightBrushSizeEdit_value_changed"]
[connection signal="mouse_entered" from="UI/ViewportContainer" to="." method="_on_ViewportContainer_mouse_entered"] [connection signal="mouse_entered" from="UI/CanvasAndTimeline/ViewportContainer" to="." method="_on_ViewportContainer_mouse_entered"]
[connection signal="mouse_exited" from="UI/ViewportContainer" to="." method="_on_ViewportContainer_mouse_exited"] [connection signal="mouse_exited" from="UI/CanvasAndTimeline/ViewportContainer" to="." method="_on_ViewportContainer_mouse_exited"]
[connection signal="pressed" from="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer/AddLayerButton" to="." method="_on_AddLayerButton_pressed"] [connection signal="toggled" from="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/ButtonContainer/AnimationButtons/LoopAnim" to="." method="_on_LoopAnim_toggled"]
[connection signal="pressed" from="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer/RemoveLayerButton" to="." method="_on_RemoveLayerButton_pressed"] [connection signal="toggled" from="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/ButtonContainer/AnimationButtons/PlayBackwards" to="." method="_on_PlayBackwards_toggled"]
[connection signal="pressed" from="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer/MoveUpLayer" to="." method="_on_MoveUpLayer_pressed"] [connection signal="toggled" from="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/ButtonContainer/AnimationButtons/PlayForward" to="." method="_on_PlayForward_toggled"]
[connection signal="pressed" from="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer/MoveDownLayer" to="." method="_on_MoveDownLayer_pressed"] [connection signal="value_changed" from="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/ButtonContainer/AnimationButtons/FPSValue" to="." method="_on_FPSValue_value_changed"]
[connection signal="pressed" from="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer/CloneLayer" to="." method="_on_CloneLayer_pressed"] [connection signal="pressed" from="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/CenterContainer/FrameButtons/AddFrame" to="." method="_on_AddFrame_pressed"]
[connection signal="pressed" from="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer/MergeDownLayer" to="." method="_on_MergeLayer_pressed"] [connection signal="pressed" from="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/CenterContainer/FrameButtons/RemoveFrame" to="." method="_on_RemoveFrame_pressed"]
[connection signal="pressed" from="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/CenterContainer/FrameButtons/MoveFrameLeft" to="." method="_on_MoveFrameLeft_pressed"]
[connection signal="pressed" from="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/CenterContainer/FrameButtons/MoveFrameRight" to="." method="_on_MoveFrameRight_pressed"]
[connection signal="pressed" from="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/CenterContainer/FrameButtons/CloneFrame" to="." method="_on_CloneFrame_pressed"]
[connection signal="pressed" from="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer/CenterContainer/LayerButtons/AddLayerButton" to="." method="_on_AddLayerButton_pressed"]
[connection signal="pressed" from="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer/CenterContainer/LayerButtons/RemoveLayerButton" to="." method="_on_RemoveLayerButton_pressed"]
[connection signal="pressed" from="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer/CenterContainer/LayerButtons/MoveUpLayer" to="." method="_on_MoveUpLayer_pressed"]
[connection signal="pressed" from="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer/CenterContainer/LayerButtons/MoveDownLayer" to="." method="_on_MoveDownLayer_pressed"]
[connection signal="pressed" from="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer/CenterContainer/LayerButtons/CloneLayer" to="." method="_on_CloneLayer_pressed"]
[connection signal="pressed" from="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer/CenterContainer/LayerButtons/MergeDownLayer" to="." method="_on_MergeLayer_pressed"]
[connection signal="confirmed" from="CreateNewImage" to="." method="_on_CreateNewImage_confirmed"] [connection signal="confirmed" from="CreateNewImage" to="." method="_on_CreateNewImage_confirmed"]
[connection signal="popup_hide" from="CreateNewImage" to="." method="_can_draw_true"] [connection signal="popup_hide" from="CreateNewImage" to="." method="_can_draw_true"]
[connection signal="file_selected" from="OpenSprite" to="." method="_on_OpenSprite_file_selected"] [connection signal="files_selected" from="OpenSprite" to="." method="_on_OpenSprite_files_selected"]
[connection signal="popup_hide" from="OpenSprite" to="." method="_on_OpenSprite_popup_hide"] [connection signal="popup_hide" from="OpenSprite" to="." method="_on_OpenSprite_popup_hide"]
[connection signal="file_selected" from="SaveSprite" to="." method="_on_SaveSprite_file_selected"] [connection signal="file_selected" from="SaveSprite" to="." method="_on_SaveSprite_file_selected"]
[connection signal="popup_hide" from="SaveSprite" to="." method="_can_draw_true"] [connection signal="popup_hide" from="SaveSprite" to="." method="_can_draw_true"]
[connection signal="confirmed" from="ScaleImage" to="." method="_on_ScaleImage_confirmed"] [connection signal="confirmed" from="ScaleImage" to="." method="_on_ScaleImage_confirmed"]
[connection signal="popup_hide" from="ScaleImage" to="." method="_can_draw_true"] [connection signal="popup_hide" from="ScaleImage" to="." method="_can_draw_true"]
[connection signal="timeout" from="AnimationTimer" to="." method="_on_AnimationTimer_timeout"]

View file

@ -1,7 +1,7 @@
extends Camera2D extends Camera2D
var zoom_min := Vector2(0.005, 0.005) var zoom_min := Vector2(0.005, 0.005)
var zoom_max := Vector2(0.8, 0.8) var zoom_max := Vector2.ONE
var drag := false var drag := false
@ -21,5 +21,11 @@ func _input(event) -> void:
# Zoom Camera # Zoom Camera
func zoom_camera(dir : int) -> void: func zoom_camera(dir : int) -> void:
var zoom_margin = zoom * dir / 10 var zoom_margin = zoom * dir / 10
if zoom + zoom_margin > zoom_min && zoom + zoom_margin < zoom_max: #if zoom + zoom_margin > zoom_min && zoom + zoom_margin < zoom_max:
if zoom + zoom_margin > zoom_min:
zoom += zoom_margin zoom += zoom_margin
if zoom > zoom_max:
zoom = zoom_max
Global.zoom_level_label.text = "Zoom: x%s" % [stepify(1 / zoom.x, 0.01)]

View file

@ -4,20 +4,18 @@ class_name Canvas
var layers := [] var layers := []
var current_layer_index := 0 var current_layer_index := 0
var trans_background : ImageTexture var trans_background : ImageTexture
var current_sprite : Image
var location := Vector2.ZERO var location := Vector2.ZERO
var size := Vector2(64, 64) var size := Vector2(64, 64)
var frame := 0
var frame_button : VBoxContainer
var frame_texture_rect : TextureRect
var previous_mouse_pos := Vector2.ZERO var previous_mouse_pos := Vector2.ZERO
var mouse_inside_canvas := false #used for undo var mouse_inside_canvas := false #used for undo
var sprite_changed_this_frame := false #for optimization purposes var sprite_changed_this_frame := false #for optimization purposes
var left_square_indicator_visible := true
var right_square_indicator_visible := false
var left_brush_size := 1
var right_brush_size := 1
var is_making_line := false var is_making_line := false
var line_2d : Line2D var line_2d : Line2D
var draw_grid := false
# Called when the node enters the scene tree for the first time. # Called when the node enters the scene tree for the first time.
func _ready() -> void: func _ready() -> void:
@ -27,24 +25,29 @@ func _ready() -> void:
trans_background.create_from_image(load("res://Transparent Background.png"), 0) trans_background.create_from_image(load("res://Transparent Background.png"), 0)
#The sprite itself #The sprite itself
if !current_sprite: if layers.empty():
current_sprite = Image.new() var sprite := Image.new()
current_sprite.create(size.x, size.y, false, Image.FORMAT_RGBA8) sprite.create(size.x, size.y, false, Image.FORMAT_RGBA8)
current_sprite.lock() sprite.lock()
var tex := ImageTexture.new() var tex := ImageTexture.new()
tex.create_from_image(current_sprite, 0) tex.create_from_image(sprite, 0)
#Store [Image, ImageTexture, Layer Name, Visibity boolean] #Store [Image, ImageTexture, Layer Name, Visibity boolean]
layers.append([current_sprite, tex, "Layer 0", true]) layers.append([sprite, tex, "Layer 0", true])
generate_layer_panels() generate_layer_panels()
#Set camera offset to the center of canvas
$"../Camera2D".offset = size / 2 frame_button = load("res://FrameButton.tscn").instance()
#Set camera zoom based on the sprite size frame_button.name = "Frame_%s" % frame
var bigger = max(size.x, size.y) frame_button.get_node("FrameButton").frame = frame
$"../Camera2D".zoom_max = Vector2(bigger, bigger) * 0.01 frame_button.get_node("FrameID").text = str(frame)
$"../Camera2D".zoom = Vector2(bigger, bigger) * 0.002 Global.frame_container.add_child(frame_button)
frame_texture_rect = Global.find_node_by_name(frame_button, "FrameTexture")
frame_texture_rect.texture = layers[0][1] #ImageTexture current_layer_index
camera_zoom()
# warning-ignore:unused_argument # warning-ignore:unused_argument
func _process(delta) -> void: func _process(delta) -> void:
@ -60,11 +63,16 @@ func _process(delta) -> void:
current_mouse_button = "R" current_mouse_button = "R"
current_action = Global.current_right_tool current_action = Global.current_right_tool
if visible:
if !point_in_rectangle(mouse_pos, location, location + size): if !point_in_rectangle(mouse_pos, location, location + size):
if !Input.is_mouse_button_pressed(BUTTON_LEFT) && !Input.is_mouse_button_pressed(BUTTON_RIGHT): if !Input.is_mouse_button_pressed(BUTTON_LEFT) && !Input.is_mouse_button_pressed(BUTTON_RIGHT):
if mouse_inside_canvas: if mouse_inside_canvas:
mouse_inside_canvas = false mouse_inside_canvas = false
Global.cursor_position_label.text = "[%sx%s]" % [size.x, size.y]
else:
var mouse_pos_floored := mouse_pos.floor()
Global.cursor_position_label.text = "[%sx%s] %s, %s" % [size.x, size.y, mouse_pos_floored.x, mouse_pos_floored.y]
match current_action: match current_action:
"Pencil": "Pencil":
var current_color : Color var current_color : Color
@ -76,7 +84,7 @@ func _process(delta) -> void:
"Eraser": "Eraser":
pencil_and_eraser(mouse_pos, Color(0, 0, 0, 0), current_mouse_button) pencil_and_eraser(mouse_pos, Color(0, 0, 0, 0), current_mouse_button)
"Fill": "Fill":
if point_in_rectangle(mouse_pos, location, location + size) && Global.can_draw && Global.has_focus: if point_in_rectangle(mouse_pos, location, location + size) && Global.can_draw && Global.has_focus && Global.current_frame == frame:
var current_color : Color var current_color : Color
if current_mouse_button == "L": if current_mouse_button == "L":
current_color = Global.left_color_picker.color current_color = Global.left_color_picker.color
@ -94,10 +102,19 @@ func _process(delta) -> void:
if sprite_changed_this_frame: if sprite_changed_this_frame:
update_texture(current_layer_index) update_texture(current_layer_index)
func update_texture(layer_index : int): func update_texture(layer_index : int) -> void:
layers[layer_index][1].create_from_image(layers[layer_index][0], 0) layers[layer_index][1].create_from_image(layers[layer_index][0], 0)
get_layer_container(layer_index).get_child(0).get_child(1).texture = layers[layer_index][1] get_layer_container(layer_index).get_child(0).get_child(1).texture = layers[layer_index][1]
var whole_image := Image.new()
whole_image.create(size.x, size.y, false, Image.FORMAT_RGBA8)
for layer in layers:
whole_image.blend_rect(layer[0], Rect2(position, size), Vector2.ZERO)
layer[0].lock()
var whole_image_texture := ImageTexture.new()
whole_image_texture.create_from_image(whole_image, 0)
frame_texture_rect.texture = whole_image_texture
func get_layer_container(layer_index : int) -> PanelContainer: func get_layer_container(layer_index : int) -> PanelContainer:
for container in Global.vbox_layer_container.get_children(): for container in Global.vbox_layer_container.get_children():
if container is PanelContainer && container.i == layer_index: if container is PanelContainer && container.i == layer_index:
@ -112,7 +129,7 @@ func _draw() -> void:
draw_texture(texture[1], location) draw_texture(texture[1], location)
#Idea taken from flurick (on GitHub) #Idea taken from flurick (on GitHub)
if draw_grid: if Global.draw_grid:
for x in size.x: for x in size.x:
draw_line(Vector2(x, location.y), Vector2(x, size.y), Color.black, true) draw_line(Vector2(x, location.y), Vector2(x, size.y), Color.black, true)
for y in size.y: for y in size.y:
@ -122,14 +139,14 @@ func _draw() -> void:
var mouse_pos := get_local_mouse_position() - location var mouse_pos := get_local_mouse_position() - location
if point_in_rectangle(mouse_pos, location, location + size): if point_in_rectangle(mouse_pos, location, location + size):
mouse_pos = mouse_pos.floor() mouse_pos = mouse_pos.floor()
if left_square_indicator_visible: if Global.left_square_indicator_visible:
var start_pos_x = mouse_pos.x - (left_brush_size >> 1) var start_pos_x = mouse_pos.x - (Global.left_brush_size >> 1)
var start_pos_y = mouse_pos.y - (left_brush_size >> 1) var start_pos_y = mouse_pos.y - (Global.left_brush_size >> 1)
draw_rect(Rect2(start_pos_x, start_pos_y, left_brush_size, left_brush_size), Color.blue, false) draw_rect(Rect2(start_pos_x, start_pos_y, Global.left_brush_size, Global.left_brush_size), Color.blue, false)
if right_square_indicator_visible: if Global.right_square_indicator_visible:
var start_pos_x = mouse_pos.x - (right_brush_size >> 1) var start_pos_x = mouse_pos.x - (Global.right_brush_size >> 1)
var start_pos_y = mouse_pos.y - (right_brush_size >> 1) var start_pos_y = mouse_pos.y - (Global.right_brush_size >> 1)
draw_rect(Rect2(start_pos_x, start_pos_y, right_brush_size, right_brush_size), Color.red, false) draw_rect(Rect2(start_pos_x, start_pos_y, Global.right_brush_size, Global.right_brush_size), Color.red, false)
func generate_layer_panels() -> void: func generate_layer_panels() -> void:
for child in Global.vbox_layer_container.get_children(): for child in Global.vbox_layer_container.get_children():
@ -155,6 +172,19 @@ func generate_layer_panels() -> void:
layer_container.get_child(0).get_child(1).texture = layers[i][1] layer_container.get_child(0).get_child(1).texture = layers[i][1]
Global.vbox_layer_container.add_child(layer_container) Global.vbox_layer_container.add_child(layer_container)
func camera_zoom() -> void:
#Set camera offset to the center of canvas
Global.camera.offset = size / 2
#Set camera zoom based on the sprite size
var bigger = max(size.x, size.y)
var zoom_max := Vector2(bigger, bigger) * 0.01
if zoom_max > Vector2.ONE:
Global.camera.zoom_max = zoom_max
else:
Global.camera.zoom_max = Vector2.ONE
Global.camera.zoom = Vector2(bigger, bigger) * 0.002
Global.zoom_level_label.text = "Zoom: x%s" % [stepify(1 / $"../Camera2D".zoom.x, 0.01)]
func pencil_and_eraser(mouse_pos : Vector2, color : Color, current_mouse_button : String) -> void: func pencil_and_eraser(mouse_pos : Vector2, color : Color, current_mouse_button : String) -> void:
if Input.is_key_pressed(KEY_SHIFT): if Input.is_key_pressed(KEY_SHIFT):
if !is_making_line: if !is_making_line:
@ -168,9 +198,9 @@ func pencil_and_eraser(mouse_pos : Vector2, color : Color, current_mouse_button
else: else:
var brush_size := 1 var brush_size := 1
if current_mouse_button == "L": if current_mouse_button == "L":
brush_size = left_brush_size brush_size = Global.left_brush_size
elif current_mouse_button == "R": elif current_mouse_button == "R":
brush_size = right_brush_size brush_size = Global.right_brush_size
if is_making_line: if is_making_line:
fill_gaps(mouse_pos, color, brush_size) fill_gaps(mouse_pos, color, brush_size)
@ -187,7 +217,7 @@ func pencil_and_eraser(mouse_pos : Vector2, color : Color, current_mouse_button
fill_gaps(mouse_pos, color, brush_size) fill_gaps(mouse_pos, color, brush_size)
func draw_pixel(pos : Vector2, color : Color, brush_size : int) -> void: func draw_pixel(pos : Vector2, color : Color, brush_size : int) -> void:
if Global.can_draw && Global.has_focus: if Global.can_draw && Global.has_focus && Global.current_frame == frame:
var start_pos_x = pos.x - (brush_size >> 1) var start_pos_x = pos.x - (brush_size >> 1)
var start_pos_y = pos.y - (brush_size >> 1) var start_pos_y = pos.y - (brush_size >> 1)
for cur_pos_x in range(start_pos_x, start_pos_x + brush_size): for cur_pos_x in range(start_pos_x, start_pos_x + brush_size):

8
Scripts/FrameButton.gd Normal file
View file

@ -0,0 +1,8 @@
extends Button
var frame := 0
func _on_FrameButton_pressed() -> void:
Global.current_frame = frame
#print(len(Global.canvases))
Global.change_frame()

View file

@ -1,22 +1,44 @@
extends Node extends Node
# warning-ignore:unused_class_variable
var current_frame := 0
# warning-ignore:unused_class_variable # warning-ignore:unused_class_variable
var can_draw := false var can_draw := false
# warning-ignore:unused_class_variable # warning-ignore:unused_class_variable
var has_focus := true var has_focus := true
# warning-ignore:unused_class_variable
var draw_grid := false
var canvases := []
var canvas : Canvas var canvas : Canvas
var canvas_parent var canvas_parent : Node
# warning-ignore:unused_class_variable
var left_square_indicator_visible := true
# warning-ignore:unused_class_variable
var right_square_indicator_visible := false
# warning-ignore:unused_class_variable
var left_brush_size := 1
# warning-ignore:unused_class_variable
var right_brush_size := 1
var camera : Camera2D
var left_color_picker : ColorPickerButton var left_color_picker : ColorPickerButton
var right_color_picker : ColorPickerButton var right_color_picker : ColorPickerButton
var file_menu : MenuButton var file_menu : MenuButton
var edit_menu : MenuButton var edit_menu : MenuButton
var left_indicator : Sprite var left_indicator : Sprite
var right_indicator : Sprite var right_indicator : Sprite
var play_forward : Button
var play_backwards : Button
var frame_container : HBoxContainer
var remove_frame_button : Button
var move_left_frame_button : Button
var move_right_frame_button : Button
var vbox_layer_container : VBoxContainer var vbox_layer_container : VBoxContainer
var remove_layer_button : Button var remove_layer_button : Button
var move_up_layer_button : Button var move_up_layer_button : Button
var move_down_layer_button : Button var move_down_layer_button : Button
var merge_down_layer_button : Button var merge_down_layer_button : Button
var cursor_position_label : Label
var zoom_level_label : Label
# warning-ignore:unused_class_variable # warning-ignore:unused_class_variable
var current_left_tool := "Pencil" var current_left_tool := "Pencil"
# warning-ignore:unused_class_variable # warning-ignore:unused_class_variable
@ -25,18 +47,28 @@ var current_right_tool := "Eraser"
func _ready() -> void: func _ready() -> void:
var root = get_tree().get_root() var root = get_tree().get_root()
canvas = find_node_by_name(root, "Canvas") canvas = find_node_by_name(root, "Canvas")
canvases.append(canvas)
canvas_parent = canvas.get_parent() canvas_parent = canvas.get_parent()
camera = find_node_by_name(canvas_parent, "Camera2D")
left_color_picker = find_node_by_name(root, "LeftColorPickerButton") left_color_picker = find_node_by_name(root, "LeftColorPickerButton")
right_color_picker = find_node_by_name(root, "RightColorPickerButton") right_color_picker = find_node_by_name(root, "RightColorPickerButton")
file_menu = find_node_by_name(root, "FileMenu") file_menu = find_node_by_name(root, "FileMenu")
edit_menu = find_node_by_name(root, "EditMenu") edit_menu = find_node_by_name(root, "EditMenu")
left_indicator = find_node_by_name(root, "LeftIndicator") left_indicator = find_node_by_name(root, "LeftIndicator")
right_indicator = find_node_by_name(root, "RightIndicator") right_indicator = find_node_by_name(root, "RightIndicator")
play_forward = find_node_by_name(root, "PlayForward")
play_backwards = find_node_by_name(root, "PlayBackwards")
frame_container = find_node_by_name(root, "FrameContainer")
remove_frame_button = find_node_by_name(root, "RemoveFrame")
move_left_frame_button = find_node_by_name(root, "MoveFrameLeft")
move_right_frame_button = find_node_by_name(root, "MoveFrameRight")
vbox_layer_container = find_node_by_name(root, "VBoxLayerContainer") vbox_layer_container = find_node_by_name(root, "VBoxLayerContainer")
remove_layer_button = find_node_by_name(root, "RemoveLayerButton") remove_layer_button = find_node_by_name(root, "RemoveLayerButton")
move_up_layer_button = find_node_by_name(root, "MoveUpLayer") move_up_layer_button = find_node_by_name(root, "MoveUpLayer")
move_down_layer_button = find_node_by_name(root, "MoveDownLayer") move_down_layer_button = find_node_by_name(root, "MoveDownLayer")
merge_down_layer_button = find_node_by_name(root, "MergeDownLayer") merge_down_layer_button = find_node_by_name(root, "MergeDownLayer")
cursor_position_label = find_node_by_name(root, "CursorPosition")
zoom_level_label = find_node_by_name(root, "ZoomLevel")
#Thanks to https://godotengine.org/qa/17524/how-to-find-an-instanced-scene-by-its-name #Thanks to https://godotengine.org/qa/17524/how-to-find-an-instanced-scene-by-its-name
func find_node_by_name(root, node_name) -> Node: func find_node_by_name(root, node_name) -> Node:
@ -49,3 +81,26 @@ func find_node_by_name(root, node_name) -> Node:
if found: if found:
return found return found
return null return null
func change_frame() -> void:
for c in canvases:
c.visible = false
canvas = canvases[current_frame]
canvas.visible = true
canvas.generate_layer_panels()
handle_layer_order_buttons()
func handle_layer_order_buttons() -> void:
if current_frame == 0:
move_left_frame_button.disabled = true
move_left_frame_button.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN
else:
move_left_frame_button.disabled = false
move_left_frame_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
if current_frame == canvases.size() - 1:
move_right_frame_button.disabled = true
move_right_frame_button.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN
else:
move_right_frame_button.disabled = false
move_right_frame_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND

View file

@ -5,21 +5,30 @@ var opensprite_file_selected := false
var pencil_tool var pencil_tool
var eraser_tool var eraser_tool
var fill_tool var fill_tool
var export_all_frames : CheckButton
var export_as_single_file : CheckButton
var export_vertical_spritesheet : CheckButton
var fps := 1.0
var animation_loop := false
var animation_forward := true
# Called when the node enters the scene tree for the first time. # Called when the node enters the scene tree for the first time.
func _ready() -> void: func _ready() -> void:
var file_menu_items := { var file_menu_items := {
"New..." : KEY_MASK_CTRL + KEY_N, "New..." : KEY_MASK_CTRL + KEY_N,
#The import and export key shortcuts will change,
#and they will be bound to Open and Save/Save as once I
#make a custom file for Pixelorama projects
"Import..." : KEY_MASK_CTRL + KEY_O, "Import..." : KEY_MASK_CTRL + KEY_O,
"Export..." : KEY_MASK_CTRL + KEY_S, "Export..." : KEY_MASK_CTRL + KEY_S,
"Export as..." : KEY_MASK_SHIFT + KEY_MASK_CTRL + KEY_S, "Export as..." : KEY_MASK_SHIFT + KEY_MASK_CTRL + KEY_S,
"Quit" : KEY_MASK_CTRL + KEY_Q "Quit" : KEY_MASK_CTRL + KEY_Q
} }
var edit_menu_items := { var edit_menu_items := {
"Scale Image" : 0,
"Show Grid" : KEY_MASK_CTRL + KEY_G "Show Grid" : KEY_MASK_CTRL + KEY_G
#"Undo" : KEY_MASK_CTRL + KEY_Z, #"Undo" : KEY_MASK_CTRL + KEY_Z,
#"Redo" : KEY_MASK_SHIFT + KEY_MASK_CTRL + KEY_Z, #"Redo" : KEY_MASK_SHIFT + KEY_MASK_CTRL + KEY_Z,
#"Scale Image" : 0
} }
var file_menu : PopupMenu = Global.file_menu.get_popup() var file_menu : PopupMenu = Global.file_menu.get_popup()
var edit_menu : PopupMenu = Global.edit_menu.get_popup() var edit_menu : PopupMenu = Global.edit_menu.get_popup()
@ -42,6 +51,16 @@ func _ready() -> void:
eraser_tool.connect("pressed", self, "_on_Tool_pressed", [eraser_tool]) eraser_tool.connect("pressed", self, "_on_Tool_pressed", [eraser_tool])
fill_tool.connect("pressed", self, "_on_Tool_pressed", [fill_tool]) fill_tool.connect("pressed", self, "_on_Tool_pressed", [fill_tool])
export_all_frames = CheckButton.new()
export_all_frames.text = "Export all frames?"
export_as_single_file = CheckButton.new()
export_as_single_file.text = "Export frames as a single file?"
export_vertical_spritesheet = CheckButton.new()
export_vertical_spritesheet.text = "Vertical spritesheet?"
$SaveSprite.get_vbox().add_child(export_all_frames)
$SaveSprite.get_vbox().add_child(export_as_single_file)
$SaveSprite.get_vbox().add_child(export_vertical_spritesheet)
func _input(event): func _input(event):
#Handle tool shortcuts #Handle tool shortcuts
if event.is_action_pressed("right_pencil_tool"): if event.is_action_pressed("right_pencil_tool"):
@ -57,6 +76,7 @@ func _input(event):
elif event.is_action_pressed("left_fill_tool"): elif event.is_action_pressed("left_fill_tool"):
_on_Tool_pressed(fill_tool, false, true) _on_Tool_pressed(fill_tool, false, true)
func file_menu_id_pressed(id : int) -> void: func file_menu_id_pressed(id : int) -> void:
match id: match id:
0: #New 0: #New
@ -71,7 +91,7 @@ func file_menu_id_pressed(id : int) -> void:
$SaveSprite.popup_centered() $SaveSprite.popup_centered()
Global.can_draw = false Global.can_draw = false
else: else:
save_sprite() export_project()
3: #Export as 3: #Export as
$SaveSprite.popup_centered() $SaveSprite.popup_centered()
Global.can_draw = false Global.can_draw = false
@ -80,58 +100,165 @@ func file_menu_id_pressed(id : int) -> void:
func edit_menu_id_pressed(id : int) -> void: func edit_menu_id_pressed(id : int) -> void:
match id: match id:
0: #Show grid 0: #Scale Image
Global.canvas.draw_grid = !Global.canvas.draw_grid $ScaleImage.popup_centered()
Global.can_draw = false
1: #Show grid
Global.draw_grid = !Global.draw_grid
func _on_CreateNewImage_confirmed() -> void: func _on_CreateNewImage_confirmed() -> void:
var width = float($CreateNewImage/VBoxContainer/WidthCont/LineEdit.text) var width = float($CreateNewImage/VBoxContainer/WidthCont/WidthValue.value)
var height = float($CreateNewImage/VBoxContainer/HeightCont/LineEdit.text) var height = float($CreateNewImage/VBoxContainer/HeightCont/HeightValue.value)
width = clamp(width, 1, 16384)
height = clamp(height, 1, 16384)
new_canvas(Vector2(width, height).floor()) new_canvas(Vector2(width, height).floor())
func _on_OpenSprite_file_selected(path : String) -> void: #func _on_OpenSprite_file_selected(path : String) -> void:
# var image = Image.new()
# var err = image.load(path)
# if err == OK:
# opensprite_file_selected = true
# new_canvas(image.get_size(), image)
# else:
# OS.alert("Can't load file")
func _on_OpenSprite_files_selected(paths) -> void:
for child in Global.vbox_layer_container.get_children():
if child is PanelContainer:
child.queue_free()
for child in Global.frame_container.get_children():
child.queue_free()
for child in Global.canvas_parent.get_children():
if child is Canvas:
child.queue_free()
Global.canvases.clear()
#Find the biggest image and let it handle the camera zoom options
var max_size : Vector2
var biggest_canvas : Canvas
var i := 0
for path in paths:
var image = Image.new() var image = Image.new()
var err = image.load(path) var err = image.load(path)
if err == OK: if err == OK:
opensprite_file_selected = true opensprite_file_selected = true
new_canvas(image.get_size(), image) var canvas : Canvas = load("res://Canvas.tscn").instance()
canvas.size = image.get_size()
image.convert(Image.FORMAT_RGBA8)
image.lock()
var tex := ImageTexture.new()
tex.create_from_image(image, 0)
#Store [Image, ImageTexture, Layer Name, Visibity boolean]
canvas.layers.append([image, tex, "Layer 0", true])
canvas.frame = i
Global.canvas_parent.add_child(canvas)
Global.canvases.append(canvas)
canvas.visible = false
if i == 0:
max_size = canvas.size
biggest_canvas = canvas
else:
if canvas.size > max_size:
biggest_canvas = canvas
else: else:
OS.alert("Can't load file") OS.alert("Can't load file")
func new_canvas(size : Vector2, sprite : Image = null) -> void: i += 1
var left_indicator_visible = Global.canvas.left_square_indicator_visible Global.current_frame = i - 1
var right_indicator_visible = Global.canvas.right_square_indicator_visible Global.canvas = Global.canvases[Global.canvases.size() - 1]
var left_brush_size = Global.canvas.left_brush_size Global.canvas.visible = true
var right_brush_size = Global.canvas.right_brush_size Global.handle_layer_order_buttons()
biggest_canvas.camera_zoom()
if i > 1:
Global.remove_frame_button.disabled = false
Global.remove_frame_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
else:
Global.remove_frame_button.disabled = true
Global.remove_frame_button.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN
func new_canvas(size : Vector2, sprite : Image = null) -> void:
for child in Global.vbox_layer_container.get_children(): for child in Global.vbox_layer_container.get_children():
if child is PanelContainer: if child is PanelContainer:
child.queue_free() child.queue_free()
Global.canvas.queue_free() for child in Global.frame_container.get_children():
child.queue_free()
for child in Global.canvas_parent.get_children():
if child is Canvas:
child.queue_free()
Global.canvases.clear()
Global.canvas = load("res://Canvas.tscn").instance() Global.canvas = load("res://Canvas.tscn").instance()
Global.canvas.size = size Global.canvas.size = size
Global.canvas.left_square_indicator_visible = left_indicator_visible
Global.canvas.right_square_indicator_visible = right_indicator_visible
Global.canvas.left_brush_size = left_brush_size
Global.canvas.right_brush_size = right_brush_size
if sprite: # if sprite:
Global.canvas.current_sprite = sprite # var layer0 := sprite
Global.canvas.current_sprite.convert(Image.FORMAT_RGBA8) # layer0.convert(Image.FORMAT_RGBA8)
# var tex := ImageTexture.new()
# tex.create_from_image(layer0, 0)
# #Store [Image, ImageTexture, Layer Name, Visibity boolean]
# Global.canvas.layers.append([layer0, tex, "Layer 0", true])
Global.canvas_parent.add_child(Global.canvas) Global.canvas_parent.add_child(Global.canvas)
Global.canvases.append(Global.canvas)
Global.current_frame = 0
Global.remove_frame_button.disabled = true
Global.remove_frame_button.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN
func _on_SaveSprite_file_selected(path : String) -> void: func _on_SaveSprite_file_selected(path : String) -> void:
current_path = path current_path = path
save_sprite() export_project()
func save_sprite() -> void: func export_project() -> void:
if export_all_frames.pressed:
if !export_as_single_file.pressed:
var i := 0
for canvas in Global.canvases:
var path := "%s_%s" % [current_path, str(i)]
path = path.replace(".png", "")
path = "%s.png" % path
save_sprite(canvas, path)
i += 1
else:
save_spritesheet()
else:
save_sprite(Global.canvas, current_path)
func save_sprite(canvas : Canvas, path : String) -> void:
var whole_image := Image.new() var whole_image := Image.new()
whole_image.create(Global.canvas.size.x, Global.canvas.size.y, false, Image.FORMAT_RGBA8) whole_image.create(canvas.size.x, canvas.size.y, false, Image.FORMAT_RGBA8)
for layer in Global.canvas.layers: for layer in canvas.layers:
whole_image.blend_rect(layer[0], Rect2(Global.canvas.position, Global.canvas.size), Vector2.ZERO) whole_image.blend_rect(layer[0], Rect2(canvas.position, canvas.size), Vector2.ZERO)
layer[0].lock() layer[0].lock()
#var err = Global.canvas.current_sprite.save_png(current_path) var err = whole_image.save_png(path)
if err != OK:
OS.alert("Can't save file")
func save_spritesheet() -> void:
var width
var height
if export_vertical_spritesheet.pressed:
width = Global.canvas.size.x
height = 0
for canvas in Global.canvases:
height += canvas.size.y
if canvas.size.x > width:
width = canvas.size.x
else:
width = 0
height = Global.canvas.size.y
for canvas in Global.canvases:
width += canvas.size.x
if canvas.size.y > height:
height = canvas.size.y
var whole_image := Image.new()
whole_image.create(width, height, false, Image.FORMAT_RGBA8)
var dst := Vector2.ZERO
for canvas in Global.canvases:
for layer in canvas.layers:
whole_image.blend_rect(layer[0], Rect2(canvas.position, canvas.size), dst)
layer[0].lock()
if export_vertical_spritesheet.pressed:
dst += Vector2(0, canvas.size.y)
else:
dst += Vector2(canvas.size.x, 0)
var err = whole_image.save_png(current_path) var err = whole_image.save_png(current_path)
if err != OK: if err != OK:
OS.alert("Can't save file") OS.alert("Can't save file")
@ -163,22 +290,19 @@ func _on_Tool_pressed(tool_pressed : BaseButton, mouse_press := true, key_for_le
Global.right_indicator.get_parent().remove_child(Global.right_indicator) Global.right_indicator.get_parent().remove_child(Global.right_indicator)
tool_pressed.add_child(Global.right_indicator) tool_pressed.add_child(Global.right_indicator)
func _on_ScaleImage_confirmed() -> void: func _on_ScaleImage_confirmed() -> void:
var width = float($ScaleImage/VBoxContainer/WidthCont/LineEdit.text) var width = float($ScaleImage/VBoxContainer/WidthCont/WidthValue.value)
var height = float($ScaleImage/VBoxContainer/HeightCont/LineEdit.text) var height = float($ScaleImage/VBoxContainer/HeightCont/HeightValue.value)
width = clamp(width, 1, 16384)
height = clamp(height, 1, 16384)
#var sprites := []
for i in range(Global.canvas.layers.size() - 1, -1, -1): for i in range(Global.canvas.layers.size() - 1, -1, -1):
var sprite = Image.new() var sprite = Image.new()
sprite = Global.canvas.layers[i][1].get_data() sprite = Global.canvas.layers[i][1].get_data()
sprite.resize(width, height) sprite.resize(width, height, $ScaleImage/VBoxContainer/InterpolationContainer/InterpolationType.selected)
Global.canvas.layers[i][0] = sprite Global.canvas.layers[i][0] = sprite
Global.canvas.layers[i][0].lock() Global.canvas.layers[i][0].lock()
Global.canvas.update_texture(i) Global.canvas.update_texture(i)
Global.canvas.size = Vector2(width, height).floor() Global.canvas.size = Vector2(width, height).floor()
Global.canvas.camera_zoom()
func add_layer(is_new := true) -> void: func add_layer(is_new := true) -> void:
var new_layer := Image.new() var new_layer := Image.new()
@ -226,16 +350,164 @@ func _on_MergeLayer_pressed() -> void:
Global.canvas.update_texture(Global.canvas.current_layer_index - 1) Global.canvas.update_texture(Global.canvas.current_layer_index - 1)
_on_RemoveLayerButton_pressed() _on_RemoveLayerButton_pressed()
func _on_LeftIndicatorCheckbox_toggled(button_pressed): func _on_LeftIndicatorCheckbox_toggled(button_pressed) -> void:
Global.canvas.left_square_indicator_visible = button_pressed Global.left_square_indicator_visible = button_pressed
func _on_RightIndicatorCheckbox_toggled(button_pressed): func _on_RightIndicatorCheckbox_toggled(button_pressed) -> void:
Global.canvas.right_square_indicator_visible = button_pressed Global.right_square_indicator_visible = button_pressed
func _on_LeftBrushSizeEdit_value_changed(value): func _on_LeftBrushSizeEdit_value_changed(value) -> void:
var new_size = int(value) var new_size = int(value)
Global.canvas.left_brush_size = new_size Global.left_brush_size = new_size
func _on_RightBrushSizeEdit_value_changed(value): func _on_RightBrushSizeEdit_value_changed(value) -> void:
var new_size = int(value) var new_size = int(value)
Global.canvas.right_brush_size = new_size Global.right_brush_size = new_size
func _on_AddFrame_pressed() -> void:
var canvas = load("res://Canvas.tscn").instance()
canvas.size = Global.canvas.size
Global.current_frame = Global.canvases.size()
canvas.frame = Global.current_frame
for canvas in Global.canvases:
canvas.visible = false
Global.canvases.append(canvas)
Global.canvas = canvas
Global.canvas_parent.add_child(canvas)
Global.remove_frame_button.disabled = false
Global.remove_frame_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
Global.move_left_frame_button.disabled = false
Global.move_left_frame_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
func _on_RemoveFrame_pressed() -> void:
Global.canvas.frame_button.queue_free()
Global.canvas.queue_free()
Global.canvases.remove(Global.current_frame)
for canvas in Global.canvases:
if canvas.frame > Global.current_frame:
canvas.frame -= 1
canvas.frame_button.get_node("FrameButton").frame = canvas.frame
canvas.frame_button.get_node("FrameID").text = str(canvas.frame)
if Global.current_frame > 0:
Global.current_frame -= 1
if len(Global.canvases) == 1:
Global.remove_frame_button.disabled = true
Global.remove_frame_button.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN
Global.canvas = Global.canvases[Global.current_frame]
Global.canvas.visible = true
Global.canvas.generate_layer_panels()
Global.handle_layer_order_buttons()
func _on_CloneFrame_pressed() -> void:
var canvas = load("res://Canvas.tscn").instance()
canvas.size = Global.canvas.size
#canvas.layers = Global.canvas.layers.duplicate(true)
for layer in Global.canvas.layers:
var sprite := Image.new()
sprite.copy_from(layer[0])
sprite.lock()
var tex := ImageTexture.new()
tex.create_from_image(sprite, 0)
canvas.layers.append([sprite, tex, layer[2], layer[3]])
Global.current_frame = Global.canvases.size()
canvas.frame = Global.current_frame
for canvas in Global.canvases:
canvas.visible = false
Global.canvases.append(canvas)
Global.canvas = canvas
Global.canvas_parent.add_child(canvas)
Global.remove_frame_button.disabled = false
Global.remove_frame_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
Global.move_left_frame_button.disabled = false
Global.move_left_frame_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
func _on_MoveFrameLeft_pressed() -> void:
change_frame_order(-1)
func _on_MoveFrameRight_pressed() -> void:
change_frame_order(1)
func change_frame_order(rate : int) -> void:
var frame_button = Global.frame_container.get_node("Frame_%s" % Global.current_frame)
var change = Global.current_frame + rate
var temp = Global.canvases[Global.current_frame]
Global.canvases[Global.current_frame] = Global.canvases[change]
Global.canvases[change] = temp
#Clear frame button names first, to avoid duplicates like two Frame_0s
for canvas in Global.canvases:
canvas.frame_button.name = "frame"
for canvas in Global.canvases:
canvas.frame = Global.canvases.find(canvas)
canvas.frame_button.name = "Frame_%s" % canvas.frame
canvas.frame_button.get_node("FrameButton").frame = canvas.frame
canvas.frame_button.get_node("FrameID").text = str(canvas.frame)
Global.current_frame = change
Global.frame_container.move_child(frame_button, Global.current_frame)
Global.canvas_parent.move_child(Global.canvas, Global.current_frame)
#Global.canvas.generate_layer_panels()
Global.handle_layer_order_buttons()
func _on_PlayForward_toggled(button_pressed) -> void:
Global.play_backwards.pressed = false
Global.play_backwards.text = "Play Backwards"
if button_pressed:
Global.play_forward.text = "Stop"
$AnimationTimer.wait_time = 1 / fps
$AnimationTimer.start()
animation_forward = true
else:
Global.play_forward.text = "Play Forward"
$AnimationTimer.stop()
func _on_PlayBackwards_toggled(button_pressed) -> void:
Global.play_forward.pressed = false
Global.play_forward.text = "Play Forward"
if button_pressed:
Global.play_backwards.text = "Stop"
$AnimationTimer.wait_time = 1 / fps
$AnimationTimer.start()
animation_forward = false
else:
Global.play_backwards.text = "Play Backwards"
$AnimationTimer.stop()
func _on_AnimationTimer_timeout() -> void:
if animation_forward:
if Global.current_frame < Global.canvases.size() - 1:
Global.current_frame += 1
else:
if animation_loop:
Global.current_frame = 0
else:
Global.play_forward.pressed = false
Global.play_forward.text = "Play Forward"
$AnimationTimer.stop()
else:
if Global.current_frame > 0:
Global.current_frame -= 1
else:
if animation_loop:
Global.current_frame = Global.canvases.size() - 1
else:
Global.play_backwards.pressed = false
Global.play_backwards.text = "Play Backwards"
$AnimationTimer.stop()
Global.change_frame()
func _on_FPSValue_value_changed(value) -> void:
fps = float(value)
$AnimationTimer.wait_time = 1 / fps
func _on_LoopAnim_toggled(button_pressed) -> void:
animation_loop = button_pressed

View file

@ -23,8 +23,8 @@ binary_format/64_bits=true
custom_template/release="" custom_template/release=""
custom_template/debug="" custom_template/debug=""
application/icon="" application/icon=""
application/file_version="0.1" application/file_version="0.2"
application/product_version="0.1" application/product_version="0.2"
application/company_name="Orama Interactive" application/company_name="Orama Interactive"
application/product_name="Pixelorama" application/product_name="Pixelorama"
application/file_description="" application/file_description=""