static void delete_action_keys (bAnimContext *ac) { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; int filter; /* filter data */ if (ac->datatype == ANIMCONT_GPENCIL) filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); else filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY | ANIMFILTER_NODUPLIS); ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* loop through filtered data and delete selected keys */ for (ale= anim_data.first; ale; ale= ale->next) { if (ale->type != ANIMTYPE_GPLAYER) { FCurve *fcu= (FCurve *)ale->key_data; AnimData *adt= ale->adt; /* delete selected keyframes only */ delete_fcurve_keys(fcu); /* Only delete curve too if it won't be doing anything anymore */ if ((fcu->totvert == 0) && (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0)) ANIM_fcurve_delete_from_animdata(ac, adt, fcu); } else delete_gplayer_frames((bGPDlayer *)ale->data); } /* free filtered list */ BLI_freelistN(&anim_data); }
static bool delete_action_keys(bAnimContext *ac) { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; int filter; bool changed_final = false; /* filter data */ if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); else filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* loop through filtered data and delete selected keys */ for (ale = anim_data.first; ale; ale = ale->next) { bool changed = false; if (ale->type == ANIMTYPE_GPLAYER) { changed = ED_gplayer_frames_delete((bGPDlayer *)ale->data); } else if (ale->type == ANIMTYPE_MASKLAYER) { changed = ED_masklayer_frames_delete((MaskLayer *)ale->data); } else { FCurve *fcu = (FCurve *)ale->key_data; AnimData *adt = ale->adt; /* delete selected keyframes only */ changed = delete_fcurve_keys(fcu); /* Only delete curve too if it won't be doing anything anymore */ if ((fcu->totvert == 0) && (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0)) { ANIM_fcurve_delete_from_animdata(ac, adt, fcu); ale->key_data = NULL; } } if (changed) { ale->update |= ANIM_UPDATE_DEFAULT; changed_final = true; } } ANIM_animdata_update(ac, &anim_data); ANIM_animdata_freelist(&anim_data); return changed_final; }
/* this function is responsible for setting extrapolation mode for keyframes */ static void setexpo_action_keys(bAnimContext *ac, short mode) { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; int filter; /* filter data */ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_SEL /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* loop through setting mode per F-Curve */ for (ale = anim_data.first; ale; ale = ale->next) { FCurve *fcu = (FCurve *)ale->data; if (mode >= 0) { /* just set mode setting */ fcu->extend = mode; } else { /* shortcuts for managing Cycles F-Modifiers to make it easier to toggle cyclic animation * without having to go through FModifier UI in Graph Editor to do so */ if (mode == MAKE_CYCLIC_EXPO) { /* only add if one doesn't exist */ if (list_has_suitable_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES, -1) == 0) { /* TODO: add some more preset versions which set different extrapolation options? */ add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES); } } else if (mode == CLEAR_CYCLIC_EXPO) { /* remove all the modifiers fitting this description */ FModifier *fcm, *fcn = NULL; for (fcm = fcu->modifiers.first; fcm; fcm = fcn) { fcn = fcm->next; if (fcm->type == FMODIFIER_TYPE_CYCLES) remove_fmodifier(&fcu->modifiers, fcm); } } } ale->update |= ANIM_UPDATE_DEFAULT; } ANIM_animdata_update(ac, &anim_data); ANIM_animdata_freelist(&anim_data); }
/* 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; } } } }