optimize method

dynamic optimize()

Implementation

optimize() {
  // times or values may be shared with other tracks, so overwriting is unsafe
  var times = AnimationUtils.arraySlice(this.times),
      values = AnimationUtils.arraySlice(this.values),
      stride = getValueSize(),
      smoothInterpolation = getInterpolation() == InterpolateSmooth,
      lastIndex = times.length - 1;

  var writeIndex = 1;

  for (var i = 1; i < lastIndex; ++i) {
    var keep = false;

    var time = times[i];
    var timeNext = times[i + 1];

    // remove adjacent keyframes scheduled at the same time

    if (time != timeNext && (i != 1 || time != times[0])) {
      if (!smoothInterpolation) {
        // remove unnecessary keyframes same as their neighbors

        var offset = i * stride, offsetP = offset - stride, offsetN = offset + stride;

        for (var j = 0; j != stride; ++j) {
          var value = values[offset + j];

          if (value != values[offsetP + j] || value != values[offsetN + j]) {
            keep = true;
            break;
          }
        }
      } else {
        keep = true;
      }
    }

    // in-place compaction

    if (keep) {
      if (i != writeIndex) {
        times[writeIndex] = times[i];

        var readOffset = i * stride, writeOffset = writeIndex * stride;

        for (var j = 0; j != stride; ++j) {
          values[writeOffset + j] = values[readOffset + j];
        }
      }

      ++writeIndex;
    }
  }

  // flush last keyframe (compaction looks ahead)

  if (lastIndex > 0) {
    times[writeIndex] = times[lastIndex];

    for (var readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j != stride; ++j) {
      values[writeOffset + j] = values[readOffset + j];
    }

    ++writeIndex;
  }

  if (writeIndex != times.length) {
    this.times = AnimationUtils.arraySlice(times, 0, writeIndex);
    this.values = AnimationUtils.arraySlice(values, 0, (writeIndex * stride).toInt());
  } else {
    this.times = times;
    this.values = values;
  }

  return this;
}