1
0
Fork 0
mirror of https://github.com/Orama-Interactive/Pixelorama.git synced 2025-02-22 21:43:13 +00:00

Compare commits

...

3 commits

Author SHA1 Message Date
Emmanouil Papadeas
a0c7dd4527 Optimize the export dialog by caching all of the blended frames
No more slowness when changing the export settings. The only setting that causes the frames to be blended again is changing the layers.
2024-09-05 04:50:36 +03:00
Emmanouil Papadeas
9650dae678 Optimize the pencil & curve's fill inside option by making them check fewer pixels
Same logic as the previous commit
2024-09-05 03:50:37 +03:00
Emmanouil Papadeas
1e9c8487ba Optimize the lasso & polygon select tools by making them check fewer pixels
The time they take to complete now depends on the size of the selection, rather than checking all of the pixels of the entire canvas.
2024-09-05 03:34:30 +03:00
7 changed files with 47 additions and 25 deletions

View file

@ -46,6 +46,9 @@ var custom_exporter_generators := {}
var current_tab := ExportTab.IMAGE var current_tab := ExportTab.IMAGE
## All frames and their layers processed/blended into images ## All frames and their layers processed/blended into images
var processed_images: Array[ProcessedImage] = [] var processed_images: Array[ProcessedImage] = []
## Dictionary of [Frame] and [Image] that contains all of the blended frames.
## Changes when [method cache_blended_frames] is called.
var blended_frames := {}
var export_json := false var export_json := false
var split_layers := false var split_layers := false
var trim_sprite := false var trim_sprite := false
@ -137,6 +140,7 @@ func remove_custom_file_format(id: int) -> void:
func external_export(project := Global.current_project) -> void: func external_export(project := Global.current_project) -> void:
cache_blended_frames(project)
process_data(project) process_data(project)
export_processed_images(true, Global.export_dialog, project) export_processed_images(true, Global.export_dialog, project)
@ -149,6 +153,15 @@ func process_data(project := Global.current_project) -> void:
process_spritesheet(project) process_spritesheet(project)
func cache_blended_frames(project := Global.current_project) -> void:
blended_frames.clear()
var frames := _calculate_frames(project)
for frame in frames:
var image := Image.create(project.size.x, project.size.y, false, Image.FORMAT_RGBA8)
_blend_layers(image, frame)
blended_frames[frame] = image
func process_spritesheet(project := Global.current_project) -> void: func process_spritesheet(project := Global.current_project) -> void:
processed_images.clear() processed_images.clear()
# Range of frames determined by tags # Range of frames determined by tags
@ -252,7 +265,8 @@ func process_spritesheet(project := Global.current_project) -> void:
origin.y = project.size.y * tag_origins[0] origin.y = project.size.y * tag_origins[0]
origin.x = 0 origin.x = 0
tag_origins[0] += 1 tag_origins[0] += 1
_blend_layers(whole_image, frame, origin) whole_image.blend_rect(blended_frames[frame], Rect2i(Vector2i.ZERO, project.size), origin)
#_blend_layers(whole_image, frame, origin)
processed_images.append(ProcessedImage.new(whole_image, 0)) processed_images.append(ProcessedImage.new(whole_image, 0))
@ -271,7 +285,7 @@ func process_animation(project := Global.current_project) -> void:
) )
else: else:
var image := Image.create(project.size.x, project.size.y, false, Image.FORMAT_RGBA8) var image := Image.create(project.size.x, project.size.y, false, Image.FORMAT_RGBA8)
_blend_layers(image, frame) image.copy_from(blended_frames[frame])
if trim_sprite: if trim_sprite:
image = image.get_region(image.get_used_rect()) image = image.get_region(image.get_used_rect())
var duration := frame.duration * (1.0 / project.fps) var duration := frame.duration * (1.0 / project.fps)

View file

