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

Custom brushes, crop image, split screen, about menu & asset re-organizing

- Added support for custom brushes. When you Ctrl-C a selection, it gets added to the list of custom brushes. Each mouse button can have a different brush, and the user can choose whether their color comes from the brush itself or the selected color in the tool options. They can also be resized based on the selected brush size.
- Custom brushes are also being saved on .pxo files.
- You can now crop images (per frame). All layers of that frame are taken into account and are affected.
- Added split screen support. The user can toggle between single screen and split screen, where a second canvas is being shown. Note that you cannot draw on the second canvas.
- Added an About Pixelorama selection on the new Help menu.
- Project assets are re-organized.
This commit is contained in:
OverloadedOrama 2019-09-25 22:59:48 +03:00
parent 62b9278537
commit 4e4a526332
27 changed files with 659 additions and 150 deletions

View file

@ -0,0 +1,3 @@
source_md5="f455fa104282b0fb31b168b668bb509b"
dest_md5="c8a263d7b4be7177025be77fb2ec15d3"

View file

@ -0,0 +1,3 @@
source_md5="5fa14a5c145b08d8c1f4a92c8b4014f2"
dest_md5="c73c58f53d6dace9fc04a1eb8ed9fd67"

View file

Before

Width:  |  Height:  |  Size: 84 B

After

Width:  |  Height:  |  Size: 84 B

View file

@ -0,0 +1,13 @@
[remap]
importer="image"
type="Image"
path="res://.import/Transparent Background.png-62a2c5eb3e805ff7dbb890edc2b8d883.image"
[deps]
source_file="res://Assets/Graphics/Transparent Background.png"
dest_files=[ "res://.import/Transparent Background.png-62a2c5eb3e805ff7dbb890edc2b8d883.image" ]
[params]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 B

View file

@ -1,13 +0,0 @@
[remap]
importer="image"
type="Image"
path="res://.import/grid.png-643b5c8878aaf0c84a360796789dae22.image"
[deps]
source_file="res://Assets/Graphics/grid.png"
dest_files=[ "res://.import/grid.png-643b5c8878aaf0c84a360796789dae22.image" ]
[params]

