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