commonMain.ru.casperix.spine.animation.FrameCalculator.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of spine-jvm Show documentation
Show all versions of spine-jvm Show documentation
Signals for all occasions
package ru.casperix.spine.animation
import ru.casperix.math.curve.float32.BezierCubic2f
import ru.casperix.math.interpolation.float32.linearInterpolatef
import ru.casperix.math.vector.float32.Vector2f
import ru.casperix.math.BezierCalculation
import ru.casperix.spine.MixBlend
import ru.casperix.spine.json.component.BezierCurve
import ru.casperix.spine.json.component.LinearCurve
object FrameCalculator {
fun getRelativeValue(
frames: List,
time: Float,
weight: Float,
blend: MixBlend,
currentValue: Float,
poseValue: Float,
scaleMode: Boolean
): Float {
frames.forEachIndexed { index, nextFrame ->
if (time >= nextFrame.time) return@forEachIndexed
val isFirstFrame = index == 0 || time == 0f
if (isFirstFrame) {
return when (blend) {
MixBlend.setup -> poseValue
MixBlend.first -> currentValue + (poseValue - currentValue) * weight
else -> currentValue
}
} else {
val lastFrame = frames[index - 1]
val timeFactor = (time - lastFrame.time) / (nextFrame.time - lastFrame.time)
val type = lastFrame.curve
val summaryValue = if (type is BezierCurve) {
//bezier
val curve = BezierCubic2f(
Vector2f(lastFrame.time, lastFrame.value),
type.v1,
type.v2,
Vector2f(nextFrame.time, nextFrame.value),
)
//TODO: can optimize speed & precision
BezierCalculation.getApproximateErrorHeightPrecision(curve, time, 0.01f)
} else if (type is LinearCurve) {
val lastValue = lastFrame.value
val nextValue = nextFrame.value
linearInterpolatef(lastValue, nextValue, timeFactor)
} else {
// TODO: correct interpolation for non-linear
return currentValue
}
if (scaleMode) {
return when (blend) {
MixBlend.setup -> poseValue + (summaryValue - poseValue) * weight
MixBlend.first, MixBlend.replace -> currentValue + (summaryValue - currentValue) * weight
MixBlend.add -> currentValue + summaryValue * weight
}
} else {
return when (blend) {
MixBlend.setup -> poseValue + summaryValue * weight
MixBlend.first, MixBlend.replace -> currentValue + (summaryValue + poseValue - currentValue) * weight
MixBlend.add -> currentValue + summaryValue * weight
}
}
}
}
return currentValue
}
}