mirror of
https://github.com/Orama-Interactive/Pixelorama.git
synced 2025-01-18 17:19:50 +00:00
[GLES 3 only] Add OmniScale for scaling and rotation
This commit is contained in:
parent
8423ce7d42
commit
08e00d3c31
|
@ -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)
|
||||
|
|
350
src/Shaders/Rotation/OmniScale.gdshader
Normal file
350
src/Shaders/Rotation/OmniScale.gdshader
Normal file
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"]
|
||||
|
|
Loading…
Reference in a new issue