diff --git a/.gitignore b/.gitignore index 852a042..841dbac 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ mono_crash.*.json *.x86_64 godot.*.template_release.* dist/* +!dist/.gitkeep screenshot.png.import diff --git a/README.md b/README.md index a12517b..c658569 100644 --- a/README.md +++ b/README.md @@ -3,15 +3,7 @@ ![screenshot](./screenshot.png) -

An image editing/compositing software for graphics programmers.

- -## Table of Contents - -- [Supported Platforms](#supported-platforms) -- [Usage](#usage) -- [Shaderlib](#shaderlib) -- [Commandline interface](#commandline-interface) -- [Known Issues](#known-issues) +

Create image filters by writing shaders.

## Supported Platforms @@ -21,16 +13,8 @@ You can find the latest releases [here](https://github.com/ChaoticByte/Fragmente ## Usage -With Fragemented, you are processing images with GDShaders. This brings almost endless opportunities to create unique art. -If you want to learn GDShader, take a look at the [Godot docs](https://docs.godotengine.org/en/stable/tutorials/shaders/). - -**The builtin editor got removed** from Fragmented with version **v9.0**. I advise you to write your shaders directly in the Godot Editor. - -**To get started, use the project template (see the Releases section of this repo) and open it in Godot.** - -The template includes many examples. You can use them as a starting-point to write your own stuff. - -Besides the regular GDShader stuff, Fragmented has so-called directives. Those allow to further control the behaviour of the application. **The most important directive is `//!load` to load an image.** +The repo includes examples. You can use them as a starting-point to write your own filters. +Just load an image using `//!load`, edit the shader code and hit `F5` to see the changes. ### Load TEXTURE using the `//!load` directive @@ -62,17 +46,13 @@ Example: //!load ... //!steps 5 -uniform int STEP; -uniform int STEPS; - void fragment() { if (STEP == 0) { - ... + ... } else if (STEP == 1) { - ... - } else if (STEP == STEPS-1) { - ... + ... } + // ... and so on } ``` @@ -86,15 +66,12 @@ Here is an example: ```glsl shader_type canvas_item; -#include "./shaderlib/oklab.gdshaderinc" +#include "res://shaderlib/hsv.gdshaderinc" -//!load ./images/swamp.jpg +//!load ./examples/images/swamp.jpg void fragment() { - vec4 oklab = rgb2oklab(COLOR); - vec4 oklch = oklab2oklch(oklab); - oklch.z -= 2.0; - COLOR = oklab2rgb(oklch2oklab(oklch)); + COLOR = hsv_offset(COLOR, 0.32, 0.2, 0.0); } ``` @@ -107,50 +84,23 @@ You can run Fragmented from the commandline or scripts. ### Usage ``` -~ Fragmented CLI ~ --================- +./Fragmented cmd --shader PATH [--load-image PATH] -Usage: - -./Fragmented - -Commands: - - help - - | Shows this help text. - - apply --shader PATH [--load-image PATH] - - | Applies a shader file. - - --shader PATH The path to the shader - --output PATH Where to write the resulting image to. - In batch mode, this must be a folder. - --load-image PATH The path to the image. This will overwrite the - load directive of the shader file. - Passing a folder activates batch mode. - (optional) + --shader PATH The path to the shader + --output PATH Where to write the resulting image to + --load-image PATH The path to the image. This will overwrite the + load directive of the shader file (optional) ``` -### Batch Mode - -Since version v8.0, you can pass a directory to `--load-image` and `--output`. This will process all images in the input directory and write the output to the output directory. - -> Note: You *can* use this feature for video frames, but it will take a loooong time. +You can also run `./Fragmented cmd help` to show the help message. #### Examples ``` -./Fragmented apply --shader ./examples/oklab.gdshader --output ./output.png +./Fragmented cmd --shader ./examples/oklab.gdshader --output ./output.png ``` ``` -./Fragmented apply --shader ./examples/oklab.gdshader --load-image ~/Pictures/test.png --output ./output.png +./Fragmented cmd --shader ./examples/oklab.gdshader --load-image ~/Pictures/test.png --output ./output.png ``` - -## Known Issues - -- screen scaling is unsupported; Using screen scaling could lead to an either blurry UI, or no scaling at all -> see #45 -- commandline interface: `--headless` is not supported diff --git a/src/assets/error.svg b/assets/error.svg similarity index 100% rename from src/assets/error.svg rename to assets/error.svg diff --git a/src/assets/error.svg.import b/assets/error.svg.import similarity index 76% rename from src/assets/error.svg.import rename to assets/error.svg.import index 368b3a5..07666be 100644 --- a/src/assets/error.svg.import +++ b/assets/error.svg.import @@ -3,15 +3,15 @@ importer="texture" type="CompressedTexture2D" uid="uid://04iv1gogpuhu" -path="res://.godot/imported/error.svg-28fb29635cf59d39cabf7052619f602f.ctex" +path="res://.godot/imported/error.svg-75fe5f417585e01e99de8885f1f45c3b.ctex" metadata={ "vram_texture": false } [deps] -source_file="res://src/assets/error.svg" -dest_files=["res://.godot/imported/error.svg-28fb29635cf59d39cabf7052619f602f.ctex"] +source_file="res://assets/error.svg" +dest_files=["res://.godot/imported/error.svg-75fe5f417585e01e99de8885f1f45c3b.ctex"] [params] diff --git a/src/assets/icon.png b/assets/icon.png similarity index 100% rename from src/assets/icon.png rename to assets/icon.png diff --git a/src/assets/icon.png.import b/assets/icon.png.import similarity index 73% rename from src/assets/icon.png.import rename to assets/icon.png.import index d1a6196..ce38ae5 100644 --- a/src/assets/icon.png.import +++ b/assets/icon.png.import @@ -3,15 +3,15 @@ importer="texture" type="CompressedTexture2D" uid="uid://kqwc4avs2xdp" -path="res://.godot/imported/icon.png-d8298ab6eda392a806be6bb7eec65b9c.ctex" +path="res://.godot/imported/icon.png-b6a7fb2db36edd3d95dc42f1dc8c1c5d.ctex" metadata={ "vram_texture": false } [deps] -source_file="res://src/assets/icon.png" -dest_files=["res://.godot/imported/icon.png-d8298ab6eda392a806be6bb7eec65b9c.ctex"] +source_file="res://assets/icon.png" +dest_files=["res://.godot/imported/icon.png-b6a7fb2db36edd3d95dc42f1dc8c1c5d.ctex"] [params] diff --git a/src/assets/okay.svg b/assets/okay.svg similarity index 100% rename from src/assets/okay.svg rename to assets/okay.svg diff --git a/src/assets/okay.svg.import b/assets/okay.svg.import similarity index 76% rename from src/assets/okay.svg.import rename to assets/okay.svg.import index e1631da..6b6c11f 100644 --- a/src/assets/okay.svg.import +++ b/assets/okay.svg.import @@ -3,15 +3,15 @@ importer="texture" type="CompressedTexture2D" uid="uid://m1omb6g45vst" -path="res://.godot/imported/okay.svg-de66a022ef37753b085371b7c60aefd1.ctex" +path="res://.godot/imported/okay.svg-7f6df15523471a86f27b6817e9528a4e.ctex" metadata={ "vram_texture": false } [deps] -source_file="res://src/assets/okay.svg" -dest_files=["res://.godot/imported/okay.svg-de66a022ef37753b085371b7c60aefd1.ctex"] +source_file="res://assets/okay.svg" +dest_files=["res://.godot/imported/okay.svg-7f6df15523471a86f27b6817e9528a4e.ctex"] [params] diff --git a/build-template/Containerfile b/build-template/Containerfile index b1a0c48..38d31a7 100644 --- a/build-template/Containerfile +++ b/build-template/Containerfile @@ -7,14 +7,15 @@ FROM docker.io/ubuntu:focal AS os-base # https://docs.godotengine.org/en/stable/contributing/development/compiling/compiling_for_linuxbsd.html RUN apt-get update -RUN DEBIAN_FRONTEND=noninteractive apt-get install -yq python3-pip git build-essential pkg-config libx11-dev libxcursor-dev libxinerama-dev libgl1-mesa-dev libglu1-mesa-dev libasound2-dev libpulse-dev libudev-dev libxi-dev libxrandr-dev libwayland-dev -RUN pip3 install --system scons +RUN DEBIAN_FRONTEND=noninteractive apt-get install -yq build-essential scons pkg-config libx11-dev libxcursor-dev libxinerama-dev libgl1-mesa-dev libglu1-mesa-dev libasound2-dev libpulse-dev libudev-dev libxi-dev libxrandr-dev libwayland-dev + +RUN DEBIAN_FRONTEND=noninteractive apt-get install -yq git FROM os-base AS clone-src -RUN git clone https://github.com/godotengine/godot.git -b 4.4-stable /godot-src +RUN git clone https://github.com/godotengine/godot.git -b 4.3-stable /godot-src FROM clone-src WORKDIR /godot-src -ENTRYPOINT scons platform=linuxbsd target=template_release lto=full optimize=size disable_3d=yes module_text_server_adv_enabled=no module_text_server_fb_enabled=yes module_basis_universal_enabled=no module_csg_enabled=no module_enet_enabled=no module_gridmap_enabled=no module_jsonrpc_enabled=no module_mbedtls_enabled=no module_meshoptimizer_enabled=no module_minimp3_enabled=no module_mobile_vr_enabled=no module_msdfgen_enabled=no module_multiplayer_enabled=no module_navigation_enabled=no module_ogg_enabled=no module_openxr_enabled=no module_raycast_enabled=no module_squish_enabled=no module_theora_enabled=no module_upnp_enabled=no module_vhacd_enabled=no module_vorbis_enabled=no module_webrtc_enabled=no module_websocket_enabled=no module_webxr_enabled=no arch=x86_64 && strip bin/godot.linuxbsd.template_release.x86_64 +ENTRYPOINT scons platform=linuxbsd target=template_release lto=full optimize=size disable_3d=yes module_text_server_adv_enabled=no module_text_server_fb_enabled=yes module_basis_universal_enabled=no module_csg_enabled=no module_dds_enabled=no module_enet_enabled=no module_gridmap_enabled=no module_hdr_enabled=no module_jsonrpc_enabled=no module_ktx_enabled=no module_mbedtls_enabled=no module_meshoptimizer_enabled=no module_minimp3_enabled=no module_mobile_vr_enabled=no module_msdfgen_enabled=no module_multiplayer_enabled=no module_navigation_enabled=no module_ogg_enabled=no module_openxr_enabled=no module_raycast_enabled=no module_squish_enabled=no module_svg_enabled=no module_tga_enabled=no module_theora_enabled=no module_tinyexr_enabled=no module_upnp_enabled=no module_vhacd_enabled=no module_vorbis_enabled=no module_webrtc_enabled=no module_websocket_enabled=no module_webxr_enabled=no module_zip_enabled=no arch=x86_64 && strip bin/godot.linuxbsd.template_release.x86_64 diff --git a/build-template/build.sh b/build-template/build.sh index feff902..5541b7c 100755 --- a/build-template/build.sh +++ b/build-template/build.sh @@ -3,12 +3,12 @@ set -e function log { - echo -e "\033[1;36m***** $@ *****\033[0m" + echo -e "\033[1;36m* $@\033[0m" } -log " " +log log "Fragmented - Godot Build Template Builder" -log " " +log cd $(dirname $0) log Switched to $(pwd) diff --git a/dist.sh b/dist.sh deleted file mode 100755 index 3b44438..0000000 --- a/dist.sh +++ /dev/null @@ -1,30 +0,0 @@ -set -e - -function log { - echo -e "\033[1;36m***** $@ *****\033[0m" -} - -mkdir -p dist - -log Building application - -VERSION="$(godot --headless --no-header -s tools/get_version.gd)" - -godot --headless --export-release "Linux/X11" "dist/Fragmented-${VERSION}.x86_64" - -log Packing shaderlib - -ZIP_PATH_SHADERLIB=$(realpath "dist/Fragmented-${VERSION}_shaderlib.zip") - -zip -r "${ZIP_PATH_SHADERLIB}" shaderlib/ - -log Packing project template - -ZIP_PATH_PROJECT_TEMPLATE=$(realpath "dist/Fragmented-${VERSION}_project_template.zip") - -rm -f "${ZIP_PATH_PROJECT_TEMPLATE}" -( - cd examples/ - mv project.godot_ project.godot && trap "mv project.godot project.godot_" EXIT - zip -r "${ZIP_PATH_PROJECT_TEMPLATE}" * -) diff --git a/dist/.gitkeep b/dist/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/examples/0_empty.tscn b/examples/0_empty.tscn deleted file mode 100644 index 5fa71b9..0000000 --- a/examples/0_empty.tscn +++ /dev/null @@ -1,3 +0,0 @@ -[gd_scene format=3 uid="uid://db2rhq8rwv5wo"] - -[node name="Node" type="Node"] diff --git a/examples/blur.gdshader b/examples/blur.gdshader index fa4d87d..8d08069 100644 --- a/examples/blur.gdshader +++ b/examples/blur.gdshader @@ -1,7 +1,7 @@ shader_type canvas_item; //!load ./images/swamp.jpg -#include "./shaderlib/blur.gdshaderinc" +#include "res://shaderlib/blur.gdshaderinc" void fragment() { COLOR = gaussian_blur(TEXTURE, UV, 48, 24.0); diff --git a/examples/blur.gdshader.uid b/examples/blur.gdshader.uid deleted file mode 100644 index 3739afe..0000000 --- a/examples/blur.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cny8dtukv54wt diff --git a/examples/channel_offset.gdshader.uid b/examples/channel_offset.gdshader.uid deleted file mode 100644 index 66e7cef..0000000 --- a/examples/channel_offset.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://0efk4fornlg6 diff --git a/examples/color_and_pixelate.gdshader b/examples/color_and_pixelate.gdshader index f490db4..bf5f18a 100644 --- a/examples/color_and_pixelate.gdshader +++ b/examples/color_and_pixelate.gdshader @@ -1,7 +1,7 @@ shader_type canvas_item; -#include "./shaderlib/hsv.gdshaderinc" -#include "./shaderlib/pixelate.gdshaderinc" +#include "res://shaderlib/colorspaces.gdshaderinc" +#include "res://shaderlib/effects.gdshaderinc" //!load ./images/swamp.jpg diff --git a/examples/color_and_pixelate.gdshader.uid b/examples/color_and_pixelate.gdshader.uid deleted file mode 100644 index d943067..0000000 --- a/examples/color_and_pixelate.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://gd23hu7ro148 diff --git a/examples/denoise.gdshader b/examples/denoise.gdshader index 229a8da..09dabb6 100644 --- a/examples/denoise.gdshader +++ b/examples/denoise.gdshader @@ -2,7 +2,7 @@ shader_type canvas_item; //!load ./images/noisy.png -#include "./shaderlib/denoise.gdshaderinc" +#include "res://shaderlib/denoise.gdshaderinc" void fragment() { COLOR = smart_denoise(TEXTURE, UV, 12.0, 1.0, .12); diff --git a/examples/denoise.gdshader.uid b/examples/denoise.gdshader.uid deleted file mode 100644 index 9337646..0000000 --- a/examples/denoise.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cbwyneu03fki6 diff --git a/examples/greyscale.gdshader.uid b/examples/greyscale.gdshader.uid deleted file mode 100644 index b6e1bbd..0000000 --- a/examples/greyscale.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dvarqolt6es27 diff --git a/examples/images/CREDITS.md b/examples/images/CREDITS.md index d662b8c..ed427c8 100644 --- a/examples/images/CREDITS.md +++ b/examples/images/CREDITS.md @@ -3,4 +3,3 @@ - swamp.jpg by [clfr21 on Pixabay](https://pixabay.com/de/users/clfr21-6530007/) - grass.png by [GDJ on Pixabay](https://pixabay.com/users/gdj-1086657/) -- mountain.jpg by [Phghvvcftyyufj on Pixabay](https://pixabay.com/users/phghvvcftyyufj-12646982) diff --git a/examples/images/mountain.jpg b/examples/images/mountain.jpg deleted file mode 100644 index 591c06d..0000000 Binary files a/examples/images/mountain.jpg and /dev/null differ diff --git a/examples/images/mountain.jpg.import b/examples/images/mountain.jpg.import deleted file mode 100644 index e914676..0000000 --- a/examples/images/mountain.jpg.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ben72llmopgaj" -path="res://.godot/imported/mountain.jpg-c1b7de1e6557b826bc6f9324027e11af.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://examples/images/mountain.jpg" -dest_files=["res://.godot/imported/mountain.jpg-c1b7de1e6557b826bc6f9324027e11af.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/examples/kuwahara.gdshader b/examples/kuwahara.gdshader deleted file mode 100644 index 246e162..0000000 --- a/examples/kuwahara.gdshader +++ /dev/null @@ -1,16 +0,0 @@ -shader_type canvas_item; - -//!load ./images/mountain.jpg - -#include "./shaderlib/kuwahara.gdshaderinc" -#include "./shaderlib/hsv.gdshaderinc" - -void fragment() { - // Kuwahara - COLOR.rgb = kuwahara(TEXTURE, UV, 20, 80.0, 18.0, 0.6, .15, 8); - // A litte bit of color adjustments - vec4 hsv = rgb2hsv(COLOR); - hsv.x += .03; - hsv.y *= 1.4; - COLOR = hsv2rgb(hsv); -} diff --git a/examples/kuwahara.gdshader.uid b/examples/kuwahara.gdshader.uid deleted file mode 100644 index 2e0241a..0000000 --- a/examples/kuwahara.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cdhyuk7u8kxyk diff --git a/examples/lowpass.gdshader.uid b/examples/lowpass.gdshader.uid deleted file mode 100644 index 80b19c7..0000000 --- a/examples/lowpass.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dn02xsjm1kok8 diff --git a/examples/multistep_distort.gdshader b/examples/multistep_distort.gdshader index fd7883e..cea638f 100644 --- a/examples/multistep_distort.gdshader +++ b/examples/multistep_distort.gdshader @@ -3,8 +3,6 @@ shader_type canvas_item; //!steps 9 //!load ./images/swamp.jpg -uniform int STEP; - const float strength = 0.01; void fragment() { diff --git a/examples/multistep_distort.gdshader.uid b/examples/multistep_distort.gdshader.uid deleted file mode 100644 index 22efbc6..0000000 --- a/examples/multistep_distort.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c17u5jx7a7o81 diff --git a/examples/multistep_pixelsort.gdshader b/examples/multistep_pixelsort.gdshader deleted file mode 100644 index 21ba1b6..0000000 --- a/examples/multistep_pixelsort.gdshader +++ /dev/null @@ -1,20 +0,0 @@ -shader_type canvas_item; - -#include "./shaderlib/pixelsort.gdshaderinc" - -//!steps 1500 -uniform int STEP; - -//!load ./images/mountain.jpg - -void fragment() { - // pixel sorting works in multiple steps - COLOR = pixelsort_step( - TEXTURE, UV, - DIRECTION_BOTTOM_TO_TOP, - COLOR_MODE_OKLCH, - {true, false, false}, - {-INF, .007, -INF}, - {INF, INF, INF}, - STEP); -} diff --git a/examples/multistep_pixelsort.gdshader.uid b/examples/multistep_pixelsort.gdshader.uid deleted file mode 100644 index 47eaaf5..0000000 --- a/examples/multistep_pixelsort.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://csk0fg4by651b diff --git a/examples/oklab.gdshader b/examples/oklab.gdshader index 08f46b5..0d8f093 100644 --- a/examples/oklab.gdshader +++ b/examples/oklab.gdshader @@ -1,6 +1,6 @@ shader_type canvas_item; -#include "./shaderlib/oklab.gdshaderinc" +#include "res://shaderlib/colorspaces.gdshaderinc" //!load ./images/swamp.jpg diff --git a/examples/oklab.gdshader.uid b/examples/oklab.gdshader.uid deleted file mode 100644 index 87cef6b..0000000 --- a/examples/oklab.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cu37y8lc0x83 diff --git a/examples/place_texture.gdshader b/examples/place_texture.gdshader index b0c50ca..183d080 100644 --- a/examples/place_texture.gdshader +++ b/examples/place_texture.gdshader @@ -1,7 +1,7 @@ shader_type canvas_item; -#include "./shaderlib/place_texture.gdshaderinc" -#include "./shaderlib/common.gdshaderinc" +#include "res://shaderlib/transform.gdshaderinc" +#include "res://shaderlib/transparency.gdshaderinc" //!load ./images/swamp.jpg //!load+ img2 ./images/grass.png diff --git a/examples/place_texture.gdshader.uid b/examples/place_texture.gdshader.uid deleted file mode 100644 index 8ced27b..0000000 --- a/examples/place_texture.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dybe4t5rbbkc6 diff --git a/examples/project.godot_ b/examples/project.godot_ deleted file mode 100644 index 5eff383..0000000 --- a/examples/project.godot_ +++ /dev/null @@ -1,15 +0,0 @@ -; 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=5 - -[application] - -config/name="Fragmented Project" -run/main_scene="res://0_empty.tscn" -config/features=PackedStringArray("4.4", "Forward Plus") diff --git a/examples/shaderlib b/examples/shaderlib deleted file mode 120000 index dedec01..0000000 --- a/examples/shaderlib +++ /dev/null @@ -1 +0,0 @@ -../shaderlib \ No newline at end of file diff --git a/examples/sobel.gdshader b/examples/sobel.gdshader deleted file mode 100644 index 3a7a8b5..0000000 --- a/examples/sobel.gdshader +++ /dev/null @@ -1,10 +0,0 @@ -shader_type canvas_item; - -//!load ./images/noisy.png - -#include "./shaderlib/sobel.gdshaderinc" - -void fragment() { - // Sobel Filter - COLOR = sobel(TEXTURE, UV); -} diff --git a/examples/sobel.gdshader.uid b/examples/sobel.gdshader.uid deleted file mode 100644 index 33b657a..0000000 --- a/examples/sobel.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://h376mk1fq4ky diff --git a/export_presets.cfg b/export_presets.cfg index 79a474d..f4ce4eb 100644 --- a/export_presets.cfg +++ b/export_presets.cfg @@ -8,12 +8,10 @@ dedicated_server=false custom_features="" export_filter="all_resources" include_filter="" -exclude_filter="screenshot.png, examples/*, shaderlib/*, tools/*, build-template/*" +exclude_filter="screenshot.png, examples/*" export_path="dist/Fragmented.x86_64" -patches=PackedStringArray() encryption_include_filters="" encryption_exclude_filters="" -seed=0 encrypt_pck=false encrypt_directory=false script_export_mode=2 diff --git a/project.godot b/project.godot index 95da5af..a8dffd7 100644 --- a/project.godot +++ b/project.godot @@ -11,10 +11,11 @@ config_version=5 [application] config/name="Fragmented" -config/version="v10.2" -run/main_scene="res://src/scenes/main.tscn" -config/features=PackedStringArray("4.4", "Mobile") -config/icon="res://src/assets/icon.png" +config/version="v7.0" +run/main_scene="res://scenes/main.tscn" +config/features=PackedStringArray("4.3", "Mobile") +run/low_processor_mode=true +config/icon="res://assets/icon.png" [autoload] @@ -23,10 +24,11 @@ ShaderDirectiveParser="*res://src/ShaderDirectiveParser.gd" [display] -window/size/viewport_width=640 -window/size/viewport_height=672 +window/size/viewport_width=704 +window/size/viewport_height=704 window/energy_saving/keep_screen_on=false window/subwindows/embed_subwindows=false +window/vsync/vsync_mode=0 [editor_plugins] @@ -70,4 +72,4 @@ renderer/rendering_method="mobile" textures/vram_compression/import_etc2_astc=true textures/lossless_compression/force_png=true shader_compiler/shader_cache/enabled=false -environment/defaults/default_clear_color=Color(0.501961, 0.501961, 0.501961, 1) +environment/defaults/default_clear_color=Color(0, 0, 0, 1) diff --git a/scenes/main.tscn b/scenes/main.tscn new file mode 100644 index 0000000..2d104a3 --- /dev/null +++ b/scenes/main.tscn @@ -0,0 +1,46 @@ +[gd_scene load_steps=10 format=3 uid="uid://bjah7k4bxo044"] + +[ext_resource type="Script" path="res://src/Main.gd" id="1_2625y"] +[ext_resource type="Script" path="res://src/ImageCompositor.gd" id="2_4thch"] +[ext_resource type="Shader" path="res://src/shader/ivd_outline.gdshader" id="3_6xihe"] +[ext_resource type="Script" path="res://src/ImageViewportDisplay.gd" id="3_n4itb"] +[ext_resource type="Script" path="res://src/UIWindow.gd" id="6_8k0ha"] +[ext_resource type="PackedScene" uid="uid://btgits2mfup0h" path="res://scenes/ui_container.tscn" id="7_5ci0e"] +[ext_resource type="Script" path="res://src/Camera.gd" id="8_mls06"] + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_y2ea0"] +shader = ExtResource("3_6xihe") +shader_parameter/zoom_level = Vector2(1, 1) + +[sub_resource type="ViewportTexture" id="ViewportTexture_lct1c"] +viewport_path = NodePath("Compositor") + +[node name="Main" type="Node2D"] +script = ExtResource("1_2625y") + +[node name="Compositor" type="SubViewport" parent="."] +unique_name_in_owner = true +script = ExtResource("2_4thch") + +[node name="ImageViewportDisplay" type="Sprite2D" parent="."] +unique_name_in_owner = true +material = SubResource("ShaderMaterial_y2ea0") +texture = SubResource("ViewportTexture_lct1c") +script = ExtResource("3_n4itb") + +[node name="Camera" type="Camera2D" parent="."] +unique_name_in_owner = true +script = ExtResource("8_mls06") + +[node name="EditorWindow" type="Window" parent="."] +unique_name_in_owner = true +disable_3d = true +position = Vector2i(48, 36) +size = Vector2i(704, 704) +visible = false +script = ExtResource("6_8k0ha") + +[node name="UserInterfaceContainer" parent="EditorWindow" instance=ExtResource("7_5ci0e")] +unique_name_in_owner = true + +[connection signal="close_requested" from="EditorWindow" to="EditorWindow" method="_on_close_requested"] diff --git a/scenes/ui_container.tscn b/scenes/ui_container.tscn new file mode 100644 index 0000000..6be4c94 --- /dev/null +++ b/scenes/ui_container.tscn @@ -0,0 +1,204 @@ +[gd_scene load_steps=3 format=3 uid="uid://btgits2mfup0h"] + +[ext_resource type="Script" path="res://src/UIAppVersion.gd" id="1_5qvnb"] +[ext_resource type="Script" path="res://src/Editor.gd" id="2_haub5"] + +[node name="UserInterfaceContainer" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="AppName" type="Label" parent="."] +layout_mode = 0 +offset_left = 24.0 +offset_top = 16.0 +offset_right = 208.0 +offset_bottom = 48.0 +theme_override_font_sizes/font_size = 20 +text = "Fragmented" +vertical_alignment = 2 + +[node name="AppVersion" type="Label" parent="."] +layout_mode = 0 +offset_left = 152.0 +offset_top = 17.0 +offset_right = 208.0 +offset_bottom = 47.0 +theme_override_font_sizes/font_size = 14 +text = "v0 +" +vertical_alignment = 2 +script = ExtResource("1_5qvnb") + +[node name="Editor" type="Control" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 24.0 +offset_top = 64.0 +offset_right = -24.0 +offset_bottom = -16.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("2_haub5") + +[node name="OpenShaderDialog" type="FileDialog" parent="Editor"] +unique_name_in_owner = true +auto_translate_mode = 1 +title = "Load Shader" +size = Vector2i(521, 175) +ok_button_text = "Open" +mode_overrides_title = false +file_mode = 0 +access = 2 +filters = PackedStringArray("*.gdshader") +use_native_dialog = true + +[node name="SaveShaderDialog" type="FileDialog" parent="Editor"] +unique_name_in_owner = true +auto_translate_mode = 1 +title = "Save Shader" +size = Vector2i(661, 175) +ok_button_text = "Save" +mode_overrides_title = false +access = 2 +filters = PackedStringArray("*.gdshader") +use_native_dialog = true + +[node name="SaveImageDialog" type="FileDialog" parent="Editor"] +unique_name_in_owner = true +auto_translate_mode = 1 +title = "Export Image" +size = Vector2i(661, 175) +ok_button_text = "Save" +mode_overrides_title = false +access = 2 +filters = PackedStringArray("*.png") +use_native_dialog = true + +[node name="CodeEdit" type="CodeEdit" parent="Editor"] +unique_name_in_owner = true +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_top = 48.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_font_sizes/font_size = 14 +placeholder_text = "// Test" +wrap_mode = 1 +minimap_draw = true +minimap_width = 40 +caret_blink = true +draw_control_chars = true +draw_tabs = true +draw_spaces = true +line_length_guidelines = Array[int]([80]) +gutters_draw_line_numbers = true +code_completion_enabled = true +indent_automatic = true +auto_brace_completion_enabled = true +auto_brace_completion_highlight_matching = true + +[node name="NewShaderButton" type="Button" parent="Editor"] +layout_mode = 1 +offset_right = 48.0 +offset_bottom = 32.0 +text = "New" + +[node name="OpenShaderButton" type="Button" parent="Editor"] +layout_mode = 1 +offset_left = 56.0 +offset_right = 112.0 +offset_bottom = 32.0 +text = "Open" + +[node name="SaveShaderButton" type="Button" parent="Editor"] +layout_mode = 1 +offset_left = 120.0 +offset_top = -1.0 +offset_right = 176.0 +offset_bottom = 31.0 +text = "Save" + +[node name="SaveShaderAsButton" type="Button" parent="Editor"] +layout_mode = 1 +offset_left = 184.0 +offset_right = 263.0 +offset_bottom = 32.0 +text = "Save As" + +[node name="SaveImageButton" type="Button" parent="Editor"] +unique_name_in_owner = true +layout_mode = 1 +anchors_preset = 1 +anchor_left = 1.0 +anchor_right = 1.0 +offset_left = -72.0 +offset_bottom = 32.0 +grow_horizontal = 0 +disabled = true +text = "Export" + +[node name="FitImageButton" type="Button" parent="Editor"] +layout_mode = 1 +anchors_preset = 1 +anchor_left = 1.0 +anchor_right = 1.0 +offset_left = -128.0 +offset_right = -80.0 +offset_bottom = 32.0 +grow_horizontal = 0 +text = "Fit" + +[node name="ApplyShaderButton" type="Button" parent="Editor"] +layout_mode = 1 +anchors_preset = 1 +anchor_left = 1.0 +anchor_right = 1.0 +offset_left = -232.0 +offset_right = -136.0 +offset_bottom = 31.0 +grow_horizontal = 0 +text = "Apply (F5)" + +[node name="StatusIndicator" type="TextureButton" parent="Editor"] +unique_name_in_owner = true +layout_mode = 1 +anchors_preset = 1 +anchor_left = 1.0 +anchor_right = 1.0 +offset_left = -76.0 +offset_top = 56.0 +offset_right = -56.0 +offset_bottom = 76.0 +grow_horizontal = 0 +disabled = true +ignore_texture_size = true +stretch_mode = 0 + +[node name="ErrorMessageDialog" type="AcceptDialog" parent="Editor"] +unique_name_in_owner = true +title = "Status" +initial_position = 2 +size = Vector2i(256, 128) +popup_window = true +ok_button_text = "Close" + +[connection signal="file_selected" from="Editor/OpenShaderDialog" to="Editor" method="_on_open_shader_dialog_file_selected"] +[connection signal="file_selected" from="Editor/SaveShaderDialog" to="Editor" method="_on_save_shader_dialog_file_selected"] +[connection signal="file_selected" from="Editor/SaveImageDialog" to="Editor" method="_on_save_image_dialog_file_selected"] +[connection signal="code_completion_requested" from="Editor/CodeEdit" to="Editor" method="_on_code_edit_code_completion_requested"] +[connection signal="pressed" from="Editor/NewShaderButton" to="Editor" method="_on_new_shader_button_pressed"] +[connection signal="pressed" from="Editor/OpenShaderButton" to="Editor" method="_on_open_shader_button_pressed"] +[connection signal="pressed" from="Editor/SaveShaderButton" to="Editor" method="_on_save_shader_button_pressed"] +[connection signal="pressed" from="Editor/SaveShaderAsButton" to="Editor" method="_on_save_shader_as_button_pressed"] +[connection signal="pressed" from="Editor/SaveImageButton" to="Editor" method="_on_save_image_button_pressed"] +[connection signal="pressed" from="Editor/FitImageButton" to="Editor" method="_on_fit_image_button_pressed"] +[connection signal="pressed" from="Editor/ApplyShaderButton" to="Editor" method="_on_apply_shader_button_pressed"] +[connection signal="pressed" from="Editor/StatusIndicator" to="Editor" method="_on_status_indicator_pressed"] diff --git a/screenshot.png b/screenshot.png index ce0ac8a..19fb490 100644 Binary files a/screenshot.png and b/screenshot.png differ diff --git a/shaderlib/blur.gdshaderinc.uid b/shaderlib/blur.gdshaderinc.uid deleted file mode 100644 index d5c8dfd..0000000 --- a/shaderlib/blur.gdshaderinc.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bjtljvcjcu6dr diff --git a/shaderlib/oklab.gdshaderinc b/shaderlib/colorspaces.gdshaderinc similarity index 62% rename from shaderlib/oklab.gdshaderinc rename to shaderlib/colorspaces.gdshaderinc index 5a456c7..6a8ae9b 100644 --- a/shaderlib/oklab.gdshaderinc +++ b/shaderlib/colorspaces.gdshaderinc @@ -1,19 +1,43 @@ +/* + Color space conversion functions always work with vec4. + The fourth value is always alpha. +*/ + +#include "res://shaderlib/common.gdshaderinc" + +/* + rgb2hsv and hsv2rgb functions adapted + from https://godotshaders.com/shader/hsv-adjustment/ + original code by https://godotshaders.com/author/al1-ce/ +*/ + +// Convert RGB to HSV (hue, saturation, brightness) +vec4 rgb2hsv(vec4 c) { + vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return vec4(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x, c.a); +} + +// Convert HSV back to RGB (red, green, blue) +vec4 hsv2rgb(vec4 c) { + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + vec3 rgb = c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); + return vec4(rgb.r, rgb.g, rgb.b, c.a); +} + /* OkLab and OkLCh For more details on oklab, see - https://bottosson.github.io/posts/oklab/ - https://en.wikipedia.org/wiki/Oklab_color_space - - Color space conversion functions always work with vec4. - The fourth value is always alpha. */ -#include "./common.gdshaderinc" - vec4 rgb2oklab(vec4 c) { - // oklab.x and .y (a and b) should range from -0.5 to 0.5 - float l = 0.4122214708f * c.r + 0.5363325363f * c.g + 0.0514459929f * c.b; float m = 0.2119034982f * c.r + 0.6806995451f * c.g + 0.1073969566f * c.b; float s = 0.0883024619f * c.r + 0.2817188376f * c.g + 0.6299787005f * c.b; @@ -31,8 +55,6 @@ vec4 rgb2oklab(vec4 c) { } vec4 oklab2rgb(vec4 c) { - // oklab.x and .y (a and b) should range from -0.5 to 0.5 - float l_ = c.x + 0.3963377774f * c.y + 0.2158037573f * c.z; float m_ = c.x - 0.1055613458f * c.y - 0.0638541728f * c.z; float s_ = c.x - 0.0894841775f * c.y - 1.2914855480f * c.z; @@ -50,7 +72,6 @@ vec4 oklab2rgb(vec4 c) { } vec4 oklab2oklch(vec4 c) { - // oklch.z (hue) ranges from -3.6 to 3.6 return vec4( c.x, sqrt((c.y * c.y) + (c.z * c.z)), @@ -60,7 +81,6 @@ vec4 oklab2oklch(vec4 c) { } vec4 oklch2oklab(vec4 c) { - // oklch.z (hue) ranges from -3.6 to 3.6 return vec4( c.x, c.y * cos(c.z), diff --git a/shaderlib/common.gdshaderinc b/shaderlib/common.gdshaderinc index 9352d6a..7ee57f8 100644 --- a/shaderlib/common.gdshaderinc +++ b/shaderlib/common.gdshaderinc @@ -3,25 +3,3 @@ float cbrt(float x) { return pow(x, 1.0/3.0); } - -/* - Alpha Blending a over b after Bruce A. Wallace - source: https://en.wikipedia.org/wiki/Alpha_compositing -*/ -vec4 alpha_blend(vec4 b, vec4 a) { - float alpha = a.a + (b.a * (1.0 - a.a)); - vec3 col = ((a.rgb*a.a) + ((b.rgb*b.a) * (1.0 - a.a)) / alpha); - return vec4(col.r, col.g, col.b, alpha); -} - -/* - Rotate UV -*/ - -vec2 rotateUV(vec2 uv, float rotation, vec2 center) { - float cosRot = cos(rotation); - float sinRot = sin(rotation); - return vec2( - cosRot * (uv.x - center.x) + sinRot * (uv.y - center.y) + center.x, - cosRot * (uv.y - center.y) - sinRot * (uv.x - center.x) + center.y); -} diff --git a/shaderlib/common.gdshaderinc.uid b/shaderlib/common.gdshaderinc.uid deleted file mode 100644 index f43430d..0000000 --- a/shaderlib/common.gdshaderinc.uid +++ /dev/null @@ -1 +0,0 @@ -uid://764b6ekchgb8 diff --git a/shaderlib/denoise.gdshaderinc.uid b/shaderlib/denoise.gdshaderinc.uid deleted file mode 100644 index 132a166..0000000 --- a/shaderlib/denoise.gdshaderinc.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b7ksfifyyfcip diff --git a/shaderlib/pixelate.gdshaderinc b/shaderlib/effects.gdshaderinc similarity index 100% rename from shaderlib/pixelate.gdshaderinc rename to shaderlib/effects.gdshaderinc diff --git a/shaderlib/hsv.gdshaderinc b/shaderlib/hsv.gdshaderinc deleted file mode 100644 index 2a7834d..0000000 --- a/shaderlib/hsv.gdshaderinc +++ /dev/null @@ -1,27 +0,0 @@ - -/* - rgb2hsv and hsv2rgb functions adapted - from https://godotshaders.com/shader/hsv-adjustment/ - original code by https://godotshaders.com/author/al1-ce/ - - Color space conversion functions always work with vec4. - The fourth value is always alpha. -*/ - -// Convert RGB to HSV (hue, saturation, brightness) -vec4 rgb2hsv(vec4 c) { - vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); - vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); - vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); - float d = q.x - min(q.w, q.y); - float e = 1.0e-10; - return vec4(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x, c.a); -} - -// Convert HSV back to RGB (red, green, blue) -vec4 hsv2rgb(vec4 c) { - vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); - vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); - vec3 rgb = c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); - return vec4(rgb.r, rgb.g, rgb.b, c.a); -} diff --git a/shaderlib/hsv.gdshaderinc.uid b/shaderlib/hsv.gdshaderinc.uid deleted file mode 100644 index 771cc38..0000000 --- a/shaderlib/hsv.gdshaderinc.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bbr3tq6mp5qa2 diff --git a/shaderlib/kuwahara.gdshaderinc b/shaderlib/kuwahara.gdshaderinc deleted file mode 100644 index ea6e22b..0000000 --- a/shaderlib/kuwahara.gdshaderinc +++ /dev/null @@ -1,116 +0,0 @@ -/* - Kuwahara Filter, adapted - original code: https://godotshaders.com/shader/generalized-kuwahara/ - original authors: - - https://godotshaders.com/author/firerabbit/ - - https://github.com/GarrettGunnell (Acerola) - license of the original code: - - MIT License - - Copyright (c) 2022 Garrett Gunnell - Copyright (c) 2024 Firerabbit - - 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. -*/ - -vec3 kuwahara( - sampler2D texture, - vec2 uv, - int kernel_size, // should be > 2 - high values will affect performance - float hardness, // should be in the range of 1.0 - 100.0 - float sharpness, // should be in the range of 1.0 - 18.0 - float zero_crossing, // should be in the range of 0.5 - 2.0 - float zeta, // should be in the range of 0.01 - 3.0 - int n // number of iterations, should be 8, must be <= 8 -) { - vec2 texelSize = vec2(1.0 / vec2(textureSize(texture, 0))); - vec4 m[8]; - vec3 s[8]; - - int kernel_radius = kernel_size / 2; - - float sin_zero_crossing = sin(zero_crossing); - float eta = (zeta + cos(zero_crossing)) / (sin_zero_crossing * sin_zero_crossing); - - for (int k = 0; k < n; ++k) { - m[k] = vec4(0.0f); - s[k] = vec3(0.0f); - } - - for (int y = -kernel_radius; y <= kernel_radius; ++y) { - for (int x = -kernel_radius; x <= kernel_radius; ++x) { - vec2 v = vec2(float(x), float(y)) / float(kernel_radius); - vec3 c = texture(texture, uv + vec2(float(x), float(y)) * texelSize.xy).rgb; - c = clamp(c, 0.0f, 1.0f); - float sum = 0.0f; - float w[8]; - float z, vxx, vyy; - - /* Calculate Polynomial Weights */ - vxx = zeta - eta * v.x * v.x; - vyy = zeta - eta * v.y * v.y; - z = max(0, v.y + vxx); - w[0] = z * z; - sum += w[0]; - z = max(0, -v.x + vyy); - w[2] = z * z; - sum += w[2]; - z = max(0, -v.y + vxx); - w[4] = z * z; - sum += w[4]; - z = max(0, v.x + vyy); - w[6] = z * z; - sum += w[6]; - v = sqrt(2.0f) / 2.0f * vec2(v.x - v.y, v.x + v.y); - vxx = zeta - eta * v.x * v.x; - vyy = zeta - eta * v.y * v.y; - z = max(0, v.y + vxx); - w[1] = z * z; - sum += w[1]; - z = max(0, -v.x + vyy); - w[3] = z * z; - sum += w[3]; - z = max(0, -v.y + vxx); - w[5] = z * z; - sum += w[5]; - z = max(0, v.x + vyy); - w[7] = z * z; - sum += w[7]; - - float g = exp(-3.125f * dot(v,v)) / sum; - - for (int k = 0; k < 8; ++k) { - float wk = w[k] * g; - m[k] += vec4(c * wk, wk); - s[k] += c * c * wk; - } - } - } - - vec4 output = vec4(0.0f); - for (int k = 0; k < n; ++k) { - m[k].rgb /= m[k].w; - s[k] = abs(s[k] / m[k].w - m[k].rgb * m[k].rgb); - float sigma2 = s[k].r + s[k].g + s[k].b; - float w = 1.0f / (1.0f + pow(hardness * 1000.0f * sigma2, 0.5f * sharpness)); - output += vec4(m[k].rgb * w, w); - } - - return clamp(output / output.w, 0.0f, 1.0f).rgb; -} diff --git a/shaderlib/kuwahara.gdshaderinc.uid b/shaderlib/kuwahara.gdshaderinc.uid deleted file mode 100644 index 1ff911b..0000000 --- a/shaderlib/kuwahara.gdshaderinc.uid +++ /dev/null @@ -1 +0,0 @@ -uid://chqh2cni1qiuu diff --git a/shaderlib/oklab.gdshaderinc.uid b/shaderlib/oklab.gdshaderinc.uid deleted file mode 100644 index 7f0bf5f..0000000 --- a/shaderlib/oklab.gdshaderinc.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ckw4nfslk4m6l diff --git a/shaderlib/pixelate.gdshaderinc.uid b/shaderlib/pixelate.gdshaderinc.uid deleted file mode 100644 index a0a0d4d..0000000 --- a/shaderlib/pixelate.gdshaderinc.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dpu5nneo5bgnq diff --git a/shaderlib/pixelsort.gdshaderinc b/shaderlib/pixelsort.gdshaderinc deleted file mode 100644 index 73ed5da..0000000 --- a/shaderlib/pixelsort.gdshaderinc +++ /dev/null @@ -1,126 +0,0 @@ - -/* - Pixelsorting using odd-even sort - - I roughly followed https://ciphrd.com/2020/04/08/pixel-sorting-on-shader-using-well-crafted-sorting-filters-glsl/ - - vector fields aren't implemented, diagonal sorting is not supported! -*/ - -#include "./hsv.gdshaderinc" -#include "./oklab.gdshaderinc" - -#define INF (1.0/0.0) - -#define DIRECTION_LEFT_TO_RIGHT vec2(1, 0) -#define DIRECTION_RIGHT_TO_LEFT vec2(-1, 0) -#define DIRECTION_TOP_TO_BOTTOM vec2(0, 1) -#define DIRECTION_BOTTOM_TO_TOP vec2(0, -1) - -#define COLOR_MODE_RGB 0 -#define COLOR_MODE_OKLAB 1 -#define COLOR_MODE_OKLCH 2 -#define COLOR_MODE_HSV 3 - -vec4 pixelsort_step( - sampler2D tex, vec2 uv, - vec2 direction, // e.g. (1, 0) for left-to-right or (0, -1) for bottom-to-top - // see DIRECTION_LEFT_TO_RIGHT, etc. - // note: vertical sorting doesn't work, so using e.g. (1, 1) won't work - int color_mode, // 0 = RGB, 1 = OKLAB, 2 = OKLCH, 3 = HSV - // see COLOR_MODE_RGB, etc. - bool color_channel_mask[3], // which color channel(s) to take into account - float lower_threshold[3], // lower threshold for pixels to be considered sorted - // when in doubt, use {-INF, -INF, -INF} - float upper_threshold[3], // upper threshold; {INF, INF, INF} - int step_ // from STEP -) { - // sanitize inputs - direction = clamp(direction, vec2(-1, -1), vec2(1, 1)); - color_mode = clamp(color_mode, 0, 3); - // get neighbour - vec2 texture_size = vec2(textureSize(tex, 0)); - vec2 a = (mod(floor(uv * texture_size), 2.0) * 2.0 - 1.0) * (mod(float(step_), 2.0) * 2.0 - 1.0); - vec2 neighbour_uv = uv + (direction * a / texture_size); - // - vec4 x = texture(tex, uv); - vec4 y = texture(tex, neighbour_uv); - if ( // stop at borders - neighbour_uv.x > 1.0 || - neighbour_uv.x < 0.0 || - neighbour_uv.y > 1.0 || - neighbour_uv.y < 0.0 - ) { - return x; - } else { - // convert color if necessary - // get value to compare - float vx = 0.0; - float vy = 0.0; - vec3 color_x; - vec3 color_y; - if (color_mode == COLOR_MODE_RGB) { - color_x = x.rgb; - color_y = y.rgb; - } else if (color_mode == COLOR_MODE_OKLAB) { - color_x = rgb2oklab(x).rgb; - color_y = rgb2oklab(y).rgb; - } else if (color_mode == COLOR_MODE_OKLCH) { - color_x = oklab2oklch(rgb2oklab(x)).rgb; - color_y = oklab2oklch(rgb2oklab(y)).rgb; - } else if (color_mode == COLOR_MODE_HSV) { - color_x = rgb2hsv(x).rgb; - color_y = rgb2hsv(y).rgb; - } - float divisor = 0.0; - if (color_channel_mask[0]) { - vx += color_x.r; - vy += color_y.r; - divisor += 1.0; - } - if (color_channel_mask[1]) { - vx += color_x.g; - vy += color_y.g; - divisor += 1.0; - } - if (color_channel_mask[2]) { - vx += color_x.b; - vy += color_y.b; - divisor += 1.0; - } - divisor = max(divisor, 1.0); - vx /= divisor; - vy /= divisor; - // - if ( - (a.x < .0 && abs(direction).y == .0) || - (a.y < .0 && abs(direction).x == .0) - ) { - if ( - vy > vx && - // threshold - color_x.r < upper_threshold[0] && - color_x.g < upper_threshold[1] && - color_x.b < upper_threshold[2] && - color_x.r > lower_threshold[0] && - color_x.g > lower_threshold[1] && - color_x.b > lower_threshold[2] - ) { return y; } - else { return x; } - } else if ( - (a.x > .0 && abs(direction).y == .0) || - (a.y > .0 && abs(direction).x == .0) - ) { - if ( - vx >= vy && - // threshold - color_y.r < upper_threshold[0] && - color_y.g < upper_threshold[1] && - color_y.b < upper_threshold[2] && - color_y.r > lower_threshold[0] && - color_y.g > lower_threshold[1] && - color_y.b > lower_threshold[2] - ) { return y; } - else { return x; } - } - } -} diff --git a/shaderlib/pixelsort.gdshaderinc.uid b/shaderlib/pixelsort.gdshaderinc.uid deleted file mode 100644 index e02f48e..0000000 --- a/shaderlib/pixelsort.gdshaderinc.uid +++ /dev/null @@ -1 +0,0 @@ -uid://doefnwk3vyr0o diff --git a/shaderlib/place_texture.gdshaderinc.uid b/shaderlib/place_texture.gdshaderinc.uid deleted file mode 100644 index f0b6f69..0000000 --- a/shaderlib/place_texture.gdshaderinc.uid +++ /dev/null @@ -1 +0,0 @@ -uid://51u2hjq62e5i diff --git a/shaderlib/sobel.gdshaderinc b/shaderlib/sobel.gdshaderinc deleted file mode 100644 index dd665b3..0000000 --- a/shaderlib/sobel.gdshaderinc +++ /dev/null @@ -1,50 +0,0 @@ - -/* - Edge Detection (Sobel Filter and Gaussian Blur) by FencerDevLog, adapted - original code: https://godotshaders.com/shader/edge-detection-sobel-filter-and-gaussian-blur/ - license of the original code: CC0 -*/ - -vec3 _convolution(sampler2D tex, vec2 uv, vec2 pixel_size) { - vec3 conv = vec3(0.0); - // Gaussian blur kernel - float gauss[25] = { - 0.00390625, 0.015625, 0.0234375, 0.015625, 0.00390625, - 0.015625, 0.0625, 0.09375, 0.0625, 0.015625, - 0.0234375, 0.09375, 0.140625, 0.09375, 0.0234375, - 0.015625, 0.0625, 0.09375, 0.0625, 0.015625, - 0.00390625, 0.015625, 0.0234375, 0.015625, 0.00390625 - }; - for (int row = 0; row < 5; row++) { - for (int col = 0; col < 5; col++) { - conv += texture(tex, uv + vec2(float(col - 2), float(row - 2)) * pixel_size).rgb * gauss[row * 5 + col]; - } - } - return conv; -} - -vec4 sobel(sampler2D tex, vec2 uv) { - vec2 pixel_size = 1.0/vec2(textureSize(tex, 0)); - vec3 pixels[9]; // Sobel kernel - // [0, 1, 2] - // [3, 4, 5] - // [6, 7, 8] - for (int row = 0; row < 3; row++) { - for (int col = 0; col < 3; col++) { - vec2 uv_ = uv + vec2(float(col - 1), float(row - 1)) * pixel_size; - pixels[row * 3 + col] = _convolution(tex, uv_, pixel_size); - } - } - - // Sobel operator - vec3 gx = ( - pixels[0] * -1.0 + pixels[3] * -2.0 + pixels[6] * -1.0 - + pixels[2] * 1.0 + pixels[5] * 2.0 + pixels[8] * 1.0 - ); - vec3 gy = ( - pixels[0] * -1.0 + pixels[1] * -2.0 + pixels[2] * -1.0 - + pixels[6] * 1.0 + pixels[7] * 2.0 + pixels[8] * 1.0 - ); - vec3 sobel = sqrt(gx * gx + gy * gy); - return vec4(sobel, 1.0); -} \ No newline at end of file diff --git a/shaderlib/sobel.gdshaderinc.uid b/shaderlib/sobel.gdshaderinc.uid deleted file mode 100644 index 5753e70..0000000 --- a/shaderlib/sobel.gdshaderinc.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bqo1fpunnl05f diff --git a/shaderlib/place_texture.gdshaderinc b/shaderlib/transform.gdshaderinc similarity index 100% rename from shaderlib/place_texture.gdshaderinc rename to shaderlib/transform.gdshaderinc diff --git a/shaderlib/transparency.gdshaderinc b/shaderlib/transparency.gdshaderinc new file mode 100644 index 0000000..a97e4b7 --- /dev/null +++ b/shaderlib/transparency.gdshaderinc @@ -0,0 +1,10 @@ + +/* + Alpha Blending a over b after Bruce A. Wallace + source: https://en.wikipedia.org/wiki/Alpha_compositing +*/ +vec4 alpha_blend(vec4 b, vec4 a) { + float alpha = a.a + (b.a * (1.0 - a.a)); + vec3 col = ((a.rgb*a.a) + ((b.rgb*b.a) * (1.0 - a.a)) / alpha); + return vec4(col.r, col.g, col.b, alpha); +} diff --git a/src/Camera.gd b/src/Camera.gd index 416e035..5ad2855 100644 --- a/src/Camera.gd +++ b/src/Camera.gd @@ -1,9 +1,9 @@ extends Camera2D -@onready var image_viewport_display = %ImageViewportDisplay - var drag = false +@onready var image_viewport_display = %ImageViewportDisplay + func _input(event): if event.is_action_pressed("zoom_out"): zoom_out() @@ -16,35 +16,31 @@ func _input(event): if self.drag && event is InputEventMouseMotion: self.global_position -= event.relative / self.zoom -var old_zoom = self.zoom - -func _process(_delta: float) -> void: - if self.zoom != old_zoom: - image_viewport_display.update_zoom_texture_filter(self.zoom) - image_viewport_display.material.set_shader_parameter("zoom_level", self.zoom) - old_zoom = self.zoom - func fit_image(): if Filesystem.original_image != null: var image_size = Filesystem.original_image.get_size() var viewport_size = get_viewport_rect().size - var zoomf = 1.0 - if viewport_size.x / image_size.x * image_size.y > viewport_size.y: - zoomf = viewport_size.y / image_size.y / 1.25 - else: - zoomf = viewport_size.x / image_size.x / 1.2 + var zoomf = viewport_size.x / image_size.x / 1.1 + if zoomf * image_size.y > viewport_size.y: + zoomf = viewport_size.y / image_size.y / 1.1 self.zoom = Vector2(zoomf, zoomf) self.global_position = Vector2(0, 0) +func update_vd_zoomlevel(): + image_viewport_display.update_zoom_texture_filter(self.zoom) + image_viewport_display.material.set_shader_parameter("zoom_level", self.zoom) + func zoom_in(): var old_mouse_pos = get_global_mouse_position() self.zoom *= 1.2 self.global_position += old_mouse_pos - get_global_mouse_position() + update_vd_zoomlevel() func zoom_out(): var old_mouse_pos = get_global_mouse_position() self.zoom *= 1/1.2 self.global_position += old_mouse_pos - get_global_mouse_position() + update_vd_zoomlevel() func _on_fit_image_button_pressed(): fit_image() diff --git a/src/Camera.gd.uid b/src/Camera.gd.uid deleted file mode 100644 index f25b715..0000000 --- a/src/Camera.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b6r8rigubdctk diff --git a/src/Editor.gd b/src/Editor.gd new file mode 100644 index 0000000..4fb716c --- /dev/null +++ b/src/Editor.gd @@ -0,0 +1,307 @@ +extends Control + +@onready var code_editor = %CodeEdit + +@onready var open_shader_dialog = %OpenShaderDialog +@onready var save_shader_dialog = %SaveShaderDialog +@onready var ui_control_filesave = %SaveImageDialog + +@onready var save_image_button = %SaveImageButton + +@onready var status_indicator = %StatusIndicator +@onready var error_msg_dialog = %ErrorMessageDialog + +@onready var main = get_tree().root.get_node("Main") +@onready var compositor = main.get_node("%Compositor") +@onready var camera = main.get_node("%Camera") + +# + +var status_okay_texture: CompressedTexture2D = preload("uid://m1omb6g45vst") +var status_error_texture: CompressedTexture2D = preload("uid://04iv1gogpuhu") + +# # # # # # # # # # # +# GDShader keywords # +# https://github.com/godotengine/godot/blob/e96ad5af98547df71b50c4c4695ac348638113e0/servers/rendering/shader_language.cpp +# https://github.com/godotengine/godot/blob/e96ad5af98547df71b50c4c4695ac348638113e0/servers/rendering/shader_types.cpp +# +const gdshader_boolean_values = [ + "true", "false" +] +const gdshader_datatypes = [ + "void", + "bool", "bvec2", "bvec3", "bvec4", + "int", "ivec2", "ivec3", "ivec4", + "uint", "uvec2", "uvec3", "uvec4", + "float", "vec2", "vec3", "vec4", + "mat2", "mat3", "mat4", + "sampler2D", "isampler2D", "usampler2D", + "sampler2DArray", "isampler2DArray", "usampler2DArray", +] +const gdshader_precision_modifiers = [ + "lowp", "mediump", "heighp" +] +const gdshader_global_space_keywords = [ + "uniform", "group_uniforms", "varying", "const", + "struct", "shader_type", "render_mode" +] +const gdshader_uniform_qualifiers = [ + "instance", "global" +] +const gdshader_block_keywords = [ + "if", "else", + "for", "while", "do", + "switch", "case", + "default", "break", "continue", + "return", "discard" +] +const gdshader_function_specifier_keywords = [ + "in", "out", "inout" +] +const gdshader_hints = [ + "source_color", "hint_range", "instance_index" +] +const gdshader_sampler_hints = [ + "hint_normal", + "hint_default_white", "hint_default_black", "hint_default_transparent", + "hint_anisotropy", + "hint_roughness_r", "hint_roughness_g", "hint_roughness_b", "hint_roughness_a", + "hint_roughness_normal", "hint_roughness_gray", + "hint_screen_texture", "hint_normal_roughness_texture", + "hint_depth_texture", + "filter_nearest", "filter_linear", + "filter_nearest_mipmap", "filter_linear_mipmap", + "filter_nearest_mipmap_anisotropic", "filter_linear_mipmap_anisotropic", + "repeat_enable", "repeat_disable" +] +const gdshader_builtin_functions = [ + "radians", "degrees", + "sin", "cos", "tan", "asin", "acos", "atan", "sinh", "cosh", "tanh", + "asinh", "acosh", "atanh", + "pow", "exp", "exp2", "log", "log2", "sqrt", "inversesqrt", + "abs", "sign", "floor", "trunc", "round", "roundEven", "ceil", "fract", + "mod", "modf", "min", "max", "clamp", + "mix", "step", "smoothstep", + "isnan", "isinf", + "floatBitsToInt", "floatBitsToUint", "intBitsToFloat", "uintBitsToFloat", + "length", "distance", + "dot", "cross", + "normalize", "reflect", "refract", "faceforward", + "matrixCompMult", "outerProduct", "transpose", + "determinant", "inverse", + "lessThan", "greaterThan", "lessThanEqual", "greaterThanEqual", + "equal", "notEqual", + "any", "all", "not", + "textureSize", "texture", "textureProj", "textureLod", "texelFetch", + "textureProjLod", "textureGrad", "textureProjGrad", "textureGather", + "textureQueryLod", "textureQueryLevels", + "dFdx", "dFdxCoarse", "dFdxFine", "dFdy", "dFdyCoarse", "dFdyFine", + "fwidth", "fwidthCoarse", "fwidthFine" +] +const gdshader_sub_functions = [ + "length", "fma", + "packHalf2x16", "packUnorm2x16", "packSnorm2x16", "packUnorm4x8", "packSnorm4x8", + "unpackHalf2x16", "unpackUnorm2x16", "unpackSnorm2x16", "unpackUnorm4x8", "unpackSnorm4x8", + "bitfieldExtract", "bitfieldInsert", "bitfieldReverse", "bitCount", + "findLSB", "findMSB", + "umulExtended", "imulExtended", + "uaddCarry", "usubBorrow", + "ldexp", "frexp" +] +const gdshader_builtins = [ + "TIME", "PI", "TAU", "E", + "VERTEX", + "UV", + "COLOR", + "POINT_SIZE", + "AT_LIGHT_PASS", + "TEXTURE_PIXEL_SIZE", + "SHADOW_VERTEX", "LIGHT_VERTEX", + "FRAGCOORD", + "NORMAL", "NORMAL_MAP", "NORMAL_MAP_DEPTH", + "TEXTURE", + "POINT_COORD", + "SPECULAR_SHININESS" +] +const gdshader_preprocessor = [ + "define", "undef", "include", "pragma", + "if", "elif", "ifdef", "ifndef", "else", "endif" +] +# shaderlib +var shaderlib_regex = { + "colorspaces": RegEx.create_from_string(r'\s*\#include\s+\"res\:\/\/shaderlib\/colorspaces\.gdshaderinc\"'), + "transform": RegEx.create_from_string(r'\s*\#include\s+\"res\:\/\/shaderlib\/transform\.gdshaderinc\"'), + "transparency": RegEx.create_from_string(r'\s*\#include\s+\"res\:\/\/shaderlib\/transparency\.gdshaderinc\"'), + "effects": RegEx.create_from_string(r'\s*\#include\s+\"res\:\/\/shaderlib\/effects\.gdshaderinc\"'), + "denoise": RegEx.create_from_string(r'\s*\#include\s+\"res\:\/\/shaderlib\/denoise\.gdshaderinc\"'), + "blur": RegEx.create_from_string(r'\s*\#include\s+\"res\:\/\/shaderlib\/blur\.gdshaderinc\"'), +} +const shaderlib_functions = { + "colorspaces": ["rgb2hsv", "hsv2rgb", "oklab2rgb", "rgb2oklab", "oklab2oklch", "oklch2oklab"], + "transform": ["place_texture"], + "transparency": ["alpha_blend"], + "effects": ["pixelate"], + "denoise": ["smart_denoise"], + "blur": ["gaussian_blur"], +} +# +# configure Highlighter +# +class ShaderSyntaxHighlighter extends CodeHighlighter: + func _init(): + add_color_region("//", "", Color.WEB_GRAY, true) + add_color_region("/*", "*/", Color.WEB_GRAY, false) + function_color = Color.INDIAN_RED + for k in gdshader_boolean_values: + keyword_colors[k] = Color.INDIAN_RED + for k in ( gdshader_datatypes + + gdshader_hints + + gdshader_sampler_hints + + gdshader_global_space_keywords + + gdshader_function_specifier_keywords + + gdshader_precision_modifiers + + gdshader_uniform_qualifiers): + keyword_colors[k] = Color.ORCHID; + for k in gdshader_block_keywords: + keyword_colors[k] = Color.CORAL + for k in gdshader_builtins: + keyword_colors[k] = Color.DARK_TURQUOISE + member_variable_color = Color.LIGHT_BLUE + number_color = Color.AQUA + symbol_color = Color.GRAY +# +# and code completion +# +func _on_code_edit_code_completion_requested(): + for k in gdshader_boolean_values: + code_editor.code_completion_prefixes.append(k) + code_editor.add_code_completion_option(CodeEdit.KIND_PLAIN_TEXT, k, k, Color.INDIAN_RED) + for k in ( gdshader_datatypes + + gdshader_hints + + gdshader_sampler_hints + + gdshader_global_space_keywords + + gdshader_function_specifier_keywords + + gdshader_precision_modifiers + + gdshader_uniform_qualifiers): + code_editor.code_completion_prefixes.append(k) + code_editor.add_code_completion_option(CodeEdit.KIND_CLASS, k, k, Color.ORCHID) + for k in gdshader_block_keywords: + code_editor.code_completion_prefixes.append(k) + code_editor.add_code_completion_option(CodeEdit.KIND_PLAIN_TEXT, k, k, Color.CORAL) + for k in gdshader_builtins: + code_editor.code_completion_prefixes.append(k) + code_editor.add_code_completion_option(CodeEdit.KIND_CONSTANT, k, k, Color.DARK_TURQUOISE) + for k in gdshader_builtin_functions + gdshader_sub_functions: + code_editor.code_completion_prefixes.append(k) + code_editor.add_code_completion_option(CodeEdit.KIND_FUNCTION, k, k+"(", Color.INDIAN_RED) + for k in gdshader_preprocessor: + code_editor.code_completion_prefixes.append(k) + code_editor.add_code_completion_option(CodeEdit.KIND_PLAIN_TEXT, "#" + k, k) + # shaderlib # + var shader_code = code_editor.text + for key in shaderlib_regex: + if shaderlib_regex[key].search(shader_code) != null: + if key in shaderlib_functions: + for k in shaderlib_functions[key]: + code_editor.code_completion_prefixes.append(k) + code_editor.add_code_completion_option(CodeEdit.KIND_FUNCTION, k, k+"(", Color.INDIAN_RED) + # # # # # # # + code_editor.update_code_completion_options(true) +# +# # # # # # # # # # # # + +func _ready(): + code_editor.code_completion_enabled = true + code_editor.syntax_highlighter = ShaderSyntaxHighlighter.new() + self.update_code_edit() + +func _input(event): + if event.is_action_pressed("apply_shader"): + _on_apply_shader_button_pressed() + elif event.is_action_pressed("save_shader"): + accept_event() # Event is now handled. + _on_save_shader_button_pressed() + +func update_code_edit(): + code_editor.text = Filesystem.shader_code + +enum Status {OKAY, ERROR, UNKNOWN = -1} + +func update_status(status: Status, msg: String = ""): + error_msg_dialog.dialog_text = msg + error_msg_dialog.reset_size() + if status == Status.OKAY: + status_indicator.texture_normal = status_okay_texture + elif status == Status.ERROR: + status_indicator.texture_normal = status_error_texture + else: + status_indicator.texture_normal = null + if msg == "": + status_indicator.disabled = true + else: + status_indicator.disabled = false + +# + +func _on_new_shader_button_pressed(): + main.update_title() + Filesystem.reset() + self.update_code_edit() + compositor.update() + update_status(Status.UNKNOWN) + +func _on_open_shader_button_pressed(): + open_shader_dialog.show() + +func _on_save_shader_button_pressed(): + Filesystem.shader_code = code_editor.text + if Filesystem.last_shader_savepath == "": + _on_save_shader_as_button_pressed() + else: + _on_save_shader_dialog_file_selected(Filesystem.last_shader_savepath) + +func _on_save_shader_as_button_pressed() -> void: + Filesystem.shader_code = code_editor.text + if Filesystem.last_shader_savepath == "": + save_shader_dialog.current_file = "filter.gdshader" + else: + save_shader_dialog.current_path = Filesystem.last_shader_savepath + save_shader_dialog.show() + +func _on_fit_image_button_pressed(): + camera.fit_image() + +func _on_apply_shader_button_pressed(): + save_image_button.disabled = true + Filesystem.shader_code = code_editor.text + var errors = await compositor.update() + if len(errors) > 0: + update_status(Status.ERROR, "\n".join(errors)) + else: + update_status(Status.OKAY) + save_image_button.disabled = false + +func _on_save_image_button_pressed(): + if Filesystem.result != null: + ui_control_filesave.current_path = Filesystem.last_image_savepath + ui_control_filesave.show() + +# + +func _on_open_shader_dialog_file_selected(path: String): + Filesystem.load_shader(path) + main.update_title(path.split("/")[-1]) + self.update_code_edit() + self._on_apply_shader_button_pressed() + +func _on_save_shader_dialog_file_selected(path): + Filesystem.save_shader(path) + main.update_title(path.split("/")[-1]) + +func _on_save_image_dialog_file_selected(path): + Filesystem.save_result(path) + +# + +func _on_status_indicator_pressed() -> void: + error_msg_dialog.show() diff --git a/src/Filesystem.gd b/src/Filesystem.gd index cb1ac7d..0fb9507 100644 --- a/src/Filesystem.gd +++ b/src/Filesystem.gd @@ -1,31 +1,25 @@ extends Node -var cwd = "." - -var shader_path = "": - get(): - return shader_path - set(v): - var old = shader_path - shader_path = v - if "/" in v: # update current working directory - cwd = v.substr(0, v.rfind("/")) - if old != shader_path: - store_last_opened_file() - -var shader: Shader: - get(): - print("Load ", shader_path) - return load(shader_path) +@onready var template_shader: Shader = load("res://src/shader/template.gdshader") +@onready var shader_code: String = template_shader.code var original_image: ImageTexture - var additional_images: Dictionary var result: Image +var cwd = "." var last_image_savepath = "" +var last_shader_savepath = "" var last_original_image_path = "" +func reset(): + self.shader_code = self.template_shader.code + self.last_image_savepath = "" + self.last_shader_savepath = "" + self.last_original_image_path = "" + self.original_image = null + self.result = null + func get_absolute_path(p: String) -> String: # this only works on Linux! if !p.begins_with("/"): @@ -33,14 +27,14 @@ func get_absolute_path(p: String) -> String: return p func load_original_image(path: String) -> String: # returns an error message - print("Load ", path) var img = Image.new() var err = img.load(path) if err == OK: original_image = ImageTexture.create_from_image(img) - if self.last_image_savepath == "" or path != self.last_original_image_path: + if path != self.last_original_image_path: + self.last_original_image_path = path + if self.last_image_savepath == "": self.last_image_savepath = path - self.last_original_image_path = path return "" return error_string(err) + " " + path @@ -48,7 +42,6 @@ func clear_additional_images(): additional_images.clear() func load_additional_image(key: String, path: String) -> String: # returns Error Message String - print("Load ", path) var img = Image.new() var err = img.load(path) if err == OK: @@ -65,13 +58,33 @@ func save_result(path: String): else: self.last_image_savepath = path +func load_shader(path: String): + print("Load ", path) + var file = FileAccess.open(path, FileAccess.READ) + if file != null: + self.shader_code = file.get_as_text() + if "/" in path: # update current working directory + self.cwd = path.substr(0, path.rfind("/")) + self.last_shader_savepath = path + store_last_opened_file() + +func save_shader(path: String): + print("Save ", path) + var file = FileAccess.open(path, FileAccess.WRITE) + file.store_string(self.shader_code) + file.flush() + if "/" in path: # update current working directory + self.cwd = path.substr(0, path.rfind("/")) + self.last_shader_savepath = path + store_last_opened_file() + func store_last_opened_file(): var f = FileAccess.open("user://last_opened", FileAccess.WRITE) if f != null: - f.store_pascal_string(shader_path) + f.store_pascal_string(last_shader_savepath) f.flush() func remember_last_opened_file(): var f = FileAccess.open("user://last_opened", FileAccess.READ) if f != null: - shader_path = f.get_pascal_string() + last_shader_savepath = f.get_pascal_string() diff --git a/src/Filesystem.gd.uid b/src/Filesystem.gd.uid deleted file mode 100644 index a89dcab..0000000 --- a/src/Filesystem.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://rlb041ygdwol diff --git a/src/ImageCompositor.gd b/src/ImageCompositor.gd index 9f3e95a..5999b88 100644 --- a/src/ImageCompositor.gd +++ b/src/ImageCompositor.gd @@ -37,26 +37,17 @@ func validate_shader_compilation(shader: Shader) -> bool: # test if uniform list is empty -> if it is empty, the shader compilation failed return len(shader.get_shader_uniform_list()) > 0 -func shader_has_uniform(shader: Shader, name: String, type: int) -> bool: - for u in shader.get_shader_uniform_list(): - if u["name"] == name && u["type"] == type: - return true - return false - -func set_vsync(enabled: bool): - if enabled: - DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_ENABLED) - else: - DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED) +func inject_step_uniform(shader_code: String) -> Shader: + var shader = Shader.new() + # this should run after validate_shader_compilation() + var fragment_function_match = _fragment_function_regex.search(shader_code) + shader.code = shader_code.insert(fragment_function_match.get_start(), "\nuniform int STEP;") + return shader func update(overwrite_image_path: String = "") -> Array: # returns error messages (strings) - var shader = Filesystem.shader # read from disk - if shader == null: - return ["No shader opened!"] - # get number of steps & check if code has STEP uniform + # inject STEP uniform & get number of steps + var shader: Shader = inject_step_uniform(Filesystem.shader_code) var steps: int = ShaderDirectiveParser.parse_steps_directive(shader.code) - var has_step_uniform: bool = shader_has_uniform(shader, "STEP", 2) - var has_steps_uniform: bool = shader_has_uniform(shader, "STEPS", 2) # validate shader if not validate_shader_compilation(shader): return ["Shader compilation failed!"] @@ -91,9 +82,6 @@ func update(overwrite_image_path: String = "") -> Array: # returns error message image_sprite.texture = Filesystem.original_image image_sprite.offset = Filesystem.original_image.get_size() / 2 self.size = Filesystem.original_image.get_size() - # already show the image viewport & fit the image - if fit_image: camera.fit_image() - image_viewport_display.show() # create shader material var mat = ShaderMaterial.new() mat.shader = shader @@ -105,19 +93,17 @@ func update(overwrite_image_path: String = "") -> Array: # returns error message # assign material image_sprite.material = mat # iterate n times - set_vsync(false) # speed up processing - if has_steps_uniform: - # set STEPS param - mat.set_shader_parameter("STEPS", steps) for i in range(steps): - if has_step_uniform: - # set STEP param - mat.set_shader_parameter("STEP", i) + # set STEP param + mat.set_shader_parameter("STEP", i) # Get viewport texture await RenderingServer.frame_post_draw # wait for next frame to get drawn Filesystem.result = get_texture().get_image() image_sprite.texture = ImageTexture.create_from_image(Filesystem.result) - set_vsync(true) # reenable vsync image_sprite.material = null + if fit_image: + camera.fit_image() + camera.update_vd_zoomlevel() + image_viewport_display.show() # done return errors diff --git a/src/ImageCompositor.gd.uid b/src/ImageCompositor.gd.uid deleted file mode 100644 index 2e55fae..0000000 --- a/src/ImageCompositor.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://d106170kuigl3 diff --git a/src/ImageViewportDisplay.gd.uid b/src/ImageViewportDisplay.gd.uid deleted file mode 100644 index dbde761..0000000 --- a/src/ImageViewportDisplay.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ctc4lhbdsoq7u diff --git a/src/Main.gd b/src/Main.gd index dcf32b3..8e54a86 100644 --- a/src/Main.gd +++ b/src/Main.gd @@ -1,27 +1,17 @@ extends Node -const BATCH_MODE_SUPPORTED_EXTS = [ - ".bmp", ".dds", ".exr", ".hdr", ".jpeg", ".jpg", ".ktx", ".png", ".svg", ".webp" -] - +@onready var editor_window = %EditorWindow +@onready var ui_container = %UserInterfaceContainer @onready var app_name = ProjectSettings.get_setting("application/config/name") func show_help(): print( "Usage:\n\n", - "./Fragmented \n\n", - "Commands:\n\n", - " help\n\n", - " | Shows this help text.\n\n", - " apply --shader PATH [--load-image PATH]\n\n", - " | Applies a shader file.\n\n", - " --shader PATH The path to the shader\n", - " --output PATH Where to write the resulting image to.\n", - " In batch mode, this must be a folder.\n", - " --load-image PATH The path to the image. This will overwrite the\n", - " load directive of the shader file.\n", - " Passing a folder activates batch mode.\n", - " (optional)\n") + "./Fragmented cmd --shader PATH [--load-image PATH]\n\n", + " --shader PATH The path to the shader\n", + " --output PATH Where to write the resulting image to\n", + " --load-image PATH The path to the image. This will overwrite the\n", + " load directive of the shader file (optional)\n") func parse_custom_cmdline(args: PackedStringArray): var kwargs: Dictionary = {"--shader": null, "--output": null, "--load-image": null} @@ -35,92 +25,50 @@ func parse_custom_cmdline(args: PackedStringArray): i += 1 return kwargs -func cli_handle_errors(errors: Array) -> int: - # returns number of errors - var n_errors = errors.size() - if n_errors > 0: - print("One or more errors occurred.") - for e in errors: - printerr(e) - return n_errors - -func cli(args: PackedStringArray): - print( - "~ Fragmented CLI ~\n", - "-================-\n") - if "help" in args: - show_help() - get_tree().quit(1) - return - var kwargs: Dictionary = parse_custom_cmdline(args) - if kwargs["--shader"] == null or kwargs["--output"] == null: - show_help() - get_tree().quit(1) - return - var batch_mode = false - var load_image_dir: DirAccess - if kwargs["--load-image"] != null: - load_image_dir = DirAccess.open(kwargs["--load-image"]) - if load_image_dir != null: - # batch mode - if DirAccess.open(kwargs["--output"]) == null: - printerr("If --load-image is a directory, --output has to be one too.\n") - show_help() - get_tree().quit(1) - return - else: - batch_mode = true - # - Filesystem.shader_path = kwargs["--shader"] - # - if batch_mode: - var in_dir_path = load_image_dir.get_current_dir() - var out_dir_path: String = kwargs["--output"].rstrip("/") - for f in load_image_dir.get_files(): - var supported = false - for e in BATCH_MODE_SUPPORTED_EXTS: - if f.ends_with(e): - supported = true - break - if supported: - f = in_dir_path + "/" + f - print(f) - var errors = await $Compositor.update(f) - if cli_handle_errors(errors) == 0: - var filename = out_dir_path + "/" + f.substr(f.rfind("/"), -1) - Filesystem.save_result(filename) - else: - get_tree().quit(1) - return - get_tree().quit(0) - else: - var errors = [] - if kwargs["--load-image"] == null: - errors = await $Compositor.update() - else: - errors = await $Compositor.update(kwargs["--load-image"]) - if cli_handle_errors(errors) == 0: - Filesystem.save_result(kwargs["--output"]) - get_tree().quit(0) - else: - get_tree().quit(1) - -func prepare_gui(): - update_title() - # Load last opened file - Filesystem.remember_last_opened_file() - %MainUI._on_apply_shader_button_pressed() - func _ready(): var args = OS.get_cmdline_args() - if len(args) > 0 and args[0] in ["apply", "help"]: - # use the commandline interface - cli(args) + if "cmd" in args: # commandline interface + if "help" in args: + show_help() + get_tree().quit(1) + else: + var kwargs: Dictionary = parse_custom_cmdline(args) + if kwargs["--shader"] == null or kwargs["--output"] == null: + show_help() + get_tree().quit(1) + else: + Filesystem.load_shader(kwargs["--shader"]) + var errors = [] + if kwargs["--load-image"] == null: + errors = await $Compositor.update() + else: + errors = await $Compositor.update(kwargs["--load-image"]) + if errors.size() > 0: + print("One or more errors occurred.") + for e in errors: + printerr(e) + get_tree().quit(1) + else: + Filesystem.save_result(kwargs["--output"]) + get_tree().quit(0) else: - prepare_gui() + update_title() + # position windows + get_window().position = Vector2i( + editor_window.position.x + editor_window.size.x + 50, + editor_window.position.y) + get_window().min_size = Vector2i(400, 400) + editor_window.min_size = Vector2i(560, 400) + editor_window.show() + # Load last opened file + Filesystem.remember_last_opened_file() + if Filesystem.last_shader_savepath != "": + ui_container.get_node("Editor")._on_open_shader_dialog_file_selected(Filesystem.last_shader_savepath) func update_title(current_file: String = ""): if current_file == "": get_window().title = app_name + " - Viewer" + editor_window.title = app_name + " - Editor" else: get_window().title = current_file + " - " + app_name + " - Viewer" + editor_window.title = current_file + " - " + app_name + " - Editor" diff --git a/src/Main.gd.uid b/src/Main.gd.uid deleted file mode 100644 index 2f9a508..0000000 --- a/src/Main.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://5sbslwysin5a diff --git a/src/MainUI.gd b/src/MainUI.gd deleted file mode 100644 index 8a62ff1..0000000 --- a/src/MainUI.gd +++ /dev/null @@ -1,100 +0,0 @@ -extends Control - -@onready var open_shader_dialog = %OpenShaderDialog -@onready var save_image_dialog = %SaveImageDialog - -@onready var open_shader_button = %OpenShaderButton -@onready var save_image_button = %SaveImageButton -@onready var fit_image_button = %FitImageButton -@onready var apply_shader_button = %ApplyShaderButton - -@onready var status_indicator = %StatusIndicator -@onready var error_msg_dialog = %ErrorMessageDialog - -@onready var main = get_tree().root.get_node("Main") -@onready var compositor = %Compositor -@onready var camera = %Camera - -var status_okay_texture: CompressedTexture2D = preload("uid://m1omb6g45vst") -var status_error_texture: CompressedTexture2D = preload("uid://04iv1gogpuhu") - -enum Status {OKAY, ERROR, UNKNOWN = -1} - -# - -func _input(event): - if event.is_action_pressed("apply_shader"): - _on_apply_shader_button_pressed() - elif event.is_action_pressed("save_shader"): - accept_event() # Event is now handled. - -# - -func set_buttons_disabled(disabled: bool): - for b in [open_shader_button, save_image_button, fit_image_button, apply_shader_button, status_indicator]: - b.disabled = disabled - -func _on_open_shader_button_pressed(): - set_buttons_disabled(true) - open_shader_dialog.show() - -func _on_fit_image_button_pressed(): - camera.fit_image() - -func _on_apply_shader_button_pressed(): - set_buttons_disabled(true) - var errors = await compositor.update() - set_buttons_disabled(false) - if len(errors) > 0: - update_status(Status.ERROR, "\n".join(errors)) - else: - update_status(Status.OKAY) - status_indicator.disabled = true - -func _on_save_image_button_pressed(): - if Filesystem.result != null: - set_buttons_disabled(true) - save_image_dialog.current_path = Filesystem.last_image_savepath - save_image_dialog.show() - -# - -func _on_open_shader_dialog_file_selected(path: String): - Filesystem.shader_path = path - main.update_title(path.split("/")[-1]) - self._on_apply_shader_button_pressed() - -func _on_open_shader_dialog_canceled() -> void: - set_buttons_disabled(false) - -func _on_open_shader_dialog_confirmed() -> void: - set_buttons_disabled(false) - -func _on_save_image_dialog_file_selected(path): - Filesystem.save_result(path) - set_buttons_disabled(false) - -func _on_save_image_dialog_canceled() -> void: - set_buttons_disabled(false) - -func _on_save_image_dialog_confirmed() -> void: - set_buttons_disabled(false) - -# - -func update_status(status: Status, msg: String = ""): - error_msg_dialog.dialog_text = msg - error_msg_dialog.reset_size() - if status == Status.OKAY: - status_indicator.texture_normal = status_okay_texture - elif status == Status.ERROR: - status_indicator.texture_normal = status_error_texture - else: - status_indicator.texture_normal = null - if msg == "": - status_indicator.disabled = true - else: - status_indicator.disabled = false - -func _on_status_indicator_pressed() -> void: - error_msg_dialog.show() diff --git a/src/MainUI.gd.uid b/src/MainUI.gd.uid deleted file mode 100644 index 0077ccd..0000000 --- a/src/MainUI.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bxgmf2ny7yuc8 diff --git a/src/ShaderDirectiveParser.gd.uid b/src/ShaderDirectiveParser.gd.uid deleted file mode 100644 index 59f7f0e..0000000 --- a/src/ShaderDirectiveParser.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dw8bep14j4j3w diff --git a/src/UIAppVersion.gd b/src/UIAppVersion.gd new file mode 100644 index 0000000..60fe35a --- /dev/null +++ b/src/UIAppVersion.gd @@ -0,0 +1,4 @@ +extends Label + +func _ready(): + text = ProjectSettings.get_setting("application/config/version") diff --git a/src/UIWindow.gd b/src/UIWindow.gd new file mode 100644 index 0000000..72836ce --- /dev/null +++ b/src/UIWindow.gd @@ -0,0 +1,4 @@ +extends Window + +func _on_close_requested() -> void: + get_tree().quit() diff --git a/src/VersionLabel.gd b/src/VersionLabel.gd deleted file mode 100644 index c3c07e7..0000000 --- a/src/VersionLabel.gd +++ /dev/null @@ -1,8 +0,0 @@ -extends Label - -func _ready(): - text = ProjectSettings.get_setting("application/config/name") \ - + " " \ - + ProjectSettings.get_setting("application/config/version") \ - + " | Godot " \ - + Engine.get_version_info()["string"] diff --git a/src/VersionLabel.gd.uid b/src/VersionLabel.gd.uid deleted file mode 100644 index e731c41..0000000 --- a/src/VersionLabel.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bh0gpu3i2p47f diff --git a/src/assets/bg.png b/src/assets/bg.png deleted file mode 100644 index fb67c19..0000000 Binary files a/src/assets/bg.png and /dev/null differ diff --git a/src/assets/bg.png.import b/src/assets/bg.png.import deleted file mode 100644 index e61ed86..0000000 --- a/src/assets/bg.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://d2nwchyd6huob" -path="res://.godot/imported/bg.png-7c8713dd1fab321784216191fa747e53.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://src/assets/bg.png" -dest_files=["res://.godot/imported/bg.png-7c8713dd1fab321784216191fa747e53.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/src/scenes/main.tscn b/src/scenes/main.tscn deleted file mode 100644 index 14b19bd..0000000 --- a/src/scenes/main.tscn +++ /dev/null @@ -1,194 +0,0 @@ -[gd_scene load_steps=13 format=3 uid="uid://bjah7k4bxo044"] - -[ext_resource type="Script" uid="uid://5sbslwysin5a" path="res://src/Main.gd" id="1_64y3g"] -[ext_resource type="Script" uid="uid://d106170kuigl3" path="res://src/ImageCompositor.gd" id="2_4ykh7"] -[ext_resource type="Shader" uid="uid://ctk7jomfyx0fh" path="res://src/shader/ivd_outline.gdshader" id="3_0fllm"] -[ext_resource type="Script" uid="uid://ctc4lhbdsoq7u" path="res://src/ImageViewportDisplay.gd" id="4_pbpx2"] -[ext_resource type="Script" uid="uid://b6r8rigubdctk" path="res://src/Camera.gd" id="5_hkdq6"] -[ext_resource type="Texture2D" uid="uid://d2nwchyd6huob" path="res://src/assets/bg.png" id="6_kokaf"] -[ext_resource type="Theme" uid="uid://cwqlns34rj3vx" path="res://src/theme.tres" id="6_rjp5f"] -[ext_resource type="Script" uid="uid://bxgmf2ny7yuc8" path="res://src/MainUI.gd" id="7_5puhk"] -[ext_resource type="Script" uid="uid://bh0gpu3i2p47f" path="res://src/VersionLabel.gd" id="8_kod8x"] - -[sub_resource type="ShaderMaterial" id="ShaderMaterial_y2ea0"] -shader = ExtResource("3_0fllm") -shader_parameter/zoom_level = Vector2(1, 1) - -[sub_resource type="ViewportTexture" id="ViewportTexture_lct1c"] -viewport_path = NodePath("Compositor") - -[sub_resource type="LabelSettings" id="LabelSettings_6o860"] -font_size = 12 -shadow_color = Color(0, 0, 0, 1) - -[node name="Main" type="Node2D"] -script = ExtResource("1_64y3g") - -[node name="Compositor" type="SubViewport" parent="."] -unique_name_in_owner = true -script = ExtResource("2_4ykh7") - -[node name="ImageViewportDisplay" type="Sprite2D" parent="."] -unique_name_in_owner = true -material = SubResource("ShaderMaterial_y2ea0") -texture = SubResource("ViewportTexture_lct1c") -script = ExtResource("4_pbpx2") - -[node name="Camera" type="Camera2D" parent="."] -unique_name_in_owner = true -offset = Vector2(0, -64) -script = ExtResource("5_hkdq6") - -[node name="CanvasLayerBg" type="CanvasLayer" parent="."] -layer = -1 - -[node name="Control" type="Control" parent="CanvasLayerBg"] -layout_mode = 3 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="TextureRect" type="TextureRect" parent="CanvasLayerBg/Control"] -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -texture = ExtResource("6_kokaf") -stretch_mode = 1 - -[node name="CanvasLayer" type="CanvasLayer" parent="."] - -[node name="MainUI" type="Control" parent="CanvasLayer"] -unique_name_in_owner = true -layout_mode = 3 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -pivot_offset = Vector2(320, 320) -theme = ExtResource("6_rjp5f") -script = ExtResource("7_5puhk") - -[node name="OpenShaderDialog" type="FileDialog" parent="CanvasLayer/MainUI"] -unique_name_in_owner = true -auto_translate_mode = 1 -title = "Load Shader" -size = Vector2i(521, 175) -ok_button_text = "Open" -mode_overrides_title = false -file_mode = 0 -access = 2 -filters = PackedStringArray("*.gdshader") -use_native_dialog = true - -[node name="SaveImageDialog" type="FileDialog" parent="CanvasLayer/MainUI"] -unique_name_in_owner = true -auto_translate_mode = 1 -title = "Export Image" -size = Vector2i(661, 175) -mode_overrides_title = false -access = 2 -filters = PackedStringArray("*.png") -use_native_dialog = true - -[node name="ErrorMessageDialog" type="AcceptDialog" parent="CanvasLayer/MainUI"] -unique_name_in_owner = true -auto_translate_mode = 1 -title = "Status" -initial_position = 2 -size = Vector2i(256, 128) -popup_window = true -ok_button_text = "Close" - -[node name="OpenShaderButton" type="Button" parent="CanvasLayer/MainUI"] -unique_name_in_owner = true -layout_mode = 1 -offset_left = 16.0 -offset_top = 16.0 -offset_right = 128.0 -offset_bottom = 48.0 -text = "Open Shader" - -[node name="SaveImageButton" type="Button" parent="CanvasLayer/MainUI"] -unique_name_in_owner = true -layout_mode = 1 -offset_left = 144.0 -offset_top = 16.0 -offset_right = 216.0 -offset_bottom = 48.0 -disabled = true -text = "Export" - -[node name="FitImageButton" type="Button" parent="CanvasLayer/MainUI"] -unique_name_in_owner = true -layout_mode = 1 -anchors_preset = 1 -anchor_left = 1.0 -anchor_right = 1.0 -offset_left = -176.0 -offset_top = 16.0 -offset_right = -128.0 -offset_bottom = 48.0 -grow_horizontal = 0 -text = "Fit" - -[node name="ApplyShaderButton" type="Button" parent="CanvasLayer/MainUI"] -unique_name_in_owner = true -layout_mode = 1 -anchors_preset = 1 -anchor_left = 1.0 -anchor_right = 1.0 -offset_left = -112.0 -offset_top = 16.0 -offset_right = -16.0 -offset_bottom = 48.0 -grow_horizontal = 0 -text = "Apply (F5)" - -[node name="StatusIndicator" type="TextureButton" parent="CanvasLayer/MainUI"] -unique_name_in_owner = true -layout_mode = 1 -anchors_preset = 1 -anchor_left = 1.0 -anchor_right = 1.0 -offset_left = -220.0 -offset_top = 21.0 -offset_right = -196.0 -offset_bottom = 45.0 -grow_horizontal = 0 -disabled = true -ignore_texture_size = true -stretch_mode = 0 - -[node name="VersionLabel" type="Label" parent="CanvasLayer/MainUI"] -layout_mode = 1 -anchors_preset = 12 -anchor_top = 1.0 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 16.0 -offset_top = -24.0 -offset_right = -16.0 -grow_horizontal = 2 -grow_vertical = 0 -label_settings = SubResource("LabelSettings_6o860") -horizontal_alignment = 1 -vertical_alignment = 1 -script = ExtResource("8_kod8x") - -[connection signal="canceled" from="CanvasLayer/MainUI/OpenShaderDialog" to="CanvasLayer/MainUI" method="_on_open_shader_dialog_canceled"] -[connection signal="confirmed" from="CanvasLayer/MainUI/OpenShaderDialog" to="CanvasLayer/MainUI" method="_on_open_shader_dialog_confirmed"] -[connection signal="file_selected" from="CanvasLayer/MainUI/OpenShaderDialog" to="CanvasLayer/MainUI" method="_on_open_shader_dialog_file_selected"] -[connection signal="canceled" from="CanvasLayer/MainUI/SaveImageDialog" to="CanvasLayer/MainUI" method="_on_save_image_dialog_canceled"] -[connection signal="confirmed" from="CanvasLayer/MainUI/SaveImageDialog" to="CanvasLayer/MainUI" method="_on_save_image_dialog_confirmed"] -[connection signal="file_selected" from="CanvasLayer/MainUI/SaveImageDialog" to="CanvasLayer/MainUI" method="_on_save_image_dialog_file_selected"] -[connection signal="pressed" from="CanvasLayer/MainUI/OpenShaderButton" to="CanvasLayer/MainUI" method="_on_open_shader_button_pressed"] -[connection signal="pressed" from="CanvasLayer/MainUI/SaveImageButton" to="CanvasLayer/MainUI" method="_on_save_image_button_pressed"] -[connection signal="pressed" from="CanvasLayer/MainUI/FitImageButton" to="CanvasLayer/MainUI" method="_on_fit_image_button_pressed"] -[connection signal="pressed" from="CanvasLayer/MainUI/ApplyShaderButton" to="CanvasLayer/MainUI" method="_on_apply_shader_button_pressed"] -[connection signal="pressed" from="CanvasLayer/MainUI/StatusIndicator" to="CanvasLayer/MainUI" method="_on_status_indicator_pressed"] diff --git a/src/shader/ivd_outline.gdshader b/src/shader/ivd_outline.gdshader index 78bfe77..14ce6e0 100644 --- a/src/shader/ivd_outline.gdshader +++ b/src/shader/ivd_outline.gdshader @@ -11,6 +11,6 @@ void fragment() { UV.x > 1.0-t.x || UV.y > 1.0-t.y ) { - COLOR = mix(COLOR, vec4(0.5), 0.5); + COLOR = mix(COLOR, vec4(1.0), 0.5); } } diff --git a/src/shader/ivd_outline.gdshader.uid b/src/shader/ivd_outline.gdshader.uid deleted file mode 100644 index b42ac31..0000000 --- a/src/shader/ivd_outline.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ctk7jomfyx0fh diff --git a/src/shader/template.gdshader b/src/shader/template.gdshader new file mode 100644 index 0000000..be6c5cc --- /dev/null +++ b/src/shader/template.gdshader @@ -0,0 +1,7 @@ +shader_type canvas_item; + +//!load /path/to/your/image + +void fragment() { + // Called for every pixel the material is visible on. +} diff --git a/src/theme.tres b/src/theme.tres deleted file mode 100644 index 782d3e9..0000000 --- a/src/theme.tres +++ /dev/null @@ -1,57 +0,0 @@ -[gd_resource type="Theme" load_steps=4 format=3 uid="uid://cwqlns34rj3vx"] - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_bm5o2"] -content_margin_left = 4.0 -content_margin_top = 4.0 -content_margin_right = 4.0 -content_margin_bottom = 4.0 -bg_color = Color(0.1, 0.1, 0.1, 0.3) -border_width_left = 1 -border_width_top = 1 -border_width_right = 1 -border_width_bottom = 1 -border_color = Color(1, 1, 1, 0.27451) -corner_radius_top_left = 3 -corner_radius_top_right = 3 -corner_radius_bottom_right = 3 -corner_radius_bottom_left = 3 -corner_detail = 5 - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_l0k8a"] -content_margin_left = 4.0 -content_margin_top = 4.0 -content_margin_right = 4.0 -content_margin_bottom = 4.0 -bg_color = Color(0.225, 0.225, 0.225, 0.6) -border_width_left = 1 -border_width_top = 1 -border_width_right = 1 -border_width_bottom = 1 -border_color = Color(1, 1, 1, 0.784314) -corner_radius_top_left = 3 -corner_radius_top_right = 3 -corner_radius_bottom_right = 3 -corner_radius_bottom_left = 3 -corner_detail = 5 - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_1dkyv"] -content_margin_left = 4.0 -content_margin_top = 4.0 -content_margin_right = 4.0 -content_margin_bottom = 4.0 -bg_color = Color(0.1, 0.1, 0.1, 0.6) -border_width_left = 1 -border_width_top = 1 -border_width_right = 1 -border_width_bottom = 1 -border_color = Color(1, 1, 1, 0.509804) -corner_radius_top_left = 3 -corner_radius_top_right = 3 -corner_radius_bottom_right = 3 -corner_radius_bottom_left = 3 -corner_detail = 5 - -[resource] -Button/styles/disabled = SubResource("StyleBoxFlat_bm5o2") -Button/styles/hover = SubResource("StyleBoxFlat_l0k8a") -Button/styles/normal = SubResource("StyleBoxFlat_1dkyv") diff --git a/tools/get_version.gd b/tools/get_version.gd deleted file mode 100644 index 8384f1b..0000000 --- a/tools/get_version.gd +++ /dev/null @@ -1,7 +0,0 @@ -extends SceneTree - -# godot --headless --no-header -s tools/get_version.gd - -func _init() -> void: - print(ProjectSettings.get_setting("application/config/version")) - quit(0) diff --git a/tools/get_version.gd.uid b/tools/get_version.gd.uid deleted file mode 100644 index e14829d..0000000 --- a/tools/get_version.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cdhqbascy6pvy