123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875 |
- -------------------------------------------------------------------------------
- -- 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.
- -------------------------------------------------------------------------------
- local table_insert = table.insert
- local SkeletonData = require "spine-lua.SkeletonData"
- local BoneData = require "spine-lua.BoneData"
- local SlotData = require "spine-lua.SlotData"
- local Skin = require "spine-lua.Skin"
- local AttachmentLoader = require "spine-lua.AttachmentLoader"
- local Animation = require "spine-lua.Animation"
- local IkConstraintData = require "spine-lua.IkConstraintData"
- local IkConstraint = require "spine-lua.IkConstraint"
- local PathConstraintData = require "spine-lua.PathConstraintData"
- local PathConstraint = require "spine-lua.PathConstraint"
- local TransformConstraintData = require "spine-lua.TransformConstraintData"
- local TransformConstraint = require "spine-lua.TransformConstraint"
- local EventData = require "spine-lua.EventData"
- local Event = require "spine-lua.Event"
- local AttachmentType = require "spine-lua.attachments.AttachmentType"
- local BlendMode = require "spine-lua.BlendMode"
- local TransformMode = require "spine-lua.TransformMode"
- local utils = require "spine-lua.utils"
- local Color = require "spine-lua.Color"
- local SkeletonJson = {}
- function SkeletonJson.new (attachmentLoader)
- if not attachmentLoader then attachmentLoader = AttachmentLoader.new() end
- local self = {
- attachmentLoader = attachmentLoader,
- scale = 1,
- linkedMeshes = {}
- }
- function self:readSkeletonDataFile (fileName, base)
- return self:readSkeletonData(utils.readFile(fileName, base))
- end
- local readAttachment
- local readAnimation
- local readCurve
- local getArray
- local getValue = function (map, name, default)
- local value = map[name]
- if value == nil then return default else return value end
- end
- function self:readSkeletonData (jsonText)
- local scale = self.scale
- local skeletonData = SkeletonData.new(self.attachmentLoader)
- local root = utils.readJSON(jsonText)
- if not root then error("Invalid JSON: " .. jsonText, 2) end
- -- Skeleton.
- local skeletonMap = root["skeleton"]
- if skeletonMap then
- skeletonData.hash = skeletonMap["hash"]
- skeletonData.version = skeletonMap["spine"]
- skeletonData.width = skeletonMap["width"]
- skeletonData.height = skeletonMap["height"]
- skeletonData.fps = skeletonMap["fps"]
- skeletonData.imagesPath = skeletonMap["images"]
- end
- -- Bones.
- for i,boneMap in ipairs(root["bones"]) do
- local boneName = boneMap["name"]
- local parent = nil
- local parentName = boneMap["parent"]
- if parentName then
- parent = skeletonData:findBone(parentName)
- if not parent then error("Parent bone not found: " .. parentName) end
- end
- local data = BoneData.new(i, boneName, parent)
- data.length = getValue(boneMap, "length", 0) * scale;
- data.x = getValue(boneMap, "x", 0) * scale;
- data.y = getValue(boneMap, "y", 0) * scale;
- data.rotation = getValue(boneMap, "rotation", 0);
- data.scaleX = getValue(boneMap, "scaleX", 1);
- data.scaleY = getValue(boneMap, "scaleY", 1);
- data.shearX = getValue(boneMap, "shearX", 0);
- data.shearY = getValue(boneMap, "shearY", 0);
- data.transformMode = TransformMode[getValue(boneMap, "transform", "normal")]
- table_insert(skeletonData.bones, data)
- end
- -- Slots.
- if root["slots"] then
- for i,slotMap in ipairs(root["slots"]) do
- local slotName = slotMap["name"]
- local boneName = slotMap["bone"]
- local boneData = skeletonData:findBone(boneName)
- if not boneData then error("Slot bone not found: " .. boneName) end
- local data = SlotData.new(i, slotName, boneData)
- local color = slotMap["color"]
- if color then
- data.color:set(tonumber(color:sub(1, 2), 16) / 255,
- tonumber(color:sub(3, 4), 16) / 255,
- tonumber(color:sub(5, 6), 16) / 255,
- tonumber(color:sub(7, 8), 16) / 255)
- end
- local dark = slotMap["dark"]
- if dark then
- data.darkColor = Color.newWith(1, 1, 1, 1)
- data.darkColor:set(tonumber(dark:sub(1, 2), 16) / 255,
- tonumber(dark:sub(3, 4), 16) / 255,
- tonumber(dark:sub(5, 6), 16) / 255,
- 0)
- end
- data.attachmentName = getValue(slotMap, "attachment", nil)
- data.blendMode = BlendMode[getValue(slotMap, "blend", "normal")]
- table_insert(skeletonData.slots, data)
- skeletonData.slotNameIndices[data.name] = #skeletonData.slots
- end
- end
- -- IK constraints.
- if root["ik"] then
- for _,constraintMap in ipairs(root["ik"]) do
- local data = IkConstraintData.new(constraintMap["name"])
- data.order = getValue(constraintMap, "order", 0)
- for _,boneName in ipairs(constraintMap["bones"]) do
- local bone = skeletonData:findBone(boneName)
- if not bone then error("IK bone not found: " .. boneName) end
- table_insert(data.bones, bone)
- end
- local targetName = constraintMap["target"]
- data.target = skeletonData:findBone(targetName)
- if not data.target then error("Target bone not found: " .. targetName) end
- data.mix = getValue(constraintMap, "mix", 1)
- if constraintMap["bendPositive"] == nil or constraintMap["bendPositive"] == false then data.bendDirection = -1 else data.bendDirection = 1 end
- if constraintMap["compress"] == nil or constraintMap["compress"] == false then data.compress = false else data.compress = true end
- if constraintMap["stretch"] == nil or constraintMap["stretch"] == false then data.stretch = false else data.stretch = true end
- if constraintMap["uniform"] == nil or constraintMap["uniform"] == false then data.uniform = false else data.uniform = true end
- table_insert(skeletonData.ikConstraints, data)
- end
- end
- -- Transform constraints
- if root["transform"] then
- for _,constraintMap in ipairs(root["transform"]) do
- local data = TransformConstraintData.new(constraintMap.name)
- data.order = getValue(constraintMap, "order", 0)
- for _,boneName in ipairs(constraintMap.bones) do
- local bone = skeletonData:findBone(boneName)
- if not bone then error("Transform constraint bone not found: " .. boneName, 2) end
- table_insert(data.bones, bone)
- end
- local targetName = constraintMap.target
- data.target = skeletonData:findBone(targetName)
- if not data.target then error("Transform constraint target bone not found: " .. (targetName or "none"), 2) end
- data.offsetRotation = getValue(constraintMap, "rotation", 0);
- data.offsetX = getValue(constraintMap, "x", 0) * scale;
- data.offsetY = getValue(constraintMap, "y", 0) * scale;
- data.offsetScaleX = getValue(constraintMap, "scaleX", 0);
- data.offsetScaleY = getValue(constraintMap, "scaleY", 0);
- data.offsetShearY = getValue(constraintMap, "shearY", 0);
- data.rotateMix = getValue(constraintMap, "rotateMix", 1);
- data.translateMix = getValue(constraintMap, "translateMix", 1);
- data.scaleMix = getValue(constraintMap, "scaleMix", 1);
- data.shearMix = getValue(constraintMap, "shearMix", 1);
- table_insert(skeletonData.transformConstraints, data)
- end
- end
- -- Path constraints
- if root["path"] then
- for _,constraintMap in ipairs(root.path) do
- local data = PathConstraintData.new(constraintMap.name);
- data.order = getValue(constraintMap, "order", 0)
- for _,boneName in ipairs(constraintMap.bones) do
- local bone = skeletonData:findBone(boneName)
- if not bone then error("Path constraint bone not found: " .. boneName, 2) end
- table_insert(data.bones, bone)
- end
- local targetName = constraintMap.target;
- data.target = skeletonData:findSlot(targetName)
- if data.target == nil then error("Path target slot not found: " .. targetName, 2) end
- data.positionMode = PathConstraintData.PositionMode[getValue(constraintMap, "positionMode", "percent"):lower()]
- data.spacingMode = PathConstraintData.SpacingMode[getValue(constraintMap, "spacingMode", "length"):lower()]
- data.rotateMode = PathConstraintData.RotateMode[getValue(constraintMap, "rotateMode", "tangent"):lower()]
- data.offsetRotation = getValue(constraintMap, "rotation", 0);
- data.position = getValue(constraintMap, "position", 0);
- if data.positionMode == PathConstraintData.PositionMode.fixed then data.position = data.position * scale end
- data.spacing = getValue(constraintMap, "spacing", 0);
- if data.spacingMode == PathConstraintData.SpacingMode.length or data.spacingMode == PathConstraintData.SpacingMode.fixed then data.spacing = data.spacing * scale end
- data.rotateMix = getValue(constraintMap, "rotateMix", 1);
- data.translateMix = getValue(constraintMap, "translateMix", 1);
- table_insert(skeletonData.pathConstraints, data)
- end
- end
- -- Skins.
- if root["skins"] then
- for skinName,skinMap in pairs(root["skins"]) do
- local skin = Skin.new(skinName)
- for slotName,slotMap in pairs(skinMap) do
- local slotIndex = skeletonData.slotNameIndices[slotName]
- for attachmentName,attachmentMap in pairs(slotMap) do
- local attachment = readAttachment(attachmentMap, skin, slotIndex, attachmentName, skeletonData)
- if attachment then
- skin:addAttachment(slotIndex, attachmentName, attachment)
- end
- end
- end
- table_insert(skeletonData.skins, skin)
- if skin.name == "default" then skeletonData.defaultSkin = skin end
- end
- end
- -- Linked meshes
- for _, linkedMesh in ipairs(self.linkedMeshes) do
- local skin = skeletonData.defaultSkin
- if linkedMesh.skin then skin = skeletonData:findSkin(linkedMesh.skin) end
- if not skin then error("Skin not found: " .. linkedMesh.skin) end
- local parent = skin:getAttachment(linkedMesh.slotIndex, linkedMesh.parent)
- if not parent then error("Parent mesh not found: " + linkedMesh.parent) end
- linkedMesh.mesh:setParentMesh(parent)
- linkedMesh.mesh:updateUVs()
- end
- self.linkedMeshes = {}
- -- Events.
- if root["events"] then
- for eventName,eventMap in pairs(root["events"]) do
- local data = EventData.new(eventName)
- data.intValue = getValue(eventMap, "int", 0)
- data.floatValue = getValue(eventMap, "float", 0)
- data.stringValue = getValue(eventMap, "string", "")
- data.audioPath = getValue(eventMap, "audio", nil)
- if data.audioPath ~= nil then
- data.volume = getValue(eventMap, "volume", 1)
- data.balance = getValue(eventMap, "balance", 0)
- end
- table_insert(skeletonData.events, data)
- end
- end
- -- Animations.
- if root["animations"] then
- for animationName,animationMap in pairs(root["animations"]) do
- readAnimation(animationMap, animationName, skeletonData)
- end
- end
- return skeletonData
- end
- readAttachment = function (map, skin, slotIndex, name, skeletonData)
- local scale = self.scale
- name = getValue(map, "name", name)
- local type = AttachmentType[getValue(map, "type", "region")]
- local path = getValue(map, "path", name)
- if type == AttachmentType.region then
- local region = attachmentLoader:newRegionAttachment(skin, name, path)
- if not region then return nil end
- region.path = path
- region.x = getValue(map, "x", 0) * scale
- region.y = getValue(map, "y", 0) * scale
- region.scaleX = getValue(map, "scaleX", 1);
- region.scaleY = getValue(map, "scaleY", 1);
- region.rotation = getValue(map, "rotation", 0);
- region.width = map.width * scale;
- region.height = map.height * scale;
- local color = map["color"]
- if color then
- region.color:set(tonumber(color:sub(1, 2), 16) / 255,
- tonumber(color:sub(3, 4), 16) / 255,
- tonumber(color:sub(5, 6), 16) / 255,
- tonumber(color:sub(7, 8), 16) / 255)
- end
- region:updateOffset()
- return region
- elseif type == AttachmentType.boundingbox then
- local box = attachmentLoader:newBoundingBoxAttachment(skin, name)
- if not box then return nil end
- readVertices(map, box, map.vertexCount * 2)
- local color = map.color
- if color then
- box.color:set(tonumber(color:sub(1, 2), 16) / 255,
- tonumber(color:sub(3, 4), 16) / 255,
- tonumber(color:sub(5, 6), 16) / 255,
- tonumber(color:sub(7, 8), 16) / 255)
- end
- return box
- elseif type == AttachmentType.mesh or type == AttachmentType.linkedmesh then
- local mesh = attachmentLoader:newMeshAttachment(skin, name, path)
- if not mesh then return nil end
- mesh.path = path
- local color = map.color
- if color then
- mesh.color:set(tonumber(color:sub(1, 2), 16) / 255,
- tonumber(color:sub(3, 4), 16) / 255,
- tonumber(color:sub(5, 6), 16) / 255,
- tonumber(color:sub(7, 8), 16) / 255)
- end
- local parent = map.parent
- if parent then
- mesh.inheritDeform = getValue(map, "deform", true)
- table_insert(self.linkedMeshes, {
- mesh = mesh,
- skin = getValue(map, "skin", nil),
- slotIndex = slotIndex,
- parent = parent
- })
- return mesh
- end
- local uvs = getArray(map, "uvs", 1)
- readVertices(map, mesh, #uvs)
- mesh.triangles = getArray(map, "triangles", 1)
- -- adjust triangle indices by 1, vertices are one-indexed
- for i,v in ipairs(mesh.triangles) do
- mesh.triangles[i] = v + 1
- end
- mesh.regionUVs = uvs
- mesh:updateUVs()
- mesh.hullLength = getValue(map, "hull", 0) * 2
- return mesh
- elseif type == AttachmentType.path then
- local path = self.attachmentLoader:newPathAttachment(skin, name)
- if not path then return nil end
- path.closed = getValue(map, "closed", false)
- path.constantSpeed = getValue(map, "constantSpeed", true)
- local vertexCount = map.vertexCount
- readVertices(map, path, vertexCount * 2)
- local lengths = utils.newNumberArray(vertexCount / 3, 0)
- for i,v in ipairs(map.lengths) do
- lengths[i] = v * scale
- end
- path.lengths = lengths
- local color = map.color
- if color then
- path.color:set(tonumber(color:sub(1, 2), 16) / 255,
- tonumber(color:sub(3, 4), 16) / 255,
- tonumber(color:sub(5, 6), 16) / 255,
- tonumber(color:sub(7, 8), 16) / 255)
- end
- return path;
-
- elseif type == AttachmentType.point then
- local point = self.attachmentLoader:newPointAttachment(skin, name)
- if not point then return nil end
- point.x = getValue(map, "x", 0) * scale
- point.y = getValue(map, "y", 0) * scale
- point.rotation = getValue(map, "rotation", 0)
-
- local color = map.color
- if color then
- path.color:set(tonumber(color:sub(1, 2), 16) / 255,
- tonumber(color:sub(3, 4), 16) / 255,
- tonumber(color:sub(5, 6), 16) / 255,
- tonumber(color:sub(7, 8), 16) / 255)
- end
- return point
-
- elseif type == AttachmentType.clipping then
- local clip = attachmentLoader:newClippingAttachment(skin, name)
- if not clip then return nil end
-
- local _end = getValue(map, "end", nil)
- if _end then
- local slot = skeletonData:findSlot(_end)
- if not slot then error("Clipping end slot not found: " + _end) end
- clip.endSlot = slot
- end
-
- readVertices(map, clip, map.vertexCount * 2)
- local color = map.color
- if color then
- clip.color:set(tonumber(color:sub(1, 2), 16) / 255,
- tonumber(color:sub(3, 4), 16) / 255,
- tonumber(color:sub(5, 6), 16) / 255,
- tonumber(color:sub(7, 8), 16) / 255)
- end
- return clip
- end
- error("Unknown attachment type: " .. type .. " (" .. name .. ")")
- end
- readVertices = function (map, attachment, verticesLength)
- local scale = self.scale
- attachment.worldVerticesLength = verticesLength
- local vertices = getArray(map, "vertices", 1)
- if verticesLength == #vertices then
- if scale ~= 1 then
- local i = 0
- local n = #vertices
- while i < n do
- vertices[i + 1] = vertices[i + 1] * scale
- i = i + 1
- end
- end
- attachment.vertices = vertices
- return
- end
- local weights = {}
- local bones = {}
- local i = 0
- local n = #vertices
- while i < n do
- local boneCount = vertices[i + 1]
- i = i + 1
- table_insert(bones, boneCount)
- local nn = i + boneCount * 4
- while i < nn do
- table_insert(bones, vertices[i + 1] + 1) -- +1 because bones are one-indexed
- table_insert(weights, vertices[i + 2] * scale)
- table_insert(weights, vertices[i + 3] * scale)
- table_insert(weights, vertices[i + 4])
- i = i + 4
- end
- end
- attachment.bones = bones
- attachment.vertices = weights
- end
- readAnimation = function (map, name, skeletonData)
- local timelines = {}
- local duration = 0
- local scale = self.scale
- -- Slot timelines
- local slotsMap = map["slots"]
- if slotsMap then
- for slotName,timelineMap in pairs(slotsMap) do
- local slotIndex = skeletonData.slotNameIndices[slotName]
- for timelineName,values in pairs(timelineMap) do
- if timelineName == "color" then
- local timeline = Animation.ColorTimeline.new(#values)
- timeline.slotIndex = slotIndex
- local frameIndex = 0
- for _,valueMap in ipairs(values) do
- local color = valueMap["color"]
- timeline:setFrame(
- frameIndex, valueMap["time"],
- tonumber(color:sub(1, 2), 16) / 255,
- tonumber(color:sub(3, 4), 16) / 255,
- tonumber(color:sub(5, 6), 16) / 255,
- tonumber(color:sub(7, 8), 16) / 255
- )
- readCurve(valueMap, timeline, frameIndex)
- frameIndex = frameIndex + 1
- end
- table_insert(timelines, timeline)
- duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.ColorTimeline.ENTRIES])
- elseif timelineName == "twoColor" then
- local timeline = Animation.TwoColorTimeline.new(#values)
- timeline.slotIndex = slotIndex
- local frameIndex = 0
- for _,valueMap in ipairs(values) do
- local light = valueMap["light"]
- local dark = valueMap["dark"]
- timeline:setFrame(
- frameIndex, valueMap["time"],
- tonumber(light:sub(1, 2), 16) / 255,
- tonumber(light:sub(3, 4), 16) / 255,
- tonumber(light:sub(5, 6), 16) / 255,
- tonumber(light:sub(7, 8), 16) / 255,
- tonumber(dark:sub(1, 2), 16) / 255,
- tonumber(dark:sub(3, 4), 16) / 255,
- tonumber(dark:sub(5, 6), 16) / 255
- )
- readCurve(valueMap, timeline, frameIndex)
- frameIndex = frameIndex + 1
- end
- table_insert(timelines, timeline)
- duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.TwoColorTimeline.ENTRIES])
- elseif timelineName == "attachment" then
- local timeline = Animation.AttachmentTimeline.new(#values)
- timeline.slotIndex = slotIndex
- local frameIndex = 0
- for _,valueMap in ipairs(values) do
- local attachmentName = valueMap["name"]
- timeline:setFrame(frameIndex, valueMap["time"], attachmentName)
- frameIndex = frameIndex + 1
- end
- table_insert(timelines, timeline)
- duration = math.max(duration, timeline.frames[timeline:getFrameCount() - 1])
- else
- error("Invalid frame type for a slot: " .. timelineName .. " (" .. slotName .. ")")
- end
- end
- end
- end
- -- Bone timelines
- local bonesMap = map["bones"]
- if bonesMap then
- for boneName,timelineMap in pairs(bonesMap) do
- local boneIndex = skeletonData:findBoneIndex(boneName)
- if boneIndex == -1 then error("Bone not found: " .. boneName) end
- for timelineName,values in pairs(timelineMap) do
- if timelineName == "rotate" then
- local timeline = Animation.RotateTimeline.new(#values)
- timeline.boneIndex = boneIndex
- local frameIndex = 0
- for _,valueMap in ipairs(values) do
- timeline:setFrame(frameIndex, valueMap["time"], valueMap["angle"])
- readCurve(valueMap, timeline, frameIndex)
- frameIndex = frameIndex + 1
- end
- table_insert(timelines, timeline)
- duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.RotateTimeline.ENTRIES])
- elseif timelineName == "translate" or timelineName == "scale" or timelineName == "shear" then
- local timeline
- local timelineScale = 1
- if timelineName == "scale" then
- timeline = Animation.ScaleTimeline.new(#values)
- elseif timelineName == "shear" then
- timeline = Animation.ShearTimeline.new(#values)
- else
- timeline = Animation.TranslateTimeline.new(#values)
- timelineScale = self.scale
- end
- timeline.boneIndex = boneIndex
- local frameIndex = 0
- for _,valueMap in ipairs(values) do
- local x = (valueMap["x"] or 0) * timelineScale
- local y = (valueMap["y"] or 0) * timelineScale
- timeline:setFrame(frameIndex, valueMap["time"], x, y)
- readCurve(valueMap, timeline, frameIndex)
- frameIndex = frameIndex + 1
- end
- table_insert(timelines, timeline)
- duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.TranslateTimeline.ENTRIES])
- else
- error("Invalid timeline type for a bone: " .. timelineName .. " (" .. boneName .. ")")
- end
- end
- end
- end
- -- IK timelines.
- local ik = map["ik"]
- if ik then
- for ikConstraintName,values in pairs(ik) do
- local ikConstraint = skeletonData:findIkConstraint(ikConstraintName)
- local timeline = Animation.IkConstraintTimeline.new(#values)
- for i,other in pairs(skeletonData.ikConstraints) do
- if other == ikConstraint then
- timeline.ikConstraintIndex = i
- break
- end
- end
- local frameIndex = 0
- for _,valueMap in ipairs(values) do
- local mix = 1
- if valueMap["mix"] ~= nil then mix = valueMap["mix"] end
- local bendPositive = 1
- if valueMap["bendPositive"] == false then bendPositive = -1 end
- local stretch = false
- if valueMap["stretch"] ~= nil then stretch = valueMap["stretch"] end
- local compress = false
- if valueMap["compress"] ~= nil then compress = valueMap["compress"] end
- timeline:setFrame(frameIndex, valueMap["time"], mix, bendPositive, compress, stretch)
- readCurve(valueMap, timeline, frameIndex)
- frameIndex = frameIndex + 1
- end
- table_insert(timelines, timeline)
- duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.IkConstraintTimeline.ENTRIES])
- end
- end
- -- Transform constraint timelines.
- local transform = map["transform"]
- if transform then
- for constraintName, values in pairs(transform) do
- local constraint = skeletonData:findTransformConstraint(constraintName)
- local timeline = Animation.TransformConstraintTimeline.new(#values)
- for i,other in pairs(skeletonData.transformConstraints) do
- if other == constraint then
- timeline.transformConstraintIndex = i
- break
- end
- end
- local frameIndex = 0
- for _,valueMap in ipairs(values) do
- timeline:setFrame(frameIndex, valueMap.time, getValue(valueMap, "rotateMix", 1), getValue(valueMap, "translateMix", 1), getValue(valueMap, "scaleMix", 1), getValue(valueMap, "shearMix", 1))
- readCurve(valueMap, timeline, frameIndex)
- frameIndex = frameIndex + 1
- end
- table_insert(timelines, timeline)
- duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.TransformConstraintTimeline.ENTRIES])
- end
- end
- -- Path constraint timelines.
- if map.paths then
- for constraintName,constraintMap in pairs(map.paths) do
- local index = skeletonData:findPathConstraintIndex(constraintName)
- if index == -1 then error("Path constraint not found: " .. constraintName, 2) end
- local data = skeletonData.pathConstraints[index]
- for timelineName, timelineMap in pairs(constraintMap) do
- if timelineName == "position" or timelineName == "spacing" then
- local timeline = nil
- local timelineScale = 1
- if timelineName == "spacing" then
- timeline = Animation.PathConstraintSpacingTimeline.new(#timelineMap)
- if data.spacingMode == PathConstraintData.SpacingMode.length or data.spacingMode == PathConstraintData.SpacingMode.fixed then timelineScale = scale end
- else
- timeline = Animation.PathConstraintPositionTimeline.new(#timelineMap)
- if data.positionMode == PathConstraintData.PositionMode.fixed then timelineScale = scale end
- end
- timeline.pathConstraintIndex = index
- local frameIndex = 0
- for _,valueMap in ipairs(timelineMap) do
- timeline:setFrame(frameIndex, valueMap.time, getValue(valueMap, timelineName, 0) * timelineScale)
- readCurve(valueMap, timeline, frameIndex)
- frameIndex = frameIndex + 1
- end
- table_insert(timelines, timeline)
- duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.PathConstraintPositionTimeline.ENTRIES])
- elseif timelineName == "mix" then
- local timeline = Animation.PathConstraintMixTimeline.new(#timelineMap)
- timeline.pathConstraintIndex = index
- local frameIndex = 0
- for _,valueMap in ipairs(timelineMap) do
- timeline:setFrame(frameIndex, valueMap.time, getValue(valueMap, "rotateMix", 1), getValue(valueMap, "translateMix", 1))
- readCurve(valueMap, timeline, frameIndex)
- frameIndex = frameIndex + 1
- end
- table_insert(timelines, timeline)
- duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.PathConstraintMixTimeline.ENTRIES])
- end
- end
- end
- end
- -- Deform timelines.
- if map.deform then
- for deformName, deformMap in pairs(map.deform) do
- local skin = skeletonData:findSkin(deformName)
- if not skin then error("Skin not found: " .. deformName, 2) end
- for slotName,slotMap in pairs(deformMap) do
- local slotIndex = skeletonData:findSlotIndex(slotName)
- if slotIndex == -1 then error("Slot not found: " .. slotMap.name, 2) end
- for timelineName,timelineMap in pairs(slotMap) do
- local attachment = skin:getAttachment(slotIndex, timelineName)
- if not attachment then error("Deform attachment not found: " .. timelineMap.name, 2) end
- local weighted = attachment.bones ~= nil
- local vertices = attachment.vertices;
- local deformLength = #vertices
- if weighted then deformLength = math.floor(#vertices / 3) * 2 end
- local timeline = Animation.DeformTimeline.new(#timelineMap)
- timeline.slotIndex = slotIndex
- timeline.attachment = attachment
- local frameIndex = 0
- for _,valueMap in ipairs(timelineMap) do
- local deform = nil
- local verticesValue = getValue(valueMap, "vertices", nil)
- if verticesValue == nil then
- deform = vertices
- if weighted then deform = utils.newNumberArray(deformLength) end
- else
- deform = utils.newNumberArray(deformLength)
- local start = getValue(valueMap, "offset", 0) + 1
- utils.arrayCopy(verticesValue, 1, deform, start, #verticesValue)
- if scale ~= 1 then
- local i = start
- local n = i + #verticesValue
- while i < n do
- deform[i] = deform[i] * scale
- i = i + 1
- end
- end
- if not weighted then
- local i = 1
- local n = i + deformLength
- while i < n do
- deform[i] = deform[i] + vertices[i]
- i = i + 1
- end
- end
- end
- timeline:setFrame(frameIndex, valueMap.time, deform)
- readCurve(valueMap, timeline, frameIndex)
- frameIndex = frameIndex + 1
- end
- table_insert(timelines, timeline)
- duration = math.max(duration, timeline.frames[timeline:getFrameCount() - 1])
- end
- end
- end
- end
- -- Draworder timeline.
- local drawOrderValues = map["drawOrder"]
- if not drawOrderValues then drawOrderValues = map["draworder"] end
- if drawOrderValues then
- local timeline = Animation.DrawOrderTimeline.new(#drawOrderValues)
- local slotCount = #skeletonData.slots
- local frameIndex = 0
- for _,drawOrderMap in ipairs(drawOrderValues) do
- local drawOrder = nil
- local offsets = drawOrderMap["offsets"]
- if offsets then
- drawOrder = {}
- local unchanged = {}
- local originalIndex = 1
- local unchangedIndex = 1
- for _,offsetMap in ipairs(offsets) do
- local slotIndex = skeletonData:findSlotIndex(offsetMap["slot"])
- if slotIndex == -1 then error("Slot not found: " .. offsetMap["slot"]) end
- -- Collect unchanged items.
- while originalIndex ~= slotIndex do
- unchanged[unchangedIndex] = originalIndex
- unchangedIndex = unchangedIndex + 1
- originalIndex = originalIndex + 1
- end
- -- Set changed items.
- drawOrder[originalIndex + offsetMap["offset"]] = originalIndex
- originalIndex = originalIndex + 1
- end
- -- Collect remaining unchanged items.
- while originalIndex <= slotCount do
- unchanged[unchangedIndex] = originalIndex
- unchangedIndex = unchangedIndex + 1
- originalIndex = originalIndex + 1
- end
- -- Fill in unchanged items.
- for ii = slotCount, 1, -1 do
- if not drawOrder[ii] then
- unchangedIndex = unchangedIndex - 1
- drawOrder[ii] = unchanged[unchangedIndex]
- end
- end
- end
- timeline:setFrame(frameIndex, drawOrderMap["time"], drawOrder)
- frameIndex = frameIndex + 1
- end
- table_insert(timelines, timeline)
- duration = math.max(duration, timeline.frames[timeline:getFrameCount() - 1])
- end
- -- Event timeline.
- local events = map["events"]
- if events then
- local timeline = Animation.EventTimeline.new(#events)
- local frameIndex = 0
- for _,eventMap in ipairs(events) do
- local eventData = skeletonData:findEvent(eventMap["name"])
- if not eventData then error("Event not found: " .. eventMap["name"]) end
- local event = Event.new(eventMap["time"], eventData)
- if eventMap["int"] ~= nil then
- event.intValue = eventMap["int"]
- else
- event.intValue = eventData.intValue
- end
- if eventMap["float"] ~= nil then
- event.floatValue = eventMap["float"]
- else
- event.floatValue = eventData.floatValue
- end
- if eventMap["string"] ~= nil then
- event.stringValue = eventMap["string"]
- else
- event.stringValue = eventData.stringValue
- end
- if eventData.audioPath ~= nil then
- event.volume = getValue(eventMap, "volume", 1)
- event.balance = getValue(eventMap, "balance", 0)
- end
- timeline:setFrame(frameIndex, event)
- frameIndex = frameIndex + 1
- end
- table_insert(timelines, timeline)
- duration = math.max(duration, timeline.frames[timeline:getFrameCount() - 1])
- end
- table_insert(skeletonData.animations, Animation.new(name, timelines, duration))
- end
- readCurve = function (map, timeline, frameIndex)
- local curve = map["curve"]
- if not curve then return end
- if curve == "stepped" then
- timeline:setStepped(frameIndex)
- elseif #curve > 0 then
- timeline:setCurve(frameIndex, curve[1], curve[2], curve[3], curve[4])
- end
- end
- getArray = function (map, name, scale)
- local list = map[name]
- local values = {}
- if scale == 1 then
- for i = 1, #list do
- values[i] = list[i]
- end
- else
- for i = 1, #list do
- values[i] = list[i] * scale
- end
- end
- return values
- end
- return self
- end
- return SkeletonJson
|