Keyframe-related bugfixes:
[blender-staging.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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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_arithb.h"
37
38 #include "DNA_anim_types.h"
39 #include "DNA_action_types.h"
40 #include "DNA_curve_types.h"
41 #include "DNA_ipo_types.h" // XXX to be removed
42 #include "DNA_key_types.h"
43 #include "DNA_object_types.h"
44 #include "DNA_space_types.h"
45 #include "DNA_scene_types.h"
46
47 #include "BKE_action.h"
48 #include "BKE_fcurve.h"
49 #include "BKE_key.h"
50 #include "BKE_utildefines.h"
51
52 #include "ED_anim_api.h"
53 #include "ED_keyframing.h"
54 #include "ED_keyframes_edit.h"
55
56 /* This file contains code for various keyframe-editing tools which are 'destructive'
57  * (i.e. they will modify the order of the keyframes, and change the size of the array).
58  * While some of these tools may eventually be moved out into blenkernel, for now, it is
59  * fine to have these calls here.
60  * 
61  * There are also a few tools here which cannot be easily coded for in the other system (yet).
62  * These may also be moved around at some point, but for now, they 
63  *
64  * - Joshua Leung, Dec 2008
65  */
66  
67 /* **************************************************** */
68
69 /* Only delete the nominated keyframe from provided ipo-curve. 
70  * Not recommended to be used many times successively. For that
71  * there is delete_ipo_keys(). 
72  */
73 void delete_fcurve_key(FCurve *fcu, int index, short do_recalc)
74 {
75         /* firstly check that index is valid */
76         if (index < 0) 
77                 index *= -1;
78         if (fcu == NULL) 
79                 return;
80         if (index >= fcu->totvert)
81                 return;
82         
83         /*      Delete this key */
84         memmove(&fcu->bezt[index], &fcu->bezt[index+1], sizeof(BezTriple)*(fcu->totvert-index-1));
85         fcu->totvert--;
86         
87         /* recalc handles - only if it won't cause problems */
88         if (do_recalc)
89                 calchandles_fcurve(fcu);
90 }
91
92 /* Delete selected keyframes in given F-Curve */
93 void delete_fcurve_keys(FCurve *fcu)
94 {
95         int i;
96         
97         /* Delete selected BezTriples */
98         for (i=0; i < fcu->totvert; i++) {
99                 if (fcu->bezt[i].f2 & SELECT) {
100                         memmove(&fcu->bezt[i], &fcu->bezt[i+1], sizeof(BezTriple)*(fcu->totvert-i-1));
101                         fcu->totvert--;
102                         i--;
103                 }
104         }
105         
106         /* Free the array of BezTriples if there are not keyframes */
107         if (fcu->totvert == 0) {
108                 if (fcu->bezt) 
109                         MEM_freeN(fcu->bezt);
110                 fcu->bezt= NULL;
111         }
112         
113 #if 0 // XXX for now, we don't get rid of empty curves...
114         /* Only delete if there isn't an ipo-driver still hanging around on an empty curve */
115         if ((icu->totvert==0) && (icu->driver==NULL)) {
116                 BLI_remlink(&ipo->curve, icu);
117                 free_ipo_curve(icu);
118         }
119 #endif 
120 }
121
122 /* ---------------- */
123
124 /* duplicate selected keyframes for the given F-Curve */
125 void duplicate_fcurve_keys(FCurve *fcu)
126 {
127         BezTriple *newbezt;
128         int i;
129
130         if (fcu == NULL)
131                 return;
132         
133         // XXX this does not take into account sample data...
134         for (i=0; i < fcu->totvert; i++) {
135                 /* If a key is selected */
136                 if (fcu->bezt[i].f2 & SELECT) {
137                         /* Expand the list */
138                         newbezt = MEM_callocN(sizeof(BezTriple) * (fcu->totvert+1), "beztriple");
139                         
140                         memcpy(newbezt, fcu->bezt, sizeof(BezTriple) * (i+1));
141                         memcpy(newbezt+i+1, fcu->bezt+i, sizeof(BezTriple));
142                         memcpy(newbezt+i+2, fcu->bezt+i+1, sizeof (BezTriple) *(fcu->totvert-(i+1)));
143                         fcu->totvert++;
144                         
145                         /* reassign pointers... (free old, and add new) */
146                         MEM_freeN(fcu->bezt);
147                         fcu->bezt=newbezt;
148                         
149                         /* Unselect the current key */
150                         BEZ_DESEL(&fcu->bezt[i]);
151                         i++;
152                         
153                         /* Select the copied key */
154                         BEZ_SEL(&fcu->bezt[i]);
155                 }
156         }
157 }
158
159 /* **************************************************** */
160 /* Various Tools */
161
162 /* Basic IPO-Curve 'cleanup' function that removes 'double points' and unnecessary keyframes on linear-segments only */
163 void clean_fcurve(FCurve *fcu, float thresh)
164 {
165         BezTriple *old_bezts, *bezt, *beztn;
166         BezTriple *lastb;
167         int totCount, i;
168         
169         /* check if any points  */
170         if ((fcu == NULL) || (fcu->totvert <= 1)) 
171                 return;
172         
173         /* make a copy of the old BezTriples, and clear IPO curve */
174         old_bezts = fcu->bezt;
175         totCount = fcu->totvert;        
176         fcu->bezt = NULL;
177         fcu->totvert = 0;
178         
179         /* now insert first keyframe, as it should be ok */
180         bezt = old_bezts;
181         insert_vert_fcurve(fcu, bezt->vec[1][0], bezt->vec[1][1], 0);
182         
183         /* Loop through BezTriples, comparing them. Skip any that do 
184          * not fit the criteria for "ok" points.
185          */
186         for (i=1; i<totCount; i++) {    
187                 float prev[2], cur[2], next[2];
188                 
189                 /* get BezTriples and their values */
190                 if (i < (totCount - 1)) {
191                         beztn = (old_bezts + (i+1));
192                         next[0]= beztn->vec[1][0]; next[1]= beztn->vec[1][1];
193                 }
194                 else {
195                         beztn = NULL;
196                         next[0] = next[1] = 0.0f;
197                 }
198                 lastb= (fcu->bezt + (fcu->totvert - 1));
199                 bezt= (old_bezts + i);
200                 
201                 /* get references for quicker access */
202                 prev[0] = lastb->vec[1][0]; prev[1] = lastb->vec[1][1];
203                 cur[0] = bezt->vec[1][0]; cur[1] = bezt->vec[1][1];
204                 
205                 /* check if current bezt occurs at same time as last ok */
206                 if (IS_EQT(cur[0], prev[0], thresh)) {
207                         /* If there is a next beztriple, and if occurs at the same time, only insert 
208                          * if there is a considerable distance between the points, and also if the 
209                          * current is further away than the next one is to the previous.
210                          */
211                         if (beztn && (IS_EQT(cur[0], next[0], thresh)) && 
212                                 (IS_EQT(next[1], prev[1], thresh)==0)) 
213                         {
214                                 /* only add if current is further away from previous */
215                                 if (cur[1] > next[1]) {
216                                         if (IS_EQT(cur[1], prev[1], thresh) == 0) {
217                                                 /* add new keyframe */
218                                                 insert_vert_fcurve(fcu, cur[0], cur[1], 0);
219                                         }
220                                 }
221                         }
222                         else {
223                                 /* only add if values are a considerable distance apart */
224                                 if (IS_EQT(cur[1], prev[1], thresh) == 0) {
225                                         /* add new keyframe */
226                                         insert_vert_fcurve(fcu, cur[0], cur[1], 0);
227                                 }
228                         }
229                 }
230                 else {
231                         /* checks required are dependent on whether this is last keyframe or not */
232                         if (beztn) {
233                                 /* does current have same value as previous and next? */
234                                 if (IS_EQT(cur[1], prev[1], thresh) == 0) {
235                                         /* add new keyframe*/
236                                         insert_vert_fcurve(fcu, cur[0], cur[1], 0);
237                                 }
238                                 else if (IS_EQT(cur[1], next[1], thresh) == 0) {
239                                         /* add new keyframe */
240                                         insert_vert_fcurve(fcu, cur[0], cur[1], 0);
241                                 }
242                         }
243                         else {  
244                                 /* add if value doesn't equal that of previous */
245                                 if (IS_EQT(cur[1], prev[1], thresh) == 0) {
246                                         /* add new keyframe */
247                                         insert_vert_fcurve(fcu, cur[0], cur[1], 0);
248                                 }
249                         }
250                 }
251         }
252         
253         /* now free the memory used by the old BezTriples */
254         if (old_bezts)
255                 MEM_freeN(old_bezts);
256 }
257
258 /* ---------------- */
259
260 /* temp struct used for smooth_ipo */
261 typedef struct tSmooth_Bezt {
262         float *h1, *h2, *h3;    /* bezt->vec[0,1,2][1] */
263 } tSmooth_Bezt;
264
265 /* Use a weighted moving-means method to reduce intensity of fluctuations */
266 void smooth_fcurve (FCurve *fcu)
267 {
268         BezTriple *bezt;
269         int i, x, totSel = 0;
270         
271         /* first loop through - count how many verts are selected, and fix up handles 
272          *      this is done for both modes
273          */
274         bezt= fcu->bezt;
275         for (i=0; i < fcu->totvert; i++, bezt++) {                                              
276                 if (BEZSELECTED(bezt)) {                                                        
277                         /* line point's handles up with point's vertical position */
278                         bezt->vec[0][1]= bezt->vec[2][1]= bezt->vec[1][1];
279                         if ((bezt->h1==HD_AUTO) || (bezt->h1==HD_VECT)) bezt->h1= HD_ALIGN;
280                         if ((bezt->h2==HD_AUTO) || (bezt->h2==HD_VECT)) bezt->h2= HD_ALIGN;
281                         
282                         /* add value to total */
283                         totSel++;
284                 }
285         }
286         
287                 /* if any points were selected, allocate tSmooth_Bezt points to work on */
288                 if (totSel >= 3) {
289                         tSmooth_Bezt *tarray, *tsb;
290                         
291                         /* allocate memory in one go */
292                         tsb= tarray= MEM_callocN(totSel*sizeof(tSmooth_Bezt), "tSmooth_Bezt Array");
293                         
294                         /* populate tarray with data of selected points */
295                         bezt= fcu->bezt;
296                         for (i=0, x=0; (i < fcu->totvert) && (x < totSel); i++, bezt++) {
297                                 if (BEZSELECTED(bezt)) {
298                                         /* tsb simply needs pointer to vec, and index */
299                                         tsb->h1 = &bezt->vec[0][1];
300                                         tsb->h2 = &bezt->vec[1][1];
301                                         tsb->h3 = &bezt->vec[2][1];
302                                         
303                                         /* advance to the next tsb to populate */
304                                         if (x < totSel- 1) 
305                                                 tsb++;
306                                         else
307                                                 break;
308                                 }
309                         }
310                         
311         /* calculate the new smoothed F-Curve's with weighted averages:
312          *      - this is done with two passes
313          *      - uses 5 points for each operation (which stores in the relevant handles)
314          *      -       previous: w/a ratio = 3:5:2:1:1
315          *      -       next: w/a ratio = 1:1:2:5:3
316          */
317         
318         /* round 1: calculate previous and next */ 
319         tsb= tarray;
320         for (i=0; i < totSel; i++, tsb++) {
321                 /* don't touch end points (otherwise, curves slowly explode) */
322                 if (ELEM(i, 0, (totSel-1)) == 0) {
323                         const tSmooth_Bezt *tP1 = tsb - 1;
324                         const tSmooth_Bezt *tP2 = (i-2 > 0) ? (tsb - 2) : (NULL);
325                         const tSmooth_Bezt *tN1 = tsb + 1;
326                         const tSmooth_Bezt *tN2 = (i+2 < totSel) ? (tsb + 2) : (NULL);
327                         
328                         const float p1 = *tP1->h2;
329                         const float p2 = (tP2) ? (*tP2->h2) : (*tP1->h2);
330                         const float c1 = *tsb->h2;
331                         const float n1 = *tN1->h2;
332                         const float n2 = (tN2) ? (*tN2->h2) : (*tN1->h2);
333                         
334                         /* calculate previous and next */
335                         *tsb->h1= (3*p2 + 5*p1 + 2*c1 + n1 + n2) / 12;
336                         *tsb->h3= (p2 + p1 + 2*c1 + 5*n1 + 3*n2) / 12;
337                 }
338         }
339         
340         /* round 2: calculate new values and reset handles */
341         tsb= tarray;
342         for (i=0; i < totSel; i++, tsb++) {
343                 /* calculate new position by averaging handles */
344                 *tsb->h2 = (*tsb->h1 + *tsb->h3) / 2;
345                 
346                 /* reset handles now */
347                 *tsb->h1 = *tsb->h2;
348                 *tsb->h3 = *tsb->h2;
349         }
350         
351         /* free memory required for tarray */
352         MEM_freeN(tarray);
353 }
354         
355         /* recalculate handles */
356         calchandles_fcurve(fcu);
357 }
358
359 /* **************************************************** */