Dopesheet: Keyframe size can be adjusted as part of theme settings
[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_utildefines.h"
40
41 #include "DNA_anim_types.h"
42 #include "DNA_object_types.h"
43 #include "DNA_scene_types.h"
44
45
46 #include "BKE_action.h"
47 #include "BKE_fcurve.h"
48 #include "BKE_report.h"
49 #include "BKE_library.h"
50 #include "BKE_global.h"
51 #include "BKE_deform.h"
52
53 #include "RNA_access.h"
54
55 #include "ED_anim_api.h"
56 #include "ED_keyframing.h"
57 #include "ED_keyframes_edit.h"
58
59 /* This file contains code for various keyframe-editing tools which are 'destructive'
60  * (i.e. they will modify the order of the keyframes, and change the size of the array).
61  * While some of these tools may eventually be moved out into blenkernel, for now, it is
62  * fine to have these calls here.
63  * 
64  * There are also a few tools here which cannot be easily coded for in the other system (yet).
65  * These may also be moved around at some point, but for now, they are best added here.
66  *
67  * - Joshua Leung, Dec 2008
68  */
69  
70 /* **************************************************** */
71
72 /* Only delete the nominated keyframe from provided F-Curve. 
73  * Not recommended to be used many times successively. For that
74  * there is delete_fcurve_keys(). 
75  */
76 void delete_fcurve_key(FCurve *fcu, int index, bool do_recalc)
77 {
78         /* sanity check */
79         if (fcu == NULL) 
80                 return;
81                 
82         /* verify the index:
83          *      1) cannot be greater than the number of available keyframes
84          *      2) negative indices are for specifying a value from the end of the array
85          */
86         if (abs(index) >= fcu->totvert)
87                 return;
88         else if (index < 0)
89                 index += fcu->totvert;
90         
91         /* Delete this keyframe */
92         memmove(&fcu->bezt[index], &fcu->bezt[index + 1], sizeof(BezTriple) * (fcu->totvert - index - 1));
93         fcu->totvert--;
94
95         if (fcu->totvert == 0) {
96                 if (fcu->bezt)
97                         MEM_freeN(fcu->bezt);
98                 fcu->bezt = NULL;
99         }
100         
101         /* recalc handles - only if it won't cause problems */
102         if (do_recalc)
103                 calchandles_fcurve(fcu);
104 }
105
106 /* Delete selected keyframes in given F-Curve */
107 bool delete_fcurve_keys(FCurve *fcu)
108 {
109         int i;
110         bool changed = false;
111         
112         if (fcu->bezt == NULL) /* ignore baked curves */
113                 return false;
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                         changed = true;
122                 }
123         }
124         
125         /* Free the array of BezTriples if there are not keyframes */
126         if (fcu->totvert == 0)
127                 clear_fcurve_keys(fcu);
128
129         return changed;
130 }
131
132
133 void clear_fcurve_keys(FCurve *fcu)
134 {
135         if (fcu->bezt)
136                 MEM_freeN(fcu->bezt);
137         fcu->bezt = NULL;
138
139         fcu->totvert = 0;
140 }
141
142 /* ---------------- */
143
144 /* duplicate selected keyframes for the given F-Curve */
145 void duplicate_fcurve_keys(FCurve *fcu)
146 {
147         BezTriple *newbezt;
148         int i;
149         
150         /* this can only work when there is an F-Curve, and also when there are some BezTriples */
151         if (ELEM(NULL, fcu, fcu->bezt))
152                 return;
153         
154         for (i = 0; i < fcu->totvert; i++) {
155                 /* If a key is selected */
156                 if (fcu->bezt[i].f2 & SELECT) {
157                         /* Expand the list */
158                         newbezt = MEM_callocN(sizeof(BezTriple) * (fcu->totvert + 1), "beztriple");
159                         
160                         memcpy(newbezt, fcu->bezt, sizeof(BezTriple) * (i + 1));
161                         memcpy(newbezt + i + 1, fcu->bezt + i, sizeof(BezTriple));
162                         memcpy(newbezt + i + 2, fcu->bezt + i + 1, sizeof(BezTriple) * (fcu->totvert - (i + 1)));
163                         fcu->totvert++;
164                         
165                         /* reassign pointers... (free old, and add new) */
166                         MEM_freeN(fcu->bezt);
167                         fcu->bezt = newbezt;
168                         
169                         /* Unselect the current key */
170                         BEZT_DESEL_ALL(&fcu->bezt[i]);
171                         i++;
172                         
173                         /* Select the copied key */
174                         BEZT_SEL_ALL(&fcu->bezt[i]);
175                 }
176         }
177 }
178
179 /* **************************************************** */
180 /* Various Tools */
181
182 /* Basic F-Curve 'cleanup' function that removes 'double points' and unnecessary keyframes on linear-segments only
183  * optionally clears up curve if one keyframe with default value remains */
184 void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, bool cleardefault)
185 {
186         FCurve *fcu = (FCurve *)ale->key_data;
187         BezTriple *old_bezts, *bezt, *beztn;
188         BezTriple *lastb;
189         int totCount, i;
190         
191         /* check if any points  */
192         if ((fcu == NULL) || (fcu->bezt == NULL) || (fcu->totvert == 0) ||
193             (!cleardefault && fcu->totvert == 1))
194         {
195                 return;
196         }
197
198         /* make a copy of the old BezTriples, and clear F-Curve */
199         old_bezts = fcu->bezt;
200         totCount = fcu->totvert;
201         fcu->bezt = NULL;
202         fcu->totvert = 0;
203         
204         /* now insert first keyframe, as it should be ok */
205         bezt = old_bezts;
206         insert_vert_fcurve(fcu, bezt->vec[1][0], bezt->vec[1][1], BEZKEYTYPE(bezt), 0);
207         if (!(bezt->f2 & SELECT)) {
208                 lastb = fcu->bezt;
209                 lastb->f1 = lastb->f2 = lastb->f3 = 0;
210         }
211         
212         /* Loop through BezTriples, comparing them. Skip any that do 
213          * not fit the criteria for "ok" points.
214          */
215         for (i = 1; i < totCount; i++) {
216                 float prev[2], cur[2], next[2];
217
218                 /* get BezTriples and their values */
219                 if (i < (totCount - 1)) {
220                         beztn = (old_bezts + (i + 1));
221                         next[0] = beztn->vec[1][0]; next[1] = beztn->vec[1][1];
222                 }
223                 else {
224                         beztn = NULL;
225                         next[0] = next[1] = 0.0f;
226                 }
227                 lastb = (fcu->bezt + (fcu->totvert - 1));
228                 bezt = (old_bezts + i);
229                 
230                 /* get references for quicker access */
231                 prev[0] = lastb->vec[1][0]; prev[1] = lastb->vec[1][1];
232                 cur[0] = bezt->vec[1][0]; cur[1] = bezt->vec[1][1];
233                 
234                 if (!(bezt->f2 & SELECT)) {
235                         insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0);
236                         lastb = (fcu->bezt + (fcu->totvert - 1));
237                         lastb->f1 = lastb->f2 = lastb->f3 = 0;
238                         continue;
239                 }
240                 
241                 /* check if current bezt occurs at same time as last ok */
242                 if (IS_EQT(cur[0], prev[0], thresh)) {
243                         /* If there is a next beztriple, and if occurs at the same time, only insert 
244                          * if there is a considerable distance between the points, and also if the 
245                          * current is further away than the next one is to the previous.
246                          */
247                         if (beztn && (IS_EQT(cur[0], next[0], thresh)) &&
248                             (IS_EQT(next[1], prev[1], thresh) == 0))
249                         {
250                                 /* only add if current is further away from previous */
251                                 if (cur[1] > next[1]) {
252                                         if (IS_EQT(cur[1], prev[1], thresh) == 0) {
253                                                 /* add new keyframe */
254                                                 insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0);
255                                         }
256                                 }
257                         }
258                         else {
259                                 /* only add if values are a considerable distance apart */
260                                 if (IS_EQT(cur[1], prev[1], thresh) == 0) {
261                                         /* add new keyframe */
262                                         insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0);
263                                 }
264                         }
265                 }
266                 else {
267                         /* checks required are dependent on whether this is last keyframe or not */
268                         if (beztn) {
269                                 /* does current have same value as previous and next? */
270                                 if (IS_EQT(cur[1], prev[1], thresh) == 0) {
271                                         /* add new keyframe*/
272                                         insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0);
273                                 }
274                                 else if (IS_EQT(cur[1], next[1], thresh) == 0) {
275                                         /* add new keyframe */
276                                         insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0);
277                                 }
278                         }
279                         else {
280                                 /* add if value doesn't equal that of previous */
281                                 if (IS_EQT(cur[1], prev[1], thresh) == 0) {
282                                         /* add new keyframe */
283                                         insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0);
284                                 }
285                         }
286                 }
287         }
288         
289         /* now free the memory used by the old BezTriples */
290         if (old_bezts)
291                 MEM_freeN(old_bezts);
292
293         /* final step, if there is just one key in fcurve, check if it's
294          * the default value and if is, remove fcurve completely. */
295         if (cleardefault && fcu->totvert == 1) {
296                 float default_value = 0.0f;
297                 PointerRNA id_ptr, ptr;
298                 PropertyRNA *prop;
299                 RNA_id_pointer_create(ale->id, &id_ptr);
300
301                 /* get property to read from, and get value as appropriate */
302                 if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) {
303                         if (RNA_property_type(prop) == PROP_FLOAT)
304                                 default_value = RNA_property_float_get_default_index(&ptr, prop, fcu->array_index);
305                 }
306
307                 if (fcu->bezt->vec[1][1] == default_value) {
308                         clear_fcurve_keys(fcu);
309
310                         /* check if curve is really unused and if it is, return signal for deletion */
311                         if ((list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0) &&
312                             (fcu->driver == NULL))
313                         {
314                                 AnimData *adt = ale->adt;
315                                 ANIM_fcurve_delete_from_animdata(ac, adt, fcu);
316                                 ale->key_data = NULL;
317                         }
318                 }
319         }
320 }
321
322 /* ---------------- */
323
324 /* temp struct used for smooth_fcurve */
325 typedef struct tSmooth_Bezt {
326         float *h1, *h2, *h3;    /* bezt->vec[0,1,2][1] */
327         float y1, y2, y3;       /* averaged before/new/after y-values */
328 } tSmooth_Bezt;
329
330 /* Use a weighted moving-means method to reduce intensity of fluctuations */
331 // TODO: introduce scaling factor for weighting falloff
332 void smooth_fcurve(FCurve *fcu)
333 {
334         BezTriple *bezt;
335         int i, x, totSel = 0;
336
337         if (fcu->bezt == NULL) {
338                 return;
339         }
340
341         /* first loop through - count how many verts are selected */
342         bezt = fcu->bezt;
343         for (i = 0; i < fcu->totvert; i++, bezt++) {
344                 if (BEZT_ISSEL_ANY(bezt))
345                         totSel++;
346         }
347         
348         /* if any points were selected, allocate tSmooth_Bezt points to work on */
349         if (totSel >= 3) {
350                 tSmooth_Bezt *tarray, *tsb;
351                 
352                 /* allocate memory in one go */
353                 tsb = tarray = MEM_callocN(totSel * sizeof(tSmooth_Bezt), "tSmooth_Bezt Array");
354                 
355                 /* populate tarray with data of selected points */
356                 bezt = fcu->bezt;
357                 for (i = 0, x = 0; (i < fcu->totvert) && (x < totSel); i++, bezt++) {
358                         if (BEZT_ISSEL_ANY(bezt)) {
359                                 /* tsb simply needs pointer to vec, and index */
360                                 tsb->h1 = &bezt->vec[0][1];
361                                 tsb->h2 = &bezt->vec[1][1];
362                                 tsb->h3 = &bezt->vec[2][1];
363                                 
364                                 /* advance to the next tsb to populate */
365                                 if (x < totSel - 1)
366                                         tsb++;
367                                 else
368                                         break;
369                         }
370                 }
371                         
372                 /* calculate the new smoothed F-Curve's with weighted averages:
373                  *      - this is done with two passes to avoid progressive corruption errors
374                  *      - uses 5 points for each operation (which stores in the relevant handles)
375                  *      -   previous: w/a ratio = 3:5:2:1:1
376                  *      -   next: w/a ratio = 1:1:2:5:3
377                  */
378                 
379                 /* round 1: calculate smoothing deltas and new values */ 
380                 tsb = tarray;
381                 for (i = 0; i < totSel; i++, tsb++) {
382                         /* don't touch end points (otherwise, curves slowly explode, as we don't have enough data there) */
383                         if (ELEM(i, 0, (totSel - 1)) == 0) {
384                                 const tSmooth_Bezt *tP1 = tsb - 1;
385                                 const tSmooth_Bezt *tP2 = (i - 2 > 0) ? (tsb - 2) : (NULL);
386                                 const tSmooth_Bezt *tN1 = tsb + 1;
387                                 const tSmooth_Bezt *tN2 = (i + 2 < totSel) ? (tsb + 2) : (NULL);
388                                 
389                                 const float p1 = *tP1->h2;
390                                 const float p2 = (tP2) ? (*tP2->h2) : (*tP1->h2);
391                                 const float c1 = *tsb->h2;
392                                 const float n1 = *tN1->h2;
393                                 const float n2 = (tN2) ? (*tN2->h2) : (*tN1->h2);
394                                 
395                                 /* calculate previous and next, then new position by averaging these */
396                                 tsb->y1 = (3 * p2 + 5 * p1 + 2 * c1 + n1 + n2) / 12;
397                                 tsb->y3 = (p2 + p1 + 2 * c1 + 5 * n1 + 3 * n2) / 12;
398                                 
399                                 tsb->y2 = (tsb->y1 + tsb->y3) / 2;
400                         }
401                 }
402                 
403                 /* round 2: apply new values */
404                 tsb = tarray;
405                 for (i = 0; i < totSel; i++, tsb++) {
406                         /* don't touch end points, as their values weren't touched above */
407                         if (ELEM(i, 0, (totSel - 1)) == 0) {
408                                 /* y2 takes the average of the 2 points */
409                                 *tsb->h2 = tsb->y2;
410                                 
411                                 /* handles are weighted between their original values and the averaged values */
412                                 *tsb->h1 = ((*tsb->h1) * 0.7f) + (tsb->y1 * 0.3f); 
413                                 *tsb->h3 = ((*tsb->h3) * 0.7f) + (tsb->y3 * 0.3f);
414                         }
415                 }
416                 
417                 /* free memory required for tarray */
418                 MEM_freeN(tarray);
419         }
420         
421         /* recalculate handles */
422         calchandles_fcurve(fcu);
423 }
424
425 /* ---------------- */
426
427 /* little cache for values... */
428 typedef struct TempFrameValCache {
429         float frame, val;
430 } TempFrameValCache;
431
432
433 /* Evaluates the curves between each selected keyframe on each frame, and keys the value  */
434 void sample_fcurve(FCurve *fcu)
435 {
436         BezTriple *bezt, *start = NULL, *end = NULL;
437         TempFrameValCache *value_cache, *fp;
438         int sfra, range;
439         int i, n;
440
441         if (fcu->bezt == NULL) /* ignore baked */
442                 return;
443         
444         /* find selected keyframes... once pair has been found, add keyframes  */
445         for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
446                 /* check if selected, and which end this is */
447                 if (BEZT_ISSEL_ANY(bezt)) {
448                         if (start) {
449                                 /* set end */
450                                 end = bezt;
451                                 
452                                 /* cache values then add keyframes using these values, as adding
453                                  * keyframes while sampling will affect the outcome...
454                                  *      - only start sampling+adding from index=1, so that we don't overwrite original keyframe
455                                  */
456                                 range = (int)(ceil(end->vec[1][0] - start->vec[1][0]));
457                                 sfra = (int)(floor(start->vec[1][0]));
458                                 
459                                 if (range) {
460                                         value_cache = MEM_callocN(sizeof(TempFrameValCache) * range, "IcuFrameValCache");
461                                         
462                                         /* sample values */
463                                         for (n = 1, fp = value_cache; n < range && fp; n++, fp++) {
464                                                 fp->frame = (float)(sfra + n);
465                                                 fp->val = evaluate_fcurve(fcu, fp->frame);
466                                         }
467                                         
468                                         /* add keyframes with these, tagging as 'breakdowns' */
469                                         for (n = 1, fp = value_cache; n < range && fp; n++, fp++) {
470                                                 insert_vert_fcurve(fcu, fp->frame, fp->val, BEZT_KEYTYPE_BREAKDOWN, 1);
471                                         }
472                                         
473                                         /* free temp cache */
474                                         MEM_freeN(value_cache);
475                                         
476                                         /* as we added keyframes, we need to compensate so that bezt is at the right place */
477                                         bezt = fcu->bezt + i + range - 1;
478                                         i += (range - 1);
479                                 }
480                                 
481                                 /* bezt was selected, so it now marks the start of a whole new chain to search */
482                                 start = bezt;
483                                 end = NULL;
484                         }
485                         else {
486                                 /* just set start keyframe */
487                                 start = bezt;
488                                 end = NULL;
489                         }
490                 }
491         }
492         
493         /* recalculate channel's handles? */
494         calchandles_fcurve(fcu);
495 }
496
497 /* **************************************************** */
498 /* Copy/Paste Tools */
499 /* - The copy/paste buffer currently stores a set of temporary F-Curves containing only the keyframes 
500  *   that were selected in each of the original F-Curves
501  * - All pasted frames are offset by the same amount. This is calculated as the difference in the times of
502  *      the current frame and the 'first keyframe' (i.e. the earliest one in all channels).
503  * - The earliest frame is calculated per copy operation.
504  */
505
506 /* globals for copy/paste data (like for other copy/paste buffers) */
507 static ListBase animcopybuf = {NULL, NULL};
508 static float animcopy_firstframe = 999999999.0f;
509 static float animcopy_lastframe = -999999999.0f;
510 static float animcopy_cfra = 0.0;
511
512 /* datatype for use in copy/paste buffer */
513 typedef struct tAnimCopybufItem {
514         struct tAnimCopybufItem *next, *prev;
515         
516         ID *id;             /* ID which owns the curve */
517         bActionGroup *grp;  /* Action Group */
518         char *rna_path;     /* RNA-Path */
519         int array_index;    /* array index */
520         
521         int totvert;        /* number of keyframes stored for this channel */
522         BezTriple *bezt;    /* keyframes in buffer */
523
524         short id_type;      /* Result of GS(id->name)*/
525         bool  is_bone;      /* special flag for armature bones */
526 } tAnimCopybufItem;
527
528
529 /* This function frees any MEM_calloc'ed copy/paste buffer data */
530 void ANIM_fcurves_copybuf_free(void)
531 {
532         tAnimCopybufItem *aci, *acn;
533         
534         /* free each buffer element */
535         for (aci = animcopybuf.first; aci; aci = acn) {
536                 acn = aci->next;
537                 
538                 /* free keyframes */
539                 if (aci->bezt) 
540                         MEM_freeN(aci->bezt);
541                         
542                 /* free RNA-path */
543                 if (aci->rna_path)
544                         MEM_freeN(aci->rna_path);
545                         
546                 /* free ourself */
547                 BLI_freelinkN(&animcopybuf, aci);
548         }
549         
550         /* restore initial state */
551         BLI_listbase_clear(&animcopybuf);
552         animcopy_firstframe = 999999999.0f;
553         animcopy_lastframe = -999999999.0f;
554 }
555
556 /* ------------------- */
557
558 /* This function adds data to the keyframes copy/paste buffer, freeing existing data first */
559 short copy_animedit_keys(bAnimContext *ac, ListBase *anim_data)
560 {       
561         bAnimListElem *ale;
562         Scene *scene = ac->scene;
563         
564         /* clear buffer first */
565         ANIM_fcurves_copybuf_free();
566         
567         /* assume that each of these is an F-Curve */
568         for (ale = anim_data->first; ale; ale = ale->next) {
569                 FCurve *fcu = (FCurve *)ale->key_data;
570                 tAnimCopybufItem *aci;
571                 BezTriple *bezt, *nbezt, *newbuf;
572                 int i;
573                 
574                 /* firstly, check if F-Curve has any selected keyframes
575                  *      - skip if no selected keyframes found (so no need to create unnecessary copy-buffer data)
576                  *      - this check should also eliminate any problems associated with using sample-data
577                  */
578                 if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, ANIM_editkeyframes_ok(BEZT_OK_SELECTED), NULL) == 0)
579                         continue;
580                 
581                 /* init copybuf item info */
582                 aci = MEM_callocN(sizeof(tAnimCopybufItem), "AnimCopybufItem");
583                 aci->id = ale->id;
584                 aci->id_type = GS(ale->id->name);
585                 aci->grp = fcu->grp;
586                 aci->rna_path = MEM_dupallocN(fcu->rna_path);
587                 aci->array_index = fcu->array_index;
588                 
589                 /* detect if this is a bone. We do that here rather than during pasting because ID pointers will get invalidated if we undo.
590                  * storing the relevant information here helps avoiding crashes if we undo-repaste */
591                 if ((aci->id_type == ID_OB) && (((Object *)aci->id)->type == OB_ARMATURE) && aci->rna_path) {
592                         Object *ob = (Object *)aci->id;
593                         bPoseChannel *pchan;
594                         char *bone_name;
595
596                         bone_name = BLI_str_quoted_substrN(aci->rna_path, "pose.bones[");
597                         pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
598                         if (pchan) {
599                                 aci->is_bone = true;
600                         }
601                         if (bone_name) MEM_freeN(bone_name);
602                 }
603                 
604                 BLI_addtail(&animcopybuf, aci);
605                 
606                 /* add selected keyframes to buffer */
607                 /* TODO: currently, we resize array every time we add a new vert -
608                  * this works ok as long as it is assumed only a few keys are copied */
609                 for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
610                         if (BEZT_ISSEL_ANY(bezt)) {
611                                 /* add to buffer */
612                                 newbuf = MEM_callocN(sizeof(BezTriple) * (aci->totvert + 1), "copybuf beztriple");
613                                 
614                                 /* assume that since we are just re-sizing the array, just copy all existing data across */
615                                 if (aci->bezt)
616                                         memcpy(newbuf, aci->bezt, sizeof(BezTriple) * (aci->totvert));
617                                 
618                                 /* copy current beztriple across too */
619                                 nbezt = &newbuf[aci->totvert];
620                                 *nbezt = *bezt;
621                                 
622                                 /* ensure copy buffer is selected so pasted keys are selected */
623                                 BEZT_SEL_ALL(nbezt);
624                                 
625                                 /* free old array and set the new */
626                                 if (aci->bezt) MEM_freeN(aci->bezt);
627                                 aci->bezt = newbuf;
628                                 aci->totvert++;
629                                 
630                                 /* check if this is the earliest frame encountered so far */
631                                 if (bezt->vec[1][0] < animcopy_firstframe)
632                                         animcopy_firstframe = bezt->vec[1][0];
633                                 if (bezt->vec[1][0] > animcopy_lastframe)
634                                         animcopy_lastframe = bezt->vec[1][0];
635                         }
636                 }
637                 
638         }
639         
640         /* check if anything ended up in the buffer */
641         if (ELEM(NULL, animcopybuf.first, animcopybuf.last))
642                 return -1;
643
644         /* in case 'relative' paste method is used */
645         animcopy_cfra = CFRA;
646
647         /* everything went fine */
648         return 0;
649 }
650
651 static void flip_names(tAnimCopybufItem *aci, char **name)
652 {
653         if (aci->is_bone) {
654                 char *str_start;
655                 if ((str_start = strstr(aci->rna_path, "pose.bones["))) {
656                         /* ninja coding, try to change the name */
657                         char bname_new[MAX_VGROUP_NAME];
658                         char *str_iter, *str_end;
659                         int length, prefix_l, postfix_l;
660
661                         str_start += 12;
662                         prefix_l = str_start - aci->rna_path;
663
664                         str_end = strchr(str_start, '\"');
665
666                         length = str_end - str_start;
667                         postfix_l = strlen(str_end);
668
669                         /* more ninja stuff, temporary substitute with NULL terminator */
670                         str_start[length] = 0;
671                         BKE_deform_flip_side_name(bname_new, str_start, false);
672                         str_start[length] = '\"';
673
674                         str_iter = *name = MEM_mallocN(sizeof(char) * (prefix_l + postfix_l + length + 1), "flipped_path");
675
676                         BLI_strncpy(str_iter, aci->rna_path, prefix_l + 1);
677                         str_iter += prefix_l;
678                         BLI_strncpy(str_iter, bname_new, length + 1);
679                         str_iter += length;
680                         BLI_strncpy(str_iter, str_end, postfix_l + 1);
681                         str_iter[postfix_l] = '\0';
682                 }
683         }
684 }
685
686 /* ------------------- */
687
688 /* most strict method: exact matches only */
689 static tAnimCopybufItem *pastebuf_match_path_full(FCurve *fcu, const short from_single, const short to_simple, bool flip)
690 {
691         tAnimCopybufItem *aci;
692
693         for (aci = animcopybuf.first; aci; aci = aci->next) {
694                 if (to_simple || (aci->rna_path && fcu->rna_path)) {
695                         if (!to_simple && flip && aci->is_bone && fcu->rna_path) {
696                                 if ((from_single) || (aci->array_index == fcu->array_index)) {
697                                         char *name = NULL;
698                                         flip_names(aci, &name);
699                                         if (STREQ(name, fcu->rna_path)) {
700                                                 MEM_freeN(name);
701                                                 break;
702                                         }
703                                         MEM_freeN(name);
704                                 }
705                         }
706                         else if (to_simple || STREQ(aci->rna_path, fcu->rna_path)) {
707                                 if ((from_single) || (aci->array_index == fcu->array_index)) {
708                                         break;
709                                 }
710                         }
711                 }
712         }
713
714         return aci;
715 }
716
717 /* medium match strictness: path match only (i.e. ignore ID) */
718 static tAnimCopybufItem *pastebuf_match_path_property(FCurve *fcu, const short from_single, const short UNUSED(to_simple))
719 {
720         tAnimCopybufItem *aci;
721
722         for (aci = animcopybuf.first; aci; aci = aci->next) {
723                 /* check that paths exist */
724                 if (aci->rna_path && fcu->rna_path) {
725                         /* find the property of the fcurve and compare against the end of the tAnimCopybufItem
726                          * more involved since it needs to to path lookups.
727                          * This is not 100% reliable since the user could be editing the curves on a path that wont
728                          * resolve, or a bone could be renamed after copying for eg. but in normal copy & paste
729                          * this should work out ok. 
730                          */
731                         if (BLI_findindex(which_libbase(G.main, aci->id_type), aci->id) == -1) {
732                                 /* pedantic but the ID could have been removed, and beats crashing! */
733                                 printf("paste_animedit_keys: error ID has been removed!\n");
734                         }
735                         else {
736                                 PointerRNA id_ptr, rptr;
737                                 PropertyRNA *prop;
738                                 
739                                 RNA_id_pointer_create(aci->id, &id_ptr);
740                                 
741                                 if (RNA_path_resolve_property(&id_ptr, aci->rna_path, &rptr, &prop)) {
742                                         const char *identifier = RNA_property_identifier(prop);
743                                         int len_id = strlen(identifier);
744                                         int len_path = strlen(fcu->rna_path);
745                                         if (len_id <= len_path) {
746                                                 /* note, paths which end with "] will fail with this test - Animated ID Props */
747                                                 if (STREQ(identifier, fcu->rna_path + (len_path - len_id))) {
748                                                         if ((from_single) || (aci->array_index == fcu->array_index))
749                                                                 break;
750                                                 }
751                                         }
752                                 }
753                                 else {
754                                         printf("paste_animedit_keys: failed to resolve path id:%s, '%s'!\n", aci->id->name, aci->rna_path);
755                                 }
756                         }
757                 }
758         }
759
760         return aci;
761 }
762
763 /* least strict matching heuristic: indices only */
764 static tAnimCopybufItem *pastebuf_match_index_only(FCurve *fcu, const short from_single, const short UNUSED(to_simple))
765 {
766         tAnimCopybufItem *aci;
767
768         for (aci = animcopybuf.first; aci; aci = aci->next) {
769                 /* check that paths exist */
770                 if ((from_single) || (aci->array_index == fcu->array_index)) {
771                         break;
772                 }
773         }
774
775         return aci;
776 }
777
778 /* ................ */
779
780 static void do_curve_mirror_flippping(tAnimCopybufItem *aci, BezTriple *bezt)
781 {
782         if (aci->is_bone) {
783                 const size_t slength = strlen(aci->rna_path);
784                 bool flip = false;
785                 if (BLI_strn_endswith(aci->rna_path, "location", slength) && aci->array_index == 0)
786                         flip = true;
787                 else if (BLI_strn_endswith(aci->rna_path, "rotation_quaternion", slength) && ELEM(aci->array_index, 2, 3))
788                         flip = true;
789                 else if (BLI_strn_endswith(aci->rna_path, "rotation_euler", slength) && ELEM(aci->array_index, 1, 2))
790                         flip = true;
791                 else if (BLI_strn_endswith(aci->rna_path, "rotation_axis_angle", slength) && ELEM(aci->array_index, 2, 3))
792                         flip = true;
793                 
794                 if (flip) {
795                         bezt->vec[0][1] = -bezt->vec[0][1];
796                         bezt->vec[1][1] = -bezt->vec[1][1];
797                         bezt->vec[2][1] = -bezt->vec[2][1];
798                 }
799         }
800 }
801
802 /* helper for paste_animedit_keys() - performs the actual pasting */
803 static void paste_animedit_keys_fcurve(FCurve *fcu, tAnimCopybufItem *aci, float offset, const eKeyMergeMode merge_mode, bool flip)
804 {
805         BezTriple *bezt;
806         int i;
807
808         /* First de-select existing FCurve's keyframes */
809         for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
810                 BEZT_DESEL_ALL(bezt);
811         }
812
813         /* mix mode with existing data */
814         switch (merge_mode) {
815                 case KEYFRAME_PASTE_MERGE_MIX:
816                         /* do-nothing */
817                         break;
818                         
819                 case KEYFRAME_PASTE_MERGE_OVER:
820                         /* remove all keys */
821                         clear_fcurve_keys(fcu);
822                         break;
823                         
824                 case KEYFRAME_PASTE_MERGE_OVER_RANGE:
825                 case KEYFRAME_PASTE_MERGE_OVER_RANGE_ALL:
826                 {
827                         float f_min;
828                         float f_max;
829                         
830                         if (merge_mode == KEYFRAME_PASTE_MERGE_OVER_RANGE) {
831                                 f_min = aci->bezt[0].vec[1][0] + offset;
832                                 f_max = aci->bezt[aci->totvert - 1].vec[1][0] + offset;
833                         }
834                         else { /* Entire Range */
835                                 f_min = animcopy_firstframe + offset;
836                                 f_max = animcopy_lastframe + offset;
837                         }
838                         
839                         /* remove keys in range */
840                         if (f_min < f_max) {
841                                 /* select verts in range for removal */
842                                 for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
843                                         if ((f_min < bezt[0].vec[1][0]) && (bezt[0].vec[1][0] < f_max)) {
844                                                 bezt->f2 |= SELECT;
845                                         }
846                                 }
847                                 
848                                 /* remove frames in the range */
849                                 delete_fcurve_keys(fcu);
850                         }
851                         break;
852                 }
853         }
854         
855         /* just start pasting, with the first keyframe on the current frame, and so on */
856         for (i = 0, bezt = aci->bezt; i < aci->totvert; i++, bezt++) {
857                 /* temporarily apply offset to src beztriple while copying */
858                 if (flip)
859                         do_curve_mirror_flippping(aci, bezt);
860                 
861                 bezt->vec[0][0] += offset;
862                 bezt->vec[1][0] += offset;
863                 bezt->vec[2][0] += offset;
864                 
865                 /* insert the keyframe
866                  * NOTE: we do not want to inherit handles from existing keyframes in this case!
867                  */
868                 
869                 insert_bezt_fcurve(fcu, bezt, INSERTKEY_OVERWRITE_FULL);
870                 
871                 /* un-apply offset from src beztriple after copying */
872                 bezt->vec[0][0] -= offset;
873                 bezt->vec[1][0] -= offset;
874                 bezt->vec[2][0] -= offset;
875                 
876                 if (flip)
877                         do_curve_mirror_flippping(aci, bezt);
878         }
879         
880         /* recalculate F-Curve's handles? */
881         calchandles_fcurve(fcu);
882 }
883
884 /* ------------------- */
885
886 EnumPropertyItem rna_enum_keyframe_paste_offset_items[] = {
887         {KEYFRAME_PASTE_OFFSET_CFRA_START, "START", 0, "Frame Start", "Paste keys starting at current frame"},
888         {KEYFRAME_PASTE_OFFSET_CFRA_END, "END", 0, "Frame End", "Paste keys ending at current frame"},
889         {KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE, "RELATIVE", 0, "Frame Relative", "Paste keys relative to the current frame when copying"},
890         {KEYFRAME_PASTE_OFFSET_NONE, "NONE", 0, "No Offset", "Paste keys from original time"},
891         {0, NULL, 0, NULL, NULL}};
892
893 EnumPropertyItem rna_enum_keyframe_paste_merge_items[] = {
894         {KEYFRAME_PASTE_MERGE_MIX, "MIX", 0, "Mix", "Overlay existing with new keys"},
895         {KEYFRAME_PASTE_MERGE_OVER, "OVER_ALL", 0, "Overwrite All", "Replace all keys"},
896         {KEYFRAME_PASTE_MERGE_OVER_RANGE, "OVER_RANGE", 0, "Overwrite Range", "Overwrite keys in pasted range"},
897         {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"},
898         {0, NULL, 0, NULL, NULL}};
899
900
901 /**
902  * This function pastes data from the keyframes copy/paste buffer
903  *
904  * \return Status code is whether the method FAILED to do anything
905  */
906 short paste_animedit_keys(bAnimContext *ac, ListBase *anim_data,
907                           const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode, bool flip)
908 {
909         bAnimListElem *ale;
910         
911         const Scene *scene = (ac->scene);
912         
913         const bool from_single = BLI_listbase_is_single(&animcopybuf);
914         const bool to_simple = BLI_listbase_is_single(anim_data);
915         
916         float offset = 0.0f;
917         int pass;
918
919         /* check if buffer is empty */
920         if (BLI_listbase_is_empty(&animcopybuf)) {
921                 BKE_report(ac->reports, RPT_ERROR, "No animation data in buffer to paste");
922                 return -1;
923         }
924
925         if (BLI_listbase_is_empty(anim_data)) {
926                 BKE_report(ac->reports, RPT_ERROR, "No selected F-Curves to paste into");
927                 return -1;
928         }
929         
930         /* methods of offset */
931         switch (offset_mode) {
932                 case KEYFRAME_PASTE_OFFSET_CFRA_START:
933                         offset = (float)(CFRA - animcopy_firstframe);
934                         break;
935                 case KEYFRAME_PASTE_OFFSET_CFRA_END:
936                         offset = (float)(CFRA - animcopy_lastframe);
937                         break;
938                 case KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE:
939                         offset = (float)(CFRA - animcopy_cfra);
940                         break;
941                 case KEYFRAME_PASTE_OFFSET_NONE:
942                         offset = 0.0f;
943                         break;
944         }
945
946         if (from_single && to_simple) {
947                 /* 1:1 match, no tricky checking, just paste */
948                 FCurve *fcu;
949                 tAnimCopybufItem *aci;
950                 
951                 ale = anim_data->first;
952                 fcu = (FCurve *)ale->data;  /* destination F-Curve */
953                 aci = animcopybuf.first;
954                 
955                 paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, false);
956                 ale->update |= ANIM_UPDATE_DEFAULT;
957         }
958         else {
959                 /* from selected channels 
960                  *  This "passes" system aims to try to find "matching" channels to paste keyframes
961                  *  into with increasingly loose matching heuristics. The process finishes when at least
962                  *  one F-Curve has been pasted into.
963                  */
964                 for (pass = 0; pass < 3; pass++) {
965                         unsigned int totmatch = 0;
966                         
967                         for (ale = anim_data->first; ale; ale = ale->next) {
968                                 /* find buffer item to paste from 
969                                  *      - if names don't matter (i.e. only 1 channel in buffer), don't check id/group
970                                  *      - if names do matter, only check if id-type is ok for now (group check is not that important)
971                                  *      - most importantly, rna-paths should match (array indices are unimportant for now)
972                                  */
973                                 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
974                                 FCurve *fcu = (FCurve *)ale->data;  /* destination F-Curve */
975                                 tAnimCopybufItem *aci = NULL;
976                                 
977                                 switch (pass) {
978                                         case 0:
979                                                 /* most strict, must be exact path match data_path & index */
980                                                 aci = pastebuf_match_path_full(fcu, from_single, to_simple, flip);
981                                                 break;
982                                         
983                                         case 1:
984                                                 /* less strict, just compare property names */
985                                                 aci = pastebuf_match_path_property(fcu, from_single, to_simple);
986                                                 break;
987                                         
988                                         case 2:
989                                                 /* Comparing properties gave no results, so just do index comparisons */
990                                                 aci = pastebuf_match_index_only(fcu, from_single, to_simple);
991                                                 break;
992                                 }
993                                 
994                                 /* copy the relevant data from the matching buffer curve */
995                                 if (aci) {
996                                         totmatch++;
997                                         
998                                         if (adt) {
999                                                 ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
1000                                                 paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, flip);
1001                                                 ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
1002                                         }
1003                                         else {
1004                                                 paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, flip);
1005                                         }
1006                                 }
1007                                 
1008                                 ale->update |= ANIM_UPDATE_DEFAULT;
1009                         }
1010                         
1011                         /* don't continue if some fcurves were pasted */
1012                         if (totmatch)
1013                                 break;
1014                 }
1015         }
1016         
1017         ANIM_animdata_update(ac, anim_data);
1018
1019         return 0;
1020 }
1021
1022 /* **************************************************** */