diff --git a/Translations/Translations.pot b/Translations/Translations.pot index 67fe10234..6a479eb3b 100644 --- a/Translations/Translations.pot +++ b/Translations/Translations.pot @@ -963,6 +963,26 @@ msgstr "" msgid "Shadow color:" msgstr "" +#. An image effect. https://en.wikipedia.org/wiki/Gaussian_blur +msgid "Gaussian Blur" +msgstr "" + +#. The type of the Gaussian blur, an image effect. +msgid "Blur type:" +msgstr "" + +#. The applied amount of Gaussian blur, an image effect. +msgid "Blur amount:" +msgstr "" + +#. The applied radius of Gaussian blur, an image effect. +msgid "Blur radius:" +msgstr "" + +#. The applied direction of Gaussian blur, an image effect. +msgid "Blur direction:" +msgstr "" + msgid "Gradient" msgstr "" diff --git a/project.godot b/project.godot index 264a7b517..a1ea06ec0 100644 --- a/project.godot +++ b/project.godot @@ -884,6 +884,10 @@ change_layer_automatically={ "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"command_or_control_autoremap":true,"alt_pressed":false,"shift_pressed":true,"pressed":false,"keycode":0,"physical_keycode":4194328,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) ] } +gaussian_blur={ +"deadzone": 0.5, +"events": [] +} [input_devices] diff --git a/src/Autoload/Global.gd b/src/Autoload/Global.gd index 766ee428c..28fc249c8 100644 --- a/src/Autoload/Global.gd +++ b/src/Autoload/Global.gd @@ -63,6 +63,7 @@ enum EffectsMenu { PALETTIZE, PIXELIZE, POSTERIZE, + GAUSSIAN_BLUR, GRADIENT, GRADIENT_MAP, SHADER @@ -762,6 +763,7 @@ func _initialize_keychain() -> void: &"drop_shadow": Keychain.InputAction.new("", "Effects menu", true), &"adjust_hsv": Keychain.InputAction.new("", "Effects menu", true), &"adjust_brightness_contrast": Keychain.InputAction.new("", "Effects menu", true), + &"gaussian_blur": Keychain.InputAction.new("", "Effects menu", true), &"gradient": Keychain.InputAction.new("", "Effects menu", true), &"gradient_map": Keychain.InputAction.new("", "Effects menu", true), &"palettize": Keychain.InputAction.new("", "Effects menu", true), diff --git a/src/Shaders/Effects/GaussianBlur.gdshader b/src/Shaders/Effects/GaussianBlur.gdshader index 85581dcd9..7e26bead3 100644 --- a/src/Shaders/Effects/GaussianBlur.gdshader +++ b/src/Shaders/Effects/GaussianBlur.gdshader @@ -7,6 +7,7 @@ uniform int blur_type : hint_range(0, 3, 1) = 0; uniform int blur_amount = 16; uniform float blur_radius = 1.0; uniform vec2 blur_direction = vec2(1, 1); +uniform sampler2D selection : filter_nearest; // Xor's gaussian blur function // Link: https://xorshaders.weebly.com/tutorials/blur-shaders-5-part-2 @@ -93,6 +94,7 @@ vec4 texture_nodevgaussian_singlepass(sampler2D tex, vec2 uv, vec2 pixel_size, f blurred_tex *= norm; return blurred_tex; } + vec4 texture_nodevgaussian_multipass(sampler2D tex, vec2 uv, vec2 pixel_size, float blurriness, vec2 direction) { float n = 0.0015; vec4 blurred_tex = vec4(0); @@ -112,23 +114,28 @@ vec4 texture_nodevgaussian_multipass(sampler2D tex, vec2 uv, vec2 pixel_size, fl } void fragment() { + vec4 original_color = texture(TEXTURE, UV); + vec4 selection_color = texture(selection, UV); + vec4 col = original_color; if (blur_type == 0) { vec4 xorgaussian = texture_xorgaussian(TEXTURE, UV, TEXTURE_PIXEL_SIZE, float(blur_amount), 16, 4); - COLOR = xorgaussian; + col = xorgaussian; } else if (blur_type == 1) { vec4 monksgaussian_multipass = texture_monksgaussian_multipass(TEXTURE, UV, TEXTURE_PIXEL_SIZE, blur_amount, blur_direction); - COLOR = monksgaussian_multipass; + col = monksgaussian_multipass; } else if (blur_type == 2) { vec4 nodevgaussian_singlepass = texture_nodevgaussian_singlepass(TEXTURE, UV, TEXTURE_PIXEL_SIZE, float(blur_amount), blur_radius); - COLOR = nodevgaussian_singlepass; + col = nodevgaussian_singlepass; } else if (blur_type == 3) { vec4 nodevgaussian_multipass = texture_nodevgaussian_multipass(TEXTURE, UV, TEXTURE_PIXEL_SIZE, float(blur_amount), blur_direction); - COLOR = nodevgaussian_multipass; + col = nodevgaussian_multipass; } else { - COLOR = texture(TEXTURE, UV); + col = texture(TEXTURE, UV); } + vec4 output = mix(original_color.rgba, col, selection_color.a); + COLOR = output; } diff --git a/src/UI/Dialogs/ImageEffects/GaussianBlur.gd b/src/UI/Dialogs/ImageEffects/GaussianBlur.gd new file mode 100644 index 000000000..d30a5485f --- /dev/null +++ b/src/UI/Dialogs/ImageEffects/GaussianBlur.gd @@ -0,0 +1,55 @@ +extends ImageEffect + +var blur_type := 0 +var blur_amount := 16 +var blur_radius := 1.0 +var blur_direction := Vector2.ONE +var shader := preload("res://src/Shaders/Effects/GaussianBlur.gdshader") + + +func _ready() -> void: + super._ready() + var sm := ShaderMaterial.new() + sm.shader = shader + preview.set_material(sm) + + +func commit_action(cel: Image, project := Global.current_project) -> void: + var selection_tex: ImageTexture + if selection_checkbox.button_pressed and project.has_selection: + var selection := project.selection_map.return_cropped_copy(project.size) + selection_tex = ImageTexture.create_from_image(selection) + + var params := { + "blur_type": blur_type, + "blur_amount": blur_amount, + "blur_radius": blur_radius, + "blur_direction": blur_direction, + "selection": selection_tex + } + if !has_been_confirmed: + for param in params: + preview.material.set_shader_parameter(param, params[param]) + else: + var gen := ShaderImageEffect.new() + gen.generate_image(cel, shader, params, project.size) + + +func _on_blur_type_item_selected(index: int) -> void: + blur_type = index + update_preview() + + +func _on_blur_amount_value_changed(value: float) -> void: + blur_amount = value + update_preview() + + +func _on_blur_radius_value_changed(value: float) -> void: + blur_radius = value + update_preview() + + +func _on_blur_direction_value_changed(value: Vector2) -> void: + blur_direction = value + update_preview() diff --git a/src/UI/Dialogs/ImageEffects/GaussianBlur.tscn b/src/UI/Dialogs/ImageEffects/GaussianBlur.tscn new file mode 100644 index 000000000..7c5b5c885 --- /dev/null +++ b/src/UI/Dialogs/ImageEffects/GaussianBlur.tscn @@ -0,0 +1,91 @@ +[gd_scene load_steps=5 format=3 uid="uid://beile55gp1bc"] + +[ext_resource type="PackedScene" uid="uid://bybqhhayl5ay5" path="res://src/UI/Dialogs/ImageEffects/ImageEffectParent.tscn" id="1_cuu40"] +[ext_resource type="Script" path="res://src/UI/Dialogs/ImageEffects/GaussianBlur.gd" id="2_37xhl"] +[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="3_237k2"] +[ext_resource type="PackedScene" path="res://src/UI/Nodes/ValueSliderV2.tscn" id="4_yprgi"] + +[node name="GaussianBlur" instance=ExtResource("1_cuu40")] +title = "Gaussian Blur" +size = Vector2i(427, 437) +visible = true +script = ExtResource("2_37xhl") + +[node name="VBoxContainer" parent="." index="3"] +offset_right = 419.0 +offset_bottom = 388.0 + +[node name="ShowAnimate" parent="VBoxContainer" index="0"] +visible = false + +[node name="BlurOptions" type="GridContainer" parent="VBoxContainer" index="2"] +layout_mode = 2 +columns = 2 + +[node name="BlurTypeLabel" type="Label" parent="VBoxContainer/BlurOptions" index="0"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Blur type:" + +[node name="BlurType" type="OptionButton" parent="VBoxContainer/BlurOptions" index="1"] +layout_mode = 2 +size_flags_horizontal = 3 +selected = 0 +item_count = 4 +popup/item_0/text = "Xor's Gaussian Blur" +popup/item_1/text = "Monk's Multi-Pass Gaussian Blur" +popup/item_1/id = 1 +popup/item_2/text = "NoDev's Single-Pass Gaussian Blur" +popup/item_2/id = 2 +popup/item_3/text = "NoDev's Multi-Pass Gaussian Blur" +popup/item_3/id = 3 + +[node name="BlurAmountLabel" type="Label" parent="VBoxContainer/BlurOptions" index="2"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Blur amount:" + +[node name="BlurAmount" type="TextureProgressBar" parent="VBoxContainer/BlurOptions" index="3"] +layout_mode = 2 +focus_mode = 2 +mouse_default_cursor_shape = 2 +theme_type_variation = &"ValueSlider" +value = 16.0 +nine_patch_stretch = true +stretch_margin_left = 3 +stretch_margin_top = 3 +stretch_margin_right = 3 +stretch_margin_bottom = 3 +script = ExtResource("3_237k2") + +[node name="BlurRadiusLabel" type="Label" parent="VBoxContainer/BlurOptions" index="4"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Blur radius:" + +[node name="BlurRadius" type="TextureProgressBar" parent="VBoxContainer/BlurOptions" index="5"] +layout_mode = 2 +focus_mode = 2 +mouse_default_cursor_shape = 2 +theme_type_variation = &"ValueSlider" +value = 1.0 +nine_patch_stretch = true +stretch_margin_left = 3 +stretch_margin_top = 3 +stretch_margin_right = 3 +stretch_margin_bottom = 3 +script = ExtResource("3_237k2") + +[node name="BlurDirectionLabel" type="Label" parent="VBoxContainer/BlurOptions" index="6"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Blur direction:" + +[node name="BlurDirection" parent="VBoxContainer/BlurOptions" index="7" instance=ExtResource("4_yprgi")] +layout_mode = 2 +value = Vector2(1, 1) + +[connection signal="item_selected" from="VBoxContainer/BlurOptions/BlurType" to="." method="_on_blur_type_item_selected"] +[connection signal="value_changed" from="VBoxContainer/BlurOptions/BlurAmount" to="." method="_on_blur_amount_value_changed"] +[connection signal="value_changed" from="VBoxContainer/BlurOptions/BlurRadius" to="." method="_on_blur_radius_value_changed"] +[connection signal="value_changed" from="VBoxContainer/BlurOptions/BlurDirection" to="." method="_on_blur_direction_value_changed"] diff --git a/src/UI/TopMenuContainer/TopMenuContainer.gd b/src/UI/TopMenuContainer/TopMenuContainer.gd index 66215ec35..b3feece4d 100644 --- a/src/UI/TopMenuContainer/TopMenuContainer.gd +++ b/src/UI/TopMenuContainer/TopMenuContainer.gd @@ -30,6 +30,7 @@ var hsv_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/HSVDialog.tscn") var adjust_brightness_saturation_dialog := Dialog.new( "res://src/UI/Dialogs/ImageEffects/BrightnessContrastDialog.tscn" ) +var gaussian_blur_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/GaussianBlur.tscn") var gradient_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/GradientDialog.tscn") var gradient_map_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/GradientMapDialog.tscn") var palettize_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/PalettizeDialog.tscn") @@ -405,6 +406,7 @@ func _setup_effects_menu() -> void: "Palettize": "palettize", "Pixelize": "pixelize", "Posterize": "posterize", + "Gaussian Blur": "gaussian_blur", "Gradient": "gradient", "Gradient Map": "gradient_map", # "Shader": "" @@ -817,6 +819,8 @@ func effects_menu_id_pressed(id: int) -> void: hsv_dialog.popup() Global.EffectsMenu.BRIGHTNESS_SATURATION: adjust_brightness_saturation_dialog.popup() + Global.EffectsMenu.GAUSSIAN_BLUR: + gaussian_blur_dialog.popup() Global.EffectsMenu.GRADIENT: gradient_dialog.popup() Global.EffectsMenu.GRADIENT_MAP: