Добавил персонажа и движение на курсор
This commit is contained in:
38
addons/sprite_painter/image_scripts/Adjust HSV.gd
Normal file
38
addons/sprite_painter/image_scripts/Adjust HSV.gd
Normal file
@@ -0,0 +1,38 @@
|
||||
extends ImageScript
|
||||
|
||||
|
||||
func _get_param_list():
|
||||
return [
|
||||
[
|
||||
"Hue",
|
||||
SCRIPT_PARAM_INT,
|
||||
0,
|
||||
[0, 360]
|
||||
],
|
||||
[
|
||||
"Saturation",
|
||||
SCRIPT_PARAM_INT,
|
||||
0,
|
||||
[-100, +100]
|
||||
],
|
||||
[
|
||||
"Value",
|
||||
SCRIPT_PARAM_INT,
|
||||
0,
|
||||
[-100, +100]
|
||||
],
|
||||
]
|
||||
|
||||
|
||||
func _get_image(new_image, selection):
|
||||
var pix : Color
|
||||
for i in new_image.get_width():
|
||||
for j in new_image.get_width():
|
||||
if !selection.get_bit(i, j): continue
|
||||
pix = new_image.get_pixel(i, j)
|
||||
pix.h += get_param("Hue") / 360.0
|
||||
pix.s *= 1.0 + get_param("Saturation") * 0.01
|
||||
pix.v *= 1.0 + get_param("Value") * 0.01
|
||||
new_image.set_pixel(i, j, pix)
|
||||
|
||||
return new_image
|
||||
52
addons/sprite_painter/image_scripts/Channel Curves.gd
Normal file
52
addons/sprite_painter/image_scripts/Channel Curves.gd
Normal file
@@ -0,0 +1,52 @@
|
||||
extends ImageScript
|
||||
|
||||
|
||||
func _get_param_list():
|
||||
var default_curve = Curve.new()
|
||||
default_curve.add_point(Vector2.ZERO, 1, 1)
|
||||
default_curve.add_point(Vector2.ONE, 1, 1)
|
||||
return [
|
||||
[
|
||||
"Red",
|
||||
SCRIPT_PARAM_RESOURCE,
|
||||
default_curve.duplicate(),
|
||||
"Curve",
|
||||
],
|
||||
[
|
||||
"Green",
|
||||
SCRIPT_PARAM_RESOURCE,
|
||||
default_curve.duplicate(),
|
||||
"Curve",
|
||||
],
|
||||
[
|
||||
"Blue",
|
||||
SCRIPT_PARAM_RESOURCE,
|
||||
default_curve.duplicate(),
|
||||
"Curve",
|
||||
],
|
||||
[
|
||||
"Alpha",
|
||||
SCRIPT_PARAM_RESOURCE,
|
||||
default_curve.duplicate(),
|
||||
"Curve",
|
||||
],
|
||||
]
|
||||
|
||||
|
||||
func _get_image(new_image, selection):
|
||||
var r_curve = get_param("Red")
|
||||
var g_curve = get_param("Green")
|
||||
var b_curve = get_param("Blue")
|
||||
var a_curve = get_param("Alpha")
|
||||
var pix : Color
|
||||
for i in new_image.get_width():
|
||||
for j in new_image.get_width():
|
||||
if !selection.get_bit(i, j): continue
|
||||
pix = new_image.get_pixel(i, j)
|
||||
pix.r = r_curve.sample(pix.r)
|
||||
pix.g = g_curve.sample(pix.g)
|
||||
pix.b = b_curve.sample(pix.b)
|
||||
pix.a = a_curve.sample(pix.a)
|
||||
new_image.set_pixel(i, j, pix)
|
||||
|
||||
return new_image
|
||||
68
addons/sprite_painter/image_scripts/Constrain to Palette.gd
Normal file
68
addons/sprite_painter/image_scripts/Constrain to Palette.gd
Normal file
@@ -0,0 +1,68 @@
|
||||
extends ImageScript
|
||||
|
||||
|
||||
func _get_param_list():
|
||||
return [
|
||||
[
|
||||
"Palette Texture",
|
||||
SCRIPT_PARAM_RESOURCE,
|
||||
# Does not work well on gradients: doesn't consider Interp Mode and Width
|
||||
# so with no proper spatial partitioning takes an eternity
|
||||
# GradientTexture1D.new(),
|
||||
null,
|
||||
"Texture2D"
|
||||
],
|
||||
]
|
||||
|
||||
|
||||
func _get_image(new_image, selection):
|
||||
if get_param("Palette Texture") == null:
|
||||
return new_image
|
||||
|
||||
var palette_img = get_param("Palette Texture").get_image()
|
||||
if palette_img == null:
|
||||
return new_image
|
||||
|
||||
var palette = {}
|
||||
var pix : Color
|
||||
for i in palette_img.get_width():
|
||||
for j in palette_img.get_height():
|
||||
pix = palette_img.get_pixel(i, j)
|
||||
if pix.a > 0.01:
|
||||
palette[Color(pix, 1.0)] = true
|
||||
|
||||
var image_width = new_image.get_width()
|
||||
var image_color_mapping = {}
|
||||
var nearest_color : Color
|
||||
for i in new_image.get_width():
|
||||
for j in new_image.get_height():
|
||||
pix = new_image.get_pixel(i, j)
|
||||
if image_color_mapping.has(pix):
|
||||
if selection.get_bit(i, j):
|
||||
new_image.set_pixel(i, j, Color(image_color_mapping[pix], pix.a))
|
||||
|
||||
elif selection.get_bit(i, j):
|
||||
# I'll rewrite this into a proper spatial algo access later,
|
||||
# bruteforce will do for now
|
||||
nearest_color = Color(pick_nearest(pix, palette), 1.0)
|
||||
image_color_mapping[Color(pix, 1.0)] = nearest_color
|
||||
new_image.set_pixel(i, j, Color(nearest_color, pix.a))
|
||||
|
||||
return new_image
|
||||
|
||||
|
||||
func pick_nearest(to : Color, from : Dictionary):
|
||||
var nearest_dist := INF
|
||||
var nearest : Color
|
||||
var cur_dist : float
|
||||
for x in from:
|
||||
cur_dist = (
|
||||
(x.r - to.r) * (x.r - to.r)
|
||||
+ (x.g - to.g) * (x.g - to.g)
|
||||
+ (x.b - to.b) * (x.b - to.b)
|
||||
)
|
||||
if cur_dist < nearest_dist:
|
||||
nearest = x
|
||||
nearest_dist = cur_dist
|
||||
|
||||
return nearest
|
||||
87
addons/sprite_painter/image_scripts/Outline.gd
Normal file
87
addons/sprite_painter/image_scripts/Outline.gd
Normal file
@@ -0,0 +1,87 @@
|
||||
extends ImageScript
|
||||
|
||||
var sample_modes = [
|
||||
[Vector2(0, 1), Vector2(1, 0), Vector2(-1, 0), Vector2(0, -1)],
|
||||
range(8).map(func(i):return Vector2(cos(i * PI * 0.25), sin(i * PI * 0.25))),
|
||||
range(16).map(func(i):return Vector2(cos(i * PI * 0.125), sin(i * PI * 0.125))),
|
||||
# The following modes sample two rings around the pixel,
|
||||
# resulting in a more precise thick outline around thin objects
|
||||
range(16).map(func(i):return ceil((i + 1) * 0.125) * 0.5 * Vector2(cos(i * PI * 0.25), sin(i * PI * 0.25))),
|
||||
range(32).map(func(i):return ceil((i + 1) * 0.0625) * 0.5 * Vector2(cos(i * PI * 0.125), sin(i * PI * 0.125))),
|
||||
]
|
||||
|
||||
|
||||
func _get_param_list():
|
||||
return [
|
||||
[
|
||||
"Width",
|
||||
SCRIPT_PARAM_INT,
|
||||
1,
|
||||
[1, 150]
|
||||
],
|
||||
[
|
||||
"Color",
|
||||
SCRIPT_PARAM_COLOR,
|
||||
Color.BLACK
|
||||
],
|
||||
[
|
||||
"Samples",
|
||||
SCRIPT_PARAM_ENUM,
|
||||
0,
|
||||
["4 (Naive)", "8", "16", "4+4 (Wide Line)", "8+8 (Wide Line Ultra)"]
|
||||
],
|
||||
[
|
||||
"Mode",
|
||||
SCRIPT_PARAM_ENUM,
|
||||
0,
|
||||
["Outline + Image", "Just Outline"]
|
||||
],
|
||||
]
|
||||
|
||||
|
||||
func _get_image(new_image, selection):
|
||||
var line_color = get_param("Color")
|
||||
var width = get_param("Width")
|
||||
var line_only = get_param("Mode") == 1
|
||||
var samples = sample_modes[get_param("Samples")]
|
||||
var image_size = new_image.get_size()
|
||||
var new_new_image = Image.create_from_data(
|
||||
image_size.x,
|
||||
image_size.y,
|
||||
false,
|
||||
new_image.get_format(),
|
||||
new_image.get_data()
|
||||
)
|
||||
var pix : Color
|
||||
var pix_outline_alpha := 0.0
|
||||
for i in new_image.get_width():
|
||||
for j in new_image.get_height():
|
||||
if !selection.get_bit(i, j): continue
|
||||
pix = new_image.get_pixel(i, j)
|
||||
if pix.a == 1.0:
|
||||
if line_only:
|
||||
new_new_image.set_pixel(i, j, Color.TRANSPARENT)
|
||||
|
||||
continue
|
||||
|
||||
pix_outline_alpha = 0.0
|
||||
for x in samples:
|
||||
if pix_outline_alpha >= line_color.a: break
|
||||
if ImageFillTools.is_out_of_bounds(Vector2(i, j) + x * width, image_size):
|
||||
continue
|
||||
|
||||
pix_outline_alpha = max(pix_outline_alpha, min(
|
||||
line_color.a,
|
||||
new_image.get_pixelv(Vector2(i, j) + x * width).a
|
||||
))
|
||||
|
||||
if pix_outline_alpha > 0.0:
|
||||
if line_only:
|
||||
pix = Color(line_color, pix_outline_alpha)
|
||||
|
||||
else:
|
||||
pix = Color(line_color, pix_outline_alpha).blend(pix)
|
||||
|
||||
new_new_image.set_pixel(i, j, pix)
|
||||
|
||||
return new_new_image
|
||||
@@ -0,0 +1,140 @@
|
||||
extends ImageScript
|
||||
|
||||
const ROOT2DIV2 = 0.7071
|
||||
|
||||
|
||||
func _get_param_list():
|
||||
var default_curve = Curve.new()
|
||||
default_curve.add_point(Vector2(0.0, 0.5), 1, 1, Curve.TANGENT_LINEAR, Curve.TANGENT_LINEAR)
|
||||
default_curve.add_point(Vector2(1.0, 0.5), 1, 1, Curve.TANGENT_LINEAR, Curve.TANGENT_LINEAR)
|
||||
return [
|
||||
[
|
||||
"Bevel",
|
||||
SCRIPT_PARAM_INT,
|
||||
1,
|
||||
[1, 150]
|
||||
],
|
||||
[
|
||||
"Bevel Distance",
|
||||
SCRIPT_PARAM_ENUM,
|
||||
0,
|
||||
["Circle", "Square", "Diamond"]
|
||||
],
|
||||
]
|
||||
|
||||
|
||||
func _get_image(new_image, selection):
|
||||
var image_size : Vector2i = new_image.get_size()
|
||||
var closest_edge : Array[Vector2] = []
|
||||
var entropy := {}
|
||||
closest_edge.resize(image_size.x * image_size.y)
|
||||
|
||||
var pix : Color
|
||||
var vec : Vector2
|
||||
for i in image_size.x:
|
||||
for j in image_size.y:
|
||||
pix = new_image.get_pixel(i, j)
|
||||
if pix.a == 0.0:
|
||||
closest_edge[i + j * image_size.x] = Vector2.ZERO
|
||||
|
||||
else:
|
||||
vec = Vector2(0, 0)
|
||||
if i == 0: vec.x -= 1
|
||||
if j == 0: vec.y -= 1
|
||||
if i == image_size.x - 1: vec.x += 1
|
||||
if j == image_size.y - 1: vec.y += 1
|
||||
|
||||
if vec == Vector2.ZERO:
|
||||
vec = Vector2(-INF, -INF)
|
||||
entropy[Vector2(i, j)] = 5
|
||||
|
||||
closest_edge[i + j * image_size.x] = vec
|
||||
|
||||
var neighbors = []
|
||||
var neighbor_pos = []
|
||||
var iters = 0
|
||||
var closest_edge_new : Array[Vector2]
|
||||
while entropy.size() > 0:
|
||||
iters += 1
|
||||
closest_edge_new = closest_edge.duplicate()
|
||||
for pos in entropy.keys():
|
||||
neighbor_pos = [
|
||||
pos + Vector2.RIGHT,
|
||||
pos + Vector2.DOWN,
|
||||
pos + Vector2.LEFT,
|
||||
pos + Vector2.UP,
|
||||
]
|
||||
var any_neighbor_defined = false
|
||||
for x in neighbor_pos:
|
||||
if closest_edge[x.x + x.y * image_size.x] != Vector2(-INF, -INF):
|
||||
any_neighbor_defined = true
|
||||
break
|
||||
|
||||
if any_neighbor_defined:
|
||||
entropy.erase(pos)
|
||||
|
||||
neighbors = [
|
||||
closest_edge[pos.x + 1 + pos.y * image_size.x]
|
||||
if !entropy.has(pos + Vector2.RIGHT) else Vector2(-INF, -INF),
|
||||
closest_edge[pos.x + (pos.y + 1) * image_size.x]
|
||||
if !entropy.has(pos + Vector2.DOWN) else Vector2(-INF, -INF),
|
||||
closest_edge[pos.x - 1 + pos.y * image_size.x]
|
||||
if !entropy.has(pos + Vector2.LEFT) else Vector2(-INF, -INF),
|
||||
closest_edge[pos.x + (pos.y - 1) * image_size.x]
|
||||
if !entropy.has(pos + Vector2.UP) else Vector2(-INF, -INF),
|
||||
]
|
||||
closest_edge_new[pos.x + pos.y * image_size.x] = get_closest_edge(neighbors)
|
||||
|
||||
closest_edge = closest_edge_new
|
||||
|
||||
var bevel = get_param("Bevel")
|
||||
var dist_func = [
|
||||
# Three different distance calculations have their own artifacts..
|
||||
func (x): return x.length_squared() > bevel * 2.0, # Circle
|
||||
func (x): return max(abs(x.x), abs(x.y)) > bevel, # Square
|
||||
func (x): return abs(x.x) + abs(x.y) > bevel * 2.0, # Diamond
|
||||
][get_param("Bevel Distance")]
|
||||
|
||||
var vec3 : Vector3
|
||||
var vec_len : float
|
||||
var vec_dir : Vector2
|
||||
for i in image_size.x:
|
||||
for j in image_size.y:
|
||||
vec = closest_edge[i + j * image_size.x]
|
||||
if vec == Vector2.ZERO || dist_func.call(vec):
|
||||
new_image.set_pixel(i, j, Color(0.5, 0.5, 1.0))
|
||||
continue
|
||||
|
||||
vec_len = vec.length()
|
||||
vec_dir = vec / vec_len
|
||||
vec3 = Vector3.BACK.rotated(
|
||||
Vector3(-vec_dir.y, vec_dir.x, 0.0),
|
||||
PI * 0.25
|
||||
)
|
||||
vec3 = vec3 * Vector3(0.5, -0.5, 1.0) + Vector3(0.5, 0.5, 0.0)
|
||||
|
||||
new_image.set_pixel(i, j, Color(vec3.x, vec3.y, vec3.z))
|
||||
|
||||
return new_image
|
||||
|
||||
|
||||
func get_closest_edge(neighbor_vecs):
|
||||
var lengths = [
|
||||
neighbor_vecs[0].length_squared(),
|
||||
neighbor_vecs[1].length_squared(),
|
||||
neighbor_vecs[2].length_squared(),
|
||||
neighbor_vecs[3].length_squared(),
|
||||
]
|
||||
var closest_length = INF
|
||||
for i in 4:
|
||||
if lengths[i] < closest_length:
|
||||
closest_length = lengths[i]
|
||||
|
||||
var result = Vector2.ZERO
|
||||
var neighbor_dirs = [Vector2.RIGHT, Vector2.DOWN, Vector2.LEFT, Vector2.UP]
|
||||
var coeff = 1.0
|
||||
for i in 4:
|
||||
if lengths[i] == closest_length:
|
||||
result += neighbor_vecs[i] + neighbor_dirs[i]
|
||||
|
||||
return result
|
||||
Reference in New Issue
Block a user