Created
December 21, 2020 02:59
-
-
Save stillwwater/acebb2b47bef240501a05da92aaa37c1 to your computer and use it in GitHub Desktop.
Aseprite exporter for texture atlas files
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ------------------------------------------------------------------------ | |
| -- Export texture atlas file format | |
| -- | |
| -- The file format is as follows: | |
| -- | |
| -- # version VERSION_NUMBER | |
| -- # ASEPRITE_FILE | |
| -- i IMAGE_FILE NUMBER_OF_FRAMES | |
| -- s SPRITE_X SPRITE_Y SPRITE_W SPRITE_H SPRITE_PIVOT_X SPRITE_PIVOT_Y | |
| -- a ANIM_NAME ANIM_START ANIM_END ANIM_DIRECTON ANIM_FRAME_TIME_SECONDS | |
| -- | |
| -- Do not use spaces in filenames! | |
| ------------------------------------------------------------------------- | |
| local Version = 1 | |
| local json = dofile("lib/json.lua") | |
| local function renameWithExtension(path, extension) | |
| return app.fs.filePathAndTitle(path) .. "." .. extension | |
| end | |
| local function tempJsonFilename(filename) | |
| return app.fs.joinPath(app.fs.tempPath, app.fs.fileTitle(filename) .. ".json") | |
| end | |
| local function nextPowerOfTwo(value) | |
| return 2 ^ math.ceil(math.log(value) / math.log(2)) | |
| end | |
| local function exportSpriteSheet(sprite, trimSprites, showUI, imFormat, w, h) | |
| app.command.ExportSpriteSheet { | |
| ui = showUI, | |
| askOverwrite = false, | |
| type = SpriteSheetType.PACKED, | |
| columns = 0, | |
| rows = 0, | |
| width = w, | |
| height = h, | |
| bestFit = false, | |
| textureFilename = renameWithExtension(sprite.filename, imFormat), | |
| dataFilename = tempJsonFilename(sprite.filename), | |
| dataFormat = SpriteSheetDataFormat.JSON_ARRAY, | |
| borderPadding = 0, | |
| shapePadding = 0, | |
| innerPadding = 0, | |
| trim = trimSprites, | |
| extrude = false, | |
| openGenerated = false, | |
| layer = "", | |
| tag = "", | |
| splitLayers = false, | |
| listLayers = true, | |
| listTags = true, | |
| listSlices = true | |
| } | |
| end | |
| local function spriteSheetSize(sprite) | |
| local atlasInput = io.open(tempJsonFilename(sprite.filename), "r") | |
| if atlasInput == nil then | |
| app.alert("Error: Could not open sprite sheet json file") | |
| return | |
| end | |
| local data = json.decode(atlasInput:read("a")) | |
| return {width = data.meta.size.w, height = data.meta.size.h} | |
| end | |
| local function exportAtlasFile(sprite, imFormat, pivotX, pivotY) | |
| local atlasFilename = renameWithExtension(sprite.filename, "atlas") | |
| local textureFilename = app.fs.fileTitle(sprite.filename) .. "." .. imFormat | |
| local atlasOutput = io.open(atlasFilename, "w+") | |
| local atlasInput = io.open(tempJsonFilename(sprite.filename), "r") | |
| if atlasInput == nil then | |
| app.alert("Error: Could not open sprite sheet json file %s") | |
| return | |
| end | |
| local data = json.decode(atlasInput:read("a")) | |
| io.output(atlasOutput) | |
| -- Header | |
| io.write("# version" .. Version .. "\n") | |
| io.write("# " .. app.fs.fileName(sprite.filename) .. "\n") | |
| io.write(string.format("i %s %d\n", textureFilename, #data.frames)) | |
| -- Frames | |
| for i, v in ipairs(data.frames) do | |
| io.write(string.format("s %d %d %d %d %.2f %.2f\n", | |
| v.frame.x, v.frame.y, v.frame.w, v.frame.h, pivotX, pivotY)) | |
| end | |
| -- Animations | |
| local animationFrames = 0; | |
| local directionMap = {forward = "Forward", pingpong = "PingPong"} | |
| for i, v in ipairs(data.meta.frameTags) do | |
| local name = v.name:gsub(" ", "_") | |
| local direction = directionMap[v.direction] | |
| local frameTimeS = data.frames[v.from + 1].duration / 1000.0 | |
| if direction == nil then | |
| app.alert("Warning: Animation direction %s is not supported", v.direction) | |
| end | |
| io.write(string.format("a %s %d %d %s %.3f\n", name, v.from, v.to, direction, frameTimeS)) | |
| animationFrames = animationFrames + (v.to - v.from) + 1 | |
| end | |
| if animationFrames ~= #data.frames then | |
| app.alert("Warning: Missing animation tags on some frames") | |
| end | |
| io.close(atlasOutput) | |
| return atlasFilename | |
| end | |
| local function exportAtlas(requirePowerOfTwoSize, trimSprites, showUI, imFormat, pivotX, pivotY) | |
| local sprite = app.activeSprite | |
| exportSpriteSheet(sprite, trimSprites, showUI and not requirePowerOfTwoSize, imFormat, 0, 0) | |
| if requirePowerOfTwoSize then | |
| local size = spriteSheetSize(sprite) | |
| local w = nextPowerOfTwo(size.width) | |
| local h = nextPowerOfTwo(size.height) | |
| exportSpriteSheet(sprite, trimSprites, showUI, imFormat, w, h) | |
| end | |
| local atlasFilename = exportAtlasFile(sprite, imFormat, pivotX, pivotY) | |
| end | |
| local function onExport(dlg) | |
| exportAtlas(dlg.data.pow2, dlg.data.trimSprites, dlg.data.preview, dlg.data.imFormat, | |
| dlg.data.pivotX / 100.0, dlg.data.pivotY / 100.0) | |
| dlg:close() | |
| local prefsFile = io.open(app.fs.joinPath(app.fs.tempPath, "atlas_exporter_cache.json"), "w+") | |
| io.output(prefsFile) | |
| io.write(json.encode(dlg.data)) | |
| io.close(prefsFile) | |
| end | |
| local function showExportDialog() | |
| local prefsFile = io.open(app.fs.joinPath(app.fs.tempPath, "atlas_exporter_cache.json"), "r") | |
| local prefs = { | |
| pow2 = true, | |
| trimSprites = true, | |
| preview = false, | |
| imFormat = "png", | |
| pivotX = "0", | |
| pivotY = "0" | |
| } | |
| if prefsFile ~= nil then | |
| prefs = json.decode(prefsFile:read("a")) | |
| io.close(prefsFile) | |
| end | |
| local dlg = Dialog("Export Atlas") | |
| local imFormatOptions = {"png", "tga", "bmp"} | |
| dlg:combobox{id = "imFormat", label = "Image Format", | |
| options = prefs.imFormat, options = imFormatOptions} | |
| dlg:number{id = "pivotX", label = "Pivot", text = tostring(prefs.pivotX)} | |
| dlg:number{id = "pivotY", text = tostring(prefs.pivotY)} | |
| dlg:check{id = "pow2", text = "Power Of 2", selected = prefs.pow2} | |
| dlg:newrow() | |
| dlg:check{id = "trimSprites", text = "Trim Sprites", selected = prefs.trimSprites} | |
| dlg:newrow() | |
| dlg:check{id = "preview", text = "Preview", selected = prefs.Preview} | |
| dlg:newrow() | |
| dlg:separator() | |
| dlg:button{id = "ok", text = "&Export", focus = true, onclick = function() onExport(dlg) end} | |
| dlg:button{id = "cancel", text = "&Cancel", focus = false, onclick = function () dlg:close() end} | |
| dlg:show {wait = false} | |
| end | |
| if app.isUIAvailable then | |
| showExportDialog() | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment