mirror of
https://github.com/Orama-Interactive/Pixelorama.git
synced 2025-01-18 17:19:50 +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:
parent
92d7bbf539
commit
b0a284583b
|
@ -196,7 +196,7 @@ func get_ellipse_points_filled(pos: Vector2i, size: Vector2i, thickness := 1) ->
|
||||||
return border + filling
|
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(
|
var scaled := Image.create(
|
||||||
sprite.get_width() * 3, sprite.get_height() * 3, false, Image.FORMAT_RGBA8
|
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))
|
sprite.set_pixel(x, y, Color(0, 0, 0, 0))
|
||||||
|
|
||||||
|
|
||||||
func similar_colors(c1: Color, c2: Color, tol := 100.0) -> bool:
|
## Compares two colors, and returns [code]true[/code] if the difference of these colors is
|
||||||
var v1 := Vector4(c1.r, c1.g, c1.b, c1.a)
|
## less or equal to the tolerance [param tol]. [param tol] is in the range of 0-1.
|
||||||
var v2 := Vector4(c2.r, c2.g, c2.b, c2.a)
|
func similar_colors(c1: Color, c2: Color, tol := 0.392157) -> bool:
|
||||||
var dist := v2.distance_to(v1)
|
return (
|
||||||
return dist <= (tol / 255.0)
|
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
|
# Image effects
|
||||||
|
|
|
@ -5,7 +5,7 @@ uniform vec2 size;
|
||||||
|
|
||||||
uniform vec4 old_color;
|
uniform vec4 old_color;
|
||||||
uniform vec4 new_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
|
// Must be the same size as image
|
||||||
// Selected pixels are 1,1,1,1 and unselected 0,0,0,0
|
// 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_size;
|
||||||
uniform vec2 pattern_uv_offset;
|
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));
|
void fragment() {
|
||||||
|
vec4 original_color = texture(TEXTURE, UV);
|
||||||
if (max_diff <= similarity) // We found our match and pixel is proven guilty (small is precise)
|
vec4 selection_color = texture(selection, UV);
|
||||||
|
vec4 col = original_color;
|
||||||
|
if (similar_colors(original_color, old_color, tolerance))
|
||||||
if (has_pattern)
|
if (has_pattern)
|
||||||
col = textureLod(pattern, UV * (size / pattern_size) + pattern_uv_offset, 0.0);
|
col = textureLod(pattern, UV * (size / pattern_size) + pattern_uv_offset, 0.0);
|
||||||
else
|
else
|
||||||
col = new_color;
|
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);
|
COLOR = mix(original_color, col, selection_color.a);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ const PATTERN_FILL_SHADER := preload("res://src/Shaders/PatternFill.gdshader")
|
||||||
var _undo_data := {}
|
var _undo_data := {}
|
||||||
var _prev_mode := 0
|
var _prev_mode := 0
|
||||||
var _pattern: Patterns.Pattern
|
var _pattern: Patterns.Pattern
|
||||||
var _similarity := 100
|
var _tolerance := 0.003
|
||||||
var _fill_area: int = FillArea.AREA
|
var _fill_area: int = FillArea.AREA
|
||||||
var _fill_with: int = FillWith.COLOR
|
var _fill_with: int = FillWith.COLOR
|
||||||
var _offset_x := 0
|
var _offset_x := 0
|
||||||
|
@ -60,7 +60,7 @@ func _on_FillAreaOptions_item_selected(index: int) -> void:
|
||||||
|
|
||||||
func _select_fill_area_optionbutton() -> void:
|
func _select_fill_area_optionbutton() -> void:
|
||||||
$FillAreaOptions.selected = _fill_area
|
$FillAreaOptions.selected = _fill_area
|
||||||
$SimilaritySlider.visible = (_fill_area == FillArea.COLORS)
|
$ToleranceSlider.visible = (_fill_area != FillArea.SELECTION)
|
||||||
|
|
||||||
|
|
||||||
func _on_FillWithOptions_item_selected(index: int) -> void:
|
func _on_FillWithOptions_item_selected(index: int) -> void:
|
||||||
|
@ -69,8 +69,8 @@ func _on_FillWithOptions_item_selected(index: int) -> void:
|
||||||
save_config()
|
save_config()
|
||||||
|
|
||||||
|
|
||||||
func _on_SimilaritySlider_value_changed(value: float) -> void:
|
func _on_tolerance_slider_value_changed(value: float) -> void:
|
||||||
_similarity = value
|
_tolerance = value / 255.0
|
||||||
update_config()
|
update_config()
|
||||||
save_config()
|
save_config()
|
||||||
|
|
||||||
|
@ -102,12 +102,12 @@ func _on_PatternOffsetY_value_changed(value: float) -> void:
|
||||||
|
|
||||||
func get_config() -> Dictionary:
|
func get_config() -> Dictionary:
|
||||||
if !_pattern:
|
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 {
|
return {
|
||||||
"pattern_index": _pattern.index,
|
"pattern_index": _pattern.index,
|
||||||
"fill_area": _fill_area,
|
"fill_area": _fill_area,
|
||||||
"fill_with": _fill_with,
|
"fill_with": _fill_with,
|
||||||
"similarity": _similarity,
|
"tolerance": _tolerance,
|
||||||
"offset_x": _offset_x,
|
"offset_x": _offset_x,
|
||||||
"offset_y": _offset_y,
|
"offset_y": _offset_y,
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ func set_config(config: Dictionary) -> void:
|
||||||
_pattern = Global.patterns_popup.get_pattern(index)
|
_pattern = Global.patterns_popup.get_pattern(index)
|
||||||
_fill_area = config.get("fill_area", _fill_area)
|
_fill_area = config.get("fill_area", _fill_area)
|
||||||
_fill_with = config.get("fill_with", _fill_with)
|
_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_x = config.get("offset_x", _offset_x)
|
||||||
_offset_y = config.get("offset_y", _offset_y)
|
_offset_y = config.get("offset_y", _offset_y)
|
||||||
update_pattern()
|
update_pattern()
|
||||||
|
@ -128,7 +128,7 @@ func set_config(config: Dictionary) -> void:
|
||||||
func update_config() -> void:
|
func update_config() -> void:
|
||||||
_select_fill_area_optionbutton()
|
_select_fill_area_optionbutton()
|
||||||
$FillWithOptions.selected = _fill_with
|
$FillWithOptions.selected = _fill_with
|
||||||
$SimilaritySlider.value = _similarity
|
$ToleranceSlider.value = _tolerance * 255.0
|
||||||
$FillPattern.visible = _fill_with == FillWith.PATTERN
|
$FillPattern.visible = _fill_with == FillWith.PATTERN
|
||||||
$FillPattern/OffsetX.value = _offset_x
|
$FillPattern/OffsetX.value = _offset_x
|
||||||
$FillPattern/OffsetY.value = _offset_y
|
$FillPattern/OffsetY.value = _offset_y
|
||||||
|
@ -224,7 +224,7 @@ func fill_in_color(pos: Vector2i) -> void:
|
||||||
"size": project.size,
|
"size": project.size,
|
||||||
"old_color": color,
|
"old_color": color,
|
||||||
"new_color": tool_slot.color,
|
"new_color": tool_slot.color,
|
||||||
"similarity_percent": _similarity,
|
"tolerance": _tolerance,
|
||||||
"selection": selection_tex,
|
"selection": selection_tex,
|
||||||
"pattern": pattern_tex,
|
"pattern": pattern_tex,
|
||||||
"has_pattern": true if _fill_with == FillWith.PATTERN else false
|
"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(
|
func _flood_line_around_point(
|
||||||
pos: Vector2i, project: Project, image: Image, src_color: Color
|
pos: Vector2i, project: Project, image: Image, src_color: Color
|
||||||
) -> int:
|
) -> 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
|
return pos.x + 1
|
||||||
var west := pos
|
var west := pos
|
||||||
var east := pos
|
var east := pos
|
||||||
if project.has_selection:
|
if project.has_selection:
|
||||||
while (
|
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
|
west += Vector2i.LEFT
|
||||||
while (
|
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
|
east += Vector2i.RIGHT
|
||||||
else:
|
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
|
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
|
east += Vector2i.RIGHT
|
||||||
# Make a note of the stuff we processed
|
# Make a note of the stuff we processed
|
||||||
var c := pos.y
|
var c := pos.y
|
||||||
|
|
|
@ -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://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="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/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"]
|
[sub_resource type="StyleBoxFlat" id="1"]
|
||||||
bg_color = Color(1, 1, 1, 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/text = "Whole selection"
|
||||||
popup/item_2/id = 2
|
popup/item_2/id = 2
|
||||||
|
|
||||||
[node name="SimilaritySlider" parent="." index="4" instance=ExtResource("1")]
|
[node name="ToleranceSlider" type="TextureProgressBar" parent="." index="4"]
|
||||||
visible = false
|
custom_minimum_size = Vector2(32, 24)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
value = 100.0
|
focus_mode = 2
|
||||||
prefix = "Similarity:"
|
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"]
|
[node name="FillWith" type="Label" parent="." index="5"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
@ -101,7 +111,7 @@ layout_mode = 2
|
||||||
prefix = "Offset Y:"
|
prefix = "Offset Y:"
|
||||||
|
|
||||||
[connection signal="item_selected" from="FillAreaOptions" to="." method="_on_FillAreaOptions_item_selected"]
|
[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="item_selected" from="FillWithOptions" to="." method="_on_FillWithOptions_item_selected"]
|
||||||
[connection signal="pressed" from="FillPattern/Type" to="." method="_on_PatternType_pressed"]
|
[connection signal="pressed" from="FillPattern/Type" to="." method="_on_PatternType_pressed"]
|
||||||
[connection signal="value_changed" from="FillPattern/OffsetX" to="." method="_on_PatternOffsetX_value_changed"]
|
[connection signal="value_changed" from="FillPattern/OffsetX" to="." method="_on_PatternOffsetX_value_changed"]
|
||||||
|
|
Loading…
Reference in a new issue