1
0
Fork 0
mirror of https://github.com/Orama-Interactive/Pixelorama.git synced 2025-02-22 05:23: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", "language": "GDScript",
"path": "res://src/Classes/Project.gd" "path": "res://src/Classes/Project.gd"
}, { }, {
"base": "Image",
"class": "SelectionMap",
"language": "GDScript",
"path": "res://src/Classes/SelectionMap.gd"
}, {
"base": "BaseTool", "base": "BaseTool",
"class": "SelectionTool", "class": "SelectionTool",
"language": "GDScript", "language": "GDScript",
@ -149,6 +154,7 @@ _global_script_class_icons={
"PaletteSwatch": "", "PaletteSwatch": "",
"Patterns": "", "Patterns": "",
"Project": "", "Project": "",
"SelectionMap": "",
"SelectionTool": "", "SelectionTool": "",
"ShaderImageEffect": "", "ShaderImageEffect": "",
"ShortcutProfile": "", "ShortcutProfile": "",

View file

@ -426,8 +426,9 @@ func general_do_scale(width: int, height: int) -> void:
var x_ratio = project.size.x / width var x_ratio = project.size.x / width
var y_ratio = project.size.y / height var y_ratio = project.size.y / height
var bitmap: BitMap var selection_map_copy := SelectionMap.new()
bitmap = project.resize_bitmap(project.selection_bitmap, size) 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_x_symmetry_point = project.x_symmetry_point / x_ratio
var new_y_symmetry_point = project.y_symmetry_point / y_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.undos += 1
project.undo_redo.create_action("Scale") project.undo_redo.create_action("Scale")
project.undo_redo.add_do_property(project, "size", size) 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, "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, "y_symmetry_point", new_y_symmetry_point)
project.undo_redo.add_do_property(project.x_symmetry_axis, "points", new_x_symmetry_axis_points) 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: func general_undo_scale() -> void:
var project: Project = Global.current_project var project: Project = Global.current_project
project.undo_redo.add_undo_property(project, "size", project.size) 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, "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(project, "y_symmetry_point", project.y_symmetry_point)
project.undo_redo.add_undo_property( project.undo_redo.add_undo_property(

View file

@ -452,6 +452,7 @@ func undo_or_redo(
canvas.camera_zoom() canvas.camera_zoom()
canvas.grid.update() canvas.grid.update()
canvas.pixel_grid.update() canvas.pixel_grid.update()
project.selection_map_changed()
cursor_position_label.text = "[%s×%s]" % [project.size.x, project.size.y] cursor_position_label.text = "[%s×%s]" % [project.size.x, project.size.y]
elif "Frame" in action_name: 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 x in current_project.size.x:
for y in current_project.size.y: for y in current_project.size.y:
var pos := Vector2(x, 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) pixels.append(pos)
_fill_new_palette_with_colors(pixels, new_palette, add_alpha_colors, get_colors_from) _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 x_symmetry_axis := SymmetryGuide.new()
var y_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, # This is useful for when the selection is outside of the canvas boundaries,
# on the left and/or above (negative coords) # on the left and/or above (negative coords)
var selection_offset := Vector2.ZERO setget _selection_offset_changed 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 name = _name
size = _size size = _size
tiles = Tiles.new(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) Global.tabs.add_tab(name)
OpenSave.current_save_paths.append("") OpenSave.current_save_paths.append("")
@ -118,13 +118,11 @@ func new_empty_frame() -> Frame:
return frame return frame
func selection_bitmap_changed() -> void: func selection_map_changed() -> void:
var image := Image.new()
var image_texture := ImageTexture.new() var image_texture := ImageTexture.new()
has_selection = selection_bitmap.get_true_bit_count() > 0 has_selection = !selection_map.is_invisible()
if has_selection: if has_selection:
image = bitmap_to_image(selection_bitmap) image_texture.create_from_image(selection_map, 0)
image_texture.create_from_image(image, 0)
Global.canvas.selection.marching_ants_outline.texture = image_texture Global.canvas.selection.marching_ants_outline.texture = image_texture
Global.top_menu_container.edit_menu_button.get_popup().set_item_disabled(6, !has_selection) 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 # Change selection effect & bounding rectangle
Global.canvas.selection.marching_ants_outline.offset = selection_offset Global.canvas.selection.marching_ants_outline.offset = selection_offset
selection_bitmap_changed() selection_map_changed()
Global.canvas.selection.big_bounding_rectangle = get_selection_rectangle() Global.canvas.selection.big_bounding_rectangle = selection_map.get_used_rect()
Global.canvas.selection.big_bounding_rectangle.position += selection_offset Global.canvas.selection.big_bounding_rectangle.position += selection_offset
Global.canvas.selection.update() Global.canvas.selection.update()
Global.top_menu_container.edit_menu_button.get_popup().set_item_disabled(6, !has_selection) 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.x = dict.size_x
size.y = dict.size_y size.y = dict.size_y
tiles.tile_size = size tiles.tile_size = size
selection_bitmap = resize_bitmap(selection_bitmap, size) selection_map.crop(size.x, size.y)
if dict.has("has_mask"): if dict.has("has_mask"):
tiles.has_mask = dict.has_mask tiles.has_mask = dict.has_mask
if dict.has("tile_mode_x_basis_x") and dict.has("tile_mode_x_basis_y"): 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( func can_pixel_get_drawn(
pixel: Vector2, pixel: Vector2,
bitmap: BitMap = selection_bitmap, image: SelectionMap = selection_map,
selection_position: Vector2 = Global.canvas.selection.big_bounding_rectangle.position selection_position: Vector2 = Global.canvas.selection.big_bounding_rectangle.position
) -> bool: ) -> bool:
if pixel.x < 0 or pixel.y < 0 or pixel.x >= size.x or pixel.y >= size.y: 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 pixel.x -= selection_position.x
if selection_position.y < 0: if selection_position.y < 0:
pixel.y -= selection_position.y pixel.y -= selection_position.y
return bitmap.get_bit(pixel) return image.is_pixel_selected(pixel)
else: else:
return true 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: func _get_draw_rect() -> Rect2:
if Global.current_project.has_selection: if Global.current_project.has_selection:
return Global.current_project.get_selection_rectangle() return Global.current_project.selection_map.get_used_rect()
else: else:
return Rect2(Vector2.ZERO, Global.current_project.size) 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: Image
var selection_tex := ImageTexture.new() var selection_tex := ImageTexture.new()
if project.has_selection: if project.has_selection:
selection = project.bitmap_to_image(project.selection_bitmap) selection = project.selection_map
else: else:
selection = Image.new() selection = Image.new()
selection.create(project.size.x, project.size.y, false, Image.FORMAT_RGBA8) 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 x in size.x:
for y in size.y: for y in size.y:
var pos := Vector2(x, y) + dst 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.set_pixel(x, y, Color(0))
new_brush.unlock() new_brush.unlock()
return new_brush return new_brush

View file

@ -1,5 +1,27 @@
extends SelectionTool 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: func apply_selection(position: Vector2) -> void:
var project: Project = Global.current_project 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: if position.x > project.size.x - 1 or position.y > project.size.y - 1:
return 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() var cel_image := Image.new()
cel_image.copy_from(_get_draw_image()) cel_image.copy_from(_get_draw_image())
cel_image.lock() cel_image.lock()
var color := cel_image.get_pixelv(position) 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() cel_image.unlock()
project.selection_bitmap = selection_bitmap_copy var operation := 0
Global.canvas.selection.big_bounding_rectangle = project.get_selection_rectangle( if _subtract:
project.selection_bitmap 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) Global.canvas.selection.commit_undo("Select", undo_data)

View file

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

View file

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

View file

@ -8,37 +8,38 @@ var _allegro_image_segments: Array
func apply_selection(position: Vector2) -> void: func apply_selection(position: Vector2) -> void:
var project: Project = Global.current_project 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: if !_add and !_subtract and !_intersect:
Global.canvas.selection.clear_selection() 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: if _intersect:
var full_rect = Rect2(Vector2.ZERO, selection_bitmap_copy.get_size()) selection_map_copy.clear()
selection_bitmap_copy.set_bit_rect(full_rect, false)
var cel_image := Image.new() var cel_image := Image.new()
cel_image.copy_from(_get_draw_image()) cel_image.copy_from(_get_draw_image())
cel_image.lock() cel_image.lock()
_flood_fill(position, cel_image, selection_bitmap_copy) _flood_fill(position, cel_image, selection_map_copy)
# Handle mirroring # Handle mirroring
if Tools.horizontal_mirror: if Tools.horizontal_mirror:
var mirror_x := position var mirror_x := position
mirror_x.x = Global.current_project.x_symmetry_point - position.x 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: if Tools.vertical_mirror:
var mirror_xy := mirror_x var mirror_xy := mirror_x
mirror_xy.y = Global.current_project.y_symmetry_point - position.y 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: if Tools.vertical_mirror:
var mirror_y := position var mirror_y := position
mirror_y.y = Global.current_project.y_symmetry_point - position.y 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() cel_image.unlock()
project.selection_bitmap = selection_bitmap_copy project.selection_map = selection_map_copy
Global.canvas.selection.big_bounding_rectangle = project.get_selection_rectangle( Global.canvas.selection.big_bounding_rectangle = project.selection_map.get_used_rect()
project.selection_bitmap
)
Global.canvas.selection.commit_undo("Select", undo_data) Global.canvas.selection.commit_undo("Select", undo_data)
@ -128,7 +129,7 @@ func _check_flooded_segment(
return ret 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 # implements the floodfill routine by Shawn Hargreaves
# from https://www1.udel.edu/CIS/software/dist/allegro-4.2.1/src/flood.c # from https://www1.udel.edu/CIS/software/dist/allegro-4.2.1/src/flood.c
var project: Project = Global.current_project 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) _compute_segments_for_image(position, project, image, color)
# now actually color the image: since we have already checked a few things for the points # 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. # 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( func _compute_segments_for_image(
@ -171,18 +172,18 @@ func _compute_segments_for_image(
done = false done = false
func _select_segments(bitmap: BitMap) -> void: func _select_segments(selection_map: SelectionMap) -> void:
# short circuit for flat colors # short circuit for flat colors
for c in _allegro_image_segments.size(): for c in _allegro_image_segments.size():
var p = _allegro_image_segments[c] var p = _allegro_image_segments[c]
for px in range(p.left_position, p.right_position + 1): 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 # 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 var project: Project = Global.current_project
if _intersect: 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: 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 cleared = true
Global.canvas.selection.clear_selection() Global.canvas.selection.clear_selection()
if _draw_points.size() > 3: if _draw_points.size() > 3:
var selection_bitmap_copy: BitMap = project.selection_bitmap.duplicate() var selection_map_copy := SelectionMap.new()
var bitmap_size: Vector2 = selection_bitmap_copy.get_size() selection_map_copy.copy_from(project.selection_map)
if _intersect: if _intersect:
selection_bitmap_copy.set_bit_rect(Rect2(Vector2.ZERO, bitmap_size), false) selection_map_copy.clear()
lasso_selection(selection_bitmap_copy, _draw_points) lasso_selection(selection_map_copy, _draw_points)
# Handle mirroring # Handle mirroring
if Tools.horizontal_mirror: 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: 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: 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 project.selection_map = selection_map_copy
Global.canvas.selection.big_bounding_rectangle = project.get_selection_rectangle( Global.canvas.selection.big_bounding_rectangle = project.selection_map.get_used_rect()
project.selection_bitmap
)
else: else:
if !cleared: if !cleared:
Global.canvas.selection.clear_selection() Global.canvas.selection.clear_selection()
@ -142,17 +140,17 @@ func apply_selection(_position) -> void:
Global.canvas.previews.update() 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 project: Project = Global.current_project
var size := bitmap.get_size() var size := selection_map.get_size()
for point in points: for point in points:
if point.x < 0 or point.y < 0 or point.x >= size.x or point.y >= size.y: if point.x < 0 or point.y < 0 or point.x >= size.x or point.y >= size.y:
continue continue
if _intersect: if _intersect:
if project.selection_bitmap.get_bit(point): if project.selection_map.is_pixel_selected(point):
bitmap.set_bit(point, true) selection_map.select_pixel(point, true)
else: else:
bitmap.set_bit(point, !_subtract) selection_map.select_pixel(point, !_subtract)
var v := Vector2() var v := Vector2()
var image_size: Vector2 = project.size var image_size: Vector2 = project.size
@ -162,10 +160,10 @@ func lasso_selection(bitmap: BitMap, points: PoolVector2Array) -> void:
v.y = y v.y = y
if Geometry.is_point_in_polygon(v, points): if Geometry.is_point_in_polygon(v, points):
if _intersect: if _intersect:
if project.selection_bitmap.get_bit(v): if project.selection_map.is_pixel_selected(v):
bitmap.set_bit(v, true) selection_map.select_pixel(v, true)
else: else:
bitmap.set_bit(v, !_subtract) selection_map.select_pixel(v, !_subtract)
# Bresenham's Algorithm # Bresenham's Algorithm

View file

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

View file

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

View file

@ -26,8 +26,7 @@ func set_nodes() -> void:
func commit_action(cel: Image, project: Project = Global.current_project) -> void: func commit_action(cel: Image, project: Project = Global.current_project) -> void:
var selection_tex := ImageTexture.new() var selection_tex := ImageTexture.new()
if selection_checkbox.pressed and project.has_selection: if selection_checkbox.pressed and project.has_selection:
var selection: Image = project.bitmap_to_image(project.selection_bitmap) selection_tex.create_from_image(project.selection_map, 0)
selection_tex.create_from_image(selection, 0)
var params := { var params := {
"shadow_offset": offset, "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 selected := Image.new()
var rectangle: Rect2 = Global.canvas.selection.big_bounding_rectangle var rectangle: Rect2 = Global.canvas.selection.big_bounding_rectangle
if project != Global.current_project: if project != Global.current_project:
rectangle = project.get_selection_rectangle() rectangle = project.selection_map.get_used_rect()
selected = cel.get_rect(rectangle) selected = cel.get_rect(rectangle)
selected.lock() selected.lock()
cel.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) var redo_data := _get_undo_data(project)
project.undos += 1 project.undos += 1
project.undo_redo.create_action(action) 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_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"]) project.undo_redo.add_undo_property(project, "selection_offset", undo_data["outline_offset"])
for image in redo_data: for image in redo_data:
@ -76,15 +76,17 @@ func _commit_undo(action: String, undo_data: Dictionary, project: Project) -> vo
continue continue
project.undo_redo.add_undo_property(image, "data", undo_data[image]) 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(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(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() project.undo_redo.commit_action()
func _get_undo_data(project: Project) -> Dictionary: func _get_undo_data(project: Project) -> Dictionary:
var bitmap_image := SelectionMap.new()
bitmap_image.copy_from(project.selection_map)
var data := {} var data := {}
data["selection_bitmap"] = project.selection_bitmap.duplicate() data["selection_map"] = bitmap_image
data["outline_offset"] = project.selection_offset data["outline_offset"] = project.selection_offset
var images := _get_selected_draw_images(project) 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): if !(selection_checkbox.pressed and project.has_selection):
return 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 selection_rect := bitmap_image.get_used_rect()
var smaller_bitmap_image := bitmap_image.get_rect(selection_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()), Rect2(Vector2.ZERO, smaller_bitmap_image.get_size()),
selection_rect.position selection_rect.position
) )
var bitmap_copy: BitMap = project.selection_bitmap.duplicate() project.selection_map = bitmap_image
bitmap_copy.create_from_image_alpha(bitmap_image)
project.selection_bitmap = bitmap_copy

View file

@ -65,7 +65,7 @@ func commit_action(cel: Image, project: Project = Global.current_project) -> voi
var selection: Image var selection: Image
var selection_tex := ImageTexture.new() var selection_tex := ImageTexture.new()
if selection_checkbox.pressed and project.has_selection: 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 else: # This is needed to prevent a weird bug with the dithering shaders and GLES2
selection = Image.new() selection = Image.new()
selection.create(project.size.x, project.size.y, false, Image.FORMAT_L8) 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: func commit_action(cel: Image, project: Project = Global.current_project) -> void:
var selection_tex := ImageTexture.new() var selection_tex := ImageTexture.new()
if selection_checkbox.pressed and project.has_selection: if selection_checkbox.pressed and project.has_selection:
var selection: Image = project.bitmap_to_image(project.selection_bitmap) selection_tex.create_from_image(project.selection_map, 0)
selection_tex.create_from_image(selection, 0)
var params := {"selection": selection_tex, "map": $VBoxContainer/GradientEdit.texture} 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: func commit_action(cel: Image, project: Project = Global.current_project) -> void:
var selection_tex := ImageTexture.new() var selection_tex := ImageTexture.new()
if selection_checkbox.pressed and project.has_selection: if selection_checkbox.pressed and project.has_selection:
var selection: Image = project.bitmap_to_image(project.selection_bitmap) selection_tex.create_from_image(project.selection_map, 0)
selection_tex.create_from_image(selection, 0)
var params := { var params := {
"hue_shift_amount": hue_slider.value / 360, "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: func commit_action(cel: Image, project: Project = Global.current_project) -> void:
var selection_tex := ImageTexture.new() var selection_tex := ImageTexture.new()
if selection_checkbox.pressed and project.has_selection: if selection_checkbox.pressed and project.has_selection:
var selection: Image = project.bitmap_to_image(project.selection_bitmap) selection_tex.create_from_image(project.selection_map, 0)
selection_tex.create_from_image(selection, 0)
var params := { var params := {
"red": red, "red": red,

View file

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

View file

@ -61,7 +61,7 @@ func decide_pivot() -> void:
pivot.y -= 0.5 pivot.y -= 0.5
if Global.current_project.has_selection and selection_checkbox.pressed: 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 = ( pivot = (
selection_rectangle.position selection_rectangle.position
+ ((selection_rectangle.end - selection_rectangle.position) / 2) + ((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() var image := Image.new()
image.copy_from(cel) image.copy_from(cel)
if _project.has_selection and selection_checkbox.pressed: 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 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) selection_tex.create_from_image(selection, 0)
if !_type_is_shader(): if !_type_is_shader():