BIN
Assets/Graphics/pixel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 B

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/pixel.png-02d24c392cbedb7afeccdbe493729855.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://Assets/Graphics/pixel.png"
dest_files=[ "res://.import/pixel.png-02d24c392cbedb7afeccdbe493729855.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=false
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

337
Main.tscn
View file

@ -1,12 +1,15 @@
[gd_scene load_steps=8 format=2]
[gd_scene load_steps=11 format=2]
[ext_resource path="res://Scripts/Main.gd" type="Script" id=1]
[ext_resource path="res://Main Theme.tres" type="Theme" id=2]
[ext_resource path="res://Assets/Graphics/left.png" type="Texture" id=3]
[ext_resource path="res://Assets/Graphics/right.png" type="Texture" id=4]
[ext_resource path="res://Canvas.tscn" type="PackedScene" id=5]
[ext_resource path="res://Scripts/CameraMovement.gd" type="Script" id=6]
[ext_resource path="res://Scripts/SelectionRectangle.gd" type="Script" id=7]
[ext_resource path="res://Prefabs/BrushButton.tscn" type="PackedScene" id=5]
[ext_resource path="res://Prefabs/Canvas.tscn" type="PackedScene" id=6]
[ext_resource path="res://Scripts/CameraMovement.gd" type="Script" id=7]
[ext_resource path="res://Scripts/SelectionRectangle.gd" type="Script" id=8]
[ext_resource path="res://Scripts/SecondViewport.gd" type="Script" id=9]
[ext_resource path="res://Scripts/AboutDialog.gd" type="Script" id=10]
[node name="Control" type="Control"]
anchor_right = 1.0
@ -17,8 +20,10 @@ script = ExtResource( 1 )
anchor_right = 1.0
anchor_bottom = 1.0
size_flags_horizontal = 3
custom_constants/separation = 0
[node name="ToolPanel" type="Panel" parent="UI"]
editor/display_folded = true
margin_right = 320.0
margin_bottom = 600.0
rect_min_size = Vector2( 320, 0 )
@ -32,7 +37,7 @@ size_flags_vertical = 3
[node name="MenusAndTools" type="VBoxContainer" parent="UI/ToolPanel/Tools"]
margin_right = 320.0
margin_bottom = 294.0
margin_bottom = 270.0
size_flags_vertical = 3
[node name="MenuItems" type="HBoxContainer" parent="UI/ToolPanel/Tools/MenusAndTools"]
@ -62,7 +67,16 @@ mouse_default_cursor_shape = 2
theme = ExtResource( 2 )
text = "View"
[node name="HelpMenu" type="MenuButton" parent="UI/ToolPanel/Tools/MenusAndTools/MenuItems"]
margin_left = 125.0
margin_right = 167.0
margin_bottom = 20.0
mouse_default_cursor_shape = 2
theme = ExtResource( 2 )
text = "Help"
[node name="ToolsContainer" type="HBoxContainer" parent="UI/ToolPanel/Tools/MenusAndTools"]
editor/display_folded = true
margin_top = 24.0
margin_right = 320.0
margin_bottom = 44.0
@ -122,19 +136,20 @@ button_mask = 3
text = "RectSelect"
[node name="HSeparator" type="HSeparator" parent="UI/ToolPanel/Tools"]
margin_top = 298.0
margin_top = 274.0
margin_right = 320.0
margin_bottom = 302.0
margin_bottom = 278.0
[node name="ToolOptions" type="HBoxContainer" parent="UI/ToolPanel/Tools"]
margin_top = 306.0
editor/display_folded = true
margin_top = 282.0
margin_right = 320.0
margin_bottom = 600.0
margin_bottom = 552.0
size_flags_vertical = 3
[node name="LeftToolOptions" type="VBoxContainer" parent="UI/ToolPanel/Tools/ToolOptions"]
margin_right = 154.0
margin_bottom = 294.0
margin_bottom = 270.0
size_flags_horizontal = 3
[node name="LeftLabel" type="Label" parent="UI/ToolPanel/Tools/ToolOptions/LeftToolOptions"]
@ -161,6 +176,7 @@ size_flags_horizontal = 0
size_flags_vertical = 0
[node name="BrushSize" type="HBoxContainer" parent="UI/ToolPanel/Tools/ToolOptions/LeftToolOptions"]
editor/display_folded = true
margin_top = 82.0
margin_right = 154.0
margin_bottom = 106.0
@ -180,15 +196,51 @@ min_value = 1.0
value = 1.0
suffix = "px"
[node name="ColorComesFrom" type="Label" parent="UI/ToolPanel/Tools/ToolOptions/LeftToolOptions"]
margin_top = 110.0
margin_right = 154.0
margin_bottom = 124.0
text = "Brush's color from"
[node name="InterpolateColor" type="HBoxContainer" parent="UI/ToolPanel/Tools/ToolOptions/LeftToolOptions"]
margin_top = 128.0
margin_right = 154.0
margin_bottom = 144.0
[node name="BrushColorLabel" type="Label" parent="UI/ToolPanel/Tools/ToolOptions/LeftToolOptions/InterpolateColor"]
margin_top = 1.0
margin_right = 37.0
margin_bottom = 15.0
rect_pivot_offset = Vector2( -90, -47 )
text = "Brush"
[node name="LeftInterpolateFactor" type="HSlider" parent="UI/ToolPanel/Tools/ToolOptions/LeftToolOptions/InterpolateColor"]
margin_left = 41.0
margin_right = 117.0
margin_bottom = 16.0
size_flags_horizontal = 3
max_value = 1.0
step = 0.01
value = 0.5
ticks_on_borders = true
[node name="SelectedColorLabel" type="Label" parent="UI/ToolPanel/Tools/ToolOptions/LeftToolOptions/InterpolateColor"]
margin_left = 121.0
margin_top = 1.0
margin_right = 154.0
margin_bottom = 15.0
rect_pivot_offset = Vector2( -90, -47 )
text = "Color"
[node name="VSeparator" type="VSeparator" parent="UI/ToolPanel/Tools/ToolOptions"]
margin_left = 158.0
margin_right = 162.0
margin_bottom = 294.0
margin_bottom = 270.0
[node name="RightToolOptions" type="VBoxContainer" parent="UI/ToolPanel/Tools/ToolOptions"]
margin_left = 166.0
margin_right = 320.0
margin_bottom = 294.0
margin_bottom = 270.0
size_flags_horizontal = 3
[node name="RightLabel" type="Label" parent="UI/ToolPanel/Tools/ToolOptions/RightToolOptions"]
@ -233,13 +285,107 @@ min_value = 1.0
value = 1.0
suffix = "px"
[node name="ColorComesFrom" type="Label" parent="UI/ToolPanel/Tools/ToolOptions/RightToolOptions"]
margin_top = 110.0
margin_right = 154.0
margin_bottom = 124.0
text = "Brush's color from"
[node name="InterpolateColor" type="HBoxContainer" parent="UI/ToolPanel/Tools/ToolOptions/RightToolOptions"]
margin_top = 128.0
margin_right = 154.0
margin_bottom = 144.0
[node name="BrushColorLabel" type="Label" parent="UI/ToolPanel/Tools/ToolOptions/RightToolOptions/InterpolateColor"]
margin_top = 1.0
margin_right = 37.0
margin_bottom = 15.0
rect_pivot_offset = Vector2( -90, -47 )
text = "Brush"
[node name="RightInterpolateFactor" type="HSlider" parent="UI/ToolPanel/Tools/ToolOptions/RightToolOptions/InterpolateColor"]
margin_left = 41.0
margin_right = 117.0
margin_bottom = 16.0
size_flags_horizontal = 3
max_value = 1.0
step = 0.01
value = 0.5
ticks_on_borders = true
[node name="SelectedColorLabel" type="Label" parent="UI/ToolPanel/Tools/ToolOptions/RightToolOptions/InterpolateColor"]
margin_left = 121.0
margin_top = 1.0
margin_right = 154.0
margin_bottom = 15.0
rect_pivot_offset = Vector2( -90, -47 )
text = "Color"
[node name="HSeparator2" type="HSeparator" parent="UI/ToolPanel/Tools"]
margin_top = 556.0
margin_right = 320.0
margin_bottom = 560.0
[node name="BrushesContainer" type="ScrollContainer" parent="UI/ToolPanel/Tools"]
margin_top = 564.0
margin_right = 320.0
margin_bottom = 600.0
size_flags_horizontal = 3
scroll_vertical_enabled = false
[node name="BrushHBoxContainer" type="HBoxContainer" parent="UI/ToolPanel/Tools/BrushesContainer"]
margin_right = 36.0
margin_bottom = 36.0
[node name="PixelBrushButton" parent="UI/ToolPanel/Tools/BrushesContainer/BrushHBoxContainer" instance=ExtResource( 5 )]
[node name="CanvasAndTimeline" type="VBoxContainer" parent="UI"]
margin_left = 324.0
margin_right = 860.0
margin_left = 320.0
margin_right = 864.0
margin_bottom = 600.0
size_flags_horizontal = 3
[node name="ViewportContainer" type="ViewportContainer" parent="UI/CanvasAndTimeline"]
[node name="HBoxContainer" type="HBoxContainer" parent="UI/CanvasAndTimeline"]
margin_right = 544.0
margin_bottom = 464.0
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="ViewportContainer" type="ViewportContainer" parent="UI/CanvasAndTimeline/HBoxContainer"]
margin_right = 544.0
margin_bottom = 464.0
mouse_default_cursor_shape = 3
size_flags_horizontal = 3
size_flags_vertical = 3
stretch = true
[node name="Viewport" type="Viewport" parent="UI/CanvasAndTimeline/HBoxContainer/ViewportContainer"]
size = Vector2( 544, 464 )
handle_input_locally = false
render_target_update_mode = 3
[node name="Canvas" parent="UI/CanvasAndTimeline/HBoxContainer/ViewportContainer/Viewport" instance=ExtResource( 6 )]
[node name="Camera2D" type="Camera2D" parent="UI/CanvasAndTimeline/HBoxContainer/ViewportContainer/Viewport"]
current = true
zoom = Vector2( 0.15, 0.15 )
script = ExtResource( 7 )
[node name="SelectionRectangle" type="Polygon2D" parent="UI/CanvasAndTimeline/HBoxContainer/ViewportContainer/Viewport"]
z_index = 1
color = Color( 0.0823529, 0.694118, 0.623529, 0.592157 )
polygon = PoolVector2Array( 0, 0, 0, 0, 0, 0, 0, 0 )
script = ExtResource( 8 )
[node name="ViewportSeparator" type="VSeparator" parent="UI/CanvasAndTimeline/HBoxContainer"]
visible = false
margin_left = 532.0
margin_right = 536.0
margin_bottom = 464.0
[node name="ViewportContainer2" type="ViewportContainer" parent="UI/CanvasAndTimeline/HBoxContainer"]
visible = false
margin_left = 270.0
margin_right = 536.0
margin_bottom = 464.0
mouse_default_cursor_shape = 3
@ -247,27 +393,21 @@ size_flags_horizontal = 3
size_flags_vertical = 3
stretch = true
[node name="Viewport" type="Viewport" parent="UI/CanvasAndTimeline/ViewportContainer"]
size = Vector2( 536, 464 )
[node name="Viewport" type="Viewport" parent="UI/CanvasAndTimeline/HBoxContainer/ViewportContainer2"]
size = Vector2( 266, 464 )
handle_input_locally = false
render_target_update_mode = 3
render_target_update_mode = 0
script = ExtResource( 9 )
[node name="Canvas" parent="UI/CanvasAndTimeline/ViewportContainer/Viewport" instance=ExtResource( 5 )]
[node name="Camera2D" type="Camera2D" parent="UI/CanvasAndTimeline/ViewportContainer/Viewport"]
[node name="Camera2D2" type="Camera2D" parent="UI/CanvasAndTimeline/HBoxContainer/ViewportContainer2/Viewport"]
current = true
zoom = Vector2( 0.15, 0.15 )
script = ExtResource( 6 )
[node name="SelectionRectangle" type="Polygon2D" parent="UI/CanvasAndTimeline/ViewportContainer/Viewport"]
z_index = 1
color = Color( 0.0823529, 0.694118, 0.623529, 0.592157 )
polygon = PoolVector2Array( 0, 0, 0, 0, 0, 0, 0, 0 )
script = ExtResource( 7 )
[node name="AnimationTimeline" type="Panel" parent="UI/CanvasAndTimeline"]
editor/display_folded = true
margin_top = 468.0
margin_right = 536.0
margin_right = 544.0
margin_bottom = 600.0
rect_min_size = Vector2( 0, 132 )
size_flags_horizontal = 3
@ -278,12 +418,12 @@ anchor_bottom = 1.0
size_flags_horizontal = 3
[node name="ButtonContainer" type="CenterContainer" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer"]
margin_right = 536.0
margin_right = 544.0
margin_bottom = 24.0
[node name="AnimationButtons" type="HBoxContainer" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/ButtonContainer"]
margin_left = 90.0
margin_right = 446.0
margin_left = 94.0
margin_right = 450.0
margin_bottom = 24.0
[node name="LoopLabel" type="Label" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/ButtonContainer/AnimationButtons"]
@ -325,25 +465,25 @@ margin_right = 356.0
margin_bottom = 24.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 = 0.01
step = 0.01
min_value = 0.1
step = 0.1
value = 1.0
suffix = "FPS"
[node name="HSeparator" type="HSeparator" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer"]
margin_top = 28.0
margin_right = 536.0
margin_right = 544.0
margin_bottom = 32.0
[node name="CenterContainer" type="CenterContainer" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer"]
editor/display_folded = true
margin_top = 36.0
margin_right = 536.0
margin_right = 544.0
margin_bottom = 56.0
[node name="FrameButtons" type="HBoxContainer" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/CenterContainer"]
margin_left = 209.0
margin_right = 326.0
margin_left = 213.0
margin_right = 330.0
margin_bottom = 20.0
[node name="AddFrame" type="Button" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/CenterContainer/FrameButtons"]
@ -392,12 +532,12 @@ text = "Cl"
[node name="HSeparator2" type="HSeparator" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer"]
margin_top = 60.0
margin_right = 536.0
margin_right = 544.0
margin_bottom = 64.0
[node name="ScrollContainer" type="ScrollContainer" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer"]
margin_top = 68.0
margin_right = 536.0
margin_right = 544.0
margin_bottom = 132.0
size_flags_horizontal = 3
size_flags_vertical = 3
@ -414,11 +554,12 @@ rect_min_size = Vector2( 160, 0 )
[node name="LayersAndMisc" type="VBoxContainer" parent="UI/LayerPanel"]
anchor_right = 1.0
anchor_bottom = 1.0
custom_constants/separation = 3
[node name="ScrollContainer" type="ScrollContainer" parent="UI/LayerPanel/LayersAndMisc"]
editor/display_folded = true
margin_right = 160.0
margin_bottom = 375.0
margin_bottom = 382.0
size_flags_horizontal = 3
size_flags_vertical = 3
@ -498,15 +639,15 @@ disabled = true
text = "M"
[node name="HSeparator" type="HSeparator" parent="UI/LayerPanel/LayersAndMisc"]
margin_top = 379.0
margin_top = 385.0
margin_right = 160.0
margin_bottom = 383.0
margin_bottom = 389.0
[node name="OnionSkinningButtons" type="VBoxContainer" parent="UI/LayerPanel/LayersAndMisc"]
editor/display_folded = true
margin_top = 387.0
margin_top = 392.0
margin_right = 160.0
margin_bottom = 520.0
margin_bottom = 525.0
[node name="OnionSkinning" type="Label" parent="UI/LayerPanel/LayersAndMisc/OnionSkinningButtons"]
margin_right = 160.0
@ -537,26 +678,26 @@ margin_bottom = 133.0
text = "Blue-Red Mode"
[node name="HSeparator2" type="HSeparator" parent="UI/LayerPanel/LayersAndMisc"]
margin_top = 524.0
margin_top = 528.0
margin_right = 160.0
margin_bottom = 528.0
margin_bottom = 532.0
[node name="CursorPosition" type="Label" parent="UI/LayerPanel/LayersAndMisc"]
margin_top = 532.0
margin_top = 535.0
margin_right = 160.0
margin_bottom = 546.0
margin_bottom = 549.0
text = "[64x64]"
[node name="ZoomLevel" type="Label" parent="UI/LayerPanel/LayersAndMisc"]
margin_top = 550.0
margin_top = 552.0
margin_right = 160.0
margin_bottom = 564.0
margin_bottom = 566.0
text = "Zoom: x7.81"
[node name="CurrentFrame" type="Label" parent="UI/LayerPanel/LayersAndMisc"]
margin_top = 568.0
margin_top = 569.0
margin_right = 160.0
margin_bottom = 582.0
margin_bottom = 583.0
text = "Current frame: 1/1"
[node name="EmptyLabel" type="Label" parent="UI/LayerPanel/LayersAndMisc"]
@ -564,6 +705,16 @@ margin_top = 586.0
margin_right = 160.0
margin_bottom = 600.0
[node name="SplitScreenButton" type="Button" parent="."]
anchor_left = 1.0
anchor_right = 1.0
margin_left = -184.0
margin_right = -164.0
margin_bottom = 20.0
size_flags_vertical = 0
toggle_mode = true
text = "<"
[node name="CreateNewImage" type="ConfirmationDialog" parent="."]
editor/display_folded = true
margin_right = 200.0
@ -769,6 +920,76 @@ text = "Nearest"
items = [ "Nearest", null, false, 0, null, "Bilinear", null, false, 1, null, "Cubic", null, false, 2, null, "Trilinear", null, false, 3, null, "Lanczos", null, true, 4, null ]
selected = 0
[node name="AboutDialog" type="AcceptDialog" parent="."]
editor/display_folded = true
margin_right = 284.0
margin_bottom = 186.0
window_title = "About Pixelorama"
script = ExtResource( 10 )
[node name="AboutUI" type="VBoxContainer" parent="AboutDialog"]
margin_left = 8.0
margin_top = 8.0
margin_right = 276.0
margin_bottom = 150.0
[node name="Pixelorama" type="Label" parent="AboutDialog/AboutUI"]
margin_right = 339.0
margin_bottom = 31.0
text = "Pixelorama v0.3
"
align = 1
[node name="MadeBy" type="Label" parent="AboutDialog/AboutUI"]
margin_top = 35.0
margin_right = 339.0
margin_bottom = 83.0
text = "Your Free and Open Source Sprite Editor
Developed by Orama Interactive
"
align = 1
[node name="Links" type="CenterContainer" parent="AboutDialog/AboutUI"]
margin_top = 87.0
margin_right = 339.0
margin_bottom = 107.0
[node name="LinkButtons" type="HBoxContainer" parent="AboutDialog/AboutUI/Links"]
margin_left = 35.0
margin_right = 303.0
margin_bottom = 20.0
[node name="Website" type="Button" parent="AboutDialog/AboutUI/Links/LinkButtons"]
margin_right = 65.0
margin_bottom = 20.0
text = "Website"
[node name="GitHub" type="Button" parent="AboutDialog/AboutUI/Links/LinkButtons"]
margin_left = 69.0
margin_right = 162.0
margin_bottom = 20.0
text = "GitHub Repo"
[node name="Donate" type="Button" parent="AboutDialog/AboutUI/Links/LinkButtons"]
margin_left = 166.0
margin_right = 224.0
margin_bottom = 20.0
text = "Donate"
[node name="Blog" type="Button" parent="AboutDialog/AboutUI/Links/LinkButtons"]
margin_left = 228.0
margin_right = 268.0
margin_bottom = 20.0
text = "Blog"
[node name="Copyright" type="Label" parent="AboutDialog/AboutUI"]
margin_top = 111.0
margin_right = 339.0
margin_bottom = 142.0
text = "
Copyright 2019 - Orama Interactive"
align = 1
[node name="AnimationTimer" type="Timer" parent="."]
[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"]
@ -778,8 +999,10 @@ selected = 0
[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="value_changed" from="UI/ToolPanel/Tools/ToolOptions/RightToolOptions/BrushSize/RightBrushSizeEdit" to="." method="_on_RightBrushSizeEdit_value_changed"]
[connection signal="mouse_entered" from="UI/CanvasAndTimeline/ViewportContainer" to="." method="_on_ViewportContainer_mouse_entered"]
[connection signal="mouse_exited" from="UI/CanvasAndTimeline/ViewportContainer" to="." method="_on_ViewportContainer_mouse_exited"]
[connection signal="mouse_entered" from="UI/CanvasAndTimeline/HBoxContainer/ViewportContainer" to="." method="_on_ViewportContainer_mouse_entered"]
[connection signal="mouse_exited" from="UI/CanvasAndTimeline/HBoxContainer/ViewportContainer" to="." method="_on_ViewportContainer_mouse_exited"]
[connection signal="mouse_entered" from="UI/CanvasAndTimeline/HBoxContainer/ViewportContainer2" to="." method="_on_ViewportContainer_mouse_entered"]
[connection signal="mouse_exited" from="UI/CanvasAndTimeline/HBoxContainer/ViewportContainer2" to="." method="_on_ViewportContainer_mouse_exited"]
[connection signal="pressed" from="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/ButtonContainer/AnimationButtons/LoopAnim" to="." method="_on_LoopAnim_pressed"]
[connection signal="toggled" from="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/ButtonContainer/AnimationButtons/PlayBackwards" to="." method="_on_PlayBackwards_toggled"]
[connection signal="toggled" from="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/ButtonContainer/AnimationButtons/PlayForward" to="." method="_on_PlayForward_toggled"]
@ -798,6 +1021,7 @@ selected = 0
[connection signal="value_changed" from="UI/LayerPanel/LayersAndMisc/OnionSkinningButtons/PastOnionSkinning" to="." method="_on_PastOnionSkinning_value_changed"]
[connection signal="value_changed" from="UI/LayerPanel/LayersAndMisc/OnionSkinningButtons/FutureOnionSkinning" to="." method="_on_FutureOnionSkinning_value_changed"]
[connection signal="toggled" from="UI/LayerPanel/LayersAndMisc/OnionSkinningButtons/BlueRedMode" to="." method="_on_BlueRedMode_toggled"]
[connection signal="toggled" from="SplitScreenButton" to="." method="_on_SplitScreenButton_toggled"]
[connection signal="confirmed" from="CreateNewImage" to="." method="_on_CreateNewImage_confirmed"]
[connection signal="popup_hide" from="CreateNewImage" to="." method="_can_draw_true"]
[connection signal="file_selected" from="OpenSprite" to="." method="_on_OpenSprite_file_selected"]
@ -810,4 +1034,9 @@ selected = 0
[connection signal="popup_hide" from="ExportSprites" to="." method="_can_draw_true"]
[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="AboutDialog" to="." method="_can_draw_true"]
[connection signal="pressed" from="AboutDialog/AboutUI/Links/LinkButtons/Website" to="AboutDialog" method="_on_Website_pressed"]
[connection signal="pressed" from="AboutDialog/AboutUI/Links/LinkButtons/GitHub" to="AboutDialog" method="_on_GitHub_pressed"]
[connection signal="pressed" from="AboutDialog/AboutUI/Links/LinkButtons/Donate" to="AboutDialog" method="_on_Donate_pressed"]
[connection signal="pressed" from="AboutDialog/AboutUI/Links/LinkButtons/Blog" to="AboutDialog" method="_on_Blog_pressed"]
[connection signal="timeout" from="AnimationTimer" to="." method="_on_AnimationTimer_timeout"]

22
Prefabs/BrushButton.tscn Normal file
View file

@ -0,0 +1,22 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://Scripts/BrushButton.gd" type="Script" id=1]
[ext_resource path="res://Assets/Graphics/pixel.png" type="Texture" id=2]
[node name="BrushButton" type="Button"]
margin_right = 36.0
margin_bottom = 36.0
rect_min_size = Vector2( 36, 36 )
button_mask = 3
script = ExtResource( 1 )
[node name="BrushTexture" type="TextureRect" parent="."]
margin_left = 2.0
margin_top = 2.0
margin_right = 34.0
margin_bottom = 34.0
rect_min_size = Vector2( 32, 32 )
texture = ExtResource( 2 )
expand = true
stretch_mode = 6
[connection signal="pressed" from="." to="." method="_on_BrushButton_pressed"]

19
Scripts/AboutDialog.gd Normal file
View file

@ -0,0 +1,19 @@
extends AcceptDialog
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
var current_version : String = ProjectSettings.get_setting("application/config/Version")
$AboutUI/Pixelorama.text = "Pixelorama %s\n" % current_version
func _on_Website_pressed() -> void:
OS.shell_open("http://oramagamestudios.com/")
func _on_GitHub_pressed() -> void:
OS.shell_open("https://github.com/OverloadedOrama/Pixelorama")
func _on_Donate_pressed() -> void:
OS.shell_open("https://www.paypal.com/paypalme2/OverloadedOrama")
OS.shell_open("https://ko-fi.com/overloadedorama")
func _on_Blog_pressed() -> void:
OS.shell_open("https://functionoverload590613498.wordpress.com/")

14
Scripts/BrushButton.gd Normal file
View file

@ -0,0 +1,14 @@
extends Button
var brush_type = Global.BRUSH_TYPES.PIXEL
var custom_brush_index := -1
func _on_BrushButton_pressed() -> void:
if Input.is_action_just_released("left_mouse"):
Global.current_left_brush_type = brush_type
if custom_brush_index > -1:
Global.custom_left_brush_index = custom_brush_index
elif Input.is_action_just_released("right_mouse"):
Global.current_right_brush_type = brush_type
if custom_brush_index > -1:
Global.custom_right_brush_index = custom_brush_index

View file

@ -2,16 +2,22 @@ extends Camera2D
var zoom_min := Vector2(0.005, 0.005)
var zoom_max := Vector2.ONE
var viewport_container : ViewportContainer
var drag := false
func _ready() -> void:
viewport_container = get_parent().get_parent()
func _input(event) -> void:
if Global.can_draw && Global.has_focus:
if event.is_action_pressed("camera_drag"):
drag = true
elif event.is_action_released("camera_drag"):
drag = false
elif event.is_action_pressed("zoom_in"): # Wheel Up Event
var mouse_pos := viewport_container.get_local_mouse_position()
var viewport_size := viewport_container.rect_size
if event.is_action_pressed("camera_drag"):
drag = true
elif event.is_action_released("camera_drag"):
drag = false
if Global.can_draw && Global.has_focus && Rect2(Vector2.ZERO, viewport_size).has_point(mouse_pos):
if event.is_action_pressed("zoom_in"): # Wheel Up Event
zoom_camera(-1)
elif event.is_action_pressed("zoom_out"): # Wheel Down Event
zoom_camera(1)
@ -27,5 +33,5 @@ func zoom_camera(dir : int) -> void:
if zoom > zoom_max:
zoom = zoom_max
Global.zoom_level_label.text = "Zoom: x%s" % [stepify(1 / zoom.x, 0.01)]
if name == "Camera2D":
Global.zoom_level_label.text = "Zoom: x%s" % [stepify(1 / zoom.x, 0.01)]

View file

@ -23,7 +23,7 @@ func _ready() -> void:
Global.can_draw = false
#Background
trans_background = ImageTexture.new()
trans_background.create_from_image(load("res://Transparent Background.png"), 0)
trans_background.create_from_image(load("res://Assets/Graphics/Transparent Background.png"), 0)
#The sprite itself
if layers.empty():
@ -39,7 +39,7 @@ func _ready() -> void:
generate_layer_panels()
frame_button = load("res://FrameButton.tscn").instance()
frame_button = load("res://Prefabs/FrameButton.tscn").instance()
frame_button.name = "Frame_%s" % frame
frame_button.get_node("FrameButton").frame = frame
frame_button.get_node("FrameID").text = str(frame + 1)
@ -50,6 +50,23 @@ func _ready() -> void:
camera_zoom()
func camera_zoom() -> void:
#Set camera offset to the center of canvas
Global.camera.offset = size / 2
Global.camera2.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
Global.camera2.zoom_max = zoom_max
else:
Global.camera.zoom_max = Vector2.ONE
Global.camera2.zoom_max = Vector2.ONE
Global.camera.zoom = Vector2(bigger, bigger) * 0.002
Global.camera2.zoom = Vector2(bigger, bigger) * 0.002
Global.zoom_level_label.text = "Zoom: x%s" % [stepify(1 / Global.camera.zoom.x, 0.01)]
# warning-ignore:unused_argument
func _process(delta) -> void:
sprite_changed_this_frame = false
@ -147,8 +164,7 @@ func _process(delta) -> void:
for xx in range(start_pos.x, end_pos.x):
for yy in range(start_pos.y, end_pos.y):
if xx >= location.x && xx < size.x && yy >= location.y && yy < size.y:
Global.selected_pixels.append(Vector2(xx, yy))
Global.selected_pixels.append(Vector2(xx, yy))
is_making_selection = "None"
if sprite_changed_this_frame:
@ -255,7 +271,7 @@ func generate_layer_panels() -> void:
Global.remove_layer_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
for i in range(layers.size() -1, -1, -1):
var layer_container = load("res://LayerContainer.tscn").instance()
var layer_container = load("res://Prefabs/LayerContainer.tscn").instance()
#layer_names.insert(i, "Layer %s" % i)
layers[i][2] = "Layer %s" % i
layer_container.i = i
@ -265,19 +281,6 @@ func generate_layer_panels() -> void:
layer_container.get_child(0).get_child(1).texture = layers[i][1]
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:
if Input.is_key_pressed(KEY_SHIFT):
if !is_making_line:
@ -290,55 +293,85 @@ func pencil_and_eraser(mouse_pos : Vector2, color : Color, current_mouse_button
is_making_line = true
else:
var brush_size := 1
var brush_type = Global.BRUSH_TYPES.PIXEL
var brush_index := -1
var interpolate_factor := 0.5
if current_mouse_button == "left_mouse":
brush_size = Global.left_brush_size
brush_type = Global.current_left_brush_type
brush_index = Global.custom_left_brush_index
interpolate_factor = Global.left_interpolate_slider.value
elif current_mouse_button == "right_mouse":
brush_size = Global.right_brush_size
brush_type = Global.current_right_brush_type
brush_index = Global.custom_right_brush_index
interpolate_factor = Global.right_interpolate_slider.value
if is_making_line:
fill_gaps(mouse_pos, color, brush_size)
fill_gaps(mouse_pos, color, brush_size, brush_type, brush_index, interpolate_factor)
is_making_line = false
line_2d.queue_free()
else:
if point_in_rectangle(mouse_pos, location, location + size):
mouse_inside_canvas = true
#Draw
draw_pixel(mouse_pos, color, brush_size)
fill_gaps(mouse_pos, color, brush_size) #Fill the gaps
draw_pixel(mouse_pos, color, brush_size, brush_type, brush_index, interpolate_factor)
fill_gaps(mouse_pos, color, brush_size, brush_type, brush_index, interpolate_factor) #Fill the gaps
#If mouse is not inside bounds but it used to be, fill the gaps
elif point_in_rectangle(previous_mouse_pos, location, location + size):
fill_gaps(mouse_pos, color, brush_size)
fill_gaps(mouse_pos, color, brush_size, brush_type, brush_index, interpolate_factor)
func draw_pixel(pos : Vector2, color : Color, brush_size : int) -> void:
func draw_pixel(pos : Vector2, color : Color, brush_size : int, brush_type : int, brush_index : int, interpolate_factor : float) -> void:
if Global.can_draw && Global.has_focus && Global.current_frame == frame:
#If there is a selection and current pixel is not in it
var west_limit := location.x
var east_limit := location.x + size.x
var north_limit := location.y
var south_limit := location.y + size.y
if Global.selected_pixels.size() != 0:
if Global.selected_pixels.size() != 0: #If there is a selection and current pixel position is not in it
west_limit = max(west_limit, Global.selection_rectangle.polygon[0].x)
east_limit = min(east_limit, Global.selection_rectangle.polygon[2].x)
north_limit = max(north_limit, Global.selection_rectangle.polygon[0].y)
south_limit = min(south_limit, Global.selection_rectangle.polygon[2].y)
var start_pos_x = pos.x - (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):
#layers[current_layer_index][0].set_pixel(cur_pos_x, pos.y, color)
for cur_pos_y in range(start_pos_y, start_pos_y + brush_size):
if point_in_rectangle(Vector2(cur_pos_x, cur_pos_y), Vector2(west_limit - 1, north_limit - 1), Vector2(east_limit, south_limit)):
if layers[current_layer_index][0].get_pixel(cur_pos_x, cur_pos_y) != color: #don't draw the same pixel over and over
layers[current_layer_index][0].set_pixel(cur_pos_x, cur_pos_y, color)
#layers[current_layer_index][0].set_pixelv(pos, color)
sprite_changed_this_frame = true
func point_in_rectangle(p : Vector2, coord1 : Vector2, coord2 : Vector2) -> bool:
return p.x > coord1.x && p.y > coord1.y && p.x < coord2.x && p.y < coord2.y
var start_pos_x
var start_pos_y
var end_pos_x
var end_pos_y
match(brush_type):
Global.BRUSH_TYPES.PIXEL:
start_pos_x = pos.x - (brush_size >> 1)
start_pos_y = pos.y - (brush_size >> 1)
end_pos_x = start_pos_x + brush_size
end_pos_y = start_pos_y + brush_size
for cur_pos_x in range(start_pos_x, end_pos_x):
for cur_pos_y in range(start_pos_y, end_pos_y):
if point_in_rectangle(Vector2(cur_pos_x, cur_pos_y), Vector2(west_limit - 1, north_limit - 1), Vector2(east_limit, south_limit)):
if layers[current_layer_index][0].get_pixel(cur_pos_x, cur_pos_y) != color: #don't draw the same pixel over and over
layers[current_layer_index][0].set_pixel(cur_pos_x, cur_pos_y, color)
sprite_changed_this_frame = true
Global.BRUSH_TYPES.CUSTOM:
var custom_brush := Image.new()
custom_brush.copy_from(Global.custom_brushes[brush_index])
var custom_brush_blended := blend_image_with_color(custom_brush, color, interpolate_factor)
var custom_brush_size = custom_brush_blended.get_size()
custom_brush_blended.resize(custom_brush_size.x * brush_size, custom_brush_size.y * brush_size, Image.INTERPOLATE_NEAREST)
custom_brush_size = custom_brush_blended.get_size()
var dst : Vector2 = pos - custom_brush_size / 4
var src_rect := Rect2(Vector2.ZERO, custom_brush_size)
#src_rect = src_rect.clip(Rect2(west_limit - dst.x, north_limit - dst.y, east_limit - custom_brush_size.x, south_limit - custom_brush_size.y))
if color.a > 0: #If it's the pencil
layers[current_layer_index][0].blend_rect(custom_brush_blended, src_rect, dst)
else: #if it's transparent - if it's the eraser
layers[current_layer_index][0].blit_rect_mask(custom_brush_blended, custom_brush, src_rect, dst)
layers[current_layer_index][0].lock()
update_texture(current_layer_index)
#Bresenham's Algorithm
#Thanks to https://godotengine.org/qa/35276/tile-based-line-drawing-algorithm-efficiency
func fill_gaps(mouse_pos : Vector2, color : Color, brush_size : int) -> void:
func fill_gaps(mouse_pos : Vector2, color : Color, brush_size : int, brush_type : int, brush_index : int, interpolate_factor : float) -> void:
var previous_mouse_pos_floored = previous_mouse_pos.floor()
var mouse_pos_floored = mouse_pos.floor()
mouse_pos_floored.x = clamp(mouse_pos_floored.x, location.x - 1, location.x + size.x)
@ -352,7 +385,7 @@ func fill_gaps(mouse_pos : Vector2, color : Color, brush_size : int) -> void:
var x = previous_mouse_pos_floored.x
var y = previous_mouse_pos_floored.y
while !(x == mouse_pos_floored.x && y == mouse_pos_floored.y):
draw_pixel(Vector2(x, y), color, brush_size)
draw_pixel(Vector2(x, y), color, brush_size, brush_type, brush_index, interpolate_factor)
e2 = err << 1
if e2 >= dy:
err += dy
@ -393,13 +426,35 @@ func flood_fill(pos : Vector2, target_color : Color, replace_color : Color) -> v
east += Vector2.RIGHT
for px in range(west.x + 1, east.x):
var p := Vector2(px, n.y)
draw_pixel(p, replace_color, 1)
#Draw
layers[current_layer_index][0].set_pixelv(p, replace_color)
var north := p + Vector2.UP
var south := p + Vector2.DOWN
if north.y >= north_limit && layers[current_layer_index][0].get_pixelv(north) == target_color:
q.append(north)
if south.y < south_limit && layers[current_layer_index][0].get_pixelv(south) == target_color:
q.append(south)
sprite_changed_this_frame = true
func point_in_rectangle(p : Vector2, coord1 : Vector2, coord2 : Vector2) -> bool:
return p.x > coord1.x && p.y > coord1.y && p.x < coord2.x && p.y < coord2.y
func blend_image_with_color(image : Image, color : Color, interpolate_factor : float) -> Image:
var blended_image := Image.new()
blended_image.copy_from(image)
var size := image.get_size()
blended_image.lock()
for xx in size.x:
for yy in size.y:
if color.a > 0: #If it's the pencil
var current_color := blended_image.get_pixel(xx, yy)
if current_color.a > 0:
#var blended_color = current_color.blend(color)
var new_color := current_color.linear_interpolate(color, interpolate_factor)
blended_image.set_pixel(xx, yy, new_color)
else: #If color is transparent - if it's the eraser
blended_image.set_pixel(xx, yy, Color(0, 0, 0, 0))
return blended_image
func _on_Timer_timeout() -> void:
Global.can_draw = true

View file

@ -18,28 +18,34 @@ var draw_grid := false
var canvases := []
var canvas : Canvas
var canvas_parent : Node
var second_viewport : ViewportContainer
var viewport_separator : VSeparator
var split_screen_button : Button
# 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 camera2 : Camera2D
var selection_rectangle : Polygon2D
# warning-ignore:unused_class_variable
var selected_pixels := []
var image_clipboard : Image
var file_menu : MenuButton
var edit_menu : MenuButton
var view_menu : MenuButton
var help_menu : MenuButton
var left_indicator : Sprite
var right_indicator : Sprite
var left_color_picker : ColorPickerButton
var right_color_picker : ColorPickerButton
var left_brush_size_edit : SpinBox
var right_brush_size_edit : SpinBox
var left_interpolate_slider : HSlider
var right_interpolate_slider : HSlider
var loop_animation_button : Button
var play_forward : Button
var play_backwards : Button
@ -60,12 +66,34 @@ var current_left_tool := "Pencil"
# warning-ignore:unused_class_variable
var current_right_tool := "Eraser"
#Brushes
enum BRUSH_TYPES {PIXEL, CUSTOM}
# warning-ignore:unused_class_variable
var left_brush_size := 1
# warning-ignore:unused_class_variable
var right_brush_size := 1
# warning-ignore:unused_class_variable
var current_left_brush_type = BRUSH_TYPES.PIXEL
# warning-ignore:unused_class_variable
var current_right_brush_type = BRUSH_TYPES.PIXEL
# warning-ignore:unused_class_variable
var custom_brushes := []
# warning-ignore:unused_class_variable
var custom_left_brush_index := -1
# warning-ignore:unused_class_variable
var custom_right_brush_index := -1
func _ready() -> void:
var root = get_tree().get_root()
canvas = find_node_by_name(root, "Canvas")
canvases.append(canvas)
canvas_parent = canvas.get_parent()
second_viewport = find_node_by_name(root, "ViewportContainer2")
viewport_separator = find_node_by_name(root, "ViewportSeparator")
split_screen_button = find_node_by_name(root, "SplitScreenButton")
camera = find_node_by_name(canvas_parent, "Camera2D")
camera2 = find_node_by_name(canvas_parent.get_parent().get_parent(), "Camera2D2")
selection_rectangle = find_node_by_name(root, "SelectionRectangle")
image_clipboard = Image.new()
@ -73,12 +101,15 @@ func _ready() -> void:
file_menu = find_node_by_name(root, "FileMenu")
edit_menu = find_node_by_name(root, "EditMenu")
view_menu = find_node_by_name(root, "ViewMenu")
help_menu = find_node_by_name(root, "HelpMenu")
left_indicator = find_node_by_name(root, "LeftIndicator")
right_indicator = find_node_by_name(root, "RightIndicator")
left_color_picker = find_node_by_name(root, "LeftColorPickerButton")
right_color_picker = find_node_by_name(root, "RightColorPickerButton")
left_brush_size_edit = find_node_by_name(root, "LeftBrushSizeEdit")
right_brush_size_edit = find_node_by_name(root, "RightBrushSizeEdit")
left_interpolate_slider = find_node_by_name(root, "LeftInterpolateFactor")
right_interpolate_slider = find_node_by_name(root, "RightInterpolateFactor")
loop_animation_button = find_node_by_name(root, "LoopAnim")
play_forward = find_node_by_name(root, "PlayForward")
@ -133,4 +164,14 @@ func handle_layer_order_buttons() -> void:
func set_current_frame_label(value) -> void:
current_frame = value
current_frame_label.text = "Current frame: %s/%s" % [str(current_frame + 1), canvases.size()]
current_frame_label.text = "Current frame: %s/%s" % [str(current_frame + 1), canvases.size()]
func create_brush_button(brush_img : Image) -> void:
var brush_button = load("res://Prefabs/BrushButton.tscn").instance()
brush_button.brush_type = Global.BRUSH_TYPES.CUSTOM
brush_button.custom_brush_index = Global.custom_brushes.size() - 1
var brush_tex := ImageTexture.new()
brush_tex.create_from_image(brush_img, 0)
brush_button.get_child(0).texture = brush_tex
var hbox_container := find_node_by_name(get_tree().get_root(), "BrushHBoxContainer")
hbox_container.add_child(brush_button)

View file

@ -14,7 +14,7 @@ func _ready() -> void:
# warning-ignore:unused_argument
func _process(delta) -> void:
var mouse_pos := get_local_mouse_position() + rect_position
if point_in_rectangle(mouse_pos, rect_position, rect_position + rect_size) && !visibility_toggled:
if Rect2(rect_position, rect_position + rect_size).has_point(mouse_pos) && !visibility_toggled:
if Input.is_action_just_pressed("left_mouse"):
Global.canvas.current_layer_index = i
changed_selection()
@ -48,9 +48,6 @@ func changed_selection() -> void:
child.currently_selected = false
child.get_stylebox("panel").bg_color = Color("3d3b45")
func point_in_rectangle(p : Vector2, coord1 : Vector2, coord2 : Vector2) -> bool:
return p.x > coord1.x && p.y > coord1.y && p.x < coord2.x && p.y < coord2.y
func _on_VisibilityButton_pressed() -> void:
if Global.canvas.layers[i][3]:
Global.canvas.layers[i][3] = false

View file

@ -34,6 +34,7 @@ func _ready() -> void:
}
var edit_menu_items := {
"Scale Image" : 0,
"Crop Image" : 0,
"Clear Selection" : 0
#"Undo" : KEY_MASK_CTRL + KEY_Z,
#"Redo" : KEY_MASK_SHIFT + KEY_MASK_CTRL + KEY_Z,
@ -41,12 +42,15 @@ func _ready() -> void:
var view_menu_items := {
"Tile Mode" : KEY_MASK_CTRL + KEY_T,
"Show Grid" : KEY_MASK_CTRL + KEY_G
#"Undo" : KEY_MASK_CTRL + KEY_Z,
#"Redo" : KEY_MASK_SHIFT + KEY_MASK_CTRL + KEY_Z,
}
var help_menu_items := {
"About Pixelorama" : 0
}
var file_menu : PopupMenu = Global.file_menu.get_popup()
var edit_menu : PopupMenu = Global.edit_menu.get_popup()
view_menu = Global.view_menu.get_popup()
var help_menu : PopupMenu = Global.help_menu.get_popup()
var i = 0
for item in file_menu_items.keys():
file_menu.add_item(item, i, file_menu_items[item])
@ -59,9 +63,15 @@ func _ready() -> void:
for item in view_menu_items.keys():
view_menu.add_check_item(item, i, view_menu_items[item])
i += 1
i = 0
for item in help_menu_items.keys():
help_menu.add_item(item, i, help_menu_items[item])
i += 1
file_menu.connect("id_pressed", self, "file_menu_id_pressed")
edit_menu.connect("id_pressed", self, "edit_menu_id_pressed")
view_menu.connect("id_pressed", self, "view_menu_id_pressed")
help_menu.connect("id_pressed", self, "help_menu_id_pressed")
var root = get_tree().get_root()
pencil_tool = Global.find_node_by_name(root, "Pencil")
@ -149,7 +159,37 @@ func edit_menu_id_pressed(id : int) -> void:
0: #Scale Image
$ScaleImage.popup_centered()
Global.can_draw = false
1: #Clear selection
1: #Crop Image
#Use first layer as a starting rectangle
var used_rect : Rect2 = Global.canvas.layers[0][0].get_used_rect()
#However, if first layer is empty, loop through all layers until we find one that isn't
var i := 0
while(i < Global.canvas.layers.size() - 1 && Global.canvas.layers[i][0].get_used_rect() == Rect2(0, 0, 0, 0)):
i += 1
used_rect = Global.canvas.layers[i][0].get_used_rect()
#Merge all layers with content
for j in range(Global.canvas.layers.size() - 1, i, -1):
if Global.canvas.layers[j][0].get_used_rect() != Rect2(0, 0, 0, 0):
used_rect = used_rect.merge(Global.canvas.layers[j][0].get_used_rect())
#If no layer has any content, just return
if used_rect == Rect2(0, 0, 0, 0):
return
#Loop through all the layers to crop them
for j in range(Global.canvas.layers.size() - 1, -1, -1):
var sprite := Image.new()
sprite = Global.canvas.layers[j][0].get_rect(used_rect)
Global.canvas.layers[j][0] = sprite
Global.canvas.layers[j][0].lock()
Global.canvas.update_texture(j)
var width = Global.canvas.layers[0][0].get_width()
var height = Global.canvas.layers[0][0].get_height()
Global.canvas.size = Vector2(width, height).floor()
Global.canvas.camera_zoom()
2: #Clear selection
Global.selection_rectangle.polygon[0] = Vector2.ZERO
Global.selection_rectangle.polygon[1] = Vector2.ZERO
Global.selection_rectangle.polygon[2] = Vector2.ZERO
@ -165,12 +205,18 @@ func view_menu_id_pressed(id : int) -> void:
Global.draw_grid = !Global.draw_grid
view_menu.set_item_checked(1, Global.draw_grid)
func help_menu_id_pressed(id : int) -> void:
match id:
0: #About Pixelorama
$AboutDialog.popup_centered()
Global.can_draw = false
func _on_CreateNewImage_confirmed() -> void:
var width := float($CreateNewImage/VBoxContainer/WidthCont/WidthValue.value)
var height := float($CreateNewImage/VBoxContainer/HeightCont/HeightValue.value)
var fill_color : Color = $CreateNewImage/VBoxContainer/FillColor/FillColor.color
clear_canvases()
Global.canvas = load("res://Canvas.tscn").instance()
Global.canvas = load("res://Prefabs/Canvas.tscn").instance()
Global.canvas.size = Vector2(width, height).floor()
Global.canvas_parent.add_child(Global.canvas)
@ -187,12 +233,15 @@ func _on_OpenSprite_file_selected(path) -> void:
var file := File.new()
var err := file.open(path, File.READ)
if err == 0:
var current_version : String = ProjectSettings.get_setting("application/config/Version")
var version := file.get_line()
if current_version != version:
OS.alert("File is from an older version of Pixelorama, as such it might not work properly")
var frame := 0
var frame_line := file.get_line()
clear_canvases()
while frame_line == "--":
var canvas : Canvas = load("res://Canvas.tscn").instance()
var canvas : Canvas = load("res://Prefabs/Canvas.tscn").instance()
Global.canvas = canvas
var width := file.get_16()
var height := file.get_16()
@ -233,6 +282,18 @@ func _on_OpenSprite_file_selected(path) -> void:
for color in right_palette:
Global.right_color_picker.get_picker().add_preset(color)
#Load custom brushes
var brush_line := file.get_line()
while brush_line == "/":
var b_width := file.get_16()
var b_height := file.get_16()
var buffer := file.get_buffer(b_width * b_height * 4)
var image := Image.new()
image.create_from_data(b_width, b_height, false, Image.FORMAT_RGBA8, buffer)
Global.custom_brushes.append(image)
Global.create_brush_button(image)
brush_line = file.get_line()
file.close()
func _on_SaveSprite_file_selected(path) -> void:
@ -264,6 +325,13 @@ func _on_SaveSprite_file_selected(path) -> void:
file.store_8(right_brush_size)
file.store_var(left_palette)
file.store_var(right_palette)
#Save custom brushes
for brush in Global.custom_brushes:
file.store_line("/")
file.store_16(brush.get_size().x)
file.store_16(brush.get_size().y)
file.store_buffer(brush.get_data())
file.store_line("END_BRUSHES")
file.close()
func _on_ImportSprites_files_selected(paths) -> void:
@ -279,7 +347,7 @@ func _on_ImportSprites_files_selected(paths) -> void:
var err = image.load(path)
if err == OK:
opensprite_file_selected = true
var canvas : Canvas = load("res://Canvas.tscn").instance()
var canvas : Canvas = load("res://Prefabs/Canvas.tscn").instance()
canvas.size = image.get_size()
image.convert(Image.FORMAT_RGBA8)
image.lock()
@ -488,7 +556,7 @@ func _on_RightBrushSizeEdit_value_changed(value) -> void:
Global.right_brush_size = new_size
func _on_AddFrame_pressed() -> void:
var canvas = load("res://Canvas.tscn").instance()
var canvas = load("res://Prefabs/Canvas.tscn").instance()
canvas.size = Global.canvas.size
canvas.frame = Global.canvases.size()
for canvas in Global.canvases:
@ -524,7 +592,7 @@ func _on_RemoveFrame_pressed() -> void:
func _on_CloneFrame_pressed() -> void:
var canvas = load("res://Canvas.tscn").instance()
var canvas = load("res://Prefabs/Canvas.tscn").instance()
canvas.size = Global.canvas.size
#canvas.layers = Global.canvas.layers.duplicate(true)
for layer in Global.canvas.layers:
@ -666,4 +734,14 @@ func _on_FutureOnionSkinning_value_changed(value) -> void:
Global.onion_skinning_future_rate = int(value)
func _on_BlueRedMode_toggled(button_pressed) -> void:
Global.onion_skinning_blue_red = button_pressed
Global.onion_skinning_blue_red = button_pressed
func _on_SplitScreenButton_toggled(button_pressed) -> void:
if button_pressed:
Global.split_screen_button.text = ">"
Global.viewport_separator.visible = true
Global.second_viewport.visible = true
else:
Global.split_screen_button.text = "<"
Global.viewport_separator.visible = false
Global.second_viewport.visible = false

13
Scripts/SecondViewport.gd Normal file
View file

@ -0,0 +1,13 @@
extends Viewport
# Declare member variables here. Examples:
# var a = 2
# var b = "text"
# Called when the node enters the scene tree for the first time.
func _ready():
world_2d = $"../../ViewportContainer/Viewport".world_2d
# Called every frame. 'delta' is the elapsed time since the previous frame.
#func _process(delta):
# pass

View file

@ -91,11 +91,18 @@ func _process(delta) -> void:
Global.selected_pixels.clear()
for xx in range(start_pos.x, end_pos.x):
for yy in range(start_pos.y, end_pos.y):
Global.selected_pixels.append(Vector2(xx, yy))
Global.selected_pixels.append(Vector2(xx, yy))
#Handle copy
if Input.is_action_just_pressed("copy") && Global.selected_pixels.size() > 0:
Global.image_clipboard = layer.get_rect(Rect2(polygon[0], polygon[2]))
Global.image_clipboard = layer.get_rect(Rect2(polygon[0], polygon[2] - polygon[0]))
#And save as custom brush
var brush_img := Image.new()
brush_img = layer.get_rect(Rect2(polygon[0], polygon[2] - polygon[0]))
brush_img = brush_img.get_rect(brush_img.get_used_rect()) #save only the visible pixels
Global.custom_brushes.append(brush_img)
Global.create_brush_button(brush_img)
#Handle paste
#if Input.is_action_just_pressed("paste") && Global.selected_pixels.size() > 0 && !is_dragging:

View file

@ -1,13 +0,0 @@
[remap]
importer="image"
type="Image"
path="res://.import/Transparent Background.png-b5955c8e7e6eaecd8f24a1732239745d.image"
[deps]
source_file="res://Transparent Background.png"
dest_files=[ "res://.import/Transparent Background.png-b5955c8e7e6eaecd8f24a1732239745d.image" ]
[params]

View file

@ -37,6 +37,7 @@ Global="*res://Scripts/Global.gd"
[debug]
gdscript/warnings/narrowing_conversion=false
gdscript/warnings/return_value_discarded=false
[input]