diff --git a/src/Shaders/DropShadow.tres b/src/Shaders/DropShadow.tres new file mode 100644 index 000000000..3b80b0f4e --- /dev/null +++ b/src/Shaders/DropShadow.tres @@ -0,0 +1,20 @@ +[gd_resource type="Shader" format=2] + +[resource] +code = "shader_type canvas_item; + +uniform vec2 shadow_offset; // Offset, in pixel coordinate [0, 1, 2, and so on] +uniform vec4 shadow_color; +uniform sampler2D selection; + + +void fragment() { + vec2 offset = shadow_offset * TEXTURE_PIXEL_SIZE; // Normalize shadow_offset to [0..1] + vec4 original = texture(TEXTURE, UV); // Original texture + float shadow = texture(TEXTURE, UV - offset).a; // Shadow, alpha only + shadow *= shadow_color.a; // Multiply this mask by shadow alpha + shadow = mix(0.0, shadow, texture(selection, UV).a); // Clip shadow by selection mask + + COLOR.rgb = mix(shadow_color.rgb, original.rgb, original.a); // Set background color + COLOR.a = mix(original.a, 1.0, shadow); // Combine alpha +}" diff --git a/src/UI/Dialogs/ImageEffects/DropShadowDialog.gd b/src/UI/Dialogs/ImageEffects/DropShadowDialog.gd new file mode 100644 index 000000000..dbf2d4259 --- /dev/null +++ b/src/UI/Dialogs/ImageEffects/DropShadowDialog.gd @@ -0,0 +1,73 @@ +extends ImageEffect + +var offset := Vector2(5, 5) +var color := Color.black +var confirmed := false +var shader: Shader = load("res://src/Shaders/DropShadow.tres") + +onready var x_spinbox: SpinBox = $VBoxContainer/OptionsContainer/XSpinBox +onready var y_spinbox: SpinBox = $VBoxContainer/OptionsContainer/YSpinBox +onready var shadow_color = $VBoxContainer/OptionsContainer/ShadowColor + + +func _ready() -> void: + shadow_color.get_picker().presets_visible = false + color = shadow_color.color + + +func _about_to_show() -> void: + confirmed = false + var sm := ShaderMaterial.new() + sm.shader = shader + preview.set_material(sm) + ._about_to_show() + + +func _confirmed() -> void: + confirmed = true + ._confirmed() + + +func set_nodes() -> void: + preview = $VBoxContainer/AspectRatioContainer/Preview + selection_checkbox = $VBoxContainer/OptionsContainer/SelectionCheckBox + + +func commit_action(cel: Image, project: Project = Global.current_project) -> void: + var selection_tex := ImageTexture.new() + if selection_checkbox.pressed and project.has_selection: + var selection: Image = project.bitmap_to_image(project.selection_bitmap) + selection_tex.create_from_image(selection, 0) + + if !confirmed: + preview.material.set_shader_param("shadow_offset", offset) + preview.material.set_shader_param("shadow_color", color) + preview.material.set_shader_param("selection", selection_tex) + else: + var params := { + "shadow_offset": offset, + "shadow_color": color, + "selection": selection_tex, + } + var gen := ShaderImageEffect.new() + gen.generate_image(cel, shader, params, project.size) + yield(gen, "done") + + +func _on_XSpinBox_value_changed(value) -> void: + x_spinbox.max_value = value + 1 + x_spinbox.min_value = value - 1 + offset.x = value + update_preview() + + +func _on_YSpinBox_value_changed(value) -> void: + y_spinbox.max_value = value + 1 + y_spinbox.min_value = value - 1 + offset.y = value + update_preview() + + +func _on_OutlineColor_color_changed(_color: Color) -> void: + color = _color + update_preview() diff --git a/src/UI/Dialogs/ImageEffects/DropShadowDialog.tscn b/src/UI/Dialogs/ImageEffects/DropShadowDialog.tscn new file mode 100644 index 000000000..daf9dee85 --- /dev/null +++ b/src/UI/Dialogs/ImageEffects/DropShadowDialog.tscn @@ -0,0 +1,120 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://src/UI/TransparentChecker.tscn" type="PackedScene" id=1] +[ext_resource path="res://src/UI/Dialogs/ImageEffects/DropShadowDialog.gd" type="Script" id=2] + +[node name="DropShadowDialog" type="ConfirmationDialog"] +margin_right = 294.0 +margin_bottom = 352.0 +rect_min_size = Vector2( 172, 60.2 ) +window_title = "Drop Shadow" +resizable = true +script = ExtResource( 2 ) + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +margin_left = 8.0 +margin_top = 8.0 +margin_right = 286.0 +margin_bottom = 316.0 + +[node name="AspectRatioContainer" type="AspectRatioContainer" parent="VBoxContainer"] +margin_right = 278.0 +margin_bottom = 200.0 +size_flags_vertical = 3 + +[node name="Preview" type="TextureRect" parent="VBoxContainer/AspectRatioContainer"] +margin_left = 39.0 +margin_right = 239.0 +margin_bottom = 200.0 +rect_min_size = Vector2( 200, 200 ) +expand = true +stretch_mode = 5 + +[node name="TransparentChecker" parent="VBoxContainer/AspectRatioContainer/Preview" instance=ExtResource( 1 )] +show_behind_parent = true +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_right = 0.0 +margin_bottom = 0.0 + +[node name="OptionsContainer" type="GridContainer" parent="VBoxContainer"] +margin_top = 204.0 +margin_right = 278.0 +margin_bottom = 308.0 +custom_constants/vseparation = 4 +custom_constants/hseparation = 4 +columns = 2 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="XLabel" type="Label" parent="VBoxContainer/OptionsContainer"] +margin_top = 5.0 +margin_right = 160.0 +margin_bottom = 19.0 +text = "Offset X:" + +[node name="XSpinBox" type="SpinBox" parent="VBoxContainer/OptionsContainer"] +margin_left = 164.0 +margin_right = 278.0 +margin_bottom = 24.0 +mouse_default_cursor_shape = 2 +max_value = 5.0 +value = 5.0 +allow_greater = true +allow_lesser = true +suffix = "px" + +[node name="YLabel" type="Label" parent="VBoxContainer/OptionsContainer"] +margin_top = 33.0 +margin_right = 160.0 +margin_bottom = 47.0 +text = "Offset Y:" + +[node name="YSpinBox" type="SpinBox" parent="VBoxContainer/OptionsContainer"] +margin_left = 164.0 +margin_top = 28.0 +margin_right = 278.0 +margin_bottom = 52.0 +mouse_default_cursor_shape = 2 +max_value = 5.0 +value = 5.0 +allow_greater = true +allow_lesser = true +suffix = "px" + +[node name="ShadowColorLabel" type="Label" parent="VBoxContainer/OptionsContainer"] +margin_top = 59.0 +margin_right = 160.0 +margin_bottom = 73.0 +text = "Shadow Color" + +[node name="ShadowColor" type="ColorPickerButton" parent="VBoxContainer/OptionsContainer"] +margin_left = 164.0 +margin_top = 56.0 +margin_right = 278.0 +margin_bottom = 76.0 +rect_min_size = Vector2( 64, 20 ) +color = Color( 0.0823529, 0.0823529, 0.0823529, 0.627451 ) + +[node name="SelectionCheckBox" type="CheckBox" parent="VBoxContainer/OptionsContainer"] +margin_top = 80.0 +margin_right = 160.0 +margin_bottom = 104.0 +mouse_default_cursor_shape = 2 +pressed = true +text = "Only affect selection" + +[node name="AffectOptionButton" type="OptionButton" parent="VBoxContainer/OptionsContainer"] +margin_left = 164.0 +margin_top = 80.0 +margin_right = 278.0 +margin_bottom = 104.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="value_changed" from="VBoxContainer/OptionsContainer/XSpinBox" to="." method="_on_XSpinBox_value_changed"] +[connection signal="value_changed" from="VBoxContainer/OptionsContainer/YSpinBox" to="." method="_on_YSpinBox_value_changed"] +[connection signal="color_changed" from="VBoxContainer/OptionsContainer/ShadowColor" to="." method="_on_OutlineColor_color_changed"] diff --git a/src/UI/Dialogs/ImageEffects/ImageEffects.tscn b/src/UI/Dialogs/ImageEffects/ImageEffects.tscn index fb3d68453..4e1d67a90 100644 --- a/src/UI/Dialogs/ImageEffects/ImageEffects.tscn +++ b/src/UI/Dialogs/ImageEffects/ImageEffects.tscn @@ -1,8 +1,9 @@ -[gd_scene load_steps=11 format=2] +[gd_scene load_steps=12 format=2] [ext_resource path="res://src/UI/Dialogs/ImageEffects/FlipImageDialog.tscn" type="PackedScene" id=1] [ext_resource path="res://src/UI/Dialogs/ImageEffects/InvertColorsDialog.tscn" type="PackedScene" id=2] [ext_resource path="res://src/UI/Dialogs/ImageEffects/DesaturateDialog.tscn" type="PackedScene" id=3] +[ext_resource path="res://src/UI/Dialogs/ImageEffects/DropShadowDialog.tscn" type="PackedScene" id=4] [ext_resource path="res://src/UI/Dialogs/ImageEffects/ResizeCanvas.tscn" type="PackedScene" id=8] [ext_resource path="res://src/UI/Dialogs/ImageEffects/RotateImage.tscn" type="PackedScene" id=9] [ext_resource path="res://src/UI/Dialogs/ImageEffects/ShaderEffect.tscn" type="PackedScene" id=10] @@ -33,9 +34,12 @@ margin_bottom = 392.0 [node name="DesaturateDialog" parent="." instance=ExtResource( 3 )] [node name="OutlineDialog" parent="." instance=ExtResource( 13 )] +visible = false margin_right = 217.0 margin_bottom = 106.0 +[node name="DropShadowDialog" parent="." instance=ExtResource( 4 )] + [node name="HSVDialog" parent="." instance=ExtResource( 11 )] [node name="GradientDialog" parent="." instance=ExtResource( 12 )] diff --git a/src/UI/TopMenuContainer.gd b/src/UI/TopMenuContainer.gd index 0cea1f87d..3214c214d 100644 --- a/src/UI/TopMenuContainer.gd +++ b/src/UI/TopMenuContainer.gd @@ -22,6 +22,7 @@ enum ImageMenuId { INVERT_COLORS, DESATURATION, OUTLINE, + DROP_SHADOW, HSV, GRADIENT, SHADER @@ -273,6 +274,7 @@ func _setup_image_menu() -> void: "Invert Colors": 0, "Desaturation": 0, "Outline": 0, + "Drop Shadow": 0, "Adjust Hue/Saturation/Value": 0, "Gradient": 0, # "Shader": 0 @@ -636,6 +638,9 @@ func image_menu_id_pressed(id: int) -> void: ImageMenuId.OUTLINE: _show_add_outline_popup() + ImageMenuId.DROP_SHADOW: + _show_drop_shadow_popup() + ImageMenuId.HSV: _show_hsv_configuration_popup() @@ -671,6 +676,11 @@ func _show_add_outline_popup() -> void: Global.dialog_open(true) +func _show_drop_shadow_popup() -> void: + Global.control.get_node("Dialogs/ImageEffects/DropShadowDialog").popup_centered() + Global.dialog_open(true) + + func _show_hsv_configuration_popup() -> void: Global.control.get_node("Dialogs/ImageEffects/HSVDialog").popup_centered() Global.dialog_open(true)