Skip to content

Instantly share code, notes, and snippets.

@Shchvova
Last active June 6, 2016 01:45
Show Gist options
  • Save Shchvova/90a56bc8a691569782454354fa6f1b54 to your computer and use it in GitHub Desktop.
Save Shchvova/90a56bc8a691569782454354fa6f1b54 to your computer and use it in GitHub Desktop.
Loading Spine atlases into Corona

Loading images from Spine atlases instead of separate files.

Add spine-atlas-loader.lua so you can require it, and use as shown in spineboy-demo-atlas.lua.

Make sure that directory has spineboy.json, spineboy.atlas and all spineboy.png.

So far only basic features are supported. Cropped sheets aren't supported.

Update: this version requires at least 2016.2892

Update: added support of min/mag filters, added warning about not currently supporting stripping whitespaces.

local spineLoader = {}
local json = require "json"
local function parseAtlasFile( atlasPath )
local function parseIntTuple4( l )
local a,b,c,d = string.match( l , " ? ?%a+: ([+-]?%d+), ?([+-]?%d+), ?([+-]?%d+), ?([+-]?%d+)" )
local a,b,c,d = tonumber( a ), tonumber( b ), tonumber( c ), tonumber( d )
return a and b and c and d and {a, b, c ,d}
end
local function parseIntTuple2( l )
local a,b = string.match( l , " ? ?%a+: ([+-]?%d+), ?([+-]?%d+)" )
local a,b = tonumber( a ), tonumber( b )
return a and b and {a, b}
end
if not atlasPath then
print("Error: " .. path .. ".atlas" .. " doesn't exist!")
return nil
end
local atlasFile = io.open( atlasPath, "r" )
if not atlasFile then
print("Error: " .. path .. ".atlas" .. " doesn't exist!")
return nil
end
local pages = {}
local it = atlasFile:lines()
for l in it do
if #l == 0 then
l = it()
if l then
local page = { name = l }
l = it()
page.size = parseIntTuple2( l )
if page.size then
l = it()
end
page.format = string.match( l, "%a+: (.+)" )
page.filter = {string.match( it(), "%a+: (.+),(.+)" )}
page.wrap = string.match( it(), "%a+: (.+)" )
page.regions = {}
table.insert( pages, page )
else
break
end
else
local region = {name = l}
region.rotate = string.match( it(), "%a+: (.+)" ) == "true"
region.xy = parseIntTuple2( it() )
region.size = parseIntTuple2( it() )
l = it()
region.splits = parseIntTuple4(l)
if region.splits then
l = it()
region.pad = parseIntTuple4(l)
if region.pad then
l = it()
end
end
region.orig = parseIntTuple2( l )
region.offset = parseIntTuple2( it() )
region.index = tonumber( string.match( it() , "%a+: ([+-]?%d+)" ) )
table.insert( pages[#pages].regions, region )
end
end
atlasFile:close( )
return pages
end
function spineLoader.load( name, dir )
dir = dir or "/"
if string.sub(dir, -1) ~= "/" then
dir = dir .. "/"
end
local pages = parseAtlasFile( system.pathForFile( dir .. name ) )
local sprites = {}
for _,page in ipairs(pages) do
local options = { frames={} }
if page.size then
options.sheetContentWidth, options.sheetContentHeight = unpack( page.size )
end
for i,region in ipairs(page.regions) do
sprites[region.name] = { frame=i, region=region, page=page }
local frame = { }
frame.x, frame.y = unpack(region.xy)
frame.width, frame.height = unpack(region.size)
if region.rotate then
frame.width, frame.height = frame.height, frame.width
end
if region.offset[1] ~= 0 or region.offset[2] ~= 0 or region.size[1] ~= region.orig[1] or region.size[2] ~= region.orig[2] then
print("WARNING: Corona currently does not srtipping whitespaces in Spine atlases")
end
table.insert( options.frames, frame )
end
local oldMag, oldMin = display.getDefault( "magTextureFilter" ), display.getDefault( "minTextureFilter" )
local newMag, newMin = "linear", "linear"
if string.find("Nearest", page.filter[1]) then
newMin = "nearest"
end
if string.find("Nearest", page.filter[2]) then
newMag = "nearest"
end
display.setDefault( "magTextureFilter", newMag )
display.setDefault( "minTextureFilter", newMin )
page.sheet = graphics.newImageSheet( dir..page.name, options )
display.setDefault( "magTextureFilter", oldMag )
display.setDefault( "minTextureFilter", oldMin )
end
function sprites.createImage(_, attachment)
local sprite = sprites[attachment.name]
local obj = display.newRect( 0, 0, 100, 100 )
if sprite then
obj.fill = { type="image", sheet=sprite.page.sheet, frame=sprite.frame}
if sprite.region.rotate then
obj.fill.rotation = 90
end
end
return obj
end
function sprites.createMesh(_, attachment, meshParameters)
local sprite = sprites[attachment.name]
local obj = display.newMesh(meshParameters)
if sprite then
obj.fill = { type="image", sheet=sprite.page.sheet, frame=sprite.frame}
if sprite.region.rotate then
obj.fill.rotation = 90
end
end
return obj
end
function sprites.setupImageFunctions(skeleton)
skeleton.createImage = sprites.createImage
skeleton.createMesh = sprites.createMesh
end
return sprites
end
return spineLoader
-- .....
local json = spine.SkeletonJson.new()
json.scale = 0.6
local skeletonData = json:readSkeletonDataFile("examples/spineboy-atlas/spineboy.json")
local skeleton = spine.Skeleton.new(skeletonData)
-- instead of setting up createImage/createMesh functions, use setupImageFunctions to do it
-- atlas filename, directory with atlas and images
local sprites = atlasLoader.load( "spineboy.atlas", "examples/spineboy-atlas/" )
sprites.setupImageFunctions(skeleton)
-- ..... or setup manually
function skeleton:createImage(attachment)
local obj = display.newRect( 0, 0, 100, 100 )
local sprite = sprites[attachment.name]
if sprite then
obj.fill = { type="image", sheet=sprite.page.sheet, frame=sprite.frame}
if sprite.region.rotate then
obj.fill.rotation = 90
end
end
return obj
end
function skeleton:createMesh(attachment, meshParameters)
local obj = display.newMesh(meshParameters)
local sprite = sprites[attachment.name]
print(attachment.name)
if sprite then
obj.fill = { type="image", sheet=sprite.page.sheet, frame=sprite.frame}
if sprite.region.rotate then
obj.fill.rotation = 90
end
end
return obj
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment