Bone.lua 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  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 parent = self.parent
  87. if parent == nil then
  88. local rotationY = rotation + 90 + shearY
  89. local rotationRad = math_rad(rotation + shearX)
  90. local rotationYRad = math_rad(rotationY)
  91. local la = math_cos(rotationRad) * scaleX
  92. local lb = math_cos(rotationYRad) * scaleY
  93. local lc = math_sin(rotationRad) * scaleX
  94. local ld = math_sin(rotationYRad) * scaleY
  95. local skeleton = self.skeleton
  96. if skeleton.flipX then
  97. x = -x
  98. la = -la
  99. lb = -lb
  100. end
  101. if skeleton.flipY then
  102. y = -y
  103. lc = -lc
  104. ld = -ld
  105. end
  106. self.a = la
  107. self.b = lb
  108. self.c = lc
  109. self.d = ld
  110. self.worldX = x + skeleton.x
  111. self.worldY = y + skeleton.y
  112. return
  113. end
  114. local pa = parent.a
  115. local pb = parent.b
  116. local pc = parent.c
  117. local pd = parent.d
  118. self.worldX = pa * x + pb * y + parent.worldX
  119. self.worldY = pc * x + pd * y + parent.worldY
  120. local transformMode = self.data.transformMode
  121. if transformMode == TransformMode.normal then
  122. local rotationY = rotation + 90 + shearY
  123. local la = math_cos(math_rad(rotation + shearX)) * scaleX
  124. local lb = math_cos(math_rad(rotationY)) * scaleY
  125. local lc = math_sin(math_rad(rotation + shearX)) * scaleX
  126. local ld = math_sin(math_rad(rotationY)) * scaleY
  127. self.a = pa * la + pb * lc
  128. self.b = pa * lb + pb * ld
  129. self.c = pc * la + pd * lc
  130. self.d = pc * lb + pd * ld
  131. return;
  132. elseif transformMode == TransformMode.onlyTranslation then
  133. local rotationY = rotation + 90 + shearY
  134. self.a = math_cos(math_rad(rotation + shearX)) * scaleX
  135. self.b = math_cos(math_rad(rotationY)) * scaleY
  136. self.c = math_sin(math_rad(rotation + shearX)) * scaleX
  137. self.d = math_sin(math_rad(rotationY)) * scaleY
  138. elseif transformMode == TransformMode.noRotationOrReflection then
  139. local s = pa * pa + pc * pc
  140. local prx = 0
  141. if s > 0.0001 then
  142. s = math_abs(pa * pd - pb * pc) / s
  143. pb = pc * s
  144. pd = pa * s
  145. prx = math_deg(math_atan2(pc, pa));
  146. else
  147. pa = 0;
  148. pc = 0;
  149. prx = 90 - math_deg(math_atan2(pd, pb));
  150. end
  151. local rx = rotation + shearX - prx
  152. local ry = rotation + shearY - prx + 90
  153. local la = math_cos(math_rad(rx)) * scaleX
  154. local lb = math_cos(math_rad(ry)) * scaleY
  155. local lc = math_sin(math_rad(rx)) * scaleX
  156. local ld = math_sin(math_rad(ry)) * scaleY
  157. self.a = pa * la - pb * lc
  158. self.b = pa * lb - pb * ld
  159. self.c = pc * la + pd * lc
  160. self.d = pc * lb + pd * ld
  161. elseif transformMode == TransformMode.noScale or transformMode == TransformMode.noScaleOrReflection then
  162. local cos = math_cos(math_rad(rotation))
  163. local sin = math_sin(math_rad(rotation))
  164. local za = pa * cos + pb * sin
  165. local zc = pc * cos + pd * sin
  166. local s = math_sqrt(za * za + zc * zc)
  167. if s > 0.00001 then s = 1 / s end
  168. za = za * s
  169. zc = zc * s
  170. s = math_sqrt(za * za + zc * zc)
  171. local r = math_pi / 2 + math_atan2(zc, za)
  172. local zb = math_cos(r) * s
  173. local zd = math_sin(r) * s
  174. local la = math_cos(math_rad(shearX)) * scaleX;
  175. local lb = math_cos(math_rad(90 + shearY)) * scaleY;
  176. local lc = math_sin(math_rad(shearX)) * scaleX;
  177. local ld = math_sin(90 + shearY) * scaleY;
  178. self.a = za * la + zb * lc
  179. self.b = za * lb + zb * ld
  180. self.c = zc * la + zd * lc
  181. self.d = zc * lb + zd * ld
  182. local flip = self.skeleton.flipX ~= self.skeleton.flipY
  183. if transformMode ~= TransformMode.noScaleOrReflection then flip = pa * pd - pb * pc < 0 end
  184. if flip then
  185. self.b = -self.b
  186. self.d = -self.d
  187. end
  188. return
  189. end
  190. if self.skeleton.flipX then
  191. self.a = -self.a
  192. self.b = -self.b
  193. end
  194. if self.skeleton.flipY then
  195. self.c = -self.c
  196. self.d = -self.d
  197. end
  198. end
  199. function Bone:setToSetupPose ()
  200. local data = self.data
  201. self.x = data.x
  202. self.y = data.y
  203. self.rotation = data.rotation
  204. self.scaleX = data.scaleX
  205. self.scaleY = data.scaleY
  206. self.shearX = data.shearX
  207. self.shearY = data.shearY
  208. end
  209. function Bone:getWorldRotationX ()
  210. return math_deg(math_atan2(self.c, self.a))
  211. end
  212. function Bone:getWorldRotationY ()
  213. return math_deg(math_atan2(self.d, self.b))
  214. end
  215. function Bone:getWorldScaleX ()
  216. return math_sqrt(self.a * self.a + self.c * self.c)
  217. end
  218. function Bone:getWorldScaleY ()
  219. return math_sqrt(self.b * self.b + self.d * self.d)
  220. end
  221. function updateAppliedTransform ()
  222. local parent = self.parent
  223. if parent == nil then
  224. self.ax = self.worldX
  225. self.ay = self.worldY
  226. self.arotation = math_deg(math_atan2(self.c, self.a))
  227. self.ascaleX = math_sqrt(self.a * self.a + self.c * self.c)
  228. self.ascaleY = math_sqrt(self.b * self.b + self.d * self.d)
  229. self.ashearX = 0
  230. self.ashearY = math_deg(math_atan2(self.a * self.b + self.c * self.d, self.a * self.d - self.b * self.c))
  231. return
  232. end
  233. local pa = parent.a
  234. local pb = parent.b
  235. local pc = parent.c
  236. local pd = parent.d
  237. local pid = 1 / (pa * pd - pb * pc)
  238. local dx = self.worldX - parent.worldX
  239. local dy = self.worldY - parent.worldY
  240. self.ax = (dx * pd * pid - dy * pb * pid)
  241. self.ay = (dy * pa * pid - dx * pc * pid)
  242. local ia = pid * pd
  243. local id = pid * pa
  244. local ib = pid * pb
  245. local ic = pid * pc
  246. local ra = ia * self.a - ib * self.c
  247. local rb = ia * self.b - ib * self.d
  248. local rc = id * self.c - ic * self.a
  249. local rd = id * self.d - ic * self.b
  250. self.ashearX = 0
  251. self.ascaleX = math_sqrt(ra * ra + rc * rc)
  252. if self.ascaleX > 0.0001 then
  253. local det = ra * rd - rb * rc
  254. self.ascaleY = det / self.ascaleX
  255. self.ashearY = math_deg(math_atan2(ra * rb + rc * rd, det))
  256. self.arotation = math_deg(math_atan2(rc, ra))
  257. else
  258. self.ascaleX = 0
  259. self.ascaleY = math_sqrt(rb * rb + rd * rd)
  260. self.ashearY = 0
  261. self.arotation = 90 - math_deg(math_atan2(rd, rb))
  262. end
  263. end
  264. function Bone:worldToLocal (world)
  265. local a = self.a
  266. local b = self.b
  267. local c = self.c
  268. local d = self.d
  269. local invDet = 1 / (a * d - b * c)
  270. local x = world[1] - self.worldX
  271. local y = world[2] - self.worldY
  272. world[1] = (x * d * invDet - y * b * invDet)
  273. world[2] = (y * a * invDet - x * c * invDet)
  274. return world
  275. end
  276. function Bone:localToWorld (localCoords)
  277. local x = localCoords[1]
  278. local y = localCoords[2]
  279. localCoords[1] = x * self.a + y * self.b + self.worldX
  280. localCoords[2] = x * self.c + y * self.d + self.worldY
  281. return localCoords
  282. end
  283. function Bone:worldToLocalRotation (worldRotation)
  284. local sin = math_sin(math_rad(worldRotation))
  285. local cos = math_cos(math_rad(worldRotation))
  286. return math_deg(math_atan2(self.a * sin - self.c * cos, self.d * cos - self.b * sin))
  287. end
  288. function Bone:localToWorldRotation (localRotation)
  289. local sin = math_sin(math_rad(localRotation))
  290. local cos = math_cos(math_rad(localRotation))
  291. return math_deg(math_atan2(cos * self.c + sin * self.d, cos * self.a + sin * self.b))
  292. end
  293. function Bone:rotateWorld (degrees)
  294. local a = self.a
  295. local b = self.b
  296. local c = self.c
  297. local d = self.d
  298. local degreesRad = math_rad(degrees)
  299. local cos = math_cos(degreesRad)
  300. local sin = math_sin(degreesRad)
  301. self.a = cos * a - sin * c
  302. self.b = cos * b - sin * d
  303. self.c = sin * a + cos * c
  304. self.d = sin * b + cos * d
  305. self.appliedValid = false
  306. end
  307. return Bone