Initial commit
2
.gitattributes
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# Auto detect text files and perform LF normalization
|
||||||
|
* text=auto
|
1
.github/FUNDING.yml
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
custom: https://www.paypal.me/OverloadedOrama
|
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Scripts/Old/
|
3
.import/.png-05675a12d3f10112da9382ffea612140.md5
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="b8469a8d2b9b7f33cde9c50c882514d3"
|
||||||
|
dest_md5="611bf34048e600d74fb53c849097c026"
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="3f3e12abce4c2177df141c708b02c3cc"
|
||||||
|
dest_md5="5bb71e82d18a6514c7bec6e2f2996585"
|
||||||
|
|
BIN
.import/Sprite Editor.png-13de7b2e25322c0fe05acb73bde7971f.stex
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="90f1e764a9d0303186411784568ef237"
|
||||||
|
dest_md5="b40997122ed6d10d1612023e114c7315"
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="90f1e764a9d0303186411784568ef237"
|
||||||
|
dest_md5="5d2507d2ac9dd6d7f8b781cd64e5e4b6"
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="4c6be4fbf792fca422d20d3708852deb"
|
||||||
|
dest_md5="3f5ec639e0b1538d10f32d07e82950fc"
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="6861c2574df688e89c30a4d2c3ff0512"
|
||||||
|
dest_md5="5eaa4f1834b413cd6fba1a5e73afdea5"
|
||||||
|
|
3
.import/eraser.png-63c5caed334f555f34b58013167136d1.md5
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="6942d1787a239574517fad8cb24f6443"
|
||||||
|
dest_md5="5bff2bbc2ec94087f5589b982b0b041d"
|
||||||
|
|
BIN
.import/eraser.png-63c5caed334f555f34b58013167136d1.stex
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="12b72e84ba20c6659f35eb14d15e384f"
|
||||||
|
dest_md5="58d1bf2a5d6f24f60937a609877419e1"
|
||||||
|
|
BIN
.import/fill bucket.png-52b75bf5bbdd3ccd544de66c0c6f7825.stex
Normal file
BIN
.import/grid.png-643b5c8878aaf0c84a360796789dae22.image
Normal file
3
.import/grid.png-643b5c8878aaf0c84a360796789dae22.md5
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="8cf2e7f9a33f51edd3c13d15baef18e3"
|
||||||
|
dest_md5="f4ac734b475a905875624c9103984093"
|
||||||
|
|
BIN
.import/grid.png-643b5c8878aaf0c84a360796789dae22.stex
Normal file
3
.import/hello.png-e103c16b45db77894c95005feb7fad3f.md5
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="327bd47a99785cc67d3b563e11e15386"
|
||||||
|
dest_md5="f762a141beffeb685bedf56872c571fc"
|
||||||
|
|
3
.import/icon.png-487276ed1e3a0c39cad0279d744ee560.md5
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="8dd9ff1eebf38898a54579d8c01b0a88"
|
||||||
|
dest_md5="da70afec3c66d4e872db67f808e12edb"
|
||||||
|
|
BIN
.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex
Normal file
3
.import/left.png-a0857f5581a7224bc4706f5b5b072c04.md5
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="afb486d3e8d644a5cef52b79404018c8"
|
||||||
|
dest_md5="9c8d35cdd51018124a515cca005b90c8"
|
||||||
|
|
BIN
.import/left.png-a0857f5581a7224bc4706f5b5b072c04.stex
Normal file
3
.import/o.png-32d3b5843c98359b9557fafcc551e353.md5
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="3b9968d48bb94408d74340e812e4a715"
|
||||||
|
dest_md5="2d008139a38b2c0df1d773b0eb202d2f"
|
||||||
|
|
3
.import/ok.png-436d9a0bf8e96a20d85e9c9482696318.md5
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="d0ec0d56b87c9a8c60688d6af9d226a0"
|
||||||
|
dest_md5="605f5c73c93dc2a072713c6f3fcd0563"
|
||||||
|
|
3
.import/ooo.png-987fe23e74877197b78dca2a42501332.md5
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="1afa25ff3984b4aa5d235e151ea745f2"
|
||||||
|
dest_md5="3331184ae61337c572353772eeedb37b"
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="8cc6a8f03f20c923403c7d96eb234a23"
|
||||||
|
dest_md5="b99e77f302c757ba661cafd4fec3bab0"
|
||||||
|
|
3
.import/pencil.png-f45fc5ea6bc3e16a40ce7f3bc56fc30d.md5
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="2d305c9c1574dd800cd89ab58219d34e"
|
||||||
|
dest_md5="24117996741ddae3a5250c04b3b71e04"
|
||||||
|
|
BIN
.import/pencil.png-f45fc5ea6bc3e16a40ce7f3bc56fc30d.stex
Normal file
3
.import/right.png-e081bdade321da1277a90c4dc43840cc.md5
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="bcdb748e2ada0c3dbc28698c89b242ea"
|
||||||
|
dest_md5="2bd02d97a5efa3e07380fe97a40d14e8"
|
||||||
|
|
BIN
.import/right.png-e081bdade321da1277a90c4dc43840cc.stex
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="c0a02d16fd2d93552cb4f1b3bd38e1ba"
|
||||||
|
dest_md5="c20e14e5d1164cacc78d8d9dad66d3a3"
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="16bf0d760b5c4ff30efd2a7ddb10c5a7"
|
||||||
|
dest_md5="c9a9e4d828f496f7c9371c42dd41c332"
|
||||||
|
|
3
.import/yy.png-6cdc85baf6ec3016cd63aa20e3a024a2.md5
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
source_md5="702bfdd94a8185490af255dd080e549d"
|
||||||
|
dest_md5="0944e37fba7b57fbcd1c1b699eddb31f"
|
||||||
|
|
8
Assets/Fonts/Roboto-Regular.tres
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://Assets/Fonts/Roboto-Regular.ttf" type="DynamicFontData" id=1]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
use_mipmaps = true
|
||||||
|
use_filter = true
|
||||||
|
font_data = ExtResource( 1 )
|
BIN
Assets/Fonts/Roboto-Regular.ttf
Normal file
BIN
Assets/Graphics/Tools/eraser.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
34
Assets/Graphics/Tools/eraser.png.import
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/eraser.png-63c5caed334f555f34b58013167136d1.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://Assets/Graphics/Tools/eraser.png"
|
||||||
|
dest_files=[ "res://.import/eraser.png-63c5caed334f555f34b58013167136d1.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
|
BIN
Assets/Graphics/Tools/fill bucket.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
34
Assets/Graphics/Tools/fill bucket.png.import
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/fill bucket.png-52b75bf5bbdd3ccd544de66c0c6f7825.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://Assets/Graphics/Tools/fill bucket.png"
|
||||||
|
dest_files=[ "res://.import/fill bucket.png-52b75bf5bbdd3ccd544de66c0c6f7825.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
|
BIN
Assets/Graphics/Tools/pencil.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
34
Assets/Graphics/Tools/pencil.png.import
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/pencil.png-f45fc5ea6bc3e16a40ce7f3bc56fc30d.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://Assets/Graphics/Tools/pencil.png"
|
||||||
|
dest_files=[ "res://.import/pencil.png-f45fc5ea6bc3e16a40ce7f3bc56fc30d.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
|
53
Assets/Graphics/Tools/spraying-bottle-outline.svg
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="792px" height="792px" viewBox="0 0 792 792" style="enable-background:new 0 0 792 792;" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path d="M587.812,235.125h-2.475c-16.385-46.122-54.858-81.725-102.713-94.112V68.062c0-10.247-8.316-18.562-18.562-18.562
|
||||||
|
h-37.125c-10.246,0-18.562,8.316-18.562,18.562v72.951c-47.854,12.387-86.328,47.99-102.712,94.112h-1.238
|
||||||
|
c-40.949,0-69.3,27.114-69.3,68.062V722.7c0,40.948,28.351,69.3,69.3,69.3h283.388c40.949,0,68.062-28.352,68.062-69.3V303.188
|
||||||
|
C655.875,262.239,628.762,235.125,587.812,235.125z M445.5,185.625c36.543,0,68.459,19.961,85.61,49.5H359.89
|
||||||
|
C377.042,205.586,408.957,185.625,445.5,185.625z M304.425,284.625H346.5h198h37.125h6.188c13.612,0,18.562,4.95,18.562,18.562
|
||||||
|
v30.938h-321.75v-30.938C284.625,289.575,290.812,284.625,304.425,284.625z M606.375,383.625V643.5h-321.75V383.625H606.375z
|
||||||
|
M587.812,742.5H304.425c-13.612,0-19.8-6.188-19.8-19.8V693h321.75v29.7C606.375,736.312,601.425,742.5,587.812,742.5z"/>
|
||||||
|
<circle cx="346.5" cy="86.625" r="24.75"/>
|
||||||
|
<circle cx="235.125" cy="86.625" r="24.75"/>
|
||||||
|
<circle cx="297" cy="148.5" r="24.75"/>
|
||||||
|
<circle cx="297" cy="24.75" r="24.75"/>
|
||||||
|
<circle cx="160.875" cy="148.5" r="24.75"/>
|
||||||
|
<circle cx="160.875" cy="24.75" r="24.75"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.7 KiB |
34
Assets/Graphics/Tools/spraying-bottle-outline.svg.import
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/spraying-bottle-outline.svg-1ab842341f40f026a62a13ccf7ff4577.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://Assets/Graphics/Tools/spraying-bottle-outline.svg"
|
||||||
|
dest_files=[ "res://.import/spraying-bottle-outline.svg-1ab842341f40f026a62a13ccf7ff4577.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=true
|
||||||
|
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
|
BIN
Assets/Graphics/grid.png
Normal file
After Width: | Height: | Size: 87 B |
13
Assets/Graphics/grid.png.import
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
[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/left.png
Normal file
After Width: | Height: | Size: 154 B |
34
Assets/Graphics/left.png.import
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/left.png-a0857f5581a7224bc4706f5b5b072c04.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://Assets/Graphics/left.png"
|
||||||
|
dest_files=[ "res://.import/left.png-a0857f5581a7224bc4706f5b5b072c04.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
|
BIN
Assets/Graphics/right.png
Normal file
After Width: | Height: | Size: 154 B |
34
Assets/Graphics/right.png.import
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/right.png-e081bdade321da1277a90c4dc43840cc.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://Assets/Graphics/right.png"
|
||||||
|
dest_files=[ "res://.import/right.png-e081bdade321da1277a90c4dc43840cc.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
|
12
Canvas.tscn
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
[gd_scene load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://Scripts/Canvas.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[node name="Canvas" type="Node2D"]
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
|
||||||
|
[node name="Timer" type="Timer" parent="."]
|
||||||
|
wait_time = 0.2
|
||||||
|
one_shot = true
|
||||||
|
autostart = true
|
||||||
|
[connection signal="timeout" from="Timer" to="." method="_on_Timer_timeout"]
|
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2019 OverloadedOrama
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
38
LayerContainer.tscn
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
[gd_scene load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://Scripts/LayerContainer.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[node name="LayerContainer" type="PanelContainer"]
|
||||||
|
margin_top = 42.0
|
||||||
|
margin_right = 159.0
|
||||||
|
margin_bottom = 88.0
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
|
||||||
|
[node name="HBoxContainer" type="HBoxContainer" parent="."]
|
||||||
|
margin_left = 7.0
|
||||||
|
margin_top = 7.0
|
||||||
|
margin_right = 152.0
|
||||||
|
margin_bottom = 39.0
|
||||||
|
|
||||||
|
[node name="VisibilityButton" type="Button" parent="HBoxContainer"]
|
||||||
|
margin_right = 20.0
|
||||||
|
margin_bottom = 32.0
|
||||||
|
text = "V"
|
||||||
|
|
||||||
|
[node name="TextureRect" type="TextureRect" parent="HBoxContainer"]
|
||||||
|
margin_left = 24.0
|
||||||
|
margin_right = 56.0
|
||||||
|
margin_bottom = 32.0
|
||||||
|
rect_min_size = Vector2( 32, 32 )
|
||||||
|
expand = true
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="HBoxContainer"]
|
||||||
|
margin_left = 60.0
|
||||||
|
margin_top = 9.0
|
||||||
|
margin_right = 106.0
|
||||||
|
margin_bottom = 23.0
|
||||||
|
text = "Layer 0"
|
||||||
|
align = 1
|
||||||
|
[connection signal="button_down" from="HBoxContainer/VisibilityButton" to="." method="_on_VisibilityButton_button_down"]
|
||||||
|
[connection signal="button_up" from="HBoxContainer/VisibilityButton" to="." method="_on_VisibilityButton_button_up"]
|
||||||
|
[connection signal="pressed" from="HBoxContainer/VisibilityButton" to="." method="_on_VisibilityButton_pressed"]
|
7
Main Theme.tres
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
[gd_resource type="Theme" load_steps=2 format=2]
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id=1]
|
||||||
|
bg_color = Color( 0.239216, 0.231373, 0.270588, 1 )
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
PanelContainer/styles/panel = SubResource( 1 )
|
335
Main.tscn
Normal file
|
@ -0,0 +1,335 @@
|
||||||
|
[gd_scene load_steps=7 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]
|
||||||
|
|
||||||
|
[node name="Control" type="Control"]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
|
||||||
|
[node name="UI" type="HBoxContainer" parent="."]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
|
||||||
|
[node name="ToolPanel" type="Panel" parent="UI"]
|
||||||
|
margin_right = 320.0
|
||||||
|
margin_bottom = 600.0
|
||||||
|
rect_min_size = Vector2( 320, 0 )
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="UI/ToolPanel"]
|
||||||
|
margin_right = 40.0
|
||||||
|
margin_bottom = 44.0
|
||||||
|
|
||||||
|
[node name="MenuItems" type="HBoxContainer" parent="UI/ToolPanel/VBoxContainer"]
|
||||||
|
margin_right = 166.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
|
||||||
|
[node name="FileMenu" type="MenuButton" parent="UI/ToolPanel/VBoxContainer/MenuItems"]
|
||||||
|
margin_right = 35.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
theme = ExtResource( 2 )
|
||||||
|
text = "File"
|
||||||
|
|
||||||
|
[node name="EditMenu" type="MenuButton" parent="UI/ToolPanel/VBoxContainer/MenuItems"]
|
||||||
|
margin_left = 39.0
|
||||||
|
margin_right = 75.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
theme = ExtResource( 2 )
|
||||||
|
text = "Edit"
|
||||||
|
|
||||||
|
[node name="ToolsContainer" type="HBoxContainer" parent="UI/ToolPanel/VBoxContainer"]
|
||||||
|
margin_top = 24.0
|
||||||
|
margin_right = 166.0
|
||||||
|
margin_bottom = 44.0
|
||||||
|
|
||||||
|
[node name="Pencil" type="Button" parent="UI/ToolPanel/VBoxContainer/ToolsContainer"]
|
||||||
|
margin_right = 51.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
button_mask = 3
|
||||||
|
text = "Pencil"
|
||||||
|
|
||||||
|
[node name="LeftIndicator" type="Sprite" parent="UI/ToolPanel/VBoxContainer/ToolsContainer/Pencil"]
|
||||||
|
z_index = 1
|
||||||
|
texture = ExtResource( 3 )
|
||||||
|
centered = false
|
||||||
|
offset = Vector2( 0, -10 )
|
||||||
|
|
||||||
|
[node name="Eraser" type="Button" parent="UI/ToolPanel/VBoxContainer/ToolsContainer"]
|
||||||
|
margin_left = 55.0
|
||||||
|
margin_right = 106.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
button_mask = 3
|
||||||
|
text = "Eraser"
|
||||||
|
|
||||||
|
[node name="RightIndicator" type="Sprite" parent="UI/ToolPanel/VBoxContainer/ToolsContainer/Eraser"]
|
||||||
|
z_index = 1
|
||||||
|
texture = ExtResource( 4 )
|
||||||
|
centered = false
|
||||||
|
offset = Vector2( 35, -10 )
|
||||||
|
|
||||||
|
[node name="Fill" type="Button" parent="UI/ToolPanel/VBoxContainer/ToolsContainer"]
|
||||||
|
margin_left = 110.0
|
||||||
|
margin_right = 166.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
button_mask = 3
|
||||||
|
text = "Bucket"
|
||||||
|
|
||||||
|
[node name="ColorPickers" type="HBoxContainer" parent="UI/ToolPanel/VBoxContainer"]
|
||||||
|
margin_top = 48.0
|
||||||
|
margin_right = 166.0
|
||||||
|
margin_bottom = 80.0
|
||||||
|
|
||||||
|
[node name="LeftColorPickerButton" type="ColorPickerButton" parent="UI/ToolPanel/VBoxContainer/ColorPickers"]
|
||||||
|
margin_right = 32.0
|
||||||
|
margin_bottom = 32.0
|
||||||
|
rect_min_size = Vector2( 32, 32 )
|
||||||
|
size_flags_horizontal = 0
|
||||||
|
|
||||||
|
[node name="RightColorPickerButton" type="ColorPickerButton" parent="UI/ToolPanel/VBoxContainer/ColorPickers"]
|
||||||
|
margin_left = 36.0
|
||||||
|
margin_right = 68.0
|
||||||
|
margin_bottom = 32.0
|
||||||
|
rect_min_size = Vector2( 32, 32 )
|
||||||
|
size_flags_horizontal = 0
|
||||||
|
|
||||||
|
[node name="ViewportContainer" type="ViewportContainer" parent="UI"]
|
||||||
|
editor/display_folded = true
|
||||||
|
margin_left = 324.0
|
||||||
|
margin_right = 860.0
|
||||||
|
margin_bottom = 600.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
stretch = true
|
||||||
|
|
||||||
|
[node name="Viewport" type="Viewport" parent="UI/ViewportContainer"]
|
||||||
|
size = Vector2( 536, 600 )
|
||||||
|
handle_input_locally = false
|
||||||
|
render_target_update_mode = 3
|
||||||
|
|
||||||
|
[node name="Canvas" parent="UI/ViewportContainer/Viewport" instance=ExtResource( 5 )]
|
||||||
|
|
||||||
|
[node name="Camera2D" type="Camera2D" parent="UI/ViewportContainer/Viewport"]
|
||||||
|
current = true
|
||||||
|
zoom = Vector2( 0.15, 0.15 )
|
||||||
|
script = ExtResource( 6 )
|
||||||
|
|
||||||
|
[node name="LayerPanel" type="Panel" parent="UI"]
|
||||||
|
margin_left = 864.0
|
||||||
|
margin_right = 1024.0
|
||||||
|
margin_bottom = 600.0
|
||||||
|
rect_min_size = Vector2( 160, 0 )
|
||||||
|
|
||||||
|
[node name="ScrollContainer" type="ScrollContainer" parent="UI/LayerPanel"]
|
||||||
|
margin_right = 160.0
|
||||||
|
margin_bottom = 600.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
[node name="VBoxLayerContainer" type="VBoxContainer" parent="UI/LayerPanel/ScrollContainer"]
|
||||||
|
margin_right = 160.0
|
||||||
|
margin_bottom = 38.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
|
||||||
|
[node name="LayerLabel" type="Label" parent="UI/LayerPanel/ScrollContainer/VBoxLayerContainer"]
|
||||||
|
margin_right = 160.0
|
||||||
|
margin_bottom = 14.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 0
|
||||||
|
text = "Layers"
|
||||||
|
align = 1
|
||||||
|
|
||||||
|
[node name="HBoxContainer" type="HBoxContainer" parent="UI/LayerPanel/ScrollContainer/VBoxLayerContainer"]
|
||||||
|
margin_top = 18.0
|
||||||
|
margin_right = 160.0
|
||||||
|
margin_bottom = 38.0
|
||||||
|
|
||||||
|
[node name="AddLayerButton" type="Button" parent="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer"]
|
||||||
|
margin_right = 20.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
text = "+"
|
||||||
|
|
||||||
|
[node name="RemoveLayerButton" type="Button" parent="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer"]
|
||||||
|
margin_left = 24.0
|
||||||
|
margin_right = 44.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
disabled = true
|
||||||
|
text = "X"
|
||||||
|
|
||||||
|
[node name="MoveUpLayer" type="Button" parent="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer"]
|
||||||
|
margin_left = 48.0
|
||||||
|
margin_right = 67.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
disabled = true
|
||||||
|
text = "^"
|
||||||
|
|
||||||
|
[node name="MoveDownLayer" type="Button" parent="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer"]
|
||||||
|
margin_left = 71.0
|
||||||
|
margin_right = 90.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
disabled = true
|
||||||
|
text = "v"
|
||||||
|
|
||||||
|
[node name="CloneLayer" type="Button" parent="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer"]
|
||||||
|
margin_left = 94.0
|
||||||
|
margin_right = 118.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
text = "Cl"
|
||||||
|
|
||||||
|
[node name="MergeDownLayer" type="Button" parent="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer"]
|
||||||
|
margin_left = 122.0
|
||||||
|
margin_right = 146.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
disabled = true
|
||||||
|
text = "M"
|
||||||
|
|
||||||
|
[node name="CreateNewImage" type="ConfirmationDialog" parent="."]
|
||||||
|
editor/display_folded = true
|
||||||
|
margin_right = 200.0
|
||||||
|
margin_bottom = 70.0
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="CreateNewImage"]
|
||||||
|
margin_left = 8.0
|
||||||
|
margin_top = 8.0
|
||||||
|
margin_right = 192.0
|
||||||
|
margin_bottom = 78.0
|
||||||
|
|
||||||
|
[node name="ImageSize" type="Label" parent="CreateNewImage/VBoxContainer"]
|
||||||
|
margin_right = 184.0
|
||||||
|
margin_bottom = 14.0
|
||||||
|
text = "Image Size"
|
||||||
|
|
||||||
|
[node name="WidthCont" type="HBoxContainer" parent="CreateNewImage/VBoxContainer"]
|
||||||
|
margin_top = 18.0
|
||||||
|
margin_right = 184.0
|
||||||
|
margin_bottom = 42.0
|
||||||
|
|
||||||
|
[node name="WidthLabel" type="Label" parent="CreateNewImage/VBoxContainer/WidthCont"]
|
||||||
|
margin_top = 5.0
|
||||||
|
margin_right = 46.0
|
||||||
|
margin_bottom = 19.0
|
||||||
|
text = "Width: "
|
||||||
|
|
||||||
|
[node name="LineEdit" type="LineEdit" parent="CreateNewImage/VBoxContainer/WidthCont"]
|
||||||
|
margin_left = 50.0
|
||||||
|
margin_right = 108.0
|
||||||
|
margin_bottom = 24.0
|
||||||
|
text = "64"
|
||||||
|
|
||||||
|
[node name="HeightCont" type="HBoxContainer" parent="CreateNewImage/VBoxContainer"]
|
||||||
|
margin_top = 46.0
|
||||||
|
margin_right = 184.0
|
||||||
|
margin_bottom = 70.0
|
||||||
|
|
||||||
|
[node name="Height" type="Label" parent="CreateNewImage/VBoxContainer/HeightCont"]
|
||||||
|
margin_top = 5.0
|
||||||
|
margin_right = 46.0
|
||||||
|
margin_bottom = 19.0
|
||||||
|
text = "Height:"
|
||||||
|
|
||||||
|
[node name="LineEdit" type="LineEdit" parent="CreateNewImage/VBoxContainer/HeightCont"]
|
||||||
|
margin_left = 50.0
|
||||||
|
margin_right = 108.0
|
||||||
|
margin_bottom = 24.0
|
||||||
|
text = "64"
|
||||||
|
|
||||||
|
[node name="OpenSprite" type="FileDialog" parent="."]
|
||||||
|
margin_right = 515.0
|
||||||
|
margin_bottom = 348.0
|
||||||
|
window_title = "Open a File"
|
||||||
|
resizable = true
|
||||||
|
mode = 0
|
||||||
|
access = 2
|
||||||
|
filters = PoolStringArray( "*jpg, *.png ; JPG, PNG Images" )
|
||||||
|
current_dir = "C:/Users/Overloaded/Dropbox/Orama Founding Members/εταιρικα αρχεια/Godot Projects/Pixelorama"
|
||||||
|
current_path = "C:/Users/Overloaded/Dropbox/Orama Founding Members/εταιρικα αρχεια/Godot Projects/Pixelorama/"
|
||||||
|
|
||||||
|
[node name="SaveSprite" type="FileDialog" parent="."]
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
margin_left = -512.0
|
||||||
|
margin_top = -300.0
|
||||||
|
margin_right = 3.0
|
||||||
|
margin_bottom = 48.0
|
||||||
|
window_title = "Create a new image"
|
||||||
|
resizable = true
|
||||||
|
access = 2
|
||||||
|
filters = PoolStringArray( "*.png ; PNG Image" )
|
||||||
|
current_dir = "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="."]
|
||||||
|
editor/display_folded = true
|
||||||
|
margin_right = 200.0
|
||||||
|
margin_bottom = 114.0
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="ScaleImage"]
|
||||||
|
margin_left = 8.0
|
||||||
|
margin_top = 8.0
|
||||||
|
margin_right = 192.0
|
||||||
|
margin_bottom = 78.0
|
||||||
|
|
||||||
|
[node name="ImageSize" type="Label" parent="ScaleImage/VBoxContainer"]
|
||||||
|
margin_right = 184.0
|
||||||
|
margin_bottom = 14.0
|
||||||
|
text = "Image Size"
|
||||||
|
|
||||||
|
[node name="WidthCont" type="HBoxContainer" parent="ScaleImage/VBoxContainer"]
|
||||||
|
margin_top = 18.0
|
||||||
|
margin_right = 184.0
|
||||||
|
margin_bottom = 42.0
|
||||||
|
|
||||||
|
[node name="WidthLabel" type="Label" parent="ScaleImage/VBoxContainer/WidthCont"]
|
||||||
|
margin_top = 5.0
|
||||||
|
margin_right = 46.0
|
||||||
|
margin_bottom = 19.0
|
||||||
|
text = "Width: "
|
||||||
|
|
||||||
|
[node name="LineEdit" type="LineEdit" parent="ScaleImage/VBoxContainer/WidthCont"]
|
||||||
|
margin_left = 50.0
|
||||||
|
margin_right = 108.0
|
||||||
|
margin_bottom = 24.0
|
||||||
|
text = "64"
|
||||||
|
|
||||||
|
[node name="HeightCont" type="HBoxContainer" parent="ScaleImage/VBoxContainer"]
|
||||||
|
margin_top = 46.0
|
||||||
|
margin_right = 184.0
|
||||||
|
margin_bottom = 70.0
|
||||||
|
|
||||||
|
[node name="Height" type="Label" parent="ScaleImage/VBoxContainer/HeightCont"]
|
||||||
|
margin_top = 5.0
|
||||||
|
margin_right = 46.0
|
||||||
|
margin_bottom = 19.0
|
||||||
|
text = "Height:"
|
||||||
|
|
||||||
|
[node name="LineEdit" type="LineEdit" parent="ScaleImage/VBoxContainer/HeightCont"]
|
||||||
|
margin_left = 50.0
|
||||||
|
margin_right = 108.0
|
||||||
|
margin_bottom = 24.0
|
||||||
|
text = "64"
|
||||||
|
[connection signal="popup_closed" from="UI/ToolPanel/VBoxContainer/ColorPickers/LeftColorPickerButton" to="." method="_can_draw_true"]
|
||||||
|
[connection signal="pressed" from="UI/ToolPanel/VBoxContainer/ColorPickers/LeftColorPickerButton" to="." method="_can_draw_false"]
|
||||||
|
[connection signal="popup_closed" from="UI/ToolPanel/VBoxContainer/ColorPickers/RightColorPickerButton" to="." method="_can_draw_true"]
|
||||||
|
[connection signal="pressed" from="UI/ToolPanel/VBoxContainer/ColorPickers/RightColorPickerButton" to="." method="_can_draw_false"]
|
||||||
|
[connection signal="mouse_entered" from="UI/ViewportContainer" to="." method="_on_ViewportContainer_mouse_entered"]
|
||||||
|
[connection signal="mouse_exited" from="UI/ViewportContainer" to="." method="_on_ViewportContainer_mouse_exited"]
|
||||||
|
[connection signal="pressed" from="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer/AddLayerButton" to="." method="_on_AddLayerButton_pressed"]
|
||||||
|
[connection signal="pressed" from="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer/RemoveLayerButton" to="." method="_on_RemoveLayerButton_pressed"]
|
||||||
|
[connection signal="pressed" from="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer/MoveUpLayer" to="." method="_on_MoveUpLayer_pressed"]
|
||||||
|
[connection signal="pressed" from="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer/MoveDownLayer" to="." method="_on_MoveDownLayer_pressed"]
|
||||||
|
[connection signal="pressed" from="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer/CloneLayer" to="." method="_on_CloneLayer_pressed"]
|
||||||
|
[connection signal="pressed" from="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer/MergeDownLayer" to="." method="_on_MergeLayer_pressed"]
|
||||||
|
[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"]
|
||||||
|
[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="popup_hide" from="SaveSprite" 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"]
|
2
README.md
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# Pixelorama
|
||||||
|
A free & open-source 2D sprite editor, made with Godot Engine!
|
25
Scripts/CameraMovement.gd
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
extends Camera2D
|
||||||
|
|
||||||
|
var zoom_min := Vector2(0.005, 0.005)
|
||||||
|
var zoom_max := Vector2(0.8, 0.8)
|
||||||
|
|
||||||
|
var drag := false
|
||||||
|
|
||||||
|
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
|
||||||
|
zoom_camera(-1)
|
||||||
|
elif event.is_action_pressed("zoom_out"): # Wheel Down Event
|
||||||
|
zoom_camera(1)
|
||||||
|
elif event is InputEventMouseMotion && drag:
|
||||||
|
offset = offset - event.relative * zoom
|
||||||
|
|
||||||
|
# Zoom Camera
|
||||||
|
func zoom_camera(dir : int) -> void:
|
||||||
|
var zoom_margin = zoom * dir / 10
|
||||||
|
if zoom + zoom_margin > zoom_min && zoom + zoom_margin < zoom_max:
|
||||||
|
zoom += zoom_margin
|
233
Scripts/Canvas.gd
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
extends Node2D
|
||||||
|
class_name Canvas
|
||||||
|
|
||||||
|
var layers := []
|
||||||
|
var current_layer_index := 0
|
||||||
|
var trans_background : ImageTexture
|
||||||
|
var current_sprite : Image
|
||||||
|
var location := Vector2.ZERO
|
||||||
|
var size := Vector2(64, 64)
|
||||||
|
|
||||||
|
var previous_mouse_pos := Vector2.ZERO
|
||||||
|
var mouse_inside_canvas := false #used for undo
|
||||||
|
var sprite_changed_this_frame := false #for optimization purposes
|
||||||
|
var is_making_line := false
|
||||||
|
var line_2d : Line2D
|
||||||
|
var draw_grid := false
|
||||||
|
|
||||||
|
# Called when the node enters the scene tree for the first time.
|
||||||
|
func _ready() -> void:
|
||||||
|
Global.can_draw = false
|
||||||
|
#Background
|
||||||
|
trans_background = ImageTexture.new()
|
||||||
|
trans_background.create_from_image(load("res://Transparent Background.png"), 0)
|
||||||
|
|
||||||
|
#The sprite itself
|
||||||
|
if !current_sprite:
|
||||||
|
current_sprite = Image.new()
|
||||||
|
current_sprite.create(size.x, size.y, false, Image.FORMAT_RGBA8)
|
||||||
|
|
||||||
|
current_sprite.lock()
|
||||||
|
var tex := ImageTexture.new()
|
||||||
|
tex.create_from_image(current_sprite, 0)
|
||||||
|
|
||||||
|
#Store [Image, ImageTexture, Layer Name, Visibity boolean]
|
||||||
|
layers.append([current_sprite, tex, "Layer 0", true])
|
||||||
|
|
||||||
|
generate_layer_panels()
|
||||||
|
#Set camera offset to the center of canvas
|
||||||
|
$"../Camera2D".offset = size / 2
|
||||||
|
#Set camera zoom based on the sprite size
|
||||||
|
var bigger = max(size.x, size.y)
|
||||||
|
$"../Camera2D".zoom_max = Vector2(bigger, bigger) * 0.01
|
||||||
|
$"../Camera2D".zoom = Vector2(bigger, bigger) * 0.002
|
||||||
|
|
||||||
|
# warning-ignore:unused_argument
|
||||||
|
func _process(delta) -> void:
|
||||||
|
sprite_changed_this_frame = false
|
||||||
|
update()
|
||||||
|
var mouse_pos := get_local_mouse_position() - location
|
||||||
|
var current_mouse_button := "None"
|
||||||
|
var current_action := "None"
|
||||||
|
if Input.is_mouse_button_pressed(BUTTON_LEFT):
|
||||||
|
current_mouse_button = "L"
|
||||||
|
current_action = Global.current_left_tool
|
||||||
|
elif Input.is_mouse_button_pressed(BUTTON_RIGHT):
|
||||||
|
current_mouse_button = "R"
|
||||||
|
current_action = Global.current_right_tool
|
||||||
|
|
||||||
|
|
||||||
|
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 mouse_inside_canvas:
|
||||||
|
mouse_inside_canvas = false
|
||||||
|
match current_action:
|
||||||
|
"Pencil":
|
||||||
|
var current_color : Color
|
||||||
|
if current_mouse_button == "L":
|
||||||
|
current_color = Global.left_color_picker.color
|
||||||
|
elif current_mouse_button == "R":
|
||||||
|
current_color = Global.right_color_picker.color
|
||||||
|
pencil_and_eraser(mouse_pos, current_color)
|
||||||
|
"Eraser":
|
||||||
|
pencil_and_eraser(mouse_pos, Color(0, 0, 0, 0))
|
||||||
|
"Fill":
|
||||||
|
if point_in_rectangle(mouse_pos, location, location + size) && Global.can_draw && Global.has_focus:
|
||||||
|
var current_color : Color
|
||||||
|
if current_mouse_button == "L":
|
||||||
|
current_color = Global.left_color_picker.color
|
||||||
|
elif current_mouse_button == "R":
|
||||||
|
current_color = Global.right_color_picker.color
|
||||||
|
flood_fill(mouse_pos, layers[current_layer_index][0].get_pixelv(mouse_pos), current_color)
|
||||||
|
|
||||||
|
if !is_making_line:
|
||||||
|
previous_mouse_pos = mouse_pos
|
||||||
|
previous_mouse_pos.x = clamp(previous_mouse_pos.x, location.x, location.x + size.x)
|
||||||
|
previous_mouse_pos.y = clamp(previous_mouse_pos.y, location.y, location.y + size.y)
|
||||||
|
else:
|
||||||
|
line_2d.set_point_position(1, mouse_pos)
|
||||||
|
|
||||||
|
if sprite_changed_this_frame:
|
||||||
|
update_texture(current_layer_index)
|
||||||
|
|
||||||
|
func update_texture(layer_index : int):
|
||||||
|
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]
|
||||||
|
|
||||||
|
func get_layer_container(layer_index : int) -> PanelContainer:
|
||||||
|
for container in Global.vbox_layer_container.get_children():
|
||||||
|
if container is PanelContainer && container.i == layer_index:
|
||||||
|
return container
|
||||||
|
return null
|
||||||
|
|
||||||
|
func _draw() -> void:
|
||||||
|
draw_texture_rect(trans_background, Rect2(location, size), true)
|
||||||
|
#for texture in layer_textures:
|
||||||
|
for texture in layers:
|
||||||
|
if texture[3]: #if it's visible
|
||||||
|
draw_texture(texture[1], location)
|
||||||
|
|
||||||
|
#Draw grid (causes lag - unused. If you wanna test it just set draw_grid = true)
|
||||||
|
if draw_grid:
|
||||||
|
for x in size.x:
|
||||||
|
for y in size.y:
|
||||||
|
draw_rect(Rect2(location.x + x, location.y + y, 1, 1), Color.black, false)
|
||||||
|
|
||||||
|
#Draw rectangle to indicate the pixel currently being hovered on
|
||||||
|
var mouse_pos := get_local_mouse_position() - location
|
||||||
|
if point_in_rectangle(mouse_pos, location, location + size):
|
||||||
|
mouse_pos = mouse_pos.floor()
|
||||||
|
draw_rect(Rect2(mouse_pos.x, mouse_pos.y, 1, 1), Color.red, false)
|
||||||
|
|
||||||
|
func generate_layer_panels() -> void:
|
||||||
|
for child in Global.vbox_layer_container.get_children():
|
||||||
|
if child is PanelContainer:
|
||||||
|
child.queue_free()
|
||||||
|
|
||||||
|
current_layer_index = layers.size() - 1
|
||||||
|
if layers.size() == 1:
|
||||||
|
Global.remove_layer_button.disabled = true
|
||||||
|
else:
|
||||||
|
Global.remove_layer_button.disabled = false
|
||||||
|
|
||||||
|
for i in range(layers.size() -1, -1, -1):
|
||||||
|
var layer_container = load("res://LayerContainer.tscn").instance()
|
||||||
|
#layer_names.insert(i, "Layer %s" % i)
|
||||||
|
layers[i][2] = "Layer %s" % i
|
||||||
|
layer_container.i = i
|
||||||
|
#layer_container.get_child(0).get_child(2).text = layer_names[i]
|
||||||
|
layer_container.get_child(0).get_child(2).text = layers[i][2]
|
||||||
|
layers[i][3] = true #set visible
|
||||||
|
layer_container.get_child(0).get_child(1).texture = layers[i][1]
|
||||||
|
Global.vbox_layer_container.add_child(layer_container)
|
||||||
|
|
||||||
|
func pencil_and_eraser(mouse_pos : Vector2, color : Color) -> void:
|
||||||
|
if Input.is_key_pressed(KEY_SHIFT):
|
||||||
|
if !is_making_line:
|
||||||
|
line_2d = Line2D.new()
|
||||||
|
line_2d.width = 0.5
|
||||||
|
line_2d.default_color = Color.darkgray
|
||||||
|
line_2d.add_point(previous_mouse_pos)
|
||||||
|
line_2d.add_point(mouse_pos)
|
||||||
|
add_child(line_2d)
|
||||||
|
is_making_line = true
|
||||||
|
else:
|
||||||
|
if is_making_line:
|
||||||
|
fill_gaps(mouse_pos, color)
|
||||||
|
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)
|
||||||
|
fill_gaps(mouse_pos, color) #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)
|
||||||
|
|
||||||
|
func draw_pixel(pos : Vector2, color : Color) -> void:
|
||||||
|
if layers[current_layer_index][0].get_pixelv(pos) != color: #don't draw the same pixel over and over
|
||||||
|
if Global.can_draw && Global.has_focus:
|
||||||
|
#sprite.lock()
|
||||||
|
layers[current_layer_index][0].set_pixelv(pos, color)
|
||||||
|
#sprite.unlock()
|
||||||
|
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
|
||||||
|
|
||||||
|
#Bresenham's Algorithm
|
||||||
|
#Thanks to https://godotengine.org/qa/35276/tile-based-line-drawing-algorithm-efficiency
|
||||||
|
func fill_gaps(mouse_pos : Vector2, color : Color) -> 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)
|
||||||
|
mouse_pos_floored.y = clamp(mouse_pos_floored.y, location.y - 1, location.y + size.y)
|
||||||
|
var dx := int(abs(mouse_pos_floored.x - previous_mouse_pos_floored.x))
|
||||||
|
var dy := int(-abs(mouse_pos_floored.y - previous_mouse_pos_floored.y))
|
||||||
|
var err := dx + dy
|
||||||
|
var e2 := err << 1 #err * 2
|
||||||
|
var sx = 1 if previous_mouse_pos_floored.x < mouse_pos_floored.x else -1
|
||||||
|
var sy = 1 if previous_mouse_pos_floored.y < mouse_pos_floored.y else -1
|
||||||
|
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)
|
||||||
|
e2 = err << 1
|
||||||
|
if e2 >= dy:
|
||||||
|
err += dy
|
||||||
|
x += sx
|
||||||
|
if e2 <= dx:
|
||||||
|
err += dx
|
||||||
|
y += sy
|
||||||
|
|
||||||
|
#Thanks to https://en.wikipedia.org/wiki/Flood_fill
|
||||||
|
func flood_fill(pos : Vector2, target_color : Color, replace_color : Color) -> void:
|
||||||
|
pos = pos.floor()
|
||||||
|
var pixel = layers[current_layer_index][0].get_pixelv(pos)
|
||||||
|
if target_color == replace_color:
|
||||||
|
return
|
||||||
|
elif pixel != target_color:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
var q = [pos]
|
||||||
|
for n in q:
|
||||||
|
var west : Vector2 = n
|
||||||
|
var east : Vector2 = n
|
||||||
|
while west.x >= location.x && layers[current_layer_index][0].get_pixelv(west) == target_color:
|
||||||
|
west += Vector2.LEFT
|
||||||
|
while east.x < location.x + size.x && layers[current_layer_index][0].get_pixelv(east) == target_color:
|
||||||
|
east += Vector2.RIGHT
|
||||||
|
for px in range(west.x + 1, east.x):
|
||||||
|
var p := Vector2(px, n.y)
|
||||||
|
draw_pixel(p, replace_color)
|
||||||
|
var north := p + Vector2.UP
|
||||||
|
var south := p + Vector2.DOWN
|
||||||
|
if north.y >= location.y && layers[current_layer_index][0].get_pixelv(north) == target_color:
|
||||||
|
q.append(north)
|
||||||
|
if south.y < location.y + size.y && layers[current_layer_index][0].get_pixelv(south) == target_color:
|
||||||
|
q.append(south)
|
||||||
|
|
||||||
|
func _on_Timer_timeout() -> void:
|
||||||
|
Global.can_draw = true
|
51
Scripts/Global.gd
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
# warning-ignore:unused_class_variable
|
||||||
|
var can_draw := false
|
||||||
|
# warning-ignore:unused_class_variable
|
||||||
|
var has_focus := true
|
||||||
|
var canvas : Canvas
|
||||||
|
var canvas_parent
|
||||||
|
var left_color_picker : ColorPickerButton
|
||||||
|
var right_color_picker : ColorPickerButton
|
||||||
|
var file_menu : MenuButton
|
||||||
|
var edit_menu : MenuButton
|
||||||
|
var left_indicator : Sprite
|
||||||
|
var right_indicator : Sprite
|
||||||
|
var vbox_layer_container : VBoxContainer
|
||||||
|
var remove_layer_button : Button
|
||||||
|
var move_up_layer_button : Button
|
||||||
|
var move_down_layer_button : Button
|
||||||
|
var merge_down_layer_button : Button
|
||||||
|
# warning-ignore:unused_class_variable
|
||||||
|
var current_left_tool := "Pencil"
|
||||||
|
# warning-ignore:unused_class_variable
|
||||||
|
var current_right_tool := "Eraser"
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
var root = get_tree().get_root()
|
||||||
|
canvas = find_node_by_name(root, "Canvas")
|
||||||
|
canvas_parent = canvas.get_parent()
|
||||||
|
left_color_picker = find_node_by_name(root, "LeftColorPickerButton")
|
||||||
|
right_color_picker = find_node_by_name(root, "RightColorPickerButton")
|
||||||
|
file_menu = find_node_by_name(root, "FileMenu")
|
||||||
|
edit_menu = find_node_by_name(root, "EditMenu")
|
||||||
|
left_indicator = find_node_by_name(root, "LeftIndicator")
|
||||||
|
right_indicator = find_node_by_name(root, "RightIndicator")
|
||||||
|
vbox_layer_container = find_node_by_name(root, "VBoxLayerContainer")
|
||||||
|
remove_layer_button = find_node_by_name(root, "RemoveLayerButton")
|
||||||
|
move_up_layer_button = find_node_by_name(root, "MoveUpLayer")
|
||||||
|
move_down_layer_button = find_node_by_name(root, "MoveDownLayer")
|
||||||
|
merge_down_layer_button = find_node_by_name(root, "MergeDownLayer")
|
||||||
|
|
||||||
|
#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:
|
||||||
|
if root.get_name() == node_name:
|
||||||
|
return root
|
||||||
|
for child in root.get_children():
|
||||||
|
if child.get_name() == node_name:
|
||||||
|
return child
|
||||||
|
var found = find_node_by_name(child, node_name)
|
||||||
|
if found:
|
||||||
|
return found
|
||||||
|
return null
|
60
Scripts/LayerContainer.gd
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
extends PanelContainer
|
||||||
|
|
||||||
|
var i
|
||||||
|
var currently_selected := false
|
||||||
|
var visibility_toggled := false
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
var stylebox = StyleBoxFlat.new()
|
||||||
|
stylebox.bg_color = Color("3d3b45")
|
||||||
|
add_stylebox_override("panel", stylebox)
|
||||||
|
changed_selection()
|
||||||
|
|
||||||
|
# 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 Input.is_action_just_pressed("left_mouse"):
|
||||||
|
Global.canvas.current_layer_index = i
|
||||||
|
changed_selection()
|
||||||
|
|
||||||
|
func changed_selection() -> void:
|
||||||
|
var parent = get_parent()
|
||||||
|
for child in parent.get_children():
|
||||||
|
if child is PanelContainer:
|
||||||
|
if Global.canvas.current_layer_index == child.i:
|
||||||
|
child.currently_selected = true
|
||||||
|
child.get_stylebox("panel").bg_color = Color("282532")
|
||||||
|
|
||||||
|
if Global.canvas.current_layer_index < Global.canvas.layers.size() - 1:
|
||||||
|
Global.move_up_layer_button.disabled = false
|
||||||
|
else:
|
||||||
|
Global.move_up_layer_button.disabled = true
|
||||||
|
|
||||||
|
if Global.canvas.current_layer_index > 0:
|
||||||
|
Global.move_down_layer_button.disabled = false
|
||||||
|
Global.merge_down_layer_button.disabled = false
|
||||||
|
else:
|
||||||
|
Global.move_down_layer_button.disabled = true
|
||||||
|
Global.merge_down_layer_button.disabled = true
|
||||||
|
else:
|
||||||
|
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
|
||||||
|
get_child(0).get_child(0).text = "I"
|
||||||
|
else:
|
||||||
|
Global.canvas.layers[i][3] = true
|
||||||
|
get_child(0).get_child(0).text = "V"
|
||||||
|
|
||||||
|
|
||||||
|
func _on_VisibilityButton_button_down() -> void:
|
||||||
|
visibility_toggled = true
|
||||||
|
|
||||||
|
func _on_VisibilityButton_button_up() -> void:
|
||||||
|
visibility_toggled = false
|
214
Scripts/Main.gd
Normal file
|
@ -0,0 +1,214 @@
|
||||||
|
extends Control
|
||||||
|
|
||||||
|
var current_path := ""
|
||||||
|
var opensprite_file_selected := false
|
||||||
|
var pencil_tool
|
||||||
|
var eraser_tool
|
||||||
|
var fill_tool
|
||||||
|
|
||||||
|
# Called when the node enters the scene tree for the first time.
|
||||||
|
func _ready() -> void:
|
||||||
|
var file_menu_items := {
|
||||||
|
"New..." : KEY_MASK_CTRL + KEY_N,
|
||||||
|
"Import..." : KEY_MASK_CTRL + KEY_O,
|
||||||
|
"Export..." : KEY_MASK_CTRL + KEY_S,
|
||||||
|
"Export as..." : KEY_MASK_SHIFT + KEY_MASK_CTRL + KEY_S,
|
||||||
|
"Quit" : KEY_MASK_CTRL + KEY_Q
|
||||||
|
}
|
||||||
|
# var edit_menu_items := {
|
||||||
|
# "Undo" : 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 edit_menu : PopupMenu = Global.edit_menu.get_popup()
|
||||||
|
var i = 0
|
||||||
|
for item in file_menu_items.keys():
|
||||||
|
file_menu.add_item(item, i, file_menu_items[item])
|
||||||
|
i += 1
|
||||||
|
# i = 0
|
||||||
|
# for item in edit_menu_items.keys():
|
||||||
|
# edit_menu.add_item(item, i, edit_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")
|
||||||
|
|
||||||
|
pencil_tool = $UI/ToolPanel/VBoxContainer/ToolsContainer/Pencil
|
||||||
|
eraser_tool = $UI/ToolPanel/VBoxContainer/ToolsContainer/Eraser
|
||||||
|
fill_tool = $UI/ToolPanel/VBoxContainer/ToolsContainer/Fill
|
||||||
|
|
||||||
|
pencil_tool.connect("pressed", self, "_on_Tool_pressed", [pencil_tool])
|
||||||
|
eraser_tool.connect("pressed", self, "_on_Tool_pressed", [eraser_tool])
|
||||||
|
fill_tool.connect("pressed", self, "_on_Tool_pressed", [fill_tool])
|
||||||
|
pencil_tool.hint_tooltip = "P for left mouse button, Alt + P for right mouse button"
|
||||||
|
eraser_tool.hint_tooltip = "E for left mouse button, Alt + E for right mouse button"
|
||||||
|
fill_tool.hint_tooltip = "B for left mouse button, Alt + B for right mouse button"
|
||||||
|
|
||||||
|
func _input(event):
|
||||||
|
#Handle tool shortcuts
|
||||||
|
if event.is_action_pressed("right_pencil_tool"):
|
||||||
|
_on_Tool_pressed(pencil_tool, false, false)
|
||||||
|
elif event.is_action_pressed("left_pencil_tool"):
|
||||||
|
_on_Tool_pressed(pencil_tool, false, true)
|
||||||
|
elif event.is_action_pressed("right_eraser_tool"):
|
||||||
|
_on_Tool_pressed(eraser_tool, false, false)
|
||||||
|
elif event.is_action_pressed("left_eraser_tool"):
|
||||||
|
_on_Tool_pressed(eraser_tool, false, true)
|
||||||
|
elif event.is_action_pressed("right_fill_tool"):
|
||||||
|
_on_Tool_pressed(fill_tool, false, false)
|
||||||
|
elif event.is_action_pressed("left_fill_tool"):
|
||||||
|
_on_Tool_pressed(fill_tool, false, true)
|
||||||
|
|
||||||
|
func file_menu_id_pressed(id : int) -> void:
|
||||||
|
match id:
|
||||||
|
0: #New
|
||||||
|
$CreateNewImage.popup_centered()
|
||||||
|
Global.can_draw = false
|
||||||
|
1: #Import
|
||||||
|
$OpenSprite.popup_centered()
|
||||||
|
Global.can_draw = false
|
||||||
|
opensprite_file_selected = false
|
||||||
|
2: #Export
|
||||||
|
if current_path == "":
|
||||||
|
$SaveSprite.popup_centered()
|
||||||
|
Global.can_draw = false
|
||||||
|
else:
|
||||||
|
save_sprite()
|
||||||
|
3: #Export as
|
||||||
|
$SaveSprite.popup_centered()
|
||||||
|
Global.can_draw = false
|
||||||
|
4: #Quit
|
||||||
|
get_tree().quit()
|
||||||
|
|
||||||
|
func _on_CreateNewImage_confirmed() -> void:
|
||||||
|
var width = float($CreateNewImage/VBoxContainer/WidthCont/LineEdit.text)
|
||||||
|
var height = float($CreateNewImage/VBoxContainer/HeightCont/LineEdit.text)
|
||||||
|
width = clamp(width, 1, 16384)
|
||||||
|
height = clamp(height, 1, 16384)
|
||||||
|
new_canvas(Vector2(width, height).floor())
|
||||||
|
|
||||||
|
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 new_canvas(size : Vector2, sprite : Image = null) -> void:
|
||||||
|
for child in Global.vbox_layer_container.get_children():
|
||||||
|
if child is PanelContainer:
|
||||||
|
child.queue_free()
|
||||||
|
Global.canvas.queue_free()
|
||||||
|
Global.canvas = load("res://Canvas.tscn").instance()
|
||||||
|
Global.canvas.size = size
|
||||||
|
if sprite:
|
||||||
|
Global.canvas.current_sprite = sprite
|
||||||
|
Global.canvas.current_sprite.convert(Image.FORMAT_RGBA8)
|
||||||
|
Global.canvas_parent.add_child(Global.canvas)
|
||||||
|
|
||||||
|
func _on_SaveSprite_file_selected(path : String) -> void:
|
||||||
|
current_path = path
|
||||||
|
save_sprite()
|
||||||
|
|
||||||
|
func save_sprite() -> void:
|
||||||
|
var whole_image := Image.new()
|
||||||
|
whole_image.create(Global.canvas.size.x, Global.canvas.size.y, false, Image.FORMAT_RGBA8)
|
||||||
|
for layer in Global.canvas.layers:
|
||||||
|
whole_image.blend_rect(layer[0], Rect2(Global.canvas.position, Global.canvas.size), Vector2.ZERO)
|
||||||
|
layer[0].lock()
|
||||||
|
#var err = Global.canvas.current_sprite.save_png(current_path)
|
||||||
|
var err = whole_image.save_png(current_path)
|
||||||
|
if err != OK:
|
||||||
|
OS.alert("Can't save file")
|
||||||
|
|
||||||
|
func _on_OpenSprite_popup_hide() -> void:
|
||||||
|
if !opensprite_file_selected:
|
||||||
|
Global.can_draw = true
|
||||||
|
print(Global.can_draw)
|
||||||
|
|
||||||
|
func _on_ViewportContainer_mouse_entered() -> void:
|
||||||
|
Global.has_focus = true
|
||||||
|
|
||||||
|
func _on_ViewportContainer_mouse_exited() -> void:
|
||||||
|
Global.has_focus = false
|
||||||
|
|
||||||
|
func _can_draw_true() -> void:
|
||||||
|
Global.can_draw = true
|
||||||
|
func _can_draw_false() -> void:
|
||||||
|
Global.can_draw = false
|
||||||
|
|
||||||
|
func _on_Tool_pressed(tool_pressed : BaseButton, mouse_press := true, key_for_left := true) -> void:
|
||||||
|
var current_action := tool_pressed.name
|
||||||
|
if (mouse_press && Input.is_action_just_released("left_mouse")) || (!mouse_press && key_for_left):
|
||||||
|
Global.current_left_tool = current_action
|
||||||
|
Global.left_indicator.get_parent().remove_child(Global.left_indicator)
|
||||||
|
tool_pressed.add_child(Global.left_indicator)
|
||||||
|
elif (mouse_press && Input.is_action_just_released("right_mouse")) || (!mouse_press && !key_for_left):
|
||||||
|
Global.current_right_tool = current_action
|
||||||
|
Global.right_indicator.get_parent().remove_child(Global.right_indicator)
|
||||||
|
tool_pressed.add_child(Global.right_indicator)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_ScaleImage_confirmed() -> void:
|
||||||
|
var width = float($ScaleImage/VBoxContainer/WidthCont/LineEdit.text)
|
||||||
|
var height = float($ScaleImage/VBoxContainer/HeightCont/LineEdit.text)
|
||||||
|
width = clamp(width, 1, 16384)
|
||||||
|
height = clamp(height, 1, 16384)
|
||||||
|
#var sprites := []
|
||||||
|
for i in range(Global.canvas.layers.size() - 1, -1, -1):
|
||||||
|
var sprite = Image.new()
|
||||||
|
sprite = Global.canvas.layers[i][1].get_data()
|
||||||
|
sprite.resize(width, height)
|
||||||
|
Global.canvas.layers[i][0] = sprite
|
||||||
|
Global.canvas.layers[i][0].lock()
|
||||||
|
Global.canvas.update_texture(i)
|
||||||
|
|
||||||
|
Global.canvas.size = Vector2(width, height).floor()
|
||||||
|
|
||||||
|
func add_layer(is_new := true) -> void:
|
||||||
|
var new_layer := Image.new()
|
||||||
|
if is_new:
|
||||||
|
new_layer.create(Global.canvas.size.x, Global.canvas.size.y, false, Image.FORMAT_RGBA8)
|
||||||
|
else: #clone layer
|
||||||
|
new_layer.copy_from(Global.canvas.layers[Global.canvas.current_layer_index][0])
|
||||||
|
new_layer.lock()
|
||||||
|
var new_layer_tex := ImageTexture.new()
|
||||||
|
new_layer_tex.create_from_image(new_layer, 0)
|
||||||
|
Global.canvas.layers.append([new_layer, new_layer_tex, null, true])
|
||||||
|
Global.canvas.generate_layer_panels()
|
||||||
|
|
||||||
|
func _on_AddLayerButton_pressed() -> void:
|
||||||
|
add_layer()
|
||||||
|
|
||||||
|
func _on_RemoveLayerButton_pressed() -> void:
|
||||||
|
Global.canvas.layers.remove(Global.canvas.current_layer_index)
|
||||||
|
Global.canvas.generate_layer_panels()
|
||||||
|
|
||||||
|
func _on_MoveUpLayer_pressed() -> void:
|
||||||
|
change_layer_order(1)
|
||||||
|
|
||||||
|
func _on_MoveDownLayer_pressed() -> void:
|
||||||
|
change_layer_order(-1)
|
||||||
|
|
||||||
|
func change_layer_order(rate : int) -> void:
|
||||||
|
var change = Global.canvas.current_layer_index + rate
|
||||||
|
|
||||||
|
var temp = Global.canvas.layers[Global.canvas.current_layer_index]
|
||||||
|
Global.canvas.layers[Global.canvas.current_layer_index] = Global.canvas.layers[change]
|
||||||
|
Global.canvas.layers[change] = temp
|
||||||
|
|
||||||
|
Global.canvas.generate_layer_panels()
|
||||||
|
Global.canvas.current_layer_index = change
|
||||||
|
Global.canvas.get_layer_container(Global.canvas.current_layer_index).changed_selection()
|
||||||
|
|
||||||
|
func _on_CloneLayer_pressed() -> void:
|
||||||
|
add_layer(false)
|
||||||
|
|
||||||
|
func _on_MergeLayer_pressed() -> void:
|
||||||
|
var selected_layer = Global.canvas.layers[Global.canvas.current_layer_index][0]
|
||||||
|
Global.canvas.layers[Global.canvas.current_layer_index - 1][0].blend_rect(selected_layer, Rect2(Global.canvas.position, Global.canvas.size), Vector2.ZERO)
|
||||||
|
Global.canvas.layers[Global.canvas.current_layer_index - 1][0].lock()
|
||||||
|
Global.canvas.update_texture(Global.canvas.current_layer_index - 1)
|
||||||
|
_on_RemoveLayerButton_pressed()
|
BIN
Transparent Background.png
Normal file
After Width: | Height: | Size: 558 B |
13
Transparent Background.png.import
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
[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]
|
||||||
|
|
BIN
default_env.tres
Normal file
55
export_presets.cfg
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
[preset.0]
|
||||||
|
|
||||||
|
name="HTML5"
|
||||||
|
platform="HTML5"
|
||||||
|
runnable=true
|
||||||
|
custom_features=""
|
||||||
|
export_filter="all_resources"
|
||||||
|
include_filter=""
|
||||||
|
exclude_filter=""
|
||||||
|
export_path="C:/Users/Overloaded/Dropbox/Orama Founding Members/εταιρικα αρχεια/Godot Projects/Sprite Editor/Exported/HTML5/Sprite Editor.html"
|
||||||
|
patch_list=PoolStringArray( )
|
||||||
|
script_export_mode=1
|
||||||
|
script_encryption_key=""
|
||||||
|
|
||||||
|
[preset.0.options]
|
||||||
|
|
||||||
|
vram_texture_compression/for_desktop=true
|
||||||
|
vram_texture_compression/for_mobile=false
|
||||||
|
html/custom_html_shell=""
|
||||||
|
html/head_include=""
|
||||||
|
custom_template/release=""
|
||||||
|
custom_template/debug=""
|
||||||
|
|
||||||
|
[preset.1]
|
||||||
|
|
||||||
|
name="Windows Desktop"
|
||||||
|
platform="Windows Desktop"
|
||||||
|
runnable=true
|
||||||
|
custom_features=""
|
||||||
|
export_filter="all_resources"
|
||||||
|
include_filter=""
|
||||||
|
exclude_filter=""
|
||||||
|
export_path="C:/Users/manos/Dropbox/Orama Founding Members/εταιρικα αρχεια/Godot Projects/Sprite Editor/Exported/Sprite Editor.exe"
|
||||||
|
patch_list=PoolStringArray( )
|
||||||
|
script_export_mode=1
|
||||||
|
script_encryption_key=""
|
||||||
|
|
||||||
|
[preset.1.options]
|
||||||
|
|
||||||
|
texture_format/bptc=false
|
||||||
|
texture_format/s3tc=true
|
||||||
|
texture_format/etc=false
|
||||||
|
texture_format/etc2=false
|
||||||
|
texture_format/no_bptc_fallbacks=true
|
||||||
|
binary_format/64_bits=true
|
||||||
|
custom_template/release=""
|
||||||
|
custom_template/debug=""
|
||||||
|
application/icon=""
|
||||||
|
application/file_version=""
|
||||||
|
application/product_version=""
|
||||||
|
application/company_name=""
|
||||||
|
application/product_name=""
|
||||||
|
application/file_description=""
|
||||||
|
application/copyright=""
|
||||||
|
application/trademarks=""
|
34
icon.png.import
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://icon.png"
|
||||||
|
dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.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=true
|
||||||
|
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
|
103
project.godot
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
; Engine configuration file.
|
||||||
|
; It's best edited using the editor UI and not directly,
|
||||||
|
; since the parameters that go here are not all obvious.
|
||||||
|
;
|
||||||
|
; Format:
|
||||||
|
; [section] ; section goes between []
|
||||||
|
; param=value ; assign values to parameters
|
||||||
|
|
||||||
|
config_version=4
|
||||||
|
|
||||||
|
_global_script_classes=[ {
|
||||||
|
"base": "Node2D",
|
||||||
|
"class": "Canvas",
|
||||||
|
"language": "GDScript",
|
||||||
|
"path": "res://Scripts/Canvas.gd"
|
||||||
|
}, {
|
||||||
|
"base": "Node2D",
|
||||||
|
"class": "CanvasOLD",
|
||||||
|
"language": "GDScript",
|
||||||
|
"path": "res://Scripts/Old/Canvas.gd"
|
||||||
|
} ]
|
||||||
|
_global_script_class_icons={
|
||||||
|
"Canvas": "",
|
||||||
|
"CanvasOLD": ""
|
||||||
|
}
|
||||||
|
|
||||||
|
[application]
|
||||||
|
|
||||||
|
config/name="Pixelorama"
|
||||||
|
run/main_scene="res://Main.tscn"
|
||||||
|
config/icon="res://icon.png"
|
||||||
|
|
||||||
|
[autoload]
|
||||||
|
|
||||||
|
Global="*res://Scripts/Global.gd"
|
||||||
|
|
||||||
|
[debug]
|
||||||
|
|
||||||
|
gdscript/warnings/return_value_discarded=false
|
||||||
|
|
||||||
|
[input]
|
||||||
|
|
||||||
|
zoom_in={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":4,"pressed":false,"doubleclick":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
zoom_out={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":5,"pressed":false,"doubleclick":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
camera_drag={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":3,"pressed":false,"doubleclick":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
left_mouse={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":1,"pressed":false,"doubleclick":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
right_mouse={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":2,"pressed":false,"doubleclick":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
left_pencil_tool={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":80,"unicode":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
right_pencil_tool={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":true,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":80,"unicode":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
left_eraser_tool={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":69,"unicode":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
right_eraser_tool={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":true,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":69,"unicode":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
left_fill_tool={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":66,"unicode":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
right_fill_tool={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":true,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":66,"unicode":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
[rendering]
|
||||||
|
|
||||||
|
quality/driver/driver_name="GLES2"
|
||||||
|
vram_compression/import_etc=true
|
||||||
|
vram_compression/import_etc2=false
|