Animation.fromFlatbuffer constructor

Animation.fromFlatbuffer(
  1. Animation animation,
  2. List<Node> sceneNodes
)

Builds an Animation from a deserialized flatbuffer animation description.

Channels with missing or malformed keyframe data are skipped with no error. Node references are resolved against sceneNodes to recover the target name for each channel's BindKey.

Implementation

factory Animation.fromFlatbuffer(
  fb.Animation animation,
  List<Node> sceneNodes,
) {
  List<AnimationChannel> channels = [];
  for (fb.Channel fbChannel in animation.channels!) {
    if (fbChannel.node < 0 ||
        fbChannel.node >= sceneNodes.length ||
        fbChannel.timeline == null) {
      continue;
    }

    final outTimes = fbChannel.timeline!;
    AnimationProperty outProperty;
    PropertyResolver resolver;

    // TODO(bdero): Why are the entries in the keyframe value arrays not
    //              contiguous in the flatbuffer? We should be able to get rid
    //              of the subloops below and just memcpy instead.
    switch (fbChannel.keyframesType) {
      case fb.KeyframesTypeId.TranslationKeyframes:
        outProperty = AnimationProperty.translation;
        fb.TranslationKeyframes? keyframes =
            fbChannel.keyframes as fb.TranslationKeyframes?;
        if (keyframes?.values == null) {
          continue;
        }
        List<Vector3> outValues = [];
        for (int i = 0; i < keyframes!.values!.length; i++) {
          outValues.add(keyframes.values![i].toVector3());
        }
        resolver = PropertyResolver.makeTranslationTimeline(
          outTimes,
          outValues,
        );
        break;
      case fb.KeyframesTypeId.RotationKeyframes:
        outProperty = AnimationProperty.rotation;
        fb.RotationKeyframes? keyframes =
            fbChannel.keyframes as fb.RotationKeyframes?;
        if (keyframes?.values == null) {
          continue;
        }
        List<Quaternion> outValues = [];
        for (int i = 0; i < keyframes!.values!.length; i++) {
          outValues.add(keyframes.values![i].toQuaternion());
        }
        resolver = PropertyResolver.makeRotationTimeline(outTimes, outValues);
        break;
      case fb.KeyframesTypeId.ScaleKeyframes:
        outProperty = AnimationProperty.scale;
        fb.ScaleKeyframes? keyframes =
            fbChannel.keyframes as fb.ScaleKeyframes?;
        if (keyframes?.values == null) {
          continue;
        }
        List<Vector3> outValues = [];
        for (int i = 0; i < keyframes!.values!.length; i++) {
          outValues.add(keyframes.values![i].toVector3());
        }
        resolver = PropertyResolver.makeScaleTimeline(outTimes, outValues);
        break;
      default:
        continue;
    }

    final bindKey = BindKey(
      nodeName: sceneNodes[fbChannel.node].name,
      property: outProperty,
    );
    channels.add(AnimationChannel(bindTarget: bindKey, resolver: resolver));
  }

  return Animation(name: animation.name!.toString(), channels: channels);
}