Fix syntax for ID keyword.
[blender-staging.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 i;
94         
95         /* sanity check */
96         if (ELEM(NULL, fcu, fcu->bezt))
97                 return 0;
98         
99         /* set the F-Curve into the editdata so that it can be accessed */
100         if (bed) {
101                 bed->fcu= fcu;
102                 bed->curIndex= 0;
103         }
104         
105         /* if function to apply to bezier curves is set, then loop through executing it on beztriples */
106         if (bezt_cb) {
107                 /* if there's a validation func, include that check in the loop 
108                  * (this is should be more efficient than checking for it in every loop)
109                  */
110                 if (bezt_ok) {
111                         for (bezt=fcu->bezt, i=0; i < fcu->totvert; bezt++, i++) {
112                                 if (bed) bed->curIndex= i;
113                                 
114                                 /* Only operate on this BezTriple if it fullfills the criteria of the validation func */
115                                 if (bezt_ok(bed, bezt)) {
116                                         /* Exit with return-code '1' if function returns positive
117                                          * This is useful if finding if some BezTriple satisfies a condition.
118                                          */
119                                         if (bezt_cb(bed, bezt)) return 1;
120                                 }
121                         }
122                 }
123                 else {
124                         for (bezt=fcu->bezt, i=0; i < fcu->totvert; bezt++, i++) {
125                                 if (bed) bed->curIndex= i;
126                                 
127                                 /* Exit with return-code '1' if function returns positive
128                                  * This is useful if finding if some BezTriple satisfies a condition.
129                                  */
130                                 if (bezt_cb(bed, bezt)) return 1;
131                         }
132                 }
133          }
134         
135         /* unset the F-Curve from the editdata now that it's done */
136         if (bed) {
137                 bed->fcu= NULL;
138                 bed->curIndex= 0;
139         }
140
141         /* if fcu_cb (F-Curve post-editing callback) has been specified then execute it */
142         if (fcu_cb)
143                 fcu_cb(fcu);
144         
145         /* done */      
146         return 0;
147 }
148
149 /* -------------------------------- Further Abstracted (Not Exposed Directly) ----------------------------- */
150
151 /* This function is used to loop over the keyframe data in an Action Group */
152 static short agrp_keys_bezier_loop(BeztEditData *bed, bActionGroup *agrp, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, FcuEditFunc fcu_cb)
153 {
154         FCurve *fcu;
155         
156         /* sanity check */
157         if (agrp == NULL)
158                 return 0;
159         
160         /* only iterate over the F-Curves that are in this group */
161         for (fcu= agrp->channels.first; fcu && fcu->grp==agrp; fcu= fcu->next) {
162                 if (ANIM_fcurve_keys_bezier_loop(bed, fcu, bezt_ok, bezt_cb, fcu_cb))
163                         return 1;
164         }
165         
166         return 0;
167 }
168
169 /* This function is used to loop over the keyframe data in an Action */
170 static short act_keys_bezier_loop(BeztEditData *bed, bAction *act, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, FcuEditFunc fcu_cb)
171 {
172         FCurve *fcu;
173         
174         /* sanity check */
175         if (act == NULL)
176                 return 0;
177         
178         /* just loop through all F-Curves */
179         for (fcu= act->curves.first; fcu; fcu= fcu->next) {
180                 if (ANIM_fcurve_keys_bezier_loop(bed, fcu, bezt_ok, bezt_cb, fcu_cb))
181                         return 1;
182         }
183         
184         return 0;
185 }
186
187 /* This function is used to loop over the keyframe data of an AnimData block */
188 static short adt_keys_bezier_loop(BeztEditData *bed, AnimData *adt, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, FcuEditFunc fcu_cb, int filterflag)
189 {
190         /* sanity check */
191         if (adt == NULL)
192                 return 0;
193         
194         /* drivers or actions? */
195         if (filterflag & ADS_FILTER_ONLYDRIVERS) {
196                 FCurve *fcu;
197                 
198                 /* just loop through all F-Curves acting as Drivers */
199                 for (fcu= adt->drivers.first; fcu; fcu= fcu->next) {
200                         if (ANIM_fcurve_keys_bezier_loop(bed, fcu, bezt_ok, bezt_cb, fcu_cb))
201                                 return 1;
202                 }
203         }
204         else if (adt->action) {
205                 /* call the function for actions */
206                 if (act_keys_bezier_loop(bed, adt->action, bezt_ok, bezt_cb, fcu_cb))
207                         return 1;
208         }
209         
210         return 0;
211 }
212
213 /* This function is used to loop over the keyframe data in an Object */
214 static short ob_keys_bezier_loop(BeztEditData *bed, Object *ob, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, FcuEditFunc fcu_cb, int filterflag)
215 {
216         Key *key= ob_get_key(ob);
217         
218         /* sanity check */
219         if (ob == NULL)
220                 return 0;
221         
222         /* firstly, Object's own AnimData */
223         if (ob->adt) {
224                 if (adt_keys_bezier_loop(bed, ob->adt, bezt_ok, bezt_cb, fcu_cb, filterflag))
225                         return 1;
226         }
227         
228         /* shapekeys */
229         if ((key && key->adt) && !(filterflag & ADS_FILTER_NOSHAPEKEYS)) {
230                 if (adt_keys_bezier_loop(bed, key->adt, bezt_ok, bezt_cb, fcu_cb, filterflag))
231                         return 1;
232         }
233                 
234         /* Add material keyframes */
235         if ((ob->totcol) && !(filterflag & ADS_FILTER_NOMAT)) {
236                 int a;
237                 
238                 for (a=1; a <= ob->totcol; a++) {
239                         Material *ma= give_current_material(ob, a);
240                         
241                         /* there might not be a material */
242                         if (ELEM(NULL, ma, ma->adt)) 
243                                 continue;
244                         
245                         /* add material's data */
246                         if (adt_keys_bezier_loop(bed, ma->adt, bezt_ok, bezt_cb, fcu_cb, filterflag))
247                                 return 1;
248                 }
249         }
250         
251         /* Add object data keyframes */
252         switch (ob->type) {
253                 case OB_CAMERA: /* ------- Camera ------------ */
254                 {
255                         Camera *ca= (Camera *)ob->data;
256                         
257                         if ((ca->adt) && !(filterflag & ADS_FILTER_NOCAM)) {
258                                 if (adt_keys_bezier_loop(bed, ca->adt, bezt_ok, bezt_cb, fcu_cb, filterflag))
259                                         return 1;
260                         }
261                 }
262                         break;
263                 case OB_LAMP: /* ---------- Lamp ----------- */
264                 {
265                         Lamp *la= (Lamp *)ob->data;
266                         
267                         if ((la->adt) && !(filterflag & ADS_FILTER_NOLAM)) {
268                                 if (adt_keys_bezier_loop(bed, la->adt, bezt_ok, bezt_cb, fcu_cb, filterflag))
269                                         return 1;
270                         }
271                 }
272                         break;
273                 case OB_CURVE: /* ------- Curve ---------- */
274                 case OB_SURF: /* ------- Nurbs Surface ---------- */
275                 case OB_FONT: /* ------- Text Curve ---------- */
276                 {
277                         Curve *cu= (Curve *)ob->data;
278                         
279                         if ((cu->adt) && !(filterflag & ADS_FILTER_NOCUR)) {
280                                 if (adt_keys_bezier_loop(bed, cu->adt, bezt_ok, bezt_cb, fcu_cb, filterflag))
281                                         return 1;
282                         }
283                 }
284                         break;
285                 case OB_MBALL: /* ------- MetaBall ---------- */
286                 {
287                         MetaBall *mb= (MetaBall *)ob->data;
288                         
289                         if ((mb->adt) && !(filterflag & ADS_FILTER_NOMBA)) {
290                                 if (adt_keys_bezier_loop(bed, mb->adt, bezt_ok, bezt_cb, fcu_cb, filterflag))
291                                         return 1;
292                         }
293                 }
294                         break;
295                 case OB_ARMATURE: /* ------- Armature ---------- */
296                 {
297                         bArmature *arm= (bArmature *)ob->data;
298                         
299                         if ((arm->adt) && !(filterflag & ADS_FILTER_NOARM)) {
300                                 if (adt_keys_bezier_loop(bed, arm->adt, bezt_ok, bezt_cb, fcu_cb, filterflag))
301                                         return 1;
302                         }
303                 }
304                         break;
305                 case OB_MESH: /* ------- Mesh ---------- */
306                 {
307                         Mesh *me= (Mesh *)ob->data;
308                         
309                         if ((me->adt) && !(filterflag & ADS_FILTER_NOMESH)) {
310                                 if (adt_keys_bezier_loop(bed, me->adt, bezt_ok, bezt_cb, fcu_cb, filterflag))
311                                         return 1;
312                         }
313                 }
314                         break;
315         }
316         
317         /* Add Particle System Keyframes */
318         if ((ob->particlesystem.first) && !(filterflag & ADS_FILTER_NOPART)) {
319                 ParticleSystem *psys = ob->particlesystem.first;
320                 
321                 for(; psys; psys=psys->next) {
322                         if (ELEM(NULL, psys->part, psys->part->adt))
323                                 continue;
324                                 
325                         if (adt_keys_bezier_loop(bed, psys->part->adt, bezt_ok, bezt_cb, fcu_cb, filterflag))
326                                 return 1;
327                 }
328         }
329         
330         return 0;
331 }
332
333 /* This function is used to loop over the keyframe data in a Scene */
334 static short scene_keys_bezier_loop(BeztEditData *bed, Scene *sce, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, FcuEditFunc fcu_cb, int filterflag)
335 {
336         World *wo= (sce) ? sce->world : NULL;
337         bNodeTree *ntree= (sce) ? sce->nodetree : NULL;
338         
339         /* sanity check */
340         if (sce == NULL)
341                 return 0;
342         
343         /* Scene's own animation */
344         if (sce->adt) {
345                 if (adt_keys_bezier_loop(bed, sce->adt, bezt_ok, bezt_cb, fcu_cb, filterflag))
346                         return 1;
347         }
348         
349         /* World */
350         if (wo && wo->adt) {
351                 if (adt_keys_bezier_loop(bed, wo->adt, bezt_ok, bezt_cb, fcu_cb, filterflag))
352                         return 1;
353         }
354         
355         /* NodeTree */
356         if (ntree && ntree->adt) {
357                 if (adt_keys_bezier_loop(bed, ntree->adt, bezt_ok, bezt_cb, fcu_cb, filterflag))
358                         return 1;
359         }
360         
361         
362         return 0;
363 }
364
365 /* This function is used to loop over the keyframe data in a DopeSheet summary */
366 static short summary_keys_bezier_loop(BeztEditData *bed, bAnimContext *ac, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, FcuEditFunc fcu_cb, int filterflag)
367 {
368         ListBase anim_data = {NULL, NULL};
369         bAnimListElem *ale;
370         int filter, ret_code=0;
371         
372         /* sanity check */
373         if (ac == NULL)
374                 return 0;
375         
376         /* get F-Curves to take keyframes from */
377         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY);
378         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
379         
380         /* loop through each F-Curve, working on the keyframes until the first curve aborts */
381         for (ale= anim_data.first; ale; ale= ale->next) {
382                 ret_code= ANIM_fcurve_keys_bezier_loop(bed, ale->data, bezt_ok, bezt_cb, fcu_cb);
383                 
384                 if (ret_code)
385                         break;
386         }
387         
388         BLI_freelistN(&anim_data);
389         
390         return ret_code;
391 }
392
393 /* --- */
394
395 /* This function is used to apply operation to all keyframes, regardless of the type */
396 short ANIM_animchannel_keys_bezier_loop(BeztEditData *bed, bAnimListElem *ale, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, FcuEditFunc fcu_cb, int filterflag)
397 {
398         /* sanity checks */
399         if (ale == NULL)
400                 return 0;
401         
402         /* method to use depends on the type of keyframe data */
403         switch (ale->datatype) {
404                 /* direct keyframe data (these loops are exposed) */
405                 case ALE_FCURVE: /* F-Curve */
406                         return ANIM_fcurve_keys_bezier_loop(bed, ale->key_data, bezt_ok, bezt_cb, fcu_cb);
407                 
408                 /* indirect 'summaries' (these are not exposed directly) 
409                  * NOTE: must keep this code in sync with the drawing code and also the filtering code!
410                  */
411                 case ALE_GROUP: /* action group */
412                         return agrp_keys_bezier_loop(bed, (bActionGroup *)ale->data, bezt_ok, bezt_cb, fcu_cb);
413                 case ALE_ACT: /* action */
414                         return act_keys_bezier_loop(bed, (bAction *)ale->key_data, bezt_ok, bezt_cb, fcu_cb);
415                         
416                 case ALE_OB: /* object */
417                         return ob_keys_bezier_loop(bed, (Object *)ale->key_data, bezt_ok, bezt_cb, fcu_cb, filterflag);
418                 case ALE_SCE: /* scene */
419                         return scene_keys_bezier_loop(bed, (Scene *)ale->data, bezt_ok, bezt_cb, fcu_cb, filterflag);
420                 case ALE_ALL: /* 'all' (DopeSheet summary) */
421                         return summary_keys_bezier_loop(bed, (bAnimContext *)ale->data, bezt_ok, bezt_cb, fcu_cb, filterflag);
422         }
423         
424         return 0;
425 }
426
427 /* This function is used to apply operation to all keyframes, regardless of the type without needed an AnimListElem wrapper */
428 short ANIM_animchanneldata_keys_bezier_loop(BeztEditData *bed, void *data, int keytype, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, FcuEditFunc fcu_cb, int filterflag)
429 {
430         /* sanity checks */
431         if (data == NULL)
432                 return 0;
433         
434         /* method to use depends on the type of keyframe data */
435         switch (keytype) {
436                 /* direct keyframe data (these loops are exposed) */
437                 case ALE_FCURVE: /* F-Curve */
438                         return ANIM_fcurve_keys_bezier_loop(bed, data, bezt_ok, bezt_cb, fcu_cb);
439                 
440                 /* indirect 'summaries' (these are not exposed directly) 
441                  * NOTE: must keep this code in sync with the drawing code and also the filtering code!
442                  */
443                 case ALE_GROUP: /* action group */
444                         return agrp_keys_bezier_loop(bed, (bActionGroup *)data, bezt_ok, bezt_cb, fcu_cb);
445                 case ALE_ACT: /* action */
446                         return act_keys_bezier_loop(bed, (bAction *)data, bezt_ok, bezt_cb, fcu_cb);
447                         
448                 case ALE_OB: /* object */
449                         return ob_keys_bezier_loop(bed, (Object *)data, bezt_ok, bezt_cb, fcu_cb, filterflag);
450                 case ALE_SCE: /* scene */
451                         return scene_keys_bezier_loop(bed, (Scene *)data, bezt_ok, bezt_cb, fcu_cb, filterflag);
452                 case ALE_ALL: /* 'all' (DopeSheet summary) */
453                         return summary_keys_bezier_loop(bed, (bAnimContext *)data, bezt_ok, bezt_cb, fcu_cb, filterflag);
454         }
455         
456         return 0;
457 }
458
459 /* ************************************************************************** */
460 /* Keyframe Integrity Tools */
461
462 /* Rearrange keyframes if some are out of order */
463 // used to be recalc_*_ipos() where * was object or action
464 void ANIM_editkeyframes_refresh(bAnimContext *ac)
465 {
466         ListBase anim_data = {NULL, NULL};
467         bAnimListElem *ale;
468         int filter;
469         
470         /* filter animation data */
471         filter= ANIMFILTER_CURVESONLY; 
472         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
473         
474         /* loop over F-Curves that are likely to have been edited, and check them */
475         for (ale= anim_data.first; ale; ale= ale->next) {
476                 FCurve *fcu= ale->key_data;
477                 
478                 /* make sure keyframes in F-Curve are all in order, and handles are in valid positions */
479                 sort_time_fcurve(fcu);
480                 testhandles_fcurve(fcu);
481         }
482         
483         /* free temp data */
484         BLI_freelistN(&anim_data);
485 }
486
487 /* ************************************************************************** */
488 /* BezTriple Validation Callbacks */
489
490 static short ok_bezier_frame(BeztEditData *bed, BezTriple *bezt)
491 {
492         /* frame is stored in f1 property (this float accuracy check may need to be dropped?) */
493         return IS_EQ(bezt->vec[1][0], bed->f1);
494 }
495
496 static short ok_bezier_framerange(BeztEditData *bed, BezTriple *bezt)
497 {
498         /* frame range is stored in float properties */
499         return ((bezt->vec[1][0] > bed->f1) && (bezt->vec[1][0] < bed->f2));
500 }
501
502 static short ok_bezier_selected(BeztEditData *bed, BezTriple *bezt)
503 {
504         /* this macro checks all beztriple handles for selection... */
505         return BEZSELECTED(bezt);
506 }
507
508 static short ok_bezier_value(BeztEditData *bed, BezTriple *bezt)
509 {
510         /* value is stored in f1 property 
511          *      - this float accuracy check may need to be dropped?
512          *      - should value be stored in f2 instead so that we won't have conflicts when using f1 for frames too?
513          */
514         return IS_EQ(bezt->vec[1][1], bed->f1);
515 }
516
517 static short ok_bezier_valuerange(BeztEditData *bed, BezTriple *bezt)
518 {
519         /* value range is stored in float properties */
520         return ((bezt->vec[1][1] > bed->f1) && (bezt->vec[1][1] < bed->f2));
521 }
522
523 static short ok_bezier_region(BeztEditData *bed, BezTriple *bezt)
524 {
525         /* rect is stored in data property (it's of type rectf, but may not be set) */
526         if (bed->data)
527                 return BLI_in_rctf(bed->data, bezt->vec[1][0], bezt->vec[1][1]);
528         else 
529                 return 0;
530 }
531
532
533 BeztEditFunc ANIM_editkeyframes_ok(short mode)
534 {
535         /* eEditKeyframes_Validate */
536         switch (mode) {
537                 case BEZT_OK_FRAME: /* only if bezt falls on the right frame (float) */
538                         return ok_bezier_frame;
539                 case BEZT_OK_FRAMERANGE: /* only if bezt falls within the specified frame range (floats) */
540                         return ok_bezier_framerange;
541                 case BEZT_OK_SELECTED:  /* only if bezt is selected (self) */
542                         return ok_bezier_selected;
543                 case BEZT_OK_VALUE: /* only if bezt value matches (float) */
544                         return ok_bezier_value;
545                 case BEZT_OK_VALUERANGE: /* only if bezier falls within the specified value range (floats) */
546                         return ok_bezier_valuerange;
547                 case BEZT_OK_REGION: /* only if bezier falls within the specified rect (data -> rectf) */
548                         return ok_bezier_region;
549                 default: /* nothing was ok */
550                         return NULL;
551         }
552 }
553
554 /* ******************************************* */
555 /* Assorted Utility Functions */
556
557 /* helper callback for <animeditor>_cfrasnap_exec() -> used to help get the average time of all selected beztriples */
558 short bezt_calc_average(BeztEditData *bed, BezTriple *bezt)
559 {
560         /* only if selected */
561         if (bezt->f2 & SELECT) {
562                 /* store average time in float 1 (only do rounding at last step) */
563                 bed->f1 += bezt->vec[1][0];
564                 
565                 /* store average value in float 2 (only do rounding at last step) 
566                  *      - this isn't always needed, but some operators may also require this
567                  */
568                 bed->f2 += bezt->vec[1][1];
569                 
570                 /* increment number of items */
571                 bed->i1++;
572         }
573         
574         return 0;
575 }
576
577 /* helper callback for columnselect_<animeditor>_keys() -> populate list CfraElems with frame numbers from selected beztriples */
578 short bezt_to_cfraelem(BeztEditData *bed, BezTriple *bezt)
579 {
580         /* only if selected */
581         if (bezt->f2 & SELECT) {
582                 CfraElem *ce= MEM_callocN(sizeof(CfraElem), "cfraElem");
583                 BLI_addtail(&bed->list, ce);
584                 
585                 ce->cfra= bezt->vec[1][0];
586         }
587         
588         return 0;
589 }
590
591 /* used to remap times from one range to another
592  * requires:  bed->data = BeztEditCD_Remap      
593  */
594 void bezt_remap_times(BeztEditData *bed, BezTriple *bezt)
595 {
596         BeztEditCD_Remap *rmap= (BeztEditCD_Remap*)bed->data;
597         const float scale = (rmap->newMax - rmap->newMin) / (rmap->oldMax - rmap->oldMin);
598         
599         /* perform transform on all three handles unless indicated otherwise */
600         // TODO: need to include some checks for that
601         
602         bezt->vec[0][0]= scale*(bezt->vec[0][0] - rmap->oldMin) + rmap->newMin;
603         bezt->vec[1][0]= scale*(bezt->vec[1][0] - rmap->oldMin) + rmap->newMin;
604         bezt->vec[2][0]= scale*(bezt->vec[2][0] - rmap->oldMin) + rmap->newMin;
605 }
606
607 /* ******************************************* */
608 /* Transform */
609
610 static short snap_bezier_nearest(BeztEditData *bed, BezTriple *bezt)
611 {
612         if (bezt->f2 & SELECT)
613                 bezt->vec[1][0]= (float)(floor(bezt->vec[1][0]+0.5));
614         return 0;
615 }
616
617 static short snap_bezier_nearestsec(BeztEditData *bed, BezTriple *bezt)
618 {
619         const Scene *scene= bed->scene;
620         const float secf = (float)FPS;
621         
622         if (bezt->f2 & SELECT)
623                 bezt->vec[1][0]= ((float)floor(bezt->vec[1][0]/secf + 0.5f) * secf);
624         return 0;
625 }
626
627 static short snap_bezier_cframe(BeztEditData *bed, BezTriple *bezt)
628 {
629         const Scene *scene= bed->scene;
630         if (bezt->f2 & SELECT)
631                 bezt->vec[1][0]= (float)CFRA;
632         return 0;
633 }
634
635 static short snap_bezier_nearmarker(BeztEditData *bed, BezTriple *bezt)
636 {
637         if (bezt->f2 & SELECT)
638                 bezt->vec[1][0]= (float)ED_markers_find_nearest_marker_time(&bed->list, bezt->vec[1][0]);
639         return 0;
640 }
641
642 static short snap_bezier_horizontal(BeztEditData *bed, BezTriple *bezt)
643 {
644         if (bezt->f2 & SELECT) {
645                 // XXX currently this snaps both handles to the nearest horizontal value, but perhaps user just wants to level out handles instead?
646                 bezt->vec[0][1]= bezt->vec[2][1]= (float)floor(bezt->vec[1][1] + 0.5f);
647                 if ((bezt->h1==HD_AUTO) || (bezt->h1==HD_VECT)) bezt->h1= HD_ALIGN;
648                 if ((bezt->h2==HD_AUTO) || (bezt->h2==HD_VECT)) bezt->h2= HD_ALIGN;
649         }
650         return 0;       
651 }
652
653 static short snap_bezier_value(BeztEditData *bed, BezTriple *bezt)
654 {
655         /* value to snap to is stored in the custom data -> first float value slot */
656         if (bezt->f2 & SELECT)
657                 bezt->vec[1][1]= bed->f1;
658         return 0;
659 }
660
661 BeztEditFunc ANIM_editkeyframes_snap(short type)
662 {
663         /* eEditKeyframes_Snap */
664         switch (type) {
665                 case SNAP_KEYS_NEARFRAME: /* snap to nearest frame */
666                         return snap_bezier_nearest;
667                 case SNAP_KEYS_CURFRAME: /* snap to current frame */
668                         return snap_bezier_cframe;
669                 case SNAP_KEYS_NEARMARKER: /* snap to nearest marker */
670                         return snap_bezier_nearmarker;
671                 case SNAP_KEYS_NEARSEC: /* snap to nearest second */
672                         return snap_bezier_nearestsec;
673                 case SNAP_KEYS_HORIZONTAL: /* snap handles to same value */
674                         return snap_bezier_horizontal;
675                 case SNAP_KEYS_VALUE: /* snap to given value */
676                         return snap_bezier_value;
677                 default: /* just in case */
678                         return snap_bezier_nearest;
679         }
680 }
681
682 /* --------- */
683
684 static short mirror_bezier_cframe(BeztEditData *bed, BezTriple *bezt)
685 {
686         const Scene *scene= bed->scene;
687         float diff;
688         
689         if (bezt->f2 & SELECT) {
690                 diff= ((float)CFRA - bezt->vec[1][0]);
691                 bezt->vec[1][0]= ((float)CFRA + diff);
692         }
693         
694         return 0;
695 }
696
697 static short mirror_bezier_yaxis(BeztEditData *bed, BezTriple *bezt)
698 {
699         float diff;
700         
701         if (bezt->f2 & SELECT) {
702                 diff= (0.0f - bezt->vec[1][0]);
703                 bezt->vec[1][0]= (0.0f + diff);
704         }
705         
706         return 0;
707 }
708
709 static short mirror_bezier_xaxis(BeztEditData *bed, BezTriple *bezt)
710 {
711         float diff;
712         
713         if (bezt->f2 & SELECT) {
714                 diff= (0.0f - bezt->vec[1][1]);
715                 bezt->vec[1][1]= (0.0f + diff);
716         }
717         
718         return 0;
719 }
720
721 static short mirror_bezier_marker(BeztEditData *bed, BezTriple *bezt)
722 {
723         /* mirroring time stored in f1 */
724         if (bezt->f2 & SELECT) {
725                 const float diff= (bed->f1 - bezt->vec[1][0]);
726                 bezt->vec[1][0]= (bed->f1 + diff);
727         }
728         
729         return 0;
730 }
731
732 static short mirror_bezier_value(BeztEditData *bed, BezTriple *bezt)
733 {
734         float diff;
735         
736         /* value to mirror over is stored in the custom data -> first float value slot */
737         if (bezt->f2 & SELECT) {
738                 diff= (bed->f1 - bezt->vec[1][1]);
739                 bezt->vec[1][1]= (bed->f1 + diff);
740         }
741         
742         return 0;
743 }
744
745 /* Note: for markers and 'value', the values to use must be supplied as the first float value */
746 // calchandles_fcurve
747 BeztEditFunc ANIM_editkeyframes_mirror(short type)
748 {
749         switch (type) {
750                 case MIRROR_KEYS_CURFRAME: /* mirror over current frame */
751                         return mirror_bezier_cframe;
752                 case MIRROR_KEYS_YAXIS: /* mirror over frame 0 */
753                         return mirror_bezier_yaxis;
754                 case MIRROR_KEYS_XAXIS: /* mirror over value 0 */
755                         return mirror_bezier_xaxis;
756                 case MIRROR_KEYS_MARKER: /* mirror over marker */
757                         return mirror_bezier_marker; 
758                 case MIRROR_KEYS_VALUE: /* mirror over given value */
759                         return mirror_bezier_value;
760                 default: /* just in case */
761                         return mirror_bezier_yaxis;
762                         break;
763         }
764 }
765
766 /* ******************************************* */
767 /* Settings */
768
769 /* Sets the selected bezier handles to type 'auto' */
770 static short set_bezier_auto(BeztEditData *bed, BezTriple *bezt) 
771 {
772         if((bezt->f1  & SELECT) || (bezt->f3 & SELECT)) {
773                 if (bezt->f1 & SELECT) bezt->h1= HD_AUTO; /* the secret code for auto */
774                 if (bezt->f3 & SELECT) bezt->h2= HD_AUTO;
775                 
776                 /* if the handles are not of the same type, set them
777                  * to type free
778                  */
779                 if (bezt->h1 != bezt->h2) {
780                         if ELEM(bezt->h1, HD_ALIGN, HD_AUTO) bezt->h1= HD_FREE;
781                         if ELEM(bezt->h2, HD_ALIGN, HD_AUTO) bezt->h2= HD_FREE;
782                 }
783         }
784         return 0;
785 }
786
787 /* Sets the selected bezier handles to type 'vector'  */
788 static short set_bezier_vector(BeztEditData *bed, BezTriple *bezt) 
789 {
790         if ((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) {
791                 if (bezt->f1 & SELECT) bezt->h1= HD_VECT;
792                 if (bezt->f3 & SELECT) bezt->h2= HD_VECT;
793                 
794                 /* if the handles are not of the same type, set them
795                  * to type free
796                  */
797                 if (bezt->h1 != bezt->h2) {
798                         if ELEM(bezt->h1, HD_ALIGN, HD_AUTO) bezt->h1= HD_FREE;
799                         if ELEM(bezt->h2, HD_ALIGN, HD_AUTO) bezt->h2= HD_FREE;
800                 }
801         }
802         return 0;
803 }
804
805 /* Queries if the handle should be set to 'free' or 'align' */
806 // NOTE: this was used for the 'toggle free/align' option
807 //              currently this isn't used, but may be restored later
808 static short bezier_isfree(BeztEditData *bed, BezTriple *bezt) 
809 {
810         if ((bezt->f1 & SELECT) && (bezt->h1)) return 1;
811         if ((bezt->f3 & SELECT) && (bezt->h2)) return 1;
812         return 0;
813 }
814
815 /* Sets selected bezier handles to type 'align' */
816 static short set_bezier_align(BeztEditData *bed, BezTriple *bezt) 
817 {       
818         if (bezt->f1 & SELECT) bezt->h1= HD_ALIGN;
819         if (bezt->f3 & SELECT) bezt->h2= HD_ALIGN;
820         return 0;
821 }
822
823 /* Sets selected bezier handles to type 'free'  */
824 static short set_bezier_free(BeztEditData *bed, BezTriple *bezt) 
825 {
826         if (bezt->f1 & SELECT) bezt->h1= HD_FREE;
827         if (bezt->f3 & SELECT) bezt->h2= HD_FREE;
828         return 0;
829 }
830
831 /* Set all selected Bezier Handles to a single type */
832 // calchandles_fcurve
833 BeztEditFunc ANIM_editkeyframes_handles(short code)
834 {
835         switch (code) {
836                 case HD_AUTO: /* auto */
837                 case HD_AUTO_ANIM: /* auto clamped */
838                         return set_bezier_auto;
839                         
840                 case HD_VECT: /* vector */
841                         return set_bezier_vector;
842                 case HD_FREE: /* free */
843                         return set_bezier_free;
844                 case HD_ALIGN: /* align */
845                         return set_bezier_align;
846                 
847                 default: /* check for toggle free or align? */
848                         return bezier_isfree;
849         }
850 }
851
852 /* ------- */
853
854 static short set_bezt_constant(BeztEditData *bed, BezTriple *bezt) 
855 {
856         if (bezt->f2 & SELECT) 
857                 bezt->ipo= BEZT_IPO_CONST;
858         return 0;
859 }
860
861 static short set_bezt_linear(BeztEditData *bed, BezTriple *bezt) 
862 {
863         if (bezt->f2 & SELECT) 
864                 bezt->ipo= BEZT_IPO_LIN;
865         return 0;
866 }
867
868 static short set_bezt_bezier(BeztEditData *bed, BezTriple *bezt) 
869 {
870         if (bezt->f2 & SELECT) 
871                 bezt->ipo= BEZT_IPO_BEZ;
872         return 0;
873 }
874
875 /* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
876 // ANIM_editkeyframes_ipocurve_ipotype() !
877 BeztEditFunc ANIM_editkeyframes_ipo(short code)
878 {
879         switch (code) {
880                 case BEZT_IPO_CONST: /* constant */
881                         return set_bezt_constant;
882                 case BEZT_IPO_LIN: /* linear */ 
883                         return set_bezt_linear;
884                 default: /* bezier */
885                         return set_bezt_bezier;
886         }
887 }
888
889 /* ------- */
890
891 static short set_keytype_keyframe(BeztEditData *bed, BezTriple *bezt) 
892 {
893         if (bezt->f2 & SELECT) 
894                 BEZKEYTYPE(bezt)= BEZT_KEYTYPE_KEYFRAME;
895         return 0;
896 }
897
898 static short set_keytype_breakdown(BeztEditData *bed, BezTriple *bezt) 
899 {
900         if (bezt->f2 & SELECT) 
901                 BEZKEYTYPE(bezt)= BEZT_KEYTYPE_BREAKDOWN;
902         return 0;
903 }
904
905 static short set_keytype_extreme(BeztEditData *bed, BezTriple *bezt) 
906 {
907         if (bezt->f2 & SELECT) 
908                 BEZKEYTYPE(bezt)= BEZT_KEYTYPE_EXTREME;
909         return 0;
910 }
911
912 /* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
913 BeztEditFunc ANIM_editkeyframes_keytype(short code)
914 {
915         switch (code) {
916                 case BEZT_KEYTYPE_BREAKDOWN: /* breakdown */
917                         return set_keytype_breakdown;
918                         
919                 case BEZT_KEYTYPE_EXTREME: /* extreme keyframe */
920                         return set_keytype_extreme;
921                         
922                 case BEZT_KEYTYPE_KEYFRAME: /* proper keyframe */       
923                 default:
924                         return set_keytype_keyframe;
925         }
926 }
927
928 /* ******************************************* */
929 /* Selection */
930
931 static short select_bezier_add(BeztEditData *bed, BezTriple *bezt) 
932 {
933         /* Select the bezier triple */
934         BEZ_SEL(bezt);
935         return 0;
936 }
937
938 static short select_bezier_subtract(BeztEditData *bed, BezTriple *bezt) 
939 {
940         /* Deselect the bezier triple */
941         BEZ_DESEL(bezt);
942         return 0;
943 }
944
945 static short select_bezier_invert(BeztEditData *bed, BezTriple *bezt) 
946 {
947         /* Invert the selection for the bezier triple */
948         bezt->f2 ^= SELECT;
949         if (bezt->f2 & SELECT) {
950                 bezt->f1 |= SELECT;
951                 bezt->f3 |= SELECT;
952         }
953         else {
954                 bezt->f1 &= ~SELECT;
955                 bezt->f3 &= ~SELECT;
956         }
957         return 0;
958 }
959
960 BeztEditFunc ANIM_editkeyframes_select(short selectmode)
961 {
962         switch (selectmode) {
963                 case SELECT_ADD: /* add */
964                         return select_bezier_add;
965                 case SELECT_SUBTRACT: /* subtract */
966                         return select_bezier_subtract;
967                 case SELECT_INVERT: /* invert */
968                         return select_bezier_invert;
969                 default: /* replace (need to clear all, then add) */
970                         return select_bezier_add;
971         }
972 }
973
974 /* ******************************************* */
975 /* Selection Maps */
976
977 /* Selection maps are simply fancy names for char arrays that store on/off
978  * info for whether the selection status. The main purpose for these is to
979  * allow extra info to be tagged to the keyframes without influencing their
980  * values or having to be removed later.
981  */
982
983 /* ----------- */
984
985 static short selmap_build_bezier_more(BeztEditData *bed, BezTriple *bezt)
986 {
987         FCurve *fcu= bed->fcu;
988         char *map= bed->data;
989         int i= bed->curIndex;
990         
991         /* if current is selected, just make sure it stays this way */
992         if (BEZSELECTED(bezt)) {
993                 map[i]= 1;
994                 return 0;
995         }
996         
997         /* if previous is selected, that means that selection should extend across */
998         if (i > 0) {
999                 BezTriple *prev= bezt - 1;
1000                 
1001                 if (BEZSELECTED(prev)) {
1002                         map[i]= 1;
1003                         return 0;
1004                 }
1005         }
1006         
1007         /* if next is selected, that means that selection should extend across */
1008         if (i < (fcu->totvert-1)) {
1009                 BezTriple *next= bezt + 1;
1010                 
1011                 if (BEZSELECTED(next)) {
1012                         map[i]= 1;
1013                         return 0;
1014                 }
1015         }
1016         
1017         return 0;
1018 }
1019
1020 static short selmap_build_bezier_less(BeztEditData *bed, BezTriple *bezt)
1021 {
1022         FCurve *fcu= bed->fcu;
1023         char *map= bed->data;
1024         int i= bed->curIndex;
1025         
1026         /* if current is selected, check the left/right keyframes
1027          * since it might need to be deselected (but otherwise no)
1028          */
1029         if (BEZSELECTED(bezt)) {
1030                 /* if previous is not selected, we're on the tip of an iceberg */
1031                 if (i > 0) {
1032                         BezTriple *prev= bezt - 1;
1033                         
1034                         if (BEZSELECTED(prev) == 0)
1035                                 return 0;
1036                 }
1037                 else if (i == 0) {
1038                         /* current keyframe is selected at an endpoint, so should get deselected */
1039                         return 0;
1040                 }
1041                 
1042                 /* if next is not selected, we're on the tip of an iceberg */
1043                 if (i < (fcu->totvert-1)) {
1044                         BezTriple *next= bezt + 1;
1045                         
1046                         if (BEZSELECTED(next) == 0)
1047                                 return 0;
1048                 }
1049                 else if (i == (fcu->totvert-1)) {
1050                         /* current keyframe is selected at an endpoint, so should get deselected */
1051                         return 0;
1052                 }
1053                 
1054                 /* if we're still here, that means that keyframe should remain untouched */
1055                 map[i]= 1;
1056         }
1057         
1058         return 0;
1059 }
1060
1061 /* Get callback for building selection map */
1062 BeztEditFunc ANIM_editkeyframes_buildselmap(short mode)
1063 {
1064         switch (mode) {
1065                 case SELMAP_LESS: /* less */
1066                         return selmap_build_bezier_less;
1067                 
1068                 case SELMAP_MORE: /* more */
1069                 default:
1070                         return selmap_build_bezier_more;
1071         }
1072 }
1073
1074 /* ----------- */
1075
1076 /* flush selection map values to the given beztriple */
1077 short bezt_selmap_flush(BeztEditData *bed, BezTriple *bezt)
1078 {
1079         char *map= bed->data;
1080         short on= map[bed->curIndex];
1081         
1082         /* select or deselect based on whether the map allows it or not */
1083         if (on) {
1084                 BEZ_SEL(bezt);
1085         }
1086         else {
1087                 BEZ_DESEL(bezt);
1088         }
1089         
1090         return 0;
1091 }
1092