diff --git a/README.md b/README.md index 1803499..a12517b 100644 --- a/README.md +++ b/README.md @@ -62,22 +62,22 @@ Example: //!load ... //!steps 5 -uniform int STEP; // this is mandatory! +uniform int STEP; +uniform int STEPS; void fragment() { if (STEP == 0) { - ... + ... } else if (STEP == 1) { - ... + ... + } else if (STEP == STEPS-1) { + ... } - // ... and so on } ``` ## Shaderlib -> Note: The shaderlib API is still unstable as I am figuring things out. It will be declared stable with version 10. - This repo comes with a (still small) shader library including pre-written functions and more. Have a look at the `shaderlib` folder. @@ -153,5 +153,4 @@ Since version v8.0, you can pass a directory to `--load-image` and `--output`. T ## Known Issues - screen scaling is unsupported; Using screen scaling could lead to an either blurry UI, or no scaling at all -> see #45 -- the shaderlib API is still unstable, this will change with version 10 - commandline interface: `--headless` is not supported diff --git a/build-template/Containerfile b/build-template/Containerfile index e47f847..b1a0c48 100644 --- a/build-template/Containerfile +++ b/build-template/Containerfile @@ -7,13 +7,12 @@ 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 build-essential scons pkg-config libx11-dev libxcursor-dev libxinerama-dev libgl1-mesa-dev libglu1-mesa-dev libasound2-dev libpulse-dev libudev-dev libxi-dev libxrandr-dev libwayland-dev - -RUN DEBIAN_FRONTEND=noninteractive apt-get install -yq git +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.3-stable /godot-src +RUN git clone https://github.com/godotengine/godot.git -b 4.4-stable /godot-src FROM clone-src diff --git a/examples/blur.gdshader.uid b/examples/blur.gdshader.uid new file mode 100644 index 0000000..3739afe --- /dev/null +++ b/examples/blur.gdshader.uid @@ -0,0 +1 @@ +uid://cny8dtukv54wt diff --git a/examples/channel_offset.gdshader.uid b/examples/channel_offset.gdshader.uid new file mode 100644 index 0000000..66e7cef --- /dev/null +++ b/examples/channel_offset.gdshader.uid @@ -0,0 +1 @@ +uid://0efk4fornlg6 diff --git a/examples/color_and_pixelate.gdshader.uid b/examples/color_and_pixelate.gdshader.uid new file mode 100644 index 0000000..d943067 --- /dev/null +++ b/examples/color_and_pixelate.gdshader.uid @@ -0,0 +1 @@ +uid://gd23hu7ro148 diff --git a/examples/denoise.gdshader.uid b/examples/denoise.gdshader.uid new file mode 100644 index 0000000..9337646 --- /dev/null +++ b/examples/denoise.gdshader.uid @@ -0,0 +1 @@ +uid://cbwyneu03fki6 diff --git a/examples/greyscale.gdshader.uid b/examples/greyscale.gdshader.uid new file mode 100644 index 0000000..b6e1bbd --- /dev/null +++ b/examples/greyscale.gdshader.uid @@ -0,0 +1 @@ +uid://dvarqolt6es27 diff --git a/examples/kuwahara.gdshader.uid b/examples/kuwahara.gdshader.uid new file mode 100644 index 0000000..2e0241a --- /dev/null +++ b/examples/kuwahara.gdshader.uid @@ -0,0 +1 @@ +uid://cdhyuk7u8kxyk diff --git a/examples/lowpass.gdshader.uid b/examples/lowpass.gdshader.uid new file mode 100644 index 0000000..80b19c7 --- /dev/null +++ b/examples/lowpass.gdshader.uid @@ -0,0 +1 @@ +uid://dn02xsjm1kok8 diff --git a/examples/multistep_distort.gdshader.uid b/examples/multistep_distort.gdshader.uid new file mode 100644 index 0000000..22efbc6 --- /dev/null +++ b/examples/multistep_distort.gdshader.uid @@ -0,0 +1 @@ +uid://c17u5jx7a7o81 diff --git a/examples/multistep_pixelsort.gdshader b/examples/multistep_pixelsort.gdshader new file mode 100644 index 0000000..21ba1b6 --- /dev/null +++ b/examples/multistep_pixelsort.gdshader @@ -0,0 +1,20 @@ +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 new file mode 100644 index 0000000..47eaaf5 --- /dev/null +++ b/examples/multistep_pixelsort.gdshader.uid @@ -0,0 +1 @@ +uid://csk0fg4by651b diff --git a/examples/oklab.gdshader.uid b/examples/oklab.gdshader.uid new file mode 100644 index 0000000..87cef6b --- /dev/null +++ b/examples/oklab.gdshader.uid @@ -0,0 +1 @@ +uid://cu37y8lc0x83 diff --git a/examples/place_texture.gdshader.uid b/examples/place_texture.gdshader.uid new file mode 100644 index 0000000..8ced27b --- /dev/null +++ b/examples/place_texture.gdshader.uid @@ -0,0 +1 @@ +uid://dybe4t5rbbkc6 diff --git a/examples/project.godot_ b/examples/project.godot_ index bd350d3..5eff383 100644 --- a/examples/project.godot_ +++ b/examples/project.godot_ @@ -11,6 +11,5 @@ config_version=5 [application] config/name="Fragmented Project" -config/features=PackedStringArray("4.3", "Forward Plus") run/main_scene="res://0_empty.tscn" - +config/features=PackedStringArray("4.4", "Forward Plus") diff --git a/examples/sobel.gdshader b/examples/sobel.gdshader new file mode 100644 index 0000000..3a7a8b5 --- /dev/null +++ b/examples/sobel.gdshader @@ -0,0 +1,10 @@ +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 new file mode 100644 index 0000000..33b657a --- /dev/null +++ b/examples/sobel.gdshader.uid @@ -0,0 +1 @@ +uid://h376mk1fq4ky diff --git a/export_presets.cfg b/export_presets.cfg index 4b10743..79a474d 100644 --- a/export_presets.cfg +++ b/export_presets.cfg @@ -10,8 +10,10 @@ export_filter="all_resources" include_filter="" exclude_filter="screenshot.png, examples/*, shaderlib/*, tools/*, build-template/*" export_path="dist/Fragmented.x86_64" +patches=PackedStringArray() encryption_include_filters="" encryption_exclude_filters="" +seed=0 encrypt_pck=false encrypt_directory=false script_export_mode=2 diff --git a/project.godot b/project.godot index 4b605af..95da5af 100644 --- a/project.godot +++ b/project.godot @@ -11,10 +11,9 @@ config_version=5 [application] config/name="Fragmented" -config/version="v9.0" +config/version="v10.2" run/main_scene="res://src/scenes/main.tscn" -config/features=PackedStringArray("4.3", "Mobile") -run/low_processor_mode=true +config/features=PackedStringArray("4.4", "Mobile") config/icon="res://src/assets/icon.png" [autoload] @@ -28,7 +27,6 @@ window/size/viewport_width=640 window/size/viewport_height=672 window/energy_saving/keep_screen_on=false window/subwindows/embed_subwindows=false -window/vsync/vsync_mode=0 [editor_plugins] @@ -72,4 +70,4 @@ renderer/rendering_method="mobile" textures/vram_compression/import_etc2_astc=true textures/lossless_compression/force_png=true shader_compiler/shader_cache/enabled=false -environment/defaults/default_clear_color=Color(0, 0, 0, 1) +environment/defaults/default_clear_color=Color(0.501961, 0.501961, 0.501961, 1) diff --git a/screenshot.png b/screenshot.png index 0ba5b66..ce0ac8a 100644 Binary files a/screenshot.png and b/screenshot.png differ diff --git a/shaderlib/blur.gdshaderinc.uid b/shaderlib/blur.gdshaderinc.uid new file mode 100644 index 0000000..d5c8dfd --- /dev/null +++ b/shaderlib/blur.gdshaderinc.uid @@ -0,0 +1 @@ +uid://bjtljvcjcu6dr diff --git a/shaderlib/common.gdshaderinc b/shaderlib/common.gdshaderinc index 8af35dc..9352d6a 100644 --- a/shaderlib/common.gdshaderinc +++ b/shaderlib/common.gdshaderinc @@ -13,3 +13,15 @@ vec4 alpha_blend(vec4 b, vec4 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 new file mode 100644 index 0000000..f43430d --- /dev/null +++ b/shaderlib/common.gdshaderinc.uid @@ -0,0 +1 @@ +uid://764b6ekchgb8 diff --git a/shaderlib/denoise.gdshaderinc.uid b/shaderlib/denoise.gdshaderinc.uid new file mode 100644 index 0000000..132a166 --- /dev/null +++ b/shaderlib/denoise.gdshaderinc.uid @@ -0,0 +1 @@ +uid://b7ksfifyyfcip diff --git a/shaderlib/hsv.gdshaderinc.uid b/shaderlib/hsv.gdshaderinc.uid new file mode 100644 index 0000000..771cc38 --- /dev/null +++ b/shaderlib/hsv.gdshaderinc.uid @@ -0,0 +1 @@ +uid://bbr3tq6mp5qa2 diff --git a/shaderlib/kuwahara.gdshaderinc.uid b/shaderlib/kuwahara.gdshaderinc.uid new file mode 100644 index 0000000..1ff911b --- /dev/null +++ b/shaderlib/kuwahara.gdshaderinc.uid @@ -0,0 +1 @@ +uid://chqh2cni1qiuu diff --git a/shaderlib/oklab.gdshaderinc b/shaderlib/oklab.gdshaderinc index 833db27..5a456c7 100644 --- a/shaderlib/oklab.gdshaderinc +++ b/shaderlib/oklab.gdshaderinc @@ -12,6 +12,8 @@ #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; @@ -29,6 +31,8 @@ vec4 rgb2oklab(vec4 c) { } vec4 oklab2rgb(vec4 c) { + // oklab.x and .y (a and b) should range from -0.5 to 0.5 + float l_ = c.x + 0.3963377774f * c.y + 0.2158037573f * c.z; float m_ = c.x - 0.1055613458f * c.y - 0.0638541728f * c.z; float s_ = c.x - 0.0894841775f * c.y - 1.2914855480f * c.z; @@ -46,6 +50,7 @@ vec4 oklab2rgb(vec4 c) { } vec4 oklab2oklch(vec4 c) { + // oklch.z (hue) ranges from -3.6 to 3.6 return vec4( c.x, sqrt((c.y * c.y) + (c.z * c.z)), @@ -55,6 +60,7 @@ vec4 oklab2oklch(vec4 c) { } vec4 oklch2oklab(vec4 c) { + // oklch.z (hue) ranges from -3.6 to 3.6 return vec4( c.x, c.y * cos(c.z), diff --git a/shaderlib/oklab.gdshaderinc.uid b/shaderlib/oklab.gdshaderinc.uid new file mode 100644 index 0000000..7f0bf5f --- /dev/null +++ b/shaderlib/oklab.gdshaderinc.uid @@ -0,0 +1 @@ +uid://ckw4nfslk4m6l diff --git a/shaderlib/pixelate.gdshaderinc.uid b/shaderlib/pixelate.gdshaderinc.uid new file mode 100644 index 0000000..a0a0d4d --- /dev/null +++ b/shaderlib/pixelate.gdshaderinc.uid @@ -0,0 +1 @@ +uid://dpu5nneo5bgnq diff --git a/shaderlib/pixelsort.gdshaderinc b/shaderlib/pixelsort.gdshaderinc new file mode 100644 index 0000000..73ed5da --- /dev/null +++ b/shaderlib/pixelsort.gdshaderinc @@ -0,0 +1,126 @@ + +/* + 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 new file mode 100644 index 0000000..e02f48e --- /dev/null +++ b/shaderlib/pixelsort.gdshaderinc.uid @@ -0,0 +1 @@ +uid://doefnwk3vyr0o diff --git a/shaderlib/place_texture.gdshaderinc.uid b/shaderlib/place_texture.gdshaderinc.uid new file mode 100644 index 0000000..f0b6f69 --- /dev/null +++ b/shaderlib/place_texture.gdshaderinc.uid @@ -0,0 +1 @@ +uid://51u2hjq62e5i diff --git a/shaderlib/sobel.gdshaderinc b/shaderlib/sobel.gdshaderinc new file mode 100644 index 0000000..dd665b3 --- /dev/null +++ b/shaderlib/sobel.gdshaderinc @@ -0,0 +1,50 @@ + +/* + 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 new file mode 100644 index 0000000..5753e70 --- /dev/null +++ b/shaderlib/sobel.gdshaderinc.uid @@ -0,0 +1 @@ +uid://bqo1fpunnl05f diff --git a/src/Camera.gd b/src/Camera.gd index 9ca1b84..416e035 100644 --- a/src/Camera.gd +++ b/src/Camera.gd @@ -16,6 +16,14 @@ func _input(event): if self.drag && event is InputEventMouseMotion: self.global_position -= event.relative / self.zoom +var old_zoom = self.zoom + +func _process(_delta: float) -> void: + if self.zoom != old_zoom: + image_viewport_display.update_zoom_texture_filter(self.zoom) + image_viewport_display.material.set_shader_parameter("zoom_level", self.zoom) + old_zoom = self.zoom + func fit_image(): if Filesystem.original_image != null: var image_size = Filesystem.original_image.get_size() @@ -28,21 +36,15 @@ func fit_image(): self.zoom = Vector2(zoomf, zoomf) self.global_position = Vector2(0, 0) -func update_vd_zoomlevel(): - image_viewport_display.update_zoom_texture_filter(self.zoom) - image_viewport_display.material.set_shader_parameter("zoom_level", self.zoom) - func zoom_in(): var old_mouse_pos = get_global_mouse_position() self.zoom *= 1.2 self.global_position += old_mouse_pos - get_global_mouse_position() - update_vd_zoomlevel() func zoom_out(): var old_mouse_pos = get_global_mouse_position() self.zoom *= 1/1.2 self.global_position += old_mouse_pos - get_global_mouse_position() - update_vd_zoomlevel() func _on_fit_image_button_pressed(): fit_image() diff --git a/src/Camera.gd.uid b/src/Camera.gd.uid new file mode 100644 index 0000000..f25b715 --- /dev/null +++ b/src/Camera.gd.uid @@ -0,0 +1 @@ +uid://b6r8rigubdctk diff --git a/src/Filesystem.gd.uid b/src/Filesystem.gd.uid new file mode 100644 index 0000000..a89dcab --- /dev/null +++ b/src/Filesystem.gd.uid @@ -0,0 +1 @@ +uid://rlb041ygdwol diff --git a/src/ImageCompositor.gd b/src/ImageCompositor.gd index ad1ffb5..9f3e95a 100644 --- a/src/ImageCompositor.gd +++ b/src/ImageCompositor.gd @@ -37,19 +37,26 @@ func validate_shader_compilation(shader: Shader) -> bool: # test if uniform list is empty -> if it is empty, the shader compilation failed return len(shader.get_shader_uniform_list()) > 0 -func shader_has_step_uniform(shader: Shader) -> bool: +func shader_has_uniform(shader: Shader, name: String, type: int) -> bool: for u in shader.get_shader_uniform_list(): - if u["name"] == "STEP" && u["type"] == 2: + 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_step_uniform(shader) + 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!"] @@ -84,6 +91,9 @@ func update(overwrite_image_path: String = "") -> Array: # returns error message image_sprite.texture = Filesystem.original_image image_sprite.offset = Filesystem.original_image.get_size() / 2 self.size = Filesystem.original_image.get_size() + # already show the image viewport & fit the image + if fit_image: camera.fit_image() + image_viewport_display.show() # create shader material var mat = ShaderMaterial.new() mat.shader = shader @@ -95,6 +105,10 @@ func update(overwrite_image_path: String = "") -> Array: # returns error message # assign material image_sprite.material = mat # iterate n times + set_vsync(false) # speed up processing + if has_steps_uniform: + # set STEPS param + mat.set_shader_parameter("STEPS", steps) for i in range(steps): if has_step_uniform: # set STEP param @@ -103,10 +117,7 @@ func update(overwrite_image_path: String = "") -> Array: # returns error message await RenderingServer.frame_post_draw # wait for next frame to get drawn Filesystem.result = get_texture().get_image() image_sprite.texture = ImageTexture.create_from_image(Filesystem.result) + set_vsync(true) # reenable vsync image_sprite.material = null - if fit_image: - camera.fit_image() - camera.update_vd_zoomlevel() - image_viewport_display.show() # done return errors diff --git a/src/ImageCompositor.gd.uid b/src/ImageCompositor.gd.uid new file mode 100644 index 0000000..2e55fae --- /dev/null +++ b/src/ImageCompositor.gd.uid @@ -0,0 +1 @@ +uid://d106170kuigl3 diff --git a/src/ImageViewportDisplay.gd.uid b/src/ImageViewportDisplay.gd.uid new file mode 100644 index 0000000..dbde761 --- /dev/null +++ b/src/ImageViewportDisplay.gd.uid @@ -0,0 +1 @@ +uid://ctc4lhbdsoq7u diff --git a/src/Main.gd.uid b/src/Main.gd.uid new file mode 100644 index 0000000..2f9a508 --- /dev/null +++ b/src/Main.gd.uid @@ -0,0 +1 @@ +uid://5sbslwysin5a diff --git a/src/MainUI.gd b/src/MainUI.gd index 3727f08..8a62ff1 100644 --- a/src/MainUI.gd +++ b/src/MainUI.gd @@ -72,6 +72,7 @@ func _on_open_shader_dialog_confirmed() -> void: 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) diff --git a/src/MainUI.gd.uid b/src/MainUI.gd.uid new file mode 100644 index 0000000..0077ccd --- /dev/null +++ b/src/MainUI.gd.uid @@ -0,0 +1 @@ +uid://bxgmf2ny7yuc8 diff --git a/src/ShaderDirectiveParser.gd.uid b/src/ShaderDirectiveParser.gd.uid new file mode 100644 index 0000000..59f7f0e --- /dev/null +++ b/src/ShaderDirectiveParser.gd.uid @@ -0,0 +1 @@ +uid://dw8bep14j4j3w diff --git a/src/VersionLabel.gd.uid b/src/VersionLabel.gd.uid new file mode 100644 index 0000000..e731c41 --- /dev/null +++ b/src/VersionLabel.gd.uid @@ -0,0 +1 @@ +uid://bh0gpu3i2p47f diff --git a/src/assets/bg.png b/src/assets/bg.png new file mode 100644 index 0000000..fb67c19 Binary files /dev/null and b/src/assets/bg.png differ diff --git a/src/assets/bg.png.import b/src/assets/bg.png.import new file mode 100644 index 0000000..e61ed86 --- /dev/null +++ b/src/assets/bg.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d2nwchyd6huob" +path="res://.godot/imported/bg.png-7c8713dd1fab321784216191fa747e53.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://src/assets/bg.png" +dest_files=["res://.godot/imported/bg.png-7c8713dd1fab321784216191fa747e53.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/src/scenes/main.tscn b/src/scenes/main.tscn index e6580b3..14b19bd 100644 --- a/src/scenes/main.tscn +++ b/src/scenes/main.tscn @@ -1,13 +1,14 @@ -[gd_scene load_steps=12 format=3 uid="uid://bjah7k4bxo044"] +[gd_scene load_steps=13 format=3 uid="uid://bjah7k4bxo044"] -[ext_resource type="Script" uid="uid://n6vumf2emghl" path="res://src/Main.gd" id="1_64y3g"] -[ext_resource type="Script" path="res://src/ImageCompositor.gd" id="2_4ykh7"] -[ext_resource type="Shader" uid="uid://on6oju7dt0dj" path="res://src/shader/ivd_outline.gdshader" id="3_0fllm"] -[ext_resource type="Script" uid="uid://c51lc0hv2d7uq" path="res://src/ImageViewportDisplay.gd" id="4_pbpx2"] -[ext_resource type="Script" uid="uid://t71vu44i5cr5" path="res://src/Camera.gd" id="5_hkdq6"] +[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://e5gf0r42elmx" path="res://src/MainUI.gd" id="7_5puhk"] -[ext_resource type="Script" uid="uid://b254xv4j2uexg" path="res://src/VersionLabel.gd" id="8_kod8x"] +[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") @@ -18,7 +19,6 @@ viewport_path = NodePath("Compositor") [sub_resource type="LabelSettings" id="LabelSettings_6o860"] font_size = 12 -font_color = Color(1, 1, 1, 0.509804) shadow_color = Color(0, 0, 0, 1) [node name="Main" type="Node2D"] @@ -39,6 +39,27 @@ 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"] @@ -70,7 +91,6 @@ unique_name_in_owner = true auto_translate_mode = 1 title = "Export Image" size = Vector2i(661, 175) -ok_button_text = "Save" mode_overrides_title = false access = 2 filters = PackedStringArray("*.png") diff --git a/src/shader/ivd_outline.gdshader b/src/shader/ivd_outline.gdshader index 14ce6e0..78bfe77 100644 --- a/src/shader/ivd_outline.gdshader +++ b/src/shader/ivd_outline.gdshader @@ -11,6 +11,6 @@ void fragment() { UV.x > 1.0-t.x || UV.y > 1.0-t.y ) { - COLOR = mix(COLOR, vec4(1.0), 0.5); + COLOR = mix(COLOR, vec4(0.5), 0.5); } } diff --git a/src/shader/ivd_outline.gdshader.uid b/src/shader/ivd_outline.gdshader.uid new file mode 100644 index 0000000..b42ac31 --- /dev/null +++ b/src/shader/ivd_outline.gdshader.uid @@ -0,0 +1 @@ +uid://ctk7jomfyx0fh diff --git a/tools/get_version.gd.uid b/tools/get_version.gd.uid new file mode 100644 index 0000000..e14829d --- /dev/null +++ b/tools/get_version.gd.uid @@ -0,0 +1 @@ +uid://cdhqbascy6pvy