Compare commits

...

18 commits
v9.0 ... main

Author SHA1 Message Date
54cbddbbba
Bump version to v10.2 2025-04-09 19:18:09 +02:00
65fddc0bd8
Update README regarding STEPS uniform 2025-04-09 19:09:32 +02:00
ebc8ce2cb9
Add STEPS uniform to get the number of steps programmatically 2025-04-09 19:04:11 +02:00
c9c5428dbc
shaderlib: Add rotateUV function to common.gdshader 2025-04-09 19:00:02 +02:00
4d0f7ca538
Bump version to v10.1 2025-04-01 21:42:38 +02:00
3dcc4ca02c
shaderlib: Add multipass pixelsorting 2025-04-01 21:37:32 +02:00
bf1c1327ac
Add better documentation of value ranges in oklab and oklch 2025-03-31 21:24:56 +02:00
560e455cd2
Disable VSync while ImageCompositor.update processes the image 2025-03-31 21:24:07 +02:00
77273f9c1b
Add sobel filter (edge detection) 2025-03-31 15:41:31 +02:00
9d23efea63
Fix: Show and align image viewport before first step 2025-03-31 15:39:36 +02:00
4278cde44b
Disable low_processor_mode in the settings to improve multistep performance 2025-03-31 15:37:55 +02:00
f940061135
Declare shaderlib as stable, bump version to v10.0 2025-03-15 20:45:30 +01:00
4546b9eac0
fix: re-enable buttons after image export 2025-03-15 20:40:11 +01:00
e7bb3c8f16
Update example project and export_presets.cfg for Godot 4.4 2025-03-15 18:16:02 +01:00
46829e72e9
Bump version to v9.1 2025-03-13 21:55:57 +01:00
df85ceb469
Update screenshot 2025-03-13 21:55:27 +01:00
b6f6c3d27e
Change background and fix image viewport outline 2025-03-13 21:41:01 +01:00
9b1efc1513
Update to Godot 4.4 2025-03-13 20:57:31 +01:00
51 changed files with 363 additions and 42 deletions

View file

@ -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

View file

@ -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

View file

@ -0,0 +1 @@
uid://cny8dtukv54wt

View file

@ -0,0 +1 @@
uid://0efk4fornlg6

View file

@ -0,0 +1 @@
uid://gd23hu7ro148

View file

@ -0,0 +1 @@
uid://cbwyneu03fki6

View file

@ -0,0 +1 @@
uid://dvarqolt6es27

View file

@ -0,0 +1 @@
uid://cdhyuk7u8kxyk

View file

@ -0,0 +1 @@
uid://dn02xsjm1kok8

View file

@ -0,0 +1 @@
uid://c17u5jx7a7o81

View file

@ -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);
}

View file

@ -0,0 +1 @@
uid://csk0fg4by651b

View file

@ -0,0 +1 @@
uid://cu37y8lc0x83

View file

@ -0,0 +1 @@
uid://dybe4t5rbbkc6

View file

@ -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")

10
examples/sobel.gdshader Normal file
View file

@ -0,0 +1,10 @@
shader_type canvas_item;
//!load ./images/noisy.png
#include "./shaderlib/sobel.gdshaderinc"
void fragment() {
// Sobel Filter
COLOR = sobel(TEXTURE, UV);
}

View file

@ -0,0 +1 @@
uid://h376mk1fq4ky

View file

@ -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

View file

@ -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)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 395 KiB

After

Width:  |  Height:  |  Size: 502 KiB

Before After
Before After

View file

@ -0,0 +1 @@
uid://bjtljvcjcu6dr

View file

@ -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);
}

View file

@ -0,0 +1 @@
uid://764b6ekchgb8

View file

@ -0,0 +1 @@
uid://b7ksfifyyfcip

View file

@ -0,0 +1 @@
uid://bbr3tq6mp5qa2

View file

@ -0,0 +1 @@
uid://chqh2cni1qiuu

View file

@ -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),

View file

@ -0,0 +1 @@
uid://ckw4nfslk4m6l

View file

@ -0,0 +1 @@
uid://dpu5nneo5bgnq

View file

@ -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; }
}
}
}

View file

@ -0,0 +1 @@
uid://doefnwk3vyr0o

View file

@ -0,0 +1 @@
uid://51u2hjq62e5i

View file

@ -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);
}

View file

@ -0,0 +1 @@
uid://bqo1fpunnl05f

View file

@ -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()

1
src/Camera.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://b6r8rigubdctk

1
src/Filesystem.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://rlb041ygdwol

View file

@ -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

View file

@ -0,0 +1 @@
uid://d106170kuigl3

View file

@ -0,0 +1 @@
uid://ctc4lhbdsoq7u

1
src/Main.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://5sbslwysin5a

View file

@ -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)

1
src/MainUI.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://bxgmf2ny7yuc8

View file

@ -0,0 +1 @@
uid://dw8bep14j4j3w

1
src/VersionLabel.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://bh0gpu3i2p47f

BIN
src/assets/bg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 532 B

34
src/assets/bg.png.import Normal file
View file

@ -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

View file

@ -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")

View file

@ -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);
}
}

View file

@ -0,0 +1 @@
uid://ctk7jomfyx0fh

1
tools/get_version.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://cdhqbascy6pvy