Animato - More work on Action Editor
[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 #if 0 // XXX for now, we don't get rid of empty curves...
107         /* Only delete if there isn't an ipo-driver still hanging around on an empty curve */
108         if ((icu->totvert==0) && (icu->driver==NULL)) {
109                 BLI_remlink(&ipo->curve, icu);
110                 free_ipo_curve(icu);
111         }
112 #endif 
113 }
114
115 /* ---------------- */
116
117 /* duplicate selected keyframes for the given F-Curve */
118 void duplicate_fcurve_keys(FCurve *fcu)
119 {
120         BezTriple *newbezt;
121         int i;
122
123         if (fcu == NULL)
124                 return;
125         
126         // XXX this does not take into account sample data...
127         for (i=0; i < fcu->totvert; i++) {
128                 /* If a key is selected */
129                 if (fcu->bezt[i].f2 & SELECT) {
130                         /* Expand the list */
131                         newbezt = MEM_callocN(sizeof(BezTriple) * (fcu->totvert+1), "beztriple");
132                         
133                         memcpy(newbezt, fcu->bezt, sizeof(BezTriple) * (i+1));
134                         memcpy(newbezt+i+1, fcu->bezt+i, sizeof(BezTriple));
135                         memcpy(newbezt+i+2, fcu->bezt+i+1, sizeof (BezTriple) *(fcu->totvert-(i+1)));
136                         fcu->totvert++;
137                         
138                         /* reassign pointers... (free old, and add new) */
139                         MEM_freeN(fcu->bezt);
140                         fcu->bezt=newbezt;
141                         
142                         /* Unselect the current key */
143                         BEZ_DESEL(&fcu->bezt[i]);
144                         i++;
145                         
146                         /* Select the copied key */
147                         BEZ_SEL(&fcu->bezt[i]);
148                 }
149         }
150 }
151
152 /* **************************************************** */
153 /* Various Tools */
154
155 // XXX - stub... until keyframing code is fixed...
156 static void insert_vert_fcu(FCurve *fcu, float x, float y, short flag)
157 {
158 }
159
160 /* Basic IPO-Curve 'cleanup' function that removes 'double points' and unnecessary keyframes on linear-segments only */
161 void clean_fcurve(FCurve *fcu, float thresh)
162 {
163         BezTriple *old_bezts, *bezt, *beztn;
164         BezTriple *lastb;
165         int totCount, i;
166         
167         /* check if any points  */
168         if ((fcu == NULL) || (fcu->totvert <= 1)) 
169                 return;
170         
171         /* make a copy of the old BezTriples, and clear IPO curve */
172         old_bezts = fcu->bezt;
173         totCount = fcu->totvert;        
174         fcu->bezt = NULL;
175         fcu->totvert = 0;
176         
177         /* now insert first keyframe, as it should be ok */
178         bezt = old_bezts;
179         insert_vert_fcu(fcu, bezt->vec[1][0], bezt->vec[1][1], 0);
180         
181         /* Loop through BezTriples, comparing them. Skip any that do 
182          * not fit the criteria for "ok" points.
183          */
184         for (i=1; i<totCount; i++) {    
185                 float prev[2], cur[2], next[2];
186                 
187                 /* get BezTriples and their values */
188                 if (i < (totCount - 1)) {
189                         beztn = (old_bezts + (i+1));
190                         next[0]= beztn->vec[1][0]; next[1]= beztn->vec[1][1];
191                 }
192                 else {
193                         beztn = NULL;
194                         next[0] = next[1] = 0.0f;
195                 }
196                 lastb= (fcu->bezt + (fcu->totvert - 1));
197                 bezt= (old_bezts + i);
198                 
199                 /* get references for quicker access */
200                 prev[0] = lastb->vec[1][0]; prev[1] = lastb->vec[1][1];
201                 cur[0] = bezt->vec[1][0]; cur[1] = bezt->vec[1][1];
202                 
203                 /* check if current bezt occurs at same time as last ok */
204                 if (IS_EQT(cur[0], prev[0], thresh)) {
205                         /* If there is a next beztriple, and if occurs at the same time, only insert 
206                          * if there is a considerable distance between the points, and also if the 
207                          * current is further away than the next one is to the previous.
208                          */
209                         if (beztn && (IS_EQT(cur[0], next[0], thresh)) && 
210                                 (IS_EQT(next[1], prev[1], thresh)==0)) 
211                         {
212                                 /* only add if current is further away from previous */
213                                 if (cur[1] > next[1]) {
214                                         if (IS_EQT(cur[1], prev[1], thresh) == 0) {
215                                                 /* add new keyframe */
216                                                 insert_vert_fcu(fcu, cur[0], cur[1], 0);
217                                         }
218                                 }
219                         }
220                         else {
221                                 /* only add if values are a considerable distance apart */
222                                 if (IS_EQT(cur[1], prev[1], thresh) == 0) {
223                                         /* add new keyframe */
224                                         insert_vert_fcu(fcu, cur[0], cur[1], 0);
225                                 }
226                         }
227                 }
228                 else {
229                         /* checks required are dependent on whether this is last keyframe or not */
230                         if (beztn) {
231                                 /* does current have same value as previous and next? */
232                                 if (IS_EQT(cur[1], prev[1], thresh) == 0) {
233                                         /* add new keyframe*/
234                                         insert_vert_fcu(fcu, cur[0], cur[1], 0);
235                                 }
236                                 else if (IS_EQT(cur[1], next[1], thresh) == 0) {
237                                         /* add new keyframe */
238                                         insert_vert_fcu(fcu, cur[0], cur[1], 0);
239                                 }
240                         }
241                         else {  
242                                 /* add if value doesn't equal that of previous */
243                                 if (IS_EQT(cur[1], prev[1], thresh) == 0) {
244                                         /* add new keyframe */
245                                         insert_vert_fcu(fcu, cur[0], cur[1], 0);
246                                 }
247                         }
248                 }
249         }
250         
251         /* now free the memory used by the old BezTriples */
252         if (old_bezts)
253                 MEM_freeN(old_bezts);
254 }
255
256 /* ---------------- */
257
258 /* temp struct used for smooth_ipo */
259 typedef struct tSmooth_Bezt {
260         float *h1, *h2, *h3;    /* bezt->vec[0,1,2][1] */
261 } tSmooth_Bezt;
262
263 /* Use a weighted moving-means method to reduce intensity of fluctuations */
264 //mode= pupmenu("Smooth F-Curve%t|Tweak Points%x1|Flatten Handles%x2");
265 void smooth_fcurve(FCurve *fcu, short mode)
266 {
267         BezTriple *bezt;
268         int i, x, totSel = 0;
269         
270         /* first loop through - count how many verts are selected, and fix up handles 
271          *      this is done for both modes
272          */
273         bezt= fcu->bezt;
274         for (i=0; i < fcu->totvert; i++, bezt++) {                                              
275                 if (BEZSELECTED(bezt)) {                                                        
276                         /* line point's handles up with point's vertical position */
277                         bezt->vec[0][1]= bezt->vec[2][1]= bezt->vec[1][1];
278                         if ((bezt->h1==HD_AUTO) || (bezt->h1==HD_VECT)) bezt->h1= HD_ALIGN;
279                         if ((bezt->h2==HD_AUTO) || (bezt->h2==HD_VECT)) bezt->h2= HD_ALIGN;
280                         
281                         /* add value to total */
282                         totSel++;
283                 }
284         }
285         
286         /* check if adjust values too... */
287         if (mode == 2) {
288                 /* if any points were selected, allocate tSmooth_Bezt points to work on */
289                 if (totSel >= 3) {
290                         tSmooth_Bezt *tarray, *tsb;
291                         
292                         /* allocate memory in one go */
293                         tsb= tarray= MEM_callocN(totSel*sizeof(tSmooth_Bezt), "tSmooth_Bezt Array");
294                         
295                         /* populate tarray with data of selected points */
296                         bezt= fcu->bezt;
297                         for (i=0, x=0; (i < fcu->totvert) && (x < totSel); i++, bezt++) {
298                                 if (BEZSELECTED(bezt)) {
299                                         /* tsb simply needs pointer to vec, and index */
300                                         tsb->h1 = &bezt->vec[0][1];
301                                         tsb->h2 = &bezt->vec[1][1];
302                                         tsb->h3 = &bezt->vec[2][1];
303                                         
304                                         /* advance to the next tsb to populate */
305                                         if (x < totSel- 1) 
306                                                 tsb++;
307                                         else
308                                                 break;
309                                 }
310                         }
311                         
312                         /* calculate the new smoothed ipo's with weighted averages:
313                          *      - this is done with two passes
314                          *      - uses 5 points for each operation (which stores in the relevant handles)
315                          *      -       previous: w/a ratio = 3:5:2:1:1
316                          *      -       next: w/a ratio = 1:1:2:5:3
317                          */
318                         
319                         /* round 1: calculate previous and next */ 
320                         tsb= tarray;
321                         for (i=0; i < totSel; i++, tsb++) {
322                                 /* don't touch end points (otherwise, curves slowly explode) */
323                                 if (ELEM(i, 0, (totSel-1)) == 0) {
324                                         const tSmooth_Bezt *tP1 = tsb - 1;
325                                         const tSmooth_Bezt *tP2 = (i-2 > 0) ? (tsb - 2) : (NULL);
326                                         const tSmooth_Bezt *tN1 = tsb + 1;
327                                         const tSmooth_Bezt *tN2 = (i+2 < totSel) ? (tsb + 2) : (NULL);
328                                         
329                                         const float p1 = *tP1->h2;
330                                         const float p2 = (tP2) ? (*tP2->h2) : (*tP1->h2);
331                                         const float c1 = *tsb->h2;
332                                         const float n1 = *tN1->h2;
333                                         const float n2 = (tN2) ? (*tN2->h2) : (*tN1->h2);
334                                         
335                                         /* calculate previous and next */
336                                         *tsb->h1= (3*p2 + 5*p1 + 2*c1 + n1 + n2) / 12;
337                                         *tsb->h3= (p2 + p1 + 2*c1 + 5*n1 + 3*n2) / 12;
338                                 }
339                         }
340                         
341                         /* round 2: calculate new values and reset handles */
342                         tsb= tarray;
343                         for (i=0; i < totSel; i++, tsb++) {
344                                 /* calculate new position by averaging handles */
345                                 *tsb->h2 = (*tsb->h1 + *tsb->h3) / 2;
346                                 
347                                 /* reset handles now */
348                                 *tsb->h1 = *tsb->h2;
349                                 *tsb->h3 = *tsb->h2;
350                         }
351                         
352                         /* free memory required for tarray */
353                         MEM_freeN(tarray);
354                 }
355         }
356         
357         /* recalculate handles */
358         calchandles_fcurve(fcu);
359 }
360
361 /* **************************************************** */