Bone.lua 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. -------------------------------------------------------------------------------
  2. -- Spine Runtimes License Agreement
  3. -- Last updated May 1, 2019. Replaces all prior versions.
  4. --
  5. -- Copyright (c) 2013-2019, Esoteric Software LLC
  6. --
  7. -- Integration of the Spine Runtimes into software or otherwise creating
  8. -- derivative works of the Spine Runtimes is permitted under the terms and
  9. -- conditions of Section 2 of the Spine Editor License Agreement:
  10. -- http://esotericsoftware.com/spine-editor-license
  11. --
  12. -- Otherwise, it is permitted to integrate the Spine Runtimes into software
  13. -- or otherwise create derivative works of the Spine Runtimes (collectively,
  14. -- "Products"), provided that each user of the Products must obtain their own
  15. -- Spine Editor license and redistribution of the Products in any form must
  16. -- include this license and copyright notice.
  17. --
  18. -- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY EXPRESS
  19. -- OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  20. -- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
  21. -- NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. -- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23. -- BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS
  24. -- INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY
  25. -- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  26. -- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  27. -- EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. -------------------------------------------------------------------------------
  29. local setmetatable = setmetatable
  30. local math_rad = math.rad
  31. local math_deg = math.deg
  32. local math_sin = math.sin
  33. local math_cos = math.cos
  34. local math_atan2 = math.atan2
  35. local math_sqrt = math.sqrt
  36. local math_abs = math.abs
  37. local math_pi = math.pi
  38. local TransformMode = require "spine-lua.TransformMode"
  39. function math.sign(x)
  40. if x<0 then
  41. return -1
  42. elseif x>0 then
  43. return 1
  44. else
  45. return 0
  46. end
  47. end
  48. local math_sign = math.sign
  49. local Bone = {}
  50. Bone.__index = Bone
  51. function Bone.new (data, skeleton, parent)
  52. if not data then error("data cannot be nil", 2) end
  53. if not skeleton then error("skeleton cannot be nil", 2) end
  54. local self = {
  55. data = data,
  56. skeleton = skeleton,
  57. parent = parent,
  58. children = { },
  59. x = 0, y = 0, rotation = 0, scaleX = 1, scaleY = 1, shearX = 0, shearY = 0,
  60. ax = 0, ay = 0, arotation = 0, ascaleX = 0, ascaleY = 0, ashearX = 0, ashearY = 0,
  61. appliedValid = false,
  62. a = 0, b = 0, worldX = 0, -- a b x
  63. c = 0, d = 0, worldY = 0, -- c d y
  64. sorted = false
  65. }
  66. setmetatable(self, Bone)
  67. self:setToSetupPose()
  68. return self
  69. end
  70. function Bone:update ()
  71. self:updateWorldTransformWith(self.x, self.y, self.rotation, self.scaleX, self.scaleY, self.shearX, self.shearY)
  72. end
  73. function Bone:updateWorldTransform ()
  74. self:updateWorldTransformWith(self.x, self.y, self.rotation, self.scaleX, self.scaleY, self.shearX, self.shearY)
  75. end
  76. function Bone:updateWorldTransformWith (x, y, rotation, scaleX, scaleY, shearX, shearY)
  77. self.ax = x
  78. self.ay = y
  79. self.arotation = rotation
  80. self.ascaleX = scaleX
  81. self.ascaleY = scaleY
  82. self.ashearX = shearX
  83. self.ashearY = shearY
  84. self.appliedValid = true
  85. local sx = self.skeleton.scaleX;
  86. local sy = self.skeleton.scaleY;
  87. local parent = self.parent
  88. if parent == nil then
  89. local rotationY = rotation + 90 + shearY
  90. local rotationRad = math_rad(rotation + shearX)
  91. local rotationYRad = math_rad(rotationY)
  92. local skeleton = self.skeleton
  93. self.a = math_cos(rotationRad) * scaleX * sx
  94. self.b = math_cos(rotationYRad) * scaleY * sx
  95. self.c = math_sin(rotationRad) * scaleX * sy
  96. self.d = math_sin(rotationYRad) * scaleY * sy
  97. self.worldX = x * sx + skeleton.x
  98. self.worldY = y * sy + skeleton.y
  99. return
  100. end
  101. local pa = parent.a
  102. local pb = parent.b
  103. local pc = parent.c
  104. local pd = parent.d
  105. self.worldX = pa * x + pb * y + parent.worldX
  106. self.worldY = pc * x + pd * y + parent.worldY
  107. local transformMode = self.data.transformMode
  108. if transformMode == TransformMode.normal then
  109. local rotationY = rotation + 90 + shearY
  110. local la = math_cos(math_rad(rotation + shearX)) * scaleX
  111. local lb = math_cos(math_rad(rotationY)) * scaleY
  112. local lc = math_sin(math_rad(rotation + shearX)) * scaleX
  113. local ld = math_sin(math_rad(rotationY)) * scaleY
  114. self.a = pa * la + pb * lc
  115. self.b = pa * lb + pb * ld
  116. self.c = pc * la + pd * lc
  117. self.d = pc * lb + pd * ld
  118. return;
  119. elseif transformMode == TransformMode.onlyTranslation then
  120. local rotationY = rotation + 90 + shearY
  121. self.a = math_cos(math_rad(rotation + shearX)) * scaleX
  122. self.b = math_cos(math_rad(rotationY)) * scaleY
  123. self.c = math_sin(math_rad(rotation + shearX)) * scaleX
  124. self.d = math_sin(math_rad(rotationY)) * scaleY
  125. elseif transformMode == TransformMode.noRotationOrReflection then
  126. local s = pa * pa + pc * pc
  127. local prx = 0
  128. if s > 0.0001 then
  129. s = math_abs(pa * pd - pb * pc) / s
  130. pb = pc * s
  131. pd = pa * s
  132. prx = math_deg(math_atan2(pc, pa));
  133. else
  134. pa = 0;
  135. pc = 0;
  136. prx = 90 - math_deg(math_atan2(pd, pb));
  137. end
  138. local rx = rotation + shearX - prx
  139. local ry = rotation + shearY - prx + 90
  140. local la = math_cos(math_rad(rx)) * scaleX
  141. local lb = math_cos(math_rad(ry)) * scaleY
  142. local lc = math_sin(math_rad(rx)) * scaleX
  143. local ld = math_sin(math_rad(ry)) * scaleY
  144. self.a = pa * la - pb * lc
  145. self.b = pa * lb - pb * ld
  146. self.c = pc * la + pd * lc
  147. self.d = pc * lb + pd * ld
  148. elseif transformMode == TransformMode.noScale or transformMode == TransformMode.noScaleOrReflection then
  149. local cos = math_cos(math_rad(rotation))
  150. local sin = math_sin(math_rad(rotation))
  151. local za = (pa * cos + pb * sin) / sx
  152. local zc = (pc * cos + pd * sin) / sy
  153. local s = math_sqrt(za * za + zc * zc)
  154. if s > 0.00001 then s = 1 / s end
  155. za = za * s
  156. zc = zc * s
  157. s = math_sqrt(za * za + zc * zc)
  158. if transformMode == TransformMode.noScale and pa * pd - pb * pc < 0 ~= (sx < 0) ~= (sy < 0) then
  159. s = -s
  160. end
  161. local r = math_pi / 2 + math_atan2(zc, za)
  162. local zb = math_cos(r) * s
  163. local zd = math_sin(r) * s
  164. local la = math_cos(math_rad(shearX)) * scaleX;
  165. local lb = math_cos(math_rad(90 + shearY)) * scaleY;
  166. local lc = math_sin(math_rad(shearX)) * scaleX;
  167. local ld = math_sin(math_rad(90 + shearY)) * scaleY;
  168. self.a = za * la + zb * lc
  169. self.b = za * lb + zb * ld
  170. self.c = zc * la + zd * lc
  171. self.d = zc * lb + zd * ld
  172. end
  173. self.a = self.a * sx
  174. self.b = self.b * sx
  175. self.c = self.c * sy
  176. self.d = self.d * sy
  177. end
  178. function Bone:setToSetupPose ()
  179. local data = self.data
  180. self.x = data.x
  181. self.y = data.y
  182. self.rotation = data.rotation
  183. self.scaleX = data.scaleX
  184. self.scaleY = data.scaleY
  185. self.shearX = data.shearX
  186. self.shearY = data.shearY
  187. end
  188. function Bone:getWorldRotationX ()
  189. return math_deg(math_atan2(self.c, self.a))
  190. end
  191. function Bone:getWorldRotationY ()
  192. return math_deg(math_atan2(self.d, self.b))
  193. end
  194. function Bone:getWorldScaleX ()
  195. return math_sqrt(self.a * self.a + self.c * self.c)
  196. end
  197. function Bone:getWorldScaleY ()
  198. return math_sqrt(self.b * self.b + self.d * self.d)
  199. end
  200. function Bone:updateAppliedTransform ()
  201. local parent = self.parent
  202. if parent == nil then
  203. self.ax = self.worldX
  204. self.ay = self.worldY
  205. self.arotation = math_deg(math_atan2(self.c, self.a))
  206. self.ascaleX = math_sqrt(self.a * self.a + self.c * self.c)
  207. self.ascaleY = math_sqrt(self.b * self.b + self.d * self.d)
  208. self.ashearX = 0
  209. self.ashearY = math_deg(math_atan2(self.a * self.b + self.c * self.d, self.a * self.d - self.b * self.c))
  210. return
  211. end
  212. local pa = parent.a
  213. local pb = parent.b
  214. local pc = parent.c
  215. local pd = parent.d
  216. local pid = 1 / (pa * pd - pb * pc)
  217. local dx = self.worldX - parent.worldX
  218. local dy = self.worldY - parent.worldY
  219. self.ax = (dx * pd * pid - dy * pb * pid)
  220. self.ay = (dy * pa * pid - dx * pc * pid)
  221. local ia = pid * pd
  222. local id = pid * pa
  223. local ib = pid * pb
  224. local ic = pid * pc
  225. local ra = ia * self.a - ib * self.c
  226. local rb = ia * self.b - ib * self.d
  227. local rc = id * self.c - ic * self.a
  228. local rd = id * self.d - ic * self.b
  229. self.ashearX = 0
  230. self.ascaleX = math_sqrt(ra * ra + rc * rc)
  231. if self.ascaleX > 0.0001 then
  232. local det = ra * rd - rb * rc
  233. self.ascaleY = det / self.ascaleX
  234. self.ashearY = math_deg(math_atan2(ra * rb + rc * rd, det))
  235. self.arotation = math_deg(math_atan2(rc, ra))
  236. else
  237. self.ascaleX = 0
  238. self.ascaleY = math_sqrt(rb * rb + rd * rd)
  239. self.ashearY = 0
  240. self.arotation = 90 - math_deg(math_atan2(rd, rb))
  241. end
  242. end
  243. function Bone:worldToLocal (world)
  244. local a = self.a
  245. local b = self.b
  246. local c = self.c
  247. local d = self.d
  248. local invDet = 1 / (a * d - b * c)
  249. local x = world[1] - self.worldX
  250. local y = world[2] - self.worldY
  251. world[1] = (x * d * invDet - y * b * invDet)
  252. world[2] = (y * a * invDet - x * c * invDet)
  253. return world
  254. end
  255. function Bone:localToWorld (localCoords)
  256. local x = localCoords[1]
  257. local y = localCoords[2]
  258. localCoords[1] = x * self.a + y * self.b + self.worldX
  259. localCoords[2] = x * self.c + y * self.d + self.worldY
  260. return localCoords
  261. end
  262. function Bone:worldToLocalRotation (worldRotation)
  263. local sin = math_sin(math_rad(worldRotation))
  264. local cos = math_cos(math_rad(worldRotation))
  265. return math_deg(math_atan2(self.a * sin - self.c * cos, self.d * cos - self.b * sin)) + self.rotation - self.shearX
  266. end
  267. function Bone:localToWorldRotation (localRotation)
  268. localRotation = localRotation - (self.rotation - self.shearX)
  269. local sin = math_sin(math_rad(localRotation))
  270. local cos = math_cos(math_rad(localRotation))
  271. return math_deg(math_atan2(cos * self.c + sin * self.d, cos * self.a + sin * self.b))
  272. end
  273. function Bone:rotateWorld (degrees)
  274. local a = self.a
  275. local b = self.b
  276. local c = self.c
  277. local d = self.d
  278. local degreesRad = math_rad(degrees)
  279. local cos = math_cos(degreesRad)
  280. local sin = math_sin(degreesRad)
  281. self.a = cos * a - sin * c
  282. self.b = cos * b - sin * d
  283. self.c = sin * a + cos * c
  284. self.d = sin * b + cos * d
  285. self.appliedValid = false
  286. end
  287. return Bone