diff --git a/.gitignore b/.gitignore
index 852a042..99ff9ef 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,9 +13,8 @@ data_*/
mono_crash.*.json
# Builds
-*.x86_64
-godot.*.template_release.*
dist/*
+!dist/.gitkeep
screenshot.png.import
diff --git a/LICENSE b/LICENSE
index ba50b01..920dc4f 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,28 +1,21 @@
-BSD 3-Clause License
+MIT License
-Copyright (c) 2025, Julian Müller (ChaoticByte)
+Copyright (c) 2024 Julian Müller (ChaoticByte)
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
+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:
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-3. Neither the name of the copyright holder nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+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.
diff --git a/README.md b/README.md
index a12517b..a7dcfea 100644
--- a/README.md
+++ b/README.md
@@ -1,156 +1,39 @@
-
Fragmented
+GlitchApp

-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
-- Linux
+- Linux [tested]
+- Windows
-You can find the latest releases [here](https://github.com/ChaoticByte/Fragmented/releases/latest).
+You can find the latest releases [here](https://github.com/ChaoticByte/GlitchApp/releases/latest).
## 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 application includes presets. You can use them as a starting-point to write your own filters.
+Just load an image, apply a preset, edit the code and hit `F5` to see the changes.
-**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.**
-
-### Load TEXTURE using the `//!load` directive
+### Load additional images using the `//!load` directive
```glsl
-//!load
-```
-
-The main image file will be read and available as the sampler2D `TEXTURE`.
-
-#### Load additional images
-
-```glsl
-//!load+
-
+//!load
uniform sampler2D ;
```
-Have a look at the `place_texture.gdshader` example.
-
-### Have multiple steps with `//!steps n`
-
-You can apply your shaderfile multiple times. At every additional step, `TEXTURE` is the result of the previous step. This can be used to chain effects that cannot be easily chained otherwise.
-
-To query the current step index, a `STEP` uniform is automatically injected. If `steps` is set to `0`, your shader won't be applied at all.
-
-Example:
-
-```glsl
-//!load ...
-//!steps 5
-
-uniform int STEP;
-uniform int STEPS;
-
-void fragment() {
- if (STEP == 0) {
- ...
- } else if (STEP == 1) {
- ...
- } else if (STEP == STEPS-1) {
- ...
- }
-}
-```
-
-## Shaderlib
-
-This repo comes with a (still small) shader library including pre-written functions and more.
-Have a look at the `shaderlib` folder.
-
-Here is an example:
+With this you can load additional images into your shader.
+Have a look at the `Mix` preset:
```glsl
shader_type canvas_item;
-#include "./shaderlib/oklab.gdshaderinc"
-
-//!load ./images/swamp.jpg
+//!load img2 ./icon.png
+uniform sampler2D img2: repeat_enable, filter_nearest;
void fragment() {
- vec4 oklab = rgb2oklab(COLOR);
- vec4 oklch = oklab2oklch(oklab);
- oklch.z -= 2.0;
- COLOR = oklab2rgb(oklch2oklab(oklch));
+ COLOR = mix(COLOR, texture(img2, UV), .5);
}
```
-
-## Commandline interface
-
-You can run Fragmented from the commandline or scripts.
-
-> Note: Headless mode is not supported. Using the commandline interface still opens a window.
-
-### Usage
-
-```
-~ Fragmented CLI ~
--================-
-
-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)
-
-```
-
-### 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.
-
-#### Examples
-
-```
-./Fragmented apply --shader ./examples/oklab.gdshader --output ./output.png
-```
-
-```
-./Fragmented apply --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/build-template/Containerfile b/build-template/Containerfile
deleted file mode 100644
index b1a0c48..0000000
--- a/build-template/Containerfile
+++ /dev/null
@@ -1,20 +0,0 @@
-
-MAINTAINER ChaoticByte
-
-# Using Ubuntu 20.04
-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
-
-FROM os-base AS clone-src
-
-RUN git clone https://github.com/godotengine/godot.git -b 4.4-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
diff --git a/build-template/build.sh b/build-template/build.sh
deleted file mode 100755
index feff902..0000000
--- a/build-template/build.sh
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-
-function log {
- echo -e "\033[1;36m***** $@ *****\033[0m"
-}
-
-log " "
-log "Fragmented - Godot Build Template Builder"
-log " "
-
-cd $(dirname $0)
-log Switched to $(pwd)
-
-tmpsuffix=$(date +%s%N)
-image_name=fragmented-godot-template-builder
-container_name=${image_name}-${tmpsuffix}
-output_file=godot.linuxbsd.template_release.x86_64
-
-log Building image ${image_name} ...
-buildah build -t ${image_name}
-log Building godot build template with container ${container_name} ...
-podman run --name ${container_name} localhost/${image_name}:latest
-log Copying ${output_file} from container to $(realpath ./${output_file})
-podman cp ${container_name}:/godot-src/bin/${output_file} ./${output_file}
-log Removing container ${container_name}
-podman container rm ${container_name}
-log Done :D
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
deleted file mode 100644
index fa4d87d..0000000
--- a/examples/blur.gdshader
+++ /dev/null
@@ -1,8 +0,0 @@
-shader_type canvas_item;
-
-//!load ./images/swamp.jpg
-#include "./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
deleted file mode 100644
index f490db4..0000000
--- a/examples/color_and_pixelate.gdshader
+++ /dev/null
@@ -1,14 +0,0 @@
-shader_type canvas_item;
-
-#include "./shaderlib/hsv.gdshaderinc"
-#include "./shaderlib/pixelate.gdshaderinc"
-
-//!load ./images/swamp.jpg
-
-void fragment() {
- COLOR = pixelate(TEXTURE, UV, 200.0);
- vec4 hsv = rgb2hsv(COLOR);
- hsv.xyz += vec3(0.65, .42-(hsv.y*.3), -.125);
- hsv.xyz *= vec3(1.0, 1.0, 1.25);
- COLOR = hsv2rgb(hsv);
-}
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
deleted file mode 100644
index 229a8da..0000000
--- a/examples/denoise.gdshader
+++ /dev/null
@@ -1,9 +0,0 @@
-shader_type canvas_item;
-
-//!load ./images/noisy.png
-
-#include "./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
deleted file mode 100644
index d662b8c..0000000
--- a/examples/images/CREDITS.md
+++ /dev/null
@@ -1,6 +0,0 @@
-
-# Example Images
-
-- 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/grass.png b/examples/images/grass.png
deleted file mode 100644
index bb7e120..0000000
Binary files a/examples/images/grass.png and /dev/null differ
diff --git a/examples/images/grass.png.import b/examples/images/grass.png.import
deleted file mode 100644
index 327f716..0000000
--- a/examples/images/grass.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="CompressedTexture2D"
-uid="uid://c1mh1d2f3u4ju"
-path="res://.godot/imported/grass.png-61a458998da568ce60ccb8a0c7caaf6d.ctex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://examples/images/grass.png"
-dest_files=["res://.godot/imported/grass.png-61a458998da568ce60ccb8a0c7caaf6d.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/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/images/noisy.png b/examples/images/noisy.png
deleted file mode 100644
index 08e0664..0000000
Binary files a/examples/images/noisy.png and /dev/null differ
diff --git a/examples/images/noisy.png.import b/examples/images/noisy.png.import
deleted file mode 100644
index e8bab73..0000000
--- a/examples/images/noisy.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="CompressedTexture2D"
-uid="uid://cfe2d0qes5x87"
-path="res://.godot/imported/noisy.png-1b2e79340785c6c0f50d5bad5ce97356.ctex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://examples/images/noisy.png"
-dest_files=["res://.godot/imported/noisy.png-1b2e79340785c6c0f50d5bad5ce97356.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/images/swamp.jpg b/examples/images/swamp.jpg
deleted file mode 100644
index d7bdf3c..0000000
Binary files a/examples/images/swamp.jpg and /dev/null differ
diff --git a/examples/images/swamp.jpg.import b/examples/images/swamp.jpg.import
deleted file mode 100644
index e0efe23..0000000
--- a/examples/images/swamp.jpg.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="CompressedTexture2D"
-uid="uid://ckjb0agn5btv7"
-path="res://.godot/imported/swamp.jpg-1dfdcd52a5ef03d42a82a7f06acefa98.ctex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://examples/images/swamp.jpg"
-dest_files=["res://.godot/imported/swamp.jpg-1dfdcd52a5ef03d42a82a7f06acefa98.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 b/examples/lowpass.gdshader
deleted file mode 100644
index a84c2a2..0000000
--- a/examples/lowpass.gdshader
+++ /dev/null
@@ -1,13 +0,0 @@
-shader_type canvas_item;
-
-//!load ./images/swamp.jpg
-
-// Settings
-const float threshold = 0.6;
-//
-
-void fragment() {
- vec4 tex = texture(TEXTURE , UV);
- COLOR.rgb = min(tex.rgb, vec3(threshold));
- COLOR.a = tex.a;
-}
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
deleted file mode 100644
index fd7883e..0000000
--- a/examples/multistep_distort.gdshader
+++ /dev/null
@@ -1,22 +0,0 @@
-shader_type canvas_item;
-
-//!steps 9
-//!load ./images/swamp.jpg
-
-uniform int STEP;
-
-const float strength = 0.01;
-
-void fragment() {
- float v;
- if (STEP % 3 == 0) {
- v = COLOR.r; // 3 times
- } else if (STEP % 3 == 0) {
- v = COLOR.g; // 3 times
- } else {
- v = COLOR.b; // 3 times
- }
- vec2 uv = UV;
- uv.y -= v * strength;
- COLOR = texture(TEXTURE, uv);
-}
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
deleted file mode 100644
index 08f46b5..0000000
--- a/examples/oklab.gdshader
+++ /dev/null
@@ -1,12 +0,0 @@
-shader_type canvas_item;
-
-#include "./shaderlib/oklab.gdshaderinc"
-
-//!load ./images/swamp.jpg
-
-void fragment() {
- vec4 oklab = rgb2oklab(COLOR);
- vec4 oklch = oklab2oklch(oklab);
- oklch.z -= 2.0;
- COLOR = oklab2rgb(oklch2oklab(oklch));
-}
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
deleted file mode 100644
index b0c50ca..0000000
--- a/examples/place_texture.gdshader
+++ /dev/null
@@ -1,15 +0,0 @@
-shader_type canvas_item;
-
-#include "./shaderlib/place_texture.gdshaderinc"
-#include "./shaderlib/common.gdshaderinc"
-
-//!load ./images/swamp.jpg
-//!load+ img2 ./images/grass.png
-
-uniform sampler2D img2: repeat_disable, filter_nearest;
-
-void fragment() {
- vec4 grass = place_texture(img2, UV, TEXTURE_PIXEL_SIZE, vec2(0, .47), vec2(1));
- grass.rgb += (vec3(0.02, 0.07, 0.1) - ((UV.y - .8) * 0.15)); // color correction
- COLOR = alpha_blend(COLOR, grass);
-}
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..8f9be37 100644
--- a/export_presets.cfg
+++ b/export_presets.cfg
@@ -1,31 +1,29 @@
[preset.0]
name="Linux/X11"
-platform="Linux"
+platform="Linux/X11"
runnable=true
-advanced_options=false
dedicated_server=false
custom_features=""
export_filter="all_resources"
include_filter=""
-exclude_filter="screenshot.png, examples/*, shaderlib/*, tools/*, build-template/*"
-export_path="dist/Fragmented.x86_64"
-patches=PackedStringArray()
+exclude_filter=""
+export_path="dist/GlitchApp.x86_64"
encryption_include_filters=""
encryption_exclude_filters=""
-seed=0
encrypt_pck=false
encrypt_directory=false
-script_export_mode=2
[preset.0.options]
custom_template/debug=""
-custom_template/release="./build-template/godot.linuxbsd.template_release.x86_64"
+custom_template/release=""
debug/export_console_wrapper=1
binary_format/embed_pck=true
-texture_format/s3tc_bptc=true
-texture_format/etc2_astc=false
+texture_format/bptc=true
+texture_format/s3tc=true
+texture_format/etc=false
+texture_format/etc2=false
binary_format/architecture="x86_64"
ssh_remote_deploy/enabled=false
ssh_remote_deploy/host="user@host_ip"
@@ -39,7 +37,66 @@ unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\"
ssh_remote_deploy/cleanup_script="#!/usr/bin/env bash
kill $(pgrep -x -f \"{temp_dir}/{exe_name} {cmd_args}\")
rm -rf \"{temp_dir}\""
+
+[preset.1]
+
+name="Windows Desktop"
+platform="Windows Desktop"
+runnable=true
+dedicated_server=false
+custom_features=""
+export_filter="all_resources"
+include_filter=""
+exclude_filter=""
+export_path="dist/GlitchApp.exe"
+encryption_include_filters=""
+encryption_exclude_filters=""
+encrypt_pck=false
+encrypt_directory=false
+
+[preset.1.options]
+
+custom_template/debug=""
+custom_template/release=""
+debug/export_console_wrapper=1
+binary_format/embed_pck=true
texture_format/bptc=true
texture_format/s3tc=true
texture_format/etc=false
texture_format/etc2=false
+binary_format/architecture="x86_64"
+codesign/enable=false
+codesign/timestamp=true
+codesign/timestamp_server_url=""
+codesign/digest_algorithm=1
+codesign/description=""
+codesign/custom_options=PackedStringArray()
+application/modify_resources=true
+application/icon=""
+application/console_wrapper_icon=""
+application/icon_interpolation=4
+application/file_version=""
+application/product_version=""
+application/company_name=""
+application/product_name="GlitchApp"
+application/file_description=""
+application/copyright="ChaoticByte"
+application/trademarks=""
+application/export_angle=0
+ssh_remote_deploy/enabled=false
+ssh_remote_deploy/host="user@host_ip"
+ssh_remote_deploy/port="22"
+ssh_remote_deploy/extra_args_ssh=""
+ssh_remote_deploy/extra_args_scp=""
+ssh_remote_deploy/run_script="Expand-Archive -LiteralPath '{temp_dir}\\{archive_name}' -DestinationPath '{temp_dir}'
+$action = New-ScheduledTaskAction -Execute '{temp_dir}\\{exe_name}' -Argument '{cmd_args}'
+$trigger = New-ScheduledTaskTrigger -Once -At 00:00
+$settings = New-ScheduledTaskSettingsSet
+$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings
+Register-ScheduledTask godot_remote_debug -InputObject $task -Force:$true
+Start-ScheduledTask -TaskName godot_remote_debug
+while (Get-ScheduledTask -TaskName godot_remote_debug | ? State -eq running) { Start-Sleep -Milliseconds 100 }
+Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue"
+ssh_remote_deploy/cleanup_script="Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue
+Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue
+Remove-Item -Recurse -Force '{temp_dir}'"
diff --git a/src/assets/icon.png b/icon.png
similarity index 100%
rename from src/assets/icon.png
rename to icon.png
diff --git a/src/assets/icon.png.import b/icon.png.import
similarity index 73%
rename from src/assets/icon.png.import
rename to icon.png.import
index d1a6196..a0840e4 100644
--- a/src/assets/icon.png.import
+++ b/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-487276ed1e3a0c39cad0279d744ee560.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://icon.png"
+dest_files=["res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"]
[params]
diff --git a/project.godot b/project.godot
index 95da5af..6ae1868 100644
--- a/project.godot
+++ b/project.godot
@@ -10,23 +10,24 @@ 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/name="Glitch"
+config/version="v3.3"
+run/main_scene="res://scenes/main.tscn"
+config/features=PackedStringArray("4.2", "Mobile")
+run/low_processor_mode=true
+config/icon="res://icon.png"
[autoload]
-Filesystem="*res://src/Filesystem.gd"
-ShaderDirectiveParser="*res://src/ShaderDirectiveParser.gd"
+ShaderPresets="*res://src/presets/Presets.gd"
+Globals="*res://src/Globals.gd"
[display]
-window/size/viewport_width=640
-window/size/viewport_height=672
+window/size/viewport_width=1280
+window/size/viewport_height=720
+window/size/mode=2
window/energy_saving/keep_screen_on=false
-window/subwindows/embed_subwindows=false
[editor_plugins]
@@ -37,15 +38,15 @@ enabled=PackedStringArray()
zoom_out={
"deadzone": 0.5,
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":16,"position":Vector2(244, 15),"global_position":Vector2(248, 56),"factor":1.0,"button_index":5,"canceled":false,"pressed":true,"double_click":false,"script":null)
-, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":true,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":45,"physical_keycode":0,"key_label":0,"unicode":45,"location":0,"echo":false,"script":null)
-, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":true,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194435,"key_label":0,"unicode":45,"location":0,"echo":false,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":true,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":45,"physical_keycode":0,"key_label":0,"unicode":45,"echo":false,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":true,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194435,"key_label":0,"unicode":45,"echo":false,"script":null)
]
}
zoom_in={
"deadzone": 0.5,
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":8,"position":Vector2(270, 19),"global_position":Vector2(274, 60),"factor":1.0,"button_index":4,"canceled":false,"pressed":true,"double_click":false,"script":null)
-, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":true,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":43,"physical_keycode":0,"key_label":0,"unicode":43,"location":0,"echo":false,"script":null)
-, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":true,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194437,"key_label":0,"unicode":43,"location":0,"echo":false,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":true,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":43,"physical_keycode":0,"key_label":0,"unicode":43,"echo":false,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":true,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194437,"key_label":0,"unicode":43,"echo":false,"script":null)
]
}
drag={
@@ -55,12 +56,12 @@ drag={
}
apply_shader={
"deadzone": 0.5,
-"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194336,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194336,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
]
}
save_shader={
"deadzone": 0.5,
-"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":true,"meta_pressed":false,"pressed":false,"keycode":83,"physical_keycode":0,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null)
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":true,"meta_pressed":false,"pressed":false,"keycode":83,"physical_keycode":0,"key_label":0,"unicode":115,"echo":false,"script":null)
]
}
@@ -69,5 +70,4 @@ save_shader={
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..e49b48c
--- /dev/null
+++ b/scenes/main.tscn
@@ -0,0 +1,254 @@
+[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/ImageViewport.gd" id="2_hvo65"]
+[ext_resource type="Script" path="res://src/ImageViewportDisplays.gd" id="3_n4itb"]
+[ext_resource type="Shader" path="res://src/ui_background.gdshader" id="4_ty3qx"]
+[ext_resource type="Script" path="res://src/UIAppVersion.gd" id="5_o1ggv"]
+[ext_resource type="Script" path="res://src/Editor.gd" id="7_g8bap"]
+[ext_resource type="Script" path="res://src/Camera.gd" id="8_mls06"]
+
+[sub_resource type="ViewportTexture" id="ViewportTexture_lct1c"]
+viewport_path = NodePath("ImageViewport")
+
+[sub_resource type="ShaderMaterial" id="ShaderMaterial_onhxk"]
+shader = ExtResource("4_ty3qx")
+
+[node name="Main" type="Node2D"]
+script = ExtResource("1_2625y")
+
+[node name="ImageViewport" type="SubViewport" parent="."]
+disable_3d = true
+canvas_item_default_texture_filter = 0
+render_target_update_mode = 4
+script = ExtResource("2_hvo65")
+
+[node name="ImageSprite" type="Sprite2D" parent="ImageViewport"]
+
+[node name="ImageViewportDisplay" type="Sprite2D" parent="."]
+texture = SubResource("ViewportTexture_lct1c")
+script = ExtResource("3_n4itb")
+
+[node name="UI_Layer" type="CanvasLayer" parent="."]
+
+[node name="FokusStealer" type="Control" parent="UI_Layer"]
+layout_mode = 3
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+focus_mode = 2
+
+[node name="UserInterfaceContainer" type="Control" parent="UI_Layer"]
+layout_mode = 3
+anchor_right = 0.225
+anchor_bottom = 1.0
+offset_right = 288.0
+grow_horizontal = 2
+grow_vertical = 2
+
+[node name="Background" type="ColorRect" parent="UI_Layer/UserInterfaceContainer"]
+material = SubResource("ShaderMaterial_onhxk")
+layout_mode = 1
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+focus_mode = 2
+color = Color(1, 1, 1, 0)
+
+[node name="AppName" type="Label" parent="UI_Layer/UserInterfaceContainer"]
+layout_mode = 0
+offset_left = 24.0
+offset_top = 24.0
+offset_right = 208.0
+offset_bottom = 56.0
+theme_override_font_sizes/font_size = 20
+text = "GlitchApp
+"
+vertical_alignment = 2
+
+[node name="AppVersion" type="Label" parent="UI_Layer/UserInterfaceContainer"]
+layout_mode = 0
+offset_left = 128.0
+offset_top = 24.0
+offset_right = 208.0
+offset_bottom = 56.0
+theme_override_font_sizes/font_size = 14
+text = "v0
+"
+vertical_alignment = 2
+script = ExtResource("5_o1ggv")
+
+[node name="OpenImageDialog" type="FileDialog" parent="UI_Layer/UserInterfaceContainer"]
+title = "Load Image"
+size = Vector2i(521, 159)
+ok_button_text = "Open"
+mode_overrides_title = false
+file_mode = 0
+access = 2
+use_native_dialog = true
+
+[node name="SaveImageDialog" type="FileDialog" parent="UI_Layer/UserInterfaceContainer"]
+title = "Export Image"
+size = Vector2i(661, 159)
+ok_button_text = "Save"
+mode_overrides_title = false
+access = 2
+filters = PackedStringArray("*.png")
+use_native_dialog = true
+
+[node name="OpenImageButton" type="Button" parent="UI_Layer/UserInterfaceContainer"]
+layout_mode = 1
+anchors_preset = 1
+anchor_left = 1.0
+anchor_right = 1.0
+offset_left = -360.0
+offset_top = 24.0
+offset_right = -248.0
+offset_bottom = 56.0
+grow_horizontal = 0
+text = "Load Image"
+
+[node name="SaveImageButton" type="Button" parent="UI_Layer/UserInterfaceContainer"]
+layout_mode = 1
+anchors_preset = 1
+anchor_left = 1.0
+anchor_right = 1.0
+offset_left = -240.0
+offset_top = 23.0
+offset_right = -120.0
+offset_bottom = 55.0
+grow_horizontal = 0
+text = "Export Image"
+
+[node name="FitImageButton" type="Button" parent="UI_Layer/UserInterfaceContainer"]
+layout_mode = 1
+anchors_preset = 1
+anchor_left = 1.0
+anchor_right = 1.0
+offset_left = -112.0
+offset_top = 24.0
+offset_right = -24.0
+offset_bottom = 56.0
+grow_horizontal = 0
+text = "Fit Image"
+
+[node name="Editor" type="Control" parent="UI_Layer/UserInterfaceContainer"]
+layout_mode = 1
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+offset_left = 24.0
+offset_top = 80.0
+offset_right = -24.0
+offset_bottom = -24.0
+grow_horizontal = 2
+grow_vertical = 2
+script = ExtResource("7_g8bap")
+
+[node name="OpenShaderDialog" type="FileDialog" parent="UI_Layer/UserInterfaceContainer/Editor"]
+title = "Load Shader"
+size = Vector2i(521, 159)
+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="UI_Layer/UserInterfaceContainer/Editor"]
+title = "Save Shader"
+size = Vector2i(661, 159)
+ok_button_text = "Save"
+mode_overrides_title = false
+access = 2
+filters = PackedStringArray("*.gdshader")
+use_native_dialog = true
+
+[node name="Label" type="Label" parent="UI_Layer/UserInterfaceContainer/Editor"]
+layout_mode = 0
+offset_right = 104.0
+offset_bottom = 32.0
+text = "Load Preset: "
+vertical_alignment = 1
+
+[node name="PresetOptions" type="OptionButton" parent="UI_Layer/UserInterfaceContainer/Editor"]
+layout_mode = 0
+offset_left = 104.0
+offset_right = 240.0
+offset_bottom = 32.0
+
+[node name="CodeEdit" type="CodeEdit" parent="UI_Layer/UserInterfaceContainer/Editor"]
+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="OpenShaderButton" type="Button" parent="UI_Layer/UserInterfaceContainer/Editor"]
+layout_mode = 1
+anchors_preset = 1
+anchor_left = 1.0
+anchor_right = 1.0
+offset_left = -216.0
+offset_right = -160.0
+offset_bottom = 32.0
+grow_horizontal = 0
+text = "Open"
+
+[node name="SaveShaderButton" type="Button" parent="UI_Layer/UserInterfaceContainer/Editor"]
+layout_mode = 1
+anchors_preset = 1
+anchor_left = 1.0
+anchor_right = 1.0
+offset_left = -152.0
+offset_right = -96.0
+offset_bottom = 32.0
+grow_horizontal = 0
+text = "Save"
+
+[node name="ApplyShaderButton" type="Button" parent="UI_Layer/UserInterfaceContainer/Editor"]
+layout_mode = 1
+anchors_preset = 1
+anchor_left = 1.0
+anchor_right = 1.0
+offset_left = -88.0
+offset_bottom = 32.0
+grow_horizontal = 0
+text = "Apply (F5)"
+
+[node name="Camera" type="Camera2D" parent="."]
+script = ExtResource("8_mls06")
+
+[connection signal="file_selected" from="UI_Layer/UserInterfaceContainer/OpenImageDialog" to="." method="_on_open_image_dialog_file_selected"]
+[connection signal="file_selected" from="UI_Layer/UserInterfaceContainer/SaveImageDialog" to="." method="_on_save_image_dialog_file_selected"]
+[connection signal="pressed" from="UI_Layer/UserInterfaceContainer/OpenImageButton" to="." method="_on_open_image_button_pressed"]
+[connection signal="pressed" from="UI_Layer/UserInterfaceContainer/SaveImageButton" to="." method="_on_save_image_button_pressed"]
+[connection signal="pressed" from="UI_Layer/UserInterfaceContainer/FitImageButton" to="Camera" method="_on_fit_image_button_pressed"]
+[connection signal="file_selected" from="UI_Layer/UserInterfaceContainer/Editor/OpenShaderDialog" to="UI_Layer/UserInterfaceContainer/Editor" method="_on_open_shader_dialog_file_selected"]
+[connection signal="file_selected" from="UI_Layer/UserInterfaceContainer/Editor/SaveShaderDialog" to="UI_Layer/UserInterfaceContainer/Editor" method="_on_save_shader_dialog_file_selected"]
+[connection signal="item_selected" from="UI_Layer/UserInterfaceContainer/Editor/PresetOptions" to="UI_Layer/UserInterfaceContainer/Editor" method="_on_preset_options_item_selected"]
+[connection signal="code_completion_requested" from="UI_Layer/UserInterfaceContainer/Editor/CodeEdit" to="UI_Layer/UserInterfaceContainer/Editor" method="_on_code_edit_code_completion_requested"]
+[connection signal="pressed" from="UI_Layer/UserInterfaceContainer/Editor/OpenShaderButton" to="UI_Layer/UserInterfaceContainer/Editor" method="_on_open_shader_button_pressed"]
+[connection signal="pressed" from="UI_Layer/UserInterfaceContainer/Editor/SaveShaderButton" to="UI_Layer/UserInterfaceContainer/Editor" method="_on_save_shader_button_pressed"]
+[connection signal="pressed" from="UI_Layer/UserInterfaceContainer/Editor/ApplyShaderButton" to="UI_Layer/UserInterfaceContainer/Editor" method="_on_apply_shader_button_pressed"]
diff --git a/screenshot.png b/screenshot.png
index ce0ac8a..5595ae5 100644
Binary files a/screenshot.png and b/screenshot.png differ
diff --git a/shaderlib/blur.gdshaderinc b/shaderlib/blur.gdshaderinc
deleted file mode 100644
index 339256d..0000000
--- a/shaderlib/blur.gdshaderinc
+++ /dev/null
@@ -1,32 +0,0 @@
-
-/*
- gaussian_blur adapted from https://godotshaders.com/shader/customizable-gausian-blur/
- original code by https://godotshaders.com/author/djbob-gaming-yt/
- maximum radius is 64
-*/
-vec4 gaussian_blur(sampler2D texture, vec2 uv, int radius, float sigma) {
- vec2 resolution = 1.0 / vec2(textureSize(texture, 0));
- // calculate kernel
- float kernel[64];
- float sum = 0.0;
- for (int i = 0; i <= radius; i++) {
- kernel[i] = exp(-0.5 * float(i * i) / (sigma * sigma));
- sum += i == 0 ? kernel[i] : 2.0 * kernel[i];
- }
- for (int i = 0; i <= radius; i++) {
- kernel[i] /= sum;
- }
- //
- vec4 final_color = vec4(0.0);
- float total_weight = 0.0;
- for (int x = -radius; x <= radius; x++) {
- for (int y = -radius; y <= radius; y++) {
- float weight = kernel[abs(x)] * kernel[abs(y)];
- vec2 offset = vec2(float(x), float(y)) * resolution;
- final_color += texture(texture, uv + offset) * weight;
- total_weight += weight;
- }
- }
- final_color /= total_weight;
- return final_color;
-}
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/common.gdshaderinc b/shaderlib/common.gdshaderinc
deleted file mode 100644
index 9352d6a..0000000
--- a/shaderlib/common.gdshaderinc
+++ /dev/null
@@ -1,27 +0,0 @@
-
-// inefficient cuberoot function
-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 b/shaderlib/denoise.gdshaderinc
deleted file mode 100644
index 585104d..0000000
--- a/shaderlib/denoise.gdshaderinc
+++ /dev/null
@@ -1,68 +0,0 @@
-
-/*
- glslSmartDenoise by Michele Morrone, adapted
- original code: https://github.com/BrutPitt/glslSmartDeNoise
- license of the original code:
-
- BSD 2-Clause License
-
- Copyright (c) 2019-2020 Michele Morrone
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- 1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-#define INV_SQRT_OF_2PI 0.39894228040143267793994605993439 // 1.0/SQRT_OF_2PI
-#define INV_PI 0.31830988618379067153776752674503
-
-vec4 smart_denoise(sampler2D tex, vec2 uv, float sigma, float kSigma, float threshold) {
- float radius = round(kSigma*sigma);
- float radQ = radius * radius;
-
- float invSigmaQx2 = .5 / (sigma * sigma); // 1.0 / (sigma^2 * 2.0)
- float invSigmaQx2PI = INV_PI * invSigmaQx2; // 1/(2 * PI * sigma^2)
-
- float invThresholdSqx2 = .5 / (threshold * threshold); // 1.0 / (sigma^2 * 2.0)
- float invThresholdSqrt2PI = INV_SQRT_OF_2PI / threshold; // 1.0 / (sqrt(2*PI) * sigma^2)
-
- vec4 centrPx = texture(tex,uv);
-
- float zBuff = 0.0;
- vec4 aBuff = vec4(0.0);
- vec2 size = vec2(textureSize(tex, 0));
-
- for (float dx = -radius; dx <= radius; dx++) {
- float pt = sqrt(radQ - dx * dx); // pt = yRadius: have circular trend
- for (float dy = -pt; dy <= pt; dy++) {
- vec2 d = vec2(dx, dy);
- float blurFactor = exp( -dot(d, d) * invSigmaQx2 ) * invSigmaQx2PI;
-
- vec4 walkPx = texture(tex,uv+d/size);
- vec4 dC = walkPx-centrPx;
- float deltaFactor = exp(-dot(dC, dC) * invThresholdSqx2) * invThresholdSqrt2PI * blurFactor;
-
- zBuff += deltaFactor;
- aBuff += deltaFactor*walkPx;
- }
- }
- return aBuff/zBuff;
-}
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/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 b/shaderlib/oklab.gdshaderinc
deleted file mode 100644
index 5a456c7..0000000
--- a/shaderlib/oklab.gdshaderinc
+++ /dev/null
@@ -1,70 +0,0 @@
-
-/*
- 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;
-
- float l_ = cbrt(l);
- float m_ = cbrt(m);
- float s_ = cbrt(s);
-
- return vec4(
- 0.2104542553f*l_ + 0.7936177850f*m_ - 0.0040720468f*s_,
- 1.9779984951f*l_ - 2.4285922050f*m_ + 0.4505937099f*s_,
- 0.0259040371f*l_ + 0.7827717662f*m_ - 0.8086757660f*s_,
- c.a
- );
-}
-
-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;
-
- float l = l_*l_*l_;
- float m = m_*m_*m_;
- float s = s_*s_*s_;
-
- return vec4(
- +4.0767416621f * l - 3.3077115913f * m + 0.2309699292f * s,
- -1.2684380046f * l + 2.6097574011f * m - 0.3413193965f * s,
- -0.0041960863f * l - 0.7034186147f * m + 1.7076147010f * s,
- c.a
- );
-}
-
-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)),
- atan(c.z, c.y),
- c.a
- );
-}
-
-vec4 oklch2oklab(vec4 c) {
- // oklch.z (hue) ranges from -3.6 to 3.6
- return vec4(
- c.x,
- c.y * cos(c.z),
- c.y * sin(c.z),
- c.a
- );
-}
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 b/shaderlib/pixelate.gdshaderinc
deleted file mode 100644
index d9b91f1..0000000
--- a/shaderlib/pixelate.gdshaderinc
+++ /dev/null
@@ -1,14 +0,0 @@
-
-// pixelate by lowering uv resolution
-vec4 pixelate(sampler2D tex, vec2 uv, float resolution_x) {
- vec2 texture_size = vec2(textureSize(tex, 0));
- vec2 ratio;
- if (texture_size.x > texture_size.y) {
- ratio = vec2(texture_size.x / texture_size.y, 1.0);
- }
- else {
- ratio = vec2(1.0, texture_size.y / texture_size.x);
- }
- vec2 r = ratio * resolution_x;
- return texture(tex, trunc(uv * r) / r);
-}
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 b/shaderlib/place_texture.gdshaderinc
deleted file mode 100644
index af57cce..0000000
--- a/shaderlib/place_texture.gdshaderinc
+++ /dev/null
@@ -1,21 +0,0 @@
-
-/*
- Load in a texture from a sampler2D with an offset and scale
- See examples/place_texture.gdshader
-*/
-vec4 place_texture(sampler2D sampler, vec2 uv, vec2 texture_pixel_size, vec2 offset, vec2 scale) {
- vec2 texture_size = vec2(textureSize(sampler, 0));
- // position of current pixel; sample color c
- vec2 pos = (uv - offset) / (texture_size*texture_pixel_size) / scale;
- vec4 c = texture(sampler, pos);
- // top-left bounds
- vec2 a = offset;
- // bottom-right bounds
- vec2 b = offset + (texture_size*texture_pixel_size) * scale;
- // check bounds
- if (
- a.x < uv.x && a.y < uv.y
- && b.x > uv.x && b.y > uv.y
- ) { return c; } // within bounds -> return color
- return vec4(0); // not within bounds -> return transparency
-}
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/src/Camera.gd b/src/Camera.gd
index 416e035..231add8 100644
--- a/src/Camera.gd
+++ b/src/Camera.gd
@@ -1,50 +1,42 @@
extends Camera2D
-@onready var image_viewport_display = %ImageViewportDisplay
-
var drag = false
+@onready var user_interface_container = get_parent().get_node("UI_Layer/UserInterfaceContainer")
+@onready var image_viewport = get_parent().get_node("ImageViewport")
+
func _input(event):
- if event.is_action_pressed("zoom_out"):
+ if event.is_action_pressed("zoom_out") && !Globals.camera_freeze:
zoom_out()
- elif event.is_action_pressed("zoom_in"):
+ elif event.is_action_pressed("zoom_in") && !Globals.camera_freeze:
zoom_in()
- if event.is_action_pressed("drag"):
- self.drag = true
+ if event.is_action_pressed("drag") && !Globals.camera_freeze:
+ drag = true
elif event.is_action_released("drag"):
- self.drag = false
- 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
+ drag = false
+ if drag && event is InputEventMouseMotion:
+ global_position -= event.relative / zoom
func fit_image():
- if Filesystem.original_image != null:
- var image_size = Filesystem.original_image.get_size()
+ if image_viewport.image_original_tex != null:
+ var ui_container_size = user_interface_container.size
+ var image_size = image_viewport.image_original_tex.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
- self.zoom = Vector2(zoomf, zoomf)
- self.global_position = Vector2(0, 0)
+ var zoomf = (viewport_size.x - ui_container_size.x) / image_size.x / 1.1
+ if zoomf * image_size.y > viewport_size.y:
+ zoomf = viewport_size.y / image_size.y / 1.1
+ zoom = Vector2(zoomf, zoomf)
+ global_position = Vector2(-((ui_container_size.x) / 2 / zoom.x), 0)
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()
+ zoom *= 1.2
+ global_position += old_mouse_pos - get_global_mouse_position()
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()
+ zoom *= 1/1.2
+ global_position += old_mouse_pos - get_global_mouse_position()
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..c006b86
--- /dev/null
+++ b/src/Editor.gd
@@ -0,0 +1,243 @@
+extends Control
+
+@onready var preset_options = $PresetOptions
+@onready var code_editor = $CodeEdit
+@onready var open_shader_dialog = $OpenShaderDialog
+@onready var save_shader_dialog = $SaveShaderDialog
+var selected_preset_name = ShaderPresets.default_preset
+var last_save_filepath = ""
+
+# # # # # # # # # # #
+# 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", "log", "exp2", "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",
+ "MODEL_MATRIX", "CANVAS_MATRIX", "SCREEN_MATRIX",
+ "INSTANCE_CUSTOM", "INSTANCE_ID",
+ "VERTEX_ID",
+ "AT_LIGHT_PASS",
+ "TEXTURE_PIXEL_SIZE",
+ "CUSTOM0", "CUSTOM1",
+ "SHADOW_VERTEX", "LIGHT_VERTEX",
+ "FRAGCOORD",
+ "NORMAL", "NORMAL_MAP", "NORMAL_MAP_DEPTH",
+ "TEXTURE", "NORMAL_TEXTURE",
+ "SCREEN_UV", "SCREEN_PIXEL_SIZE",
+ "POINT_COORD",
+]
+#
+# 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)
+ code_editor.update_code_completion_options(true)
+#
+# # # # # # # # # # # #
+
+func _camera_freeze():
+ Globals.camera_freeze = true
+
+func _camera_unfreeze():
+ Globals.camera_freeze = false
+
+func _ready():
+ code_editor.code_completion_enabled = true
+ code_editor.syntax_highlighter = ShaderSyntaxHighlighter.new()
+ for c in get_children():
+ c.connect("mouse_entered", _camera_freeze)
+ c.connect("mouse_exited", _camera_unfreeze)
+ update()
+
+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 _on_preset_options_item_selected(index):
+ selected_preset_name = preset_options.get_item_text(index)
+ Globals.shader = ShaderPresets.presets[selected_preset_name]
+ Globals.target_viewport.update()
+ update()
+ last_save_filepath = ""
+
+func update():
+ preset_options.clear()
+ # the following lines are weird af
+ var presets: Array[String] = []
+ var current_p_idx = 0
+ for p in ShaderPresets.presets:
+ presets.append(p)
+ if p == selected_preset_name:
+ current_p_idx = len(presets) - 1
+ preset_options.add_item(p)
+ preset_options.select(current_p_idx)
+ # weirdness ends here
+ code_editor.text = Globals.shader.code
+
+func _on_open_shader_button_pressed():
+ open_shader_dialog.show()
+
+func _on_save_shader_button_pressed():
+ if last_save_filepath == "":
+ save_shader_dialog.current_file = selected_preset_name + "_custom.gdshader"
+ else:
+ save_shader_dialog.current_path = last_save_filepath
+ save_shader_dialog.show()
+
+func _on_open_shader_dialog_file_selected(path):
+ var file = FileAccess.open(path, FileAccess.READ)
+ var shader_code = file.get_as_text()
+ var shader = Shader.new()
+ shader.code = shader_code
+ Globals.shader = shader
+ Globals.target_viewport.update()
+ update()
+ last_save_filepath = path
+
+func _on_save_shader_dialog_file_selected(path):
+ var file = FileAccess.open(path, FileAccess.WRITE)
+ var content = Globals.shader.code
+ file.store_string(content)
+ last_save_filepath = path
+
+func _on_apply_shader_button_pressed():
+ var shader = Shader.new()
+ shader.code = code_editor.text
+ Globals.shader = shader
+ Globals.target_viewport.update()
diff --git a/src/Filesystem.gd b/src/Filesystem.gd
deleted file mode 100644
index cb1ac7d..0000000
--- a/src/Filesystem.gd
+++ /dev/null
@@ -1,77 +0,0 @@
-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)
-
-var original_image: ImageTexture
-
-var additional_images: Dictionary
-var result: Image
-
-var last_image_savepath = ""
-var last_original_image_path = ""
-
-func get_absolute_path(p: String) -> String:
- # this only works on Linux!
- if !p.begins_with("/"):
- return self.cwd + "/" + p.lstrip("./")
- 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:
- self.last_image_savepath = path
- self.last_original_image_path = path
- return ""
- return error_string(err) + " " + path
-
-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:
- additional_images[key] = ImageTexture.create_from_image(img)
- return ""
- else:
- return error_string(err) + " " + path
-
-func save_result(path: String):
- print("Export ", path)
- var err = self.result.save_png(path)
- if err != OK:
- print("An error occured!")
- else:
- self.last_image_savepath = path
-
-func store_last_opened_file():
- var f = FileAccess.open("user://last_opened", FileAccess.WRITE)
- if f != null:
- f.store_pascal_string(shader_path)
- 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()
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/Globals.gd b/src/Globals.gd
new file mode 100644
index 0000000..3315890
--- /dev/null
+++ b/src/Globals.gd
@@ -0,0 +1,5 @@
+extends Node
+
+var camera_freeze = false
+@onready var shader: Shader = ShaderPresets.presets[ShaderPresets.default_preset]
+var target_viewport: SubViewport
diff --git a/src/ImageCompositor.gd b/src/ImageCompositor.gd
deleted file mode 100644
index 9f3e95a..0000000
--- a/src/ImageCompositor.gd
+++ /dev/null
@@ -1,123 +0,0 @@
-class_name ImageCompositor extends SubViewport
-
-var image_sprite: Sprite2D
-
-func _init() -> void:
- # Overwrite some variables
- self.render_target_update_mode = SubViewport.UPDATE_ALWAYS
- self.disable_3d = true
- self.transparent_bg = true
- self.canvas_item_default_texture_filter = Viewport.DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST
- self.image_sprite = Sprite2D.new()
-
-@onready var camera = %Camera
-@onready var image_viewport_display = %ImageViewportDisplay
-
-func _ready() -> void:
- # Add image sprite as child to be rendered
- self.add_child(image_sprite)
-
-var _fragment_function_regex: RegEx = RegEx.create_from_string(r'\s*void\s+fragment\s*\(\s*\)\s*{\s*')
-
-func validate_shader_compilation(shader: Shader) -> bool:
- # Inject code to validate shader compilation
- var shader_code = shader.code;
- # -> get position of fragment shader
- var fragment_function_match = _fragment_function_regex.search(shader.code)
- if fragment_function_match == null:
- return false
- # -> inject uniform
- var uniform_name = "shader_compilation_validate_" + str(randi_range(999999999, 100000000))
- var uniform_code_line = "\nuniform bool " + uniform_name + ";\n"
- shader_code = shader_code.insert(fragment_function_match.get_start(), uniform_code_line)
- # -> inject variable access to prevent that the uniform gets optimized away
- shader_code = shader_code.insert(fragment_function_match.get_end() + len(uniform_code_line), "\n" + uniform_name + ";\n")
- # apply shader code
- shader.code = shader_code
- # 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 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
- 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!"]
- var errors = []
- # load texture(s) from //!load directive -> TEXTURE
- var original_image_path = ""
- if overwrite_image_path == "":
- var m = ShaderDirectiveParser.parse_load_directive(shader.code)
- if len(m) < 1:
- errors.append("Didn't find a load directive!")
- return errors
- original_image_path = Filesystem.get_absolute_path(m[1])
- else:
- original_image_path = overwrite_image_path
- var fit_image = false
- if original_image_path != Filesystem.last_original_image_path:
- fit_image = true
- var err = Filesystem.load_original_image(original_image_path)
- if err != "":
- errors.append(err)
- image_viewport_display.hide()
- return errors
- # ... from //!load+ directives
- Filesystem.clear_additional_images()
- for n in ShaderDirectiveParser.parse_load_additional_directive(shader.code):
- err = Filesystem.load_additional_image(n[1], Filesystem.get_absolute_path(n[2]))
- if err != "":
- errors.append(err)
- if len(errors) > 0:
- return errors
- # apply textures
- 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
- # add images as shader parameters
- for key in Filesystem.additional_images:
- mat.set_shader_parameter(
- key, # uniform param name
- Filesystem.additional_images[key])
- # 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)
- # 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
- # 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/ImageViewport.gd b/src/ImageViewport.gd
new file mode 100644
index 0000000..7b98461
--- /dev/null
+++ b/src/ImageViewport.gd
@@ -0,0 +1,40 @@
+extends SubViewport
+
+@onready var image_sprite = $ImageSprite
+
+var image_original_tex: ImageTexture
+var image_result: Image
+var load_uniform_regex: RegEx
+
+func _ready():
+ load_uniform_regex = RegEx.new()
+ load_uniform_regex.compile(r'\/\/!load\s(\w*)\s(.*)')
+
+func set_original_image(image: Image):
+ image_original_tex = ImageTexture.create_from_image(image)
+ image_sprite.texture = image_original_tex
+ image_sprite.offset = image_original_tex.get_size() / 2
+ size = image_original_tex.get_size()
+
+func update():
+ if image_original_tex != null:
+ image_sprite.texture = image_original_tex
+ var mat = ShaderMaterial.new()
+ mat.shader = Globals.shader
+ # load images from //!load directives and apply them to
+ # the material as shader parameters
+ for m in load_uniform_regex.search_all(Globals.shader.code):
+ var u_image = Image.load_from_file(m.strings[2])
+ mat.set_shader_parameter(
+ m.strings[1], # uniform param name
+ ImageTexture.create_from_image(u_image))
+ # assign material
+ image_sprite.material = mat
+ # Get viewport texture
+ await RenderingServer.frame_post_draw # for good measure
+ image_result = get_texture().get_image()
+ image_sprite.material = null
+ image_sprite.texture = ImageTexture.create_from_image(image_result)
+
+func get_result():
+ return image_result
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/ImageViewportDisplay.gd b/src/ImageViewportDisplays.gd
similarity index 54%
rename from src/ImageViewportDisplay.gd
rename to src/ImageViewportDisplays.gd
index 7a9c827..d4817ca 100644
--- a/src/ImageViewportDisplay.gd
+++ b/src/ImageViewportDisplays.gd
@@ -1,10 +1,9 @@
extends Sprite2D
-func _ready() -> void:
- hide()
+@onready var camera = get_parent().get_node("Camera")
-func update_zoom_texture_filter(zoom: Vector2):
- if zoom.x >= 1.5:
+func _process(_delta):
+ if camera.zoom.x >= 1.5:
texture_filter = TEXTURE_FILTER_NEAREST_WITH_MIPMAPS
else:
texture_filter = TEXTURE_FILTER_LINEAR
diff --git a/src/Main.gd b/src/Main.gd
index dcf32b3..1f56020 100644
--- a/src/Main.gd
+++ b/src/Main.gd
@@ -1,126 +1,37 @@
-extends Node
+extends Node2D
-const BATCH_MODE_SUPPORTED_EXTS = [
- ".bmp", ".dds", ".exr", ".hdr", ".jpeg", ".jpg", ".ktx", ".png", ".svg", ".webp"
-]
-
-@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")
-
-func parse_custom_cmdline(args: PackedStringArray):
- var kwargs: Dictionary = {"--shader": null, "--output": null, "--load-image": null}
- var args_len = args.size()
- var i = 0
- while i < args_len:
- var a = args[i]
- if a in kwargs && args_len > i+1:
- i += 1
- kwargs[a] = args[i]
- 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()
+@onready var camera = $Camera
+@onready var image_viewport = $ImageViewport
+@onready var ui_container = $UI_Layer/UserInterfaceContainer
+@onready var ui_control_fileopen = $UI_Layer/UserInterfaceContainer/OpenImageDialog
+@onready var ui_control_filesave = $UI_Layer/UserInterfaceContainer/SaveImageDialog
+var last_save_filepath = ""
func _ready():
- var args = OS.get_cmdline_args()
- if len(args) > 0 and args[0] in ["apply", "help"]:
- # use the commandline interface
- cli(args)
- else:
- prepare_gui()
+ Globals.target_viewport = image_viewport
-func update_title(current_file: String = ""):
- if current_file == "":
- get_window().title = app_name + " - Viewer"
+func _on_open_image_button_pressed():
+ ui_control_fileopen.show()
+
+func _on_open_image_dialog_file_selected(path):
+ var img = Image.new()
+ var err = img.load(path)
+ if err == OK:
+ image_viewport.set_original_image(img)
+ image_viewport.update()
+ camera.fit_image()
+ last_save_filepath = path
else:
- get_window().title = current_file + " - " + app_name + " - Viewer"
+ print("An error occured!")
+
+func _on_save_image_button_pressed():
+ if image_viewport.get_result() != null:
+ ui_control_filesave.current_path = last_save_filepath
+ ui_control_filesave.show()
+
+func _on_save_image_dialog_file_selected(path):
+ var err = image_viewport.get_result().save_png(path)
+ if err != OK:
+ print("An error occured!")
+ else:
+ last_save_filepath = path
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 b/src/ShaderDirectiveParser.gd
deleted file mode 100644
index c06dc70..0000000
--- a/src/ShaderDirectiveParser.gd
+++ /dev/null
@@ -1,24 +0,0 @@
-extends Node
-
-var _load_regex: RegEx = RegEx.create_from_string(r'\/\/!load\s(.*)')
-var _load_additional_regex: RegEx = RegEx.create_from_string(r'\/\/!load\+\s(\w*)\s(.*)')
-var _iterate_regex: RegEx = RegEx.create_from_string(r'\/\/!steps\s([0-9]+)\s*')
-
-func parse_load_directive(shader_code: String) -> PackedStringArray:
- var regex_match = self._load_regex.search(shader_code)
- if regex_match == null:
- return []
- return regex_match.strings
-
-func parse_load_additional_directive(shader_code: String) -> Array[PackedStringArray]:
- var results : Array[PackedStringArray] = []
- for m in self._load_additional_regex.search_all(shader_code):
- results.append(m.strings)
- return results
-
-func parse_steps_directive(shader_code: String) -> int:
- var regex_match = self._iterate_regex.search(shader_code)
- if regex_match == null:
- return 1
- else:
- return max(0, int(regex_match.strings[1]))
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/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/assets/error.svg b/src/assets/error.svg
deleted file mode 100644
index af2f066..0000000
--- a/src/assets/error.svg
+++ /dev/null
@@ -1,80 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/assets/error.svg.import b/src/assets/error.svg.import
deleted file mode 100644
index 368b3a5..0000000
--- a/src/assets/error.svg.import
+++ /dev/null
@@ -1,37 +0,0 @@
-[remap]
-
-importer="texture"
-type="CompressedTexture2D"
-uid="uid://04iv1gogpuhu"
-path="res://.godot/imported/error.svg-28fb29635cf59d39cabf7052619f602f.ctex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://src/assets/error.svg"
-dest_files=["res://.godot/imported/error.svg-28fb29635cf59d39cabf7052619f602f.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
-svg/scale=2.0
-editor/scale_with_editor_scale=false
-editor/convert_colors_with_editor_theme=false
diff --git a/src/assets/okay.svg b/src/assets/okay.svg
deleted file mode 100644
index 5668fe8..0000000
--- a/src/assets/okay.svg
+++ /dev/null
@@ -1,81 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/assets/okay.svg.import b/src/assets/okay.svg.import
deleted file mode 100644
index e1631da..0000000
--- a/src/assets/okay.svg.import
+++ /dev/null
@@ -1,37 +0,0 @@
-[remap]
-
-importer="texture"
-type="CompressedTexture2D"
-uid="uid://m1omb6g45vst"
-path="res://.godot/imported/okay.svg-de66a022ef37753b085371b7c60aefd1.ctex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://src/assets/okay.svg"
-dest_files=["res://.godot/imported/okay.svg-de66a022ef37753b085371b7c60aefd1.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
-svg/scale=2.0
-editor/scale_with_editor_scale=false
-editor/convert_colors_with_editor_theme=false
diff --git a/src/presets/Presets.gd b/src/presets/Presets.gd
new file mode 100644
index 0000000..c009bd2
--- /dev/null
+++ b/src/presets/Presets.gd
@@ -0,0 +1,14 @@
+extends Node
+
+const dir = "res://src/presets/shaders/"
+
+@onready var presets = {
+ "Empty": load(dir + "empty.gdshader"),
+ "Greyscale": load(dir + "greyscale.gdshader"),
+ "Lowpass": load(dir + "lowpass.gdshader"),
+ "Channel Offset": load(dir + "channel_offset.gdshader"),
+ "RGB -> UV Distort": load(dir + "rgb_uv_distort.gdshader"),
+ "Mix": load(dir + "mix.gdshader")
+}
+
+var default_preset: String = "Empty"
diff --git a/examples/channel_offset.gdshader b/src/presets/shaders/channel_offset.gdshader
similarity index 92%
rename from examples/channel_offset.gdshader
rename to src/presets/shaders/channel_offset.gdshader
index a1ad8b5..e3ac188 100644
--- a/examples/channel_offset.gdshader
+++ b/src/presets/shaders/channel_offset.gdshader
@@ -1,7 +1,5 @@
shader_type canvas_item;
-//!load ./images/swamp.jpg
-
const vec2 offset_r = vec2(-0.002, -0.002);
const vec2 offset_g = vec2(0., 0.);
const vec2 offset_b = vec2(0.002, 0.002);
diff --git a/src/presets/shaders/empty.gdshader b/src/presets/shaders/empty.gdshader
new file mode 100644
index 0000000..0cb1281
--- /dev/null
+++ b/src/presets/shaders/empty.gdshader
@@ -0,0 +1,5 @@
+shader_type canvas_item;
+
+void fragment() {
+ // Called for every pixel the material is visible on.
+}
diff --git a/examples/greyscale.gdshader b/src/presets/shaders/greyscale.gdshader
similarity index 71%
rename from examples/greyscale.gdshader
rename to src/presets/shaders/greyscale.gdshader
index 00aac8b..cd70a78 100644
--- a/examples/greyscale.gdshader
+++ b/src/presets/shaders/greyscale.gdshader
@@ -1,10 +1,10 @@
shader_type canvas_item;
-//!load ./images/swamp.jpg
-
void fragment() {
+ vec4 tex = texture(TEXTURE , UV);
float b = (COLOR.r + COLOR.g + COLOR.b) / 3.0;
COLOR.r = b;
COLOR.g = b;
COLOR.b = b;
+ COLOR.a = tex.a;
}
diff --git a/src/presets/shaders/lowpass.gdshader b/src/presets/shaders/lowpass.gdshader
new file mode 100644
index 0000000..9dc44f7
--- /dev/null
+++ b/src/presets/shaders/lowpass.gdshader
@@ -0,0 +1,13 @@
+shader_type canvas_item;
+
+// Settings
+const float threshold = 0.5;
+//
+
+void fragment() {
+ vec4 tex = texture(TEXTURE , UV);
+ COLOR.r = min(tex.r, threshold);
+ COLOR.g = min(tex.g, threshold);
+ COLOR.b = min(tex.b, threshold);
+ COLOR.a = tex.a;
+}
diff --git a/src/presets/shaders/mix.gdshader b/src/presets/shaders/mix.gdshader
new file mode 100644
index 0000000..53ed562
--- /dev/null
+++ b/src/presets/shaders/mix.gdshader
@@ -0,0 +1,8 @@
+shader_type canvas_item;
+
+//!load img2 ./icon.png
+uniform sampler2D img2: repeat_enable, filter_nearest;
+
+void fragment() {
+ COLOR = mix(COLOR, texture(img2, UV), .5);
+}
diff --git a/src/presets/shaders/rgb_uv_distort.gdshader b/src/presets/shaders/rgb_uv_distort.gdshader
new file mode 100644
index 0000000..c07466b
--- /dev/null
+++ b/src/presets/shaders/rgb_uv_distort.gdshader
@@ -0,0 +1,11 @@
+shader_type canvas_item;
+
+const float strength = 0.1;
+
+void fragment() {
+ vec2 uv = UV;
+ float b = (COLOR.r + COLOR.g + COLOR.b) / 3.0;
+ uv.x = mix(uv.x, b, strength);
+ uv.y = mix(uv.y, b, strength);
+ COLOR = texture(TEXTURE, uv);
+}
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
deleted file mode 100644
index 78bfe77..0000000
--- a/src/shader/ivd_outline.gdshader
+++ /dev/null
@@ -1,16 +0,0 @@
-shader_type canvas_item;
-
-uniform vec2 zoom_level = vec2(1.0);
-const float thickness = 3.0;
-
-void fragment() {
- vec2 t = thickness * TEXTURE_PIXEL_SIZE / zoom_level;
- if (
- UV.x < t.x ||
- UV.y < t.y ||
- UV.x > 1.0-t.x ||
- UV.y > 1.0-t.y
- ) {
- COLOR = mix(COLOR, vec4(0.5), 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/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/src/ui_background.gdshader b/src/ui_background.gdshader
new file mode 100644
index 0000000..400d329
--- /dev/null
+++ b/src/ui_background.gdshader
@@ -0,0 +1,17 @@
+shader_type canvas_item;
+
+uniform sampler2D SCREEN_TEXTURE: hint_screen_texture, repeat_disable, filter_linear_mipmap_anisotropic;
+
+float rand(vec2 uv) {
+ return fract(sin(dot(uv, vec2(12.9898, 78.233))) * 43758.5453123);
+}
+
+void fragment() {
+ vec2 new_uv;
+ new_uv.x = mix(SCREEN_UV.x, rand(UV), 0.2);
+ new_uv.y = mix(SCREEN_UV.y, rand(UV), 0.2);
+ new_uv.x = mix(new_uv.x, rand(UV), -0.2);
+ new_uv.y = mix(new_uv.y, rand(UV), -0.2);
+ COLOR.rgb = clamp(textureLod(SCREEN_TEXTURE, new_uv, 10.0).rgb, 0.05, 0.7);
+ COLOR.a = 1.0;
+}
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