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

Novhack fill shader (#649)

* Get same color pixels shader (#2)

* Replace same color pixels bucket code with a shader

* Add pattern fill

Co-authored-by: novhack <42614907+novhack@users.noreply.github.com>

* formatting

* some minor changes and fixed a bug

* added similarity feature

* formatting

* Update Bucket.gd

* added similarity feature in shader

Co-authored-by: novhack <42614907+novhack@users.noreply.github.com>
This commit is contained in:
Variable 2022-02-16 03:15:53 +05:00 committed by GitHub
parent 196c5c2d5d
commit 008683a33a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 152 additions and 15 deletions

View file

@ -0,0 +1,37 @@
shader_type canvas_item;
render_mode unshaded;
uniform vec2 size;
uniform vec4 old_color; //Our description
uniform vec4 new_color;
uniform float similarity_percent : hint_range(0.0, 100.0);
// Must be the same size as image
// Selected pixels are 1,1,1,1 and unselected 0,0,0,0
uniform sampler2D selection;
uniform bool has_pattern;
uniform sampler2D pattern;
uniform vec2 pattern_size;
uniform vec2 pattern_uv_offset;
void fragment() { // applies on each pixel seperately
vec4 original_color = texture(TEXTURE, UV); // The drawing we have to use on
vec4 selection_color = texture(selection, UV); // use its alpha to get portion we can ignore
vec4 col = original_color; // Innocent till proven Guilty
float max_diff = distance(original_color, old_color); // How much this pixel matches our description
float similarity = abs(2.0 - ((similarity_percent/100.0) * 2.0));
if (max_diff <= similarity) // We found our match and pixel is proven Guilty (small is precise)
if (has_pattern)
col = textureLod(pattern, UV * (size / pattern_size) + pattern_uv_offset, 0.0);
else
col = new_color;
// Mix selects original color if there is selection or col if there is none
COLOR = mix(original_color, col, selection_color.a);
}

View file

@ -1,7 +1,10 @@
extends BaseTool
const ColorReplaceShader := preload("res://src/Shaders/ColorReplace.shader")
var _prev_mode := 0
var _pattern: Patterns.Pattern
var _similarity := 100
var _fill_area := 0
var _fill_with := 0
var _offset_x := 0
@ -20,9 +23,11 @@ func _input(event: InputEvent) -> void:
if event.is_action("ctrl"):
options.selected = _prev_mode ^ 1
_fill_area = options.selected
$Similarity.visible = (_fill_area == 1)
if event.is_action_released("ctrl"):
options.selected = _prev_mode
_fill_area = options.selected
$Similarity.visible = (_fill_area == 1)
func _on_FillAreaOptions_item_selected(index: int) -> void:
@ -33,6 +38,20 @@ func _on_FillAreaOptions_item_selected(index: int) -> void:
func _on_FillWithOptions_item_selected(index: int) -> void:
_fill_with = index
$Similarity/Value.value = _similarity
update_config()
save_config()
func _on_Value_value_changed(value: float) -> void:
_similarity = value
$Similarity/Slider.value = _similarity
update_config()
save_config()
func _on_Slider_value_changed(value: float) -> void:
_similarity = value
update_config()
save_config()
@ -64,11 +83,12 @@ func _on_PatternOffsetY_value_changed(value: float) -> void:
func get_config() -> Dictionary:
if !_pattern:
return {}
return {"fill_area": _fill_area, "fill_with": _fill_with, "similarity": _similarity}
return {
"pattern_index": _pattern.index,
"fill_area": _fill_area,
"fill_with": _fill_with,
"similarity": _similarity,
"offset_x": _offset_x,
"offset_y": _offset_y,
}
@ -80,6 +100,7 @@ func set_config(config: Dictionary) -> void:
_pattern = Global.patterns_popup.get_pattern(index)
_fill_area = config.get("fill_area", _fill_area)
_fill_with = config.get("fill_with", _fill_with)
_similarity = config.get("similarity", _similarity)
_offset_x = config.get("offset_x", _offset_x)
_offset_y = config.get("offset_y", _offset_y)
update_pattern()
@ -88,6 +109,9 @@ func set_config(config: Dictionary) -> void:
func update_config() -> void:
$FillAreaOptions.selected = _fill_area
$FillWithOptions.selected = _fill_with
$Similarity.visible = (_fill_area == 1)
$Similarity/Value.value = _similarity
$Similarity/Slider.value = _similarity
$Mirror.visible = _fill_area == 0
$FillPattern.visible = _fill_with == 1
$FillPattern/XOffset/OffsetX.value = _offset_x
@ -151,13 +175,37 @@ func fill_in_color(position: Vector2) -> void:
if tool_slot.color.is_equal_approx(color):
return
for x in Global.current_project.size.x:
for y in Global.current_project.size.y:
var pos := Vector2(x, y)
if project.has_selection and not project.can_pixel_get_drawn(pos):
continue
if image.get_pixelv(pos).is_equal_approx(color):
_set_pixel(image, x, y, tool_slot.color)
var selection: Image
var selection_tex := ImageTexture.new()
if project.has_selection:
selection = project.bitmap_to_image(project.selection_bitmap, false)
else:
selection = Image.new()
selection.create(project.size.x, project.size.y, false, Image.FORMAT_RGBA8)
selection.fill(Color(1, 1, 1, 1))
selection_tex.create_from_image(selection)
var pattern_tex := ImageTexture.new()
if _pattern:
pattern_tex.create_from_image(_pattern.image)
var params := {
"size": project.size,
"old_color": color,
"new_color": tool_slot.color,
"similarity_percent": _similarity,
"selection": selection_tex,
"pattern": pattern_tex,
"pattern_size": pattern_tex.get_size(),
# pixel offset converted to pattern uv offset
"pattern_uv_offset":
Vector2.ONE / pattern_tex.get_size() * Vector2(_offset_x, _offset_y),
"has_pattern": true if _fill_with == 1 else false
}
var gen := ShaderImageEffect.new()
gen.generate_image(image, ColorReplaceShader, params, project.size)
yield(gen, "done")
func fill_in_area(position: Vector2) -> void:

View file

@ -22,6 +22,8 @@ corner_radius_bottom_left = 5
anti_aliasing = false
[node name="ToolOptions" instance=ExtResource( 2 )]
margin_right = 138.0
margin_bottom = 105.0
script = ExtResource( 3 )
[node name="Label" parent="." index="0"]
@ -43,10 +45,58 @@ margin_bottom = 56.0
mouse_default_cursor_shape = 2
size_flags_horizontal = 4
text = "Same color area"
items = [ "Same color area", null, false, 0, null, "Same color pixels", null, false, 1, null ]
items = [ "Same color area", null, false, 0, null, "Similar color pixels", null, false, 1, null ]
selected = 0
[node name="FillWith" type="Label" parent="." index="3"]
[node name="Similarity" type="VBoxContainer" parent="." index="3"]
visible = false
margin_top = 60.0
margin_right = 131.0
margin_bottom = 122.0
alignment = 1
[node name="Label" type="Label" parent="Similarity" index="0"]
margin_left = 33.0
margin_right = 97.0
margin_bottom = 14.0
size_flags_horizontal = 4
text = "Similarity:"
[node name="Value" type="SpinBox" parent="Similarity" index="1"]
margin_left = 28.0
margin_top = 18.0
margin_right = 102.0
margin_bottom = 42.0
hint_tooltip = "How much two colors are Similar/Close together"
mouse_default_cursor_shape = 2
size_flags_horizontal = 4
step = 0.001
value = 100.0
align = 1
suffix = "%"
__meta__ = {
"_editor_description_": ""
}
[node name="Slider" type="HSlider" parent="Similarity" index="2"]
margin_left = 19.0
margin_top = 46.0
margin_right = 111.0
margin_bottom = 62.0
rect_min_size = Vector2( 92, 0 )
hint_tooltip = "How much two colors are Similar/Close together"
focus_mode = 0
mouse_default_cursor_shape = 2
size_flags_horizontal = 4
size_flags_vertical = 1
step = 0.001
value = 100.0
ticks_on_borders = true
__meta__ = {
"_editor_description_": ""
}
[node name="FillWith" type="Label" parent="." index="4"]
margin_left = 38.0
margin_top = 60.0
margin_right = 92.0
@ -54,7 +104,7 @@ margin_bottom = 74.0
size_flags_horizontal = 4
text = "Fill with:"
[node name="FillWithOptions" type="OptionButton" parent="." index="4"]
[node name="FillWithOptions" type="OptionButton" parent="." index="5"]
margin_left = 5.0
margin_top = 78.0
margin_right = 126.0
@ -65,7 +115,7 @@ text = "Selected Color"
items = [ "Selected Color", null, false, 0, null, "Pattern", null, false, 1, null ]
selected = 0
[node name="FillPattern" type="VBoxContainer" parent="." index="5"]
[node name="FillPattern" type="VBoxContainer" parent="." index="6"]
visible = false
margin_left = 22.0
margin_top = 102.0
@ -137,16 +187,16 @@ margin_right = 85.0
margin_bottom = 24.0
mouse_default_cursor_shape = 2
[node name="PixelPerfect" parent="." index="6"]
[node name="PixelPerfect" parent="." index="7"]
visible = false
[node name="EmptySpacer" parent="." index="7"]
[node name="EmptySpacer" parent="." index="8"]
visible = false
margin_top = 212.0
margin_right = 131.0
margin_bottom = 224.0
[node name="Mirror" parent="." index="8"]
[node name="Mirror" parent="." index="9"]
visible = false
margin_top = 212.0
margin_right = 131.0
@ -161,6 +211,8 @@ margin_left = 86.0
margin_right = 103.0
[connection signal="item_selected" from="FillAreaOptions" to="." method="_on_FillAreaOptions_item_selected"]
[connection signal="value_changed" from="Similarity/Value" to="." method="_on_Value_value_changed"]
[connection signal="value_changed" from="Similarity/Slider" to="." method="_on_Slider_value_changed"]
[connection signal="item_selected" from="FillWithOptions" to="." method="_on_FillWithOptions_item_selected"]
[connection signal="pressed" from="FillPattern/Type" to="." method="_on_PatternType_pressed"]
[connection signal="value_changed" from="FillPattern/XOffset/OffsetX" to="." method="_on_PatternOffsetX_value_changed"]