diff options
-rw-r--r-- | source/blender/editors/animation/keyframes_general.c | 121 | ||||
-rw-r--r-- | source/blender/editors/include/ED_keyframes_edit.h | 27 | ||||
-rw-r--r-- | source/blender/editors/space_action/action_edit.c | 14 | ||||
-rw-r--r-- | source/blender/editors/space_graph/graph_edit.c | 14 | ||||
-rw-r--r-- | source/blender/makesrna/RNA_enum_types.h | 3 |
5 files changed, 159 insertions, 20 deletions
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c index 3672b3901e4..437f74201e4 100644 --- a/source/blender/editors/animation/keyframes_general.c +++ b/source/blender/editors/animation/keyframes_general.c @@ -117,11 +117,18 @@ void delete_fcurve_keys(FCurve *fcu) } /* Free the array of BezTriples if there are not keyframes */ - if (fcu->totvert == 0) { - if (fcu->bezt) - MEM_freeN(fcu->bezt); - fcu->bezt= NULL; - } + if(fcu->totvert == 0) + clear_fcurve_keys(fcu); +} + + +void clear_fcurve_keys(FCurve *fcu) +{ + if (fcu->bezt) + MEM_freeN(fcu->bezt); + fcu->bezt= NULL; + + fcu->totvert= 0; } /* ---------------- */ @@ -446,6 +453,8 @@ void sample_fcurve (FCurve *fcu) /* globals for copy/paste data (like for other copy/paste buffers) */ ListBase animcopybuf = {NULL, NULL}; static float animcopy_firstframe= 999999999.0f; +static float animcopy_lastframe= -999999999.0f; +static float animcopy_cfra= 0.0; /* datatype for use in copy/paste buffer */ typedef struct tAnimCopybufItem { @@ -488,14 +497,16 @@ void free_anim_copybuf (void) /* restore initial state */ animcopybuf.first= animcopybuf.last= NULL; animcopy_firstframe= 999999999.0f; + animcopy_lastframe= -999999999.0f; } /* ------------------- */ /* This function adds data to the keyframes copy/paste buffer, freeing existing data first */ -short copy_animedit_keys (bAnimContext *UNUSED(ac), ListBase *anim_data) +short copy_animedit_keys (bAnimContext *ac, ListBase *anim_data) { bAnimListElem *ale; + Scene *scene= ac->scene; /* clear buffer first */ free_anim_copybuf(); @@ -545,6 +556,8 @@ short copy_animedit_keys (bAnimContext *UNUSED(ac), ListBase *anim_data) /* check if this is the earliest frame encountered so far */ if (bezt->vec[1][0] < animcopy_firstframe) animcopy_firstframe= bezt->vec[1][0]; + if (bezt->vec[1][0] > animcopy_lastframe) + animcopy_lastframe= bezt->vec[1][0]; } } @@ -553,7 +566,10 @@ short copy_animedit_keys (bAnimContext *UNUSED(ac), ListBase *anim_data) /* check if anything ended up in the buffer */ if (ELEM(NULL, animcopybuf.first, animcopybuf.last)) return -1; - + + /* incase 'relative' paste method is used */ + animcopy_cfra= CFRA; + /* everything went fine */ return 0; } @@ -636,11 +652,58 @@ static tAnimCopybufItem *pastebuf_match_index_only(FCurve *fcu, const short from return aci; } -static void paste_animedit_keys_fcurve(FCurve *fcu, tAnimCopybufItem *aci, float offset) +static void paste_animedit_keys_fcurve(FCurve *fcu, tAnimCopybufItem *aci, float offset, const eKeyMergeMode merge_mode) { BezTriple *bezt; int i; + /* First de-select existing FCuvre */ + for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) { + bezt->f2 &= ~SELECT; + } + + /* mix mode with existing data */ + switch(merge_mode) { + case KEYFRAME_PASTE_MERGE_MIX: + /* do-nothing */ + break; + case KEYFRAME_PASTE_MERGE_OVER: + /* remove all keys */ + clear_fcurve_keys(fcu); + break; + case KEYFRAME_PASTE_MERGE_OVER_RANGE: + case KEYFRAME_PASTE_MERGE_OVER_RANGE_ALL: + { + float f_min; + float f_max; + + if(merge_mode==KEYFRAME_PASTE_MERGE_OVER_RANGE) { + f_min= aci->bezt[0].vec[1][0] + offset; + f_max= aci->bezt[aci->totvert-1].vec[1][0] + offset; + } + else { /* Entire Range */ + f_min= animcopy_firstframe + offset; + f_max= animcopy_lastframe + offset; + } + + /* remove keys in range */ + + if(f_min < f_max) { + /* select verts in range for removal */ + for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) { + if((f_min < bezt[0].vec[1][0]) && (bezt[0].vec[1][0] < f_max)) { + bezt->f2 |= SELECT; + } + } + + /* remove frames in the range */ + delete_fcurve_keys(fcu); + } + break; + } + } + + /* just start pasting, with the the first keyframe on the current frame, and so on */ for (i=0, bezt=aci->bezt; i < aci->totvert; i++, bezt++) { /* temporarily apply offset to src beztriple while copying */ @@ -663,22 +726,54 @@ static void paste_animedit_keys_fcurve(FCurve *fcu, tAnimCopybufItem *aci, float calchandles_fcurve(fcu); } +EnumPropertyItem keyframe_paste_offset_items[] = { + {KEYFRAME_PASTE_OFFSET_CFRA_START, "START", 0, "Frame Start", "Paste keys starting at current frame"}, + {KEYFRAME_PASTE_OFFSET_CFRA_END, "END", 0, "Frame End", "Paste keys ending at current frame"}, + {KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE, "RELATIVE", 0, "Frame Relative", "Paste keys relative to the current frame when copying"}, + {KEYFRAME_PASTE_OFFSET_NONE, "NONE", 0, "No Offset", "Paste keys from original time"}, + {0, NULL, 0, NULL, NULL}}; + +EnumPropertyItem keyframe_paste_merge_items[] = { + {KEYFRAME_PASTE_MERGE_MIX, "MIX", 0, "Mix", "Overlay existing with new keys"}, + {KEYFRAME_PASTE_MERGE_OVER, "OVER_ALL", 0, "Overwrite All", "Replace all keys"}, + {KEYFRAME_PASTE_MERGE_OVER_RANGE, "OVER_RANGE", 0, "Overwrite Range", "Overwrite keys in pasted range"}, + {KEYFRAME_PASTE_MERGE_OVER_RANGE_ALL, "OVER_RANGE_ALL", 0, "Overwrite Entire Range", "Overwrite keys in pasted range, using the range of all copied keys."}, + {0, NULL, 0, NULL, NULL}}; + + /* This function pastes data from the keyframes copy/paste buffer */ -short paste_animedit_keys (bAnimContext *ac, ListBase *anim_data) +short paste_animedit_keys (bAnimContext *ac, ListBase *anim_data, + const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode) { bAnimListElem *ale; const Scene *scene= (ac->scene); - const float offset = (float)(CFRA - animcopy_firstframe); + float offset; const short from_single= (animcopybuf.first == animcopybuf.last); const short to_simple= (anim_data->first == anim_data->last); int pass; - + /* check if buffer is empty */ if (ELEM(NULL, animcopybuf.first, animcopybuf.last)) { BKE_report(ac->reports, RPT_WARNING, "No data in buffer to paste"); return -1; } + /* mathods of offset */ + switch(offset_mode) { + case KEYFRAME_PASTE_OFFSET_CFRA_START: + offset= (float)(CFRA - animcopy_firstframe); + break; + case KEYFRAME_PASTE_OFFSET_CFRA_END: + offset= (float)(CFRA - animcopy_lastframe); + break; + case KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE: + offset= (float)(CFRA - animcopy_cfra); + break; + case KEYFRAME_PASTE_OFFSET_NONE: + offset= 0.0f; + break; + } + if(from_single && to_simple) { /* 1:1 match, no tricky checking, just paste */ FCurve *fcu; @@ -688,7 +783,7 @@ short paste_animedit_keys (bAnimContext *ac, ListBase *anim_data) fcu= (FCurve *)ale->data; /* destination F-Curve */ aci= animcopybuf.first; - paste_animedit_keys_fcurve(fcu, aci, offset); + paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode); } else { /* from selected channels */ @@ -724,7 +819,7 @@ short paste_animedit_keys (bAnimContext *ac, ListBase *anim_data) /* copy the relevant data from the matching buffer curve */ if (aci) { totmatch++; - paste_animedit_keys_fcurve(fcu, aci, offset); + paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode); } } diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h index 5ea9287a71e..2a7ce9b540b 100644 --- a/source/blender/editors/include/ED_keyframes_edit.h +++ b/source/blender/editors/include/ED_keyframes_edit.h @@ -152,6 +152,29 @@ typedef struct KeyframeEditCD_Remap { float newMin, newMax; /* new range */ } KeyframeEditCD_Remap; +/* Paste options */ +typedef enum eKeyPasteOffset { + /* paste keys starting at current frame */ + KEYFRAME_PASTE_OFFSET_CFRA_START, + /* paste keys ending at current frame */ + KEYFRAME_PASTE_OFFSET_CFRA_END, + /* paste keys relative to the current frame when copying */ + KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE, + /* paste keys from original time */ + KEYFRAME_PASTE_OFFSET_NONE +} eKeyPasteOffset; + +typedef enum eKeyMergeMode { + /* overlay existing with new keys */ + KEYFRAME_PASTE_MERGE_MIX, + /* replace entire fcurve */ + KEYFRAME_PASTE_MERGE_OVER, + /* overwrite keys in pasted range */ + KEYFRAME_PASTE_MERGE_OVER_RANGE, + /* overwrite keys in pasted range (use all keyframe start & end for range) */ + KEYFRAME_PASTE_MERGE_OVER_RANGE_ALL +} eKeyMergeMode; + /* ---------------- Looping API --------------------- */ /* functions for looping over keyframes */ @@ -212,6 +235,7 @@ void bezt_remap_times(KeyframeEditData *ked, struct BezTriple *bezt); void delete_fcurve_key(struct FCurve *fcu, int index, short do_recalc); void delete_fcurve_keys(struct FCurve *fcu); +void clear_fcurve_keys(struct FCurve *fcu); void duplicate_fcurve_keys(struct FCurve *fcu); void clean_fcurve(struct FCurve *fcu, float thresh); @@ -222,7 +246,8 @@ void sample_fcurve(struct FCurve *fcu); void free_anim_copybuf(void); short copy_animedit_keys(struct bAnimContext *ac, ListBase *anim_data); -short paste_animedit_keys(struct bAnimContext *ac, ListBase *anim_data); +short paste_animedit_keys(struct bAnimContext *ac, ListBase *anim_data, + const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode); /* ************************************************ */ diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index 59e4cfcf68f..afda04d1c45 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -291,7 +291,8 @@ static short copy_action_keys (bAnimContext *ac) } -static short paste_action_keys (bAnimContext *ac) +static short paste_action_keys (bAnimContext *ac, + const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode) { ListBase anim_data = {NULL, NULL}; int filter, ok=0; @@ -301,7 +302,7 @@ static short paste_action_keys (bAnimContext *ac) ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* paste keyframes */ - ok= paste_animedit_keys(ac, &anim_data); + ok= paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode); /* clean up */ BLI_freelistN(&anim_data); @@ -341,11 +342,15 @@ void ACTION_OT_copy (wmOperatorType *ot) ot->description= "Copy selected keyframes to the copy/paste buffer"; /* api callbacks */ +// ot->invoke= WM_operator_props_popup; // better wait for graph redo panel ot->exec= actkeys_copy_exec; ot->poll= ED_operator_action_active; /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_enum(ot->srna, "offset", keyframe_paste_offset_items, KEYFRAME_PASTE_OFFSET_CFRA_START, "Offset", "Paste time offset of keys"); + RNA_def_enum(ot->srna, "merge", keyframe_paste_merge_items, KEYFRAME_PASTE_MERGE_MIX, "Type", "Method of merking pasted keys and existing"); } @@ -353,6 +358,9 @@ void ACTION_OT_copy (wmOperatorType *ot) static int actkeys_paste_exec(bContext *C, wmOperator *op) { bAnimContext ac; + + const eKeyPasteOffset offset_mode= RNA_enum_get(op->ptr, "offset"); + const eKeyMergeMode merge_mode= RNA_enum_get(op->ptr, "merge"); /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) @@ -367,7 +375,7 @@ static int actkeys_paste_exec(bContext *C, wmOperator *op) // FIXME... } else { - if (paste_action_keys(&ac)) { + if (paste_action_keys(&ac, offset_mode, merge_mode)) { BKE_report(op->reports, RPT_ERROR, "No keyframes to paste"); return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 798e1b12242..1e6443bba32 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -618,7 +618,8 @@ static short copy_graph_keys (bAnimContext *ac) return ok; } -static short paste_graph_keys (bAnimContext *ac) +static short paste_graph_keys (bAnimContext *ac, + const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode) { ListBase anim_data = {NULL, NULL}; int filter, ok=0; @@ -628,7 +629,7 @@ static short paste_graph_keys (bAnimContext *ac) ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* paste keyframes */ - ok= paste_animedit_keys(ac, &anim_data); + ok= paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode); /* clean up */ BLI_freelistN(&anim_data); @@ -676,6 +677,9 @@ void GRAPH_OT_copy (wmOperatorType *ot) static int graphkeys_paste_exec(bContext *C, wmOperator *op) { bAnimContext ac; + + const eKeyPasteOffset offset_mode= RNA_enum_get(op->ptr, "offset"); + const eKeyMergeMode merge_mode= RNA_enum_get(op->ptr, "merge"); /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) @@ -686,7 +690,7 @@ static int graphkeys_paste_exec(bContext *C, wmOperator *op) } /* paste keyframes */ - if (paste_graph_keys(&ac)) { + if (paste_graph_keys(&ac, offset_mode, merge_mode)) { return OPERATOR_CANCELLED; } @@ -707,11 +711,15 @@ void GRAPH_OT_paste (wmOperatorType *ot) ot->description= "Paste keyframes from copy/paste buffer for the selected channels, starting on the current frame"; /* api callbacks */ +// ot->invoke= WM_operator_props_popup; // better wait for graph redo panel ot->exec= graphkeys_paste_exec; ot->poll= graphop_editable_keyframes_poll; /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_enum(ot->srna, "offset", keyframe_paste_offset_items, KEYFRAME_PASTE_OFFSET_CFRA_START, "Offset", "Paste time offset of keys"); + RNA_def_enum(ot->srna, "merge", keyframe_paste_merge_items, KEYFRAME_PASTE_MERGE_MIX, "Type", "Method of merking pasted keys and existing"); } /* ******************** Duplicate Keyframes Operator ************************* */ diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index 9b6b12ef727..8e5463d5990 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -57,6 +57,9 @@ extern EnumPropertyItem beztriple_interpolation_mode_items[]; extern EnumPropertyItem keyingset_path_grouping_items[]; +extern EnumPropertyItem keyframe_paste_offset_items[]; +extern EnumPropertyItem keyframe_paste_merge_items[]; + extern EnumPropertyItem fmodifier_type_items[]; extern EnumPropertyItem nla_mode_extend_items[]; |