@ -3,6 +3,7 @@ extends "res://src/Tools/BaseDraw.gd"
var _curve := Curve2D.new() ## The [Curve2D] responsible for the shape of the curve being drawn. var _curve := Curve2D.new() ## The [Curve2D] responsible for the shape of the curve being drawn.
var _drawing := false ## Set to true when a curve is being drawn. var _drawing := false ## Set to true when a curve is being drawn.
var _fill := false ## When true, the inside area of the curve gets filled. var _fill := false ## When true, the inside area of the curve gets filled.
var _fill_inside_rect := Rect2i() ## The bounding box that surrounds the area that gets filled.
var _editing_bezier := false ## Needed to determine when to show the control points preview line. var _editing_bezier := false ## Needed to determine when to show the control points preview line.
var _editing_out_control_point := false ## True when controlling the out control point only. var _editing_out_control_point := false ## True when controlling the out control point only.
var _thickness := 1 ## The thickness of the curve. var _thickness := 1 ## The thickness of the curve.
@ -96,6 +97,7 @@ func draw_start(pos: Vector2i) -> void:
if !_drawing: if !_drawing:
_drawing = true _drawing = true
_curve.add_point(pos) _curve.add_point(pos)
_fill_inside_rect = Rect2i(pos, Vector2i.ZERO)
func draw_move(pos: Vector2i) -> void: func draw_move(pos: Vector2i) -> void:
@ -183,15 +185,15 @@ func _draw_shape() -> void:
for point in points: for point in points:
# Reset drawer every time because pixel perfect sometimes breaks the tool # Reset drawer every time because pixel perfect sometimes breaks the tool
_drawer.reset() _drawer.reset()
_fill_inside_rect = _fill_inside_rect.expand(point)
# Draw each point offsetted based on the shape's thickness # Draw each point offsetted based on the shape's thickness
_draw_pixel(point, images) _draw_pixel(point, images)
if _fill: if _fill:
var v := Vector2i() var v := Vector2i()
var image_size := Global.current_project.size for x in _fill_inside_rect.size.x:
for x in image_size.x: v.x = x + _fill_inside_rect.position.x
v.x = x for y in _fill_inside_rect.size.y:
for y in image_size.y: v.y = y + _fill_inside_rect.position.y
v.y = y
if Geometry2D.is_point_in_polygon(v, points): if Geometry2D.is_point_in_polygon(v, points):
_draw_pixel(v, images) _draw_pixel(v, images)
_clear() _clear()
@ -206,6 +208,7 @@ func _draw_pixel(point: Vector2i, images: Array[Image]) -> void:
func _clear() -> void: func _clear() -> void:
_curve.clear_points() _curve.clear_points()
_fill_inside_rect = Rect2i()
_drawing = false _drawing = false
_editing_out_control_point = false _editing_out_control_point = false
Global.canvas.previews.queue_redraw() Global.canvas.previews.queue_redraw()

View file

@ -5,6 +5,7 @@ var _last_position := Vector2i(Vector2.INF)
var _changed := false var _changed := false
var _overwrite := false var _overwrite := false
var _fill_inside := false var _fill_inside := false
var _fill_inside_rect := Rect2i() ## The bounding box that surrounds the area that gets filled.
var _draw_points := PackedVector2Array() var _draw_points := PackedVector2Array()
var _old_spacing_mode := false ## Needed to reset spacing mode in case we change it var _old_spacing_mode := false ## Needed to reset spacing mode in case we change it
@ -125,6 +126,7 @@ func draw_start(pos: Vector2i) -> void:
else: else:
if _fill_inside: if _fill_inside:
_draw_points.append(pos) _draw_points.append(pos)
_fill_inside_rect = Rect2i(pos, Vector2i.ZERO)
draw_tool(pos) draw_tool(pos)
_last_position = pos _last_position = pos
Global.canvas.sprite_changed_this_frame = true Global.canvas.sprite_changed_this_frame = true
@ -156,6 +158,7 @@ func draw_move(pos_i: Vector2i) -> void:
Global.canvas.sprite_changed_this_frame = true Global.canvas.sprite_changed_this_frame = true
if _fill_inside: if _fill_inside:
_draw_points.append(pos) _draw_points.append(pos)
_fill_inside_rect = _fill_inside_rect.expand(pos)
func draw_end(pos: Vector2i) -> void: func draw_end(pos: Vector2i) -> void:
@ -178,11 +181,10 @@ func draw_end(pos: Vector2i) -> void:
_draw_points.append(pos) _draw_points.append(pos)
if _draw_points.size() > 3: if _draw_points.size() > 3:
var v := Vector2i() var v := Vector2i()
var image_size := Global.current_project.size for x in _fill_inside_rect.size.x:
for x in image_size.x: v.x = x + _fill_inside_rect.position.x
v.x = x for y in _fill_inside_rect.size.y:
for y in image_size.y: v.y = y + _fill_inside_rect.position.y
v.y = y
if Geometry2D.is_point_in_polygon(v, _draw_points): if Geometry2D.is_point_in_polygon(v, _draw_points):
if _spacing_mode: if _spacing_mode:
# use of get_spacing_position() in Pencil.gd is a rare case # use of get_spacing_position() in Pencil.gd is a rare case
@ -190,6 +192,7 @@ func draw_end(pos: Vector2i) -> void:
v = get_spacing_position(v) v = get_spacing_position(v)
draw_tool(v) draw_tool(v)
_fill_inside_rect = Rect2i()
commit_undo() commit_undo()
cursor_text = "" cursor_text = ""
update_random_image() update_random_image()

View file

