213 lines
8.3 KiB
GDScript
213 lines
8.3 KiB
GDScript
@tool
|
|
extends RefCounted
|
|
|
|
const _Result = preload("../result.gd").Class
|
|
const _Common = preload("../common.gd")
|
|
const _Options = preload("../options.gd")
|
|
const _Setting = preload("../setting.gd")
|
|
const _DirAccessExtensions = preload("../dir_access_ext.gd")
|
|
|
|
const _SpriteSheetBuilderBase = preload("../sprite_sheet_builder/_.gd")
|
|
const _GridBasedSpriteSheetBuilder = preload("../sprite_sheet_builder/grid_based.gd")
|
|
const _PackedSpriteSheetBuilder = preload("../sprite_sheet_builder/packed.gd")
|
|
|
|
const ATLAS_TEXTURE_RESOURCE_TYPE_NAMES: PackedStringArray = [
|
|
"Embedded PortableCompressedTexture2D (compact)",
|
|
"Embedded ImageTexture (large)",
|
|
"Separated image (custom)",
|
|
]
|
|
enum AtlasResourceType {
|
|
EMBEDDED_PORTABLE_COMPRESSED_TEXTURE_2D = 0,
|
|
EMBEDDED_IMAGE_TEXTURE = 1,
|
|
SEPARATED_IMAGE = 2,
|
|
}
|
|
|
|
class ExportResult:
|
|
extends _Result
|
|
var atlas_image: Image
|
|
var sprite_sheet: _Common.SpriteSheetInfo
|
|
var animation_library: _Common.AnimationLibraryInfo
|
|
func _get_result_type_description() -> String:
|
|
return "Export"
|
|
func success(
|
|
atlas_image: Image,
|
|
sprite_sheet: _Common.SpriteSheetInfo,
|
|
animation_library: _Common.AnimationLibraryInfo
|
|
) -> void:
|
|
_success()
|
|
self.atlas_image = atlas_image
|
|
self.sprite_sheet = sprite_sheet
|
|
self.animation_library = animation_library
|
|
|
|
var __name: String
|
|
var __recognized_extensions: PackedStringArray
|
|
var __settings: Array[_Setting] = [_Common.common_temporary_files_directory_path_setting]
|
|
var __options: Array[Dictionary] = [
|
|
_Options.create_option(_Options.EDGES_ARTIFACTS_AVOIDANCE_METHOD, _Common.EdgesArtifactsAvoidanceMethod.NONE,
|
|
PROPERTY_HINT_ENUM, ",".join(_Common.EDGES_ARTIFACTS_AVOIDANCE_METHODS_NAMES),
|
|
PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED),
|
|
_Options.create_option(_Options.SPRITES_SURROUNDING_COLOR, Color.TRANSPARENT,
|
|
PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT,
|
|
func(o): return o[_Options.EDGES_ARTIFACTS_AVOIDANCE_METHOD] == \
|
|
_Common.EdgesArtifactsAvoidanceMethod.SOLID_COLOR_SURROUNDING),
|
|
_Options.create_option(_Options.SPRITE_SHEET_LAYOUT, _Common.SpriteSheetLayout.PACKED,
|
|
PROPERTY_HINT_ENUM, ",".join(_Common.SPRITE_SHEET_LAYOUTS_NAMES),
|
|
PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED),
|
|
_Options.create_option(_Options.MAX_CELLS_IN_STRIP, 0,
|
|
PROPERTY_HINT_RANGE, "0,,1,or_greater", PROPERTY_USAGE_DEFAULT,
|
|
func(o): return o[_Options.SPRITE_SHEET_LAYOUT] != \
|
|
_Common.SpriteSheetLayout.PACKED),
|
|
_Options.create_option(_Options.TRIM_SPRITES_TO_OVERALL_MIN_SIZE, true,
|
|
PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT,
|
|
func(o): return o[_Options.SPRITE_SHEET_LAYOUT] != \
|
|
_Common.SpriteSheetLayout.PACKED),
|
|
_Options.create_option(_Options.COLLAPSE_TRANSPARENT_SPRITES, true,
|
|
PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT,
|
|
func(o): return o[_Options.SPRITE_SHEET_LAYOUT] != \
|
|
_Common.SpriteSheetLayout.PACKED),
|
|
_Options.create_option(_Options.MERGE_DUPLICATED_SPRITES, true,
|
|
PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT,
|
|
func(o): return o[_Options.SPRITE_SHEET_LAYOUT] != \
|
|
_Common.SpriteSheetLayout.PACKED),
|
|
]
|
|
var __image_format_loader_extension: ImageFormatLoaderExtension
|
|
|
|
func _init(
|
|
name: String,
|
|
recognized_extensions: PackedStringArray,
|
|
options: Array[Dictionary],
|
|
settings: Array[_Setting],
|
|
image_format_loader_extension: ImageFormatLoaderExtension = null
|
|
) -> void:
|
|
__name = name
|
|
__recognized_extensions = recognized_extensions
|
|
__options.append_array(options)
|
|
__settings.append_array(settings)
|
|
__image_format_loader_extension = image_format_loader_extension
|
|
|
|
func get_recognized_extensions() -> PackedStringArray:
|
|
return __recognized_extensions
|
|
|
|
func get_options() -> Array[Dictionary]:
|
|
return __options
|
|
|
|
func get_name() -> String:
|
|
return __name
|
|
|
|
func get_settings() -> Array[_Setting]:
|
|
return __settings
|
|
|
|
func get_image_format_loader_extension() -> ImageFormatLoaderExtension:
|
|
return __image_format_loader_extension
|
|
|
|
func export(
|
|
res_source_file_path: String,
|
|
options: Dictionary,
|
|
editor_import_plugin: EditorImportPlugin
|
|
) -> ExportResult:
|
|
return _export(
|
|
res_source_file_path,
|
|
options)
|
|
|
|
func _export(source_file: String, options: Dictionary) -> ExportResult:
|
|
assert(false, "This method is abstract and must be overriden.")
|
|
var result: ExportResult = ExportResult.new()
|
|
result.fail(ERR_UNCONFIGURED)
|
|
return result
|
|
|
|
enum AnimationOptions {
|
|
FramesCount = 1,
|
|
Direction = 2,
|
|
RepeatCount = 4,
|
|
}
|
|
|
|
static var __option_regex: RegEx = RegEx.create_from_string("\\s-\\p{L}:\\s*\\S+")
|
|
static var __natural_number_regex: RegEx = RegEx.create_from_string("\\A\\d+\\z")
|
|
|
|
class AnimationParamsParsingResult:
|
|
extends _Result
|
|
var name: String
|
|
var first_frame_index: int
|
|
var frames_count: int
|
|
var direction: _Common.AnimationDirection
|
|
var repeat_count: int
|
|
func _get_result_type_description() -> String:
|
|
return "Animation parameters parsing"
|
|
|
|
static func _parse_animation_params(
|
|
raw_animation_params: String,
|
|
animation_options: AnimationOptions,
|
|
first_frame_index: int,
|
|
frames_count: int = 0
|
|
) -> AnimationParamsParsingResult:
|
|
var result = AnimationParamsParsingResult.new()
|
|
if first_frame_index < 0:
|
|
result.fail(ERR_INVALID_DATA, "Wrong value for animation first frame index. Expected natural number, got: %s" % [first_frame_index])
|
|
return result
|
|
result.first_frame_index = first_frame_index
|
|
result.frames_count = frames_count
|
|
result.direction = -1
|
|
result.repeat_count = -1
|
|
raw_animation_params = raw_animation_params.strip_edges()
|
|
var options_matches: Array[RegExMatch] = __option_regex.search_all(raw_animation_params)
|
|
var first_match_position: int = raw_animation_params.length()
|
|
for option_match in options_matches:
|
|
var match_position: int = option_match.get_start()
|
|
assert(match_position >= 0)
|
|
if match_position < first_match_position:
|
|
first_match_position = match_position
|
|
var raw_option: String = option_match.get_string().strip_edges()
|
|
var raw_value = raw_option.substr(3).strip_edges()
|
|
match raw_option.substr(0, 3):
|
|
"-f:":
|
|
if animation_options & AnimationOptions.FramesCount:
|
|
if result.frames_count == 0:
|
|
if __natural_number_regex.search(raw_value):
|
|
result.frames_count = raw_value.to_int()
|
|
if result.frames_count <= 0:
|
|
result.fail(ERR_INVALID_DATA, "Wrong value format for frames count. Expected positive integer number, got: \"%s\"" % [raw_value])
|
|
return result
|
|
"-d:":
|
|
if animation_options & AnimationOptions.Direction:
|
|
if result.direction < 0:
|
|
match raw_value:
|
|
"f": result.direction = _Common.AnimationDirection.FORWARD
|
|
"r": result.direction = _Common.AnimationDirection.REVERSE
|
|
"pp": result.direction = _Common.AnimationDirection.PING_PONG
|
|
"ppr": result.direction = _Common.AnimationDirection.PING_PONG_REVERSE
|
|
_:
|
|
result.fail(ERR_INVALID_DATA, "Wrong value format for animation direction. Expected one of: [\"f\", \"r\", \"pp\", \"ppr\"], got: \"%s\"" % [raw_value])
|
|
return result
|
|
"-r:":
|
|
if animation_options & AnimationOptions.RepeatCount:
|
|
if result.repeat_count < 0:
|
|
if __natural_number_regex.search(raw_value):
|
|
result.repeat_count = raw_value.to_int()
|
|
else:
|
|
result.fail(ERR_INVALID_DATA, "Wrong value format for repeat count. Expected positive integer number or zero, got: \"%s\"" % [raw_value])
|
|
return result
|
|
_: pass # Ignore unknown parameter
|
|
result.name = raw_animation_params.left(first_match_position).strip_edges()
|
|
if result.frames_count <= 0:
|
|
result.fail(ERR_UNCONFIGURED, "Animation frames count is required but not specified")
|
|
return result
|
|
return result
|
|
|
|
func _create_sprite_sheet_builder(options: Dictionary) -> _SpriteSheetBuilderBase:
|
|
var sprite_sheet_layout: _Common.SpriteSheetLayout = options[_Options.SPRITE_SHEET_LAYOUT]
|
|
return \
|
|
_PackedSpriteSheetBuilder.new(
|
|
options[_Options.EDGES_ARTIFACTS_AVOIDANCE_METHOD],
|
|
options[_Options.SPRITES_SURROUNDING_COLOR]) \
|
|
if sprite_sheet_layout == _Common.SpriteSheetLayout.PACKED else \
|
|
_GridBasedSpriteSheetBuilder.new(
|
|
options[_Options.EDGES_ARTIFACTS_AVOIDANCE_METHOD],
|
|
_GridBasedSpriteSheetBuilder.StripDirection.HORIZONTAL
|
|
if sprite_sheet_layout == _Common.SpriteSheetLayout.HORIZONTAL_STRIPS else
|
|
_GridBasedSpriteSheetBuilder.StripDirection.HORIZONTAL,
|
|
options[_Options.MAX_CELLS_IN_STRIP],
|
|
options[_Options.TRIM_SPRITES_TO_OVERALL_MIN_SIZE],
|
|
options[_Options.COLLAPSE_TRANSPARENT_SPRITES],
|
|
options[_Options.MERGE_DUPLICATED_SPRITES],
|
|
options[_Options.SPRITES_SURROUNDING_COLOR])
|