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.
This commit is contained in:
2010-12-09 11:49:38 +00:00
parent c6b3d4ff14
commit 9f4b5d49fc
3 changed files with 176 additions and 52 deletions

View File

@@ -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;
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) {
/* 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)
*/
FCurve *fcu = (FCurve *)ale->data; /* destination F-Curve */
tAnimCopybufItem *aci= NULL;
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;
/* 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;
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);
}
}
}
/* 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;
/* 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);
/* dont continue if some fcurves were pasted */
if(totmatch) {
break;
}
}
}
return 0;
}

View File

@@ -358,6 +358,10 @@ static int actkeys_paste_exec(bContext *C, wmOperator *op)
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
if(ac.reports==NULL) {
ac.reports= op->reports;
}
/* paste keyframes */
if (ac.datatype == ANIMCONT_GPENCIL) {
// FIXME...

View File

@@ -681,9 +681,12 @@ static int graphkeys_paste_exec(bContext *C, wmOperator *op)
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
if(ac.reports==NULL) {
ac.reports= op->reports;
}
/* paste keyframes */
if (paste_graph_keys(&ac)) {
BKE_report(op->reports, RPT_ERROR, "No keyframes to paste");
return OPERATOR_CANCELLED;
}