1
0
Fork 0
mirror of https://github.com/Orama-Interactive/Pixelorama.git synced 2025-01-18 17:19:50 +00:00

Add multi-color support for gradients, remove step gradients

Gradients are no longer limited to two colors, but can now instead have as many as we want, with each color having its own offset. Step gradients have now been removed; to generate the same effect, you can now generate a linear gradient with constant interpolation. Cubic interpolation in gradients is now also possible.

The dithering shaders were by far the biggest challenge and they had to be re-written in order for them to support multiple colors, with each one having a difference offset. I have noticed that some colors may disappear when Constant interpolation is used, though, so it can be buggy sometimes. Thanks to https://godotshaders.com/shader/dither-gradient-shader/ for the reference.

ValueSliders are now also used in the gradient window.
This commit is contained in:
Emmanouil Papadeas 2023-01-27 04:23:48 +02:00
parent 42d6f12530
commit 201992fa72
12 changed files with 279 additions and 317 deletions

View file

@ -178,3 +178,7 @@ func update_transparent_background_size() -> void:
func _popup_hide() -> void:
Global.dialog_open(false)
func _is_webgl1() -> bool:
return OS.get_name() == "HTML5" and OS.get_current_video_driver() == OS.VIDEO_DRIVER_GLES2

View file

@ -2,10 +2,8 @@ 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 sampler2D gradient_texture;
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() {
@ -13,14 +11,14 @@ void fragment() {
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);
vec2 uv = UV - 0.5;
uv = floor(uv * tex_size) / (tex_size - 1.0);
float angle_cos = cos(radians(angle));
float angle_sin = sin(radians(angle));
float rotated_uv = uv.x * angle_cos - uv.y * angle_sin;
rotated_uv /= abs(angle_cos) + abs(angle_sin);
rotated_uv -= position - 0.5;
vec4 output = texture(gradient_texture, vec2(rotated_uv));
output = mix(original_color, output, output.a);
COLOR = mix(original_color, output, selection_color.a);
}

View file

@ -1,38 +1,62 @@
shader_type canvas_item;
render_mode unshaded;
uniform sampler2D gradient_texture;
uniform sampler2D dither_texture;
uniform sampler2D offset_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;
uniform int n_of_colors = 2;
// Logic taken from https://godotshaders.com/shader/dither-gradient-shader/
float dither(vec2 uv, float modified_uv) {
float uv_lower = floor(modified_uv);
float uv_upper = (floor(modified_uv) + 1.0);
float threshold = texture(dither_texture, uv * (image_size / float(pixel_size))).r;
float ramp_val = modified_uv < threshold ? 0.0 : 1.0;
// sample at the lower bound colour if ramp_val is 0.0, upper bound color if 1.0
float col_sample = mix(uv_lower, uv_upper, ramp_val);
return col_sample;
}
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;
float rotated_uv = uv.x * angle_cos - uv.y * angle_sin;
rotated_uv /= abs(angle_cos) + abs(angle_sin);
rotated_uv -= position - 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);
vec4 output;
for (int i = 1; i <= n_of_colors; i++) {
float colors_minus = float(n_of_colors - 1);
float off = texture(offset_texture, vec2(float(i) / colors_minus)).r;
float off_prev = texture(offset_texture, vec2(float(i - 1) / colors_minus)).r;
vec4 first = texture(gradient_texture, vec2(float((i - 1)) / colors_minus));
vec4 second = texture(gradient_texture, vec2(float(i) / colors_minus));
if (rotated_uv < off_prev) {
if (i == 1) {
output = first;
}
continue;
}
if (rotated_uv > off) {
if (i == n_of_colors) {
output = second;
}
continue;
}
float uvt = (rotated_uv - off_prev) / (off - off_prev);
float col_sample = dither(UV, uvt);
output = mix(first, second, col_sample);
}
COLOR = mix(original_color, output, selection_color.a);
}

View file

@ -1,35 +0,0 @@
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);
}

View file

@ -2,11 +2,9 @@ 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 sampler2D gradient_texture;
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);
@ -15,9 +13,8 @@ void fragment() {
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;
float smooth_dist = smoothstep(0.0, 1.0, distance(uv, center / radius));
vec4 output = texture(gradient_texture, vec2(smooth_dist));
output = mix(original_color, output, output.a);
COLOR = mix(original_color, output, selection_color.a);
}

View file

