mirror of
https://github.com/Orama-Interactive/Pixelorama.git
synced 2025-02-22 05:23:14 +00:00
Performance boost
This commit is contained in:
parent
4a7f7cbde5
commit
3bd964c5b6
4 changed files with 69 additions and 31 deletions
|
@ -25,39 +25,39 @@ func blend_layers(
|
|||
only_selected_cels := false,
|
||||
only_selected_layers := false,
|
||||
) -> void:
|
||||
var frame_index := project.frames.find(frame)
|
||||
var frame_index: int = project.frames.find(frame)
|
||||
var previous_ordered_layers: Array[int] = project.ordered_layers
|
||||
project.order_layers(frame_index)
|
||||
var textures: Array[Image] = []
|
||||
# Nx4 texture, where N is the number of layers and the first row are the blend modes,
|
||||
# the second are the opacities, the third are the origins and the fourth are the
|
||||
# clipping mask booleans.
|
||||
var metadata_image := Image.create(project.layers.size(), 4, false, Image.FORMAT_R8)
|
||||
var metadata_image: Image = Image.create(project.layers.size(), 4, false, Image.FORMAT_R8)
|
||||
for i in project.layers.size():
|
||||
var ordered_index := project.ordered_layers[i]
|
||||
var layer := project.layers[ordered_index]
|
||||
var include := true if layer.is_visible_in_hierarchy() else false
|
||||
var ordered_index: int = project.ordered_layers[i]
|
||||
var layer: BaseLayer = project.layers[ordered_index]
|
||||
var include: bool = true if layer.is_visible_in_hierarchy() else false
|
||||
if only_selected_cels and include:
|
||||
var test_array := [frame_index, i]
|
||||
if not test_array in project.selected_cels:
|
||||
include = false
|
||||
if only_selected_layers and include:
|
||||
var layer_is_selected := false
|
||||
var layer_is_selected: bool = false
|
||||
for selected_cel in project.selected_cels:
|
||||
if i == selected_cel[1]:
|
||||
layer_is_selected = true
|
||||
break
|
||||
if not layer_is_selected:
|
||||
include = false
|
||||
var cel := frame.cels[ordered_index]
|
||||
var cel: BaseCel = frame.cels[ordered_index]
|
||||
if DisplayServer.get_name() == "headless":
|
||||
blend_layers_headless(image, project, layer, cel, origin)
|
||||
else:
|
||||
if layer is GroupLayer and layer.blend_mode != BaseLayer.BlendModes.PASS_THROUGH:
|
||||
var cel_image := (layer as GroupLayer).blend_children(frame)
|
||||
var cel_image: Image = (layer as GroupLayer).blend_children(frame)
|
||||
textures.append(cel_image)
|
||||
else:
|
||||
var cel_image := layer.display_effects(cel)
|
||||
var cel_image: Image = layer.display_effects(cel)
|
||||
textures.append(cel_image)
|
||||
if (
|
||||
layer.is_blended_by_ancestor()
|
||||
|
@ -67,13 +67,13 @@ func blend_layers(
|
|||
include = false
|
||||
set_layer_metadata_image(layer, cel, metadata_image, ordered_index, include)
|
||||
if DisplayServer.get_name() != "headless":
|
||||
var texture_array := Texture2DArray.new()
|
||||
var texture_array: Texture2DArray = Texture2DArray.new()
|
||||
texture_array.create_from_images(textures)
|
||||
var params := {
|
||||
"layers": texture_array,
|
||||
"metadata": ImageTexture.create_from_image(metadata_image),
|
||||
}
|
||||
var blended := Image.create(project.size.x, project.size.y, false, image.get_format())
|
||||
var blended: Image = Image.create(project.size.x, project.size.y, false, image.get_format())
|
||||
var gen := ShaderImageEffect.new()
|
||||
gen.generate_image(blended, blend_layers_shader, params, project.size)
|
||||
image.blend_rect(blended, Rect2i(Vector2i.ZERO, project.size), origin)
|
||||
|
|
|
@ -149,7 +149,14 @@ func process_data(project := Global.current_project) -> void:
|
|||
process_spritesheet(project)
|
||||
|
||||
|
||||
func process_spritesheet(project := Global.current_project) -> void:
|
||||
func process_spritesheet(project := Global.current_project, info_cache: Dictionary = {}) -> void:
|
||||
## info_cache stores the position of frame in the spritesheet and recycles the last created
|
||||
## spritesheet to construct a new one (only if info_cache is provided).
|
||||
## This causes significant performance boost for higher row or column values
|
||||
## (no significant increase in lower values).
|
||||
var old_spritesheet: Image
|
||||
if not info_cache.is_empty():
|
||||
old_spritesheet = processed_images[0].image
|
||||
processed_images.clear()
|
||||
# Range of frames determined by tags
|
||||
var frames := _calculate_frames(project)
|
||||
|
@ -192,6 +199,11 @@ func process_spritesheet(project := Global.current_project) -> void:
|
|||
var width := project.size.x * spritesheet_columns
|
||||
var height := project.size.y * spritesheet_rows
|
||||
var whole_image := Image.create(width, height, false, Image.FORMAT_RGBA8)
|
||||
if not info_cache.is_empty() and old_spritesheet:
|
||||
whole_image.blend_rect(
|
||||
old_spritesheet, Rect2i(Vector2i.ZERO, old_spritesheet.get_size()), Vector2i.ZERO
|
||||
)
|
||||
var old_origins = info_cache.values()
|
||||
var origin := Vector2i.ZERO
|
||||
var hh := 0
|
||||
var vv := 0
|
||||
|
@ -252,8 +264,17 @@ func process_spritesheet(project := Global.current_project) -> void:
|
|||
origin.y = project.size.y * tag_origins[0]
|
||||
origin.x = 0
|
||||
tag_origins[0] += 1
|
||||
old_origins.erase(origin)
|
||||
if frame in info_cache:
|
||||
if info_cache[frame] == origin:
|
||||
continue
|
||||
else:
|
||||
whole_image.fill_rect(Rect2i(origin, project.size), Color.TRANSPARENT)
|
||||
info_cache[frame] = origin
|
||||
_blend_layers(whole_image, frame, origin)
|
||||
|
||||
## remove redundant origins from image
|
||||
for useless in old_origins:
|
||||
whole_image.fill_rect(Rect2i(useless, project.size), Color.TRANSPARENT)
|
||||
processed_images.append(ProcessedImage.new(whole_image, 0))
|
||||
|
||||
|
||||
|
@ -671,7 +692,7 @@ func _blend_layers(
|
|||
# Attempt to read the image data directly from the pxo file, without having to blend
|
||||
# This is mostly useful for when running Pixelorama in headless mode
|
||||
# To handle exporting from a CLI
|
||||
var zip_reader := ZIPReader.new()
|
||||
var zip_reader: ZIPReader = ZIPReader.new()
|
||||
var err := zip_reader.open(project.save_path)
|
||||
if err == OK:
|
||||
var frame_index := project.frames.find(frame) + 1
|
||||
|
@ -679,8 +700,8 @@ func _blend_layers(
|
|||
if zip_reader.file_exists(image_path):
|
||||
# "Include blended" must be toggled on when saving the pxo file
|
||||
# in order for this to work.
|
||||
var image_data := zip_reader.read_file(image_path)
|
||||
var loaded_image := Image.create_from_data(
|
||||
var image_data: PackedByteArray = zip_reader.read_file(image_path)
|
||||
var loaded_image: Image = Image.create_from_data(
|
||||
project.size.x,
|
||||
project.size.y,
|
||||
image.has_mipmaps(),
|
||||
|
@ -698,8 +719,8 @@ func _blend_layers(
|
|||
elif export_layers == SELECTED_LAYERS:
|
||||
DrawingAlgos.blend_layers(image, frame, origin, project, false, true)
|
||||
else:
|
||||
var layer := project.layers[export_layers - 2]
|
||||
var layer_image := Image.new()
|
||||
var layer: BaseLayer = project.layers[export_layers - 2]
|
||||
var layer_image: Image = Image.new()
|
||||
if layer is GroupLayer:
|
||||
layer_image.copy_from(layer.blend_children(frame, Vector2i.ZERO))
|
||||
else:
|
||||
|
|
|
@ -6,7 +6,7 @@ signal about_to_preview(dict: Dictionary)
|
|||
|
||||
var preview_current_frame := 0
|
||||
var preview_frames: Array[Texture2D] = []
|
||||
|
||||
var spritesheet_info_cache = {}
|
||||
# Allow custom exporters to be added
|
||||
var image_exports: Array[Export.FileFormat] = [
|
||||
Export.FileFormat.PNG,
|
||||
|
@ -31,7 +31,7 @@ var _preview_images: Array[Export.ProcessedImage]
|
|||
@onready var previews: GridContainer = $"%Previews"
|
||||
|
||||
@onready var spritesheet_orientation: OptionButton = $"%Orientation"
|
||||
@onready var spritesheet_lines_count: SpinBox = $"%LinesCount"
|
||||
@onready var spritesheet_lines_count: ValueSlider = $"%LinesCount"
|
||||
@onready var spritesheet_lines_count_label: Label = $"%LinesCountLabel"
|
||||
|
||||
@onready var frames_option_button: OptionButton = $"%Frames"
|
||||
|
@ -51,6 +51,7 @@ var _preview_images: Array[Export.ProcessedImage]
|
|||
@onready var export_progress_popup: Window = $ExportProgressBar
|
||||
@onready var export_progress_bar := %ProgressBar as ProgressBar
|
||||
@onready var frame_timer: Timer = $FrameTimer
|
||||
@onready var spritesheet_update_timer: Timer = %SpritesheetUpdateTimer
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
|
@ -84,7 +85,8 @@ func show_tab() -> void:
|
|||
)
|
||||
Export.ExportTab.SPRITESHEET:
|
||||
frame_timer.stop()
|
||||
Export.process_spritesheet()
|
||||
spritesheet_info_cache.clear()
|
||||
Export.process_spritesheet(Global.current_project, spritesheet_info_cache)
|
||||
spritesheet_orientation.selected = Export.orientation
|
||||
spritesheet_lines_count.max_value = Export.number_of_frames
|
||||
spritesheet_lines_count.value = Export.lines_count
|
||||
|
@ -121,6 +123,7 @@ func add_image_preview(image: Image, canvas_number: int = -1) -> void:
|
|||
var container := create_preview_container()
|
||||
var preview := create_preview_rect()
|
||||
preview.texture = ImageTexture.create_from_image(image)
|
||||
preview.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
container.add_child(preview)
|
||||
|
||||
if canvas_number != -1:
|
||||
|
@ -145,6 +148,7 @@ func add_animated_preview() -> void:
|
|||
var preview := create_preview_rect()
|
||||
preview.name = "Preview"
|
||||
preview.texture = preview_frames[preview_current_frame]
|
||||
preview.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
container.add_child(preview)
|
||||
|
||||
previews.add_child(container)
|
||||
|
@ -305,9 +309,8 @@ func _on_Orientation_item_selected(id: Export.Orientation) -> void:
|
|||
Export.orientation = id
|
||||
_handle_orientation_ui()
|
||||
spritesheet_lines_count.value = Export.frames_divided_by_spritesheet_lines()
|
||||
Export.process_spritesheet()
|
||||
update_dimensions_label()
|
||||
set_preview()
|
||||
## Due to the above line, we don't have to process the spritesheet again
|
||||
## the value_changed signal will do this for us.
|
||||
|
||||
|
||||
func _handle_orientation_ui() -> void:
|
||||
|
@ -326,9 +329,8 @@ func _handle_orientation_ui() -> void:
|
|||
|
||||
func _on_LinesCount_value_changed(value: float) -> void:
|
||||
Export.lines_count = value
|
||||
Export.process_spritesheet()
|
||||
update_dimensions_label()
|
||||
set_preview()
|
||||
## Check if spritesheet needs to be updated (This is required when orientation gets changed)
|
||||
spritesheet_update_timer.start()
|
||||
|
||||
|
||||
func _on_Direction_item_selected(id: Export.AnimationDirection) -> void:
|
||||
|
@ -478,3 +480,9 @@ func _on_Layers_item_selected(id: int) -> void:
|
|||
|
||||
func _on_SeparatorCharacter_text_changed(new_text: String) -> void:
|
||||
Export.separator_character = new_text
|
||||
|
||||
|
||||
func _on_spritesheet_update_timer_timeout() -> void:
|
||||
Export.process_spritesheet(Global.current_project, spritesheet_info_cache)
|
||||
update_dimensions_label()
|
||||
set_preview()
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
[gd_scene load_steps=5 format=3 uid="uid://clgu8wb5o6oup"]
|
||||
[gd_scene load_steps=6 format=3 uid="uid://clgu8wb5o6oup"]
|
||||
|
||||
[ext_resource type="Script" path="res://src/UI/Dialogs/ExportDialog.gd" id="1"]
|
||||
[ext_resource type="PackedScene" uid="uid://3pmb60gpst7b" path="res://src/UI/Nodes/TransparentChecker.tscn" id="2"]
|
||||
[ext_resource type="Script" path="res://src/UI/Nodes/CollapsibleContainer.gd" id="3"]
|
||||
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/ValueSlider.tscn" id="3_u6gtq"]
|
||||
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="4"]
|
||||
|
||||
[node name="ExportDialog" type="ConfirmationDialog"]
|
||||
|
@ -84,6 +85,7 @@ item_count = 4
|
|||
popup/item_0/text = "Columns"
|
||||
popup/item_0/id = 1
|
||||
popup/item_1/text = "Rows"
|
||||
popup/item_1/id = 1
|
||||
popup/item_2/text = "Tags by column"
|
||||
popup/item_2/id = 2
|
||||
popup/item_3/text = "Tags by row"
|
||||
|
@ -94,11 +96,12 @@ unique_name_in_owner = true
|
|||
layout_mode = 2
|
||||
text = "Columns:"
|
||||
|
||||
[node name="LinesCount" type="SpinBox" parent="VBoxContainer/VSplitContainer/VBoxContainer/GridContainer" groups=["ExportSpritesheetOptions"]]
|
||||
[node name="LinesCount" parent="VBoxContainer/VSplitContainer/VBoxContainer/GridContainer" groups=["ExportSpritesheetOptions"] instance=ExtResource("3_u6gtq")]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(0, 0)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
mouse_default_cursor_shape = 2
|
||||
focus_mode = 0
|
||||
theme_type_variation = &""
|
||||
min_value = 1.0
|
||||
max_value = 1000.0
|
||||
value = 1.0
|
||||
|
@ -358,6 +361,11 @@ size_flags_horizontal = 3
|
|||
|
||||
[node name="FrameTimer" type="Timer" parent="."]
|
||||
|
||||
[node name="SpritesheetUpdateTimer" type="Timer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
wait_time = 0.2
|
||||
one_shot = true
|
||||
|
||||
[connection signal="about_to_popup" from="." to="." method="_on_ExportDialog_about_to_show"]
|
||||
[connection signal="confirmed" from="." to="." method="_on_ExportDialog_confirmed"]
|
||||
[connection signal="tab_clicked" from="VBoxContainer/TabBar" to="." method="_on_Tabs_tab_clicked"]
|
||||
|
@ -384,3 +392,4 @@ size_flags_horizontal = 3
|
|||
[connection signal="confirmed" from="FileExistsAlert" to="." method="_on_FileExistsAlert_confirmed"]
|
||||
[connection signal="custom_action" from="FileExistsAlert" to="." method="_on_FileExistsAlert_custom_action"]
|
||||
[connection signal="timeout" from="FrameTimer" to="." method="_on_FrameTimer_timeout"]
|
||||
[connection signal="timeout" from="SpritesheetUpdateTimer" to="." method="_on_spritesheet_update_timer_timeout"]
|
||||
|
|
Loading…
Add table
Reference in a new issue