ensure pasted graph keys are always selected.
[blender.git] / source / blender / editors / animation / keyframes_general.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation
21  * All rights reserved.
22  *
23  * Contributor(s): Joshua Leung
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 #include <stdlib.h>
29 #include <string.h>
30 #include <math.h>
31 #include <float.h>
32
33 #include "MEM_guardedalloc.h"
34
35 #include "BLI_blenlib.h"
36 #include "BLI_math.h"
37
38 #include "DNA_anim_types.h"
39 #include "DNA_object_types.h"
40 #include "DNA_scene_types.h"
41
42
43 #include "BKE_fcurve.h"
44 #include "BKE_utildefines.h"
45 #include "BKE_report.h"
46 #include "BKE_library.h"
47 #include "BKE_global.h"
48
49 #include "RNA_access.h"
50
51 #include "ED_anim_api.h"
52 #include "ED_keyframing.h"
53 #include "ED_keyframes_edit.h"
54
55 /* This file contains code for various keyframe-editing tools which are 'destructive'
56  * (i.e. they will modify the order of the keyframes, and change the size of the array).
57  * While some of these tools may eventually be moved out into blenkernel, for now, it is
58  * fine to have these calls here.
59  * 
60  * There are also a few tools here which cannot be easily coded for in the other system (yet).
61  * These may also be moved around at some point, but for now, they are best added here.
62  *
63  * - Joshua Leung, Dec 2008
64  */
65  
66 /* **************************************************** */
67
68 /* Only delete the nominated keyframe from provided F-Curve. 
69  * Not recommended to be used many times successively. For that
70  * there is delete_fcurve_keys(). 
71  */
72 void delete_fcurve_key(FCurve *fcu, int index, short do_recalc)
73 {
74         /* sanity check */
75         if (fcu == NULL) 
76                 return;
77                 
78         /* verify the index:
79          *      1) cannot be greater than the number of available keyframes
80          *      2) negative indices are for specifying a value from the end of the array
81          */
82         if (abs(index) >= fcu->totvert)
83                 return;
84         else if (index < 0)
85                 index += fcu->totvert;
86         
87         /* Delete this keyframe */
88         memmove(&fcu->bezt[index], &fcu->bezt[index+1], sizeof(BezTriple)*(fcu->totvert-index-1));
89         fcu->totvert--;
90
91         if (fcu->totvert == 0) {
92                 if (fcu->bezt)
93                         MEM_freeN(fcu->bezt);
94                 fcu->bezt= NULL;
95         }
96         
97         /* recalc handles - only if it won't cause problems */
98         if (do_recalc)
99                 calchandles_fcurve(fcu);
100 }
101
102 /* Delete selected keyframes in given F-Curve */
103 void delete_fcurve_keys(FCurve *fcu)
104 {
105         int i;
106         
107         if(fcu->bezt==NULL) /* ignore baked curves */
108                 return;
109     
110         /* Delete selected BezTriples */
111         for (i=0; i < fcu->totvert; i++) {
112                 if (fcu->bezt[i].f2 & SELECT) {
113                         memmove(&fcu->bezt[i], &fcu->bezt[i+1], sizeof(BezTriple)*(fcu->totvert-i-1));
114                         fcu->totvert--;
115                         i--;
116                 }
117         }
118         
119         /* Free the array of BezTriples if there are not keyframes */
120         if(fcu->totvert == 0)
121                 clear_fcurve_keys(fcu);
122 }
123
124
125 void clear_fcurve_keys(FCurve *fcu)
126 {
127         if (fcu->bezt)
128                 MEM_freeN(fcu->bezt);
129         fcu->bezt= NULL;
130
131         fcu->totvert= 0;
132 }
133
134 /* ---------------- */
135
136 /* duplicate selected keyframes for the given F-Curve */
137 void duplicate_fcurve_keys(FCurve *fcu)
138 {
139         BezTriple *newbezt;
140         int i;
141         
142         /* this can only work when there is an F-Curve, and also when there are some BezTriples */
143         if ELEM(NULL, fcu, fcu->bezt)
144                 return;
145         
146         for (i=0; i < fcu->totvert; i++) {
147                 /* If a key is selected */
148                 if (fcu->bezt[i].f2 & SELECT) {
149                         /* Expand the list */
150                         newbezt = MEM_callocN(sizeof(BezTriple) * (fcu->totvert+1), "beztriple");
151                         
152                         memcpy(newbezt, fcu->bezt, sizeof(BezTriple) * (i+1));
153                         memcpy(newbezt+i+1, fcu->bezt+i, sizeof(BezTriple));
154                         memcpy(newbezt+i+2, fcu->bezt+i+1, sizeof (BezTriple) *(fcu->totvert-(i+1)));
155                         fcu->totvert++;
156                         
157                         /* reassign pointers... (free old, and add new) */
158                         MEM_freeN(fcu->bezt);
159                         fcu->bezt=newbezt;
160                         
161                         /* Unselect the current key */
162                         BEZ_DESEL(&fcu->bezt[i]);
163                         i++;
164                         
165                         /* Select the copied key */
166                         BEZ_SEL(&fcu->bezt[i]);
167                 }
168         }
169 }
170
171 /* **************************************************** */
172 /* Various Tools */
173
174 /* Basic F-Curve 'cleanup' function that removes 'double points' and unnecessary keyframes on linear-segments only */
175 void clean_fcurve(FCurve *fcu, float thresh)
176 {
177         BezTriple *old_bezts, *bezt, *beztn;
178         BezTriple *lastb;
179         int totCount, i;
180         
181         /* check if any points  */
182         if ((fcu == NULL) || (fcu->totvert <= 1)) 
183                 return;
184         
185         /* make a copy of the old BezTriples, and clear IPO curve */
186         old_bezts = fcu->bezt;
187         totCount = fcu->totvert;        
188         fcu->bezt = NULL;
189         fcu->totvert = 0;
190         
191         /* now insert first keyframe, as it should be ok */
192         bezt = old_bezts;
193         insert_vert_fcurve(fcu, bezt->vec[1][0], bezt->vec[1][1], 0);
194         
195         /* Loop through BezTriples, comparing them. Skip any that do 
196          * not fit the criteria for "ok" points.
197          */
198         for (i=1; i<totCount; i++) {    
199                 float prev[2], cur[2], next[2];
200                 
201                 /* get BezTriples and their values */
202                 if (i < (totCount - 1)) {
203                         beztn = (old_bezts + (i+1));
204                         next[0]= beztn->vec[1][0]; next[1]= beztn->vec[1][1];
205                 }
206                 else {
207                         beztn = NULL;
208                         next[0] = next[1] = 0.0f;
209                 }
210                 lastb= (fcu->bezt + (fcu->totvert - 1));
211                 bezt= (old_bezts + i);
212                 
213                 /* get references for quicker access */
214                 prev[0] = lastb->vec[1][0]; prev[1] = lastb->vec[1][1];
215                 cur[0] = bezt->vec[1][0]; cur[1] = bezt->vec[1][1];
216                 
217                 /* check if current bezt occurs at same time as last ok */
218                 if (IS_EQT(cur[0], prev[0], thresh)) {
219                         /* If there is a next beztriple, and if occurs at the same time, only insert 
220                          * if there is a considerable distance between the points, and also if the 
221                          * current is further away than the next one is to the previous.
222                          */
223                         if (beztn && (IS_EQT(cur[0], next[0], thresh)) && 
224                                 (IS_EQT(next[1], prev[1], thresh)==0)) 
225                         {
226                                 /* only add if current is further away from previous */
227                                 if (cur[1] > next[1]) {
228                                         if (IS_EQT(cur[1], prev[1], thresh) == 0) {
229                                                 /* add new keyframe */
230                                                 insert_vert_fcurve(fcu, cur[0], cur[1], 0);
231                                         }
232                                 }
233                         }
234                         else {
235                                 /* only add if values are a considerable distance apart */
236                                 if (IS_EQT(cur[1], prev[1], thresh) == 0) {
237                                         /* add new keyframe */
238                                         insert_vert_fcurve(fcu, cur[0], cur[1], 0);
239                                 }
240                         }
241                 }
242                 else {
243                         /* checks required are dependent on whether this is last keyframe or not */
244                         if (beztn) {
245                                 /* does current have same value as previous and next? */
246                                 if (IS_EQT(cur[1], prev[1], thresh) == 0) {
247                                         /* add new keyframe*/
248                                         insert_vert_fcurve(fcu, cur[0], cur[1], 0);
249                                 }
250                                 else if (IS_EQT(cur[1], next[1], thresh) == 0) {
251                                         /* add new keyframe */
252                                         insert_vert_fcurve(fcu, cur[0], cur[1], 0);
253                                 }
254                         }
255                         else {  
256                                 /* add if value doesn't equal that of previous */
257                                 if (IS_EQT(cur[1], prev[1], thresh) == 0) {
258                                         /* add new keyframe */
259                                         insert_vert_fcurve(fcu, cur[0], cur[1], 0);
260                                 }
261                         }
262                 }
263         }
264         
265         /* now free the memory used by the old BezTriples */
266         if (old_bezts)
267                 MEM_freeN(old_bezts);
268 }
269
270 /* ---------------- */
271
272 /* temp struct used for smooth_fcurve */
273 typedef struct tSmooth_Bezt {
274         float *h1, *h2, *h3;    /* bezt->vec[0,1,2][1] */
275 } tSmooth_Bezt;
276
277 /* Use a weighted moving-means method to reduce intensity of fluctuations */
278 void smooth_fcurve (FCurve *fcu)
279 {
280         BezTriple *bezt;
281         int i, x, totSel = 0;
282         
283         /* first loop through - count how many verts are selected, and fix up handles 
284          *      this is done for both modes
285          */
286         bezt= fcu->bezt;
287         for (i=0; i < fcu->totvert; i++, bezt++) {                                              
288                 if (BEZSELECTED(bezt)) {                                                        
289                         /* line point's handles up with point's vertical position */
290                         bezt->vec[0][1]= bezt->vec[2][1]= bezt->vec[1][1];
291                         if ((bezt->h1==HD_AUTO) || (bezt->h1==HD_VECT)) bezt->h1= HD_ALIGN;
292                         if ((bezt->h2==HD_AUTO) || (bezt->h2==HD_VECT)) bezt->h2= HD_ALIGN;
293                         
294                         /* add value to total */
295                         totSel++;
296                 }
297         }
298         
299         /* if any points were selected, allocate tSmooth_Bezt points to work on */
300         if (totSel >= 3) {
301                 tSmooth_Bezt *tarray, *tsb;
302                 
303                 /* allocate memory in one go */
304                 tsb= tarray= MEM_callocN(totSel*sizeof(tSmooth_Bezt), "tSmooth_Bezt Array");
305                 
306                 /* populate tarray with data of selected points */
307                 bezt= fcu->bezt;
308                 for (i=0, x=0; (i < fcu->totvert) && (x < totSel); i++, bezt++) {
309                         if (BEZSELECTED(bezt)) {
310                                 /* tsb simply needs pointer to vec, and index */
311                                 tsb->h1 = &bezt->vec[0][1];
312                                 tsb->h2 = &bezt->vec[1][1];
313                                 tsb->h3 = &bezt->vec[2][1];
314                                 
315                                 /* advance to the next tsb to populate */
316                                 if (x < totSel- 1) 
317                                         tsb++;
318                                 else
319                                         break;
320                         }
321                 }
322                         
323                 /* calculate the new smoothed F-Curve's with weighted averages:
324                  *      - this is done with two passes
325                  *      - uses 5 points for each operation (which stores in the relevant handles)
326                  *      -       previous: w/a ratio = 3:5:2:1:1
327                  *      -       next: w/a ratio = 1:1:2:5:3
328                  */
329                 
330                 /* round 1: calculate previous and next */ 
331                 tsb= tarray;
332                 for (i=0; i < totSel; i++, tsb++) {
333                         /* don't touch end points (otherwise, curves slowly explode) */
334                         if (ELEM(i, 0, (totSel-1)) == 0) {
335                                 const tSmooth_Bezt *tP1 = tsb - 1;
336                                 const tSmooth_Bezt *tP2 = (i-2 > 0) ? (tsb - 2) : (NULL);
337                                 const tSmooth_Bezt *tN1 = tsb + 1;
338                                 const tSmooth_Bezt *tN2 = (i+2 < totSel) ? (tsb + 2) : (NULL);
339                                 
340                                 const float p1 = *tP1->h2;
341                                 const float p2 = (tP2) ? (*tP2->h2) : (*tP1->h2);
342                                 const float c1 = *tsb->h2;
343                                 const float n1 = *tN1->h2;
344                                 const float n2 = (tN2) ? (*tN2->h2) : (*tN1->h2);
345                                 
346                                 /* calculate previous and next */
347                                 *tsb->h1= (3*p2 + 5*p1 + 2*c1 + n1 + n2) / 12;
348                                 *tsb->h3= (p2 + p1 + 2*c1 + 5*n1 + 3*n2) / 12;
349                         }
350                 }
351                 
352                 /* round 2: calculate new values and reset handles */
353                 tsb= tarray;
354                 for (i=0; i < totSel; i++, tsb++) {
355                         /* calculate new position by averaging handles */
356                         *tsb->h2 = (*tsb->h1 + *tsb->h3) / 2;
357                         
358                         /* reset handles now */
359                         *tsb->h1 = *tsb->h2;
360                         *tsb->h3 = *tsb->h2;
361                 }
362                 
363                 /* free memory required for tarray */
364                 MEM_freeN(tarray);
365         }
366         
367         /* recalculate handles */
368         calchandles_fcurve(fcu);
369 }
370
371 /* ---------------- */
372
373 /* little cache for values... */
374 typedef struct tempFrameValCache {
375         float frame, val;
376 } tempFrameValCache;
377
378
379 /* Evaluates the curves between each selected keyframe on each frame, and keys the value  */
380 void sample_fcurve (FCurve *fcu)
381 {
382         BezTriple *bezt, *start=NULL, *end=NULL;
383         tempFrameValCache *value_cache, *fp;
384         int sfra, range;
385         int i, n, nIndex;
386
387         if(fcu->bezt==NULL) /* ignore baked */
388                 return;
389         
390         /* find selected keyframes... once pair has been found, add keyframes  */
391         for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) {
392                 /* check if selected, and which end this is */
393                 if (BEZSELECTED(bezt)) {
394                         if (start) {
395                                 /* set end */
396                                 end= bezt;
397                                 
398                                 /* cache values then add keyframes using these values, as adding
399                                  * keyframes while sampling will affect the outcome...
400                                  *      - only start sampling+adding from index=1, so that we don't overwrite original keyframe
401                                  */
402                                 range= (int)( ceil(end->vec[1][0] - start->vec[1][0]) );
403                                 sfra= (int)( floor(start->vec[1][0]) );
404                                 
405                                 if (range) {
406                                         value_cache= MEM_callocN(sizeof(tempFrameValCache)*range, "IcuFrameValCache");
407                                         
408                                         /*      sample values   */
409                                         for (n=1, fp=value_cache; n<range && fp; n++, fp++) {
410                                                 fp->frame= (float)(sfra + n);
411                                                 fp->val= evaluate_fcurve(fcu, fp->frame);
412                                         }
413                                         
414                                         /*      add keyframes with these, tagging as 'breakdowns'       */
415                                         for (n=1, fp=value_cache; n<range && fp; n++, fp++) {
416                                                 nIndex= insert_vert_fcurve(fcu, fp->frame, fp->val, 1);
417                                                 BEZKEYTYPE(fcu->bezt + nIndex)= BEZT_KEYTYPE_BREAKDOWN;
418                                         }
419                                         
420                                         /* free temp cache */
421                                         MEM_freeN(value_cache);
422                                         
423                                         /* as we added keyframes, we need to compensate so that bezt is at the right place */
424                                         bezt = fcu->bezt + i + range - 1;
425                                         i += (range - 1);
426                                 }
427                                 
428                                 /* bezt was selected, so it now marks the start of a whole new chain to search */
429                                 start= bezt;
430                                 end= NULL;
431                         }
432                         else {
433                                 /* just set start keyframe */
434                                 start= bezt;
435                                 end= NULL;
436                         }
437                 }
438         }
439         
440         /* recalculate channel's handles? */
441         calchandles_fcurve(fcu);
442 }
443
444 /* **************************************************** */
445 /* Copy/Paste Tools */
446 /* - The copy/paste buffer currently stores a set of temporary F-Curves containing only the keyframes 
447  *   that were selected in each of the original F-Curves
448  * - All pasted frames are offset by the same amount. This is calculated as the difference in the times of
449  *      the current frame and the 'first keyframe' (i.e. the earliest one in all channels).
450  * - The earliest frame is calculated per copy operation.
451  */
452
453 /* globals for copy/paste data (like for other copy/paste buffers) */
454 ListBase animcopybuf = {NULL, NULL};
455 static float animcopy_firstframe= 999999999.0f;
456 static float animcopy_lastframe= -999999999.0f;
457 static float animcopy_cfra= 0.0;
458
459 /* datatype for use in copy/paste buffer */
460 typedef struct tAnimCopybufItem {
461         struct tAnimCopybufItem *next, *prev;
462         
463         ID *id;                         /* ID which owns the curve */
464         bActionGroup *grp;      /* Action Group */
465         char *rna_path;         /* RNA-Path */
466         int array_index;        /* array index */
467         
468         int totvert;            /* number of keyframes stored for this channel */
469         BezTriple *bezt;        /* keyframes in buffer */
470
471         short id_type;          /* Result of GS(id->name)*/
472 } tAnimCopybufItem;
473
474
475 /* This function frees any MEM_calloc'ed copy/paste buffer data */
476 // XXX find some header to put this in!
477 void free_anim_copybuf (void)
478 {
479         tAnimCopybufItem *aci, *acn;
480         
481         /* free each buffer element */
482         for (aci= animcopybuf.first; aci; aci= acn) {
483                 acn= aci->next;
484                 
485                 /* free keyframes */
486                 if (aci->bezt) 
487                         MEM_freeN(aci->bezt);
488                         
489                 /* free RNA-path */
490                 if (aci->rna_path)
491                         MEM_freeN(aci->rna_path);
492                         
493                 /* free ourself */
494                 BLI_freelinkN(&animcopybuf, aci);
495         }
496         
497         /* restore initial state */
498         animcopybuf.first= animcopybuf.last= NULL;
499         animcopy_firstframe= 999999999.0f;
500         animcopy_lastframe= -999999999.0f;
501 }
502
503 /* ------------------- */
504
505 /* This function adds data to the keyframes copy/paste buffer, freeing existing data first */
506 short copy_animedit_keys (bAnimContext *ac, ListBase *anim_data)
507 {       
508         bAnimListElem *ale;
509         Scene *scene= ac->scene;
510         
511         /* clear buffer first */
512         free_anim_copybuf();
513         
514         /* assume that each of these is an F-Curve */
515         for (ale= anim_data->first; ale; ale= ale->next) {
516                 FCurve *fcu= (FCurve *)ale->key_data;
517                 tAnimCopybufItem *aci;
518                 BezTriple *bezt, *nbezt, *newbuf;
519                 int i;
520                 
521                 /* firstly, check if F-Curve has any selected keyframes
522                  *      - skip if no selected keyframes found (so no need to create unnecessary copy-buffer data)
523                  *      - this check should also eliminate any problems associated with using sample-data
524                  */
525                 if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, ANIM_editkeyframes_ok(BEZT_OK_SELECTED), NULL) == 0)
526                         continue;
527                 
528                 /* init copybuf item info */
529                 aci= MEM_callocN(sizeof(tAnimCopybufItem), "AnimCopybufItem");
530                 aci->id= ale->id;
531                 aci->id_type= GS(ale->id->name);
532                 aci->grp= fcu->grp;
533                 aci->rna_path= MEM_dupallocN(fcu->rna_path);
534                 aci->array_index= fcu->array_index;
535                 BLI_addtail(&animcopybuf, aci);
536                 
537                 /* add selected keyframes to buffer */
538                 // 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
539                 for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) {
540                         if (BEZSELECTED(bezt)) {
541                                 /* add to buffer */
542                                 newbuf= MEM_callocN(sizeof(BezTriple)*(aci->totvert+1), "copybuf beztriple");
543                                 
544                                 /* assume that since we are just resizing the array, just copy all existing data across */
545                                 if (aci->bezt)
546                                         memcpy(newbuf, aci->bezt, sizeof(BezTriple)*(aci->totvert));
547                                 
548                                 /* copy current beztriple across too */
549                                 nbezt= &newbuf[aci->totvert];
550                                 *nbezt= *bezt;
551
552                                 /* ensure copy buffer is selected so pasted keys are selected */
553                                 nbezt->f1 |= SELECT;
554                                 nbezt->f2 |= SELECT;
555                                 nbezt->f3 |= SELECT;
556
557                                 /* free old array and set the new */
558                                 if (aci->bezt) MEM_freeN(aci->bezt);
559                                 aci->bezt= newbuf;
560                                 aci->totvert++;
561                                 
562                                 /* check if this is the earliest frame encountered so far */
563                                 if (bezt->vec[1][0] < animcopy_firstframe)
564                                         animcopy_firstframe= bezt->vec[1][0];
565                                 if (bezt->vec[1][0] > animcopy_lastframe)
566                                         animcopy_lastframe= bezt->vec[1][0];
567                         }
568                 }
569                 
570         }
571         
572         /* check if anything ended up in the buffer */
573         if (ELEM(NULL, animcopybuf.first, animcopybuf.last))
574                 return -1;
575
576         /* incase 'relative' paste method is used */
577         animcopy_cfra= CFRA;
578
579         /* everything went fine */
580         return 0;
581 }
582
583 static tAnimCopybufItem *pastebuf_match_path_full(FCurve *fcu, const short from_single, const short to_simple) {
584         tAnimCopybufItem *aci;
585
586         for (aci= animcopybuf.first; aci; aci= aci->next) {
587                 /* check that paths exist */
588                 if (to_simple || (aci->rna_path && fcu->rna_path)) {
589                         if (to_simple || (strcmp(aci->rna_path, fcu->rna_path) == 0)) {
590                                 if ((from_single) || (aci->array_index == fcu->array_index)) {
591                                         break;
592                                 }
593                         }
594                 }
595         }
596
597         return aci;
598 }
599
600 static tAnimCopybufItem *pastebuf_match_path_property(FCurve *fcu, const short from_single, const short UNUSED(to_simple))
601 {
602         tAnimCopybufItem *aci;
603
604         for (aci= animcopybuf.first; aci; aci= aci->next) {
605                 /* check that paths exist */
606                 if (aci->rna_path && fcu->rna_path) {
607         
608                         /* find the property of the fcurve and compare against the end of the tAnimCopybufItem
609                          * more involves since it needs to to path lookups.
610                          * This is not 100% reliable since the user could be editing the curves on a path that wont
611                          * resolve, or a bone could be renamed after copying for eg. but in normal copy & paste
612                          * this should work out ok. */
613                         if(BLI_findindex(which_libbase(G.main, aci->id_type), aci->id) == -1) {
614                                 /* pedantic but the ID could have been removed, and beats crashing! */
615                                 printf("paste_animedit_keys: error ID has been removed!\n");
616                         }
617                         else {
618                                 PointerRNA id_ptr, rptr;
619                                 PropertyRNA *prop;
620         
621                                 RNA_id_pointer_create(aci->id, &id_ptr);
622                                 RNA_path_resolve(&id_ptr, aci->rna_path, &rptr, &prop);
623         
624                                 if(prop) {
625                                         const char *identifier= RNA_property_identifier(prop);
626                                         int len_id = strlen(identifier);
627                                         int len_path = strlen(fcu->rna_path);
628                                         if(len_id <= len_path) {
629                                                 /* note, paths which end with "] will fail with this test - Animated ID Props */
630                                                 if(strcmp(identifier, fcu->rna_path + (len_path-len_id))==0) {
631                                                         if ((from_single) || (aci->array_index == fcu->array_index)) {
632                                                                 break;
633                                                         }
634                                                 }
635                                         }
636                                 }
637                                 else {
638                                         printf("paste_animedit_keys: failed to resolve path id:%s, '%s'!\n", aci->id->name, aci->rna_path);
639                                 }
640                         }
641                 }
642         }
643
644         return aci;
645 }
646
647 static tAnimCopybufItem *pastebuf_match_index_only(FCurve *fcu, const short from_single, const short UNUSED(to_simple))
648 {
649         tAnimCopybufItem *aci;
650
651         for (aci= animcopybuf.first; aci; aci= aci->next) {
652                 /* check that paths exist */
653                 if ((from_single) || (aci->array_index == fcu->array_index)) {
654                         break;
655                 }
656         }
657
658         return aci;
659 }
660
661 static void paste_animedit_keys_fcurve(FCurve *fcu, tAnimCopybufItem *aci, float offset, const eKeyMergeMode merge_mode)
662 {
663         BezTriple *bezt;
664         int i;
665
666         /* First de-select existing FCuvre */
667         for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) {
668                 bezt->f2 &= ~SELECT;
669         }
670
671         /* mix mode with existing data */
672         switch(merge_mode) {
673                 case KEYFRAME_PASTE_MERGE_MIX:
674                         /* do-nothing */
675                         break;
676                 case KEYFRAME_PASTE_MERGE_OVER:
677                         /* remove all keys */
678                         clear_fcurve_keys(fcu);
679                         break;
680                 case KEYFRAME_PASTE_MERGE_OVER_RANGE:
681                 case KEYFRAME_PASTE_MERGE_OVER_RANGE_ALL:
682                 {
683                         float f_min;
684                         float f_max;
685
686                         if(merge_mode==KEYFRAME_PASTE_MERGE_OVER_RANGE) {
687                                 f_min= aci->bezt[0].vec[1][0] + offset;
688                                 f_max= aci->bezt[aci->totvert-1].vec[1][0] + offset;
689                         }
690                         else { /* Entire Range */
691                                 f_min= animcopy_firstframe + offset;
692                                 f_max= animcopy_lastframe + offset;
693                         }
694
695                         /* remove keys in range */
696
697                         if(f_min < f_max) {
698                                 /* select verts in range for removal */
699                                 for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) {
700                                         if((f_min < bezt[0].vec[1][0]) && (bezt[0].vec[1][0] < f_max)) {
701                                                 bezt->f2 |= SELECT;
702                                         }
703                                 }
704
705                                 /* remove frames in the range */
706                                 delete_fcurve_keys(fcu);
707                         }
708                         break;
709                 }
710         }
711
712
713         /* just start pasting, with the the first keyframe on the current frame, and so on */
714         for (i=0, bezt=aci->bezt; i < aci->totvert; i++, bezt++) {                                              
715                 /* temporarily apply offset to src beztriple while copying */
716                 bezt->vec[0][0] += offset;
717                 bezt->vec[1][0] += offset;
718                 bezt->vec[2][0] += offset;
719                 
720                 /* insert the keyframe
721                  * NOTE: no special flags here for now
722                  */
723                 insert_bezt_fcurve(fcu, bezt, 0); 
724                 
725                 /* un-apply offset from src beztriple after copying */
726                 bezt->vec[0][0] -= offset;
727                 bezt->vec[1][0] -= offset;
728                 bezt->vec[2][0] -= offset;
729         }
730         
731         /* recalculate F-Curve's handles? */
732         calchandles_fcurve(fcu);
733 }
734
735 EnumPropertyItem keyframe_paste_offset_items[] = {
736         {KEYFRAME_PASTE_OFFSET_CFRA_START, "START", 0, "Frame Start", "Paste keys starting at current frame"},
737         {KEYFRAME_PASTE_OFFSET_CFRA_END, "END", 0, "Frame End", "Paste keys ending at current frame"},
738         {KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE, "RELATIVE", 0, "Frame Relative", "Paste keys relative to the current frame when copying"},
739         {KEYFRAME_PASTE_OFFSET_NONE, "NONE", 0, "No Offset", "Paste keys from original time"},
740         {0, NULL, 0, NULL, NULL}};
741
742 EnumPropertyItem keyframe_paste_merge_items[] = {
743         {KEYFRAME_PASTE_MERGE_MIX, "MIX", 0, "Mix", "Overlay existing with new keys"},
744         {KEYFRAME_PASTE_MERGE_OVER, "OVER_ALL", 0, "Overwrite All", "Replace all keys"},
745         {KEYFRAME_PASTE_MERGE_OVER_RANGE, "OVER_RANGE", 0, "Overwrite Range", "Overwrite keys in pasted range"},
746         {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."},
747         {0, NULL, 0, NULL, NULL}};
748
749
750 /* This function pastes data from the keyframes copy/paste buffer */
751 short paste_animedit_keys (bAnimContext *ac, ListBase *anim_data,
752         const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode)
753 {
754         bAnimListElem *ale;
755         const Scene *scene= (ac->scene);
756         float offset;
757         const short from_single= (animcopybuf.first == animcopybuf.last);
758         const short to_simple= (anim_data->first == anim_data->last);
759         int pass;
760
761         /* check if buffer is empty */
762         if (animcopybuf.first == NULL) {
763                 BKE_report(ac->reports, RPT_WARNING, "No data in buffer to paste");
764                 return -1;
765         }
766
767         if (anim_data->first == NULL) {
768                 BKE_report(ac->reports, RPT_WARNING, "No FCurves to paste into");
769                 return -1;
770         }
771         
772         /* mathods of offset */
773         switch(offset_mode) {
774                 case KEYFRAME_PASTE_OFFSET_CFRA_START:
775                         offset= (float)(CFRA - animcopy_firstframe);
776                         break;
777                 case KEYFRAME_PASTE_OFFSET_CFRA_END:
778                         offset= (float)(CFRA - animcopy_lastframe);
779                         break;
780                 case KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE:
781                         offset= (float)(CFRA - animcopy_cfra);
782                         break;
783                 case KEYFRAME_PASTE_OFFSET_NONE:
784                         offset= 0.0f;
785                         break;
786         }
787
788         if(from_single && to_simple) {
789                 /* 1:1 match, no tricky checking, just paste */
790                 FCurve *fcu;
791                 tAnimCopybufItem *aci;
792
793                 ale= anim_data->first;
794                 fcu= (FCurve *)ale->data;               /* destination F-Curve */
795                 aci= animcopybuf.first;
796
797                 paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode);
798         }
799         else {
800                 /* from selected channels */
801                 for(pass= 0; pass < 3; pass++) {
802                         int totmatch= 0;
803                         for (ale= anim_data->first; ale; ale= ale->next) {
804                                 
805                                 /* find buffer item to paste from 
806                                  *      - if names don't matter (i.e. only 1 channel in buffer), don't check id/group
807                                  *      - if names do matter, only check if id-type is ok for now (group check is not that important)
808                                  *      - most importantly, rna-paths should match (array indices are unimportant for now)
809                                  */
810                                 FCurve *fcu = (FCurve *)ale->data;              /* destination F-Curve */
811                                 tAnimCopybufItem *aci= NULL;
812                                 
813                                 switch(pass) {
814                                 case 0:
815                                         /* most strict, must be exact path match data_path & index */
816                                         aci= pastebuf_match_path_full(fcu, from_single, to_simple);
817                                         break;
818         
819                                 case 1:
820                                         /* less strict, just compare property names */
821                                         aci= pastebuf_match_path_property(fcu, from_single, to_simple);
822                                         break;
823         
824                                 case 2:
825                                         /* Comparing properties gave no results, so just do index comparisons */
826                                         aci= pastebuf_match_index_only(fcu, from_single, to_simple);
827                                         break;
828                                 }
829
830                                 /* copy the relevant data from the matching buffer curve */
831                                 if (aci) {
832                                         totmatch++;
833                                         paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode);
834                                 }
835                         }
836                         
837                         /* dont continue if some fcurves were pasted */
838                         if(totmatch) {
839                                 break;
840                         }
841                 }
842         }
843
844         return 0;
845 }
846
847 /* **************************************************** */