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

Add tolerance to the bucket's "similar area" mode, rename "similarity" to "tolerance" and make it work the inverse way

A slightly breaking change for a minor update, but one that needed to be done. The bucket tool's "similarity" (now renamed to "tolerance") used to work the opposite way from all other software, the maximum value meant exact color match and 0 meant no color match. Now it works the inverse way to make it be consistent with other software, and the range is now 0-255 instead of 0-100. 0 means exact color match, 255 means no color match. And tolerance also now works for the "similar area" mode as well.
This commit is contained in:
Emmanouil Papadeas 2024-08-10 18:20:42 +03:00
parent 92d7bbf539
commit b0a284583b
4 changed files with 62 additions and 36 deletions

View file

@ -196,7 +196,7 @@ func get_ellipse_points_filled(pos: Vector2i, size: Vector2i, thickness := 1) ->
return border + filling
func scale_3x(sprite: Image, tol := 50.0) -> Image:
func scale_3x(sprite: Image, tol := 0.196078) -> Image:
var scaled := Image.create(
sprite.get_width() * 3, sprite.get_height() * 3, false, Image.FORMAT_RGBA8
)
@ -475,11 +475,15 @@ func nn_rotate(sprite: Image, angle: float, pivot: Vector2) -> void:
sprite.set_pixel(x, y, Color(0, 0, 0, 0))
func similar_colors(c1: Color, c2: Color, tol := 100.0) -> bool:
var v1 := Vector4(c1.r, c1.g, c1.b, c1.a)
var v2 := Vector4(c2.r, c2.g, c2.b, c2.a)
var dist := v2.distance_to(v1)
return dist <= (tol / 255.0)
## Compares two colors, and returns [code]true[/code] if the difference of these colors is
## less or equal to the tolerance [param tol]. [param tol] is in the range of 0-1.
func similar_colors(c1: Color, c2: Color, tol := 0.392157) -> bool:
return (
absf(c1.r - c2.r) <= tol
&& absf(c1.g - c2.g) <= tol
&& absf(c1.b - c2.b) <= tol
&& absf(c1.a - c2.a) <= tol
)
# Image effects

View file

