------------------------------------------------------------------------------- -- Spine Runtimes Software License v2.5 -- -- Copyright (c) 2013-2016, Esoteric Software -- All rights reserved. -- -- You are granted a perpetual, non-exclusive, non-sublicensable, and -- non-transferable license to use, install, execute, and perform the Spine -- Runtimes software and derivative works solely for personal or internal -- use. Without the written permission of Esoteric Software (see Section 2 of -- the Spine Software License Agreement), you may not (a) modify, translate, -- adapt, or develop new applications using the Spine Runtimes or otherwise -- create derivative works or improvements of the Spine Runtimes or (b) remove, -- delete, alter, or obscure any trademarks or any copyright, trademark, patent, -- or other intellectual property or proprietary rights notices on or in the -- Software, including any copy thereof. Redistributions in binary or source -- form must include this license and terms. -- -- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR -- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF -- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- spine = {} spine.utils = require "spine-lua.utils" spine.SkeletonJson = require "spine-lua.SkeletonJson" spine.SkeletonData = require "spine-lua.SkeletonData" spine.BoneData = require "spine-lua.BoneData" spine.SlotData = require "spine-lua.SlotData" spine.IkConstraintData = require "spine-lua.IkConstraintData" spine.Skin = require "spine-lua.Skin" spine.Attachment = require "spine-lua.attachments.Attachment" spine.BoundingBoxAttachment = require "spine-lua.attachments.BoundingBoxAttachment" spine.RegionAttachment = require "spine-lua.attachments.RegionAttachment" spine.MeshAttachment = require "spine-lua.attachments.MeshAttachment" spine.VertexAttachment = require "spine-lua.attachments.VertexAttachment" spine.PathAttachment = require "spine-lua.attachments.PathAttachment" spine.PointAttachment = require "spine-lua.attachments.PointAttachment" spine.ClippingAttachment = require "spine-lua.attachments.ClippingAttachment" spine.Skeleton = require "spine-lua.Skeleton" spine.Bone = require "spine-lua.Bone" spine.Slot = require "spine-lua.Slot" spine.IkConstraint = require "spine-lua.IkConstraint" spine.AttachmentType = require "spine-lua.attachments.AttachmentType" spine.AttachmentLoader = require "spine-lua.AttachmentLoader" spine.Animation = require "spine-lua.Animation" spine.AnimationStateData = require "spine-lua.AnimationStateData" spine.AnimationState = require "spine-lua.AnimationState" spine.EventData = require "spine-lua.EventData" spine.Event = require "spine-lua.Event" spine.SkeletonBounds = require "spine-lua.SkeletonBounds" spine.BlendMode = require "spine-lua.BlendMode" spine.TextureAtlas = require "spine-lua.TextureAtlas" spine.TextureRegion = require "spine-lua.TextureRegion" spine.TextureAtlasRegion = require "spine-lua.TextureAtlasRegion" spine.AtlasAttachmentLoader = require "spine-lua.AtlasAttachmentLoader" spine.Color = require "spine-lua.Color" spine.Triangulator = require "spine-lua.Triangulator" spine.SkeletonClipping = require "spine-lua.SkeletonClipping" spine.JitterEffect = require "spine-lua.vertexeffects.JitterEffect" spine.SwirlEffect = require "spine-lua.vertexeffects.SwirlEffect" spine.Interpolation = require "spine-lua.Interpolation" spine.utils.readFile = function (fileName, base) if not base then base = system.ResourceDirectory end local path = system.pathForFile(fileName, base) local file = io.open(path, "r") if not file then return nil end local contents = file:read("*a") io.close(file) return contents end local json = require "json" spine.utils.readJSON = function (text) return json.decode(text) end local QUAD_TRIANGLES = { 1, 2, 3, 3, 4, 1 } spine.Skeleton.new_super = spine.Skeleton.new spine.Skeleton.updateWorldTransform_super = spine.Skeleton.updateWorldTransform spine.Skeleton.new = function(skeletonData, group) self = spine.Skeleton.new_super(skeletonData) self.group = group or display.newGroup() self.drawingGroup = nil self.premultipliedAlpha = false self.batches = 0 self.tempColor = spine.Color.newWith(1, 1, 1, 1) self.tempColor2 = spine.Color.newWith(-1, 1, 1, 1) self.tempVertex = { x = 0, y = 0, u = 0, v = 0, light = spine.Color.newWith(1, 1, 1, 1), dark = spine.Color.newWith(0, 0, 0, 0) } self.clipper = spine.SkeletonClipping.new() return self end local function colorEquals(color1, color2) return color1.r == color2.r and color1.g == color2.g and color1.b == color2.b and color1.a == color2.a end local function toCoronaBlendMode(blendMode) if blendMode == spine.BlendMode.normal then return "normal" elseif blendMode == spine.BlendMode.additive then return "add" elseif blendMode == spine.BlendMode.multiply then return "multiply" elseif blendMode == spine.BlendMode.screen then return "screen" end end local worldVertices = spine.utils.newNumberArray(10000 * 8) function spine.Skeleton:updateWorldTransform() spine.Skeleton.updateWorldTransform_super(self) local premultipliedAlpha = self.premultipliedAlpha self.batches = 0 if (self.vertexEffect) then self.vertexEffect:beginEffect(self) end -- Remove old drawing group, we will start anew if self.drawingGroup then self.drawingGroup:removeSelf() end local drawingGroup = display.newGroup() self.drawingGroup = drawingGroup self.group:insert(drawingGroup) local drawOrder = self.drawOrder local currentGroup = nil local groupVertices = {} local groupIndices = {} local groupUvs = {} local color = self.tempColor local lastColor = self.tempColor2 lastColor.r = -1 local texture = nil local lastTexture = nil local blendMode = nil local lastBlendMode = nil local renderable = { vertices = nil, uvs = nil } for i,slot in ipairs(drawOrder) do local attachment = slot.attachment local vertices = nil local uvs = nil local numVertices = 0 local indices = nil if attachment then if attachment.type == spine.AttachmentType.region then numVertices = 4 vertices = worldVertices attachment:computeWorldVertices(slot.bone, vertices, 0, 2) uvs = attachment.uvs indices = QUAD_TRIANGLES texture = attachment.region.renderObject.texture blendMode = toCoronaBlendMode(slot.data.blendMode) elseif attachment.type == spine.AttachmentType.mesh then numVertices = attachment.worldVerticesLength / 2 vertices = worldVertices attachment:computeWorldVertices(slot, 0, attachment.worldVerticesLength, vertices, 0, 2) uvs = attachment.uvs indices = attachment.triangles texture = attachment.region.renderObject.texture blendMode = toCoronaBlendMode(slot.data.blendMode) elseif attachment.type == spine.AttachmentType.clipping then self.clipper:clipStart(slot, attachment) end if texture and vertices and indices then local skeleton = slot.bone.skeleton local skeletonColor = skeleton.color local slotColor = slot.color local attachmentColor = attachment.color local alpha = skeletonColor.a * slotColor.a * attachmentColor.a local multiplier = alpha if premultipliedAlpha then multiplier = 1 end color:set(skeletonColor.r * slotColor.r * attachmentColor.r * multiplier, skeletonColor.g * slotColor.g * attachmentColor.g * multiplier, skeletonColor.b * slotColor.b * attachmentColor.b * multiplier, alpha) if not lastTexture then lastTexture = texture end if lastColor.r == -1 then lastColor:setFrom(color) end if not lastBlendMode then lastBlendMode = blendMode end if (texture ~= lastTexture or not colorEquals(color, lastColor) or blendMode ~= lastBlendMode) then self:flush(groupVertices, groupUvs, groupIndices, lastTexture, lastColor, lastBlendMode, drawingGroup) lastTexture = texture lastColor:setFrom(color) lastBlendMode = blendMode groupVertices = {} groupUvs = {} groupIndices = {} end if self.clipper:isClipping() then self.clipper:clipTriangles(vertices, uvs, indices, #indices) vertices = self.clipper.clippedVertices numVertices = #vertices / 2 uvs = self.clipper.clippedUVs indices = self.clipper.clippedTriangles end self:batch(vertices, uvs, numVertices, indices, groupVertices, groupUvs, groupIndices) end self.clipper:clipEnd(slot) end end if #groupVertices > 0 then self:flush(groupVertices, groupUvs, groupIndices, texture, color, blendMode, drawingGroup) end self.clipper:clipEnd2() if (self.vertexEffect) then self.vertexEffect:endEffect() end end function spine.Skeleton:flush(groupVertices, groupUvs, groupIndices, texture, color, blendMode, drawingGroup) local mesh = display.newMesh(drawingGroup, 0, 0, { mode = "indexed", vertices = groupVertices, uvs = groupUvs, indices = groupIndices }) mesh.fill = texture mesh:setFillColor(color.r, color.g, color.b) mesh.alpha = color.a mesh.blendMode = blendMode mesh:translate(mesh.path:getVertexOffset()) self.batches = self.batches + 1 end function spine.Skeleton:batch(vertices, uvs, numVertices, indices, groupVertices, groupUvs, groupIndices) local numIndices = #indices local i = 1 local indexStart = #groupIndices + 1 local offset = #groupVertices / 2 local indexEnd = indexStart + numIndices while indexStart < indexEnd do groupIndices[indexStart] = indices[i] + offset indexStart = indexStart + 1 i = i + 1 end i = 1 local vertexStart = #groupVertices + 1 local vertexEnd = vertexStart + numVertices * 2 if (self.vertexEffect) then local effect = self.vertexEffect local vertex = self.tempVertex while vertexStart < vertexEnd do vertex.x = vertices[i] vertex.y = vertices[i+1] vertex.u = uvs[i] vertex.v = uvs[i+1] effect:transform(vertex); groupVertices[vertexStart] = vertex.x groupVertices[vertexStart+1] = vertex.y groupUvs[vertexStart] = vertex.u groupUvs[vertexStart+1] = vertex.v vertexStart = vertexStart + 2 i = i + 2 end else while vertexStart < vertexEnd do groupVertices[vertexStart] = vertices[i] groupVertices[vertexStart+1] = vertices[i+1] groupUvs[vertexStart] = uvs[i] groupUvs[vertexStart+1] = uvs[i+1] vertexStart = vertexStart + 2 i = i + 2 end end end return spine