Эх сурвалжийг харах

[lua] Fix IkConstraintTimeline.ENTRIES. See #1383.

badlogic 6 жил өмнө
parent
commit
3411cfaf35

+ 22 - 10
spine-lua/Animation.lua

@@ -1181,21 +1181,23 @@ function Animation.DrawOrderTimeline.new (frameCount)
 end
 end
 
 
 Animation.IkConstraintTimeline = {}
 Animation.IkConstraintTimeline = {}
-Animation.IkConstraintTimeline.ENTRIES = 5
+Animation.IkConstraintTimeline.ENTRIES = 6
 function Animation.IkConstraintTimeline.new (frameCount)
 function Animation.IkConstraintTimeline.new (frameCount)
 	local ENTRIES = Animation.IkConstraintTimeline.ENTRIES
 	local ENTRIES = Animation.IkConstraintTimeline.ENTRIES
-	local PREV_TIME = -5
-	local PREV_MIX = -4
+	local PREV_TIME = -6
+	local PREV_MIX = -5
+  local PREV_SOFTNESS = -4
 	local PREV_BEND_DIRECTION = -3
 	local PREV_BEND_DIRECTION = -3
 	local PREV_COMPRESS = -2
 	local PREV_COMPRESS = -2
 	local PREV_STRETCH = -1
 	local PREV_STRETCH = -1
 	local MIX = 1
 	local MIX = 1
-	local BEND_DIRECTION = 2
-	local COMPRESS = 3
-	local STRETCH = 4
+  local SOFTNESS = 2
+	local BEND_DIRECTION = 3
+	local COMPRESS = 4
+	local STRETCH = 5
 
 
 	local self = Animation.CurveTimeline.new(frameCount)
 	local self = Animation.CurveTimeline.new(frameCount)
-	self.frames = utils.newNumberArrayZero(frameCount * ENTRIES) -- time, mix, bendDirection, compress, stretch, ...
+	self.frames = utils.newNumberArrayZero(frameCount * ENTRIES) -- time, mix, softness, bendDirection, compress, stretch, ...
 	self.ikConstraintIndex = -1
 	self.ikConstraintIndex = -1
 	self.type = TimelineType.ikConstraint
 	self.type = TimelineType.ikConstraint
 
 
@@ -1203,10 +1205,11 @@ function Animation.IkConstraintTimeline.new (frameCount)
 		return TimelineType.ikConstraint * SHL_24 + self.ikConstraintIndex
 		return TimelineType.ikConstraint * SHL_24 + self.ikConstraintIndex
 	end
 	end
 
 
-	function self:setFrame (frameIndex, time, mix, bendDirection, compress, stretch)
+	function self:setFrame (frameIndex, time, mix, softness, bendDirection, compress, stretch)
 		frameIndex = frameIndex * ENTRIES
 		frameIndex = frameIndex * ENTRIES
 		self.frames[frameIndex] = time
 		self.frames[frameIndex] = time
 		self.frames[frameIndex + MIX] = mix
 		self.frames[frameIndex + MIX] = mix
+    		self.frames[frameIndex + SOFTNESS] = softness
 		self.frames[frameIndex + BEND_DIRECTION] = bendDirection
 		self.frames[frameIndex + BEND_DIRECTION] = bendDirection
 		if (compress) then
 		if (compress) then
 			self.frames[frameIndex + COMPRESS] = 1
 			self.frames[frameIndex + COMPRESS] = 1
@@ -1228,11 +1231,13 @@ function Animation.IkConstraintTimeline.new (frameCount)
 		if time < frames[0] then
 		if time < frames[0] then
 			if blend == MixBlend.setup then
 			if blend == MixBlend.setup then
 				constraint.mix = constraint.data.mix
 				constraint.mix = constraint.data.mix
+        constraint.softness = constraint.data.softness
 				constraint.bendDirection = constraint.data.bendDirection
 				constraint.bendDirection = constraint.data.bendDirection
 				constraint.compress = constraint.data.compress
 				constraint.compress = constraint.data.compress
 				constraint.stretch = constraint.data.stretch
 				constraint.stretch = constraint.data.stretch
 			elseif blend == MixBlend.first then
 			elseif blend == MixBlend.first then
 				constraint.mix = constraint.mix + (constraint.data.mix - constraint.mix) * alpha
 				constraint.mix = constraint.mix + (constraint.data.mix - constraint.mix) * alpha
+        constraint.softness = constraint.softness + (constraint.data.softness - constraint.softness) * alpha
 				constraint.bendDirection = constraint.data.bendDirection
 				constraint.bendDirection = constraint.data.bendDirection
 				constraint.compress = constraint.data.compress
 				constraint.compress = constraint.data.compress
 				constraint.stretch = constraint.data.stretch
 				constraint.stretch = constraint.data.stretch
