1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2008 Blender Foundation
17  */
18 
19 /** \file
20  * \ingroup edanimation
21  */
22 
23 #include <float.h>
24 #include <math.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "MEM_guardedalloc.h"
29 
30 #include "BLI_blenlib.h"
31 #include "BLI_lasso_2d.h"
32 #include "BLI_math.h"
33 #include "BLI_utildefines.h"
34 
35 #include "DNA_anim_types.h"
36 #include "DNA_object_types.h"
37 #include "DNA_scene_types.h"
38 
39 #include "BKE_fcurve.h"
40 #include "BKE_nla.h"
41 
42 #include "ED_anim_api.h"
43 #include "ED_keyframes_edit.h"
44 #include "ED_markers.h"
45 
46 /* This file defines an API and set of callback-operators for
47  * non-destructive editing of keyframe data.
48  *
49  * Two API functions are defined for actually performing the operations on the data:
50  * ANIM_fcurve_keyframes_loop()
51  * which take the data they operate on, a few callbacks defining what operations to perform.
52  *
53  * As operators which work on keyframes usually apply the same operation on all BezTriples in
54  * every channel, the code has been optimized providing a set of functions which will get the
55  * appropriate bezier-modify function to set. These functions (ANIM_editkeyframes_*) will need
56  * to be called before getting any channels.
57  *
58  * A set of 'validation' callbacks are provided for checking if a BezTriple should be operated on.
59  * These should only be used when using a 'general' BezTriple editor (i.e. selection setters which
60  * don't check existing selection status).
61  *
62  * - Joshua Leung, Dec 2008
63  */
64 
65 /* ************************************************************************** */
66 /* Keyframe Editing Loops - Exposed API */
67 
68 /* --------------------------- Base Functions ------------------------------------ */
69 
70 /* This function is used to loop over BezTriples in the given F-Curve, applying a given
71  * operation on them, and optionally applies an F-Curve validation function afterwards.
72  */
73 /* TODO: make this function work on samples too. */
ANIM_fcurve_keyframes_loop(KeyframeEditData * ked,FCurve * fcu,KeyframeEditFunc key_ok,KeyframeEditFunc key_cb,FcuEditFunc fcu_cb)74 short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked,
75                                  FCurve *fcu,
76                                  KeyframeEditFunc key_ok,
77                                  KeyframeEditFunc key_cb,
78                                  FcuEditFunc fcu_cb)
79 {
80   BezTriple *bezt;
81   short ok = 0;
82   uint i;
83 
84   /* sanity check */
85   if (ELEM(NULL, fcu, fcu->bezt)) {
86     return 0;
87   }
88 
89   /* set the F-Curve into the editdata so that it can be accessed */
90   if (ked) {
91     ked->fcu = fcu;
92     ked->curIndex = 0;
93     ked->curflags = ok;
94   }
95 
96   /* if function to apply to bezier curves is set, then loop through executing it on beztriples */
97   if (key_cb) {
98     /* if there's a validation func, include that check in the loop
99      * (this is should be more efficient than checking for it in every loop)
100      */
101     if (key_ok) {
102       for (bezt = fcu->bezt, i = 0; i < fcu->totvert; bezt++, i++) {
103         if (ked) {
104           /* advance the index, and reset the ok flags (to not influence the result) */
105           ked->curIndex = i;
106           ked->curflags = 0;
107         }
108 
109         /* Only operate on this BezTriple if it fulfills the criteria of the validation func */
110         if ((ok = key_ok(ked, bezt))) {
111           if (ked) {
112             ked->curflags = ok;
113           }
114 
115           /* Exit with return-code '1' if function returns positive
116            * This is useful if finding if some BezTriple satisfies a condition.
117            */
118           if (key_cb(ked, bezt)) {
119             return 1;
120           }
121         }
122       }
123     }
124     else {
125       for (bezt = fcu->bezt, i = 0; i < fcu->totvert; bezt++, i++) {
126         if (ked) {
127           ked->curIndex = i;
128         }
129 
130         /* Exit with return-code '1' if function returns positive
131          * This is useful if finding if some BezTriple satisfies a condition.
132          */
133         if (key_cb(ked, bezt)) {
134           return 1;
135         }
136       }
137     }
138   }
139 
140   /* unset the F-Curve from the editdata now that it's done */
141   if (ked) {
142     ked->fcu = NULL;
143     ked->curIndex = 0;
144     ked->curflags = 0;
145   }
146 
147   /* if fcu_cb (F-Curve post-editing callback) has been specified then execute it */
148   if (fcu_cb) {
149     fcu_cb(fcu);
150   }
151 
152   /* done */
153   return 0;
154 }
155 
156 /* --------------------- Further Abstracted (Not Exposed Directly) ----------------------------- */
157 
158 /* This function is used to loop over the keyframe data in an Action Group */
agrp_keyframes_loop(KeyframeEditData * ked,bActionGroup * agrp,KeyframeEditFunc key_ok,KeyframeEditFunc key_cb,FcuEditFunc fcu_cb)159 static short agrp_keyframes_loop(KeyframeEditData *ked,
160                                  bActionGroup *agrp,
161                                  KeyframeEditFunc key_ok,
162                                  KeyframeEditFunc key_cb,
163                                  FcuEditFunc fcu_cb)
164 {
165   FCurve *fcu;
166 
167   /* sanity check */
168   if (agrp == NULL) {
169     return 0;
170   }
171 
172   /* only iterate over the F-Curves that are in this group */
173   for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcu->next) {
174     if (ANIM_fcurve_keyframes_loop(ked, fcu, key_ok, key_cb, fcu_cb)) {
175       return 1;
176     }
177   }
178 
179   return 0;
180 }
181 
182 /* This function is used to loop over the keyframe data in an Action */
act_keyframes_loop(KeyframeEditData * ked,bAction * act,KeyframeEditFunc key_ok,KeyframeEditFunc key_cb,FcuEditFunc fcu_cb)183 static short act_keyframes_loop(KeyframeEditData *ked,
184                                 bAction *act,
185                                 KeyframeEditFunc key_ok,
186                                 KeyframeEditFunc key_cb,
187                                 FcuEditFunc fcu_cb)
188 {
189   FCurve *fcu;
190 
191   /* sanity check */
192   if (act == NULL) {
193     return 0;
194   }
195 
196   /* just loop through all F-Curves */
197   for (fcu = act->curves.first; fcu; fcu = fcu->next) {
198     if (ANIM_fcurve_keyframes_loop(ked, fcu, key_ok, key_cb, fcu_cb)) {
199       return 1;
200     }
201   }
202 
203   return 0;
204 }
205 
206 /* This function is used to loop over the keyframe data in an Object */
ob_keyframes_loop(KeyframeEditData * ked,bDopeSheet * ads,Object * ob,KeyframeEditFunc key_ok,KeyframeEditFunc key_cb,FcuEditFunc fcu_cb)207 static short ob_keyframes_loop(KeyframeEditData *ked,
208                                bDopeSheet *ads,
209                                Object *ob,
210                                KeyframeEditFunc key_ok,
211                                KeyframeEditFunc key_cb,
212                                FcuEditFunc fcu_cb)
213 {
214   bAnimContext ac = {NULL};
215   ListBase anim_data = {NULL, NULL};
216   bAnimListElem *ale;
217   int filter;
218   int ret = 0;
219 
220   bAnimListElem dummychan = {NULL};
221   Base dummybase = {NULL};
222 
223   if (ob == NULL) {
224     return 0;
225   }
226 
227   /* create a dummy wrapper data to work with */
228   dummybase.object = ob;
229 
230   dummychan.type = ANIMTYPE_OBJECT;
231   dummychan.data = &dummybase;
232   dummychan.id = &ob->id;
233   dummychan.adt = ob->adt;
234 
235   ac.ads = ads;
236   ac.data = &dummychan;
237   ac.datatype = ANIMCONT_CHANNEL;
238 
239   /* get F-Curves to take keyframes from */
240   filter = ANIMFILTER_DATA_VISIBLE; /* curves only */
241   ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
242 
243   /* Loop through each F-Curve, applying the operation as required,
244    * but stopping on the first one. */
245   for (ale = anim_data.first; ale; ale = ale->next) {
246     if (ANIM_fcurve_keyframes_loop(ked, (FCurve *)ale->data, key_ok, key_cb, fcu_cb)) {
247       ret = 1;
248       break;
249     }
250   }
251 
252   ANIM_animdata_freelist(&anim_data);
253 
254   /* return return code - defaults to zero if nothing happened */
255   return ret;
256 }
257 
258 /* This function is used to loop over the keyframe data in a Scene */
scene_keyframes_loop(KeyframeEditData * ked,bDopeSheet * ads,Scene * sce,KeyframeEditFunc key_ok,KeyframeEditFunc key_cb,FcuEditFunc fcu_cb)259 static short scene_keyframes_loop(KeyframeEditData *ked,
260                                   bDopeSheet *ads,
261                                   Scene *sce,
262                                   KeyframeEditFunc key_ok,
263                                   KeyframeEditFunc key_cb,
264                                   FcuEditFunc fcu_cb)
265 {
266   bAnimContext ac = {NULL};
267   ListBase anim_data = {NULL, NULL};
268   bAnimListElem *ale;
269   int filter;
270   int ret = 0;
271 
272   bAnimListElem dummychan = {NULL};
273 
274   if (sce == NULL) {
275     return 0;
276   }
277 
278   /* create a dummy wrapper data to work with */
279   dummychan.type = ANIMTYPE_SCENE;
280   dummychan.data = sce;
281   dummychan.id = &sce->id;
282   dummychan.adt = sce->adt;
283 
284   ac.ads = ads;
285   ac.data = &dummychan;
286   ac.datatype = ANIMCONT_CHANNEL;
287 
288   /* get F-Curves to take keyframes from */
289   filter = ANIMFILTER_DATA_VISIBLE; /* curves only */
290   ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
291 
292   /* Loop through each F-Curve, applying the operation as required,
293    * but stopping on the first one. */
294   for (ale = anim_data.first; ale; ale = ale->next) {
295     if (ANIM_fcurve_keyframes_loop(ked, (FCurve *)ale->data, key_ok, key_cb, fcu_cb)) {
296       ret = 1;
297       break;
298     }
299   }
300 
301   ANIM_animdata_freelist(&anim_data);
302 
303   /* return return code - defaults to zero if nothing happened */
304   return ret;
305 }
306 
307 /* This function is used to loop over the keyframe data in a DopeSheet summary */
summary_keyframes_loop(KeyframeEditData * ked,bAnimContext * ac,KeyframeEditFunc key_ok,KeyframeEditFunc key_cb,FcuEditFunc fcu_cb)308 static short summary_keyframes_loop(KeyframeEditData *ked,
309                                     bAnimContext *ac,
310                                     KeyframeEditFunc key_ok,
311                                     KeyframeEditFunc key_cb,
312                                     FcuEditFunc fcu_cb)
313 {
314   ListBase anim_data = {NULL, NULL};
315   bAnimListElem *ale;
316   int filter, ret_code = 0;
317 
318   /* sanity check */
319   if (ac == NULL) {
320     return 0;
321   }
322 
323   /* get F-Curves to take keyframes from */
324   filter = ANIMFILTER_DATA_VISIBLE;
325   ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
326 
327   /* loop through each F-Curve, working on the keyframes until the first curve aborts */
328   for (ale = anim_data.first; ale; ale = ale->next) {
329     switch (ale->datatype) {
330       case ALE_MASKLAY:
331       case ALE_GPFRAME:
332         break;
333 
334       case ALE_FCURVE:
335       default: {
336         if (ked && ked->iterflags) {
337           /* make backups of the current values, so that a localized fix
338            * (e.g. NLA time remapping) can be applied to these values
339            */
340           float f1 = ked->f1;
341           float f2 = ked->f2;
342 
343           if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) {
344             AnimData *adt = ANIM_nla_mapping_get(ac, ale);
345 
346             if (ked->iterflags & KED_F1_NLA_UNMAP) {
347               ked->f1 = BKE_nla_tweakedit_remap(adt, f1, NLATIME_CONVERT_UNMAP);
348             }
349             if (ked->iterflags & KED_F2_NLA_UNMAP) {
350               ked->f2 = BKE_nla_tweakedit_remap(adt, f2, NLATIME_CONVERT_UNMAP);
351             }
352           }
353 
354           /* now operate on the channel as per normal */
355           ret_code = ANIM_fcurve_keyframes_loop(ked, ale->data, key_ok, key_cb, fcu_cb);
356 
357           /* reset */
358           ked->f1 = f1;
359           ked->f2 = f2;
360         }
361         else {
362           /* no special handling required... */
363           ret_code = ANIM_fcurve_keyframes_loop(ked, ale->data, key_ok, key_cb, fcu_cb);
364         }
365         break;
366       }
367     }
368 
369     if (ret_code) {
370       break;
371     }
372   }
373 
374   ANIM_animdata_freelist(&anim_data);
375 
376   return ret_code;
377 }
378 
379 /* --- */
380 
381 /* This function is used to apply operation to all keyframes, regardless of the type */
ANIM_animchannel_keyframes_loop(KeyframeEditData * ked,bDopeSheet * ads,bAnimListElem * ale,KeyframeEditFunc key_ok,KeyframeEditFunc key_cb,FcuEditFunc fcu_cb)382 short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked,
383                                       bDopeSheet *ads,
384                                       bAnimListElem *ale,
385                                       KeyframeEditFunc key_ok,
386                                       KeyframeEditFunc key_cb,
387                                       FcuEditFunc fcu_cb)
388 {
389   /* sanity checks */
390   if (ale == NULL) {
391     return 0;
392   }
393 
394   /* method to use depends on the type of keyframe data */
395   switch (ale->datatype) {
396     /* direct keyframe data (these loops are exposed) */
397     case ALE_FCURVE: /* F-Curve */
398       return ANIM_fcurve_keyframes_loop(ked, ale->key_data, key_ok, key_cb, fcu_cb);
399 
400     /* indirect 'summaries' (these are not exposed directly)
401      * NOTE: must keep this code in sync with the drawing code and also the filtering code!
402      */
403     case ALE_GROUP: /* action group */
404       return agrp_keyframes_loop(ked, (bActionGroup *)ale->data, key_ok, key_cb, fcu_cb);
405     case ALE_ACT: /* action */
406       return act_keyframes_loop(ked, (bAction *)ale->key_data, key_ok, key_cb, fcu_cb);
407 
408     case ALE_OB: /* object */
409       return ob_keyframes_loop(ked, ads, (Object *)ale->key_data, key_ok, key_cb, fcu_cb);
410     case ALE_SCE: /* scene */
411       return scene_keyframes_loop(ked, ads, (Scene *)ale->data, key_ok, key_cb, fcu_cb);
412     case ALE_ALL: /* 'all' (DopeSheet summary) */
413       return summary_keyframes_loop(ked, (bAnimContext *)ale->data, key_ok, key_cb, fcu_cb);
414   }
415 
416   return 0;
417 }
418 
419 /* This function is used to apply operation to all keyframes,
420  * regardless of the type without needed an AnimListElem wrapper */
ANIM_animchanneldata_keyframes_loop(KeyframeEditData * ked,bDopeSheet * ads,void * data,int keytype,KeyframeEditFunc key_ok,KeyframeEditFunc key_cb,FcuEditFunc fcu_cb)421 short ANIM_animchanneldata_keyframes_loop(KeyframeEditData *ked,
422                                           bDopeSheet *ads,
423                                           void *data,
424                                           int keytype,
425                                           KeyframeEditFunc key_ok,
426                                           KeyframeEditFunc key_cb,
427                                           FcuEditFunc fcu_cb)
428 {
429   /* sanity checks */
430   if (data == NULL) {
431     return 0;
432   }
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_keyframes_loop(ked, data, key_ok, key_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_keyframes_loop(ked, (bActionGroup *)data, key_ok, key_cb, fcu_cb);
445     case ALE_ACT: /* action */
446       return act_keyframes_loop(ked, (bAction *)data, key_ok, key_cb, fcu_cb);
447 
448     case ALE_OB: /* object */
449       return ob_keyframes_loop(ked, ads, (Object *)data, key_ok, key_cb, fcu_cb);
450     case ALE_SCE: /* scene */
451       return scene_keyframes_loop(ked, ads, (Scene *)data, key_ok, key_cb, fcu_cb);
452     case ALE_ALL: /* 'all' (DopeSheet summary) */
453       return summary_keyframes_loop(ked, (bAnimContext *)data, key_ok, key_cb, fcu_cb);
454   }
455 
456   return 0;
457 }
458 
ANIM_animdata_keyframe_callback(bAnimContext * ac,eAnimFilter_Flags filter,KeyframeEditFunc callback_fn)459 void ANIM_animdata_keyframe_callback(bAnimContext *ac,
460                                      eAnimFilter_Flags filter,
461                                      KeyframeEditFunc callback_fn)
462 {
463   ListBase anim_data = {NULL, NULL};
464   bAnimListElem *ale;
465 
466   ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
467 
468   for (ale = anim_data.first; ale; ale = ale->next) {
469     ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, callback_fn, calchandles_fcurve);
470     ale->update |= ANIM_UPDATE_DEFAULT;
471   }
472 
473   ANIM_animdata_update(ac, &anim_data);
474   ANIM_animdata_freelist(&anim_data);
475 }
476 
477 /* ************************************************************************** */
478 /* Keyframe Integrity Tools */
479 
480 /* Rearrange keyframes if some are out of order */
481 /* used to be recalc_*_ipos() where * was object or action */
ANIM_editkeyframes_refresh(bAnimContext * ac)482 void ANIM_editkeyframes_refresh(bAnimContext *ac)
483 {
484   ListBase anim_data = {NULL, NULL};
485   bAnimListElem *ale;
486   int filter;
487 
488   /* filter animation data */
489   filter = ANIMFILTER_DATA_VISIBLE;
490   ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
491 
492   /* Loop over F-Curves that are likely to have been edited, and tag them to
493    * ensure the keyframes are in order and handles are in a valid position. */
494   for (ale = anim_data.first; ale; ale = ale->next) {
495     ale->update |= ANIM_UPDATE_DEPS | ANIM_UPDATE_HANDLES | ANIM_UPDATE_ORDER;
496   }
497 
498   /* free temp data */
499   ANIM_animdata_update(ac, &anim_data);
500   ANIM_animdata_freelist(&anim_data);
501 }
502 
503 /* ************************************************************************** */
504 /* BezTriple Validation Callbacks */
505 
506 /* ------------------------ */
507 /* Some macros to make this easier... */
508 
509 /* run the given check on the 3 handles:
510  * - Check should be a macro, which takes the handle index as its single arg,
511  *   which it substitutes later.
512  * - Requires that a var, of type short, is named 'ok',
513  *   and has been initialized to 0.
514  */
515 #define KEYFRAME_OK_CHECKS(check) \
516   { \
517     CHECK_TYPE(ok, short); \
518     if (check(1)) { \
519       ok |= KEYFRAME_OK_KEY; \
520     } \
521     if (ked && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES)) { \
522       /* Only act on visible items, so check handle visibility state. */ \
523       const bool handles_visible = ((ked->iterflags & KEYFRAME_ITER_HANDLES_DEFAULT_INVISIBLE) ? \
524                                         (BEZT_ISSEL_ANY(bezt)) : \
525                                         true); \
526       if (handles_visible) { \
527         if (check(0)) { \
528           ok |= KEYFRAME_OK_H1; \
529         } \
530         if (check(2)) { \
531           ok |= KEYFRAME_OK_H2; \
532         } \
533       } \
534     } \
535   } \
536   (void)0
537 
538 /* ------------------------ */
539 
ok_bezier_frame(KeyframeEditData * ked,BezTriple * bezt)540 static short ok_bezier_frame(KeyframeEditData *ked, BezTriple *bezt)
541 {
542   short ok = 0;
543 
544   /* frame is stored in f1 property (this float accuracy check may need to be dropped?) */
545 #define KEY_CHECK_OK(_index) IS_EQF(bezt->vec[_index][0], ked->f1)
546   KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
547 #undef KEY_CHECK_OK
548 
549   /* return ok flags */
550   return ok;
551 }
552 
ok_bezier_framerange(KeyframeEditData * ked,BezTriple * bezt)553 static short ok_bezier_framerange(KeyframeEditData *ked, BezTriple *bezt)
554 {
555   short ok = 0;
556 
557   /* frame range is stored in float properties */
558 #define KEY_CHECK_OK(_index) ((bezt->vec[_index][0] > ked->f1) && (bezt->vec[_index][0] < ked->f2))
559   KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
560 #undef KEY_CHECK_OK
561 
562   /* return ok flags */
563   return ok;
564 }
565 
ok_bezier_selected(KeyframeEditData * UNUSED (ked),BezTriple * bezt)566 static short ok_bezier_selected(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
567 {
568   /* this macro checks all beztriple handles for selection...
569    * only one of the verts has to be selected for this to be ok...
570    */
571   if (BEZT_ISSEL_ANY(bezt)) {
572     return KEYFRAME_OK_ALL;
573   }
574   return 0;
575 }
576 
ok_bezier_value(KeyframeEditData * ked,BezTriple * bezt)577 static short ok_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
578 {
579   short ok = 0;
580 
581   /* Value is stored in f1 property:
582    * - This float accuracy check may need to be dropped?
583    * - Should value be stored in f2 instead
584    *   so that we won't have conflicts when using f1 for frames too?
585    */
586 #define KEY_CHECK_OK(_index) IS_EQF(bezt->vec[_index][1], ked->f1)
587   KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
588 #undef KEY_CHECK_OK
589 
590   /* return ok flags */
591   return ok;
592 }
593 
ok_bezier_valuerange(KeyframeEditData * ked,BezTriple * bezt)594 static short ok_bezier_valuerange(KeyframeEditData *ked, BezTriple *bezt)
595 {
596   short ok = 0;
597 
598   /* value range is stored in float properties */
599 #define KEY_CHECK_OK(_index) ((bezt->vec[_index][1] > ked->f1) && (bezt->vec[_index][1] < ked->f2))
600   KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
601 #undef KEY_CHECK_OK
602 
603   /* return ok flags */
604   return ok;
605 }
606 
ok_bezier_region(KeyframeEditData * ked,BezTriple * bezt)607 static short ok_bezier_region(KeyframeEditData *ked, BezTriple *bezt)
608 {
609   /* rect is stored in data property (it's of type rectf, but may not be set) */
610   if (ked->data) {
611     short ok = 0;
612 
613 #define KEY_CHECK_OK(_index) BLI_rctf_isect_pt_v(ked->data, bezt->vec[_index])
614     KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
615 #undef KEY_CHECK_OK
616 
617     /* return ok flags */
618     return ok;
619   }
620   return 0;
621 }
622 
623 /**
624  * Called from #ok_bezier_region_lasso and #ok_bezier_channel_lasso
625  */
keyframe_region_lasso_test(const KeyframeEdit_LassoData * data_lasso,const float xy[2])626 bool keyframe_region_lasso_test(const KeyframeEdit_LassoData *data_lasso, const float xy[2])
627 {
628   if (BLI_rctf_isect_pt_v(data_lasso->rectf_scaled, xy)) {
629     float xy_view[2];
630 
631     BLI_rctf_transform_pt_v(data_lasso->rectf_view, data_lasso->rectf_scaled, xy_view, xy);
632 
633     if (BLI_lasso_is_point_inside(
634             data_lasso->mcoords, data_lasso->mcoords_len, xy_view[0], xy_view[1], INT_MAX)) {
635       return true;
636     }
637   }
638 
639   return false;
640 }
641 
ok_bezier_region_lasso(KeyframeEditData * ked,BezTriple * bezt)642 static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt)
643 {
644   /* check for lasso customdata (KeyframeEdit_LassoData) */
645   if (ked->data) {
646     short ok = 0;
647 
648 #define KEY_CHECK_OK(_index) keyframe_region_lasso_test(ked->data, bezt->vec[_index])
649     KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
650 #undef KEY_CHECK_OK
651 
652     /* return ok flags */
653     return ok;
654   }
655   return 0;
656 }
657 
ok_bezier_channel_lasso(KeyframeEditData * ked,BezTriple * bezt)658 static short ok_bezier_channel_lasso(KeyframeEditData *ked, BezTriple *bezt)
659 {
660   /* check for lasso customdata (KeyframeEdit_LassoData) */
661   if (ked->data) {
662     KeyframeEdit_LassoData *data = ked->data;
663     float pt[2];
664 
665     /* late-binding remap of the x values (for summary channels) */
666     /* XXX: Ideally we reset, but it should be fine just leaving it as-is
667      * as the next channel will reset it properly, while the next summary-channel
668      * curve will also reset by itself...
669      */
670     if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) {
671       data->rectf_scaled->xmin = ked->f1;
672       data->rectf_scaled->xmax = ked->f2;
673     }
674 
675     /* only use the x-coordinate of the point; the y is the channel range... */
676     pt[0] = bezt->vec[1][0];
677     pt[1] = ked->channel_y;
678 
679     if (keyframe_region_lasso_test(data, pt)) {
680       return KEYFRAME_OK_KEY;
681     }
682   }
683   return 0;
684 }
685 
686 /**
687  * Called from #ok_bezier_region_circle and #ok_bezier_channel_circle
688  */
keyframe_region_circle_test(const KeyframeEdit_CircleData * data_circle,const float xy[2])689 bool keyframe_region_circle_test(const KeyframeEdit_CircleData *data_circle, const float xy[2])
690 {
691   if (BLI_rctf_isect_pt_v(data_circle->rectf_scaled, xy)) {
692     float xy_view[2];
693 
694     BLI_rctf_transform_pt_v(data_circle->rectf_view, data_circle->rectf_scaled, xy_view, xy);
695 
696     xy_view[0] = xy_view[0] - data_circle->mval[0];
697     xy_view[1] = xy_view[1] - data_circle->mval[1];
698     return len_squared_v2(xy_view) < data_circle->radius_squared;
699   }
700 
701   return false;
702 }
703 
ok_bezier_region_circle(KeyframeEditData * ked,BezTriple * bezt)704 static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt)
705 {
706   /* check for circle select customdata (KeyframeEdit_CircleData) */
707   if (ked->data) {
708     short ok = 0;
709 
710 #define KEY_CHECK_OK(_index) keyframe_region_circle_test(ked->data, bezt->vec[_index])
711     KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
712 #undef KEY_CHECK_OK
713 
714     /* return ok flags */
715     return ok;
716   }
717   return 0;
718 }
719 
ok_bezier_channel_circle(KeyframeEditData * ked,BezTriple * bezt)720 static short ok_bezier_channel_circle(KeyframeEditData *ked, BezTriple *bezt)
721 {
722   /* check for circle select customdata (KeyframeEdit_CircleData) */
723   if (ked->data) {
724     KeyframeEdit_CircleData *data = ked->data;
725     float pt[2];
726 
727     /* late-binding remap of the x values (for summary channels) */
728     /* XXX: Ideally we reset, but it should be fine just leaving it as-is
729      * as the next channel will reset it properly, while the next summary-channel
730      * curve will also reset by itself...
731      */
732     if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) {
733       data->rectf_scaled->xmin = ked->f1;
734       data->rectf_scaled->xmax = ked->f2;
735     }
736 
737     /* only use the x-coordinate of the point; the y is the channel range... */
738     pt[0] = bezt->vec[1][0];
739     pt[1] = ked->channel_y;
740 
741     if (keyframe_region_circle_test(data, pt)) {
742       return KEYFRAME_OK_KEY;
743     }
744   }
745   return 0;
746 }
747 
ANIM_editkeyframes_ok(short mode)748 KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
749 {
750   /* eEditKeyframes_Validate */
751   switch (mode) {
752     case BEZT_OK_FRAME:
753       /* only if bezt falls on the right frame (float) */
754       return ok_bezier_frame;
755     case BEZT_OK_FRAMERANGE:
756       /* only if bezt falls within the specified frame range (floats) */
757       return ok_bezier_framerange;
758     case BEZT_OK_SELECTED:
759       /* only if bezt is selected (self) */
760       return ok_bezier_selected;
761     case BEZT_OK_VALUE:
762       /* only if bezt value matches (float) */
763       return ok_bezier_value;
764     case BEZT_OK_VALUERANGE:
765       /* only if bezier falls within the specified value range (floats) */
766       return ok_bezier_valuerange;
767     case BEZT_OK_REGION:
768       /* only if bezier falls within the specified rect (data -> rectf) */
769       return ok_bezier_region;
770     case BEZT_OK_REGION_LASSO:
771       /* only if the point falls within KeyframeEdit_LassoData defined data */
772       return ok_bezier_region_lasso;
773     case BEZT_OK_REGION_CIRCLE:
774       /* only if the point falls within KeyframeEdit_CircleData defined data */
775       return ok_bezier_region_circle;
776     case BEZT_OK_CHANNEL_LASSO:
777       /* same as BEZT_OK_REGION_LASSO, but we're only using the x-value of the points */
778       return ok_bezier_channel_lasso;
779     case BEZT_OK_CHANNEL_CIRCLE:
780       /* same as BEZT_OK_REGION_CIRCLE, but we're only using the x-value of the points */
781       return ok_bezier_channel_circle;
782     default: /* nothing was ok */
783       return NULL;
784   }
785 }
786 
787 /* ******************************************* */
788 /* Assorted Utility Functions */
789 
790 /**
791  * Helper callback for <animeditor>_cfrasnap_exec() ->
792  * used to help get the average time of all selected beztriples
793  */
bezt_calc_average(KeyframeEditData * ked,BezTriple * bezt)794 short bezt_calc_average(KeyframeEditData *ked, BezTriple *bezt)
795 {
796   /* only if selected */
797   if (bezt->f2 & SELECT) {
798     /* store average time in float 1 (only do rounding at last step) */
799     ked->f1 += bezt->vec[1][0];
800 
801     /* store average value in float 2 (only do rounding at last step)
802      * - this isn't always needed, but some operators may also require this
803      */
804     ked->f2 += bezt->vec[1][1];
805 
806     /* increment number of items */
807     ked->i1++;
808   }
809 
810   return 0;
811 }
812 
813 /* helper callback for columnselect_<animeditor>_keys() -> populate
814  * list CfraElems with frame numbers from selected beztriples */
bezt_to_cfraelem(KeyframeEditData * ked,BezTriple * bezt)815 short bezt_to_cfraelem(KeyframeEditData *ked, BezTriple *bezt)
816 {
817   /* only if selected */
818   if (bezt->f2 & SELECT) {
819     CfraElem *ce = MEM_callocN(sizeof(CfraElem), "cfraElem");
820     BLI_addtail(&ked->list, ce);
821 
822     ce->cfra = bezt->vec[1][0];
823   }
824 
825   return 0;
826 }
827 
828 /* used to remap times from one range to another
829  * requires:  ked->data = KeyframeEditCD_Remap
830  */
bezt_remap_times(KeyframeEditData * ked,BezTriple * bezt)831 void bezt_remap_times(KeyframeEditData *ked, BezTriple *bezt)
832 {
833   KeyframeEditCD_Remap *rmap = (KeyframeEditCD_Remap *)ked->data;
834   const float scale = (rmap->newMax - rmap->newMin) / (rmap->oldMax - rmap->oldMin);
835 
836   /* perform transform on all three handles unless indicated otherwise */
837   /* TODO: need to include some checks for that */
838 
839   bezt->vec[0][0] = scale * (bezt->vec[0][0] - rmap->oldMin) + rmap->newMin;
840   bezt->vec[1][0] = scale * (bezt->vec[1][0] - rmap->oldMin) + rmap->newMin;
841   bezt->vec[2][0] = scale * (bezt->vec[2][0] - rmap->oldMin) + rmap->newMin;
842 }
843 
844 /* ******************************************* */
845 /* Transform */
846 
847 /* snaps the keyframe to the nearest frame */
snap_bezier_nearest(KeyframeEditData * UNUSED (ked),BezTriple * bezt)848 static short snap_bezier_nearest(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
849 {
850   if (bezt->f2 & SELECT) {
851     bezt->vec[1][0] = (float)(floorf(bezt->vec[1][0] + 0.5f));
852   }
853   return 0;
854 }
855 
856 /* snaps the keyframe to the nearest second */
snap_bezier_nearestsec(KeyframeEditData * ked,BezTriple * bezt)857 static short snap_bezier_nearestsec(KeyframeEditData *ked, BezTriple *bezt)
858 {
859   const Scene *scene = ked->scene;
860   const float secf = (float)FPS;
861 
862   if (bezt->f2 & SELECT) {
863     bezt->vec[1][0] = (floorf(bezt->vec[1][0] / secf + 0.5f) * secf);
864   }
865   return 0;
866 }
867 
868 /* snaps the keyframe to the current frame */
snap_bezier_cframe(KeyframeEditData * ked,BezTriple * bezt)869 static short snap_bezier_cframe(KeyframeEditData *ked, BezTriple *bezt)
870 {
871   const Scene *scene = ked->scene;
872   if (bezt->f2 & SELECT) {
873     bezt->vec[1][0] = (float)CFRA;
874   }
875   return 0;
876 }
877 
878 /* snaps the keyframe time to the nearest marker's frame */
snap_bezier_nearmarker(KeyframeEditData * ked,BezTriple * bezt)879 static short snap_bezier_nearmarker(KeyframeEditData *ked, BezTriple *bezt)
880 {
881   if (bezt->f2 & SELECT) {
882     bezt->vec[1][0] = (float)ED_markers_find_nearest_marker_time(&ked->list, bezt->vec[1][0]);
883   }
884   return 0;
885 }
886 
887 /* make the handles have the same value as the key */
snap_bezier_horizontal(KeyframeEditData * UNUSED (ked),BezTriple * bezt)888 static short snap_bezier_horizontal(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
889 {
890   if (bezt->f2 & SELECT) {
891     bezt->vec[0][1] = bezt->vec[2][1] = bezt->vec[1][1];
892 
893     if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) {
894       bezt->h1 = HD_ALIGN;
895     }
896     if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) {
897       bezt->h2 = HD_ALIGN;
898     }
899   }
900   return 0;
901 }
902 
903 /* frame to snap to is stored in the custom data -> first float value slot */
snap_bezier_time(KeyframeEditData * ked,BezTriple * bezt)904 static short snap_bezier_time(KeyframeEditData *ked, BezTriple *bezt)
905 {
906   if (bezt->f2 & SELECT) {
907     bezt->vec[1][0] = ked->f1;
908   }
909   return 0;
910 }
911 
912 /* value to snap to is stored in the custom data -> first float value slot */
snap_bezier_value(KeyframeEditData * ked,BezTriple * bezt)913 static short snap_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
914 {
915   if (bezt->f2 & SELECT) {
916     bezt->vec[1][1] = ked->f1;
917   }
918   return 0;
919 }
920 
ANIM_editkeyframes_snap(short mode)921 KeyframeEditFunc ANIM_editkeyframes_snap(short mode)
922 {
923   /* eEditKeyframes_Snap */
924   switch (mode) {
925     case SNAP_KEYS_NEARFRAME: /* snap to nearest frame */
926       return snap_bezier_nearest;
927     case SNAP_KEYS_CURFRAME: /* snap to current frame */
928       return snap_bezier_cframe;
929     case SNAP_KEYS_NEARMARKER: /* snap to nearest marker */
930       return snap_bezier_nearmarker;
931     case SNAP_KEYS_NEARSEC: /* snap to nearest second */
932       return snap_bezier_nearestsec;
933     case SNAP_KEYS_HORIZONTAL: /* snap handles to same value */
934       return snap_bezier_horizontal;
935     case SNAP_KEYS_TIME: /* snap to given frame/time */
936       return snap_bezier_time;
937     case SNAP_KEYS_VALUE: /* snap to given value */
938       return snap_bezier_value;
939     default: /* just in case */
940       return snap_bezier_nearest;
941   }
942 }
943 
944 /* --------- */
945 
mirror_bezier_xaxis_ex(BezTriple * bezt,const float center)946 static void mirror_bezier_xaxis_ex(BezTriple *bezt, const float center)
947 {
948   for (int i = 0; i < 3; i++) {
949     float diff = (center - bezt->vec[i][0]);
950     bezt->vec[i][0] = (center + diff);
951   }
952   swap_v3_v3(bezt->vec[0], bezt->vec[2]);
953 
954   SWAP(uint8_t, bezt->h1, bezt->h2);
955   SWAP(uint8_t, bezt->f1, bezt->f3);
956 }
957 
mirror_bezier_yaxis_ex(BezTriple * bezt,const float center)958 static void mirror_bezier_yaxis_ex(BezTriple *bezt, const float center)
959 {
960   for (int i = 0; i < 3; i++) {
961     float diff = (center - bezt->vec[i][1]);
962     bezt->vec[i][1] = (center + diff);
963   }
964 }
965 
mirror_bezier_cframe(KeyframeEditData * ked,BezTriple * bezt)966 static short mirror_bezier_cframe(KeyframeEditData *ked, BezTriple *bezt)
967 {
968   const Scene *scene = ked->scene;
969 
970   if (bezt->f2 & SELECT) {
971     mirror_bezier_xaxis_ex(bezt, CFRA);
972   }
973 
974   return 0;
975 }
976 
mirror_bezier_yaxis(KeyframeEditData * UNUSED (ked),BezTriple * bezt)977 static short mirror_bezier_yaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
978 {
979   if (bezt->f2 & SELECT) {
980     /* Yes, names are inverted, we are mirroring across y axis, hence along x axis... */
981     mirror_bezier_xaxis_ex(bezt, 0.0f);
982   }
983 
984   return 0;
985 }
986 
mirror_bezier_xaxis(KeyframeEditData * UNUSED (ked),BezTriple * bezt)987 static short mirror_bezier_xaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
988 {
989   if (bezt->f2 & SELECT) {
990     /* Yes, names are inverted, we are mirroring across x axis, hence along y axis... */
991     mirror_bezier_yaxis_ex(bezt, 0.0f);
992   }
993 
994   return 0;
995 }
996 
mirror_bezier_marker(KeyframeEditData * ked,BezTriple * bezt)997 static short mirror_bezier_marker(KeyframeEditData *ked, BezTriple *bezt)
998 {
999   /* mirroring time stored in f1 */
1000   if (bezt->f2 & SELECT) {
1001     mirror_bezier_xaxis_ex(bezt, ked->f1);
1002   }
1003 
1004   return 0;
1005 }
1006 
mirror_bezier_time(KeyframeEditData * ked,BezTriple * bezt)1007 static short mirror_bezier_time(KeyframeEditData *ked, BezTriple *bezt)
1008 {
1009   /* value to mirror over is stored in f1 */
1010   if (bezt->f2 & SELECT) {
1011     mirror_bezier_xaxis_ex(bezt, ked->f1);
1012   }
1013 
1014   return 0;
1015 }
1016 
mirror_bezier_value(KeyframeEditData * ked,BezTriple * bezt)1017 static short mirror_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
1018 {
1019   /* value to mirror over is stored in the custom data -> first float value slot */
1020   if (bezt->f2 & SELECT) {
1021     mirror_bezier_yaxis_ex(bezt, ked->f1);
1022   }
1023 
1024   return 0;
1025 }
1026 
1027 /* Note: for markers and 'value', the values to use must be supplied as the first float value */
1028 /* calchandles_fcurve */
ANIM_editkeyframes_mirror(short mode)1029 KeyframeEditFunc ANIM_editkeyframes_mirror(short mode)
1030 {
1031   switch (mode) {
1032     case MIRROR_KEYS_CURFRAME: /* mirror over current frame */
1033       return mirror_bezier_cframe;
1034     case MIRROR_KEYS_YAXIS: /* mirror over frame 0 */
1035       return mirror_bezier_yaxis;
1036     case MIRROR_KEYS_XAXIS: /* mirror over value 0 */
1037       return mirror_bezier_xaxis;
1038     case MIRROR_KEYS_MARKER: /* mirror over marker */
1039       return mirror_bezier_marker;
1040     case MIRROR_KEYS_TIME: /* mirror over frame/time */
1041       return mirror_bezier_time;
1042     case MIRROR_KEYS_VALUE: /* mirror over given value */
1043       return mirror_bezier_value;
1044     default: /* just in case */
1045       return mirror_bezier_yaxis;
1046   }
1047 }
1048 
1049 /* ******************************************* */
1050 /* Settings */
1051 
1052 /**
1053  * Standard validation step for a few of these
1054  * (implemented as macro for inlining without fn-call overhead):
1055  * "if the handles are not of the same type, set them to type free".
1056  */
1057 #define ENSURE_HANDLES_MATCH(bezt) \
1058   if (bezt->h1 != bezt->h2) { \
1059     if (ELEM(bezt->h1, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM)) { \
1060       bezt->h1 = HD_FREE; \
1061     } \
1062     if (ELEM(bezt->h2, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM)) { \
1063       bezt->h2 = HD_FREE; \
1064     } \
1065   } \
1066   (void)0
1067 
1068 /* Sets the selected bezier handles to type 'auto' */
set_bezier_auto(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1069 static short set_bezier_auto(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1070 {
1071   /* If the key is selected, always apply to both handles. */
1072   if (bezt->f2 & SELECT) {
1073     bezt->h1 = bezt->h2 = HD_AUTO;
1074   }
1075   else {
1076     if (bezt->f1 & SELECT) {
1077       bezt->h1 = HD_AUTO;
1078     }
1079     if (bezt->f3 & SELECT) {
1080       bezt->h2 = HD_AUTO;
1081     }
1082 
1083     ENSURE_HANDLES_MATCH(bezt);
1084   }
1085 
1086   return 0;
1087 }
1088 
1089 /* Sets the selected bezier handles to type 'auto-clamped'
1090  * NOTE: this is like auto above, but they're handled a bit different
1091  */
set_bezier_auto_clamped(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1092 static short set_bezier_auto_clamped(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1093 {
1094   /* If the key is selected, always apply to both handles. */
1095   if (bezt->f2 & SELECT) {
1096     bezt->h1 = bezt->h2 = HD_AUTO_ANIM;
1097   }
1098   else {
1099     if (bezt->f1 & SELECT) {
1100       bezt->h1 = HD_AUTO_ANIM;
1101     }
1102     if (bezt->f3 & SELECT) {
1103       bezt->h2 = HD_AUTO_ANIM;
1104     }
1105 
1106     ENSURE_HANDLES_MATCH(bezt);
1107   }
1108 
1109   return 0;
1110 }
1111 
1112 /* Sets the selected bezier handles to type 'vector'  */
set_bezier_vector(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1113 static short set_bezier_vector(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1114 {
1115   /* If the key is selected, always apply to both handles. */
1116   if (bezt->f2 & SELECT) {
1117     bezt->h1 = bezt->h2 = HD_VECT;
1118   }
1119   else {
1120     if (bezt->f1 & SELECT) {
1121       bezt->h1 = HD_VECT;
1122     }
1123     if (bezt->f3 & SELECT) {
1124       bezt->h2 = HD_VECT;
1125     }
1126   }
1127 
1128   return 0;
1129 }
1130 
1131 /**
1132  * Queries if the handle should be set to 'free' or 'align'.
1133  *
1134  * \note This was used for the 'toggle free/align' option
1135  * currently this isn't used, but may be restored later.
1136  */
bezier_isfree(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1137 static short bezier_isfree(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1138 {
1139   if ((bezt->f1 & SELECT) && (bezt->h1)) {
1140     return 1;
1141   }
1142   if ((bezt->f3 & SELECT) && (bezt->h2)) {
1143     return 1;
1144   }
1145   return 0;
1146 }
1147 
1148 /* Sets selected bezier handles to type 'align' */
set_bezier_align(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1149 static short set_bezier_align(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1150 {
1151   /* If the key is selected, always apply to both handles. */
1152   if (bezt->f2 & SELECT) {
1153     bezt->h1 = bezt->h2 = HD_ALIGN;
1154   }
1155   else {
1156     if (bezt->f1 & SELECT) {
1157       bezt->h1 = HD_ALIGN;
1158     }
1159     if (bezt->f3 & SELECT) {
1160       bezt->h2 = HD_ALIGN;
1161     }
1162   }
1163 
1164   return 0;
1165 }
1166 
1167 /* Sets selected bezier handles to type 'free'  */
set_bezier_free(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1168 static short set_bezier_free(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1169 {
1170   /* If the key is selected, always apply to both handles. */
1171   if (bezt->f2 & SELECT) {
1172     bezt->h1 = bezt->h2 = HD_FREE;
1173   }
1174   else {
1175     if (bezt->f1 & SELECT) {
1176       bezt->h1 = HD_FREE;
1177     }
1178     if (bezt->f3 & SELECT) {
1179       bezt->h2 = HD_FREE;
1180     }
1181   }
1182 
1183   return 0;
1184 }
1185 
1186 /* Set all selected Bezier Handles to a single type */
1187 /* calchandles_fcurve */
ANIM_editkeyframes_handles(short mode)1188 KeyframeEditFunc ANIM_editkeyframes_handles(short mode)
1189 {
1190   switch (mode) {
1191     case HD_AUTO: /* auto */
1192       return set_bezier_auto;
1193     case HD_AUTO_ANIM: /* auto clamped */
1194       return set_bezier_auto_clamped;
1195 
1196     case HD_VECT: /* vector */
1197       return set_bezier_vector;
1198     case HD_FREE: /* free */
1199       return set_bezier_free;
1200     case HD_ALIGN: /* align */
1201       return set_bezier_align;
1202 
1203     default: /* check for toggle free or align? */
1204       return bezier_isfree;
1205   }
1206 }
1207 
1208 /* ------- */
1209 
set_bezt_constant(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1210 static short set_bezt_constant(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1211 {
1212   if (bezt->f2 & SELECT) {
1213     bezt->ipo = BEZT_IPO_CONST;
1214   }
1215   return 0;
1216 }
1217 
set_bezt_linear(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1218 static short set_bezt_linear(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1219 {
1220   if (bezt->f2 & SELECT) {
1221     bezt->ipo = BEZT_IPO_LIN;
1222   }
1223   return 0;
1224 }
1225 
set_bezt_bezier(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1226 static short set_bezt_bezier(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1227 {
1228   if (bezt->f2 & SELECT) {
1229     bezt->ipo = BEZT_IPO_BEZ;
1230   }
1231   return 0;
1232 }
1233 
set_bezt_back(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1234 static short set_bezt_back(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1235 {
1236   if (bezt->f2 & SELECT) {
1237     bezt->ipo = BEZT_IPO_BACK;
1238   }
1239   return 0;
1240 }
1241 
set_bezt_bounce(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1242 static short set_bezt_bounce(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1243 {
1244   if (bezt->f2 & SELECT) {
1245     bezt->ipo = BEZT_IPO_BOUNCE;
1246   }
1247   return 0;
1248 }
1249 
set_bezt_circle(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1250 static short set_bezt_circle(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1251 {
1252   if (bezt->f2 & SELECT) {
1253     bezt->ipo = BEZT_IPO_CIRC;
1254   }
1255   return 0;
1256 }
1257 
set_bezt_cubic(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1258 static short set_bezt_cubic(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1259 {
1260   if (bezt->f2 & SELECT) {
1261     bezt->ipo = BEZT_IPO_CUBIC;
1262   }
1263   return 0;
1264 }
1265 
set_bezt_elastic(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1266 static short set_bezt_elastic(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1267 {
1268   if (bezt->f2 & SELECT) {
1269     bezt->ipo = BEZT_IPO_ELASTIC;
1270   }
1271   return 0;
1272 }
1273 
set_bezt_expo(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1274 static short set_bezt_expo(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1275 {
1276   if (bezt->f2 & SELECT) {
1277     bezt->ipo = BEZT_IPO_EXPO;
1278   }
1279   return 0;
1280 }
1281 
set_bezt_quad(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1282 static short set_bezt_quad(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1283 {
1284   if (bezt->f2 & SELECT) {
1285     bezt->ipo = BEZT_IPO_QUAD;
1286   }
1287   return 0;
1288 }
1289 
set_bezt_quart(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1290 static short set_bezt_quart(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1291 {
1292   if (bezt->f2 & SELECT) {
1293     bezt->ipo = BEZT_IPO_QUART;
1294   }
1295   return 0;
1296 }
1297 
set_bezt_quint(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1298 static short set_bezt_quint(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1299 {
1300   if (bezt->f2 & SELECT) {
1301     bezt->ipo = BEZT_IPO_QUINT;
1302   }
1303   return 0;
1304 }
1305 
set_bezt_sine(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1306 static short set_bezt_sine(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1307 {
1308   if (bezt->f2 & SELECT) {
1309     bezt->ipo = BEZT_IPO_SINE;
1310   }
1311   return 0;
1312 }
1313 
1314 /* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
1315 /* ANIM_editkeyframes_ipocurve_ipotype() ! */
ANIM_editkeyframes_ipo(short mode)1316 KeyframeEditFunc ANIM_editkeyframes_ipo(short mode)
1317 {
1318   switch (mode) {
1319     /* interpolation */
1320     case BEZT_IPO_CONST: /* constant */
1321       return set_bezt_constant;
1322     case BEZT_IPO_LIN: /* linear */
1323       return set_bezt_linear;
1324 
1325     /* easing */
1326     case BEZT_IPO_BACK:
1327       return set_bezt_back;
1328     case BEZT_IPO_BOUNCE:
1329       return set_bezt_bounce;
1330     case BEZT_IPO_CIRC:
1331       return set_bezt_circle;
1332     case BEZT_IPO_CUBIC:
1333       return set_bezt_cubic;
1334     case BEZT_IPO_ELASTIC:
1335       return set_bezt_elastic;
1336     case BEZT_IPO_EXPO:
1337       return set_bezt_expo;
1338     case BEZT_IPO_QUAD:
1339       return set_bezt_quad;
1340     case BEZT_IPO_QUART:
1341       return set_bezt_quart;
1342     case BEZT_IPO_QUINT:
1343       return set_bezt_quint;
1344     case BEZT_IPO_SINE:
1345       return set_bezt_sine;
1346 
1347     default: /* bezier */
1348       return set_bezt_bezier;
1349   }
1350 }
1351 
1352 /* ------- */
1353 
set_keytype_keyframe(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1354 static short set_keytype_keyframe(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1355 {
1356   if (bezt->f2 & SELECT) {
1357     BEZKEYTYPE(bezt) = BEZT_KEYTYPE_KEYFRAME;
1358   }
1359   return 0;
1360 }
1361 
set_keytype_breakdown(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1362 static short set_keytype_breakdown(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1363 {
1364   if (bezt->f2 & SELECT) {
1365     BEZKEYTYPE(bezt) = BEZT_KEYTYPE_BREAKDOWN;
1366   }
1367   return 0;
1368 }
1369 
set_keytype_extreme(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1370 static short set_keytype_extreme(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1371 {
1372   if (bezt->f2 & SELECT) {
1373     BEZKEYTYPE(bezt) = BEZT_KEYTYPE_EXTREME;
1374   }
1375   return 0;
1376 }
1377 
set_keytype_jitter(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1378 static short set_keytype_jitter(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1379 {
1380   if (bezt->f2 & SELECT) {
1381     BEZKEYTYPE(bezt) = BEZT_KEYTYPE_JITTER;
1382   }
1383   return 0;
1384 }
1385 
set_keytype_moving_hold(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1386 static short set_keytype_moving_hold(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1387 {
1388   if (bezt->f2 & SELECT) {
1389     BEZKEYTYPE(bezt) = BEZT_KEYTYPE_MOVEHOLD;
1390   }
1391   return 0;
1392 }
1393 
1394 /* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
ANIM_editkeyframes_keytype(short mode)1395 KeyframeEditFunc ANIM_editkeyframes_keytype(short mode)
1396 {
1397   switch (mode) {
1398     case BEZT_KEYTYPE_BREAKDOWN: /* breakdown */
1399       return set_keytype_breakdown;
1400 
1401     case BEZT_KEYTYPE_EXTREME: /* extreme keyframe */
1402       return set_keytype_extreme;
1403 
1404     case BEZT_KEYTYPE_JITTER: /* jitter keyframe */
1405       return set_keytype_jitter;
1406 
1407     case BEZT_KEYTYPE_MOVEHOLD: /* moving hold */
1408       return set_keytype_moving_hold;
1409 
1410     case BEZT_KEYTYPE_KEYFRAME: /* proper keyframe */
1411     default:
1412       return set_keytype_keyframe;
1413   }
1414 }
1415 
1416 /* ------- */
1417 
set_easingtype_easein(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1418 static short set_easingtype_easein(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1419 {
1420   if (bezt->f2 & SELECT) {
1421     bezt->easing = BEZT_IPO_EASE_IN;
1422   }
1423   return 0;
1424 }
1425 
set_easingtype_easeout(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1426 static short set_easingtype_easeout(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1427 {
1428   if (bezt->f2 & SELECT) {
1429     bezt->easing = BEZT_IPO_EASE_OUT;
1430   }
1431   return 0;
1432 }
1433 
set_easingtype_easeinout(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1434 static short set_easingtype_easeinout(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1435 {
1436   if (bezt->f2 & SELECT) {
1437     bezt->easing = BEZT_IPO_EASE_IN_OUT;
1438   }
1439   return 0;
1440 }
1441 
set_easingtype_easeauto(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1442 static short set_easingtype_easeauto(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1443 {
1444   if (bezt->f2 & SELECT) {
1445     bezt->easing = BEZT_IPO_EASE_AUTO;
1446   }
1447   return 0;
1448 }
1449 
1450 /* Set the easing type of the selected BezTriples in each F-Curve to the specified one */
ANIM_editkeyframes_easing(short mode)1451 KeyframeEditFunc ANIM_editkeyframes_easing(short mode)
1452 {
1453   switch (mode) {
1454     case BEZT_IPO_EASE_IN: /* ease in */
1455       return set_easingtype_easein;
1456 
1457     case BEZT_IPO_EASE_OUT: /* ease out */
1458       return set_easingtype_easeout;
1459 
1460     case BEZT_IPO_EASE_IN_OUT: /* both */
1461       return set_easingtype_easeinout;
1462 
1463     default: /* auto */
1464       return set_easingtype_easeauto;
1465   }
1466 }
1467 
1468 /* ******************************************* */
1469 /* Selection */
1470 
select_bezier_add(KeyframeEditData * ked,BezTriple * bezt)1471 static short select_bezier_add(KeyframeEditData *ked, BezTriple *bezt)
1472 {
1473   /* Only act on visible items, so check handle visibility state. */
1474   const bool handles_visible = ked && ((ked->iterflags & KEYFRAME_ITER_HANDLES_DEFAULT_INVISIBLE) ?
1475                                            (BEZT_ISSEL_ANY(bezt)) :
1476                                            true);
1477 
1478   /* if we've got info on what to select, use it, otherwise select all */
1479   if ((ked) && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES) && handles_visible) {
1480     if (ked->curflags & KEYFRAME_OK_KEY) {
1481       bezt->f2 |= SELECT;
1482     }
1483     if (ked->curflags & KEYFRAME_OK_H1) {
1484       bezt->f1 |= SELECT;
1485     }
1486     if (ked->curflags & KEYFRAME_OK_H2) {
1487       bezt->f3 |= SELECT;
1488     }
1489   }
1490   else {
1491     BEZT_SEL_ALL(bezt);
1492   }
1493 
1494   return 0;
1495 }
1496 
select_bezier_subtract(KeyframeEditData * ked,BezTriple * bezt)1497 static short select_bezier_subtract(KeyframeEditData *ked, BezTriple *bezt)
1498 {
1499   /* Only act on visible items, so check handle visibility state. */
1500   const bool handles_visible = ked && ((ked->iterflags & KEYFRAME_ITER_HANDLES_DEFAULT_INVISIBLE) ?
1501                                            (BEZT_ISSEL_ANY(bezt)) :
1502                                            true);
1503 
1504   /* if we've got info on what to deselect, use it, otherwise deselect all */
1505   if ((ked) && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES) && handles_visible) {
1506     if (ked->curflags & KEYFRAME_OK_KEY) {
1507       bezt->f2 &= ~SELECT;
1508     }
1509     if (ked->curflags & KEYFRAME_OK_H1) {
1510       bezt->f1 &= ~SELECT;
1511     }
1512     if (ked->curflags & KEYFRAME_OK_H2) {
1513       bezt->f3 &= ~SELECT;
1514     }
1515   }
1516   else {
1517     BEZT_DESEL_ALL(bezt);
1518   }
1519 
1520   return 0;
1521 }
1522 
select_bezier_invert(KeyframeEditData * UNUSED (ked),BezTriple * bezt)1523 static short select_bezier_invert(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1524 {
1525   /* Invert the selection for the whole bezier triple */
1526   bezt->f2 ^= SELECT;
1527   if (bezt->f2 & SELECT) {
1528     bezt->f1 |= SELECT;
1529     bezt->f3 |= SELECT;
1530   }
1531   else {
1532     bezt->f1 &= ~SELECT;
1533     bezt->f3 &= ~SELECT;
1534   }
1535   return 0;
1536 }
1537 
ANIM_editkeyframes_select(short selectmode)1538 KeyframeEditFunc ANIM_editkeyframes_select(short selectmode)
1539 {
1540   switch (selectmode) {
1541     case SELECT_ADD: /* add */
1542       return select_bezier_add;
1543     case SELECT_SUBTRACT: /* subtract */
1544       return select_bezier_subtract;
1545     case SELECT_INVERT: /* invert */
1546       return select_bezier_invert;
1547     default: /* replace (need to clear all, then add) */
1548       return select_bezier_add;
1549   }
1550 }
1551 
1552 /* ******************************************* */
1553 /* Selection Maps */
1554 
1555 /* Selection maps are simply fancy names for char arrays that store on/off
1556  * info for whether the selection status. The main purpose for these is to
1557  * allow extra info to be tagged to the keyframes without influencing their
1558  * values or having to be removed later.
1559  */
1560 
1561 /* ----------- */
1562 
selmap_build_bezier_more(KeyframeEditData * ked,BezTriple * bezt)1563 static short selmap_build_bezier_more(KeyframeEditData *ked, BezTriple *bezt)
1564 {
1565   FCurve *fcu = ked->fcu;
1566   char *map = ked->data;
1567   int i = ked->curIndex;
1568 
1569   /* if current is selected, just make sure it stays this way */
1570   if (BEZT_ISSEL_ANY(bezt)) {
1571     map[i] = 1;
1572     return 0;
1573   }
1574 
1575   /* if previous is selected, that means that selection should extend across */
1576   if (i > 0) {
1577     BezTriple *prev = bezt - 1;
1578 
1579     if (BEZT_ISSEL_ANY(prev)) {
1580       map[i] = 1;
1581       return 0;
1582     }
1583   }
1584 
1585   /* if next is selected, that means that selection should extend across */
1586   if (i < (fcu->totvert - 1)) {
1587     BezTriple *next = bezt + 1;
1588 
1589     if (BEZT_ISSEL_ANY(next)) {
1590       map[i] = 1;
1591       return 0;
1592     }
1593   }
1594 
1595   return 0;
1596 }
1597 
selmap_build_bezier_less(KeyframeEditData * ked,BezTriple * bezt)1598 static short selmap_build_bezier_less(KeyframeEditData *ked, BezTriple *bezt)
1599 {
1600   FCurve *fcu = ked->fcu;
1601   char *map = ked->data;
1602   int i = ked->curIndex;
1603 
1604   /* if current is selected, check the left/right keyframes
1605    * since it might need to be deselected (but otherwise no)
1606    */
1607   if (BEZT_ISSEL_ANY(bezt)) {
1608     /* if previous is not selected, we're on the tip of an iceberg */
1609     if (i > 0) {
1610       BezTriple *prev = bezt - 1;
1611 
1612       if (BEZT_ISSEL_ANY(prev) == 0) {
1613         return 0;
1614       }
1615     }
1616     else if (i == 0) {
1617       /* current keyframe is selected at an endpoint, so should get deselected */
1618       return 0;
1619     }
1620 
1621     /* if next is not selected, we're on the tip of an iceberg */
1622     if (i < (fcu->totvert - 1)) {
1623       BezTriple *next = bezt + 1;
1624 
1625       if (BEZT_ISSEL_ANY(next) == 0) {
1626         return 0;
1627       }
1628     }
1629     else if (i == (fcu->totvert - 1)) {
1630       /* current keyframe is selected at an endpoint, so should get deselected */
1631       return 0;
1632     }
1633 
1634     /* if we're still here, that means that keyframe should remain untouched */
1635     map[i] = 1;
1636   }
1637 
1638   return 0;
1639 }
1640 
1641 /* Get callback for building selection map */
ANIM_editkeyframes_buildselmap(short mode)1642 KeyframeEditFunc ANIM_editkeyframes_buildselmap(short mode)
1643 {
1644   switch (mode) {
1645     case SELMAP_LESS: /* less */
1646       return selmap_build_bezier_less;
1647 
1648     case SELMAP_MORE: /* more */
1649     default:
1650       return selmap_build_bezier_more;
1651   }
1652 }
1653 
1654 /* ----------- */
1655 
1656 /* flush selection map values to the given beztriple */
bezt_selmap_flush(KeyframeEditData * ked,BezTriple * bezt)1657 short bezt_selmap_flush(KeyframeEditData *ked, BezTriple *bezt)
1658 {
1659   const char *map = ked->data;
1660   short on = map[ked->curIndex];
1661 
1662   /* select or deselect based on whether the map allows it or not */
1663   if (on) {
1664     BEZT_SEL_ALL(bezt);
1665   }
1666   else {
1667     BEZT_DESEL_ALL(bezt);
1668   }
1669 
1670   return 0;
1671 }
1672