diff --git a/src/Classes/ImageEffect.gd b/src/Classes/ImageEffect.gd index e233db410..3d391e75b 100644 --- a/src/Classes/ImageEffect.gd +++ b/src/Classes/ImageEffect.gd @@ -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 diff --git a/src/Shaders/Gradients/Linear.gdshader b/src/Shaders/Gradients/Linear.gdshader index e34ff0f91..fe348bf8f 100644 --- a/src/Shaders/Gradients/Linear.gdshader +++ b/src/Shaders/Gradients/Linear.gdshader @@ -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); } diff --git a/src/Shaders/Gradients/LinearDithering.gdshader b/src/Shaders/Gradients/LinearDithering.gdshader index f7d5a2636..b7bd59432 100644 --- a/src/Shaders/Gradients/LinearDithering.gdshader +++ b/src/Shaders/Gradients/LinearDithering.gdshader @@ -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); } diff --git a/src/Shaders/Gradients/LinearStep.gdshader b/src/Shaders/Gradients/LinearStep.gdshader deleted file mode 100644 index 5ce691e7c..000000000 --- a/src/Shaders/Gradients/LinearStep.gdshader +++ /dev/null @@ -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); -} diff --git a/src/Shaders/Gradients/Radial.gdshader b/src/Shaders/Gradients/Radial.gdshader index 47e439cb9..6881819e6 100644 --- a/src/Shaders/Gradients/Radial.gdshader +++ b/src/Shaders/Gradients/Radial.gdshader @@ -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); } diff --git a/src/Shaders/Gradients/RadialDithering.gdshader b/src/Shaders/Gradients/RadialDithering.gdshader index 7cbdaf8fb..c792bb8ea 100644 --- a/src/Shaders/Gradients/RadialDithering.gdshader +++ b/src/Shaders/Gradients/RadialDithering.gdshader @@ -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); } diff --git a/src/Shaders/Gradients/RadialStep.gdshader b/src/Shaders/Gradients/RadialStep.gdshader deleted file mode 100644 index a717dd981..000000000 --- a/src/Shaders/Gradients/RadialStep.gdshader +++ /dev/null @@ -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); -} diff --git a/src/UI/Dialogs/ImageEffects/GradientDialog.gd b/src/UI/Dialogs/ImageEffects/GradientDialog.gd index 81bf8c1af..111f09907 100644 --- a/src/UI/Dialogs/ImageEffects/GradientDialog.gd +++ b/src/UI/Dialogs/ImageEffects/GradientDialog.gd @@ -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() diff --git a/src/UI/Dialogs/ImageEffects/GradientDialog.tscn b/src/UI/Dialogs/ImageEffects/GradientDialog.tscn index bf7d21930..f16fe445c 100644 --- a/src/UI/Dialogs/ImageEffects/GradientDialog.tscn +++ b/src/UI/Dialogs/ImageEffects/GradientDialog.tscn @@ -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"] diff --git a/src/UI/Dialogs/ImageEffects/OutlineDialog.gd b/src/UI/Dialogs/ImageEffects/OutlineDialog.gd index 3502c8301..4d468e9ce 100644 --- a/src/UI/Dialogs/ImageEffects/OutlineDialog.gd +++ b/src/UI/Dialogs/ImageEffects/OutlineDialog.gd @@ -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") diff --git a/src/UI/Dialogs/ImageEffects/RotateImage.gd b/src/UI/Dialogs/ImageEffects/RotateImage.gd index 86bbb9be4..46c289923 100644 --- a/src/UI/Dialogs/ImageEffects/RotateImage.gd +++ b/src/UI/Dialogs/ImageEffects/RotateImage.gd @@ -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) diff --git a/src/UI/Nodes/GradientEdit.gd b/src/UI/Nodes/GradientEdit.gd index fd6e2146f..963af519f 100644 --- a/src/UI/Nodes/GradientEdit.gd +++ b/src/UI/Nodes/GradientEdit.gd @@ -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)