@ -1,16 +1,27 @@
shader_type canvas_item;
render_mode unshaded;
uniform sampler2D gradient_texture;
uniform sampler2D dither_texture;
uniform sampler2D offset_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;
uniform int n_of_colors = 2;
// Logic taken from https://godotshaders.com/shader/dither-gradient-shader/
float dither(vec2 uv, float modified_uv) {
float uv_lower = floor(modified_uv);
float uv_upper = (floor(modified_uv) + 1.0);
float threshold = texture(dither_texture, uv * (image_size / float(pixel_size))).r;
float ramp_val = modified_uv < threshold ? 0.0 : 1.0;
// sample at the lower bound colour if ramp_val is 0.0, upper bound color if 1.0
float col_sample = mix(uv_lower, uv_upper, ramp_val);
return col_sample;
}
void fragment() {
vec4 original_color = texture(TEXTURE, UV);
@ -19,21 +30,33 @@ void fragment() {
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);
vec4 dither_value = texture(dither_texture, uv * (image_size / float(pixel_size)));
vec4 output;
for (int i = 1; i <= n_of_colors; i++) {
float colors_minus = float(n_of_colors - 1);
float off = texture(offset_texture, vec2(float(i) / colors_minus)).r;
float off_prev = texture(offset_texture, vec2(float(i - 1) / colors_minus)).r;
vec4 first = texture(gradient_texture, vec2(float((i - 1)) / colors_minus));
vec4 second = texture(gradient_texture, vec2(float(i) / colors_minus));
if (polar_uv < off_prev) {
if (i == 1) {
output = first;
}
continue;
}
if (polar_uv > off) {
if (i == n_of_colors) {
output = second;
}
continue;
}
float uvt = (polar_uv - off_prev) / (off - off_prev);
float col_sample = dither(UV, uvt);
output = mix(first, second, col_sample);
}
COLOR = mix(original_color, output, selection_color.a);
}

View file

@ -1,36 +0,0 @@
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);
}

View file

@ -1,55 +1,52 @@
extends ImageEffect
enum { LINEAR, RADIAL, LINEAR_STEP, RADIAL_STEP, LINEAR_DITHERING, RADIAL_DITHERING }
enum { LINEAR, RADIAL, LINEAR_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_linear_step: Shader = preload("res://src/Shaders/Gradients/LinearStep.gdshader")
var shader_radial_step: Shader = preload("res://src/Shaders/Gradients/RadialStep.gdshader")
var shader_linear_dither: Shader = preload("res://src/Shaders/Gradients/LinearDithering.gdshader")
var shader_radial_dither: Shader = preload("res://src/Shaders/Gradients/RadialDithering.gdshader")
var shader_linear_dither: Shader
var shader_radial_dither: Shader
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),
DitherMatrix.new(preload("res://assets/dither-matrices/bayer4.png"), "Bayer 4x4"),
DitherMatrix.new(preload("res://assets/dither-matrices/bayer8.png"), "Bayer 8x8"),
DitherMatrix.new(preload("res://assets/dither-matrices/bayer16.png"), "Bayer 16x16"),
]
var selected_dither_matrix: DitherMatrix = dither_matrices[0]
onready var options_cont: Container = $VBoxContainer/OptionsContainer
onready var gradient_edit: GradientEditNode = $VBoxContainer/GradientEdit
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 position: ValueSlider = $"%PositionSlider"
onready var angle: ValueSlider = $"%AngleSlider"
onready var center_x: ValueSlider = $"%XCenterSlider"
onready var center_y: ValueSlider = $"%YCenterSlider"
onready var radius_x: ValueSlider = $"%XRadiusSlider"
onready var radius_y: ValueSlider = $"%YRadiusSlider"
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:
func _init(_texture: Texture, _name: String) -> void:
texture = _texture
name = _name
n_of_colors = _n_of_colors
func _ready() -> void:
color1.get_picker().presets_visible = false
color2.get_picker().presets_visible = false
var sm := ShaderMaterial.new()
sm.shader = shader
preview.set_material(sm)
if _is_webgl1():
type_option_button.set_item_disabled(LINEAR_DITHERING, true)
type_option_button.set_item_disabled(RADIAL_DITHERING, true)
else:
shader_linear_dither = load("res://src/Shaders/Gradients/LinearDithering.gdshader")
shader_radial_dither = load("res://src/Shaders/Gradients/RadialDithering.gdshader")
for matrix in dither_matrices:
dithering_option_button.add_item(matrix.name)
@ -72,22 +69,33 @@ func commit_action(cel: Image, project: Project = Global.current_project) -> voi
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 pixel_size := dither_texture.get_width()
var gradient: Gradient = gradient_edit.texture.gradient
var n_of_colors := gradient.offsets.size()
# Pass the gradient offsets as an array to the shader
# ...but since Godot 3.x doesn't support uniform arrays, instead we construct
# a nx1 grayscale texture with each offset stored in each pixel, and pass it to the shader
var offsets_image := Image.new()
offsets_image.create(n_of_colors, 1, false, Image.FORMAT_L8)
offsets_image.lock()
for i in n_of_colors:
var c := gradient.offsets[i]
offsets_image.set_pixel(i, 0, Color(c, c, c, c))
offsets_image.unlock()
var offsets_tex := ImageTexture.new()
offsets_tex.create_from_image(offsets_image, 0)
var params := {
"first_color": color1.color,
"second_color": color2.color,
"gradient_texture": gradient_edit.texture,
"offset_texture": offsets_tex,
"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,
"n_of_colors": n_of_colors
}
if !confirmed:
@ -112,12 +120,6 @@ func _on_TypeOptionButton_item_selected(index: int) -> void:
RADIAL:
shader = shader_radial
get_tree().set_group("gradient_radial", "visible", true)
LINEAR_STEP:
shader = shader_linear_step
get_tree().set_group("gradient_step", "visible", true)
RADIAL_STEP:
shader = shader_radial_step
get_tree().set_group("gradient_radial_step", "visible", true)
LINEAR_DITHERING:
shader = shader_linear_dither
get_tree().set_group("gradient_dithering", "visible", true)
@ -127,10 +129,6 @@ func _on_TypeOptionButton_item_selected(index: int) -> void:
update_preview()
func _color_changed(_color: Color) -> void:
update_preview()
func _value_changed(_value: float) -> void:
update_preview()
@ -138,3 +136,7 @@ func _value_changed(_value: float) -> void:
func _on_DitheringOptionButton_item_selected(index: int) -> void:
selected_dither_matrix = dither_matrices[index]
update_preview()
func _on_GradientEdit_updated(_gradient, _cc) -> void:
update_preview()

