mirror of
https://github.com/Orama-Interactive/Pixelorama.git
synced 2025-01-31 15:39:49 +00:00
Compare commits
89 commits
6a0ad2e3db
...
e0e328f967
Author | SHA1 | Date | |
---|---|---|---|
e0e328f967 | |||
0c3facf376 | |||
58ab5b7083 | |||
4365ed8a3a | |||
d579baf830 | |||
ad2fcf4891 | |||
7fb65c3136 | |||
4d5eebc670 | |||
8efbf0bf83 | |||
61a3488ead | |||
23304079b6 | |||
889e93e548 | |||
228bc65a38 | |||
e20585fde3 | |||
ef1b77662c | |||
137ac25c00 | |||
a9946099ef | |||
8346b465b6 | |||
cfa067ebb0 | |||
800c8a6c19 | |||
423c77235d | |||
31c5bf7cac | |||
ca2e67612f | |||
a1f785f67e | |||
59a2ec4db1 | |||
381eed84d5 | |||
5e34faf793 | |||
a3324591be | |||
d5dac1c527 | |||
3cd4bd92ec | |||
c14ac5d579 | |||
f197c6c55b | |||
0b2fa7ab6e | |||
d341d73fcf | |||
f9b2ff2d6a | |||
533b28452b | |||
58d4e7efab | |||
45ae8b7dee | |||
ae52151021 | |||
5e3cc0a9a1 | |||
50da6c0ce9 | |||
ad83823f58 | |||
442285d15f | |||
b059ae4c8b | |||
5e4eebe139 | |||
2c6dcdcf78 | |||
ac75c8197c | |||
5f10a913d4 | |||
3bf556345d | |||
4e62d00296 | |||
a696db3fc0 | |||
610d2deb27 | |||
9f3564fe71 | |||
177428cc1b | |||
afe51262c9 | |||
81d4812b92 | |||
ad1252c142 | |||
2301ba9fcc | |||
c1fd209588 | |||
20c7a9fdfc | |||
14d0c76310 | |||
6c200d3afe | |||
04ab9faa87 | |||
9c5b0f0f76 | |||
419154bafe | |||
f077b147e9 | |||
c24a2240fe | |||
d8c27a7966 | |||
5b50270ee2 | |||
664197c9f3 | |||
0678fd8719 | |||
12eda32176 | |||
b87bfdf7e8 | |||
6b77e30e08 | |||
6c79136f09 | |||
cd6212d892 | |||
d95c3f7555 | |||
bd90f28de8 | |||
f69e4bdc9e | |||
9187d8a9be | |||
dd4f6b7b6c | |||
27c0787f26 | |||
f42454ef03 | |||
a8755bd92f | |||
4f1ee0e828 | |||
e119a91f5b | |||
062889b4bb | |||
174f7d4b9f | |||
b48bb4a094 |
|
@ -583,6 +583,87 @@ func calculate_mirror_x_minus_y(pos: Vector2i, project: Project) -> Vector2i:
|
|||
)
|
||||
|
||||
|
||||
func is_placing_tiles() -> bool:
|
||||
if Global.current_project.frames.size() == 0 or Global.current_project.layers.size() == 0:
|
||||
return false
|
||||
return Global.current_project.get_current_cel() is CelTileMap and TileSetPanel.placing_tiles
|
||||
|
||||
|
||||
func _get_closest_point_to_grid(pos: Vector2, distance: float, grid_pos: Vector2) -> Vector2:
|
||||
# If the cursor is close to the start/origin of a grid cell, snap to that
|
||||
var snap_distance := distance * Vector2.ONE
|
||||
var closest_point := Vector2.INF
|
||||
var rect := Rect2()
|
||||
rect.position = pos - (snap_distance / 4.0)
|
||||
rect.end = pos + (snap_distance / 4.0)
|
||||
if rect.has_point(grid_pos):
|
||||
closest_point = grid_pos
|
||||
return closest_point
|
||||
# If the cursor is far from the grid cell origin but still close to a grid line
|
||||
# Look for a point close to a horizontal grid line
|
||||
var grid_start_hor := Vector2(0, grid_pos.y)
|
||||
var grid_end_hor := Vector2(Global.current_project.size.x, grid_pos.y)
|
||||
var closest_point_hor := get_closest_point_to_segment(
|
||||
pos, distance, grid_start_hor, grid_end_hor
|
||||
)
|
||||
# Look for a point close to a vertical grid line
|
||||
var grid_start_ver := Vector2(grid_pos.x, 0)
|
||||
var grid_end_ver := Vector2(grid_pos.x, Global.current_project.size.y)
|
||||
var closest_point_ver := get_closest_point_to_segment(
|
||||
pos, distance, grid_start_ver, grid_end_ver
|
||||
)
|
||||
# Snap to the closest point to the closest grid line
|
||||
var horizontal_distance := (closest_point_hor - pos).length()
|
||||
var vertical_distance := (closest_point_ver - pos).length()
|
||||
if horizontal_distance < vertical_distance:
|
||||
closest_point = closest_point_hor
|
||||
elif horizontal_distance > vertical_distance:
|
||||
closest_point = closest_point_ver
|
||||
elif horizontal_distance == vertical_distance and closest_point_hor != Vector2.INF:
|
||||
closest_point = grid_pos
|
||||
return closest_point
|
||||
|
||||
|
||||
func get_closest_point_to_segment(
|
||||
pos: Vector2, distance: float, s1: Vector2, s2: Vector2
|
||||
) -> Vector2:
|
||||
var test_line := (s2 - s1).rotated(deg_to_rad(90)).normalized()
|
||||
var from_a := pos - test_line * distance
|
||||
var from_b := pos + test_line * distance
|
||||
var closest_point := Vector2.INF
|
||||
if Geometry2D.segment_intersects_segment(from_a, from_b, s1, s2):
|
||||
closest_point = Geometry2D.get_closest_point_to_segment(pos, s1, s2)
|
||||
return closest_point
|
||||
|
||||
|
||||
func snap_to_rectangular_grid_boundary(
|
||||
pos: Vector2, grid_size: Vector2i, grid_offset := Vector2i.ZERO, snapping_distance := 9999.0
|
||||
) -> Vector2:
|
||||
var grid_pos := pos.snapped(grid_size)
|
||||
grid_pos += Vector2(grid_offset)
|
||||
# keeping grid_pos as is would have been fine but this adds extra accuracy as to
|
||||
# which snap point (from the list below) is closest to mouse and occupy THAT point
|
||||
# t_l is for "top left" and so on
|
||||
var t_l := grid_pos + Vector2(-grid_size.x, -grid_size.y)
|
||||
var t_c := grid_pos + Vector2(0, -grid_size.y)
|
||||
var t_r := grid_pos + Vector2(grid_size.x, -grid_size.y)
|
||||
var m_l := grid_pos + Vector2(-grid_size.x, 0)
|
||||
var m_c := grid_pos
|
||||
var m_r := grid_pos + Vector2(grid_size.x, 0)
|
||||
var b_l := grid_pos + Vector2(-grid_size.x, grid_size.y)
|
||||
var b_c := grid_pos + Vector2(0, grid_size.y)
|
||||
var b_r := grid_pos + Vector2(grid_size)
|
||||
var vec_arr: PackedVector2Array = [t_l, t_c, t_r, m_l, m_c, m_r, b_l, b_c, b_r]
|
||||
for vec in vec_arr:
|
||||
if vec.distance_to(pos) < grid_pos.distance_to(pos):
|
||||
grid_pos = vec
|
||||
|
||||
var grid_point := _get_closest_point_to_grid(pos, snapping_distance, grid_pos)
|
||||
if grid_point != Vector2.INF:
|
||||
pos = grid_point.floor()
|
||||
return pos
|
||||
|
||||
|
||||
func set_button_size(button_size: int) -> void:
|
||||
var size := Vector2(24, 24) if button_size == Global.ButtonSize.SMALL else Vector2(32, 32)
|
||||
if not is_instance_valid(_tool_buttons):
|
||||
|
|
|
@ -77,6 +77,13 @@ func select_pixel(pixel: Vector2i, select := true) -> void:
|
|||
set_pixelv(pixel, Color(0))
|
||||
|
||||
|
||||
func select_rect(rect: Rect2i, select := true) -> void:
|
||||
if select:
|
||||
fill_rect(rect, Color(1, 1, 1, 1))
|
||||
else:
|
||||
fill_rect(rect, Color(0))
|
||||
|
||||
|
||||
func select_all() -> void:
|
||||
fill(Color(1, 1, 1, 1))
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ const SPLASH_DIALOG_SCENE_PATH := "res://src/UI/Dialogs/SplashDialog.tscn"
|
|||
var opensprite_file_selected := false
|
||||
var redone := false
|
||||
var is_quitting_on_save := false
|
||||
var is_writing_text := false
|
||||
var changed_projects_on_quit: Array[Project]
|
||||
var cursor_image := preload("res://assets/graphics/cursor.png")
|
||||
## Used to download an image when dragged and dropped directly from a browser into Pixelorama
|
||||
|
@ -202,7 +203,7 @@ func _ready() -> void:
|
|||
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if event is InputEventKey and is_instance_valid(Global.main_viewport):
|
||||
if is_writing_text and event is InputEventKey and is_instance_valid(Global.main_viewport):
|
||||
Global.main_viewport.get_child(0).push_input(event)
|
||||
left_cursor.position = get_global_mouse_position() + Vector2(-32, 32)
|
||||
right_cursor.position = get_global_mouse_position() + Vector2(32, 32)
|
||||
|
|
|
@ -163,7 +163,7 @@ func update_config() -> void:
|
|||
|
||||
func update_brush() -> void:
|
||||
$Brush/BrushSize.suffix = "px" # Assume we are using default brushes
|
||||
if is_placing_tiles():
|
||||
if Tools.is_placing_tiles():
|
||||
var tilemap_cel := Global.current_project.get_current_cel() as CelTileMap
|
||||
var tileset := tilemap_cel.tileset
|
||||
var tile_index := clampi(TileSetPanel.selected_tile_index, 0, tileset.tiles.size() - 1)
|
||||
|
@ -517,7 +517,7 @@ func remove_unselected_parts_of_brush(brush: Image, dst: Vector2i) -> Image:
|
|||
func draw_indicator(left: bool) -> void:
|
||||
var color := Global.left_tool_color if left else Global.right_tool_color
|
||||
var snapped_position := snap_position(_cursor)
|
||||
if is_placing_tiles():
|
||||
if Tools.is_placing_tiles():
|
||||
var tileset := (Global.current_project.get_current_cel() as CelTileMap).tileset
|
||||
var grid_size := tileset.tile_size
|
||||
snapped_position = _snap_to_rectangular_grid_center(
|
||||
|
@ -545,7 +545,7 @@ func draw_indicator(left: bool) -> void:
|
|||
|
||||
func draw_indicator_at(pos: Vector2i, offset: Vector2i, color: Color) -> void:
|
||||
var canvas: Node2D = Global.canvas.indicators
|
||||
if _brush.type in IMAGE_BRUSHES and not _draw_line or is_placing_tiles():
|
||||
if _brush.type in IMAGE_BRUSHES and not _draw_line or Tools.is_placing_tiles():
|
||||
pos -= _brush_image.get_size() / 2
|
||||
pos -= offset
|
||||
canvas.draw_texture(_brush_texture, pos)
|
||||
|
@ -580,7 +580,7 @@ func _set_pixel_no_cache(pos: Vector2i, ignore_mirroring := false) -> void:
|
|||
pos = _stroke_project.tiles.get_canon_position(pos)
|
||||
if Global.current_project.has_selection:
|
||||
pos = Global.current_project.selection_map.get_canon_position(pos)
|
||||
if is_placing_tiles():
|
||||
if Tools.is_placing_tiles():
|
||||
draw_tile(pos)
|
||||
return
|
||||
if !_stroke_project.can_pixel_get_drawn(pos):
|
||||
|
|
|
@ -152,6 +152,10 @@ func draw_move(pos: Vector2i) -> void:
|
|||
if not _move:
|
||||
return
|
||||
|
||||
if Tools.is_placing_tiles():
|
||||
var tileset := (Global.current_project.get_current_cel() as CelTileMap).tileset
|
||||
var grid_size := tileset.tile_size
|
||||
pos = Tools.snap_to_rectangular_grid_boundary(pos, grid_size)
|
||||
if Input.is_action_pressed("transform_snap_axis"): # Snap to axis
|
||||
var angle := Vector2(pos).angle_to_point(_start_pos)
|
||||
if absf(angle) <= PI / 4 or absf(angle) >= 3 * PI / 4:
|
||||
|
@ -211,6 +215,13 @@ func apply_selection(_position: Vector2i) -> void:
|
|||
_intersect = true
|
||||
|
||||
|
||||
func select_tilemap_cell(
|
||||
cel: CelTileMap, cell_position: int, selection: SelectionMap, select: bool
|
||||
) -> void:
|
||||
var rect := Rect2i(cel.get_cell_coords_in_image(cell_position), cel.tileset.tile_size)
|
||||
selection.select_rect(rect, select)
|
||||
|
||||
|
||||
func _on_confirm_button_pressed() -> void:
|
||||
if selection_node.is_moving_content:
|
||||
selection_node.transform_content_confirm()
|
||||
|
|
|
@ -189,7 +189,7 @@ func _draw_shape(origin: Vector2i, dest: Vector2i) -> void:
|
|||
_drawer.reset()
|
||||
# Draw each point offsetted based on the shape's thickness
|
||||
var draw_pos := point + thickness_vector
|
||||
if is_placing_tiles():
|
||||
if Tools.is_placing_tiles():
|
||||
draw_tile(draw_pos)
|
||||
else:
|
||||
if Global.current_project.can_pixel_get_drawn(draw_pos):
|
||||
|
|
|
@ -79,12 +79,6 @@ func draw_end(_pos: Vector2i) -> void:
|
|||
project.can_undo = true
|
||||
|
||||
|
||||
func is_placing_tiles() -> bool:
|
||||
if Global.current_project.frames.size() == 0 or Global.current_project.layers.size() == 0:
|
||||
return false
|
||||
return Global.current_project.get_current_cel() is CelTileMap and TileSetPanel.placing_tiles
|
||||
|
||||
|
||||
func get_cell_position(pos: Vector2i) -> int:
|
||||
var tile_pos := 0
|
||||
if Global.current_project.get_current_cel() is not CelTileMap:
|
||||
|
@ -145,7 +139,7 @@ func draw_preview() -> void:
|
|||
func snap_position(pos: Vector2) -> Vector2:
|
||||
var snapping_distance := Global.snapping_distance / Global.camera.zoom.x
|
||||
if Global.snap_to_rectangular_grid_boundary:
|
||||
pos = _snap_to_rectangular_grid_boundary(
|
||||
pos = Tools.snap_to_rectangular_grid_boundary(
|
||||
pos, Global.grids[0].grid_size, Global.grids[0].grid_offset, snapping_distance
|
||||
)
|
||||
|
||||
|
@ -218,81 +212,6 @@ func mirror_array(array: Array[Vector2i], callable := func(_array): pass) -> Arr
|
|||
return new_array
|
||||
|
||||
|
||||
func _get_closest_point_to_grid(pos: Vector2, distance: float, grid_pos: Vector2) -> Vector2:
|
||||
# If the cursor is close to the start/origin of a grid cell, snap to that
|
||||
var snap_distance := distance * Vector2.ONE
|
||||
var closest_point := Vector2.INF
|
||||
var rect := Rect2()
|
||||
rect.position = pos - (snap_distance / 4.0)
|
||||
rect.end = pos + (snap_distance / 4.0)
|
||||
if rect.has_point(grid_pos):
|
||||
closest_point = grid_pos
|
||||
return closest_point
|
||||
# If the cursor is far from the grid cell origin but still close to a grid line
|
||||
# Look for a point close to a horizontal grid line
|
||||
var grid_start_hor := Vector2(0, grid_pos.y)
|
||||
var grid_end_hor := Vector2(Global.current_project.size.x, grid_pos.y)
|
||||
var closest_point_hor := _get_closest_point_to_segment(
|
||||
pos, distance, grid_start_hor, grid_end_hor
|
||||
)
|
||||
# Look for a point close to a vertical grid line
|
||||
var grid_start_ver := Vector2(grid_pos.x, 0)
|
||||
var grid_end_ver := Vector2(grid_pos.x, Global.current_project.size.y)
|
||||
var closest_point_ver := _get_closest_point_to_segment(
|
||||
pos, distance, grid_start_ver, grid_end_ver
|
||||
)
|
||||
# Snap to the closest point to the closest grid line
|
||||
var horizontal_distance := (closest_point_hor - pos).length()
|
||||
var vertical_distance := (closest_point_ver - pos).length()
|
||||
if horizontal_distance < vertical_distance:
|
||||
closest_point = closest_point_hor
|
||||
elif horizontal_distance > vertical_distance:
|
||||
closest_point = closest_point_ver
|
||||
elif horizontal_distance == vertical_distance and closest_point_hor != Vector2.INF:
|
||||
closest_point = grid_pos
|
||||
return closest_point
|
||||
|
||||
|
||||
func _get_closest_point_to_segment(
|
||||
pos: Vector2, distance: float, s1: Vector2, s2: Vector2
|
||||
) -> Vector2:
|
||||
var test_line := (s2 - s1).rotated(deg_to_rad(90)).normalized()
|
||||
var from_a := pos - test_line * distance
|
||||
var from_b := pos + test_line * distance
|
||||
var closest_point := Vector2.INF
|
||||
if Geometry2D.segment_intersects_segment(from_a, from_b, s1, s2):
|
||||
closest_point = Geometry2D.get_closest_point_to_segment(pos, s1, s2)
|
||||
return closest_point
|
||||
|
||||
|
||||
func _snap_to_rectangular_grid_boundary(
|
||||
pos: Vector2, grid_size: Vector2i, grid_offset: Vector2i, snapping_distance: float
|
||||
) -> Vector2:
|
||||
var grid_pos := pos.snapped(grid_size)
|
||||
grid_pos += Vector2(grid_offset)
|
||||
# keeping grid_pos as is would have been fine but this adds extra accuracy as to
|
||||
# which snap point (from the list below) is closest to mouse and occupy THAT point
|
||||
# t_l is for "top left" and so on
|
||||
var t_l := grid_pos + Vector2(-grid_size.x, -grid_size.y)
|
||||
var t_c := grid_pos + Vector2(0, -grid_size.y)
|
||||
var t_r := grid_pos + Vector2(grid_size.x, -grid_size.y)
|
||||
var m_l := grid_pos + Vector2(-grid_size.x, 0)
|
||||
var m_c := grid_pos
|
||||
var m_r := grid_pos + Vector2(grid_size.x, 0)
|
||||
var b_l := grid_pos + Vector2(-grid_size.x, grid_size.y)
|
||||
var b_c := grid_pos + Vector2(0, grid_size.y)
|
||||
var b_r := grid_pos + Vector2(grid_size)
|
||||
var vec_arr: PackedVector2Array = [t_l, t_c, t_r, m_l, m_c, m_r, b_l, b_c, b_r]
|
||||
for vec in vec_arr:
|
||||
if vec.distance_to(pos) < grid_pos.distance_to(pos):
|
||||
grid_pos = vec
|
||||
|
||||
var grid_point := _get_closest_point_to_grid(pos, snapping_distance, grid_pos)
|
||||
if grid_point != Vector2.INF:
|
||||
pos = grid_point.floor()
|
||||
return pos
|
||||
|
||||
|
||||
func _snap_to_rectangular_grid_center(
|
||||
pos: Vector2, grid_size: Vector2i, grid_offset: Vector2i, snapping_distance: float
|
||||
) -> Vector2:
|
||||
|
@ -325,7 +244,7 @@ func _snap_to_rectangular_grid_center(
|
|||
func _snap_to_guide(
|
||||
snap_to: Vector2, pos: Vector2, distance: float, s1: Vector2, s2: Vector2
|
||||
) -> Vector2:
|
||||
var closest_point := _get_closest_point_to_segment(pos, distance, s1, s2)
|
||||
var closest_point := Tools.get_closest_point_to_segment(pos, distance, s1, s2)
|
||||
if closest_point == Vector2.INF: # Is not close to a guide
|
||||
return Vector2.INF
|
||||
# Snap to the closest guide
|
||||
|
@ -386,7 +305,7 @@ func _pick_color(pos: Vector2i) -> void:
|
|||
|
||||
if pos.x < 0 or pos.y < 0:
|
||||
return
|
||||
if is_placing_tiles():
|
||||
if Tools.is_placing_tiles():
|
||||
var cel := Global.current_project.get_current_cel() as CelTileMap
|
||||
Tools.selected_tile_index_changed.emit(cel.get_cell_index_at_coords(pos))
|
||||
return
|
||||
|
|
|
@ -204,7 +204,7 @@ func fill(pos: Vector2i) -> void:
|
|||
|
||||
func fill_in_color(pos: Vector2i) -> void:
|
||||
var project := Global.current_project
|
||||
if is_placing_tiles():
|
||||
if Tools.is_placing_tiles():
|
||||
for cel in _get_selected_draw_cels():
|
||||
if cel is not CelTileMap:
|
||||
continue
|
||||
|
@ -331,7 +331,7 @@ func _flood_fill(pos: Vector2i) -> 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 := Global.current_project
|
||||
if is_placing_tiles():
|
||||
if Tools.is_placing_tiles():
|
||||
for cel in _get_selected_draw_cels():
|
||||
if cel is not CelTileMap:
|
||||
continue
|
||||
|
|
|
@ -195,7 +195,7 @@ func _draw_shape() -> void:
|
|||
|
||||
|
||||
func _draw_pixel(point: Vector2i, images: Array[ImageExtended]) -> void:
|
||||
if is_placing_tiles():
|
||||
if Tools.is_placing_tiles():
|
||||
draw_tile(point)
|
||||
else:
|
||||
if Global.current_project.can_pixel_get_drawn(point):
|
||||
|
|
|
@ -174,7 +174,7 @@ func _draw_shape() -> void:
|
|||
for point in points:
|
||||
# Reset drawer every time because pixel perfect sometimes breaks the tool
|
||||
_drawer.reset()
|
||||
if is_placing_tiles():
|
||||
if Tools.is_placing_tiles():
|
||||
draw_tile(point)
|
||||
else:
|
||||
# Draw each point offsetted based on the shape's thickness
|
||||
|
|
|
@ -32,23 +32,46 @@ func apply_selection(pos: Vector2i) -> void:
|
|||
if pos.x > project.size.x - 1 or pos.y > project.size.y - 1:
|
||||
return
|
||||
|
||||
var cel_image := Image.new()
|
||||
cel_image.copy_from(_get_draw_image())
|
||||
var color := cel_image.get_pixelv(pos)
|
||||
var operation := 0
|
||||
if _subtract:
|
||||
operation = 1
|
||||
elif _intersect:
|
||||
operation = 2
|
||||
|
||||
var params := {"color": color, "tolerance": _tolerance, "operation": operation}
|
||||
if _add or _subtract or _intersect:
|
||||
var selection_tex := ImageTexture.create_from_image(project.selection_map)
|
||||
params["selection"] = selection_tex
|
||||
var gen := ShaderImageEffect.new()
|
||||
gen.generate_image(cel_image, shader, params, project.size)
|
||||
cel_image.convert(Image.FORMAT_LA8)
|
||||
if Tools.is_placing_tiles():
|
||||
var prev_selection_map := SelectionMap.new() # Used for intersect
|
||||
prev_selection_map.copy_from(project.selection_map)
|
||||
if !_add and !_subtract and !_intersect:
|
||||
Global.canvas.selection.clear_selection()
|
||||
if _intersect:
|
||||
project.selection_map.clear()
|
||||
for cel in _get_selected_draw_cels():
|
||||
if cel is not CelTileMap:
|
||||
continue
|
||||
var tilemap_cel := cel as CelTileMap
|
||||
var tile_index := tilemap_cel.get_cell_index_at_coords(pos)
|
||||
for i in tilemap_cel.cells.size():
|
||||
var cell := tilemap_cel.cells[i]
|
||||
if cell.index == tile_index:
|
||||
if _intersect:
|
||||
var p := (cel as CelTileMap).get_cell_coords_in_image(i)
|
||||
select_tilemap_cell(
|
||||
cel, i, project.selection_map, prev_selection_map.is_pixel_selected(p)
|
||||
)
|
||||
else:
|
||||
select_tilemap_cell(cel, i, project.selection_map, !_subtract)
|
||||
else:
|
||||
var cel_image := Image.new()
|
||||
cel_image.copy_from(_get_draw_image())
|
||||
var color := cel_image.get_pixelv(pos)
|
||||
var params := {"color": color, "tolerance": _tolerance, "operation": operation}
|
||||
if _add or _subtract or _intersect:
|
||||
var selection_tex := ImageTexture.create_from_image(project.selection_map)
|
||||
params["selection"] = selection_tex
|
||||
var gen := ShaderImageEffect.new()
|
||||
gen.generate_image(cel_image, shader, params, project.size)
|
||||
cel_image.convert(Image.FORMAT_LA8)
|
||||
|
||||
project.selection_map.copy_from(cel_image)
|
||||
project.selection_map.copy_from(cel_image)
|
||||
Global.canvas.selection.big_bounding_rectangle = project.selection_map.get_used_rect()
|
||||
Global.canvas.selection.commit_undo("Select", undo_data)
|
||||
|
|
|
@ -81,18 +81,36 @@ func apply_selection(_position: Vector2i) -> void:
|
|||
Global.canvas.selection.commit_undo("Select", undo_data)
|
||||
if _rect.size == Vector2i.ZERO:
|
||||
return
|
||||
set_ellipse(project.selection_map, _rect.position)
|
||||
# Handle mirroring
|
||||
var mirror_positions := Tools.get_mirrored_positions(_rect.position, project, 1)
|
||||
var mirror_ends := Tools.get_mirrored_positions(_rect.end, project, 1)
|
||||
for i in mirror_positions.size():
|
||||
var mirror_rect := Rect2i()
|
||||
mirror_rect.position = mirror_positions[i]
|
||||
mirror_rect.end = mirror_ends[i]
|
||||
set_ellipse(project.selection_map, mirror_rect.abs().position)
|
||||
if Tools.is_placing_tiles():
|
||||
var operation := 0
|
||||
if _subtract:
|
||||
operation = 1
|
||||
elif _intersect:
|
||||
operation = 2
|
||||
Global.canvas.selection.select_rect(_rect, operation)
|
||||
# Handle mirroring
|
||||
var mirror_positions := Tools.get_mirrored_positions(_rect.position, project, 1)
|
||||
var mirror_ends := Tools.get_mirrored_positions(_rect.end, project, 1)
|
||||
for i in mirror_positions.size():
|
||||
var mirror_rect := Rect2i()
|
||||
mirror_rect.position = mirror_positions[i]
|
||||
mirror_rect.end = mirror_ends[i]
|
||||
Global.canvas.selection.select_rect(mirror_rect.abs(), operation)
|
||||
|
||||
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)
|
||||
else:
|
||||
set_ellipse(project.selection_map, _rect.position)
|
||||
# Handle mirroring
|
||||
var mirror_positions := Tools.get_mirrored_positions(_rect.position, project, 1)
|
||||
var mirror_ends := Tools.get_mirrored_positions(_rect.end, project, 1)
|
||||
for i in mirror_positions.size():
|
||||
var mirror_rect := Rect2i()
|
||||
mirror_rect.position = mirror_positions[i]
|
||||
mirror_rect.end = mirror_ends[i]
|
||||
set_ellipse(project.selection_map, mirror_rect.abs().position)
|
||||
|
||||
Global.canvas.selection.big_bounding_rectangle = project.selection_map.get_used_rect()
|
||||
Global.canvas.selection.commit_undo("Select", undo_data)
|
||||
|
||||
|
||||
func set_ellipse(selection_map: SelectionMap, pos: Vector2i) -> void:
|
||||
|
@ -116,8 +134,12 @@ func set_ellipse(selection_map: SelectionMap, pos: Vector2i) -> void:
|
|||
# Given an origin point and destination point, returns a rect representing
|
||||
# where the shape will be drawn and what is its size
|
||||
func _get_result_rect(origin: Vector2i, dest: Vector2i) -> Rect2i:
|
||||
if Tools.is_placing_tiles():
|
||||
var tileset := (Global.current_project.get_current_cel() as CelTileMap).tileset
|
||||
var grid_size := tileset.tile_size
|
||||
origin = Tools.snap_to_rectangular_grid_boundary(origin, grid_size)
|
||||
dest = Tools.snap_to_rectangular_grid_boundary(dest, grid_size)
|
||||
var rect := Rect2i()
|
||||
|
||||
# Center the rect on the mouse
|
||||
if _expand_from_center:
|
||||
var new_size := dest - origin
|
||||
|
@ -140,6 +162,7 @@ func _get_result_rect(origin: Vector2i, dest: Vector2i) -> Rect2i:
|
|||
rect.position = Vector2i(mini(origin.x, dest.x), mini(origin.y, dest.y))
|
||||
rect.size = (origin - dest).abs()
|
||||
|
||||
rect.size += Vector2i.ONE
|
||||
if not Tools.is_placing_tiles():
|
||||
rect.size += Vector2i.ONE
|
||||
|
||||
return rect
|
||||
|
|
|
@ -70,9 +70,9 @@ func apply_selection(_position) -> void:
|
|||
if _draw_points.size() > 3:
|
||||
if _intersect:
|
||||
project.selection_map.clear()
|
||||
lasso_selection(_draw_points, project.selection_map, previous_selection_map)
|
||||
lasso_selection(_draw_points, project, previous_selection_map)
|
||||
# Handle mirroring
|
||||
var callable := lasso_selection.bind(project.selection_map, previous_selection_map)
|
||||
var callable := lasso_selection.bind(project, previous_selection_map)
|
||||
mirror_array(_draw_points, callable)
|
||||
Global.canvas.selection.big_bounding_rectangle = project.selection_map.get_used_rect()
|
||||
else:
|
||||
|
@ -85,8 +85,9 @@ func apply_selection(_position) -> void:
|
|||
|
||||
|
||||
func lasso_selection(
|
||||
points: Array[Vector2i], selection_map: SelectionMap, previous_selection_map: SelectionMap
|
||||
points: Array[Vector2i], project: Project, previous_selection_map: SelectionMap
|
||||
) -> void:
|
||||
var selection_map := project.selection_map
|
||||
var selection_size := selection_map.get_size()
|
||||
var bounding_rect := Rect2i(points[0], Vector2i.ZERO)
|
||||
for point in points:
|
||||
|
@ -95,9 +96,9 @@ func lasso_selection(
|
|||
bounding_rect = bounding_rect.expand(point)
|
||||
if _intersect:
|
||||
if previous_selection_map.is_pixel_selected(point):
|
||||
selection_map.select_pixel(point, true)
|
||||
select_pixel(point, project, true)
|
||||
else:
|
||||
selection_map.select_pixel(point, !_subtract)
|
||||
select_pixel(point, project, !_subtract)
|
||||
|
||||
var v := Vector2i()
|
||||
for x in bounding_rect.size.x:
|
||||
|
@ -107,9 +108,17 @@ func lasso_selection(
|
|||
if Geometry2D.is_point_in_polygon(v, points):
|
||||
if _intersect:
|
||||
if previous_selection_map.is_pixel_selected(v):
|
||||
selection_map.select_pixel(v, true)
|
||||
select_pixel(v, project, true)
|
||||
else:
|
||||
selection_map.select_pixel(v, !_subtract)
|
||||
select_pixel(v, project, !_subtract)
|
||||
|
||||
|
||||
func select_pixel(point: Vector2i, project: Project, select: bool) -> void:
|
||||
if Tools.is_placing_tiles():
|
||||
var tilemap := project.get_current_cel() as CelTileMap
|
||||
var cell_position := tilemap.get_cell_position(point)
|
||||
select_tilemap_cell(tilemap, cell_position, project.selection_map, select)
|
||||
project.selection_map.select_pixel(point, select)
|
||||
|
||||
|
||||
# Bresenham's Algorithm
|
||||
|
|
|
@ -34,10 +34,10 @@ func apply_selection(pos: Vector2i) -> void:
|
|||
|
||||
var cel_image := Image.new()
|
||||
cel_image.copy_from(_get_draw_image())
|
||||
_flood_fill(pos, cel_image, project.selection_map, previous_selection_map)
|
||||
_flood_fill(pos, cel_image, project, previous_selection_map)
|
||||
# Handle mirroring
|
||||
for mirror_pos in Tools.get_mirrored_positions(pos):
|
||||
_flood_fill(mirror_pos, cel_image, project.selection_map, previous_selection_map)
|
||||
_flood_fill(mirror_pos, cel_image, project, previous_selection_map)
|
||||
|
||||
Global.canvas.selection.big_bounding_rectangle = project.selection_map.get_used_rect()
|
||||
Global.canvas.selection.commit_undo("Select", undo_data)
|
||||
|
@ -59,6 +59,39 @@ func update_config() -> void:
|
|||
$ToleranceSlider.value = _tolerance * 255.0
|
||||
|
||||
|
||||
func _on_tolerance_slider_value_changed(value: float) -> void:
|
||||
_tolerance = value / 255.0
|
||||
update_config()
|
||||
save_config()
|
||||
|
||||
|
||||
func _flood_fill(
|
||||
pos: Vector2i, image: Image, project: Project, previous_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 selection_map := project.selection_map
|
||||
if Tools.is_placing_tiles():
|
||||
for cel in _get_selected_draw_cels():
|
||||
if cel is not CelTileMap:
|
||||
continue
|
||||
var tile_index := (cel as CelTileMap).get_cell_index_at_coords(pos)
|
||||
# init flood data structures
|
||||
_allegro_flood_segments = []
|
||||
_allegro_image_segments = []
|
||||
_compute_segments_for_tilemap(pos, cel, tile_index)
|
||||
_select_segments_tilemap(project, previous_selection_map)
|
||||
return
|
||||
var color := image.get_pixelv(pos)
|
||||
# init flood data structures
|
||||
_allegro_flood_segments = []
|
||||
_allegro_image_segments = []
|
||||
_compute_segments_for_image(pos, 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(selection_map, previous_selection_map)
|
||||
|
||||
|
||||
# Add a new segment to the array
|
||||
func _add_new_segment(y := 0) -> void:
|
||||
_allegro_flood_segments.append(Segment.new(y))
|
||||
|
@ -140,22 +173,6 @@ func _check_flooded_segment(
|
|||
return ret
|
||||
|
||||
|
||||
func _flood_fill(
|
||||
pos: Vector2i, image: Image, selection_map: SelectionMap, previous_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 := Global.current_project
|
||||
var color := image.get_pixelv(pos)
|
||||
# init flood data structures
|
||||
_allegro_flood_segments = []
|
||||
_allegro_image_segments = []
|
||||
_compute_segments_for_image(pos, 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(selection_map, previous_selection_map)
|
||||
|
||||
|
||||
func _compute_segments_for_image(
|
||||
pos: Vector2i, project: Project, image: Image, src_color: Color
|
||||
) -> void:
|
||||
|
@ -201,7 +218,128 @@ func _set_bit(p: Vector2i, selection_map: SelectionMap, prev_selection_map: Sele
|
|||
selection_map.select_pixel(p, !_subtract)
|
||||
|
||||
|
||||
func _on_tolerance_slider_value_changed(value: float) -> void:
|
||||
_tolerance = value / 255.0
|
||||
update_config()
|
||||
save_config()
|
||||
func _compute_segments_for_tilemap(pos: Vector2i, cel: CelTileMap, src_index: int) -> void:
|
||||
# initially allocate at least 1 segment per line of the tilemap
|
||||
for j in cel.vertical_cells:
|
||||
_add_new_segment(j)
|
||||
pos /= cel.tileset.tile_size
|
||||
# start flood algorithm
|
||||
_flood_line_around_point_tilemap(pos, cel, src_index)
|
||||
# test all segments while also discovering more
|
||||
var done := false
|
||||
while not done:
|
||||
done = true
|
||||
var max_index := _allegro_flood_segments.size()
|
||||
for c in max_index:
|
||||
var p := _allegro_flood_segments[c]
|
||||
if p.todo_below: # check below the segment?
|
||||
p.todo_below = false
|
||||
if _check_flooded_segment_tilemap(
|
||||
p.y + 1, p.left_position, p.right_position, cel, src_index
|
||||
):
|
||||
done = false
|
||||
if p.todo_above: # check above the segment?
|
||||
p.todo_above = false
|
||||
if _check_flooded_segment_tilemap(
|
||||
p.y - 1, p.left_position, p.right_position, cel, src_index
|
||||
):
|
||||
done = false
|
||||
|
||||
|
||||
## Fill an horizontal segment around the specified position, and adds it to the
|
||||
## list of segments filled. Returns the first x coordinate after the part of the
|
||||
## line that has been filled.
|
||||
## Τhis method is called by [method _flood_fill] after the required data structures
|
||||
## have been initialized.
|
||||
func _flood_line_around_point_tilemap(pos: Vector2i, cel: CelTileMap, src_index: int) -> int:
|
||||
if cel.get_cell_index_at_coords_in_tilemap_space(pos) != src_index:
|
||||
return pos.x + 1
|
||||
var west := pos
|
||||
var east := pos
|
||||
while west.x >= 0 && cel.get_cell_index_at_coords_in_tilemap_space(west) == src_index:
|
||||
west += Vector2i.LEFT
|
||||
while (
|
||||
east.x < cel.horizontal_cells
|
||||
&& cel.get_cell_index_at_coords_in_tilemap_space(east) == src_index
|
||||
):
|
||||
east += Vector2i.RIGHT
|
||||
# Make a note of the stuff we processed
|
||||
var c := pos.y
|
||||
var segment := _allegro_flood_segments[c]
|
||||
# we may have already processed some segments on this y coordinate
|
||||
if segment.flooding:
|
||||
while segment.next > 0:
|
||||
c = segment.next # index of next segment in this line of image
|
||||
segment = _allegro_flood_segments[c]
|
||||
# found last current segment on this line
|
||||
c = _allegro_flood_segments.size()
|
||||
segment.next = c
|
||||
_add_new_segment(pos.y)
|
||||
segment = _allegro_flood_segments[c]
|
||||
# set the values for the current segment
|
||||
segment.flooding = true
|
||||
segment.left_position = west.x + 1
|
||||
segment.right_position = east.x - 1
|
||||
segment.y = pos.y
|
||||
segment.next = 0
|
||||
# Should we process segments above or below this one?
|
||||
# when there is a selected area, the pixels above and below the one we started creating this
|
||||
# segment from may be outside it. It's easier to assume we should be checking for segments
|
||||
# above and below this one than to specifically check every single pixel in it, because that
|
||||
# test will be performed later anyway.
|
||||
# On the other hand, this test we described is the same `project.can_pixel_get_drawn` does if
|
||||
# there is no selection, so we don't need branching here.
|
||||
segment.todo_above = pos.y > 0
|
||||
segment.todo_below = pos.y < cel.vertical_cells - 1
|
||||
# this is an actual segment we should be coloring, so we add it to the results for the
|
||||
# current image
|
||||
if segment.right_position >= segment.left_position:
|
||||
_allegro_image_segments.append(segment)
|
||||
# we know the point just east of the segment is not part of a segment that should be
|
||||
# processed, else it would be part of this segment
|
||||
return east.x + 1
|
||||
|
||||
|
||||
func _check_flooded_segment_tilemap(
|
||||
y: int, left: int, right: int, cel: CelTileMap, src_index: int
|
||||
) -> bool:
|
||||
var ret := false
|
||||
var c := 0
|
||||
while left <= right:
|
||||
c = y
|
||||
while true:
|
||||
var segment := _allegro_flood_segments[c]
|
||||
if left >= segment.left_position and left <= segment.right_position:
|
||||
left = segment.right_position + 2
|
||||
break
|
||||
c = segment.next
|
||||
if c == 0: # couldn't find a valid segment, so we draw a new one
|
||||
left = _flood_line_around_point_tilemap(Vector2i(left, y), cel, src_index)
|
||||
ret = true
|
||||
break
|
||||
return ret
|
||||
|
||||
|
||||
func _select_segments_tilemap(project: Project, previous_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_rect(Vector2i(px, p.y), project, previous_selection_map)
|
||||
|
||||
|
||||
func _set_bit_rect(p: Vector2i, project: Project, prev_selection_map: SelectionMap) -> void:
|
||||
var selection_map := project.selection_map
|
||||
var tilemap := project.get_current_cel() as CelTileMap
|
||||
var cell_position := tilemap.get_cell_position_in_tilemap_space(p)
|
||||
if _intersect:
|
||||
var image_coords := tilemap.get_cell_coords_in_image(cell_position)
|
||||
select_tilemap_cell(
|
||||
tilemap,
|
||||
cell_position,
|
||||
project.selection_map,
|
||||
prev_selection_map.is_pixel_selected(image_coords)
|
||||
)
|
||||
else:
|
||||
select_tilemap_cell(tilemap, cell_position, project.selection_map, !_subtract)
|
||||
|
|
|
@ -99,10 +99,10 @@ func apply_selection(pos: Vector2i) -> void:
|
|||
if _draw_points.size() >= 1:
|
||||
if _intersect:
|
||||
project.selection_map.clear()
|
||||
paint_selection(project.selection_map, previous_selection_map, _draw_points)
|
||||
paint_selection(project, previous_selection_map, _draw_points)
|
||||
# Handle mirroring
|
||||
var mirror := mirror_array(_draw_points)
|
||||
paint_selection(project.selection_map, previous_selection_map, mirror)
|
||||
paint_selection(project, previous_selection_map, mirror)
|
||||
Global.canvas.selection.big_bounding_rectangle = project.selection_map.get_used_rect()
|
||||
else:
|
||||
if !cleared:
|
||||
|
@ -114,17 +114,26 @@ func apply_selection(pos: Vector2i) -> void:
|
|||
|
||||
|
||||
func paint_selection(
|
||||
selection_map: SelectionMap, previous_selection_map: SelectionMap, points: Array[Vector2i]
|
||||
project: Project, previous_selection_map: SelectionMap, points: Array[Vector2i]
|
||||
) -> void:
|
||||
var selection_map := project.selection_map
|
||||
var selection_size := selection_map.get_size()
|
||||
for point in points:
|
||||
if point.x < 0 or point.y < 0 or point.x >= selection_size.x or point.y >= selection_size.y:
|
||||
continue
|
||||
if _intersect:
|
||||
if previous_selection_map.is_pixel_selected(point):
|
||||
selection_map.select_pixel(point, true)
|
||||
select_pixel(point, project, true)
|
||||
else:
|
||||
selection_map.select_pixel(point, !_subtract)
|
||||
select_pixel(point, project, !_subtract)
|
||||
|
||||
|
||||
func select_pixel(point: Vector2i, project: Project, select: bool) -> void:
|
||||
if Tools.is_placing_tiles():
|
||||
var tilemap := project.get_current_cel() as CelTileMap
|
||||
var cell_position := tilemap.get_cell_position(point)
|
||||
select_tilemap_cell(tilemap, cell_position, project.selection_map, select)
|
||||
project.selection_map.select_pixel(point, select)
|
||||
|
||||
|
||||
# Bresenham's Algorithm
|
||||
|
|
|
@ -107,9 +107,9 @@ func apply_selection(pos: Vector2i) -> void:
|
|||
if _draw_points.size() > 3:
|
||||
if _intersect:
|
||||
project.selection_map.clear()
|
||||
lasso_selection(_draw_points, project.selection_map, previous_selection_map)
|
||||
lasso_selection(_draw_points, project, previous_selection_map)
|
||||
# Handle mirroring
|
||||
var callable := lasso_selection.bind(project.selection_map, previous_selection_map)
|
||||
var callable := lasso_selection.bind(project, previous_selection_map)
|
||||
mirror_array(_draw_points, callable)
|
||||
Global.canvas.selection.big_bounding_rectangle = project.selection_map.get_used_rect()
|
||||
else:
|
||||
|
@ -128,8 +128,9 @@ func _clear() -> void:
|
|||
|
||||
|
||||
func lasso_selection(
|
||||
points: Array[Vector2i], selection_map: SelectionMap, previous_selection_map: SelectionMap
|
||||
points: Array[Vector2i], project: Project, previous_selection_map: SelectionMap
|
||||
) -> void:
|
||||
var selection_map := project.selection_map
|
||||
var selection_size := selection_map.get_size()
|
||||
var bounding_rect := Rect2i(points[0], Vector2i.ZERO)
|
||||
for point in points:
|
||||
|
@ -138,9 +139,9 @@ func lasso_selection(
|
|||
bounding_rect = bounding_rect.expand(point)
|
||||
if _intersect:
|
||||
if previous_selection_map.is_pixel_selected(point):
|
||||
selection_map.select_pixel(point, true)
|
||||
select_pixel(point, project, true)
|
||||
else:
|
||||
selection_map.select_pixel(point, !_subtract)
|
||||
select_pixel(point, project, !_subtract)
|
||||
|
||||
var v := Vector2i()
|
||||
for x in bounding_rect.size.x:
|
||||
|
@ -150,9 +151,17 @@ func lasso_selection(
|
|||
if Geometry2D.is_point_in_polygon(v, points):
|
||||
if _intersect:
|
||||
if previous_selection_map.is_pixel_selected(v):
|
||||
selection_map.select_pixel(v, true)
|
||||
select_pixel(v, project, true)
|
||||
else:
|
||||
selection_map.select_pixel(v, !_subtract)
|
||||
select_pixel(v, project, !_subtract)
|
||||
|
||||
|
||||
func select_pixel(point: Vector2i, project: Project, select: bool) -> void:
|
||||
if Tools.is_placing_tiles():
|
||||
var tilemap := project.get_current_cel() as CelTileMap
|
||||
var cell_position := tilemap.get_cell_position(point)
|
||||
select_tilemap_cell(tilemap, cell_position, project.selection_map, select)
|
||||
project.selection_map.select_pixel(point, select)
|
||||
|
||||
|
||||
# Bresenham's Algorithm
|
||||
|
|
|
@ -101,6 +101,11 @@ func apply_selection(pos: Vector2i) -> void:
|
|||
## Given an origin point and destination point, returns a rect representing
|
||||
## where the shape will be drawn and what is its size
|
||||
func _get_result_rect(origin: Vector2i, dest: Vector2i) -> Rect2i:
|
||||
if Tools.is_placing_tiles():
|
||||
var tileset := (Global.current_project.get_current_cel() as CelTileMap).tileset
|
||||
var grid_size := tileset.tile_size
|
||||
origin = Tools.snap_to_rectangular_grid_boundary(origin, grid_size)
|
||||
dest = Tools.snap_to_rectangular_grid_boundary(dest, grid_size)
|
||||
var rect := Rect2i()
|
||||
|
||||
# Center the rect on the mouse
|
||||
|
@ -125,6 +130,7 @@ func _get_result_rect(origin: Vector2i, dest: Vector2i) -> Rect2i:
|
|||
rect.position = Vector2i(mini(origin.x, dest.x), mini(origin.y, dest.y))
|
||||
rect.size = (origin - dest).abs()
|
||||
|
||||
rect.size += Vector2i.ONE
|
||||
if not Tools.is_placing_tiles():
|
||||
rect.size += Vector2i.ONE
|
||||
|
||||
return rect
|
||||
|
|
|
@ -65,7 +65,7 @@ func _pick_color(pos: Vector2i) -> void:
|
|||
pos = project.tiles.get_canon_position(pos)
|
||||
if pos.x < 0 or pos.y < 0:
|
||||
return
|
||||
if is_placing_tiles():
|
||||
if Tools.is_placing_tiles():
|
||||
var cel := Global.current_project.get_current_cel() as CelTileMap
|
||||
Tools.selected_tile_index_changed.emit(cel.get_cell_index_at_coords(pos))
|
||||
return
|
||||
|
|
|
@ -10,6 +10,7 @@ var text_edit: TextToolEdit:
|
|||
set(value):
|
||||
text_edit = value
|
||||
confirm_buttons.visible = is_instance_valid(text_edit)
|
||||
get_tree().current_scene.is_writing_text = is_instance_valid(text_edit)
|
||||
var text_size := 16
|
||||
var font := FontVariation.new()
|
||||
var font_name := "":
|
||||
|
|
|
@ -224,6 +224,10 @@ func _move_with_arrow_keys(event: InputEvent) -> void:
|
|||
if is_zero_approx(absf(move.y)):
|
||||
move.y = 0
|
||||
var final_direction := (move * step).round()
|
||||
if Tools.is_placing_tiles():
|
||||
var tileset := (Global.current_project.get_current_cel() as CelTileMap).tileset
|
||||
var grid_size := tileset.tile_size
|
||||
final_direction *= Vector2(grid_size)
|
||||
move_content(final_direction)
|
||||
|
||||
|
||||
|
@ -313,6 +317,8 @@ func _update_on_zoom() -> void:
|
|||
|
||||
|
||||
func _gizmo_resize() -> void:
|
||||
if Tools.is_placing_tiles():
|
||||
return
|
||||
var dir := dragged_gizmo.direction
|
||||
if Input.is_action_pressed("shape_center"):
|
||||
# Code inspired from https://github.com/GDQuest/godot-open-rpg
|
||||
|
@ -379,10 +385,11 @@ func resize_selection() -> void:
|
|||
else:
|
||||
Global.current_project.selection_map.copy_from(original_bitmap)
|
||||
if is_moving_content:
|
||||
content_pivot = original_big_bounding_rectangle.size / 2.0
|
||||
preview_image.copy_from(original_preview_image)
|
||||
DrawingAlgos.nn_rotate(preview_image, angle, content_pivot)
|
||||
preview_image.resize(size.x, size.y, Image.INTERPOLATE_NEAREST)
|
||||
if not Tools.is_placing_tiles():
|
||||
content_pivot = original_big_bounding_rectangle.size / 2.0
|
||||
DrawingAlgos.nn_rotate(preview_image, angle, content_pivot)
|
||||
preview_image.resize(size.x, size.y, Image.INTERPOLATE_NEAREST)
|
||||
if temp_rect.size.x < 0:
|
||||
preview_image.flip_x()
|
||||
if temp_rect.size.y < 0:
|
||||
|
@ -456,6 +463,15 @@ func move_borders(move: Vector2i) -> void:
|
|||
return
|
||||
marching_ants_outline.offset += Vector2(move)
|
||||
big_bounding_rectangle.position += move
|
||||
if Tools.is_placing_tiles():
|
||||
var tileset := (Global.current_project.get_current_cel() as CelTileMap).tileset
|
||||
var grid_size := tileset.tile_size
|
||||
marching_ants_outline.offset = Tools.snap_to_rectangular_grid_boundary(
|
||||
marching_ants_outline.offset, grid_size
|
||||
)
|
||||
big_bounding_rectangle.position = Vector2i(
|
||||
Tools.snap_to_rectangular_grid_boundary(big_bounding_rectangle.position, grid_size)
|
||||
)
|
||||
queue_redraw()
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue