mirror of
https://github.com/Orama-Interactive/Pixelorama.git
synced 2025-01-18 09:09:47 +00:00
Shader-based gradients (#677)
* Add 6 shader-based gradient types * Shaders now respect selection * Fix step gradient * Remove comments * Disable step and dithering shaders in Web version * Fixed a weird bug with dithering shaders, selection and GLES2 Having a selection, applying a dithering gradient, removing the selection and then going to the gradient dialog again causes the dithering shaders to "remember" the previous selection, even if there is no selection currently. This only happens with the two dithering shaders and only with the GLES2 renderer. Removing `uniform sampler2D dither_texture;` from the shader code seems to fix the issue, but that's obviously isn't what we want so a "proper" fix is included in this commit. * Format & lint * Removed old gradient code * Change how centers work on radial step and dithering * Made angle, center and radius option a bit more clear * Rename bayer-matrices directory to dither-matrices * Use DitherMatrix class * Create dithering types programmatically * Remove unneeded code in shaders * Rewrite the step shader without a for loop More optimized and works on the Web version with GLES2 * Rewrite radial step and dithering shaders without for loop Now all shaders work on the Web version and have been optimized. * Fix Linear & Radial size range and remove some unneeded lines * Added size uniform to Radial Step and Radial Dither * Swap colors in the Linear gradient * Make size a percentage * Make the preview look the same as the result Didn't change the dithering shaders because they seemed to give different results. * Remove ratio uniform and divide uvs by the radius instead This makes more sense because the smaller the number, the smaller the radius. * Fix linear gradient * Change Position to percentage and "Size" to "Transition size" * Mix gradients with original color, if the gradient colors have transparency
This commit is contained in:
parent
539ccb2e58
commit
cf926942ac
BIN
assets/dither-matrices/bayer16.png
Normal file
BIN
assets/dither-matrices/bayer16.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 805 B |
35
assets/dither-matrices/bayer16.png.import
Normal file
35
assets/dither-matrices/bayer16.png.import
Normal file
|
@ -0,0 +1,35 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/bayer16.png-48f80e5e8f0bdac9e83b3acfa8588cf2.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/dither-matrices/bayer16.png"
|
||||
dest_files=[ "res://.import/bayer16.png-48f80e5e8f0bdac9e83b3acfa8588cf2.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=1
|
||||
flags/filter=false
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
process/normal_map_invert_y=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=false
|
||||
svg/scale=1.0
|
BIN
assets/dither-matrices/bayer2.png
Normal file
BIN
assets/dither-matrices/bayer2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 79 B |
35
assets/dither-matrices/bayer2.png.import
Normal file
35
assets/dither-matrices/bayer2.png.import
Normal file
|
@ -0,0 +1,35 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/bayer2.png-c060ec2442edc204b9ec0ab2d99e19bf.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/dither-matrices/bayer2.png"
|
||||
dest_files=[ "res://.import/bayer2.png-c060ec2442edc204b9ec0ab2d99e19bf.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=1
|
||||
flags/filter=false
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
process/normal_map_invert_y=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=false
|
||||
svg/scale=1.0
|
BIN
assets/dither-matrices/bayer4.png
Normal file
BIN
assets/dither-matrices/bayer4.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 120 B |
35
assets/dither-matrices/bayer4.png.import
Normal file
35
assets/dither-matrices/bayer4.png.import
Normal file
|
@ -0,0 +1,35 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/bayer4.png-2008f73a4dd6b2f9f4ba6aac825a7b9b.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/dither-matrices/bayer4.png"
|
||||
dest_files=[ "res://.import/bayer4.png-2008f73a4dd6b2f9f4ba6aac825a7b9b.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=1
|
||||
flags/filter=false
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
process/normal_map_invert_y=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=false
|
||||
svg/scale=1.0
|
BIN
assets/dither-matrices/bayer8.png
Normal file
BIN
assets/dither-matrices/bayer8.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 265 B |
35
assets/dither-matrices/bayer8.png.import
Normal file
35
assets/dither-matrices/bayer8.png.import
Normal file
|
@ -0,0 +1,35 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/bayer8.png-2c0f9ff189b3d219f822ce84a94f5abd.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/dither-matrices/bayer8.png"
|
||||
dest_files=[ "res://.import/bayer8.png-2c0f9ff189b3d219f822ce84a94f5abd.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=1
|
||||
flags/filter=false
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
process/normal_map_invert_y=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=false
|
||||
svg/scale=1.0
|
|
@ -650,60 +650,3 @@ func generate_outline(
|
|||
image.unlock()
|
||||
new_image.unlock()
|
||||
image.copy_from(new_image)
|
||||
|
||||
|
||||
func generate_gradient(
|
||||
image: Image,
|
||||
colors: Array,
|
||||
steps: int,
|
||||
direction: int,
|
||||
affect_selection: bool,
|
||||
project: Project
|
||||
) -> void:
|
||||
if colors.size() < 2:
|
||||
return
|
||||
|
||||
var t = 1.0 / (steps - 1)
|
||||
for i in range(1, steps - 1):
|
||||
var color: Color
|
||||
color = colors[-1].linear_interpolate(colors[0], t * i)
|
||||
colors.insert(1, color)
|
||||
|
||||
if direction == GradientDirection.BOTTOM or direction == GradientDirection.RIGHT:
|
||||
colors.invert()
|
||||
|
||||
var draw_rectangle := Rect2()
|
||||
var selection := affect_selection and project.has_selection
|
||||
if selection:
|
||||
draw_rectangle = project.get_selection_rectangle()
|
||||
else:
|
||||
draw_rectangle = Rect2(Vector2.ZERO, project.size)
|
||||
var size := draw_rectangle.size
|
||||
image.lock()
|
||||
var gradient_size
|
||||
|
||||
if direction == GradientDirection.TOP or direction == GradientDirection.BOTTOM:
|
||||
gradient_size = size.y / steps
|
||||
for i in steps:
|
||||
for xx in size.x:
|
||||
var start = i * gradient_size
|
||||
var end = (i + 1) * gradient_size
|
||||
for yy in range(start, end):
|
||||
var pos: Vector2 = Vector2(xx, yy) + draw_rectangle.position
|
||||
if selection and !project.selection_bitmap.get_bit(pos):
|
||||
continue
|
||||
image.set_pixelv(pos, colors[i])
|
||||
|
||||
else:
|
||||
gradient_size = size.x / steps
|
||||
for i in steps:
|
||||
for yy in size.y:
|
||||
var start = i * gradient_size
|
||||
var end = (i + 1) * gradient_size
|
||||
for xx in range(start, end):
|
||||
var pos: Vector2 = Vector2(xx, yy) + draw_rectangle.position
|
||||
if selection and !project.selection_bitmap.get_bit(pos):
|
||||
continue
|
||||
image.set_pixelv(pos, colors[i])
|
||||
|
||||
image.unlock()
|
||||
|
|
38
src/Shaders/Gradients/Dithering.gdshader
Normal file
38
src/Shaders/Gradients/Dithering.gdshader
Normal file
|
@ -0,0 +1,38 @@
|
|||
shader_type canvas_item;
|
||||
render_mode unshaded;
|
||||
|
||||
uniform sampler2D dither_texture;
|
||||
uniform sampler2D selection;
|
||||
uniform vec4 first_color : hint_color = vec4(1.0);
|
||||
uniform vec4 second_color : hint_color = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
uniform vec2 image_size = vec2(64.0);
|
||||
uniform float position : hint_range(-0.5, 0.5) = 0.0;
|
||||
uniform float size : hint_range(0.01, 2.0) = 1.0;
|
||||
uniform float angle : hint_range(0.0, 360.0) = 0.0;
|
||||
uniform int dither_steps : hint_range(2, 257) = 5;
|
||||
uniform int pixel_size : hint_range(2, 16) = 2;
|
||||
|
||||
|
||||
void fragment() {
|
||||
vec4 original_color = texture(TEXTURE, UV);
|
||||
vec4 selection_color = texture(selection, UV);
|
||||
|
||||
float pivot = position / size;
|
||||
vec2 uv = UV - 0.5;
|
||||
float angle_cos = cos(radians(angle));
|
||||
float angle_sin = sin(radians(angle));
|
||||
float rotated = uv.x * angle_cos - uv.y * angle_sin;
|
||||
rotated /= abs(angle_cos) + abs(angle_sin);
|
||||
rotated /= size;
|
||||
rotated -= pivot - 0.5;
|
||||
vec4 dither_value = texture(dither_texture, uv * (image_size / float(pixel_size)));
|
||||
|
||||
float step_v = 1.0 / float(dither_steps);
|
||||
float step_v_m = 1.0 / float(dither_steps - 1);
|
||||
float rotated_stepped = floor(rotated / step_v) * step_v_m; // Similar to GDScript's stepify
|
||||
float dithered = step(rotated_stepped, dither_value.r);
|
||||
vec4 output = first_color * dithered + second_color * (1.0 - dithered);
|
||||
output = mix(original_color, output, output.a);
|
||||
|
||||
COLOR = mix(original_color, output, selection_color.a);
|
||||
}
|
26
src/Shaders/Gradients/Linear.gdshader
Normal file
26
src/Shaders/Gradients/Linear.gdshader
Normal file
|
@ -0,0 +1,26 @@
|
|||
shader_type canvas_item;
|
||||
render_mode unshaded;
|
||||
|
||||
uniform sampler2D selection;
|
||||
uniform vec4 first_color : hint_color = vec4(1.0);
|
||||
uniform vec4 second_color : hint_color = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
uniform float position : hint_range(-0.5, 0.5) = 0.0;
|
||||
uniform float size : hint_range(0.01, 2.0) = 1.0;
|
||||
uniform float angle : hint_range(0.0, 360.0) = 0.0;
|
||||
|
||||
void fragment() {
|
||||
vec4 original_color = texture(TEXTURE, UV);
|
||||
vec4 selection_color = texture(selection, UV);
|
||||
|
||||
vec2 tex_size = 1.0 / TEXTURE_PIXEL_SIZE;
|
||||
vec2 uv = floor(UV * tex_size) / (tex_size - 1.0);
|
||||
uv -= 0.5;
|
||||
float rotated = uv.x * cos(radians(angle)) - uv.y * sin(radians(angle));
|
||||
float fixed_position = position - 0.5;
|
||||
float fixed_size = (size / 2.0) + 0.5;
|
||||
|
||||
float pos = smoothstep((1.0 - fixed_size) + fixed_position, fixed_size + fixed_position, rotated);
|
||||
vec4 output = mix(first_color, second_color, pos);
|
||||
output = mix(original_color, output, output.a);
|
||||
COLOR = mix(original_color, output, selection_color.a);
|
||||
}
|
23
src/Shaders/Gradients/Radial.gdshader
Normal file
23
src/Shaders/Gradients/Radial.gdshader
Normal file
|
@ -0,0 +1,23 @@
|
|||
shader_type canvas_item;
|
||||
render_mode unshaded;
|
||||
|
||||
uniform sampler2D selection;
|
||||
uniform vec4 first_color : hint_color = vec4(1.0);
|
||||
uniform vec4 second_color : hint_color = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
uniform vec2 center = vec2(0.5);
|
||||
uniform vec2 radius = vec2(1.0);
|
||||
uniform float size : hint_range(0.01, 2.0) = 1.0;
|
||||
|
||||
void fragment() {
|
||||
vec4 original_color = texture(TEXTURE, UV);
|
||||
vec4 selection_color = texture(selection, UV);
|
||||
|
||||
vec2 tex_size = 1.0 / TEXTURE_PIXEL_SIZE;
|
||||
vec2 uv = floor(UV * tex_size) / (tex_size - 1.0);
|
||||
uv /= radius;
|
||||
float fixed_size = (size / 2.0) + 0.5;
|
||||
float smooth_dist = smoothstep(1.0 - fixed_size, fixed_size, distance(uv, center / radius));
|
||||
vec4 output = second_color * smooth_dist + (1.0 - smooth_dist) * first_color;
|
||||
output = mix(original_color, output, output.a);
|
||||
COLOR = mix(original_color, output, selection_color.a);
|
||||
}
|
39
src/Shaders/Gradients/RadialDithering.gdshader
Normal file
39
src/Shaders/Gradients/RadialDithering.gdshader
Normal file
|
@ -0,0 +1,39 @@
|
|||
shader_type canvas_item;
|
||||
render_mode unshaded;
|
||||
|
||||
uniform sampler2D dither_texture;
|
||||
uniform sampler2D selection;
|
||||
uniform vec4 first_color : hint_color = vec4(1.0);
|
||||
uniform vec4 second_color : hint_color = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
uniform vec2 image_size = vec2(64.0);
|
||||
uniform vec2 center = vec2(0.5);
|
||||
uniform vec2 radius = vec2(1.0);
|
||||
uniform float size : hint_range(0.01, 2) = 1.0;
|
||||
uniform int dither_steps : hint_range(2, 100) = 5;
|
||||
uniform int pixel_size : hint_range(2, 16) = 2;
|
||||
|
||||
void fragment() {
|
||||
vec4 original_color = texture(TEXTURE, UV);
|
||||
vec4 selection_color = texture(selection, UV);
|
||||
|
||||
vec2 uv = UV * 2.0 - 1.0;
|
||||
uv -= (center * 2.0) - vec2(1.0);
|
||||
uv /= radius;
|
||||
vec4 dither_value = texture(dither_texture, UV * (image_size / float(pixel_size)));
|
||||
|
||||
float polar_uv = length(uv);
|
||||
float step_v = 1.0 / float(dither_steps);
|
||||
float step_v_m = 1.0 / float(dither_steps - 1);
|
||||
float uv_stepped = floor(polar_uv / step_v) * step_v_m; // Similar to GDScript's stepify
|
||||
if (uv_stepped > 0.0) {
|
||||
// Size should not affect the center, only the steps
|
||||
polar_uv /= size;
|
||||
uv_stepped = floor(polar_uv / step_v) * step_v_m;
|
||||
uv_stepped += step_v_m * step(1.0, (1.0 - uv_stepped));
|
||||
}
|
||||
float dithered = step(uv_stepped, dither_value.r);
|
||||
vec4 output = first_color * dithered + second_color * (1.0 - dithered);
|
||||
output = mix(original_color, output, output.a);
|
||||
|
||||
COLOR = mix(original_color, output, selection_color.a);
|
||||
}
|
36
src/Shaders/Gradients/RadialStep.gdshader
Normal file
36
src/Shaders/Gradients/RadialStep.gdshader
Normal file
|
@ -0,0 +1,36 @@
|
|||
shader_type canvas_item;
|
||||
render_mode unshaded;
|
||||
|
||||
uniform sampler2D selection;
|
||||
uniform vec4 first_color : hint_color = vec4(1.0);
|
||||
uniform vec4 second_color : hint_color = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
uniform vec2 center = vec2(0.5);
|
||||
uniform vec2 radius = vec2(1.0);
|
||||
uniform float size : hint_range(0.01, 2) = 1.0;
|
||||
uniform int steps : hint_range(2, 257) = 2;
|
||||
|
||||
void fragment() {
|
||||
vec4 original_color = texture(TEXTURE, UV);
|
||||
vec4 selection_color = texture(selection, UV);
|
||||
|
||||
vec2 tex_size = 1.0 / TEXTURE_PIXEL_SIZE;
|
||||
vec2 uv = floor(UV * tex_size) / (tex_size - 1.0);
|
||||
uv = uv * 2.0 - 1.0;
|
||||
uv -= (center * 2.0) - vec2(1.0);
|
||||
uv /= radius;
|
||||
float polar_uv = length(uv);
|
||||
float step_v = 1.0 / float(steps);
|
||||
float step_v_m = 1.0 / float(steps - 1);
|
||||
float uv_stepped = floor(polar_uv / step_v) * step_v_m; // Similar to GDScript's stepify
|
||||
if (uv_stepped > 0.0) {
|
||||
// Size should not affect the center, only the steps
|
||||
polar_uv /= size;
|
||||
uv_stepped = floor(polar_uv / step_v) * step_v_m;
|
||||
uv_stepped += step_v_m * step(1.0, (1.0 - uv_stepped));
|
||||
}
|
||||
uv_stepped = clamp(uv_stepped, 0.0, 1.0);
|
||||
vec4 output = mix(first_color, second_color, uv_stepped);
|
||||
output = mix(original_color, output, output.a);
|
||||
|
||||
COLOR = mix(original_color, output, selection_color.a);
|
||||
}
|
35
src/Shaders/Gradients/Step.gdshader
Normal file
35
src/Shaders/Gradients/Step.gdshader
Normal file
|
@ -0,0 +1,35 @@
|
|||
shader_type canvas_item;
|
||||
render_mode unshaded;
|
||||
|
||||
uniform sampler2D selection;
|
||||
uniform vec4 first_color : hint_color = vec4(1.0);
|
||||
uniform vec4 second_color : hint_color = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
uniform float position : hint_range(-0.5, 0.5) = 0.0;
|
||||
uniform float size : hint_range(0.01, 2.0) = 1.0;
|
||||
uniform float angle : hint_range(0.0, 360.0) = 0.0;
|
||||
uniform int steps : hint_range(2, 100) = 2;
|
||||
|
||||
|
||||
void fragment() {
|
||||
vec4 original_color = texture(TEXTURE, UV);
|
||||
vec4 selection_color = texture(selection, UV);
|
||||
|
||||
float pivot = position / size;
|
||||
vec2 tex_size = 1.0 / TEXTURE_PIXEL_SIZE;
|
||||
vec2 uv = floor(UV * tex_size) / (tex_size - 1.0);
|
||||
uv -= 0.5;
|
||||
float angle_cos = cos(radians(angle));
|
||||
float angle_sin = sin(radians(angle));
|
||||
float rotated = uv.x * angle_cos - uv.y * angle_sin;
|
||||
rotated /= abs(angle_cos) + abs(angle_sin);
|
||||
rotated /= size;
|
||||
rotated -= pivot - 0.5;
|
||||
float step_v = 1.0 / float(steps);
|
||||
float step_v_m = 1.0 / float(steps - 1);
|
||||
float rotated_stepped = floor(rotated / step_v) * step_v_m; // Similar to GDScript's stepify
|
||||
rotated_stepped = clamp(rotated_stepped, 0.0, 1.0);
|
||||
vec4 output = mix(first_color, second_color, rotated_stepped);
|
||||
output = mix(original_color, output, output.a);
|
||||
|
||||
COLOR = mix(original_color, output, selection_color.a);
|
||||
}
|
|
@ -1,17 +1,69 @@
|
|||
extends ImageEffect
|
||||
|
||||
onready var options_cont = $VBoxContainer/OptionsContainer
|
||||
enum { LINEAR, RADIAL, STEP, RADIAL_STEP, DITHERING, RADIAL_DITHERING }
|
||||
|
||||
var shader_linear: Shader = preload("res://src/Shaders/Gradients/Linear.gdshader")
|
||||
var shader_radial: Shader = preload("res://src/Shaders/Gradients/Radial.gdshader")
|
||||
var shader_step: Shader = preload("res://src/Shaders/Gradients/Step.gdshader")
|
||||
var shader_radial_step: Shader = preload("res://src/Shaders/Gradients/RadialStep.gdshader")
|
||||
var shader_dither: Shader = preload("res://src/Shaders/Gradients/Dithering.gdshader")
|
||||
var shader_radial_dither: Shader = preload("res://src/Shaders/Gradients/RadialDithering.gdshader")
|
||||
|
||||
var confirmed := false
|
||||
var shader: Shader = shader_linear
|
||||
var dither_matrices := [
|
||||
DitherMatrix.new(preload("res://assets/dither-matrices/bayer2.png"), "Bayer 2x2"),
|
||||
DitherMatrix.new(preload("res://assets/dither-matrices/bayer4.png"), "Bayer 4x4", 16),
|
||||
DitherMatrix.new(preload("res://assets/dither-matrices/bayer8.png"), "Bayer 8x8", 64),
|
||||
DitherMatrix.new(preload("res://assets/dither-matrices/bayer16.png"), "Bayer 16x16", 256),
|
||||
]
|
||||
var selected_dither_matrix: DitherMatrix = dither_matrices[0]
|
||||
|
||||
onready var options_cont: Container = $VBoxContainer/OptionsContainer
|
||||
onready var type_option_button: OptionButton = options_cont.get_node("TypeOptionButton")
|
||||
onready var color1: ColorPickerButton = options_cont.get_node("ColorsContainer/ColorPickerButton")
|
||||
onready var color2: ColorPickerButton = options_cont.get_node("ColorsContainer/ColorPickerButton2")
|
||||
onready var position: SpinBox = options_cont.get_node("PositionSpinBox")
|
||||
onready var angle: SpinBox = options_cont.get_node("AngleSpinBox")
|
||||
onready var center_x: SpinBox = options_cont.get_node("CenterContainer/CenterXSpinBox")
|
||||
onready var center_y: SpinBox = options_cont.get_node("CenterContainer/CenterYSpinBox")
|
||||
onready var radius_x: SpinBox = options_cont.get_node("RadiusContainer/RadiusXSpinBox")
|
||||
onready var radius_y: SpinBox = options_cont.get_node("RadiusContainer/RadiusYSpinBox")
|
||||
onready var size: SpinBox = options_cont.get_node("SizeSpinBox")
|
||||
onready var steps: SpinBox = options_cont.get_node("StepSpinBox")
|
||||
onready var direction: OptionButton = options_cont.get_node("DirectionOptionButton")
|
||||
onready var dithering_option_button: OptionButton = options_cont.get_node("DitheringOptionButton")
|
||||
|
||||
|
||||
class DitherMatrix:
|
||||
var texture: Texture
|
||||
var name: String
|
||||
var n_of_colors: int
|
||||
|
||||
func _init(_texture: Texture, _name: String, _n_of_colors := 4) -> void:
|
||||
texture = _texture
|
||||
name = _name
|
||||
n_of_colors = _n_of_colors
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
color1.get_picker().presets_visible = false
|
||||
color1.get_picker().deferred_mode = true
|
||||
color2.get_picker().presets_visible = false
|
||||
color2.get_picker().deferred_mode = true
|
||||
var sm := ShaderMaterial.new()
|
||||
sm.shader = shader
|
||||
preview.set_material(sm)
|
||||
|
||||
for matrix in dither_matrices:
|
||||
dithering_option_button.add_item(matrix.name)
|
||||
|
||||
|
||||
func _about_to_show() -> void:
|
||||
confirmed = false
|
||||
._about_to_show()
|
||||
|
||||
|
||||
func _confirmed() -> void:
|
||||
confirmed = true
|
||||
._confirmed()
|
||||
|
||||
|
||||
func set_nodes() -> void:
|
||||
|
@ -20,28 +72,80 @@ func set_nodes() -> void:
|
|||
affect_option_button = $VBoxContainer/OptionsContainer/AffectOptionButton
|
||||
|
||||
|
||||
func commit_action(_cel: Image, _project: Project = Global.current_project) -> void:
|
||||
DrawingAlgos.generate_gradient(
|
||||
_cel,
|
||||
[color1.color, color2.color],
|
||||
steps.value,
|
||||
direction.selected,
|
||||
selection_checkbox.pressed,
|
||||
_project
|
||||
)
|
||||
func commit_action(cel: Image, project: Project = Global.current_project) -> void:
|
||||
var selection: Image
|
||||
var selection_tex := ImageTexture.new()
|
||||
if selection_checkbox.pressed and project.has_selection:
|
||||
selection = project.bitmap_to_image(project.selection_bitmap)
|
||||
else: # This is needed to prevent a weird bug with the dithering shaders and GLES2
|
||||
selection = Image.new()
|
||||
selection.create(project.size.x, project.size.y, false, Image.FORMAT_L8)
|
||||
selection_tex.create_from_image(selection, 0)
|
||||
|
||||
var dither_texture: Texture = selected_dither_matrix.texture
|
||||
var dither_steps: int = selected_dither_matrix.n_of_colors + 1
|
||||
var pixel_size: int = dither_texture.get_width()
|
||||
var params := {
|
||||
"first_color": color1.color,
|
||||
"second_color": color2.color,
|
||||
"selection": selection_tex,
|
||||
"position": (position.value / 100.0) - 0.5,
|
||||
"angle": angle.value,
|
||||
"center": Vector2(center_x.value / 100.0, center_y.value / 100.0),
|
||||
"radius": Vector2(radius_x.value, radius_y.value),
|
||||
"size": size.value / 100.0,
|
||||
"steps": steps.value,
|
||||
"dither_texture": dither_texture,
|
||||
"image_size": project.size,
|
||||
"dither_steps": dither_steps,
|
||||
"pixel_size": pixel_size,
|
||||
}
|
||||
|
||||
if !confirmed:
|
||||
preview.material.shader = shader
|
||||
for param in params:
|
||||
preview.material.set_shader_param(param, params[param])
|
||||
else:
|
||||
var gen := ShaderImageEffect.new()
|
||||
gen.generate_image(cel, shader, params, project.size)
|
||||
yield(gen, "done")
|
||||
|
||||
|
||||
func _on_ColorPickerButton_color_changed(_color: Color) -> void:
|
||||
func _on_TypeOptionButton_item_selected(index: int) -> void:
|
||||
for child in options_cont.get_children():
|
||||
if not child.is_in_group("gradient_common"):
|
||||
child.visible = false
|
||||
|
||||
match index:
|
||||
LINEAR:
|
||||
shader = shader_linear
|
||||
get_tree().set_group("gradient_linear", "visible", true)
|
||||
RADIAL:
|
||||
shader = shader_radial
|
||||
get_tree().set_group("gradient_radial", "visible", true)
|
||||
STEP:
|
||||
shader = shader_step
|
||||
get_tree().set_group("gradient_step", "visible", true)
|
||||
RADIAL_STEP:
|
||||
shader = shader_radial_step
|
||||
get_tree().set_group("gradient_radial_step", "visible", true)
|
||||
DITHERING:
|
||||
shader = shader_dither
|
||||
get_tree().set_group("gradient_dithering", "visible", true)
|
||||
RADIAL_DITHERING:
|
||||
shader = shader_radial_dither
|
||||
get_tree().set_group("gradient_radial_dithering", "visible", true)
|
||||
update_preview()
|
||||
|
||||
|
||||
func _on_ColorPickerButton2_color_changed(_color: Color) -> void:
|
||||
func _color_changed(_color: Color) -> void:
|
||||
update_preview()
|
||||
|
||||
|
||||
func _on_StepSpinBox_value_changed(_value: int) -> void:
|
||||
func _value_changed(_value: float) -> void:
|
||||
update_preview()
|
||||
|
||||
|
||||
func _on_DirectionOptionButton_item_selected(_index: int) -> void:
|
||||
func _on_DitheringOptionButton_item_selected(index: int) -> void:
|
||||
selected_dither_matrix = dither_matrices[index]
|
||||
update_preview()
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
[ext_resource path="res://src/UI/TransparentChecker.tscn" type="PackedScene" id=2]
|
||||
|
||||
[node name="GradientDialog" type="ConfirmationDialog"]
|
||||
margin_right = 200.0
|
||||
margin_bottom = 196.0
|
||||
rect_min_size = Vector2( 172, 60.2 )
|
||||
margin_right = 334.0
|
||||
margin_bottom = 444.0
|
||||
rect_min_size = Vector2( 334, 444 )
|
||||
window_title = "Gradient"
|
||||
resizable = true
|
||||
script = ExtResource( 1 )
|
||||
|
@ -26,14 +26,14 @@ __meta__ = {
|
|||
}
|
||||
|
||||
[node name="AspectRatioContainer" type="AspectRatioContainer" parent="VBoxContainer"]
|
||||
margin_right = 285.0
|
||||
margin_bottom = 200.0
|
||||
margin_right = 318.0
|
||||
margin_bottom = 240.0
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="Preview" type="TextureRect" parent="VBoxContainer/AspectRatioContainer"]
|
||||
margin_left = 42.5
|
||||
margin_right = 242.5
|
||||
margin_bottom = 200.0
|
||||
margin_left = 39.0
|
||||
margin_right = 279.0
|
||||
margin_bottom = 240.0
|
||||
rect_min_size = Vector2( 200, 200 )
|
||||
size_flags_horizontal = 5
|
||||
size_flags_vertical = 3
|
||||
|
@ -48,86 +48,248 @@ margin_right = 0.0
|
|||
margin_bottom = 0.0
|
||||
|
||||
[node name="OptionsContainer" type="GridContainer" parent="VBoxContainer"]
|
||||
margin_top = 204.0
|
||||
margin_right = 285.0
|
||||
margin_bottom = 304.0
|
||||
margin_top = 244.0
|
||||
margin_right = 318.0
|
||||
margin_bottom = 400.0
|
||||
columns = 2
|
||||
|
||||
[node name="Label" type="Label" parent="VBoxContainer/OptionsContainer"]
|
||||
[node name="TypeLabel" type="Label" parent="VBoxContainer/OptionsContainer" groups=["gradient_common"]]
|
||||
margin_top = 3.0
|
||||
margin_right = 160.0
|
||||
margin_bottom = 17.0
|
||||
text = "Type:"
|
||||
|
||||
[node name="TypeOptionButton" type="OptionButton" parent="VBoxContainer/OptionsContainer" groups=["gradient_common"]]
|
||||
margin_left = 164.0
|
||||
margin_right = 278.0
|
||||
margin_bottom = 20.0
|
||||
mouse_default_cursor_shape = 2
|
||||
text = "Linear"
|
||||
items = [ "Linear", null, false, 0, null, "Radial", null, false, 1, null, "Step", null, false, 2, null, "Radial Step", null, false, 3, null, "Dithering", null, false, 4, null, "Radial Dithering", null, false, 5, null ]
|
||||
selected = 0
|
||||
|
||||
[node name="ColorsLabel" type="Label" parent="VBoxContainer/OptionsContainer" groups=["gradient_common"]]
|
||||
margin_top = 27.0
|
||||
margin_right = 160.0
|
||||
margin_bottom = 41.0
|
||||
text = "Colors:"
|
||||
|
||||
[node name="ColorsContainer" type="HBoxContainer" parent="VBoxContainer/OptionsContainer"]
|
||||
margin_left = 164.0
|
||||
margin_right = 285.0
|
||||
margin_bottom = 20.0
|
||||
|
||||
[node name="ColorPickerButton" type="ColorPickerButton" parent="VBoxContainer/OptionsContainer/ColorsContainer"]
|
||||
margin_right = 20.0
|
||||
margin_bottom = 20.0
|
||||
rect_min_size = Vector2( 20, 0 )
|
||||
mouse_default_cursor_shape = 2
|
||||
|
||||
[node name="ColorPickerButton2" type="ColorPickerButton" parent="VBoxContainer/OptionsContainer/ColorsContainer"]
|
||||
margin_left = 24.0
|
||||
margin_right = 44.0
|
||||
margin_bottom = 20.0
|
||||
rect_min_size = Vector2( 20, 0 )
|
||||
mouse_default_cursor_shape = 2
|
||||
color = Color( 1, 1, 1, 1 )
|
||||
|
||||
[node name="Label2" type="Label" parent="VBoxContainer/OptionsContainer"]
|
||||
margin_top = 29.0
|
||||
margin_right = 160.0
|
||||
margin_bottom = 43.0
|
||||
text = "Steps:"
|
||||
|
||||
[node name="StepSpinBox" type="SpinBox" parent="VBoxContainer/OptionsContainer"]
|
||||
[node name="ColorsContainer" type="HBoxContainer" parent="VBoxContainer/OptionsContainer" groups=["gradient_common"]]
|
||||
margin_left = 164.0
|
||||
margin_top = 24.0
|
||||
margin_right = 285.0
|
||||
margin_bottom = 48.0
|
||||
margin_right = 278.0
|
||||
margin_bottom = 44.0
|
||||
|
||||
[node name="ColorPickerButton" type="ColorPickerButton" parent="VBoxContainer/OptionsContainer/ColorsContainer"]
|
||||
margin_right = 55.0
|
||||
margin_bottom = 20.0
|
||||
rect_min_size = Vector2( 20, 0 )
|
||||
mouse_default_cursor_shape = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="ColorPickerButton2" type="ColorPickerButton" parent="VBoxContainer/OptionsContainer/ColorsContainer"]
|
||||
margin_left = 59.0
|
||||
margin_right = 114.0
|
||||
margin_bottom = 20.0
|
||||
rect_min_size = Vector2( 20, 0 )
|
||||
mouse_default_cursor_shape = 2
|
||||
size_flags_horizontal = 3
|
||||
color = Color( 1, 1, 1, 1 )
|
||||
|
||||
[node name="PositionLabel" type="Label" parent="VBoxContainer/OptionsContainer" groups=["gradient_dithering", "gradient_linear", "gradient_step"]]
|
||||
margin_top = 53.0
|
||||
margin_right = 160.0
|
||||
margin_bottom = 67.0
|
||||
text = "Position:"
|
||||
|
||||
[node name="PositionSpinBox" type="SpinBox" parent="VBoxContainer/OptionsContainer" groups=["gradient_dithering", "gradient_linear", "gradient_step"]]
|
||||
margin_left = 164.0
|
||||
margin_top = 48.0
|
||||
margin_right = 278.0
|
||||
margin_bottom = 72.0
|
||||
mouse_default_cursor_shape = 2
|
||||
value = 50.0
|
||||
suffix = "%"
|
||||
|
||||
[node name="AngleLabel" type="Label" parent="VBoxContainer/OptionsContainer" groups=["gradient_dithering", "gradient_linear", "gradient_step"]]
|
||||
margin_top = 81.0
|
||||
margin_right = 160.0
|
||||
margin_bottom = 95.0
|
||||
text = "Angle:"
|
||||
|
||||
[node name="AngleSpinBox" type="SpinBox" parent="VBoxContainer/OptionsContainer" groups=["gradient_dithering", "gradient_linear", "gradient_step"]]
|
||||
margin_left = 164.0
|
||||
margin_top = 76.0
|
||||
margin_right = 278.0
|
||||
margin_bottom = 100.0
|
||||
mouse_default_cursor_shape = 2
|
||||
max_value = 360.0
|
||||
suffix = "°"
|
||||
|
||||
[node name="SizeLabel" type="Label" parent="VBoxContainer/OptionsContainer" groups=["gradient_common"]]
|
||||
margin_top = 109.0
|
||||
margin_right = 160.0
|
||||
margin_bottom = 123.0
|
||||
text = "Transition size:"
|
||||
|
||||
[node name="SizeSpinBox" type="SpinBox" parent="VBoxContainer/OptionsContainer" groups=["gradient_common"]]
|
||||
margin_left = 164.0
|
||||
margin_top = 104.0
|
||||
margin_right = 278.0
|
||||
margin_bottom = 128.0
|
||||
mouse_default_cursor_shape = 2
|
||||
min_value = 1.0
|
||||
max_value = 200.0
|
||||
value = 100.0
|
||||
suffix = "%"
|
||||
|
||||
[node name="StepsLabel" type="Label" parent="VBoxContainer/OptionsContainer" groups=["gradient_radial_step", "gradient_step"]]
|
||||
visible = false
|
||||
margin_top = 137.0
|
||||
margin_right = 160.0
|
||||
margin_bottom = 151.0
|
||||
text = "Steps:"
|
||||
|
||||
[node name="StepSpinBox" type="SpinBox" parent="VBoxContainer/OptionsContainer" groups=["gradient_radial_step", "gradient_step"]]
|
||||
visible = false
|
||||
margin_left = 164.0
|
||||
margin_top = 132.0
|
||||
margin_right = 316.0
|
||||
margin_bottom = 156.0
|
||||
mouse_default_cursor_shape = 2
|
||||
min_value = 2.0
|
||||
value = 2.0
|
||||
|
||||
[node name="Label3" type="Label" parent="VBoxContainer/OptionsContainer"]
|
||||
margin_top = 55.0
|
||||
[node name="CenterLabel" type="Label" parent="VBoxContainer/OptionsContainer" groups=["gradient_radial", "gradient_radial_dithering", "gradient_radial_step"]]
|
||||
visible = false
|
||||
margin_top = 165.0
|
||||
margin_right = 160.0
|
||||
margin_bottom = 69.0
|
||||
text = "Direction:"
|
||||
margin_bottom = 179.0
|
||||
text = "Center:"
|
||||
|
||||
[node name="DirectionOptionButton" type="OptionButton" parent="VBoxContainer/OptionsContainer"]
|
||||
margin_left = 164.0
|
||||
margin_top = 52.0
|
||||
margin_right = 285.0
|
||||
margin_bottom = 72.0
|
||||
[node name="CenterContainer" type="HBoxContainer" parent="VBoxContainer/OptionsContainer" groups=["gradient_radial", "gradient_radial_dithering", "gradient_radial_step"]]
|
||||
visible = false
|
||||
margin_top = 132.0
|
||||
margin_right = 183.0
|
||||
margin_bottom = 156.0
|
||||
|
||||
[node name="XLabel" type="Label" parent="VBoxContainer/OptionsContainer/CenterContainer"]
|
||||
margin_top = 5.0
|
||||
margin_right = 12.0
|
||||
margin_bottom = 19.0
|
||||
text = "X:"
|
||||
|
||||
[node name="CenterXSpinBox" type="SpinBox" parent="VBoxContainer/OptionsContainer/CenterContainer"]
|
||||
margin_left = 16.0
|
||||
margin_right = 90.0
|
||||
margin_bottom = 24.0
|
||||
mouse_default_cursor_shape = 2
|
||||
text = "Top to Bottom"
|
||||
items = [ "Top to Bottom", null, false, 0, null, "Bottom to Top", null, false, 1, null, "Left to Right", null, false, 2, null, "Right to Left", null, false, 3, null ]
|
||||
selected = 0
|
||||
value = 50.0
|
||||
suffix = "%"
|
||||
|
||||
[node name="SelectionCheckBox" type="CheckBox" parent="VBoxContainer/OptionsContainer"]
|
||||
margin_top = 76.0
|
||||
[node name="YLabel" type="Label" parent="VBoxContainer/OptionsContainer/CenterContainer"]
|
||||
margin_left = 94.0
|
||||
margin_top = 5.0
|
||||
margin_right = 105.0
|
||||
margin_bottom = 19.0
|
||||
text = "Y:"
|
||||
|
||||
[node name="CenterYSpinBox" type="SpinBox" parent="VBoxContainer/OptionsContainer/CenterContainer"]
|
||||
margin_left = 109.0
|
||||
margin_right = 183.0
|
||||
margin_bottom = 24.0
|
||||
mouse_default_cursor_shape = 2
|
||||
value = 50.0
|
||||
suffix = "%"
|
||||
|
||||
[node name="RadiusLabel" type="Label" parent="VBoxContainer/OptionsContainer" groups=["gradient_radial", "gradient_radial_dithering", "gradient_radial_step"]]
|
||||
visible = false
|
||||
margin_top = 193.0
|
||||
margin_right = 160.0
|
||||
margin_bottom = 100.0
|
||||
margin_bottom = 207.0
|
||||
text = "Radius:"
|
||||
|
||||
[node name="RadiusContainer" type="HBoxContainer" parent="VBoxContainer/OptionsContainer" groups=["gradient_radial", "gradient_radial_dithering", "gradient_radial_step"]]
|
||||
visible = false
|
||||
margin_left = 164.0
|
||||
margin_top = 188.0
|
||||
margin_right = 316.0
|
||||
margin_bottom = 212.0
|
||||
|
||||
[node name="XLabel" type="Label" parent="VBoxContainer/OptionsContainer/RadiusContainer"]
|
||||
margin_left = -164.0
|
||||
margin_top = -51.0
|
||||
margin_right = -152.0
|
||||
margin_bottom = -37.0
|
||||
text = "X:"
|
||||
|
||||
[node name="RadiusXSpinBox" type="SpinBox" parent="VBoxContainer/OptionsContainer/RadiusContainer"]
|
||||
margin_right = 74.0
|
||||
margin_bottom = 24.0
|
||||
mouse_default_cursor_shape = 2
|
||||
min_value = 0.01
|
||||
step = 0.01
|
||||
value = 1.0
|
||||
|
||||
[node name="YLabel" type="Label" parent="VBoxContainer/OptionsContainer/RadiusContainer"]
|
||||
margin_left = -70.0
|
||||
margin_top = -51.0
|
||||
margin_right = -59.0
|
||||
margin_bottom = -37.0
|
||||
text = "Y:"
|
||||
|
||||
[node name="RadiusYSpinBox" type="SpinBox" parent="VBoxContainer/OptionsContainer/RadiusContainer"]
|
||||
margin_left = 78.0
|
||||
margin_right = 152.0
|
||||
margin_bottom = 24.0
|
||||
mouse_default_cursor_shape = 2
|
||||
min_value = 0.01
|
||||
step = 0.01
|
||||
value = 1.0
|
||||
|
||||
[node name="DitheringLabel" type="Label" parent="VBoxContainer/OptionsContainer" groups=["gradient_dithering", "gradient_radial_dithering"]]
|
||||
visible = false
|
||||
margin_top = 219.0
|
||||
margin_right = 160.0
|
||||
margin_bottom = 233.0
|
||||
text = "Dithering pattern:"
|
||||
|
||||
[node name="DitheringOptionButton" type="OptionButton" parent="VBoxContainer/OptionsContainer" groups=["gradient_dithering", "gradient_radial_dithering"]]
|
||||
visible = false
|
||||
margin_left = 164.0
|
||||
margin_top = 216.0
|
||||
margin_right = 316.0
|
||||
margin_bottom = 236.0
|
||||
mouse_default_cursor_shape = 2
|
||||
text = "Bayer 2x2"
|
||||
|
||||
[node name="SelectionCheckBox" type="CheckBox" parent="VBoxContainer/OptionsContainer" groups=["gradient_common"]]
|
||||
margin_top = 132.0
|
||||
margin_right = 160.0
|
||||
margin_bottom = 156.0
|
||||
mouse_default_cursor_shape = 2
|
||||
pressed = true
|
||||
text = "Only affect selection"
|
||||
|
||||
[node name="AffectOptionButton" type="OptionButton" parent="VBoxContainer/OptionsContainer"]
|
||||
[node name="AffectOptionButton" type="OptionButton" parent="VBoxContainer/OptionsContainer" groups=["gradient_common"]]
|
||||
margin_left = 164.0
|
||||
margin_top = 76.0
|
||||
margin_right = 285.0
|
||||
margin_bottom = 100.0
|
||||
margin_top = 132.0
|
||||
margin_right = 278.0
|
||||
margin_bottom = 156.0
|
||||
mouse_default_cursor_shape = 2
|
||||
text = "Selected cels"
|
||||
items = [ "Selected cels", null, false, 0, null, "Current frame", null, false, 1, null, "All frames", null, false, 2, null, "All projects", null, false, 3, null ]
|
||||
selected = 0
|
||||
|
||||
[connection signal="color_changed" from="VBoxContainer/OptionsContainer/ColorsContainer/ColorPickerButton" to="." method="_on_ColorPickerButton_color_changed"]
|
||||
[connection signal="color_changed" from="VBoxContainer/OptionsContainer/ColorsContainer/ColorPickerButton2" to="." method="_on_ColorPickerButton2_color_changed"]
|
||||
[connection signal="value_changed" from="VBoxContainer/OptionsContainer/StepSpinBox" to="." method="_on_StepSpinBox_value_changed"]
|
||||
[connection signal="item_selected" from="VBoxContainer/OptionsContainer/DirectionOptionButton" to="." method="_on_DirectionOptionButton_item_selected"]
|
||||
[connection signal="item_selected" from="VBoxContainer/OptionsContainer/TypeOptionButton" to="." method="_on_TypeOptionButton_item_selected"]
|
||||
[connection signal="color_changed" from="VBoxContainer/OptionsContainer/ColorsContainer/ColorPickerButton" to="." method="_color_changed"]
|
||||
[connection signal="color_changed" from="VBoxContainer/OptionsContainer/ColorsContainer/ColorPickerButton2" to="." method="_color_changed"]
|
||||
[connection signal="value_changed" from="VBoxContainer/OptionsContainer/PositionSpinBox" to="." method="_value_changed"]
|
||||
[connection signal="value_changed" from="VBoxContainer/OptionsContainer/AngleSpinBox" to="." method="_value_changed"]
|
||||
[connection signal="value_changed" from="VBoxContainer/OptionsContainer/SizeSpinBox" to="." method="_value_changed"]
|
||||
[connection signal="value_changed" from="VBoxContainer/OptionsContainer/StepSpinBox" to="." method="_value_changed"]
|
||||
[connection signal="value_changed" from="VBoxContainer/OptionsContainer/CenterContainer/CenterXSpinBox" to="." method="_value_changed"]
|
||||
[connection signal="value_changed" from="VBoxContainer/OptionsContainer/CenterContainer/CenterYSpinBox" to="." method="_value_changed"]
|
||||
[connection signal="value_changed" from="VBoxContainer/OptionsContainer/RadiusContainer/RadiusXSpinBox" to="." method="_value_changed"]
|
||||
[connection signal="value_changed" from="VBoxContainer/OptionsContainer/RadiusContainer/RadiusYSpinBox" to="." method="_value_changed"]
|
||||
[connection signal="item_selected" from="VBoxContainer/OptionsContainer/DitheringOptionButton" to="." method="_on_DitheringOptionButton_item_selected"]
|
||||
|
|
Loading…
Reference in a new issue