spine.lua 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  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 spine = {}
  31. spine.utils = require "lib/spine-lua/utils"
  32. spine.SkeletonJson = require "lib/spine-lua/SkeletonJson"
  33. spine.SkeletonData = require "lib/spine-lua/SkeletonData"
  34. spine.BoneData = require "lib/spine-lua/BoneData"
  35. spine.SlotData = require "lib/spine-lua/SlotData"
  36. spine.IkConstraintData = require "lib/spine-lua/IkConstraintData"
  37. spine.Skin = require "lib/spine-lua/Skin"
  38. spine.RegionAttachment = require "lib/spine-lua/RegionAttachment"
  39. spine.MeshAttachment = require "lib/spine-lua/MeshAttachment"
  40. spine.SkinnedMeshAttachment = require "lib/spine-lua/SkinnedMeshAttachment"
  41. spine.Skeleton = require "lib/spine-lua/Skeleton"
  42. spine.Bone = require "lib/spine-lua/Bone"
  43. spine.Slot = require "lib/spine-lua/Slot"
  44. spine.IkConstraint = require "lib/spine-lua/IkConstraint"
  45. spine.AttachmentType = require "lib/spine-lua/AttachmentType"
  46. spine.AttachmentLoader = require "lib/spine-lua/AttachmentLoader"
  47. spine.AtlasAttachmentLoader = require "lib/spine-lua/AtlasAttachmentLoader"
  48. spine.Atlas = require "lib/spine-lua/Atlas"
  49. spine.Animation = require "lib/spine-lua/Animation"
  50. spine.AnimationStateData = require "lib/spine-lua/AnimationStateData"
  51. spine.AnimationState = require "lib/spine-lua/AnimationState"
  52. spine.EventData = require "lib/spine-lua/EventData"
  53. spine.Event = require "lib/spine-lua/Event"
  54. spine.SkeletonBounds = require "lib/spine-lua/SkeletonBounds"
  55. spine.utils.readFile = function (fileName, base)
  56. local path = fileName
  57. if base then path = base .. '/' .. path end
  58. return love.filesystem.read(path)
  59. end
  60. spine.utils.readJSON = function (text)
  61. return lib.json.decode(text)
  62. end
  63. spine.Skeleton.failed = {} -- Placeholder for an image that failed to load.
  64. spine.Skeleton.new_super = spine.Skeleton.new
  65. function spine.Skeleton.new (skeletonData, group)
  66. local self = spine.Skeleton.new_super(skeletonData)
  67. -- createImage can customize where images are found.
  68. function self:createImage (attachment)
  69. return love.graphics.newImage(attachment.name .. ".png")
  70. end
  71. -- updateWorldTransform positions images.
  72. local updateWorldTransform_super = self.updateWorldTransform
  73. function self:updateWorldTransform ()
  74. updateWorldTransform_super(self)
  75. if not self.quads then self.quads = {} end
  76. local quads = self.quads
  77. if not self.images then self.images = {} end
  78. local images = self.images
  79. if not self.attachments then self.attachments = {} end
  80. local attachments = self.attachments
  81. for i,slot in ipairs(self.drawOrder) do
  82. local attachment = slot.attachment
  83. if not attachment then
  84. images[slot] = nil
  85. quads[slot] = nil
  86. elseif attachment.type == spine.AttachmentType.region then
  87. if attachment.rendererObject then -- Quad
  88. local page = attachment.rendererObject.page
  89. page.image = page.image or self:createAtlasImage(page)
  90. self.spritebatch = self.spritebatch or love.graphics.newSpriteBatch(page.image, 32, 'stream')
  91. local quad = quads[slot]
  92. if quad then
  93. local u1, v1, u2, v2 = unpack(attachment.uvs)
  94. local qw, qh = page.image:getDimensions()
  95. local x, y, w, h = u1 * qw, v1 * qh, (u2 - u1) * qw, (v2 - v1) * qh
  96. local x2, y2, w2, h2 = quad:getViewport()
  97. if x ~= x2 or y ~= y2 or w ~= w2 or h ~= h2 then
  98. quad = nil
  99. end
  100. end
  101. if not quad then
  102. local x1, y1, x2, y2 = unpack(attachment.uvs)
  103. local w, h = page.image:getDimensions()
  104. quad = love.graphics.newQuad(x1 * w, y1 * h, (x2 - x1) * w, (y2 - y1) * h, w, h)
  105. attachment.widthRatio = attachment.width / attachment.regionWidth
  106. attachment.heightRatio = attachment.height / attachment.regionHeight
  107. attachment.originX = attachment.regionWidth / 2
  108. attachment.originY = attachment.regionHeight / 2
  109. end
  110. quads[slot] = quad
  111. else -- Image
  112. local image = images[slot]
  113. if image and attachments[image] ~= attachment then -- Attachment image has changed.
  114. image = nil
  115. end
  116. if not image then -- Create new image.
  117. image = self:createImage(attachment)
  118. if image then
  119. local imageWidth = image:getWidth()
  120. local imageHeight = image:getHeight()
  121. attachment.widthRatio = attachment.width / imageWidth
  122. attachment.heightRatio = attachment.height / imageHeight
  123. attachment.originX = imageWidth / 2
  124. attachment.originY = imageHeight / 2
  125. else
  126. image = spine.Skeleton.failed
  127. end
  128. images[slot] = image
  129. attachments[image] = attachment
  130. end
  131. end
  132. end
  133. end
  134. end
  135. function self:draw()
  136. if not self.images then self.images = {} end
  137. if not self.quads then self.quads = {} end
  138. local images = self.images
  139. local quads = self.quads
  140. local batching = false
  141. local r, g, b, a = self.r * 255, self.g * 255, self.b * 255, self.a * 255
  142. for i,slot in ipairs(self.drawOrder) do
  143. local image = images[slot]
  144. local quad = quads[slot]
  145. if quad then
  146. if not batching then
  147. batching = true
  148. self.spritebatch:clear()
  149. end
  150. local attachment = slot.attachment
  151. if attachment then
  152. local x = slot.bone.worldX + attachment.x * slot.bone.m00 + attachment.y * slot.bone.m01
  153. local y = slot.bone.worldY + attachment.x * slot.bone.m10 + attachment.y * slot.bone.m11
  154. local rotation = slot.bone.worldRotation + attachment.rotation
  155. local xScale = slot.bone.worldScaleX + attachment.scaleX - 1
  156. local yScale = slot.bone.worldScaleY + attachment.scaleY - 1
  157. if self.flipX then
  158. xScale = -xScale
  159. rotation = -rotation
  160. end
  161. if self.flipY then
  162. yScale = -yScale
  163. rotation = -rotation
  164. end
  165. self.spritebatch:setColor(r * slot.r, g * slot.g, b * slot.b, a * slot.a)
  166. if slot.data.additiveBlending then
  167. love.graphics.setBlendMode("additive")
  168. else
  169. love.graphics.setBlendMode("alpha")
  170. end
  171. self.spritebatch:add(quad,
  172. self.x + x,
  173. self.y - y,
  174. -rotation * 3.1415927 / 180,
  175. xScale * attachment.widthRatio,
  176. yScale * attachment.heightRatio,
  177. attachment.originX,
  178. attachment.originY)
  179. end
  180. elseif image and image ~= spine.Skeleton.failed then
  181. local attachment = slot.attachment
  182. local x = slot.bone.worldX + attachment.x * slot.bone.m00 + attachment.y * slot.bone.m01
  183. local y = slot.bone.worldY + attachment.x * slot.bone.m10 + attachment.y * slot.bone.m11
  184. local rotation = slot.bone.worldRotation + attachment.rotation
  185. local xScale = slot.bone.worldScaleX + attachment.scaleX - 1
  186. local yScale = slot.bone.worldScaleY + attachment.scaleY - 1
  187. if self.flipX then
  188. xScale = -xScale
  189. rotation = -rotation
  190. end
  191. if self.flipY then
  192. yScale = -yScale
  193. rotation = -rotation
  194. end
  195. love.graphics.setColor(r * slot.r, g * slot.g, b * slot.b, a * slot.a)
  196. if slot.data.additiveBlending then
  197. love.graphics.setBlendMode("additive")
  198. else
  199. love.graphics.setBlendMode("alpha")
  200. end
  201. love.graphics.draw(image,
  202. self.x + x,
  203. self.y - y,
  204. -rotation * 3.1415927 / 180,
  205. xScale * attachment.widthRatio,
  206. yScale * attachment.heightRatio,
  207. attachment.originX,
  208. attachment.originY)
  209. end
  210. end
  211. -- Debug bones.
  212. if self.debugBones then
  213. for i,bone in ipairs(self.bones) do
  214. local xScale
  215. local yScale
  216. local rotation = -bone.worldRotation
  217. if self.flipX then
  218. xScale = -1
  219. rotation = -rotation
  220. else
  221. xScale = 1
  222. end
  223. if self.flipY then
  224. yScale = -1
  225. rotation = -rotation
  226. else
  227. yScale = 1
  228. end
  229. love.graphics.push()
  230. love.graphics.translate(self.x + bone.worldX, self.y - bone.worldY)
  231. love.graphics.rotate(rotation * 3.1415927 / 180)
  232. love.graphics.scale(xScale, yScale)
  233. love.graphics.setColor(255, 0, 0)
  234. love.graphics.line(0, 0, bone.data.length, 0)
  235. love.graphics.setColor(0, 255, 0)
  236. love.graphics.circle('fill', 0, 0, 3)
  237. love.graphics.pop()
  238. end
  239. end
  240. -- Debug slots.
  241. if self.debugSlots then
  242. love.graphics.setColor(0, 0, 255, 128)
  243. for i,slot in ipairs(self.drawOrder) do
  244. local attachment = slot.attachment
  245. if attachment and attachment.type == spine.AttachmentType.region then
  246. local x = slot.bone.worldX + attachment.x * slot.bone.m00 + attachment.y * slot.bone.m01
  247. local y = slot.bone.worldY + attachment.x * slot.bone.m10 + attachment.y * slot.bone.m11
  248. local rotation = slot.bone.worldRotation + attachment.rotation
  249. local xScale = slot.bone.worldScaleX + attachment.scaleX - 1
  250. local yScale = slot.bone.worldScaleY + attachment.scaleY - 1
  251. if self.flipX then
  252. xScale = -xScale
  253. rotation = -rotation
  254. end
  255. if self.flipY then
  256. yScale = -yScale
  257. rotation = -rotation
  258. end
  259. love.graphics.push()
  260. love.graphics.translate(self.x + x, self.y - y)
  261. love.graphics.rotate(-rotation * 3.1415927 / 180)
  262. love.graphics.scale(xScale, yScale)
  263. love.graphics.rectangle('line', -attachment.width / 2, -attachment.height / 2, attachment.width, attachment.height)
  264. love.graphics.pop()
  265. end
  266. end
  267. end
  268. if batching then
  269. love.graphics.setColor(255, 255, 255)
  270. love.graphics.draw(self.spritebatch)
  271. end
  272. end
  273. return self
  274. end
  275. return spine