SkeletonJson.lua 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. -------------------------------------------------------------------------------
  2. -- Spine Runtimes Software License
  3. -- Version 2.1
  4. --
  5. -- Copyright (c) 2013, Esoteric Software
  6. -- All rights reserved.
  7. --
  8. -- You are granted a perpetual, non-exclusive, non-sublicensable and
  9. -- non-transferable license to install, execute and perform the Spine Runtimes
  10. -- Software (the "Software") solely for internal use. Without the written
  11. -- permission of Esoteric Software (typically granted by licensing Spine), you
  12. -- may not (a) modify, translate, adapt or otherwise create derivative works,
  13. -- improvements of the Software or develop new applications using the Software
  14. -- or (b) remove, delete, alter or obscure any trademarks or any copyright,
  15. -- trademark, patent or other intellectual property or proprietary rights
  16. -- notices on or in the Software, including any copy thereof. Redistributions
  17. -- in binary or source 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 SOFTARE 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; LOSS OF USE, DATA, OR PROFITS;
  25. -- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  26. -- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  27. -- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  28. -- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. -------------------------------------------------------------------------------
  30. local SkeletonData = require "spine-lua.SkeletonData"
  31. local BoneData = require "spine-lua.BoneData"
  32. local SlotData = require "spine-lua.SlotData"
  33. local Skin = require "spine-lua.Skin"
  34. local AttachmentLoader = require "spine-lua.AttachmentLoader"
  35. local Animation = require "spine-lua.Animation"
  36. local EventData = require "spine-lua.EventData"
  37. local Event = require "spine-lua.Event"
  38. local AttachmentType = require "spine-lua.AttachmentType"
  39. local SkeletonJson = {}
  40. function SkeletonJson.new (attachmentLoader)
  41. if not attachmentLoader then attachmentLoader = AttachmentLoader.new() end
  42. local self = {
  43. attachmentLoader = attachmentLoader,
  44. scale = 1
  45. }
  46. function self:readSkeletonDataFile (fileName, base)
  47. return self:readSkeletonData(spine.utils.readFile(fileName, base))
  48. end
  49. local readAttachment
  50. local readAnimation
  51. local readCurve
  52. local getArray
  53. function self:readSkeletonData (jsonText)
  54. local skeletonData = SkeletonData.new(self.attachmentLoader)
  55. local root = spine.utils.readJSON(jsonText)
  56. if not root then error("Invalid JSON: " .. jsonText, 2) end
  57. -- Bones.
  58. for i,boneMap in ipairs(root["bones"]) do
  59. local boneName = boneMap["name"]
  60. local parent = nil
  61. local parentName = boneMap["parent"]
  62. if parentName then
  63. parent = skeletonData:findBone(parentName)
  64. if not parent then error("Parent bone not found: " .. parentName) end
  65. end
  66. local boneData = BoneData.new(boneName, parent)
  67. boneData.length = (boneMap["length"] or 0) * self.scale
  68. boneData.x = (boneMap["x"] or 0) * self.scale
  69. boneData.y = (boneMap["y"] or 0) * self.scale
  70. boneData.rotation = (boneMap["rotation"] or 0)
  71. if boneMap["scaleX"] ~= nil then
  72. boneData.scaleX = boneMap["scaleX"]
  73. else
  74. boneData.scaleX = 1
  75. end
  76. if boneMap["scaleY"] ~= nil then
  77. boneData.scaleY = boneMap["scaleY"]
  78. else
  79. boneData.scaleY = 1
  80. end
  81. if boneMap["inheritScale"] == false then
  82. boneData.inheritScale = false
  83. else
  84. boneData.inheritScale = true
  85. end
  86. if boneMap["inheritRotation"] == false then
  87. boneData.inheritRotation = false
  88. else
  89. boneData.inheritRotation = true
  90. end
  91. table.insert(skeletonData.bones, boneData)
  92. end
  93. -- Slots.
  94. if root["slots"] then
  95. for i,slotMap in ipairs(root["slots"]) do
  96. local slotName = slotMap["name"]
  97. local boneName = slotMap["bone"]
  98. local boneData = skeletonData:findBone(boneName)
  99. if not boneData then error("Slot bone not found: " .. boneName) end
  100. local slotData = SlotData.new(slotName, boneData)
  101. local color = slotMap["color"]
  102. if color then
  103. slotData:setColor(
  104. tonumber(color:sub(1, 2), 16) / 255,
  105. tonumber(color:sub(3, 4), 16) / 255,
  106. tonumber(color:sub(5, 6), 16) / 255,
  107. tonumber(color:sub(7, 8), 16) / 255
  108. )
  109. end
  110. slotData.attachmentName = slotMap["attachment"]
  111. slotData.additiveBlending = slotMap["additive"]
  112. table.insert(skeletonData.slots, slotData)
  113. skeletonData.slotNameIndices[slotData.name] = #skeletonData.slots
  114. end
  115. end
  116. -- Skins.
  117. if root["skins"] then
  118. for skinName,skinMap in pairs(root["skins"]) do
  119. local skin = Skin.new(skinName)
  120. for slotName,slotMap in pairs(skinMap) do
  121. local slotIndex = skeletonData.slotNameIndices[slotName]
  122. for attachmentName,attachmentMap in pairs(slotMap) do
  123. local attachment = readAttachment(attachmentName, attachmentMap)
  124. if attachment then
  125. skin:addAttachment(slotIndex, attachmentName, attachment)
  126. end
  127. end
  128. end
  129. if skin.name == "default" then
  130. skeletonData.defaultSkin = skin
  131. else
  132. table.insert(skeletonData.skins, skin)
  133. end
  134. end
  135. end
  136. -- Events.
  137. if root["events"] then
  138. for eventName,eventMap in pairs(root["events"]) do
  139. local eventData = EventData.new(eventName)
  140. eventData.intValue = eventMap["int"] or 0
  141. eventData.floatValue = eventMap["float"] or 0
  142. eventData.stringValue = eventMap["string"]
  143. table.insert(skeletonData.events, eventData)
  144. end
  145. end
  146. -- Animations.
  147. if root["animations"] then
  148. for animationName,animationMap in pairs(root["animations"]) do
  149. readAnimation(animationName, animationMap, skeletonData)
  150. end
  151. end
  152. return skeletonData
  153. end
  154. readAttachment = function (name, map)
  155. name = map["name"] or name
  156. local type = AttachmentType[map["type"] or "region"]
  157. local path = map["path"] or name
  158. local scale = self.scale
  159. if type == AttachmentType.region then
  160. local region = attachmentLoader:newRegionAttachment(type, name, path)
  161. if not region then return nil end
  162. region.x = (map["x"] or 0) * scale
  163. region.y = (map["y"] or 0) * scale
  164. if map["scaleX"] ~= nil then
  165. region.scaleX = map["scaleX"]
  166. else
  167. region.scaleX = 1
  168. end
  169. if map["scaleY"] ~= nil then
  170. region.scaleY = map["scaleY"]
  171. else
  172. region.scaleY = 1
  173. end
  174. region.rotation = (map["rotation"] or 0)
  175. region.width = map["width"] * scale
  176. region.height = map["height"] * scale
  177. local color = map["color"]
  178. if color then
  179. region.r = tonumber(color:sub(1, 2), 16) / 255
  180. region.g = tonumber(color:sub(3, 4), 16) / 255
  181. region.b = tonumber(color:sub(5, 6), 16) / 255
  182. region.a = tonumber(color:sub(7, 8), 16) / 255
  183. end
  184. region:updateOffset()
  185. return region
  186. elseif type == AttachmentType.mesh then
  187. local mesh = attachmentLoader:newMeshAttachment(skin, name, path)
  188. if not mesh then return null end
  189. mesh.path = path
  190. mesh.vertices = getArray(map, "vertices", scale)
  191. mesh.triangles = getArray(map, "triangles", 1)
  192. mesh.regionUVs = getArray(map, "uvs", 1)
  193. mesh:updateUVs()
  194. local color = map["color"]
  195. if color then
  196. mesh.r = tonumber(color:sub(1, 2), 16) / 255
  197. mesh.g = tonumber(color:sub(3, 4), 16) / 255
  198. mesh.b = tonumber(color:sub(5, 6), 16) / 255
  199. mesh.a = tonumber(color:sub(7, 8), 16) / 255
  200. end
  201. mesh.hullLength = (map["hull"] or 0) * 2
  202. if map["edges"] then mesh.edges = getArray(map, "edges", 1) end
  203. mesh.width = (map["width"] or 0) * scale
  204. mesh.height = (map["height"] or 0) * scale
  205. return mesh
  206. elseif type == AttachmentType.skinnedmesh then
  207. local mesh = self.attachmentLoader.newSkinnedMeshAttachment(skin, name, path)
  208. if not mesh then return null end
  209. mesh.path = path
  210. local uvs = getArray(map, "uvs", 1)
  211. vertices = getArray(map, "vertices", 1)
  212. local weights = {}
  213. local bones = {}
  214. for i = 1, vertices do
  215. local boneCount = vertices[i]
  216. i = i + 1
  217. table.insert(bones, boneCount)
  218. for ii = 1, i + boneCount * 4 do
  219. table.insert(bones, vertices[i])
  220. table.insert(weights, vertices[i + 1] * scale)
  221. table.insert(weights, vertices[i + 2] * scale)
  222. table.insert(weights, vertices[i + 3])
  223. i = i + 4
  224. end
  225. end
  226. mesh.bones = bones
  227. mesh.weights = weights
  228. mesh.triangles = getArray(map, "triangles", 1)
  229. mesh.regionUVs = uvs
  230. mesh:updateUVs()
  231. local color = map["color"]
  232. if color then
  233. mesh.r = tonumber(color:sub(1, 2), 16) / 255
  234. mesh.g = tonumber(color:sub(3, 4), 16) / 255
  235. mesh.b = tonumber(color:sub(5, 6), 16) / 255
  236. mesh.a = tonumber(color:sub(7, 8), 16) / 255
  237. end
  238. mesh.hullLength = (map["hull"] or 0) * 2
  239. if map["edges"] then mesh.edges = getArray(map, "edges", 1) end
  240. mesh.width = (map["width"] or 0) * scale
  241. mesh.height = (map["height"] or 0) * scale
  242. return mesh
  243. elseif type == AttachmentType.boundingbox then
  244. local box = attachmentLoader:newBoundingBoxAttachment(type, name)
  245. if not box then return nil end
  246. local vertices = map["vertices"]
  247. for i,point in ipairs(vertices) do
  248. table.insert(box.vertices, vertices[i] * scale)
  249. end
  250. return box
  251. end
  252. error("Unknown attachment type: " .. type .. " (" .. name .. ")")
  253. end
  254. readAnimation = function (name, map, skeletonData)
  255. local timelines = {}
  256. local duration = 0
  257. local slotsMap = map["slots"]
  258. if slotsMap then
  259. for slotName,timelineMap in pairs(slotsMap) do
  260. local slotIndex = skeletonData.slotNameIndices[slotName]
  261. for timelineName,values in pairs(timelineMap) do
  262. if timelineName == "color" then
  263. local timeline = Animation.ColorTimeline.new()
  264. timeline.slotIndex = slotIndex
  265. local frameIndex = 0
  266. for i,valueMap in ipairs(values) do
  267. local color = valueMap["color"]
  268. timeline:setFrame(
  269. frameIndex, valueMap["time"],
  270. tonumber(color:sub(1, 2), 16) / 255,
  271. tonumber(color:sub(3, 4), 16) / 255,
  272. tonumber(color:sub(5, 6), 16) / 255,
  273. tonumber(color:sub(7, 8), 16) / 255
  274. )
  275. readCurve(timeline, frameIndex, valueMap)
  276. frameIndex = frameIndex + 1
  277. end
  278. table.insert(timelines, timeline)
  279. duration = math.max(duration, timeline:getDuration())
  280. elseif timelineName == "attachment" then
  281. local timeline = Animation.AttachmentTimeline.new()
  282. timeline.slotName = slotName
  283. local frameIndex = 0
  284. for i,valueMap in ipairs(values) do
  285. local attachmentName = valueMap["name"]
  286. if not attachmentName then attachmentName = nil end
  287. timeline:setFrame(frameIndex, valueMap["time"], attachmentName)
  288. frameIndex = frameIndex + 1
  289. end
  290. table.insert(timelines, timeline)
  291. duration = math.max(duration, timeline:getDuration())
  292. else
  293. error("Invalid frame type for a slot: " .. timelineName .. " (" .. slotName .. ")")
  294. end
  295. end
  296. end
  297. end
  298. local bonesMap = map["bones"]
  299. if bonesMap then
  300. for boneName,timelineMap in pairs(bonesMap) do
  301. local boneIndex = skeletonData:findBoneIndex(boneName)
  302. if boneIndex == -1 then error("Bone not found: " .. boneName) end
  303. for timelineName,values in pairs(timelineMap) do
  304. if timelineName == "rotate" then
  305. local timeline = Animation.RotateTimeline.new()
  306. timeline.boneIndex = boneIndex
  307. local frameIndex = 0
  308. for i,valueMap in ipairs(values) do
  309. timeline:setFrame(frameIndex, valueMap["time"], valueMap["angle"])
  310. readCurve(timeline, frameIndex, valueMap)
  311. frameIndex = frameIndex + 1
  312. end
  313. table.insert(timelines, timeline)
  314. duration = math.max(duration, timeline:getDuration())
  315. elseif timelineName == "translate" or timelineName == "scale" then
  316. local timeline
  317. local timelineScale = 1
  318. if timelineName == "scale" then
  319. timeline = Animation.ScaleTimeline.new()
  320. else
  321. timeline = Animation.TranslateTimeline.new()
  322. timelineScale = self.scale
  323. end
  324. timeline.boneIndex = boneIndex
  325. local frameIndex = 0
  326. for i,valueMap in ipairs(values) do
  327. local x = (valueMap["x"] or 0) * timelineScale
  328. local y = (valueMap["y"] or 0) * timelineScale
  329. timeline:setFrame(frameIndex, valueMap["time"], x, y)
  330. readCurve(timeline, frameIndex, valueMap)
  331. frameIndex = frameIndex + 1
  332. end
  333. table.insert(timelines, timeline)
  334. duration = math.max(duration, timeline:getDuration())
  335. else
  336. error("Invalid timeline type for a bone: " .. timelineName .. " (" .. boneName .. ")")
  337. end
  338. end
  339. end
  340. end
  341. local ffd = map["ffd"]
  342. if ffd then
  343. for skinName,slotMap in pairs(ffd) do
  344. local skin = skeletonData.findSkin(skinName)
  345. for slotName,meshMap in pairs(slotMap) do
  346. local slotIndex = skeletonData.findSlotIndex(slotName)
  347. for meshName,values in pairs(meshMap) do
  348. local timeline = Animation.FfdTimeline.new()
  349. local attachment = skin:getAttachment(slotIndex, meshName)
  350. if not attachment then error("FFD attachment not found: " .. meshName) end
  351. timeline.slotIndex = slotIndex
  352. timeline.attachment = attachment
  353. local isMesh = attachment.type == AttachmentType.mesh
  354. local vertexCount
  355. if isMesh then
  356. vertexCount = attachment.vertices.length
  357. else
  358. vertexCount = attachment.weights.length / 3 * 2
  359. end
  360. local frameIndex = 0
  361. for i,valueMap in ipairs(values) do
  362. local vertices
  363. if not valueMap["vertices"] then
  364. if isMesh then
  365. vertices = attachment.vertices
  366. else
  367. vertices = {}
  368. vertices.length = vertexCount
  369. end
  370. else
  371. local verticesValue = valueMap["vertices"]
  372. local vertices = {}
  373. local start = valueMap["offset"] or 0
  374. if scale == 1 then
  375. for ii = 1, #verticesValue do
  376. vertices[ii + start] = verticesValue[ii]
  377. end
  378. else
  379. for ii = 1, #verticesValue do
  380. vertices[ii + start] = verticesValue[ii] * scale
  381. end
  382. end
  383. if isMesh then
  384. local meshVertices = attachment.vertices
  385. for ii = 1, vertexCount do
  386. vertices[ii] = vertices[ii] + meshVertices[ii]
  387. end
  388. elseif #verticesValue < vertexCount then
  389. vertices[vertexCount] = 0
  390. end
  391. end
  392. timeline:setFrame(frameIndex, valueMap["time"], vertices)
  393. readCurve(timeline, frameIndex, valueMap)
  394. frameIndex = frameIndex + 1
  395. end
  396. table.insert(timelines, timeline)
  397. duration = math.max(duration, timeline:getDuration())
  398. end
  399. end
  400. end
  401. end
  402. local drawOrderValues = map["draworder"]
  403. if drawOrderValues then
  404. local timeline = Animation.DrawOrderTimeline.new(#drawOrderValues)
  405. local slotCount = #skeletonData.slots
  406. local frameIndex = 0
  407. for i,drawOrderMap in ipairs(drawOrderValues) do
  408. local drawOrder = nil
  409. local offsets = drawOrderMap["offsets"]
  410. if offsets then
  411. drawOrder = {}
  412. local unchanged = {}
  413. local originalIndex = 1
  414. local unchangedIndex = 1
  415. for ii,offsetMap in ipairs(offsets) do
  416. local slotIndex = skeletonData:findSlotIndex(offsetMap["slot"])
  417. if slotIndex == -1 then error("Slot not found: " .. offsetMap["slot"]) end
  418. -- Collect unchanged items.
  419. while originalIndex ~= slotIndex do
  420. unchanged[unchangedIndex] = originalIndex
  421. unchangedIndex = unchangedIndex + 1
  422. originalIndex = originalIndex + 1
  423. end
  424. -- Set changed items.
  425. drawOrder[originalIndex + offsetMap["offset"]] = originalIndex
  426. originalIndex = originalIndex + 1
  427. end
  428. -- Collect remaining unchanged items.
  429. while originalIndex <= slotCount do
  430. unchanged[unchangedIndex] = originalIndex
  431. unchangedIndex = unchangedIndex + 1
  432. originalIndex = originalIndex + 1
  433. end
  434. -- Fill in unchanged items.
  435. for ii = slotCount, 1, -1 do
  436. if not drawOrder[ii] then
  437. unchangedIndex = unchangedIndex - 1
  438. drawOrder[ii] = unchanged[unchangedIndex]
  439. end
  440. end
  441. end
  442. timeline:setFrame(frameIndex, drawOrderMap["time"], drawOrder)
  443. frameIndex = frameIndex + 1
  444. end
  445. table.insert(timelines, timeline)
  446. duration = math.max(duration, timeline:getDuration())
  447. end
  448. local events = map["events"]
  449. if events then
  450. local timeline = Animation.EventTimeline.new(#events)
  451. local frameIndex = 0
  452. for i,eventMap in ipairs(events) do
  453. local eventData = skeletonData:findEvent(eventMap["name"])
  454. if not eventData then error("Event not found: " .. eventMap["name"]) end
  455. local event = Event.new(eventData)
  456. if eventMap["int"] ~= nil then
  457. event.intValue = eventMap["int"]
  458. else
  459. event.intValue = eventData.intValue
  460. end
  461. if eventMap["float"] ~= nil then
  462. event.floatValue = eventMap["float"]
  463. else
  464. event.floatValue = eventData.floatValue
  465. end
  466. if eventMap["string"] ~= nil then
  467. event.stringValue = eventMap["string"]
  468. else
  469. event.stringValue = eventData.stringValue
  470. end
  471. timeline:setFrame(frameIndex, eventMap["time"], event)
  472. frameIndex = frameIndex + 1
  473. end
  474. table.insert(timelines, timeline)
  475. duration = math.max(duration, timeline:getDuration())
  476. end
  477. table.insert(skeletonData.animations, Animation.new(name, timelines, duration))
  478. end
  479. readCurve = function (timeline, frameIndex, valueMap)
  480. local curve = valueMap["curve"]
  481. if not curve then return end
  482. if curve == "stepped" then
  483. timeline:setStepped(frameIndex)
  484. else
  485. timeline:setCurve(frameIndex, curve[1], curve[2], curve[3], curve[4])
  486. end
  487. end
  488. getArray = function (map, name, scale)
  489. local list = map[name]
  490. local values = {}
  491. if scale == 1 then
  492. for i = 1, #list do
  493. values[i] = list[i]
  494. end
  495. else
  496. for i = 1, #list do
  497. values[i] = list[i] * scale
  498. end
  499. end
  500. return values
  501. end
  502. return self
  503. end
  504. return SkeletonJson