mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-21 01:36:02 +08:00
The spine-lua API has been updated to be compatible with Spine version 3.4.02 (latest stable). The spine-lua API now supports path constraints, transform constraints, uses the new way we encode meshes etc. There are no API breaking changes, only API additions, such as PathConstraints and TransformConstraints as well as additional methods to Skeleton and similar classes. The internals of the spine-lua API have also been updated to follow Lua best performance practices by localizing heavily and using meta tables for "class methods". The spine-lua API now also loads texture atlases as exported by Spine. All that is required for a consumer is to supply an image loading function for their specific engine/framework. We provide implementations for spine-love and spine-corona. The spine-love API can now render all Spine attachment types, including meshes and linked meshes. The API has changed. Where previously a "class" Skeleton existed with a draw function, the new spine-love API introduces a new SkeletonRenderer. See the example on API usage. The spine-corona API can now also render all Spine attachment types. The API has not changed.
192 lines
6.4 KiB
Lua
192 lines
6.4 KiB
Lua
-------------------------------------------------------------------------------
|
|
-- Spine Runtimes Software License
|
|
-- Version 2.3
|
|
--
|
|
-- Copyright (c) 2013-2015, 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 (the "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 otherwise create derivative works, improvements of the
|
|
-- Software or develop new applications using the Software 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; LOSS OF USE, DATA, OR PROFITS;
|
|
-- OR BUSINESS INTERRUPTION) 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 AttachmentType = require "spine-lua.attachments.AttachmentType"
|
|
local utils = require "spine-lua.utils"
|
|
|
|
local setmetatable = setmetatable
|
|
local math_min = math.min
|
|
local math_max = math.max
|
|
local ipairs = ipairs
|
|
local table_insert = table.insert
|
|
|
|
local SkeletonBounds = {}
|
|
SkeletonBounds.__index = SkeletonBounds
|
|
|
|
function SkeletonBounds.new ()
|
|
local self = {
|
|
minX = 0, minY = 0, maxX = 0, maxY = 0,
|
|
polygons = {},
|
|
boundingBoxes = {},
|
|
}
|
|
setmetatable(self, SkeletonBounds)
|
|
|
|
return self
|
|
end
|
|
|
|
function SkeletonBounds:update (skeleton, updateAabb)
|
|
if skeleton == nil then error("skeleton cannot be null", 2) end
|
|
local boundingBoxes = {}
|
|
self.boundingBoxes = boundingBoxes
|
|
local polygons = {}
|
|
self.polygons = polygons
|
|
local slots = skeleton.slots
|
|
|
|
for i,slot in ipairs(skeleton.slots) do
|
|
local attachment = slot.attachment
|
|
if attachment and attachment.type == AttachmentType.boundingbox then
|
|
local boundingBox = attachment
|
|
table_insert(boundingBoxes, boundingBox)
|
|
|
|
local polygon = {}
|
|
table_insert(polygons, polygon)
|
|
|
|
boundingBox:computeWorldVertices(slot, polygon)
|
|
end
|
|
end
|
|
|
|
if updateAabb then self:aabbCompute() end
|
|
end
|
|
|
|
function SkeletonBounds:aabbCompute ()
|
|
local minX, minY, maxX, maxY = 9999999, 9999999, -9999999, -9999999
|
|
local polygons = self.polygons
|
|
for i,vertices in ipairs(polygons) do
|
|
local count = #vertices
|
|
for ii = 1, count, 2 do
|
|
local x = vertices[ii]
|
|
local y = vertices[ii + 1]
|
|
minX = math_min(minX, x)
|
|
minY = math_min(minY, y)
|
|
maxX = math_max(maxX, x)
|
|
maxY = math_max(maxY, y)
|
|
end
|
|
end
|
|
self.minX = minX
|
|
self.minY = minY
|
|
self.maxX = maxX
|
|
self.maxY = maxY
|
|
end
|
|
|
|
function SkeletonBounds:aabbContainsPoint (x, y)
|
|
return x >= self.minX and x <= self.maxX and y >= self.minY and y <= self.maxY
|
|
end
|
|
|
|
function SkeletonBounds:aabbIntersectsSegment (x1, y1, x2, y2)
|
|
local minX, minY, maxX, maxY = self.minX, self.minY, self.maxX, self.maxY
|
|
if (x1 <= minX and x2 <= minX) or (y1 <= minY and y2 <= minY) or (x1 >= maxX and x2 >= maxX) or (y1 >= maxY and y2 >= maxY) then
|
|
return false
|
|
end
|
|
local m = (y2 - y1) / (x2 - x1)
|
|
local y = m * (minX - x1) + y1
|
|
if y > minY and y < maxY then return true end
|
|
y = m * (maxX - x1) + y1
|
|
if y > minY and y < maxY then return true end
|
|
local x = (minY - y1) / m + x1
|
|
if x > minX and x < maxX then return true end
|
|
x = (maxY - y1) / m + x1
|
|
if x > minX and x < maxX then return true end
|
|
return false
|
|
end
|
|
|
|
function SkeletonBounds:aabbIntersectsSkeleton (bounds)
|
|
return self.minX < bounds.maxX and self.maxX > bounds.minX and self.minY < bounds.maxY and self.maxY > bounds.minY
|
|
end
|
|
|
|
function SkeletonBounds:containsPoint (x, y)
|
|
for i,polygon in ipairs(self.polygons) do
|
|
if self:polygonContainsPoint(polygon, x, y) then return self.boundingBoxes[i] end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
function SkeletonBounds:intersectsSegment (x1, y1, x2, y2)
|
|
for i,polygon in ipairs(self.polygons) do
|
|
if self:polygonIntersectsSegment(polygon, x1, y1, x2, y2) then return self.boundingBoxes[i] end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
function SkeletonBounds:polygonContainsPoint (polygon, x, y)
|
|
local nn = #polygon
|
|
local prevIndex = nn - 1
|
|
local inside = false
|
|
for ii = 1, nn, 2 do
|
|
local vertexY = polygon[ii + 1]
|
|
local prevY = polygon[prevIndex + 1]
|
|
if (vertexY < y and prevY >= y) or (prevY < y and vertexY >= y) then
|
|
local vertexX = polygon[ii]
|
|
if vertexX + (y - vertexY) / (prevY - vertexY) * (polygon[prevIndex] - vertexX) < x then inside = not inside end
|
|
end
|
|
prevIndex = ii
|
|
end
|
|
return inside
|
|
end
|
|
|
|
function SkeletonBounds:polygonIntersectsSegment (polygon, x1, y1, x2, y2)
|
|
local nn = #polygon
|
|
local width12, height12 = x1 - x2, y1 - y2
|
|
local det1 = x1 * y2 - y1 * x2
|
|
local x3, y3 = polygon[nn - 2], polygon[nn - 1]
|
|
for ii = 1, nn, 2 do
|
|
local x4, y4 = polygon[ii], polygon[ii + 1]
|
|
local det2 = x3 * y4 - y3 * x4
|
|
local width34, height34 = x3 - x4, y3 - y4
|
|
local det3 = width12 * height34 - height12 * width34
|
|
local x = (det1 * width34 - width12 * det2) / det3
|
|
if ((x >= x3 and x <= x4) or (x >= x4 and x <= x3)) and ((x >= x1 and x <= x2) or (x >= x2 and x <= x1)) then
|
|
local y = (det1 * height34 - height12 * det2) / det3
|
|
if ((y >= y3 and y <= y4) or (y >= y4 and y <= y3)) and ((y >= y1 and y <= y2) or (y >= y2 and y <= y1)) then return true end
|
|
end
|
|
x3 = x4
|
|
y3 = y4
|
|
end
|
|
return false
|
|
end
|
|
|
|
function SkeletonBounds:getPolygon (attachment)
|
|
local index = spine.utils.indexOf(self.boundingBoxes, attachment)
|
|
if index == -1 then
|
|
return nil
|
|
else
|
|
return self.polygons[index]
|
|
end
|
|
end
|
|
|
|
function SkeletonBounds:getWidth()
|
|
return self.maxX - self.minX
|
|
end
|
|
|
|
function SkeletonBounds:getHeight()
|
|
return self.maxY - self.minY
|
|
end
|
|
|
|
return SkeletonBounds |