diff --git a/src/Autoload/DrawingAlgos.gd b/src/Autoload/DrawingAlgos.gd index 3d2afe827..606ce6015 100644 --- a/src/Autoload/DrawingAlgos.gd +++ b/src/Autoload/DrawingAlgos.gd @@ -1,7 +1,15 @@ extends Node enum GradientDirection { TOP, BOTTOM, LEFT, RIGHT } +# Continuation from Image.Interpolation +enum Interpolation { SCALE3X = 5, CLEANEDGE = 6, OMNISCALE = 7 } var clean_edge_shader: Shader = preload("res://src/Shaders/Rotation/cleanEdge.gdshader") +var omniscale_shader: Shader + + +func _ready() -> void: + if OS.get_current_video_driver() == OS.VIDEO_DRIVER_GLES3: + omniscale_shader = load("res://src/Shaders/Rotation/OmniScale.gdshader") # Algorithm based on http://members.chello.at/easyfilter/bresenham.html @@ -428,7 +436,7 @@ func scale_image(width: int, height: int, interpolation: int) -> void: continue var sprite := Image.new() sprite.copy_from(f.cels[i].image) - if interpolation == 5: # scale3x + if interpolation == Interpolation.SCALE3X: var times: Vector2 = Vector2( ceil(width / (3.0 * sprite.get_width())), ceil(height / (3.0 * sprite.get_height())) @@ -436,10 +444,14 @@ func scale_image(width: int, height: int, interpolation: int) -> void: for _j in range(max(times.x, times.y)): sprite.copy_from(scale_3x(sprite)) sprite.resize(width, height, 0) - elif interpolation == 6: # cleanEdge + elif interpolation == Interpolation.CLEANEDGE: var params := {"angle": 0, "slope": true, "cleanup": true, "preview": false} var gen := ShaderImageEffect.new() gen.generate_image(sprite, clean_edge_shader, params, Vector2(width, height)) + elif interpolation == Interpolation.OMNISCALE and omniscale_shader: + var params := {"angle": 0, "preview": false} + var gen := ShaderImageEffect.new() + gen.generate_image(sprite, omniscale_shader, params, Vector2(width, height)) else: sprite.resize(width, height, interpolation) Global.current_project.undo_redo.add_do_property(f.cels[i].image, "data", sprite.data) diff --git a/src/Shaders/Rotation/OmniScale.gdshader b/src/Shaders/Rotation/OmniScale.gdshader new file mode 100644 index 000000000..6a293e6f8 --- /dev/null +++ b/src/Shaders/Rotation/OmniScale.gdshader @@ -0,0 +1,350 @@ +// No AA version from https://github.com/deakcor/godot-omniscale/blob/5dfee6e89cd955dd01dccfe70c9979f9b55bb1bf/OmniScale.shader +// Edited slightly by Overloaded to add rotation support for Pixelorama +shader_type canvas_item; + +//#version 130 + +// OmniScale +// by Lior Halphon +// original GLSL code from hunterk by way of RetroArch +// ported to Godot3 shader language by Nobuyuki + +// +// MIT License +// +// Copyright (c) 2015-2016 Lior Halphon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +uniform int ScaleMultiplier : hint_range(0, 100) = 4; + +// vertex compatibility #defines +// #define vTexCoord TEX0.xy +// #define outsize vec4(OutputSize, 1.0 / OutputSize) + +// Pixelorama-specific uniforms +uniform float angle; +uniform sampler2D selection_tex; +uniform vec2 selection_pivot; +uniform vec2 selection_size; +uniform bool preview; + + +bool is_different(vec4 a, vec4 b) +{ + return distance(a,b)>0.1; +} + +// This define could've made code a ton more readable if godot shaders supported it, but it doesn't. +// 55 occurances of this in code; use regexp to turn it back once supported? +// #define P(m, r) ((pattern & (m)) == (r)) + + +vec4 scale(sampler2D image, vec2 coord, vec2 pxSize) { + + vec2 OutputSize = vec2(float(ScaleMultiplier), float(ScaleMultiplier)); + vec2 textureDimensions = vec2(1.0,1.0); + + // o = offset, the width of a pixel + vec2 o = pxSize; + vec2 texCoord = coord; + + // We always calculate the top left quarter. If we need a different quarter, we flip our co-ordinates */ + + // p = the position within a pixel [0...1] + vec2 p = fract(texCoord / pxSize); + + if (p.x > 0.5) { + o.x = -o.x; + p.x = 1.0 - p.x; + } + if (p.y > 0.5) { + o.y = -o.y; + p.y = 1.0 - p.y; + } + + + + vec4 w0 = texture(image, texCoord + vec2( -o.x, -o.y)); + vec4 w1 = texture(image, texCoord + vec2( 0, -o.y)); + vec4 w2 = texture(image, texCoord + vec2( o.x, -o.y)); + vec4 w3 = texture(image, texCoord + vec2( -o.x, 0)); + vec4 w4 = texture(image, texCoord + vec2( 0, 0)); + vec4 w5 = texture(image, texCoord + vec2( o.x, 0)); + vec4 w6 = texture(image, texCoord + vec2( -o.x, o.y)); + vec4 w7 = texture(image, texCoord + vec2( 0, o.y)); + vec4 w8 = texture(image, texCoord + vec2( o.x, o.y)); + + int pattern = 0; + if (is_different(w0, w4)) pattern |= 1 << 0; + if (is_different(w1, w4)) pattern |= 1 << 1; + if (is_different(w2, w4)) pattern |= 1 << 2; + if (is_different(w3, w4)) pattern |= 1 << 3; + if (is_different(w5, w4)) pattern |= 1 << 4; + if (is_different(w6, w4)) pattern |= 1 << 5; + if (is_different(w7, w4)) pattern |= 1 << 6; + if (is_different(w8, w4)) pattern |= 1 << 7; + + if ((((pattern & (191)) == (55)) || ((pattern & (219)) == (19))) && is_different(w1, w5)) + return mix(w4, w3, 0.5 - p.x>0.5?1.0:0.0); + if ((((pattern & (219)) == (73)) || ((pattern & (239)) == (109))) && is_different(w7, w3)) + return mix(w4, w1, 0.5 - p.y>0.5?1.0:0.0); + if ((((pattern & (11)) == (11)) || ((pattern & (254)) == (74)) || ((pattern & (254)) == (26))) && is_different(w3, w1)) + return w4; + if ((((pattern & (111)) == (42)) || ((pattern & (91)) == (10)) || ((pattern & (191)) == (58)) || ((pattern & (223)) == (90)) || + ((pattern & (159)) == (138)) || ((pattern & (207)) == (138)) || ((pattern & (239)) == (78)) || ((pattern & (63)) == (14)) || + ((pattern & (251)) == (90)) || ((pattern & (187)) == (138)) || ((pattern & (127)) == (90)) || ((pattern & (175)) == (138)) || + ((pattern & (235)) == (138))) && is_different(w3, w1)) + return mix(w4, mix(w4, w0, 0.5 - p.x>0.5?1.0:0.0), 0.5 - p.y>0.5?1.0:0.0); + if (((pattern & (11)) == (8))) + return mix(mix(w0 * 0.375 + w1 * 0.25 + w4 * 0.375, w4 * 0.5 + w1 * 0.5, p.x * 2.0>0.5?1.0:0.0), w4, p.y * 2.0>0.5?1.0:0.0); + if (((pattern & (11)) == (2))) + return mix(mix(w0 * 0.375 + w3 * 0.25 + w4 * 0.375, w4 * 0.5 + w3 * 0.5, p.y * 2.0>0.5?1.0:0.0), w4, p.x * 2.0>0.5?1.0:0.0); + if (((pattern & (47)) == (47))) { + float dist = length(p - vec2(0.5)); + float pixel_size = length(1.0 / (OutputSize / textureDimensions)); + if (dist < 0.5 - pixel_size / 2.0) { + return w4; + } + vec4 r; + if (is_different(w0, w1) || is_different(w0, w3)) { + r = mix(w1, w3, p.y - p.x + 0.5>0.5?1.0:0.0); + } + else { + r = mix(mix(w1 * 0.375 + w0 * 0.25 + w3 * 0.375, w3, p.y * 2.0>0.5?1.0:0.0), w1, p.x * 2.0>0.5?1.0:0.0); + } + + if (dist > 0.5 + pixel_size / 2.0) { + return r; + } + return mix(w4, r, (dist - 0.5 + pixel_size / 2.0) / pixel_size>0.5?1.0:0.0); + } + if (((pattern & (191)) == (55)) || ((pattern & (219)) == (19))) { + float dist = p.x - 2.0 * p.y; + float pixel_size = length(1.0 / (OutputSize / textureDimensions)) * sqrt(5.0); + if (dist > pixel_size / 2.0) { + return w1; + } + vec4 r = mix(w3, w4, p.x + 0.5>0.5?1.0:0.0); + if (dist < -pixel_size / 2.0) { + return r; + } + return mix(r, w1, (dist + pixel_size / 2.0) / pixel_size>0.5?1.0:0.0); + } + if (((pattern & (219)) == (73)) || ((pattern & (239)) == (109))) { + float dist = p.y - 2.0 * p.x; + float pixel_size = length(1.0 / (OutputSize / textureDimensions)) * sqrt(5.0); + if (p.y - 2.0 * p.x > pixel_size / 2.0) { + return w3; + } + vec4 r = mix(w1, w4, p.x + 0.5>0.5?1.0:0.0); + if (dist < -pixel_size / 2.0) { + return r; + } + return mix(r, w3, (dist + pixel_size / 2.0) / pixel_size>0.5?1.0:0.0); + } + if (((pattern & (191)) == (143)) || ((pattern & (126)) == (14))) { + float dist = p.x + 2.0 * p.y; + float pixel_size = length(1.0 / (OutputSize / textureDimensions)) * sqrt(5.0); + + if (dist > 1.0 + pixel_size / 2.0) { + return w4; + } + + vec4 r; + if (is_different(w0, w1) || is_different(w0, w3)) { + r = mix(w1, w3, p.y - p.x + 0.5>0.5?1.0:0.0); + } + else { + r = mix(mix(w1 * 0.375 + w0 * 0.25 + w3 * 0.375, w3, p.y * 2.0>0.5?1.0:0.0), w1, p.x * 2.0>0.5?1.0:0.0); + } + + if (dist < 1.0 - pixel_size / 2.0) { + return r; + } + + return mix(r, w4, (dist + pixel_size / 2.0 - 1.0) / pixel_size>0.5?1.0:0.0); + + } + + if (((pattern & (126)) == (42)) || ((pattern & (239)) == (171))) { + float dist = p.y + 2.0 * p.x; + float pixel_size = length(1.0 / (OutputSize / textureDimensions)) * sqrt(5.0); + + if (p.y + 2.0 * p.x > 1.0 + pixel_size / 2.0) { + return w4; + } + + vec4 r; + + if (is_different(w0, w1) || is_different(w0, w3)) { + r = mix(w1, w3, p.y - p.x + 0.5>0.5?1.0:0.0); + } + else { + r = mix(mix(w1 * 0.375 + w0 * 0.25 + w3 * 0.375, w3, p.y * 2.0>0.5?1.0:0.0), w1, p.x * 2.0>0.5?1.0:0.0); + } + + if (dist < 1.0 - pixel_size / 2.0) { + return r; + } + + return mix(r, w4, (dist + pixel_size / 2.0 - 1.0) / pixel_size>0.5?1.0:0.0); + } + + if (((pattern & (27)) == (3)) || ((pattern & (79)) == (67)) || ((pattern & (139)) == (131)) || ((pattern & (107)) == (67))) + return mix(w4, w3, 0.5 - p.x>0.5?1.0:0.0); + + if (((pattern & (75)) == (9)) || ((pattern & (139)) == (137)) || ((pattern & (31)) == (25)) || ((pattern & (59)) == (25))) + return mix(w4, w1, 0.5 - p.y>0.5?1.0:0.0); + + if (((pattern & (251)) == (106)) || ((pattern & (111)) == (110)) || ((pattern & (63)) == (62)) || ((pattern & (251)) == (250)) || + ((pattern & (223)) == (222)) || ((pattern & (223)) == (30))) + return mix(w4, w0, (1.0 - p.x - p.y) / 2.0>0.5?1.0:0.0); + + if (((pattern & (79)) == (75)) || ((pattern & (159)) == (27)) || ((pattern & (47)) == (11)) || + ((pattern & (190)) == (10)) || ((pattern & (238)) == (10)) || ((pattern & (126)) == (10)) || ((pattern & (235)) == (75)) || + ((pattern & (59)) == (27))) { + float dist = p.x + p.y; + float pixel_size = length(1.0 / (OutputSize / textureDimensions)); + + if (dist > 0.5 + pixel_size / 2.0) { + return w4; + } + + vec4 r; + if (is_different(w0, w1) || is_different(w0, w3)) { + r = mix(w1, w3, p.y - p.x + 0.5>0.5?1.0:0.0); + } + else { + r = mix(mix(w1 * 0.375 + w0 * 0.25 + w3 * 0.375, w3, p.y * 2.0>0.5?1.0:0.0), w1, p.x * 2.0>0.5?1.0:0.0); + } + + if (dist < 0.5 - pixel_size / 2.0) { + return r; + } + + return mix(r, w4, (dist + pixel_size / 2.0 - 0.5) / pixel_size>0.5?1.0:0.0); + } + + if (((pattern & (11)) == (1))) + return mix(mix(w4, w3, 0.5 - p.x>0.5?1.0:0.0), mix(w1, (w1 + w3) / 2.0, 0.5 - p.x>0.5?1.0:0.0), 0.5 - p.y>0.5?1.0:0.0); + + if (((pattern & (11)) == (0))) + return mix(mix(w4, w3, 0.5 - p.x>0.5?1.0:0.0), mix(w1, w0, 0.5 - p.x>0.5?1.0:0.0), 0.5 - p.y>0.5?1.0:0.0); + + float dist = p.x + p.y; + float pixel_size = length(1.0 / (OutputSize / textureDimensions)); + + if (dist > 0.5 + pixel_size / 2.0) + return w4; + + /* We need more samples to "solve" this diagonal */ + vec4 x0 = texture(image, texCoord + vec2( -o.x * 2.0, -o.y * 2.0)); + vec4 x1 = texture(image, texCoord + vec2( -o.x , -o.y * 2.0)); + vec4 x2 = texture(image, texCoord + vec2( 0.0 , -o.y * 2.0)); + vec4 x3 = texture(image, texCoord + vec2( o.x , -o.y * 2.0)); + vec4 x4 = texture(image, texCoord + vec2( -o.x * 2.0, -o.y )); + vec4 x5 = texture(image, texCoord + vec2( -o.x * 2.0, 0.0 )); + vec4 x6 = texture(image, texCoord + vec2( -o.x * 2.0, o.y )); + + if (is_different(x0, w4)) pattern |= 1 << 8; + if (is_different(x1, w4)) pattern |= 1 << 9; + if (is_different(x2, w4)) pattern |= 1 << 10; + if (is_different(x3, w4)) pattern |= 1 << 11; + if (is_different(x4, w4)) pattern |= 1 << 12; + if (is_different(x5, w4)) pattern |= 1 << 13; + if (is_different(x6, w4)) pattern |= 1 << 14; + + int diagonal_bias = -7; + while (pattern != 0) { + diagonal_bias += pattern & 1; + pattern >>= 1; + } + + if (diagonal_bias <= 0) { + vec4 r = mix(w1, w3, p.y - p.x + 0.5>0.5?1.0:0.0); + if (dist < 0.5 - pixel_size / 2.0) { + return r; + } + return mix(r, w4, (dist + pixel_size / 2.0 - 0.5) / pixel_size>0.5?1.0:0.0); + } + + return w4; +} + + +vec2 rotate(vec2 uv, vec2 pivot, float ratio) { // Taken from NearestNeighbour shader + // Scale and center image + uv.x -= pivot.x; + uv.x *= ratio; + uv.x += pivot.x; + + // Rotate image + uv -= pivot; + uv = vec2(cos(angle) * uv.x + sin(angle) * uv.y, + -sin(angle) * uv.x + cos(angle) * uv.y); + uv.x /= ratio; + uv += pivot; + + return uv; +} + + +void fragment() +{ + vec4 original = texture(TEXTURE, UV); + float selection = texture(selection_tex, UV).a; + vec2 size = 1.0 / TEXTURE_PIXEL_SIZE; + vec2 pivot = selection_pivot / size; // Normalize pivot position + float ratio = size.x / size.y; // Resolution ratio + vec2 pixelated_uv = floor(UV * size) / (size - 1.0); // Pixelate UV to fit resolution + vec2 rotated_uv; + if (preview) { + rotated_uv = rotate(pixelated_uv, pivot, ratio); + } + else { + rotated_uv = rotate(UV, pivot, ratio); + } + vec4 c; + c = scale(TEXTURE, rotated_uv, TEXTURE_PIXEL_SIZE); + + // Taken from NearestNeighbour shader + c.a *= texture(selection_tex, rotated_uv).a; // Combine with selection mask + // Make a border to prevent stretching pixels on the edge + vec2 border_uv = rotated_uv; + + // Center the border + border_uv -= 0.5; + border_uv *= 2.0; + border_uv = abs(border_uv); + + float border = max(border_uv.x, border_uv.y); // This is a rectangular gradient + border = floor(border - TEXTURE_PIXEL_SIZE.x); // Turn the grad into a rectangle shape + border = 1.0 - clamp(border, 0.0, 1.0); // Invert the rectangle + + float mask = mix(selection, 1.0, 1.0 - ceil(original.a)); // Combine selection mask with area outside original + + // Combine original and rotated image only when intersecting, otherwise just pure rotated image. + COLOR.rgb = mix(mix(original.rgb, c.rgb, c.a * border), c.rgb, mask); + COLOR.a = mix(original.a, 0.0, selection); // Remove alpha on the selected area + COLOR.a = mix(COLOR.a, 1.0, c.a * border); // Combine alpha of original image and rotated + //c.a = step(0.5,c.a); + //COLOR = c; +} \ No newline at end of file diff --git a/src/UI/Dialogs/ImageEffects/RotateImage.gd b/src/UI/Dialogs/ImageEffects/RotateImage.gd index b7098566a..d9d1dac35 100644 --- a/src/UI/Dialogs/ImageEffects/RotateImage.gd +++ b/src/UI/Dialogs/ImageEffects/RotateImage.gd @@ -1,5 +1,7 @@ extends ImageEffect +enum { ROTXEL_SMEAR, CLEANEDGE, OMNISCALE, NNS, NN, ROTXEL, URD } + var live_preview: bool = true var rotxel_shader: Shader var nn_shader: Shader = preload("res://src/Shaders/Rotation/NearestNeighbour.shader") @@ -20,15 +22,16 @@ onready var wait_time_slider: ValueSlider = $VBoxContainer/WaitTime func _ready() -> void: - # Algorithms are arranged according to their speed if OS.get_name() != "HTML5": - type_option_button.add_item("Rotxel with Smear") + type_option_button.add_item("Rotxel with Smear", ROTXEL_SMEAR) rotxel_shader = load("res://src/Shaders/Rotation/SmearRotxel.shader") - type_option_button.add_item("cleanEdge") - type_option_button.add_item("Nearest neighbour (Shader)") - type_option_button.add_item("Nearest neighbour") - type_option_button.add_item("Rotxel") - type_option_button.add_item("Upscale, Rotate and Downscale") + type_option_button.add_item("cleanEdge", CLEANEDGE) + type_option_button.add_item("OmniScale", OMNISCALE) + type_option_button.set_item_disabled(OMNISCALE, not DrawingAlgos.omniscale_shader) + type_option_button.add_item("Nearest neighbour (Shader)", NNS) + type_option_button.add_item("Nearest neighbour", NN) + type_option_button.add_item("Rotxel", ROTXEL) + type_option_button.add_item("Upscale, Rotate and Downscale", URD) type_option_button.emit_signal("item_selected", 0) @@ -56,6 +59,7 @@ func decide_pivot() -> void: if ( type_option_button.text != "Nearest neighbour (Shader)" and type_option_button.text != "cleanEdge" + and type_option_button.text != "OmniScale" ): if int(size.x) % 2 == 0: pivot.x -= 0.5 @@ -71,6 +75,7 @@ func decide_pivot() -> void: if ( type_option_button.text != "Nearest neighbour (Shader)" and type_option_button.text != "cleanEdge" + and type_option_button.text != "OmniScale" ): # Pivot correction in case of even size if int(selection_rectangle.end.x - selection_rectangle.position.x) % 2 == 0: @@ -145,6 +150,22 @@ func commit_action(cel: Image, _project: Project = Global.current_project) -> vo var gen := ShaderImageEffect.new() gen.generate_image(cel, clean_edge_shader, params, _project.size) yield(gen, "done") + "OmniScale": + var params := { + "angle": angle, + "selection_tex": selection_tex, + "selection_pivot": pivot, + "selection_size": selection_size, + "preview": true + } + if !confirmed: + for param in params: + preview.material.set_shader_param(param, params[param]) + else: + params["preview"] = false + var gen := ShaderImageEffect.new() + gen.generate_image(cel, DrawingAlgos.omniscale_shader, params, _project.size) + yield(gen, "done") "Nearest neighbour (Shader)": var params := { "angle": angle, @@ -177,6 +198,7 @@ func _type_is_shader() -> bool: type_option_button.text == "Nearest neighbour (Shader)" or type_option_button.text == "Rotxel with Smear" or type_option_button.text == "cleanEdge" + or type_option_button.text == "OmniScale" ) @@ -191,6 +213,11 @@ func _on_TypeOptionButton_item_selected(_id: int) -> void: sm.shader = clean_edge_shader preview.set_material(sm) smear_options.visible = false + elif type_option_button.text == "OmniScale": + var sm := ShaderMaterial.new() + sm.shader = DrawingAlgos.omniscale_shader + preview.set_material(sm) + smear_options.visible = false elif type_option_button.text == "Nearest neighbour (Shader)": var sm := ShaderMaterial.new() sm.shader = nn_shader diff --git a/src/UI/Dialogs/ImageEffects/ScaleImage.gd b/src/UI/Dialogs/ImageEffects/ScaleImage.gd index e4e60dd1a..c7aabd689 100644 --- a/src/UI/Dialogs/ImageEffects/ScaleImage.gd +++ b/src/UI/Dialogs/ImageEffects/ScaleImage.gd @@ -10,6 +10,19 @@ onready var interpolation_type: OptionButton = find_node("InterpolationType") onready var ratio_box: BaseButton = find_node("AspectRatioButton") +func _ready() -> void: + interpolation_type.add_item("Nearest", Image.INTERPOLATE_NEAREST) + interpolation_type.add_item("Bilinear", Image.INTERPOLATE_BILINEAR) + interpolation_type.add_item("Cubic", Image.INTERPOLATE_CUBIC) + interpolation_type.add_item("Trilinear", Image.INTERPOLATE_TRILINEAR) + interpolation_type.add_item("Lanczos", Image.INTERPOLATE_LANCZOS) + interpolation_type.add_item("Scale3X", DrawingAlgos.Interpolation.SCALE3X) + interpolation_type.add_item("cleanEdge", DrawingAlgos.Interpolation.CLEANEDGE) + interpolation_type.add_item("OmniScale", DrawingAlgos.Interpolation.OMNISCALE) + if not DrawingAlgos.omniscale_shader: + interpolation_type.set_item_disabled(DrawingAlgos.Interpolation.OMNISCALE, true) + + func _on_ScaleImage_about_to_show() -> void: Global.canvas.selection.transform_content_confirm() aspect_ratio = Global.current_project.size.x / Global.current_project.size.y diff --git a/src/UI/Dialogs/ImageEffects/ScaleImage.tscn b/src/UI/Dialogs/ImageEffects/ScaleImage.tscn index 5f7453cc2..f86c556db 100644 --- a/src/UI/Dialogs/ImageEffects/ScaleImage.tscn +++ b/src/UI/Dialogs/ImageEffects/ScaleImage.tscn @@ -207,9 +207,6 @@ margin_right = 234.0 margin_bottom = 20.0 mouse_default_cursor_shape = 2 size_flags_horizontal = 3 -text = "Nearest" -items = [ "Nearest", null, false, 0, null, "Bilinear", null, false, 1, null, "Cubic", null, false, 2, null, "Trilinear", null, false, 3, null, "Lanczos", null, false, 4, null, "Scale3X", null, false, 5, null, "cleanEdge", null, false, 6, null ] -selected = 0 [connection signal="about_to_show" from="." to="." method="_on_ScaleImage_about_to_show"] [connection signal="confirmed" from="." to="." method="_on_ScaleImage_confirmed"]