@@ -1243,6 +1248,8 @@ function Animation.IkConstraintTimeline.new (frameCount)
 		if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame.
 		if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame.
 			if blend == MixBlend.setup then
 			if blend == MixBlend.setup then
 				constraint.mix = constraint.data.mix + (frames[zlen(frames) + PREV_MIX] - constraint.data.mix) * alpha
 				constraint.mix = constraint.data.mix + (frames[zlen(frames) + PREV_MIX] - constraint.data.mix) * alpha
+        constraint.softness = constraint.data.softness
+						+ (frames[zlen(frames) + PREV_SOFTNESS] - constraint.data.softness) * alpha
 				if direction == MixDirection.out then
 				if direction == MixDirection.out then
 					constraint.bendDirection = constraint.data.bendDirection
 					constraint.bendDirection = constraint.data.bendDirection
 					constraint.compress = constraint.data.compress
 					constraint.compress = constraint.data.compress
@@ -1253,7 +1260,8 @@ function Animation.IkConstraintTimeline.new (frameCount)
 					if (math_floor(frames[zlen(frames) + PREV_STRETCH]) == 1) then constraint.stretch = true else constraint.stretch = false end
 					if (math_floor(frames[zlen(frames) + PREV_STRETCH]) == 1) then constraint.stretch = true else constraint.stretch = false end
 				end
 				end
 			else
 			else
-				constraint.mix = constraint.mix + (frames[zlen(frames) + PREV_MIX] - constraint.mix) * alpha;
+        constraint.mix = constraint.mix + (frames[zlen(frames) + PREV_MIX] - constraint.mix) * alpha
+        constraint.softness = constraint.softness + (frames[zlen(frames) + PREV_SOFTNESS] - constraint.softness) * alpha
 				if direction == MixDirection._in then
 				if direction == MixDirection._in then
 					constraint.bendDirection = math_floor(frames[zlen(frames) + PREV_BEND_DIRECTION])
 					constraint.bendDirection = math_floor(frames[zlen(frames) + PREV_BEND_DIRECTION])
 					if (math_floor(frames[zlen(frames) + PREV_COMPRESS]) == 1) then constraint.compress = true else constraint.compress = false end
 					if (math_floor(frames[zlen(frames) + PREV_COMPRESS]) == 1) then constraint.compress = true else constraint.compress = false end
@@ -1266,12 +1274,15 @@ function Animation.IkConstraintTimeline.new (frameCount)
 		-- Interpolate between the previous frame and the current frame.
 		-- Interpolate between the previous frame and the current frame.
 		local frame = binarySearch(frames, time, ENTRIES)
 		local frame = binarySearch(frames, time, ENTRIES)
 		local mix = frames[frame + PREV_MIX]
 		local mix = frames[frame + PREV_MIX]
+    local softness = frames[frame + PREV_SOFTNESS]
 		local frameTime = frames[frame]
 		local frameTime = frames[frame]
 		local percent = self:getCurvePercent(math.floor(frame / ENTRIES) - 1,
 		local percent = self:getCurvePercent(math.floor(frame / ENTRIES) - 1,
 				1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime))
 				1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime))
 
 
 		if blend == MixBlend.setup then
 		if blend == MixBlend.setup then
 			constraint.mix = constraint.data.mix + (mix + (frames[frame + MIX] - mix) * percent - constraint.data.mix) * alpha
 			constraint.mix = constraint.data.mix + (mix + (frames[frame + MIX] - mix) * percent - constraint.data.mix) * alpha
+      constraint.softness = constraint.data.softness
+					+ (softness + (frames[frame + SOFTNESS] - softness) * percent - constraint.data.softness) * alpha
 			if direction == MixDirection.out then
 			if direction == MixDirection.out then
 				constraint.bendDirection = constraint.data.bendDirection
 				constraint.bendDirection = constraint.data.bendDirection
 				constraint.compress = constraint.data.compress
 				constraint.compress = constraint.data.compress
@@ -1282,7 +1293,8 @@ function Animation.IkConstraintTimeline.new (frameCount)
 				if (math_floor(frames[frame + PREV_STRETCH]) == 1) then constraint.stretch = true else constraint.stretch = false end
 				if (math_floor(frames[frame + PREV_STRETCH]) == 1) then constraint.stretch = true else constraint.stretch = false end
 			end
 			end
 		else
 		else
