Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/space_graph/graph_edit.c
| Show First 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | |||||
| #include "graph_intern.h" | #include "graph_intern.h" | ||||
| /* ************************************************************************** */ | /* ************************************************************************** */ | ||||
| /* KEYFRAME-RANGE STUFF */ | /* KEYFRAME-RANGE STUFF */ | ||||
| /* *************************** Calculate Range ************************** */ | /* *************************** Calculate Range ************************** */ | ||||
| /* Get the min/max keyframes*/ | /* Get the min/max keyframes. */ | ||||
| /* note: it should return total boundbox, filter for selection only can be argument... */ | /* Note: it should return total boundbox, filter for selection only can be argument... */ | ||||
| void get_graph_keyframe_extents(bAnimContext *ac, | void get_graph_keyframe_extents(bAnimContext *ac, | ||||
| float *xmin, | float *xmin, | ||||
| float *xmax, | float *xmax, | ||||
| float *ymin, | float *ymin, | ||||
| float *ymax, | float *ymax, | ||||
| const bool do_sel_only, | const bool do_sel_only, | ||||
| const bool include_handles) | const bool include_handles) | ||||
| { | { | ||||
| Scene *scene = ac->scene; | Scene *scene = ac->scene; | ||||
| SpaceGraph *sipo = (SpaceGraph *)ac->sl; | SpaceGraph *sipo = (SpaceGraph *)ac->sl; | ||||
| ListBase anim_data = {NULL, NULL}; | ListBase anim_data = {NULL, NULL}; | ||||
| bAnimListElem *ale; | bAnimListElem *ale; | ||||
| int filter; | int filter; | ||||
| /* get data to filter, from Dopesheet */ | /* Get data to filter, from Dopesheet. */ | ||||
| filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS); | filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS); | ||||
| if (sipo->flag & SIPO_SELCUVERTSONLY) { | if (sipo->flag & SIPO_SELCUVERTSONLY) { | ||||
| filter |= ANIMFILTER_SEL; | filter |= ANIMFILTER_SEL; | ||||
| } | } | ||||
| ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ||||
| /* set large values initial values that will be easy to override */ | /* Set large values initial values that will be easy to override. */ | ||||
| if (xmin) { | if (xmin) { | ||||
| *xmin = 999999999.0f; | *xmin = 999999999.0f; | ||||
| } | } | ||||
| if (xmax) { | if (xmax) { | ||||
| *xmax = -999999999.0f; | *xmax = -999999999.0f; | ||||
| } | } | ||||
| if (ymin) { | if (ymin) { | ||||
| *ymin = 999999999.0f; | *ymin = 999999999.0f; | ||||
| } | } | ||||
| if (ymax) { | if (ymax) { | ||||
| *ymax = -999999999.0f; | *ymax = -999999999.0f; | ||||
| } | } | ||||
| /* check if any channels to set range with */ | /* Check if any channels to set range with. */ | ||||
| if (anim_data.first) { | if (anim_data.first) { | ||||
| bool foundBounds = false; | bool foundBounds = false; | ||||
| /* go through channels, finding max extents */ | /* Go through channels, finding max extents. */ | ||||
| for (ale = anim_data.first; ale; ale = ale->next) { | for (ale = anim_data.first; ale; ale = ale->next) { | ||||
| AnimData *adt = ANIM_nla_mapping_get(ac, ale); | AnimData *adt = ANIM_nla_mapping_get(ac, ale); | ||||
| FCurve *fcu = (FCurve *)ale->key_data; | FCurve *fcu = (FCurve *)ale->key_data; | ||||
| float txmin, txmax, tymin, tymax; | float txmin, txmax, tymin, tymax; | ||||
| float unitFac, offset; | float unitFac, offset; | ||||
| /* get range */ | /* Get range. */ | ||||
| if (BKE_fcurve_calc_bounds( | if (BKE_fcurve_calc_bounds( | ||||
| fcu, &txmin, &txmax, &tymin, &tymax, do_sel_only, include_handles)) { | fcu, &txmin, &txmax, &tymin, &tymax, do_sel_only, include_handles)) { | ||||
| short mapping_flag = ANIM_get_normalization_flags(ac); | short mapping_flag = ANIM_get_normalization_flags(ac); | ||||
| /* apply NLA scaling */ | /* Apply NLA scaling. */ | ||||
| if (adt) { | if (adt) { | ||||
| txmin = BKE_nla_tweakedit_remap(adt, txmin, NLATIME_CONVERT_MAP); | txmin = BKE_nla_tweakedit_remap(adt, txmin, NLATIME_CONVERT_MAP); | ||||
| txmax = BKE_nla_tweakedit_remap(adt, txmax, NLATIME_CONVERT_MAP); | txmax = BKE_nla_tweakedit_remap(adt, txmax, NLATIME_CONVERT_MAP); | ||||
| } | } | ||||
| /* apply unit corrections */ | /* Apply unit corrections. */ | ||||
| unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset); | unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset); | ||||
| tymin += offset; | tymin += offset; | ||||
| tymax += offset; | tymax += offset; | ||||
| tymin *= unitFac; | tymin *= unitFac; | ||||
| tymax *= unitFac; | tymax *= unitFac; | ||||
| /* try to set cur using these values, if they're more extreme than previously set values */ | /* Try to set cur using these values, if they're more extreme than previously set values. | ||||
| */ | |||||
| if ((xmin) && (txmin < *xmin)) { | if ((xmin) && (txmin < *xmin)) { | ||||
| *xmin = txmin; | *xmin = txmin; | ||||
| } | } | ||||
| if ((xmax) && (txmax > *xmax)) { | if ((xmax) && (txmax > *xmax)) { | ||||
| *xmax = txmax; | *xmax = txmax; | ||||
| } | } | ||||
| if ((ymin) && (tymin < *ymin)) { | if ((ymin) && (tymin < *ymin)) { | ||||
| *ymin = tymin; | *ymin = tymin; | ||||
| } | } | ||||
| if ((ymax) && (tymax > *ymax)) { | if ((ymax) && (tymax > *ymax)) { | ||||
| *ymax = tymax; | *ymax = tymax; | ||||
| } | } | ||||
| foundBounds = true; | foundBounds = true; | ||||
| } | } | ||||
| } | } | ||||
| /* ensure that the extents are not too extreme that view implodes...*/ | /* Ensure that the extents are not too extreme that view implodes...*/ | ||||
| if (foundBounds) { | if (foundBounds) { | ||||
| if ((xmin && xmax) && (fabsf(*xmax - *xmin) < 0.001f)) { | if ((xmin && xmax) && (fabsf(*xmax - *xmin) < 0.001f)) { | ||||
| *xmin -= 0.0005f; | *xmin -= 0.0005f; | ||||
| *xmax += 0.0005f; | *xmax += 0.0005f; | ||||
| } | } | ||||
| if ((ymin && ymax) && (fabsf(*ymax - *ymin) < 0.001f)) { | if ((ymin && ymax) && (fabsf(*ymax - *ymin) < 0.001f)) { | ||||
| *ymax -= 0.0005f; | *ymax -= 0.0005f; | ||||
| *ymax += 0.0005f; | *ymax += 0.0005f; | ||||
| Show All 9 Lines | else { | ||||
| if (ymin) { | if (ymin) { | ||||
| *ymin = -5; | *ymin = -5; | ||||
| } | } | ||||
| if (ymax) { | if (ymax) { | ||||
| *ymax = 5; | *ymax = 5; | ||||
| } | } | ||||
| } | } | ||||
| /* free memory */ | /* Free memory. */ | ||||
| ANIM_animdata_freelist(&anim_data); | ANIM_animdata_freelist(&anim_data); | ||||
| } | } | ||||
| else { | else { | ||||
| /* set default range */ | /* Set default range. */ | ||||
| if (ac->scene) { | if (ac->scene) { | ||||
| if (xmin) { | if (xmin) { | ||||
| *xmin = (float)PSFRA; | *xmin = (float)PSFRA; | ||||
| } | } | ||||
| if (xmax) { | if (xmax) { | ||||
| *xmax = (float)PEFRA; | *xmax = (float)PEFRA; | ||||
| } | } | ||||
| } | } | ||||
| Show All 18 Lines | |||||
| /* ****************** Automatic Preview-Range Operator ****************** */ | /* ****************** Automatic Preview-Range Operator ****************** */ | ||||
| static int graphkeys_previewrange_exec(bContext *C, wmOperator *UNUSED(op)) | static int graphkeys_previewrange_exec(bContext *C, wmOperator *UNUSED(op)) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| Scene *scene; | Scene *scene; | ||||
| float min, max; | float min, max; | ||||
| /* get editor data */ | /* Get editor data. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| if (ac.scene == NULL) { | if (ac.scene == NULL) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| scene = ac.scene; | scene = ac.scene; | ||||
| /* set the range directly */ | /* Set the range directly. */ | ||||
| get_graph_keyframe_extents(&ac, &min, &max, NULL, NULL, false, false); | get_graph_keyframe_extents(&ac, &min, &max, NULL, NULL, false, false); | ||||
| scene->r.flag |= SCER_PRV_RANGE; | scene->r.flag |= SCER_PRV_RANGE; | ||||
| scene->r.psfra = round_fl_to_int(min); | scene->r.psfra = round_fl_to_int(min); | ||||
| scene->r.pefra = round_fl_to_int(max); | scene->r.pefra = round_fl_to_int(max); | ||||
| /* set notifier that things have changed */ | /* Set notifier that things have changed. */ | ||||
| /* XXX err... there's nothing for frame ranges yet, but this should do fine too */ | // 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); | WM_event_add_notifier(C, NC_SCENE | ND_FRAME, ac.scene); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GRAPH_OT_previewrange_set(wmOperatorType *ot) | void GRAPH_OT_previewrange_set(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Auto-Set Preview Range"; | ot->name = "Auto-Set Preview Range"; | ||||
| ot->idname = "GRAPH_OT_previewrange_set"; | ot->idname = "GRAPH_OT_previewrange_set"; | ||||
| ot->description = "Automatically set Preview Range based on range of keyframes"; | ot->description = "Automatically set Preview Range based on range of keyframes"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->exec = graphkeys_previewrange_exec; | ot->exec = graphkeys_previewrange_exec; | ||||
| /* XXX: unchecked poll to get fsamples working too, but makes modifier damage trickier. */ | /* XXX: unchecked poll to get fsamples working too, but makes modifier damage trickier. */ | ||||
| ot->poll = ED_operator_graphedit_active; | ot->poll = ED_operator_graphedit_active; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| } | } | ||||
| /* ****************** View-All Operator ****************** */ | /* ****************** View-All Operator ****************** */ | ||||
| static int graphkeys_viewall(bContext *C, | static int graphkeys_viewall(bContext *C, | ||||
| const bool do_sel_only, | const bool do_sel_only, | ||||
| const bool include_handles, | const bool include_handles, | ||||
| const int smooth_viewtx) | const int smooth_viewtx) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| rctf cur_new; | rctf cur_new; | ||||
| /* get editor data */ | /* Get editor data. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* set the horizontal range, with an extra offset so that the extreme keys will be in view */ | /* Set the horizontal range, with an extra offset so that the extreme keys will be in view. */ | ||||
| get_graph_keyframe_extents(&ac, | get_graph_keyframe_extents(&ac, | ||||
| &cur_new.xmin, | &cur_new.xmin, | ||||
| &cur_new.xmax, | &cur_new.xmax, | ||||
| &cur_new.ymin, | &cur_new.ymin, | ||||
| &cur_new.ymax, | &cur_new.ymax, | ||||
| do_sel_only, | do_sel_only, | ||||
| include_handles); | include_handles); | ||||
| Show All 13 Lines | |||||
| /* ......... */ | /* ......... */ | ||||
| static int graphkeys_viewall_exec(bContext *C, wmOperator *op) | static int graphkeys_viewall_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| const bool include_handles = RNA_boolean_get(op->ptr, "include_handles"); | const bool include_handles = RNA_boolean_get(op->ptr, "include_handles"); | ||||
| const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); | const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); | ||||
| /* whole range */ | /* Whole range */ | ||||
| return graphkeys_viewall(C, false, include_handles, smooth_viewtx); | return graphkeys_viewall(C, false, include_handles, smooth_viewtx); | ||||
| } | } | ||||
| static int graphkeys_view_selected_exec(bContext *C, wmOperator *op) | static int graphkeys_view_selected_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| const bool include_handles = RNA_boolean_get(op->ptr, "include_handles"); | const bool include_handles = RNA_boolean_get(op->ptr, "include_handles"); | ||||
| const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); | const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); | ||||
| /* only selected */ | /* Only selected. */ | ||||
| return graphkeys_viewall(C, true, include_handles, smooth_viewtx); | return graphkeys_viewall(C, true, include_handles, smooth_viewtx); | ||||
| } | } | ||||
| /* ......... */ | /* ......... */ | ||||
| void GRAPH_OT_view_all(wmOperatorType *ot) | void GRAPH_OT_view_all(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Frame All"; | ot->name = "Frame All"; | ||||
| ot->idname = "GRAPH_OT_view_all"; | ot->idname = "GRAPH_OT_view_all"; | ||||
| ot->description = "Reset viewable area to show full keyframe range"; | ot->description = "Reset viewable area to show full keyframe range"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->exec = graphkeys_viewall_exec; | ot->exec = graphkeys_viewall_exec; | ||||
| /* XXX: unchecked poll to get fsamples working too, but makes modifier damage trickier... */ | /* XXX: Unchecked poll to get fsamples working too, but makes modifier damage trickier... */ | ||||
| ot->poll = ED_operator_graphedit_active; | ot->poll = ED_operator_graphedit_active; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = 0; | ot->flag = 0; | ||||
| /* props */ | /* Props */ | ||||
| ot->prop = RNA_def_boolean(ot->srna, | ot->prop = RNA_def_boolean(ot->srna, | ||||
| "include_handles", | "include_handles", | ||||
| true, | true, | ||||
| "Include Handles", | "Include Handles", | ||||
| "Include handles of keyframes when calculating extents"); | "Include handles of keyframes when calculating extents"); | ||||
| } | } | ||||
| void GRAPH_OT_view_selected(wmOperatorType *ot) | void GRAPH_OT_view_selected(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Frame Selected"; | ot->name = "Frame Selected"; | ||||
| ot->idname = "GRAPH_OT_view_selected"; | ot->idname = "GRAPH_OT_view_selected"; | ||||
| ot->description = "Reset viewable area to show selected keyframe range"; | ot->description = "Reset viewable area to show selected keyframe range"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->exec = graphkeys_view_selected_exec; | ot->exec = graphkeys_view_selected_exec; | ||||
| /* XXX: unchecked poll to get fsamples working too, but makes modifier damage trickier... */ | /* XXX: Unchecked poll to get fsamples working too, but makes modifier damage trickier... */ | ||||
| ot->poll = ED_operator_graphedit_active; | ot->poll = ED_operator_graphedit_active; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = 0; | ot->flag = 0; | ||||
| /* props */ | /* Props */ | ||||
| ot->prop = RNA_def_boolean(ot->srna, | ot->prop = RNA_def_boolean(ot->srna, | ||||
| "include_handles", | "include_handles", | ||||
| true, | true, | ||||
| "Include Handles", | "Include Handles", | ||||
| "Include handles of keyframes when calculating extents"); | "Include handles of keyframes when calculating extents"); | ||||
| } | } | ||||
| /* ********************** View Frame Operator ****************************** */ | /* ********************** View Frame Operator ****************************** */ | ||||
| static int graphkeys_view_frame_exec(bContext *C, wmOperator *op) | static int graphkeys_view_frame_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); | const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); | ||||
| ANIM_center_frame(C, smooth_viewtx); | ANIM_center_frame(C, smooth_viewtx); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GRAPH_OT_view_frame(wmOperatorType *ot) | void GRAPH_OT_view_frame(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Go to Current Frame"; | ot->name = "Go to Current Frame"; | ||||
| ot->idname = "GRAPH_OT_view_frame"; | ot->idname = "GRAPH_OT_view_frame"; | ||||
| ot->description = "Move the view to the current frame"; | ot->description = "Move the view to the current frame"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->exec = graphkeys_view_frame_exec; | ot->exec = graphkeys_view_frame_exec; | ||||
| ot->poll = ED_operator_graphedit_active; | ot->poll = ED_operator_graphedit_active; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = 0; | ot->flag = 0; | ||||
| } | } | ||||
| /* ******************** Create Ghost-Curves Operator *********************** */ | /* ******************** Create Ghost-Curves Operator *********************** */ | ||||
| /* This operator samples the data of the selected F-Curves to F-Points, storing them | /* This operator samples the data of the selected F-Curves to F-Points, storing them | ||||
| * as 'ghost curves' in the active Graph Editor | * as 'ghost curves' in the active Graph Editor. | ||||
| */ | */ | ||||
| /* Bake each F-Curve into a set of samples, and store as a ghost curve */ | /* 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) | static void create_ghost_curves(bAnimContext *ac, int start, int end) | ||||
| { | { | ||||
| SpaceGraph *sipo = (SpaceGraph *)ac->sl; | SpaceGraph *sipo = (SpaceGraph *)ac->sl; | ||||
| ListBase anim_data = {NULL, NULL}; | ListBase anim_data = {NULL, NULL}; | ||||
| bAnimListElem *ale; | bAnimListElem *ale; | ||||
| int filter; | int filter; | ||||
| /* free existing ghost curves */ | /* Free existing ghost curves. */ | ||||
| BKE_fcurves_free(&sipo->runtime.ghost_curves); | BKE_fcurves_free(&sipo->runtime.ghost_curves); | ||||
| /* sanity check */ | /* Sanity check. */ | ||||
| if (start >= end) { | if (start >= end) { | ||||
| printf("Error: Frame range for Ghost F-Curve creation is inappropriate\n"); | printf("Error: Frame range for Ghost F-Curve creation is inappropriate\n"); | ||||
| return; | return; | ||||
| } | } | ||||
| /* filter data */ | /* Filter data. */ | ||||
| filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL | | filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL | | ||||
| ANIMFILTER_NODUPLIS); | ANIMFILTER_NODUPLIS); | ||||
| ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ||||
| /* loop through filtered data and add keys between selected keyframes on every frame */ | /* Loop through filtered data and add keys between selected keyframes on every frame . */ | ||||
| for (ale = anim_data.first; ale; ale = ale->next) { | for (ale = anim_data.first; ale; ale = ale->next) { | ||||
| FCurve *fcu = (FCurve *)ale->key_data; | FCurve *fcu = (FCurve *)ale->key_data; | ||||
| FCurve *gcu = BKE_fcurve_create(); | FCurve *gcu = BKE_fcurve_create(); | ||||
| AnimData *adt = ANIM_nla_mapping_get(ac, ale); | AnimData *adt = ANIM_nla_mapping_get(ac, ale); | ||||
| ChannelDriver *driver = fcu->driver; | ChannelDriver *driver = fcu->driver; | ||||
| FPoint *fpt; | FPoint *fpt; | ||||
| float unitFac, offset; | float unitFac, offset; | ||||
| int cfra; | int cfra; | ||||
| short mapping_flag = ANIM_get_normalization_flags(ac); | short mapping_flag = ANIM_get_normalization_flags(ac); | ||||
| /* disable driver so that it don't muck up the sampling process */ | /* Disable driver so that it don't muck up the sampling process. */ | ||||
| fcu->driver = NULL; | fcu->driver = NULL; | ||||
| /* calculate unit-mapping factor */ | /* Calculate unit-mapping factor. */ | ||||
| unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset); | unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset); | ||||
| /* create samples, but store them in a new curve | /* Create samples, but store them in a new curve | ||||
| * - we cannot use fcurve_store_samples() as that will only overwrite the original 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->fpt = fpt = MEM_callocN(sizeof(FPoint) * (end - start + 1), "Ghost FPoint Samples"); | ||||
| gcu->totvert = end - start + 1; | gcu->totvert = end - start + 1; | ||||
| /* use the sampling callback at 1-frame intervals from start to end frames */ | /* Use the sampling callback at 1-frame intervals from start to end frames. */ | ||||
| for (cfra = start; cfra <= end; cfra++, fpt++) { | for (cfra = start; cfra <= end; cfra++, fpt++) { | ||||
| float cfrae = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP); | float cfrae = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP); | ||||
| fpt->vec[0] = cfrae; | fpt->vec[0] = cfrae; | ||||
| fpt->vec[1] = (fcurve_samplingcb_evalcurve(fcu, NULL, cfrae) + offset) * unitFac; | fpt->vec[1] = (fcurve_samplingcb_evalcurve(fcu, NULL, cfrae) + offset) * unitFac; | ||||
| } | } | ||||
| /* set color of ghost curve | /* Set color of ghost curve | ||||
| * - make the color slightly darker | * - make the color slightly darker. | ||||
| */ | */ | ||||
| gcu->color[0] = fcu->color[0] - 0.07f; | gcu->color[0] = fcu->color[0] - 0.07f; | ||||
| gcu->color[1] = fcu->color[1] - 0.07f; | gcu->color[1] = fcu->color[1] - 0.07f; | ||||
| gcu->color[2] = fcu->color[2] - 0.07f; | gcu->color[2] = fcu->color[2] - 0.07f; | ||||
| /* store new ghost curve */ | /* Store new ghost curve. */ | ||||
| BLI_addtail(&sipo->runtime.ghost_curves, gcu); | BLI_addtail(&sipo->runtime.ghost_curves, gcu); | ||||
| /* restore driver */ | /* Restore driver. */ | ||||
| fcu->driver = driver; | fcu->driver = driver; | ||||
| } | } | ||||
| /* admin and redraws */ | /* Admin and redraws. */ | ||||
| ANIM_animdata_freelist(&anim_data); | ANIM_animdata_freelist(&anim_data); | ||||
| } | } | ||||
| /* ------------------- */ | /* ------------------- */ | ||||
| static int graphkeys_create_ghostcurves_exec(bContext *C, wmOperator *UNUSED(op)) | static int graphkeys_create_ghostcurves_exec(bContext *C, wmOperator *UNUSED(op)) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| View2D *v2d; | View2D *v2d; | ||||
| int start, end; | int start, end; | ||||
| /* get editor data */ | /* Get editor data. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* Ghost curves are snapshots of the visible portions of the curves, | /* Ghost curves are snapshots of the visible portions of the curves, | ||||
| * so set range to be the visible range. */ | * so set range to be the visible range. */ | ||||
| v2d = &ac.region->v2d; | v2d = &ac.region->v2d; | ||||
| start = (int)v2d->cur.xmin; | start = (int)v2d->cur.xmin; | ||||
| end = (int)v2d->cur.xmax; | end = (int)v2d->cur.xmax; | ||||
| /* bake selected curves into a ghost curve */ | /* Bake selected curves into a ghost curve. */ | ||||
| create_ghost_curves(&ac, start, end); | create_ghost_curves(&ac, start, end); | ||||
| /* update this editor only */ | /* Update this editor only. */ | ||||
| ED_area_tag_redraw(CTX_wm_area(C)); | ED_area_tag_redraw(CTX_wm_area(C)); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GRAPH_OT_ghost_curves_create(wmOperatorType *ot) | void GRAPH_OT_ghost_curves_create(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Create Ghost Curves"; | ot->name = "Create Ghost Curves"; | ||||
| ot->idname = "GRAPH_OT_ghost_curves_create"; | ot->idname = "GRAPH_OT_ghost_curves_create"; | ||||
| ot->description = | ot->description = | ||||
| "Create snapshot (Ghosts) of selected F-Curves as background aid for active Graph Editor"; | "Create snapshot (Ghosts) of selected F-Curves as background aid for active Graph Editor"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->exec = graphkeys_create_ghostcurves_exec; | ot->exec = graphkeys_create_ghostcurves_exec; | ||||
| ot->poll = graphop_visible_keyframes_poll; | ot->poll = graphop_visible_keyframes_poll; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| /* TODO: add props for start/end frames */ | /* TODO: add props for start/end frames */ | ||||
| } | } | ||||
| /* ******************** Clear Ghost-Curves Operator *********************** */ | /* ******************** Clear Ghost-Curves Operator *********************** */ | ||||
| /* This operator clears the 'ghost curves' for the active Graph Editor */ | /* This operator clears the 'ghost curves' for the active Graph Editor */ | ||||
| static int graphkeys_clear_ghostcurves_exec(bContext *C, wmOperator *UNUSED(op)) | static int graphkeys_clear_ghostcurves_exec(bContext *C, wmOperator *UNUSED(op)) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| SpaceGraph *sipo; | SpaceGraph *sipo; | ||||
| /* get editor data */ | /* Get editor data. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| sipo = (SpaceGraph *)ac.sl; | sipo = (SpaceGraph *)ac.sl; | ||||
| /* if no ghost curves, don't do anything */ | /* If no ghost curves, don't do anything. */ | ||||
| if (BLI_listbase_is_empty(&sipo->runtime.ghost_curves)) { | if (BLI_listbase_is_empty(&sipo->runtime.ghost_curves)) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* free ghost curves */ | /* Free ghost curves. */ | ||||
| BKE_fcurves_free(&sipo->runtime.ghost_curves); | BKE_fcurves_free(&sipo->runtime.ghost_curves); | ||||
| /* update this editor only */ | /* Update this editor only. */ | ||||
| ED_area_tag_redraw(CTX_wm_area(C)); | ED_area_tag_redraw(CTX_wm_area(C)); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GRAPH_OT_ghost_curves_clear(wmOperatorType *ot) | void GRAPH_OT_ghost_curves_clear(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Clear Ghost Curves"; | ot->name = "Clear Ghost Curves"; | ||||
| ot->idname = "GRAPH_OT_ghost_curves_clear"; | ot->idname = "GRAPH_OT_ghost_curves_clear"; | ||||
| ot->description = "Clear F-Curve snapshots (Ghosts) for active Graph Editor"; | ot->description = "Clear F-Curve snapshots (Ghosts) for active Graph Editor"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->exec = graphkeys_clear_ghostcurves_exec; | ot->exec = graphkeys_clear_ghostcurves_exec; | ||||
| ot->poll = ED_operator_graphedit_active; | ot->poll = ED_operator_graphedit_active; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| } | } | ||||
| /* ************************************************************************** */ | /* ************************************************************************** */ | ||||
| /* GENERAL STUFF */ | /* GENERAL STUFF */ | ||||
| /* ******************** Insert Keyframes Operator ************************* */ | /* ******************** Insert Keyframes Operator ************************* */ | ||||
| /* Mode defines for insert keyframes tool */ | /* Mode defines for insert keyframes tool. */ | ||||
| typedef enum eGraphKeys_InsertKey_Types { | typedef enum eGraphKeys_InsertKey_Types { | ||||
| GRAPHKEYS_INSERTKEY_ALL = (1 << 0), | GRAPHKEYS_INSERTKEY_ALL = (1 << 0), | ||||
| GRAPHKEYS_INSERTKEY_SEL = (1 << 1), | GRAPHKEYS_INSERTKEY_SEL = (1 << 1), | ||||
| GRAPHKEYS_INSERTKEY_CURSOR = (1 << 2), | GRAPHKEYS_INSERTKEY_CURSOR = (1 << 2), | ||||
| GRAPHKEYS_INSERTKEY_ACTIVE = (1 << 3), | GRAPHKEYS_INSERTKEY_ACTIVE = (1 << 3), | ||||
| } eGraphKeys_InsertKey_Types; | } eGraphKeys_InsertKey_Types; | ||||
| /* RNA mode types for insert keyframes tool */ | /* RNA mode types for insert keyframes tool. */ | ||||
| static const EnumPropertyItem prop_graphkeys_insertkey_types[] = { | static const EnumPropertyItem prop_graphkeys_insertkey_types[] = { | ||||
| {GRAPHKEYS_INSERTKEY_ALL, | {GRAPHKEYS_INSERTKEY_ALL, | ||||
| "ALL", | "ALL", | ||||
| 0, | 0, | ||||
| "All Channels", | "All Channels", | ||||
| "Insert a keyframe on all visible and editable F-Curves using each curve's current value"}, | "Insert a keyframe on all visible and editable F-Curves using each curve's current value"}, | ||||
| {GRAPHKEYS_INSERTKEY_SEL, | {GRAPHKEYS_INSERTKEY_SEL, | ||||
| "SEL", | "SEL", | ||||
| 0, | 0, | ||||
| "Only Selected Channels", | "Only Selected Channels", | ||||
| "Insert a keyframe on selected F-Curves using each curve's current value"}, | "Insert a keyframe on selected F-Curves using each curve's current value"}, | ||||
| {GRAPHKEYS_INSERTKEY_ACTIVE | GRAPHKEYS_INSERTKEY_CURSOR, | {GRAPHKEYS_INSERTKEY_ACTIVE | GRAPHKEYS_INSERTKEY_CURSOR, | ||||
| "CURSOR_ACTIVE", | "CURSOR_ACTIVE", | ||||
| 0, | 0, | ||||
| "Active Channels At Cursor", | "Active Channels At Cursor", | ||||
| "Insert a keyframe for the active F-Curve at the cursor point"}, | "Insert a keyframe for the active F-Curve at the cursor point"}, | ||||
| {GRAPHKEYS_INSERTKEY_SEL | GRAPHKEYS_INSERTKEY_CURSOR, | {GRAPHKEYS_INSERTKEY_SEL | GRAPHKEYS_INSERTKEY_CURSOR, | ||||
| "CURSOR_SEL", | "CURSOR_SEL", | ||||
| 0, | 0, | ||||
| "Selected Channels At Cursor", | "Selected Channels At Cursor", | ||||
| "Insert a keyframe for selected F-Curves at the cursor point"}, | "Insert a keyframe for selected F-Curves at the cursor point"}, | ||||
| {0, NULL, 0, NULL, NULL}, | {0, NULL, 0, NULL, NULL}, | ||||
| }; | }; | ||||
| /* this function is responsible for snapping keyframes to frame-times */ | /* This function is responsible for snapping keyframes to frame-times. */ | ||||
| static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode) | static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode) | ||||
| { | { | ||||
| ListBase anim_data = {NULL, NULL}; | ListBase anim_data = {NULL, NULL}; | ||||
| ListBase nla_cache = {NULL, NULL}; | ListBase nla_cache = {NULL, NULL}; | ||||
| bAnimListElem *ale; | bAnimListElem *ale; | ||||
| int filter; | int filter; | ||||
| size_t num_items; | size_t num_items; | ||||
| ReportList *reports = ac->reports; | ReportList *reports = ac->reports; | ||||
| SpaceGraph *sipo = (SpaceGraph *)ac->sl; | SpaceGraph *sipo = (SpaceGraph *)ac->sl; | ||||
| Scene *scene = ac->scene; | Scene *scene = ac->scene; | ||||
| ToolSettings *ts = scene->toolsettings; | ToolSettings *ts = scene->toolsettings; | ||||
| eInsertKeyFlags flag = 0; | eInsertKeyFlags flag = 0; | ||||
| /* filter data */ | /* Filter data. */ | ||||
| filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | ||||
| ANIMFILTER_NODUPLIS); | ANIMFILTER_NODUPLIS); | ||||
| if (mode & GRAPHKEYS_INSERTKEY_SEL) { | if (mode & GRAPHKEYS_INSERTKEY_SEL) { | ||||
| filter |= ANIMFILTER_SEL; | filter |= ANIMFILTER_SEL; | ||||
| } | } | ||||
| else if (mode & GRAPHKEYS_INSERTKEY_ACTIVE) { | else if (mode & GRAPHKEYS_INSERTKEY_ACTIVE) { | ||||
| filter |= ANIMFILTER_ACTIVE; | filter |= ANIMFILTER_ACTIVE; | ||||
| } | } | ||||
| Show All 13 Lines | if (num_items == 0) { | ||||
| } | } | ||||
| return; | return; | ||||
| } | } | ||||
| /* Init key-framing flag. */ | /* Init key-framing flag. */ | ||||
| flag = ANIM_get_keyframing_flags(scene, true); | flag = ANIM_get_keyframing_flags(scene, true); | ||||
| /* insert keyframes */ | /* Insert keyframes. */ | ||||
| if (mode & GRAPHKEYS_INSERTKEY_CURSOR) { | if (mode & GRAPHKEYS_INSERTKEY_CURSOR) { | ||||
| for (ale = anim_data.first; ale; ale = ale->next) { | for (ale = anim_data.first; ale; ale = ale->next) { | ||||
| AnimData *adt = ANIM_nla_mapping_get(ac, ale); | AnimData *adt = ANIM_nla_mapping_get(ac, ale); | ||||
| FCurve *fcu = (FCurve *)ale->key_data; | FCurve *fcu = (FCurve *)ale->key_data; | ||||
| short mapping_flag = ANIM_get_normalization_flags(ac); | short mapping_flag = ANIM_get_normalization_flags(ac); | ||||
| float offset; | float offset; | ||||
| float unit_scale = ANIM_unit_mapping_get_factor( | float unit_scale = ANIM_unit_mapping_get_factor( | ||||
| ac->scene, ale->id, ale->key_data, mapping_flag, &offset); | ac->scene, ale->id, ale->key_data, mapping_flag, &offset); | ||||
| float x, y; | float x, y; | ||||
| /* perform time remapping for x-coordinate (if necessary) */ | /* perform time remapping for x-coordinate (if necessary) */ | ||||
| if ((sipo) && (sipo->mode == SIPO_MODE_DRIVERS)) { | if ((sipo) && (sipo->mode == SIPO_MODE_DRIVERS)) { | ||||
| x = sipo->cursorTime; | x = sipo->cursorTime; | ||||
| } | } | ||||
| else if (adt) { | else if (adt) { | ||||
| x = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP); | x = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP); | ||||
| } | } | ||||
| else { | else { | ||||
| x = (float)CFRA; | x = (float)CFRA; | ||||
| } | } | ||||
| /* normalise units of cursor's value */ | /* Normalise units of cursor's value. */ | ||||
| if (sipo) { | if (sipo) { | ||||
| y = (sipo->cursorVal / unit_scale) - offset; | y = (sipo->cursorVal / unit_scale) - offset; | ||||
| } | } | ||||
| else { | else { | ||||
| y = 0.0f; | y = 0.0f; | ||||
| } | } | ||||
| /* insert keyframe directly into the F-Curve */ | /* Insert keyframe directly into the F-Curve. */ | ||||
| insert_vert_fcurve(fcu, x, y, ts->keyframe_type, 0); | insert_vert_fcurve(fcu, x, y, ts->keyframe_type, 0); | ||||
| ale->update |= ANIM_UPDATE_DEFAULT; | ale->update |= ANIM_UPDATE_DEFAULT; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct( | const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct( | ||||
| ac->depsgraph, (float)CFRA); | ac->depsgraph, (float)CFRA); | ||||
| for (ale = anim_data.first; ale; ale = ale->next) { | for (ale = anim_data.first; ale; ale = ale->next) { | ||||
| FCurve *fcu = (FCurve *)ale->key_data; | FCurve *fcu = (FCurve *)ale->key_data; | ||||
| /* Read value from property the F-Curve represents, or from the curve only? | /* Read value from property the F-Curve represents, or from the curve only? | ||||
| * | * | ||||
| * - ale->id != NULL: | * - ale->id != NULL: | ||||
| * Typically, this means that we have enough info to try resolving the path. | * Typically, this means that we have enough info to try resolving the path. | ||||
| * - ale->owner != NULL: | * - ale->owner != NULL: | ||||
| * If this is set, then the path may not be resolvable from the ID alone, | * If this is set, then the path may not be resolvable from the ID alone, | ||||
| * so it's easier for now to just read the F-Curve directly. | * so it's easier for now to just read the F-Curve directly. | ||||
| * (TODO: add the full-blown PointerRNA relative parsing case here...) | * (TODO: add the full-blown PointerRNA relative parsing case here... (Joshua Leung 2015)) | ||||
| * - fcu->driver != NULL: | * - fcu->driver != NULL: | ||||
| * If this is set, then it's a driver. If we don't check for this, we'd end | * If this is set, then it's a driver. If we don't check for this, we'd end | ||||
| * up adding the keyframes on a new F-Curve in the action data instead. | * up adding the keyframes on a new F-Curve in the action data instead. | ||||
| */ | */ | ||||
| if (ale->id && !ale->owner && !fcu->driver) { | if (ale->id && !ale->owner && !fcu->driver) { | ||||
| insert_keyframe(ac->bmain, | insert_keyframe(ac->bmain, | ||||
| reports, | reports, | ||||
| ale->id, | ale->id, | ||||
| NULL, | NULL, | ||||
| ((fcu->grp) ? (fcu->grp->name) : (NULL)), | ((fcu->grp) ? (fcu->grp->name) : (NULL)), | ||||
| fcu->rna_path, | fcu->rna_path, | ||||
| fcu->array_index, | fcu->array_index, | ||||
| &anim_eval_context, | &anim_eval_context, | ||||
| ts->keyframe_type, | ts->keyframe_type, | ||||
| &nla_cache, | &nla_cache, | ||||
| flag); | flag); | ||||
| } | } | ||||
| else { | else { | ||||
| AnimData *adt = ANIM_nla_mapping_get(ac, ale); | AnimData *adt = ANIM_nla_mapping_get(ac, ale); | ||||
| /* adjust current frame for NLA-mapping */ | /* Adjust current frame for NLA-mapping. */ | ||||
| float cfra = (float)CFRA; | float cfra = (float)CFRA; | ||||
| if ((sipo) && (sipo->mode == SIPO_MODE_DRIVERS)) { | if ((sipo) && (sipo->mode == SIPO_MODE_DRIVERS)) { | ||||
| cfra = sipo->cursorTime; | cfra = sipo->cursorTime; | ||||
| } | } | ||||
| else if (adt) { | else if (adt) { | ||||
| cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP); | cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP); | ||||
| } | } | ||||
| Show All 13 Lines | |||||
| /* ------------------- */ | /* ------------------- */ | ||||
| static int graphkeys_insertkey_exec(bContext *C, wmOperator *op) | static int graphkeys_insertkey_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| eGraphKeys_InsertKey_Types mode; | eGraphKeys_InsertKey_Types mode; | ||||
| /* get editor data */ | /* Get editor data. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* which channels to affect? */ | /* Which channels to affect?. */ | ||||
| mode = RNA_enum_get(op->ptr, "type"); | mode = RNA_enum_get(op->ptr, "type"); | ||||
| /* insert keyframes */ | /* Insert keyframes. */ | ||||
| insert_graph_keys(&ac, mode); | insert_graph_keys(&ac, mode); | ||||
| /* set notifier that keyframes have changed */ | /* Set notifier that keyframes have changed. */ | ||||
| WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL); | WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GRAPH_OT_keyframe_insert(wmOperatorType *ot) | void GRAPH_OT_keyframe_insert(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Insert Keyframes"; | ot->name = "Insert Keyframes"; | ||||
| ot->idname = "GRAPH_OT_keyframe_insert"; | ot->idname = "GRAPH_OT_keyframe_insert"; | ||||
| ot->description = "Insert keyframes for the specified channels"; | ot->description = "Insert keyframes for the specified channels"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->invoke = WM_menu_invoke; | ot->invoke = WM_menu_invoke; | ||||
| ot->exec = graphkeys_insertkey_exec; | ot->exec = graphkeys_insertkey_exec; | ||||
| ot->poll = graphop_editable_keyframes_poll; | ot->poll = graphop_editable_keyframes_poll; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| /* id-props */ | /* Id-props */ | ||||
| ot->prop = RNA_def_enum(ot->srna, "type", prop_graphkeys_insertkey_types, 0, "Type", ""); | ot->prop = RNA_def_enum(ot->srna, "type", prop_graphkeys_insertkey_types, 0, "Type", ""); | ||||
| } | } | ||||
| /* ******************** Click-Insert Keyframes Operator ************************* */ | /* ******************** Click-Insert Keyframes Operator ************************* */ | ||||
| static int graphkeys_click_insert_exec(bContext *C, wmOperator *op) | static int graphkeys_click_insert_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| bAnimListElem *ale; | bAnimListElem *ale; | ||||
| AnimData *adt; | AnimData *adt; | ||||
| FCurve *fcu; | FCurve *fcu; | ||||
| float frame, val; | float frame, val; | ||||
| /* get animation context */ | /* Get animation context. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* get active F-Curve 'anim-list-element' */ | /* Get active F-Curve 'anim-list-element'. */ | ||||
| ale = get_active_fcurve_channel(&ac); | ale = get_active_fcurve_channel(&ac); | ||||
| if (ELEM(NULL, ale, ale->data)) { | if (ELEM(NULL, ale, ale->data)) { | ||||
| if (ale) { | if (ale) { | ||||
| MEM_freeN(ale); | MEM_freeN(ale); | ||||
| } | } | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| fcu = ale->data; | fcu = ale->data; | ||||
| /* when there are F-Modifiers on the curve, only allow adding | /* When there are F-Modifiers on the curve, only allow adding | ||||
| * keyframes if these will be visible after doing so... | * keyframes if these will be visible after doing so... | ||||
| */ | */ | ||||
| if (BKE_fcurve_is_keyframable(fcu)) { | if (BKE_fcurve_is_keyframable(fcu)) { | ||||
| ListBase anim_data; | ListBase anim_data; | ||||
| ToolSettings *ts = ac.scene->toolsettings; | ToolSettings *ts = ac.scene->toolsettings; | ||||
| short mapping_flag = ANIM_get_normalization_flags(&ac); | short mapping_flag = ANIM_get_normalization_flags(&ac); | ||||
| float scale, offset; | float scale, offset; | ||||
| /* preserve selection? */ | /* Preserve selection? */ | ||||
| if (RNA_boolean_get(op->ptr, "extend") == false) { | if (RNA_boolean_get(op->ptr, "extend") == false) { | ||||
| /* Deselect all keyframes first, | /* Deselect all keyframes first, | ||||
| * so that we can immediately start manipulating the newly added one(s) | * so that we can immediately start manipulating the newly added one(s) | ||||
| * - only affect the keyframes themselves, as we don't want channels popping in and out. */ | * - only affect the keyframes themselves, as we don't want channels popping in and out. */ | ||||
| deselect_graph_keys(&ac, false, SELECT_SUBTRACT, false); | deselect_graph_keys(&ac, false, SELECT_SUBTRACT, false); | ||||
| } | } | ||||
| /* get frame and value from props */ | /* Get frame and value from props. */ | ||||
| frame = RNA_float_get(op->ptr, "frame"); | frame = RNA_float_get(op->ptr, "frame"); | ||||
| val = RNA_float_get(op->ptr, "value"); | val = RNA_float_get(op->ptr, "value"); | ||||
| /* apply inverse NLA-mapping to frame to get correct time in un-scaled action */ | /* Apply inverse NLA-mapping to frame to get correct time in un-scaled action. */ | ||||
| adt = ANIM_nla_mapping_get(&ac, ale); | adt = ANIM_nla_mapping_get(&ac, ale); | ||||
| frame = BKE_nla_tweakedit_remap(adt, frame, NLATIME_CONVERT_UNMAP); | frame = BKE_nla_tweakedit_remap(adt, frame, NLATIME_CONVERT_UNMAP); | ||||
| /* apply inverse unit-mapping to value to get correct value for F-Curves */ | /* Apply inverse unit-mapping to value to get correct value for F-Curves. */ | ||||
| scale = ANIM_unit_mapping_get_factor( | scale = ANIM_unit_mapping_get_factor( | ||||
| ac.scene, ale->id, fcu, mapping_flag | ANIM_UNITCONV_RESTORE, &offset); | ac.scene, ale->id, fcu, mapping_flag | ANIM_UNITCONV_RESTORE, &offset); | ||||
| val = val * scale - offset; | val = val * scale - offset; | ||||
| /* insert keyframe on the specified frame + value */ | /* Insert keyframe on the specified frame + value. */ | ||||
| insert_vert_fcurve(fcu, frame, val, ts->keyframe_type, 0); | insert_vert_fcurve(fcu, frame, val, ts->keyframe_type, 0); | ||||
| ale->update |= ANIM_UPDATE_DEPS; | ale->update |= ANIM_UPDATE_DEPS; | ||||
| BLI_listbase_clear(&anim_data); | BLI_listbase_clear(&anim_data); | ||||
| BLI_addtail(&anim_data, ale); | BLI_addtail(&anim_data, ale); | ||||
| ANIM_animdata_update(&ac, &anim_data); | ANIM_animdata_update(&ac, &anim_data); | ||||
| } | } | ||||
| else { | else { | ||||
| /* warn about why this can't happen */ | /* Warn about why this can't happen. */ | ||||
| if (fcu->fpt) { | if (fcu->fpt) { | ||||
| BKE_report(op->reports, RPT_ERROR, "Keyframes cannot be added to sampled F-Curves"); | BKE_report(op->reports, RPT_ERROR, "Keyframes cannot be added to sampled F-Curves"); | ||||
| } | } | ||||
| else if (fcu->flag & FCURVE_PROTECTED) { | else if (fcu->flag & FCURVE_PROTECTED) { | ||||
| BKE_report(op->reports, RPT_ERROR, "Active F-Curve is not editable"); | BKE_report(op->reports, RPT_ERROR, "Active F-Curve is not editable"); | ||||
| } | } | ||||
| else { | else { | ||||
| BKE_report(op->reports, RPT_ERROR, "Remove F-Modifiers from F-Curve to add keyframes"); | BKE_report(op->reports, RPT_ERROR, "Remove F-Modifiers from F-Curve to add keyframes"); | ||||
| } | } | ||||
| } | } | ||||
| /* free temp data */ | /* Free temp data. */ | ||||
| MEM_freeN(ale); | MEM_freeN(ale); | ||||
| /* set notifier that keyframes have changed */ | /* Set notifier that keyframes have changed. */ | ||||
| WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | ||||
| /* done */ | /* Done */ | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| static int graphkeys_click_insert_invoke(bContext *C, wmOperator *op, const wmEvent *event) | static int graphkeys_click_insert_invoke(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| ARegion *region; | ARegion *region; | ||||
| View2D *v2d; | View2D *v2d; | ||||
| int mval[2]; | int mval[2]; | ||||
| float x, y; | float x, y; | ||||
| /* get animation context */ | /* Get animation context. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* store mouse coordinates in View2D space, into the operator's properties */ | /* Store mouse coordinates in View2D space, into the operator's properties. */ | ||||
| region = ac.region; | region = ac.region; | ||||
| v2d = ®ion->v2d; | v2d = ®ion->v2d; | ||||
| mval[0] = (event->x - region->winrct.xmin); | mval[0] = (event->x - region->winrct.xmin); | ||||
| mval[1] = (event->y - region->winrct.ymin); | mval[1] = (event->y - region->winrct.ymin); | ||||
| UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); | UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); | ||||
| RNA_float_set(op->ptr, "frame", x); | RNA_float_set(op->ptr, "frame", x); | ||||
| RNA_float_set(op->ptr, "value", y); | RNA_float_set(op->ptr, "value", y); | ||||
| /* run exec now */ | /* Run exec now. */ | ||||
| return graphkeys_click_insert_exec(C, op); | return graphkeys_click_insert_exec(C, op); | ||||
| } | } | ||||
| void GRAPH_OT_click_insert(wmOperatorType *ot) | void GRAPH_OT_click_insert(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Click-Insert Keyframes"; | ot->name = "Click-Insert Keyframes"; | ||||
| ot->idname = "GRAPH_OT_click_insert"; | ot->idname = "GRAPH_OT_click_insert"; | ||||
| ot->description = "Insert new keyframe at the cursor position for the active F-Curve"; | ot->description = "Insert new keyframe at the cursor position for the active F-Curve"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->invoke = graphkeys_click_insert_invoke; | ot->invoke = graphkeys_click_insert_invoke; | ||||
| ot->exec = graphkeys_click_insert_exec; | ot->exec = graphkeys_click_insert_exec; | ||||
| ot->poll = graphop_active_fcurve_poll; | ot->poll = graphop_active_fcurve_poll; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| /* properties */ | /* Properties */ | ||||
| RNA_def_float(ot->srna, | RNA_def_float(ot->srna, | ||||
| "frame", | "frame", | ||||
| 1.0f, | 1.0f, | ||||
| -FLT_MAX, | -FLT_MAX, | ||||
| FLT_MAX, | FLT_MAX, | ||||
| "Frame Number", | "Frame Number", | ||||
| "Frame to insert keyframe on", | "Frame to insert keyframe on", | ||||
| 0, | 0, | ||||
| Show All 11 Lines | |||||
| /* ******************** Copy/Paste Keyframes Operator ************************* */ | /* ******************** Copy/Paste Keyframes Operator ************************* */ | ||||
| /* NOTE: the backend code for this is shared with the dopesheet editor */ | /* NOTE: the backend code for this is shared with the dopesheet editor */ | ||||
| static short copy_graph_keys(bAnimContext *ac) | static short copy_graph_keys(bAnimContext *ac) | ||||
| { | { | ||||
| ListBase anim_data = {NULL, NULL}; | ListBase anim_data = {NULL, NULL}; | ||||
| int filter, ok = 0; | int filter, ok = 0; | ||||
| /* clear buffer first */ | /* Clear buffer first. */ | ||||
| ANIM_fcurves_copybuf_free(); | ANIM_fcurves_copybuf_free(); | ||||
| /* filter data | /* Filter data | ||||
| * - First time we try to filter more strictly, allowing only selected channels | * - First time we try to filter more strictly, allowing only selected channels | ||||
| * to allow copying animation between channels | * to allow copying animation between channels. | ||||
| */ | */ | ||||
| filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS); | filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS); | ||||
| if (ANIM_animdata_filter(ac, &anim_data, filter | ANIMFILTER_SEL, ac->data, ac->datatype) == 0) { | if (ANIM_animdata_filter(ac, &anim_data, filter | ANIMFILTER_SEL, ac->data, ac->datatype) == 0) { | ||||
| ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ||||
| } | } | ||||
| /* copy keyframes */ | /* Copy keyframes. */ | ||||
| ok = copy_animedit_keys(ac, &anim_data); | ok = copy_animedit_keys(ac, &anim_data); | ||||
| /* clean up */ | /* Clean up. */ | ||||
| ANIM_animdata_freelist(&anim_data); | ANIM_animdata_freelist(&anim_data); | ||||
| return ok; | return ok; | ||||
| } | } | ||||
| static short paste_graph_keys(bAnimContext *ac, | static short paste_graph_keys(bAnimContext *ac, | ||||
| const eKeyPasteOffset offset_mode, | const eKeyPasteOffset offset_mode, | ||||
| const eKeyMergeMode merge_mode, | const eKeyMergeMode merge_mode, | ||||
| bool flip) | bool flip) | ||||
| { | { | ||||
| ListBase anim_data = {NULL, NULL}; | ListBase anim_data = {NULL, NULL}; | ||||
| int filter, ok = 0; | int filter, ok = 0; | ||||
| /* filter data | /* Filter data | ||||
| * - First time we try to filter more strictly, allowing only selected channels | * - First time we try to filter more strictly, allowing only selected channels | ||||
| * to allow copying animation between channels | * to allow copying animation between channels | ||||
| * - Second time, we loosen things up if nothing was found the first time, allowing | * - Second time, we loosen things up if nothing was found the first time, allowing | ||||
| * users to just paste keyframes back into the original curve again T31670. | * users to just paste keyframes back into the original curve again T31670. | ||||
| */ | */ | ||||
| filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | ||||
| ANIMFILTER_NODUPLIS); | ANIMFILTER_NODUPLIS); | ||||
| if (ANIM_animdata_filter(ac, &anim_data, filter | ANIMFILTER_SEL, ac->data, ac->datatype) == 0) { | if (ANIM_animdata_filter(ac, &anim_data, filter | ANIMFILTER_SEL, ac->data, ac->datatype) == 0) { | ||||
| ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ||||
| } | } | ||||
| /* paste keyframes */ | /* Paste keyframes. */ | ||||
| ok = paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode, flip); | ok = paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode, flip); | ||||
| /* clean up */ | /* Clean up. */ | ||||
| ANIM_animdata_freelist(&anim_data); | ANIM_animdata_freelist(&anim_data); | ||||
| return ok; | return ok; | ||||
| } | } | ||||
| /* ------------------- */ | /* ------------------- */ | ||||
| static int graphkeys_copy_exec(bContext *C, wmOperator *op) | static int graphkeys_copy_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| /* get editor data */ | /* Get editor data. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* copy keyframes */ | /* Copy keyframes. */ | ||||
| if (copy_graph_keys(&ac)) { | if (copy_graph_keys(&ac)) { | ||||
| BKE_report(op->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer"); | BKE_report(op->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer"); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* just return - no operator needed here (no changes) */ | /* Just return - no operator needed here (no changes). */ | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GRAPH_OT_copy(wmOperatorType *ot) | void GRAPH_OT_copy(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Copy Keyframes"; | ot->name = "Copy Keyframes"; | ||||
| ot->idname = "GRAPH_OT_copy"; | ot->idname = "GRAPH_OT_copy"; | ||||
| ot->description = "Copy selected keyframes to the copy/paste buffer"; | ot->description = "Copy selected keyframes to the copy/paste buffer"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->exec = graphkeys_copy_exec; | ot->exec = graphkeys_copy_exec; | ||||
| ot->poll = graphop_editable_keyframes_poll; | ot->poll = graphop_editable_keyframes_poll; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| } | } | ||||
| static int graphkeys_paste_exec(bContext *C, wmOperator *op) | static int graphkeys_paste_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| const eKeyPasteOffset offset_mode = RNA_enum_get(op->ptr, "offset"); | const eKeyPasteOffset offset_mode = RNA_enum_get(op->ptr, "offset"); | ||||
| const eKeyMergeMode merge_mode = RNA_enum_get(op->ptr, "merge"); | const eKeyMergeMode merge_mode = RNA_enum_get(op->ptr, "merge"); | ||||
| const bool flipped = RNA_boolean_get(op->ptr, "flipped"); | const bool flipped = RNA_boolean_get(op->ptr, "flipped"); | ||||
| /* get editor data */ | /* Get editor data. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* ac.reports by default will be the global reports list, which won't show warnings */ | /* Ac.reports by default will be the global reports list, which won't show warnings. */ | ||||
| ac.reports = op->reports; | ac.reports = op->reports; | ||||
| /* paste keyframes - non-zero return means an error occurred while trying to paste */ | /* Paste keyframes - non-zero return means an error occurred while trying to paste. */ | ||||
| if (paste_graph_keys(&ac, offset_mode, merge_mode, flipped)) { | if (paste_graph_keys(&ac, offset_mode, merge_mode, flipped)) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* set notifier that keyframes have changed */ | /* Set notifier that keyframes have changed. */ | ||||
| WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GRAPH_OT_paste(wmOperatorType *ot) | void GRAPH_OT_paste(wmOperatorType *ot) | ||||
| { | { | ||||
| PropertyRNA *prop; | PropertyRNA *prop; | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Paste Keyframes"; | ot->name = "Paste Keyframes"; | ||||
| ot->idname = "GRAPH_OT_paste"; | ot->idname = "GRAPH_OT_paste"; | ||||
| ot->description = | ot->description = | ||||
| "Paste keyframes from copy/paste buffer for the selected channels, starting on the current " | "Paste keyframes from copy/paste buffer for the selected channels, starting on the current " | ||||
| "frame"; | "frame"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| // ot->invoke = WM_operator_props_popup; /* better wait for graph redo panel */ | // ot->invoke = WM_operator_props_popup; /* better wait for graph redo panel */ | ||||
| ot->exec = graphkeys_paste_exec; | ot->exec = graphkeys_paste_exec; | ||||
| ot->poll = graphop_editable_keyframes_poll; | ot->poll = graphop_editable_keyframes_poll; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| /* props */ | /* Props */ | ||||
| RNA_def_enum(ot->srna, | RNA_def_enum(ot->srna, | ||||
| "offset", | "offset", | ||||
| rna_enum_keyframe_paste_offset_items, | rna_enum_keyframe_paste_offset_items, | ||||
| KEYFRAME_PASTE_OFFSET_CFRA_START, | KEYFRAME_PASTE_OFFSET_CFRA_START, | ||||
| "Offset", | "Offset", | ||||
| "Paste time offset of keys"); | "Paste time offset of keys"); | ||||
| RNA_def_enum(ot->srna, | RNA_def_enum(ot->srna, | ||||
| "merge", | "merge", | ||||
| Show All 9 Lines | |||||
| /* ******************** Duplicate Keyframes Operator ************************* */ | /* ******************** Duplicate Keyframes Operator ************************* */ | ||||
| static void duplicate_graph_keys(bAnimContext *ac) | static void duplicate_graph_keys(bAnimContext *ac) | ||||
| { | { | ||||
| ListBase anim_data = {NULL, NULL}; | ListBase anim_data = {NULL, NULL}; | ||||
| bAnimListElem *ale; | bAnimListElem *ale; | ||||
| int filter; | int filter; | ||||
| /* filter data */ | /* Filter data. */ | ||||
| filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | ||||
| ANIMFILTER_NODUPLIS); | ANIMFILTER_NODUPLIS); | ||||
| ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ||||
| /* loop through filtered data and delete selected keys */ | /* Loop through filtered data and delete selected keys. */ | ||||
| for (ale = anim_data.first; ale; ale = ale->next) { | for (ale = anim_data.first; ale; ale = ale->next) { | ||||
| duplicate_fcurve_keys((FCurve *)ale->key_data); | duplicate_fcurve_keys((FCurve *)ale->key_data); | ||||
| ale->update |= ANIM_UPDATE_DEFAULT; | ale->update |= ANIM_UPDATE_DEFAULT; | ||||
| } | } | ||||
| ANIM_animdata_update(ac, &anim_data); | ANIM_animdata_update(ac, &anim_data); | ||||
| ANIM_animdata_freelist(&anim_data); | ANIM_animdata_freelist(&anim_data); | ||||
| } | } | ||||
| /* ------------------- */ | /* ------------------- */ | ||||
| static int graphkeys_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) | static int graphkeys_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| /* get editor data */ | /* Get editor data. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* duplicate keyframes */ | /* Duplicate keyframes. */ | ||||
| duplicate_graph_keys(&ac); | duplicate_graph_keys(&ac); | ||||
| /* set notifier that keyframes have changed */ | /* Set notifier that keyframes have changed. */ | ||||
| WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL); | WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GRAPH_OT_duplicate(wmOperatorType *ot) | void GRAPH_OT_duplicate(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Duplicate Keyframes"; | ot->name = "Duplicate Keyframes"; | ||||
| ot->idname = "GRAPH_OT_duplicate"; | ot->idname = "GRAPH_OT_duplicate"; | ||||
| ot->description = "Make a copy of all selected keyframes"; | ot->description = "Make a copy of all selected keyframes"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->exec = graphkeys_duplicate_exec; | ot->exec = graphkeys_duplicate_exec; | ||||
| ot->poll = graphop_editable_keyframes_poll; | ot->poll = graphop_editable_keyframes_poll; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| /* to give to transform */ | /* To give to transform. */ | ||||
| RNA_def_enum(ot->srna, "mode", rna_enum_transform_mode_types, TFM_TRANSLATION, "Mode", ""); | RNA_def_enum(ot->srna, "mode", rna_enum_transform_mode_types, TFM_TRANSLATION, "Mode", ""); | ||||
| } | } | ||||
| /* ******************** Delete Keyframes Operator ************************* */ | /* ******************** Delete Keyframes Operator ************************* */ | ||||
| static bool delete_graph_keys(bAnimContext *ac) | static bool delete_graph_keys(bAnimContext *ac) | ||||
| { | { | ||||
| ListBase anim_data = {NULL, NULL}; | ListBase anim_data = {NULL, NULL}; | ||||
| bAnimListElem *ale; | bAnimListElem *ale; | ||||
| int filter; | int filter; | ||||
| bool changed_final = false; | bool changed_final = false; | ||||
| /* filter data */ | /* Filter data. */ | ||||
| filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | ||||
| ANIMFILTER_NODUPLIS); | ANIMFILTER_NODUPLIS); | ||||
| ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ||||
| /* loop through filtered data and delete selected keys */ | /* Loop through filtered data and delete selected keys. */ | ||||
| for (ale = anim_data.first; ale; ale = ale->next) { | for (ale = anim_data.first; ale; ale = ale->next) { | ||||
| FCurve *fcu = (FCurve *)ale->key_data; | FCurve *fcu = (FCurve *)ale->key_data; | ||||
| AnimData *adt = ale->adt; | AnimData *adt = ale->adt; | ||||
| bool changed; | bool changed; | ||||
| /* delete selected keyframes only */ | /* Delete selected keyframes only. */ | ||||
| changed = delete_fcurve_keys(fcu); | changed = delete_fcurve_keys(fcu); | ||||
| if (changed) { | if (changed) { | ||||
| ale->update |= ANIM_UPDATE_DEFAULT; | ale->update |= ANIM_UPDATE_DEFAULT; | ||||
| changed_final = true; | changed_final = true; | ||||
| } | } | ||||
| /* Only delete curve too if it won't be doing anything anymore */ | /* Only delete curve too if it won't be doing anything anymore. */ | ||||
| if (BKE_fcurve_is_empty(fcu)) { | if (BKE_fcurve_is_empty(fcu)) { | ||||
| ANIM_fcurve_delete_from_animdata(ac, adt, fcu); | ANIM_fcurve_delete_from_animdata(ac, adt, fcu); | ||||
| ale->key_data = NULL; | ale->key_data = NULL; | ||||
| } | } | ||||
| } | } | ||||
| ANIM_animdata_update(ac, &anim_data); | ANIM_animdata_update(ac, &anim_data); | ||||
| ANIM_animdata_freelist(&anim_data); | ANIM_animdata_freelist(&anim_data); | ||||
| return changed_final; | return changed_final; | ||||
| } | } | ||||
| /* ------------------- */ | /* ------------------- */ | ||||
| static int graphkeys_delete_exec(bContext *C, wmOperator *UNUSED(op)) | static int graphkeys_delete_exec(bContext *C, wmOperator *UNUSED(op)) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| /* get editor data */ | /* Get editor data. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* delete keyframes */ | /* Delete keyframes. */ | ||||
| if (!delete_graph_keys(&ac)) { | if (!delete_graph_keys(&ac)) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* set notifier that keyframes have changed */ | /* Set notifier that keyframes have changed. */ | ||||
| WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL); | WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GRAPH_OT_delete(wmOperatorType *ot) | void GRAPH_OT_delete(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Delete Keyframes"; | ot->name = "Delete Keyframes"; | ||||
| ot->idname = "GRAPH_OT_delete"; | ot->idname = "GRAPH_OT_delete"; | ||||
| ot->description = "Remove all selected keyframes"; | ot->description = "Remove all selected keyframes"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->invoke = WM_operator_confirm; | ot->invoke = WM_operator_confirm; | ||||
| ot->exec = graphkeys_delete_exec; | ot->exec = graphkeys_delete_exec; | ||||
| ot->poll = graphop_editable_keyframes_poll; | ot->poll = graphop_editable_keyframes_poll; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| } | } | ||||
| /* ******************** Clean Keyframes Operator ************************* */ | /* ******************** Clean Keyframes Operator ************************* */ | ||||
| static void clean_graph_keys(bAnimContext *ac, float thresh, bool clean_chan) | static void clean_graph_keys(bAnimContext *ac, float thresh, bool clean_chan) | ||||
| { | { | ||||
| ListBase anim_data = {NULL, NULL}; | ListBase anim_data = {NULL, NULL}; | ||||
| bAnimListElem *ale; | bAnimListElem *ale; | ||||
| int filter; | int filter; | ||||
| /* filter data */ | /* Filter data. */ | ||||
| filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | ||||
| ANIMFILTER_SEL | ANIMFILTER_NODUPLIS); | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS); | ||||
| ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ||||
| /* loop through filtered data and clean curves */ | /* Loop through filtered data and clean curves. */ | ||||
| for (ale = anim_data.first; ale; ale = ale->next) { | for (ale = anim_data.first; ale; ale = ale->next) { | ||||
| clean_fcurve(ac, ale, thresh, clean_chan); | clean_fcurve(ac, ale, thresh, clean_chan); | ||||
| ale->update |= ANIM_UPDATE_DEFAULT; | ale->update |= ANIM_UPDATE_DEFAULT; | ||||
| } | } | ||||
| ANIM_animdata_update(ac, &anim_data); | ANIM_animdata_update(ac, &anim_data); | ||||
| ANIM_animdata_freelist(&anim_data); | ANIM_animdata_freelist(&anim_data); | ||||
| } | } | ||||
| /* ------------------- */ | /* ------------------- */ | ||||
| static int graphkeys_clean_exec(bContext *C, wmOperator *op) | static int graphkeys_clean_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| float thresh; | float thresh; | ||||
| bool clean_chan; | bool clean_chan; | ||||
| /* get editor data */ | /* Get editor data. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* get cleaning threshold */ | /* Get cleaning threshold. */ | ||||
| thresh = RNA_float_get(op->ptr, "threshold"); | thresh = RNA_float_get(op->ptr, "threshold"); | ||||
| clean_chan = RNA_boolean_get(op->ptr, "channels"); | clean_chan = RNA_boolean_get(op->ptr, "channels"); | ||||
| /* clean keyframes */ | /* Clean keyframes. */ | ||||
| clean_graph_keys(&ac, thresh, clean_chan); | clean_graph_keys(&ac, thresh, clean_chan); | ||||
| /* set notifier that keyframes have changed */ | /* Set notifier that keyframes have changed. */ | ||||
| WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GRAPH_OT_clean(wmOperatorType *ot) | void GRAPH_OT_clean(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Clean Keyframes"; | ot->name = "Clean Keyframes"; | ||||
| ot->idname = "GRAPH_OT_clean"; | ot->idname = "GRAPH_OT_clean"; | ||||
| ot->description = "Simplify F-Curves by removing closely spaced keyframes"; | ot->description = "Simplify F-Curves by removing closely spaced keyframes"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| // ot->invoke = ???; /* XXX we need that number popup for this! */ | // ot->invoke = ???; /* XXX we need that number popup for this! */ | ||||
| ot->exec = graphkeys_clean_exec; | ot->exec = graphkeys_clean_exec; | ||||
| ot->poll = graphop_editable_keyframes_poll; | ot->poll = graphop_editable_keyframes_poll; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| /* properties */ | /* Properties */ | ||||
| ot->prop = RNA_def_float( | ot->prop = RNA_def_float( | ||||
| ot->srna, "threshold", 0.001f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 1000.0f); | ot->srna, "threshold", 0.001f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 1000.0f); | ||||
| RNA_def_boolean(ot->srna, "channels", false, "Channels", ""); | RNA_def_boolean(ot->srna, "channels", false, "Channels", ""); | ||||
| } | } | ||||
| /* ******************** Decimate Keyframes Operator ************************* */ | /* ******************** Decimate Keyframes Operator ************************* */ | ||||
| static void decimate_graph_keys(bAnimContext *ac, float remove_ratio, float error_sq_max) | static void decimate_graph_keys(bAnimContext *ac, float remove_ratio, float error_sq_max) | ||||
| { | { | ||||
| ListBase anim_data = {NULL, NULL}; | ListBase anim_data = {NULL, NULL}; | ||||
| bAnimListElem *ale; | bAnimListElem *ale; | ||||
| int filter; | int filter; | ||||
| /* filter data */ | /* Filter data. */ | ||||
| filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | ||||
| ANIMFILTER_SEL | ANIMFILTER_NODUPLIS); | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS); | ||||
| ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ||||
| /* loop through filtered data and clean curves */ | /* Loop through filtered data and clean curves. */ | ||||
| for (ale = anim_data.first; ale; ale = ale->next) { | for (ale = anim_data.first; ale; ale = ale->next) { | ||||
| if (!decimate_fcurve(ale, remove_ratio, error_sq_max)) { | if (!decimate_fcurve(ale, remove_ratio, error_sq_max)) { | ||||
| /* The selection contains unsupported keyframe types! */ | /* The selection contains unsupported keyframe types! */ | ||||
| WM_report(RPT_WARNING, "Decimate: Skipping non linear/bezier keyframes!"); | WM_report(RPT_WARNING, "Decimate: Skipping non linear/bezier keyframes!"); | ||||
| } | } | ||||
| ale->update |= ANIM_UPDATE_DEFAULT; | ale->update |= ANIM_UPDATE_DEFAULT; | ||||
| } | } | ||||
| Show All 35 Lines | |||||
| { | { | ||||
| ListBase anim_data = {NULL, NULL}; | ListBase anim_data = {NULL, NULL}; | ||||
| LinkData *link_bezt; | LinkData *link_bezt; | ||||
| bAnimListElem *ale; | bAnimListElem *ale; | ||||
| int filter; | int filter; | ||||
| bAnimContext *ac = &dgo->ac; | bAnimContext *ac = &dgo->ac; | ||||
| /* filter data */ | /* Filter data. */ | ||||
| filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | ||||
| ANIMFILTER_SEL | ANIMFILTER_NODUPLIS); | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS); | ||||
| ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ||||
| /* Loop through filtered data and reset bezts. */ | /* Loop through filtered data and reset bezts. */ | ||||
| for (ale = anim_data.first, link_bezt = dgo->bezt_arr_list.first; ale; ale = ale->next) { | for (ale = anim_data.first, link_bezt = dgo->bezt_arr_list.first; ale; ale = ale->next) { | ||||
| FCurve *fcu = (FCurve *)ale->key_data; | FCurve *fcu = (FCurve *)ale->key_data; | ||||
| if (fcu->bezt == NULL) { | if (fcu->bezt == NULL) { | ||||
| /* This curve is baked, skip it */ | /* This curve is baked, skip it. */ | ||||
| continue; | continue; | ||||
| } | } | ||||
| tBeztCopyData *data = link_bezt->data; | tBeztCopyData *data = link_bezt->data; | ||||
| const int arr_size = sizeof(BezTriple) * data->tot_vert; | const int arr_size = sizeof(BezTriple) * data->tot_vert; | ||||
| MEM_freeN(fcu->bezt); | MEM_freeN(fcu->bezt); | ||||
| Show All 30 Lines | static void decimate_exit(bContext *C, wmOperator *op) | ||||
| BLI_freelistN(&dgo->bezt_arr_list); | BLI_freelistN(&dgo->bezt_arr_list); | ||||
| MEM_freeN(dgo); | MEM_freeN(dgo); | ||||
| /* Return to normal cursor and header status. */ | /* Return to normal cursor and header status. */ | ||||
| WM_cursor_modal_restore(win); | WM_cursor_modal_restore(win); | ||||
| ED_area_status_text(area, NULL); | ED_area_status_text(area, NULL); | ||||
| /* cleanup */ | /* Cleanup. */ | ||||
| op->customdata = NULL; | op->customdata = NULL; | ||||
| } | } | ||||
| /* Draw a percentage indicator in header. */ | /* Draw a percentage indicator in header. */ | ||||
| static void decimate_draw_status_header(wmOperator *op, tDecimateGraphOp *dgo) | static void decimate_draw_status_header(wmOperator *op, tDecimateGraphOp *dgo) | ||||
| { | { | ||||
| char status_str[UI_MAX_DRAW_STR]; | char status_str[UI_MAX_DRAW_STR]; | ||||
| char mode_str[32]; | char mode_str[32]; | ||||
| ▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | static int graphkeys_decimate_invoke(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| */ | */ | ||||
| { | { | ||||
| ListBase anim_data = {NULL, NULL}; | ListBase anim_data = {NULL, NULL}; | ||||
| bAnimContext *ac = &dgo->ac; | bAnimContext *ac = &dgo->ac; | ||||
| bAnimListElem *ale; | bAnimListElem *ale; | ||||
| int filter; | int filter; | ||||
| /* filter data */ | /* Filter data. */ | ||||
| filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | ||||
| ANIMFILTER_SEL | ANIMFILTER_NODUPLIS); | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS); | ||||
| ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ||||
| /* Loop through filtered data and copy the curves. */ | /* Loop through filtered data and copy the curves. */ | ||||
| for (ale = anim_data.first; ale; ale = ale->next) { | for (ale = anim_data.first; ale; ale = ale->next) { | ||||
| FCurve *fcu = (FCurve *)ale->key_data; | FCurve *fcu = (FCurve *)ale->key_data; | ||||
| if (fcu->bezt == NULL) { | if (fcu->bezt == NULL) { | ||||
| /* This curve is baked, skip it */ | /* This curve is baked, skip it. */ | ||||
| continue; | continue; | ||||
| } | } | ||||
| const int arr_size = sizeof(BezTriple) * fcu->totvert; | const int arr_size = sizeof(BezTriple) * fcu->totvert; | ||||
| tBeztCopyData *copy = MEM_mallocN(sizeof(tBeztCopyData), "bezts_copy"); | tBeztCopyData *copy = MEM_mallocN(sizeof(tBeztCopyData), "bezts_copy"); | ||||
| BezTriple *bezts_copy = MEM_mallocN(arr_size, "bezts_copy_array"); | BezTriple *bezts_copy = MEM_mallocN(arr_size, "bezts_copy_array"); | ||||
| Show All 30 Lines | static void graphkeys_decimate_modal_update(bContext *C, wmOperator *op) | ||||
| * (e.g. pressing a key or moving the mouse). */ | * (e.g. pressing a key or moving the mouse). */ | ||||
| tDecimateGraphOp *dgo = op->customdata; | tDecimateGraphOp *dgo = op->customdata; | ||||
| decimate_draw_status_header(op, dgo); | decimate_draw_status_header(op, dgo); | ||||
| /* Reset keyframe data (so we get back to the original state). */ | /* Reset keyframe data (so we get back to the original state). */ | ||||
| decimate_reset_bezts(dgo); | decimate_reset_bezts(dgo); | ||||
| /* apply... */ | /* Apply... */ | ||||
| float remove_ratio = RNA_property_float_get(op->ptr, dgo->percentage_prop); | 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. */ | /* We don't want to limit the decimation to a certain error margin. */ | ||||
| const float error_sq_max = FLT_MAX; | const float error_sq_max = FLT_MAX; | ||||
| decimate_graph_keys(&dgo->ac, remove_ratio, error_sq_max); | decimate_graph_keys(&dgo->ac, remove_ratio, error_sq_max); | ||||
| WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | ||||
| } | } | ||||
| static int graphkeys_decimate_modal(bContext *C, wmOperator *op, const wmEvent *event) | 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 | /* 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 | * 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 | * error margin mode is not adjusted by the modal operator but instead tweaked via the redo | ||||
| * panel.*/ | * panel.*/ | ||||
| tDecimateGraphOp *dgo = op->customdata; | tDecimateGraphOp *dgo = op->customdata; | ||||
| const bool has_numinput = hasNumInput(&dgo->num); | const bool has_numinput = hasNumInput(&dgo->num); | ||||
| switch (event->type) { | switch (event->type) { | ||||
| case LEFTMOUSE: /* confirm */ | case LEFTMOUSE: /* Confirm */ | ||||
| case EVT_RETKEY: | case EVT_RETKEY: | ||||
| case EVT_PADENTER: { | case EVT_PADENTER: { | ||||
| if (event->val == KM_PRESS) { | if (event->val == KM_PRESS) { | ||||
| decimate_exit(C, op); | decimate_exit(C, op); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| case EVT_ESCKEY: /* cancel */ | case EVT_ESCKEY: /* Cancel */ | ||||
| case RIGHTMOUSE: { | case RIGHTMOUSE: { | ||||
| if (event->val == KM_PRESS) { | if (event->val == KM_PRESS) { | ||||
| decimate_reset_bezts(dgo); | decimate_reset_bezts(dgo); | ||||
| WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | ||||
| decimate_exit(C, op); | decimate_exit(C, op); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| /* Percentage Change... */ | /* Percentage Change... */ | ||||
| case MOUSEMOVE: /* calculate new position */ | case MOUSEMOVE: /* Calculate new position. */ | ||||
| { | { | ||||
| if (has_numinput == false) { | if (has_numinput == false) { | ||||
| /* Update percentage based on position of mouse. */ | /* Update percentage based on position of mouse. */ | ||||
| decimate_mouse_update_percentage(dgo, op, event); | decimate_mouse_update_percentage(dgo, op, event); | ||||
| /* Update pose to reflect the new values. */ | /* Update pose to reflect the new values. */ | ||||
| graphkeys_decimate_modal_update(C, op); | graphkeys_decimate_modal_update(C, op); | ||||
| } | } | ||||
| Show All 13 Lines | default: { | ||||
| percentage = value / 100.0f; | percentage = value / 100.0f; | ||||
| RNA_property_float_set(op->ptr, dgo->percentage_prop, percentage); | RNA_property_float_set(op->ptr, dgo->percentage_prop, percentage); | ||||
| /* Update decimate output to reflect the new values. */ | /* Update decimate output to reflect the new values. */ | ||||
| graphkeys_decimate_modal_update(C, op); | graphkeys_decimate_modal_update(C, op); | ||||
| break; | break; | ||||
| } | } | ||||
| /* unhandled event - maybe it was some view manip? */ | /* Unhandled event - maybe it was some view manip? */ | ||||
| /* allow to pass through */ | /* Allow to pass through. */ | ||||
| return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH; | return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH; | ||||
| } | } | ||||
| } | } | ||||
| return OPERATOR_RUNNING_MODAL; | return OPERATOR_RUNNING_MODAL; | ||||
| } | } | ||||
| static int graphkeys_decimate_exec(bContext *C, wmOperator *op) | static int graphkeys_decimate_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| /* get editor data */ | /* Get editor data. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| tDecimModes mode = RNA_enum_get(op->ptr, "mode"); | tDecimModes mode = RNA_enum_get(op->ptr, "mode"); | ||||
| /* We want to be able to work on all available keyframes. */ | /* We want to be able to work on all available keyframes. */ | ||||
| float remove_ratio = 1.0f; | float remove_ratio = 1.0f; | ||||
| /* We don't want to limit the decimation to a certain error margin. */ | /* We don't want to limit the decimation to a certain error margin. */ | ||||
| Show All 13 Lines | static int graphkeys_decimate_exec(bContext *C, wmOperator *op) | ||||
| if (remove_ratio == 0.0f || error_sq_max == 0.0f) { | if (remove_ratio == 0.0f || error_sq_max == 0.0f) { | ||||
| /* Nothing to remove. */ | /* Nothing to remove. */ | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| decimate_graph_keys(&ac, remove_ratio, error_sq_max); | decimate_graph_keys(&ac, remove_ratio, error_sq_max); | ||||
| /* set notifier that keyframes have changed */ | /* Set notifier that keyframes have changed. */ | ||||
| WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| static bool graphkeys_decimate_poll_property(const bContext *UNUSED(C), | static bool graphkeys_decimate_poll_property(const bContext *UNUSED(C), | ||||
| wmOperator *op, | wmOperator *op, | ||||
| const PropertyRNA *prop) | const PropertyRNA *prop) | ||||
| Show All 40 Lines | static const EnumPropertyItem decimate_mode_items[] = { | ||||
| "Error Margin", | "Error Margin", | ||||
| "Use an error margin to specify how much the curve is allowed to deviate from the original " | "Use an error margin to specify how much the curve is allowed to deviate from the original " | ||||
| "path"}, | "path"}, | ||||
| {0, NULL, 0, NULL, NULL}, | {0, NULL, 0, NULL, NULL}, | ||||
| }; | }; | ||||
| void GRAPH_OT_decimate(wmOperatorType *ot) | void GRAPH_OT_decimate(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Decimate Keyframes"; | ot->name = "Decimate Keyframes"; | ||||
| ot->idname = "GRAPH_OT_decimate"; | ot->idname = "GRAPH_OT_decimate"; | ||||
| ot->description = | ot->description = | ||||
| "Decimate F-Curves by removing keyframes that influence the curve shape the least"; | "Decimate F-Curves by removing keyframes that influence the curve shape the least"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->poll_property = graphkeys_decimate_poll_property; | ot->poll_property = graphkeys_decimate_poll_property; | ||||
| ot->get_description = graphkeys_decimate_desc; | ot->get_description = graphkeys_decimate_desc; | ||||
| ot->invoke = graphkeys_decimate_invoke; | ot->invoke = graphkeys_decimate_invoke; | ||||
| ot->modal = graphkeys_decimate_modal; | ot->modal = graphkeys_decimate_modal; | ||||
| ot->exec = graphkeys_decimate_exec; | ot->exec = graphkeys_decimate_exec; | ||||
| ot->poll = graphop_editable_keyframes_poll; | ot->poll = graphop_editable_keyframes_poll; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| /* properties */ | /* Properties */ | ||||
| RNA_def_enum(ot->srna, | RNA_def_enum(ot->srna, | ||||
| "mode", | "mode", | ||||
| decimate_mode_items, | decimate_mode_items, | ||||
| DECIM_RATIO, | DECIM_RATIO, | ||||
| "Mode", | "Mode", | ||||
| "Which mode to use for decimation"); | "Which mode to use for decimation"); | ||||
| RNA_def_float_percentage(ot->srna, | RNA_def_float_percentage(ot->srna, | ||||
| Show All 14 Lines | RNA_def_float(ot->srna, | ||||
| "How much the new decimated curve is allowed to deviate from the original", | "How much the new decimated curve is allowed to deviate from the original", | ||||
| 0.0f, | 0.0f, | ||||
| 10.0f); | 10.0f); | ||||
| } | } | ||||
| /* ******************** Bake F-Curve Operator *********************** */ | /* ******************** Bake F-Curve Operator *********************** */ | ||||
| /* This operator bakes the data of the selected F-Curves to F-Points */ | /* This operator bakes the data of the selected F-Curves to F-Points */ | ||||
| /* Bake each F-Curve into a set of samples */ | /* Bake each F-Curve into a set of samples. */ | ||||
| static void bake_graph_curves(bAnimContext *ac, int start, int end) | static void bake_graph_curves(bAnimContext *ac, int start, int end) | ||||
| { | { | ||||
| ListBase anim_data = {NULL, NULL}; | ListBase anim_data = {NULL, NULL}; | ||||
| bAnimListElem *ale; | bAnimListElem *ale; | ||||
| int filter; | int filter; | ||||
| /* filter data */ | /* Filter data. */ | ||||
| filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL | | filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL | | ||||
| ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); | ||||
| ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ||||
| /* loop through filtered data and add keys between selected keyframes on every frame */ | /* Loop through filtered data and add keys between selected keyframes on every frame. */ | ||||
| for (ale = anim_data.first; ale; ale = ale->next) { | for (ale = anim_data.first; ale; ale = ale->next) { | ||||
| FCurve *fcu = (FCurve *)ale->key_data; | FCurve *fcu = (FCurve *)ale->key_data; | ||||
| ChannelDriver *driver = fcu->driver; | ChannelDriver *driver = fcu->driver; | ||||
| /* disable driver so that it don't muck up the sampling process */ | /* Disable driver so that it don't muck up the sampling process. */ | ||||
| fcu->driver = NULL; | fcu->driver = NULL; | ||||
| /* create samples */ | /* Create samples. */ | ||||
| fcurve_store_samples(fcu, NULL, start, end, fcurve_samplingcb_evalcurve); | fcurve_store_samples(fcu, NULL, start, end, fcurve_samplingcb_evalcurve); | ||||
| /* restore driver */ | /* Restore driver. */ | ||||
| fcu->driver = driver; | fcu->driver = driver; | ||||
| ale->update |= ANIM_UPDATE_DEPS; | ale->update |= ANIM_UPDATE_DEPS; | ||||
| } | } | ||||
| ANIM_animdata_update(ac, &anim_data); | ANIM_animdata_update(ac, &anim_data); | ||||
| ANIM_animdata_freelist(&anim_data); | ANIM_animdata_freelist(&anim_data); | ||||
| } | } | ||||
| /* ------------------- */ | /* ------------------- */ | ||||
| static int graphkeys_bake_exec(bContext *C, wmOperator *UNUSED(op)) | static int graphkeys_bake_exec(bContext *C, wmOperator *UNUSED(op)) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| Scene *scene = NULL; | Scene *scene = NULL; | ||||
| int start, end; | int start, end; | ||||
| /* get editor data */ | /* Get editor data. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* for now, init start/end from preview-range extents */ | /* For now, init start/end from preview-range extents. */ | ||||
| /* TODO: add properties for this */ | /* TODO: add properties for this. (Joshua Leung 2009) */ | ||||
| scene = ac.scene; | scene = ac.scene; | ||||
| start = PSFRA; | start = PSFRA; | ||||
| end = PEFRA; | end = PEFRA; | ||||
| /* bake keyframes */ | /* Bake keyframes. */ | ||||
| bake_graph_curves(&ac, start, end); | bake_graph_curves(&ac, start, end); | ||||
| /* set notifier that keyframes have changed */ | /* Set notifier that keyframes have changed. */ | ||||
| /* NOTE: some distinction between order/number of keyframes and type should be made? */ | /* 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); | WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GRAPH_OT_bake(wmOperatorType *ot) | void GRAPH_OT_bake(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Bake Curve"; | ot->name = "Bake Curve"; | ||||
| ot->idname = "GRAPH_OT_bake"; | ot->idname = "GRAPH_OT_bake"; | ||||
| ot->description = "Bake selected F-Curves to a set of sampled points defining a similar curve"; | ot->description = "Bake selected F-Curves to a set of sampled points defining a similar curve"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->invoke = WM_operator_confirm; /* FIXME */ | ot->invoke = WM_operator_confirm; /* FIXME */ | ||||
| ot->exec = graphkeys_bake_exec; | ot->exec = graphkeys_bake_exec; | ||||
| ot->poll = graphop_selected_fcurve_poll; | ot->poll = graphop_selected_fcurve_poll; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| /* TODO: add props for start/end frames */ | /* TODO: add props for start/end frames (Joshua Leung 2009) */ | ||||
| } | } | ||||
| #ifdef WITH_AUDASPACE | #ifdef WITH_AUDASPACE | ||||
| /* ******************** Sound Bake F-Curve Operator *********************** */ | /* ******************** Sound Bake F-Curve Operator *********************** */ | ||||
| /* This operator bakes the given sound to the selected F-Curves */ | /* This operator bakes the given sound to the selected F-Curves */ | ||||
| /* ------------------- */ | /* ------------------- */ | ||||
| /* Custom data storage passed to the F-Sample-ing function, | /* Custom data storage passed to the F-Sample-ing function, | ||||
| * which provides the necessary info for baking the sound | * which provides the necessary info for baking the sound. | ||||
| */ | */ | ||||
| typedef struct tSoundBakeInfo { | typedef struct tSoundBakeInfo { | ||||
| float *samples; | float *samples; | ||||
| int length; | int length; | ||||
| int cfra; | int cfra; | ||||
| } tSoundBakeInfo; | } tSoundBakeInfo; | ||||
| /* ------------------- */ | /* ------------------- */ | ||||
| /* Sampling callback used to determine the value from the sound to | /* Sampling callback used to determine the value from the sound to | ||||
| * save in the F-Curve at the specified frame | * save in the F-Curve at the specified frame. | ||||
| */ | */ | ||||
| static float fcurve_samplingcb_sound(FCurve *UNUSED(fcu), void *data, float evaltime) | static float fcurve_samplingcb_sound(FCurve *UNUSED(fcu), void *data, float evaltime) | ||||
| { | { | ||||
| tSoundBakeInfo *sbi = (tSoundBakeInfo *)data; | tSoundBakeInfo *sbi = (tSoundBakeInfo *)data; | ||||
| int position = evaltime - sbi->cfra; | int position = evaltime - sbi->cfra; | ||||
| if ((position < 0) || (position >= sbi->length)) { | if ((position < 0) || (position >= sbi->length)) { | ||||
| return 0.0f; | return 0.0f; | ||||
| Show All 12 Lines | static int graphkeys_sound_bake_exec(bContext *C, wmOperator *op) | ||||
| int filter; | int filter; | ||||
| tSoundBakeInfo sbi; | tSoundBakeInfo sbi; | ||||
| Scene *scene = NULL; | Scene *scene = NULL; | ||||
| int start, end; | int start, end; | ||||
| char path[FILE_MAX]; | char path[FILE_MAX]; | ||||
| /* get editor data */ | /* Get editor data. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| RNA_string_get(op->ptr, "filepath", path); | RNA_string_get(op->ptr, "filepath", path); | ||||
| if (!BLI_is_file(path)) { | if (!BLI_is_file(path)) { | ||||
| BKE_reportf(op->reports, RPT_ERROR, "File not found '%s'", path); | BKE_reportf(op->reports, RPT_ERROR, "File not found '%s'", path); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| scene = ac.scene; /* current scene */ | scene = ac.scene; /* Current scene. */ | ||||
| /* store necessary data for the baking steps */ | /* Store necessary data for the baking steps. */ | ||||
| sbi.samples = AUD_readSoundBuffer(path, | sbi.samples = AUD_readSoundBuffer(path, | ||||
| RNA_float_get(op->ptr, "low"), | RNA_float_get(op->ptr, "low"), | ||||
| RNA_float_get(op->ptr, "high"), | RNA_float_get(op->ptr, "high"), | ||||
| RNA_float_get(op->ptr, "attack"), | RNA_float_get(op->ptr, "attack"), | ||||
| RNA_float_get(op->ptr, "release"), | RNA_float_get(op->ptr, "release"), | ||||
| RNA_float_get(op->ptr, "threshold"), | RNA_float_get(op->ptr, "threshold"), | ||||
| RNA_boolean_get(op->ptr, "use_accumulate"), | RNA_boolean_get(op->ptr, "use_accumulate"), | ||||
| RNA_boolean_get(op->ptr, "use_additive"), | RNA_boolean_get(op->ptr, "use_additive"), | ||||
| RNA_boolean_get(op->ptr, "use_square"), | RNA_boolean_get(op->ptr, "use_square"), | ||||
| RNA_float_get(op->ptr, "sthreshold"), | RNA_float_get(op->ptr, "sthreshold"), | ||||
| FPS, | FPS, | ||||
| &sbi.length); | &sbi.length); | ||||
| if (sbi.samples == NULL) { | if (sbi.samples == NULL) { | ||||
| BKE_report(op->reports, RPT_ERROR, "Unsupported audio format"); | BKE_report(op->reports, RPT_ERROR, "Unsupported audio format"); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* determine extents of the baking */ | /* Determine extents of the baking. */ | ||||
| sbi.cfra = start = CFRA; | sbi.cfra = start = CFRA; | ||||
| end = CFRA + sbi.length - 1; | end = CFRA + sbi.length - 1; | ||||
| /* filter anim channels */ | /* Filter anim channels. */ | ||||
| filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL | | filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL | | ||||
| ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); | ||||
| ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); | ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); | ||||
| /* loop through all selected F-Curves, replacing its data with the sound samples */ | /* Loop through all selected F-Curves, replacing its data with the sound samples. */ | ||||
| for (ale = anim_data.first; ale; ale = ale->next) { | for (ale = anim_data.first; ale; ale = ale->next) { | ||||
| FCurve *fcu = (FCurve *)ale->key_data; | FCurve *fcu = (FCurve *)ale->key_data; | ||||
| /* sample the sound */ | /* Sample the sound. */ | ||||
| fcurve_store_samples(fcu, &sbi, start, end, fcurve_samplingcb_sound); | fcurve_store_samples(fcu, &sbi, start, end, fcurve_samplingcb_sound); | ||||
| ale->update |= ANIM_UPDATE_DEFAULT; | ale->update |= ANIM_UPDATE_DEFAULT; | ||||
| } | } | ||||
| /* free sample data */ | /* Free sample data. */ | ||||
| free(sbi.samples); | free(sbi.samples); | ||||
| /* validate keyframes after editing */ | /* Validate keyframes after editing. */ | ||||
| ANIM_animdata_update(&ac, &anim_data); | ANIM_animdata_update(&ac, &anim_data); | ||||
| ANIM_animdata_freelist(&anim_data); | ANIM_animdata_freelist(&anim_data); | ||||
| /* set notifier that 'keyframes' have changed */ | /* Set notifier that 'keyframes' have changed. */ | ||||
| WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| #else /* WITH_AUDASPACE */ | #else /* WITH_AUDASPACE */ | ||||
| static int graphkeys_sound_bake_exec(bContext *UNUSED(C), wmOperator *op) | static int graphkeys_sound_bake_exec(bContext *UNUSED(C), wmOperator *op) | ||||
| { | { | ||||
| BKE_report(op->reports, RPT_ERROR, "Compiled without sound support"); | BKE_report(op->reports, RPT_ERROR, "Compiled without sound support"); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| #endif /* WITH_AUDASPACE */ | #endif /* WITH_AUDASPACE */ | ||||
| static int graphkeys_sound_bake_invoke(bContext *C, wmOperator *op, const wmEvent *event) | static int graphkeys_sound_bake_invoke(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| /* verify editor data */ | /* Verify editor data. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| return WM_operator_filesel(C, op, event); | return WM_operator_filesel(C, op, event); | ||||
| } | } | ||||
| void GRAPH_OT_sound_bake(wmOperatorType *ot) | void GRAPH_OT_sound_bake(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Bake Sound to F-Curves"; | ot->name = "Bake Sound to F-Curves"; | ||||
| ot->idname = "GRAPH_OT_sound_bake"; | ot->idname = "GRAPH_OT_sound_bake"; | ||||
| ot->description = "Bakes a sound wave to selected F-Curves"; | ot->description = "Bakes a sound wave to selected F-Curves"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->invoke = graphkeys_sound_bake_invoke; | ot->invoke = graphkeys_sound_bake_invoke; | ||||
| ot->exec = graphkeys_sound_bake_exec; | ot->exec = graphkeys_sound_bake_exec; | ||||
| ot->poll = graphop_selected_fcurve_poll; | ot->poll = graphop_selected_fcurve_poll; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| /* properties */ | /* Properties */ | ||||
| WM_operator_properties_filesel(ot, | WM_operator_properties_filesel(ot, | ||||
| FILE_TYPE_FOLDER | FILE_TYPE_SOUND | FILE_TYPE_MOVIE, | FILE_TYPE_FOLDER | FILE_TYPE_SOUND | FILE_TYPE_MOVIE, | ||||
| FILE_SPECIAL, | FILE_SPECIAL, | ||||
| FILE_OPENFILE, | FILE_OPENFILE, | ||||
| WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS, | WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS, | ||||
| FILE_DEFAULTDISPLAY, | FILE_DEFAULTDISPLAY, | ||||
| FILE_SORT_ALPHA); | FILE_SORT_ALPHA); | ||||
| RNA_def_float(ot->srna, | RNA_def_float(ot->srna, | ||||
| ▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Lines | RNA_def_float(ot->srna, | ||||
| 0.1); | 0.1); | ||||
| } | } | ||||
| /* ******************** Sample Keyframes Operator *********************** */ | /* ******************** Sample Keyframes Operator *********************** */ | ||||
| /* This operator 'bakes' the values of the curve into new keyframes between pairs | /* This operator 'bakes' the values of the curve into new keyframes between pairs | ||||
| * of selected keyframes. It is useful for creating keyframes for tweaking overlap. | * of selected keyframes. It is useful for creating keyframes for tweaking overlap. | ||||
| */ | */ | ||||
| /* Evaluates the curves between each selected keyframe on each frame, and keys the value */ | /* Evaluates the curves between each selected keyframe on each frame, and keys the value. */ | ||||
| static void sample_graph_keys(bAnimContext *ac) | static void sample_graph_keys(bAnimContext *ac) | ||||
| { | { | ||||
| ListBase anim_data = {NULL, NULL}; | ListBase anim_data = {NULL, NULL}; | ||||
| bAnimListElem *ale; | bAnimListElem *ale; | ||||
| int filter; | int filter; | ||||
| /* filter data */ | /* filter data */ | ||||
| filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | ||||
| ANIMFILTER_NODUPLIS); | ANIMFILTER_NODUPLIS); | ||||
| ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ||||
| /* loop through filtered data and add keys between selected keyframes on every frame */ | /* Loop through filtered data and add keys between selected keyframes on every frame. */ | ||||
| for (ale = anim_data.first; ale; ale = ale->next) { | for (ale = anim_data.first; ale; ale = ale->next) { | ||||
| sample_fcurve((FCurve *)ale->key_data); | sample_fcurve((FCurve *)ale->key_data); | ||||
| ale->update |= ANIM_UPDATE_DEPS; | ale->update |= ANIM_UPDATE_DEPS; | ||||
| } | } | ||||
| ANIM_animdata_update(ac, &anim_data); | ANIM_animdata_update(ac, &anim_data); | ||||
| ANIM_animdata_freelist(&anim_data); | ANIM_animdata_freelist(&anim_data); | ||||
| } | } | ||||
| /* ------------------- */ | /* ------------------- */ | ||||
| static int graphkeys_sample_exec(bContext *C, wmOperator *UNUSED(op)) | static int graphkeys_sample_exec(bContext *C, wmOperator *UNUSED(op)) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| /* get editor data */ | /* Get editor data. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* sample keyframes */ | /* Sample keyframes. */ | ||||
| sample_graph_keys(&ac); | sample_graph_keys(&ac); | ||||
| /* set notifier that keyframes have changed */ | /* Set notifier that keyframes have changed. */ | ||||
| WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GRAPH_OT_sample(wmOperatorType *ot) | void GRAPH_OT_sample(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Sample Keyframes"; | ot->name = "Sample Keyframes"; | ||||
| ot->idname = "GRAPH_OT_sample"; | ot->idname = "GRAPH_OT_sample"; | ||||
| ot->description = "Add keyframes on every frame between the selected keyframes"; | ot->description = "Add keyframes on every frame between the selected keyframes"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->exec = graphkeys_sample_exec; | ot->exec = graphkeys_sample_exec; | ||||
| ot->poll = graphop_editable_keyframes_poll; | ot->poll = graphop_editable_keyframes_poll; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| } | } | ||||
| /* ************************************************************************** */ | /* ************************************************************************** */ | ||||
| /* SETTINGS STUFF */ | /* SETTINGS STUFF */ | ||||
| /* ******************** Set Extrapolation-Type Operator *********************** */ | /* ******************** Set Extrapolation-Type Operator *********************** */ | ||||
| /* defines for make/clear cyclic extrapolation tools */ | /* Defines for make/clear cyclic extrapolation tools. */ | ||||
| #define MAKE_CYCLIC_EXPO -1 | #define MAKE_CYCLIC_EXPO -1 | ||||
| #define CLEAR_CYCLIC_EXPO -2 | #define CLEAR_CYCLIC_EXPO -2 | ||||
| /* defines for set extrapolation-type for selected keyframes tool */ | /* Defines for set extrapolation-type for selected keyframes tool. */ | ||||
| static const EnumPropertyItem prop_graphkeys_expo_types[] = { | static const EnumPropertyItem prop_graphkeys_expo_types[] = { | ||||
| {FCURVE_EXTRAPOLATE_CONSTANT, | {FCURVE_EXTRAPOLATE_CONSTANT, | ||||
| "CONSTANT", | "CONSTANT", | ||||
| 0, | 0, | ||||
| "Constant Extrapolation", | "Constant Extrapolation", | ||||
| "Values on endpoint keyframes are held"}, | "Values on endpoint keyframes are held"}, | ||||
| {FCURVE_EXTRAPOLATE_LINEAR, | {FCURVE_EXTRAPOLATE_LINEAR, | ||||
| "LINEAR", | "LINEAR", | ||||
| Show All 9 Lines | static const EnumPropertyItem prop_graphkeys_expo_types[] = { | ||||
| {CLEAR_CYCLIC_EXPO, | {CLEAR_CYCLIC_EXPO, | ||||
| "CLEAR_CYCLIC", | "CLEAR_CYCLIC", | ||||
| 0, | 0, | ||||
| "Clear Cyclic (F-Modifier)", | "Clear Cyclic (F-Modifier)", | ||||
| "Remove Cycles F-Modifier if not needed anymore"}, | "Remove Cycles F-Modifier if not needed anymore"}, | ||||
| {0, NULL, 0, NULL, NULL}, | {0, NULL, 0, NULL, NULL}, | ||||
| }; | }; | ||||
| /* this function is responsible for setting extrapolation mode for keyframes */ | /* This function is responsible for setting extrapolation mode for keyframes. */ | ||||
| static void setexpo_graph_keys(bAnimContext *ac, short mode) | static void setexpo_graph_keys(bAnimContext *ac, short mode) | ||||
| { | { | ||||
| ListBase anim_data = {NULL, NULL}; | ListBase anim_data = {NULL, NULL}; | ||||
| bAnimListElem *ale; | bAnimListElem *ale; | ||||
| int filter; | int filter; | ||||
| /* filter data */ | /* Filter data. */ | ||||
| filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL | | filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL | | ||||
| ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); | ||||
| ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ||||
| /* loop through setting mode per F-Curve */ | /* Loop through setting mode per F-Curve. */ | ||||
| for (ale = anim_data.first; ale; ale = ale->next) { | for (ale = anim_data.first; ale; ale = ale->next) { | ||||
| FCurve *fcu = (FCurve *)ale->data; | FCurve *fcu = (FCurve *)ale->data; | ||||
| if (mode >= 0) { | if (mode >= 0) { | ||||
| /* just set mode setting */ | /* Just set mode setting. */ | ||||
| fcu->extend = mode; | fcu->extend = mode; | ||||
| ale->update |= ANIM_UPDATE_HANDLES; | ale->update |= ANIM_UPDATE_HANDLES; | ||||
| } | } | ||||
| else { | else { | ||||
| /* shortcuts for managing Cycles F-Modifiers to make it easier to toggle cyclic animation | /* 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 | * without having to go through FModifier UI in Graph Editor to do so. | ||||
| */ | */ | ||||
| if (mode == MAKE_CYCLIC_EXPO) { | if (mode == MAKE_CYCLIC_EXPO) { | ||||
| /* only add if one doesn't exist */ | /* Only add if one doesn't exist. */ | ||||
| if (list_has_suitable_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES, -1) == 0) { | if (list_has_suitable_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES, -1) == 0) { | ||||
| /* TODO: add some more preset versions which set different extrapolation options? */ | /* TODO: add some more preset versions which set different extrapolation options? | ||||
| * (Joshua Leung 2011) */ | |||||
| add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES, fcu); | add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES, fcu); | ||||
| } | } | ||||
| } | } | ||||
| else if (mode == CLEAR_CYCLIC_EXPO) { | else if (mode == CLEAR_CYCLIC_EXPO) { | ||||
| /* remove all the modifiers fitting this description */ | /* Remove all the modifiers fitting this description. */ | ||||
| FModifier *fcm, *fcn = NULL; | FModifier *fcm, *fcn = NULL; | ||||
| for (fcm = fcu->modifiers.first; fcm; fcm = fcn) { | for (fcm = fcu->modifiers.first; fcm; fcm = fcn) { | ||||
| fcn = fcm->next; | fcn = fcm->next; | ||||
| if (fcm->type == FMODIFIER_TYPE_CYCLES) { | if (fcm->type == FMODIFIER_TYPE_CYCLES) { | ||||
| remove_fmodifier(&fcu->modifiers, fcm); | remove_fmodifier(&fcu->modifiers, fcm); | ||||
| } | } | ||||
| Show All 10 Lines | |||||
| /* ------------------- */ | /* ------------------- */ | ||||
| static int graphkeys_expo_exec(bContext *C, wmOperator *op) | static int graphkeys_expo_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| short mode; | short mode; | ||||
| /* get editor data */ | /* Get editor data. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* get handle setting mode */ | /* Get handle setting mode. */ | ||||
| mode = RNA_enum_get(op->ptr, "type"); | mode = RNA_enum_get(op->ptr, "type"); | ||||
| /* set handle type */ | /* Set handle type. */ | ||||
| setexpo_graph_keys(&ac, mode); | setexpo_graph_keys(&ac, mode); | ||||
| /* set notifier that keyframe properties have changed */ | /* Set notifier that keyframe properties have changed. */ | ||||
| WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL); | WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GRAPH_OT_extrapolation_type(wmOperatorType *ot) | void GRAPH_OT_extrapolation_type(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Set Keyframe Extrapolation"; | ot->name = "Set Keyframe Extrapolation"; | ||||
| ot->idname = "GRAPH_OT_extrapolation_type"; | ot->idname = "GRAPH_OT_extrapolation_type"; | ||||
| ot->description = "Set extrapolation mode for selected F-Curves"; | ot->description = "Set extrapolation mode for selected F-Curves"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->invoke = WM_menu_invoke; | ot->invoke = WM_menu_invoke; | ||||
| ot->exec = graphkeys_expo_exec; | ot->exec = graphkeys_expo_exec; | ||||
| ot->poll = graphop_editable_keyframes_poll; | ot->poll = graphop_editable_keyframes_poll; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| /* id-props */ | /* Id-props */ | ||||
| ot->prop = RNA_def_enum(ot->srna, "type", prop_graphkeys_expo_types, 0, "Type", ""); | ot->prop = RNA_def_enum(ot->srna, "type", prop_graphkeys_expo_types, 0, "Type", ""); | ||||
| } | } | ||||
| /* ******************** Set Interpolation-Type Operator *********************** */ | /* ******************** Set Interpolation-Type Operator *********************** */ | ||||
| /* this function is responsible for setting interpolation mode for keyframes */ | /* This function is responsible for setting interpolation mode for keyframes. */ | ||||
| static void setipo_graph_keys(bAnimContext *ac, short mode) | static void setipo_graph_keys(bAnimContext *ac, short mode) | ||||
| { | { | ||||
| ListBase anim_data = {NULL, NULL}; | ListBase anim_data = {NULL, NULL}; | ||||
| bAnimListElem *ale; | bAnimListElem *ale; | ||||
| int filter; | int filter; | ||||
| KeyframeEditFunc set_cb = ANIM_editkeyframes_ipo(mode); | KeyframeEditFunc set_cb = ANIM_editkeyframes_ipo(mode); | ||||
| /* filter data */ | /* Filter data. */ | ||||
| filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | ||||
| ANIMFILTER_NODUPLIS); | ANIMFILTER_NODUPLIS); | ||||
| ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ||||
| /* Loop through setting BezTriple interpolation | /* Loop through setting BezTriple interpolation | ||||
| * Note: we do not supply KeyframeEditData to the looper yet. | * Note: we do not supply KeyframeEditData to the looper yet. | ||||
| * Currently that's not necessary here. | * Currently that's not necessary here. | ||||
| */ | */ | ||||
| Show All 9 Lines | |||||
| /* ------------------- */ | /* ------------------- */ | ||||
| static int graphkeys_ipo_exec(bContext *C, wmOperator *op) | static int graphkeys_ipo_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| short mode; | short mode; | ||||
| /* get editor data */ | /* Get editor data. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* get handle setting mode */ | /* Get handle setting mode. */ | ||||
| mode = RNA_enum_get(op->ptr, "type"); | mode = RNA_enum_get(op->ptr, "type"); | ||||
| /* set handle type */ | /* Set handle type. */ | ||||
| setipo_graph_keys(&ac, mode); | setipo_graph_keys(&ac, mode); | ||||
| /* set notifier that keyframe properties have changed */ | /* Set notifier that keyframe properties have changed. */ | ||||
| WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL); | WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GRAPH_OT_interpolation_type(wmOperatorType *ot) | void GRAPH_OT_interpolation_type(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Set Keyframe Interpolation"; | ot->name = "Set Keyframe Interpolation"; | ||||
| ot->idname = "GRAPH_OT_interpolation_type"; | ot->idname = "GRAPH_OT_interpolation_type"; | ||||
| ot->description = | ot->description = | ||||
| "Set interpolation mode for the F-Curve segments starting from the selected keyframes"; | "Set interpolation mode for the F-Curve segments starting from the selected keyframes"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->invoke = WM_menu_invoke; | ot->invoke = WM_menu_invoke; | ||||
| ot->exec = graphkeys_ipo_exec; | ot->exec = graphkeys_ipo_exec; | ||||
| ot->poll = graphop_editable_keyframes_poll; | ot->poll = graphop_editable_keyframes_poll; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| /* id-props */ | /* Id-props */ | ||||
| ot->prop = RNA_def_enum( | ot->prop = RNA_def_enum( | ||||
| ot->srna, "type", rna_enum_beztriple_interpolation_mode_items, 0, "Type", ""); | ot->srna, "type", rna_enum_beztriple_interpolation_mode_items, 0, "Type", ""); | ||||
| } | } | ||||
| /* ******************** Set Easing Operator *********************** */ | /* ******************** Set Easing Operator *********************** */ | ||||
| static void seteasing_graph_keys(bAnimContext *ac, short mode) | static void seteasing_graph_keys(bAnimContext *ac, short mode) | ||||
| { | { | ||||
| ListBase anim_data = {NULL, NULL}; | ListBase anim_data = {NULL, NULL}; | ||||
| bAnimListElem *ale; | bAnimListElem *ale; | ||||
| int filter; | int filter; | ||||
| KeyframeEditFunc set_cb = ANIM_editkeyframes_easing(mode); | KeyframeEditFunc set_cb = ANIM_editkeyframes_easing(mode); | ||||
| /* filter data */ | /* Filter data. */ | ||||
| filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | ||||
| ANIMFILTER_NODUPLIS); | ANIMFILTER_NODUPLIS); | ||||
| ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ||||
| /* Loop through setting BezTriple easing. | /* Loop through setting BezTriple easing. | ||||
| * Note: we do not supply KeyframeEditData to the looper yet. | * Note: we do not supply KeyframeEditData to the looper yet. | ||||
| * Currently that's not necessary here. | * Currently that's not necessary here. | ||||
| */ | */ | ||||
| for (ale = anim_data.first; ale; ale = ale->next) { | for (ale = anim_data.first; ale; ale = ale->next) { | ||||
| ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve); | ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve); | ||||
| ale->update |= ANIM_UPDATE_DEFAULT_NOHANDLES; | ale->update |= ANIM_UPDATE_DEFAULT_NOHANDLES; | ||||
| } | } | ||||
| ANIM_animdata_update(ac, &anim_data); | ANIM_animdata_update(ac, &anim_data); | ||||
| ANIM_animdata_freelist(&anim_data); | ANIM_animdata_freelist(&anim_data); | ||||
| } | } | ||||
| static int graphkeys_easing_exec(bContext *C, wmOperator *op) | static int graphkeys_easing_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| short mode; | short mode; | ||||
| /* get editor data */ | /* Get editor data. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* get handle setting mode */ | /* Get handle setting mode. */ | ||||
| mode = RNA_enum_get(op->ptr, "type"); | mode = RNA_enum_get(op->ptr, "type"); | ||||
| /* set handle type */ | /* Set handle type. */ | ||||
| seteasing_graph_keys(&ac, mode); | seteasing_graph_keys(&ac, mode); | ||||
| /* set notifier that keyframe properties have changed */ | /* Set notifier that keyframe properties have changed. */ | ||||
| WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL); | WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GRAPH_OT_easing_type(wmOperatorType *ot) | void GRAPH_OT_easing_type(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Set Keyframe Easing Type"; | ot->name = "Set Keyframe Easing Type"; | ||||
| ot->idname = "GRAPH_OT_easing_type"; | ot->idname = "GRAPH_OT_easing_type"; | ||||
| ot->description = | ot->description = | ||||
| "Set easing type for the F-Curve segments starting from the selected keyframes"; | "Set easing type for the F-Curve segments starting from the selected keyframes"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->invoke = WM_menu_invoke; | ot->invoke = WM_menu_invoke; | ||||
| ot->exec = graphkeys_easing_exec; | ot->exec = graphkeys_easing_exec; | ||||
| ot->poll = graphop_editable_keyframes_poll; | ot->poll = graphop_editable_keyframes_poll; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| /* id-props */ | /* Id-props */ | ||||
| ot->prop = RNA_def_enum( | ot->prop = RNA_def_enum( | ||||
| ot->srna, "type", rna_enum_beztriple_interpolation_easing_items, 0, "Type", ""); | ot->srna, "type", rna_enum_beztriple_interpolation_easing_items, 0, "Type", ""); | ||||
| } | } | ||||
| /* ******************** Set Handle-Type Operator *********************** */ | /* ******************** Set Handle-Type Operator *********************** */ | ||||
| /* this function is responsible for setting handle-type of selected keyframes */ | /* This function is responsible for setting handle-type of selected keyframes. */ | ||||
| static void sethandles_graph_keys(bAnimContext *ac, short mode) | static void sethandles_graph_keys(bAnimContext *ac, short mode) | ||||
| { | { | ||||
| ListBase anim_data = {NULL, NULL}; | ListBase anim_data = {NULL, NULL}; | ||||
| bAnimListElem *ale; | bAnimListElem *ale; | ||||
| int filter; | int filter; | ||||
| KeyframeEditFunc edit_cb = ANIM_editkeyframes_handles(mode); | KeyframeEditFunc edit_cb = ANIM_editkeyframes_handles(mode); | ||||
| KeyframeEditFunc sel_cb = ANIM_editkeyframes_ok(BEZT_OK_SELECTED); | KeyframeEditFunc sel_cb = ANIM_editkeyframes_ok(BEZT_OK_SELECTED); | ||||
| /* filter data */ | /* Filter data. */ | ||||
| filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | ||||
| ANIMFILTER_NODUPLIS); | ANIMFILTER_NODUPLIS); | ||||
| ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ||||
| /* Loop through setting flags for handles. | /* Loop through setting flags for handles. | ||||
| * Note: we do not supply KeyframeEditData to the looper yet. | * Note: we do not supply KeyframeEditData to the looper yet. | ||||
| * Currently that's not necessary here. | * Currently that's not necessary here. | ||||
| */ | */ | ||||
| for (ale = anim_data.first; ale; ale = ale->next) { | for (ale = anim_data.first; ale; ale = ale->next) { | ||||
| FCurve *fcu = (FCurve *)ale->key_data; | FCurve *fcu = (FCurve *)ale->key_data; | ||||
| /* any selected keyframes for editing? */ | /* Any selected keyframes for editing? */ | ||||
| if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, sel_cb, NULL)) { | if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, sel_cb, NULL)) { | ||||
| /* change type of selected handles */ | /* Change type of selected handles. */ | ||||
| ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, edit_cb, calchandles_fcurve); | ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, edit_cb, calchandles_fcurve); | ||||
| ale->update |= ANIM_UPDATE_DEFAULT; | ale->update |= ANIM_UPDATE_DEFAULT; | ||||
| } | } | ||||
| } | } | ||||
| ANIM_animdata_update(ac, &anim_data); | ANIM_animdata_update(ac, &anim_data); | ||||
| ANIM_animdata_freelist(&anim_data); | ANIM_animdata_freelist(&anim_data); | ||||
| } | } | ||||
| /* ------------------- */ | /* ------------------- */ | ||||
| static int graphkeys_handletype_exec(bContext *C, wmOperator *op) | static int graphkeys_handletype_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| short mode; | short mode; | ||||
| /* get editor data */ | /* Get editor data. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* get handle setting mode */ | /* Get handle setting mode. */ | ||||
| mode = RNA_enum_get(op->ptr, "type"); | mode = RNA_enum_get(op->ptr, "type"); | ||||
| /* set handle type */ | /* Set handle type. */ | ||||
| sethandles_graph_keys(&ac, mode); | sethandles_graph_keys(&ac, mode); | ||||
| /* set notifier that keyframe properties have changed */ | /* Set notifier that keyframe properties have changed. */ | ||||
| WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL); | WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GRAPH_OT_handle_type(wmOperatorType *ot) | void GRAPH_OT_handle_type(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Set Keyframe Handle Type"; | ot->name = "Set Keyframe Handle Type"; | ||||
| ot->idname = "GRAPH_OT_handle_type"; | ot->idname = "GRAPH_OT_handle_type"; | ||||
| ot->description = "Set type of handle for selected keyframes"; | ot->description = "Set type of handle for selected keyframes"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->invoke = WM_menu_invoke; | ot->invoke = WM_menu_invoke; | ||||
| ot->exec = graphkeys_handletype_exec; | ot->exec = graphkeys_handletype_exec; | ||||
| ot->poll = graphop_editable_keyframes_poll; | ot->poll = graphop_editable_keyframes_poll; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| /* id-props */ | /* Id-props */ | ||||
| ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_keyframe_handle_type_items, 0, "Type", ""); | ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_keyframe_handle_type_items, 0, "Type", ""); | ||||
| } | } | ||||
| /* ************************************************************************** */ | /* ************************************************************************** */ | ||||
| /* TRANSFORM STUFF */ | /* TRANSFORM STUFF */ | ||||
| /* ***************** 'Euler Filter' Operator **************************** */ | /* ***************** 'Euler Filter' Operator **************************** */ | ||||
| /* Euler filter tools (as seen in Maya), are necessary for working with 'baked' | /* Euler filter tools (as seen in Maya), are necessary for working with 'baked' | ||||
| * rotation curves (with Euler rotations). The main purpose of such tools is to | * rotation curves (with Euler rotations). The main purpose of such tools is to | ||||
| * resolve any discontinuities that may arise in the curves due to the clamping | * resolve any discontinuities that may arise in the curves due to the clamping | ||||
| * of values to -180 degrees to 180 degrees. | * of values to -180 degrees to 180 degrees. | ||||
| */ | */ | ||||
| /* set of three euler-rotation F-Curves */ | /* Set of three euler-rotation F-Curves. */ | ||||
| typedef struct tEulerFilter { | typedef struct tEulerFilter { | ||||
| struct tEulerFilter *next, *prev; | struct tEulerFilter *next, *prev; | ||||
| /** ID-block which owns the channels */ | /** ID-block which owns the channels */ | ||||
| ID *id; | ID *id; | ||||
| /** 3 Pointers to F-Curves */ | /** 3 Pointers to F-Curves. */ | ||||
| FCurve *(fcurves[3]); | FCurve *(fcurves[3]); | ||||
| /** Pointer to one of the RNA Path's used by one of the F-Curves */ | /** Pointer to one of the RNA Path's used by one of the F-Curves. */ | ||||
| const char *rna_path; | const char *rna_path; | ||||
| } tEulerFilter; | } tEulerFilter; | ||||
| static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op) | static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| ListBase anim_data = {NULL, NULL}; | ListBase anim_data = {NULL, NULL}; | ||||
| bAnimListElem *ale; | bAnimListElem *ale; | ||||
| int filter; | int filter; | ||||
| ListBase eulers = {NULL, NULL}; | ListBase eulers = {NULL, NULL}; | ||||
| tEulerFilter *euf = NULL; | tEulerFilter *euf = NULL; | ||||
| int groups = 0, failed = 0; | int groups = 0, failed = 0; | ||||
| /* get editor data */ | /* Get editor data. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* The process is done in two passes: | /* The process is done in two passes: | ||||
| * 1) Sets of three related rotation curves are identified from the selected channels, | * 1) Sets of three related rotation curves are identified from the selected channels, | ||||
| * and are stored as a single 'operation unit' for the next step | * and are stored as a single 'operation unit' for the next step. | ||||
| * 2) Each set of three F-Curves is processed for each keyframe, with the values being | * 2) Each set of three F-Curves is processed for each keyframe, with the values being | ||||
| * processed as necessary | * processed as necessary. | ||||
| */ | */ | ||||
| /* step 1: extract only the rotation f-curves */ | /* Step 1: extract only the rotation f-curves. */ | ||||
| filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_CURVE_VISIBLE | | filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_CURVE_VISIBLE | | ||||
| ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); | ||||
| ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); | ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); | ||||
| for (ale = anim_data.first; ale; ale = ale->next) { | for (ale = anim_data.first; ale; ale = ale->next) { | ||||
| FCurve *fcu = (FCurve *)ale->data; | FCurve *fcu = (FCurve *)ale->data; | ||||
| /* check if this is an appropriate F-Curve | /* Check if this is an appropriate F-Curve | ||||
| * - only rotation curves | * - Only rotation curves. | ||||
| * - for pchan curves, make sure we're only using the euler curves | * - For pchan curves, make sure we're only using the euler curves. | ||||
| */ | */ | ||||
| if (strstr(fcu->rna_path, "rotation_euler") == NULL) { | if (strstr(fcu->rna_path, "rotation_euler") == NULL) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (ELEM(fcu->array_index, 0, 1, 2) == 0) { | if (ELEM(fcu->array_index, 0, 1, 2) == 0) { | ||||
| BKE_reportf(op->reports, | BKE_reportf(op->reports, | ||||
| RPT_WARNING, | RPT_WARNING, | ||||
| "Euler Rotation F-Curve has invalid index (ID='%s', Path='%s', Index=%d)", | "Euler Rotation F-Curve has invalid index (ID='%s', Path='%s', Index=%d)", | ||||
| (ale->id) ? ale->id->name : TIP_("<No ID>"), | (ale->id) ? ale->id->name : TIP_("<No ID>"), | ||||
| fcu->rna_path, | fcu->rna_path, | ||||
| fcu->array_index); | fcu->array_index); | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* optimization: assume that xyz curves will always be stored consecutively, | /* Optimization: assume that xyz curves will always be stored consecutively, | ||||
| * so if the paths or the ID's don't match up, then a curve needs to be added | * so if the paths or the ID's don't match up, then a curve needs to be added | ||||
| * to a new group | * to a new group. | ||||
| */ | */ | ||||
| if ((euf) && (euf->id == ale->id) && (STREQ(euf->rna_path, fcu->rna_path))) { | if ((euf) && (euf->id == ale->id) && (STREQ(euf->rna_path, fcu->rna_path))) { | ||||
| /* this should be fine to add to the existing group then */ | /* This should be fine to add to the existing group then. */ | ||||
| euf->fcurves[fcu->array_index] = fcu; | euf->fcurves[fcu->array_index] = fcu; | ||||
| } | } | ||||
| else { | else { | ||||
| /* just add to a new block */ | /* Just add to a new block. */ | ||||
| euf = MEM_callocN(sizeof(tEulerFilter), "tEulerFilter"); | euf = MEM_callocN(sizeof(tEulerFilter), "tEulerFilter"); | ||||
| BLI_addtail(&eulers, euf); | BLI_addtail(&eulers, euf); | ||||
| groups++; | groups++; | ||||
| euf->id = ale->id; | euf->id = ale->id; | ||||
| /* this should be safe, since we're only using it for a short time */ | /* This should be safe, since we're only using it for a short time. */ | ||||
| euf->rna_path = fcu->rna_path; | euf->rna_path = fcu->rna_path; | ||||
| euf->fcurves[fcu->array_index] = fcu; | euf->fcurves[fcu->array_index] = fcu; | ||||
| } | } | ||||
| ale->update |= ANIM_UPDATE_DEFAULT; | ale->update |= ANIM_UPDATE_DEFAULT; | ||||
| } | } | ||||
| if (groups == 0) { | if (groups == 0) { | ||||
| ANIM_animdata_freelist(&anim_data); | ANIM_animdata_freelist(&anim_data); | ||||
| BKE_report(op->reports, RPT_WARNING, "No Euler Rotation F-Curves to fix up"); | BKE_report(op->reports, RPT_WARNING, "No Euler Rotation F-Curves to fix up"); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* step 2: go through each set of curves, processing the values at each keyframe | /* Step 2: go through each set of curves, processing the values at each keyframe. | ||||
| * - it is assumed that there must be a full set of keyframes at each keyframe position | * - It is assumed that there must be a full set of keyframes at each keyframe position. | ||||
| */ | */ | ||||
| for (euf = eulers.first; euf; euf = euf->next) { | for (euf = eulers.first; euf; euf = euf->next) { | ||||
| int f; | int f; | ||||
| /* sanity check: ensure that there are enough F-Curves to work on in this group */ | /* Sanity check: ensure that there are enough F-Curves to work on in this group. */ | ||||
| /* TODO: also enforce assumption that there be a full set of keyframes | /* TODO: also enforce assumption that there be a full set of keyframes | ||||
| * at each position by ensuring that totvert counts are same? */ | * at each position by ensuring that totvert counts are same? (Joshua Leung 2011) */ | ||||
| if (ELEM(NULL, euf->fcurves[0], euf->fcurves[1], euf->fcurves[2])) { | if (ELEM(NULL, euf->fcurves[0], euf->fcurves[1], euf->fcurves[2])) { | ||||
| /* report which components are missing */ | /* Report which components are missing. */ | ||||
| BKE_reportf(op->reports, | BKE_reportf(op->reports, | ||||
| RPT_WARNING, | RPT_WARNING, | ||||
| "Missing %s%s%s component(s) of euler rotation for ID='%s' and RNA-Path='%s'", | "Missing %s%s%s component(s) of euler rotation for ID='%s' and RNA-Path='%s'", | ||||
| (euf->fcurves[0] == NULL) ? "X" : "", | (euf->fcurves[0] == NULL) ? "X" : "", | ||||
| (euf->fcurves[1] == NULL) ? "Y" : "", | (euf->fcurves[1] == NULL) ? "Y" : "", | ||||
| (euf->fcurves[2] == NULL) ? "Z" : "", | (euf->fcurves[2] == NULL) ? "Z" : "", | ||||
| euf->id->name, | euf->id->name, | ||||
| euf->rna_path); | euf->rna_path); | ||||
| /* keep track of number of failed sets, and carry on to next group */ | /* Keep track of number of failed sets, and carry on to next group. */ | ||||
| failed++; | failed++; | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* Simple method: just treat any difference between | /* Simple method: just treat any difference between | ||||
| * keys of greater than 180 degrees as being a flip. */ | * keys of greater than 180 degrees as being a flip. */ | ||||
| /* FIXME: there are more complicated methods that | /* FIXME: there are more complicated methods that | ||||
| * will be needed to fix more cases than just some */ | * will be needed to fix more cases than just some */ | ||||
| for (f = 0; f < 3; f++) { | for (f = 0; f < 3; f++) { | ||||
| FCurve *fcu = euf->fcurves[f]; | FCurve *fcu = euf->fcurves[f]; | ||||
| BezTriple *bezt, *prev; | BezTriple *bezt, *prev; | ||||
| uint i; | uint i; | ||||
| /* skip if not enough vets to do a decent analysis of... */ | /* Skip if not enough vets to do a decent analysis of.... */ | ||||
| if (fcu->totvert <= 2) { | if (fcu->totvert <= 2) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* prev follows bezt, bezt = "current" point to be fixed */ | /* Prev follows bezt, bezt = "current" point to be fixed. */ | ||||
| /* our method depends on determining a "difference" from the previous vert */ | /* Our method depends on determining a "difference" from the previous vert. */ | ||||
| for (i = 1, prev = fcu->bezt, bezt = fcu->bezt + 1; i < fcu->totvert; i++, prev = bezt++) { | for (i = 1, prev = fcu->bezt, bezt = fcu->bezt + 1; i < fcu->totvert; i++, prev = bezt++) { | ||||
| const float sign = (prev->vec[1][1] > bezt->vec[1][1]) ? 1.0f : -1.0f; | const float sign = (prev->vec[1][1] > bezt->vec[1][1]) ? 1.0f : -1.0f; | ||||
| /* > 180 degree flip? */ | /* > 180 degree flip? */ | ||||
| if ((sign * (prev->vec[1][1] - bezt->vec[1][1])) >= (float)M_PI) { | if ((sign * (prev->vec[1][1] - bezt->vec[1][1])) >= (float)M_PI) { | ||||
| /* 360 degrees to add/subtract frame value until difference | /* 360 degrees to add/subtract frame value until difference | ||||
| * is acceptably small that there's no more flip */ | * is acceptably small that there's no more flip. */ | ||||
| const float fac = sign * 2.0f * (float)M_PI; | const float fac = sign * 2.0f * (float)M_PI; | ||||
| while ((sign * (prev->vec[1][1] - bezt->vec[1][1])) >= (float)M_PI) { | while ((sign * (prev->vec[1][1] - bezt->vec[1][1])) >= (float)M_PI) { | ||||
| bezt->vec[0][1] += fac; | bezt->vec[0][1] += fac; | ||||
| bezt->vec[1][1] += fac; | bezt->vec[1][1] += fac; | ||||
| bezt->vec[2][1] += fac; | bezt->vec[2][1] += fac; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| BLI_freelistN(&eulers); | BLI_freelistN(&eulers); | ||||
| ANIM_animdata_update(&ac, &anim_data); | ANIM_animdata_update(&ac, &anim_data); | ||||
| ANIM_animdata_freelist(&anim_data); | ANIM_animdata_freelist(&anim_data); | ||||
| /* updates + finishing warnings */ | /* Updates + finishing warnings. */ | ||||
| if (failed == groups) { | if (failed == groups) { | ||||
| BKE_report( | BKE_report( | ||||
| op->reports, | op->reports, | ||||
| RPT_ERROR, | RPT_ERROR, | ||||
| "No Euler Rotations could be corrected, ensure each rotation has keys for all components, " | "No Euler Rotations could be corrected, ensure each rotation has keys for all components, " | ||||
| "and that F-Curves for these are in consecutive XYZ order and selected"); | "and that F-Curves for these are in consecutive XYZ order and selected"); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| if (failed) { | if (failed) { | ||||
| BKE_report( | BKE_report( | ||||
| op->reports, | op->reports, | ||||
| RPT_ERROR, | RPT_ERROR, | ||||
| "Some Euler Rotations could not be corrected due to missing/unselected/out-of-order " | "Some Euler Rotations could not be corrected due to missing/unselected/out-of-order " | ||||
| "F-Curves, " | "F-Curves, " | ||||
| "ensure each rotation has keys for all components, and that F-Curves for these are in " | "ensure each rotation has keys for all components, and that F-Curves for these are in " | ||||
| "consecutive XYZ order and selected"); | "consecutive XYZ order and selected"); | ||||
| } | } | ||||
| /* set notifier that keyframes have changed */ | /* Set notifier that keyframes have changed. */ | ||||
| WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | ||||
| /* done at last */ | /* Done at last. */ | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GRAPH_OT_euler_filter(wmOperatorType *ot) | void GRAPH_OT_euler_filter(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Euler Discontinuity Filter"; | ot->name = "Euler Discontinuity Filter"; | ||||
| ot->idname = "GRAPH_OT_euler_filter"; | ot->idname = "GRAPH_OT_euler_filter"; | ||||
| ot->description = | ot->description = | ||||
| "Fix large jumps and flips in the selected " | "Fix large jumps and flips in the selected " | ||||
| "Euler Rotation F-Curves arising from rotation " | "Euler Rotation F-Curves arising from rotation " | ||||
| "values being clipped when baking physics"; | "values being clipped when baking physics"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->exec = graphkeys_euler_filter_exec; | ot->exec = graphkeys_euler_filter_exec; | ||||
| ot->poll = graphop_editable_keyframes_poll; | ot->poll = graphop_editable_keyframes_poll; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| } | } | ||||
| /* ***************** Jump to Selected Frames Operator *********************** */ | /* ***************** Jump to Selected Frames Operator *********************** */ | ||||
| static bool graphkeys_framejump_poll(bContext *C) | static bool graphkeys_framejump_poll(bContext *C) | ||||
| { | { | ||||
| /* prevent changes during render */ | /* Prevent changes during render. */ | ||||
| if (G.is_rendering) { | if (G.is_rendering) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| return graphop_visible_keyframes_poll(C); | return graphop_visible_keyframes_poll(C); | ||||
| } | } | ||||
| static KeyframeEditData sum_selected_keyframes(bAnimContext *ac) | static KeyframeEditData sum_selected_keyframes(bAnimContext *ac) | ||||
| { | { | ||||
| ListBase anim_data = {NULL, NULL}; | ListBase anim_data = {NULL, NULL}; | ||||
| bAnimListElem *ale; | bAnimListElem *ale; | ||||
| int filter; | int filter; | ||||
| KeyframeEditData ked; | KeyframeEditData ked; | ||||
| /* init edit data */ | /* Init edit data. */ | ||||
| memset(&ked, 0, sizeof(KeyframeEditData)); | memset(&ked, 0, sizeof(KeyframeEditData)); | ||||
| /* loop over action data, averaging values */ | /* Loop over action data, averaging values. */ | ||||
| filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS); | filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS); | ||||
| ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ||||
| for (ale = anim_data.first; ale; ale = ale->next) { | for (ale = anim_data.first; ale; ale = ale->next) { | ||||
| AnimData *adt = ANIM_nla_mapping_get(ac, ale); | AnimData *adt = ANIM_nla_mapping_get(ac, ale); | ||||
| short mapping_flag = ANIM_get_normalization_flags(ac); | short mapping_flag = ANIM_get_normalization_flags(ac); | ||||
| KeyframeEditData current_ked; | KeyframeEditData current_ked; | ||||
| float offset; | float offset; | ||||
| Show All 17 Lines | for (ale = anim_data.first; ale; ale = ale->next) { | ||||
| ked.i2 += current_ked.i2; | ked.i2 += current_ked.i2; | ||||
| } | } | ||||
| ANIM_animdata_freelist(&anim_data); | ANIM_animdata_freelist(&anim_data); | ||||
| return ked; | return ked; | ||||
| } | } | ||||
| /* snap current-frame indicator to 'average time' of selected keyframe */ | /* Snap current-frame indicator to 'average time' of selected keyframe. */ | ||||
| static int graphkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op)) | static int graphkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op)) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| /* get editor data */ | /* Get editor data. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| const KeyframeEditData keyframe_sum = sum_selected_keyframes(&ac); | const KeyframeEditData keyframe_sum = sum_selected_keyframes(&ac); | ||||
| const float sum_time = keyframe_sum.f1; | const float sum_time = keyframe_sum.f1; | ||||
| const float sum_value = keyframe_sum.f2; | const float sum_value = keyframe_sum.f2; | ||||
| const int num_keyframes = keyframe_sum.i1; | const int num_keyframes = keyframe_sum.i1; | ||||
| if (num_keyframes == 0) { | if (num_keyframes == 0) { | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| /* set the new current frame and cursor values, based on the average time and value */ | /* Set the new current frame and cursor values, based on the average time and value. */ | ||||
| SpaceGraph *sipo = (SpaceGraph *)ac.sl; | SpaceGraph *sipo = (SpaceGraph *)ac.sl; | ||||
| Scene *scene = ac.scene; | Scene *scene = ac.scene; | ||||
| /* take the average values, rounding to the nearest int as necessary for int results */ | /* Take the average values, rounding to the nearest int as necessary for int results. */ | ||||
| if (sipo->mode == SIPO_MODE_DRIVERS) { | if (sipo->mode == SIPO_MODE_DRIVERS) { | ||||
| /* Drivers Mode - Affects cursor (float) */ | /* Drivers Mode - Affects cursor (float) */ | ||||
| sipo->cursorTime = sum_time / (float)num_keyframes; | sipo->cursorTime = sum_time / (float)num_keyframes; | ||||
| } | } | ||||
| else { | else { | ||||
| /* Animation Mode - Affects current frame (int) */ | /* Animation Mode - Affects current frame (int) */ | ||||
| CFRA = round_fl_to_int(sum_time / num_keyframes); | CFRA = round_fl_to_int(sum_time / num_keyframes); | ||||
| SUBFRA = 0.f; | SUBFRA = 0.f; | ||||
| } | } | ||||
| sipo->cursorVal = sum_value / (float)num_keyframes; | sipo->cursorVal = sum_value / (float)num_keyframes; | ||||
| /* set notifier that things have changed */ | /* Set notifier that things have changed. */ | ||||
| WM_event_add_notifier(C, NC_SCENE | ND_FRAME, ac.scene); | WM_event_add_notifier(C, NC_SCENE | ND_FRAME, ac.scene); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GRAPH_OT_frame_jump(wmOperatorType *ot) | void GRAPH_OT_frame_jump(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Jump to Keyframes"; | ot->name = "Jump to Keyframes"; | ||||
| ot->idname = "GRAPH_OT_frame_jump"; | ot->idname = "GRAPH_OT_frame_jump"; | ||||
| ot->description = "Place the cursor on the midpoint of selected keyframes"; | ot->description = "Place the cursor on the midpoint of selected keyframes"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->exec = graphkeys_framejump_exec; | ot->exec = graphkeys_framejump_exec; | ||||
| ot->poll = graphkeys_framejump_poll; | ot->poll = graphkeys_framejump_poll; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| } | } | ||||
| /* snap 2D cursor value to the average value of selected keyframe */ | /* snap 2D cursor value to the average value of selected keyframe */ | ||||
| static int graphkeys_snap_cursor_value_exec(bContext *C, wmOperator *UNUSED(op)) | static int graphkeys_snap_cursor_value_exec(bContext *C, wmOperator *UNUSED(op)) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| Show All 29 Lines | void GRAPH_OT_snap_cursor_value(wmOperatorType *ot) | ||||
| ot->poll = graphkeys_framejump_poll; | ot->poll = graphkeys_framejump_poll; | ||||
| /* Flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| } | } | ||||
| /* ******************** Snap Keyframes Operator *********************** */ | /* ******************** Snap Keyframes Operator *********************** */ | ||||
| /* defines for snap keyframes tool */ | /* Defines for snap keyframes tool. */ | ||||
| static const EnumPropertyItem prop_graphkeys_snap_types[] = { | static const EnumPropertyItem prop_graphkeys_snap_types[] = { | ||||
| {GRAPHKEYS_SNAP_CFRA, | {GRAPHKEYS_SNAP_CFRA, | ||||
| "CFRA", | "CFRA", | ||||
| 0, | 0, | ||||
| "Current Frame", | "Current Frame", | ||||
| "Snap selected keyframes to the current frame"}, | "Snap selected keyframes to the current frame"}, | ||||
| {GRAPHKEYS_SNAP_VALUE, | {GRAPHKEYS_SNAP_VALUE, | ||||
| "VALUE", | "VALUE", | ||||
| Show All 19 Lines | static const EnumPropertyItem prop_graphkeys_snap_types[] = { | ||||
| {GRAPHKEYS_SNAP_HORIZONTAL, | {GRAPHKEYS_SNAP_HORIZONTAL, | ||||
| "HORIZONTAL", | "HORIZONTAL", | ||||
| 0, | 0, | ||||
| "Flatten Handles", | "Flatten Handles", | ||||
| "Flatten handles for a smoother transition"}, | "Flatten handles for a smoother transition"}, | ||||
| {0, NULL, 0, NULL, NULL}, | {0, NULL, 0, NULL, NULL}, | ||||
| }; | }; | ||||
| /* this function is responsible for snapping keyframes to frame-times */ | /* This function is responsible for snapping keyframes to frame-times. */ | ||||
| static void snap_graph_keys(bAnimContext *ac, short mode) | static void snap_graph_keys(bAnimContext *ac, short mode) | ||||
| { | { | ||||
| ListBase anim_data = {NULL, NULL}; | ListBase anim_data = {NULL, NULL}; | ||||
| bAnimListElem *ale; | bAnimListElem *ale; | ||||
| int filter; | int filter; | ||||
| SpaceGraph *sipo = (SpaceGraph *)ac->sl; | SpaceGraph *sipo = (SpaceGraph *)ac->sl; | ||||
| KeyframeEditData ked; | KeyframeEditData ked; | ||||
| KeyframeEditFunc edit_cb; | KeyframeEditFunc edit_cb; | ||||
| float cursor_value = 0.0f; | float cursor_value = 0.0f; | ||||
| /* filter data */ | /* Filter data. */ | ||||
| filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | ||||
| ANIMFILTER_NODUPLIS); | ANIMFILTER_NODUPLIS); | ||||
| ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ||||
| /* init custom data for iterating over keyframes */ | /* Init custom data for iterating over keyframes. */ | ||||
| memset(&ked, 0, sizeof(KeyframeEditData)); | memset(&ked, 0, sizeof(KeyframeEditData)); | ||||
| ked.scene = ac->scene; | ked.scene = ac->scene; | ||||
| if (mode == GRAPHKEYS_SNAP_NEAREST_MARKER) { | if (mode == GRAPHKEYS_SNAP_NEAREST_MARKER) { | ||||
| ked.list.first = (ac->markers) ? ac->markers->first : NULL; | ked.list.first = (ac->markers) ? ac->markers->first : NULL; | ||||
| ked.list.last = (ac->markers) ? ac->markers->last : NULL; | ked.list.last = (ac->markers) ? ac->markers->last : NULL; | ||||
| } | } | ||||
| else if (mode == GRAPHKEYS_SNAP_VALUE) { | else if (mode == GRAPHKEYS_SNAP_VALUE) { | ||||
| cursor_value = (sipo) ? sipo->cursorVal : 0.0f; | cursor_value = (sipo) ? sipo->cursorVal : 0.0f; | ||||
| } | } | ||||
| else if (mode == GRAPHKEYS_SNAP_CFRA) { | else if (mode == GRAPHKEYS_SNAP_CFRA) { | ||||
| /* In drivers mode, use the cursor value instead | /* In drivers mode, use the cursor value instead | ||||
| * (We need to use a different callback for that though) | * (We need to use a different callback for that though) | ||||
| */ | */ | ||||
| if (sipo->mode == SIPO_MODE_DRIVERS) { | if (sipo->mode == SIPO_MODE_DRIVERS) { | ||||
| ked.f1 = sipo->cursorTime; | ked.f1 = sipo->cursorTime; | ||||
| mode = SNAP_KEYS_TIME; | mode = SNAP_KEYS_TIME; | ||||
| } | } | ||||
| } | } | ||||
| /* get beztriple editing callbacks */ | /* Get beztriple editing callbacks. */ | ||||
| edit_cb = ANIM_editkeyframes_snap(mode); | edit_cb = ANIM_editkeyframes_snap(mode); | ||||
| /* snap keyframes */ | /* Snap keyframes. */ | ||||
| for (ale = anim_data.first; ale; ale = ale->next) { | for (ale = anim_data.first; ale; ale = ale->next) { | ||||
| AnimData *adt = ANIM_nla_mapping_get(ac, ale); | AnimData *adt = ANIM_nla_mapping_get(ac, ale); | ||||
| /* normalise cursor value (for normalised F-Curves display) */ | /* Normalise cursor value (for normalised F-Curves display). */ | ||||
| if (mode == GRAPHKEYS_SNAP_VALUE) { | if (mode == GRAPHKEYS_SNAP_VALUE) { | ||||
| short mapping_flag = ANIM_get_normalization_flags(ac); | short mapping_flag = ANIM_get_normalization_flags(ac); | ||||
| float offset; | float offset; | ||||
| float unit_scale = ANIM_unit_mapping_get_factor( | float unit_scale = ANIM_unit_mapping_get_factor( | ||||
| ac->scene, ale->id, ale->key_data, mapping_flag, &offset); | ac->scene, ale->id, ale->key_data, mapping_flag, &offset); | ||||
| ked.f1 = (cursor_value / unit_scale) - offset; | ked.f1 = (cursor_value / unit_scale) - offset; | ||||
| } | } | ||||
| /* perform snapping */ | /* Perform snapping. */ | ||||
| if (adt) { | if (adt) { | ||||
| ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0); | ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0); | ||||
| ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve); | ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve); | ||||
| ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0); | ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0); | ||||
| } | } | ||||
| else { | else { | ||||
| ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve); | ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve); | ||||
| } | } | ||||
| ale->update |= ANIM_UPDATE_DEFAULT; | ale->update |= ANIM_UPDATE_DEFAULT; | ||||
| } | } | ||||
| ANIM_animdata_update(ac, &anim_data); | ANIM_animdata_update(ac, &anim_data); | ||||
| ANIM_animdata_freelist(&anim_data); | ANIM_animdata_freelist(&anim_data); | ||||
| } | } | ||||
| /* ------------------- */ | /* ------------------- */ | ||||
| static int graphkeys_snap_exec(bContext *C, wmOperator *op) | static int graphkeys_snap_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| short mode; | short mode; | ||||
| /* get editor data */ | /* Get editor data. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* get snapping mode */ | /* Get snapping mode. */ | ||||
| mode = RNA_enum_get(op->ptr, "type"); | mode = RNA_enum_get(op->ptr, "type"); | ||||
| /* snap keyframes */ | /* Snap keyframes. */ | ||||
| snap_graph_keys(&ac, mode); | snap_graph_keys(&ac, mode); | ||||
| /* set notifier that keyframes have changed */ | /* Set notifier that keyframes have changed. */ | ||||
| WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GRAPH_OT_snap(wmOperatorType *ot) | void GRAPH_OT_snap(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Snap Keys"; | ot->name = "Snap Keys"; | ||||
| ot->idname = "GRAPH_OT_snap"; | ot->idname = "GRAPH_OT_snap"; | ||||
| ot->description = "Snap selected keyframes to the chosen times/values"; | ot->description = "Snap selected keyframes to the chosen times/values"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->invoke = WM_menu_invoke; | ot->invoke = WM_menu_invoke; | ||||
| ot->exec = graphkeys_snap_exec; | ot->exec = graphkeys_snap_exec; | ||||
| ot->poll = graphop_editable_keyframes_poll; | ot->poll = graphop_editable_keyframes_poll; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| /* id-props */ | /* Id-props */ | ||||
| ot->prop = RNA_def_enum(ot->srna, "type", prop_graphkeys_snap_types, 0, "Type", ""); | ot->prop = RNA_def_enum(ot->srna, "type", prop_graphkeys_snap_types, 0, "Type", ""); | ||||
| } | } | ||||
| /* ******************** Mirror Keyframes Operator *********************** */ | /* ******************** Mirror Keyframes Operator *********************** */ | ||||
| /* defines for mirror keyframes tool */ | /* Defines for mirror keyframes tool. */ | ||||
| static const EnumPropertyItem prop_graphkeys_mirror_types[] = { | static const EnumPropertyItem prop_graphkeys_mirror_types[] = { | ||||
| {GRAPHKEYS_MIRROR_CFRA, | {GRAPHKEYS_MIRROR_CFRA, | ||||
| "CFRA", | "CFRA", | ||||
| 0, | 0, | ||||
| "By Times Over Current Frame", | "By Times Over Current Frame", | ||||
| "Flip times of selected keyframes using the current frame as the mirror line"}, | "Flip times of selected keyframes using the current frame as the mirror line"}, | ||||
| {GRAPHKEYS_MIRROR_VALUE, | {GRAPHKEYS_MIRROR_VALUE, | ||||
| "VALUE", | "VALUE", | ||||
| Show All 14 Lines | static const EnumPropertyItem prop_graphkeys_mirror_types[] = { | ||||
| {GRAPHKEYS_MIRROR_MARKER, | {GRAPHKEYS_MIRROR_MARKER, | ||||
| "MARKER", | "MARKER", | ||||
| 0, | 0, | ||||
| "By Times Over First Selected Marker", | "By Times Over First Selected Marker", | ||||
| "Flip times of selected keyframes using the first selected marker as the reference point"}, | "Flip times of selected keyframes using the first selected marker as the reference point"}, | ||||
| {0, NULL, 0, NULL, NULL}, | {0, NULL, 0, NULL, NULL}, | ||||
| }; | }; | ||||
| /* this function is responsible for mirroring keyframes */ | /* This function is responsible for mirroring keyframes. */ | ||||
| static void mirror_graph_keys(bAnimContext *ac, short mode) | static void mirror_graph_keys(bAnimContext *ac, short mode) | ||||
| { | { | ||||
| ListBase anim_data = {NULL, NULL}; | ListBase anim_data = {NULL, NULL}; | ||||
| bAnimListElem *ale; | bAnimListElem *ale; | ||||
| int filter; | int filter; | ||||
| SpaceGraph *sipo = (SpaceGraph *)ac->sl; | SpaceGraph *sipo = (SpaceGraph *)ac->sl; | ||||
| KeyframeEditData ked; | KeyframeEditData ked; | ||||
| KeyframeEditFunc edit_cb; | KeyframeEditFunc edit_cb; | ||||
| float cursor_value = 0.0f; | float cursor_value = 0.0f; | ||||
| /* init custom data for looping over keyframes */ | /* Init custom data for looping over keyframes. */ | ||||
| memset(&ked, 0, sizeof(KeyframeEditData)); | memset(&ked, 0, sizeof(KeyframeEditData)); | ||||
| ked.scene = ac->scene; | ked.scene = ac->scene; | ||||
| /* store mode-specific custom data... */ | /* Store mode-specific custom data... */ | ||||
| if (mode == GRAPHKEYS_MIRROR_MARKER) { | if (mode == GRAPHKEYS_MIRROR_MARKER) { | ||||
| TimeMarker *marker = NULL; | TimeMarker *marker = NULL; | ||||
| /* find first selected marker */ | /* Find first selected marker. */ | ||||
| marker = ED_markers_get_first_selected(ac->markers); | marker = ED_markers_get_first_selected(ac->markers); | ||||
| /* store marker's time (if available) */ | /* Store marker's time (if available). */ | ||||
| if (marker) { | if (marker) { | ||||
| ked.f1 = (float)marker->frame; | ked.f1 = (float)marker->frame; | ||||
| } | } | ||||
| else { | else { | ||||
| return; | return; | ||||
| } | } | ||||
| } | } | ||||
| else if (mode == GRAPHKEYS_MIRROR_VALUE) { | else if (mode == GRAPHKEYS_MIRROR_VALUE) { | ||||
| cursor_value = (sipo) ? sipo->cursorVal : 0.0f; | cursor_value = (sipo) ? sipo->cursorVal : 0.0f; | ||||
| } | } | ||||
| else if (mode == GRAPHKEYS_MIRROR_CFRA) { | else if (mode == GRAPHKEYS_MIRROR_CFRA) { | ||||
| /* In drivers mode, use the cursor value instead | /* In drivers mode, use the cursor value instead | ||||
| * (We need to use a different callback for that though) | * (We need to use a different callback for that though) | ||||
| */ | */ | ||||
| if (sipo->mode == SIPO_MODE_DRIVERS) { | if (sipo->mode == SIPO_MODE_DRIVERS) { | ||||
| ked.f1 = sipo->cursorTime; | ked.f1 = sipo->cursorTime; | ||||
| mode = MIRROR_KEYS_TIME; | mode = MIRROR_KEYS_TIME; | ||||
| } | } | ||||
| } | } | ||||
| /* get beztriple editing callbacks */ | /* Get beztriple editing callbacks. */ | ||||
| edit_cb = ANIM_editkeyframes_mirror(mode); | edit_cb = ANIM_editkeyframes_mirror(mode); | ||||
| /* filter data */ | /* Filter data. */ | ||||
| filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | ||||
| ANIMFILTER_NODUPLIS); | ANIMFILTER_NODUPLIS); | ||||
| ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); | ||||
| /* mirror keyframes */ | /* Mirror keyframes. */ | ||||
| for (ale = anim_data.first; ale; ale = ale->next) { | for (ale = anim_data.first; ale; ale = ale->next) { | ||||
| AnimData *adt = ANIM_nla_mapping_get(ac, ale); | AnimData *adt = ANIM_nla_mapping_get(ac, ale); | ||||
| /* apply unit corrections */ | /* Apply unit corrections. */ | ||||
| if (mode == GRAPHKEYS_MIRROR_VALUE) { | if (mode == GRAPHKEYS_MIRROR_VALUE) { | ||||
| short mapping_flag = ANIM_get_normalization_flags(ac); | short mapping_flag = ANIM_get_normalization_flags(ac); | ||||
| float offset; | float offset; | ||||
| float unit_scale = ANIM_unit_mapping_get_factor( | float unit_scale = ANIM_unit_mapping_get_factor( | ||||
| ac->scene, ale->id, ale->key_data, mapping_flag | ANIM_UNITCONV_ONLYKEYS, &offset); | ac->scene, ale->id, ale->key_data, mapping_flag | ANIM_UNITCONV_ONLYKEYS, &offset); | ||||
| ked.f1 = (cursor_value + offset) * unit_scale; | ked.f1 = (cursor_value + offset) * unit_scale; | ||||
| } | } | ||||
| /* perform actual mirroring */ | /* Perform actual mirroring. */ | ||||
| if (adt) { | if (adt) { | ||||
| ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0); | ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0); | ||||
| ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve); | ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve); | ||||
| ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0); | ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0); | ||||
| } | } | ||||
| else { | else { | ||||
| ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve); | ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve); | ||||
| } | } | ||||
| ale->update |= ANIM_UPDATE_DEFAULT; | ale->update |= ANIM_UPDATE_DEFAULT; | ||||
| } | } | ||||
| ANIM_animdata_update(ac, &anim_data); | ANIM_animdata_update(ac, &anim_data); | ||||
| ANIM_animdata_freelist(&anim_data); | ANIM_animdata_freelist(&anim_data); | ||||
| } | } | ||||
| /* ------------------- */ | /* ------------------- */ | ||||
| static int graphkeys_mirror_exec(bContext *C, wmOperator *op) | static int graphkeys_mirror_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| short mode; | short mode; | ||||
| /* get editor data */ | /* Get editor data. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* get mirroring mode */ | /* Get mirroring mode. */ | ||||
| mode = RNA_enum_get(op->ptr, "type"); | mode = RNA_enum_get(op->ptr, "type"); | ||||
| /* mirror keyframes */ | /* Mirror keyframes. */ | ||||
| mirror_graph_keys(&ac, mode); | mirror_graph_keys(&ac, mode); | ||||
| /* set notifier that keyframes have changed */ | /* Set notifier that keyframes have changed. */ | ||||
| WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GRAPH_OT_mirror(wmOperatorType *ot) | void GRAPH_OT_mirror(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Mirror Keys"; | ot->name = "Mirror Keys"; | ||||
| ot->idname = "GRAPH_OT_mirror"; | ot->idname = "GRAPH_OT_mirror"; | ||||
| ot->description = "Flip selected keyframes over the selected mirror line"; | ot->description = "Flip selected keyframes over the selected mirror line"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->invoke = WM_menu_invoke; | ot->invoke = WM_menu_invoke; | ||||
| ot->exec = graphkeys_mirror_exec; | ot->exec = graphkeys_mirror_exec; | ||||
| ot->poll = graphop_editable_keyframes_poll; | ot->poll = graphop_editable_keyframes_poll; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| /* id-props */ | /* Id-props */ | ||||
| ot->prop = RNA_def_enum(ot->srna, "type", prop_graphkeys_mirror_types, 0, "Type", ""); | ot->prop = RNA_def_enum(ot->srna, "type", prop_graphkeys_mirror_types, 0, "Type", ""); | ||||
| } | } | ||||
| /* ******************** Smooth Keyframes Operator *********************** */ | /* ******************** Smooth Keyframes Operator *********************** */ | ||||
| static int graphkeys_smooth_exec(bContext *C, wmOperator *UNUSED(op)) | static int graphkeys_smooth_exec(bContext *C, wmOperator *UNUSED(op)) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| ListBase anim_data = {NULL, NULL}; | ListBase anim_data = {NULL, NULL}; | ||||
| bAnimListElem *ale; | bAnimListElem *ale; | ||||
| int filter; | int filter; | ||||
| /* get editor data */ | /* Get editor data. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* filter data */ | /* Filter data. */ | ||||
| filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | | ||||
| ANIMFILTER_NODUPLIS); | ANIMFILTER_NODUPLIS); | ||||
| ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); | ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); | ||||
| /* smooth keyframes */ | /* Smooth keyframes. */ | ||||
| for (ale = anim_data.first; ale; ale = ale->next) { | for (ale = anim_data.first; ale; ale = ale->next) { | ||||
| /* For now, we can only smooth by flattening handles AND smoothing curve values. | /* For now, we can only smooth by flattening handles AND smoothing curve values. | ||||
| * Perhaps the mode argument could be removed, as that functionality is offered through | * Perhaps the mode argument could be removed, as that functionality is offered through | ||||
| * Snap->Flatten Handles anyway. | * Snap->Flatten Handles anyway. | ||||
| */ | */ | ||||
| smooth_fcurve(ale->key_data); | smooth_fcurve(ale->key_data); | ||||
| ale->update |= ANIM_UPDATE_DEFAULT; | ale->update |= ANIM_UPDATE_DEFAULT; | ||||
| } | } | ||||
| ANIM_animdata_update(&ac, &anim_data); | ANIM_animdata_update(&ac, &anim_data); | ||||
| ANIM_animdata_freelist(&anim_data); | ANIM_animdata_freelist(&anim_data); | ||||
| /* set notifier that keyframes have changed */ | /* Set notifier that keyframes have changed. */ | ||||
| WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GRAPH_OT_smooth(wmOperatorType *ot) | void GRAPH_OT_smooth(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Smooth Keys"; | ot->name = "Smooth Keys"; | ||||
| ot->idname = "GRAPH_OT_smooth"; | ot->idname = "GRAPH_OT_smooth"; | ||||
| ot->description = "Apply weighted moving means to make selected F-Curves less bumpy"; | ot->description = "Apply weighted moving means to make selected F-Curves less bumpy"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->exec = graphkeys_smooth_exec; | ot->exec = graphkeys_smooth_exec; | ||||
| ot->poll = graphop_editable_keyframes_poll; | ot->poll = graphop_editable_keyframes_poll; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| } | } | ||||
| /* ************************************************************************** */ | /* ************************************************************************** */ | ||||
| /* F-CURVE MODIFIERS */ | /* F-CURVE MODIFIERS */ | ||||
| /* ******************** Add F-Modifier Operator *********************** */ | /* ******************** Add F-Modifier Operator *********************** */ | ||||
| static const EnumPropertyItem *graph_fmodifier_itemf(bContext *C, | static const EnumPropertyItem *graph_fmodifier_itemf(bContext *C, | ||||
| PointerRNA *UNUSED(ptr), | PointerRNA *UNUSED(ptr), | ||||
| PropertyRNA *UNUSED(prop), | PropertyRNA *UNUSED(prop), | ||||
| bool *r_free) | bool *r_free) | ||||
| { | { | ||||
| EnumPropertyItem *item = NULL; | EnumPropertyItem *item = NULL; | ||||
| int totitem = 0; | int totitem = 0; | ||||
| int i = 0; | int i = 0; | ||||
| if (C == NULL) { | if (C == NULL) { | ||||
| return rna_enum_fmodifier_type_items; | return rna_enum_fmodifier_type_items; | ||||
| } | } | ||||
| /* start from 1 to skip the 'Invalid' modifier type */ | /* Start from 1 to skip the 'Invalid' modifier type. */ | ||||
| for (i = 1; i < FMODIFIER_NUM_TYPES; i++) { | for (i = 1; i < FMODIFIER_NUM_TYPES; i++) { | ||||
| const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(i); | const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(i); | ||||
| int index; | int index; | ||||
| /* check if modifier is valid for this context */ | /* Check if modifier is valid for this context. */ | ||||
| if (fmi == NULL) { | if (fmi == NULL) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| index = RNA_enum_from_value(rna_enum_fmodifier_type_items, fmi->type); | index = RNA_enum_from_value(rna_enum_fmodifier_type_items, fmi->type); | ||||
| if (index != -1) { /* Not all types are implemented yet... */ | if (index != -1) { /* Not all types are implemented yet... */ | ||||
| RNA_enum_item_add(&item, &totitem, &rna_enum_fmodifier_type_items[index]); | RNA_enum_item_add(&item, &totitem, &rna_enum_fmodifier_type_items[index]); | ||||
| } | } | ||||
| } | } | ||||
| RNA_enum_item_end(&item, &totitem); | RNA_enum_item_end(&item, &totitem); | ||||
| *r_free = true; | *r_free = true; | ||||
| return item; | return item; | ||||
| } | } | ||||
| static int graph_fmodifier_add_exec(bContext *C, wmOperator *op) | static int graph_fmodifier_add_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| ListBase anim_data = {NULL, NULL}; | ListBase anim_data = {NULL, NULL}; | ||||
| bAnimListElem *ale; | bAnimListElem *ale; | ||||
| int filter; | int filter; | ||||
| short type; | short type; | ||||
| /* get editor data */ | /* Get editor data. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* get type of modifier to add */ | /* Get type of modifier to add. */ | ||||
| type = RNA_enum_get(op->ptr, "type"); | type = RNA_enum_get(op->ptr, "type"); | ||||
| /* filter data */ | /* Filter data. */ | ||||
| filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); | filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); | ||||
| if (RNA_boolean_get(op->ptr, "only_active")) { | if (RNA_boolean_get(op->ptr, "only_active")) { | ||||
| /* FIXME: enforce in this case only a single channel to get handled? */ | /* FIXME: enforce in this case only a single channel to get handled? */ | ||||
| filter |= ANIMFILTER_ACTIVE; | filter |= ANIMFILTER_ACTIVE; | ||||
| } | } | ||||
| else { | else { | ||||
| filter |= (ANIMFILTER_SEL | ANIMFILTER_CURVE_VISIBLE); | filter |= (ANIMFILTER_SEL | ANIMFILTER_CURVE_VISIBLE); | ||||
| } | } | ||||
| ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); | ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); | ||||
| /* add f-modifier to each curve */ | /* Add f-modifier to each curve. */ | ||||
| for (ale = anim_data.first; ale; ale = ale->next) { | for (ale = anim_data.first; ale; ale = ale->next) { | ||||
| FCurve *fcu = (FCurve *)ale->data; | FCurve *fcu = (FCurve *)ale->data; | ||||
| FModifier *fcm; | FModifier *fcm; | ||||
| /* add F-Modifier of specified type to active F-Curve, and make it the active one */ | /* Add F-Modifier of specified type to active F-Curve, and make it the active one. */ | ||||
| fcm = add_fmodifier(&fcu->modifiers, type, fcu); | fcm = add_fmodifier(&fcu->modifiers, type, fcu); | ||||
| if (fcm) { | if (fcm) { | ||||
| set_active_fmodifier(&fcu->modifiers, fcm); | set_active_fmodifier(&fcu->modifiers, fcm); | ||||
| } | } | ||||
| else { | else { | ||||
| BKE_report(op->reports, RPT_ERROR, "Modifier could not be added (see console for details)"); | BKE_report(op->reports, RPT_ERROR, "Modifier could not be added (see console for details)"); | ||||
| break; | break; | ||||
| } | } | ||||
| ale->update |= ANIM_UPDATE_DEPS; | ale->update |= ANIM_UPDATE_DEPS; | ||||
| } | } | ||||
| ANIM_animdata_update(&ac, &anim_data); | ANIM_animdata_update(&ac, &anim_data); | ||||
| ANIM_animdata_freelist(&anim_data); | ANIM_animdata_freelist(&anim_data); | ||||
| /* set notifier that things have changed */ | /* Set notifier that things have changed. */ | ||||
| WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GRAPH_OT_fmodifier_add(wmOperatorType *ot) | void GRAPH_OT_fmodifier_add(wmOperatorType *ot) | ||||
| { | { | ||||
| PropertyRNA *prop; | PropertyRNA *prop; | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Add F-Curve Modifier"; | ot->name = "Add F-Curve Modifier"; | ||||
| ot->idname = "GRAPH_OT_fmodifier_add"; | ot->idname = "GRAPH_OT_fmodifier_add"; | ||||
| ot->description = "Add F-Modifier to the active/selected F-Curves"; | ot->description = "Add F-Modifier to the active/selected F-Curves"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->invoke = WM_menu_invoke; | ot->invoke = WM_menu_invoke; | ||||
| ot->exec = graph_fmodifier_add_exec; | ot->exec = graph_fmodifier_add_exec; | ||||
| ot->poll = graphop_selected_fcurve_poll; | ot->poll = graphop_selected_fcurve_poll; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| /* id-props */ | /* Id-props */ | ||||
| prop = RNA_def_enum(ot->srna, "type", rna_enum_fmodifier_type_items, 0, "Type", ""); | prop = RNA_def_enum(ot->srna, "type", rna_enum_fmodifier_type_items, 0, "Type", ""); | ||||
| RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ACTION); | RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ACTION); | ||||
| RNA_def_enum_funcs(prop, graph_fmodifier_itemf); | RNA_def_enum_funcs(prop, graph_fmodifier_itemf); | ||||
| ot->prop = prop; | ot->prop = prop; | ||||
| RNA_def_boolean( | RNA_def_boolean( | ||||
| ot->srna, "only_active", 1, "Only Active", "Only add F-Modifier to active F-Curve"); | ot->srna, "only_active", 1, "Only Active", "Only add F-Modifier to active F-Curve"); | ||||
| } | } | ||||
| /* ******************** Copy F-Modifiers Operator *********************** */ | /* ******************** Copy F-Modifiers Operator *********************** */ | ||||
| static int graph_fmodifier_copy_exec(bContext *C, wmOperator *op) | static int graph_fmodifier_copy_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| bAnimListElem *ale; | bAnimListElem *ale; | ||||
| bool ok = false; | bool ok = false; | ||||
| /* get editor data */ | /* Get editor data. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* clear buffer first */ | /* Clear buffer first. */ | ||||
| ANIM_fmodifiers_copybuf_free(); | ANIM_fmodifiers_copybuf_free(); | ||||
| /* get the active F-Curve */ | /* Get the active F-Curve. */ | ||||
| ale = get_active_fcurve_channel(&ac); | ale = get_active_fcurve_channel(&ac); | ||||
| /* if this exists, call the copy F-Modifiers API function */ | /* If this exists, call the copy F-Modifiers API function. */ | ||||
| if (ale && ale->data) { | if (ale && ale->data) { | ||||
| FCurve *fcu = (FCurve *)ale->data; | FCurve *fcu = (FCurve *)ale->data; | ||||
| /* TODO: when 'active' vs 'all' boolean is added, change last param! */ | /* TODO: When 'active' vs 'all' boolean is added, change last param! (Joshua Leung 2010) */ | ||||
| ok = ANIM_fmodifiers_copy_to_buf(&fcu->modifiers, 0); | ok = ANIM_fmodifiers_copy_to_buf(&fcu->modifiers, 0); | ||||
| /* free temp data now */ | /* Free temp data now. */ | ||||
| MEM_freeN(ale); | MEM_freeN(ale); | ||||
| } | } | ||||
| /* successful or not? */ | /* Successful or not? */ | ||||
| if (ok == 0) { | if (ok == 0) { | ||||
| BKE_report(op->reports, RPT_ERROR, "No F-Modifiers available to be copied"); | BKE_report(op->reports, RPT_ERROR, "No F-Modifiers available to be copied"); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GRAPH_OT_fmodifier_copy(wmOperatorType *ot) | void GRAPH_OT_fmodifier_copy(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Copy F-Modifiers"; | ot->name = "Copy F-Modifiers"; | ||||
| ot->idname = "GRAPH_OT_fmodifier_copy"; | ot->idname = "GRAPH_OT_fmodifier_copy"; | ||||
| ot->description = "Copy the F-Modifier(s) of the active F-Curve"; | ot->description = "Copy the F-Modifier(s) of the active F-Curve"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->exec = graph_fmodifier_copy_exec; | ot->exec = graph_fmodifier_copy_exec; | ||||
| ot->poll = graphop_active_fcurve_poll; | ot->poll = graphop_active_fcurve_poll; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| /* id-props */ | /* Id-props */ | ||||
| #if 0 | #if 0 | ||||
| ot->prop = RNA_def_boolean(ot->srna, | ot->prop = RNA_def_boolean(ot->srna, | ||||
| "all", | "all", | ||||
| 1, | 1, | ||||
| "All F-Modifiers", | "All F-Modifiers", | ||||
| "Copy all the F-Modifiers, instead of just the active one"); | "Copy all the F-Modifiers, instead of just the active one"); | ||||
| #endif | #endif | ||||
| } | } | ||||
| /* ******************** Paste F-Modifiers Operator *********************** */ | /* ******************** Paste F-Modifiers Operator *********************** */ | ||||
| static int graph_fmodifier_paste_exec(bContext *C, wmOperator *op) | static int graph_fmodifier_paste_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| ListBase anim_data = {NULL, NULL}; | ListBase anim_data = {NULL, NULL}; | ||||
| bAnimListElem *ale; | bAnimListElem *ale; | ||||
| int filter; | int filter; | ||||
| const bool replace = RNA_boolean_get(op->ptr, "replace"); | const bool replace = RNA_boolean_get(op->ptr, "replace"); | ||||
| bool ok = false; | bool ok = false; | ||||
| /* get editor data */ | /* Get editor data. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* filter data */ | /* Filter data. */ | ||||
| if (RNA_boolean_get(op->ptr, "only_active")) { | if (RNA_boolean_get(op->ptr, "only_active")) { | ||||
| /* This should be the default (for buttons) - Just paste to the active FCurve */ | /* This should be the default (for buttons) - Just paste to the active FCurve. */ | ||||
| filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ACTIVE | ANIMFILTER_FOREDIT | | filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ACTIVE | ANIMFILTER_FOREDIT | | ||||
| ANIMFILTER_NODUPLIS); | ANIMFILTER_NODUPLIS); | ||||
| } | } | ||||
| else { | else { | ||||
| /* This is only if the operator gets called from a hotkey or search - | /* This is only if the operator gets called from a hotkey or search - | ||||
| * Paste to all visible curves. */ | * Paste to all visible curves. */ | ||||
| filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL | | filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL | | ||||
| ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); | ||||
| } | } | ||||
| ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); | ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); | ||||
| /* paste modifiers */ | /* Paste modifiers. */ | ||||
| for (ale = anim_data.first; ale; ale = ale->next) { | for (ale = anim_data.first; ale; ale = ale->next) { | ||||
| FCurve *fcu = (FCurve *)ale->data; | FCurve *fcu = (FCurve *)ale->data; | ||||
| int tot; | int tot; | ||||
| tot = ANIM_fmodifiers_paste_from_buf(&fcu->modifiers, replace, fcu); | tot = ANIM_fmodifiers_paste_from_buf(&fcu->modifiers, replace, fcu); | ||||
| if (tot) { | if (tot) { | ||||
| ale->update |= ANIM_UPDATE_DEPS; | ale->update |= ANIM_UPDATE_DEPS; | ||||
| ok = true; | ok = true; | ||||
| } | } | ||||
| } | } | ||||
| if (ok) { | if (ok) { | ||||
| ANIM_animdata_update(&ac, &anim_data); | ANIM_animdata_update(&ac, &anim_data); | ||||
| } | } | ||||
| ANIM_animdata_freelist(&anim_data); | ANIM_animdata_freelist(&anim_data); | ||||
| /* successful or not? */ | /* Successful or not?. */ | ||||
| if (ok) { | if (ok) { | ||||
| /* set notifier that keyframes have changed */ | /* Set notifier that keyframes have changed. */ | ||||
| WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| BKE_report(op->reports, RPT_ERROR, "No F-Modifiers to paste"); | BKE_report(op->reports, RPT_ERROR, "No F-Modifiers to paste"); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| void GRAPH_OT_fmodifier_paste(wmOperatorType *ot) | void GRAPH_OT_fmodifier_paste(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Paste F-Modifiers"; | ot->name = "Paste F-Modifiers"; | ||||
| ot->idname = "GRAPH_OT_fmodifier_paste"; | ot->idname = "GRAPH_OT_fmodifier_paste"; | ||||
| ot->description = "Add copied F-Modifiers to the selected F-Curves"; | ot->description = "Add copied F-Modifiers to the selected F-Curves"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->exec = graph_fmodifier_paste_exec; | ot->exec = graph_fmodifier_paste_exec; | ||||
| ot->poll = graphop_active_fcurve_poll; | ot->poll = graphop_active_fcurve_poll; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| /* properties */ | /* Properties */ | ||||
| RNA_def_boolean( | RNA_def_boolean( | ||||
| ot->srna, "only_active", true, "Only Active", "Only paste F-Modifiers on active F-Curve"); | ot->srna, "only_active", true, "Only Active", "Only paste F-Modifiers on active F-Curve"); | ||||
| RNA_def_boolean( | RNA_def_boolean( | ||||
| ot->srna, | ot->srna, | ||||
| "replace", | "replace", | ||||
| false, | false, | ||||
| "Replace Existing", | "Replace Existing", | ||||
| "Replace existing F-Modifiers, instead of just appending to the end of the existing list"); | "Replace existing F-Modifiers, instead of just appending to the end of the existing list"); | ||||
| } | } | ||||
| /* ************************************************************************** */ | /* ************************************************************************** */ | ||||
| /* Drivers */ | /* Drivers */ | ||||
| /* ******************** Copy Driver Vars Operator *********************** */ | /* ******************** Copy Driver Vars Operator *********************** */ | ||||
| static int graph_driver_vars_copy_exec(bContext *C, wmOperator *op) | static int graph_driver_vars_copy_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bool ok = false; | bool ok = false; | ||||
| PointerRNA ptr = CTX_data_pointer_get_type(C, "active_editable_fcurve", &RNA_FCurve); | PointerRNA ptr = CTX_data_pointer_get_type(C, "active_editable_fcurve", &RNA_FCurve); | ||||
| /* if this exists, call the copy driver vars API function */ | /* If this exists, call the copy driver vars API function. */ | ||||
| FCurve *fcu = ptr.data; | FCurve *fcu = ptr.data; | ||||
| if (fcu) { | if (fcu) { | ||||
| ok = ANIM_driver_vars_copy(op->reports, fcu); | ok = ANIM_driver_vars_copy(op->reports, fcu); | ||||
| } | } | ||||
| /* successful or not? */ | /* Successful or not?. */ | ||||
| if (ok) { | if (ok) { | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| void GRAPH_OT_driver_variables_copy(wmOperatorType *ot) | void GRAPH_OT_driver_variables_copy(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Copy Driver Variables"; | ot->name = "Copy Driver Variables"; | ||||
| ot->idname = "GRAPH_OT_driver_variables_copy"; | ot->idname = "GRAPH_OT_driver_variables_copy"; | ||||
| ot->description = "Copy the driver variables of the active driver"; | ot->description = "Copy the driver variables of the active driver"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->exec = graph_driver_vars_copy_exec; | ot->exec = graph_driver_vars_copy_exec; | ||||
| ot->poll = graphop_active_editable_fcurve_ctx_poll; | ot->poll = graphop_active_editable_fcurve_ctx_poll; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| } | } | ||||
| /* ******************** Paste Driver Vars Operator *********************** */ | /* ******************** Paste Driver Vars Operator *********************** */ | ||||
| static int graph_driver_vars_paste_exec(bContext *C, wmOperator *op) | static int graph_driver_vars_paste_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| const bool replace = RNA_boolean_get(op->ptr, "replace"); | const bool replace = RNA_boolean_get(op->ptr, "replace"); | ||||
| bool ok = false; | bool ok = false; | ||||
| PointerRNA ptr = CTX_data_pointer_get_type(C, "active_editable_fcurve", &RNA_FCurve); | PointerRNA ptr = CTX_data_pointer_get_type(C, "active_editable_fcurve", &RNA_FCurve); | ||||
| /* if this exists, call the paste driver vars API function */ | /* If this exists, call the paste driver vars API function. */ | ||||
| FCurve *fcu = ptr.data; | FCurve *fcu = ptr.data; | ||||
| if (fcu) { | if (fcu) { | ||||
| ok = ANIM_driver_vars_paste(op->reports, fcu, replace); | ok = ANIM_driver_vars_paste(op->reports, fcu, replace); | ||||
| } | } | ||||
| /* successful or not? */ | /* Successful or not?. */ | ||||
| if (ok) { | if (ok) { | ||||
| /* rebuild depsgraph, now that there are extra deps here */ | /* Rebuild depsgraph, now that there are extra deps here. */ | ||||
| DEG_relations_tag_update(CTX_data_main(C)); | DEG_relations_tag_update(CTX_data_main(C)); | ||||
| /* set notifier that keyframes have changed */ | /* Set notifier that keyframes have changed. */ | ||||
| WM_event_add_notifier(C, NC_SCENE | ND_FRAME, CTX_data_scene(C)); | WM_event_add_notifier(C, NC_SCENE | ND_FRAME, CTX_data_scene(C)); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| void GRAPH_OT_driver_variables_paste(wmOperatorType *ot) | void GRAPH_OT_driver_variables_paste(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Paste Driver Variables"; | ot->name = "Paste Driver Variables"; | ||||
| ot->idname = "GRAPH_OT_driver_variables_paste"; | ot->idname = "GRAPH_OT_driver_variables_paste"; | ||||
| ot->description = "Add copied driver variables to the active driver"; | ot->description = "Add copied driver variables to the active driver"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
| ot->exec = graph_driver_vars_paste_exec; | ot->exec = graph_driver_vars_paste_exec; | ||||
| ot->poll = graphop_active_editable_fcurve_ctx_poll; | ot->poll = graphop_active_editable_fcurve_ctx_poll; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| /* properties */ | /* Properties */ | ||||
| RNA_def_boolean(ot->srna, | RNA_def_boolean(ot->srna, | ||||
| "replace", | "replace", | ||||
| false, | false, | ||||
| "Replace Existing", | "Replace Existing", | ||||
| "Replace existing driver variables, instead of just appending to the end of the " | "Replace existing driver variables, instead of just appending to the end of the " | ||||
| "existing list"); | "existing list"); | ||||
| } | } | ||||
| /* ************************************************************************** */ | /* ************************************************************************** */ | ||||
| static int graph_driver_delete_invalid_exec(bContext *C, wmOperator *op) | static int graph_driver_delete_invalid_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| ListBase anim_data = {NULL, NULL}; | ListBase anim_data = {NULL, NULL}; | ||||
| bAnimListElem *ale; | bAnimListElem *ale; | ||||
| int filter; | int filter; | ||||
| bool ok = false; | bool ok = false; | ||||
| uint deleted = 0; | uint deleted = 0; | ||||
| /* get editor data */ | /* Get editor data. */ | ||||
| if (ANIM_animdata_get_context(C, &ac) == 0) { | if (ANIM_animdata_get_context(C, &ac) == 0) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* NOTE: we might need a scene update to evaluate the driver flags */ | /* NOTE: We might need a scene update to evaluate the driver flags. */ | ||||
| /* filter data */ | /* Filter data. */ | ||||
| filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS); | filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS); | ||||
| ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); | ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); | ||||
| /* find invalid drivers */ | /* Find invalid drivers. */ | ||||
| for (ale = anim_data.first; ale; ale = ale->next) { | for (ale = anim_data.first; ale; ale = ale->next) { | ||||
| FCurve *fcu = (FCurve *)ale->data; | FCurve *fcu = (FCurve *)ale->data; | ||||
| if (ELEM(NULL, fcu, fcu->driver)) { | if (ELEM(NULL, fcu, fcu->driver)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (!(fcu->driver->flag & DRIVER_FLAG_INVALID)) { | if (!(fcu->driver->flag & DRIVER_FLAG_INVALID)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| ok |= ANIM_remove_driver(op->reports, ale->id, fcu->rna_path, fcu->array_index, 0); | ok |= ANIM_remove_driver(op->reports, ale->id, fcu->rna_path, fcu->array_index, 0); | ||||
| if (!ok) { | if (!ok) { | ||||
| break; | break; | ||||
| } | } | ||||
| deleted += 1; | deleted += 1; | ||||
| } | } | ||||
| /* cleanup */ | /* Cleanup. */ | ||||
| ANIM_animdata_freelist(&anim_data); | ANIM_animdata_freelist(&anim_data); | ||||
| if (deleted > 0) { | if (deleted > 0) { | ||||
| /* notify the world of any changes */ | /* Notify the world of any changes. */ | ||||
| DEG_relations_tag_update(CTX_data_main(C)); | DEG_relations_tag_update(CTX_data_main(C)); | ||||
| WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL); | WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL); | ||||
| WM_reportf(RPT_INFO, "Deleted %u drivers", deleted); | WM_reportf(RPT_INFO, "Deleted %u drivers", deleted); | ||||
| } | } | ||||
| else { | else { | ||||
| WM_report(RPT_INFO, "No drivers deleted"); | WM_report(RPT_INFO, "No drivers deleted"); | ||||
| } | } | ||||
| /* successful or not? */ | /* Successful or not?*/ | ||||
| if (!ok) { | if (!ok) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| static bool graph_driver_delete_invalid_poll(bContext *C) | static bool graph_driver_delete_invalid_poll(bContext *C) | ||||
| { | { | ||||
| bAnimContext ac; | bAnimContext ac; | ||||
| ScrArea *area = CTX_wm_area(C); | ScrArea *area = CTX_wm_area(C); | ||||
| /* firstly, check if in Graph Editor */ | /* Firstly, check if in Graph Editor. */ | ||||
| if ((area == NULL) || (area->spacetype != SPACE_GRAPH)) { | if ((area == NULL) || (area->spacetype != SPACE_GRAPH)) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* try to init Anim-Context stuff ourselves and check */ | /* Try to init Anim-Context stuff ourselves and check. */ | ||||
| return ANIM_animdata_get_context(C, &ac) != 0; | return ANIM_animdata_get_context(C, &ac) != 0; | ||||
| } | } | ||||
| void GRAPH_OT_driver_delete_invalid(wmOperatorType *ot) | void GRAPH_OT_driver_delete_invalid(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* Identifiers */ | ||||
| ot->name = "Delete Invalid Drivers"; | ot->name = "Delete Invalid Drivers"; | ||||
| ot->idname = "GRAPH_OT_driver_delete_invalid"; | ot->idname = "GRAPH_OT_driver_delete_invalid"; | ||||
| ot->description = "Delete all visible drivers considered invalid"; | ot->description = "Delete all visible drivers considered invalid"; | ||||
| /* api callbacks */ | /* API callbacks */ | ||||
sybren: API ;-) | |||||
| ot->exec = graph_driver_delete_invalid_exec; | ot->exec = graph_driver_delete_invalid_exec; | ||||
| ot->poll = graph_driver_delete_invalid_poll; | ot->poll = graph_driver_delete_invalid_poll; | ||||
| /* flags */ | /* Flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| } | } | ||||
API ;-)