mirror of
https://github.com/Orama-Interactive/Pixelorama.git
synced 2025-02-13 01:03:07 +00:00
Add files via upload
This commit is contained in:
parent
aa1731b701
commit
bb63d10310
259
SelectionMap.gd
Normal file
259
SelectionMap.gd
Normal file
|
@ -0,0 +1,259 @@
|
|||
class_name SelectionMap
|
||||
extends Image
|
||||
|
||||
const INVERT_SHADER := preload("res://src/Shaders/Effects/Invert.gdshader")
|
||||
const OUTLINE_INLINE_SHADER := preload("res://src/Shaders/Effects/OutlineInline.gdshader")
|
||||
|
||||
|
||||
func is_pixel_selected(pixel: Vector2i, calculate_offset := true) -> bool:
|
||||
var selection_position: Vector2i = Global.canvas.selection.big_bounding_rectangle.position
|
||||
if calculate_offset:
|
||||
if selection_position.x < 0:
|
||||
pixel.x -= selection_position.x
|
||||
if selection_position.y < 0:
|
||||
pixel.y -= selection_position.y
|
||||
if pixel.x < 0 or pixel.y < 0 or pixel.x >= get_width() or pixel.y >= get_height():
|
||||
return false
|
||||
var selected: bool = get_pixelv(pixel).a > 0
|
||||
return selected
|
||||
|
||||
|
||||
func get_nearest_position(pixel: Vector2i) -> Vector2i:
|
||||
if Global.canvas.selection.flag_tilemode:
|
||||
# functions more or less the same way as the tilemode
|
||||
var size := Global.current_project.size
|
||||
var selection_rect := get_used_rect()
|
||||
var start_x := selection_rect.position.x - selection_rect.size.x
|
||||
var end_x := selection_rect.position.x + 2 * selection_rect.size.x
|
||||
var start_y := selection_rect.position.y - selection_rect.size.y
|
||||
var end_y := selection_rect.position.y + 2 * selection_rect.size.y
|
||||
for x in range(start_x, end_x, selection_rect.size.x):
|
||||
for y in range(start_y, end_y, selection_rect.size.y):
|
||||
var test_image := Image.create(size.x, size.y, false, Image.FORMAT_LA8)
|
||||
test_image.blit_rect(self, selection_rect, Vector2(x, y))
|
||||
if (
|
||||
pixel.x < 0
|
||||
or pixel.y < 0
|
||||
or pixel.x >= test_image.get_width()
|
||||
or pixel.y >= test_image.get_height()
|
||||
):
|
||||
continue
|
||||
var selected: bool = test_image.get_pixelv(pixel).a > 0
|
||||
if selected:
|
||||
var offset := Vector2i(x, y) - selection_rect.position
|
||||
return offset
|
||||
return Vector2i.ZERO
|
||||
else:
|
||||
return Vector2i.ZERO
|
||||
|
||||
|
||||
func get_point_in_tile_mode(pixel: Vector2i) -> Array[Vector2i]:
|
||||
var result: Array[Vector2i] = []
|
||||
if Global.canvas.selection.flag_tilemode:
|
||||
var selection_rect := get_used_rect()
|
||||
var start_x := selection_rect.position.x - selection_rect.size.x
|
||||
var end_x := selection_rect.position.x + 2 * selection_rect.size.x
|
||||
var start_y := selection_rect.position.y - selection_rect.size.y
|
||||
var end_y := selection_rect.position.y + 2 * selection_rect.size.y
|
||||
for x in range(start_x, end_x, selection_rect.size.x):
|
||||
for y in range(start_y, end_y, selection_rect.size.y):
|
||||
result.append(Vector2i(x, y) + pixel - selection_rect.position)
|
||||
else:
|
||||
result.append(pixel)
|
||||
return result
|
||||
|
||||
|
||||
func get_canon_position(position: Vector2i) -> Vector2i:
|
||||
if Global.canvas.selection.flag_tilemode:
|
||||
return position - get_nearest_position(position)
|
||||
else:
|
||||
return position
|
||||
|
||||
|
||||
func select_pixel(pixel: Vector2i, select := true) -> void:
|
||||
if select:
|
||||
set_pixelv(pixel, Color(1, 1, 1, 1))
|
||||
else:
|
||||
set_pixelv(pixel, Color(0))
|
||||
|
||||
|
||||
func select_all() -> void:
|
||||
fill(Color(1, 1, 1, 1))
|
||||
|
||||
|
||||
func clear() -> void:
|
||||
fill(Color(0))
|
||||
|
||||
|
||||
func invert() -> void:
|
||||
var params := {"red": true, "green": true, "blue": true, "alpha": true}
|
||||
var gen := ShaderImageEffect.new()
|
||||
gen.generate_image(self, INVERT_SHADER, params, get_size())
|
||||
|
||||
|
||||
## Returns a copy of itself that is cropped to [param size].
|
||||
## Used for when the selection map is bigger than the [Project] size.
|
||||
func return_cropped_copy(size: Vector2i) -> SelectionMap:
|
||||
var selection_map_copy := SelectionMap.new()
|
||||
selection_map_copy.copy_from(self)
|
||||
var diff := Vector2i.ZERO
|
||||
var selection_position: Vector2i = Global.canvas.selection.big_bounding_rectangle.position
|
||||
if selection_position.x < 0:
|
||||
diff.x += selection_position.x
|
||||
if selection_position.y < 0:
|
||||
diff.y += selection_position.y
|
||||
if diff != Vector2i.ZERO:
|
||||
# If there are pixels out of bounds on the negative side (left & up),
|
||||
# move them before resizing
|
||||
selection_map_copy.fill(Color(0))
|
||||
selection_map_copy.blit_rect(self, Rect2i(Vector2i.ZERO, get_size()), diff)
|
||||
selection_map_copy.crop(size.x, size.y)
|
||||
return selection_map_copy
|
||||
|
||||
|
||||
func move_bitmap_values(project: Project, move_offset := true) -> void:
|
||||
var size := project.size
|
||||
var selection_node = Global.canvas.selection
|
||||
var selection_position: Vector2i = selection_node.big_bounding_rectangle.position
|
||||
var selection_end: Vector2i = selection_node.big_bounding_rectangle.end
|
||||
|
||||
var selection_rect := get_used_rect()
|
||||
var smaller_image := get_region(selection_rect)
|
||||
clear()
|
||||
var dst := selection_position
|
||||
var x_diff := selection_end.x - size.x
|
||||
var y_diff := selection_end.y - size.y
|
||||
var nw := maxi(size.x, size.x + x_diff)
|
||||
var nh := maxi(size.y, size.y + y_diff)
|
||||
|
||||
if selection_position.x < 0:
|
||||
nw -= selection_position.x
|
||||
if move_offset:
|
||||
project.selection_offset.x = selection_position.x
|
||||
dst.x = 0
|
||||
else:
|
||||
if move_offset:
|
||||
project.selection_offset.x = 0
|
||||
if selection_position.y < 0:
|
||||
nh -= selection_position.y
|
||||
if move_offset:
|
||||
project.selection_offset.y = selection_position.y
|
||||
dst.y = 0
|
||||
else:
|
||||
if move_offset:
|
||||
project.selection_offset.y = 0
|
||||
|
||||
if nw <= size.x:
|
||||
nw = size.x
|
||||
if nh <= size.y:
|
||||
nh = size.y
|
||||
|
||||
crop(nw, nh)
|
||||
blit_rect(smaller_image, Rect2i(Vector2i.ZERO, Vector2i(nw, nh)), dst)
|
||||
|
||||
|
||||
func resize_bitmap_values(
|
||||
project: Project, new_size: Vector2i, flip_hor: bool, flip_ver: bool
|
||||
) -> void:
|
||||
var size := project.size
|
||||
var selection_node: Node2D = Global.canvas.selection
|
||||
var selection_position: Vector2i = selection_node.big_bounding_rectangle.position
|
||||
var dst := selection_position
|
||||
var new_bitmap_size := size
|
||||
new_bitmap_size.x = maxi(size.x, absi(selection_position.x) + new_size.x)
|
||||
new_bitmap_size.y = maxi(size.y, absi(selection_position.y) + new_size.y)
|
||||
var selection_rect := get_used_rect()
|
||||
var smaller_image := get_region(selection_rect)
|
||||
if selection_position.x <= 0:
|
||||
project.selection_offset.x = selection_position.x
|
||||
dst.x = 0
|
||||
else:
|
||||
project.selection_offset.x = 0
|
||||
if selection_position.y <= 0:
|
||||
project.selection_offset.y = selection_position.y
|
||||
dst.y = 0
|
||||
else:
|
||||
project.selection_offset.y = 0
|
||||
clear()
|
||||
|
||||
var is_ellipse_select := true
|
||||
var w := smaller_image.get_width()
|
||||
var h := smaller_image.get_height()
|
||||
var ellipse_select := DrawingAlgos.get_ellipse_points(Vector2.ZERO, Vector2i(w,h))
|
||||
var x_min := []
|
||||
var x_max := []
|
||||
x_min.resize(h)
|
||||
x_max.resize(h)
|
||||
# Determine x_min and x_max of y
|
||||
for i in ellipse_select.size()/2:
|
||||
i*=2
|
||||
var y := ellipse_select[i].y
|
||||
var xmin := ellipse_select[i].x if ellipse_select[i].x < ellipse_select[i+1].x else ellipse_select[i+1].x
|
||||
var xmax := ellipse_select[i].x if ellipse_select[i].x >= ellipse_select[i+1].x else ellipse_select[i+1].x
|
||||
|
||||
if x_min[y] == null && x_max[y] == null:
|
||||
x_min[y] = xmin
|
||||
x_max[y] = xmax
|
||||
else:
|
||||
if x_min[y] != null && x_min[y] > xmin:
|
||||
x_min[y] = xmin
|
||||
if x_max[y] != null && x_max[y] < xmax:
|
||||
x_max[y] = xmax
|
||||
# Determine whether the selection is an ellipse selection
|
||||
for y in range(h):
|
||||
if !is_ellipse_select:
|
||||
break
|
||||
for x in range(w):
|
||||
if smaller_image.get_pixel(x,y) == Color(1,1,1,1) && (x < x_min[y] || x > x_max[y]):
|
||||
is_ellipse_select = false
|
||||
break
|
||||
# if selection is an ellipse selection, resized as standard ellipse
|
||||
if !is_ellipse_select:
|
||||
smaller_image.resize(new_size.x, new_size.y, Image.INTERPOLATE_BILINEAR)
|
||||
else:
|
||||
var resized_img := Image.create(new_size.x, new_size.y, false, smaller_image.get_format())
|
||||
var new_ellipse_select := DrawingAlgos.get_ellipse_points_filled(Vector2.ZERO, Vector2i(new_size.x,new_size.y))
|
||||
for p in new_ellipse_select:
|
||||
resized_img.set_pixel(p.x, p.y, Color(1, 1, 1, 1))
|
||||
smaller_image = resized_img
|
||||
|
||||
if flip_hor:
|
||||
smaller_image.flip_x()
|
||||
if flip_ver:
|
||||
smaller_image.flip_y()
|
||||
if new_bitmap_size != size:
|
||||
crop(new_bitmap_size.x, new_bitmap_size.y)
|
||||
blit_rect(smaller_image, Rect2i(Vector2i.ZERO, new_bitmap_size), dst)
|
||||
|
||||
|
||||
func expand(width: int, brush: int) -> void:
|
||||
var params := {
|
||||
"color": Color(1, 1, 1, 1),
|
||||
"width": width,
|
||||
"brush": brush,
|
||||
}
|
||||
var gen := ShaderImageEffect.new()
|
||||
gen.generate_image(self, OUTLINE_INLINE_SHADER, params, get_size())
|
||||
|
||||
|
||||
func shrink(width: int, brush: int) -> void:
|
||||
var params := {
|
||||
"color": Color(0),
|
||||
"width": width,
|
||||
"brush": brush,
|
||||
"inside": true,
|
||||
}
|
||||
var gen := ShaderImageEffect.new()
|
||||
gen.generate_image(self, OUTLINE_INLINE_SHADER, params, get_size())
|
||||
|
||||
|
||||
func border(width: int, brush: int) -> void:
|
||||
var params := {
|
||||
"color": Color(1, 1, 1, 1),
|
||||
"width": width,
|
||||
"brush": brush,
|
||||
"inside": true,
|
||||
"keep_border_only": true,
|
||||
}
|
||||
var gen := ShaderImageEffect.new()
|
||||
gen.generate_image(self, OUTLINE_INLINE_SHADER, params, get_size())
|
Loading…
Reference in a new issue