/* NOTE: this is exported to other modules that use the ActKeyColumns for finding keyframes */ short compare_ak_cfraPtr(void *node, void *data) { ActKeyColumn *ak = (ActKeyColumn *)node; const float *cframe = data; float val = *cframe; if (IS_EQT(val, ak->cfra, BEZT_BINARYSEARCH_THRESH)) return 0; if (val < ak->cfra) return -1; else if (val > ak->cfra) return 1; else return 0; }
/* Basic F-Curve 'cleanup' function that removes 'double points' and unnecessary keyframes on linear-segments only */ void clean_fcurve(FCurve *fcu, float thresh) { BezTriple *old_bezts, *bezt, *beztn; BezTriple *lastb; int totCount, i; /* check if any points */ if ((fcu == NULL) || (fcu->bezt == NULL) || (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], 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]; /* 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], 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], 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], 0); } else if (IS_EQT(cur[1], next[1], thresh) == 0) { /* add new keyframe */ insert_vert_fcurve(fcu, cur[0], cur[1], 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], 0); } } } } /* now free the memory used by the old BezTriples */ if (old_bezts) MEM_freeN(old_bezts); }
/* 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], 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], 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], 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], 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], 0); } else if (IS_EQT(cur[1], next[1], thresh) == 0) { /* add new keyframe */ insert_vert_fcurve(fcu, cur[0], cur[1], 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], 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 - same value(s)? * -> firstly, handles must have same central value as each other * -> secondly, handles which control that section of the curve must be constant */ if (prev == NULL) return; 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 (BEZSELECTED(beztn)) ab->sel = SELECT; 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); }
int BKE_fcm_envelope_find_index(FCM_EnvelopeData array[], float frame, int arraylen, bool *r_exists) { int start = 0, end = arraylen; int loopbreaker = 0, maxloop = arraylen * 2; /* initialize exists-flag first */ *r_exists = 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 */ if ((arraylen <= 0) || (array == NULL)) { CLOG_WARN(&LOG, "encountered invalid array"); return 0; } else { /* check whether to add before/after/on */ float framenum; /* 'First' Point (when only one point, this case is used) */ framenum = array[0].time; if (IS_EQT(frame, framenum, BINARYSEARCH_FRAMEEQ_THRESH)) { *r_exists = true; return 0; } else if (frame < framenum) { return 0; } /* 'Last' Point */ framenum = array[(arraylen - 1)].time; if (IS_EQT(frame, framenum, BINARYSEARCH_FRAMEEQ_THRESH)) { *r_exists = true; return (arraylen - 1); } else if (frame > framenum) { return arraylen; } } /* 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 */ int mid = start + ((end - start) / 2); /* we calculate the midpoint this way to avoid int overflows... */ float midfra = array[mid].time; /* check if exactly equal to midpoint */ if (IS_EQT(frame, midfra, BINARYSEARCH_FRAMEEQ_THRESH)) { *r_exists = true; return mid; } /* repeat in upper/lower half */ if (frame > midfra) { start = mid + 1; } else if (frame < midfra) { end = mid - 1; } } /* print error if loop-limit exceeded */ if (loopbreaker == (maxloop - 1)) { CLOG_ERROR(&LOG, "binary search was taking too long"); // include debug info CLOG_ERROR(&LOG, "\tround = %d: start = %d, end = %d, arraylen = %d", loopbreaker, start, end, arraylen); } /* not found, so return where to place it */ return start; }