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