diff options
author | Campbell Barton <ideasman42@gmail.com> | 2010-12-09 14:49:38 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2010-12-09 14:49:38 +0300 |
commit | 9f4b5d49fcc90c1ac41d3c969a5cfd3d75fc432d (patch) | |
tree | 31cb82ad964424cbcbb3e05cc04afb3728cf7220 /source/blender/editors/animation | |
parent | c6b3d4ff1417cf0c87d8fc79552ae01a27b1a15a (diff) |
Problem with FCurve pasting reported by Rob Garlington.
- Pasting from 1 fcurve to any other fcurve now works (skip index and rna path checking).
- Pasting multiple fcurves between bones now works.
- If path checking fails, pasting matches indices so Scale XYZ can be pasted into Location XYZ for eg.
Diffstat (limited to 'source/blender/editors/animation')
-rw-r--r-- | source/blender/editors/animation/keyframes_general.c | 217 |
1 files changed, 167 insertions, 50 deletions
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c index 68e38d04620..3672b3901e4 100644 --- a/source/blender/editors/animation/keyframes_general.c +++ b/source/blender/editors/animation/keyframes_general.c @@ -42,6 +42,11 @@ #include "BKE_fcurve.h" #include "BKE_utildefines.h" +#include "BKE_report.h" +#include "BKE_library.h" +#include "BKE_global.h" + +#include "RNA_access.h" #include "ED_anim_api.h" #include "ED_keyframing.h" @@ -453,6 +458,8 @@ typedef struct tAnimCopybufItem { int totvert; /* number of keyframes stored for this channel */ BezTriple *bezt; /* keyframes in buffer */ + + short id_type; /* Result of GS(id->name)*/ } tAnimCopybufItem; @@ -510,6 +517,7 @@ short copy_animedit_keys (bAnimContext *UNUSED(ac), ListBase *anim_data) /* init copybuf item info */ aci= MEM_callocN(sizeof(tAnimCopybufItem), "AnimCopybufItem"); aci->id= ale->id; + aci->id_type= GS(ale->id->name); aci->grp= fcu->grp; aci->rna_path= MEM_dupallocN(fcu->rna_path); aci->array_index= fcu->array_index; @@ -550,74 +558,183 @@ short copy_animedit_keys (bAnimContext *UNUSED(ac), ListBase *anim_data) return 0; } +static tAnimCopybufItem *pastebuf_match_path_full(FCurve *fcu, const short from_single, const short to_simple) { + tAnimCopybufItem *aci; + + for (aci= animcopybuf.first; aci; aci= aci->next) { + /* check that paths exist */ + if (to_simple || (aci->rna_path && fcu->rna_path)) { + if (to_simple || (strcmp(aci->rna_path, fcu->rna_path) == 0)) { + if ((from_single) || (aci->array_index == fcu->array_index)) { + break; + } + } + } + } + + return aci; +} + +static tAnimCopybufItem *pastebuf_match_path_property(FCurve *fcu, const short from_single, const short UNUSED(to_simple)) +{ + tAnimCopybufItem *aci; + + for (aci= animcopybuf.first; aci; aci= aci->next) { + /* check that paths exist */ + if (aci->rna_path && fcu->rna_path) { + + /* find the property of the fcurve and compare against the end of the tAnimCopybufItem + * more involves since it needs to to path lookups. + * This is not 100% reliable since the user could be editing the curves on a path that wont + * resolve, or a bone could be renamed after copying for eg. but in normal copy & paste + * this should work out ok. */ + if(BLI_findindex(which_libbase(G.main, aci->id_type), aci->id) == -1) { + /* pedantic but the ID could have been removed, and beats crashing! */ + printf("paste_animedit_keys: error ID has been removed!\n"); + } + else { + PointerRNA id_ptr, rptr; + PropertyRNA *prop; + + RNA_id_pointer_create(aci->id, &id_ptr); + RNA_path_resolve(&id_ptr, aci->rna_path, &rptr, &prop); + + if(prop) { + const char *identifier= RNA_property_identifier(prop); + int len_id = strlen(identifier); + int len_path = strlen(fcu->rna_path); + if(len_id <= len_path) { + /* note, paths which end with "] will fail with this test - Animated ID Props */ + if(strcmp(identifier, fcu->rna_path + (len_path-len_id))==0) { + if ((from_single) || (aci->array_index == fcu->array_index)) { + break; + } + } + } + } + else { + printf("paste_animedit_keys: failed to resolve path id:%s, '%s'!\n", aci->id->name, aci->rna_path); + } + } + } + } + + return aci; +} + +static tAnimCopybufItem *pastebuf_match_index_only(FCurve *fcu, const short from_single, const short UNUSED(to_simple)) +{ + tAnimCopybufItem *aci; + + for (aci= animcopybuf.first; aci; aci= aci->next) { + /* check that paths exist */ + if ((from_single) || (aci->array_index == fcu->array_index)) { + break; + } + } + + return aci; +} + +static void paste_animedit_keys_fcurve(FCurve *fcu, tAnimCopybufItem *aci, float offset) +{ + BezTriple *bezt; + int i; + + /* 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 */ + bezt->vec[0][0] += offset; + bezt->vec[1][0] += offset; + bezt->vec[2][0] += offset; + + /* insert the keyframe + * NOTE: no special flags here for now + */ + insert_bezt_fcurve(fcu, bezt, 0); + + /* un-apply offset from src beztriple after copying */ + bezt->vec[0][0] -= offset; + bezt->vec[1][0] -= offset; + bezt->vec[2][0] -= offset; + } + + /* recalculate F-Curve's handles? */ + calchandles_fcurve(fcu); +} + /* This function pastes data from the keyframes copy/paste buffer */ short paste_animedit_keys (bAnimContext *ac, ListBase *anim_data) { bAnimListElem *ale; const Scene *scene= (ac->scene); const float offset = (float)(CFRA - animcopy_firstframe); - short no_name= 0; + 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)) { - //error("No data in buffer to paste"); + BKE_report(ac->reports, RPT_WARNING, "No data in buffer to paste"); return -1; } - /* check if single channel in buffer (disregard names if so) */ - if (animcopybuf.first == animcopybuf.last) - no_name= 1; - - /* from selected channels */ - for (ale= anim_data->first; ale; ale= ale->next) { - FCurve *fcu = (FCurve *)ale->data; /* destination F-Curve */ - tAnimCopybufItem *aci= NULL; - BezTriple *bezt; - int i; - - /* find buffer item to paste from - * - if names don't matter (i.e. only 1 channel in buffer), don't check id/group - * - if names do matter, only check if id-type is ok for now (group check is not that important) - * - most importantly, rna-paths should match (array indices are unimportant for now) - */ - // TODO: the matching algorithm here is pathetic! - for (aci= animcopybuf.first; aci; aci= aci->next) { - /* check that paths exist */ - if (aci->rna_path && fcu->rna_path) { - // FIXME: this breaks for bone names! - if (strcmp(aci->rna_path, fcu->rna_path) == 0) { - /* should be a match unless there's more than one of these */ - if ((no_name) || (aci->array_index == fcu->array_index)) - break; - } - } - } - - - /* copy the relevant data from the matching buffer curve */ - if (aci) { - /* 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 */ - bezt->vec[0][0] += offset; - bezt->vec[1][0] += offset; - bezt->vec[2][0] += offset; + + if(from_single && to_simple) { + /* 1:1 match, no tricky checking, just paste */ + FCurve *fcu; + tAnimCopybufItem *aci; + + ale= anim_data->first; + fcu= (FCurve *)ale->data; /* destination F-Curve */ + aci= animcopybuf.first; + + paste_animedit_keys_fcurve(fcu, aci, offset); + } + else { + /* from selected channels */ + for(pass= 0; pass < 3; pass++) { + int totmatch= 0; + for (ale= anim_data->first; ale; ale= ale->next) { - /* insert the keyframe - * NOTE: no special flags here for now + /* find buffer item to paste from + * - if names don't matter (i.e. only 1 channel in buffer), don't check id/group + * - if names do matter, only check if id-type is ok for now (group check is not that important) + * - most importantly, rna-paths should match (array indices are unimportant for now) */ - insert_bezt_fcurve(fcu, bezt, 0); + FCurve *fcu = (FCurve *)ale->data; /* destination F-Curve */ + tAnimCopybufItem *aci= NULL; - /* un-apply offset from src beztriple after copying */ - bezt->vec[0][0] -= offset; - bezt->vec[1][0] -= offset; - bezt->vec[2][0] -= offset; + switch(pass) { + case 0: + /* most strict, must be exact path match data_path & index */ + aci= pastebuf_match_path_full(fcu, from_single, to_simple); + break; + + case 1: + /* less strict, just compare property names */ + aci= pastebuf_match_path_property(fcu, from_single, to_simple); + break; + + case 2: + /* Comparing properties gave no results, so just do index comparisons */ + aci= pastebuf_match_index_only(fcu, from_single, to_simple); + break; + } + + /* copy the relevant data from the matching buffer curve */ + if (aci) { + totmatch++; + paste_animedit_keys_fcurve(fcu, aci, offset); + } } - /* recalculate F-Curve's handles? */ - calchandles_fcurve(fcu); + /* dont continue if some fcurves were pasted */ + if(totmatch) { + break; + } } } - + return 0; } |