diff --git a/src/Autoload/DrawingAlgos.gd b/src/Autoload/DrawingAlgos.gd index c30a361bb..00e5ce3d7 100644 --- a/src/Autoload/DrawingAlgos.gd +++ b/src/Autoload/DrawingAlgos.gd @@ -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 diff --git a/src/Shaders/ColorReplace.gdshader b/src/Shaders/ColorReplace.gdshader index ea6c74abd..b765f2281 100644 --- a/src/Shaders/ColorReplace.gdshader +++ b/src/Shaders/ColorReplace.gdshader @@ -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); } diff --git a/src/Tools/DesignTools/Bucket.gd b/src/Tools/DesignTools/Bucket.gd index c4ccaf01e..a2dbf3df5 100644 --- a/src/Tools/DesignTools/Bucket.gd +++ b/src/Tools/DesignTools/Bucket.gd @@ -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 diff --git a/src/Tools/DesignTools/Bucket.tscn b/src/Tools/DesignTools/Bucket.tscn index 37c0e9c6a..17ed602d7 100644 --- a/src/Tools/DesignTools/Bucket.tscn +++ b/src/Tools/DesignTools/Bucket.tscn @@ -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"]