diff options
Diffstat (limited to 'source/blender/blenkernel/intern/fcurve.c')
-rw-r--r-- | source/blender/blenkernel/intern/fcurve.c | 667 |
1 files changed, 439 insertions, 228 deletions
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index d5b54eb1cd1..e6d3696b198 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -82,41 +82,41 @@ void BKE_fcurve_free(FCurve *fcu) return; } - /* free curve data */ + /* Free curve data. */ MEM_SAFE_FREE(fcu->bezt); MEM_SAFE_FREE(fcu->fpt); - /* free RNA-path, as this were allocated when getting the path string */ + /* Free RNA-path, as this were allocated when getting the path string. */ MEM_SAFE_FREE(fcu->rna_path); - /* free extra data - i.e. modifiers, and driver */ + /* Free extra data - i.e. modifiers, and driver. */ fcurve_free_driver(fcu); free_fmodifiers(&fcu->modifiers); - /* free f-curve itself */ + /* Free the f-curve itself. */ MEM_freeN(fcu); } -/* Frees a list of F-Curves */ +/* Frees a list of F-Curves. */ void BKE_fcurves_free(ListBase *list) { FCurve *fcu, *fcn; - /* sanity check */ + /* Sanity check. */ if (list == NULL) { return; } - /* free data - no need to call remlink before freeing each curve, + /* Free data - no need to call remlink before freeing each curve, * as we store reference to next, and freeing only touches the curve - * it's given + * it's given. */ for (fcu = list->first; fcu; fcu = fcn) { fcn = fcu->next; BKE_fcurve_free(fcu); } - /* clear pointers just in case */ + /* Clear pointers just in case. */ BLI_listbase_clear(list); } @@ -126,53 +126,53 @@ void BKE_fcurves_free(ListBase *list) /** \name F-Curve Data Copy * \{ */ -/* duplicate an F-Curve */ +/* Duplicate a F-Curve. */ FCurve *BKE_fcurve_copy(const FCurve *fcu) { FCurve *fcu_d; - /* sanity check */ + /* Sanity check. */ if (fcu == NULL) { return NULL; } - /* make a copy */ + /* Make a copy. */ fcu_d = MEM_dupallocN(fcu); fcu_d->next = fcu_d->prev = NULL; fcu_d->grp = NULL; - /* copy curve data */ + /* Copy curve data. */ fcu_d->bezt = MEM_dupallocN(fcu_d->bezt); fcu_d->fpt = MEM_dupallocN(fcu_d->fpt); - /* copy rna-path */ + /* Copy rna-path. */ fcu_d->rna_path = MEM_dupallocN(fcu_d->rna_path); - /* copy driver */ + /* Copy driver. */ fcu_d->driver = fcurve_copy_driver(fcu_d->driver); - /* copy modifiers */ + /* Copy modifiers. */ copy_fmodifiers(&fcu_d->modifiers, &fcu->modifiers); - /* return new data */ + /* Return new data. */ return fcu_d; } -/* duplicate a list of F-Curves */ +/* Duplicate a list of F-Curves. */ void BKE_fcurves_copy(ListBase *dst, ListBase *src) { FCurve *dfcu, *sfcu; - /* sanity checks */ + /* Sanity checks. */ if (ELEM(NULL, dst, src)) { return; } - /* clear destination list first */ + /* Clear destination list first. */ BLI_listbase_clear(dst); - /* copy one-by-one */ + /* Copy one-by-one. */ for (sfcu = src->first; sfcu; sfcu = sfcu->next) { dfcu = BKE_fcurve_copy(sfcu); BLI_addtail(dst, dfcu); @@ -213,15 +213,15 @@ void BKE_fcurve_foreach_id(FCurve *fcu, LibraryForeachIDData *data) /* ----------------- Finding F-Curves -------------------------- */ -/* high level function to get an fcurve from C without having the rna */ +/* High level function to get an fcurve from C without having the RNA. */ FCurve *id_data_find_fcurve( ID *id, void *data, StructRNA *type, const char *prop_name, int index, bool *r_driven) { - /* anim vars */ + /* Anim vars */ AnimData *adt = BKE_animdata_from_id(id); FCurve *fcu = NULL; - /* rna vars */ + /* Rna vars */ PointerRNA ptr; PropertyRNA *prop; char *path; @@ -230,7 +230,7 @@ FCurve *id_data_find_fcurve( *r_driven = false; } - /* only use the current action ??? */ + /* Only use the current action ??? */ if (ELEM(NULL, adt, adt->action)) { return NULL; } @@ -246,12 +246,12 @@ FCurve *id_data_find_fcurve( return NULL; } - /* animation takes priority over drivers */ + /* Animation takes priority over drivers. */ if (adt->action && adt->action->curves.first) { fcu = BKE_fcurve_find(&adt->action->curves, path, index); } - /* if not animated, check if driven */ + /* If not animated, check if driven. */ if (fcu == NULL && adt->drivers.first) { fcu = BKE_fcurve_find(&adt->drivers, path, index); if (fcu && r_driven) { @@ -271,45 +271,43 @@ FCurve *BKE_fcurve_find(ListBase *list, const char rna_path[], const int array_i { FCurve *fcu; - /* sanity checks */ + /* Sanity checks. */ if (ELEM(NULL, list, rna_path) || (array_index < 0)) { return NULL; } - /* check paths of curves, then array indices... */ + /* Check paths of curves, then array indices... */ for (fcu = list->first; fcu; fcu = fcu->next) { - /* simple string-compare (this assumes that they have the same root...) */ + /* Simple string-compare (this assumes that they have the same root...) */ if (fcu->rna_path && STREQ(fcu->rna_path, rna_path)) { - /* now check indices */ + /* Now check indices. */ if (fcu->array_index == array_index) { return fcu; } } } - /* return */ return NULL; } -/* quick way to loop over all fcurves of a given 'path' */ +/* Quick way to loop over all fcurves of a given 'path'. */ FCurve *BKE_fcurve_iter_step(FCurve *fcu_iter, const char rna_path[]) { FCurve *fcu; - /* sanity checks */ + /* Sanity checks. */ if (ELEM(NULL, fcu_iter, rna_path)) { return NULL; } - /* check paths of curves, then array indices... */ + /* Check paths of curves, then array indices... */ for (fcu = fcu_iter; fcu; fcu = fcu->next) { - /* simple string-compare (this assumes that they have the same root...) */ + /* Simple string-compare (this assumes that they have the same root...) */ if (fcu->rna_path && STREQ(fcu->rna_path, rna_path)) { return fcu; } } - /* return */ return NULL; } @@ -330,7 +328,7 @@ int BKE_fcurves_filter(ListBase *dst, ListBase *src, const char *dataPrefix, con FCurve *fcu; int matches = 0; - /* sanity checks */ + /* Sanity checks. */ if (ELEM(NULL, dst, src, dataPrefix, dataName)) { return 0; } @@ -338,9 +336,9 @@ int BKE_fcurves_filter(ListBase *dst, ListBase *src, const char *dataPrefix, con return 0; } - /* search each F-Curve one by one */ + /* Search each F-Curve one by one. */ for (fcu = src->first; fcu; fcu = fcu->next) { - /* check if quoted string matches the path */ + /* Check if quoted string matches the path. */ if (fcu->rna_path == NULL || !strstr(fcu->rna_path, dataPrefix)) { continue; } @@ -350,7 +348,7 @@ int BKE_fcurves_filter(ListBase *dst, ListBase *src, const char *dataPrefix, con continue; } - /* check if the quoted name matches the required name */ + /* Check if the quoted name matches the required name. */ if (STREQ(quotedName, dataName)) { LinkData *ld = MEM_callocN(sizeof(LinkData), __func__); @@ -360,10 +358,10 @@ int BKE_fcurves_filter(ListBase *dst, ListBase *src, const char *dataPrefix, con matches++; } - /* always free the quoted string, since it needs freeing */ + /* Always free the quoted string, since it needs freeing. */ MEM_freeN(quotedName); } - /* return the number of matches */ + /* Return the number of matches. */ return matches; } @@ -415,7 +413,7 @@ FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *C, return fcu; } - /* there must be some RNA-pointer + property combon */ + /* There must be some RNA-pointer + property combo. */ if (prop && tptr.owner_id && RNA_property_animateable(&tptr, prop)) { AnimData *adt = BKE_animdata_from_id(tptr.owner_id); int step = ( @@ -429,14 +427,14 @@ FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *C, step--; } - /* Standard F-Curve - Animation (Action) or Drivers */ + /* Standard F-Curve - Animation (Action) or Drivers. */ while (adt && step--) { if ((adt->action == NULL || adt->action->curves.first == NULL) && (adt->drivers.first == NULL)) { continue; } - /* XXX this function call can become a performance bottleneck */ + /* XXX This function call can become a performance bottleneck. */ if (step) { path = RNA_path_from_ID_to_property(&tptr, prop); } @@ -444,8 +442,8 @@ FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *C, continue; } - // XXX: the logic here is duplicated with a function up above - /* animation takes priority over drivers */ + /* XXX: The logic here is duplicated with a function up above. */ + /* animation takes priority over drivers. */ if (adt->action && adt->action->curves.first) { fcu = BKE_fcurve_find(&adt->action->curves, path, rnaindex); @@ -454,7 +452,7 @@ FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *C, } } - /* if not animated, check if driven */ + /* If not animated, check if driven. */ if (!fcu && (adt->drivers.first)) { fcu = BKE_fcurve_find(&adt->drivers, path, rnaindex); @@ -502,25 +500,25 @@ FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *C, * with optional argument for precision required. * Returns the index to insert at (data already at that index will be offset if replace is 0) */ -static int binarysearch_bezt_index_ex( +static int BKE_fcurve_bezt_binarysearch_index_ex( BezTriple array[], float frame, int arraylen, float threshold, bool *r_replace) { int start = 0, end = arraylen; int loopbreaker = 0, maxloop = arraylen * 2; - /* initialize replace-flag first */ + /* Initialize replace-flag first. */ *r_replace = false; - /* sneaky optimizations (don't go through searching process if...): - * - keyframe to be added is to be added out of current bounds - * - keyframe to be added would replace one of the existing ones on bounds + /* Sneaky optimizations (don't go through searching process if...): + * - Keyframe to be added is to be added out of current bounds. + * - Keyframe to be added would replace one of the existing ones on bounds. */ if ((arraylen <= 0) || (array == NULL)) { CLOG_WARN(&LOG, "encountered invalid array"); return 0; } - /* check whether to add before/after/on */ + /* Check whether to add before/after/on. */ float framenum; /* 'First' Keyframe (when only one keyframe, this case is used) */ @@ -543,24 +541,24 @@ static int binarysearch_bezt_index_ex( return arraylen; } - /* most of the time, this loop is just to find where to put it - * 'loopbreaker' is just here to prevent infinite loops + /* Most of the time, this loop is just to find where to put it + * 'loopbreaker' is just here to prevent infinite loops. */ for (loopbreaker = 0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) { - /* compute and get midpoint */ + /* Compute and get midpoint. */ /* We calculate the midpoint this way to avoid int overflows... */ int mid = start + ((end - start) / 2); float midfra = array[mid].vec[1][0]; - /* check if exactly equal to midpoint */ + /* Check if exactly equal to midpoint. */ if (IS_EQT(frame, midfra, threshold)) { *r_replace = true; return mid; } - /* repeat in upper/lower half */ + /* Repeat in upper/lower half. */ if (frame > midfra) { start = mid + 1; } @@ -569,11 +567,11 @@ static int binarysearch_bezt_index_ex( } } - /* print error if loop-limit exceeded */ + /* Print error if loop-limit exceeded. */ if (loopbreaker == (maxloop - 1)) { CLOG_ERROR(&LOG, "search taking too long"); - /* include debug info */ + /* Include debug info. */ CLOG_ERROR(&LOG, "\tround = %d: start = %d, end = %d, arraylen = %d", loopbreaker, @@ -582,22 +580,26 @@ static int binarysearch_bezt_index_ex( arraylen); } - /* not found, so return where to place it */ + /* Not found, so return where to place it. */ return start; } /* Binary search algorithm for finding where to insert BezTriple. (for use by insert_bezt_fcurve) * Returns the index to insert at (data already at that index will be offset if replace is 0) */ -int binarysearch_bezt_index(BezTriple array[], float frame, int arraylen, bool *r_replace) +int BKE_fcurve_bezt_binarysearch_index(BezTriple array[], + float frame, + int arraylen, + bool *r_replace) { - /* this is just a wrapper which uses the default threshold */ - return binarysearch_bezt_index_ex(array, frame, arraylen, BEZT_BINARYSEARCH_THRESH, r_replace); + /* This is just a wrapper which uses the default threshold. */ + return BKE_fcurve_bezt_binarysearch_index_ex( + array, frame, arraylen, BEZT_BINARYSEARCH_THRESH, r_replace); } /* ...................................... */ -/* helper for calc_fcurve_* functions -> find first and last BezTriple to be used */ +/* Helper for calc_fcurve_* functions -> find first and last BezTriple to be used. */ static short get_fcurve_end_keyframes(FCurve *fcu, BezTriple **first, BezTriple **last, @@ -605,20 +607,20 @@ static short get_fcurve_end_keyframes(FCurve *fcu, { bool found = false; - /* init outputs */ + /* Init outputs. */ *first = NULL; *last = NULL; - /* sanity checks */ + /* Sanity checks. */ if (fcu->bezt == NULL) { return found; } - /* only include selected items? */ + /* Only include selected items? */ if (do_sel_only) { BezTriple *bezt; - /* find first selected */ + /* Find first selected. */ bezt = fcu->bezt; for (int i = 0; i < fcu->totvert; bezt++, i++) { if (BEZT_ISSEL_ANY(bezt)) { @@ -628,7 +630,7 @@ static short get_fcurve_end_keyframes(FCurve *fcu, } } - /* find last selected */ + /* Find last selected. */ bezt = ARRAY_LAST_ITEM(fcu->bezt, BezTriple, fcu->totvert); for (int i = 0; i < fcu->totvert; bezt--, i++) { if (BEZT_ISSEL_ANY(bezt)) { @@ -639,7 +641,7 @@ static short get_fcurve_end_keyframes(FCurve *fcu, } } else { - /* just full array */ + /* Use the whole array. */ *first = fcu->bezt; *last = ARRAY_LAST_ITEM(fcu->bezt, BezTriple, fcu->totvert); found = true; @@ -648,7 +650,7 @@ static short get_fcurve_end_keyframes(FCurve *fcu, return found; } -/* Calculate the extents of F-Curve's data */ +/* Calculate the extents of F-Curve's data. */ bool BKE_fcurve_calc_bounds(FCurve *fcu, float *xmin, float *xmax, @@ -666,7 +668,7 @@ bool BKE_fcurve_calc_bounds(FCurve *fcu, BezTriple *bezt_first = NULL, *bezt_last = NULL; if (xmin || xmax) { - /* get endpoint keyframes */ + /* Get endpoint keyframes. */ foundvert = get_fcurve_end_keyframes(fcu, &bezt_first, &bezt_last, do_sel_only); if (bezt_first) { @@ -683,19 +685,19 @@ bool BKE_fcurve_calc_bounds(FCurve *fcu, } } - /* only loop over keyframes to find extents for values if needed */ + /* Only loop over keyframes to find extents for values if needed. */ if (ymin || ymax) { BezTriple *bezt, *prevbezt = NULL; int i; for (bezt = fcu->bezt, i = 0; i < fcu->totvert; prevbezt = bezt, bezt++, i++) { if ((do_sel_only == false) || BEZT_ISSEL_ANY(bezt)) { - /* keyframe itself */ + /* Keyframe itself. */ yminv = min_ff(yminv, bezt->vec[1][1]); ymaxv = max_ff(ymaxv, bezt->vec[1][1]); if (include_handles) { - /* left handle - only if applicable + /* Left handle - only if applicable. * NOTE: for the very first keyframe, * the left handle actually has no bearings on anything. */ if (prevbezt && (prevbezt->ipo == BEZT_IPO_BEZ)) { @@ -703,7 +705,7 @@ bool BKE_fcurve_calc_bounds(FCurve *fcu, ymaxv = max_ff(ymaxv, bezt->vec[0][1]); } - /* right handle - only if applicable */ + /* Right handle - only if applicable. */ if (bezt->ipo == BEZT_IPO_BEZ) { yminv = min_ff(yminv, bezt->vec[2][1]); ymaxv = max_ff(ymaxv, bezt->vec[2][1]); @@ -716,13 +718,13 @@ bool BKE_fcurve_calc_bounds(FCurve *fcu, } } else if (fcu->fpt) { - /* frame range can be directly calculated from end verts */ + /* Frame range can be directly calculated from end verts. */ if (xmin || xmax) { xminv = min_ff(xminv, fcu->fpt[0].vec[0]); xmaxv = max_ff(xmaxv, fcu->fpt[fcu->totvert - 1].vec[0]); } - /* only loop over keyframes to find extents for values if needed */ + /* Only loop over keyframes to find extents for values if needed. */ if (ymin || ymax) { FPoint *fpt; int i; @@ -779,7 +781,7 @@ bool BKE_fcurve_calc_bounds(FCurve *fcu, return foundvert; } -/* Calculate the extents of F-Curve's keyframes */ +/* Calculate the extents of F-Curve's keyframes. */ bool BKE_fcurve_calc_range( FCurve *fcu, float *start, float *end, const bool do_sel_only, const bool do_min_length) { @@ -790,7 +792,7 @@ bool BKE_fcurve_calc_range( if (fcu->bezt) { BezTriple *bezt_first = NULL, *bezt_last = NULL; - /* get endpoint keyframes */ + /* Get endpoint keyframes. */ get_fcurve_end_keyframes(fcu, &bezt_first, &bezt_last, do_sel_only); if (bezt_first) { @@ -815,7 +817,7 @@ bool BKE_fcurve_calc_range( } if (do_min_length) { - /* minimum length is 1 frame */ + /* Minimum length is 1 frame. */ if (min == max) { max += 1.0f; } @@ -830,6 +832,59 @@ bool BKE_fcurve_calc_range( /** \} */ /* -------------------------------------------------------------------- */ +/** \name Active Keyframe + * \{ */ + +/** + * Set the index that stores the FCurve's active keyframe, assuming that \a active_bezt + * is already part of `fcu->bezt`. If NULL, set active keyframe index to "none." + */ +void BKE_fcurve_active_keyframe_set(FCurve *fcu, const BezTriple *active_bezt) +{ + if (active_bezt == NULL) { + fcu->active_keyframe_index = FCURVE_ACTIVE_KEYFRAME_NONE; + return; + } + + /* Gracefully handle out-of-bounds pointers. Ideally this would do a BLI_assert() as well, but + * then the unit tests would break in debug mode. */ + ptrdiff_t offset = active_bezt - fcu->bezt; + if (offset < 0 || offset >= fcu->totvert) { + fcu->active_keyframe_index = FCURVE_ACTIVE_KEYFRAME_NONE; + return; + } + + /* The active keyframe should always be selected. */ + BLI_assert(BEZT_ISSEL_ANY(active_bezt) || !"active keyframe must be selected"); + + fcu->active_keyframe_index = (int)offset; +} + +/** + * Get the active keyframe index, with sanity checks for point bounds. + */ +int BKE_fcurve_active_keyframe_index(const FCurve *fcu) +{ + const int active_keyframe_index = fcu->active_keyframe_index; + + /* Array access boundary checks. */ + if ((fcu->bezt == NULL) || (active_keyframe_index >= fcu->totvert) || + (active_keyframe_index < 0)) { + return FCURVE_ACTIVE_KEYFRAME_NONE; + } + + const BezTriple *active_bezt = &fcu->bezt[active_keyframe_index]; + if (((active_bezt->f1 | active_bezt->f2 | active_bezt->f3) & SELECT) == 0) { + /* The active keyframe should always be selected. If it's not selected, it can't be active. */ + return FCURVE_ACTIVE_KEYFRAME_NONE; + } + + return active_keyframe_index; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Status Checks * \{ */ @@ -839,37 +894,37 @@ bool BKE_fcurve_calc_range( */ bool BKE_fcurve_are_keyframes_usable(FCurve *fcu) { - /* F-Curve must exist */ + /* F-Curve must exist. */ if (fcu == NULL) { return false; } - /* F-Curve must not have samples - samples are mutually exclusive of keyframes */ + /* F-Curve must not have samples - samples are mutually exclusive of keyframes. */ if (fcu->fpt) { return false; } - /* if it has modifiers, none of these should "drastically" alter the curve */ + /* If it has modifiers, none of these should "drastically" alter the curve. */ if (fcu->modifiers.first) { FModifier *fcm; - /* check modifiers from last to first, as last will be more influential */ - /* TODO: optionally, only check modifier if it is the active one... */ + /* Check modifiers from last to first, as last will be more influential. */ + /* TODO: optionally, only check modifier if it is the active one... (Joshua Leung 2010) */ for (fcm = fcu->modifiers.last; fcm; fcm = fcm->prev) { - /* ignore if muted/disabled */ + /* Ignore if muted/disabled. */ if (fcm->flag & (FMODIFIER_FLAG_DISABLED | FMODIFIER_FLAG_MUTED)) { continue; } - /* type checks */ + /* Type checks. */ switch (fcm->type) { - /* clearly harmless - do nothing */ + /* Clearly harmless - do nothing. */ case FMODIFIER_TYPE_CYCLES: case FMODIFIER_TYPE_STEPPED: case FMODIFIER_TYPE_NOISE: break; - /* sometimes harmful - depending on whether they're "additive" or not */ + /* Sometimes harmful - depending on whether they're "additive" or not. */ case FMODIFIER_TYPE_GENERATOR: { FMod_Generator *data = (FMod_Generator *)fcm->data; @@ -886,14 +941,14 @@ bool BKE_fcurve_are_keyframes_usable(FCurve *fcu) } break; } - /* always harmful - cannot allow */ + /* Always harmful - cannot allow. */ default: return false; } } } - /* keyframes are usable */ + /* Keyframes are usable. */ return true; } @@ -903,7 +958,7 @@ bool BKE_fcurve_is_protected(FCurve *fcu) } /* Can keyframes be added to F-Curve? - * Keyframes can only be added if they are already visible + * Keyframes can only be added if they are already visible. */ bool BKE_fcurve_is_keyframable(FCurve *fcu) { @@ -912,12 +967,12 @@ bool BKE_fcurve_is_keyframable(FCurve *fcu) return false; } - /* F-Curve must currently be editable too */ + /* F-Curve must currently be editable too. */ if (BKE_fcurve_is_protected(fcu)) { return false; } - /* F-Curve is keyframable */ + /* F-Curve is keyframable. */ return true; } @@ -927,26 +982,26 @@ bool BKE_fcurve_is_keyframable(FCurve *fcu) /** \name Keyframe Column Tools * \{ */ -/* add a BezTriple to a column */ -void bezt_add_to_cfra_elem(ListBase *lb, BezTriple *bezt) +/* Add a BezTriple to a column. */ +static void UNUSED_FUNCTION(bezt_add_to_cfra_elem)(ListBase *lb, BezTriple *bezt) { CfraElem *ce, *cen; for (ce = lb->first; ce; ce = ce->next) { - /* double key? */ + /* Double key? */ if (IS_EQT(ce->cfra, bezt->vec[1][0], BEZT_BINARYSEARCH_THRESH)) { if (bezt->f2 & SELECT) { ce->sel = bezt->f2; } return; } - /* should key be inserted before this column? */ + /* Should key be inserted before this column? */ if (ce->cfra > bezt->vec[1][0]) { break; } } - /* create a new column */ + /* Create a new column */ cen = MEM_callocN(sizeof(CfraElem), "add_to_cfra_elem"); if (ce) { BLI_insertlinkbefore(lb, ce, cen); @@ -975,7 +1030,7 @@ void bezt_add_to_cfra_elem(ListBase *lb, BezTriple *bezt) */ float fcurve_samplingcb_evalcurve(FCurve *fcu, void *UNUSED(data), float evaltime) { - /* assume any interference from drivers on the curve is intended... */ + /* Assume any interference from drivers on the curve is intended... */ return evaluate_fcurve(fcu, evaltime); } @@ -987,8 +1042,8 @@ void fcurve_store_samples(FCurve *fcu, void *data, int start, int end, FcuSample FPoint *fpt, *new_fpt; int cfra; - /* sanity checks */ - /* TODO: make these tests report errors using reports not CLOG's */ + /* Sanity checks. */ + /* TODO: make these tests report errors using reports not CLOG's (Joshua Leung 2009) */ if (ELEM(NULL, fcu, sample_cb)) { CLOG_ERROR(&LOG, "No F-Curve with F-Curve Modifiers to Bake"); return; @@ -998,16 +1053,16 @@ void fcurve_store_samples(FCurve *fcu, void *data, int start, int end, FcuSample return; } - /* set up sample data */ + /* Set up sample data. */ fpt = new_fpt = MEM_callocN(sizeof(FPoint) * (end - start + 1), "FPoint Samples"); - /* use the sampling callback at 1-frame intervals from start to end frames */ + /* Use the sampling callback at 1-frame intervals from start to end frames. */ for (cfra = start; cfra <= end; cfra++, fpt++) { fpt->vec[0] = (float)cfra; fpt->vec[1] = sample_cb(fcu, data, (float)cfra); } - /* free any existing sample/keyframe data on curve */ + /* Free any existing sample/keyframe data on curve. */ if (fcu->bezt) { MEM_freeN(fcu->bezt); } @@ -1015,16 +1070,94 @@ void fcurve_store_samples(FCurve *fcu, void *data, int start, int end, FcuSample MEM_freeN(fcu->fpt); } - /* store the samples */ + /* Store the samples. */ fcu->bezt = NULL; fcu->fpt = new_fpt; fcu->totvert = end - start + 1; } +static void init_unbaked_bezt_data(BezTriple *bezt) +{ + bezt->f1 = bezt->f2 = bezt->f3 = SELECT; + /* Baked FCurve points always use linear interpolation. */ + bezt->ipo = BEZT_IPO_LIN; + bezt->h1 = bezt->h2 = HD_AUTO_ANIM; +} + +/* Convert baked/sampled fcurves into bezt/regular fcurves. */ +void fcurve_samples_to_keyframes(FCurve *fcu, const int start, const int end) +{ + + /* Sanity checks. */ + /* TODO: make these tests report errors using reports not CLOG's (Joshua Leung 2009). */ + if (fcu == NULL) { + CLOG_ERROR(&LOG, "No F-Curve with F-Curve Modifiers to Un-Bake"); + return; + } + + if (start > end) { + CLOG_ERROR(&LOG, "Error: Frame range to unbake F-Curve is inappropriate"); + return; + } + + if (fcu->fpt == NULL) { + /* No data to unbake. */ + CLOG_ERROR(&LOG, "Error: Curve containts no baked keyframes"); + return; + } + + /* Free any existing sample/keyframe data on the curve. */ + if (fcu->bezt) { + MEM_freeN(fcu->bezt); + } + + BezTriple *bezt; + FPoint *fpt = fcu->fpt; + int keyframes_to_insert = end - start; + int sample_points = fcu->totvert; + + bezt = fcu->bezt = MEM_callocN(sizeof(*fcu->bezt) * (size_t)keyframes_to_insert, __func__); + fcu->totvert = keyframes_to_insert; + + /* Get first sample point to 'copy' as keyframe. */ + for (; sample_points && (fpt->vec[0] < start); fpt++, sample_points--) { + /* pass */ + } + + /* Current position in the timeline. */ + int cur_pos = start; + + /* Add leading dummy flat points if needed. */ + for (; keyframes_to_insert && (fpt->vec[0] > start); cur_pos++, bezt++, keyframes_to_insert--) { + init_unbaked_bezt_data(bezt); + bezt->vec[1][0] = (float)cur_pos; + bezt->vec[1][1] = fpt->vec[1]; + } + + /* Copy actual sample points. */ + for (; keyframes_to_insert && sample_points; + cur_pos++, bezt++, keyframes_to_insert--, fpt++, sample_points--) { + init_unbaked_bezt_data(bezt); + copy_v2_v2(bezt->vec[1], fpt->vec); + } + + /* Add trailing dummy flat points if needed. */ + for (fpt--; keyframes_to_insert; cur_pos++, bezt++, keyframes_to_insert--) { + init_unbaked_bezt_data(bezt); + bezt->vec[1][0] = (float)cur_pos; + bezt->vec[1][1] = fpt->vec[1]; + } + + MEM_SAFE_FREE(fcu->fpt); + + /* Not strictly needed since we use linear interpolation, but better be consistent here. */ + calchandles_fcurve(fcu); +} + /* ***************************** F-Curve Sanity ********************************* */ /* The functions here are used in various parts of Blender, usually after some editing * of keyframe data has occurred. They ensure that keyframe data is properly ordered and - * that the handles are correctly + * that the handles are correct. */ /* Checks if the F-Curve has a Cycles modifier, and returns the type of the cycle behavior. */ @@ -1104,28 +1237,28 @@ void calchandles_fcurve_ex(FCurve *fcu, eBezTriple_Flag handle_sel_flag) int a = fcu->totvert; /* Error checking: - * - need at least two points - * - need bezier keys - * - only bezier-interpolation has handles (for now) + * - Need at least two points. + * - Need bezier keys. + * - Only bezier-interpolation has handles (for now). */ if (ELEM(NULL, fcu, fcu->bezt) || (a < 2) /*|| ELEM(fcu->ipo, BEZT_IPO_CONST, BEZT_IPO_LIN)*/) { return; } - /* if the first modifier is Cycles, smooth the curve through the cycle */ + /* If the first modifier is Cycles, smooth the curve through the cycle. */ BezTriple *first = &fcu->bezt[0], *last = &fcu->bezt[fcu->totvert - 1]; BezTriple tmp; bool cycle = BKE_fcurve_is_cyclic(fcu) && BEZT_IS_AUTOH(first) && BEZT_IS_AUTOH(last); - /* get initial pointers */ + /* Get initial pointers. */ bezt = fcu->bezt; prev = cycle_offset_triple(cycle, &tmp, &fcu->bezt[fcu->totvert - 2], last, first); next = (bezt + 1); - /* loop over all beztriples, adjusting handles */ + /* Loop over all beztriples, adjusting handles. */ while (a--) { - /* clamp timing of handles to be on either side of beztriple */ + /* Clamp timing of handles to be on either side of beztriple. */ if (bezt->vec[0][0] > bezt->vec[1][0]) { bezt->vec[0][0] = bezt->vec[1][0]; } @@ -1133,28 +1266,28 @@ void calchandles_fcurve_ex(FCurve *fcu, eBezTriple_Flag handle_sel_flag) bezt->vec[2][0] = bezt->vec[1][0]; } - /* calculate auto-handles */ + /* Calculate auto-handles. */ BKE_nurb_handle_calc_ex(bezt, prev, next, handle_sel_flag, true, fcu->auto_smoothing); - /* for automatic ease in and out */ + /* For automatic ease in and out. */ if (BEZT_IS_AUTOH(bezt) && !cycle) { - /* only do this on first or last beztriple */ - if ((a == 0) || (a == fcu->totvert - 1)) { - /* set both handles to have same horizontal value as keyframe */ + /* Only do this on first or last beztriple. */ + if (ELEM(a, 0, fcu->totvert - 1)) { + /* Set both handles to have same horizontal value as keyframe. */ if (fcu->extend == FCURVE_EXTRAPOLATE_CONSTANT) { bezt->vec[0][1] = bezt->vec[2][1] = bezt->vec[1][1]; - /* remember that these keyframes are special, they don't need to be adjusted */ + /* Remember that these keyframes are special, they don't need to be adjusted. */ bezt->f5 = HD_AUTOTYPE_SPECIAL; } } } - /* avoid total smoothing failure on duplicate keyframes (can happen during grab) */ + /* Avoid total smoothing failure on duplicate keyframes (can happen during grab). */ if (prev && prev->vec[1][0] >= bezt->vec[1][0]) { prev->f5 = bezt->f5 = HD_AUTOTYPE_SPECIAL; } - /* advance pointers for next iteration */ + /* Advance pointers for next iteration. */ prev = bezt; if (a == 1) { @@ -1167,14 +1300,14 @@ void calchandles_fcurve_ex(FCurve *fcu, eBezTriple_Flag handle_sel_flag) bezt++; } - /* if cyclic extrapolation and Auto Clamp has triggered, ensure it is symmetric */ + /* If cyclic extrapolation and Auto Clamp has triggered, ensure it is symmetric. */ if (cycle && (first->f5 != HD_AUTOTYPE_NORMAL || last->f5 != HD_AUTOTYPE_NORMAL)) { first->vec[0][1] = first->vec[2][1] = first->vec[1][1]; last->vec[0][1] = last->vec[2][1] = last->vec[1][1]; first->f5 = last->f5 = HD_AUTOTYPE_SPECIAL; } - /* do a second pass for auto handle: compute the handle to have 0 acceleration step */ + /* Do a second pass for auto handle: compute the handle to have 0 acceleration step. */ if (fcu->auto_smoothing != FCURVE_SMOOTH_NONE) { BKE_nurb_handle_smooth_fcurve(fcu->bezt, fcu->totvert, cycle); } @@ -1207,17 +1340,17 @@ void testhandles_fcurve(FCurve *fcu, eBezTriple_Flag sel_flag, const bool use_ha BezTriple *bezt; unsigned int a; - /* only beztriples have handles (bpoints don't though) */ + /* Only beztriples have handles (bpoints don't though). */ if (ELEM(NULL, fcu, fcu->bezt)) { return; } - /* loop over beztriples */ + /* Loop over beztriples. */ for (a = 0, bezt = fcu->bezt; a < fcu->totvert; a++, bezt++) { BKE_nurb_bezt_handle_test(bezt, sel_flag, use_handle, false); } - /* recalculate handles */ + /* Recalculate handles. */ calchandles_fcurve_ex(fcu, sel_flag); } @@ -1230,20 +1363,20 @@ void sort_time_fcurve(FCurve *fcu) return; } - /* keep adjusting order of beztriples until nothing moves (bubble-sort) */ + /* Keep adjusting order of beztriples until nothing moves (bubble-sort). */ BezTriple *bezt; uint a; bool ok = true; while (ok) { ok = 0; - /* currently, will only be needed when there are beztriples */ + /* Currently, will only be needed when there are beztriples. */ - /* loop over ALL points to adjust position in array and recalculate handles */ + /* Loop over ALL points to adjust position in array and recalculate handles. */ for (a = 0, bezt = fcu->bezt; a < fcu->totvert; a++, bezt++) { - /* check if thee's a next beztriple which we could try to swap with current */ + /* Check if thee's a next beztriple which we could try to swap with current. */ if (a < (fcu->totvert - 1)) { - /* swap if one is after the other (and indicate that order has changed) */ + /* Swap if one is after the other (and indicate that order has changed). */ if (bezt->vec[1][0] > (bezt + 1)->vec[1][0]) { SWAP(BezTriple, *bezt, *(bezt + 1)); ok = 1; @@ -1253,34 +1386,34 @@ void sort_time_fcurve(FCurve *fcu) } for (a = 0, bezt = fcu->bezt; a < fcu->totvert; a++, bezt++) { - /* if either one of both of the points exceeds crosses over the keyframe time... */ + /* If either one of both of the points exceeds crosses over the keyframe time... */ if ((bezt->vec[0][0] > bezt->vec[1][0]) && (bezt->vec[2][0] < bezt->vec[1][0])) { - /* swap handles if they have switched sides for some reason */ + /* Swap handles if they have switched sides for some reason. */ swap_v2_v2(bezt->vec[0], bezt->vec[2]); } else { - /* clamp handles */ + /* Clamp handles. */ CLAMP_MAX(bezt->vec[0][0], bezt->vec[1][0]); CLAMP_MIN(bezt->vec[2][0], bezt->vec[1][0]); } } } -/* This function tests if any BezTriples are out of order, thus requiring a sort */ +/* This function tests if any BezTriples are out of order, thus requiring a sort. */ bool test_time_fcurve(FCurve *fcu) { unsigned int a; - /* sanity checks */ + /* Sanity checks. */ if (fcu == NULL) { return false; } - /* currently, only need to test beztriples */ + /* Currently, only need to test beztriples. */ if (fcu->bezt) { BezTriple *bezt; - /* loop through all BezTriples, stopping when one exceeds the one after it */ + /* Loop through all BezTriples, stopping when one exceeds the one after it. */ for (a = 0, bezt = fcu->bezt; a < (fcu->totvert - 1); a++, bezt++) { if (bezt->vec[1][0] > (bezt + 1)->vec[1][0]) { return true; @@ -1290,7 +1423,7 @@ bool test_time_fcurve(FCurve *fcu) else if (fcu->fpt) { FPoint *fpt; - /* loop through all FPoints, stopping when one exceeds the one after it */ + /* Loop through all FPoints, stopping when one exceeds the one after it. */ for (a = 0, fpt = fcu->fpt; a < (fcu->totvert - 1); a++, fpt++) { if (fpt->vec[0] > (fpt + 1)->vec[0]) { return true; @@ -1298,7 +1431,7 @@ bool test_time_fcurve(FCurve *fcu) } } - /* none need any swapping */ + /* None need any swapping. */ return false; } @@ -1308,60 +1441,61 @@ bool test_time_fcurve(FCurve *fcu) /** \name F-Curve Calculations * \{ */ -/* The total length of the handles is not allowed to be more +/* The length of each handle is not allowed to be more * than the horizontal distance between (v1-v4). * This is to prevent curve loops. + * + * This function is very similar to BKE_curve_correct_bezpart(), but allows a steeper tangent for + * more snappy animations. This is not desired for other areas in which curves are used, though. */ -void correct_bezpart(const float v1[2], float v2[2], float v3[2], const float v4[2]) +void BKE_fcurve_correct_bezpart(const float v1[2], float v2[2], float v3[2], const float v4[2]) { float h1[2], h2[2], len1, len2, len, fac; - /* calculate handle deltas */ + /* Calculate handle deltas. */ h1[0] = v1[0] - v2[0]; h1[1] = v1[1] - v2[1]; h2[0] = v4[0] - v3[0]; h2[1] = v4[1] - v3[1]; - /* calculate distances: - * - len = span of time between keyframes - * - len1 = length of handle of start key - * - len2 = length of handle of end key + /* Calculate distances: + * - len = Span of time between keyframes. + * - len1 = Length of handle of start key. + * - len2 = Length of handle of end key. */ len = v4[0] - v1[0]; len1 = fabsf(h1[0]); len2 = fabsf(h2[0]); - /* if the handles have no length, no need to do any corrections */ + /* If the handles have no length, no need to do any corrections. */ if ((len1 + len2) == 0.0f) { return; } - /* the two handles cross over each other, so force them - * apart using the proportion they overlap - */ - if ((len1 + len2) > len) { - fac = len / (len1 + len2); - + /* To prevent looping or rewinding, handles cannot + * exceed the adjacent key-frames time position. */ + if (len1 > len) { + fac = len / len1; v2[0] = (v1[0] - fac * h1[0]); v2[1] = (v1[1] - fac * h1[1]); + } + if (len2 > len) { + fac = len / len2; v3[0] = (v4[0] - fac * h2[0]); v3[1] = (v4[1] - fac * h2[1]); } } -/* find root ('zero') */ -static int findzero(float x, float q0, float q1, float q2, float q3, float *o) +/** Find roots of cubic equation (c0 x³ + c1 x² + c2 x + c3) + * \return number of roots in `o`. + * NOTE: it is up to the caller to allocate enough memory for `o`. */ +static int solve_cubic(double c0, double c1, double c2, double c3, float *o) { - double c0, c1, c2, c3, a, b, c, p, q, d, t, phi; + double a, b, c, p, q, d, t, phi; int nr = 0; - c0 = q0 - x; - c1 = 3.0f * (q1 - q0); - c2 = 3.0f * (q0 - 2.0f * q1 + q2); - c3 = q3 - q0 + 3.0f * (q1 - q2); - if (c3 != 0.0) { a = c2 / c3; b = c1 / c3; @@ -1423,7 +1557,7 @@ static int findzero(float x, float q0, float q1, float q2, float q3, float *o) c = c0; if (a != 0.0) { - /* discriminant */ + /* Discriminant */ p = b * b - 4 * a * c; if (p > 0) { @@ -1468,6 +1602,17 @@ static int findzero(float x, float q0, float q1, float q2, float q3, float *o) return 0; } +/* Find root(s) ('zero') of a Bezier curve. */ +static int findzero(float x, float q0, float q1, float q2, float q3, float *o) +{ + const double c0 = q0 - x; + const double c1 = 3.0f * (q1 - q0); + const double c2 = 3.0f * (q0 - 2.0f * q1 + q2); + const double c3 = q3 - q0 + 3.0f * (q1 - q2); + + return solve_cubic(c0, c1, c2, c3, o); +} + static void berekeny(float f1, float f2, float f3, float f4, float *o, int b) { float t, c0, c1, c2, c3; @@ -1484,6 +1629,75 @@ static void berekeny(float f1, float f2, float f3, float f4, float *o, int b) } } +/** + * Adjust Bezier handles of all three given BezTriples, so that `bezt` can be inserted between + * `prev` and `next` without changing the resulting curve shape. + * + * \param r_pdelta: return Y difference between `bezt` and the original curve value at its X + * position. + * \return Whether the split was successful. + */ +bool BKE_fcurve_bezt_subdivide_handles(struct BezTriple *bezt, + struct BezTriple *prev, + struct BezTriple *next, + float *r_pdelta) +{ + /* The four points that make up this section of the Bezier curve. */ + const float *prev_coords = prev->vec[1]; + float *prev_handle_right = prev->vec[2]; + float *next_handle_left = next->vec[0]; + const float *next_coords = next->vec[1]; + + float *new_handle_left = bezt->vec[0]; + const float *new_coords = bezt->vec[1]; + float *new_handle_right = bezt->vec[2]; + + if (new_coords[0] <= prev_coords[0] || new_coords[0] >= next_coords[0]) { + /* The new keyframe is outside the (prev_coords, next_coords) range. */ + return false; + } + + /* Apply evaluation-time limits and compute the effective curve. */ + BKE_fcurve_correct_bezpart(prev_coords, prev_handle_right, next_handle_left, next_coords); + float roots[4]; + if (!findzero(new_coords[0], + prev_coords[0], + prev_handle_right[0], + next_handle_left[0], + next_coords[0], + roots)) { + return false; + } + + const float t = roots[0]; /* Percentage of the curve at which the split should occur. */ + if (t <= 0.0f || t >= 1.0f) { + /* The split would occur outside the curve, which isn't possible. */ + return false; + } + + /* De Casteljau split, requires three iterations of splitting. + * See https://pomax.github.io/bezierinfo/#decasteljau */ + float split1[3][2], split2[2][2], split3[2]; + interp_v2_v2v2(split1[0], prev_coords, prev_handle_right, t); + interp_v2_v2v2(split1[1], prev_handle_right, next_handle_left, t); + interp_v2_v2v2(split1[2], next_handle_left, next_coords, t); + interp_v2_v2v2(split2[0], split1[0], split1[1], t); + interp_v2_v2v2(split2[1], split1[1], split1[2], t); + interp_v2_v2v2(split3, split2[0], split2[1], t); + + /* Update the existing handles. */ + copy_v2_v2(prev_handle_right, split1[0]); + copy_v2_v2(next_handle_left, split1[2]); + + float diff_coords[2]; + sub_v2_v2v2(diff_coords, new_coords, split3); + add_v2_v2v2(new_handle_left, split2[0], diff_coords); + add_v2_v2v2(new_handle_right, split2[1], diff_coords); + + *r_pdelta = diff_coords[1]; + return true; +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -1543,36 +1757,36 @@ static float fcurve_eval_keyframes_interpolate(FCurve *fcu, BezTriple *bezts, fl BezTriple *bezt, *prevbezt; unsigned int a; - /* evaltime occurs somewhere in the middle of the curve */ + /* Evaltime occurs somewhere in the middle of the curve. */ bool exact = false; /* Use binary search to find appropriate keyframes... * * The threshold here has the following constraints: * - 0.001 is too coarse: - * We get artifacts with 2cm driver movements at 1BU = 1m (see T40332) + * We get artifacts with 2cm driver movements at 1BU = 1m (see T40332). * * - 0.00001 is too fine: * Weird errors, like selecting the wrong keyframe range (see T39207), occur. * This lower bound was established in b888a32eee8147b028464336ad2404d8155c64dd. */ - a = binarysearch_bezt_index_ex(bezts, evaltime, fcu->totvert, 0.0001, &exact); + a = BKE_fcurve_bezt_binarysearch_index_ex(bezts, evaltime, fcu->totvert, 0.0001, &exact); bezt = bezts + a; if (exact) { - /* index returned must be interpreted differently when it sits on top of an existing keyframe - * - that keyframe is the start of the segment we need (see action_bug_2.blend in T39207) + /* Index returned must be interpreted differently when it sits on top of an existing keyframe + * - That keyframe is the start of the segment we need (see action_bug_2.blend in T39207). */ return bezt->vec[1][1]; } - /* index returned refers to the keyframe that the eval-time occurs *before* - * - hence, that keyframe marks the start of the segment we're dealing with + /* Index returned refers to the keyframe that the eval-time occurs *before* + * - hence, that keyframe marks the start of the segment we're dealing with. */ prevbezt = (a > 0) ? (bezt - 1) : bezt; /* Use if the key is directly on the frame, in rare cases this is needed else we get 0.0 instead. - * XXX: consult T39207 for examples of files where failure of these checks can cause issues */ + * XXX: consult T39207 for examples of files where failure of these checks can cause issues. */ if (fabsf(bezt->vec[1][0] - evaltime) < eps) { return bezt->vec[1][1]; } @@ -1596,25 +1810,25 @@ static float fcurve_eval_keyframes_interpolate(FCurve *fcu, BezTriple *bezts, fl const float amplitude = prevbezt->amplitude; const float period = prevbezt->period; - /* value depends on interpolation mode */ + /* Value depends on interpolation mode. */ if ((prevbezt->ipo == BEZT_IPO_CONST) || (fcu->flag & FCURVE_DISCRETE_VALUES) || (duration == 0)) { - /* constant (evaltime not relevant, so no interpolation needed) */ + /* Constant (evaltime not relevant, so no interpolation needed). */ return prevbezt->vec[1][1]; } switch (prevbezt->ipo) { - /* interpolation ...................................... */ + /* Interpolation ...................................... */ case BEZT_IPO_BEZ: { float v1[2], v2[2], v3[2], v4[2], opl[32]; - /* bezier interpolation */ - /* (v1, v2) are the first keyframe and its 2nd handle */ + /* Bezier interpolation. */ + /* (v1, v2) are the first keyframe and its 2nd handle. */ v1[0] = prevbezt->vec[1][0]; v1[1] = prevbezt->vec[1][1]; v2[0] = prevbezt->vec[2][0]; v2[1] = prevbezt->vec[2][1]; - /* (v3, v4) are the last keyframe's 1st handle + the last keyframe */ + /* (v3, v4) are the last keyframe's 1st handle + the last keyframe. */ v3[0] = bezt->vec[0][0]; v3[1] = bezt->vec[0][1]; v4[0] = bezt->vec[1][0]; @@ -1623,14 +1837,14 @@ static float fcurve_eval_keyframes_interpolate(FCurve *fcu, BezTriple *bezts, fl if (fabsf(v1[1] - v4[1]) < FLT_EPSILON && fabsf(v2[1] - v3[1]) < FLT_EPSILON && fabsf(v3[1] - v4[1]) < FLT_EPSILON) { /* Optimization: If all the handles are flat/at the same values, - * the value is simply the shared value (see T40372 -> F91346) + * the value is simply the shared value (see T40372 -> F91346). */ return v1[1]; } - /* adjust handles so that they don't overlap (forming a loop) */ - correct_bezpart(v1, v2, v3, v4); + /* Adjust handles so that they don't overlap (forming a loop). */ + BKE_fcurve_correct_bezpart(v1, v2, v3, v4); - /* try to get a value for this position - if failure, try another set of points */ + /* Try to get a value for this position - if failure, try another set of points. */ if (!findzero(evaltime, v1[0], v2[0], v3[0], v4[0], opl)) { if (G.debug & G_DEBUG) { printf(" ERROR: findzero() failed at %f with %f %f %f %f\n", @@ -1647,10 +1861,10 @@ static float fcurve_eval_keyframes_interpolate(FCurve *fcu, BezTriple *bezts, fl return opl[0]; } case BEZT_IPO_LIN: - /* linear - simply linearly interpolate between values of the two keyframes */ + /* Linear - simply linearly interpolate between values of the two keyframes. */ return BLI_easing_linear_ease(time, begin, change, duration); - /* easing ............................................ */ + /* Easing ............................................ */ case BEZT_IPO_BACK: switch (prevbezt->easing) { case BEZT_IPO_EASE_IN: @@ -1660,7 +1874,7 @@ static float fcurve_eval_keyframes_interpolate(FCurve *fcu, BezTriple *bezts, fl case BEZT_IPO_EASE_IN_OUT: return BLI_easing_back_ease_in_out(time, begin, change, duration, prevbezt->back); - default: /* default/auto: same as ease out */ + default: /* Default/Auto: same as ease out. */ return BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back); } break; @@ -1674,7 +1888,7 @@ static float fcurve_eval_keyframes_interpolate(FCurve *fcu, BezTriple *bezts, fl case BEZT_IPO_EASE_IN_OUT: return BLI_easing_bounce_ease_in_out(time, begin, change, duration); - default: /* default/auto: same as ease out */ + default: /* Default/Auto: same as ease out. */ return BLI_easing_bounce_ease_out(time, begin, change, duration); } break; @@ -1688,7 +1902,7 @@ static float fcurve_eval_keyframes_interpolate(FCurve *fcu, BezTriple *bezts, fl case BEZT_IPO_EASE_IN_OUT: return BLI_easing_circ_ease_in_out(time, begin, change, duration); - default: /* default/auto: same as ease in */ + default: /* Default/Auto: same as ease in. */ return BLI_easing_circ_ease_in(time, begin, change, duration); } break; @@ -1702,7 +1916,7 @@ static float fcurve_eval_keyframes_interpolate(FCurve *fcu, BezTriple *bezts, fl case BEZT_IPO_EASE_IN_OUT: return BLI_easing_cubic_ease_in_out(time, begin, change, duration); - default: /* default/auto: same as ease in */ + default: /* Default/Auto: same as ease in. */ return BLI_easing_cubic_ease_in(time, begin, change, duration); } break; @@ -1716,7 +1930,7 @@ static float fcurve_eval_keyframes_interpolate(FCurve *fcu, BezTriple *bezts, fl case BEZT_IPO_EASE_IN_OUT: return BLI_easing_elastic_ease_in_out(time, begin, change, duration, amplitude, period); - default: /* default/auto: same as ease out */ + default: /* Default/Auto: same as ease out. */ return BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period); } break; @@ -1730,7 +1944,7 @@ static float fcurve_eval_keyframes_interpolate(FCurve *fcu, BezTriple *bezts, fl case BEZT_IPO_EASE_IN_OUT: return BLI_easing_expo_ease_in_out(time, begin, change, duration); - default: /* default/auto: same as ease in */ + default: /* Default/Auto: same as ease in. */ return BLI_easing_expo_ease_in(time, begin, change, duration); } break; @@ -1744,7 +1958,7 @@ static float fcurve_eval_keyframes_interpolate(FCurve *fcu, BezTriple *bezts, fl case BEZT_IPO_EASE_IN_OUT: return BLI_easing_quad_ease_in_out(time, begin, change, duration); - default: /* default/auto: same as ease in */ + default: /* Default/Auto: same as ease in. */ return BLI_easing_quad_ease_in(time, begin, change, duration); } break; @@ -1758,7 +1972,7 @@ static float fcurve_eval_keyframes_interpolate(FCurve *fcu, BezTriple *bezts, fl case BEZT_IPO_EASE_IN_OUT: return BLI_easing_quart_ease_in_out(time, begin, change, duration); - default: /* default/auto: same as ease in */ + default: /* Default/Auto: same as ease in. */ return BLI_easing_quart_ease_in(time, begin, change, duration); } break; @@ -1772,7 +1986,7 @@ static float fcurve_eval_keyframes_interpolate(FCurve *fcu, BezTriple *bezts, fl case BEZT_IPO_EASE_IN_OUT: return BLI_easing_quint_ease_in_out(time, begin, change, duration); - default: /* default/auto: same as ease in */ + default: /* Default/Auto: same as ease in. */ return BLI_easing_quint_ease_in(time, begin, change, duration); } break; @@ -1786,7 +2000,7 @@ static float fcurve_eval_keyframes_interpolate(FCurve *fcu, BezTriple *bezts, fl case BEZT_IPO_EASE_IN_OUT: return BLI_easing_sine_ease_in_out(time, begin, change, duration); - default: /* default/auto: same as ease in */ + default: /* Default/Auto: same as ease in. */ return BLI_easing_sine_ease_in(time, begin, change, duration); } break; @@ -1798,7 +2012,7 @@ static float fcurve_eval_keyframes_interpolate(FCurve *fcu, BezTriple *bezts, fl return 0.0f; } -/* Calculate F-Curve value for 'evaltime' using BezTriple keyframes */ +/* Calculate F-Curve value for 'evaltime' using #BezTriple keyframes. */ static float fcurve_eval_keyframes(FCurve *fcu, BezTriple *bezts, float evaltime) { if (evaltime <= bezts->vec[1][0]) { @@ -1813,32 +2027,32 @@ static float fcurve_eval_keyframes(FCurve *fcu, BezTriple *bezts, float evaltime return fcurve_eval_keyframes_interpolate(fcu, bezts, evaltime); } -/* Calculate F-Curve value for 'evaltime' using FPoint samples */ +/* Calculate F-Curve value for 'evaltime' using #FPoint samples. */ static float fcurve_eval_samples(FCurve *fcu, FPoint *fpts, float evaltime) { FPoint *prevfpt, *lastfpt, *fpt; float cvalue = 0.0f; - /* get pointers */ + /* Get pointers. */ prevfpt = fpts; lastfpt = prevfpt + fcu->totvert - 1; - /* evaluation time at or past endpoints? */ + /* Evaluation time at or past endpoints? */ if (prevfpt->vec[0] >= evaltime) { - /* before or on first sample, so just extend value */ + /* Before or on first sample, so just extend value. */ cvalue = prevfpt->vec[1]; } else if (lastfpt->vec[0] <= evaltime) { - /* after or on last sample, so just extend value */ + /* After or on last sample, so just extend value. */ cvalue = lastfpt->vec[1]; } else { float t = fabsf(evaltime - floorf(evaltime)); - /* find the one on the right frame (assume that these are spaced on 1-frame intervals) */ + /* Find the one on the right frame (assume that these are spaced on 1-frame intervals). */ fpt = prevfpt + ((int)evaltime - (int)prevfpt->vec[0]); - /* if not exactly on the frame, perform linear interpolation with the next one */ + /* If not exactly on the frame, perform linear interpolation with the next one. */ if ((t != 0.0f) && (t < 1.0f)) { cvalue = interpf(fpt->vec[1], (fpt + 1)->vec[1], 1.0f - t); } @@ -1847,7 +2061,6 @@ static float fcurve_eval_samples(FCurve *fcu, FPoint *fpts, float evaltime) } } - /* return value */ return cvalue; } @@ -1858,13 +2071,13 @@ static float fcurve_eval_samples(FCurve *fcu, FPoint *fpts, float evaltime) * \{ */ /* Evaluate and return the value of the given F-Curve at the specified frame ("evaltime") - * Note: this is also used for drivers + * Note: this is also used for drivers. */ static float evaluate_fcurve_ex(FCurve *fcu, float evaltime, float cvalue) { float devaltime; - /* evaluate modifiers which modify time to evaluate the base curve at */ + /* Evaluate modifiers which modify time to evaluate the base curve at. */ FModifiersStackStorage storage; storage.modifier_count = BLI_listbase_count(&fcu->modifiers); storage.size_per_modifier = evaluate_fmodifiers_storage_size_per_modifier(&fcu->modifiers); @@ -1872,9 +2085,9 @@ static float evaluate_fcurve_ex(FCurve *fcu, float evaltime, float cvalue) devaltime = evaluate_time_fmodifiers(&storage, &fcu->modifiers, fcu, cvalue, evaltime); - /* evaluate curve-data + /* Evaluate curve-data * - 'devaltime' instead of 'evaltime', as this is the time that the last time-modifying - * F-Curve modifier on the stack requested the curve to be evaluated at + * F-Curve modifier on the stack requested the curve to be evaluated at. */ if (fcu->bezt) { cvalue = fcurve_eval_keyframes(fcu, fcu->bezt, devaltime); @@ -1883,17 +2096,16 @@ static float evaluate_fcurve_ex(FCurve *fcu, float evaltime, float cvalue) cvalue = fcurve_eval_samples(fcu, fcu->fpt, devaltime); } - /* evaluate modifiers */ + /* Evaluate modifiers. */ evaluate_value_fmodifiers(&storage, &fcu->modifiers, fcu, &cvalue, devaltime); - /* if curve can only have integral values, perform truncation (i.e. drop the decimal part) - * here so that the curve can be sampled correctly + /* If curve can only have integral values, perform truncation (i.e. drop the decimal part) + * here so that the curve can be sampled correctly. */ if (fcu->flag & FCURVE_INT_VALUES) { cvalue = floorf(cvalue + 0.5f); } - /* return evaluated value */ return cvalue; } @@ -1925,19 +2137,19 @@ float evaluate_fcurve_driver(PathResolvedRNA *anim_rna, * evaluate it to find value to use as "evaltime" since drivers essentially act as alternative * input (i.e. in place of 'time') for F-Curves. */ if (fcu->driver) { - /* evaltime now serves as input for the curve */ + /* Evaltime now serves as input for the curve. */ evaltime = evaluate_driver(anim_rna, fcu->driver, driver_orig, anim_eval_context); - /* only do a default 1-1 mapping if it's unlikely that anything else will set a value... */ + /* Only do a default 1-1 mapping if it's unlikely that anything else will set a value... */ if (fcu->totvert == 0) { FModifier *fcm; bool do_linear = true; - /* out-of-range F-Modifiers will block, as will those which just plain overwrite the values + /* Out-of-range F-Modifiers will block, as will those which just plain overwrite the values * XXX: additive is a bit more dicey; it really depends then if things are in range or not... */ for (fcm = fcu->modifiers.first; fcm; fcm = fcm->next) { - /* if there are range-restrictions, we must definitely block [#36950] */ + /* If there are range-restrictions, we must definitely block T36950. */ if ((fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) == 0 || ((fcm->sfra <= evaltime) && (fcm->efra >= evaltime))) { /* Within range: here it probably doesn't matter, @@ -1950,7 +2162,7 @@ float evaluate_fcurve_driver(PathResolvedRNA *anim_rna, } } - /* only copy over results if none of the modifiers disagreed with this */ + /* Only copy over results if none of the modifiers disagreed with this. */ if (do_linear) { cvalue = evaltime; } @@ -1967,19 +2179,19 @@ bool BKE_fcurve_is_empty(FCurve *fcu) !list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE); } -/* Calculate the value of the given F-Curve at the given frame, and set its curval */ +/* Calculate the value of the given F-Curve at the given frame, and set its curval. */ float calculate_fcurve(PathResolvedRNA *anim_rna, FCurve *fcu, const AnimationEvalContext *anim_eval_context) { - /* only calculate + set curval (overriding the existing value) if curve has + /* Only calculate + set curval (overriding the existing value) if curve has * any data which warrants this... */ if (BKE_fcurve_is_empty(fcu)) { return 0.0f; } - /* calculate and set curval (evaluates driver too if necessary) */ + /* Calculate and set curval (evaluates driver too if necessary). */ float curval; if (fcu->driver) { curval = evaluate_fcurve_driver(anim_rna, fcu, fcu->driver, anim_eval_context); @@ -1987,7 +2199,7 @@ float calculate_fcurve(PathResolvedRNA *anim_rna, else { curval = evaluate_fcurve(fcu, anim_eval_context->eval_time); } - fcu->curval = curval; /* debug display only, not thread safe! */ + fcu->curval = curval; /* Debug display only, not thread safe! */ return curval; } @@ -2161,7 +2373,7 @@ void BKE_fcurve_blend_read_data(BlendDataReader *reader, ListBase *fcurves) /* group */ BLO_read_data_address(reader, &fcu->grp); - /* clear disabled flag - allows disabled drivers to be tried again ([#32155]), + /* clear disabled flag - allows disabled drivers to be tried again (T32155), * but also means that another method for "reviving disabled F-Curves" exists */ fcu->flag &= ~FCURVE_DISABLED; @@ -2176,9 +2388,8 @@ void BKE_fcurve_blend_read_data(BlendDataReader *reader, ListBase *fcurves) driver->expr_comp = NULL; driver->expr_simple = NULL; - /* give the driver a fresh chance - the operating environment may be different now - * (addons, etc. may be different) so the driver namespace may be sane now [#32155] - */ + /* Give the driver a fresh chance - the operating environment may be different now + * (addons, etc. may be different) so the driver namespace may be sane now T32155. */ driver->flag &= ~DRIVER_FLAG_INVALID; /* relink variables, targets and their paths */ |