mirror of
https://github.com/Orama-Interactive/Pixelorama.git
synced 2025-01-18 17:19:50 +00:00
Compare commits
2 commits
e0e328f967
...
2e589d6dcc
Author | SHA1 | Date | |
---|---|---|---|
2e589d6dcc | |||
adf250583c |
|
@ -1,3 +1,4 @@
|
|||
# gdlint: ignore=max-public-methods
|
||||
class_name CelTileMap
|
||||
extends PixelCel
|
||||
|
||||
|
@ -150,7 +151,7 @@ func get_cell_index_at_coords_in_tilemap_space(coords: Vector2i) -> int:
|
|||
|
||||
## Returns [code]true[/code] if the tile at cell position [param cell_position]
|
||||
## with image [param image_portion] is equal to [param tile_image].
|
||||
func tiles_equal(cell_position: int, image_portion: Image, tile_image: Image) -> bool:
|
||||
func _tiles_equal(cell_position: int, image_portion: Image, tile_image: Image) -> bool:
|
||||
var cell_data := cells[cell_position]
|
||||
var final_image_portion := transform_tile(
|
||||
tile_image, cell_data.flip_h, cell_data.flip_v, cell_data.transpose
|
||||
|
@ -187,6 +188,125 @@ func transform_tile(
|
|||
return transformed_tile
|
||||
|
||||
|
||||
## Given a [param selection_map] and a [param selection_rect],
|
||||
## the method finds the cells that are currently selected and returns them
|
||||
## in the form of a 2D array that contains the serialiazed data
|
||||
##of the selected cells in the form of [Dictionary].
|
||||
func get_selected_cells(selection_map: SelectionMap, selection_rect: Rect2i) -> Array[Array]:
|
||||
var selected_cells: Array[Array] = []
|
||||
for x in range(0, selection_rect.size.x, tileset.tile_size.x):
|
||||
selected_cells.append([])
|
||||
for y in range(0, selection_rect.size.y, tileset.tile_size.y):
|
||||
var pos := Vector2i(x, y) + selection_rect.position
|
||||
var x_index := x / tileset.tile_size.x
|
||||
if selection_map.is_pixel_selected(pos):
|
||||
var cell_pos := get_cell_position(pos)
|
||||
selected_cells[x_index].append(cells[cell_pos].serialize())
|
||||
else:
|
||||
# If it's not selected, append the transparent tile 0.
|
||||
selected_cells[x_index].append(
|
||||
{"index": 0, "flip_h": false, "flip_v": false, "transpose": false}
|
||||
)
|
||||
return selected_cells
|
||||
|
||||
|
||||
## Resizes [param selected_indices], which is an array of arrays of [Dictionary],
|
||||
## to [param horizontal_size] and [param vertical_size].
|
||||
## This method is used when resizing a selection and draw tiles mode is enabled.
|
||||
func resize_selection(
|
||||
selected_cells: Array[Array], horizontal_size: int, vertical_size: int
|
||||
) -> Array[Array]:
|
||||
var resized_cells: Array[Array] = []
|
||||
var current_columns := selected_cells.size()
|
||||
if current_columns == 0:
|
||||
return resized_cells
|
||||
var current_rows := selected_cells[0].size()
|
||||
if current_rows == 0:
|
||||
return resized_cells
|
||||
resized_cells.resize(horizontal_size)
|
||||
for x in horizontal_size:
|
||||
resized_cells[x] = []
|
||||
resized_cells[x].resize(vertical_size)
|
||||
var column_middles := current_columns - 2
|
||||
if current_columns == 1:
|
||||
for x in horizontal_size:
|
||||
_resize_rows(selected_cells[0], resized_cells[x], current_rows, vertical_size)
|
||||
else:
|
||||
for x in horizontal_size:
|
||||
if x == 0:
|
||||
_resize_rows(selected_cells[0], resized_cells[x], current_rows, vertical_size)
|
||||
elif x == horizontal_size - 1:
|
||||
_resize_rows(selected_cells[-1], resized_cells[x], current_rows, vertical_size)
|
||||
else:
|
||||
if x < current_columns - 1:
|
||||
_resize_rows(selected_cells[x], resized_cells[x], current_rows, vertical_size)
|
||||
else:
|
||||
if column_middles == 0:
|
||||
_resize_rows(
|
||||
selected_cells[-1], resized_cells[x], current_rows, vertical_size
|
||||
)
|
||||
else:
|
||||
var x_index := x - (column_middles * ((x - 1) / column_middles))
|
||||
_resize_rows(
|
||||
selected_cells[x_index], resized_cells[x], current_rows, vertical_size
|
||||
)
|
||||
return resized_cells
|
||||
|
||||
|
||||
## Helper method of [method resize_selection].
|
||||
func _resize_rows(
|
||||
selected_cells: Array, resized_cells: Array, current_rows: int, vertical_size: int
|
||||
) -> void:
|
||||
var row_middles := current_rows - 2
|
||||
if current_rows == 1:
|
||||
for y in vertical_size:
|
||||
resized_cells[y] = selected_cells[0]
|
||||
else:
|
||||
for y in vertical_size:
|
||||
if y == 0:
|
||||
resized_cells[y] = selected_cells[0]
|
||||
elif y == vertical_size - 1:
|
||||
resized_cells[y] = selected_cells[-1]
|
||||
else:
|
||||
if y < current_rows - 1:
|
||||
resized_cells[y] = selected_cells[y]
|
||||
else:
|
||||
if row_middles == 0:
|
||||
resized_cells[y] = selected_cells[-1]
|
||||
else:
|
||||
var y_index := y - (row_middles * ((y - 1) / row_middles))
|
||||
resized_cells[y] = selected_cells[y_index]
|
||||
|
||||
|
||||
## Applies the [param selected_cells] data to [param target_image] data,
|
||||
## offset by [param selection_rect]. The target image needs to be resized first.
|
||||
## This method is used when resizing a selection and draw tiles mode is enabled.
|
||||
func apply_resizing_to_image(
|
||||
target_image: Image, selected_cells: Array[Array], selection_rect: Rect2i
|
||||
) -> void:
|
||||
for x in selected_cells.size():
|
||||
for y in selected_cells[x].size():
|
||||
var pos := Vector2i(x, y) * tileset.tile_size + selection_rect.position
|
||||
var cell_pos := get_cell_position(pos)
|
||||
var coords := get_cell_coords_in_image(cell_pos) - selection_rect.position
|
||||
var rect := Rect2i(coords, tileset.tile_size)
|
||||
var image_portion := target_image.get_region(rect)
|
||||
var cell_data := Cell.new()
|
||||
cell_data.deserialize(selected_cells[x][y])
|
||||
var index := cell_data.index
|
||||
if index >= tileset.tiles.size():
|
||||
index = 0
|
||||
var current_tile := tileset.tiles[index].image
|
||||
var transformed_tile := transform_tile(
|
||||
current_tile, cell_data.flip_h, cell_data.flip_v, cell_data.transpose
|
||||
)
|
||||
if image_portion.get_data() != transformed_tile.get_data():
|
||||
var tile_size := transformed_tile.get_size()
|
||||
target_image.blit_rect(transformed_tile, Rect2i(Vector2i.ZERO, tile_size), coords)
|
||||
if target_image is ImageExtended:
|
||||
target_image.convert_rgb_to_indexed()
|
||||
|
||||
|
||||
## Appends data to a [Dictionary] to be used for undo/redo.
|
||||
func serialize_undo_data() -> Dictionary:
|
||||
var dict := {}
|
||||
|
@ -261,7 +381,7 @@ func update_tilemap(
|
|||
tileset.add_tile(image_portion, self)
|
||||
cells[i].index = tileset.tiles.size() - 1
|
||||
continue
|
||||
if not tiles_equal(i, image_portion, current_tile.image):
|
||||
if not _tiles_equal(i, image_portion, current_tile.image):
|
||||
tileset.replace_tile_at(image_portion, index, self)
|
||||
elif tile_editing_mode == TileSetPanel.TileEditingMode.AUTO:
|
||||
_handle_auto_editing_mode(i, image_portion, tileset_size_before_update)
|
||||
|
@ -271,7 +391,7 @@ func update_tilemap(
|
|||
var found_tile := false
|
||||
for j in range(1, tileset.tiles.size()):
|
||||
var tile := tileset.tiles[j]
|
||||
if tiles_equal(i, image_portion, tile.image):
|
||||
if _tiles_equal(i, image_portion, tile.image):
|
||||
if cells[i].index != j:
|
||||
cells[i].index = j
|
||||
cells[i].remove_transformations()
|
||||
|
@ -296,7 +416,7 @@ func update_tilemap(
|
|||
if index >= tileset.tiles.size():
|
||||
index = 0
|
||||
var current_tile := tileset.tiles[index]
|
||||
if not tiles_equal(i, image_portion, current_tile.image):
|
||||
if not _tiles_equal(i, image_portion, current_tile.image):
|
||||
set_index(i, cells[i].index)
|
||||
|
||||
|
||||
|
@ -371,7 +491,7 @@ func _handle_auto_editing_mode(
|
|||
tileset.add_tile(image_portion, self)
|
||||
cells[i].index = tileset.tiles.size() - 1
|
||||
else: # If the cell is already mapped.
|
||||
if tiles_equal(i, image_portion, current_tile.image):
|
||||
if _tiles_equal(i, image_portion, current_tile.image):
|
||||
# Case 3: The cell is mapped and it did not change.
|
||||
# Do nothing and move on to the next cell.
|
||||
return
|
||||
|
@ -452,12 +572,12 @@ func _re_index_all_cells() -> void:
|
|||
var index := cells[i].index
|
||||
if index > 0 and index < tileset.tiles.size():
|
||||
var current_tile := tileset.tiles[index]
|
||||
if not tiles_equal(i, image_portion, current_tile.image):
|
||||
if not _tiles_equal(i, image_portion, current_tile.image):
|
||||
set_index(i, cells[i].index)
|
||||
continue
|
||||
for j in range(1, tileset.tiles.size()):
|
||||
var tile := tileset.tiles[j]
|
||||
if tiles_equal(i, image_portion, tile.image):
|
||||
if _tiles_equal(i, image_portion, tile.image):
|
||||
cells[i].index = j
|
||||
break
|
||||
|
||||
|
@ -551,7 +671,7 @@ func update_texture(undo := false) -> void:
|
|||
var tile_size := image_portion.get_size()
|
||||
image.blit_rect(transformed_editing_image, Rect2i(Vector2i.ZERO, tile_size), coords)
|
||||
else:
|
||||
if not tiles_equal(i, image_portion, current_tile.image):
|
||||
if not _tiles_equal(i, image_portion, current_tile.image):
|
||||
var transformed_image := transform_tile(
|
||||
image_portion, cell_data.flip_h, cell_data.flip_v, cell_data.transpose, true
|
||||
)
|
||||
|
|
|
@ -28,7 +28,7 @@ var big_bounding_rectangle := Rect2i():
|
|||
if slot.tool_node is BaseSelectionTool:
|
||||
slot.tool_node.set_spinbox_values()
|
||||
_update_gizmos()
|
||||
var image_current_pixel := Vector2.ZERO ## The ACTUAL pixel coordinate of image
|
||||
var image_current_pixel := Vector2.ZERO ## The pixel coordinates of the cursor
|
||||
|
||||
var temp_rect := Rect2()
|
||||
var rect_aspect_ratio := 0.0
|
||||
|
@ -38,6 +38,7 @@ var original_big_bounding_rectangle := Rect2i()
|
|||
var original_preview_image := Image.new()
|
||||
var original_bitmap := SelectionMap.new()
|
||||
var original_offset := Vector2.ZERO
|
||||
var original_selected_tilemap_cells: Array[Array]
|
||||
|
||||
var preview_image := Image.new()
|
||||
var preview_image_texture := ImageTexture.new()
|
||||
|
@ -317,20 +318,22 @@ func _update_on_zoom() -> void:
|
|||
|
||||
|
||||
func _gizmo_resize() -> void:
|
||||
if Tools.is_placing_tiles():
|
||||
return
|
||||
var dir := dragged_gizmo.direction
|
||||
var mouse_pos := image_current_pixel
|
||||
if Tools.is_placing_tiles():
|
||||
var tilemap := Global.current_project.get_current_cel() as CelTileMap
|
||||
mouse_pos = mouse_pos.snapped(tilemap.tileset.tile_size)
|
||||
if Input.is_action_pressed("shape_center"):
|
||||
# Code inspired from https://github.com/GDQuest/godot-open-rpg
|
||||
if dir.x != 0 and dir.y != 0: # Border gizmos
|
||||
temp_rect.size = ((image_current_pixel - temp_rect_pivot) * 2.0 * Vector2(dir))
|
||||
temp_rect.size = ((mouse_pos - temp_rect_pivot) * 2.0 * Vector2(dir))
|
||||
elif dir.y == 0: # Center left and right gizmos
|
||||
temp_rect.size.x = (image_current_pixel.x - temp_rect_pivot.x) * 2.0 * dir.x
|
||||
temp_rect.size.x = (mouse_pos.x - temp_rect_pivot.x) * 2.0 * dir.x
|
||||
elif dir.x == 0: # Center top and bottom gizmos
|
||||
temp_rect.size.y = (image_current_pixel.y - temp_rect_pivot.y) * 2.0 * dir.y
|
||||
temp_rect.size.y = (mouse_pos.y - temp_rect_pivot.y) * 2.0 * dir.y
|
||||
temp_rect = Rect2(-1.0 * temp_rect.size / 2 + temp_rect_pivot, temp_rect.size)
|
||||
else:
|
||||
_resize_rect(image_current_pixel, dir)
|
||||
_resize_rect(mouse_pos, dir)
|
||||
|
||||
if Input.is_action_pressed("shape_perfect") or resize_keep_ratio: # Maintain aspect ratio
|
||||
var end_y := temp_rect.end.y
|
||||
|
@ -386,14 +389,28 @@ func resize_selection() -> void:
|
|||
Global.current_project.selection_map.copy_from(original_bitmap)
|
||||
if is_moving_content:
|
||||
preview_image.copy_from(original_preview_image)
|
||||
if not Tools.is_placing_tiles():
|
||||
if Tools.is_placing_tiles():
|
||||
for cel in _get_selected_draw_cels():
|
||||
if cel is not CelTileMap:
|
||||
continue
|
||||
var tilemap := cel as CelTileMap
|
||||
var horizontal_size := size.x / tilemap.tileset.tile_size.x
|
||||
var vertical_size := size.y / tilemap.tileset.tile_size.y
|
||||
var selected_cells := tilemap.resize_selection(
|
||||
original_selected_tilemap_cells, horizontal_size, vertical_size
|
||||
)
|
||||
preview_image.crop(size.x, size.y)
|
||||
tilemap.apply_resizing_to_image(
|
||||
preview_image, selected_cells, big_bounding_rectangle
|
||||
)
|
||||
else:
|
||||
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:
|
||||
preview_image.flip_y()
|
||||
if temp_rect.size.x < 0:
|
||||
preview_image.flip_x()
|
||||
if temp_rect.size.y < 0:
|
||||
preview_image.flip_y()
|
||||
preview_image_texture = ImageTexture.create_from_image(preview_image)
|
||||
|
||||
Global.current_project.selection_map.copy_from(original_bitmap)
|
||||
|
@ -495,9 +512,15 @@ func transform_content_start() -> void:
|
|||
undo_data = get_undo_data(false)
|
||||
return
|
||||
is_moving_content = true
|
||||
original_bitmap.copy_from(Global.current_project.selection_map)
|
||||
var project := Global.current_project
|
||||
original_bitmap.copy_from(project.selection_map)
|
||||
original_big_bounding_rectangle = big_bounding_rectangle
|
||||
original_offset = Global.current_project.selection_offset
|
||||
original_offset = project.selection_offset
|
||||
var current_cel := project.get_current_cel()
|
||||
if current_cel is CelTileMap:
|
||||
original_selected_tilemap_cells = (current_cel as CelTileMap).get_selected_cells(
|
||||
project.selection_map, big_bounding_rectangle
|
||||
)
|
||||
queue_redraw()
|
||||
canvas.queue_redraw()
|
||||
|
||||
|
@ -517,21 +540,40 @@ func transform_content_confirm() -> void:
|
|||
if not is_pasting:
|
||||
src.copy_from(cel.transformed_content)
|
||||
cel.transformed_content = null
|
||||
DrawingAlgos.nn_rotate(src, angle, content_pivot)
|
||||
src.resize(
|
||||
preview_image.get_width(), preview_image.get_height(), Image.INTERPOLATE_NEAREST
|
||||
)
|
||||
if temp_rect.size.x < 0:
|
||||
src.flip_x()
|
||||
if temp_rect.size.y < 0:
|
||||
src.flip_y()
|
||||
if Tools.is_placing_tiles():
|
||||
if cel is not CelTileMap:
|
||||
continue
|
||||
var tilemap := cel as CelTileMap
|
||||
var horizontal_size := preview_image.get_width() / tilemap.tileset.tile_size.x
|
||||
var vertical_size := preview_image.get_height() / tilemap.tileset.tile_size.y
|
||||
var selected_cells := tilemap.resize_selection(
|
||||
original_selected_tilemap_cells, horizontal_size, vertical_size
|
||||
)
|
||||
src.crop(preview_image.get_width(), preview_image.get_height())
|
||||
tilemap.apply_resizing_to_image(src, selected_cells, big_bounding_rectangle)
|
||||
else:
|
||||
DrawingAlgos.nn_rotate(src, angle, content_pivot)
|
||||
src.resize(
|
||||
preview_image.get_width(), preview_image.get_height(), Image.INTERPOLATE_NEAREST
|
||||
)
|
||||
if temp_rect.size.x < 0:
|
||||
src.flip_x()
|
||||
if temp_rect.size.y < 0:
|
||||
src.flip_y()
|
||||
|
||||
cel_image.blit_rect_mask(
|
||||
src,
|
||||
src,
|
||||
Rect2i(Vector2i.ZERO, project.selection_map.get_size()),
|
||||
big_bounding_rectangle.position
|
||||
)
|
||||
if Tools.is_placing_tiles():
|
||||
cel_image.blit_rect(
|
||||
src,
|
||||
Rect2i(Vector2i.ZERO, project.selection_map.get_size()),
|
||||
big_bounding_rectangle.position
|
||||
)
|
||||
else:
|
||||
cel_image.blit_rect_mask(
|
||||
src,
|
||||
src,
|
||||
Rect2i(Vector2i.ZERO, project.selection_map.get_size()),
|
||||
big_bounding_rectangle.position
|
||||
)
|
||||
cel_image.convert_rgb_to_indexed()
|
||||
project.selection_map.move_bitmap_values(project)
|
||||
commit_undo("Move Selection", undo_data)
|
||||
|
@ -539,6 +581,7 @@ func transform_content_confirm() -> void:
|
|||
original_preview_image = Image.new()
|
||||
preview_image = Image.new()
|
||||
original_bitmap = SelectionMap.new()
|
||||
original_selected_tilemap_cells.clear()
|
||||
is_moving_content = false
|
||||
is_pasting = false
|
||||
angle = 0.0
|
||||
|
@ -573,6 +616,7 @@ func transform_content_cancel() -> void:
|
|||
original_preview_image = Image.new()
|
||||
preview_image = Image.new()
|
||||
original_bitmap = SelectionMap.new()
|
||||
original_selected_tilemap_cells.clear()
|
||||
is_pasting = false
|
||||
angle = 0.0
|
||||
content_pivot = Vector2.ZERO
|
||||
|
|
Loading…
Reference in a new issue