-			constraint.mix = constraint.mix + (mix + (frames[frame + MIX] - mix) * percent - constraint.mix) * alpha;
+			constraint.mix = constraint.mix + (mix + (frames[frame + MIX] - mix) * percent - constraint.mix) * alpha
+      constraint.softness = constraint.softness + (softness + (frames[frame + SOFTNESS] - softness) * percent - constraint.softness) * alpha
 			if direction == MixDirection._in then
 			if direction == MixDirection._in then
 				constraint.bendDirection = math_floor(frames[frame + PREV_BEND_DIRECTION])
 				constraint.bendDirection = math_floor(frames[frame + PREV_BEND_DIRECTION])
 				if (math_floor(frames[frame + PREV_COMPRESS]) == 1) then constraint.compress = true else constraint.compress = false end
 				if (math_floor(frames[frame + PREV_COMPRESS]) == 1) then constraint.compress = true else constraint.compress = false end

+ 34 - 15
spine-lua/IkConstraint.lua

@@ -34,6 +34,7 @@ local math_sqrt = math.sqrt
 local math_acos = math.acos
 local math_acos = math.acos
 local math_sin = math.sin
 local math_sin = math.sin
 local math_cos = math.cos
 local math_cos = math.cos
+local math_min = math.min
 local table_insert = table.insert
 local table_insert = table.insert
 local math_deg = math.deg
 local math_deg = math.deg
 local math_rad = math.rad
 local math_rad = math.rad
@@ -51,6 +52,7 @@ function IkConstraint.new (data, skeleton)
 		bones = {},
 		bones = {},
 		target = nil,
 		target = nil,
 		mix = data.mix,
 		mix = data.mix,
+    softness = data.softness,
 		compress = data.compress,
 		compress = data.compress,
 		stretch = data.stretch,
 		stretch = data.stretch,
 		bendDirection = data.bendDirection,
 		bendDirection = data.bendDirection,
@@ -78,7 +80,7 @@ function IkConstraint:update ()
 	if boneCount == 1 then
 	if boneCount == 1 then
 		self:apply1(bones[1], target.worldX, target.worldY, self.compress, self.stretch, self.data.uniform, self.mix)
 		self:apply1(bones[1], target.worldX, target.worldY, self.compress, self.stretch, self.data.uniform, self.mix)
 	elseif boneCount == 2 then
 	elseif boneCount == 2 then
-		self:apply2(bones[1], bones[2], target.worldX, target.worldY, self.bendDirection, self.stretch, self.mix)
+		self:apply2(bones[1], bones[2], target.worldX, target.worldY, self.bendDirection, self.stretch, self.softness, self.mix)
 	end
 	end
 end
 end
 
 
@@ -111,7 +113,7 @@ function IkConstraint:apply1 (bone, targetX, targetY, compress, stretch, uniform
 	bone:updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, sy, bone.ashearX, bone.ashearY)
 	bone:updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, sy, bone.ashearX, bone.ashearY)
 end
 end
 
 
-function IkConstraint:apply2 (parent, child, targetX, targetY, bendDir, stretch, alpha)
+function IkConstraint:apply2 (parent, child, targetX, targetY, bendDir, stretch, softness, alpha)
 	if alpha == 0 then
 	if alpha == 0 then
 		child:updateWorldTransform()
 		child:updateWorldTransform()
 		return
 		return
@@ -169,19 +171,36 @@ function IkConstraint:apply2 (parent, child, targetX, targetY, bendDir, stretch,
 	c = pp.c
 	c = pp.c
 	d = pp.d
 	d = pp.d
 	local id = 1 / (a * d - b * c)
 	local id = 1 / (a * d - b * c)
-	local x = targetX - pp.worldX
-	local y = targetY - pp.worldY
-	local tx = (x * d - y * b) * id - px
-	local ty = (y * a - x * c) * id - py
-	local dd = tx * tx + ty * ty
-	x = cwx - pp.worldX
-	y = cwy - pp.worldY
-	local dx = (x * d - y * b) * id - px
-	local dy = (y * a - x * c) * id - py
-	local l1 = math_sqrt(dx * dx + dy * dy)
-	local l2 = child.data.length * csx
-	local a1 = 0
-	local a2 = 0
+  local x = cwx - pp.worldX
+  local y = cwy - pp.worldY
+  local dx = (x * d - y * b) * id - px
+  local dy = (y * a - x * c) * id - py
+  local l1 = math_sqrt(dx * dx + dy * dy)
+  local l2 = child.data.length * csx
+  local a1 = 0
+  local a2 = 0
+  if l1 < 0.0001 then
+    self:apply1(parent, targetX, targetY, false, stretch, false, alpha)
+    child:updateWorldTransformWith(cx, cy, 0, child.ascaleX, child.ascaleY, child.ashearX, child.ashearY)
+    return
+  end
+  x = targetX - pp.worldX
+  y = targetY - pp.worldY
+  local tx = (x * d - y * b) * id - px
+  local ty = (y * a - x * c) * id - py
+  local dd = tx * tx + ty * ty
+  if softness ~= 0 then
+    softness = softness * (psx * (csx + 1) / 2)
+    local td = math_sqrt(dd)
+    local sd = td - l1 - l2 * psx + softness
+    if sd > 0 then
+      local p = math_min(1, sd / (softness * 2)) - 1
+      p = (sd - softness * (1 - p * p)) / td
+      tx = tx - p * tx
+      ty = ty - p * ty
+      dd = tx * tx + ty * ty
+    end
+  end
 
 
 	if u then
 	if u then
 		l2 = l2 * psx
 		l2 = l2 * psx

+ 2 - 1
spine-lua/IkConstraintData.lua

@@ -41,7 +41,8 @@ function IkConstraintData.new (name)
 		compress = false,
 		compress = false,
 		stretch = false,
 		stretch = false,
 		uniform = false,
 		uniform = false,
-		mix = 1
+		mix = 1,
+    softness = 0
 	}
 	}
 
 
 	return self
 	return self

