/* Evaluates the curves between each selected keyframe on each frame, and keys the value */ void sample_fcurve (FCurve *fcu) { BezTriple *bezt, *start=NULL, *end=NULL; tempFrameValCache *value_cache, *fp; int sfra, range; int i, n, nIndex; /* find selected keyframes... once pair has been found, add keyframes */ for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) { /* check if selected, and which end this is */ if (BEZSELECTED(bezt)) { if (start) { /* set end */ end= bezt; /* cache values then add keyframes using these values, as adding * keyframes while sampling will affect the outcome... * - only start sampling+adding from index=1, so that we don't overwrite original keyframe */ range= (int)( ceil(end->vec[1][0] - start->vec[1][0]) ); sfra= (int)( floor(start->vec[1][0]) ); if (range) { value_cache= MEM_callocN(sizeof(tempFrameValCache)*range, "IcuFrameValCache"); /* sample values */ for (n=1, fp=value_cache; n<range && fp; n++, fp++) { fp->frame= (float)(sfra + n); fp->val= evaluate_fcurve(fcu, fp->frame); } /* add keyframes with these, tagging as 'breakdowns' */ for (n=1, fp=value_cache; n<range && fp; n++, fp++) { nIndex= insert_vert_fcurve(fcu, fp->frame, fp->val, 1); BEZKEYTYPE(fcu->bezt + nIndex)= BEZT_KEYTYPE_BREAKDOWN; } /* free temp cache */ MEM_freeN(value_cache); /* as we added keyframes, we need to compensate so that bezt is at the right place */ bezt = fcu->bezt + i + range - 1; i += (range - 1); } /* bezt was selected, so it now marks the start of a whole new chain to search */ start= bezt; end= NULL; } else { /* just set start keyframe */ start= bezt; end= NULL; } } } /* recalculate channel's handles? */ calchandles_fcurve(fcu); }
/* Add the given BezTriple to the given 'list' of Keyframes */ static void add_bezt_to_keycolumns_list(DLRBT_Tree *keys, BezTriple *bezt) { ActKeyColumn *new_ak=NULL; if ELEM(NULL, keys, bezt) return; /* if there are no keys already, just add as root */ if (keys->root == NULL) { /* just add this as the root, then call the tree-balancing functions to validate */ new_ak= bezt_to_new_actkeycolumn(bezt); keys->root= (DLRBT_Node *)new_ak; } else { ActKeyColumn *ak, *akp=NULL, *akn=NULL; /* traverse tree to find an existing entry to update the status of, * or a suitable point to add at */ for (ak= keys->root; ak; akp= ak, ak= akn) { /* check if this is a match, or whether we go left or right */ if (ak->cfra == bezt->vec[1][0]) { /* set selection status and 'touched' status */ if (BEZSELECTED(bezt)) ak->sel = SELECT; ak->modified += 1; /* for keyframe type, 'proper' keyframes have priority over breakdowns (and other types for now) */ if (BEZKEYTYPE(bezt) == BEZT_KEYTYPE_KEYFRAME) ak->key_type= BEZT_KEYTYPE_KEYFRAME; /* done... no need to insert */ return; } else { ActKeyColumn **aknp= NULL; /* check if go left or right, but if not available, add new node */ if (ak->cfra < bezt->vec[1][0]) aknp= &ak->right; else aknp= &ak->left; /* if this does not exist, add a new node, otherwise continue... */ if (*aknp == NULL) { /* add a new node representing this, and attach it to the relevant place */ new_ak= bezt_to_new_actkeycolumn(bezt); new_ak->parent= ak; *aknp= new_ak; break; } else akn= *aknp; } } } /* now, balance the tree taking into account this newly added node */ BLI_dlrbTree_insert(keys, (DLRBT_Node *)new_ak); }
/* Node updater callback used for building ActKeyColumns from BezTriples */ static void nupdate_ak_bezt(void *node, void *data) { ActKeyColumn *ak = (ActKeyColumn *)node; BezTriple *bezt = (BezTriple *)data; /* set selection status and 'touched' status */ if (BEZSELECTED(bezt)) ak->sel = SELECT; ak->modified += 1; /* for keyframe type, 'proper' keyframes have priority over breakdowns (and other types for now) */ if (BEZKEYTYPE(bezt) == BEZT_KEYTYPE_KEYFRAME) ak->key_type = BEZT_KEYTYPE_KEYFRAME; }
/* Create a ActKeyColumn from a BezTriple */ static ActKeyColumn *bezt_to_new_actkeycolumn(BezTriple *bezt) { ActKeyColumn *ak= MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumn"); /* store settings based on state of BezTriple */ ak->cfra= bezt->vec[1][0]; ak->sel= BEZSELECTED(bezt) ? SELECT : 0; ak->key_type= BEZKEYTYPE(bezt); /* set 'modified', since this is used to identify long keyframes */ ak->modified = 1; return ak; }
/* New node callback used for building ActKeyColumns from BezTriples */ static DLRBT_Node *nalloc_ak_bezt(void *data) { ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumn"); BezTriple *bezt = (BezTriple *)data; /* store settings based on state of BezTriple */ ak->cfra = bezt->vec[1][0]; ak->sel = BEZSELECTED(bezt) ? SELECT : 0; ak->key_type = BEZKEYTYPE(bezt); /* set 'modified', since this is used to identify long keyframes */ ak->modified = 1; return (DLRBT_Node *)ak; }
/* Create a ActKeyColumn for a pair of BezTriples */ static ActKeyBlock *bezts_to_new_actkeyblock(BezTriple *prev, BezTriple *beztn) { ActKeyBlock *ab = MEM_callocN(sizeof(ActKeyBlock), "ActKeyBlock"); ab->start = prev->vec[1][0]; ab->end = beztn->vec[1][0]; ab->val = beztn->vec[1][1]; ab->sel = (BEZT_ISSEL_ANY(prev) || BEZT_ISSEL_ANY(beztn)) ? SELECT : 0; ab->modified = 1; if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD) ab->flag |= ACTKEYBLOCK_FLAG_MOVING_HOLD; return ab; }
static short set_keytype_jitter(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { if (bezt->f2 & SELECT) BEZKEYTYPE(bezt) = BEZT_KEYTYPE_JITTER; return 0; }
static short set_keytype_extreme(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { if (bezt->f2 & SELECT) BEZKEYTYPE(bezt) = BEZT_KEYTYPE_EXTREME; return 0; }
static short set_keytype_breakdown(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { if (bezt->f2 & SELECT) BEZKEYTYPE(bezt) = BEZT_KEYTYPE_BREAKDOWN; return 0; }
/* Basic F-Curve 'cleanup' function that removes 'double points' and unnecessary keyframes on linear-segments only * optionally clears up curve if one keyframe with default value remains */ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, bool cleardefault) { FCurve *fcu = (FCurve *)ale->key_data; BezTriple *old_bezts, *bezt, *beztn; BezTriple *lastb; int totCount, i; /* check if any points */ if ((fcu == NULL) || (fcu->bezt == NULL) || (fcu->totvert == 0) || (!cleardefault && fcu->totvert == 1)) { return; } /* make a copy of the old BezTriples, and clear F-Curve */ old_bezts = fcu->bezt; totCount = fcu->totvert; fcu->bezt = NULL; fcu->totvert = 0; /* now insert first keyframe, as it should be ok */ bezt = old_bezts; insert_vert_fcurve(fcu, bezt->vec[1][0], bezt->vec[1][1], BEZKEYTYPE(bezt), 0); if (!(bezt->f2 & SELECT)) { lastb = fcu->bezt; lastb->f1 = lastb->f2 = lastb->f3 = 0; } /* Loop through BezTriples, comparing them. Skip any that do * not fit the criteria for "ok" points. */ for (i = 1; i < totCount; i++) { float prev[2], cur[2], next[2]; /* get BezTriples and their values */ if (i < (totCount - 1)) { beztn = (old_bezts + (i + 1)); next[0] = beztn->vec[1][0]; next[1] = beztn->vec[1][1]; } else { beztn = NULL; next[0] = next[1] = 0.0f; } lastb = (fcu->bezt + (fcu->totvert - 1)); bezt = (old_bezts + i); /* get references for quicker access */ prev[0] = lastb->vec[1][0]; prev[1] = lastb->vec[1][1]; cur[0] = bezt->vec[1][0]; cur[1] = bezt->vec[1][1]; if (!(bezt->f2 & SELECT)) { insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0); lastb = (fcu->bezt + (fcu->totvert - 1)); lastb->f1 = lastb->f2 = lastb->f3 = 0; continue; } /* check if current bezt occurs at same time as last ok */ if (IS_EQT(cur[0], prev[0], thresh)) { /* If there is a next beztriple, and if occurs at the same time, only insert * if there is a considerable distance between the points, and also if the * current is further away than the next one is to the previous. */ if (beztn && (IS_EQT(cur[0], next[0], thresh)) && (IS_EQT(next[1], prev[1], thresh) == 0)) { /* only add if current is further away from previous */ if (cur[1] > next[1]) { if (IS_EQT(cur[1], prev[1], thresh) == 0) { /* add new keyframe */ insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0); } } } else { /* only add if values are a considerable distance apart */ if (IS_EQT(cur[1], prev[1], thresh) == 0) { /* add new keyframe */ insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0); } } } else { /* checks required are dependent on whether this is last keyframe or not */ if (beztn) { /* does current have same value as previous and next? */ if (IS_EQT(cur[1], prev[1], thresh) == 0) { /* add new keyframe*/ insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0); } else if (IS_EQT(cur[1], next[1], thresh) == 0) { /* add new keyframe */ insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0); } } else { /* add if value doesn't equal that of previous */ if (IS_EQT(cur[1], prev[1], thresh) == 0) { /* add new keyframe */ insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0); } } } } /* now free the memory used by the old BezTriples */ if (old_bezts) MEM_freeN(old_bezts); /* final step, if there is just one key in fcurve, check if it's * the default value and if is, remove fcurve completely. */ if (cleardefault && fcu->totvert == 1) { float default_value = 0.0f; PointerRNA id_ptr, ptr; PropertyRNA *prop; RNA_id_pointer_create(ale->id, &id_ptr); /* get property to read from, and get value as appropriate */ if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) { if (RNA_property_type(prop) == PROP_FLOAT) default_value = RNA_property_float_get_default_index(&ptr, prop, fcu->array_index); } if (fcu->bezt->vec[1][1] == default_value) { clear_fcurve_keys(fcu); /* check if curve is really unused and if it is, return signal for deletion */ if ((list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0) && (fcu->driver == NULL)) { AnimData *adt = ale->adt; ANIM_fcurve_delete_from_animdata(ac, adt, fcu); ale->key_data = NULL; } } } }
static void add_bezt_to_keyblocks_list(DLRBT_Tree *blocks, BezTriple *first_bezt, BezTriple *beztn) { ActKeyBlock *new_ab = NULL; BezTriple *prev = NULL; /* get the BezTriple immediately before the given one which has the same value */ if (beztn != first_bezt) { /* XXX: Unless I'm overlooking some details from the past, this should be sufficient? * The old code did some elaborate stuff trying to find keyframe columns for * the given BezTriple, then step backwards to the column before that, and find * an appropriate BezTriple with matching values there. Maybe that was warranted * in the past, but now, that list is only ever filled with keyframes from the * current FCurve. * * -- Aligorith (20140415) */ prev = beztn - 1; } /* check if block needed */ if (prev == NULL) return; if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD) { /* Animator tagged a "moving hold" * - Previous key must also be tagged as a moving hold, otherwise * we're just dealing with the first of a pair, and we don't * want to be creating any phantom holds... */ if (BEZKEYTYPE(prev) != BEZT_KEYTYPE_MOVEHOLD) return; } else { /* Check for same values... * - Handles must have same central value as each other * - Handles which control that section of the curve must be constant */ if (IS_EQF(beztn->vec[1][1], prev->vec[1][1]) == 0) return; if (IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) == 0) return; if (IS_EQF(prev->vec[1][1], prev->vec[2][1]) == 0) return; } /* if there are no blocks already, just add as root */ if (blocks->root == NULL) { /* just add this as the root, then call the tree-balancing functions to validate */ new_ab = bezts_to_new_actkeyblock(prev, beztn); blocks->root = (DLRBT_Node *)new_ab; } else { ActKeyBlock *ab, *abn = NULL; /* try to find a keyblock that starts on the previous beztriple, and add a new one if none start there * Note: we perform a tree traversal here NOT a standard linked-list traversal... * Note: we can't search from end to try to optimize this as it causes errors there's * an A ___ B |---| B situation */ // FIXME: here there is a bug where we are trying to get the summary for the following channels // A|--------------|A ______________ B|--------------|B // A|------------------------------------------------|A // A|----|A|---|A|-----------------------------------|A for (ab = blocks->root; ab; ab = abn) { /* check if this is a match, or whether we go left or right * NOTE: we now use a float threshold to prevent precision errors causing problems with summaries */ if (IS_EQT(ab->start, prev->vec[1][0], BEZT_BINARYSEARCH_THRESH)) { /* set selection status and 'touched' status */ if (BEZT_ISSEL_ANY(beztn)) ab->sel = SELECT; /* XXX: only when the first one was a moving hold? */ if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD) ab->flag |= ACTKEYBLOCK_FLAG_MOVING_HOLD; ab->modified++; /* done... no need to insert */ return; } else { ActKeyBlock **abnp = NULL; /* branch to go down - used to hook new blocks to parents */ /* check if go left or right, but if not available, add new node */ if (ab->start < prev->vec[1][0]) abnp = &ab->right; else abnp = &ab->left; /* if this does not exist, add a new node, otherwise continue... */ if (*abnp == NULL) { /* add a new node representing this, and attach it to the relevant place */ new_ab = bezts_to_new_actkeyblock(prev, beztn); new_ab->parent = ab; *abnp = new_ab; break; } else abn = *abnp; } } } /* now, balance the tree taking into account this newly added node */ BLI_dlrbTree_insert(blocks, (DLRBT_Node *)new_ab); }
static short set_keytype_moving_hold(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { if (bezt->f2 & SELECT) BEZKEYTYPE(bezt) = BEZT_KEYTYPE_MOVEHOLD; return 0; }