Animation.lua 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  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 Animation = {}
  31. function Animation.new (name, timelines, duration)
  32. if not timelines then error("timelines cannot be nil", 2) end
  33. local self = {
  34. name = name,
  35. timelines = timelines,
  36. duration = duration
  37. }
  38. function self:apply (skeleton, lastTime, time, loop, events)
  39. if not skeleton then error("skeleton cannot be nil.", 2) end
  40. if loop and duration > 0 then
  41. time = time % self.duration
  42. lastTime = lastTime % self.duration
  43. end
  44. for i,timeline in ipairs(self.timelines) do
  45. timeline:apply(skeleton, lastTime, time, events, 1)
  46. end
  47. end
  48. function self:mix (skeleton, lastTime, time, loop, events, alpha)
  49. if not skeleton then error("skeleton cannot be nil.", 2) end
  50. if loop and duration > 0 then
  51. time = time % self.duration
  52. lastTime = lastTime % self.duration
  53. end
  54. for i,timeline in ipairs(self.timelines) do
  55. timeline:apply(skeleton, lastTime, time, events, alpha)
  56. end
  57. end
  58. return self
  59. end
  60. local function binarySearch (values, target, step)
  61. local low = 0
  62. local high = math.floor((#values + 1) / step - 2)
  63. if high == 0 then return step end
  64. local current = math.floor(high / 2)
  65. while true do
  66. if values[(current + 1) * step] <= target then
  67. low = current + 1
  68. else
  69. high = current
  70. end
  71. if low == high then return (low + 1) * step end
  72. current = math.floor((low + high) / 2)
  73. end
  74. end
  75. local function linearSearch (values, target, step)
  76. for i = 0, #values, step do
  77. if (values[i] > target) then return i end
  78. end
  79. return -1
  80. end
  81. Animation.CurveTimeline = {}
  82. function Animation.CurveTimeline.new ()
  83. local LINEAR = 0
  84. local STEPPED = -1
  85. local BEZIER_SEGMENTS = 10
  86. local self = {
  87. curves = {}
  88. }
  89. function self:setLinear (frameIndex)
  90. self.curves[frameIndex * 6] = LINEAR
  91. end
  92. function self:setStepped (frameIndex)
  93. self.curves[frameIndex * 6] = STEPPED
  94. end
  95. function self:setCurve (frameIndex, cx1, cy1, cx2, cy2)
  96. local subdiv_step = 1 / BEZIER_SEGMENTS
  97. local subdiv_step2 = subdiv_step * subdiv_step
  98. local subdiv_step3 = subdiv_step2 * subdiv_step
  99. local pre1 = 3 * subdiv_step
  100. local pre2 = 3 * subdiv_step2
  101. local pre4 = 6 * subdiv_step2
  102. local pre5 = 6 * subdiv_step3
  103. local tmp1x = -cx1 * 2 + cx2
  104. local tmp1y = -cy1 * 2 + cy2
  105. local tmp2x = (cx1 - cx2) * 3 + 1
  106. local tmp2y = (cy1 - cy2) * 3 + 1
  107. local i = frameIndex * 6
  108. local curves = self.curves
  109. curves[i] = cx1 * pre1 + tmp1x * pre2 + tmp2x * subdiv_step3
  110. curves[i + 1] = cy1 * pre1 + tmp1y * pre2 + tmp2y * subdiv_step3
  111. curves[i + 2] = tmp1x * pre4 + tmp2x * pre5
  112. curves[i + 3] = tmp1y * pre4 + tmp2y * pre5
  113. curves[i + 4] = tmp2x * pre5
  114. curves[i + 5] = tmp2y * pre5
  115. end
  116. function self:getCurvePercent (frameIndex, percent)
  117. local curveIndex = frameIndex * 6
  118. local curves = self.curves
  119. local dfx = curves[curveIndex]
  120. if not dfx then return percent end -- linear
  121. if dfx == STEPPED then return 0 end
  122. local dfy = curves[curveIndex + 1]
  123. local ddfx = curves[curveIndex + 2]
  124. local ddfy = curves[curveIndex + 3]
  125. local dddfx = curves[curveIndex + 4]
  126. local dddfy = curves[curveIndex + 5]
  127. local x = dfx
  128. local y = dfy
  129. local i = BEZIER_SEGMENTS - 2
  130. while true do
  131. if x >= percent then
  132. local lastX = x - dfx
  133. local lastY = y - dfy
  134. return lastY + (y - lastY) * (percent - lastX) / (x - lastX)
  135. end
  136. if i == 0 then break end
  137. i = i - 1
  138. dfx = dfx + ddfx
  139. dfy = dfy + ddfy
  140. ddfx = ddfx + dddfx
  141. ddfy = ddfy + dddfy
  142. x = x + dfx
  143. y = y + dfy
  144. end
  145. return y + (1 - y) * (percent - x) / (1 - x) -- Last point is 1,1.
  146. end
  147. return self
  148. end
  149. Animation.RotateTimeline = {}
  150. function Animation.RotateTimeline.new ()
  151. local LAST_FRAME_TIME = -2
  152. local FRAME_VALUE = 1
  153. local self = Animation.CurveTimeline.new()
  154. self.frames = {}
  155. self.boneIndex = -1
  156. function self:getDuration ()
  157. return self.frames[#self.frames - 1]
  158. end
  159. function self:getFrameCount ()
  160. return (#self.frames + 1) / 2
  161. end
  162. function self:setFrame (frameIndex, time, value)
  163. frameIndex = frameIndex * 2
  164. self.frames[frameIndex] = time
  165. self.frames[frameIndex + 1] = value
  166. end
  167. function self:apply (skeleton, lastTime, time, firedEvents, alpha)
  168. local frames = self.frames
  169. if time < frames[0] then return end -- Time is before first frame.
  170. local bone = skeleton.bones[self.boneIndex]
  171. if time >= frames[#frames - 1] then -- Time is after last frame.
  172. local amount = bone.data.rotation + frames[#frames] - bone.rotation
  173. while amount > 180 do
  174. amount = amount - 360
  175. end
  176. while amount < -180 do
  177. amount = amount + 360
  178. end
  179. bone.rotation = bone.rotation + amount * alpha
  180. return
  181. end
  182. -- Interpolate between the last frame and the current frame.
  183. local frameIndex = binarySearch(frames, time, 2)
  184. local lastFrameValue = frames[frameIndex - 1]
  185. local frameTime = frames[frameIndex]
  186. local percent = 1 - (time - frameTime) / (frames[frameIndex + LAST_FRAME_TIME] - frameTime)
  187. if percent < 0 then percent = 0 elseif percent > 1 then percent = 1 end
  188. percent = self:getCurvePercent(frameIndex / 2 - 1, percent)
  189. local amount = frames[frameIndex + FRAME_VALUE] - lastFrameValue
  190. while amount > 180 do
  191. amount = amount - 360
  192. end
  193. while amount < -180 do
  194. amount = amount + 360
  195. end
  196. amount = bone.data.rotation + (lastFrameValue + amount * percent) - bone.rotation
  197. while amount > 180 do
  198. amount = amount - 360
  199. end
  200. while amount < -180 do
  201. amount = amount + 360
  202. end
  203. bone.rotation = bone.rotation + amount * alpha
  204. end
  205. return self
  206. end
  207. Animation.TranslateTimeline = {}
  208. function Animation.TranslateTimeline.new ()
  209. local LAST_FRAME_TIME = -3
  210. local FRAME_X = 1
  211. local FRAME_Y = 2
  212. local self = Animation.CurveTimeline.new()
  213. self.frames = {}
  214. self.boneIndex = -1
  215. function self:getDuration ()
  216. return self.frames[#self.frames - 2]
  217. end
  218. function self:getFrameCount ()
  219. return (#self.frames + 1) / 3
  220. end
  221. function self:setFrame (frameIndex, time, x, y)
  222. frameIndex = frameIndex * 3
  223. self.frames[frameIndex] = time
  224. self.frames[frameIndex + 1] = x
  225. self.frames[frameIndex + 2] = y
  226. end
  227. function self:apply (skeleton, lastTime, time, firedEvents, alpha)
  228. local frames = self.frames
  229. if time < frames[0] then return end -- Time is before first frame.
  230. local bone = skeleton.bones[self.boneIndex]
  231. if time >= frames[#frames - 2] then -- Time is after last frame.
  232. bone.x = bone.x + (bone.data.x + frames[#frames - 1] - bone.x) * alpha
  233. bone.y = bone.y + (bone.data.y + frames[#frames] - bone.y) * alpha
  234. return
  235. end
  236. -- Interpolate between the last frame and the current frame.
  237. local frameIndex = binarySearch(frames, time, 3)
  238. local lastFrameX = frames[frameIndex - 2]
  239. local lastFrameY = frames[frameIndex - 1]
  240. local frameTime = frames[frameIndex]
  241. local percent = 1 - (time - frameTime) / (frames[frameIndex + LAST_FRAME_TIME] - frameTime)
  242. if percent < 0 then percent = 0 elseif percent > 1 then percent = 1 end
  243. percent = self:getCurvePercent(frameIndex / 3 - 1, percent)
  244. bone.x = bone.x + (bone.data.x + lastFrameX + (frames[frameIndex + FRAME_X] - lastFrameX) * percent - bone.x) * alpha
  245. bone.y = bone.y + (bone.data.y + lastFrameY + (frames[frameIndex + FRAME_Y] - lastFrameY) * percent - bone.y) * alpha
  246. end
  247. return self
  248. end
  249. Animation.ScaleTimeline = {}
  250. function Animation.ScaleTimeline.new ()
  251. local LAST_FRAME_TIME = -3
  252. local FRAME_X = 1
  253. local FRAME_Y = 2
  254. local self = Animation.TranslateTimeline.new()
  255. function self:apply (skeleton, lastTime, time, firedEvents, alpha)
  256. local frames = self.frames
  257. if time < frames[0] then return end -- Time is before first frame.
  258. local bone = skeleton.bones[self.boneIndex]
  259. if time >= frames[#frames - 2] then -- Time is after last frame.
  260. bone.scaleX = bone.scaleX + (bone.data.scaleX - 1 + frames[#frames - 1] - bone.scaleX) * alpha
  261. bone.scaleY = bone.scaleY + (bone.data.scaleY - 1 + frames[#frames] - bone.scaleY) * alpha
  262. return
  263. end
  264. -- Interpolate between the last frame and the current frame.
  265. local frameIndex = binarySearch(frames, time, 3)
  266. local lastFrameX = frames[frameIndex - 2]
  267. local lastFrameY = frames[frameIndex - 1]
  268. local frameTime = frames[frameIndex]
  269. local percent = 1 - (time - frameTime) / (frames[frameIndex + LAST_FRAME_TIME] - frameTime)
  270. if percent < 0 then percent = 0 elseif percent > 1 then percent = 1 end
  271. percent = self:getCurvePercent(frameIndex / 3 - 1, percent)
  272. bone.scaleX = bone.scaleX + (bone.data.scaleX - 1 + lastFrameX + (frames[frameIndex + FRAME_X] - lastFrameX) * percent - bone.scaleX) * alpha
  273. bone.scaleY = bone.scaleY + (bone.data.scaleY - 1 + lastFrameY + (frames[frameIndex + FRAME_Y] - lastFrameY) * percent - bone.scaleY) * alpha
  274. end
  275. return self
  276. end
  277. Animation.ColorTimeline = {}
  278. function Animation.ColorTimeline.new ()
  279. local LAST_FRAME_TIME = -5
  280. local FRAME_R = 1
  281. local FRAME_G = 2
  282. local FRAME_B = 3
  283. local FRAME_A = 4
  284. local self = Animation.CurveTimeline.new()
  285. self.frames = {}
  286. self.slotIndex = -1
  287. function self:getDuration ()
  288. return self.frames[#self.frames - 4]
  289. end
  290. function self:getFrameCount ()
  291. return (#self.frames + 1) / 5
  292. end
  293. function self:setFrame (frameIndex, time, r, g, b, a)
  294. frameIndex = frameIndex * 5
  295. self.frames[frameIndex] = time
  296. self.frames[frameIndex + 1] = r
  297. self.frames[frameIndex + 2] = g
  298. self.frames[frameIndex + 3] = b
  299. self.frames[frameIndex + 4] = a
  300. end
  301. function self:apply (skeleton, lastTime, time, firedEvents, alpha)
  302. local frames = self.frames
  303. if time < frames[0] then return end -- Time is before first frame.
  304. local r, g, b, a
  305. if time >= frames[#frames - 4] then -- Time is after last frame.
  306. r = frames[#frames - 3]
  307. g = frames[#frames - 2]
  308. b = frames[#frames - 1]
  309. a = frames[#frames]
  310. else
  311. -- Interpolate between the last frame and the current frame.
  312. local frameIndex = binarySearch(frames, time, 5)
  313. local lastFrameR = frames[frameIndex - 4]
  314. local lastFrameG = frames[frameIndex - 3]
  315. local lastFrameB = frames[frameIndex - 2]
  316. local lastFrameA = frames[frameIndex - 1]
  317. local frameTime = frames[frameIndex]
  318. local percent = 1 - (time - frameTime) / (frames[frameIndex + LAST_FRAME_TIME] - frameTime)
  319. if percent < 0 then percent = 0 elseif percent > 255 then percent = 255 end
  320. percent = self:getCurvePercent(frameIndex / 5 - 1, percent)
  321. r = lastFrameR + (frames[frameIndex + FRAME_R] - lastFrameR) * percent
  322. g = lastFrameG + (frames[frameIndex + FRAME_G] - lastFrameG) * percent
  323. b = lastFrameB + (frames[frameIndex + FRAME_B] - lastFrameB) * percent
  324. a = lastFrameA + (frames[frameIndex + FRAME_A] - lastFrameA) * percent
  325. end
  326. local slot = skeleton.slots[self.slotIndex]
  327. if alpha < 1 then
  328. slot:setColor(slot.r + (r - slot.r) * alpha, slot.g + (g - slot.g) * alpha, slot.b + (b - slot.b) * alpha, slot.a + (a - slot.a) * alpha)
  329. else
  330. slot:setColor(r, g, b, a)
  331. end
  332. end
  333. return self
  334. end
  335. Animation.AttachmentTimeline = {}
  336. function Animation.AttachmentTimeline.new ()
  337. local self = {
  338. frames = {},
  339. attachmentNames = {},
  340. slotName = nil
  341. }
  342. function self:getDuration ()
  343. return self.frames[#self.frames]
  344. end
  345. function self:getFrameCount ()
  346. return #self.frames + 1
  347. end
  348. function self:setFrame (frameIndex, time, attachmentName)
  349. self.frames[frameIndex] = time
  350. self.attachmentNames[frameIndex] = attachmentName
  351. end
  352. function self:apply (skeleton, lastTime, time, firedEvents, alpha)
  353. local frames = self.frames
  354. if time < frames[0] then return end -- Time is before first frame.
  355. local frameIndex
  356. if time >= frames[#frames] then -- Time is after last frame.
  357. frameIndex = #frames
  358. else
  359. frameIndex = binarySearch(frames, time, 1) - 1
  360. end
  361. local attachmentName = self.attachmentNames[frameIndex]
  362. local slot = skeleton.slotsByName[self.slotName]
  363. if attachmentName then
  364. if not slot.attachment then
  365. slot:setAttachment(skeleton:getAttachment(self.slotName, attachmentName))
  366. elseif slot.attachment.name ~= attachmentName then
  367. slot:setAttachment(skeleton:getAttachment(self.slotName, attachmentName))
  368. end
  369. else
  370. slot:setAttachment(nil)
  371. end
  372. end
  373. return self
  374. end
  375. Animation.EventTimeline = {}
  376. function Animation.EventTimeline.new ()
  377. local self = {
  378. frames = {},
  379. events = {}
  380. }
  381. function self:getDuration ()
  382. return self.frames[#self.frames]
  383. end
  384. function self:getFrameCount ()
  385. return #self.frames + 1
  386. end
  387. function self:setFrame (frameIndex, time, event)
  388. self.frames[frameIndex] = time
  389. self.events[frameIndex] = event
  390. end
  391. -- Fires events for frames > lastTime and <= time.
  392. function self:apply (skeleton, lastTime, time, firedEvents, alpha)
  393. if not firedEvents then return end
  394. local frames = self.frames
  395. local frameCount = #frames
  396. if lastTime > time then -- Fire events after last time for looped animations.
  397. self:apply(skeleton, lastTime, 999999, firedEvents, alpha)
  398. lastTime = -1
  399. elseif lastTime >= frames[frameCount - 1] then -- Last time is after last frame.
  400. return
  401. end
  402. if time < frames[0] then return end -- Time is before first frame.
  403. local frameIndex
  404. if lastTime < frames[0] then
  405. frameIndex = 0
  406. else
  407. frameIndex = binarySearch(frames, lastTime, 1)
  408. local frame = frames[frameIndex]
  409. while frameIndex > 0 do -- Fire multiple events with the same frame.
  410. if frames[frameIndex - 1] ~= frame then break end
  411. frameIndex = frameIndex - 1
  412. end
  413. end
  414. local events = self.events
  415. while frameIndex < frameCount and time >= frames[frameIndex] do
  416. table.insert(firedEvents, events[frameIndex])
  417. frameIndex = frameIndex + 1
  418. end
  419. end
  420. return self
  421. end
  422. Animation.DrawOrderTimeline = {}
  423. function Animation.DrawOrderTimeline.new ()
  424. local self = {
  425. frames = {},
  426. drawOrders = {}
  427. }
  428. function self:getDuration ()
  429. return self.frames[#self.frames]
  430. end
  431. function self:getFrameCount ()
  432. return #self.frames + 1
  433. end
  434. function self:setFrame (frameIndex, time, drawOrder)
  435. self.frames[frameIndex] = time
  436. self.drawOrders[frameIndex] = drawOrder
  437. end
  438. function self:apply (skeleton, lastTime, time, firedEvents, alpha)
  439. local frames = self.frames
  440. if time < frames[0] then return end -- Time is before first frame.
  441. local frameIndex
  442. if time >= frames[#frames] then -- Time is after last frame.
  443. frameIndex = #frames
  444. else
  445. frameIndex = binarySearch(frames, time, 1) - 1
  446. end
  447. local drawOrder = skeleton.drawOrder
  448. local slots = skeleton.slots
  449. local drawOrderToSetupIndex = self.drawOrders[frameIndex]
  450. if not drawOrderToSetupIndex then
  451. for i,slot in ipairs(slots) do
  452. drawOrder[i] = slots[i]
  453. end
  454. else
  455. for i,setupIndex in ipairs(drawOrderToSetupIndex) do
  456. drawOrder[i] = skeleton.slots[setupIndex]
  457. end
  458. end
  459. end
  460. return self
  461. end
  462. return Animation