mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-21 01:36:02 +08:00
252 lines
7.6 KiB
Lua
252 lines
7.6 KiB
Lua
-------------------------------------------------------------------------------
|
|
-- Spine Runtimes Software License v2.5
|
|
--
|
|
-- Copyright (c) 2013-2016, Esoteric Software
|
|
-- All rights reserved.
|
|
--
|
|
-- You are granted a perpetual, non-exclusive, non-sublicensable, and
|
|
-- non-transferable license to use, install, execute, and perform the Spine
|
|
-- Runtimes software and derivative works solely for personal or internal
|
|
-- use. Without the written permission of Esoteric Software (see Section 2 of
|
|
-- the Spine Software License Agreement), you may not (a) modify, translate,
|
|
-- adapt, or develop new applications using the Spine Runtimes or otherwise
|
|
-- create derivative works or improvements of the Spine Runtimes or (b) remove,
|
|
-- delete, alter, or obscure any trademarks or any copyright, trademark, patent,
|
|
-- or other intellectual property or proprietary rights notices on or in the
|
|
-- Software, including any copy thereof. Redistributions in binary or source
|
|
-- form must include this license and terms.
|
|
--
|
|
-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
|
|
-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
|
|
-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
|
-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
-- POSSIBILITY OF SUCH DAMAGE.
|
|
-------------------------------------------------------------------------------
|
|
|
|
local setmetatable = setmetatable
|
|
local table_insert = table.insert
|
|
local math_abs = math.abs
|
|
|
|
local TextureAtlasRegion = require "spine-lua.TextureAtlasRegion"
|
|
local TextureWrap = require "spine-lua.TextureWrap"
|
|
local TextureFilter = require "spine-lua.TextureFilter"
|
|
|
|
local TextureAtlasPage = {}
|
|
TextureAtlasPage.__index = TextureAtlasPage
|
|
|
|
function TextureAtlasPage.new ()
|
|
local self = {
|
|
name = nil,
|
|
minFilter = nil,
|
|
magFilter = nil,
|
|
uWrap = nil,
|
|
vWrap = nil,
|
|
texture = nil,
|
|
width = 0,
|
|
height = 0
|
|
}
|
|
setmetatable(self, TextureAtlasPage)
|
|
return self
|
|
end
|
|
|
|
|
|
local TextureAtlas = {}
|
|
TextureAtlas.__index = TextureAtlas
|
|
|
|
function TextureAtlas.new (atlasContent, imageLoader)
|
|
local self = {
|
|
pages = {},
|
|
regions = {}
|
|
}
|
|
setmetatable(self, TextureAtlas)
|
|
|
|
self:parse(atlasContent, imageLoader)
|
|
|
|
return self
|
|
end
|
|
|
|
function TextureAtlas:parse (atlasContent, imageLoader)
|
|
if not atlasContent then error("atlasContent cannot be nil.", 2) end
|
|
if not imageLoader then error("imageLoader cannot be nil.", 2) end
|
|
|
|
function lineIterator(s)
|
|
if s:sub(-1)~="\n" then s=s.."\n" end
|
|
return s:gmatch("(.-)\n")
|
|
end
|
|
|
|
local lines = {}
|
|
local index = 0
|
|
local numLines = 0
|
|
for line in lineIterator(atlasContent) do
|
|
lines[numLines] = line
|
|
numLines = numLines + 1
|
|
end
|
|
|
|
local readLine = function ()
|
|
if index >= numLines then return nil end
|
|
local line = lines[index]
|
|
index = index + 1
|
|
return line
|
|
end
|
|
|
|
local readValue = function ()
|
|
local line = readLine()
|
|
local idx = line:find(":")
|
|
if not idx then error("Invalid line: " .. line, 2) end
|
|
return line:sub(idx + 1):match'^%s*(.*%S)' or ''
|
|
end
|
|
|
|
local readTuple = function ()
|
|
local line = readLine()
|
|
local idx = line:find(":")
|
|
if not idx then
|
|
error("Invalid line: " .. line, 2)
|
|
end
|
|
local i = 1
|
|
local lastMatch = idx + 1
|
|
local tuple = {}
|
|
while i <= 3 do
|
|
local comma = line:find(",", lastMatch)
|
|
if not comma then break end
|
|
tuple[i] = line:sub(lastMatch, comma - 1):match'^%s*(.*%S)' or ''
|
|
lastMatch = comma + 1
|
|
i = i + 1
|
|
end
|
|
tuple[i] = line:sub(lastMatch):match'^%s*(.*%S)' or ''
|
|
return tuple
|
|
end
|
|
|
|
local parseInt = function (str)
|
|
return tonumber(str)
|
|
end
|
|
|
|
local filterFromString = function (str)
|
|
str = str:lower()
|
|
if str == "nearest" then return TextureFilter.Nearest
|
|
elseif str == "linear" then return TextureFilter.Linear
|
|
elseif str == "mipmap" then return TextureFilter.MipMap
|
|
elseif str == "mipmapnearestnearest" then return TextureFilter.MipMapNearestNearest
|
|
elseif str == "mipmaplinearnearest" then return TextureFilter.MipMapLinearNearest
|
|
elseif str == "mipmapnearestlinear" then return TextureFilter.MipMapNearestLinear
|
|
elseif str == "mipmaplinearlinear" then return TextureFilter.MipMapLinearLinear
|
|
else error("Unknown texture wrap: " .. str, 2)
|
|
end
|
|
end
|
|
|
|
local page = nil
|
|
while true do
|
|
local line = readLine()
|
|
if not line then break end
|
|
line = line:match'^%s*(.*%S)' or ''
|
|
if line:len() == 0 then
|
|
page = nil
|
|
elseif not page then
|
|
page = TextureAtlasPage.new()
|
|
page.name = line
|
|
|
|
local tuple = readTuple()
|
|
if #tuple == 2 then
|
|
page.width = parseInt(tuple[1])
|
|
page.height = parseInt(tuple[2])
|
|
tuple = readTuple()
|
|
else
|
|
-- We only support atlases that have the page width/height
|
|
-- encoded in them. That way we don't rely on any special
|
|
-- wrapper objects for images to get the page size from
|
|
error("Atlas must specify page width/height. Please export to the latest atlas format", 2)
|
|
end
|
|
|
|
tuple = readTuple()
|
|
page.minFilter = filterFromString(tuple[1])
|
|
page.magFilter = filterFromString(tuple[2])
|
|
|
|
local direction = readValue()
|
|
page.uWrap = TextureWrap.ClampToEdge
|
|
page.vWrap = TextureWrap.ClampToEdge
|
|
if direction == "x" then
|
|
page.uWrap = TextureWrap.Repeat
|
|
elseif direction == "y" then
|
|
page.vWrap = TextureWrap.Repeat
|
|
elseif direction == "xy" then
|
|
page.uWrap = TextureWrap.Repeat
|
|
page.vWrap = TextureWrap.Repeat
|
|
end
|
|
|
|
page.texture = imageLoader(line)
|
|
-- FIXME page.texture:setFilters(page.minFilter, page.magFilter)
|
|
-- FIXME page.texture:setWraps(page.uWrap, page.vWrap)
|
|
table_insert(self.pages, page)
|
|
else
|
|
local region = TextureAtlasRegion.new()
|
|
region.name = line
|
|
region.page = page
|
|
|
|
if readValue() == "true" then region.rotate = true end
|
|
|
|
local tuple = readTuple()
|
|
local x = parseInt(tuple[1])
|
|
local y = parseInt(tuple[2])
|
|
|
|
tuple = readTuple()
|
|
local width = parseInt(tuple[1])
|
|
local height = parseInt(tuple[2])
|
|
|
|
region.u = x / page.width
|
|
region.v = y / page.height
|
|
if region.rotate then
|
|
region.u2 = (x + height) / page.width
|
|
region.v2 = (y + width) / page.height
|
|
else
|
|
region.u2 = (x + width) / page.width
|
|
region.v2 = (y + height) / page.height
|
|
end
|
|
|
|
region.x = x
|
|
region.y = y
|
|
region.width = math_abs(width)
|
|
region.height = math_abs(height)
|
|
|
|
-- Read and skip optional splits
|
|
tuple = readTuple()
|
|
if #tuple == 4 then
|
|
tuple = readTuple()
|
|
if #tuple == 4 then
|
|
readTuple()
|
|
end
|
|
end
|
|
|
|
region.originalWidth = parseInt(tuple[1])
|
|
region.originalHeight = parseInt(tuple[2])
|
|
|
|
tuple = readTuple()
|
|
region.offsetX = parseInt(tuple[1])
|
|
region.offsetY = parseInt(tuple[2])
|
|
|
|
region.index = parseInt(readValue())
|
|
region.texture = page.texture
|
|
table_insert(self.regions, region)
|
|
end
|
|
end
|
|
end
|
|
|
|
function TextureAtlas:findRegion(name)
|
|
for i, region in ipairs(self.regions) do
|
|
if region.name == name then return region end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
function TextureAtlas:dispose()
|
|
for i, page in ipairs(self.pairs) do
|
|
-- FIXME implement disposing of pages
|
|
-- love2d doesn't support manual disposing
|
|
end
|
|
end
|
|
|
|
return TextureAtlas
|