Mesh Animation + Depsgraph Tweaks:
[blender.git] / source / blender / editors / animation / keyframes_edit.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  *
22  * Contributor(s): Joshua Leung
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 #include <stdlib.h>
28 #include <string.h>
29 #include <math.h>
30 #include <float.h>
31
32 #include "MEM_guardedalloc.h"
33
34 #include "BLI_blenlib.h"
35 #include "BLI_math.h"
36
37 #include "DNA_anim_types.h"
38 #include "DNA_action_types.h"
39 #include "DNA_armature_types.h"
40 #include "DNA_camera_types.h"
41 #include "DNA_curve_types.h"
42 #include "DNA_key_types.h"
43 #include "DNA_lamp_types.h"
44 #include "DNA_mesh_types.h"
45 #include "DNA_material_types.h"
46 #include "DNA_object_types.h"
47 #include "DNA_meta_types.h"
48 #include "DNA_node_types.h"
49 #include "DNA_particle_types.h"
50 #include "DNA_space_types.h"
51 #include "DNA_scene_types.h"
52 #include "DNA_world_types.h"
53
54 #include "BKE_action.h"
55 #include "BKE_fcurve.h"
56 #include "BKE_key.h"
57 #include "BKE_material.h"
58 #include "BKE_utildefines.h"
59
60 #include "ED_anim_api.h"
61 #include "ED_keyframes_edit.h"
62 #include "ED_markers.h"
63
64 /* This file defines an API and set of callback-operators for non-destructive editing of keyframe data.
65  *
66  * Two API functions are defined for actually performing the operations on the data:
67  *                      ANIM_fcurve_keys_bezier_loop()
68  * which take the data they operate on, a few callbacks defining what operations to perform.
69  *
70  * As operators which work on keyframes usually apply the same operation on all BezTriples in 
71  * every channel, the code has been optimised providing a set of functions which will get the 
72  * appropriate bezier-modify function to set. These functions (ANIM_editkeyframes_*) will need
73  * to be called before getting any channels.
74  * 
75  * A set of 'validation' callbacks are provided for checking if a BezTriple should be operated on.
76  * These should only be used when using a 'general' BezTriple editor (i.e. selection setters which 
77  * don't check existing selection status).
78  * 
79  * - Joshua Leung, Dec 2008
80  */
81
82 /* ************************************************************************** */
83 /* Keyframe Editing Loops - Exposed API */
84
85 /* --------------------------- Base Functions ------------------------------------ */
86
87 /* This function is used to loop over BezTriples in the given F-Curve, applying a given 
88  * operation on them, and optionally applies an F-Curve validation function afterwards.
89  */
90 short ANIM_fcurve_keys_bezier_loop(BeztEditData *bed, FCurve *fcu, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, FcuEditFunc fcu_cb) 
91 {
92     BezTriple *bezt;
93         int b;
94         
95         /* sanity check */
96         if (ELEM(NULL, fcu, fcu->bezt))
97                 return 0;
98         
99         /* if function to apply to bezier curves is set, then loop through executing it on beztriples */
100     if (bezt_cb) {
101                 /* if there's a validation func, include that check in the loop 
102                  * (this is should be more efficient than checking for it in every loop)
103                  */
104                 if (bezt_ok) {
105                         for (b=0, bezt=fcu->bezt; b < fcu->totvert; b++, bezt++) {
106                                 /* Only operate on this BezTriple if it fullfills the criteria of the validation func */
107                                 if (bezt_ok(bed, bezt)) {
108                                         /* Exit with return-code '1' if function returns positive
109                                          * This is useful if finding if some BezTriple satisfies a condition.
110                                          */
111                                 if (bezt_cb(bed, bezt)) return 1;
112                                 }
113                         }
114                 }
115                 else {
116                         for (b=0, bezt=fcu->bezt; b < fcu->totvert; b++, bezt++) {
117                                 /* Exit with return-code '1' if function returns positive
118                                  * This is useful if finding if some BezTriple satisfies a condition.
119                                  */
120                         if (bezt_cb(bed, bezt)) return 1;
121                         }
122                 }
123     }
124
125     /* if fcu_cb (F-Curve post-editing callback) has been specified then execute it */
126     if (fcu_cb)
127         fcu_cb(fcu);
128         
129         /* done */      
130     return 0;
131 }
132
133 /* -------------------------------- Further Abstracted (Not Exposed Directly) ----------------------------- */
134
135 /* This function is used to loop over the keyframe data in an Action Group */
136 static short agrp_keys_bezier_loop(BeztEditData *bed, bActionGroup *agrp, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, FcuEditFunc fcu_cb)
137 {
138         FCurve *fcu;
139         
140         /* sanity check */
141         if (agrp == NULL)
142                 return 0;
143         
144         /* only iterate over the F-Curves that are in this group */
145         for (fcu= agrp->channels.first; fcu && fcu->grp==agrp; fcu= fcu->next) {
146                 if (ANIM_fcurve_keys_bezier_loop(bed, fcu, bezt_ok, bezt_cb, fcu_cb))
147                         return 1;
148         }
149         
150         return 0;
151 }
152
153 /* This function is used to loop over the keyframe data in an Action */
154 static short act_keys_bezier_loop(BeztEditData *bed, bAction *act, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, FcuEditFunc fcu_cb)
155 {
156         FCurve *fcu;
157         
158         /* sanity check */
159         if (act == NULL)
160                 return 0;
161         
162         /* just loop through all F-Curves */
163         for (fcu= act->curves.first; fcu; fcu= fcu->next) {
164                 if (ANIM_fcurve_keys_bezier_loop(bed, fcu, bezt_ok, bezt_cb, fcu_cb))
165                         return 1;
166         }
167         
168         return 0;
169 }
170
171 /* This function is used to loop over the keyframe data of an AnimData block */
172 static short adt_keys_bezier_loop(BeztEditData *bed, AnimData *adt, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, FcuEditFunc fcu_cb, int filterflag)
173 {
174         /* sanity check */
175         if (adt == NULL)
176                 return 0;
177         
178         /* drivers or actions? */
179         if (filterflag & ADS_FILTER_ONLYDRIVERS) {
180                 FCurve *fcu;
181                 
182                 /* just loop through all F-Curves acting as Drivers */
183                 for (fcu= adt->drivers.first; fcu; fcu= fcu->next) {
184                         if (ANIM_fcurve_keys_bezier_loop(bed, fcu, bezt_ok, bezt_cb, fcu_cb))
185                                 return 1;
186                 }
187         }
188         else if (adt->action) {
189                 /* call the function for actions */
190                 if (act_keys_bezier_loop(bed, adt->action, bezt_ok, bezt_cb, fcu_cb))
191                         return 1;
192         }
193         
194         return 0;
195 }
196
197 /* This function is used to loop over the keyframe data in an Object */
198 static short ob_keys_bezier_loop(BeztEditData *bed, Object *ob, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, FcuEditFunc fcu_cb, int filterflag)
199 {
200         Key *key= ob_get_key(ob);
201         
202         /* sanity check */
203         if (ob == NULL)
204                 return 0;
205         
206         /* firstly, Object's own AnimData */
207         if (ob->adt) {
208                 if (adt_keys_bezier_loop(bed, ob->adt, bezt_ok, bezt_cb, fcu_cb, filterflag))
209                         return 1;
210         }
211         
212         /* shapekeys */
213         if ((key && key->adt) && !(filterflag & ADS_FILTER_NOSHAPEKEYS)) {
214                 if (adt_keys_bezier_loop(bed, key->adt, bezt_ok, bezt_cb, fcu_cb, filterflag))
215                         return 1;
216         }
217                 
218         /* Add material keyframes */
219         if ((ob->totcol) && !(filterflag & ADS_FILTER_NOMAT)) {
220                 int a;
221                 
222                 for (a=0; a < ob->totcol; a++) {
223                         Material *ma= give_current_material(ob, a);
224                         
225                         /* there might not be a material */
226                         if (ELEM(NULL, ma, ma->adt)) 
227                                 continue;
228                         
229                         /* add material's data */
230                         if (adt_keys_bezier_loop(bed, ma->adt, bezt_ok, bezt_cb, fcu_cb, filterflag))
231                                 return 1;
232                 }
233         }
234         
235         /* Add object data keyframes */
236         switch (ob->type) {
237                 case OB_CAMERA: /* ------- Camera ------------ */
238                 {
239                         Camera *ca= (Camera *)ob->data;
240                         
241                         if ((ca->adt) && !(filterflag & ADS_FILTER_NOCAM)) {
242                                 if (adt_keys_bezier_loop(bed, ca->adt, bezt_ok, bezt_cb, fcu_cb, filterflag))
243                                         return 1;
244                         }
245                 }
246                         break;
247                 case OB_LAMP: /* ---------- Lamp ----------- */
248                 {
249                         Lamp *la= (Lamp *)ob->data;
250                         
251                         if ((la->adt) && !(filterflag & ADS_FILTER_NOLAM)) {
252                                 if (adt_keys_bezier_loop(bed, la->adt, bezt_ok, bezt_cb, fcu_cb, filterflag))
253                                         return 1;
254                         }
255                 }
256                         break;
257                 case OB_CURVE: /* ------- Curve ---------- */
258                 case OB_SURF: /* ------- Nurbs Surface ---------- */
259                 case OB_FONT: /* ------- Text Curve ---------- */
260                 {
261                         Curve *cu= (Curve *)ob->data;
262                         
263                         if ((cu->adt) && !(filterflag & ADS_FILTER_NOCUR)) {
264                                 if (adt_keys_bezier_loop(bed, cu->adt, bezt_ok, bezt_cb, fcu_cb, filterflag))
265                                         return 1;
266                         }
267                 }
268                         break;
269                 case OB_MBALL: /* ------- MetaBall ---------- */
270                 {
271                         MetaBall *mb= (MetaBall *)ob->data;
272                         
273                         if ((mb->adt) && !(filterflag & ADS_FILTER_NOMBA)) {
274                                 if (adt_keys_bezier_loop(bed, mb->adt, bezt_ok, bezt_cb, fcu_cb, filterflag))
275                                         return 1;
276                         }
277                 }
278                         break;
279                 case OB_ARMATURE: /* ------- Armature ---------- */
280                 {
281                         bArmature *arm= (bArmature *)ob->data;
282                         
283                         if ((arm->adt) && !(filterflag & ADS_FILTER_NOARM)) {
284                                 if (adt_keys_bezier_loop(bed, arm->adt, bezt_ok, bezt_cb, fcu_cb, filterflag))
285                                         return 1;
286                         }
287                 }
288                         break;
289                 case OB_MESH: /* ------- Mesh ---------- */
290                 {
291                         Mesh *me= (Mesh *)ob->data;
292                         
293                         if ((me->adt) && !(filterflag & ADS_FILTER_NOMESH)) {
294                                 if (adt_keys_bezier_loop(bed, me->adt, bezt_ok, bezt_cb, fcu_cb, filterflag))
295                                         return 1;
296                         }
297                 }
298                         break;
299         }
300         
301         /* Add Particle System Keyframes */
302         if ((ob->particlesystem.first) && !(filterflag & ADS_FILTER_NOPART)) {
303                 ParticleSystem *psys = ob->particlesystem.first;
304                 
305                 for(; psys; psys=psys->next) {
306                         if (ELEM(NULL, psys->part, psys->part->adt))
307                                 continue;
308                                 
309                         if (adt_keys_bezier_loop(bed, psys->part->adt, bezt_ok, bezt_cb, fcu_cb, filterflag))
310                                 return 1;
311                 }
312         }
313         
314         return 0;
315 }
316
317 /* This function is used to loop over the keyframe data in a Scene */
318 static short scene_keys_bezier_loop(BeztEditData *bed, Scene *sce, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, FcuEditFunc fcu_cb, int filterflag)
319 {
320         World *wo= (sce) ? sce->world : NULL;
321         bNodeTree *ntree= (sce) ? sce->nodetree : NULL;
322         
323         /* sanity check */
324         if (sce == NULL)
325                 return 0;
326         
327         /* Scene's own animation */
328         if (sce->adt) {
329                 if (adt_keys_bezier_loop(bed, sce->adt, bezt_ok, bezt_cb, fcu_cb, filterflag))
330                         return 1;
331         }
332         
333         /* World */
334         if (wo && wo->adt) {
335                 if (adt_keys_bezier_loop(bed, wo->adt, bezt_ok, bezt_cb, fcu_cb, filterflag))
336                         return 1;
337         }
338         
339         /* NodeTree */
340         if (ntree && ntree->adt) {
341                 if (adt_keys_bezier_loop(bed, ntree->adt, bezt_ok, bezt_cb, fcu_cb, filterflag))
342                         return 1;
343         }
344         
345         
346         return 0;
347 }
348
349 /* This function is used to loop over the keyframe data in a DopeSheet summary */
350 static short summary_keys_bezier_loop(BeztEditData *bed, bAnimContext *ac, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, FcuEditFunc fcu_cb, int filterflag)
351 {
352         ListBase anim_data = {NULL, NULL};
353         bAnimListElem *ale;
354         int filter, ret_code=0;
355         
356         /* sanity check */
357         if (ac == NULL)
358                 return 0;
359         
360         /* get F-Curves to take keyframes from */
361         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY);
362         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
363         
364         /* loop through each F-Curve, working on the keyframes until the first curve aborts */
365         for (ale= anim_data.first; ale; ale= ale->next) {
366                 ret_code= ANIM_fcurve_keys_bezier_loop(bed, ale->data, bezt_ok, bezt_cb, fcu_cb);
367                 
368                 if (ret_code)
369                         break;
370         }
371         
372         BLI_freelistN(&anim_data);
373         
374         return ret_code;
375 }
376
377 /* --- */
378
379 /* This function is used to apply operation to all keyframes, regardless of the type */
380 short ANIM_animchannel_keys_bezier_loop(BeztEditData *bed, bAnimListElem *ale, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, FcuEditFunc fcu_cb, int filterflag)
381 {
382         /* sanity checks */
383         if (ale == NULL)
384                 return 0;
385         
386         /* method to use depends on the type of keyframe data */
387         switch (ale->datatype) {
388                 /* direct keyframe data (these loops are exposed) */
389                 case ALE_FCURVE: /* F-Curve */
390                         return ANIM_fcurve_keys_bezier_loop(bed, ale->key_data, bezt_ok, bezt_cb, fcu_cb);
391                 
392                 /* indirect 'summaries' (these are not exposed directly) 
393                  * NOTE: must keep this code in sync with the drawing code and also the filtering code!
394                  */
395                 case ALE_GROUP: /* action group */
396                         return agrp_keys_bezier_loop(bed, (bActionGroup *)ale->data, bezt_ok, bezt_cb, fcu_cb);
397                 case ALE_ACT: /* action */
398                         return act_keys_bezier_loop(bed, (bAction *)ale->key_data, bezt_ok, bezt_cb, fcu_cb);
399                         
400                 case ALE_OB: /* object */
401                         return ob_keys_bezier_loop(bed, (Object *)ale->key_data, bezt_ok, bezt_cb, fcu_cb, filterflag);
402                 case ALE_SCE: /* scene */
403                         return scene_keys_bezier_loop(bed, (Scene *)ale->data, bezt_ok, bezt_cb, fcu_cb, filterflag);
404                 case ALE_ALL: /* 'all' (DopeSheet summary) */
405                         return summary_keys_bezier_loop(bed, (bAnimContext *)ale->data, bezt_ok, bezt_cb, fcu_cb, filterflag);
406         }
407         
408         return 0;
409 }
410
411 /* This function is used to apply operation to all keyframes, regardless of the type without needed an AnimListElem wrapper */
412 short ANIM_animchanneldata_keys_bezier_loop(BeztEditData *bed, void *data, int keytype, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, FcuEditFunc fcu_cb, int filterflag)
413 {
414         /* sanity checks */
415         if (data == NULL)
416                 return 0;
417         
418         /* method to use depends on the type of keyframe data */
419         switch (keytype) {
420                 /* direct keyframe data (these loops are exposed) */
421                 case ALE_FCURVE: /* F-Curve */
422                         return ANIM_fcurve_keys_bezier_loop(bed, data, bezt_ok, bezt_cb, fcu_cb);
423                 
424                 /* indirect 'summaries' (these are not exposed directly) 
425                  * NOTE: must keep this code in sync with the drawing code and also the filtering code!
426                  */
427                 case ALE_GROUP: /* action group */
428                         return agrp_keys_bezier_loop(bed, (bActionGroup *)data, bezt_ok, bezt_cb, fcu_cb);
429                 case ALE_ACT: /* action */
430                         return act_keys_bezier_loop(bed, (bAction *)data, bezt_ok, bezt_cb, fcu_cb);
431                         
432                 case ALE_OB: /* object */
433                         return ob_keys_bezier_loop(bed, (Object *)data, bezt_ok, bezt_cb, fcu_cb, filterflag);
434                 case ALE_SCE: /* scene */
435                         return scene_keys_bezier_loop(bed, (Scene *)data, bezt_ok, bezt_cb, fcu_cb, filterflag);
436                 case ALE_ALL: /* 'all' (DopeSheet summary) */
437                         return summary_keys_bezier_loop(bed, (bAnimContext *)data, bezt_ok, bezt_cb, fcu_cb, filterflag);
438         }
439         
440         return 0;
441 }
442
443 /* ************************************************************************** */
444 /* Keyframe Integrity Tools */
445
446 /* Rearrange keyframes if some are out of order */
447 // used to be recalc_*_ipos() where * was object or action
448 void ANIM_editkeyframes_refresh(bAnimContext *ac)
449 {
450         ListBase anim_data = {NULL, NULL};
451         bAnimListElem *ale;
452         int filter;
453         
454         /* filter animation data */
455         filter= ANIMFILTER_CURVESONLY; 
456         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
457         
458         /* loop over ipo-curves that are likely to have been edited, and check them */
459         for (ale= anim_data.first; ale; ale= ale->next) {
460                 FCurve *fcu= ale->key_data;
461                 
462                 /* make sure keyframes in F-curve are all in order, and handles are in valid positions */
463                 sort_time_fcurve(fcu);
464                 testhandles_fcurve(fcu);
465         }
466         
467         /* free temp data */
468         BLI_freelistN(&anim_data);
469 }
470
471 /* ************************************************************************** */
472 /* BezTriple Validation Callbacks */
473
474 static short ok_bezier_frame(BeztEditData *bed, BezTriple *bezt)
475 {
476         /* frame is stored in f1 property (this float accuracy check may need to be dropped?) */
477         return IS_EQ(bezt->vec[1][0], bed->f1);
478 }
479
480 static short ok_bezier_framerange(BeztEditData *bed, BezTriple *bezt)
481 {
482         /* frame range is stored in float properties */
483         return ((bezt->vec[1][0] > bed->f1) && (bezt->vec[1][0] < bed->f2));
484 }
485
486 static short ok_bezier_selected(BeztEditData *bed, BezTriple *bezt)
487 {
488         /* this macro checks all beztriple handles for selection... */
489         return BEZSELECTED(bezt);
490 }
491
492 static short ok_bezier_value(BeztEditData *bed, BezTriple *bezt)
493 {
494         /* value is stored in f1 property 
495          *      - this float accuracy check may need to be dropped?
496          *      - should value be stored in f2 instead so that we won't have conflicts when using f1 for frames too?
497          */
498         return IS_EQ(bezt->vec[1][1], bed->f1);
499 }
500
501 static short ok_bezier_valuerange(BeztEditData *bed, BezTriple *bezt)
502 {
503         /* value range is stored in float properties */
504         return ((bezt->vec[1][1] > bed->f1) && (bezt->vec[1][1] < bed->f2));
505 }
506
507 static short ok_bezier_region(BeztEditData *bed, BezTriple *bezt)
508 {
509         /* rect is stored in data property (it's of type rectf, but may not be set) */
510         if (bed->data)
511                 return BLI_in_rctf(bed->data, bezt->vec[1][0], bezt->vec[1][1]);
512         else 
513                 return 0;
514 }
515
516
517 BeztEditFunc ANIM_editkeyframes_ok(short mode)
518 {
519         /* eEditKeyframes_Validate */
520         switch (mode) {
521                 case BEZT_OK_FRAME: /* only if bezt falls on the right frame (float) */
522                         return ok_bezier_frame;
523                 case BEZT_OK_FRAMERANGE: /* only if bezt falls within the specified frame range (floats) */
524                         return ok_bezier_framerange;
525                 case BEZT_OK_SELECTED:  /* only if bezt is selected (self) */
526                         return ok_bezier_selected;
527                 case BEZT_OK_VALUE: /* only if bezt value matches (float) */
528                         return ok_bezier_value;
529                 case BEZT_OK_VALUERANGE: /* only if bezier falls within the specified value range (floats) */
530                         return ok_bezier_valuerange;
531                 case BEZT_OK_REGION: /* only if bezier falls within the specified rect (data -> rectf) */
532                         return ok_bezier_region;
533                 default: /* nothing was ok */
534                         return NULL;
535         }
536 }
537
538 /* ******************************************* */
539 /* Assorted Utility Functions */
540
541 /* helper callback for <animeditor>_cfrasnap_exec() -> used to help get the average time of all selected beztriples */
542 short bezt_calc_average(BeztEditData *bed, BezTriple *bezt)
543 {
544         /* only if selected */
545         if (bezt->f2 & SELECT) {
546                 /* store average time in float 1 (only do rounding at last step) */
547                 bed->f1 += bezt->vec[1][0];
548                 
549                 /* store average value in float 2 (only do rounding at last step) 
550                  *      - this isn't always needed, but some operators may also require this
551                  */
552                 bed->f2 += bezt->vec[1][1];
553                 
554                 /* increment number of items */
555                 bed->i1++;
556         }
557         
558         return 0;
559 }
560
561 /* helper callback for columnselect_<animeditor>_keys() -> populate list CfraElems with frame numbers from selected beztriples */
562 short bezt_to_cfraelem(BeztEditData *bed, BezTriple *bezt)
563 {
564         /* only if selected */
565         if (bezt->f2 & SELECT) {
566                 CfraElem *ce= MEM_callocN(sizeof(CfraElem), "cfraElem");
567                 BLI_addtail(&bed->list, ce);
568                 
569                 ce->cfra= bezt->vec[1][0];
570         }
571         
572         return 0;
573 }
574
575 /* used to remap times from one range to another
576  * requires:  bed->data = BeztEditCD_Remap      
577  */
578 void bezt_remap_times(BeztEditData *bed, BezTriple *bezt)
579 {
580         BeztEditCD_Remap *rmap= (BeztEditCD_Remap*)bed->data;
581         const float scale = (rmap->newMax - rmap->newMin) / (rmap->oldMax - rmap->oldMin);
582         
583         /* perform transform on all three handles unless indicated otherwise */
584         // TODO: need to include some checks for that
585         
586         bezt->vec[0][0]= scale*(bezt->vec[0][0] - rmap->oldMin) + rmap->newMin;
587         bezt->vec[1][0]= scale*(bezt->vec[1][0] - rmap->oldMin) + rmap->newMin;
588         bezt->vec[2][0]= scale*(bezt->vec[2][0] - rmap->oldMin) + rmap->newMin;
589 }
590
591 /* ******************************************* */
592 /* Transform */
593
594 static short snap_bezier_nearest(BeztEditData *bed, BezTriple *bezt)
595 {
596         if (bezt->f2 & SELECT)
597                 bezt->vec[1][0]= (float)(floor(bezt->vec[1][0]+0.5));
598         return 0;
599 }
600
601 static short snap_bezier_nearestsec(BeztEditData *bed, BezTriple *bezt)
602 {
603         const Scene *scene= bed->scene;
604         const float secf = (float)FPS;
605         
606         if (bezt->f2 & SELECT)
607                 bezt->vec[1][0]= ((float)floor(bezt->vec[1][0]/secf + 0.5f) * secf);
608         return 0;
609 }
610
611 static short snap_bezier_cframe(BeztEditData *bed, BezTriple *bezt)
612 {
613         const Scene *scene= bed->scene;
614         if (bezt->f2 & SELECT)
615                 bezt->vec[1][0]= (float)CFRA;
616         return 0;
617 }
618
619 static short snap_bezier_nearmarker(BeztEditData *bed, BezTriple *bezt)
620 {
621         if (bezt->f2 & SELECT)
622                 bezt->vec[1][0]= (float)ED_markers_find_nearest_marker_time(&bed->list, bezt->vec[1][0]);
623         return 0;
624 }
625
626 static short snap_bezier_horizontal(BeztEditData *bed, BezTriple *bezt)
627 {
628         if (bezt->f2 & SELECT) {
629                 bezt->vec[0][1]= bezt->vec[2][1]= (float)floor(bezt->vec[1][1] + 0.5f);
630                 if ((bezt->h1==HD_AUTO) || (bezt->h1==HD_VECT)) bezt->h1= HD_ALIGN;
631                 if ((bezt->h2==HD_AUTO) || (bezt->h2==HD_VECT)) bezt->h2= HD_ALIGN;
632         }
633         return 0;       
634 }
635
636 static short snap_bezier_value(BeztEditData *bed, BezTriple *bezt)
637 {
638         /* value to snap to is stored in the custom data -> first float value slot */
639         if (bezt->f2 & SELECT)
640                 bezt->vec[1][1]= bed->f1;
641         return 0;
642 }
643
644 BeztEditFunc ANIM_editkeyframes_snap(short type)
645 {
646         /* eEditKeyframes_Snap */
647         switch (type) {
648                 case SNAP_KEYS_NEARFRAME: /* snap to nearest frame */
649                         return snap_bezier_nearest;
650                 case SNAP_KEYS_CURFRAME: /* snap to current frame */
651                         return snap_bezier_cframe;
652                 case SNAP_KEYS_NEARMARKER: /* snap to nearest marker */
653                         return snap_bezier_nearmarker;
654                 case SNAP_KEYS_NEARSEC: /* snap to nearest second */
655                         return snap_bezier_nearestsec;
656                 case SNAP_KEYS_HORIZONTAL: /* snap handles to same value */
657                         return snap_bezier_horizontal;
658                 case SNAP_KEYS_VALUE: /* snap to given value */
659                         return snap_bezier_value;
660                 default: /* just in case */
661                         return snap_bezier_nearest;
662         }
663 }
664
665 /* --------- */
666
667 static short mirror_bezier_cframe(BeztEditData *bed, BezTriple *bezt)
668 {
669         const Scene *scene= bed->scene;
670         float diff;
671         
672         if (bezt->f2 & SELECT) {
673                 diff= ((float)CFRA - bezt->vec[1][0]);
674                 bezt->vec[1][0]= ((float)CFRA + diff);
675         }
676         
677         return 0;
678 }
679
680 static short mirror_bezier_yaxis(BeztEditData *bed, BezTriple *bezt)
681 {
682         float diff;
683         
684         if (bezt->f2 & SELECT) {
685                 diff= (0.0f - bezt->vec[1][0]);
686                 bezt->vec[1][0]= (0.0f + diff);
687         }
688         
689         return 0;
690 }
691
692 static short mirror_bezier_xaxis(BeztEditData *bed, BezTriple *bezt)
693 {
694         float diff;
695         
696         if (bezt->f2 & SELECT) {
697                 diff= (0.0f - bezt->vec[1][1]);
698                 bezt->vec[1][1]= (0.0f + diff);
699         }
700         
701         return 0;
702 }
703
704 static short mirror_bezier_marker(BeztEditData *bed, BezTriple *bezt)
705 {
706         /* mirroring time stored in f1 */
707         if (bezt->f2 & SELECT) {
708                 const float diff= (bed->f1 - bezt->vec[1][0]);
709                 bezt->vec[1][0]= (bed->f1 + diff);
710         }
711         
712         return 0;
713 }
714
715 static short mirror_bezier_value(BeztEditData *bed, BezTriple *bezt)
716 {
717         float diff;
718         
719         /* value to mirror over is stored in the custom data -> first float value slot */
720         if (bezt->f2 & SELECT) {
721                 diff= (bed->f1 - bezt->vec[1][1]);
722                 bezt->vec[1][1]= (bed->f1 + diff);
723         }
724         
725         return 0;
726 }
727
728 /* Note: for markers and 'value', the values to use must be supplied as the first float value */
729 // calchandles_fcurve
730 BeztEditFunc ANIM_editkeyframes_mirror(short type)
731 {
732         switch (type) {
733                 case MIRROR_KEYS_CURFRAME: /* mirror over current frame */
734                         return mirror_bezier_cframe;
735                 case MIRROR_KEYS_YAXIS: /* mirror over frame 0 */
736                         return mirror_bezier_yaxis;
737                 case MIRROR_KEYS_XAXIS: /* mirror over value 0 */
738                         return mirror_bezier_xaxis;
739                 case MIRROR_KEYS_MARKER: /* mirror over marker */
740                         return mirror_bezier_marker; 
741                 case MIRROR_KEYS_VALUE: /* mirror over given value */
742                         return mirror_bezier_value;
743                 default: /* just in case */
744                         return mirror_bezier_yaxis;
745                         break;
746         }
747 }
748
749 /* ******************************************* */
750 /* Settings */
751
752 /* Sets the selected bezier handles to type 'auto' */
753 static short set_bezier_auto(BeztEditData *bed, BezTriple *bezt) 
754 {
755         if((bezt->f1  & SELECT) || (bezt->f3 & SELECT)) {
756                 if (bezt->f1 & SELECT) bezt->h1= 1; /* the secret code for auto */
757                 if (bezt->f3 & SELECT) bezt->h2= 1;
758                 
759                 /* if the handles are not of the same type, set them
760                  * to type free
761                  */
762                 if (bezt->h1 != bezt->h2) {
763                         if ELEM(bezt->h1, HD_ALIGN, HD_AUTO) bezt->h1= HD_FREE;
764                         if ELEM(bezt->h2, HD_ALIGN, HD_AUTO) bezt->h2= HD_FREE;
765                 }
766         }
767         return 0;
768 }
769
770 /* Sets the selected bezier handles to type 'vector'  */
771 static short set_bezier_vector(BeztEditData *bed, BezTriple *bezt) 
772 {
773         if ((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) {
774                 if (bezt->f1 & SELECT) bezt->h1= HD_VECT;
775                 if (bezt->f3 & SELECT) bezt->h2= HD_VECT;
776                 
777                 /* if the handles are not of the same type, set them
778                  * to type free
779                  */
780                 if (bezt->h1 != bezt->h2) {
781                         if ELEM(bezt->h1, HD_ALIGN, HD_AUTO) bezt->h1= HD_FREE;
782                         if ELEM(bezt->h2, HD_ALIGN, HD_AUTO) bezt->h2= HD_FREE;
783                 }
784         }
785         return 0;
786 }
787
788 /* Queries if the handle should be set to 'free' or 'align' */
789 static short bezier_isfree(BeztEditData *bed, BezTriple *bezt) 
790 {
791         if ((bezt->f1 & SELECT) && (bezt->h1)) return 1;
792         if ((bezt->f3 & SELECT) && (bezt->h2)) return 1;
793         return 0;
794 }
795
796 /* Sets selected bezier handles to type 'align' */
797 static short set_bezier_align(BeztEditData *bed, BezTriple *bezt) 
798 {       
799         if (bezt->f1 & SELECT) bezt->h1= HD_ALIGN;
800         if (bezt->f3 & SELECT) bezt->h2= HD_ALIGN;
801         return 0;
802 }
803
804 /* Sets selected bezier handles to type 'free'  */
805 static short set_bezier_free(BeztEditData *bed, BezTriple *bezt) 
806 {
807         if (bezt->f1 & SELECT) bezt->h1= HD_FREE;
808         if (bezt->f3 & SELECT) bezt->h2= HD_FREE;
809         return 0;
810 }
811
812 /* Set all Bezier Handles to a single type */
813 // calchandles_fcurve
814 BeztEditFunc ANIM_editkeyframes_handles(short code)
815 {
816         switch (code) {
817                 case HD_AUTO: /* auto */
818                         return set_bezier_auto;
819                 case HD_VECT: /* vector */
820                         return set_bezier_vector;
821                 case HD_FREE: /* free */
822                         return set_bezier_free;
823                 case HD_ALIGN: /* align */
824                         return set_bezier_align;
825                 
826                 default: /* free or align? */
827                         return bezier_isfree;
828         }
829 }
830
831 /* ------- */
832
833 static short set_bezt_constant(BeztEditData *bed, BezTriple *bezt) 
834 {
835         if (bezt->f2 & SELECT) 
836                 bezt->ipo= BEZT_IPO_CONST;
837         return 0;
838 }
839
840 static short set_bezt_linear(BeztEditData *bed, BezTriple *bezt) 
841 {
842         if (bezt->f2 & SELECT) 
843                 bezt->ipo= BEZT_IPO_LIN;
844         return 0;
845 }
846
847 static short set_bezt_bezier(BeztEditData *bed, BezTriple *bezt) 
848 {
849         if (bezt->f2 & SELECT) 
850                 bezt->ipo= BEZT_IPO_BEZ;
851         return 0;
852 }
853
854 /* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
855 // ANIM_editkeyframes_ipocurve_ipotype() !
856 BeztEditFunc ANIM_editkeyframes_ipo(short code)
857 {
858         switch (code) {
859                 case BEZT_IPO_CONST: /* constant */
860                         return set_bezt_constant;
861                 case BEZT_IPO_LIN: /* linear */ 
862                         return set_bezt_linear;
863                 default: /* bezier */
864                         return set_bezt_bezier;
865         }
866 }
867
868 /* ------- */
869
870 static short set_keytype_keyframe(BeztEditData *bed, BezTriple *bezt) 
871 {
872         if (bezt->f2 & SELECT) 
873                 BEZKEYTYPE(bezt)= BEZT_KEYTYPE_KEYFRAME;
874         return 0;
875 }
876
877 static short set_keytype_breakdown(BeztEditData *bed, BezTriple *bezt) 
878 {
879         if (bezt->f2 & SELECT) 
880                 BEZKEYTYPE(bezt)= BEZT_KEYTYPE_BREAKDOWN;
881         return 0;
882 }
883
884 static short set_keytype_extreme(BeztEditData *bed, BezTriple *bezt) 
885 {
886         if (bezt->f2 & SELECT) 
887                 BEZKEYTYPE(bezt)= BEZT_KEYTYPE_EXTREME;
888         return 0;
889 }
890
891 /* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
892 BeztEditFunc ANIM_editkeyframes_keytype(short code)
893 {
894         switch (code) {
895                 case BEZT_KEYTYPE_BREAKDOWN: /* breakdown */
896                         return set_keytype_breakdown;
897                         
898                 case BEZT_KEYTYPE_EXTREME: /* extreme keyframe */
899                         return set_keytype_extreme;
900                         
901                 case BEZT_KEYTYPE_KEYFRAME: /* proper keyframe */       
902                 default:
903                         return set_keytype_keyframe;
904         }
905 }
906
907 /* ******************************************* */
908 /* Selection */
909
910 static short select_bezier_add(BeztEditData *bed, BezTriple *bezt) 
911 {
912         /* Select the bezier triple */
913         BEZ_SEL(bezt);
914         return 0;
915 }
916
917 static short select_bezier_subtract(BeztEditData *bed, BezTriple *bezt) 
918 {
919         /* Deselect the bezier triple */
920         BEZ_DESEL(bezt);
921         return 0;
922 }
923
924 static short select_bezier_invert(BeztEditData *bed, BezTriple *bezt) 
925 {
926         /* Invert the selection for the bezier triple */
927         bezt->f2 ^= SELECT;
928         if (bezt->f2 & SELECT) {
929                 bezt->f1 |= SELECT;
930                 bezt->f3 |= SELECT;
931         }
932         else {
933                 bezt->f1 &= ~SELECT;
934                 bezt->f3 &= ~SELECT;
935         }
936         return 0;
937 }
938
939 // NULL
940 BeztEditFunc ANIM_editkeyframes_select(short selectmode)
941 {
942         switch (selectmode) {
943                 case SELECT_ADD: /* add */
944                         return select_bezier_add;
945                 case SELECT_SUBTRACT: /* subtract */
946                         return select_bezier_subtract;
947                 case SELECT_INVERT: /* invert */
948                         return select_bezier_invert;
949                 default: /* replace (need to clear all, then add) */
950                         return select_bezier_add;
951         }
952 }