diff options
-rw-r--r-- | release/scripts/startup/bl_ui/space_graph.py | 1 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_fcurve.h | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/fcurve.c | 78 | ||||
-rw-r--r-- | source/blender/editors/space_graph/graph_edit.c | 69 | ||||
-rw-r--r-- | source/blender/editors/space_graph/graph_intern.h | 1 | ||||
-rw-r--r-- | source/blender/editors/space_graph/graph_ops.c | 1 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_fcurve_api.c | 47 |
7 files changed, 154 insertions, 46 deletions
diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py index 1bf7465e54c..3fee0ae9d47 100644 --- a/release/scripts/startup/bl_ui/space_graph.py +++ b/release/scripts/startup/bl_ui/space_graph.py @@ -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") diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index c9bc5e83a1f..f527f40d0d7 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -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); diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index c4055c0f611..bd7d65f1e6f 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -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 diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index b25a275a0ab..753e41b7ec7 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -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 *********************** */ diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h index eaa14fedb93..7add2f7cbb8 100644 --- a/source/blender/editors/space_graph/graph_intern.h +++ b/source/blender/editors/space_graph/graph_intern.h @@ -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); diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index fd68303e759..63acc2a1774 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -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); diff --git a/source/blender/makesrna/intern/rna_fcurve_api.c b/source/blender/makesrna/intern/rna_fcurve_api.c index f7be65b4e75..5a720b91f87 100644 --- a/source/blender/makesrna/intern/rna_fcurve_api.c +++ b/source/blender/makesrna/intern/rna_fcurve_api.c @@ -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); } } |