mirror of
https://github.com/Orama-Interactive/Pixelorama.git
synced 2025-02-20 12:33:14 +00:00
Add a Posterize image effect, with optional dithering
Seems to produce the same result as GIMP's Posterize color filter. Should be useful for reducing the colors of an image, and it could work together with 3D lighting. Thanks to https://godotshaders.com/shader/color-reduction-and-dither/ for the shader.
This commit is contained in:
parent
9607981567
commit
ec2dcae8f7
8 changed files with 178 additions and 11 deletions
|
@ -855,16 +855,16 @@ msgstr ""
|
|||
msgid "Steps:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Top to Bottom"
|
||||
#. An image effect. For more details about what it does, you can refer to GIMP's documentation https://docs.gimp.org/2.8/en/gimp-tool-posterize.html
|
||||
msgid "Posterize"
|
||||
msgstr ""
|
||||
|
||||
msgid "Bottom to Top"
|
||||
#. An option for the posterize image effect. For more details about what it does, you can refer to GIMP's documentation https://docs.gimp.org/2.8/en/gimp-tool-posterize.html
|
||||
msgid "Posterize levels:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Left to Right"
|
||||
msgstr ""
|
||||
|
||||
msgid "Right to Left"
|
||||
#. An option for the posterize image effect.
|
||||
msgid "Dither intensity:"
|
||||
msgstr ""
|
||||
|
||||
msgid "View Splash Screen"
|
||||
|
|
|
@ -988,6 +988,14 @@ gradient={
|
|||
"deadzone": 0.5,
|
||||
"events": [ ]
|
||||
}
|
||||
gradient_map={
|
||||
"deadzone": 0.5,
|
||||
"events": [ ]
|
||||
}
|
||||
posterize={
|
||||
"deadzone": 0.5,
|
||||
"events": [ ]
|
||||
}
|
||||
view_splash_screen={
|
||||
"deadzone": 0.5,
|
||||
"events": [ ]
|
||||
|
@ -1008,10 +1016,6 @@ about_pixelorama={
|
|||
"deadzone": 0.5,
|
||||
"events": [ ]
|
||||
}
|
||||
gradient_map={
|
||||
"deadzone": 0.5,
|
||||
"events": [ ]
|
||||
}
|
||||
left_paint_selection_tool={
|
||||
"deadzone": 0.5,
|
||||
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":73,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
|
||||
|
|
|
@ -37,6 +37,7 @@ enum ImageMenu {
|
|||
HSV,
|
||||
GRADIENT,
|
||||
GRADIENT_MAP,
|
||||
POSTERIZE,
|
||||
SHADER
|
||||
}
|
||||
enum SelectMenu { SELECT_ALL, CLEAR_SELECTION, INVERT }
|
||||
|
@ -310,6 +311,8 @@ func _initialize_keychain() -> void:
|
|||
Keychain.MenuInputAction.new("", "Image menu", true, "ImageMenu", ImageMenu.GRADIENT),
|
||||
"gradient_map":
|
||||
Keychain.MenuInputAction.new("", "Image menu", true, "ImageMenu", ImageMenu.GRADIENT_MAP),
|
||||
"posterize":
|
||||
Keychain.MenuInputAction.new("", "Image menu", true, "ImageMenu", ImageMenu.POSTERIZE),
|
||||
"mirror_view":
|
||||
Keychain.MenuInputAction.new("", "View menu", true, "ViewMenu", ViewMenu.MIRROR_VIEW),
|
||||
"show_grid":
|
||||
|
|
27
src/Shaders/Posterize.gdshader
Normal file
27
src/Shaders/Posterize.gdshader
Normal file
|
@ -0,0 +1,27 @@
|
|||
// https://godotshaders.com/shader/color-reduction-and-dither/
|
||||
shader_type canvas_item;
|
||||
|
||||
uniform sampler2D selection;
|
||||
uniform float colors : hint_range(1.0, 255.0) = 2.0;
|
||||
uniform float dither : hint_range(0.0, 0.5) = 0.0;
|
||||
|
||||
void fragment()
|
||||
{
|
||||
vec4 color = texture(TEXTURE, UV);
|
||||
vec4 selection_color = texture(selection, UV);
|
||||
|
||||
float a = floor(mod(UV.x / TEXTURE_PIXEL_SIZE.x, 2.0));
|
||||
float b = floor(mod(UV.y / TEXTURE_PIXEL_SIZE.y, 2.0));
|
||||
float c = mod(a + b, 2.0);
|
||||
vec4 col;
|
||||
col.r = (round(color.r * colors + dither) / colors) * c;
|
||||
col.g = (round(color.g * colors + dither) / colors) * c;
|
||||
col.b = (round(color.b * colors + dither) / colors) * c;
|
||||
c = 1.0 - c;
|
||||
col.r += (round(color.r * colors - dither) / colors) * c;
|
||||
col.g += (round(color.g * colors - dither) / colors) * c;
|
||||
col.b += (round(color.b * colors - dither) / colors) * c;
|
||||
col.a = color.a;
|
||||
vec4 output = mix(color.rgba, col, selection_color.a);
|
||||
COLOR = output;
|
||||
}
|
|
@ -1,10 +1,11 @@
|
|||
[gd_scene load_steps=13 format=2]
|
||||
[gd_scene load_steps=14 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/GradientMapDialog.tscn" type="PackedScene" id=5]
|
||||
[ext_resource path="res://src/UI/Dialogs/ImageEffects/Posterize.tscn" type="PackedScene" id=6]
|
||||
[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]
|
||||
|
@ -44,4 +45,6 @@ margin_bottom = 214.0
|
|||
|
||||
[node name="GradientMapDialog" parent="." instance=ExtResource( 5 )]
|
||||
|
||||
[node name="Posterize" parent="." instance=ExtResource( 6 )]
|
||||
|
||||
[node name="ShaderEffect" parent="." instance=ExtResource( 10 )]
|
||||
|
|
43
src/UI/Dialogs/ImageEffects/Posterize.gd
Normal file
43
src/UI/Dialogs/ImageEffects/Posterize.gd
Normal file
|
@ -0,0 +1,43 @@
|
|||
extends ImageEffect
|
||||
|
||||
var shader: Shader = preload("res://src/Shaders/Posterize.gdshader")
|
||||
var levels := 2.0
|
||||
var dither := 0.0
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
var sm := ShaderMaterial.new()
|
||||
sm.shader = shader
|
||||
preview.set_material(sm)
|
||||
|
||||
|
||||
func set_nodes() -> void:
|
||||
preview = $VBoxContainer/AspectRatioContainer/Preview
|
||||
selection_checkbox = $VBoxContainer/OptionsContainer/SelectionCheckBox
|
||||
affect_option_button = $VBoxContainer/OptionsContainer/AffectOptionButton
|
||||
|
||||
|
||||
func commit_action(cel: Image, project: Project = Global.current_project) -> void:
|
||||
var selection_tex := ImageTexture.new()
|
||||
if selection_checkbox.pressed and project.has_selection:
|
||||
selection_tex.create_from_image(project.selection_map, 0)
|
||||
|
||||
var params := {"colors": levels, "dither": dither, "selection": selection_tex}
|
||||
|
||||
if !confirmed:
|
||||
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_LevelsSlider_value_changed(value: float) -> void:
|
||||
levels = value - 1.0
|
||||
update_preview()
|
||||
|
||||
|
||||
func _on_DitherSlider_value_changed(value: float) -> void:
|
||||
dither = value
|
||||
update_preview()
|
83
src/UI/Dialogs/ImageEffects/Posterize.tscn
Normal file
83
src/UI/Dialogs/ImageEffects/Posterize.tscn
Normal file
|
@ -0,0 +1,83 @@
|
|||
[gd_scene load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://src/UI/Dialogs/ImageEffects/ImageEffectParent.tscn" type="PackedScene" id=1]
|
||||
[ext_resource path="res://src/UI/Nodes/ValueSlider.gd" type="Script" id=2]
|
||||
[ext_resource path="res://src/UI/Dialogs/ImageEffects/Posterize.gd" type="Script" id=3]
|
||||
|
||||
[node name="Posterize" instance=ExtResource( 1 )]
|
||||
window_title = "Posterize"
|
||||
script = ExtResource( 3 )
|
||||
|
||||
[node name="VBoxContainer" parent="." index="3"]
|
||||
margin_bottom = 292.0
|
||||
|
||||
[node name="AspectRatioContainer" parent="VBoxContainer" index="0"]
|
||||
margin_right = 278.0
|
||||
|
||||
[node name="Preview" parent="VBoxContainer/AspectRatioContainer" index="0"]
|
||||
margin_left = 39.0
|
||||
margin_right = 239.0
|
||||
|
||||
[node name="LevelsSlider" type="TextureProgress" parent="VBoxContainer" index="1"]
|
||||
margin_top = 204.0
|
||||
margin_right = 278.0
|
||||
margin_bottom = 228.0
|
||||
rect_min_size = Vector2( 0, 24 )
|
||||
mouse_default_cursor_shape = 2
|
||||
theme_type_variation = "ValueSlider"
|
||||
min_value = 2.0
|
||||
max_value = 256.0
|
||||
step = 0.01
|
||||
value = 3.0
|
||||
nine_patch_stretch = true
|
||||
stretch_margin_left = 3
|
||||
stretch_margin_top = 3
|
||||
stretch_margin_right = 3
|
||||
stretch_margin_bottom = 3
|
||||
script = ExtResource( 2 )
|
||||
prefix = "Posterize levels:"
|
||||
snap_by_default = true
|
||||
|
||||
[node name="DitherSlider" type="TextureProgress" parent="VBoxContainer" index="2"]
|
||||
margin_top = 232.0
|
||||
margin_right = 278.0
|
||||
margin_bottom = 256.0
|
||||
rect_min_size = Vector2( 0, 24 )
|
||||
mouse_default_cursor_shape = 2
|
||||
theme_type_variation = "ValueSlider"
|
||||
max_value = 0.5
|
||||
step = 0.01
|
||||
nine_patch_stretch = true
|
||||
stretch_margin_left = 3
|
||||
stretch_margin_top = 3
|
||||
stretch_margin_right = 3
|
||||
stretch_margin_bottom = 3
|
||||
script = ExtResource( 2 )
|
||||
prefix = "Dither intensity:"
|
||||
snap_step = 0.1
|
||||
|
||||
[node name="OptionsContainer" parent="VBoxContainer" index="3"]
|
||||
margin_top = 260.0
|
||||
margin_right = 278.0
|
||||
margin_bottom = 284.0
|
||||
|
||||
[node name="AffectOptionButton" parent="VBoxContainer/OptionsContainer" index="1"]
|
||||
margin_right = 278.0
|
||||
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 ]
|
||||
|
||||
[node name="AnimationOptions" parent="VBoxContainer" index="4"]
|
||||
visible = false
|
||||
margin_right = 278.0
|
||||
|
||||
[node name="PanelContainer" parent="VBoxContainer/AnimationOptions" index="1"]
|
||||
margin_right = 157.0
|
||||
|
||||
[node name="AnimateMenu" parent="VBoxContainer/AnimationOptions/PanelContainer" index="0"]
|
||||
margin_right = 88.0
|
||||
|
||||
[node name="InitalButton" parent="VBoxContainer/AnimationOptions" index="2"]
|
||||
margin_left = 161.0
|
||||
margin_right = 278.0
|
||||
|
||||
[connection signal="value_changed" from="VBoxContainer/LevelsSlider" to="." method="_on_LevelsSlider_value_changed"]
|
||||
[connection signal="value_changed" from="VBoxContainer/DitherSlider" to="." method="_on_DitherSlider_value_changed"]
|
|
@ -285,6 +285,7 @@ func _setup_image_menu() -> void:
|
|||
"Adjust Hue/Saturation/Value",
|
||||
"Gradient",
|
||||
"Gradient Map",
|
||||
"Posterize",
|
||||
# "Shader"
|
||||
]
|
||||
var image_menu: PopupMenu = image_menu_button.get_popup()
|
||||
|
@ -680,6 +681,9 @@ func image_menu_id_pressed(id: int) -> void:
|
|||
Global.ImageMenu.GRADIENT_MAP:
|
||||
_popup_dialog(Global.control.get_node("Dialogs/ImageEffects/GradientMapDialog"))
|
||||
|
||||
Global.ImageMenu.POSTERIZE:
|
||||
_popup_dialog(Global.control.get_node("Dialogs/ImageEffects/Posterize"))
|
||||
|
||||
# Global.ImageMenu.SHADER:
|
||||
# _popup_dialog(Global.control.get_node("Dialogs/ImageEffects/ShaderEffect"))
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue