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