2020-05-29 00:16:44 +00:00
|
|
|
extends Node
|
|
|
|
|
|
|
|
|
2020-07-18 16:01:24 +00:00
|
|
|
enum GradientDirection {TOP, BOTTOM, LEFT, RIGHT}
|
|
|
|
|
|
|
|
|
2020-05-29 00:16:44 +00:00
|
|
|
func scale3X(sprite : Image, tol : float = 50) -> Image:
|
|
|
|
var scaled = Image.new()
|
|
|
|
scaled.create(sprite.get_width()*3, sprite.get_height()*3, false, Image.FORMAT_RGBA8)
|
|
|
|
scaled.lock()
|
|
|
|
sprite.lock()
|
|
|
|
var a : Color
|
|
|
|
var b : Color
|
|
|
|
var c : Color
|
|
|
|
var d : Color
|
|
|
|
var e : Color
|
|
|
|
var f : Color
|
|
|
|
var g : Color
|
|
|
|
var h : Color
|
|
|
|
var i : Color
|
|
|
|
|
|
|
|
for x in range(1,sprite.get_width()-1):
|
|
|
|
for y in range(1,sprite.get_height()-1):
|
|
|
|
var xs : float = 3*x
|
|
|
|
var ys : float = 3*y
|
|
|
|
|
|
|
|
a = sprite.get_pixel(x-1,y-1)
|
|
|
|
b = sprite.get_pixel(x,y-1)
|
|
|
|
c = sprite.get_pixel(x+1,y-1)
|
|
|
|
d = sprite.get_pixel(x-1,y)
|
|
|
|
e = sprite.get_pixel(x,y)
|
|
|
|
f = sprite.get_pixel(x+1,y)
|
|
|
|
g = sprite.get_pixel(x-1,y+1)
|
|
|
|
h = sprite.get_pixel(x,y+1)
|
|
|
|
i = sprite.get_pixel(x+1,y+1)
|
|
|
|
|
|
|
|
var db : bool = similarColors(d, b, tol)
|
|
|
|
var dh : bool = similarColors(d, h, tol)
|
|
|
|
var bf : bool = similarColors(f, b, tol)
|
|
|
|
var ec : bool = similarColors(e, c, tol)
|
|
|
|
var ea : bool = similarColors(e, a, tol)
|
|
|
|
var fh : bool = similarColors(f, h, tol)
|
|
|
|
var eg : bool = similarColors(e, g, tol)
|
|
|
|
var ei : bool = similarColors(e, i, tol)
|
|
|
|
|
|
|
|
scaled.set_pixel(xs-1, ys-1, d if (db and !dh and !bf) else e )
|
|
|
|
scaled.set_pixel(xs, ys-1, b if (db and !dh and !bf and !ec) or
|
|
|
|
(bf and !db and !fh and !ea) else e)
|
|
|
|
scaled.set_pixel(xs+1, ys-1, f if (bf and !db and !fh) else e)
|
|
|
|
scaled.set_pixel(xs-1, ys, d if (dh and !fh and !db and !ea) or
|
|
|
|
(db and !dh and !bf and !eg) else e)
|
|
|
|
scaled.set_pixel(xs, ys, e);
|
|
|
|
scaled.set_pixel(xs+1, ys, f if (bf and !db and !fh and !ei) or
|
|
|
|
(fh and !bf and !dh and !ec) else e)
|
|
|
|
scaled.set_pixel(xs-1, ys+1, d if (dh and !fh and !db) else e)
|
|
|
|
scaled.set_pixel(xs, ys+1, h if (fh and !bf and !dh and !eg) or
|
|
|
|
(dh and !fh and !db and !ei) else e)
|
|
|
|
scaled.set_pixel(xs+1, ys+1, f if (fh and !bf and !dh) else e)
|
|
|
|
|
|
|
|
scaled.unlock()
|
|
|
|
sprite.unlock()
|
|
|
|
return scaled
|
|
|
|
|
|
|
|
|
|
|
|
func rotxel(sprite : Image, angle : float) -> void:
|
|
|
|
# If angle is simple, then nn rotation is the best
|
|
|
|
|
|
|
|
if angle == 0 || angle == PI/2 || angle == PI || angle == 2*PI:
|
|
|
|
nn_rotate(sprite, angle)
|
|
|
|
return
|
|
|
|
|
|
|
|
var aux : Image = Image.new()
|
|
|
|
aux.copy_from(sprite)
|
2020-06-01 00:11:00 +00:00
|
|
|
# warning-ignore:integer_division
|
|
|
|
# warning-ignore:integer_division
|
|
|
|
var center : Vector2 = Vector2(sprite.get_width() / 2, sprite.get_height() / 2)
|
2020-05-29 00:16:44 +00:00
|
|
|
var ox : int
|
|
|
|
var oy : int
|
|
|
|
var p : Color
|
|
|
|
aux.lock()
|
|
|
|
sprite.lock()
|
|
|
|
for x in range(sprite.get_width()):
|
|
|
|
for y in range(sprite.get_height()):
|
|
|
|
var dx = 3*(x - center.x)
|
|
|
|
var dy = 3*(y - center.y)
|
|
|
|
var found_pixel : bool = false
|
|
|
|
for k in range(9):
|
|
|
|
var i = -1 + k % 3
|
2020-06-01 00:11:00 +00:00
|
|
|
# warning-ignore:integer_division
|
2020-05-29 00:16:44 +00:00
|
|
|
var j = -1 + int(k / 3)
|
|
|
|
var dir = atan2(dy + j, dx + i)
|
|
|
|
var mag = sqrt(pow(dx + i, 2) + pow(dy + j, 2))
|
|
|
|
dir -= angle
|
|
|
|
ox = round(center.x*3 + 1 + mag*cos(dir))
|
|
|
|
oy = round(center.y*3 + 1 + mag*sin(dir))
|
|
|
|
|
|
|
|
if (sprite.get_width() % 2 != 0):
|
|
|
|
ox += 1
|
|
|
|
oy += 1
|
|
|
|
|
|
|
|
if (ox >= 0 && ox < sprite.get_width()*3
|
|
|
|
&& oy >= 0 && oy < sprite.get_height()*3):
|
|
|
|
found_pixel = true
|
|
|
|
break
|
|
|
|
|
|
|
|
if !found_pixel:
|
|
|
|
sprite.set_pixel(x, y, Color(0,0,0,0))
|
|
|
|
continue
|
|
|
|
|
|
|
|
var fil : int = oy % 3
|
|
|
|
var col : int = ox % 3
|
|
|
|
var index : int = col + 3*fil
|
|
|
|
|
|
|
|
ox = round((ox - 1)/3.0);
|
|
|
|
oy = round((oy - 1)/3.0);
|
|
|
|
var a : Color
|
|
|
|
var b : Color
|
|
|
|
var c : Color
|
|
|
|
var d : Color
|
|
|
|
var e : Color
|
|
|
|
var f : Color
|
|
|
|
var g : Color
|
|
|
|
var h : Color
|
|
|
|
var i : Color
|
|
|
|
if (ox == 0 || ox == sprite.get_width() - 1 ||
|
|
|
|
oy == 0 || oy == sprite.get_height() - 1):
|
|
|
|
p = aux.get_pixel(ox, oy)
|
|
|
|
else:
|
|
|
|
a = aux.get_pixel(ox-1,oy-1);
|
|
|
|
b = aux.get_pixel(ox,oy-1);
|
|
|
|
c = aux.get_pixel(ox+1,oy-1);
|
|
|
|
d = aux.get_pixel(ox-1,oy);
|
|
|
|
e = aux.get_pixel(ox,oy);
|
|
|
|
f = aux.get_pixel(ox+1,oy);
|
|
|
|
g = aux.get_pixel(ox-1,oy+1);
|
|
|
|
h = aux.get_pixel(ox,oy+1);
|
|
|
|
i = aux.get_pixel(ox+1,oy+1);
|
|
|
|
|
|
|
|
match(index):
|
|
|
|
0:
|
|
|
|
p = d if (similarColors(d,b) && !similarColors(d,h)
|
|
|
|
&& !similarColors(b,f)) else e;
|
|
|
|
1:
|
|
|
|
p = b if ((similarColors(d,b) && !similarColors(d,h) &&
|
|
|
|
!similarColors(b,f) && !similarColors(e,c)) ||
|
|
|
|
(similarColors(b,f) && !similarColors(d,b) &&
|
|
|
|
!similarColors(f,h) && !similarColors(e,a))) else e;
|
|
|
|
2:
|
|
|
|
p = f if (similarColors(b,f) && !similarColors(d,b) &&
|
|
|
|
!similarColors(f,h)) else e;
|
|
|
|
3:
|
|
|
|
p = d if ((similarColors(d,h) && !similarColors(f,h) &&
|
|
|
|
!similarColors(d,b) && !similarColors(e,a)) ||
|
|
|
|
(similarColors(d,b) && !similarColors(d,h) &&
|
|
|
|
!similarColors(b,f) && !similarColors(e,g))) else e;
|
|
|
|
4:
|
|
|
|
p = e
|
|
|
|
5:
|
|
|
|
p = f if((similarColors(b,f) && !similarColors(d,b) &&
|
|
|
|
!similarColors(f,h) && !similarColors(e,i))
|
|
|
|
|| (similarColors(f,h) && !similarColors(b,f) &&
|
|
|
|
!similarColors(d,h) && !similarColors(e,c))) else e;
|
|
|
|
6:
|
|
|
|
p = d if (similarColors(d,h) && !similarColors(f,h) &&
|
|
|
|
!similarColors(d,b)) else e;
|
|
|
|
7:
|
|
|
|
p = h if ((similarColors(f,h) && !similarColors(f,b) &&
|
|
|
|
!similarColors(d,h) && !similarColors(e,g))
|
|
|
|
|| (similarColors(d,h) && !similarColors(f,h) &&
|
|
|
|
!similarColors(d,b) && !similarColors(e,i))) else e;
|
|
|
|
8:
|
|
|
|
p = f if (similarColors(f,h) && !similarColors(f,b) &&
|
|
|
|
!similarColors(d,h)) else e;
|
|
|
|
sprite.set_pixel(x, y, p)
|
|
|
|
sprite.unlock()
|
|
|
|
aux.unlock()
|
|
|
|
|
|
|
|
|
|
|
|
func fake_rotsprite(sprite : Image, angle : float) -> void:
|
|
|
|
sprite.copy_from(scale3X(sprite))
|
|
|
|
nn_rotate(sprite,angle)
|
2020-06-01 00:11:00 +00:00
|
|
|
# warning-ignore:integer_division
|
|
|
|
# warning-ignore:integer_division
|
|
|
|
sprite.resize(sprite.get_width() / 3, sprite.get_height() / 3, 0)
|
2020-05-29 00:16:44 +00:00
|
|
|
|
|
|
|
|
|
|
|
func nn_rotate(sprite : Image, angle : float) -> void:
|
|
|
|
var aux : Image = Image.new()
|
|
|
|
aux.copy_from(sprite)
|
|
|
|
sprite.lock()
|
|
|
|
aux.lock()
|
|
|
|
var ox: int
|
|
|
|
var oy: int
|
2020-06-01 00:11:00 +00:00
|
|
|
# warning-ignore:integer_division
|
|
|
|
# warning-ignore:integer_division
|
|
|
|
var center : Vector2 = Vector2(sprite.get_width() / 2, sprite.get_height() / 2)
|
2020-05-29 00:16:44 +00:00
|
|
|
for x in range(sprite.get_width()):
|
|
|
|
for y in range(sprite.get_height()):
|
|
|
|
ox = (x - center.x)*cos(angle) + (y - center.y)*sin(angle) + center.x
|
|
|
|
oy = -(x - center.x)*sin(angle) + (y - center.y)*cos(angle) + center.y
|
|
|
|
if ox >= 0 && ox < sprite.get_width() && oy >= 0 && oy < sprite.get_height():
|
|
|
|
sprite.set_pixel(x, y, aux.get_pixel(ox, oy))
|
|
|
|
else:
|
|
|
|
sprite.set_pixel(x, y, Color(0,0,0,0))
|
|
|
|
sprite.unlock()
|
|
|
|
aux.unlock()
|
|
|
|
|
|
|
|
|
|
|
|
func similarColors(c1 : Color, c2 : Color, tol : float = 100) -> bool:
|
|
|
|
var dist = colorDistance(c1, c2)
|
|
|
|
return dist <= tol
|
|
|
|
|
|
|
|
|
|
|
|
func colorDistance(c1 : Color, c2 : Color) -> float:
|
|
|
|
return sqrt(pow((c1.r - c2.r)*255, 2) + pow((c1.g - c2.g)*255, 2)
|
|
|
|
+ pow((c1.b - c2.b)*255, 2) + pow((c1.a - c2.a)*255, 2))
|
|
|
|
|
2020-06-13 15:57:28 +00:00
|
|
|
# Image effects
|
|
|
|
|
|
|
|
func scale_image(width : int, height : int, interpolation : int) -> void:
|
|
|
|
Global.current_project.undos += 1
|
|
|
|
Global.current_project.undo_redo.create_action("Scale")
|
|
|
|
Global.current_project.undo_redo.add_do_property(Global.current_project, "size", Vector2(width, height).floor())
|
|
|
|
|
|
|
|
for f in Global.current_project.frames:
|
|
|
|
for i in range(f.cels.size() - 1, -1, -1):
|
|
|
|
var sprite := Image.new()
|
|
|
|
sprite.copy_from(f.cels[i].image)
|
|
|
|
sprite.resize(width, height, interpolation)
|
|
|
|
Global.current_project.undo_redo.add_do_property(f.cels[i].image, "data", sprite.data)
|
|
|
|
Global.current_project.undo_redo.add_undo_property(f.cels[i].image, "data", f.cels[i].image.data)
|
|
|
|
|
|
|
|
Global.current_project.undo_redo.add_undo_property(Global.current_project, "size", Global.current_project.size)
|
|
|
|
Global.current_project.undo_redo.add_undo_method(Global, "undo")
|
|
|
|
Global.current_project.undo_redo.add_do_method(Global, "redo")
|
|
|
|
Global.current_project.undo_redo.commit_action()
|
|
|
|
|
|
|
|
|
|
|
|
func crop_image(image : Image) -> void:
|
|
|
|
# Use first cel as a starting rectangle
|
|
|
|
var used_rect : Rect2 = image.get_used_rect()
|
|
|
|
|
|
|
|
for f in Global.current_project.frames:
|
|
|
|
# However, if first cel is empty, loop through all cels until we find one that isn't
|
|
|
|
for cel in f.cels:
|
|
|
|
if used_rect != Rect2(0, 0, 0, 0):
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
if cel.image.get_used_rect() != Rect2(0, 0, 0, 0):
|
|
|
|
used_rect = cel.image.get_used_rect()
|
|
|
|
|
|
|
|
# Merge all layers with content
|
|
|
|
for cel in f.cels:
|
|
|
|
if cel.image.get_used_rect() != Rect2(0, 0, 0, 0):
|
|
|
|
used_rect = used_rect.merge(cel.image.get_used_rect())
|
|
|
|
|
|
|
|
# If no layer has any content, just return
|
|
|
|
if used_rect == Rect2(0, 0, 0, 0):
|
|
|
|
return
|
|
|
|
|
|
|
|
var width := used_rect.size.x
|
|
|
|
var height := used_rect.size.y
|
|
|
|
Global.current_project.undos += 1
|
|
|
|
Global.current_project.undo_redo.create_action("Scale")
|
|
|
|
Global.current_project.undo_redo.add_do_property(Global.current_project, "size", Vector2(width, height).floor())
|
|
|
|
for f in Global.current_project.frames:
|
|
|
|
# Loop through all the layers to crop them
|
|
|
|
for j in range(Global.current_project.layers.size() - 1, -1, -1):
|
|
|
|
var sprite : Image = f.cels[j].image.get_rect(used_rect)
|
|
|
|
Global.current_project.undo_redo.add_do_property(f.cels[j].image, "data", sprite.data)
|
|
|
|
Global.current_project.undo_redo.add_undo_property(f.cels[j].image, "data", f.cels[j].image.data)
|
|
|
|
|
|
|
|
Global.current_project.undo_redo.add_undo_property(Global.current_project, "size", Global.current_project.size)
|
|
|
|
Global.current_project.undo_redo.add_undo_method(Global, "undo")
|
|
|
|
Global.current_project.undo_redo.add_do_method(Global, "redo")
|
|
|
|
Global.current_project.undo_redo.commit_action()
|
2020-06-13 17:22:25 +00:00
|
|
|
|
|
|
|
|
2020-06-24 00:21:44 +00:00
|
|
|
func resize_canvas(width : int, height : int, offset_x : int, offset_y : int) -> void:
|
2020-06-13 17:22:25 +00:00
|
|
|
Global.current_project.undos += 1
|
|
|
|
Global.current_project.undo_redo.create_action("Scale")
|
|
|
|
Global.current_project.undo_redo.add_do_property(Global.current_project, "size", Vector2(width, height).floor())
|
|
|
|
for f in Global.current_project.frames:
|
|
|
|
for c in f.cels:
|
|
|
|
var sprite := Image.new()
|
2020-06-24 00:21:44 +00:00
|
|
|
sprite.create(width, height, false, Image.FORMAT_RGBA8)
|
|
|
|
sprite.blend_rect(c.image, Rect2(Vector2.ZERO, Global.current_project.size), Vector2(offset_x, offset_y))
|
2020-06-13 17:22:25 +00:00
|
|
|
Global.current_project.undo_redo.add_do_property(c.image, "data", sprite.data)
|
|
|
|
Global.current_project.undo_redo.add_undo_property(c.image, "data", c.image.data)
|
|
|
|
|
|
|
|
Global.current_project.undo_redo.add_undo_property(Global.current_project, "size", Global.current_project.size)
|
|
|
|
Global.current_project.undo_redo.add_undo_method(Global, "undo")
|
|
|
|
Global.current_project.undo_redo.add_do_method(Global, "redo")
|
|
|
|
Global.current_project.undo_redo.commit_action()
|
2020-06-13 15:57:28 +00:00
|
|
|
|
|
|
|
|
|
|
|
func invert_image_colors(image : Image) -> void:
|
|
|
|
Global.canvas.handle_undo("Draw")
|
|
|
|
for xx in image.get_size().x:
|
|
|
|
for yy in image.get_size().y:
|
|
|
|
var px_color = image.get_pixel(xx, yy).inverted()
|
|
|
|
if px_color.a == 0:
|
|
|
|
continue
|
|
|
|
image.set_pixel(xx, yy, px_color)
|
|
|
|
Global.canvas.handle_redo("Draw")
|
|
|
|
|
|
|
|
|
|
|
|
func desaturate_image(image : Image) -> void:
|
|
|
|
Global.canvas.handle_undo("Draw")
|
|
|
|
for xx in image.get_size().x:
|
|
|
|
for yy in image.get_size().y:
|
|
|
|
var px_color = image.get_pixel(xx, yy)
|
|
|
|
if px_color.a == 0:
|
|
|
|
continue
|
|
|
|
var gray = image.get_pixel(xx, yy).v
|
|
|
|
px_color = Color(gray, gray, gray, px_color.a)
|
|
|
|
image.set_pixel(xx, yy, px_color)
|
|
|
|
Global.canvas.handle_redo("Draw")
|
|
|
|
|
|
|
|
|
|
|
|
func generate_outline(image : Image, outline_color : Color, thickness : int, diagonal : bool, inside_image : bool) -> void:
|
|
|
|
if image.is_invisible():
|
|
|
|
return
|
|
|
|
var new_image := Image.new()
|
|
|
|
new_image.copy_from(image)
|
|
|
|
new_image.lock()
|
|
|
|
|
|
|
|
Global.canvas.handle_undo("Draw")
|
|
|
|
for xx in image.get_size().x:
|
|
|
|
for yy in image.get_size().y:
|
|
|
|
var pos = Vector2(xx, yy)
|
|
|
|
var current_pixel := image.get_pixelv(pos)
|
|
|
|
if current_pixel.a == 0:
|
|
|
|
continue
|
|
|
|
|
|
|
|
for i in range(1, thickness + 1):
|
|
|
|
if inside_image:
|
|
|
|
var outline_pos : Vector2 = pos + Vector2.LEFT # Left
|
|
|
|
if outline_pos.x < 0 || image.get_pixelv(outline_pos).a == 0:
|
|
|
|
var new_pos : Vector2 = pos + Vector2.RIGHT * (i - 1)
|
|
|
|
if new_pos.x < Global.current_project.size.x:
|
|
|
|
var new_pixel = image.get_pixelv(new_pos)
|
|
|
|
if new_pixel.a > 0:
|
|
|
|
new_image.set_pixelv(new_pos, outline_color)
|
|
|
|
|
|
|
|
outline_pos = pos + Vector2.RIGHT # Right
|
|
|
|
if outline_pos.x >= Global.current_project.size.x || image.get_pixelv(outline_pos).a == 0:
|
|
|
|
var new_pos : Vector2 = pos + Vector2.LEFT * (i - 1)
|
|
|
|
if new_pos.x >= 0:
|
|
|
|
var new_pixel = image.get_pixelv(new_pos)
|
|
|
|
if new_pixel.a > 0:
|
|
|
|
new_image.set_pixelv(new_pos, outline_color)
|
|
|
|
|
|
|
|
outline_pos = pos + Vector2.UP # Up
|
|
|
|
if outline_pos.y < 0 || image.get_pixelv(outline_pos).a == 0:
|
|
|
|
var new_pos : Vector2 = pos + Vector2.DOWN * (i - 1)
|
|
|
|
if new_pos.y < Global.current_project.size.y:
|
|
|
|
var new_pixel = image.get_pixelv(new_pos)
|
|
|
|
if new_pixel.a > 0:
|
|
|
|
new_image.set_pixelv(new_pos, outline_color)
|
|
|
|
|
|
|
|
outline_pos = pos + Vector2.DOWN # Down
|
|
|
|
if outline_pos.y >= Global.current_project.size.y || image.get_pixelv(outline_pos).a == 0:
|
|
|
|
var new_pos : Vector2 = pos + Vector2.UP * (i - 1)
|
|
|
|
if new_pos.y >= 0:
|
|
|
|
var new_pixel = image.get_pixelv(new_pos)
|
|
|
|
if new_pixel.a > 0:
|
|
|
|
new_image.set_pixelv(new_pos, outline_color)
|
|
|
|
|
|
|
|
if diagonal:
|
|
|
|
outline_pos = pos + (Vector2.LEFT + Vector2.UP) # Top left
|
|
|
|
if (outline_pos.x < 0 && outline_pos.y < 0) || image.get_pixelv(outline_pos).a == 0:
|
|
|
|
var new_pos : Vector2 = pos + (Vector2.RIGHT + Vector2.DOWN) * (i - 1)
|
|
|
|
if new_pos.x < Global.current_project.size.x && new_pos.y < Global.current_project.size.y:
|
|
|
|
var new_pixel = image.get_pixelv(new_pos)
|
|
|
|
if new_pixel.a > 0:
|
|
|
|
new_image.set_pixelv(new_pos, outline_color)
|
|
|
|
|
|
|
|
outline_pos = pos + (Vector2.LEFT + Vector2.DOWN) # Bottom left
|
|
|
|
if (outline_pos.x < 0 && outline_pos.y >= Global.current_project.size.y) || image.get_pixelv(outline_pos).a == 0:
|
|
|
|
var new_pos : Vector2 = pos + (Vector2.RIGHT + Vector2.UP) * (i - 1)
|
|
|
|
if new_pos.x < Global.current_project.size.x && new_pos.y >= 0:
|
|
|
|
var new_pixel = image.get_pixelv(new_pos)
|
|
|
|
if new_pixel.a > 0:
|
|
|
|
new_image.set_pixelv(new_pos, outline_color)
|
|
|
|
|
|
|
|
outline_pos = pos + (Vector2.RIGHT + Vector2.UP) # Top right
|
|
|
|
if (outline_pos.x >= Global.current_project.size.x && outline_pos.y < 0) || image.get_pixelv(outline_pos).a == 0:
|
|
|
|
var new_pos : Vector2 = pos + (Vector2.LEFT + Vector2.DOWN) * (i - 1)
|
|
|
|
if new_pos.x >= 0 && new_pos.y < Global.current_project.size.y:
|
|
|
|
var new_pixel = image.get_pixelv(new_pos)
|
|
|
|
if new_pixel.a > 0:
|
|
|
|
new_image.set_pixelv(new_pos, outline_color)
|
|
|
|
|
|
|
|
outline_pos = pos + (Vector2.RIGHT + Vector2.DOWN) # Bottom right
|
|
|
|
if (outline_pos.x >= Global.current_project.size.x && outline_pos.y >= Global.current_project.size.y) || image.get_pixelv(outline_pos).a == 0:
|
|
|
|
var new_pos : Vector2 = pos + (Vector2.LEFT + Vector2.UP) * (i - 1)
|
|
|
|
if new_pos.x >= 0 && new_pos.y >= 0:
|
|
|
|
var new_pixel = image.get_pixelv(new_pos)
|
|
|
|
if new_pixel.a > 0:
|
|
|
|
new_image.set_pixelv(new_pos, outline_color)
|
|
|
|
|
|
|
|
else:
|
|
|
|
var new_pos : Vector2 = pos + Vector2.LEFT * i # Left
|
|
|
|
if new_pos.x >= 0:
|
|
|
|
var new_pixel = image.get_pixelv(new_pos)
|
|
|
|
if new_pixel.a == 0:
|
|
|
|
new_image.set_pixelv(new_pos, outline_color)
|
|
|
|
|
|
|
|
new_pos = pos + Vector2.RIGHT * i # Right
|
|
|
|
if new_pos.x < Global.current_project.size.x:
|
|
|
|
var new_pixel = image.get_pixelv(new_pos)
|
|
|
|
if new_pixel.a == 0:
|
|
|
|
new_image.set_pixelv(new_pos, outline_color)
|
|
|
|
|
|
|
|
new_pos = pos + Vector2.UP * i # Up
|
|
|
|
if new_pos.y >= 0:
|
|
|
|
var new_pixel = image.get_pixelv(new_pos)
|
|
|
|
if new_pixel.a == 0:
|
|
|
|
new_image.set_pixelv(new_pos, outline_color)
|
|
|
|
|
|
|
|
new_pos = pos + Vector2.DOWN * i # Down
|
|
|
|
if new_pos.y < Global.current_project.size.y:
|
|
|
|
var new_pixel = image.get_pixelv(new_pos)
|
|
|
|
if new_pixel.a == 0:
|
|
|
|
new_image.set_pixelv(new_pos, outline_color)
|
|
|
|
|
|
|
|
if diagonal:
|
|
|
|
new_pos = pos + (Vector2.LEFT + Vector2.UP) * i # Top left
|
|
|
|
if new_pos.x >= 0 && new_pos.y >= 0:
|
|
|
|
var new_pixel = image.get_pixelv(new_pos)
|
|
|
|
if new_pixel.a == 0:
|
|
|
|
new_image.set_pixelv(new_pos, outline_color)
|
|
|
|
|
|
|
|
new_pos = pos + (Vector2.LEFT + Vector2.DOWN) * i # Bottom left
|
|
|
|
if new_pos.x >= 0 && new_pos.y < Global.current_project.size.y:
|
|
|
|
var new_pixel = image.get_pixelv(new_pos)
|
|
|
|
if new_pixel.a == 0:
|
|
|
|
new_image.set_pixelv(new_pos, outline_color)
|
|
|
|
|
|
|
|
new_pos = pos + (Vector2.RIGHT + Vector2.UP) * i # Top right
|
|
|
|
if new_pos.x < Global.current_project.size.x && new_pos.y >= 0:
|
|
|
|
var new_pixel = image.get_pixelv(new_pos)
|
|
|
|
if new_pixel.a == 0:
|
|
|
|
new_image.set_pixelv(new_pos, outline_color)
|
|
|
|
|
|
|
|
new_pos = pos + (Vector2.RIGHT + Vector2.DOWN) * i # Bottom right
|
|
|
|
if new_pos.x < Global.current_project.size.x && new_pos.y < Global.current_project.size.y:
|
|
|
|
var new_pixel = image.get_pixelv(new_pos)
|
|
|
|
if new_pixel.a == 0:
|
|
|
|
new_image.set_pixelv(new_pos, outline_color)
|
|
|
|
|
|
|
|
image.copy_from(new_image)
|
|
|
|
Global.canvas.handle_redo("Draw")
|
|
|
|
|
2020-05-29 00:16:44 +00:00
|
|
|
|
2020-07-24 00:22:12 +00:00
|
|
|
func adjust_hsv(img: Image, delta_h : float, delta_s : float, delta_v : float, pixels : Array) -> void:
|
2020-05-29 00:16:44 +00:00
|
|
|
img.lock()
|
2020-07-24 00:22:12 +00:00
|
|
|
for i in pixels:
|
2020-07-23 01:39:23 +00:00
|
|
|
var c : Color = img.get_pixelv(i)
|
|
|
|
# Hue
|
|
|
|
var hue = range_lerp(c.h,0,1,-180,180)
|
|
|
|
hue = hue + delta_h
|
|
|
|
|
|
|
|
while(hue >= 180):
|
|
|
|
hue -= 360
|
|
|
|
while(hue < -180):
|
|
|
|
hue += 360
|
|
|
|
|
|
|
|
# Saturation
|
|
|
|
var sat = c.s
|
|
|
|
if delta_s > 0:
|
|
|
|
sat = range_lerp(delta_s,0,100,c.s,1)
|
|
|
|
elif delta_s < 0:
|
|
|
|
sat = range_lerp(delta_s,-100,0,0,c.s)
|
|
|
|
|
|
|
|
# Value
|
|
|
|
var val = c.v
|
|
|
|
if delta_v > 0:
|
|
|
|
val = range_lerp(delta_v,0,100,c.v,1)
|
|
|
|
elif delta_v < 0:
|
|
|
|
val = range_lerp(delta_v,-100,0,0,c.v)
|
|
|
|
|
|
|
|
c.h = range_lerp(hue,-180,180,0,1)
|
|
|
|
c.s = sat
|
|
|
|
c.v = val
|
|
|
|
img.set_pixelv(i,c)
|
2020-05-29 00:16:44 +00:00
|
|
|
|
|
|
|
img.unlock()
|
2020-07-18 14:23:36 +00:00
|
|
|
|
|
|
|
|
2020-07-18 16:01:24 +00:00
|
|
|
func generate_gradient(image : Image, colors : Array, steps := 2, direction : int = GradientDirection.TOP) -> void:
|
2020-07-18 14:23:36 +00:00
|
|
|
if colors.size() < 2:
|
|
|
|
return
|
|
|
|
|
|
|
|
var t = 1.0 / (steps - 1)
|
|
|
|
for i in range(1, steps - 1):
|
|
|
|
var color : Color
|
|
|
|
color = colors[-1].linear_interpolate(colors[0], t * i)
|
|
|
|
colors.insert(1, color)
|
|
|
|
|
|
|
|
image.lock()
|
2020-07-18 16:01:24 +00:00
|
|
|
if direction == GradientDirection.BOTTOM or direction == GradientDirection.RIGHT:
|
|
|
|
colors.invert()
|
2020-07-18 14:23:36 +00:00
|
|
|
var size := image.get_size()
|
2020-07-18 16:01:24 +00:00
|
|
|
var gradient_size
|
|
|
|
|
|
|
|
if direction == GradientDirection.TOP or direction == GradientDirection.BOTTOM:
|
|
|
|
gradient_size = size.y / steps
|
|
|
|
for i in steps:
|
|
|
|
for xx in size.x:
|
|
|
|
var start = i * gradient_size
|
|
|
|
var end = (i + 1) * gradient_size
|
|
|
|
for yy in range(start, end):
|
|
|
|
image.set_pixel(xx, yy, colors[i])
|
|
|
|
|
|
|
|
else:
|
|
|
|
gradient_size = size.x / steps
|
|
|
|
for i in steps:
|
|
|
|
for yy in size.y:
|
|
|
|
var start = i * gradient_size
|
|
|
|
var end = (i + 1) * gradient_size
|
|
|
|
for xx in range(start, end):
|
|
|
|
image.set_pixel(xx, yy, colors[i])
|