Blender V2.61 - r43446

keyframes_general.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2008 Blender Foundation
00019  * All rights reserved.
00020  *
00021  * Contributor(s): Joshua Leung
00022  *
00023  * ***** END GPL LICENSE BLOCK *****
00024  */
00025 
00031 #include <stdlib.h>
00032 #include <string.h>
00033 #include <math.h>
00034 #include <float.h>
00035 
00036 #include "MEM_guardedalloc.h"
00037 
00038 #include "BLI_blenlib.h"
00039 #include "BLI_math.h"
00040 #include "BLI_utildefines.h"
00041 
00042 #include "DNA_anim_types.h"
00043 #include "DNA_object_types.h"
00044 #include "DNA_scene_types.h"
00045 
00046 
00047 #include "BKE_fcurve.h"
00048 #include "BKE_utildefines.h"
00049 #include "BKE_report.h"
00050 #include "BKE_library.h"
00051 #include "BKE_global.h"
00052 
00053 #include "RNA_access.h"
00054 #include "RNA_enum_types.h"
00055 
00056 #include "ED_anim_api.h"
00057 #include "ED_keyframing.h"
00058 #include "ED_keyframes_edit.h"
00059 
00060 /* This file contains code for various keyframe-editing tools which are 'destructive'
00061  * (i.e. they will modify the order of the keyframes, and change the size of the array).
00062  * While some of these tools may eventually be moved out into blenkernel, for now, it is
00063  * fine to have these calls here.
00064  * 
00065  * There are also a few tools here which cannot be easily coded for in the other system (yet).
00066  * These may also be moved around at some point, but for now, they are best added here.
00067  *
00068  * - Joshua Leung, Dec 2008
00069  */
00070  
00071 /* **************************************************** */
00072 
00073 /* Only delete the nominated keyframe from provided F-Curve. 
00074  * Not recommended to be used many times successively. For that
00075  * there is delete_fcurve_keys(). 
00076  */
00077 void delete_fcurve_key(FCurve *fcu, int index, short do_recalc)
00078 {
00079     /* sanity check */
00080     if (fcu == NULL) 
00081         return;
00082         
00083     /* verify the index:
00084      *  1) cannot be greater than the number of available keyframes
00085      *  2) negative indices are for specifying a value from the end of the array
00086      */
00087     if (abs(index) >= fcu->totvert)
00088         return;
00089     else if (index < 0)
00090         index += fcu->totvert;
00091     
00092     /* Delete this keyframe */
00093     memmove(&fcu->bezt[index], &fcu->bezt[index+1], sizeof(BezTriple)*(fcu->totvert-index-1));
00094     fcu->totvert--;
00095 
00096     if (fcu->totvert == 0) {
00097         if (fcu->bezt)
00098             MEM_freeN(fcu->bezt);
00099         fcu->bezt= NULL;
00100     }
00101     
00102     /* recalc handles - only if it won't cause problems */
00103     if (do_recalc)
00104         calchandles_fcurve(fcu);
00105 }
00106 
00107 /* Delete selected keyframes in given F-Curve */
00108 void delete_fcurve_keys(FCurve *fcu)
00109 {
00110     int i;
00111     
00112     if (fcu->bezt==NULL) /* ignore baked curves */
00113         return;
00114 
00115     /* Delete selected BezTriples */
00116     for (i=0; i < fcu->totvert; i++) {
00117         if (fcu->bezt[i].f2 & SELECT) {
00118             memmove(&fcu->bezt[i], &fcu->bezt[i+1], sizeof(BezTriple)*(fcu->totvert-i-1));
00119             fcu->totvert--;
00120             i--;
00121         }
00122     }
00123     
00124     /* Free the array of BezTriples if there are not keyframes */
00125     if (fcu->totvert == 0)
00126         clear_fcurve_keys(fcu);
00127 }
00128 
00129 
00130 void clear_fcurve_keys(FCurve *fcu)
00131 {
00132     if (fcu->bezt)
00133         MEM_freeN(fcu->bezt);
00134     fcu->bezt= NULL;
00135 
00136     fcu->totvert= 0;
00137 }
00138 
00139 /* ---------------- */
00140 
00141 /* duplicate selected keyframes for the given F-Curve */
00142 void duplicate_fcurve_keys(FCurve *fcu)
00143 {
00144     BezTriple *newbezt;
00145     int i;
00146     
00147     /* this can only work when there is an F-Curve, and also when there are some BezTriples */
00148     if ELEM(NULL, fcu, fcu->bezt)
00149         return;
00150     
00151     for (i=0; i < fcu->totvert; i++) {
00152         /* If a key is selected */
00153         if (fcu->bezt[i].f2 & SELECT) {
00154             /* Expand the list */
00155             newbezt = MEM_callocN(sizeof(BezTriple) * (fcu->totvert+1), "beztriple");
00156             
00157             memcpy(newbezt, fcu->bezt, sizeof(BezTriple) * (i+1));
00158             memcpy(newbezt+i+1, fcu->bezt+i, sizeof(BezTriple));
00159             memcpy(newbezt+i+2, fcu->bezt+i+1, sizeof (BezTriple) *(fcu->totvert-(i+1)));
00160             fcu->totvert++;
00161             
00162             /* reassign pointers... (free old, and add new) */
00163             MEM_freeN(fcu->bezt);
00164             fcu->bezt=newbezt;
00165             
00166             /* Unselect the current key */
00167             BEZ_DESEL(&fcu->bezt[i]);
00168             i++;
00169             
00170             /* Select the copied key */
00171             BEZ_SEL(&fcu->bezt[i]);
00172         }
00173     }
00174 }
00175 
00176 /* **************************************************** */
00177 /* Various Tools */
00178 
00179 /* Basic F-Curve 'cleanup' function that removes 'double points' and unnecessary keyframes on linear-segments only */
00180 void clean_fcurve(FCurve *fcu, float thresh)
00181 {
00182     BezTriple *old_bezts, *bezt, *beztn;
00183     BezTriple *lastb;
00184     int totCount, i;
00185     
00186     /* check if any points  */
00187     if ((fcu == NULL) || (fcu->totvert <= 1)) 
00188         return;
00189     
00190     /* make a copy of the old BezTriples, and clear IPO curve */
00191     old_bezts = fcu->bezt;
00192     totCount = fcu->totvert;    
00193     fcu->bezt = NULL;
00194     fcu->totvert = 0;
00195     
00196     /* now insert first keyframe, as it should be ok */
00197     bezt = old_bezts;
00198     insert_vert_fcurve(fcu, bezt->vec[1][0], bezt->vec[1][1], 0);
00199     
00200     /* Loop through BezTriples, comparing them. Skip any that do 
00201      * not fit the criteria for "ok" points.
00202      */
00203     for (i=1; i<totCount; i++) {    
00204         float prev[2], cur[2], next[2];
00205         
00206         /* get BezTriples and their values */
00207         if (i < (totCount - 1)) {
00208             beztn = (old_bezts + (i+1));
00209             next[0]= beztn->vec[1][0]; next[1]= beztn->vec[1][1];
00210         }
00211         else {
00212             beztn = NULL;
00213             next[0] = next[1] = 0.0f;
00214         }
00215         lastb= (fcu->bezt + (fcu->totvert - 1));
00216         bezt= (old_bezts + i);
00217         
00218         /* get references for quicker access */
00219         prev[0] = lastb->vec[1][0]; prev[1] = lastb->vec[1][1];
00220         cur[0] = bezt->vec[1][0]; cur[1] = bezt->vec[1][1];
00221         
00222         /* check if current bezt occurs at same time as last ok */
00223         if (IS_EQT(cur[0], prev[0], thresh)) {
00224             /* If there is a next beztriple, and if occurs at the same time, only insert 
00225              * if there is a considerable distance between the points, and also if the 
00226              * current is further away than the next one is to the previous.
00227              */
00228             if (beztn && (IS_EQT(cur[0], next[0], thresh)) && 
00229                 (IS_EQT(next[1], prev[1], thresh)==0)) 
00230             {
00231                 /* only add if current is further away from previous */
00232                 if (cur[1] > next[1]) {
00233                     if (IS_EQT(cur[1], prev[1], thresh) == 0) {
00234                         /* add new keyframe */
00235                         insert_vert_fcurve(fcu, cur[0], cur[1], 0);
00236                     }
00237                 }
00238             }
00239             else {
00240                 /* only add if values are a considerable distance apart */
00241                 if (IS_EQT(cur[1], prev[1], thresh) == 0) {
00242                     /* add new keyframe */
00243                     insert_vert_fcurve(fcu, cur[0], cur[1], 0);
00244                 }
00245             }
00246         }
00247         else {
00248             /* checks required are dependent on whether this is last keyframe or not */
00249             if (beztn) {
00250                 /* does current have same value as previous and next? */
00251                 if (IS_EQT(cur[1], prev[1], thresh) == 0) {
00252                     /* add new keyframe*/
00253                     insert_vert_fcurve(fcu, cur[0], cur[1], 0);
00254                 }
00255                 else if (IS_EQT(cur[1], next[1], thresh) == 0) {
00256                     /* add new keyframe */
00257                     insert_vert_fcurve(fcu, cur[0], cur[1], 0);
00258                 }
00259             }
00260             else {  
00261                 /* add if value doesn't equal that of previous */
00262                 if (IS_EQT(cur[1], prev[1], thresh) == 0) {
00263                     /* add new keyframe */
00264                     insert_vert_fcurve(fcu, cur[0], cur[1], 0);
00265                 }
00266             }
00267         }
00268     }
00269     
00270     /* now free the memory used by the old BezTriples */
00271     if (old_bezts)
00272         MEM_freeN(old_bezts);
00273 }
00274 
00275 /* ---------------- */
00276 
00277 /* temp struct used for smooth_fcurve */
00278 typedef struct tSmooth_Bezt {
00279     float *h1, *h2, *h3;    /* bezt->vec[0,1,2][1] */
00280     float y1, y2, y3;       /* averaged before/new/after y-values */
00281 } tSmooth_Bezt;
00282 
00283 /* Use a weighted moving-means method to reduce intensity of fluctuations */
00284 // TODO: introduce scaling factor for weighting falloff
00285 void smooth_fcurve (FCurve *fcu)
00286 {
00287     BezTriple *bezt;
00288     int i, x, totSel = 0;
00289     
00290     /* first loop through - count how many verts are selected */
00291     bezt= fcu->bezt;
00292     for (i=0; i < fcu->totvert; i++, bezt++) {                      
00293         if (BEZSELECTED(bezt))
00294             totSel++;
00295     }
00296     
00297     /* if any points were selected, allocate tSmooth_Bezt points to work on */
00298     if (totSel >= 3) {
00299         tSmooth_Bezt *tarray, *tsb;
00300         
00301         /* allocate memory in one go */
00302         tsb= tarray= MEM_callocN(totSel*sizeof(tSmooth_Bezt), "tSmooth_Bezt Array");
00303         
00304         /* populate tarray with data of selected points */
00305         bezt= fcu->bezt;
00306         for (i=0, x=0; (i < fcu->totvert) && (x < totSel); i++, bezt++) {
00307             if (BEZSELECTED(bezt)) {
00308                 /* tsb simply needs pointer to vec, and index */
00309                 tsb->h1 = &bezt->vec[0][1];
00310                 tsb->h2 = &bezt->vec[1][1];
00311                 tsb->h3 = &bezt->vec[2][1];
00312                 
00313                 /* advance to the next tsb to populate */
00314                 if (x < totSel-1) 
00315                     tsb++;
00316                 else
00317                     break;
00318             }
00319         }
00320             
00321         /* calculate the new smoothed F-Curve's with weighted averages:
00322          *  - this is done with two passes to avoid progressive corruption errors
00323          *  - uses 5 points for each operation (which stores in the relevant handles)
00324          *  -   previous: w/a ratio = 3:5:2:1:1
00325          *  -   next: w/a ratio = 1:1:2:5:3
00326          */
00327         
00328         /* round 1: calculate smoothing deltas and new values */ 
00329         tsb= tarray;
00330         for (i=0; i < totSel; i++, tsb++) {
00331             /* don't touch end points (otherwise, curves slowly explode, as we don't have enough data there) */
00332             if (ELEM(i, 0, (totSel-1)) == 0) {
00333                 const tSmooth_Bezt *tP1 = tsb - 1;
00334                 const tSmooth_Bezt *tP2 = (i-2 > 0) ? (tsb - 2) : (NULL);
00335                 const tSmooth_Bezt *tN1 = tsb + 1;
00336                 const tSmooth_Bezt *tN2 = (i+2 < totSel) ? (tsb + 2) : (NULL);
00337                 
00338                 const float p1 = *tP1->h2;
00339                 const float p2 = (tP2) ? (*tP2->h2) : (*tP1->h2);
00340                 const float c1 = *tsb->h2;
00341                 const float n1 = *tN1->h2;
00342                 const float n2 = (tN2) ? (*tN2->h2) : (*tN1->h2);
00343                 
00344                 /* calculate previous and next, then new position by averaging these */
00345                 tsb->y1= (3*p2 + 5*p1 + 2*c1 + n1 + n2) / 12;
00346                 tsb->y3= (p2 + p1 + 2*c1 + 5*n1 + 3*n2) / 12;
00347                 
00348                 tsb->y2 = (tsb->y1 + tsb->y3) / 2;
00349             }
00350         }
00351         
00352         /* round 2: apply new values */
00353         tsb= tarray;
00354         for (i=0; i < totSel; i++, tsb++) {
00355             /* don't touch end points, as their values were't touched above */
00356             if (ELEM(i, 0, (totSel-1)) == 0) {
00357                 /* y2 takes the average of the 2 points */
00358                 *tsb->h2 = tsb->y2;
00359                 
00360                 /* handles are weighted between their original values and the averaged values */
00361                 *tsb->h1 = ((*tsb->h1) * 0.7f) + (tsb->y1 * 0.3f); 
00362                 *tsb->h3 = ((*tsb->h3) * 0.7f) + (tsb->y3 * 0.3f);
00363             }
00364         }
00365         
00366         /* free memory required for tarray */
00367         MEM_freeN(tarray);
00368     }
00369     
00370     /* recalculate handles */
00371     calchandles_fcurve(fcu);
00372 }
00373 
00374 /* ---------------- */
00375 
00376 /* little cache for values... */
00377 typedef struct tempFrameValCache {
00378     float frame, val;
00379 } tempFrameValCache;
00380 
00381 
00382 /* Evaluates the curves between each selected keyframe on each frame, and keys the value  */
00383 void sample_fcurve (FCurve *fcu)
00384 {
00385     BezTriple *bezt, *start=NULL, *end=NULL;
00386     tempFrameValCache *value_cache, *fp;
00387     int sfra, range;
00388     int i, n, nIndex;
00389 
00390     if (fcu->bezt==NULL) /* ignore baked */
00391         return;
00392     
00393     /* find selected keyframes... once pair has been found, add keyframes  */
00394     for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) {
00395         /* check if selected, and which end this is */
00396         if (BEZSELECTED(bezt)) {
00397             if (start) {
00398                 /* set end */
00399                 end= bezt;
00400                 
00401                 /* cache values then add keyframes using these values, as adding
00402                  * keyframes while sampling will affect the outcome...
00403                  *  - only start sampling+adding from index=1, so that we don't overwrite original keyframe
00404                  */
00405                 range= (int)( ceil(end->vec[1][0] - start->vec[1][0]) );
00406                 sfra= (int)( floor(start->vec[1][0]) );
00407                 
00408                 if (range) {
00409                     value_cache= MEM_callocN(sizeof(tempFrameValCache)*range, "IcuFrameValCache");
00410                     
00411                     /*  sample values   */
00412                     for (n=1, fp=value_cache; n<range && fp; n++, fp++) {
00413                         fp->frame= (float)(sfra + n);
00414                         fp->val= evaluate_fcurve(fcu, fp->frame);
00415                     }
00416                     
00417                     /*  add keyframes with these, tagging as 'breakdowns'   */
00418                     for (n=1, fp=value_cache; n<range && fp; n++, fp++) {
00419                         nIndex= insert_vert_fcurve(fcu, fp->frame, fp->val, 1);
00420                         BEZKEYTYPE(fcu->bezt + nIndex)= BEZT_KEYTYPE_BREAKDOWN;
00421                     }
00422                     
00423                     /* free temp cache */
00424                     MEM_freeN(value_cache);
00425                     
00426                     /* as we added keyframes, we need to compensate so that bezt is at the right place */
00427                     bezt = fcu->bezt + i + range - 1;
00428                     i += (range - 1);
00429                 }
00430                 
00431                 /* bezt was selected, so it now marks the start of a whole new chain to search */
00432                 start= bezt;
00433                 end= NULL;
00434             }
00435             else {
00436                 /* just set start keyframe */
00437                 start= bezt;
00438                 end= NULL;
00439             }
00440         }
00441     }
00442     
00443     /* recalculate channel's handles? */
00444     calchandles_fcurve(fcu);
00445 }
00446 
00447 /* **************************************************** */
00448 /* Copy/Paste Tools */
00449 /* - The copy/paste buffer currently stores a set of temporary F-Curves containing only the keyframes 
00450  *   that were selected in each of the original F-Curves
00451  * - All pasted frames are offset by the same amount. This is calculated as the difference in the times of
00452  *  the current frame and the 'first keyframe' (i.e. the earliest one in all channels).
00453  * - The earliest frame is calculated per copy operation.
00454  */
00455 
00456 /* globals for copy/paste data (like for other copy/paste buffers) */
00457 static ListBase animcopybuf = {NULL, NULL};
00458 static float animcopy_firstframe= 999999999.0f;
00459 static float animcopy_lastframe= -999999999.0f;
00460 static float animcopy_cfra= 0.0;
00461 
00462 /* datatype for use in copy/paste buffer */
00463 typedef struct tAnimCopybufItem {
00464     struct tAnimCopybufItem *next, *prev;
00465     
00466     ID *id;             /* ID which owns the curve */
00467     bActionGroup *grp;  /* Action Group */
00468     char *rna_path;     /* RNA-Path */
00469     int array_index;    /* array index */
00470     
00471     int totvert;        /* number of keyframes stored for this channel */
00472     BezTriple *bezt;    /* keyframes in buffer */
00473 
00474     short id_type;      /* Result of GS(id->name)*/
00475 } tAnimCopybufItem;
00476 
00477 
00478 /* This function frees any MEM_calloc'ed copy/paste buffer data */
00479 // XXX find some header to put this in!
00480 void free_anim_copybuf (void)
00481 {
00482     tAnimCopybufItem *aci, *acn;
00483     
00484     /* free each buffer element */
00485     for (aci= animcopybuf.first; aci; aci= acn) {
00486         acn= aci->next;
00487         
00488         /* free keyframes */
00489         if (aci->bezt) 
00490             MEM_freeN(aci->bezt);
00491             
00492         /* free RNA-path */
00493         if (aci->rna_path)
00494             MEM_freeN(aci->rna_path);
00495             
00496         /* free ourself */
00497         BLI_freelinkN(&animcopybuf, aci);
00498     }
00499     
00500     /* restore initial state */
00501     animcopybuf.first= animcopybuf.last= NULL;
00502     animcopy_firstframe= 999999999.0f;
00503     animcopy_lastframe= -999999999.0f;
00504 }
00505 
00506 /* ------------------- */
00507 
00508 /* This function adds data to the keyframes copy/paste buffer, freeing existing data first */
00509 short copy_animedit_keys (bAnimContext *ac, ListBase *anim_data)
00510 {   
00511     bAnimListElem *ale;
00512     Scene *scene= ac->scene;
00513     
00514     /* clear buffer first */
00515     free_anim_copybuf();
00516     
00517     /* assume that each of these is an F-Curve */
00518     for (ale= anim_data->first; ale; ale= ale->next) {
00519         FCurve *fcu= (FCurve *)ale->key_data;
00520         tAnimCopybufItem *aci;
00521         BezTriple *bezt, *nbezt, *newbuf;
00522         int i;
00523         
00524         /* firstly, check if F-Curve has any selected keyframes
00525          *  - skip if no selected keyframes found (so no need to create unnecessary copy-buffer data)
00526          *  - this check should also eliminate any problems associated with using sample-data
00527          */
00528         if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, ANIM_editkeyframes_ok(BEZT_OK_SELECTED), NULL) == 0)
00529             continue;
00530         
00531         /* init copybuf item info */
00532         aci= MEM_callocN(sizeof(tAnimCopybufItem), "AnimCopybufItem");
00533         aci->id= ale->id;
00534         aci->id_type= GS(ale->id->name);
00535         aci->grp= fcu->grp;
00536         aci->rna_path= MEM_dupallocN(fcu->rna_path);
00537         aci->array_index= fcu->array_index;
00538         BLI_addtail(&animcopybuf, aci);
00539         
00540         /* add selected keyframes to buffer */
00541         // TODO: currently, we resize array everytime we add a new vert - this works ok as long as it is assumed only a few keys are copied
00542         for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) {
00543             if (BEZSELECTED(bezt)) {
00544                 /* add to buffer */
00545                 newbuf= MEM_callocN(sizeof(BezTriple)*(aci->totvert+1), "copybuf beztriple");
00546                 
00547                 /* assume that since we are just resizing the array, just copy all existing data across */
00548                 if (aci->bezt)
00549                     memcpy(newbuf, aci->bezt, sizeof(BezTriple)*(aci->totvert));
00550                 
00551                 /* copy current beztriple across too */
00552                 nbezt= &newbuf[aci->totvert];
00553                 *nbezt= *bezt;
00554                 
00555                 /* ensure copy buffer is selected so pasted keys are selected */
00556                 BEZ_SEL(nbezt);
00557                 
00558                 /* free old array and set the new */
00559                 if (aci->bezt) MEM_freeN(aci->bezt);
00560                 aci->bezt= newbuf;
00561                 aci->totvert++;
00562                 
00563                 /* check if this is the earliest frame encountered so far */
00564                 if (bezt->vec[1][0] < animcopy_firstframe)
00565                     animcopy_firstframe= bezt->vec[1][0];
00566                 if (bezt->vec[1][0] > animcopy_lastframe)
00567                     animcopy_lastframe= bezt->vec[1][0];
00568             }
00569         }
00570         
00571     }
00572     
00573     /* check if anything ended up in the buffer */
00574     if (ELEM(NULL, animcopybuf.first, animcopybuf.last))
00575         return -1;
00576 
00577     /* incase 'relative' paste method is used */
00578     animcopy_cfra= CFRA;
00579 
00580     /* everything went fine */
00581     return 0;
00582 }
00583 
00584 /* ------------------- */
00585 
00586 /* most strict method: exact matches only */
00587 static tAnimCopybufItem *pastebuf_match_path_full(FCurve *fcu, const short from_single, const short to_simple)
00588 {
00589     tAnimCopybufItem *aci;
00590 
00591     for (aci= animcopybuf.first; aci; aci= aci->next) {
00592         /* check that paths exist */
00593         if (to_simple || (aci->rna_path && fcu->rna_path)) {
00594             if (to_simple || (strcmp(aci->rna_path, fcu->rna_path) == 0)) {
00595                 if ((from_single) || (aci->array_index == fcu->array_index))
00596                     break;
00597             }
00598         }
00599     }
00600 
00601     return aci;
00602 }
00603 
00604 /* medium match strictness: path match only (i.e. ignore ID) */
00605 static tAnimCopybufItem *pastebuf_match_path_property(FCurve *fcu, const short from_single, const short UNUSED(to_simple))
00606 {
00607     tAnimCopybufItem *aci;
00608 
00609     for (aci= animcopybuf.first; aci; aci= aci->next) {
00610         /* check that paths exist */
00611         if (aci->rna_path && fcu->rna_path) {
00612             /* find the property of the fcurve and compare against the end of the tAnimCopybufItem
00613              * more involved since it needs to to path lookups.
00614              * This is not 100% reliable since the user could be editing the curves on a path that wont
00615              * resolve, or a bone could be renamed after copying for eg. but in normal copy & paste
00616              * this should work out ok. 
00617              */
00618             if (BLI_findindex(which_libbase(G.main, aci->id_type), aci->id) == -1) {
00619                 /* pedantic but the ID could have been removed, and beats crashing! */
00620                 printf("paste_animedit_keys: error ID has been removed!\n");
00621             }
00622             else {
00623                 PointerRNA id_ptr, rptr;
00624                 PropertyRNA *prop;
00625                 
00626                 RNA_id_pointer_create(aci->id, &id_ptr);
00627                 RNA_path_resolve(&id_ptr, aci->rna_path, &rptr, &prop);
00628                 
00629                 if (prop) {
00630                     const char *identifier= RNA_property_identifier(prop);
00631                     int len_id = strlen(identifier);
00632                     int len_path = strlen(fcu->rna_path);
00633                     if (len_id <= len_path) {
00634                         /* note, paths which end with "] will fail with this test - Animated ID Props */
00635                         if (strcmp(identifier, fcu->rna_path + (len_path-len_id))==0) {
00636                             if ((from_single) || (aci->array_index == fcu->array_index))
00637                                 break;
00638                         }
00639                     }
00640                 }
00641                 else {
00642                     printf("paste_animedit_keys: failed to resolve path id:%s, '%s'!\n", aci->id->name, aci->rna_path);
00643                 }
00644             }
00645         }
00646     }
00647 
00648     return aci;
00649 }
00650 
00651 /* least strict matching heuristic: indices only */
00652 static tAnimCopybufItem *pastebuf_match_index_only(FCurve *fcu, const short from_single, const short UNUSED(to_simple))
00653 {
00654     tAnimCopybufItem *aci;
00655 
00656     for (aci= animcopybuf.first; aci; aci= aci->next) {
00657         /* check that paths exist */
00658         if ((from_single) || (aci->array_index == fcu->array_index)) {
00659             break;
00660         }
00661     }
00662 
00663     return aci;
00664 }
00665 
00666 /* ................ */
00667 
00668 /* helper for paste_animedit_keys() - performs the actual pasting */
00669 static void paste_animedit_keys_fcurve(FCurve *fcu, tAnimCopybufItem *aci, float offset, const eKeyMergeMode merge_mode)
00670 {
00671     BezTriple *bezt;
00672     int i;
00673 
00674     /* First de-select existing FCuvre */
00675     for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) {
00676         bezt->f2 &= ~SELECT;
00677     }
00678 
00679     /* mix mode with existing data */
00680     switch (merge_mode) {
00681         case KEYFRAME_PASTE_MERGE_MIX:
00682             /* do-nothing */
00683             break;
00684             
00685         case KEYFRAME_PASTE_MERGE_OVER:
00686             /* remove all keys */
00687             clear_fcurve_keys(fcu);
00688             break;
00689             
00690         case KEYFRAME_PASTE_MERGE_OVER_RANGE:
00691         case KEYFRAME_PASTE_MERGE_OVER_RANGE_ALL:
00692         {
00693             float f_min;
00694             float f_max;
00695             
00696             if (merge_mode==KEYFRAME_PASTE_MERGE_OVER_RANGE) {
00697                 f_min= aci->bezt[0].vec[1][0] + offset;
00698                 f_max= aci->bezt[aci->totvert-1].vec[1][0] + offset;
00699             }
00700             else { /* Entire Range */
00701                 f_min= animcopy_firstframe + offset;
00702                 f_max= animcopy_lastframe + offset;
00703             }
00704             
00705             /* remove keys in range */
00706             if (f_min < f_max) {
00707                 /* select verts in range for removal */
00708                 for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) {
00709                     if ((f_min < bezt[0].vec[1][0]) && (bezt[0].vec[1][0] < f_max)) {
00710                         bezt->f2 |= SELECT;
00711                     }
00712                 }
00713                 
00714                 /* remove frames in the range */
00715                 delete_fcurve_keys(fcu);
00716             }
00717             break;
00718         }
00719     }
00720     
00721     /* just start pasting, with the the first keyframe on the current frame, and so on */
00722     for (i=0, bezt=aci->bezt; i < aci->totvert; i++, bezt++) {                      
00723         /* temporarily apply offset to src beztriple while copying */
00724         bezt->vec[0][0] += offset;
00725         bezt->vec[1][0] += offset;
00726         bezt->vec[2][0] += offset;
00727         
00728         /* insert the keyframe
00729          * NOTE: no special flags here for now
00730          */
00731         insert_bezt_fcurve(fcu, bezt, 0); 
00732         
00733         /* un-apply offset from src beztriple after copying */
00734         bezt->vec[0][0] -= offset;
00735         bezt->vec[1][0] -= offset;
00736         bezt->vec[2][0] -= offset;
00737     }
00738     
00739     /* recalculate F-Curve's handles? */
00740     calchandles_fcurve(fcu);
00741 }
00742 
00743 /* ------------------- */
00744 
00745 EnumPropertyItem keyframe_paste_offset_items[] = {
00746     {KEYFRAME_PASTE_OFFSET_CFRA_START, "START", 0, "Frame Start", "Paste keys starting at current frame"},
00747     {KEYFRAME_PASTE_OFFSET_CFRA_END, "END", 0, "Frame End", "Paste keys ending at current frame"},
00748     {KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE, "RELATIVE", 0, "Frame Relative", "Paste keys relative to the current frame when copying"},
00749     {KEYFRAME_PASTE_OFFSET_NONE, "NONE", 0, "No Offset", "Paste keys from original time"},
00750     {0, NULL, 0, NULL, NULL}};
00751 
00752 EnumPropertyItem keyframe_paste_merge_items[] = {
00753     {KEYFRAME_PASTE_MERGE_MIX, "MIX", 0, "Mix", "Overlay existing with new keys"},
00754     {KEYFRAME_PASTE_MERGE_OVER, "OVER_ALL", 0, "Overwrite All", "Replace all keys"},
00755     {KEYFRAME_PASTE_MERGE_OVER_RANGE, "OVER_RANGE", 0, "Overwrite Range", "Overwrite keys in pasted range"},
00756     {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"},
00757     {0, NULL, 0, NULL, NULL}};
00758 
00759 
00760 /* This function pastes data from the keyframes copy/paste buffer 
00761  * > return status code is whether the method FAILED to do anything
00762  */
00763 short paste_animedit_keys (bAnimContext *ac, ListBase *anim_data,
00764             const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode)
00765 {
00766     bAnimListElem *ale;
00767     
00768     const Scene *scene= (ac->scene);
00769     
00770     const short from_single= (animcopybuf.first == animcopybuf.last);
00771     const short to_simple= (anim_data->first == anim_data->last);
00772     
00773     float offset = 0.0f;
00774     int pass;
00775 
00776     /* check if buffer is empty */
00777     if (animcopybuf.first == NULL) {
00778         BKE_report(ac->reports, RPT_ERROR, "No animation data in buffer to paste");
00779         return -1;
00780     }
00781 
00782     if (anim_data->first == NULL) {
00783         BKE_report(ac->reports, RPT_ERROR, "No selected F-Curves to paste into");
00784         return -1;
00785     }
00786     
00787     /* mathods of offset */
00788     switch (offset_mode) {
00789         case KEYFRAME_PASTE_OFFSET_CFRA_START:
00790             offset= (float)(CFRA - animcopy_firstframe);
00791             break;
00792         case KEYFRAME_PASTE_OFFSET_CFRA_END:
00793             offset= (float)(CFRA - animcopy_lastframe);
00794             break;
00795         case KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE:
00796             offset= (float)(CFRA - animcopy_cfra);
00797             break;
00798         case KEYFRAME_PASTE_OFFSET_NONE:
00799             offset= 0.0f;
00800             break;
00801     }
00802 
00803     if (from_single && to_simple) {
00804         /* 1:1 match, no tricky checking, just paste */
00805         FCurve *fcu;
00806         tAnimCopybufItem *aci;
00807         
00808         ale= anim_data->first;
00809         fcu= (FCurve *)ale->data;       /* destination F-Curve */
00810         aci= animcopybuf.first;
00811         
00812         paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode);
00813     }
00814     else {
00815         /* from selected channels 
00816          *  This "passes" system aims to try to find "matching" channels to paste keyframes
00817          *  into with increasingly loose matching heuristics. The process finishes when at least
00818          *  one F-Curve has been pasted into.
00819          */
00820         for (pass= 0; pass < 3; pass++) {
00821             unsigned int totmatch= 0;
00822             
00823             for (ale= anim_data->first; ale; ale= ale->next) {
00824                 /* find buffer item to paste from 
00825                  *  - if names don't matter (i.e. only 1 channel in buffer), don't check id/group
00826                  *  - if names do matter, only check if id-type is ok for now (group check is not that important)
00827                  *  - most importantly, rna-paths should match (array indices are unimportant for now)
00828                  */
00829                 FCurve *fcu = (FCurve *)ale->data;      /* destination F-Curve */
00830                 tAnimCopybufItem *aci= NULL;
00831                 
00832                 switch (pass) {
00833                     case 0:
00834                         /* most strict, must be exact path match data_path & index */
00835                         aci= pastebuf_match_path_full(fcu, from_single, to_simple);
00836                         break;
00837                     
00838                     case 1:
00839                         /* less strict, just compare property names */
00840                         aci= pastebuf_match_path_property(fcu, from_single, to_simple);
00841                         break;
00842                     
00843                     case 2:
00844                         /* Comparing properties gave no results, so just do index comparisons */
00845                         aci= pastebuf_match_index_only(fcu, from_single, to_simple);
00846                         break;
00847                 }
00848                 
00849                 /* copy the relevant data from the matching buffer curve */
00850                 if (aci) {
00851                     totmatch++;
00852                     paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode);
00853                 }
00854             }
00855             
00856             /* dont continue if some fcurves were pasted */
00857             if (totmatch)
00858                 break;
00859         }
00860     }
00861     
00862     return 0;
00863 }
00864 
00865 /* **************************************************** */