commonMain.ru.casperix.spine.animation.Curve.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 kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import ru.casperix.math.BezierCalculation
import ru.casperix.math.curve.float32.BezierCubic2f
import ru.casperix.math.vector.float32.Vector2f
import ru.casperix.misc.ceilToInt
import ru.casperix.spine.json.CurveSerializer
import kotlin.math.roundToInt
@Serializable(with = CurveSerializer::class)
interface Curve
@Serializable
object LinearCurve : Curve
@Serializable
object SteppedCurve : Curve
@Serializable
object UnknownCurve : Curve
@Serializable
class BezierCurve(val v1: Vector2f, val v2: Vector2f) : Curve {
companion object {
private val INITIAL_ERROR = 0.001f
private val STEPS = 128
}
@Transient
private var cache: BezierCurveCache? = null
fun getValue(lastFrame: ChannelFrame, nextFrame: ChannelFrame, currentTime: Float): Float {
getOrBuildCache(lastFrame, nextFrame).run {
val startTime = lastFrame.time
val finishTime = nextFrame.time
val pointIndex = ((STEPS - 1).toFloat() * (currentTime - startTime) / (finishTime - startTime)).ceilToInt().coerceIn(0..points.lastIndex)
val next = points[pointIndex]
return if (pointIndex == 0) {
next.y
} else {
val last = points[pointIndex - 1]
(currentTime - last.x) / (next.x - last.x) * (next.y - last.y) + last.y
}
}
}
private fun getOrBuildCache(lastFrame: ChannelFrame, nextFrame: ChannelFrame): BezierCurveCache {
if (cache == null) {
val curve = BezierCubic2f(
Vector2f(lastFrame.time, lastFrame.value),
v1,
v2,
Vector2f(nextFrame.time, nextFrame.value),
)
val startTime = lastFrame.time
val finishTime = nextFrame.time
val points = (0..STEPS).map { step ->
val t = step / STEPS.toFloat()
val time = startTime + t * (finishTime - startTime)
val value = BezierCalculation.getApproximateErrorHeightPrecision(curve, time, INITIAL_ERROR)
Vector2f(time, value)
}
cache = BezierCurveCache(
curve, points
)
}
return cache!!
}
class BezierCurveCache(val curve: BezierCubic2f, val points: List)
}