SkeletonJson.lua 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875
  1. -------------------------------------------------------------------------------
  2. -- Spine Runtimes Software License v2.5
  3. --
  4. -- Copyright (c) 2013-2016, Esoteric Software
  5. -- All rights reserved.
  6. --
  7. -- You are granted a perpetual, non-exclusive, non-sublicensable, and
  8. -- non-transferable license to use, install, execute, and perform the Spine
  9. -- Runtimes software and derivative works solely for personal or internal
  10. -- use. Without the written permission of Esoteric Software (see Section 2 of
  11. -- the Spine Software License Agreement), you may not (a) modify, translate,
  12. -- adapt, or develop new applications using the Spine Runtimes or otherwise
  13. -- create derivative works or improvements of the Spine Runtimes or (b) remove,
  14. -- delete, alter, or obscure any trademarks or any copyright, trademark, patent,
  15. -- or other intellectual property or proprietary rights notices on or in the
  16. -- Software, including any copy thereof. Redistributions in binary or source
  17. -- form must include this license and terms.
  18. --
  19. -- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
  20. -- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  21. -- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
  22. -- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. -- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  24. -- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
  25. -- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
  26. -- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  27. -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  28. -- POSSIBILITY OF SUCH DAMAGE.
  29. -------------------------------------------------------------------------------
  30. local table_insert = table.insert
  31. local SkeletonData = require "spine-lua.SkeletonData"
  32. local BoneData = require "spine-lua.BoneData"
  33. local SlotData = require "spine-lua.SlotData"
  34. local Skin = require "spine-lua.Skin"
  35. local AttachmentLoader = require "spine-lua.AttachmentLoader"
  36. local Animation = require "spine-lua.Animation"
  37. local IkConstraintData = require "spine-lua.IkConstraintData"
  38. local IkConstraint = require "spine-lua.IkConstraint"
  39. local PathConstraintData = require "spine-lua.PathConstraintData"
  40. local PathConstraint = require "spine-lua.PathConstraint"
  41. local TransformConstraintData = require "spine-lua.TransformConstraintData"
  42. local TransformConstraint = require "spine-lua.TransformConstraint"
  43. local EventData = require "spine-lua.EventData"
  44. local Event = require "spine-lua.Event"
  45. local AttachmentType = require "spine-lua.attachments.AttachmentType"
  46. local BlendMode = require "spine-lua.BlendMode"
  47. local TransformMode = require "spine-lua.TransformMode"
  48. local utils = require "spine-lua.utils"
  49. local Color = require "spine-lua.Color"
  50. local SkeletonJson = {}
  51. function SkeletonJson.new (attachmentLoader)
  52. if not attachmentLoader then attachmentLoader = AttachmentLoader.new() end
  53. local self = {
  54. attachmentLoader = attachmentLoader,
  55. scale = 1,
  56. linkedMeshes = {}
  57. }
  58. function self:readSkeletonDataFile (fileName, base)
  59. return self:readSkeletonData(utils.readFile(fileName, base))
  60. end
  61. local readAttachment
  62. local readAnimation
  63. local readCurve
  64. local getArray
  65. local getValue = function (map, name, default)
  66. local value = map[name]
  67. if value == nil then return default else return value end
  68. end
  69. function self:readSkeletonData (jsonText)
  70. local scale = self.scale
  71. local skeletonData = SkeletonData.new(self.attachmentLoader)
  72. local root = utils.readJSON(jsonText)
  73. if not root then error("Invalid JSON: " .. jsonText, 2) end
  74. -- Skeleton.
  75. local skeletonMap = root["skeleton"]
  76. if skeletonMap then
  77. skeletonData.hash = skeletonMap["hash"]
  78. skeletonData.version = skeletonMap["spine"]
  79. skeletonData.width = skeletonMap["width"]
  80. skeletonData.height = skeletonMap["height"]
  81. skeletonData.fps = skeletonMap["fps"]
  82. skeletonData.imagesPath = skeletonMap["images"]
  83. end
  84. -- Bones.
  85. for i,boneMap in ipairs(root["bones"]) do
  86. local boneName = boneMap["name"]
  87. local parent = nil
  88. local parentName = boneMap["parent"]
  89. if parentName then
  90. parent = skeletonData:findBone(parentName)
  91. if not parent then error("Parent bone not found: " .. parentName) end
  92. end
  93. local data = BoneData.new(i, boneName, parent)
  94. data.length = getValue(boneMap, "length", 0) * scale;
  95. data.x = getValue(boneMap, "x", 0) * scale;
  96. data.y = getValue(boneMap, "y", 0) * scale;
  97. data.rotation = getValue(boneMap, "rotation", 0);
  98. data.scaleX = getValue(boneMap, "scaleX", 1);
  99. data.scaleY = getValue(boneMap, "scaleY", 1);
  100. data.shearX = getValue(boneMap, "shearX", 0);
  101. data.shearY = getValue(boneMap, "shearY", 0);
  102. data.transformMode = TransformMode[getValue(boneMap, "transform", "normal")]
  103. table_insert(skeletonData.bones, data)
  104. end
  105. -- Slots.
  106. if root["slots"] then
  107. for i,slotMap in ipairs(root["slots"]) do
  108. local slotName = slotMap["name"]
  109. local boneName = slotMap["bone"]
  110. local boneData = skeletonData:findBone(boneName)
  111. if not boneData then error("Slot bone not found: " .. boneName) end
  112. local data = SlotData.new(i, slotName, boneData)
  113. local color = slotMap["color"]
  114. if color then
  115. data.color:set(tonumber(color:sub(1, 2), 16) / 255,
  116. tonumber(color:sub(3, 4), 16) / 255,
  117. tonumber(color:sub(5, 6), 16) / 255,
  118. tonumber(color:sub(7, 8), 16) / 255)
  119. end
  120. local dark = slotMap["dark"]
  121. if dark then
  122. data.darkColor = Color.newWith(1, 1, 1, 1)
  123. data.darkColor:set(tonumber(dark:sub(1, 2), 16) / 255,
  124. tonumber(dark:sub(3, 4), 16) / 255,
  125. tonumber(dark:sub(5, 6), 16) / 255,
  126. 0)
  127. end
  128. data.attachmentName = getValue(slotMap, "attachment", nil)
  129. data.blendMode = BlendMode[getValue(slotMap, "blend", "normal")]
  130. table_insert(skeletonData.slots, data)
  131. skeletonData.slotNameIndices[data.name] = #skeletonData.slots
  132. end
  133. end
  134. -- IK constraints.
  135. if root["ik"] then
  136. for _,constraintMap in ipairs(root["ik"]) do
  137. local data = IkConstraintData.new(constraintMap["name"])
  138. data.order = getValue(constraintMap, "order", 0)
  139. for _,boneName in ipairs(constraintMap["bones"]) do
  140. local bone = skeletonData:findBone(boneName)
  141. if not bone then error("IK bone not found: " .. boneName) end
  142. table_insert(data.bones, bone)
  143. end
  144. local targetName = constraintMap["target"]
  145. data.target = skeletonData:findBone(targetName)
  146. if not data.target then error("Target bone not found: " .. targetName) end
  147. data.mix = getValue(constraintMap, "mix", 1)
  148. if constraintMap["bendPositive"] == nil or constraintMap["bendPositive"] == false then data.bendDirection = -1 else data.bendDirection = 1 end
  149. if constraintMap["compress"] == nil or constraintMap["compress"] == false then data.compress = false else data.compress = true end
  150. if constraintMap["stretch"] == nil or constraintMap["stretch"] == false then data.stretch = false else data.stretch = true end
  151. if constraintMap["uniform"] == nil or constraintMap["uniform"] == false then data.uniform = false else data.uniform = true end
  152. table_insert(skeletonData.ikConstraints, data)
  153. end
  154. end
  155. -- Transform constraints
  156. if root["transform"] then
  157. for _,constraintMap in ipairs(root["transform"]) do
  158. local data = TransformConstraintData.new(constraintMap.name)
  159. data.order = getValue(constraintMap, "order", 0)
  160. for _,boneName in ipairs(constraintMap.bones) do
  161. local bone = skeletonData:findBone(boneName)
  162. if not bone then error("Transform constraint bone not found: " .. boneName, 2) end
  163. table_insert(data.bones, bone)
  164. end
  165. local targetName = constraintMap.target
  166. data.target = skeletonData:findBone(targetName)
  167. if not data.target then error("Transform constraint target bone not found: " .. (targetName or "none"), 2) end
  168. data.offsetRotation = getValue(constraintMap, "rotation", 0);
  169. data.offsetX = getValue(constraintMap, "x", 0) * scale;
  170. data.offsetY = getValue(constraintMap, "y", 0) * scale;
  171. data.offsetScaleX = getValue(constraintMap, "scaleX", 0);
  172. data.offsetScaleY = getValue(constraintMap, "scaleY", 0);
  173. data.offsetShearY = getValue(constraintMap, "shearY", 0);
  174. data.rotateMix = getValue(constraintMap, "rotateMix", 1);
  175. data.translateMix = getValue(constraintMap, "translateMix", 1);
  176. data.scaleMix = getValue(constraintMap, "scaleMix", 1);
  177. data.shearMix = getValue(constraintMap, "shearMix", 1);
  178. table_insert(skeletonData.transformConstraints, data)
  179. end
  180. end
  181. -- Path constraints
  182. if root["path"] then
  183. for _,constraintMap in ipairs(root.path) do
  184. local data = PathConstraintData.new(constraintMap.name);
  185. data.order = getValue(constraintMap, "order", 0)
  186. for _,boneName in ipairs(constraintMap.bones) do
  187. local bone = skeletonData:findBone(boneName)
  188. if not bone then error("Path constraint bone not found: " .. boneName, 2) end
  189. table_insert(data.bones, bone)
  190. end
  191. local targetName = constraintMap.target;
  192. data.target = skeletonData:findSlot(targetName)
  193. if data.target == nil then error("Path target slot not found: " .. targetName, 2) end
  194. data.positionMode = PathConstraintData.PositionMode[getValue(constraintMap, "positionMode", "percent"):lower()]
  195. data.spacingMode = PathConstraintData.SpacingMode[getValue(constraintMap, "spacingMode", "length"):lower()]
  196. data.rotateMode = PathConstraintData.RotateMode[getValue(constraintMap, "rotateMode", "tangent"):lower()]
  197. data.offsetRotation = getValue(constraintMap, "rotation", 0);
  198. data.position = getValue(constraintMap, "position", 0);
  199. if data.positionMode == PathConstraintData.PositionMode.fixed then data.position = data.position * scale end
  200. data.spacing = getValue(constraintMap, "spacing", 0);
  201. if data.spacingMode == PathConstraintData.SpacingMode.length or data.spacingMode == PathConstraintData.SpacingMode.fixed then data.spacing = data.spacing * scale end
  202. data.rotateMix = getValue(constraintMap, "rotateMix", 1);
  203. data.translateMix = getValue(constraintMap, "translateMix", 1);
  204. table_insert(skeletonData.pathConstraints, data)
  205. end
  206. end
  207. -- Skins.
  208. if root["skins"] then
  209. for skinName,skinMap in pairs(root["skins"]) do
  210. local skin = Skin.new(skinName)
  211. for slotName,slotMap in pairs(skinMap) do
  212. local slotIndex = skeletonData.slotNameIndices[slotName]
  213. for attachmentName,attachmentMap in pairs(slotMap) do
  214. local attachment = readAttachment(attachmentMap, skin, slotIndex, attachmentName, skeletonData)
  215. if attachment then
  216. skin:addAttachment(slotIndex, attachmentName, attachment)
  217. end
  218. end
  219. end
  220. table_insert(skeletonData.skins, skin)
  221. if skin.name == "default" then skeletonData.defaultSkin = skin end
  222. end
  223. end
  224. -- Linked meshes
  225. for _, linkedMesh in ipairs(self.linkedMeshes) do
  226. local skin = skeletonData.defaultSkin
  227. if linkedMesh.skin then skin = skeletonData:findSkin(linkedMesh.skin) end
  228. if not skin then error("Skin not found: " .. linkedMesh.skin) end
  229. local parent = skin:getAttachment(linkedMesh.slotIndex, linkedMesh.parent)
  230. if not parent then error("Parent mesh not found: " + linkedMesh.parent) end
  231. linkedMesh.mesh:setParentMesh(parent)
  232. linkedMesh.mesh:updateUVs()
  233. end
  234. self.linkedMeshes = {}
  235. -- Events.
  236. if root["events"] then
  237. for eventName,eventMap in pairs(root["events"]) do
  238. local data = EventData.new(eventName)
  239. data.intValue = getValue(eventMap, "int", 0)
  240. data.floatValue = getValue(eventMap, "float", 0)
  241. data.stringValue = getValue(eventMap, "string", "")
  242. data.audioPath = getValue(eventMap, "audio", nil)
  243. if data.audioPath ~= nil then
  244. data.volume = getValue(eventMap, "volume", 1)
  245. data.balance = getValue(eventMap, "balance", 0)
  246. end
  247. table_insert(skeletonData.events, data)
  248. end
  249. end
  250. -- Animations.
  251. if root["animations"] then
  252. for animationName,animationMap in pairs(root["animations"]) do
  253. readAnimation(animationMap, animationName, skeletonData)
  254. end
  255. end
  256. return skeletonData
  257. end
  258. readAttachment = function (map, skin, slotIndex, name, skeletonData)
  259. local scale = self.scale
  260. name = getValue(map, "name", name)
  261. local type = AttachmentType[getValue(map, "type", "region")]
  262. local path = getValue(map, "path", name)
  263. if type == AttachmentType.region then
  264. local region = attachmentLoader:newRegionAttachment(skin, name, path)
  265. if not region then return nil end
  266. region.path = path
  267. region.x = getValue(map, "x", 0) * scale
  268. region.y = getValue(map, "y", 0) * scale
  269. region.scaleX = getValue(map, "scaleX", 1);
  270. region.scaleY = getValue(map, "scaleY", 1);
  271. region.rotation = getValue(map, "rotation", 0);
  272. region.width = map.width * scale;
  273. region.height = map.height * scale;
  274. local color = map["color"]
  275. if color then
  276. region.color:set(tonumber(color:sub(1, 2), 16) / 255,
  277. tonumber(color:sub(3, 4), 16) / 255,
  278. tonumber(color:sub(5, 6), 16) / 255,
  279. tonumber(color:sub(7, 8), 16) / 255)
  280. end
  281. region:updateOffset()
  282. return region
  283. elseif type == AttachmentType.boundingbox then
  284. local box = attachmentLoader:newBoundingBoxAttachment(skin, name)
  285. if not box then return nil end
  286. readVertices(map, box, map.vertexCount * 2)
  287. local color = map.color
  288. if color then
  289. box.color:set(tonumber(color:sub(1, 2), 16) / 255,
  290. tonumber(color:sub(3, 4), 16) / 255,
  291. tonumber(color:sub(5, 6), 16) / 255,
  292. tonumber(color:sub(7, 8), 16) / 255)
  293. end
  294. return box
  295. elseif type == AttachmentType.mesh or type == AttachmentType.linkedmesh then
  296. local mesh = attachmentLoader:newMeshAttachment(skin, name, path)
  297. if not mesh then return nil end
  298. mesh.path = path
  299. local color = map.color
  300. if color then
  301. mesh.color:set(tonumber(color:sub(1, 2), 16) / 255,
  302. tonumber(color:sub(3, 4), 16) / 255,
  303. tonumber(color:sub(5, 6), 16) / 255,
  304. tonumber(color:sub(7, 8), 16) / 255)
  305. end
  306. local parent = map.parent
  307. if parent then
  308. mesh.inheritDeform = getValue(map, "deform", true)
  309. table_insert(self.linkedMeshes, {
  310. mesh = mesh,
  311. skin = getValue(map, "skin", nil),
  312. slotIndex = slotIndex,
  313. parent = parent
  314. })
  315. return mesh
  316. end
  317. local uvs = getArray(map, "uvs", 1)
  318. readVertices(map, mesh, #uvs)
  319. mesh.triangles = getArray(map, "triangles", 1)
  320. -- adjust triangle indices by 1, vertices are one-indexed
  321. for i,v in ipairs(mesh.triangles) do
  322. mesh.triangles[i] = v + 1
  323. end
  324. mesh.regionUVs = uvs
  325. mesh:updateUVs()
  326. mesh.hullLength = getValue(map, "hull", 0) * 2
  327. return mesh
  328. elseif type == AttachmentType.path then
  329. local path = self.attachmentLoader:newPathAttachment(skin, name)
  330. if not path then return nil end
  331. path.closed = getValue(map, "closed", false)
  332. path.constantSpeed = getValue(map, "constantSpeed", true)
  333. local vertexCount = map.vertexCount
  334. readVertices(map, path, vertexCount * 2)
  335. local lengths = utils.newNumberArray(vertexCount / 3, 0)
  336. for i,v in ipairs(map.lengths) do
  337. lengths[i] = v * scale
  338. end
  339. path.lengths = lengths
  340. local color = map.color
  341. if color then
  342. path.color:set(tonumber(color:sub(1, 2), 16) / 255,
  343. tonumber(color:sub(3, 4), 16) / 255,
  344. tonumber(color:sub(5, 6), 16) / 255,
  345. tonumber(color:sub(7, 8), 16) / 255)
  346. end
  347. return path;
  348. elseif type == AttachmentType.point then
  349. local point = self.attachmentLoader:newPointAttachment(skin, name)
  350. if not point then return nil end
  351. point.x = getValue(map, "x", 0) * scale
  352. point.y = getValue(map, "y", 0) * scale
  353. point.rotation = getValue(map, "rotation", 0)
  354. local color = map.color
  355. if color then
  356. path.color:set(tonumber(color:sub(1, 2), 16) / 255,
  357. tonumber(color:sub(3, 4), 16) / 255,
  358. tonumber(color:sub(5, 6), 16) / 255,
  359. tonumber(color:sub(7, 8), 16) / 255)
  360. end
  361. return point
  362. elseif type == AttachmentType.clipping then
  363. local clip = attachmentLoader:newClippingAttachment(skin, name)
  364. if not clip then return nil end
  365. local _end = getValue(map, "end", nil)
  366. if _end then
  367. local slot = skeletonData:findSlot(_end)
  368. if not slot then error("Clipping end slot not found: " + _end) end
  369. clip.endSlot = slot
  370. end
  371. readVertices(map, clip, map.vertexCount * 2)
  372. local color = map.color
  373. if color then
  374. clip.color:set(tonumber(color:sub(1, 2), 16) / 255,
  375. tonumber(color:sub(3, 4), 16) / 255,
  376. tonumber(color:sub(5, 6), 16) / 255,
  377. tonumber(color:sub(7, 8), 16) / 255)
  378. end
  379. return clip
  380. end
  381. error("Unknown attachment type: " .. type .. " (" .. name .. ")")
  382. end
  383. readVertices = function (map, attachment, verticesLength)
  384. local scale = self.scale
  385. attachment.worldVerticesLength = verticesLength
  386. local vertices = getArray(map, "vertices", 1)
  387. if verticesLength == #vertices then
  388. if scale ~= 1 then
  389. local i = 0
  390. local n = #vertices
  391. while i < n do
  392. vertices[i + 1] = vertices[i + 1] * scale
  393. i = i + 1
  394. end
  395. end
  396. attachment.vertices = vertices
  397. return
  398. end
  399. local weights = {}
  400. local bones = {}
  401. local i = 0
  402. local n = #vertices
  403. while i < n do
  404. local boneCount = vertices[i + 1]
  405. i = i + 1
  406. table_insert(bones, boneCount)
  407. local nn = i + boneCount * 4
  408. while i < nn do
  409. table_insert(bones, vertices[i + 1] + 1) -- +1 because bones are one-indexed
  410. table_insert(weights, vertices[i + 2] * scale)
  411. table_insert(weights, vertices[i + 3] * scale)
  412. table_insert(weights, vertices[i + 4])
  413. i = i + 4
  414. end
  415. end
  416. attachment.bones = bones
  417. attachment.vertices = weights
  418. end
  419. readAnimation = function (map, name, skeletonData)
  420. local timelines = {}
  421. local duration = 0
  422. local scale = self.scale
  423. -- Slot timelines
  424. local slotsMap = map["slots"]
  425. if slotsMap then
  426. for slotName,timelineMap in pairs(slotsMap) do
  427. local slotIndex = skeletonData.slotNameIndices[slotName]
  428. for timelineName,values in pairs(timelineMap) do
  429. if timelineName == "color" then
  430. local timeline = Animation.ColorTimeline.new(#values)
  431. timeline.slotIndex = slotIndex
  432. local frameIndex = 0
  433. for _,valueMap in ipairs(values) do
  434. local color = valueMap["color"]
  435. timeline:setFrame(
  436. frameIndex, valueMap["time"],
  437. tonumber(color:sub(1, 2), 16) / 255,
  438. tonumber(color:sub(3, 4), 16) / 255,
  439. tonumber(color:sub(5, 6), 16) / 255,
  440. tonumber(color:sub(7, 8), 16) / 255
  441. )
  442. readCurve(valueMap, timeline, frameIndex)
  443. frameIndex = frameIndex + 1
  444. end
  445. table_insert(timelines, timeline)
  446. duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.ColorTimeline.ENTRIES])
  447. elseif timelineName == "twoColor" then
  448. local timeline = Animation.TwoColorTimeline.new(#values)
  449. timeline.slotIndex = slotIndex
  450. local frameIndex = 0
  451. for _,valueMap in ipairs(values) do
  452. local light = valueMap["light"]
  453. local dark = valueMap["dark"]
  454. timeline:setFrame(
  455. frameIndex, valueMap["time"],
  456. tonumber(light:sub(1, 2), 16) / 255,
  457. tonumber(light:sub(3, 4), 16) / 255,
  458. tonumber(light:sub(5, 6), 16) / 255,
  459. tonumber(light:sub(7, 8), 16) / 255,
  460. tonumber(dark:sub(1, 2), 16) / 255,
  461. tonumber(dark:sub(3, 4), 16) / 255,
  462. tonumber(dark:sub(5, 6), 16) / 255
  463. )
  464. readCurve(valueMap, timeline, frameIndex)
  465. frameIndex = frameIndex + 1
  466. end
  467. table_insert(timelines, timeline)
  468. duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.TwoColorTimeline.ENTRIES])
  469. elseif timelineName == "attachment" then
  470. local timeline = Animation.AttachmentTimeline.new(#values)
  471. timeline.slotIndex = slotIndex
  472. local frameIndex = 0
  473. for _,valueMap in ipairs(values) do
  474. local attachmentName = valueMap["name"]
  475. timeline:setFrame(frameIndex, valueMap["time"], attachmentName)
  476. frameIndex = frameIndex + 1
  477. end
  478. table_insert(timelines, timeline)
  479. duration = math.max(duration, timeline.frames[timeline:getFrameCount() - 1])
  480. else
  481. error("Invalid frame type for a slot: " .. timelineName .. " (" .. slotName .. ")")
  482. end
  483. end
  484. end
  485. end
  486. -- Bone timelines
  487. local bonesMap = map["bones"]
  488. if bonesMap then
  489. for boneName,timelineMap in pairs(bonesMap) do
  490. local boneIndex = skeletonData:findBoneIndex(boneName)
  491. if boneIndex == -1 then error("Bone not found: " .. boneName) end
  492. for timelineName,values in pairs(timelineMap) do
  493. if timelineName == "rotate" then
  494. local timeline = Animation.RotateTimeline.new(#values)
  495. timeline.boneIndex = boneIndex
  496. local frameIndex = 0
  497. for _,valueMap in ipairs(values) do
  498. timeline:setFrame(frameIndex, valueMap["time"], valueMap["angle"])
  499. readCurve(valueMap, timeline, frameIndex)
  500. frameIndex = frameIndex + 1
  501. end
  502. table_insert(timelines, timeline)
  503. duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.RotateTimeline.ENTRIES])
  504. elseif timelineName == "translate" or timelineName == "scale" or timelineName == "shear" then
  505. local timeline
  506. local timelineScale = 1
  507. if timelineName == "scale" then
  508. timeline = Animation.ScaleTimeline.new(#values)
  509. elseif timelineName == "shear" then
  510. timeline = Animation.ShearTimeline.new(#values)
  511. else
  512. timeline = Animation.TranslateTimeline.new(#values)
  513. timelineScale = self.scale
  514. end
  515. timeline.boneIndex = boneIndex
  516. local frameIndex = 0
  517. for _,valueMap in ipairs(values) do
  518. local x = (valueMap["x"] or 0) * timelineScale
  519. local y = (valueMap["y"] or 0) * timelineScale
  520. timeline:setFrame(frameIndex, valueMap["time"], x, y)
  521. readCurve(valueMap, timeline, frameIndex)
  522. frameIndex = frameIndex + 1
  523. end
  524. table_insert(timelines, timeline)
  525. duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.TranslateTimeline.ENTRIES])
  526. else
  527. error("Invalid timeline type for a bone: " .. timelineName .. " (" .. boneName .. ")")
  528. end
  529. end
  530. end
  531. end
  532. -- IK timelines.
  533. local ik = map["ik"]
  534. if ik then
  535. for ikConstraintName,values in pairs(ik) do
  536. local ikConstraint = skeletonData:findIkConstraint(ikConstraintName)
  537. local timeline = Animation.IkConstraintTimeline.new(#values)
  538. for i,other in pairs(skeletonData.ikConstraints) do
  539. if other == ikConstraint then
  540. timeline.ikConstraintIndex = i
  541. break
  542. end
  543. end
  544. local frameIndex = 0
  545. for _,valueMap in ipairs(values) do
  546. local mix = 1
  547. if valueMap["mix"] ~= nil then mix = valueMap["mix"] end
  548. local bendPositive = 1
  549. if valueMap["bendPositive"] == false then bendPositive = -1 end
  550. local stretch = false
  551. if valueMap["stretch"] ~= nil then stretch = valueMap["stretch"] end
  552. local compress = false
  553. if valueMap["compress"] ~= nil then compress = valueMap["compress"] end
  554. timeline:setFrame(frameIndex, valueMap["time"], mix, bendPositive, compress, stretch)
  555. readCurve(valueMap, timeline, frameIndex)
  556. frameIndex = frameIndex + 1
  557. end
  558. table_insert(timelines, timeline)
  559. duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.IkConstraintTimeline.ENTRIES])
  560. end
  561. end
  562. -- Transform constraint timelines.
  563. local transform = map["transform"]
  564. if transform then
  565. for constraintName, values in pairs(transform) do
  566. local constraint = skeletonData:findTransformConstraint(constraintName)
  567. local timeline = Animation.TransformConstraintTimeline.new(#values)
  568. for i,other in pairs(skeletonData.transformConstraints) do
  569. if other == constraint then
  570. timeline.transformConstraintIndex = i
  571. break
  572. end
  573. end
  574. local frameIndex = 0
  575. for _,valueMap in ipairs(values) do
  576. timeline:setFrame(frameIndex, valueMap.time, getValue(valueMap, "rotateMix", 1), getValue(valueMap, "translateMix", 1), getValue(valueMap, "scaleMix", 1), getValue(valueMap, "shearMix", 1))
  577. readCurve(valueMap, timeline, frameIndex)
  578. frameIndex = frameIndex + 1
  579. end
  580. table_insert(timelines, timeline)
  581. duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.TransformConstraintTimeline.ENTRIES])
  582. end
  583. end
  584. -- Path constraint timelines.
  585. if map.paths then
  586. for constraintName,constraintMap in pairs(map.paths) do
  587. local index = skeletonData:findPathConstraintIndex(constraintName)
  588. if index == -1 then error("Path constraint not found: " .. constraintName, 2) end
  589. local data = skeletonData.pathConstraints[index]
  590. for timelineName, timelineMap in pairs(constraintMap) do
  591. if timelineName == "position" or timelineName == "spacing" then
  592. local timeline = nil
  593. local timelineScale = 1
  594. if timelineName == "spacing" then
  595. timeline = Animation.PathConstraintSpacingTimeline.new(#timelineMap)
  596. if data.spacingMode == PathConstraintData.SpacingMode.length or data.spacingMode == PathConstraintData.SpacingMode.fixed then timelineScale = scale end
  597. else
  598. timeline = Animation.PathConstraintPositionTimeline.new(#timelineMap)
  599. if data.positionMode == PathConstraintData.PositionMode.fixed then timelineScale = scale end
  600. end
  601. timeline.pathConstraintIndex = index
  602. local frameIndex = 0
  603. for _,valueMap in ipairs(timelineMap) do
  604. timeline:setFrame(frameIndex, valueMap.time, getValue(valueMap, timelineName, 0) * timelineScale)
  605. readCurve(valueMap, timeline, frameIndex)
  606. frameIndex = frameIndex + 1
  607. end
  608. table_insert(timelines, timeline)
  609. duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.PathConstraintPositionTimeline.ENTRIES])
  610. elseif timelineName == "mix" then
  611. local timeline = Animation.PathConstraintMixTimeline.new(#timelineMap)
  612. timeline.pathConstraintIndex = index
  613. local frameIndex = 0
  614. for _,valueMap in ipairs(timelineMap) do
  615. timeline:setFrame(frameIndex, valueMap.time, getValue(valueMap, "rotateMix", 1), getValue(valueMap, "translateMix", 1))
  616. readCurve(valueMap, timeline, frameIndex)
  617. frameIndex = frameIndex + 1
  618. end
  619. table_insert(timelines, timeline)
  620. duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.PathConstraintMixTimeline.ENTRIES])
  621. end
  622. end
  623. end
  624. end
  625. -- Deform timelines.
  626. if map.deform then
  627. for deformName, deformMap in pairs(map.deform) do
  628. local skin = skeletonData:findSkin(deformName)
  629. if not skin then error("Skin not found: " .. deformName, 2) end
  630. for slotName,slotMap in pairs(deformMap) do
  631. local slotIndex = skeletonData:findSlotIndex(slotName)
  632. if slotIndex == -1 then error("Slot not found: " .. slotMap.name, 2) end
  633. for timelineName,timelineMap in pairs(slotMap) do
  634. local attachment = skin:getAttachment(slotIndex, timelineName)
  635. if not attachment then error("Deform attachment not found: " .. timelineMap.name, 2) end
  636. local weighted = attachment.bones ~= nil
  637. local vertices = attachment.vertices;
  638. local deformLength = #vertices
  639. if weighted then deformLength = math.floor(#vertices / 3) * 2 end
  640. local timeline = Animation.DeformTimeline.new(#timelineMap)
  641. timeline.slotIndex = slotIndex
  642. timeline.attachment = attachment
  643. local frameIndex = 0
  644. for _,valueMap in ipairs(timelineMap) do
  645. local deform = nil
  646. local verticesValue = getValue(valueMap, "vertices", nil)
  647. if verticesValue == nil then
  648. deform = vertices
  649. if weighted then deform = utils.newNumberArray(deformLength) end
  650. else
  651. deform = utils.newNumberArray(deformLength)
  652. local start = getValue(valueMap, "offset", 0) + 1
  653. utils.arrayCopy(verticesValue, 1, deform, start, #verticesValue)
  654. if scale ~= 1 then
  655. local i = start
  656. local n = i + #verticesValue
  657. while i < n do
  658. deform[i] = deform[i] * scale
  659. i = i + 1
  660. end
  661. end
  662. if not weighted then
  663. local i = 1
  664. local n = i + deformLength
  665. while i < n do
  666. deform[i] = deform[i] + vertices[i]
  667. i = i + 1
  668. end
  669. end
  670. end
  671. timeline:setFrame(frameIndex, valueMap.time, deform)
  672. readCurve(valueMap, timeline, frameIndex)
  673. frameIndex = frameIndex + 1
  674. end
  675. table_insert(timelines, timeline)
  676. duration = math.max(duration, timeline.frames[timeline:getFrameCount() - 1])
  677. end
  678. end
  679. end
  680. end
  681. -- Draworder timeline.
  682. local drawOrderValues = map["drawOrder"]
  683. if not drawOrderValues then drawOrderValues = map["draworder"] end
  684. if drawOrderValues then
  685. local timeline = Animation.DrawOrderTimeline.new(#drawOrderValues)
  686. local slotCount = #skeletonData.slots
  687. local frameIndex = 0
  688. for _,drawOrderMap in ipairs(drawOrderValues) do
  689. local drawOrder = nil
  690. local offsets = drawOrderMap["offsets"]
  691. if offsets then
  692. drawOrder = {}
  693. local unchanged = {}
  694. local originalIndex = 1
  695. local unchangedIndex = 1
  696. for _,offsetMap in ipairs(offsets) do
  697. local slotIndex = skeletonData:findSlotIndex(offsetMap["slot"])
  698. if slotIndex == -1 then error("Slot not found: " .. offsetMap["slot"]) end
  699. -- Collect unchanged items.
  700. while originalIndex ~= slotIndex do
  701. unchanged[unchangedIndex] = originalIndex
  702. unchangedIndex = unchangedIndex + 1
  703. originalIndex = originalIndex + 1
  704. end
  705. -- Set changed items.
  706. drawOrder[originalIndex + offsetMap["offset"]] = originalIndex
  707. originalIndex = originalIndex + 1
  708. end
  709. -- Collect remaining unchanged items.
  710. while originalIndex <= slotCount do
  711. unchanged[unchangedIndex] = originalIndex
  712. unchangedIndex = unchangedIndex + 1
  713. originalIndex = originalIndex + 1
  714. end
  715. -- Fill in unchanged items.
  716. for ii = slotCount, 1, -1 do
  717. if not drawOrder[ii] then
  718. unchangedIndex = unchangedIndex - 1
  719. drawOrder[ii] = unchanged[unchangedIndex]
  720. end
  721. end
  722. end
  723. timeline:setFrame(frameIndex, drawOrderMap["time"], drawOrder)
  724. frameIndex = frameIndex + 1
  725. end
  726. table_insert(timelines, timeline)
  727. duration = math.max(duration, timeline.frames[timeline:getFrameCount() - 1])
  728. end
  729. -- Event timeline.
  730. local events = map["events"]
  731. if events then
  732. local timeline = Animation.EventTimeline.new(#events)
  733. local frameIndex = 0
  734. for _,eventMap in ipairs(events) do
  735. local eventData = skeletonData:findEvent(eventMap["name"])
  736. if not eventData then error("Event not found: " .. eventMap["name"]) end
  737. local event = Event.new(eventMap["time"], eventData)
  738. if eventMap["int"] ~= nil then
  739. event.intValue = eventMap["int"]
  740. else
  741. event.intValue = eventData.intValue
  742. end
  743. if eventMap["float"] ~= nil then
  744. event.floatValue = eventMap["float"]
  745. else
  746. event.floatValue = eventData.floatValue
  747. end
  748. if eventMap["string"] ~= nil then
  749. event.stringValue = eventMap["string"]
  750. else
  751. event.stringValue = eventData.stringValue
  752. end
  753. if eventData.audioPath ~= nil then
  754. event.volume = getValue(eventMap, "volume", 1)
  755. event.balance = getValue(eventMap, "balance", 0)
  756. end
  757. timeline:setFrame(frameIndex, event)
  758. frameIndex = frameIndex + 1
  759. end
  760. table_insert(timelines, timeline)
  761. duration = math.max(duration, timeline.frames[timeline:getFrameCount() - 1])
  762. end
  763. table_insert(skeletonData.animations, Animation.new(name, timelines, duration))
  764. end
  765. readCurve = function (map, timeline, frameIndex)
  766. local curve = map["curve"]
  767. if not curve then return end
  768. if curve == "stepped" then
  769. timeline:setStepped(frameIndex)
  770. elseif #curve > 0 then
  771. timeline:setCurve(frameIndex, curve[1], curve[2], curve[3], curve[4])
  772. end
  773. end
  774. getArray = function (map, name, scale)
  775. local list = map[name]
  776. local values = {}
  777. if scale == 1 then
  778. for i = 1, #list do
  779. values[i] = list[i]
  780. end
  781. else
  782. for i = 1, #list do
  783. values[i] = list[i] * scale
  784. end
  785. end
  786. return values
  787. end
  788. return self
  789. end
  790. return SkeletonJson