Add a Un-Bake FCurves operator

We already had the ability to bake fcurves but no way to convert the
baked result back without using python. This patch adds and operator
that is available now next to the bake operator in the drop down menu,

Reviewed By: Sybren

Differential Revision: http://developer.blender.org/D6379
This commit is contained in:
Sebastian Parborg 2020-10-28 11:45:24 +01:00
parent 2f7c6149fc
commit fb88d4eda8
7 changed files with 154 additions and 46 deletions

View File

@ -301,6 +301,7 @@ class GRAPH_MT_key(Menu):
layout.operator("graph.smooth")
layout.operator("graph.sample")
layout.operator("graph.bake")
layout.operator("graph.unbake")
layout.separator()
layout.operator("graph.euler_filter", text="Discontinuity (Euler) Filter")

View File

@ -325,6 +325,9 @@ float fcurve_samplingcb_evalcurve(struct FCurve *fcu, void *data, float evaltime
void fcurve_store_samples(
struct FCurve *fcu, void *data, int start, int end, FcuSampleFunc sample_cb);
/* Convert baked/sampled fcurves into bezt/regular fcurves. */
void fcurve_samples_to_keyframes(struct FCurve *fcu, const int start, const int end);
/* ************* F-Curve .blend file API ******************** */
void BKE_fmodifiers_blend_write(struct BlendWriter *writer, struct ListBase *fmodifiers);

View File

@ -1064,6 +1064,84 @@ void fcurve_store_samples(FCurve *fcu, void *data, int start, int end, FcuSample
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

View File

@ -1863,6 +1863,75 @@ void GRAPH_OT_bake(wmOperatorType *ot)
/* TODO: add props for start/end frames (Joshua Leung 2009) */
}
/* ******************** Un-Bake F-Curve Operator *********************** */
/* This operator unbakes the data of the selected F-Points to F-Curves. */
/* Un-Bake F-Points into F-Curves. */
static void unbake_graph_curves(bAnimContext *ac, int start, int end)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
/* Filter data. */
const int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL |
ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through filtered data and add keys between selected keyframes on every frame. */
for (ale = anim_data.first; ale; ale = ale->next) {
FCurve *fcu = (FCurve *)ale->key_data;
fcurve_samples_to_keyframes(fcu, start, end);
ale->update |= ANIM_UPDATE_DEPS;
}
ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
static int graphkeys_unbake_exec(bContext *C, wmOperator *UNUSED(op))
{
bAnimContext ac;
Scene *scene = NULL;
int start, end;
/* Get editor data. */
if (ANIM_animdata_get_context(C, &ac) == 0) {
return OPERATOR_CANCELLED;
}
scene = ac.scene;
start = PSFRA;
end = PEFRA;
/* Unbake keyframes. */
unbake_graph_curves(&ac, start, end);
/* Set notifier that keyframes have changed. */
/* NOTE: some distinction between order/number of keyframes and type should be made? */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
void GRAPH_OT_unbake(wmOperatorType *ot)
{
/* Identifiers */
ot->name = "Un-Bake Curve";
ot->idname = "GRAPH_OT_unbake";
ot->description = "Un-Bake selected F-Points to F-Curves";
/* API callbacks */
ot->exec = graphkeys_unbake_exec;
ot->poll = graphop_selected_fcurve_poll;
/* Flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
#ifdef WITH_AUDASPACE
/* ******************** Sound Bake F-Curve Operator *********************** */

View File

@ -103,6 +103,7 @@ void GRAPH_OT_clean(struct wmOperatorType *ot);
void GRAPH_OT_decimate(struct wmOperatorType *ot);
void GRAPH_OT_sample(struct wmOperatorType *ot);
void GRAPH_OT_bake(struct wmOperatorType *ot);
void GRAPH_OT_unbake(struct wmOperatorType *ot);
void GRAPH_OT_sound_bake(struct wmOperatorType *ot);
void GRAPH_OT_smooth(struct wmOperatorType *ot);
void GRAPH_OT_euler_filter(struct wmOperatorType *ot);

View File

@ -459,6 +459,7 @@ void graphedit_operatortypes(void)
WM_operatortype_append(GRAPH_OT_easing_type);
WM_operatortype_append(GRAPH_OT_sample);
WM_operatortype_append(GRAPH_OT_bake);
WM_operatortype_append(GRAPH_OT_unbake);
WM_operatortype_append(GRAPH_OT_sound_bake);
WM_operatortype_append(GRAPH_OT_smooth);
WM_operatortype_append(GRAPH_OT_clean);

View File

@ -76,52 +76,7 @@ static void rna_FCurve_convert_to_keyframes(FCurve *fcu, ReportList *reports, in
BKE_report(reports, RPT_WARNING, "FCurve has no sample points");
}
else {
BezTriple *bezt;
FPoint *fpt = fcu->fpt;
int tot_kf = end - start;
int tot_sp = fcu->totvert;
bezt = fcu->bezt = MEM_callocN(sizeof(*fcu->bezt) * (size_t)tot_kf, __func__);
fcu->totvert = tot_kf;
/* Get first sample point to 'copy' as keyframe. */
for (; tot_sp && (fpt->vec[0] < (float)start); fpt++, tot_sp--) {
/* pass */
}
/* Add heading dummy flat points if needed. */
for (; tot_kf && (fpt->vec[0] > (float)start); start++, bezt++, tot_kf--) {
/* Linear interpolation, of course. */
bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
bezt->ipo = BEZT_IPO_LIN;
bezt->h1 = bezt->h2 = HD_AUTO_ANIM;
bezt->vec[1][0] = (float)start;
bezt->vec[1][1] = fpt->vec[1];
}
/* Copy actual sample points. */
for (; tot_kf && tot_sp; start++, bezt++, tot_kf--, fpt++, tot_sp--) {
/* Linear interpolation, of course. */
bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
bezt->ipo = BEZT_IPO_LIN;
bezt->h1 = bezt->h2 = HD_AUTO_ANIM;
copy_v2_v2(bezt->vec[1], fpt->vec);
}
/* Add leading dummy flat points if needed. */
for (fpt--; tot_kf; start++, bezt++, tot_kf--) {
/* Linear interpolation, of course. */
bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
bezt->ipo = BEZT_IPO_LIN;
bezt->h1 = bezt->h2 = HD_AUTO_ANIM;
bezt->vec[1][0] = (float)start;
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);
fcurve_samples_to_keyframes(fcu, start, end);
WM_main_add_notifier(NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
}
}