249 lines
7.7 KiB
GDScript
249 lines
7.7 KiB
GDScript
@tool
|
|
extends RefCounted
|
|
|
|
|
|
# ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ PUBLIC ░░░░
|
|
func export_file(file_name: String, output_folder: String, options: Dictionary) -> Dictionary:
|
|
var exception_pattern = options.get('exception_pattern', "")
|
|
var only_visible_layers = options.get('only_visible_layers', false)
|
|
var output_name = (
|
|
file_name if options.get('output_filename') == ""
|
|
else options.get('output_filename', file_name)
|
|
)
|
|
var basename = _get_file_basename(output_name)
|
|
var output_dir = output_folder.replace("res://", "./")
|
|
var data_file = "%s/%s.json" % [output_dir, basename]
|
|
var sprite_sheet = "%s/%s.png" % [output_dir, basename]
|
|
var output = []
|
|
var arguments = _export_command_common_arguments(file_name, data_file, sprite_sheet)
|
|
|
|
if not only_visible_layers:
|
|
arguments.push_front("--all-layers")
|
|
|
|
_add_sheet_type_arguments(arguments, options)
|
|
|
|
_add_ignore_layer_arguments(file_name, arguments, exception_pattern)
|
|
|
|
var exit_code = _execute(arguments, output)
|
|
if exit_code != 0:
|
|
printerr('[Popochiu] Aseprite: failed to export spritesheet')
|
|
printerr(output)
|
|
return {}
|
|
|
|
return {
|
|
'data_file': data_file.replace("./", "res://"),
|
|
"sprite_sheet": sprite_sheet.replace("./", "res://")
|
|
}
|
|
|
|
|
|
func export_layers(file_name: String, output_folder: String, options: Dictionary) -> Array:
|
|
var exception_pattern = options.get('exception_pattern', "")
|
|
var only_visible_layers = options.get('only_visible_layers', false)
|
|
var basename = _get_file_basename(file_name)
|
|
var layers = list_layers(file_name, only_visible_layers)
|
|
var exception_regex = _compile_regex(exception_pattern)
|
|
|
|
var output = []
|
|
|
|
for layer in layers:
|
|
if layer != "" and (not exception_regex or exception_regex.search(layer) == null):
|
|
output.push_back(export_layer(file_name, layer, output_folder, options))
|
|
|
|
return output
|
|
|
|
|
|
func export_layer(file_name: String, layer_name: String, output_folder: String, options: Dictionary) -> Dictionary:
|
|
var output_prefix = options.get('output_filename', "").strip_edges()
|
|
var output_dir = output_folder.replace("res://", "./").strip_edges()
|
|
var data_file = "%s/%s%s.json" % [output_dir, output_prefix, layer_name]
|
|
var sprite_sheet = "%s/%s%s.png" % [output_dir, output_prefix, layer_name]
|
|
var output = []
|
|
var arguments = _export_command_common_arguments(file_name, data_file, sprite_sheet)
|
|
arguments.push_front(layer_name)
|
|
arguments.push_front("--layer")
|
|
|
|
_add_sheet_type_arguments(arguments, options)
|
|
|
|
var exit_code = _execute(arguments, output)
|
|
if exit_code != 0:
|
|
printerr('[Popochiu] Aseprite: Failed to export layer spritesheet. Command output follows:')
|
|
print(output)
|
|
return {}
|
|
|
|
return {
|
|
'data_file': data_file.replace("./", "res://"),
|
|
"sprite_sheet": sprite_sheet.replace("./", "res://")
|
|
}
|
|
|
|
|
|
# IMPROVE: See if we can extract JSON data limited to the single tag
|
|
# (so we don't have to reckon offset framerange)
|
|
func export_tag(file_name: String, tag_name: String, output_folder: String, options: Dictionary) -> Dictionary:
|
|
var output_prefix = options.get('output_filename', "").strip_edges()
|
|
var output_dir = output_folder.replace("res://", "./").strip_edges()
|
|
var data_file = "%s/%s%s.json" % [output_dir, output_prefix, tag_name]
|
|
var sprite_sheet = "%s/%s%s.png" % [output_dir, output_prefix, tag_name]
|
|
var output = []
|
|
var arguments = _export_command_common_arguments(file_name, data_file, sprite_sheet)
|
|
arguments.push_front(tag_name)
|
|
arguments.push_front("--tag")
|
|
|
|
_add_sheet_type_arguments(arguments, options)
|
|
|
|
var exit_code = _execute(arguments, output)
|
|
if exit_code != 0:
|
|
printerr('[Popochiu] Aseprite: Failed to export tag spritesheet. Command output follows:')
|
|
print(output)
|
|
return {}
|
|
|
|
return {
|
|
'data_file': data_file.replace("./", "res://"),
|
|
"sprite_sheet": sprite_sheet.replace("./", "res://")
|
|
}
|
|
|
|
|
|
func list_layers(file_name: String, only_visible = false) -> Array:
|
|
var output = []
|
|
var arguments = ["-b", "--list-layers", file_name]
|
|
|
|
if not only_visible:
|
|
arguments.push_front("--all-layers")
|
|
|
|
var exit_code = _execute(arguments, output)
|
|
|
|
if exit_code != 0:
|
|
printerr('[Popochiu] Aseprite: failed listing layers')
|
|
printerr(output)
|
|
return []
|
|
|
|
return _sanitize_list_output(output)
|
|
|
|
|
|
func list_tags(file_name: String) -> Array:
|
|
var output = []
|
|
var arguments = ["-b", "--list-tags", file_name]
|
|
|
|
var exit_code = _execute(arguments, output)
|
|
|
|
if exit_code != 0:
|
|
printerr('[Popochiu] Aseprite: failed listing tags')
|
|
printerr(output)
|
|
return []
|
|
|
|
return _sanitize_list_output(output)
|
|
|
|
|
|
func is_valid_spritesheet(content):
|
|
return content.has("frames") and content.has("meta") and content.meta.has('image')
|
|
|
|
|
|
func get_content_frames(content):
|
|
return content.frames if typeof(content.frames) == TYPE_ARRAY else content.frames.values()
|
|
|
|
|
|
func get_content_meta_tags(content):
|
|
return content.meta.frameTags if content.meta.has("frameTags") else []
|
|
|
|
|
|
func check_command_path():
|
|
# On Linux, MacOS or other *nix platforms, nothing to do
|
|
if not OS.get_name() in ["Windows", "UWP"]:
|
|
return true
|
|
|
|
# On Windows, OS.Execute() calls trigger an uncatchable
|
|
# internal error if the invoked executable is not found.
|
|
# Since the error is unclear, we have to check that the aseprite
|
|
# command is given as a full path and return an error if it's not.
|
|
var regex = RegEx.new()
|
|
regex.compile("^[A-Z|a-z]:[\\\\|\\/].+\\.exe$")
|
|
return \
|
|
regex.search(_get_aseprite_command()) \
|
|
and \
|
|
FileAccess.file_exists(_get_aseprite_command())
|
|
|
|
|
|
func test_command():
|
|
var exit_code = OS.execute(_get_aseprite_command(), ['--version'], [], true)
|
|
return exit_code == 0
|
|
|
|
|
|
|
|
# ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ PRIVATE ░░░░
|
|
func _add_ignore_layer_arguments(file_name: String, arguments: Array, exception_pattern: String):
|
|
var layers = _get_exception_layers(file_name, exception_pattern)
|
|
if not layers.is_empty():
|
|
for l in layers:
|
|
arguments.push_front(l)
|
|
arguments.push_front('--ignore-layer')
|
|
|
|
|
|
func _add_sheet_type_arguments(arguments: Array, options : Dictionary):
|
|
var column_count : int = options.get("column_count", 0)
|
|
if column_count > 0:
|
|
arguments.push_back("--merge-duplicates") # Yes, this is undocumented
|
|
arguments.push_back("--sheet-columns")
|
|
arguments.push_back(column_count)
|
|
else:
|
|
arguments.push_back("--sheet-pack")
|
|
|
|
|
|
func _get_exception_layers(file_name: String, exception_pattern: String) -> Array:
|
|
var layers = list_layers(file_name)
|
|
var regex = _compile_regex(exception_pattern)
|
|
if regex == null:
|
|
return []
|
|
|
|
var exception_layers = []
|
|
for layer in layers:
|
|
if regex.search(layer) != null:
|
|
exception_layers.push_back(layer)
|
|
|
|
return exception_layers
|
|
|
|
|
|
func _sanitize_list_output(output) -> Array:
|
|
if output.is_empty():
|
|
return output
|
|
|
|
var raw = output[0].split('\n')
|
|
var sanitized = []
|
|
for s in raw:
|
|
sanitized.append(s.strip_edges())
|
|
return sanitized
|
|
|
|
|
|
func _export_command_common_arguments(source_name: String, data_path: String, spritesheet_path: String) -> Array:
|
|
return [
|
|
"-b",
|
|
"--list-tags",
|
|
"--data",
|
|
data_path,
|
|
"--format",
|
|
"json-array",
|
|
"--sheet",
|
|
spritesheet_path,
|
|
source_name
|
|
]
|
|
|
|
|
|
func _execute(arguments, output):
|
|
return OS.execute(_get_aseprite_command(), arguments, output, true, true)
|
|
|
|
|
|
func _get_aseprite_command() -> String:
|
|
return PopochiuEditorConfig.get_command()
|
|
|
|
|
|
func _get_file_basename(file_path: String) -> String:
|
|
return file_path.get_file().trim_suffix('.%s' % file_path.get_extension())
|
|
|
|
|
|
func _compile_regex(pattern):
|
|
if pattern == "":
|
|
return
|
|
|
|
var rgx = RegEx.new()
|
|
if rgx.compile(pattern) == OK:
|
|
return rgx
|
|
|
|
printerr('[Popochiu] exception regex error')
|