201 lines
5.7 KiB
Lua
201 lines
5.7 KiB
Lua
local Classic = require("modules.loveanimate.libs.Classic")
|
|
|
|
---
|
|
--- @class love.animate.SparrowAtlas
|
|
---
|
|
local SparrowAtlas = Classic:extend()
|
|
|
|
local json = require("modules.loveanimate.libs.Json")
|
|
local xml = require("modules.loveanimate.libs.Xml")
|
|
require("modules.loveanimate.libs.StringUtil")
|
|
|
|
local function fileExists(path)
|
|
return love.filesystem.getInfo(path, "file") ~= nil
|
|
end
|
|
|
|
local function getFileContent(path)
|
|
if fileExists(path) then
|
|
local content, _, _, _ = love.filesystem.read("string", path, nil)
|
|
return content --- @type string
|
|
end
|
|
return ""
|
|
end
|
|
|
|
function SparrowAtlas:constructor()
|
|
self.frame = 0
|
|
self.framerate = 24
|
|
|
|
self.symbol = ""
|
|
self.playing = false
|
|
self.looping = false
|
|
|
|
self.image = nil --- @type love.Image
|
|
|
|
--- @protected
|
|
self._frameTimer = 0
|
|
|
|
--- @protected
|
|
self._symbols = {} --- @type table[]
|
|
end
|
|
|
|
--- Load the atlas from an image and xml
|
|
---
|
|
--- @param imageData love.Image|string Either a Love2D image instance or an image file path.
|
|
--- @param xmlString string Either XML data or an XML file path.
|
|
--- @param framerate? integer Framerate of each animation. (This is not specified in the XML, so it must be manually specified) (fallback is 24)
|
|
---
|
|
function SparrowAtlas:load(imageData, xmlString, framerate)
|
|
if type(imageData) == "string" and fileExists(imageData) then
|
|
imageData = love.graphics.newImage(imageData)
|
|
end
|
|
if fileExists(xmlString) then
|
|
xmlString = getFileContent(xmlString)
|
|
end
|
|
self.image = imageData
|
|
self.framerate = framerate or 24
|
|
|
|
local xmlData = xml.parse(xmlString)
|
|
local unsortedSymbols = {}
|
|
|
|
for i = 1, #xmlData.TextureAtlas.children do
|
|
local node = xmlData.TextureAtlas.children[i]
|
|
if node.name ~= "SubTexture" then
|
|
goto continue
|
|
end
|
|
local isSparrowV1 = node.att.w ~= nil
|
|
|
|
local symbolName = node.att.name:sub(1, #node.att.name - 4)
|
|
local frameNumber = tonumber(node.att.name:sub(#node.att.name - 3))
|
|
|
|
if not self._symbols[symbolName] then
|
|
local symbol = { frames = {} }
|
|
self._symbols[symbolName] = symbol
|
|
table.insert(unsortedSymbols, symbol)
|
|
end
|
|
local symbolData = self._symbols[symbolName]
|
|
table.insert(symbolData.frames, {
|
|
index = frameNumber,
|
|
quad = love.graphics.newQuad(
|
|
tonumber(node.att.x), tonumber(node.att.y),
|
|
tonumber(isSparrowV1 and node.att.w or node.att.width), tonumber(isSparrowV1 and node.att.h or node.att.height),
|
|
tonumber(imageData:getWidth()), tonumber(imageData:getHeight())
|
|
),
|
|
offset = {
|
|
x = node.att.frameX ~= nil and -tonumber(node.att.frameX) or 0.0,
|
|
y = node.att.frameY ~= nil and -tonumber(node.att.frameY) or 0.0
|
|
},
|
|
rotated = node.att.rotated ~= nil and node.att.rotated or false
|
|
})
|
|
::continue::
|
|
end
|
|
for i = 1, #unsortedSymbols do
|
|
local symbol = unsortedSymbols[i]
|
|
table.sort(symbol.frames, function(a, b)
|
|
return a.index < b.index
|
|
end)
|
|
end
|
|
end
|
|
|
|
---
|
|
--- @param symbol string?
|
|
--- @param looping boolean?
|
|
---
|
|
function SparrowAtlas:play(symbol, looping)
|
|
self.frame = 0
|
|
self.symbol = symbol or ""
|
|
|
|
self.playing = true
|
|
self._frameTimer = 0.0
|
|
|
|
self.looping = looping ~= nil and looping or true
|
|
end
|
|
|
|
function SparrowAtlas:stop()
|
|
self.playing = false
|
|
self._frameTimer = 0.0
|
|
end
|
|
|
|
function SparrowAtlas:resume()
|
|
self.playing = true
|
|
end
|
|
|
|
---
|
|
--- @param symbol string?
|
|
--- @param frame integer?
|
|
---
|
|
--- @return number
|
|
---
|
|
function SparrowAtlas:getFrameWidth(symbol, frame)
|
|
if not symbol then
|
|
symbol = self.symbol
|
|
end
|
|
if not frame then
|
|
frame = self.frame
|
|
end
|
|
local frameData = self._symbols[symbol].frames[frame + 1]
|
|
local _, _, w, _ = frameData.quad:getViewport()
|
|
return w
|
|
end
|
|
|
|
---
|
|
--- @param symbol string?
|
|
--- @param frame integer?
|
|
---
|
|
--- @return number
|
|
---
|
|
function SparrowAtlas:getFrameHeight(symbol, frame)
|
|
if not symbol then
|
|
symbol = self.symbol
|
|
end
|
|
if not frame then
|
|
frame = self.frame
|
|
end
|
|
local frameData = self._symbols[symbol].frames[frame + 1]
|
|
local _, _, _, h = frameData.quad:getViewport()
|
|
return h
|
|
end
|
|
|
|
function SparrowAtlas:update(dt)
|
|
if self.framerate <= 0.0 or not self.playing then
|
|
return
|
|
end
|
|
self._frameTimer = self._frameTimer + dt
|
|
if self._frameTimer >= 1.0 / self.framerate then
|
|
local symbol = self._symbols[self.symbol]
|
|
self.frame = self.frame + 1
|
|
|
|
if self.frame >= #symbol.frames then
|
|
if self.looping then
|
|
self.frame = 0
|
|
else
|
|
self.frame = #symbol.frames - 1
|
|
self.playing = false
|
|
end
|
|
end
|
|
self._frameTimer = 0.0
|
|
end
|
|
end
|
|
|
|
function SparrowAtlas:draw(x, y, r, sx, sy, ox, oy)
|
|
local symbol = self._symbols[self.symbol]
|
|
local frame = symbol.frames[self.frame + 1]
|
|
|
|
r = r or 0.0 -- rotation (radians)
|
|
sx = sx or 1.0 -- scale x
|
|
sy = sy or 1.0 -- scale y
|
|
ox = ox or 0.0 -- origin x
|
|
oy = oy or 0.0 -- origin y
|
|
|
|
local identity = love.math.newTransform()
|
|
identity:translate(x, y)
|
|
|
|
identity:translate(ox, oy)
|
|
identity:rotate(r)
|
|
identity:scale(sx, sy)
|
|
identity:translate(frame.offset.x, frame.offset.y)
|
|
identity:translate(-ox, -oy)
|
|
|
|
love.graphics.draw(self.image, frame.quad, identity)
|
|
end
|
|
|
|
return SparrowAtlas |