init
This commit is contained in:
283
addons/AsepriteWizard/aseprite/aseprite.gd
Normal file
283
addons/AsepriteWizard/aseprite/aseprite.gd
Normal file
@@ -0,0 +1,283 @@
|
||||
@tool
|
||||
extends RefCounted
|
||||
|
||||
var _config
|
||||
|
||||
func init(config):
|
||||
_config = config
|
||||
|
||||
#
|
||||
# Output:
|
||||
# {
|
||||
# "data_file": file path to the json file
|
||||
# "sprite_sheet": file path to the raw image file
|
||||
# }
|
||||
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 first_frame_only = options.get("first_frame_only", false)
|
||||
var basename = _get_file_basename(output_name)
|
||||
var output_dir = ProjectSettings.globalize_path(output_folder)
|
||||
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")
|
||||
|
||||
if first_frame_only:
|
||||
arguments.push_front("'[0, 0]'")
|
||||
arguments.push_front("--frame-range")
|
||||
|
||||
_add_sheet_type_arguments(arguments, options)
|
||||
|
||||
_add_ignore_layer_arguments(file_name, arguments, exception_pattern)
|
||||
|
||||
var local_sprite_sheet_path = ProjectSettings.localize_path(sprite_sheet)
|
||||
var is_new = not ResourceLoader.exists(local_sprite_sheet_path)
|
||||
|
||||
var exit_code = _execute(arguments, output)
|
||||
if exit_code != 0:
|
||||
printerr('aseprite: failed to export spritesheet')
|
||||
printerr(output)
|
||||
return {}
|
||||
|
||||
return {
|
||||
"data_file": ProjectSettings.localize_path(data_file),
|
||||
"sprite_sheet": local_sprite_sheet_path,
|
||||
"is_first_import": is_new,
|
||||
}
|
||||
|
||||
|
||||
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 first_frame_only = options.get("first_frame_only", false)
|
||||
var output = []
|
||||
var arguments = _export_command_common_arguments(file_name, data_file, sprite_sheet)
|
||||
arguments.push_front(layer_name)
|
||||
arguments.push_front("--layer")
|
||||
|
||||
if first_frame_only:
|
||||
arguments.push_front("'[0, 0]'")
|
||||
arguments.push_front("--frame-range")
|
||||
|
||||
_add_sheet_type_arguments(arguments, options)
|
||||
|
||||
var local_sprite_sheet_path = ProjectSettings.localize_path(sprite_sheet)
|
||||
var is_new = not ResourceLoader.exists(local_sprite_sheet_path)
|
||||
|
||||
var exit_code = _execute(arguments, output)
|
||||
if exit_code != 0:
|
||||
print('aseprite: failed to export layer spritesheet')
|
||||
print(output)
|
||||
return {}
|
||||
|
||||
return {
|
||||
"data_file": ProjectSettings.localize_path(data_file),
|
||||
"sprite_sheet": local_sprite_sheet_path,
|
||||
"is_first_import": is_new,
|
||||
}
|
||||
|
||||
|
||||
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 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('aseprite: failed listing layers')
|
||||
printerr(output)
|
||||
return []
|
||||
|
||||
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 list_slices(file_name: String) -> Array:
|
||||
var output = []
|
||||
var arguments = ["-b", "--list-slices", file_name]
|
||||
|
||||
var exit_code = _execute(arguments, output)
|
||||
|
||||
if exit_code != 0:
|
||||
printerr('aseprite: failed listing slices')
|
||||
printerr(output)
|
||||
return []
|
||||
|
||||
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",
|
||||
"--list-slices",
|
||||
"--data",
|
||||
data_path,
|
||||
"--format",
|
||||
"json-array",
|
||||
"--sheet",
|
||||
spritesheet_path,
|
||||
source_name
|
||||
]
|
||||
|
||||
|
||||
func _execute(arguments, output):
|
||||
return OS.execute(_aseprite_command(), arguments, output, true, true)
|
||||
|
||||
|
||||
func _aseprite_command() -> String:
|
||||
return _config.is_command_or_control_pressed()
|
||||
|
||||
|
||||
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('exception regex error')
|
||||
|
||||
|
||||
func test_command():
|
||||
var exit_code = OS.execute(_aseprite_command(), ['--version'], [], true)
|
||||
return exit_code == 0
|
||||
|
||||
|
||||
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_slice_rect(content: Dictionary, slice_name: String) -> Variant:
|
||||
if not content.has("meta") or not content.meta.has("slices"):
|
||||
return null
|
||||
for slice in content.meta.slices:
|
||||
if slice.name == slice_name:
|
||||
if slice.keys.size() > 0:
|
||||
var p = slice.keys[0].bounds
|
||||
return Rect2(p.x, p.y, p.w, p.h)
|
||||
return null
|
||||
|
||||
|
||||
##
|
||||
## Exports tileset layers
|
||||
##
|
||||
## Return (dictionary):
|
||||
## data_file: path to aseprite generated JSON file
|
||||
## sprite_sheet: localized path to spritesheet file
|
||||
func export_tileset_texture(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 = ProjectSettings.globalize_path(output_folder)
|
||||
var data_path = "%s/%s.json" % [output_dir, basename]
|
||||
var sprite_sheet = "%s/%s.png" % [output_dir, basename]
|
||||
var output = []
|
||||
|
||||
var arguments = [
|
||||
"-b",
|
||||
"--export-tileset",
|
||||
"--data",
|
||||
data_path,
|
||||
"--format",
|
||||
"json-array",
|
||||
"--sheet",
|
||||
sprite_sheet,
|
||||
file_name
|
||||
]
|
||||
|
||||
if not only_visible_layers:
|
||||
arguments.push_front("--all-layers")
|
||||
|
||||
_add_ignore_layer_arguments(file_name, arguments, exception_pattern)
|
||||
|
||||
var exit_code = _execute(arguments, output)
|
||||
if exit_code != 0:
|
||||
printerr('aseprite: failed to export spritesheet')
|
||||
printerr(output)
|
||||
return {}
|
||||
|
||||
return {
|
||||
"data_file": ProjectSettings.localize_path(data_path),
|
||||
"sprite_sheet": ProjectSettings.localize_path(sprite_sheet)
|
||||
}
|
||||
146
addons/AsepriteWizard/aseprite/file_exporter.gd
Normal file
146
addons/AsepriteWizard/aseprite/file_exporter.gd
Normal file
@@ -0,0 +1,146 @@
|
||||
@tool
|
||||
extends RefCounted
|
||||
|
||||
var result_code = preload("../config/result_codes.gd")
|
||||
var _aseprite = preload("aseprite.gd").new()
|
||||
|
||||
enum {
|
||||
FILE_EXPORT_MODE,
|
||||
LAYERS_EXPORT_MODE
|
||||
}
|
||||
|
||||
func init(config):
|
||||
_aseprite.init(config)
|
||||
|
||||
##
|
||||
## Generate Aseprite spritesheet and data files for source.
|
||||
##
|
||||
## Options:
|
||||
## output_folder (string)
|
||||
## output_filename (string, optional)
|
||||
## export_mode (FILE_EXPORT_MODE, LAYERS_EXPORT_MODE) default: FILE_EXPORT_MODE
|
||||
## exception_pattern (string, optional)
|
||||
## only_visible_layers (boolean, optional)
|
||||
##
|
||||
## Return:
|
||||
## Array
|
||||
## Dictionary
|
||||
## sprite_sheet: sprite sheet path
|
||||
## data_file: json file path
|
||||
##
|
||||
func generate_aseprite_files(source_file: String, options: Dictionary):
|
||||
var check = _initial_checks(source_file, options)
|
||||
|
||||
if check != result_code.SUCCESS:
|
||||
return result_code.error(check)
|
||||
|
||||
match options.get('export_mode', FILE_EXPORT_MODE):
|
||||
FILE_EXPORT_MODE:
|
||||
var output = _aseprite.export_file(source_file, options.output_folder, options)
|
||||
if output.is_empty():
|
||||
return result_code.error(result_code.ERR_ASEPRITE_EXPORT_FAILED)
|
||||
return result_code.result([output])
|
||||
LAYERS_EXPORT_MODE:
|
||||
var output = _aseprite.export_layers(source_file, options.output_folder, options)
|
||||
if output.is_empty():
|
||||
return result_code.error(result_code.ERR_NO_VALID_LAYERS_FOUND)
|
||||
return result_code.result(output)
|
||||
_:
|
||||
return result_code.error(result_code.ERR_UNKNOWN_EXPORT_MODE)
|
||||
|
||||
|
||||
##
|
||||
## Generate Aseprite spritesheet and data file for source.
|
||||
##
|
||||
## Options:
|
||||
## output_folder (string)
|
||||
## output_filename (string, optional)
|
||||
## layer (string, optional)
|
||||
## exception_pattern (string, optional)
|
||||
## only_visible_layers (boolean, optional)
|
||||
##
|
||||
## Return:
|
||||
## Dictionary
|
||||
## sprite_sheet: sprite sheet path
|
||||
## data_file: json file path
|
||||
##
|
||||
func generate_aseprite_file(source_file: String, options: Dictionary) -> Dictionary:
|
||||
var check = _initial_checks(source_file, options)
|
||||
|
||||
if check != result_code.SUCCESS:
|
||||
return result_code.error(check)
|
||||
|
||||
var output
|
||||
|
||||
if options.get("layer", "") == "":
|
||||
output = _aseprite.export_file(source_file, options.output_folder, options)
|
||||
else:
|
||||
output = _aseprite.export_layer(source_file, options.layer, options.output_folder, options)
|
||||
|
||||
if output.is_empty():
|
||||
return result_code.error(result_code.ERR_ASEPRITE_EXPORT_FAILED)
|
||||
|
||||
return result_code.result(output)
|
||||
|
||||
|
||||
##
|
||||
## Generate a spritesheet with all tilesets in the file
|
||||
##
|
||||
## Options:
|
||||
## exception_pattern (string)
|
||||
## only_visible_layers (boolean)
|
||||
## output_filename (string)
|
||||
## output_folder (string)
|
||||
##
|
||||
## Return:
|
||||
## Dictionary
|
||||
## sprite_sheet: sprite sheet path
|
||||
## data_file: json file path
|
||||
##
|
||||
func generate_tileset_files(source_file: String, options = {}) -> Dictionary:
|
||||
var check = _initial_checks(source_file, options)
|
||||
|
||||
if check != result_code.SUCCESS:
|
||||
return result_code.error(check)
|
||||
|
||||
var output = _aseprite.export_tileset_texture(source_file, options.output_folder, options)
|
||||
|
||||
if output.is_empty():
|
||||
return result_code.error(result_code.ERR_ASEPRITE_EXPORT_FAILED)
|
||||
|
||||
return result_code.result(output)
|
||||
|
||||
|
||||
##
|
||||
## Perform initial source file and output folder checks
|
||||
##
|
||||
func _initial_checks(source: String, options: Dictionary) -> int:
|
||||
if not _aseprite.test_command():
|
||||
return result_code.ERR_ASEPRITE_CMD_NOT_FOUND
|
||||
|
||||
if not FileAccess.file_exists(source):
|
||||
return result_code.ERR_SOURCE_FILE_NOT_FOUND
|
||||
|
||||
if not DirAccess.dir_exists_absolute(options.output_folder):
|
||||
return result_code.ERR_OUTPUT_FOLDER_NOT_FOUND
|
||||
|
||||
return result_code.SUCCESS
|
||||
|
||||
|
||||
##
|
||||
## Load Aseprite source data file and fails if the
|
||||
## content is not valid
|
||||
##
|
||||
func load_json_content(source_file: String) -> Dictionary:
|
||||
var file = FileAccess.open(source_file, FileAccess.READ)
|
||||
if file == null:
|
||||
return result_code.error(FileAccess.get_open_error())
|
||||
var test_json_conv = JSON.new()
|
||||
test_json_conv.parse(file.get_as_text())
|
||||
|
||||
var content = test_json_conv.get_data()
|
||||
|
||||
if not _aseprite.is_valid_spritesheet(content):
|
||||
return result_code.error(result_code.ERR_INVALID_ASEPRITE_SPRITESHEET)
|
||||
|
||||
return result_code.result(content)
|
||||
Reference in New Issue
Block a user