Bone.lua 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  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 setmetatable = setmetatable
  31. local math_rad = math.rad
  32. local math_deg = math.deg
  33. local math_sin = math.sin
  34. local math_cos = math.cos
  35. local math_atan2 = math.atan2
  36. local math_sqrt = math.sqrt
  37. local math_abs = math.abs
  38. local math_pi = math.pi
  39. local TransformMode = require "spine-lua.TransformMode"
  40. function math.sign(x)
  41. if x<0 then
  42. return -1
  43. elseif x>0 then
  44. return 1
  45. else
  46. return 0
  47. end
  48. end
  49. local math_sign = math.sign
  50. local Bone = {}
  51. Bone.__index = Bone
  52. function Bone.new (data, skeleton, parent)
  53. if not data then error("data cannot be nil", 2) end
  54. if not skeleton then error("skeleton cannot be nil", 2) end
  55. local self = {
  56. data = data,
  57. skeleton = skeleton,
  58. parent = parent,
  59. children = { },
  60. x = 0, y = 0, rotation = 0, scaleX = 1, scaleY = 1, shearX = 0, shearY = 0,
  61. ax = 0, ay = 0, arotation = 0, ascaleX = 0, ascaleY = 0, ashearX = 0, ashearY = 0,
  62. appliedValid = false,
  63. a = 0, b = 0, worldX = 0, -- a b x
  64. c = 0, d = 0, worldY = 0, -- c d y
  65. sorted = false
  66. }
  67. setmetatable(self, Bone)
  68. self:setToSetupPose()
  69. return self
  70. end
  71. function Bone:update ()
  72. self:updateWorldTransformWith(self.x, self.y, self.rotation, self.scaleX, self.scaleY, self.shearX, self.shearY)
  73. end
  74. function Bone:updateWorldTransform ()
  75. self:updateWorldTransformWith(self.x, self.y, self.rotation, self.scaleX, self.scaleY, self.shearX, self.shearY)
  76. end
  77. function Bone:updateWorldTransformWith (x, y, rotation, scaleX, scaleY, shearX, shearY)
  78. self.ax = x
  79. self.ay = y
  80. self.arotation = rotation
  81. self.ascaleX = scaleX
  82. self.ascaleY = scaleY
  83. self.ashearX = shearX
  84. self.ashearY = shearY
  85. self.appliedValid = true
  86. local sx = self.skeleton.scaleX;
  87. local sy = self.skeleton.scaleY;
  88. local parent = self.parent
  89. if parent == nil then
  90. local rotationY = rotation + 90 + shearY
  91. local rotationRad = math_rad(rotation + shearX)
  92. local rotationYRad = math_rad(rotationY)
  93. local skeleton = self.skeleton
  94. self.a = math_cos(rotationRad) * scaleX * sx
  95. self.b = math_cos(rotationYRad) * scaleY * sy
  96. self.c = math_sin(rotationRad) * scaleX * sx
  97. self.d = math_sin(rotationYRad) * scaleY * sy
  98. self.worldX = x * sx + skeleton.x
  99. self.worldY = y * sy + skeleton.y
  100. return
  101. end
  102. local pa = parent.a
  103. local pb = parent.b
  104. local pc = parent.c
  105. local pd = parent.d
  106. self.worldX = pa * x + pb * y + parent.worldX
  107. self.worldY = pc * x + pd * y + parent.worldY
  108. local transformMode = self.data.transformMode
  109. if transformMode == TransformMode.normal then
  110. local rotationY = rotation + 90 + shearY
  111. local la = math_cos(math_rad(rotation + shearX)) * scaleX
  112. local lb = math_cos(math_rad(rotationY)) * scaleY
  113. local lc = math_sin(math_rad(rotation + shearX)) * scaleX
  114. local ld = math_sin(math_rad(rotationY)) * scaleY
  115. self.a = pa * la + pb * lc
  116. self.b = pa * lb + pb * ld
  117. self.c = pc * la + pd * lc
  118. self.d = pc * lb + pd * ld
  119. return;
  120. elseif transformMode == TransformMode.onlyTranslation then
  121. local rotationY = rotation + 90 + shearY
  122. self.a = math_cos(math_rad(rotation + shearX)) * scaleX
  123. self.b = math_cos(math_rad(rotationY)) * scaleY
  124. self.c = math_sin(math_rad(rotation + shearX)) * scaleX
  125. self.d = math_sin(math_rad(rotationY)) * scaleY
  126. elseif transformMode == TransformMode.noRotationOrReflection then
  127. local s = pa * pa + pc * pc
  128. local prx = 0
  129. if s > 0.0001 then
  130. s = math_abs(pa * pd - pb * pc) / s
  131. pb = pc * s
  132. pd = pa * s
  133. prx = math_deg(math_atan2(pc, pa));
  134. else
  135. pa = 0;
  136. pc = 0;
  137. prx = 90 - math_deg(math_atan2(pd, pb));
  138. end
  139. local rx = rotation + shearX - prx
  140. local ry = rotation + shearY - prx + 90
  141. local la = math_cos(math_rad(rx)) * scaleX
  142. local lb = math_cos(math_rad(ry)) * scaleY
  143. local lc = math_sin(math_rad(rx)) * scaleX
  144. local ld = math_sin(math_rad(ry)) * scaleY
  145. self.a = pa * la - pb * lc
  146. self.b = pa * lb - pb * ld
  147. self.c = pc * la + pd * lc
  148. self.d = pc * lb + pd * ld
  149. elseif transformMode == TransformMode.noScale or transformMode == TransformMode.noScaleOrReflection then
  150. local cos = math_cos(math_rad(rotation))
  151. local sin = math_sin(math_rad(rotation))
  152. local za = (pa * cos + pb * sin) / sx
  153. local zc = (pc * cos + pd * sin) / sy
  154. local s = math_sqrt(za * za + zc * zc)
  155. if s > 0.00001 then s = 1 / s end
  156. za = za * s
  157. zc = zc * s
  158. s = math_sqrt(za * za + zc * zc)
  159. if transformMode == TransformMode.noScale and pa * pd - pb * pc < 0 ~= (sx < 0) ~= (sy < 0) then
  160. s = -s
  161. end
  162. local r = math_pi / 2 + math_atan2(zc, za)
  163. local zb = math_cos(r) * s
  164. local zd = math_sin(r) * s
  165. local la = math_cos(math_rad(shearX)) * scaleX;
  166. local lb = math_cos(math_rad(90 + shearY)) * scaleY;
  167. local lc = math_sin(math_rad(shearX)) * scaleX;
  168. local ld = math_sin(math_rad(90 + shearY)) * scaleY;
  169. self.a = za * la + zb * lc
  170. self.b = za * lb + zb * ld
  171. self.c = zc * la + zd * lc
  172. self.d = zc * lb + zd * ld
  173. end
  174. self.a = self.a * sx
  175. self.b = self.b * sx
  176. self.c = self.c * sy
  177. self.d = self.d * sy
  178. end
  179. function Bone:setToSetupPose ()
  180. local data = self.data
  181. self.x = data.x
  182. self.y = data.y
  183. self.rotation = data.rotation
  184. self.scaleX = data.scaleX
  185. self.scaleY = data.scaleY
  186. self.shearX = data.shearX
  187. self.shearY = data.shearY
  188. end
  189. function Bone:getWorldRotationX ()
  190. return math_deg(math_atan2(self.c, self.a))
  191. end
  192. function Bone:getWorldRotationY ()
  193. return math_deg(math_atan2(self.d, self.b))
  194. end
  195. function Bone:getWorldScaleX ()
  196. return math_sqrt(self.a * self.a + self.c * self.c)
  197. end
  198. function Bone:getWorldScaleY ()
  199. return math_sqrt(self.b * self.b + self.d * self.d)
  200. end
  201. function Bone:updateAppliedTransform ()
  202. local parent = self.parent
  203. if parent == nil then
  204. self.ax = self.worldX
  205. self.ay = self.worldY
  206. self.arotation = math_deg(math_atan2(self.c, self.a))
  207. self.ascaleX = math_sqrt(self.a * self.a + self.c * self.c)
  208. self.ascaleY = math_sqrt(self.b * self.b + self.d * self.d)
  209. self.ashearX = 0
  210. self.ashearY = math_deg(math_atan2(self.a * self.b + self.c * self.d, self.a * self.d - self.b * self.c))
  211. return
  212. end
  213. local pa = parent.a
  214. local pb = parent.b
  215. local pc = parent.c
  216. local pd = parent.d
  217. local pid = 1 / (pa * pd - pb * pc)
  218. local dx = self.worldX - parent.worldX
  219. local dy = self.worldY - parent.worldY
  220. self.ax = (dx * pd * pid - dy * pb * pid)
  221. self.ay = (dy * pa * pid - dx * pc * pid)
  222. local ia = pid * pd
  223. local id = pid * pa
  224. local ib = pid * pb
  225. local ic = pid * pc
  226. local ra = ia * self.a - ib * self.c
  227. local rb = ia * self.b - ib * self.d
  228. local rc = id * self.c - ic * self.a
  229. local rd = id * self.d - ic * self.b
  230. self.ashearX = 0
  231. self.ascaleX = math_sqrt(ra * ra + rc * rc)
  232. if self.ascaleX > 0.0001 then
  233. local det = ra * rd - rb * rc
  234. self.ascaleY = det / self.ascaleX
  235. self.ashearY = math_deg(math_atan2(ra * rb + rc * rd, det))
  236. self.arotation = math_deg(math_atan2(rc, ra))
  237. else
  238. self.ascaleX = 0
  239. self.ascaleY = math_sqrt(rb * rb + rd * rd)
  240. self.ashearY = 0
  241. self.arotation = 90 - math_deg(math_atan2(rd, rb))
  242. end
  243. end
  244. function Bone:worldToLocal (world)
  245. local a = self.a
  246. local b = self.b
  247. local c = self.c
  248. local d = self.d
  249. local invDet = 1 / (a * d - b * c)
  250. local x = world[1] - self.worldX
  251. local y = world[2] - self.worldY
  252. world[1] = (x * d * invDet - y * b * invDet)
  253. world[2] = (y * a * invDet - x * c * invDet)
  254. return world
  255. end
  256. function Bone:localToWorld (localCoords)
  257. local x = localCoords[1]
  258. local y = localCoords[2]
  259. localCoords[1] = x * self.a + y * self.b + self.worldX
  260. localCoords[2] = x * self.c + y * self.d + self.worldY
  261. return localCoords
  262. end
  263. function Bone:worldToLocalRotation (worldRotation)
  264. local sin = math_sin(math_rad(worldRotation))
  265. local cos = math_cos(math_rad(worldRotation))
  266. return math_deg(math_atan2(self.a * sin - self.c * cos, self.d * cos - self.b * sin)) + self.rotation - self.shearX
  267. end
  268. function Bone:localToWorldRotation (localRotation)
  269. localRotation = localRotation - (self.rotation - self.shearX)
  270. local sin = math_sin(math_rad(localRotation))
  271. local cos = math_cos(math_rad(localRotation))
  272. return math_deg(math_atan2(cos * self.c + sin * self.d, cos * self.a + sin * self.b))
  273. end
  274. function Bone:rotateWorld (degrees)
  275. local a = self.a
  276. local b = self.b
  277. local c = self.c
  278. local d = self.d
  279. local degreesRad = math_rad(degrees)
  280. local cos = math_cos(degreesRad)
  281. local sin = math_sin(degreesRad)
  282. self.a = cos * a - sin * c
  283. self.b = cos * b - sin * d
  284. self.c = sin * a + cos * c
  285. self.d = sin * b + cos * d
  286. self.appliedValid = false
  287. end
  288. return Bone