@ -124,6 +124,8 @@
|
||||
### Love2D
|
||||
|
||||
### Corona
|
||||
* **Breaking changes**
|
||||
* spine-corona has been renamed to spine-solar2d. Change your `require "spine-corona.spine"` statements to `require "spine-solar2d.spine"`
|
||||
|
||||
## Typescript/Javascript
|
||||
* **Breaking changes**
|
||||
|
||||
@ -118,43 +118,43 @@ cp -f ../mix-and-match/export/mix-and-match.atlas "$ROOT/spine-cocos2dx/example-
|
||||
cp -f ../mix-and-match/export/mix-and-match.png "$ROOT/spine-cocos2dx/example-v4/Resources/common/"
|
||||
|
||||
|
||||
echo "spine-corona"
|
||||
rm "$ROOT/spine-corona/data/"*
|
||||
cp -f ../coin/export/coin-pro.json "$ROOT/spine-corona/data"
|
||||
cp -f ../coin/export/coin.atlas "$ROOT/spine-corona/data"
|
||||
cp -f ../coin/export/coin.png "$ROOT/spine-corona/data"
|
||||
echo "spine-solar2d"
|
||||
rm "$ROOT/spine-solar2d/data/"*
|
||||
cp -f ../coin/export/coin-pro.json "$ROOT/spine-solar2d/data"
|
||||
cp -f ../coin/export/coin.atlas "$ROOT/spine-solar2d/data"
|
||||
cp -f ../coin/export/coin.png "$ROOT/spine-solar2d/data"
|
||||
|
||||
cp -f ../goblins/export/goblins-pro.json "$ROOT/spine-corona/data"
|
||||
cp -f ../goblins/export/goblins.atlas "$ROOT/spine-corona/data"
|
||||
cp -f ../goblins/export/goblins.png "$ROOT/spine-corona/data"
|
||||
cp -f ../goblins/export/goblins-pro.json "$ROOT/spine-solar2d/data"
|
||||
cp -f ../goblins/export/goblins.atlas "$ROOT/spine-solar2d/data"
|
||||
cp -f ../goblins/export/goblins.png "$ROOT/spine-solar2d/data"
|
||||
|
||||
cp -f ../raptor/export/raptor-pro.json "$ROOT/spine-corona/data"
|
||||
cp -f ../raptor/export/raptor.atlas "$ROOT/spine-corona/data"
|
||||
cp -f ../raptor/export/raptor.png "$ROOT/spine-corona/data"
|
||||
cp -f ../raptor/export/raptor-pro.json "$ROOT/spine-solar2d/data"
|
||||
cp -f ../raptor/export/raptor.atlas "$ROOT/spine-solar2d/data"
|
||||
cp -f ../raptor/export/raptor.png "$ROOT/spine-solar2d/data"
|
||||
|
||||
cp -f ../spineboy/export/spineboy-pro.json "$ROOT/spine-corona/data"
|
||||
cp -f ../spineboy/export/spineboy.atlas "$ROOT/spine-corona/data"
|
||||
cp -f ../spineboy/export/spineboy.png "$ROOT/spine-corona/data"
|
||||
cp -f ../spineboy/export/spineboy-pro.json "$ROOT/spine-solar2d/data"
|
||||
cp -f ../spineboy/export/spineboy.atlas "$ROOT/spine-solar2d/data"
|
||||
cp -f ../spineboy/export/spineboy.png "$ROOT/spine-solar2d/data"
|
||||
|
||||
cp -f ../tank/export/tank-pro.json "$ROOT/spine-corona/data"
|
||||
cp -f ../tank/export/tank.atlas "$ROOT/spine-corona/data"
|
||||
cp -f ../tank/export/tank.png "$ROOT/spine-corona/data"
|
||||
cp -f ../tank/export/tank-pro.json "$ROOT/spine-solar2d/data"
|
||||
cp -f ../tank/export/tank.atlas "$ROOT/spine-solar2d/data"
|
||||
cp -f ../tank/export/tank.png "$ROOT/spine-solar2d/data"
|
||||
|
||||
cp -f ../vine/export/vine-pro.json "$ROOT/spine-corona/data"
|
||||
cp -f ../vine/export/vine.atlas "$ROOT/spine-corona/data"
|
||||
cp -f ../vine/export/vine.png "$ROOT/spine-corona/data"
|
||||
cp -f ../vine/export/vine-pro.json "$ROOT/spine-solar2d/data"
|
||||
cp -f ../vine/export/vine.atlas "$ROOT/spine-solar2d/data"
|
||||
cp -f ../vine/export/vine.png "$ROOT/spine-solar2d/data"
|
||||
|
||||
cp -f ../stretchyman/export/stretchyman-pro.json "$ROOT/spine-corona/data"
|
||||
cp -f ../stretchyman/export/stretchyman.atlas "$ROOT/spine-corona/data"
|
||||
cp -f ../stretchyman/export/stretchyman.png "$ROOT/spine-corona/data"
|
||||
cp -f ../stretchyman/export/stretchyman-pro.json "$ROOT/spine-solar2d/data"
|
||||
cp -f ../stretchyman/export/stretchyman.atlas "$ROOT/spine-solar2d/data"
|
||||
cp -f ../stretchyman/export/stretchyman.png "$ROOT/spine-solar2d/data"
|
||||
|
||||
cp -f ../owl/export/owl-pro.json "$ROOT/spine-corona/data"
|
||||
cp -f ../owl/export/owl.atlas "$ROOT/spine-corona/data"
|
||||
cp -f ../owl/export/owl.png "$ROOT/spine-corona/data"
|
||||
cp -f ../owl/export/owl-pro.json "$ROOT/spine-solar2d/data"
|
||||
cp -f ../owl/export/owl.atlas "$ROOT/spine-solar2d/data"
|
||||
cp -f ../owl/export/owl.png "$ROOT/spine-solar2d/data"
|
||||
|
||||
cp -f ../mix-and-match/export/mix-and-match-pro.json "$ROOT/spine-corona/data"
|
||||
cp -f ../mix-and-match/export/mix-and-match.atlas "$ROOT/spine-corona/data"
|
||||
cp -f ../mix-and-match/export/mix-and-match.png "$ROOT/spine-corona/data"
|
||||
cp -f ../mix-and-match/export/mix-and-match-pro.json "$ROOT/spine-solar2d/data"
|
||||
cp -f ../mix-and-match/export/mix-and-match.atlas "$ROOT/spine-solar2d/data"
|
||||
cp -f ../mix-and-match/export/mix-and-match.png "$ROOT/spine-solar2d/data"
|
||||
|
||||
echo "spine-love"
|
||||
rm "$ROOT/spine-love/data/"*
|
||||
|
||||
@ -1,79 +0,0 @@
|
||||
require("mobdebug").start()
|
||||
|
||||
local spine = require "spine-corona.spine"
|
||||
|
||||
function loadSkeleton(atlasFile, jsonFile, x, y, scale, animation, skin)
|
||||
-- to load an atlas, we need to define a function that returns
|
||||
-- a Corona paint object. This allows you to resolve images
|
||||
-- however you see fit
|
||||
local imageLoader = function (path)
|
||||
local paint = { type = "image", filename = "data/" .. path }
|
||||
return paint
|
||||
end
|
||||
|
||||
-- load the atlas
|
||||
local atlas = spine.TextureAtlas.new(spine.utils.readFile("data/" .. atlasFile), imageLoader)
|
||||
|
||||
-- load the JSON and create a Skeleton from it
|
||||
local json = spine.SkeletonJson.new(spine.AtlasAttachmentLoader.new(atlas))
|
||||
json.scale = scale
|
||||
local skeletonData = json:readSkeletonDataFile("data/" .. jsonFile)
|
||||
local skeleton = spine.Skeleton.new(skeletonData)
|
||||
skeleton.scaleY = -1 -- Corona's coordinate system has its y-axis point downwards
|
||||
skeleton.group.x = x
|
||||
skeleton.group.y = y
|
||||
|
||||
-- Set the skin if we got one
|
||||
if skin then skeleton:setSkin(skin) end
|
||||
|
||||
-- create an animation state object to apply animations to the skeleton
|
||||
local animationStateData = spine.AnimationStateData.new(skeletonData)
|
||||
animationStateData.defaultMix = 0.5
|
||||
local animationState = spine.AnimationState.new(animationStateData)
|
||||
|
||||
-- set a name on the group of the skeleton so we can find it during debugging
|
||||
skeleton.group.name = jsonFile
|
||||
|
||||
-- set some event callbacks
|
||||
animationState.onStart = function (entry)
|
||||
print(entry.trackIndex.." start: "..entry.animation.name)
|
||||
end
|
||||
animationState.onInterrupt = function (entry)
|
||||
print(entry.trackIndex.." interrupt: "..entry.animation.name)
|
||||
end
|
||||
animationState.onEnd = function (entry)
|
||||
print(entry.trackIndex.." end: "..entry.animation.name)
|
||||
end
|
||||
animationState.onComplete = function (entry)
|
||||
print(entry.trackIndex.." complete: "..entry.animation.name)
|
||||
end
|
||||
animationState.onDispose = function (entry)
|
||||
print(entry.trackIndex.." dispose: "..entry.animation.name)
|
||||
end
|
||||
animationState.onEvent = function (entry, event)
|
||||
print(entry.trackIndex.." event: "..entry.animation.name..", "..event.data.name..", "..event.intValue..", "..event.floatValue..", '"..(event.stringValue or "").."'" .. ", " .. event.volume .. ", " .. event.balance)
|
||||
end
|
||||
|
||||
-- return the skeleton an animation state
|
||||
return { skeleton = skeleton, state = animationState }
|
||||
end
|
||||
|
||||
local lastTime = 0
|
||||
local result = loadSkeleton("spineboy.atlas", "spineboy-pro.json", 240, 300, 0.4, "walk")
|
||||
local skeleton = result.skeleton;
|
||||
local state = result.state;
|
||||
|
||||
state:setAnimationByName(0, "idle", true)
|
||||
state:setAnimationByName(5, "shoot", true, 0)
|
||||
|
||||
display.setDefault("background", 0.2, 0.2, 0.2, 1)
|
||||
|
||||
Runtime:addEventListener("enterFrame", function (event)
|
||||
local currentTime = event.time / 1000
|
||||
local delta = currentTime - lastTime
|
||||
lastTime = currentTime
|
||||
|
||||
state:update(delta)
|
||||
state:apply(skeleton)
|
||||
skeleton:updateWorldTransform()
|
||||
end)
|
||||
@ -1,6 +1,6 @@
|
||||
# spine-corona
|
||||
# spine-solar2d
|
||||
|
||||
The spine-corona runtime provides functionality to load, manipulate and render [Spine](http://esotericsoftware.com) skeletal animation data using [Corona](http://coronalabs.com/products/corona-sdk/). spine-corona is based on [spine-lua](../spine-lua).
|
||||
The spine-solar2d runtime provides functionality to load, manipulate and render [Spine](http://esotericsoftware.com) skeletal animation data using [Solar2D](https://solar2d.com/) (previously Corona). spine-solar2d is based on [spine-lua](../spine-lua).
|
||||
|
||||
## Licensing
|
||||
|
||||
@ -14,18 +14,18 @@ For the official legal terms governing the Spine Runtimes, please read the [Spin
|
||||
|
||||
## Spine version
|
||||
|
||||
spine-corona works with data exported from Spine 3.9.xx.
|
||||
spine-solar2d works with data exported from Spine 3.9.xx.
|
||||
|
||||
spine-corona supports all Spine features.
|
||||
spine-solar2d supports all Spine features.
|
||||
|
||||
spine-corona does not yet support loading the binary format.
|
||||
spine-solar2d does not yet support loading the binary format.
|
||||
|
||||
## Setup
|
||||
|
||||
1. Download the Spine Runtimes source using [git](https://help.github.com/articles/set-up-git) or by downloading it as a zip via the download button above.
|
||||
2. Copy the `spine-lua/spine-lua` folder to `spine-corona`.
|
||||
3. Run the `main.lua` file using Corona. Tap/click to switch between skeletons
|
||||
2. Copy the `spine-lua/spine-lua` folder to `spine-solar2d`.
|
||||
3. Run the `main.lua` file using Solar2D. Tap/click to switch between skeletons
|
||||
|
||||
Alternatively, the `spine-lua` and `spine-corona/spine-corona` directories can be copied into your project. Note that the spine-corona `require` statements use `spine-lua.Xxx`, so the spine-lua files must be in a `spine-lua` directory in your project.
|
||||
Alternatively, the `spine-lua` and `spine-solar2d/spine-solar2d` directories can be copied into your project. Note that the spine-solar2d `require` statements use `spine-lua.Xxx`, so the spine-lua files must be in a `spine-lua` directory in your project.
|
||||
|
||||
When using the `EmmyLua` plugin for IntelliJ IDEA, create a launch configuration pointing at the `Corona Simulator` executable (e.g. ` /Applications/Corona/Corona Simulator.app/Contents/MacOS/Corona Simulator` on macOS), set the working directory to `spine-corona`, and set the parameters to `main.lua`.
|
||||
When using the `EmmyLua` plugin for IntelliJ IDEA, create a launch configuration pointing at the `Corona Simulator` executable (e.g. ` /Applications/Corona/Corona Simulator.app/Contents/MacOS/Corona Simulator` on macOS), set the working directory to `spine-solar2d`, and set the parameters to `main.lua`.
|
||||
|
Before Width: | Height: | Size: 251 KiB After Width: | Height: | Size: 251 KiB |
|
Before Width: | Height: | Size: 161 KiB After Width: | Height: | Size: 161 KiB |
|
Before Width: | Height: | Size: 350 KiB After Width: | Height: | Size: 350 KiB |
|
Before Width: | Height: | Size: 314 KiB After Width: | Height: | Size: 314 KiB |
|
Before Width: | Height: | Size: 412 KiB After Width: | Height: | Size: 412 KiB |
|
Before Width: | Height: | Size: 243 KiB After Width: | Height: | Size: 243 KiB |
|
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 97 KiB |
|
Before Width: | Height: | Size: 437 KiB After Width: | Height: | Size: 437 KiB |
|
Before Width: | Height: | Size: 81 KiB After Width: | Height: | Size: 81 KiB |
@ -29,7 +29,7 @@
|
||||
|
||||
require("mobdebug").start()
|
||||
|
||||
local spine = require "spine-corona.spine"
|
||||
local spine = require "spine-solar2d.spine"
|
||||
|
||||
local skeletons = {}
|
||||
local activeSkeleton = 1
|
||||
@ -1,300 +1,300 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Spine Runtimes License Agreement
|
||||
-- Last updated January 1, 2020. Replaces all prior versions.
|
||||
--
|
||||
-- Copyright (c) 2013-2020, Esoteric Software LLC
|
||||
--
|
||||
-- Integration of the Spine Runtimes into software or otherwise creating
|
||||
-- derivative works of the Spine Runtimes is permitted under the terms and
|
||||
-- conditions of Section 2 of the Spine Editor License Agreement:
|
||||
-- http://esotericsoftware.com/spine-editor-license
|
||||
--
|
||||
-- Otherwise, it is permitted to integrate the Spine Runtimes into software
|
||||
-- or otherwise create derivative works of the Spine Runtimes (collectively,
|
||||
-- "Products"), provided that each user of the Products must obtain their own
|
||||
-- Spine Editor license and redistribution of the Products in any form must
|
||||
-- include this license and copyright notice.
|
||||
--
|
||||
-- THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "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 LLC 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
|
||||
-- THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local 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)
|
||||
local 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 _,slot in ipairs(drawOrder) do
|
||||
local attachment = slot.attachment
|
||||
local vertices = nil
|
||||
local uvs = nil
|
||||
local numVertices = 0
|
||||
local indices = nil
|
||||
|
||||
if slot.bone.active then
|
||||
local isClippingAttachment = false
|
||||
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)
|
||||
isClippingAttachment = true
|
||||
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 = 1
|
||||
if premultipliedAlpha then multiplier = alpha 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
|
||||
if not isClippingAttachment then self.clipper:clipEnd(slot) end
|
||||
end
|
||||
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
|
||||
-------------------------------------------------------------------------------
|
||||
-- Spine Runtimes License Agreement
|
||||
-- Last updated January 1, 2020. Replaces all prior versions.
|
||||
--
|
||||
-- Copyright (c) 2013-2020, Esoteric Software LLC
|
||||
--
|
||||
-- Integration of the Spine Runtimes into software or otherwise creating
|
||||
-- derivative works of the Spine Runtimes is permitted under the terms and
|
||||
-- conditions of Section 2 of the Spine Editor License Agreement:
|
||||
-- http://esotericsoftware.com/spine-editor-license
|
||||
--
|
||||
-- Otherwise, it is permitted to integrate the Spine Runtimes into software
|
||||
-- or otherwise create derivative works of the Spine Runtimes (collectively,
|
||||
-- "Products"), provided that each user of the Products must obtain their own
|
||||
-- Spine Editor license and redistribution of the Products in any form must
|
||||
-- include this license and copyright notice.
|
||||
--
|
||||
-- THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "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 LLC 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
|
||||
-- THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local 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)
|
||||
local 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 _,slot in ipairs(drawOrder) do
|
||||
local attachment = slot.attachment
|
||||
local vertices = nil
|
||||
local uvs = nil
|
||||
local numVertices = 0
|
||||
local indices = nil
|
||||
|
||||
if slot.bone.active then
|
||||
local isClippingAttachment = false
|
||||
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)
|
||||
isClippingAttachment = true
|
||||
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 = 1
|
||||
if premultipliedAlpha then multiplier = alpha 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
|
||||
if not isClippingAttachment then self.clipper:clipEnd(slot) end
|
||||
end
|
||||
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
|
||||