From 1f09dcc121ab31fe08c76947820ed59ec8f76788 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Mon, 23 Nov 2020 15:11:51 +0100 Subject: Cleanup: Animation, split `graph_edit.c` into separate files Split some of the code of `graph_edit.c` into: * `graph_view.c`: preview range, view all, view selected etc. * `graph_slider_ops.c`: the decimate modal operator code. The latter file will be extended later with more slider-based operators. Maniphest Tasks: T81785 Reviewed By: sybren Differential Revision: https://developer.blender.org/D9312 --- source/blender/editors/space_graph/graph_edit.c | 973 +----------------------- 1 file changed, 6 insertions(+), 967 deletions(-) (limited to 'source/blender/editors/space_graph/graph_edit.c') diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index bcd3adec1ab..1647fd4a6a6 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -61,7 +61,6 @@ #include "ED_keyframes_edit.h" #include "ED_keyframing.h" #include "ED_markers.h" -#include "ED_numinput.h" #include "ED_screen.h" #include "ED_transform.h" @@ -71,497 +70,7 @@ #include "graph_intern.h" /* ************************************************************************** */ -/* KEYFRAME-RANGE STUFF */ - -/* *************************** Calculate Range ************************** */ - -/* Get the min/max keyframes. */ -/* Note: it should return total boundbox, filter for selection only can be argument... */ -void get_graph_keyframe_extents(bAnimContext *ac, - float *xmin, - float *xmax, - float *ymin, - float *ymax, - const bool do_sel_only, - const bool include_handles) -{ - Scene *scene = ac->scene; - SpaceGraph *sipo = (SpaceGraph *)ac->sl; - - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - /* Get data to filter, from Dopesheet. */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS); - if (sipo->flag & SIPO_SELCUVERTSONLY) { - filter |= ANIMFILTER_SEL; - } - - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - /* Set large values initial values that will be easy to override. */ - if (xmin) { - *xmin = 999999999.0f; - } - if (xmax) { - *xmax = -999999999.0f; - } - if (ymin) { - *ymin = 999999999.0f; - } - if (ymax) { - *ymax = -999999999.0f; - } - - /* Check if any channels to set range with. */ - if (anim_data.first) { - bool foundBounds = false; - - /* Go through channels, finding max extents. */ - for (ale = anim_data.first; ale; ale = ale->next) { - AnimData *adt = ANIM_nla_mapping_get(ac, ale); - FCurve *fcu = (FCurve *)ale->key_data; - float txmin, txmax, tymin, tymax; - float unitFac, offset; - - /* Get range. */ - if (BKE_fcurve_calc_bounds( - fcu, &txmin, &txmax, &tymin, &tymax, do_sel_only, include_handles)) { - short mapping_flag = ANIM_get_normalization_flags(ac); - - /* Apply NLA scaling. */ - if (adt) { - txmin = BKE_nla_tweakedit_remap(adt, txmin, NLATIME_CONVERT_MAP); - txmax = BKE_nla_tweakedit_remap(adt, txmax, NLATIME_CONVERT_MAP); - } - - /* Apply unit corrections. */ - unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset); - tymin += offset; - tymax += offset; - tymin *= unitFac; - tymax *= unitFac; - - /* Try to set cur using these values, if they're more extreme than previously set values. - */ - if ((xmin) && (txmin < *xmin)) { - *xmin = txmin; - } - if ((xmax) && (txmax > *xmax)) { - *xmax = txmax; - } - if ((ymin) && (tymin < *ymin)) { - *ymin = tymin; - } - if ((ymax) && (tymax > *ymax)) { - *ymax = tymax; - } - - foundBounds = true; - } - } - - /* Ensure that the extents are not too extreme that view implodes...*/ - if (foundBounds) { - if ((xmin && xmax) && (fabsf(*xmax - *xmin) < 0.001f)) { - *xmin -= 0.0005f; - *xmax += 0.0005f; - } - if ((ymin && ymax) && (fabsf(*ymax - *ymin) < 0.001f)) { - *ymax -= 0.0005f; - *ymax += 0.0005f; - } - } - else { - if (xmin) { - *xmin = (float)PSFRA; - } - if (xmax) { - *xmax = (float)PEFRA; - } - if (ymin) { - *ymin = -5; - } - if (ymax) { - *ymax = 5; - } - } - - /* Free memory. */ - ANIM_animdata_freelist(&anim_data); - } - else { - /* Set default range. */ - if (ac->scene) { - if (xmin) { - *xmin = (float)PSFRA; - } - if (xmax) { - *xmax = (float)PEFRA; - } - } - else { - if (xmin) { - *xmin = -5; - } - if (xmax) { - *xmax = 100; - } - } - - if (ymin) { - *ymin = -5; - } - if (ymax) { - *ymax = 5; - } - } -} - -/* ****************** Automatic Preview-Range Operator ****************** */ - -static int graphkeys_previewrange_exec(bContext *C, wmOperator *UNUSED(op)) -{ - bAnimContext ac; - Scene *scene; - float min, max; - - /* Get editor data. */ - if (ANIM_animdata_get_context(C, &ac) == 0) { - return OPERATOR_CANCELLED; - } - if (ac.scene == NULL) { - return OPERATOR_CANCELLED; - } - - scene = ac.scene; - - /* Set the range directly. */ - get_graph_keyframe_extents(&ac, &min, &max, NULL, NULL, false, false); - scene->r.flag |= SCER_PRV_RANGE; - scene->r.psfra = round_fl_to_int(min); - scene->r.pefra = round_fl_to_int(max); - - /* Set notifier that things have changed. */ - // XXX Err... there's nothing for frame ranges yet, but this should do fine too. - WM_event_add_notifier(C, NC_SCENE | ND_FRAME, ac.scene); - - return OPERATOR_FINISHED; -} - -void GRAPH_OT_previewrange_set(wmOperatorType *ot) -{ - /* Identifiers */ - ot->name = "Auto-Set Preview Range"; - ot->idname = "GRAPH_OT_previewrange_set"; - ot->description = "Automatically set Preview Range based on range of keyframes"; - - /* API callbacks */ - ot->exec = graphkeys_previewrange_exec; - /* XXX: unchecked poll to get fsamples working too, but makes modifier damage trickier. */ - ot->poll = ED_operator_graphedit_active; - - /* Flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -/* ****************** View-All Operator ****************** */ - -static int graphkeys_viewall(bContext *C, - const bool do_sel_only, - const bool include_handles, - const int smooth_viewtx) -{ - bAnimContext ac; - rctf cur_new; - - /* Get editor data. */ - if (ANIM_animdata_get_context(C, &ac) == 0) { - return OPERATOR_CANCELLED; - } - - /* Set the horizontal range, with an extra offset so that the extreme keys will be in view. */ - get_graph_keyframe_extents(&ac, - &cur_new.xmin, - &cur_new.xmax, - &cur_new.ymin, - &cur_new.ymax, - do_sel_only, - include_handles); - - /* Give some more space at the borders. */ - BLI_rctf_scale(&cur_new, 1.1f); - - /* Take regions into account, that could block the view. - * Marker region is supposed to be larger than the scroll-bar, so prioritize it.*/ - float pad_top = UI_TIME_SCRUB_MARGIN_Y; - float pad_bottom = BLI_listbase_is_empty(ED_context_get_markers(C)) ? V2D_SCROLL_HANDLE_HEIGHT : - UI_MARKER_MARGIN_Y; - BLI_rctf_pad_y(&cur_new, ac.region->winy, pad_bottom, pad_top); - - UI_view2d_smooth_view(C, ac.region, &cur_new, smooth_viewtx); - return OPERATOR_FINISHED; -} - -/* ......... */ - -static int graphkeys_viewall_exec(bContext *C, wmOperator *op) -{ - const bool include_handles = RNA_boolean_get(op->ptr, "include_handles"); - const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); - - /* Whole range */ - return graphkeys_viewall(C, false, include_handles, smooth_viewtx); -} - -static int graphkeys_view_selected_exec(bContext *C, wmOperator *op) -{ - const bool include_handles = RNA_boolean_get(op->ptr, "include_handles"); - const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); - - /* Only selected. */ - return graphkeys_viewall(C, true, include_handles, smooth_viewtx); -} - -/* ......... */ - -void GRAPH_OT_view_all(wmOperatorType *ot) -{ - /* Identifiers */ - ot->name = "Frame All"; - ot->idname = "GRAPH_OT_view_all"; - ot->description = "Reset viewable area to show full keyframe range"; - - /* API callbacks */ - ot->exec = graphkeys_viewall_exec; - /* XXX: Unchecked poll to get fsamples working too, but makes modifier damage trickier... */ - ot->poll = ED_operator_graphedit_active; - - /* Flags */ - ot->flag = 0; - - /* Props */ - ot->prop = RNA_def_boolean(ot->srna, - "include_handles", - true, - "Include Handles", - "Include handles of keyframes when calculating extents"); -} - -void GRAPH_OT_view_selected(wmOperatorType *ot) -{ - /* Identifiers */ - ot->name = "Frame Selected"; - ot->idname = "GRAPH_OT_view_selected"; - ot->description = "Reset viewable area to show selected keyframe range"; - - /* API callbacks */ - ot->exec = graphkeys_view_selected_exec; - /* XXX: Unchecked poll to get fsamples working too, but makes modifier damage trickier... */ - ot->poll = ED_operator_graphedit_active; - - /* Flags */ - ot->flag = 0; - - /* Props */ - ot->prop = RNA_def_boolean(ot->srna, - "include_handles", - true, - "Include Handles", - "Include handles of keyframes when calculating extents"); -} - -/* ********************** View Frame Operator ****************************** */ - -static int graphkeys_view_frame_exec(bContext *C, wmOperator *op) -{ - const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); - ANIM_center_frame(C, smooth_viewtx); - return OPERATOR_FINISHED; -} - -void GRAPH_OT_view_frame(wmOperatorType *ot) -{ - /* Identifiers */ - ot->name = "Go to Current Frame"; - ot->idname = "GRAPH_OT_view_frame"; - ot->description = "Move the view to the current frame"; - - /* API callbacks */ - ot->exec = graphkeys_view_frame_exec; - ot->poll = ED_operator_graphedit_active; - - /* Flags */ - ot->flag = 0; -} - -/* ******************** Create Ghost-Curves Operator *********************** */ -/* This operator samples the data of the selected F-Curves to F-Points, storing them - * as 'ghost curves' in the active Graph Editor. - */ - -/* Bake each F-Curve into a set of samples, and store as a ghost curve. */ -static void create_ghost_curves(bAnimContext *ac, int start, int end) -{ - SpaceGraph *sipo = (SpaceGraph *)ac->sl; - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - /* Free existing ghost curves. */ - BKE_fcurves_free(&sipo->runtime.ghost_curves); - - /* Sanity check. */ - if (start >= end) { - printf("Error: Frame range for Ghost F-Curve creation is inappropriate\n"); - return; - } - - /* Filter data. */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL | - 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 *gcu = BKE_fcurve_create(); - AnimData *adt = ANIM_nla_mapping_get(ac, ale); - ChannelDriver *driver = fcu->driver; - FPoint *fpt; - float unitFac, offset; - int cfra; - short mapping_flag = ANIM_get_normalization_flags(ac); - - /* Disable driver so that it don't muck up the sampling process. */ - fcu->driver = NULL; - - /* Calculate unit-mapping factor. */ - unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset); - - /* Create samples, but store them in a new curve - * - we cannot use fcurve_store_samples() as that will only overwrite the original curve. - */ - gcu->fpt = fpt = MEM_callocN(sizeof(FPoint) * (end - start + 1), "Ghost FPoint Samples"); - gcu->totvert = end - start + 1; - - /* Use the sampling callback at 1-frame intervals from start to end frames. */ - for (cfra = start; cfra <= end; cfra++, fpt++) { - float cfrae = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP); - - fpt->vec[0] = cfrae; - fpt->vec[1] = (fcurve_samplingcb_evalcurve(fcu, NULL, cfrae) + offset) * unitFac; - } - - /* Set color of ghost curve - * - make the color slightly darker. - */ - gcu->color[0] = fcu->color[0] - 0.07f; - gcu->color[1] = fcu->color[1] - 0.07f; - gcu->color[2] = fcu->color[2] - 0.07f; - - /* Store new ghost curve. */ - BLI_addtail(&sipo->runtime.ghost_curves, gcu); - - /* Restore driver. */ - fcu->driver = driver; - } - - /* Admin and redraws. */ - ANIM_animdata_freelist(&anim_data); -} - -/* ------------------- */ - -static int graphkeys_create_ghostcurves_exec(bContext *C, wmOperator *UNUSED(op)) -{ - bAnimContext ac; - View2D *v2d; - int start, end; - - /* Get editor data. */ - if (ANIM_animdata_get_context(C, &ac) == 0) { - return OPERATOR_CANCELLED; - } - - /* Ghost curves are snapshots of the visible portions of the curves, - * so set range to be the visible range. */ - v2d = &ac.region->v2d; - start = (int)v2d->cur.xmin; - end = (int)v2d->cur.xmax; - - /* Bake selected curves into a ghost curve. */ - create_ghost_curves(&ac, start, end); - - /* Update this editor only. */ - ED_area_tag_redraw(CTX_wm_area(C)); - - return OPERATOR_FINISHED; -} - -void GRAPH_OT_ghost_curves_create(wmOperatorType *ot) -{ - /* Identifiers */ - ot->name = "Create Ghost Curves"; - ot->idname = "GRAPH_OT_ghost_curves_create"; - ot->description = - "Create snapshot (Ghosts) of selected F-Curves as background aid for active Graph Editor"; - - /* API callbacks */ - ot->exec = graphkeys_create_ghostcurves_exec; - ot->poll = graphop_visible_keyframes_poll; - - /* Flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* TODO: add props for start/end frames */ -} - -/* ******************** Clear Ghost-Curves Operator *********************** */ -/* This operator clears the 'ghost curves' for the active Graph Editor */ - -static int graphkeys_clear_ghostcurves_exec(bContext *C, wmOperator *UNUSED(op)) -{ - bAnimContext ac; - SpaceGraph *sipo; - - /* Get editor data. */ - if (ANIM_animdata_get_context(C, &ac) == 0) { - return OPERATOR_CANCELLED; - } - sipo = (SpaceGraph *)ac.sl; - - /* If no ghost curves, don't do anything. */ - if (BLI_listbase_is_empty(&sipo->runtime.ghost_curves)) { - return OPERATOR_CANCELLED; - } - /* Free ghost curves. */ - BKE_fcurves_free(&sipo->runtime.ghost_curves); - - /* Update this editor only. */ - ED_area_tag_redraw(CTX_wm_area(C)); - - return OPERATOR_FINISHED; -} - -void GRAPH_OT_ghost_curves_clear(wmOperatorType *ot) -{ - /* Identifiers */ - ot->name = "Clear Ghost Curves"; - ot->idname = "GRAPH_OT_ghost_curves_clear"; - ot->description = "Clear F-Curve snapshots (Ghosts) for active Graph Editor"; - - /* API callbacks */ - ot->exec = graphkeys_clear_ghostcurves_exec; - ot->poll = ED_operator_graphedit_active; - - /* Flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -/* ************************************************************************** */ -/* GENERAL STUFF */ +/* INSERT DUPLICATE AND BAKE KEYFRAMES */ /* ******************** Insert Keyframes Operator ************************* */ @@ -1307,479 +816,6 @@ void GRAPH_OT_clean(wmOperatorType *ot) RNA_def_boolean(ot->srna, "channels", false, "Channels", ""); } -/* ******************** Decimate Keyframes Operator ************************* */ - -static void decimate_graph_keys(bAnimContext *ac, float remove_ratio, float error_sq_max) -{ - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - /* Filter data. */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | - ANIMFILTER_SEL | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - /* Loop through filtered data and clean curves. */ - for (ale = anim_data.first; ale; ale = ale->next) { - if (!decimate_fcurve(ale, remove_ratio, error_sq_max)) { - /* The selection contains unsupported keyframe types! */ - WM_report(RPT_WARNING, "Decimate: Skipping non linear/bezier keyframes!"); - } - - ale->update |= ANIM_UPDATE_DEFAULT; - } - - ANIM_animdata_update(ac, &anim_data); - ANIM_animdata_freelist(&anim_data); -} - -/* ------------------- */ - -/* This data type is only used for modal operation. */ -typedef struct tDecimateGraphOp { - bAnimContext ac; - Scene *scene; - ScrArea *area; - ARegion *region; - - /** A 0-1 value for determining how much we should decimate. */ - PropertyRNA *percentage_prop; - - /** The original bezt curve data (used for restoring fcurves).*/ - ListBase bezt_arr_list; - - NumInput num; -} tDecimateGraphOp; - -typedef struct tBeztCopyData { - int tot_vert; - BezTriple *bezt; -} tBeztCopyData; - -typedef enum tDecimModes { - DECIM_RATIO = 1, - DECIM_ERROR, -} tDecimModes; - -/* Overwrite the current bezts arrays with the original data. */ -static void decimate_reset_bezts(tDecimateGraphOp *dgo) -{ - ListBase anim_data = {NULL, NULL}; - LinkData *link_bezt; - bAnimListElem *ale; - int filter; - - bAnimContext *ac = &dgo->ac; - - /* Filter data. */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | - ANIMFILTER_SEL | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - /* Loop through filtered data and reset bezts. */ - for (ale = anim_data.first, link_bezt = dgo->bezt_arr_list.first; ale; ale = ale->next) { - FCurve *fcu = (FCurve *)ale->key_data; - - if (fcu->bezt == NULL) { - /* This curve is baked, skip it. */ - continue; - } - - tBeztCopyData *data = link_bezt->data; - - const int arr_size = sizeof(BezTriple) * data->tot_vert; - - MEM_freeN(fcu->bezt); - - fcu->bezt = MEM_mallocN(arr_size, __func__); - fcu->totvert = data->tot_vert; - - memcpy(fcu->bezt, data->bezt, arr_size); - - link_bezt = link_bezt->next; - } - - ANIM_animdata_freelist(&anim_data); -} - -static void decimate_exit(bContext *C, wmOperator *op) -{ - tDecimateGraphOp *dgo = op->customdata; - wmWindow *win = CTX_wm_window(C); - - /* If data exists, clear its data and exit. */ - if (dgo == NULL) { - return; - } - - ScrArea *area = dgo->area; - LinkData *link; - - for (link = dgo->bezt_arr_list.first; link != NULL; link = link->next) { - tBeztCopyData *copy = link->data; - MEM_freeN(copy->bezt); - MEM_freeN(link->data); - } - - BLI_freelistN(&dgo->bezt_arr_list); - MEM_freeN(dgo); - - /* Return to normal cursor and header status. */ - WM_cursor_modal_restore(win); - ED_area_status_text(area, NULL); - - /* Cleanup. */ - op->customdata = NULL; -} - -/* Draw a percentage indicator in header. */ -static void decimate_draw_status_header(wmOperator *op, tDecimateGraphOp *dgo) -{ - char status_str[UI_MAX_DRAW_STR]; - char mode_str[32]; - - strcpy(mode_str, TIP_("Decimate Keyframes")); - - if (hasNumInput(&dgo->num)) { - char str_offs[NUM_STR_REP_LEN]; - - outputNumInput(&dgo->num, str_offs, &dgo->scene->unit); - - BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_offs); - } - else { - float percentage = RNA_property_float_get(op->ptr, dgo->percentage_prop); - BLI_snprintf( - status_str, sizeof(status_str), "%s: %d %%", mode_str, (int)(percentage * 100.0f)); - } - - ED_area_status_text(dgo->area, status_str); -} - -/* Calculate percentage based on position of mouse (we only use x-axis for now. - * Since this is more convenient for users to do), and store new percentage value. - */ -static void decimate_mouse_update_percentage(tDecimateGraphOp *dgo, - wmOperator *op, - const wmEvent *event) -{ - float percentage = (event->x - dgo->region->winrct.xmin) / ((float)dgo->region->winx); - RNA_property_float_set(op->ptr, dgo->percentage_prop, percentage); -} - -static int graphkeys_decimate_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - tDecimateGraphOp *dgo; - - WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EW_SCROLL); - - /* Init slide-op data. */ - dgo = op->customdata = MEM_callocN(sizeof(tDecimateGraphOp), "tDecimateGraphOp"); - - /* Get editor data. */ - if (ANIM_animdata_get_context(C, &dgo->ac) == 0) { - decimate_exit(C, op); - return OPERATOR_CANCELLED; - } - - dgo->percentage_prop = RNA_struct_find_property(op->ptr, "remove_ratio"); - - dgo->scene = CTX_data_scene(C); - dgo->area = CTX_wm_area(C); - dgo->region = CTX_wm_region(C); - - /* Initialize percentage so that it will have the correct value before the first mouse move. */ - decimate_mouse_update_percentage(dgo, op, event); - - decimate_draw_status_header(op, dgo); - - /* Construct a list with the original bezt arrays so we can restore them during modal operation. - */ - { - ListBase anim_data = {NULL, NULL}; - bAnimContext *ac = &dgo->ac; - bAnimListElem *ale; - - int filter; - - /* Filter data. */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | - ANIMFILTER_SEL | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - /* Loop through filtered data and copy the curves. */ - for (ale = anim_data.first; ale; ale = ale->next) { - FCurve *fcu = (FCurve *)ale->key_data; - - if (fcu->bezt == NULL) { - /* This curve is baked, skip it. */ - continue; - } - - const int arr_size = sizeof(BezTriple) * fcu->totvert; - - tBeztCopyData *copy = MEM_mallocN(sizeof(tBeztCopyData), "bezts_copy"); - BezTriple *bezts_copy = MEM_mallocN(arr_size, "bezts_copy_array"); - - copy->tot_vert = fcu->totvert; - memcpy(bezts_copy, fcu->bezt, arr_size); - - copy->bezt = bezts_copy; - - LinkData *link = NULL; - - link = MEM_callocN(sizeof(LinkData), "Bezt Link"); - link->data = copy; - - BLI_addtail(&dgo->bezt_arr_list, link); - } - - ANIM_animdata_freelist(&anim_data); - } - - if (dgo->bezt_arr_list.first == NULL) { - WM_report(RPT_WARNING, - "Fcurve Decimate: Can't decimate baked channels. Unbake them and try again."); - decimate_exit(C, op); - return OPERATOR_CANCELLED; - } - - WM_event_add_modal_handler(C, op); - return OPERATOR_RUNNING_MODAL; -} - -static void graphkeys_decimate_modal_update(bContext *C, wmOperator *op) -{ - /* Perform decimate updates - in response to some user action - * (e.g. pressing a key or moving the mouse). */ - tDecimateGraphOp *dgo = op->customdata; - - decimate_draw_status_header(op, dgo); - - /* Reset keyframe data (so we get back to the original state). */ - decimate_reset_bezts(dgo); - - /* Apply... */ - float remove_ratio = RNA_property_float_get(op->ptr, dgo->percentage_prop); - /* We don't want to limit the decimation to a certain error margin. */ - const float error_sq_max = FLT_MAX; - decimate_graph_keys(&dgo->ac, remove_ratio, error_sq_max); - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); -} - -static int graphkeys_decimate_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - /* This assumes that we are in "DECIM_RATIO" mode. This is because the error margin is very hard - * and finicky to control with this modal mouse grab method. Therefore, it is expected that the - * error margin mode is not adjusted by the modal operator but instead tweaked via the redo - * panel.*/ - tDecimateGraphOp *dgo = op->customdata; - - const bool has_numinput = hasNumInput(&dgo->num); - - switch (event->type) { - case LEFTMOUSE: /* Confirm */ - case EVT_RETKEY: - case EVT_PADENTER: { - if (event->val == KM_PRESS) { - decimate_exit(C, op); - - return OPERATOR_FINISHED; - } - break; - } - - case EVT_ESCKEY: /* Cancel */ - case RIGHTMOUSE: { - if (event->val == KM_PRESS) { - decimate_reset_bezts(dgo); - - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); - - decimate_exit(C, op); - - return OPERATOR_CANCELLED; - } - break; - } - - /* Percentage Change... */ - case MOUSEMOVE: /* Calculate new position. */ - { - if (has_numinput == false) { - /* Update percentage based on position of mouse. */ - decimate_mouse_update_percentage(dgo, op, event); - - /* Update pose to reflect the new values. */ - graphkeys_decimate_modal_update(C, op); - } - break; - } - default: { - if ((event->val == KM_PRESS) && handleNumInput(C, &dgo->num, event)) { - float value; - float percentage = RNA_property_float_get(op->ptr, dgo->percentage_prop); - - /* Grab percentage from numeric input, and store this new value for redo - * NOTE: users see ints, while internally we use a 0-1 float. - */ - value = percentage * 100.0f; - applyNumInput(&dgo->num, &value); - - percentage = value / 100.0f; - RNA_property_float_set(op->ptr, dgo->percentage_prop, percentage); - - /* Update decimate output to reflect the new values. */ - graphkeys_decimate_modal_update(C, op); - break; - } - - /* Unhandled event - maybe it was some view manip? */ - /* Allow to pass through. */ - return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH; - } - } - - return OPERATOR_RUNNING_MODAL; -} - -static int graphkeys_decimate_exec(bContext *C, wmOperator *op) -{ - bAnimContext ac; - - /* Get editor data. */ - if (ANIM_animdata_get_context(C, &ac) == 0) { - return OPERATOR_CANCELLED; - } - - tDecimModes mode = RNA_enum_get(op->ptr, "mode"); - /* We want to be able to work on all available keyframes. */ - float remove_ratio = 1.0f; - /* We don't want to limit the decimation to a certain error margin. */ - float error_sq_max = FLT_MAX; - - switch (mode) { - case DECIM_RATIO: - remove_ratio = RNA_float_get(op->ptr, "remove_ratio"); - break; - case DECIM_ERROR: - error_sq_max = RNA_float_get(op->ptr, "remove_error_margin"); - /* The decimate algorithm expects the error to be squared. */ - error_sq_max *= error_sq_max; - - break; - } - - if (remove_ratio == 0.0f || error_sq_max == 0.0f) { - /* Nothing to remove. */ - return OPERATOR_FINISHED; - } - - decimate_graph_keys(&ac, remove_ratio, error_sq_max); - - /* Set notifier that keyframes have changed. */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); - - return OPERATOR_FINISHED; -} - -static bool graphkeys_decimate_poll_property(const bContext *UNUSED(C), - wmOperator *op, - const PropertyRNA *prop) -{ - const char *prop_id = RNA_property_identifier(prop); - - if (STRPREFIX(prop_id, "remove")) { - int mode = RNA_enum_get(op->ptr, "mode"); - - if (STREQ(prop_id, "remove_ratio") && mode != DECIM_RATIO) { - return false; - } - if (STREQ(prop_id, "remove_error_margin") && mode != DECIM_ERROR) { - return false; - } - } - - return true; -} - -static char *graphkeys_decimate_desc(bContext *UNUSED(C), - wmOperatorType *UNUSED(op), - PointerRNA *ptr) -{ - - if (RNA_enum_get(ptr, "mode") == DECIM_ERROR) { - return BLI_strdup( - "Decimate F-Curves by specifying how much it can deviate from the original curve"); - } - - /* Use default description. */ - return NULL; -} - -static const EnumPropertyItem decimate_mode_items[] = { - {DECIM_RATIO, - "RATIO", - 0, - "Ratio", - "Use a percentage to specify how many keyframes you want to remove"}, - {DECIM_ERROR, - "ERROR", - 0, - "Error Margin", - "Use an error margin to specify how much the curve is allowed to deviate from the original " - "path"}, - {0, NULL, 0, NULL, NULL}, -}; - -void GRAPH_OT_decimate(wmOperatorType *ot) -{ - /* Identifiers */ - ot->name = "Decimate Keyframes"; - ot->idname = "GRAPH_OT_decimate"; - ot->description = - "Decimate F-Curves by removing keyframes that influence the curve shape the least"; - - /* API callbacks */ - ot->poll_property = graphkeys_decimate_poll_property; - ot->get_description = graphkeys_decimate_desc; - ot->invoke = graphkeys_decimate_invoke; - ot->modal = graphkeys_decimate_modal; - ot->exec = graphkeys_decimate_exec; - ot->poll = graphop_editable_keyframes_poll; - - /* Flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* Properties */ - RNA_def_enum(ot->srna, - "mode", - decimate_mode_items, - DECIM_RATIO, - "Mode", - "Which mode to use for decimation"); - - RNA_def_float_percentage(ot->srna, - "remove_ratio", - 1.0f / 3.0f, - 0.0f, - 1.0f, - "Remove", - "The percentage of keyframes to remove", - 0.0f, - 1.0f); - RNA_def_float(ot->srna, - "remove_error_margin", - 0.0f, - 0.0f, - FLT_MAX, - "Max Error Margin", - "How much the new decimated curve is allowed to deviate from the original", - 0.0f, - 10.0f); -} - /* ******************** Bake F-Curve Operator *********************** */ /* This operator bakes the data of the selected F-Curves to F-Points */ @@ -2232,7 +1268,7 @@ void GRAPH_OT_sample(wmOperatorType *ot) } /* ************************************************************************** */ -/* SETTINGS STUFF */ +/* EXTRAPOLATION MODE AND KEYFRAME HANDLE SETTINGS */ /* ******************** Set Extrapolation-Type Operator *********************** */ @@ -2589,7 +1625,7 @@ void GRAPH_OT_handle_type(wmOperatorType *ot) } /* ************************************************************************** */ -/* TRANSFORM STUFF */ +/* EULER FILTER */ /* ***************** 'Euler Filter' Operator **************************** */ /* Euler filter tools (as seen in Maya), are necessary for working with 'baked' @@ -2919,6 +1955,9 @@ void GRAPH_OT_euler_filter(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/* ************************************************************************** */ +/* SNAPPING */ + /* ***************** Jump to Selected Frames Operator *********************** */ static bool graphkeys_framejump_poll(bContext *C) -- cgit v1.2.3