1
0
Fork 0
mirror of https://github.com/Orama-Interactive/Pixelorama.git synced 2025-02-20 12:33:14 +00:00

Refactor the selection system to use an Image instead of a BitMap (#710)

* Use Image instead of BitMap for selection

Not complete and Pixelorama is currently broken

* Add a SelectionMap class

* Make the changes in Selection.gd

* Remove selection_bitmap

* Replace duplicate() with copy_from()

* Fix selection

Intersection and transforming are not working

* Fix wrong pixel color values

* Fix selection transforming

* Call selection_bitmap_changed() on scale

* Fix clipboard

* Remove bitmap_to_image()

* Rename selection_image to selection_map

* No errors in Magic Wand

* Rename selection_bitmap_changed() to selection_map_changed()

* Format

* Fix selection resizing

* Remove a line from image effects

* Fast selection inverting using shader

* Update SelectionMap.gd

* Format

* Convert SelectionMap back to LA8 after inverting

* Minor refactor in RectSelect.gd

* Fix intersections

* Use shader for ColorSelect and add color similarity option

* Update RotateImage.gd
This commit is contained in:
Emmanouil Papadeas 2022-08-08 03:03:17 +03:00 committed by GitHub
parent b4a5bf4dd0
commit 41ccc704c2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 478 additions and 423 deletions

View file

@ -104,6 +104,11 @@ _global_script_classes=[ {
"language": "GDScript",
"path": "res://src/Classes/Project.gd"
}, {
"base": "Image",
"class": "SelectionMap",
"language": "GDScript",
"path": "res://src/Classes/SelectionMap.gd"
}, {
"base": "BaseTool",
"class": "SelectionTool",
"language": "GDScript",
@ -149,6 +154,7 @@ _global_script_class_icons={
"PaletteSwatch": "",
"Patterns": "",
"Project": "",
"SelectionMap": "",
"SelectionTool": "",
"ShaderImageEffect": "",
"ShortcutProfile": "",

View file

@ -426,8 +426,9 @@ func general_do_scale(width: int, height: int) -> void:
var x_ratio = project.size.x / width
var y_ratio = project.size.y / height
var bitmap: BitMap
bitmap = project.resize_bitmap(project.selection_bitmap, size)
var selection_map_copy := SelectionMap.new()
selection_map_copy.copy_from(project.selection_map)
selection_map_copy.crop(size.x, size.y)
var new_x_symmetry_point = project.x_symmetry_point / x_ratio
var new_y_symmetry_point = project.y_symmetry_point / y_ratio
@ -441,7 +442,7 @@ func general_do_scale(width: int, height: int) -> void:
project.undos += 1
project.undo_redo.create_action("Scale")
project.undo_redo.add_do_property(project, "size", size)
project.undo_redo.add_do_property(project, "selection_bitmap", bitmap)
project.undo_redo.add_do_property(project, "selection_map", selection_map_copy)
project.undo_redo.add_do_property(project, "x_symmetry_point", new_x_symmetry_point)
project.undo_redo.add_do_property(project, "y_symmetry_point", new_y_symmetry_point)
project.undo_redo.add_do_property(project.x_symmetry_axis, "points", new_x_symmetry_axis_points)
@ -451,7 +452,7 @@ func general_do_scale(width: int, height: int) -> void:
func general_undo_scale() -> void:
var project: Project = Global.current_project
project.undo_redo.add_undo_property(project, "size", project.size)
project.undo_redo.add_undo_property(project, "selection_bitmap", project.selection_bitmap)
project.undo_redo.add_undo_property(project, "selection_map", project.selection_map)
project.undo_redo.add_undo_property(project, "x_symmetry_point", project.x_symmetry_point)
project.undo_redo.add_undo_property(project, "y_symmetry_point", project.y_symmetry_point)
project.undo_redo.add_undo_property(

View file

@ -452,6 +452,7 @@ func undo_or_redo(
canvas.camera_zoom()
canvas.grid.update()
canvas.pixel_grid.update()
project.selection_map_changed()
cursor_position_label.text = "[%s×%s]" % [project.size.x, project.size.y]
elif "Frame" in action_name:

View file

@ -144,7 +144,7 @@ func _create_new_palette_from_current_selection(
for x in current_project.size.x:
for y in current_project.size.y:
var pos := Vector2(x, y)
if current_project.selection_bitmap.get_bit(pos):
if current_project.selection_map.is_pixel_selected(pos):
pixels.append(pos)
_fill_new_palette_with_colors(pixels, new_palette, add_alpha_colors, get_colors_from)

View file

@ -25,7 +25,7 @@ var y_symmetry_point
var x_symmetry_axis := SymmetryGuide.new()
var y_symmetry_axis := SymmetryGuide.new()
var selection_bitmap := BitMap.new()
var selection_map := SelectionMap.new()
# This is useful for when the selection is outside of the canvas boundaries,
# on the left and/or above (negative coords)
var selection_offset := Vector2.ZERO setget _selection_offset_changed
@ -55,7 +55,7 @@ func _init(_frames := [], _name := tr("untitled"), _size := Vector2(64, 64)) ->
name = _name
size = _size
tiles = Tiles.new(size)
selection_bitmap.create(size)
selection_map.create(size.x, size.y, false, Image.FORMAT_LA8)
Global.tabs.add_tab(name)
OpenSave.current_save_paths.append("")
@ -118,13 +118,11 @@ func new_empty_frame() -> Frame:
return frame
func selection_bitmap_changed() -> void:
var image := Image.new()
func selection_map_changed() -> void:
var image_texture := ImageTexture.new()
has_selection = selection_bitmap.get_true_bit_count() > 0
has_selection = !selection_map.is_invisible()
if has_selection:
image = bitmap_to_image(selection_bitmap)
image_texture.create_from_image(image, 0)
image_texture.create_from_image(selection_map, 0)
Global.canvas.selection.marching_ants_outline.texture = image_texture
Global.top_menu_container.edit_menu_button.get_popup().set_item_disabled(6, !has_selection)
@ -261,8 +259,8 @@ func change_project() -> void:
# Change selection effect & bounding rectangle
Global.canvas.selection.marching_ants_outline.offset = selection_offset
selection_bitmap_changed()
Global.canvas.selection.big_bounding_rectangle = get_selection_rectangle()
selection_map_changed()
Global.canvas.selection.big_bounding_rectangle = selection_map.get_used_rect()
Global.canvas.selection.big_bounding_rectangle.position += selection_offset
Global.canvas.selection.update()
Global.top_menu_container.edit_menu_button.get_popup().set_item_disabled(6, !has_selection)
@ -388,7 +386,7 @@ func deserialize(dict: Dictionary) -> void:
size.x = dict.size_x
size.y = dict.size_y
tiles.tile_size = size
selection_bitmap = resize_bitmap(selection_bitmap, size)
selection_map.crop(size.x, size.y)
if dict.has("has_mask"):
tiles.has_mask = dict.has_mask
if dict.has("tile_mode_x_basis_x") and dict.has("tile_mode_x_basis_y"):
@ -763,7 +761,7 @@ func duplicate_layers() -> Array:
func can_pixel_get_drawn(
pixel: Vector2,
bitmap: BitMap = selection_bitmap,
image: SelectionMap = selection_map,
selection_position: Vector2 = Global.canvas.selection.big_bounding_rectangle.position
) -> bool:
if pixel.x < 0 or pixel.y < 0 or pixel.x >= size.x or pixel.y >= size.y:
@ -777,152 +775,6 @@ func can_pixel_get_drawn(
pixel.x -= selection_position.x
if selection_position.y < 0:
pixel.y -= selection_position.y
return bitmap.get_bit(pixel)
return image.is_pixel_selected(pixel)
else:
return true
func invert_bitmap(bitmap: BitMap) -> void:
for x in bitmap.get_size().x:
for y in bitmap.get_size().y:
var pos := Vector2(x, y)
bitmap.set_bit(pos, !bitmap.get_bit(pos))
# Unexposed BitMap class function
# https://github.com/godotengine/godot/blob/master/scene/resources/bit_map.cpp#L605
func resize_bitmap(bitmap: BitMap, new_size: Vector2) -> BitMap:
if new_size == bitmap.get_size():
return bitmap
var new_bitmap := BitMap.new()
new_bitmap.create(new_size)
var lw = min(bitmap.get_size().x, new_size.x)
var lh = min(bitmap.get_size().y, new_size.y)
for x in lw:
for y in lh:
new_bitmap.set_bit(Vector2(x, y), bitmap.get_bit(Vector2(x, y)))
return new_bitmap
# Unexposed BitMap class function
# https://github.com/godotengine/godot/blob/master/scene/resources/bit_map.cpp#L622
func bitmap_to_image(bitmap: BitMap) -> Image:
var image := Image.new()
var width := bitmap.get_size().x
var height := bitmap.get_size().y
image.create(width, height, false, Image.FORMAT_LA8)
image.lock()
for x in width:
for y in height:
var pos := Vector2(x, y)
var color = Color(1, 1, 1, 1) if bitmap.get_bit(pos) else Color(0, 0, 0, 0)
image.set_pixelv(pos, color)
image.unlock()
return image
# Algorithm taken from Image.get_used_rect()
# https://github.com/godotengine/godot/blob/master/core/io/image.cpp
func get_selection_rectangle(bitmap: BitMap = selection_bitmap) -> Rect2:
if bitmap.get_true_bit_count() == 0:
return Rect2()
var minx := 0xFFFFFF
var miny := 0xFFFFFF
var maxx := -1
var maxy := -1
for j in bitmap.get_size().y:
for i in bitmap.get_size().x:
if !bitmap.get_bit(Vector2(i, j)):
continue
if i > maxx:
maxx = i
if j > maxy:
maxy = j
if i < minx:
minx = i
if j < miny:
miny = j
if maxx == -1:
return Rect2()
else:
return Rect2(minx, miny, maxx - minx + 1, maxy - miny + 1)
func move_bitmap_values(bitmap: BitMap, move_offset := true) -> void:
var selection_node = Global.canvas.selection
var selection_position: Vector2 = selection_node.big_bounding_rectangle.position
var selection_end: Vector2 = selection_node.big_bounding_rectangle.end
var image: Image = bitmap_to_image(bitmap)
var selection_rect := image.get_used_rect()
var smaller_image := image.get_rect(selection_rect)
image.fill(Color(0))
var dst := selection_position
var x_diff = selection_end.x - size.x
var y_diff = selection_end.y - size.y
var nw = max(size.x, size.x + x_diff)
var nh = max(size.y, size.y + y_diff)
if selection_position.x < 0:
nw -= selection_position.x
if move_offset:
self.selection_offset.x = selection_position.x
dst.x = 0
else:
if move_offset:
self.selection_offset.x = 0
if selection_position.y < 0:
nh -= selection_position.y
if move_offset:
self.selection_offset.y = selection_position.y
dst.y = 0
else:
if move_offset:
self.selection_offset.y = 0
if nw <= image.get_size().x:
nw = image.get_size().x
if nh <= image.get_size().y:
nh = image.get_size().y
image.crop(nw, nh)
image.blit_rect(smaller_image, Rect2(Vector2.ZERO, Vector2(nw, nh)), dst)
bitmap.create_from_image_alpha(image)
func resize_bitmap_values(bitmap: BitMap, new_size: Vector2, flip_x: bool, flip_y: bool) -> BitMap:
var selection_node = Global.canvas.selection
var selection_position: Vector2 = selection_node.big_bounding_rectangle.position
var dst := selection_position
var new_bitmap_size := size
new_bitmap_size.x = max(size.x, abs(selection_position.x) + new_size.x)
new_bitmap_size.y = max(size.y, abs(selection_position.y) + new_size.y)
var new_bitmap := BitMap.new()
var image: Image = bitmap_to_image(bitmap)
var selection_rect := image.get_used_rect()
var smaller_image := image.get_rect(selection_rect)
if selection_position.x <= 0:
self.selection_offset.x = selection_position.x
dst.x = 0
else:
self.selection_offset.x = 0
if selection_position.y <= 0:
self.selection_offset.y = selection_position.y
dst.y = 0
else:
self.selection_offset.y = 0
image.fill(Color(0))
smaller_image.resize(new_size.x, new_size.y, Image.INTERPOLATE_NEAREST)
if flip_x:
smaller_image.flip_x()
if flip_y:
smaller_image.flip_y()
if new_bitmap_size != size:
image.crop(new_bitmap_size.x, new_bitmap_size.y)
image.blit_rect(smaller_image, Rect2(Vector2.ZERO, new_bitmap_size), dst)
new_bitmap.create_from_image_alpha(image)
return new_bitmap

105
src/Classes/SelectionMap.gd Normal file
View file

@ -0,0 +1,105 @@
class_name SelectionMap
extends Image
var invert_shader: Shader = preload("res://src/Shaders/Invert.shader")
func is_pixel_selected(pixel: Vector2) -> bool:
if pixel.x < 0 or pixel.y < 0 or pixel.x >= get_width() or pixel.y >= get_height():
return false
lock()
var selected: bool = get_pixelv(pixel).a > 0
unlock()
return selected
func select_pixel(pixel: Vector2, select := true) -> void:
lock()
if select:
set_pixelv(pixel, Color(1, 1, 1, 1))
else:
set_pixelv(pixel, Color(0))
unlock()
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())
self.convert(Image.FORMAT_LA8)
func move_bitmap_values(project, move_offset := true) -> void:
var size: Vector2 = project.size
var selection_node = Global.canvas.selection
var selection_position: Vector2 = selection_node.big_bounding_rectangle.position
var selection_end: Vector2 = selection_node.big_bounding_rectangle.end
var selection_rect := get_used_rect()
var smaller_image := get_rect(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 = max(size.x, size.x + x_diff)
var nh = max(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, Rect2(Vector2.ZERO, Vector2(nw, nh)), dst)
func resize_bitmap_values(project, new_size: Vector2, flip_x: bool, flip_y: bool) -> void:
var size: Vector2 = project.size
var selection_node: Node2D = Global.canvas.selection
var selection_position: Vector2 = selection_node.big_bounding_rectangle.position
var dst := selection_position
var new_bitmap_size := size
new_bitmap_size.x = max(size.x, abs(selection_position.x) + new_size.x)
new_bitmap_size.y = max(size.y, abs(selection_position.y) + new_size.y)
var selection_rect := get_used_rect()
var smaller_image := get_rect(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()
smaller_image.resize(new_size.x, new_size.y, Image.INTERPOLATE_NEAREST)
if flip_x:
smaller_image.flip_x()
if flip_y:
smaller_image.flip_y()
if new_bitmap_size != size:
crop(new_bitmap_size.x, new_bitmap_size.y)
blit_rect(smaller_image, Rect2(Vector2.ZERO, new_bitmap_size), dst)

View file

@ -0,0 +1,29 @@
shader_type canvas_item;
render_mode unshaded;
uniform sampler2D selection : hint_black;
uniform vec4 color;
uniform float similarity_percent : hint_range(0.0, 100.0);
uniform int operation = 0; // 0 = add, 1 = subtract, 2 = intersect
void fragment() {
vec4 original_color = texture(TEXTURE, UV);
float diff = distance(original_color, color);
float similarity = abs(2.0 - ((similarity_percent/100.0) * 2.0));
vec4 col = texture(selection, UV);
if (col.rgb == vec3(0.0))
col.a = 0.0;
if (diff <= similarity)
{
if (operation == 0)
col = vec4(1.0);
else if (operation == 1)
col = vec4(0.0);
}
else
if (operation == 2)
col = vec4(0.0);
COLOR = col;
}

View file

@ -75,7 +75,7 @@ func draw_preview() -> void:
func _get_draw_rect() -> Rect2:
if Global.current_project.has_selection:
return Global.current_project.get_selection_rectangle()
return Global.current_project.selection_map.get_used_rect()
else:
return Rect2(Vector2.ZERO, Global.current_project.size)

View file

@ -181,7 +181,7 @@ func fill_in_color(position: Vector2) -> void:
var selection: Image
var selection_tex := ImageTexture.new()
if project.has_selection:
selection = project.bitmap_to_image(project.selection_bitmap)
selection = project.selection_map
else:
selection = Image.new()
selection.create(project.size.x, project.size.y, false, Image.FORMAT_RGBA8)

View file

@ -397,7 +397,7 @@ func remove_unselected_parts_of_brush(brush: Image, dst: Vector2) -> Image:
for x in size.x:
for y in size.y:
var pos := Vector2(x, y) + dst
if !project.selection_bitmap.get_bit(pos):
if !project.selection_map.is_pixel_selected(pos):
new_brush.set_pixel(x, y, Color(0))
new_brush.unlock()
return new_brush

View file

@ -1,5 +1,27 @@
extends SelectionTool
var shader: Shader = preload("res://src/Shaders/ColorSelect.gdshader")
var _similarity := 100
func get_config() -> Dictionary:
return {"similarity": _similarity}
func set_config(config: Dictionary) -> void:
_similarity = config.get("similarity", _similarity)
func update_config() -> void:
$Similarity/SimilaritySpinBox.value = _similarity
$Similarity/SimilaritySlider.value = _similarity
func _on_Similarity_value_changed(value: float) -> void:
_similarity = value
update_config()
save_config()
func apply_selection(position: Vector2) -> void:
var project: Project = Global.current_project
@ -8,30 +30,28 @@ func apply_selection(position: Vector2) -> void:
if position.x > project.size.x - 1 or position.y > project.size.y - 1:
return
if !_add and !_subtract and !_intersect:
Global.canvas.selection.clear_selection()
var selection_bitmap_copy: BitMap = project.selection_bitmap.duplicate()
if _intersect:
var full_rect = Rect2(Vector2.ZERO, selection_bitmap_copy.get_size())
selection_bitmap_copy.set_bit_rect(full_rect, false)
var cel_image := Image.new()
cel_image.copy_from(_get_draw_image())
cel_image.lock()
var color := cel_image.get_pixelv(position)
for x in cel_image.get_width():
for y in cel_image.get_height():
var pos := Vector2(x, y)
if color.is_equal_approx(cel_image.get_pixelv(pos)):
if _intersect:
selection_bitmap_copy.set_bit(pos, project.selection_bitmap.get_bit(pos))
else:
selection_bitmap_copy.set_bit(pos, !_subtract)
cel_image.unlock()
project.selection_bitmap = selection_bitmap_copy
Global.canvas.selection.big_bounding_rectangle = project.get_selection_rectangle(
project.selection_bitmap
)
var operation := 0
if _subtract:
operation = 1
elif _intersect:
operation = 2
var params := {"color": color, "similarity_percent": _similarity, "operation": operation}
if _add or _subtract or _intersect:
var selection_tex := ImageTexture.new()
selection_tex.create_from_image(project.selection_map, 0)
params["selection"] = selection_tex
var gen := ShaderImageEffect.new()
gen.generate_image(cel_image, shader, params, project.size)
cel_image.convert(Image.FORMAT_LA8)
var selection_map_copy := SelectionMap.new()
selection_map_copy.copy_from(cel_image)
project.selection_map = selection_map_copy
Global.canvas.selection.big_bounding_rectangle = project.selection_map.get_used_rect()
Global.canvas.selection.commit_undo("Select", undo_data)

View file

@ -5,3 +5,50 @@
[node name="ToolOptions" instance=ExtResource( 1 )]
script = ExtResource( 2 )
[node name="Similarity" type="VBoxContainer" parent="." index="8"]
margin_top = 166.0
margin_right = 116.0
margin_bottom = 228.0
alignment = 1
[node name="Label" type="Label" parent="Similarity" index="0"]
margin_left = 26.0
margin_right = 90.0
margin_bottom = 14.0
size_flags_horizontal = 4
text = "Similarity:"
[node name="SimilaritySpinBox" type="SpinBox" parent="Similarity" index="1"]
margin_left = 21.0
margin_top = 18.0
margin_right = 95.0
margin_bottom = 42.0
hint_tooltip = "How much two colors are Similar/Close together"
mouse_default_cursor_shape = 2
size_flags_horizontal = 4
value = 100.0
align = 1
suffix = "%"
__meta__ = {
"_editor_description_": ""
}
[node name="SimilaritySlider" type="HSlider" parent="Similarity" index="2"]
margin_left = 12.0
margin_top = 46.0
margin_right = 104.0
margin_bottom = 62.0
rect_min_size = Vector2( 92, 0 )
hint_tooltip = "How much two colors are Similar/Close together"
focus_mode = 0
mouse_default_cursor_shape = 2
size_flags_horizontal = 4
size_flags_vertical = 1
value = 100.0
__meta__ = {
"_editor_description_": ""
}
[connection signal="value_changed" from="Similarity/SimilaritySpinBox" to="." method="_on_Similarity_value_changed"]
[connection signal="value_changed" from="Similarity/SimilaritySlider" to="." method="_on_Similarity_value_changed"]

View file

@ -72,8 +72,9 @@ func apply_selection(_position: Vector2) -> void:
Global.canvas.selection.commit_undo("Select", undo_data)
if _rect.size != Vector2.ZERO:
var selection_bitmap_copy: BitMap = project.selection_bitmap.duplicate()
set_ellipse(selection_bitmap_copy, _rect.position)
var selection_map_copy := SelectionMap.new()
selection_map_copy.copy_from(project.selection_map)
set_ellipse(selection_map_copy, _rect.position)
# Handle mirroring
if Tools.horizontal_mirror:
@ -84,7 +85,7 @@ func apply_selection(_position: Vector2) -> void:
+ 1
)
mirror_x_rect.end.x = Global.current_project.x_symmetry_point - _rect.end.x + 1
set_ellipse(selection_bitmap_copy, mirror_x_rect.abs().position)
set_ellipse(selection_map_copy, mirror_x_rect.abs().position)
if Tools.vertical_mirror:
var mirror_xy_rect := mirror_x_rect
mirror_xy_rect.position.y = (
@ -93,7 +94,7 @@ func apply_selection(_position: Vector2) -> void:
+ 1
)
mirror_xy_rect.end.y = Global.current_project.y_symmetry_point - _rect.end.y + 1
set_ellipse(selection_bitmap_copy, mirror_xy_rect.abs().position)
set_ellipse(selection_map_copy, mirror_xy_rect.abs().position)
if Tools.vertical_mirror:
var mirror_y_rect := _rect
mirror_y_rect.position.y = (
@ -102,30 +103,28 @@ func apply_selection(_position: Vector2) -> void:
+ 1
)
mirror_y_rect.end.y = Global.current_project.y_symmetry_point - _rect.end.y + 1
set_ellipse(selection_bitmap_copy, mirror_y_rect.abs().position)
set_ellipse(selection_map_copy, mirror_y_rect.abs().position)
project.selection_bitmap = selection_bitmap_copy
Global.canvas.selection.big_bounding_rectangle = project.get_selection_rectangle(
project.selection_bitmap
)
project.selection_map = selection_map_copy
Global.canvas.selection.big_bounding_rectangle = project.selection_map.get_used_rect()
Global.canvas.selection.commit_undo("Select", undo_data)
func set_ellipse(bitmap: BitMap, position: Vector2) -> void:
func set_ellipse(selection_map: SelectionMap, position: Vector2) -> void:
var project: Project = Global.current_project
var bitmap_size: Vector2 = bitmap.get_size()
var bitmap_size: Vector2 = selection_map.get_size()
if _intersect:
bitmap.set_bit_rect(Rect2(Vector2.ZERO, bitmap_size), false)
selection_map.clear()
var points := _get_shape_points_filled(_rect.size)
for p in points:
var pos: Vector2 = position + p
if pos.x < 0 or pos.y < 0 or pos.x >= bitmap_size.x or pos.y >= bitmap_size.y:
continue
if _intersect:
if project.selection_bitmap.get_bit(pos):
bitmap.set_bit(pos, true)
if project.selection_map.is_pixel_selected(pos):
selection_map.select_pixel(pos, true)
else:
bitmap.set_bit(pos, !_subtract)
selection_map.select_pixel(pos, !_subtract)
# Given an origin point and destination point, returns a rect representing

View file

@ -77,24 +77,22 @@ func apply_selection(_position) -> void:
cleared = true
Global.canvas.selection.clear_selection()
if _draw_points.size() > 3:
var selection_bitmap_copy: BitMap = project.selection_bitmap.duplicate()
var bitmap_size: Vector2 = selection_bitmap_copy.get_size()
var selection_map_copy := SelectionMap.new()
selection_map_copy.copy_from(project.selection_map)
if _intersect:
selection_bitmap_copy.set_bit_rect(Rect2(Vector2.ZERO, bitmap_size), false)
lasso_selection(selection_bitmap_copy, _draw_points)
selection_map_copy.clear()
lasso_selection(selection_map_copy, _draw_points)
# Handle mirroring
if Tools.horizontal_mirror:
lasso_selection(selection_bitmap_copy, mirror_array(_draw_points, true, false))
lasso_selection(selection_map_copy, mirror_array(_draw_points, true, false))
if Tools.vertical_mirror:
lasso_selection(selection_bitmap_copy, mirror_array(_draw_points, true, true))
lasso_selection(selection_map_copy, mirror_array(_draw_points, true, true))
if Tools.vertical_mirror:
lasso_selection(selection_bitmap_copy, mirror_array(_draw_points, false, true))
lasso_selection(selection_map_copy, mirror_array(_draw_points, false, true))
project.selection_bitmap = selection_bitmap_copy
Global.canvas.selection.big_bounding_rectangle = project.get_selection_rectangle(
project.selection_bitmap
)
project.selection_map = selection_map_copy
Global.canvas.selection.big_bounding_rectangle = project.selection_map.get_used_rect()
else:
if !cleared:
Global.canvas.selection.clear_selection()
@ -104,17 +102,17 @@ func apply_selection(_position) -> void:
_last_position = Vector2.INF
func lasso_selection(bitmap: BitMap, points: PoolVector2Array) -> void:
func lasso_selection(selection_map: SelectionMap, points: PoolVector2Array) -> void:
var project: Project = Global.current_project
var size := bitmap.get_size()
var size := selection_map.get_size()
for point in points:
if point.x < 0 or point.y < 0 or point.x >= size.x or point.y >= size.y:
continue
if _intersect:
if project.selection_bitmap.get_bit(point):
bitmap.set_bit(point, true)
if project.selection_map.is_pixel_selected(point):
selection_map.select_pixel(point, true)
else:
bitmap.set_bit(point, !_subtract)
selection_map.select_pixel(point, !_subtract)
var v := Vector2()
var image_size: Vector2 = project.size
@ -124,10 +122,10 @@ func lasso_selection(bitmap: BitMap, points: PoolVector2Array) -> void:
v.y = y
if Geometry.is_point_in_polygon(v, points):
if _intersect:
if project.selection_bitmap.get_bit(v):
bitmap.set_bit(v, true)
if project.selection_map.is_pixel_selected(v):
selection_map.select_pixel(v, true)
else:
bitmap.set_bit(v, !_subtract)
selection_map.select_pixel(v, !_subtract)
# Bresenham's Algorithm

View file

@ -8,37 +8,38 @@ var _allegro_image_segments: Array
func apply_selection(position: Vector2) -> void:
var project: Project = Global.current_project
var size: Vector2 = project.size
if position.x < 0 or position.y < 0 or position.x >= size.x or position.y >= size.y:
return
if !_add and !_subtract and !_intersect:
Global.canvas.selection.clear_selection()
var selection_bitmap_copy: BitMap = project.selection_bitmap.duplicate()
var selection_map_copy := SelectionMap.new()
selection_map_copy.copy_from(project.selection_map)
if _intersect:
var full_rect = Rect2(Vector2.ZERO, selection_bitmap_copy.get_size())
selection_bitmap_copy.set_bit_rect(full_rect, false)
selection_map_copy.clear()
var cel_image := Image.new()
cel_image.copy_from(_get_draw_image())
cel_image.lock()
_flood_fill(position, cel_image, selection_bitmap_copy)
_flood_fill(position, cel_image, selection_map_copy)
# Handle mirroring
if Tools.horizontal_mirror:
var mirror_x := position
mirror_x.x = Global.current_project.x_symmetry_point - position.x
_flood_fill(mirror_x, cel_image, selection_bitmap_copy)
_flood_fill(mirror_x, cel_image, selection_map_copy)
if Tools.vertical_mirror:
var mirror_xy := mirror_x
mirror_xy.y = Global.current_project.y_symmetry_point - position.y
_flood_fill(mirror_xy, cel_image, selection_bitmap_copy)
_flood_fill(mirror_xy, cel_image, selection_map_copy)
if Tools.vertical_mirror:
var mirror_y := position
mirror_y.y = Global.current_project.y_symmetry_point - position.y
_flood_fill(mirror_y, cel_image, selection_bitmap_copy)
_flood_fill(mirror_y, cel_image, selection_map_copy)
cel_image.unlock()
project.selection_bitmap = selection_bitmap_copy
Global.canvas.selection.big_bounding_rectangle = project.get_selection_rectangle(
project.selection_bitmap
)
project.selection_map = selection_map_copy
Global.canvas.selection.big_bounding_rectangle = project.selection_map.get_used_rect()
Global.canvas.selection.commit_undo("Select", undo_data)
@ -128,7 +129,7 @@ func _check_flooded_segment(
return ret
func _flood_fill(position: Vector2, image: Image, bitmap: BitMap) -> void:
func _flood_fill(position: Vector2, image: Image, selection_map: SelectionMap) -> void:
# implements the floodfill routine by Shawn Hargreaves
# from https://www1.udel.edu/CIS/software/dist/allegro-4.2.1/src/flood.c
var project: Project = Global.current_project
@ -139,7 +140,7 @@ func _flood_fill(position: Vector2, image: Image, bitmap: BitMap) -> void:
_compute_segments_for_image(position, project, image, color)
# now actually color the image: since we have already checked a few things for the points
# we'll process here, we're going to skip a bunch of safety checks to speed things up.
_select_segments(bitmap)
_select_segments(selection_map)
func _compute_segments_for_image(
@ -171,18 +172,18 @@ func _compute_segments_for_image(
done = false
func _select_segments(bitmap: BitMap) -> void:
func _select_segments(selection_map: SelectionMap) -> void:
# short circuit for flat colors
for c in _allegro_image_segments.size():
var p = _allegro_image_segments[c]
for px in range(p.left_position, p.right_position + 1):
# We don't have to check again whether the point being processed is within the bounds
_set_bit(Vector2(px, p.y), bitmap)
_set_bit(Vector2(px, p.y), selection_map)
func _set_bit(p: Vector2, bitmap: BitMap) -> void:
func _set_bit(p: Vector2, selection_map: SelectionMap) -> void:
var project: Project = Global.current_project
if _intersect:
bitmap.set_bit(p, project.selection_bitmap.get_bit(p))
selection_map.select_pixel(p, project.selection_map.is_pixel_selected(p))
else:
bitmap.set_bit(p, !_subtract)
selection_map.select_pixel(p, !_subtract)

View file

@ -113,24 +113,22 @@ func apply_selection(_position) -> void:
cleared = true
Global.canvas.selection.clear_selection()
if _draw_points.size() > 3:
var selection_bitmap_copy: BitMap = project.selection_bitmap.duplicate()
var bitmap_size: Vector2 = selection_bitmap_copy.get_size()
var selection_map_copy := SelectionMap.new()
selection_map_copy.copy_from(project.selection_map)
if _intersect:
selection_bitmap_copy.set_bit_rect(Rect2(Vector2.ZERO, bitmap_size), false)
lasso_selection(selection_bitmap_copy, _draw_points)
selection_map_copy.clear()
lasso_selection(selection_map_copy, _draw_points)
# Handle mirroring
if Tools.horizontal_mirror:
lasso_selection(selection_bitmap_copy, mirror_array(_draw_points, true, false))
lasso_selection(selection_map_copy, mirror_array(_draw_points, true, false))
if Tools.vertical_mirror:
lasso_selection(selection_bitmap_copy, mirror_array(_draw_points, true, true))
lasso_selection(selection_map_copy, mirror_array(_draw_points, true, true))
if Tools.vertical_mirror:
lasso_selection(selection_bitmap_copy, mirror_array(_draw_points, false, true))
lasso_selection(selection_map_copy, mirror_array(_draw_points, false, true))
project.selection_bitmap = selection_bitmap_copy
Global.canvas.selection.big_bounding_rectangle = project.get_selection_rectangle(
project.selection_bitmap
)
project.selection_map = selection_map_copy
Global.canvas.selection.big_bounding_rectangle = project.selection_map.get_used_rect()
else:
if !cleared:
Global.canvas.selection.clear_selection()
@ -142,17 +140,17 @@ func apply_selection(_position) -> void:
Global.canvas.previews.update()
func lasso_selection(bitmap: BitMap, points: PoolVector2Array) -> void:
func lasso_selection(selection_map: SelectionMap, points: PoolVector2Array) -> void:
var project: Project = Global.current_project
var size := bitmap.get_size()
var size := selection_map.get_size()
for point in points:
if point.x < 0 or point.y < 0 or point.x >= size.x or point.y >= size.y:
continue
if _intersect:
if project.selection_bitmap.get_bit(point):
bitmap.set_bit(point, true)
if project.selection_map.is_pixel_selected(point):
selection_map.select_pixel(point, true)
else:
bitmap.set_bit(point, !_subtract)
selection_map.select_pixel(point, !_subtract)
var v := Vector2()
var image_size: Vector2 = project.size
@ -162,10 +160,10 @@ func lasso_selection(bitmap: BitMap, points: PoolVector2Array) -> void:
v.y = y
if Geometry.is_point_in_polygon(v, points):
if _intersect:
if project.selection_bitmap.get_bit(v):
bitmap.set_bit(v, true)
if project.selection_map.is_pixel_selected(v):
selection_map.select_pixel(v, true)
else:
bitmap.set_bit(v, !_subtract)
selection_map.select_pixel(v, !_subtract)
# Bresenham's Algorithm

View file

@ -87,49 +87,39 @@ func draw_preview() -> void:
canvas.draw_set_transform(canvas.position, canvas.rotation, canvas.scale)
func apply_selection(_position) -> void:
func apply_selection(_position: Vector2) -> void:
var project: Project = Global.current_project
if !_add and !_subtract and !_intersect:
Global.canvas.selection.clear_selection()
if _rect.size == Vector2.ZERO and Global.current_project.has_selection:
if _rect.size == Vector2.ZERO and project.has_selection:
Global.canvas.selection.commit_undo("Select", undo_data)
if _rect.size != Vector2.ZERO:
var operation := 0
if _subtract:
operation = 1
elif _intersect:
operation = 2
Global.canvas.selection.select_rect(_rect, operation)
if _rect.size == Vector2.ZERO:
return
var operation := 0
if _subtract:
operation = 1
elif _intersect:
operation = 2
Global.canvas.selection.select_rect(_rect, operation)
# Handle mirroring
if Tools.horizontal_mirror:
var mirror_x_rect := _rect
mirror_x_rect.position.x = (
Global.current_project.x_symmetry_point
- _rect.position.x
+ 1
)
mirror_x_rect.end.x = Global.current_project.x_symmetry_point - _rect.end.x + 1
Global.canvas.selection.select_rect(mirror_x_rect.abs(), operation)
if Tools.vertical_mirror:
var mirror_xy_rect := mirror_x_rect
mirror_xy_rect.position.y = (
Global.current_project.y_symmetry_point
- _rect.position.y
+ 1
)
mirror_xy_rect.end.y = Global.current_project.y_symmetry_point - _rect.end.y + 1
Global.canvas.selection.select_rect(mirror_xy_rect.abs(), operation)
# Handle mirroring
if Tools.horizontal_mirror:
var mirror_x_rect := _rect
mirror_x_rect.position.x = project.x_symmetry_point - _rect.position.x + 1
mirror_x_rect.end.x = project.x_symmetry_point - _rect.end.x + 1
Global.canvas.selection.select_rect(mirror_x_rect.abs(), operation)
if Tools.vertical_mirror:
var mirror_y_rect := _rect
mirror_y_rect.position.y = (
Global.current_project.y_symmetry_point
- _rect.position.y
+ 1
)
mirror_y_rect.end.y = Global.current_project.y_symmetry_point - _rect.end.y + 1
Global.canvas.selection.select_rect(mirror_y_rect.abs(), operation)
var mirror_xy_rect := mirror_x_rect
mirror_xy_rect.position.y = project.y_symmetry_point - _rect.position.y + 1
mirror_xy_rect.end.y = project.y_symmetry_point - _rect.end.y + 1
Global.canvas.selection.select_rect(mirror_xy_rect.abs(), operation)
if Tools.vertical_mirror:
var mirror_y_rect := _rect
mirror_y_rect.position.y = project.y_symmetry_point - _rect.position.y + 1
mirror_y_rect.end.y = project.y_symmetry_point - _rect.end.y + 1
Global.canvas.selection.select_rect(mirror_y_rect.abs(), operation)
Global.canvas.selection.commit_undo("Select", undo_data)
Global.canvas.selection.commit_undo("Select", undo_data)
# Given an origin point and destination point, returns a rect representing

View file

@ -66,7 +66,7 @@ func draw_start(position: Vector2) -> void:
if (
offsetted_pos.x >= 0
and offsetted_pos.y >= 0
and project.selection_bitmap.get_bit(offsetted_pos)
and project.selection_map.is_pixel_selected(offsetted_pos)
and (!_add and !_subtract and !_intersect or quick_copy)
and !_ongoing_selection
):
@ -81,14 +81,15 @@ func draw_start(position: Vector2) -> void:
image.blit_rect_mask(
selection_node.preview_image,
selection_node.preview_image,
Rect2(Vector2.ZERO, project.selection_bitmap.get_size()),
Rect2(Vector2.ZERO, project.selection_map.get_size()),
selection_node.big_bounding_rectangle.position
)
var selected_bitmap_copy = project.selection_bitmap.duplicate()
project.move_bitmap_values(selected_bitmap_copy)
var selection_map_copy := SelectionMap.new()
selection_map_copy.copy_from(project.selection_map)
selection_map_copy.move_bitmap_values(project)
project.selection_bitmap = selected_bitmap_copy
project.selection_map = selection_map_copy
selection_node.commit_undo("Move Selection", selection_node.undo_data)
selection_node.undo_data = selection_node.get_undo_data(true)
else:
@ -98,7 +99,7 @@ func draw_start(position: Vector2) -> void:
image.blit_rect_mask(
selection_node.preview_image,
selection_node.preview_image,
Rect2(Vector2.ZERO, project.selection_bitmap.get_size()),
Rect2(Vector2.ZERO, project.selection_map.get_size()),
selection_node.big_bounding_rectangle.position
)
Global.canvas.update_selected_cels_textures()
@ -190,10 +191,11 @@ func _on_XSpinBox_value_changed(value: float) -> void:
timer.start()
selection_node.big_bounding_rectangle.position.x = value
var selection_bitmap_copy: BitMap = project.selection_bitmap.duplicate()
project.move_bitmap_values(selection_bitmap_copy)
project.selection_bitmap = selection_bitmap_copy
project.selection_bitmap_changed()
var selection_map_copy := SelectionMap.new()
selection_map_copy.copy_from(project.selection_map)
selection_map_copy.move_bitmap_values(project)
project.selection_map = selection_map_copy
project.selection_map_changed()
func _on_YSpinBox_value_changed(value: float) -> void:
@ -205,10 +207,11 @@ func _on_YSpinBox_value_changed(value: float) -> void:
timer.start()
selection_node.big_bounding_rectangle.position.y = value
var selection_bitmap_copy: BitMap = project.selection_bitmap.duplicate()
project.move_bitmap_values(selection_bitmap_copy)
project.selection_bitmap = selection_bitmap_copy
project.selection_bitmap_changed()
var selection_map_copy := SelectionMap.new()
selection_map_copy.copy_from(project.selection_map)
selection_map_copy.move_bitmap_values(project)
project.selection_map = selection_map_copy
project.selection_map_changed()
func _on_WSpinBox_value_changed(value: float) -> void:
@ -243,9 +246,9 @@ func _on_HSpinBox_value_changed(value: float) -> void:
func resize_selection() -> void:
var project: Project = Global.current_project
var bitmap: BitMap = project.selection_bitmap
var image: SelectionMap = project.selection_map
if selection_node.is_moving_content:
bitmap = selection_node.original_bitmap
image = selection_node.original_bitmap
var preview_image: Image = selection_node.preview_image
preview_image.copy_from(selection_node.original_preview_image)
preview_image.resize(
@ -255,12 +258,13 @@ func resize_selection() -> void:
)
selection_node.preview_image_texture.create_from_image(preview_image, 0)
var selection_bitmap_copy: BitMap = project.selection_bitmap.duplicate()
selection_bitmap_copy = project.resize_bitmap_values(
bitmap, selection_node.big_bounding_rectangle.size, false, false
var selection_map_copy := SelectionMap.new()
selection_map_copy.copy_from(image)
selection_map_copy.resize_bitmap_values(
project, selection_node.big_bounding_rectangle.size, false, false
)
project.selection_bitmap = selection_bitmap_copy
project.selection_bitmap_changed()
project.selection_map = selection_map_copy
project.selection_map_changed()
func _on_Timer_timeout() -> void:

View file

@ -10,14 +10,14 @@ var is_pasting := false
var big_bounding_rectangle := Rect2() setget _big_bounding_rectangle_changed
var temp_rect := Rect2()
var temp_bitmap := BitMap.new()
var temp_bitmap := SelectionMap.new()
var rect_aspect_ratio := 0.0
var temp_rect_size := Vector2.ZERO
var temp_rect_pivot := Vector2.ZERO
var original_big_bounding_rectangle := Rect2()
var original_preview_image := Image.new()
var original_bitmap := BitMap.new()
var original_bitmap := SelectionMap.new()
var original_offset := Vector2.ZERO
var preview_image := Image.new()
@ -114,7 +114,7 @@ func _input(event: InputEvent) -> void:
if Input.is_action_pressed("transform_move_selection_only"):
undo_data = get_undo_data(false)
temp_rect = big_bounding_rectangle
temp_bitmap = Global.current_project.selection_bitmap
temp_bitmap = Global.current_project.selection_map
else:
transform_content_start()
Global.current_project.selection_offset = Vector2.ZERO
@ -279,8 +279,8 @@ func _update_gizmos() -> void:
func update_on_zoom(zoom: float) -> void:
var size := max(
Global.current_project.selection_bitmap.get_size().x,
Global.current_project.selection_bitmap.get_size().y
Global.current_project.selection_map.get_size().x,
Global.current_project.selection_map.get_size().y
)
marching_ants_outline.material.set_shader_param("width", zoom)
marching_ants_outline.material.set_shader_param("frequency", (1.0 / zoom) * 10 * size / 64)
@ -351,10 +351,14 @@ func _gizmo_resize() -> void:
if temp_rect.size.y < 0:
preview_image.flip_y()
preview_image_texture.create_from_image(preview_image, 0)
Global.current_project.selection_bitmap = Global.current_project.resize_bitmap_values(
temp_bitmap, size, temp_rect.size.x < 0, temp_rect.size.y < 0
var temp_bitmap_copy := SelectionMap.new()
temp_bitmap_copy.copy_from(temp_bitmap)
temp_bitmap_copy.resize_bitmap_values(
Global.current_project, size, temp_rect.size.x < 0, temp_rect.size.y < 0
)
Global.current_project.selection_bitmap_changed()
Global.current_project.selection_map = temp_bitmap_copy
Global.current_project.selection_map_changed()
update()
@ -400,21 +404,22 @@ func _gizmo_rotate() -> void: # Does not work properly yet
DrawingAlgos.nn_rotate(preview_image, angle, pivot)
preview_image_texture.create_from_image(preview_image, 0)
var bitmap_image = Global.current_project.bitmap_to_image(original_bitmap)
var bitmap_image := original_bitmap
var bitmap_pivot = (
original_big_bounding_rectangle.position
+ ((original_big_bounding_rectangle.end - original_big_bounding_rectangle.position) / 2)
)
DrawingAlgos.nn_rotate(bitmap_image, angle, bitmap_pivot)
Global.current_project.selection_bitmap.create_from_image_alpha(bitmap_image)
Global.current_project.selection_bitmap_changed()
Global.current_project.selection_map = bitmap_image
Global.current_project.selection_map_changed()
self.big_bounding_rectangle = bitmap_image.get_used_rect()
update()
func select_rect(rect: Rect2, operation: int = SelectionOperation.ADD) -> void:
var project: Project = Global.current_project
var selection_bitmap_copy: BitMap = project.selection_bitmap.duplicate()
var selection_map_copy := SelectionMap.new()
selection_map_copy.copy_from(project.selection_map)
# Used only if the selection is outside of the canvas boundaries,
# on the left and/or above (negative coords)
var offset_position := Vector2.ZERO
@ -427,28 +432,27 @@ func select_rect(rect: Rect2, operation: int = SelectionOperation.ADD) -> void:
if offset_position != Vector2.ZERO:
big_bounding_rectangle.position -= offset_position
project.move_bitmap_values(selection_bitmap_copy)
selection_map_copy.move_bitmap_values(project)
if operation == SelectionOperation.ADD:
selection_bitmap_copy.set_bit_rect(rect, true)
selection_map_copy.fill_rect(rect, Color(1, 1, 1, 1))
elif operation == SelectionOperation.SUBTRACT:
selection_bitmap_copy.set_bit_rect(rect, false)
selection_map_copy.fill_rect(rect, Color(0))
elif operation == SelectionOperation.INTERSECT:
var full_rect = Rect2(Vector2.ZERO, selection_bitmap_copy.get_size())
selection_bitmap_copy.set_bit_rect(full_rect, false)
selection_map_copy.clear()
for x in range(rect.position.x, rect.end.x):
for y in range(rect.position.y, rect.end.y):
var pos := Vector2(x, y)
if !Rect2(Vector2.ZERO, selection_bitmap_copy.get_size()).has_point(pos):
if !Rect2(Vector2.ZERO, selection_map_copy.get_size()).has_point(pos):
continue
selection_bitmap_copy.set_bit(pos, project.selection_bitmap.get_bit(pos))
big_bounding_rectangle = project.get_selection_rectangle(selection_bitmap_copy)
selection_map_copy.select_pixel(pos, project.selection_map.is_pixel_selected(pos))
big_bounding_rectangle = selection_map_copy.get_used_rect()
if offset_position != Vector2.ZERO:
big_bounding_rectangle.position += offset_position
project.move_bitmap_values(selection_bitmap_copy)
selection_map_copy.move_bitmap_values(project)
project.selection_bitmap = selection_bitmap_copy
project.selection_map = selection_map_copy
self.big_bounding_rectangle = big_bounding_rectangle # call getter method
@ -465,14 +469,15 @@ func move_borders(move: Vector2) -> void:
func move_borders_end() -> void:
var selected_bitmap_copy: BitMap = Global.current_project.selection_bitmap.duplicate()
Global.current_project.move_bitmap_values(selected_bitmap_copy)
var selection_map_copy := SelectionMap.new()
selection_map_copy.copy_from(Global.current_project.selection_map)
selection_map_copy.move_bitmap_values(Global.current_project)
Global.current_project.selection_bitmap = selected_bitmap_copy
Global.current_project.selection_map = selection_map_copy
if !is_moving_content:
commit_undo("Select", undo_data)
else:
Global.current_project.selection_bitmap_changed()
Global.current_project.selection_map_changed()
update()
@ -480,13 +485,13 @@ func transform_content_start() -> void:
if !is_moving_content:
undo_data = get_undo_data(true)
temp_rect = big_bounding_rectangle
temp_bitmap = Global.current_project.selection_bitmap
temp_bitmap = Global.current_project.selection_map
_get_preview_image()
if original_preview_image.is_empty():
undo_data = get_undo_data(false)
return
is_moving_content = true
original_bitmap = Global.current_project.selection_bitmap.duplicate()
original_bitmap.copy_from(Global.current_project.selection_map)
original_big_bounding_rectangle = big_bounding_rectangle
original_offset = Global.current_project.selection_offset
update()
@ -525,17 +530,18 @@ func transform_content_confirm() -> void:
cel_image.blit_rect_mask(
src,
src,
Rect2(Vector2.ZERO, project.selection_bitmap.get_size()),
Rect2(Vector2.ZERO, project.selection_map.get_size()),
big_bounding_rectangle.position
)
var selected_bitmap_copy = project.selection_bitmap.duplicate()
project.move_bitmap_values(selected_bitmap_copy)
project.selection_bitmap = selected_bitmap_copy
var selection_map_copy := SelectionMap.new()
selection_map_copy.copy_from(project.selection_map)
selection_map_copy.move_bitmap_values(project)
project.selection_map = selection_map_copy
commit_undo("Move Selection", undo_data)
original_preview_image = Image.new()
preview_image = Image.new()
original_bitmap = BitMap.new()
original_bitmap = SelectionMap.new()
is_moving_content = false
is_pasting = false
clear_in_selected_cels = true
@ -550,21 +556,21 @@ func transform_content_cancel() -> void:
is_moving_content = false
self.big_bounding_rectangle = original_big_bounding_rectangle
project.selection_bitmap = original_bitmap
project.selection_bitmap_changed()
project.selection_map = original_bitmap
project.selection_map_changed()
preview_image = original_preview_image
if !is_pasting:
var cel_image: Image = project.frames[project.current_frame].cels[project.current_layer].image
cel_image.blit_rect_mask(
preview_image,
preview_image,
Rect2(Vector2.ZERO, Global.current_project.selection_bitmap.get_size()),
Rect2(Vector2.ZERO, Global.current_project.selection_map.get_size()),
big_bounding_rectangle.position
)
Global.canvas.update_texture(project.current_layer)
original_preview_image = Image.new()
preview_image = Image.new()
original_bitmap = BitMap.new()
original_bitmap = SelectionMap.new()
is_pasting = false
update()
@ -578,15 +584,13 @@ func commit_undo(action: String, undo_data_tmp: Dictionary) -> void:
project.undos += 1
project.undo_redo.create_action(action)
project.undo_redo.add_do_property(project, "selection_bitmap", redo_data["selection_bitmap"])
project.undo_redo.add_do_property(project, "selection_map", redo_data["selection_map"])
project.undo_redo.add_do_property(
self, "big_bounding_rectangle", redo_data["big_bounding_rectangle"]
)
project.undo_redo.add_do_property(project, "selection_offset", redo_data["outline_offset"])
project.undo_redo.add_undo_property(
project, "selection_bitmap", undo_data_tmp["selection_bitmap"]
)
project.undo_redo.add_undo_property(project, "selection_map", undo_data_tmp["selection_map"])
project.undo_redo.add_undo_property(
self, "big_bounding_rectangle", undo_data_tmp["big_bounding_rectangle"]
)
@ -605,9 +609,9 @@ func commit_undo(action: String, undo_data_tmp: Dictionary) -> void:
continue
project.undo_redo.add_undo_property(image, "data", undo_data_tmp[image])
project.undo_redo.add_do_method(Global, "undo_or_redo", false)
project.undo_redo.add_do_method(project, "selection_bitmap_changed")
project.undo_redo.add_do_method(project, "selection_map_changed")
project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
project.undo_redo.add_undo_method(project, "selection_bitmap_changed")
project.undo_redo.add_undo_method(project, "selection_map_changed")
project.undo_redo.commit_action()
undo_data.clear()
@ -616,7 +620,7 @@ func commit_undo(action: String, undo_data_tmp: Dictionary) -> void:
func get_undo_data(undo_image: bool) -> Dictionary:
var data := {}
var project: Project = Global.current_project
data["selection_bitmap"] = project.selection_bitmap
data["selection_map"] = project.selection_map
data["big_bounding_rectangle"] = big_bounding_rectangle
data["outline_offset"] = Global.current_project.selection_offset
data["undo_image"] = undo_image
@ -651,7 +655,7 @@ func cut() -> void:
func copy() -> void:
var project: Project = Global.current_project
var cl_image := Image.new()
var cl_selection_bitmap = BitMap.new()
var cl_selection_map := SelectionMap.new()
var cl_big_bounding_rectangle := Rect2()
var cl_selection_offset := Vector2.ZERO
@ -661,9 +665,10 @@ func copy() -> void:
var to_copy := Image.new()
if is_moving_content:
to_copy.copy_from(preview_image)
var selected_bitmap_copy := project.selection_bitmap.duplicate()
project.move_bitmap_values(selected_bitmap_copy, false)
cl_selection_bitmap = selected_bitmap_copy
var selection_map_copy := SelectionMap.new()
selection_map_copy.copy_from(project.selection_map)
selection_map_copy.move_bitmap_values(project, false)
cl_selection_map = selection_map_copy
else:
to_copy = image.get_rect(big_bounding_rectangle)
to_copy.lock()
@ -676,22 +681,22 @@ func copy() -> void:
offset_pos.x = 0
if offset_pos.y < 0:
offset_pos.y = 0
if not project.selection_bitmap.get_bit(pos + offset_pos):
if not project.selection_map.is_pixel_selected(pos + offset_pos):
to_copy.set_pixelv(pos, Color(0))
to_copy.unlock()
cl_selection_bitmap = project.selection_bitmap.duplicate()
cl_selection_map.copy_from(project.selection_map)
cl_image = to_copy
cl_big_bounding_rectangle = big_bounding_rectangle
cl_selection_offset = project.selection_offset
var transfer_clipboard = {
var transfer_clipboard := {
"image": cl_image,
"selection_bitmap": cl_selection_bitmap,
"selection_map": cl_selection_map.data,
"big_bounding_rectangle": cl_big_bounding_rectangle,
"selection_offset": cl_selection_offset,
}
# Store to ".clipboard.txt" file
var clipboard_file = File.new()
var clipboard_file := File.new()
clipboard_file.open("user://clipboard.txt", File.WRITE)
clipboard_file.store_var(transfer_clipboard, true)
clipboard_file.close()
@ -707,7 +712,7 @@ func copy() -> void:
func paste() -> void:
# Read from the ".clipboard.txt" file
var clipboard_file = File.new()
var clipboard_file := File.new()
if !clipboard_file.file_exists("user://clipboard.txt"):
return
clipboard_file.open("user://clipboard.txt", File.READ)
@ -717,7 +722,7 @@ func paste() -> void:
if typeof(clipboard) == TYPE_DICTIONARY:
# A sanity check
if not clipboard.has_all(
["image", "selection_bitmap", "big_bounding_rectangle", "selection_offset"]
["image", "selection_map", "big_bounding_rectangle", "selection_offset"]
):
return
@ -727,21 +732,23 @@ func paste() -> void:
undo_data = get_undo_data(true)
var project: Project = Global.current_project
original_bitmap = project.selection_bitmap.duplicate()
original_bitmap.copy_from(project.selection_map)
original_big_bounding_rectangle = big_bounding_rectangle
original_offset = project.selection_offset
var clip_bitmap: BitMap = clipboard.selection_bitmap.duplicate()
var clip_map := SelectionMap.new()
clip_map.data = clipboard.selection_map
var max_size := Vector2(
max(clip_bitmap.get_size().x, project.selection_bitmap.get_size().x),
max(clip_bitmap.get_size().y, project.selection_bitmap.get_size().y)
max(clip_map.get_size().x, project.selection_map.get_size().x),
max(clip_map.get_size().y, project.selection_map.get_size().y)
)
project.selection_bitmap = Global.current_project.resize_bitmap(clip_bitmap, max_size)
project.selection_map = clip_map
project.selection_map.crop(max_size.x, max_size.y)
self.big_bounding_rectangle = clipboard.big_bounding_rectangle
project.selection_offset = clipboard.selection_offset
temp_bitmap = project.selection_bitmap
temp_bitmap = project.selection_map
temp_rect = big_bounding_rectangle
is_moving_content = true
is_pasting = true
@ -749,7 +756,7 @@ func paste() -> void:
preview_image.copy_from(original_preview_image)
preview_image_texture.create_from_image(preview_image, 0)
project.selection_bitmap_changed()
project.selection_map_changed()
func delete(selected_cels := true) -> void:
@ -762,7 +769,7 @@ func delete(selected_cels := true) -> void:
is_moving_content = false
original_preview_image = Image.new()
preview_image = Image.new()
original_bitmap = BitMap.new()
original_bitmap = SelectionMap.new()
is_pasting = false
update()
commit_undo("Draw", undo_data)
@ -793,16 +800,17 @@ func new_brush() -> void:
var brush := Image.new()
if is_moving_content:
brush.copy_from(preview_image)
var selected_bitmap_copy := project.selection_bitmap.duplicate()
project.move_bitmap_values(selected_bitmap_copy, false)
var selection_map_copy := SelectionMap.new()
selection_map_copy.copy_from(project.selection_map)
selection_map_copy.move_bitmap_values(project, false)
var clipboard = str2var(OS.get_clipboard())
if typeof(clipboard) == TYPE_DICTIONARY:
# A sanity check
if not clipboard.has_all(
["image", "selection_bitmap", "big_bounding_rectangle", "selection_offset"]
["image", "selection_map", "big_bounding_rectangle", "selection_offset"]
):
return
clipboard.selection_bitmap = selected_bitmap_copy
clipboard.selection_map = selection_map_copy
else:
brush = image.get_rect(big_bounding_rectangle)
brush.lock()
@ -815,7 +823,7 @@ func new_brush() -> void:
offset_pos.x = 0
if offset_pos.y < 0:
offset_pos.y = 0
if not project.selection_bitmap.get_bit(pos + offset_pos):
if not project.selection_map.is_pixel_selected(pos + offset_pos):
brush.set_pixelv(pos, Color(0))
brush.unlock()
@ -838,12 +846,13 @@ func invert() -> void:
transform_content_confirm()
var project: Project = Global.current_project
var undo_data_tmp = get_undo_data(false)
var selection_bitmap_copy: BitMap = project.selection_bitmap.duplicate()
selection_bitmap_copy = project.resize_bitmap(selection_bitmap_copy, project.size)
project.invert_bitmap(selection_bitmap_copy)
project.selection_bitmap = selection_bitmap_copy
project.selection_bitmap_changed()
self.big_bounding_rectangle = project.get_selection_rectangle(selection_bitmap_copy)
var selection_map_copy := SelectionMap.new()
selection_map_copy.copy_from(project.selection_map)
selection_map_copy.crop(project.size.x, project.size.y)
selection_map_copy.invert()
project.selection_map = selection_map_copy
project.selection_map_changed()
self.big_bounding_rectangle = selection_map_copy.get_used_rect()
project.selection_offset = Vector2.ZERO
commit_undo("Select", undo_data_tmp)
@ -854,11 +863,11 @@ func clear_selection(use_undo := false) -> void:
return
transform_content_confirm()
var undo_data_tmp = get_undo_data(false)
var selection_bitmap_copy: BitMap = project.selection_bitmap.duplicate()
selection_bitmap_copy = project.resize_bitmap(selection_bitmap_copy, project.size)
var full_rect = Rect2(Vector2.ZERO, selection_bitmap_copy.get_size())
selection_bitmap_copy.set_bit_rect(full_rect, false)
project.selection_bitmap = selection_bitmap_copy
var selection_map_copy := SelectionMap.new()
selection_map_copy.copy_from(project.selection_map)
selection_map_copy.crop(project.size.x, project.size.y)
selection_map_copy.clear()
project.selection_map = selection_map_copy
self.big_bounding_rectangle = Rect2()
project.selection_offset = Vector2.ZERO
@ -898,7 +907,7 @@ func _get_preview_image() -> void:
cel_image.blit_rect_mask(
clear_image,
original_preview_image,
Rect2(Vector2.ZERO, Global.current_project.selection_bitmap.get_size()),
Rect2(Vector2.ZERO, Global.current_project.selection_map.get_size()),
big_bounding_rectangle.position
)
Global.canvas.update_texture(project.current_layer)
@ -930,7 +939,7 @@ func _get_selected_image(cel_image: Image, clear := true) -> Image:
cel_image.blit_rect_mask(
clear_image,
image,
Rect2(Vector2.ZERO, Global.current_project.selection_bitmap.get_size()),
Rect2(Vector2.ZERO, Global.current_project.selection_map.get_size()),
original_big_bounding_rectangle.position
)
Global.canvas.update_texture(project.current_layer)

View file

@ -23,8 +23,7 @@ func set_nodes() -> void:
func commit_action(cel: Image, project: Project = Global.current_project) -> void:
var selection_tex := ImageTexture.new()
if selection_checkbox.pressed and project.has_selection:
var selection: Image = project.bitmap_to_image(project.selection_bitmap)
selection_tex.create_from_image(selection, 0)
selection_tex.create_from_image(project.selection_map, 0)
var params := {
"red": red,

View file

@ -26,8 +26,7 @@ func set_nodes() -> void:
func commit_action(cel: Image, project: Project = Global.current_project) -> void:
var selection_tex := ImageTexture.new()
if selection_checkbox.pressed and project.has_selection:
var selection: Image = project.bitmap_to_image(project.selection_bitmap)
selection_tex.create_from_image(selection, 0)
selection_tex.create_from_image(project.selection_map, 0)
var params := {
"shadow_offset": offset,

View file

@ -33,7 +33,7 @@ func _flip_image(cel: Image, affect_selection: bool, project: Project) -> void:
var selected := Image.new()
var rectangle: Rect2 = Global.canvas.selection.big_bounding_rectangle
if project != Global.current_project:
rectangle = project.get_selection_rectangle()
rectangle = project.selection_map.get_used_rect()
selected = cel.get_rect(rectangle)
selected.lock()
cel.lock()
@ -61,9 +61,9 @@ func _commit_undo(action: String, undo_data: Dictionary, project: Project) -> vo
var redo_data := _get_undo_data(project)
project.undos += 1
project.undo_redo.create_action(action)
project.undo_redo.add_do_property(project, "selection_bitmap", redo_data["selection_bitmap"])
project.undo_redo.add_do_property(project, "selection_map", redo_data["selection_map"])
project.undo_redo.add_do_property(project, "selection_offset", redo_data["outline_offset"])
project.undo_redo.add_undo_property(project, "selection_bitmap", undo_data["selection_bitmap"])
project.undo_redo.add_undo_property(project, "selection_map", undo_data["selection_map"])
project.undo_redo.add_undo_property(project, "selection_offset", undo_data["outline_offset"])
for image in redo_data:
@ -76,15 +76,17 @@ func _commit_undo(action: String, undo_data: Dictionary, project: Project) -> vo
continue
project.undo_redo.add_undo_property(image, "data", undo_data[image])
project.undo_redo.add_do_method(Global, "undo_or_redo", false, -1, -1, project)
project.undo_redo.add_do_method(project, "selection_bitmap_changed")
project.undo_redo.add_do_method(project, "selection_map_changed")
project.undo_redo.add_undo_method(Global, "undo_or_redo", true, -1, -1, project)
project.undo_redo.add_undo_method(project, "selection_bitmap_changed")
project.undo_redo.add_undo_method(project, "selection_map_changed")
project.undo_redo.commit_action()
func _get_undo_data(project: Project) -> Dictionary:
var bitmap_image := SelectionMap.new()
bitmap_image.copy_from(project.selection_map)
var data := {}
data["selection_bitmap"] = project.selection_bitmap.duplicate()
data["selection_map"] = bitmap_image
data["outline_offset"] = project.selection_offset
var images := _get_selected_draw_images(project)
@ -99,7 +101,8 @@ func _flip_selection(project: Project = Global.current_project) -> void:
if !(selection_checkbox.pressed and project.has_selection):
return
var bitmap_image: Image = project.bitmap_to_image(project.selection_bitmap)
var bitmap_image := SelectionMap.new()
bitmap_image.copy_from(project.selection_map)
var selection_rect := bitmap_image.get_used_rect()
var smaller_bitmap_image := bitmap_image.get_rect(selection_rect)
@ -114,6 +117,4 @@ func _flip_selection(project: Project = Global.current_project) -> void:
Rect2(Vector2.ZERO, smaller_bitmap_image.get_size()),
selection_rect.position
)
var bitmap_copy: BitMap = project.selection_bitmap.duplicate()
bitmap_copy.create_from_image_alpha(bitmap_image)
project.selection_bitmap = bitmap_copy
project.selection_map = bitmap_image

View file

@ -65,7 +65,7 @@ func commit_action(cel: Image, project: Project = Global.current_project) -> voi
var selection: Image
var selection_tex := ImageTexture.new()
if selection_checkbox.pressed and project.has_selection:
selection = project.bitmap_to_image(project.selection_bitmap)
selection = project.selection_map
else: # This is needed to prevent a weird bug with the dithering shaders and GLES2
selection = Image.new()
selection.create(project.size.x, project.size.y, false, Image.FORMAT_L8)

View file

@ -18,8 +18,7 @@ func set_nodes() -> void:
func commit_action(cel: Image, project: Project = Global.current_project) -> void:
var selection_tex := ImageTexture.new()
if selection_checkbox.pressed and project.has_selection:
var selection: Image = project.bitmap_to_image(project.selection_bitmap)
selection_tex.create_from_image(selection, 0)
selection_tex.create_from_image(project.selection_map, 0)
var params := {"selection": selection_tex, "map": $VBoxContainer/GradientEdit.texture}

View file

@ -35,8 +35,7 @@ func set_nodes() -> void:
func commit_action(cel: Image, project: Project = Global.current_project) -> void:
var selection_tex := ImageTexture.new()
if selection_checkbox.pressed and project.has_selection:
var selection: Image = project.bitmap_to_image(project.selection_bitmap)
selection_tex.create_from_image(selection, 0)
selection_tex.create_from_image(project.selection_map, 0)
var params := {
"hue_shift_amount": hue_slider.value / 360,

View file

@ -23,8 +23,7 @@ func set_nodes() -> void:
func commit_action(cel: Image, project: Project = Global.current_project) -> void:
var selection_tex := ImageTexture.new()
if selection_checkbox.pressed and project.has_selection:
var selection: Image = project.bitmap_to_image(project.selection_bitmap)
selection_tex.create_from_image(selection, 0)
selection_tex.create_from_image(project.selection_map, 0)
var params := {
"red": red,

View file

@ -36,8 +36,7 @@ func commit_action(cel: Image, project: Project = Global.current_project) -> voi
var selection_tex := ImageTexture.new()
if selection_checkbox.pressed and project.has_selection:
var selection: Image = project.bitmap_to_image(project.selection_bitmap)
selection_tex.create_from_image(selection, 0)
selection_tex.create_from_image(project.selection_map, 0)
var params := {
"color": color,

View file

@ -61,7 +61,7 @@ func decide_pivot() -> void:
pivot.y -= 0.5
if Global.current_project.has_selection and selection_checkbox.pressed:
var selection_rectangle: Rect2 = Global.current_project.get_selection_rectangle()
var selection_rectangle: Rect2 = Global.current_project.selection_map.get_used_rect()
pivot = (
selection_rectangle.position
+ ((selection_rectangle.end - selection_rectangle.position) / 2)
@ -86,10 +86,10 @@ func commit_action(cel: Image, _project: Project = Global.current_project) -> vo
var image := Image.new()
image.copy_from(cel)
if _project.has_selection and selection_checkbox.pressed:
var selection_rectangle: Rect2 = _project.get_selection_rectangle()
var selection_rectangle: Rect2 = _project.selection_map.get_used_rect()
selection_size = selection_rectangle.size
var selection: Image = _project.bitmap_to_image(_project.selection_bitmap)
var selection: Image = _project.selection_map
selection_tex.create_from_image(selection, 0)
if !_type_is_shader():