@ -5,7 +5,7 @@ uniform vec2 size;
uniform vec4 old_color;
uniform vec4 new_color;
uniform float similarity_percent : hint_range(0.0, 100.0);
uniform float tolerance : hint_range(0.0, 1.0);
// Must be the same size as image
// Selected pixels are 1,1,1,1 and unselected 0,0,0,0
@ -16,22 +16,26 @@ uniform sampler2D pattern: repeat_enable;
uniform vec2 pattern_size;
uniform vec2 pattern_uv_offset;
void fragment() { // applies on each pixel separately
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
bool similar_colors(vec4 c1, vec4 c2, float tol) {
return (
abs(c1.r - c2.r) <= tol
&& abs(c1.g - c2.g) <= tol
&& abs(c1.b - c2.b) <= tol
&& abs(c1.a - c2.a) <= tol
);
}
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)
void fragment() {
vec4 original_color = texture(TEXTURE, UV);
vec4 selection_color = texture(selection, UV);
vec4 col = original_color;
if (similar_colors(original_color, old_color, tolerance))
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

@ -9,7 +9,7 @@ const PATTERN_FILL_SHADER := preload("res://src/Shaders/PatternFill.gdshader")
var _undo_data := {}
var _prev_mode := 0
var _pattern: Patterns.Pattern
var _similarity := 100
var _tolerance := 0.003
var _fill_area: int = FillArea.AREA
var _fill_with: int = FillWith.COLOR
var _offset_x := 0
@ -60,7 +60,7 @@ func _on_FillAreaOptions_item_selected(index: int) -> void:
func _select_fill_area_optionbutton() -> void:
$FillAreaOptions.selected = _fill_area
$SimilaritySlider.visible = (_fill_area == FillArea.COLORS)
$ToleranceSlider.visible = (_fill_area != FillArea.SELECTION)
func _on_FillWithOptions_item_selected(index: int) -> void:
@ -69,8 +69,8 @@ func _on_FillWithOptions_item_selected(index: int) -> void:
save_config()
func _on_SimilaritySlider_value_changed(value: float) -> void:
_similarity = value
func _on_tolerance_slider_value_changed(value: float) -> void:
_tolerance = value / 255.0
update_config()
save_config()
@ -102,12 +102,12 @@ func _on_PatternOffsetY_value_changed(value: float) -> void:
func get_config() -> Dictionary:
if !_pattern:
return {"fill_area": _fill_area, "fill_with": _fill_with, "similarity": _similarity}
return {"fill_area": _fill_area, "fill_with": _fill_with, "tolerance": _tolerance}
return {
"pattern_index": _pattern.index,
"fill_area": _fill_area,
"fill_with": _fill_with,
"similarity": _similarity,
"tolerance": _tolerance,
"offset_x": _offset_x,
"offset_y": _offset_y,
}
@ -119,7 +119,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)
_tolerance = config.get("tolerance", _tolerance)
_offset_x = config.get("offset_x", _offset_x)
_offset_y = config.get("offset_y", _offset_y)
update_pattern()
@ -128,7 +128,7 @@ func set_config(config: Dictionary) -> void:
func update_config() -> void:
_select_fill_area_optionbutton()
$FillWithOptions.selected = _fill_with
$SimilaritySlider.value = _similarity
$ToleranceSlider.value = _tolerance * 255.0
$FillPattern.visible = _fill_with == FillWith.PATTERN
$FillPattern/OffsetX.value = _offset_x
$FillPattern/OffsetY.value = _offset_y
@ -224,7 +224,7 @@ func fill_in_color(pos: Vector2i) -> void:
"size": project.size,
"old_color": color,
"new_color": tool_slot.color,
"similarity_percent": _similarity,
"tolerance": _tolerance,
"selection": selection_tex,
"pattern": pattern_tex,
"has_pattern": true if _fill_with == FillWith.PATTERN else false
@ -313,23 +313,31 @@ func _add_new_segment(y := 0) -> void:
func _flood_line_around_point(
pos: Vector2i, project: Project, image: Image, src_color: Color
) -> int:
if not image.get_pixelv(pos).is_equal_approx(src_color):
if not DrawingAlgos.similar_colors(image.get_pixelv(pos), src_color, _tolerance):
return pos.x + 1
var west := pos
var east := pos
if project.has_selection:
while (
project.can_pixel_get_drawn(west) && image.get_pixelv(west).is_equal_approx(src_color)
project.can_pixel_get_drawn(west)
&& DrawingAlgos.similar_colors(image.get_pixelv(west), src_color, _tolerance)
):
west += Vector2i.LEFT
while (
project.can_pixel_get_drawn(east) && image.get_pixelv(east).is_equal_approx(src_color)
project.can_pixel_get_drawn(east)
&& DrawingAlgos.similar_colors(image.get_pixelv(east), src_color, _tolerance)
):
east += Vector2i.RIGHT
else:
while west.x >= 0 && image.get_pixelv(west).is_equal_approx(src_color):
while (
west.x >= 0
&& DrawingAlgos.similar_colors(image.get_pixelv(west), src_color, _tolerance)
):
west += Vector2i.LEFT
while east.x < project.size.x && image.get_pixelv(east).is_equal_approx(src_color):
while (
east.x < project.size.x
&& DrawingAlgos.similar_colors(image.get_pixelv(east), src_color, _tolerance)
):
east += Vector2i.RIGHT
# Make a note of the stuff we processed
var c := pos.y

View file

@ -1,8 +1,9 @@
[gd_scene load_steps=6 format=3 uid="uid://bbvvkrrjyxugo"]
[gd_scene load_steps=7 format=3 uid="uid://bbvvkrrjyxugo"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/ValueSlider.tscn" id="1"]
[ext_resource type="PackedScene" uid="uid://ctfgfelg0sho8" path="res://src/Tools/BaseTool.tscn" id="2"]
[ext_resource type="Script" path="res://src/Tools/DesignTools/Bucket.gd" id="3"]
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="4_1pngp"]
[sub_resource type="StyleBoxFlat" id="1"]
bg_color = Color(1, 1, 1, 1)
@ -46,11 +47,20 @@ popup/item_1/id = 1
popup/item_2/text = "Whole selection"
popup/item_2/id = 2
[node name="SimilaritySlider" parent="." index="4" instance=ExtResource("1")]
visible = false
[node name="ToleranceSlider" type="TextureProgressBar" parent="." index="4"]
custom_minimum_size = Vector2(32, 24)
layout_mode = 2
value = 100.0
prefix = "Similarity:"
focus_mode = 2
mouse_default_cursor_shape = 2
theme_type_variation = &"ValueSlider"
max_value = 255.0
nine_patch_stretch = true
stretch_margin_left = 3
stretch_margin_top = 3
stretch_margin_right = 3
stretch_margin_bottom = 3
script = ExtResource("4_1pngp")
prefix = "Tolerance:"
[node name="FillWith" type="Label" parent="." index="5"]
layout_mode = 2
@ -101,7 +111,7 @@ layout_mode = 2
prefix = "Offset Y:"
[connection signal="item_selected" from="FillAreaOptions" to="." method="_on_FillAreaOptions_item_selected"]
[connection signal="value_changed" from="SimilaritySlider" to="." method="_on_SimilaritySlider_value_changed"]
[connection signal="value_changed" from="ToleranceSlider" to="." method="_on_tolerance_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/OffsetX" to="." method="_on_PatternOffsetX_value_changed"]