[lua][love] Two color tinting, one bug remaining, works otherwise.

This commit is contained in:
badlogic 2017-03-13 17:05:08 +01:00
parent 74e688d548
commit 8f923971ce
6 changed files with 403 additions and 61 deletions

View File

@ -0,0 +1,13 @@
TwoColorTest.png
size: 512,512
format: RGBA8888
filter: Linear,Linear
repeat: none
squareWithBorder
rotate: false
xy: 2, 2
size: 300, 300
orig: 300, 300
offset: 0, 0
index: -1

View File

@ -0,0 +1,150 @@
{
"skeleton": { "hash": "5Oji/z9A5lQ/crlH60repeTNBg8", "spine": "3.6.09-beta", "width": 1588, "height": 732, "images": "" },
"bones": [
{ "name": "root" },
{ "name": "singleColorTint", "parent": "root", "x": -400 },
{ "name": "singleColorTint2", "parent": "root", "x": -400, "y": -383 },
{ "name": "twoColorTint", "parent": "root", "x": 800 },
{ "name": "twoColorTint2", "parent": "root", "x": 800, "y": -382 },
{ "name": "twoColorTint (blackOnly)", "parent": "root" },
{ "name": "twoColorTint (blackOnly)2", "parent": "root", "y": -391 },
{ "name": "twoColorTint (colorOnly)", "parent": "root", "x": 400 },
{ "name": "twoColorTint (colorOnly)2", "parent": "root", "x": 400, "y": -382 }
],
"slots": [
{ "name": "squareWithBorder", "bone": "singleColorTint", "attachment": "squareWithBorder" },
{ "name": "squareWithBorder7", "bone": "singleColorTint2", "attachment": "squareWithBorder" },
{ "name": "squareWithBorder2", "bone": "twoColorTint (blackOnly)", "dark": "000000", "attachment": "squareWithBorder" },
{ "name": "squareWithBorder8", "bone": "twoColorTint (blackOnly)2", "dark": "000000", "attachment": "squareWithBorder" },
{ "name": "squareWithBorder4", "bone": "twoColorTint (colorOnly)", "dark": "000000", "attachment": "squareWithBorder" },
{ "name": "squareWithBorder5", "bone": "twoColorTint (colorOnly)2", "dark": "000000", "attachment": "squareWithBorder" },
{ "name": "squareWithBorder3", "bone": "twoColorTint", "dark": "000000", "attachment": "squareWithBorder" },
{ "name": "squareWithBorder6", "bone": "twoColorTint2", "dark": "000000", "attachment": "squareWithBorder" }
],
"skins": {
"default": {
"squareWithBorder": {
"squareWithBorder": { "width": 300, "height": 300 }
},
"squareWithBorder2": {
"squareWithBorder": { "width": 300, "height": 300 }
},
"squareWithBorder3": {
"squareWithBorder": { "width": 300, "height": 300 }
},
"squareWithBorder4": {
"squareWithBorder": { "width": 300, "height": 300 }
},
"squareWithBorder5": {
"squareWithBorder": {
"type": "mesh",
"uvs": [ 1, 1, 0, 1, 0, 0, 1, 0 ],
"triangles": [ 1, 2, 3, 1, 3, 0 ],
"vertices": [ 150, -150, -150, -150, -197, 99, 183, 155 ],
"hull": 4,
"edges": [ 0, 2, 2, 4, 4, 6, 0, 6 ],
"width": 300,
"height": 300
}
},
"squareWithBorder6": {
"squareWithBorder": {
"type": "mesh",
"uvs": [ 1, 1, 0, 1, 0, 0, 1, 0 ],
"triangles": [ 1, 2, 3, 1, 3, 0 ],
"vertices": [ 238, -200, -191, -60, -150, 150, 119, 111 ],
"hull": 4,
"edges": [ 0, 2, 2, 4, 4, 6, 0, 6 ],
"width": 300,
"height": 300
}
},
"squareWithBorder7": {
"squareWithBorder": {
"type": "mesh",
"uvs": [ 1, 1, 0, 1, 0, 0, 1, 0 ],
"triangles": [ 1, 2, 3, 1, 3, 0 ],
"vertices": [ 210, -132, -150, -150, -150, 150, 124, 119 ],
"hull": 4,
"edges": [ 0, 2, 2, 4, 4, 6, 0, 6 ],
"width": 300,
"height": 300
}
},
"squareWithBorder8": {
"squareWithBorder": {
"type": "mesh",
"uvs": [ 1, 1, 0, 1, 0, 0, 1, 0 ],
"triangles": [ 1, 2, 3, 1, 3, 0 ],
"vertices": [ 150, -150, -150, -150, -97, 58, 86, 62 ],
"hull": 4,
"edges": [ 0, 2, 2, 4, 4, 6, 0, 6 ],
"width": 300,
"height": 300
}
}
}
},
"animations": {
"animation": {
"slots": {
"squareWithBorder": {
"color": [
{ "time": 0, "color": "fffffffe" },
{ "time": 1, "color": "9e17b3fe" },
{ "time": 2, "color": "fffffffe" }
]
},
"squareWithBorder2": {
"twoColor": [
{ "time": 0, "light": "fffffffe", "dark": "000000" },
{ "time": 1, "light": "fffffffe", "dark": "ff0000" },
{ "time": 2, "light": "fffffffe", "dark": "000000" }
]
},
"squareWithBorder3": {
"twoColor": [
{ "time": 0, "light": "fffffffe", "dark": "000000" },
{ "time": 1, "light": "80ff00fe", "dark": "001cff" },
{ "time": 2, "light": "fffffffe", "dark": "000000" }
]
},
"squareWithBorder4": {
"twoColor": [
{ "time": 0, "light": "fffffffe", "dark": "000000" },
{ "time": 1, "light": "ffd300fe", "dark": "000000" },
{ "time": 2, "light": "fffffffe", "dark": "000000" }
]
},
"squareWithBorder5": {
"twoColor": [
{ "time": 0, "light": "fffffffe", "dark": "000000" },
{ "time": 1, "light": "ffd300fe", "dark": "000000" },
{ "time": 2, "light": "fffffffe", "dark": "000000" }
]
},
"squareWithBorder6": {
"twoColor": [
{ "time": 0, "light": "fffffffe", "dark": "000000" },
{ "time": 1, "light": "80ff00fe", "dark": "001cff" },
{ "time": 2, "light": "fffffffe", "dark": "000000" }
]
},
"squareWithBorder7": {
"color": [
{ "time": 0, "color": "fffffffe" },
{ "time": 1, "color": "9e17b3fe" },
{ "time": 2, "color": "fffffffe" }
]
},
"squareWithBorder8": {
"twoColor": [
{ "time": 0, "light": "fffffffe", "dark": "000000" },
{ "time": 1, "light": "fffffffe", "dark": "ff0000" },
{ "time": 2, "light": "fffffffe", "dark": "000000" }
]
}
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

View File

@ -82,14 +82,15 @@ end
function love.load(arg) function love.load(arg)
if arg[#arg] == "-debug" then require("mobdebug").start() end if arg[#arg] == "-debug" then require("mobdebug").start() end
table.insert(skeletons, loadSkeleton("test", "test", "animation", nil, 0.5, 400, 300)) --table.insert(skeletons, loadSkeleton("test", "test", "animation", nil, 0.5, 400, 300))
table.insert(skeletons, loadSkeleton("spineboy", "spineboy", "walk", nil, 0.5, 400, 500)) table.insert(skeletons, loadSkeleton("TwoColorTest", "TwoColorTest", "animation", nil, 0.3, 400, 300))
--[[table.insert(skeletons, loadSkeleton("spineboy", "spineboy", "walk", nil, 0.5, 400, 500))
table.insert(skeletons, loadSkeleton("raptor", "raptor", "walk", nil, 0.3, 400, 500)) table.insert(skeletons, loadSkeleton("raptor", "raptor", "walk", nil, 0.3, 400, 500))
table.insert(skeletons, loadSkeleton("goblins-mesh", "goblins", "walk", "goblin", 1, 400, 500)) table.insert(skeletons, loadSkeleton("goblins-mesh", "goblins", "walk", "goblin", 1, 400, 500))
table.insert(skeletons, loadSkeleton("tank", "tank", "drive", nil, 0.2, 600, 500)) table.insert(skeletons, loadSkeleton("tank", "tank", "drive", nil, 0.2, 600, 500))
table.insert(skeletons, loadSkeleton("vine", "vine", "animation", nil, 0.3, 400, 500)) table.insert(skeletons, loadSkeleton("vine", "vine", "animation", nil, 0.3, 400, 500))
table.insert(skeletons, loadSkeleton("stretchyman", "stretchyman", "sneak", nil, 0.3, 200, 500)) table.insert(skeletons, loadSkeleton("stretchyman", "stretchyman", "sneak", nil, 0.3, 200, 500))]]
skeletonRenderer = spine.SkeletonRenderer.new() skeletonRenderer = spine.SkeletonRenderer.new(true)
end end
function love.update (delta) function love.update (delta)

View File

@ -79,9 +79,53 @@ end
local PolygonBatcher = {} local PolygonBatcher = {}
PolygonBatcher.__index = PolygonBatcher PolygonBatcher.__index = PolygonBatcher
function PolygonBatcher.new(vertexCount) function PolygonBatcher.new(vertexCount, useTwoColorTint)
if useTwoColorTint == nil then useTwoColorTint = false end
local vertexFormat
local twoColorTintShader = nil
if useTwoColorTint then
vertexFormat = {
{"VertexPosition", "float", 2}, -- The x,y position of each vertex.
{"VertexTexCoord", "float", 2}, -- The u,v texture coordinates of each vertex.
{"VertexColor", "byte", 4}, -- The r,g,b,a light color of each vertex.
{"VertexColor2", "byte", 4} -- The r,g,b,a dark color of each vertex.
}
local vertexcode = [[
attribute vec4 VertexColor2;
varying vec4 color2;
vec4 position(mat4 transform_projection, vec4 vertex_position) {
color2 = VertexColor2;
return transform_projection * vertex_position;
}
]]
local pixelcode = [[
varying vec4 color2;
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) {
vec4 texColor = Texel(texture, texture_coords);
float alpha = texColor.a * color.a;
vec4 outputColor;
outputColor.a = alpha;
outputColor.rgb = (1.0 - texColor.rgb) * color2.rgb * alpha + texColor.rgb * color.rgb;
return outputColor;
}
]]
twoColorTintShader = love.graphics.newShader(pixelcode, vertexcode)
else
vertexFormat = {
{"VertexPosition", "float", 2}, -- The x,y position of each vertex.
{"VertexTexCoord", "float", 2}, -- The u,v texture coordinates of each vertex.
{"VertexColor", "byte", 4} -- The r,g,b,a light color of each vertex.
}
end
local self = { local self = {
mesh = love.graphics.newMesh(vertexCount, "triangles", "dynamic"), mesh = love.graphics.newMesh(vertexFormat, vertexCount, "triangles", "dynamic"),
maxVerticesLength = vertexCount, maxVerticesLength = vertexCount,
maxIndicesLength = vertexCount * 3, maxIndicesLength = vertexCount * 3,
verticesLength = 0, verticesLength = 0,
@ -90,7 +134,9 @@ function PolygonBatcher.new(vertexCount)
isDrawing = false, isDrawing = false,
drawCalls = 0, drawCalls = 0,
vertex = { 0, 0, 0, 0, 0, 0, 0, 0 }, vertex = { 0, 0, 0, 0, 0, 0, 0, 0 },
indices = nil indices = nil,
useTwoColorTint = useTwoColorTint,
twoColorTintShader = twoColorTintShader
} }
local indices = {} local indices = {}
@ -142,6 +188,7 @@ function PolygonBatcher:draw (texture, vertices, numVertices, indices)
local vertexStart = self.verticesLength + 1 local vertexStart = self.verticesLength + 1
local vertexEnd = vertexStart + numVertices local vertexEnd = vertexStart + numVertices
local vertex = self.vertex local vertex = self.vertex
if not self.useTwoColorTint then
while vertexStart < vertexEnd do while vertexStart < vertexEnd do
vertex[1] = vertices[i] vertex[1] = vertices[i]
vertex[2] = vertices[i+1] vertex[2] = vertices[i+1]
@ -155,6 +202,25 @@ function PolygonBatcher:draw (texture, vertices, numVertices, indices)
vertexStart = vertexStart + 1 vertexStart = vertexStart + 1
i = i + 8 i = i + 8
end end
else
while vertexStart < vertexEnd do
vertex[1] = vertices[i]
vertex[2] = vertices[i+1]
vertex[3] = vertices[i+2]
vertex[4] = vertices[i+3]
vertex[5] = vertices[i+4] * 255
vertex[6] = vertices[i+5] * 255
vertex[7] = vertices[i+6] * 255
vertex[8] = vertices[i+7] * 255
vertex[9] = vertices[i+8] * 255
vertex[10] = vertices[i+9] * 255
vertex[11] = vertices[i+10] * 255
vertex[12] = vertices[i+11] * 255
mesh:setVertex(vertexStart, vertex)
vertexStart = vertexStart + 1
i = i + 12
end
end
self.verticesLength = self.verticesLength + numVertices self.verticesLength = self.verticesLength + numVertices
end end
@ -163,7 +229,13 @@ function PolygonBatcher:flush ()
local mesh = self.mesh local mesh = self.mesh
mesh:setVertexMap(self.indices) mesh:setVertexMap(self.indices)
mesh:setDrawRange(1, self.indicesLength) mesh:setDrawRange(1, self.indicesLength)
if not self.useTwoColorTint then
love.graphics.draw(mesh, 0, 0) love.graphics.draw(mesh, 0, 0)
else
love.graphics.setShader(self.twoColorTintShader)
love.graphics.draw(mesh, 0, 0)
love.graphics.setShader()
end
self.verticesLength = 0 self.verticesLength = 0
self.indicesLength = 0 self.indicesLength = 0
@ -182,17 +254,19 @@ local SkeletonRenderer = {}
SkeletonRenderer.__index = SkeletonRenderer SkeletonRenderer.__index = SkeletonRenderer
SkeletonRenderer.QUAD_TRIANGLES = { 1, 2, 3, 3, 4, 1 } SkeletonRenderer.QUAD_TRIANGLES = { 1, 2, 3, 3, 4, 1 }
function SkeletonRenderer.new () function SkeletonRenderer.new (useTwoColorTint)
if not useTwoColorTint then useTwoColorTint = false end
local self = { local self = {
batcher = PolygonBatcher.new(3 * 500), batcher = PolygonBatcher.new(3 * 500, useTwoColorTint),
premultipliedAlpha = false premultipliedAlpha = false,
useTwoColorTint = useTwoColorTint
} }
setmetatable(self, SkeletonRenderer) setmetatable(self, SkeletonRenderer)
return self return self
end end
local worldVertices = spine.utils.newNumberArray(10000 * 8) local worldVertices = spine.utils.newNumberArray(10000 * 12)
local tmpColor = spine.Color.newWith(0, 0, 0, 0) local tmpColor = spine.Color.newWith(0, 0, 0, 0)
function SkeletonRenderer:draw (skeleton) function SkeletonRenderer:draw (skeleton)
@ -249,6 +323,8 @@ function SkeletonRenderer:draw (skeleton)
love.graphics.setBlendMode(lastLoveBlendMode) love.graphics.setBlendMode(lastLoveBlendMode)
end end
local tmpColor2 = spine.Color.new()
function SkeletonRenderer:computeRegionVertices(slot, region, pma, color) function SkeletonRenderer:computeRegionVertices(slot, region, pma, color)
local skeleton = slot.bone.skeleton local skeleton = slot.bone.skeleton
local skeletonColor = skeleton.color local skeletonColor = skeleton.color
@ -262,11 +338,19 @@ function SkeletonRenderer:computeRegionVertices(slot, region, pma, color)
skeletonColor.b * slotColor.b * regionColor.b * multiplier, skeletonColor.b * slotColor.b * regionColor.b * multiplier,
alpha) alpha)
local dark = tmpColor
if slot.darkColor then dark = slot.darkColor end
local vertices = worldVertices local vertices = worldVertices
if not self.useTwoColorTint then
region:computeWorldVertices(slot.bone, vertices, 0, 8) region:computeWorldVertices(slot.bone, vertices, 0, 8)
else
region:computeWorldVertices(slot.bone, vertices, 0, 12)
end
local uvs = region.uvs local uvs = region.uvs
if not self.useTwoColorTint then
vertices[3] = uvs[1] vertices[3] = uvs[1]
vertices[4] = uvs[2] vertices[4] = uvs[2]
vertices[5] = color.r vertices[5] = color.r
@ -294,6 +378,51 @@ function SkeletonRenderer:computeRegionVertices(slot, region, pma, color)
vertices[30] = color.g vertices[30] = color.g
vertices[31] = color.b vertices[31] = color.b
vertices[32] = color.a vertices[32] = color.a
else
vertices[3] = uvs[1]
vertices[4] = uvs[2]
vertices[5] = color.r
vertices[6] = color.g
vertices[7] = color.b
vertices[8] = color.a
vertices[9] = dark.r
vertices[10] = dark.g
vertices[11] = dark.b
vertices[12] = 0
vertices[15] = uvs[3]
vertices[16] = uvs[4]
vertices[17] = color.r
vertices[18] = color.g
vertices[19] = color.b
vertices[20] = color.a
vertices[21] = dark.r
vertices[22] = dark.g
vertices[23] = dark.b
vertices[24] = 0
vertices[27] = uvs[5]
vertices[28] = uvs[6]
vertices[29] = color.r
vertices[30] = color.g
vertices[31] = color.b
vertices[32] = color.a
vertices[33] = dark.r
vertices[34] = dark.g
vertices[35] = dark.b
vertices[36] = 0
vertices[39] = uvs[7]
vertices[40] = uvs[8]
vertices[41] = color.r
vertices[42] = color.g
vertices[43] = color.b
vertices[44] = color.a
vertices[45] = dark.r
vertices[46] = dark.g
vertices[47] = dark.b
vertices[48] = 0
end
return vertices return vertices
end end
@ -313,13 +442,22 @@ function SkeletonRenderer:computeMeshVertices(slot, mesh, pma, color)
local numVertices = mesh.worldVerticesLength / 2 local numVertices = mesh.worldVerticesLength / 2
local vertices = worldVertices local vertices = worldVertices
local dark = tmpColor
if slot.darkColor then dark = slot.darkColor end
if not self.useTwoColorTint then
mesh:computeWorldVertices(slot, 0, mesh.worldVerticesLength, vertices, 0, 8) mesh:computeWorldVertices(slot, 0, mesh.worldVerticesLength, vertices, 0, 8)
else
mesh:computeWorldVertices(slot, 0, mesh.worldVerticesLength, vertices, 0, 12)
end
local uvs = mesh.uvs local uvs = mesh.uvs
local i = 1 local i = 1
local n = numVertices + 1 local n = numVertices + 1
local u = 1 local u = 1
local v = 3 local v = 3
if not self.useTwoColorTint then
while i < n do while i < n do
vertices[v] = uvs[u] vertices[v] = uvs[u]
vertices[v + 1] = uvs[u + 1] vertices[v + 1] = uvs[u + 1]
@ -331,6 +469,23 @@ function SkeletonRenderer:computeMeshVertices(slot, mesh, pma, color)
u = u + 2 u = u + 2
v = v + 8 v = v + 8
end end
else
while i < n do
vertices[v] = uvs[u]
vertices[v + 1] = uvs[u + 1]
vertices[v + 2] = color.r
vertices[v + 3] = color.g
vertices[v + 4] = color.b
vertices[v + 5] = color.a
vertices[v + 6] = dark.r
vertices[v + 7] = dark.g
vertices[v + 8] = dark.b
vertices[v + 9] = 0
i = i + 1
u = u + 2
v = v + 12
end
end
return vertices return vertices
end end

View File

@ -47,6 +47,7 @@ local AttachmentType = require "spine-lua.attachments.AttachmentType"
local BlendMode = require "spine-lua.BlendMode" local BlendMode = require "spine-lua.BlendMode"
local TransformMode = require "spine-lua.TransformMode" local TransformMode = require "spine-lua.TransformMode"
local utils = require "spine-lua.utils" local utils = require "spine-lua.utils"
local Color = require "spine-lua.Color"
local SkeletonJson = {} local SkeletonJson = {}
function SkeletonJson.new (attachmentLoader) function SkeletonJson.new (attachmentLoader)
@ -137,7 +138,7 @@ function SkeletonJson.new (attachmentLoader)
data.darkColor:set(tonumber(dark:sub(1, 2), 16) / 255, data.darkColor:set(tonumber(dark:sub(1, 2), 16) / 255,
tonumber(dark:sub(3, 4), 16) / 255, tonumber(dark:sub(3, 4), 16) / 255,
tonumber(dark:sub(5, 6), 16) / 255, tonumber(dark:sub(5, 6), 16) / 255,
tonumber(dark:sub(7, 8), 16) / 255) 0)
end end
data.attachmentName = getValue(slotMap, "attachment", nil) data.attachmentName = getValue(slotMap, "attachment", nil)
@ -480,7 +481,29 @@ function SkeletonJson.new (attachmentLoader)
end end
table_insert(timelines, timeline) table_insert(timelines, timeline)
duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.ColorTimeline.ENTRIES]) 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 i,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 elseif timelineName == "attachment" then
local timeline = Animation.AttachmentTimeline.new(#values) local timeline = Animation.AttachmentTimeline.new(#values)
timeline.slotIndex = slotIndex timeline.slotIndex = slotIndex