From 618b459e8b3630eea747523febec666889a364f7 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Thu, 18 Mar 2010 13:04:46 +0000 Subject: [PATCH] F-Modifier Goodies (as requested by @ndy): * Copy/Paste operators for F-Modifiers Available in Graph and NLA Editors. Use the Copy/Paste buttons beside the 'Add Modifier' buttons. Copy copies all the modifiers of the ACTIVE F-Curve or Strip depending on the editor. Paste pastes modifiers from the buffer to all the selected F-Curves or Strips, adding the new modifiers to the ends of each list. * 'Stepped Interpolation' F-Modifier This modifier holds each interpolated value from the F-Curve for several frames without changing the timing. This allows to preview motions 'on-twos' for example without altering the timing, or having to go through setting heaps of keyframes. In this case, Andy wanted to use this for CG <-> StopMo. --- source/blender/blenkernel/BKE_fcurve.h | 1 + source/blender/blenkernel/intern/fmodifier.c | 69 ++++++++++ .../blender/editors/animation/fmodifier_ui.c | 108 ++++++++++++++- source/blender/editors/include/ED_anim_api.h | 19 +++ .../editors/space_graph/graph_buttons.c | 7 +- .../blender/editors/space_graph/graph_edit.c | 117 ++++++++++++++++- .../editors/space_graph/graph_intern.h | 2 + .../blender/editors/space_graph/graph_ops.c | 3 +- .../blender/editors/space_nla/nla_buttons.c | 5 + source/blender/editors/space_nla/nla_edit.c | 124 +++++++++++++++++- source/blender/editors/space_nla/nla_intern.h | 2 + source/blender/editors/space_nla/nla_ops.c | 2 + source/blender/makesdna/DNA_anim_types.h | 9 ++ source/blender/makesrna/RNA_access.h | 1 + source/blender/makesrna/intern/rna_fcurve.c | 26 ++++ .../windowmanager/intern/wm_init_exit.c | 2 + 16 files changed, 490 insertions(+), 7 deletions(-) diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index 9df6bfdbe7c..c4d74f86284 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -158,6 +158,7 @@ FModifierTypeInfo *get_fmodifier_typeinfo(int type); /* ---------------------- */ struct FModifier *add_fmodifier(ListBase *modifiers, int type); +struct FModifier *copy_fmodifier(struct FModifier *src); void copy_fmodifiers(ListBase *dst, ListBase *src); int remove_fmodifier(ListBase *modifiers, struct FModifier *fcm); int remove_fmodifier_index(ListBase *modifiers, int index); diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c index bbef3227490..02f35bb78f8 100644 --- a/source/blender/blenkernel/intern/fmodifier.c +++ b/source/blender/blenkernel/intern/fmodifier.c @@ -871,6 +871,49 @@ static FModifierTypeInfo FMI_LIMITS = { fcm_limits_evaluate /* evaluate */ }; +/* Stepped F-Curve Modifier --------------------------- */ + +static void fcm_stepped_new_data (void *mdata) +{ + FMod_Stepped *data= (FMod_Stepped *)mdata; + + /* just need to set the step-size to 2-frames by default */ + // XXX: or would 5 be more normal? + data->step_size = 2.0f; +} + +static float fcm_stepped_time (FCurve *fcu, FModifier *fcm, float cvalue, float evaltime) +{ + FMod_Stepped *data= (FMod_Stepped *)fcm->data; + int snapblock; + + /* we snap to the start of the previous closest block of 'step_size' frames + * after the start offset has been discarded + * - i.e. round down + */ + snapblock = (int)((evaltime - data->start) / data->step_size); + + /* reapply the offset, and multiple the snapblock by the size of the steps to get + * the new time to evaluate at + */ + return ((float)snapblock * data->step_size) + data->start; +} + +static FModifierTypeInfo FMI_STEPPED = { + FMODIFIER_TYPE_STEPPED, /* type */ + sizeof(FMod_Limits), /* size */ + FMI_TYPE_GENERATE_CURVE, /* action type */ /* XXX... err... */ + FMI_REQUIRES_RUNTIME_CHECK, /* requirements */ + "Stepped", /* name */ + "FMod_Stepped", /* struct name */ + NULL, /* free data */ + NULL, /* copy data */ + fcm_stepped_new_data, /* new data */ + NULL, /* verify */ + fcm_stepped_time, /* evaluate time */ + NULL /* evaluate */ +}; + /* F-Curve Modifier API --------------------------- */ /* All of the F-Curve Modifier api functions use FModifierTypeInfo structs to carry out * and operations that involve F-Curve modifier specific code. @@ -892,6 +935,7 @@ static void fmods_init_typeinfo () fmodifiersTypeInfo[6]= NULL/*&FMI_FILTER*/; /* Filter F-Curve Modifier */ // XXX unimplemented fmodifiersTypeInfo[7]= &FMI_PYTHON; /* Custom Python F-Curve Modifier */ fmodifiersTypeInfo[8]= &FMI_LIMITS; /* Limits F-Curve Modifier */ + fmodifiersTypeInfo[9]= &FMI_STEPPED; /* Stepped F-Curve Modifier */ } /* This function should be used for getting the appropriate type-info when only @@ -968,6 +1012,31 @@ FModifier *add_fmodifier (ListBase *modifiers, int type) return fcm; } +/* Make a copy of the specified F-Modifier */ +FModifier *copy_fmodifier (FModifier *src) +{ + FModifierTypeInfo *fmi= fmodifier_get_typeinfo(src); + FModifier *dst; + + /* sanity check */ + if (src == NULL) + return NULL; + + /* copy the base data, clearing the links */ + dst = MEM_dupallocN(src); + dst->next = dst->prev = NULL; + + /* make a new copy of the F-Modifier's data */ + dst->data = MEM_dupallocN(src->data); + + /* only do specific constraints if required */ + if (fmi && fmi->copy_data) + fmi->copy_data(dst, src); + + /* return the new modifier */ + return dst; +} + /* Duplicate all of the F-Modifiers in the Modifier stacks */ void copy_fmodifiers (ListBase *dst, ListBase *src) { diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c index 9d0fe99976b..22bb5317383 100644 --- a/source/blender/editors/animation/fmodifier_ui.c +++ b/source/blender/editors/animation/fmodifier_ui.c @@ -30,6 +30,9 @@ * This file defines the (C-Coded) templates + editing callbacks needed * by the interface stuff or F-Modifiers, as used by F-Curves in the Graph Editor, * and NLA-Strips in the NLA Editor. + * + * Copy/Paste Buffer for F-Modifiers: + * For now, this is also defined in this file so that it can be shared between the */ #include @@ -47,15 +50,18 @@ #include "RNA_access.h" +#include "ED_anim_api.h" + #include "UI_interface.h" #include "UI_resources.h" +/* ********************************************** */ +/* UI STUFF */ + // XXX! -------------------------------- /* temporary definition for limits of float number buttons (FLT_MAX tends to infinity with old system) */ #define UI_FLT_MAX 10000.0f -/* ********************************************** */ - #define B_REDR 1 #define B_FMODIFIER_REDRAW 20 @@ -549,6 +555,22 @@ static void draw_modifier__limits(uiLayout *layout, ID *id, FModifier *fcm, shor /* --------------- */ +/* draw settings for stepped interpolation modifier */ +static void draw_modifier__stepped(uiLayout *layout, ID *id, FModifier *fcm, short width) +{ + uiLayout *col; + PointerRNA ptr; + + /* init the RNA-pointer */ + RNA_pointer_create(id, &RNA_FModifierStepped, fcm, &ptr); + + col= uiLayoutColumn(layout, 0); + + uiItemR(col, NULL, 0, &ptr, "step_size", 0); + uiItemR(col, NULL, 0, &ptr, "start_offset", 0); +} + +/* --------------- */ void ANIM_uiTemplate_fmodifier_draw (uiLayout *layout, ID *id, ListBase *modifiers, FModifier *fcm) { @@ -635,6 +657,10 @@ void ANIM_uiTemplate_fmodifier_draw (uiLayout *layout, ID *id, ListBase *modifie case FMODIFIER_TYPE_NOISE: /* Noise */ draw_modifier__noise(box, id, fcm, width); break; + + case FMODIFIER_TYPE_STEPPED: /* Stepped */ + draw_modifier__stepped(box, id, fcm, width); + break; default: /* unknown type */ break; @@ -643,3 +669,81 @@ void ANIM_uiTemplate_fmodifier_draw (uiLayout *layout, ID *id, ListBase *modifie } /* ********************************************** */ +/* COPY/PASTE BUFFER STUFF */ + +/* Copy/Paste Buffer itself (list of FModifier 's) */ +static ListBase fmodifier_copypaste_buf = {NULL, NULL}; + +/* ---------- */ + +/* free the copy/paste buffer */ +void free_fmodifiers_copybuf (void) +{ + /* just free the whole buffer */ + free_fmodifiers(&fmodifier_copypaste_buf); +} + +/* copy the given F-Modifiers to the buffer, returning whether anything was copied or not + * assuming that the buffer has been cleared already with free_fmodifiers_copybuf() + * - active: only copy the active modifier + */ +short ANIM_fmodifiers_copy_to_buf (ListBase *modifiers, short active) +{ + short ok = 1; + + /* sanity checks */ + if ELEM(NULL, modifiers, modifiers->first) + return 0; + + /* copy the whole list, or just the active one? */ + if (active) { + FModifier *fcm = find_active_fmodifier(modifiers); + + if (fcm) { + FModifier *fcmN = copy_fmodifier(fcm); + BLI_addtail(&fmodifier_copypaste_buf, fcmN); + } + else + ok = 0; + } + else + copy_fmodifiers(&fmodifier_copypaste_buf, modifiers); + + /* did we succeed? */ + return ok; +} + +/* 'Paste' the F-Modifier(s) from the buffer to the specified list + * - replace: free all the existing modifiers to leave only the pasted ones + */ +short ANIM_fmodifiers_paste_from_buf (ListBase *modifiers, short replace) +{ + FModifier *fcm; + short ok = 0; + + /* sanity checks */ + if (modifiers == NULL) + return 0; + + /* if replacing the list, free the existing modifiers */ + if (replace) + free_fmodifiers(modifiers); + + /* now copy over all the modifiers in the buffer to the end of the list */ + for (fcm= fmodifier_copypaste_buf.first; fcm; fcm= fcm->next) { + /* make a copy of it */ + FModifier *fcmN = copy_fmodifier(fcm); + + /* make sure the new one isn't active, otherwise the list may get several actives */ + fcmN->flag &= ~FMODIFIER_FLAG_ACTIVE; + + /* now add it to the end of the list */ + BLI_addtail(modifiers, fcmN); + ok = 1; + } + + /* did we succeed? */ + return ok; +} + +/* ********************************************** */ diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index 2f089a41a3f..3892770c1f4 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -452,9 +452,28 @@ void ANIM_draw_previewrange(const struct bContext *C, struct View2D *v2d); /* ************************************************* */ /* F-MODIFIER TOOLS */ +/* ------------- UI Panel Drawing -------------- */ + /* draw a given F-Modifier for some layout/UI-Block */ void ANIM_uiTemplate_fmodifier_draw(struct uiLayout *layout, struct ID *id, ListBase *modifiers, struct FModifier *fcm); +/* ------------- Copy/Paste Buffer -------------- */ + + +/* free the copy/paste buffer */ +void free_fmodifiers_copybuf(void); + +/* copy the given F-Modifiers to the buffer, returning whether anything was copied or not + * assuming that the buffer has been cleared already with free_fmodifiers_copybuf() + * - active: only copy the active modifier + */ +short ANIM_fmodifiers_copy_to_buf(ListBase *modifiers, short active); + +/* 'Paste' the F-Modifier(s) from the buffer to the specified list + * - replace: free all the existing modifiers to leave only the pasted ones + */ +short ANIM_fmodifiers_paste_from_buf(ListBase *modifiers, short replace); + /* ************************************************* */ /* ASSORTED TOOLS */ diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c index 3975c88fe5c..78fd2e06683 100644 --- a/source/blender/editors/space_graph/graph_buttons.c +++ b/source/blender/editors/space_graph/graph_buttons.c @@ -610,8 +610,13 @@ static void graph_panel_modifiers(const bContext *C, Panel *pa) row= uiLayoutRow(pa->layout, 0); block= uiLayoutGetBlock(row); - // XXX for now, this will be a operator button which calls a temporary 'add modifier' operator + // XXX for now, this will be a operator button which calls a 'add modifier' operator uiDefButO(block, BUT, "GRAPH_OT_fmodifier_add", WM_OP_INVOKE_REGION_WIN, "Add Modifier", 10, 0, 150, 20, "Adds a new F-Curve Modifier for the active F-Curve"); + + /* copy/paste (as sub-row)*/ + row= uiLayoutRow(row, 1); + uiItemO(row, "", ICON_COPYDOWN, "GRAPH_OT_fmodifier_copy"); + uiItemO(row, "", ICON_PASTEDOWN, "GRAPH_OT_fmodifier_paste"); } /* draw each modifier */ diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 485c9ab8bf4..d23bafbc001 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -1971,7 +1971,7 @@ static int graph_fmodifier_add_exec(bContext *C, wmOperator *op) filter |= (ANIMFILTER_SEL|ANIMFILTER_CURVEVISIBLE); ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); - /* smooth keyframes */ + /* add f-modifier to each curve */ for (ale= anim_data.first; ale; ale= ale->next) { FCurve *fcu= (FCurve *)ale->data; FModifier *fcm; @@ -2017,4 +2017,119 @@ void GRAPH_OT_fmodifier_add (wmOperatorType *ot) RNA_def_boolean(ot->srna, "only_active", 1, "Only Active", "Only add F-Modifier to active F-Curve."); } +/* ******************** Copy F-Modifiers Operator *********************** */ + +static int graph_fmodifier_copy_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + bAnimListElem *ale; + short ok = 0; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* clear buffer first */ + free_fmodifiers_copybuf(); + + /* get the active F-Curve */ + ale= get_active_fcurve_channel(&ac); + + /* if this exists, call the copy F-Modifiers API function */ + if (ale && ale->data) { + FCurve *fcu= (FCurve *)ale->data; + + // TODO: when 'active' vs 'all' boolean is added, change last param! + ok= ANIM_fmodifiers_copy_to_buf(&fcu->modifiers, 0); + + /* free temp data now */ + MEM_freeN(ale); + } + + /* successful or not? */ + if (ok == 0) { + BKE_report(op->reports, RPT_ERROR, "No F-Modifiers available to be copied"); + return OPERATOR_CANCELLED; + } + else + return OPERATOR_FINISHED; +} + +void GRAPH_OT_fmodifier_copy (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Copy F-Modifiers"; + ot->idname= "GRAPH_OT_fmodifier_copy"; + ot->description= "Copy the F-Modifier(s) of the active F-Curve."; + + /* api callbacks */ + ot->exec= graph_fmodifier_copy_exec; + ot->poll= graphop_active_fcurve_poll; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* id-props */ + //ot->prop = RNA_def_boolean(ot->srna, "all", 1, "All F-Modifiers", "Copy all the F-Modifiers, instead of just the active one"); +} + +/* ******************** Paste F-Modifiers Operator *********************** */ + +static int graph_fmodifier_paste_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter, ok=0; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* filter data */ + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY); + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + /* paste modifiers */ + for (ale = anim_data.first; ale; ale = ale->next) { + FCurve *fcu= (FCurve *)ale->data; + + // TODO: do we want to replace existing modifiers? add user pref for that! + ok += ANIM_fmodifiers_paste_from_buf(&fcu->modifiers, 0); + } + + /* clean up */ + BLI_freelistN(&anim_data); + + /* successful or not? */ + if (ok) { + /* validate keyframes after editing */ + ANIM_editkeyframes_refresh(&ac); + + /* set notifier that keyframes have changed */ + WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL); + + return OPERATOR_FINISHED; + } + else { + BKE_report(op->reports, RPT_ERROR, "No F-Modifiers to paste"); + return OPERATOR_CANCELLED; + } +} + +void GRAPH_OT_fmodifier_paste (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Paste F-Modifiers"; + ot->idname= "GRAPH_OT_fmodifier_paste"; + ot->description= "Add copied F-Modifiers to the selected F-Curves"; + + /* api callbacks */ + ot->exec= graph_fmodifier_paste_exec; + ot->poll= graphop_editable_keyframes_poll; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + /* ************************************************************************** */ diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h index 696d31e22e1..356cd05b509 100644 --- a/source/blender/editors/space_graph/graph_intern.h +++ b/source/blender/editors/space_graph/graph_intern.h @@ -139,6 +139,8 @@ enum { /* ----------- */ void GRAPH_OT_fmodifier_add(struct wmOperatorType *ot); +void GRAPH_OT_fmodifier_copy(struct wmOperatorType *ot); +void GRAPH_OT_fmodifier_paste(struct wmOperatorType *ot); /* ----------- */ diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index 7c1ac14027a..63c877e7402 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -262,8 +262,9 @@ void graphedit_operatortypes(void) WM_operatortype_append(GRAPH_OT_click_insert); /* F-Curve Modifiers */ - // XXX temporary? WM_operatortype_append(GRAPH_OT_fmodifier_add); + WM_operatortype_append(GRAPH_OT_fmodifier_copy); + WM_operatortype_append(GRAPH_OT_fmodifier_paste); } /* ************************** registration - keymaps **********************************/ diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c index 4f944d1b855..944a93a713f 100644 --- a/source/blender/editors/space_nla/nla_buttons.c +++ b/source/blender/editors/space_nla/nla_buttons.c @@ -430,6 +430,11 @@ static void nla_panel_modifiers(const bContext *C, Panel *pa) // XXX for now, this will be a operator button which calls a temporary 'add modifier' operator // FIXME: we need to set the only-active property so that this will only add modifiers for the active strip (not all selected) uiDefButO(block, BUT, "NLA_OT_fmodifier_add", WM_OP_INVOKE_REGION_WIN, "Add Modifier", 10, 0, 150, 20, "Adds a new F-Modifier for the active NLA Strip"); + + /* copy/paste (as sub-row)*/ + row= uiLayoutRow(row, 1); + uiItemO(row, "", ICON_COPYDOWN, "NLA_OT_fmodifier_copy"); + uiItemO(row, "", ICON_PASTEDOWN, "NLA_OT_fmodifier_paste"); } /* draw each modifier */ diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c index 543fa1dfed7..bc99ded4db6 100644 --- a/source/blender/editors/space_nla/nla_edit.c +++ b/source/blender/editors/space_nla/nla_edit.c @@ -1633,8 +1633,7 @@ static int nla_fmodifier_add_exec(bContext *C, wmOperator *op) BLI_freelistN(&anim_data); /* set notifier that things have changed */ - // FIXME: this doesn't really do it justice... - WM_event_add_notifier(C, NC_ANIMATION, NULL); + WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_EDIT, NULL); /* done */ return OPERATOR_FINISHED; @@ -1659,4 +1658,125 @@ void NLA_OT_fmodifier_add (wmOperatorType *ot) RNA_def_boolean(ot->srna, "only_active", 0, "Only Active", "Only add F-Modifier of the specified type to the active strip."); } +/* ******************** Copy F-Modifiers Operator *********************** */ + +static int nla_fmodifier_copy_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter, ok=0; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* clear buffer first */ + free_fmodifiers_copybuf(); + + /* get a list of the editable tracks being shown in the NLA */ + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT); + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + /* for each NLA-Track, add the specified modifier to all selected strips */ + for (ale= anim_data.first; ale; ale= ale->next) { + NlaTrack *nlt= (NlaTrack *)ale->data; + NlaStrip *strip; + + for (strip= nlt->strips.first; strip; strip=strip->next) { + /* only add F-Modifier if on active strip? */ + if ((strip->flag & NLASTRIP_FLAG_ACTIVE)==0) + continue; + + // TODO: when 'active' vs 'all' boolean is added, change last param! + ok += ANIM_fmodifiers_copy_to_buf(&strip->modifiers, 0); + } + } + + /* successful or not? */ + if (ok == 0) { + BKE_report(op->reports, RPT_ERROR, "No F-Modifiers available to be copied"); + return OPERATOR_CANCELLED; + } + else + return OPERATOR_FINISHED; +} + +void NLA_OT_fmodifier_copy (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Copy F-Modifiers"; + ot->idname= "NLA_OT_fmodifier_copy"; + ot->description= "Copy the F-Modifier(s) of the active NLA-Strip."; + + /* api callbacks */ + ot->exec= nla_fmodifier_copy_exec; + ot->poll= nlaop_poll_tweakmode_off; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* id-props */ + //ot->prop = RNA_def_boolean(ot->srna, "all", 1, "All F-Modifiers", "Copy all the F-Modifiers, instead of just the active one"); +} + +/* ******************** Paste F-Modifiers Operator *********************** */ + +static int nla_fmodifier_paste_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter, ok=0; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* get a list of the editable tracks being shown in the NLA */ + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_SEL | ANIMFILTER_FOREDIT); + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + /* for each NLA-Track, add the specified modifier to all selected strips */ + for (ale= anim_data.first; ale; ale= ale->next) { + NlaTrack *nlt= (NlaTrack *)ale->data; + NlaStrip *strip; + + for (strip= nlt->strips.first; strip; strip=strip->next) { + // TODO: do we want to replace existing modifiers? add user pref for that! + ok += ANIM_fmodifiers_paste_from_buf(&strip->modifiers, 0); + } + } + + /* clean up */ + BLI_freelistN(&anim_data); + + /* successful or not? */ + if (ok) { + /* set notifier that things have changed */ + /* set notifier that things have changed */ + WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_EDIT, NULL); + return OPERATOR_FINISHED; + } + else { + BKE_report(op->reports, RPT_ERROR, "No F-Modifiers to paste"); + return OPERATOR_CANCELLED; + } +} + +void NLA_OT_fmodifier_paste (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Paste F-Modifiers"; + ot->idname= "NLA_OT_fmodifier_paste"; + ot->description= "Add copied F-Modifiers to the selected NLA-Strips"; + + /* api callbacks */ + ot->exec= nla_fmodifier_paste_exec; + ot->poll= nlaop_poll_tweakmode_off; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + /* *********************************************** */ diff --git a/source/blender/editors/space_nla/nla_intern.h b/source/blender/editors/space_nla/nla_intern.h index 1af2d2a1635..18ef91220f9 100644 --- a/source/blender/editors/space_nla/nla_intern.h +++ b/source/blender/editors/space_nla/nla_intern.h @@ -111,6 +111,8 @@ void NLA_OT_clear_scale(wmOperatorType *ot); void NLA_OT_snap(wmOperatorType *ot); void NLA_OT_fmodifier_add(wmOperatorType *ot); +void NLA_OT_fmodifier_copy(wmOperatorType *ot); +void NLA_OT_fmodifier_paste(wmOperatorType *ot); /* **************************************** */ diff --git a/source/blender/editors/space_nla/nla_ops.c b/source/blender/editors/space_nla/nla_ops.c index 10ff10f46fd..249256a47f9 100644 --- a/source/blender/editors/space_nla/nla_ops.c +++ b/source/blender/editors/space_nla/nla_ops.c @@ -165,6 +165,8 @@ void nla_operatortypes(void) WM_operatortype_append(NLA_OT_snap); WM_operatortype_append(NLA_OT_fmodifier_add); + WM_operatortype_append(NLA_OT_fmodifier_copy); + WM_operatortype_append(NLA_OT_fmodifier_paste); } /* ************************** registration - keymaps **********************************/ diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h index 8e46cfefba5..44727218f4f 100644 --- a/source/blender/makesdna/DNA_anim_types.h +++ b/source/blender/makesdna/DNA_anim_types.h @@ -73,6 +73,7 @@ typedef enum eFModifier_Types { FMODIFIER_TYPE_FILTER, /* unimplemented - for applying: fft, high/low pass filters, etc. */ FMODIFIER_TYPE_PYTHON, FMODIFIER_TYPE_LIMITS, + FMODIFIER_TYPE_STEPPED, /* NOTE: all new modifiers must be added above this line */ FMODIFIER_NUM_TYPES @@ -211,6 +212,7 @@ typedef enum eFMod_Limit_Flags { FCM_LIMIT_YMAX = (1<<3), } eFMod_Limit_Flags; + /* noise modifier data */ typedef struct FMod_Noise { float size; @@ -230,6 +232,13 @@ typedef enum eFMod_Noise_Modifications { FCM_NOISE_MODIF_MULTIPLY, /* Multiply the curve by noise */ } eFMod_Noise_Modifications; + +/* stepped modifier data */ +typedef struct FMod_Stepped { + float step_size; /* Number of frames each interpolated value should be held */ + float start; /* Reference frame number that stepping starts from */ +} FMod_Stepped; + /* Drivers -------------------------------------- */ /* Driver Target (dtar) diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index e50b1b7ad58..2671f480d3b 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -217,6 +217,7 @@ extern StructRNA RNA_FModifierGenerator; extern StructRNA RNA_FModifierLimits; extern StructRNA RNA_FModifierNoise; extern StructRNA RNA_FModifierPython; +extern StructRNA RNA_FModifierStepped; extern StructRNA RNA_FollowPathConstraint; extern StructRNA RNA_Function; extern StructRNA RNA_GameBooleanProperty; diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index d5d28ac83ae..3ab4673212d 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -51,6 +51,7 @@ EnumPropertyItem fmodifier_type_items[] = { {FMODIFIER_TYPE_FILTER, "FILTER", 0, "Filter", ""}, {FMODIFIER_TYPE_PYTHON, "PYTHON", 0, "Python", ""}, {FMODIFIER_TYPE_LIMITS, "LIMITS", 0, "Limits", ""}, + {FMODIFIER_TYPE_STEPPED, "STEPPED", 0, "Stepped Interpolation", ""}, {0, NULL, 0, NULL, NULL}}; EnumPropertyItem beztriple_keyframe_type_items[] = { @@ -84,6 +85,8 @@ static StructRNA *rna_FModifierType_refine(struct PointerRNA *ptr) return &RNA_FModifierPython; case FMODIFIER_TYPE_LIMITS: return &RNA_FModifierLimits; + case FMODIFIER_TYPE_STEPPED: + return &RNA_FModifierStepped; default: return &RNA_UnknownType; } @@ -712,9 +715,31 @@ static void rna_def_fmodifier_noise(BlenderRNA *brna) } +/* --------- */ + +static void rna_def_fmodifier_stepped(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna= RNA_def_struct(brna, "FModifierStepped", "FModifier"); + RNA_def_struct_ui_text(srna, "Stepped Interpolation F-Modifier", "Holds each interpolated value from the F-Curve for several frames without changing the timing"); + RNA_def_struct_sdna_from(srna, "FMod_Stepped", "data"); + + /* properties */ + prop= RNA_def_property(srna, "step_size", PROP_FLOAT, PROP_NONE); + RNA_def_property_ui_text(prop, "Step Size", "Number of frames to hold each value"); + RNA_def_property_update(prop, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL); + + prop= RNA_def_property(srna, "start_offset", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "start"); + RNA_def_property_ui_text(prop, "Start Offset", "Reference number of frames before frames get held. Use to get hold for '1-3' vs '5-7' holding patterns"); + RNA_def_property_update(prop, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL); +} /* --------- */ + static void rna_def_fmodifier(BlenderRNA *brna) { StructRNA *srna; @@ -1209,6 +1234,7 @@ void RNA_def_fcurve(BlenderRNA *brna) rna_def_fmodifier_python(brna); rna_def_fmodifier_limits(brna); rna_def_fmodifier_noise(brna); + rna_def_fmodifier_stepped(brna); } diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index ae310a7f59d..e5b5e0db1b4 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -217,6 +217,7 @@ extern wchar_t *copybufinfo; // XXX copy/paste buffer stuff... extern void free_anim_copybuf(); extern void free_anim_drivers_copybuf(); +extern void free_fmodifiers_copybuf(); extern void free_posebuf(); /* called in creator.c even... tsk, split this! */ @@ -272,6 +273,7 @@ void WM_exit(bContext *C) // free_matcopybuf(); free_anim_copybuf(); free_anim_drivers_copybuf(); + free_fmodifiers_copybuf(); free_posebuf(); // free_vertexpaint(); // free_imagepaint();