View file

@ -1,7 +1,9 @@
[gd_scene load_steps=3 format=2]
[gd_scene load_steps=5 format=2]
[ext_resource path="res://src/UI/Dialogs/ImageEffects/GradientDialog.gd" type="Script" id=1]
[ext_resource path="res://src/UI/Nodes/TransparentChecker.tscn" type="PackedScene" id=2]
[ext_resource path="res://src/UI/Nodes/GradientEdit.tscn" type="PackedScene" id=3]
[ext_resource path="res://src/UI/Nodes/ValueSlider.gd" type="Script" id=4]
[node name="GradientDialog" type="ConfirmationDialog"]
margin_right = 334.0
@ -10,9 +12,6 @@ rect_min_size = Vector2( 334, 444 )
window_title = "Gradient"
resizable = true
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="VBoxContainer" type="VBoxContainer" parent="."]
anchor_right = 1.0
@ -21,20 +20,16 @@ margin_left = 8.0
margin_top = 8.0
margin_right = -8.0
margin_bottom = -36.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="AspectRatioContainer" type="AspectRatioContainer" parent="VBoxContainer"]
margin_right = 318.0
margin_bottom = 240.0
margin_bottom = 230.0
size_flags_vertical = 3
[node name="Preview" type="TextureRect" parent="VBoxContainer/AspectRatioContainer"]
margin_left = 39.0
margin_right = 279.0
margin_bottom = 240.0
rect_min_size = Vector2( 200, 200 )
margin_left = 44.0
margin_right = 274.0
margin_bottom = 230.0
size_flags_horizontal = 5
size_flags_vertical = 3
expand = true
@ -47,8 +42,15 @@ anchor_bottom = 1.0
margin_right = 0.0
margin_bottom = 0.0
[node name="GradientEdit" parent="VBoxContainer" instance=ExtResource( 3 )]
anchor_right = 0.0
anchor_bottom = 0.0
margin_top = 234.0
margin_right = 318.0
margin_bottom = 312.0
[node name="OptionsContainer" type="GridContainer" parent="VBoxContainer"]
margin_top = 244.0
margin_top = 316.0
margin_right = 318.0
margin_bottom = 400.0
columns = 2
@ -57,149 +59,124 @@ columns = 2
margin_top = 3.0
margin_right = 160.0
margin_bottom = 17.0
size_flags_horizontal = 3
text = "Type:"
[node name="TypeOptionButton" type="OptionButton" parent="VBoxContainer/OptionsContainer" groups=["gradient_common"]]
margin_left = 164.0
margin_right = 278.0
margin_right = 318.0
margin_bottom = 20.0
mouse_default_cursor_shape = 2
size_flags_horizontal = 3
text = "Linear"
items = [ "Linear", null, false, 0, null, "Radial", null, false, 1, null, "Linear Step", null, false, 2, null, "Radial Step", null, false, 3, null, "Linear Dithering", null, false, 4, null, "Radial Dithering", null, false, 5, null ]
items = [ "Linear", null, false, 0, null, "Radial", null, false, 1, null, "Linear 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
visible = false
margin_top = 3.0
margin_right = 160.0
margin_bottom = 41.0
margin_bottom = 17.0
text = "Colors:"
[node name="ColorsContainer" type="HBoxContainer" parent="VBoxContainer/OptionsContainer" groups=["gradient_common"]]
margin_left = 164.0
margin_top = 24.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_top = 24.0
margin_right = 160.0
margin_bottom = 67.0
margin_bottom = 38.0
text = "Position:"
[node name="PositionSpinBox" type="SpinBox" parent="VBoxContainer/OptionsContainer" groups=["gradient_dithering", "gradient_linear", "gradient_step"]]
[node name="PositionSlider" type="TextureProgress" parent="VBoxContainer/OptionsContainer" groups=["gradient_dithering", "gradient_linear"]]
unique_name_in_owner = true
margin_left = 164.0
margin_top = 48.0
margin_right = 278.0
margin_bottom = 72.0
margin_top = 24.0
margin_right = 318.0
margin_bottom = 38.0
mouse_default_cursor_shape = 2
theme_type_variation = "ValueSlider"
value = 50.0
allow_greater = true
allow_lesser = true
nine_patch_stretch = true
stretch_margin_left = 3
stretch_margin_top = 3
stretch_margin_right = 3
stretch_margin_bottom = 3
script = ExtResource( 4 )
suffix = "%"
[node name="AngleLabel" type="Label" parent="VBoxContainer/OptionsContainer" groups=["gradient_dithering", "gradient_linear", "gradient_step"]]
margin_top = 81.0
margin_top = 42.0
margin_right = 160.0
margin_bottom = 95.0
margin_bottom = 56.0
text = "Angle:"
[node name="AngleSpinBox" type="SpinBox" parent="VBoxContainer/OptionsContainer" groups=["gradient_dithering", "gradient_linear", "gradient_step"]]
[node name="AngleSlider" type="TextureProgress" parent="VBoxContainer/OptionsContainer" groups=["gradient_dithering", "gradient_linear"]]
unique_name_in_owner = true
margin_left = 164.0
margin_top = 76.0
margin_right = 278.0
margin_bottom = 100.0
margin_top = 42.0
margin_right = 318.0
margin_bottom = 56.0
mouse_default_cursor_shape = 2
theme_type_variation = "ValueSlider"
max_value = 360.0
nine_patch_stretch = true
stretch_margin_left = 3
stretch_margin_top = 3
stretch_margin_right = 3
stretch_margin_bottom = 3
script = ExtResource( 4 )
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="CenterLabel" type="Label" parent="VBoxContainer/OptionsContainer" groups=["gradient_radial", "gradient_radial_dithering", "gradient_radial_step"]]
visible = false
margin_top = 165.0
margin_top = 60.0
margin_right = 160.0
margin_bottom = 179.0
margin_bottom = 74.0
text = "Center:"
[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
margin_top = 60.0
margin_right = 154.0
margin_bottom = 84.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
[node name="XCenterSlider" type="TextureProgress" parent="VBoxContainer/OptionsContainer/CenterContainer"]
unique_name_in_owner = true
margin_right = 75.0
margin_bottom = 24.0
mouse_default_cursor_shape = 2
size_flags_horizontal = 3
theme_type_variation = "ValueSlider"
value = 50.0
allow_greater = true
allow_lesser = true
nine_patch_stretch = true
stretch_margin_left = 3
stretch_margin_top = 3
stretch_margin_right = 3
stretch_margin_bottom = 3
script = ExtResource( 4 )
prefix = "X:"
suffix = "%"
[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
[node name="YCenterSlider" type="TextureProgress" parent="VBoxContainer/OptionsContainer/CenterContainer"]
unique_name_in_owner = true
margin_left = 79.0
margin_right = 154.0
margin_bottom = 24.0
mouse_default_cursor_shape = 2
size_flags_horizontal = 3
theme_type_variation = "ValueSlider"
value = 50.0
allow_greater = true
allow_lesser = true
nine_patch_stretch = true
stretch_margin_left = 3
stretch_margin_top = 3
stretch_margin_right = 3
stretch_margin_bottom = 3
script = ExtResource( 4 )
prefix = "Y:"
suffix = "%"
[node name="RadiusLabel" type="Label" parent="VBoxContainer/OptionsContainer" groups=["gradient_radial", "gradient_radial_dithering", "gradient_radial_step"]]
@ -211,85 +188,92 @@ 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
margin_top = 60.0
margin_right = 154.0
margin_bottom = 84.0
size_flags_vertical = 3
[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
[node name="XRadiusSlider" type="TextureProgress" parent="VBoxContainer/OptionsContainer/RadiusContainer"]
unique_name_in_owner = true
margin_right = 75.0
margin_bottom = 24.0
mouse_default_cursor_shape = 2
size_flags_horizontal = 3
theme_type_variation = "ValueSlider"
min_value = 0.01
max_value = 10.0
step = 0.01
value = 1.0
allow_greater = true
nine_patch_stretch = true
stretch_margin_left = 3
stretch_margin_top = 3
stretch_margin_right = 3
stretch_margin_bottom = 3
script = ExtResource( 4 )
prefix = "X:"
[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
[node name="YRadiusSlider" type="TextureProgress" parent="VBoxContainer/OptionsContainer/RadiusContainer"]
unique_name_in_owner = true
margin_left = 79.0
margin_right = 154.0
margin_bottom = 24.0
mouse_default_cursor_shape = 2
size_flags_horizontal = 3
theme_type_variation = "ValueSlider"
min_value = 0.01
max_value = 10.0
step = 0.01
value = 1.0
allow_greater = true
nine_patch_stretch = true
stretch_margin_left = 3
stretch_margin_top = 3
stretch_margin_right = 3
stretch_margin_bottom = 3
script = ExtResource( 4 )
prefix = "Y:"
[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
margin_top = 89.0
margin_right = 114.0
margin_bottom = 103.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
margin_top = 84.0
margin_right = 278.0
margin_bottom = 104.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_top = 60.0
margin_right = 160.0
margin_bottom = 156.0
margin_bottom = 84.0
mouse_default_cursor_shape = 2
pressed = true
text = "Only affect selection"
[node name="AffectOptionButton" type="OptionButton" parent="VBoxContainer/OptionsContainer" groups=["gradient_common"]]
margin_left = 164.0
margin_top = 132.0
margin_right = 278.0
margin_bottom = 156.0
margin_top = 60.0
margin_right = 318.0
margin_bottom = 84.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="updated" from="VBoxContainer/GradientEdit" to="." method="_on_GradientEdit_updated"]
[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="value_changed" from="VBoxContainer/OptionsContainer/PositionSlider" to="." method="_value_changed"]
[connection signal="value_changed" from="VBoxContainer/OptionsContainer/AngleSlider" to="." method="_value_changed"]
[connection signal="value_changed" from="VBoxContainer/OptionsContainer/CenterContainer/XCenterSlider" to="." method="_value_changed"]
[connection signal="value_changed" from="VBoxContainer/OptionsContainer/CenterContainer/YCenterSlider" to="." method="_value_changed"]
[connection signal="value_changed" from="VBoxContainer/OptionsContainer/RadiusContainer/XRadiusSlider" to="." method="_value_changed"]
[connection signal="value_changed" from="VBoxContainer/OptionsContainer/RadiusContainer/YRadiusSlider" to="." method="_value_changed"]
[connection signal="item_selected" from="VBoxContainer/OptionsContainer/DitheringOptionButton" to="." method="_on_DitheringOptionButton_item_selected"]

View file

@ -10,7 +10,7 @@ onready var outline_color = $VBoxContainer/OptionsContainer/OutlineColor
func _ready() -> void:
if OS.get_name() == "HTML5" and OS.get_current_video_driver() == OS.VIDEO_DRIVER_GLES2:
if _is_webgl1():
$VBoxContainer/OptionsContainer/PatternOptionButton.disabled = true
else:
shader = load("res://src/Shaders/OutlineInline.gdshader")

View file

@ -22,7 +22,7 @@ onready var wait_time_slider: ValueSlider = $VBoxContainer/WaitTime
func _ready() -> void:
if OS.get_name() != "HTML5":
if not _is_webgl1():
type_option_button.add_item("Rotxel with Smear", ROTXEL_SMEAR)
rotxel_shader = load("res://src/Shaders/Rotation/SmearRotxel.shader")
type_option_button.add_item("cleanEdge", CLEANEDGE)

View file

@ -197,3 +197,4 @@ func _on_DivideConfirmationDialog_confirmed() -> void:
for i in parts + end_point:
gradient.add_point(i / parts, colors[i])
_create_cursors()
emit_signal("updated", gradient, continuous_change)