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