void MatrixAnimFromFlatBuffers(const MatrixAnimFb& params, MatrixAnim* anim) { MatrixOpArray& ops = anim->ops(); ops.Clear(params.ops()->size()); // Count the number of splines. int num_splines = 0; for (auto op = params.ops()->begin(); op != params.ops()->end(); ++op) { if (op->value_type() == MatrixOpValueFb_CompactSplineFb) num_splines++; } // Initialize the output structure with the correct number of splines. MatrixAnim::Spline* splines = anim->Construct(num_splines); // Loop through each op, adding to the MatrixAnim ops. int spline_idx = 0; for (auto op = params.ops()->begin(); op != params.ops()->end(); ++op) { const MatrixOperationType op_type = static_cast<MatrixOperationType>(op->type()); switch (op->value_type()) { case MatrixOpValueFb_CompactSplineFb: { const CompactSplineFb* spline_fb = reinterpret_cast<const CompactSplineFb*>(op->value()); MatrixAnim::Spline& s = splines[spline_idx++]; // Copy the spline data into s.spline. // TODO: modify CompactSpline so we can just point at spline data // instead of copying it. const Range y_range(spline_fb->y_range_start(), spline_fb->y_range_end()); s.spline.Init(y_range, spline_fb->x_granularity(), spline_fb->nodes()->size()); for (auto n = spline_fb->nodes()->begin(); n != spline_fb->nodes()->end(); ++n) { s.spline.AddNodeVerbatim(n->x(), n->y(), n->angle()); } // Hold `init` and `playback` data in structures that won't disappear, // since these are referenced by pointer. const bool modular = ModularOp(op_type); const Range& op_range = RangeOfOp(op_type, y_range); s.init = SmoothInit(op_range, modular); ops.AddOp(op_type, s.init, s.spline); break; } case MatrixOpValueFb_ConstantOpFb: { const ConstantOpFb* const_fb = reinterpret_cast<const ConstantOpFb*>(op->value()); ops.AddOp(op_type, const_fb->y_const()); break; } default: assert(false); // Invalid FlatBuffer data. } } }
static void CreateDefiningAnim(const RigAnim** anims, size_t num_anims, RigAnim* defining_anim) { // This function only works for animations that follow the canonical order. for (size_t i = 0; i < num_anims; ++i) { assert(IsCanonicalAnim(*anims[i])); } // Get the bone hierarchy that covers all the hierarchies in `anims`. const RigAnim* complete_rig = FindCompleteRig(anims, num_anims); const BoneIndex num_bones = complete_rig->NumBones(); const BoneIndex* parents = complete_rig->bone_parents(); defining_anim->Init("defining_anim", num_bones, true); // For each bone, consider adding each operation in the canonical operations. for (BoneIndex j = 0; j < num_bones; ++j) { // Start initializing this bone. MatrixAnim& matrix_anim = defining_anim->InitMatrixAnim(j, parents[j], complete_rig->BoneName(j)); MatrixOpArray& ops = matrix_anim.ops(); // Loop through all possible operations for this bone. Range ranges[MOTIVE_ARRAY_SIZE(kCanonicalRigAnimOps)]; for (size_t k = 0; k < MOTIVE_ARRAY_SIZE(kCanonicalRigAnimOps); ++k) { const MatrixOperationType op = kCanonicalRigAnimOps[k]; // Loop over all anims, checking to see if they have this operation. for (size_t i = 0; i < num_anims; ++i) { if (j >= anims[i]->NumBones()) continue; const MatrixOpArray::OpVector& opv = anims[i]->Anim(j).ops().ops(); const MatrixOperationInit* op_init = FindOpInit(opv, op); if (op_init == nullptr) continue; if (op_init->init == nullptr) { ranges[k] = ranges[k].Include(op_init->initial_value); } else { const SplineInit* spline_init = static_cast<const SplineInit*>(op_init->init); ranges[k] = Range::Union(ranges[k], spline_init->range()); } } } // Count the number of ranges that need init parameters. int num_ops_with_init = 0; for (size_t k = 0; k < MOTIVE_ARRAY_SIZE(kCanonicalRigAnimOps); ++k) { if (ranges[k].Valid() && ranges[k].Length() > 0.0f) num_ops_with_init++; } MatrixAnim::Spline* splines = matrix_anim.Construct(num_ops_with_init); // Create the array of matrix operations. int num_ops_inited = 0; for (size_t k = 0; k < MOTIVE_ARRAY_SIZE(kCanonicalRigAnimOps); ++k) { if (!ranges[k].Valid()) continue; // If this operation exists, add it to the `defining_anim`. const MatrixOperationType op = kCanonicalRigAnimOps[k]; if (ranges[k].Length() == 0.0f) { // If there is only one value for an operation, add it as a const. const float const_value = ranges[k].start(); ops.AddOp(op, const_value); } else { // Otherwise, add it as an animated parameter. // The range is modular for rotate operations, but not for scale or // translate operations. const bool modular = ModularOp(op); const Range& op_range = RangeOfOp(op, ranges[k]); splines[num_ops_inited].init = SplineInit(op_range, modular); ops.AddOp(op, splines[num_ops_inited].init); num_ops_inited++; } } } }