computeAnimFromKeyframes function

NibAnim computeAnimFromKeyframes(
  1. List<NibKeyframe> keyframes,
  2. double t,
  3. Curve defaultCurve
)

Computes the NibAnim at progress t along keyframes.

keyframes is sorted by NibKeyframe.at first if it isn't already.

  • If t is at or before the first keyframe, returns its NibKeyframe.value directly.
  • If t is at or after the last keyframe, returns its NibKeyframe.value directly.
  • Otherwise, finds the two keyframes surrounding t, normalizes t into that segment, applies the upcoming keyframe's NibKeyframe.curve (or defaultCurve if unset), and interpolates between the two keyframes' values with NibAnim.lerp.

Implementation

NibAnim computeAnimFromKeyframes(
    List<NibKeyframe> keyframes, double t, Curve defaultCurve) {
  assert(keyframes.isNotEmpty, 'NibMotion.keyframes must not be empty.');

  var sorted = keyframes;
  for (var i = 1; i < sorted.length; i++) {
    if (sorted[i].at < sorted[i - 1].at) {
      sorted = List<NibKeyframe>.of(keyframes)
        ..sort((a, b) => a.at.compareTo(b.at));
      break;
    }
  }

  if (sorted.length == 1) return sorted.first.value;
  if (t <= sorted.first.at) return sorted.first.value;
  if (t >= sorted.last.at) return sorted.last.value;

  var lo = 0;
  var hi = sorted.length - 1;
  while (hi - lo > 1) {
    final mid = (lo + hi) >> 1;
    if (sorted[mid].at <= t) {
      lo = mid;
    } else {
      hi = mid;
    }
  }

  final from = sorted[lo];
  final to = sorted[hi];
  final segmentT = (t - from.at) / (to.at - from.at);
  final curvedT = (to.curve ?? defaultCurve).transform(segmentT);
  return from.value.lerp(to.value, curvedT);
}