@ -111,11 +111,12 @@ func apply_selection(_position) -> void:
func lasso_selection( func lasso_selection(
selection_map: SelectionMap, previous_selection_map: SelectionMap, points: Array[Vector2i] selection_map: SelectionMap, previous_selection_map: SelectionMap, points: Array[Vector2i]
) -> void: ) -> void:
var project := Global.current_project
var selection_size := selection_map.get_size() var selection_size := selection_map.get_size()
var bounding_rect := Rect2i(points[0], Vector2i.ZERO)
for point in points: for point in points:
if point.x < 0 or point.y < 0 or point.x >= selection_size.x or point.y >= selection_size.y: if point.x < 0 or point.y < 0 or point.x >= selection_size.x or point.y >= selection_size.y:
continue continue
bounding_rect = bounding_rect.expand(point)
if _intersect: if _intersect:
if previous_selection_map.is_pixel_selected(point): if previous_selection_map.is_pixel_selected(point):
selection_map.select_pixel(point, true) selection_map.select_pixel(point, true)
@ -123,11 +124,10 @@ func lasso_selection(
selection_map.select_pixel(point, !_subtract) selection_map.select_pixel(point, !_subtract)
var v := Vector2i() var v := Vector2i()
var image_size := project.size for x in bounding_rect.size.x:
for x in image_size.x: v.x = x + bounding_rect.position.x
v.x = x for y in bounding_rect.size.y:
for y in image_size.y: v.y = y + bounding_rect.position.y
v.y = y
if Geometry2D.is_point_in_polygon(v, points): if Geometry2D.is_point_in_polygon(v, points):
if _intersect: if _intersect:
if previous_selection_map.is_pixel_selected(v): if previous_selection_map.is_pixel_selected(v):

View file

@ -154,11 +154,12 @@ func _clear() -> void:
func lasso_selection( func lasso_selection(
selection_map: SelectionMap, previous_selection_map: SelectionMap, points: Array[Vector2i] selection_map: SelectionMap, previous_selection_map: SelectionMap, points: Array[Vector2i]
) -> void: ) -> void:
var project := Global.current_project
var selection_size := selection_map.get_size() var selection_size := selection_map.get_size()
var bounding_rect := Rect2i(points[0], Vector2i.ZERO)
for point in points: for point in points:
if point.x < 0 or point.y < 0 or point.x >= selection_size.x or point.y >= selection_size.y: if point.x < 0 or point.y < 0 or point.x >= selection_size.x or point.y >= selection_size.y:
continue continue
bounding_rect = bounding_rect.expand(point)
if _intersect: if _intersect:
if previous_selection_map.is_pixel_selected(point): if previous_selection_map.is_pixel_selected(point):
selection_map.select_pixel(point, true) selection_map.select_pixel(point, true)
@ -166,11 +167,10 @@ func lasso_selection(
selection_map.select_pixel(point, !_subtract) selection_map.select_pixel(point, !_subtract)
var v := Vector2i() var v := Vector2i()
var image_size := project.size for x in bounding_rect.size.x:
for x in image_size.x: v.x = x + bounding_rect.position.x
v.x = x for y in bounding_rect.size.y:
for y in image_size.y: v.y = y + bounding_rect.position.y
v.y = y
if Geometry2D.is_point_in_polygon(v, points): if Geometry2D.is_point_in_polygon(v, points):
if _intersect: if _intersect:
if previous_selection_map.is_pixel_selected(v): if previous_selection_map.is_pixel_selected(v):

View file

@ -290,6 +290,7 @@ func _on_ExportDialog_about_to_show() -> void:
path_dialog_popup.current_dir = project.export_directory_path path_dialog_popup.current_dir = project.export_directory_path
file_line_edit.text = project.file_name file_line_edit.text = project.file_name
file_format_options.selected = project.file_format file_format_options.selected = project.file_format
Export.cache_blended_frames()
show_tab() show_tab()
# Set the size of the preview checker # Set the size of the preview checker
@ -472,6 +473,7 @@ func _on_Frames_item_selected(id: int) -> void:
func _on_Layers_item_selected(id: int) -> void: func _on_Layers_item_selected(id: int) -> void:
Export.export_layers = id Export.export_layers = id
Export.cache_blended_frames()
Export.process_data() Export.process_data()
set_preview() set_preview()

View file

@ -82,8 +82,8 @@ mouse_default_cursor_shape = 2
selected = 0 selected = 0
item_count = 4 item_count = 4
popup/item_0/text = "Columns" popup/item_0/text = "Columns"
popup/item_0/id = 1
popup/item_1/text = "Rows" popup/item_1/text = "Rows"
popup/item_1/id = 1
popup/item_2/text = "Tags by column" popup/item_2/text = "Tags by column"
popup/item_2/id = 2 popup/item_2/id = 2
popup/item_3/text = "Tags by row" popup/item_3/text = "Tags by row"