+ 1 - 0
spine-lua/Skeleton.lua

@@ -363,6 +363,7 @@ function Skeleton:setBonesToSetupPose ()
 
 
 	for _,ikConstraint in ipairs(self.ikConstraints) do
 	for _,ikConstraint in ipairs(self.ikConstraints) do
 		ikConstraint.mix = ikConstraint.data.mix
 		ikConstraint.mix = ikConstraint.data.mix
+    ikConstraint.softness = ikConstraint.data.softness
 		ikConstraint.bendDirection = ikConstraint.data.bendDirection
 		ikConstraint.bendDirection = ikConstraint.data.bendDirection
 		ikConstraint.compress = ikConstraint.data.compress
 		ikConstraint.compress = ikConstraint.data.compress
 		ikConstraint.stretch = ikConstraint.data.stretch
 		ikConstraint.stretch = ikConstraint.data.stretch

+ 4 - 1
spine-lua/SkeletonJson.lua

@@ -168,6 +168,7 @@ function SkeletonJson.new (attachmentLoader)
 				if not data.target then error("Target bone not found: " .. targetName) end
 				if not data.target then error("Target bone not found: " .. targetName) end
 
 
 				data.mix = getValue(constraintMap, "mix", 1)
 				data.mix = getValue(constraintMap, "mix", 1)
+        data.softness = getValue(constraintMap, "softness", 0)
 				if constraintMap["bendPositive"] == nil or constraintMap["bendPositive"] == true then
 				if constraintMap["bendPositive"] == nil or constraintMap["bendPositive"] == true then
           data.bendDirection = 1
           data.bendDirection = 1
         else
         else
@@ -637,14 +638,16 @@ function SkeletonJson.new (attachmentLoader)
 				local frameIndex = 0
 				local frameIndex = 0
 				for _,valueMap in ipairs(values) do
 				for _,valueMap in ipairs(values) do
 					local mix = 1
 					local mix = 1
+          local softness = 0
 					if valueMap["mix"] ~= nil then mix = valueMap["mix"] end
 					if valueMap["mix"] ~= nil then mix = valueMap["mix"] end
+          if valueMap["softness"] ~= nil then softness = valueMap["softness"] end
 					local bendPositive = 1
 					local bendPositive = 1
 					if valueMap["bendPositive"] == false then bendPositive = -1 end
 					if valueMap["bendPositive"] == false then bendPositive = -1 end
 					local stretch = false
 					local stretch = false
 					if valueMap["stretch"] ~= nil then stretch = valueMap["stretch"] end
 					if valueMap["stretch"] ~= nil then stretch = valueMap["stretch"] end
 					local compress = false
 					local compress = false
 					if valueMap["compress"] ~= nil then compress = valueMap["compress"] end
 					if valueMap["compress"] ~= nil then compress = valueMap["compress"] end
-					timeline:setFrame(frameIndex, getValue(valueMap, "time", 0), mix, bendPositive, compress, stretch)
+					timeline:setFrame(frameIndex, getValue(valueMap, "time", 0), mix, softness, bendPositive, compress, stretch)
 					readCurve(valueMap, timeline, frameIndex)
 					readCurve(valueMap, timeline, frameIndex)
 					frameIndex = frameIndex + 1
 					frameIndex = frameIndex + 1
 				end
 				end