spine.lua 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  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. spine = {}
  31. spine.utils = require "spine-lua.utils"
  32. spine.SkeletonJson = require "spine-lua.SkeletonJson"
  33. spine.SkeletonData = require "spine-lua.SkeletonData"
  34. spine.BoneData = require "spine-lua.BoneData"
  35. spine.SlotData = require "spine-lua.SlotData"
  36. spine.IkConstraintData = require "spine-lua.IkConstraintData"
  37. spine.Skin = require "spine-lua.Skin"
  38. spine.Attachment = require "spine-lua.attachments.Attachment"
  39. spine.BoundingBoxAttachment = require "spine-lua.attachments.BoundingBoxAttachment"
  40. spine.RegionAttachment = require "spine-lua.attachments.RegionAttachment"
  41. spine.MeshAttachment = require "spine-lua.attachments.MeshAttachment"
  42. spine.VertexAttachment = require "spine-lua.attachments.VertexAttachment"
  43. spine.PathAttachment = require "spine-lua.attachments.PathAttachment"
  44. spine.PointAttachment = require "spine-lua.attachments.PointAttachment"
  45. spine.ClippingAttachment = require "spine-lua.attachments.ClippingAttachment"
  46. spine.Skeleton = require "spine-lua.Skeleton"
  47. spine.Bone = require "spine-lua.Bone"
  48. spine.Slot = require "spine-lua.Slot"
  49. spine.IkConstraint = require "spine-lua.IkConstraint"
  50. spine.AttachmentType = require "spine-lua.attachments.AttachmentType"
  51. spine.AttachmentLoader = require "spine-lua.AttachmentLoader"
  52. spine.Animation = require "spine-lua.Animation"
  53. spine.AnimationStateData = require "spine-lua.AnimationStateData"
  54. spine.AnimationState = require "spine-lua.AnimationState"
  55. spine.EventData = require "spine-lua.EventData"
  56. spine.Event = require "spine-lua.Event"
  57. spine.SkeletonBounds = require "spine-lua.SkeletonBounds"
  58. spine.BlendMode = require "spine-lua.BlendMode"
  59. spine.TextureAtlas = require "spine-lua.TextureAtlas"
  60. spine.TextureRegion = require "spine-lua.TextureRegion"
  61. spine.TextureAtlasRegion = require "spine-lua.TextureAtlasRegion"
  62. spine.AtlasAttachmentLoader = require "spine-lua.AtlasAttachmentLoader"
  63. spine.Color = require "spine-lua.Color"
  64. spine.Triangulator = require "spine-lua.Triangulator"
  65. spine.SkeletonClipping = require "spine-lua.SkeletonClipping"
  66. spine.utils.readFile = function (fileName, base)
  67. if not base then base = system.ResourceDirectory end
  68. local path = system.pathForFile(fileName, base)
  69. local file = io.open(path, "r")
  70. if not file then return nil end
  71. local contents = file:read("*a")
  72. io.close(file)
  73. return contents
  74. end
  75. local json = require "json"
  76. spine.utils.readJSON = function (text)
  77. return json.decode(text)
  78. end
  79. local QUAD_TRIANGLES = { 1, 2, 3, 3, 4, 1 }
  80. spine.Skeleton.new_super = spine.Skeleton.new
  81. spine.Skeleton.updateWorldTransform_super = spine.Skeleton.updateWorldTransform
  82. spine.Skeleton.new = function(skeletonData, group)
  83. self = spine.Skeleton.new_super(skeletonData)
  84. self.group = group or display.newGroup()
  85. self.drawingGroup = nil
  86. self.premultipliedAlpha = false
  87. self.batches = 0
  88. self.tempColor = spine.Color.newWith(1, 1, 1, 1)
  89. self.tempColor2 = spine.Color.newWith(-1, 1, 1, 1)
  90. self.clipper = spine.SkeletonClipping.new()
  91. return self
  92. end
  93. local function colorEquals(color1, color2)
  94. if not color1 and not color2 then return true end
  95. if not color1 and color2 then return false end
  96. if color1 and not color2 then return false end
  97. return color1[1] == color2[1] and color1[2] == color2[2] and color1[3] == color2[3] and color1[4] == color2[4]
  98. end
  99. local function toCoronaBlendMode(blendMode)
  100. if blendMode == spine.BlendMode.normal then
  101. return "normal"
  102. elseif blendMode == spine.BlendMode.additive then
  103. return "add"
  104. elseif blendMode == spine.BlendMode.multiply then
  105. return "multiply"
  106. elseif blendMode == spine.BlendMode.screen then
  107. return "screen"
  108. end
  109. end
  110. local worldVertices = spine.utils.newNumberArray(10000 * 8)
  111. function spine.Skeleton:updateWorldTransform()
  112. spine.Skeleton.updateWorldTransform_super(self)
  113. local premultipliedAlpha = self.premultipliedAlpha
  114. self.batches = 0
  115. -- Remove old drawing group, we will start anew
  116. if self.drawingGroup then self.drawingGroup:removeSelf() end
  117. local drawingGroup = display.newGroup()
  118. self.drawingGroup = drawingGroup
  119. self.group:insert(drawingGroup)
  120. local drawOrder = self.drawOrder
  121. local currentGroup = nil
  122. local groupVertices = {}
  123. local groupIndices = {}
  124. local groupUvs = {}
  125. local color = self.tempColor
  126. local lastColor = self.tempColor2
  127. lastColor.r = -1
  128. local texture = nil
  129. local lastTexture = nil
  130. local blendMode = nil
  131. local lastBlendMode = nil
  132. local renderable = {
  133. vertices = nil,
  134. uvs = nil
  135. }
  136. for i,slot in ipairs(drawOrder) do
  137. local attachment = slot.attachment
  138. local vertices = nil
  139. local uvs = nil
  140. local numVertices = 0
  141. local indices = nil
  142. if attachment then
  143. if attachment.type == spine.AttachmentType.region then
  144. numVertices = 4
  145. vertices = worldVertices
  146. attachment:computeWorldVertices(slot.bone, vertices, 0, 2)
  147. uvs = attachment.uvs
  148. indices = QUAD_TRIANGLES
  149. texture = attachment.region.renderObject.texture
  150. blendMode = toCoronaBlendMode(slot.data.blendMode)
  151. elseif attachment.type == spine.AttachmentType.mesh then
  152. numVertices = attachment.worldVerticesLength / 2
  153. vertices = worldVertices
  154. attachment:computeWorldVertices(slot, 0, attachment.worldVerticesLength, vertices, 0, 2)
  155. uvs = attachment.uvs
  156. indices = attachment.triangles
  157. texture = attachment.region.renderObject.texture
  158. blendMode = toCoronaBlendMode(slot.data.blendMode)
  159. elseif attachment.type == spine.AttachmentType.clipping then
  160. self.clipper:clipStart(slot, attachment)
  161. end
  162. local skeleton = slot.bone.skeleton
  163. local skeletonColor = skeleton.color
  164. local slotColor = slot.color
  165. local attachmentColor = attachment.color
  166. local alpha = skeletonColor.a * slotColor.a * attachmentColor.a
  167. local multiplier = alpha
  168. if premultipliedAlpha then multiplier = 1 end
  169. color:set(skeletonColor.r * slotColor.r * attachmentColor.r * multiplier,
  170. skeletonColor.g * slotColor.g * attachmentColor.g * multiplier,
  171. skeletonColor.b * slotColor.b * attachmentColor.b * multiplier,
  172. alpha)
  173. if texture and vertices and indices then
  174. if not lastTexture then lastTexture = texture end
  175. if lastColor.r == -1 then lastColor:setFrom(color) end
  176. if not lastBlendMode then lastBlendMode = blendMode end
  177. if (texture ~= lastTexture or not colorEquals(color, lastColor) or blendMode ~= lastBlendMode) then
  178. self:flush(groupVertices, groupUvs, groupIndices, lastTexture, lastColor, lastBlendMode, drawingGroup)
  179. lastTexture = texture
  180. lastColor = color
  181. lastBlendMode = blendMode
  182. groupVertices = {}
  183. groupUvs = {}
  184. groupIndices = {}
  185. end
  186. if self.clipper:isClipping() then
  187. self.clipper:clipTriangles(vertices, uvs, indices, #indices)
  188. vertices = self.clipper.clippedVertices
  189. numVertices = #vertices / 2
  190. uvs = self.clipper.clippedUVs
  191. indices = self.clipper.clippedTriangles
  192. end
  193. self:batch(vertices, uvs, numVertices, indices, groupVertices, groupUvs, groupIndices)
  194. end
  195. self.clipper:clipEnd(slot)
  196. end
  197. end
  198. if #groupVertices > 0 then
  199. self:flush(groupVertices, groupUvs, groupIndices, texture, color, blendMode, drawingGroup)
  200. end
  201. self.clipper:clipEnd2()
  202. end
  203. function spine.Skeleton:flush(groupVertices, groupUvs, groupIndices, texture, color, blendMode, drawingGroup)
  204. local mesh = display.newMesh(drawingGroup, 0, 0, {
  205. mode = "indexed",
  206. vertices = groupVertices,
  207. uvs = groupUvs,
  208. indices = groupIndices
  209. })
  210. mesh.fill = texture
  211. mesh:setFillColor(color.r, color.g, color.b)
  212. mesh.alpha = color.a
  213. mesh.blendMode = blendMode
  214. mesh:translate(mesh.path:getVertexOffset())
  215. self.batches = self.batches + 1
  216. end
  217. function spine.Skeleton:batch(vertices, uvs, numVertices, indices, groupVertices, groupUvs, groupIndices)
  218. local numIndices = #indices
  219. local i = 1
  220. local indexStart = #groupIndices + 1
  221. local offset = #groupVertices / 2
  222. local indexEnd = indexStart + numIndices
  223. while indexStart < indexEnd do
  224. groupIndices[indexStart] = indices[i] + offset
  225. indexStart = indexStart + 1
  226. i = i + 1
  227. end
  228. i = 1
  229. local vertexStart = #groupVertices + 1
  230. local vertexEnd = vertexStart + numVertices * 2
  231. while vertexStart < vertexEnd do
  232. groupVertices[vertexStart] = vertices[i]
  233. groupVertices[vertexStart+1] = vertices[i+1]
  234. groupUvs[vertexStart] = uvs[i]
  235. groupUvs[vertexStart+1] = uvs[i+1]
  236. vertexStart = vertexStart + 2
  237. i = i + 2
  238. end
  239. end
  240. return spine