Blender  V2.93
keyframes_edit.c
Go to the documentation of this file.
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 
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. */
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 edit-data 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 */
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 */
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 */
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;
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 */
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;
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 */
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 */
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 
344  AnimData *adt = ANIM_nla_mapping_get(ac, ale);
345 
346  if (ked->iterflags & KED_F1_NLA_UNMAP) {
348  }
349  if (ked->iterflags & KED_F2_NLA_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 */
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 */
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 
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) {
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 */
483 {
484  ListBase anim_data = {NULL, NULL};
485  bAnimListElem *ale;
486  int filter;
487 
488  /* filter animation data */
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) {
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 
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)
547 #undef KEY_CHECK_OK
548 
549  /* return ok flags */
550  return ok;
551 }
552 
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))
560 #undef KEY_CHECK_OK
561 
562  /* return ok flags */
563  return ok;
564 }
565 
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 
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)
588 #undef KEY_CHECK_OK
589 
590  /* return ok flags */
591  return ok;
592 }
593 
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))
601 #undef KEY_CHECK_OK
602 
603  /* return ok flags */
604  return ok;
605 }
606 
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])
615 #undef KEY_CHECK_OK
616 
617  /* return ok flags */
618  return ok;
619  }
620  return 0;
621 }
622 
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 
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 
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])
650 #undef KEY_CHECK_OK
651 
652  /* return ok flags */
653  return ok;
654  }
655  return 0;
656 }
657 
659 {
660  /* check for lasso customdata (KeyframeEdit_LassoData) */
661  if (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  */
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 
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 
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])
712 #undef KEY_CHECK_OK
713 
714  /* return ok flags */
715  return ok;
716  }
717  return 0;
718 }
719 
721 {
722  /* check for circle select customdata (KeyframeEdit_CircleData) */
723  if (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  */
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 
742  return KEYFRAME_OK_KEY;
743  }
744  }
745  return 0;
746 }
747 
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;
771  /* only if the point falls within KeyframeEdit_LassoData defined data */
772  return ok_bezier_region_lasso;
774  /* only if the point falls within KeyframeEdit_CircleData defined data */
777  /* same as BEZT_OK_REGION_LASSO, but we're only using the x-value of the points */
780  /* same as BEZT_OK_REGION_CIRCLE, but we're only using the x-value of the points */
782  default: /* nothing was ok */
783  return NULL;
784  }
785 }
786 
787 /* ******************************************* */
788 /* Assorted Utility Functions */
789 
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 */
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  */
832 {
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 */
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 */
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 */
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 */
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 */
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 */
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 */
914 {
915  if (bezt->f2 & SELECT) {
916  bezt->vec[1][1] = ked->f1;
917  }
918  return 0;
919 }
920 
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 
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 
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 
967 {
968  const Scene *scene = ked->scene;
969 
970  if (bezt->f2 & SELECT) {
972  }
973 
974  return 0;
975 }
976 
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 
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 
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 
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 
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 */
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 
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' */
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  */
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' */
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 
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' */
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' */
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 */
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 
1211 {
1212  if (bezt->f2 & SELECT) {
1213  bezt->ipo = BEZT_IPO_CONST;
1214  }
1215  return 0;
1216 }
1217 
1219 {
1220  if (bezt->f2 & SELECT) {
1221  bezt->ipo = BEZT_IPO_LIN;
1222  }
1223  return 0;
1224 }
1225 
1227 {
1228  if (bezt->f2 & SELECT) {
1229  bezt->ipo = BEZT_IPO_BEZ;
1230  }
1231  return 0;
1232 }
1233 
1235 {
1236  if (bezt->f2 & SELECT) {
1237  bezt->ipo = BEZT_IPO_BACK;
1238  }
1239  return 0;
1240 }
1241 
1243 {
1244  if (bezt->f2 & SELECT) {
1245  bezt->ipo = BEZT_IPO_BOUNCE;
1246  }
1247  return 0;
1248 }
1249 
1251 {
1252  if (bezt->f2 & SELECT) {
1253  bezt->ipo = BEZT_IPO_CIRC;
1254  }
1255  return 0;
1256 }
1257 
1259 {
1260  if (bezt->f2 & SELECT) {
1261  bezt->ipo = BEZT_IPO_CUBIC;
1262  }
1263  return 0;
1264 }
1265 
1267 {
1268  if (bezt->f2 & SELECT) {
1269  bezt->ipo = BEZT_IPO_ELASTIC;
1270  }
1271  return 0;
1272 }
1273 
1275 {
1276  if (bezt->f2 & SELECT) {
1277  bezt->ipo = BEZT_IPO_EXPO;
1278  }
1279  return 0;
1280 }
1281 
1283 {
1284  if (bezt->f2 & SELECT) {
1285  bezt->ipo = BEZT_IPO_QUAD;
1286  }
1287  return 0;
1288 }
1289 
1291 {
1292  if (bezt->f2 & SELECT) {
1293  bezt->ipo = BEZT_IPO_QUART;
1294  }
1295  return 0;
1296 }
1297 
1299 {
1300  if (bezt->f2 & SELECT) {
1301  bezt->ipo = BEZT_IPO_QUINT;
1302  }
1303  return 0;
1304 }
1305 
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() ! */
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 
1355 {
1356  if (bezt->f2 & SELECT) {
1358  }
1359  return 0;
1360 }
1361 
1363 {
1364  if (bezt->f2 & SELECT) {
1366  }
1367  return 0;
1368 }
1369 
1371 {
1372  if (bezt->f2 & SELECT) {
1374  }
1375  return 0;
1376 }
1377 
1379 {
1380  if (bezt->f2 & SELECT) {
1382  }
1383  return 0;
1384 }
1385 
1387 {
1388  if (bezt->f2 & SELECT) {
1390  }
1391  return 0;
1392 }
1393 
1394 /* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
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 
1419 {
1420  if (bezt->f2 & SELECT) {
1421  bezt->easing = BEZT_IPO_EASE_IN;
1422  }
1423  return 0;
1424 }
1425 
1427 {
1428  if (bezt->f2 & SELECT) {
1429  bezt->easing = BEZT_IPO_EASE_OUT;
1430  }
1431  return 0;
1432 }
1433 
1435 {
1436  if (bezt->f2 & SELECT) {
1437  bezt->easing = BEZT_IPO_EASE_IN_OUT;
1438  }
1439  return 0;
1440 }
1441 
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 */
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 
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 
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 
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 
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 
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 
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 */
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 */
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 }
typedef float(TangentPoint)[2]
void calchandles_fcurve(struct FCurve *fcu)
Definition: fcurve.c:1391
@ NLATIME_CONVERT_UNMAP
Definition: BKE_nla.h:153
float BKE_nla_tweakedit_remap(struct AnimData *adt, float cframe, short mode)
Definition: nla.c:582
bool BLI_lasso_is_point_inside(const int mcoords[][2], const unsigned int mcoords_len, const int sx, const int sy, const int error_value)
Definition: lasso_2d.c:54
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
MINLINE float len_squared_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void swap_v3_v3(float a[3], float b[3])
bool BLI_rctf_isect_pt_v(const struct rctf *rect, const float xy[2])
void BLI_rctf_transform_pt_v(const rctf *dst, const rctf *src, float xy_dst[2], const float xy_src[2])
Definition: rct.c:561
unsigned int uint
Definition: BLI_sys_types.h:83
#define SWAP(type, a, b)
#define UNUSED(x)
#define ELEM(...)
#define BEZT_SEL_ALL(bezt)
#define BEZT_ISSEL_ANY(bezt)
#define BEZT_DESEL_ALL(bezt)
@ HD_AUTO_ANIM
@ HD_VECT
@ HD_FREE
@ HD_AUTO
@ HD_ALIGN
@ BEZT_IPO_ELASTIC
@ BEZT_IPO_CIRC
@ BEZT_IPO_QUART
@ BEZT_IPO_BACK
@ BEZT_IPO_BOUNCE
@ BEZT_IPO_CUBIC
@ BEZT_IPO_EXPO
@ BEZT_IPO_CONST
@ BEZT_IPO_BEZ
@ BEZT_IPO_LIN
@ BEZT_IPO_SINE
@ BEZT_IPO_QUAD
@ BEZT_IPO_QUINT
@ BEZT_IPO_EASE_OUT
@ BEZT_IPO_EASE_AUTO
@ BEZT_IPO_EASE_IN
@ BEZT_IPO_EASE_IN_OUT
@ BEZT_KEYTYPE_EXTREME
@ BEZT_KEYTYPE_JITTER
@ BEZT_KEYTYPE_BREAKDOWN
@ BEZT_KEYTYPE_MOVEHOLD
@ BEZT_KEYTYPE_KEYFRAME
Object is a sort of wrapper for general info.
#define CFRA
#define FPS
@ ANIMTYPE_SCENE
Definition: ED_anim_api.h:204
@ ANIMTYPE_OBJECT
Definition: ED_anim_api.h:205
#define ANIM_UPDATE_DEFAULT
Definition: ED_anim_api.h:281
@ ALE_SCE
Definition: ED_anim_api.h:264
@ ALE_GPFRAME
Definition: ED_anim_api.h:259
@ ALE_FCURVE
Definition: ED_anim_api.h:258
@ ALE_ALL
Definition: ED_anim_api.h:263
@ ALE_ACT
Definition: ED_anim_api.h:266
@ ALE_OB
Definition: ED_anim_api.h:265
@ ALE_GROUP
Definition: ED_anim_api.h:267
@ ALE_MASKLAY
Definition: ED_anim_api.h:260
@ ANIM_UPDATE_DEPS
Definition: ED_anim_api.h:275
@ ANIM_UPDATE_HANDLES
Definition: ED_anim_api.h:277
@ ANIM_UPDATE_ORDER
Definition: ED_anim_api.h:276
@ ANIMCONT_CHANNEL
Definition: ED_anim_api.h:124
#define BEZKEYTYPE(bezt)
Definition: ED_anim_api.h:789
eAnimFilter_Flags
Definition: ED_anim_api.h:287
@ ANIMFILTER_DATA_VISIBLE
Definition: ED_anim_api.h:295
@ MIRROR_KEYS_VALUE
@ MIRROR_KEYS_YAXIS
@ MIRROR_KEYS_MARKER
@ MIRROR_KEYS_CURFRAME
@ MIRROR_KEYS_XAXIS
@ MIRROR_KEYS_TIME
void(* FcuEditFunc)(struct FCurve *fcu)
@ KEYFRAME_OK_KEY
@ KEYFRAME_OK_H1
@ KEYFRAME_OK_H2
@ KEYFRAME_OK_ALL
@ BEZT_OK_CHANNEL_CIRCLE
@ BEZT_OK_FRAMERANGE
@ BEZT_OK_FRAME
@ BEZT_OK_VALUERANGE
@ BEZT_OK_SELECTED
@ BEZT_OK_REGION_LASSO
@ BEZT_OK_VALUE
@ BEZT_OK_REGION_CIRCLE
@ BEZT_OK_CHANNEL_LASSO
@ BEZT_OK_REGION
@ KEYFRAME_ITER_HANDLES_DEFAULT_INVISIBLE
@ KED_F1_NLA_UNMAP
@ KEYFRAME_ITER_INCL_HANDLES
@ KED_F2_NLA_UNMAP
short(* KeyframeEditFunc)(KeyframeEditData *ked, struct BezTriple *bezt)
@ SNAP_KEYS_CURFRAME
@ SNAP_KEYS_NEARFRAME
@ SNAP_KEYS_NEARMARKER
@ SNAP_KEYS_TIME
@ SNAP_KEYS_NEARSEC
@ SNAP_KEYS_HORIZONTAL
@ SNAP_KEYS_VALUE
@ SELMAP_MORE
@ SELMAP_LESS
@ SELECT_INVERT
@ SELECT_SUBTRACT
@ SELECT_ADD
NSNotificationCenter * center
Read Guarded memory(de)allocation.
void ANIM_animdata_freelist(ListBase *anim_data)
Definition: anim_deps.c:425
void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
Definition: anim_deps.c:330
AnimData * ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale)
Definition: anim_draw.c:178
size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, eAnimFilter_Flags filter_mode, void *data, eAnimCont_Types datatype)
Definition: anim_filter.c:3442
int ED_markers_find_nearest_marker_time(ListBase *markers, float x)
Definition: anim_markers.c:193
#define SELECT
Scene scene
DO_INLINE void filter(lfVector *V, fmatrix3x3 *S)
#define floorf(x)
static short set_bezier_vector(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short ok_bezier_channel_circle(KeyframeEditData *ked, BezTriple *bezt)
static short summary_keyframes_loop(KeyframeEditData *ked, bAnimContext *ac, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
static short bezier_isfree(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short mirror_bezier_xaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static void mirror_bezier_xaxis_ex(BezTriple *bezt, const float center)
static short set_bezt_cubic(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short set_bezt_bounce(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short ok_bezier_framerange(KeyframeEditData *ked, BezTriple *bezt)
static short set_easingtype_easeinout(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short set_bezt_quart(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
KeyframeEditFunc ANIM_editkeyframes_mirror(short mode)
short bezt_selmap_flush(KeyframeEditData *ked, BezTriple *bezt)
#define KEY_CHECK_OK(_index)
static short set_keytype_moving_hold(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
KeyframeEditFunc ANIM_editkeyframes_keytype(short mode)
#define ENSURE_HANDLES_MATCH(bezt)
void ANIM_editkeyframes_refresh(bAnimContext *ac)
KeyframeEditFunc ANIM_editkeyframes_easing(short mode)
static short set_bezt_back(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short set_bezier_align(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short set_keytype_keyframe(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short snap_bezier_horizontal(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short select_bezier_subtract(KeyframeEditData *ked, BezTriple *bezt)
static short snap_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
KeyframeEditFunc ANIM_editkeyframes_ipo(short mode)
static short mirror_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
static short selmap_build_bezier_more(KeyframeEditData *ked, BezTriple *bezt)
bool keyframe_region_lasso_test(const KeyframeEdit_LassoData *data_lasso, const float xy[2])
static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt)
#define KEYFRAME_OK_CHECKS(check)
static short select_bezier_add(KeyframeEditData *ked, BezTriple *bezt)
static short set_bezt_bezier(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short snap_bezier_nearmarker(KeyframeEditData *ked, BezTriple *bezt)
static short scene_keyframes_loop(KeyframeEditData *ked, bDopeSheet *ads, Scene *sce, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
static short set_bezt_linear(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short set_easingtype_easein(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short set_bezier_auto_clamped(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short snap_bezier_time(KeyframeEditData *ked, BezTriple *bezt)
static short set_keytype_jitter(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short set_keytype_extreme(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short set_keytype_breakdown(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short set_bezt_elastic(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short set_bezt_quad(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short select_bezier_invert(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
KeyframeEditFunc ANIM_editkeyframes_select(short selectmode)
static short ok_bezier_frame(KeyframeEditData *ked, BezTriple *bezt)
static short set_easingtype_easeauto(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short set_bezt_expo(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short set_bezier_free(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
short bezt_to_cfraelem(KeyframeEditData *ked, BezTriple *bezt)
static short snap_bezier_cframe(KeyframeEditData *ked, BezTriple *bezt)
KeyframeEditFunc ANIM_editkeyframes_buildselmap(short mode)
short ANIM_animchanneldata_keyframes_loop(KeyframeEditData *ked, bDopeSheet *ads, void *data, int keytype, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
static short agrp_keyframes_loop(KeyframeEditData *ked, bActionGroup *agrp, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
static short mirror_bezier_yaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short mirror_bezier_cframe(KeyframeEditData *ked, BezTriple *bezt)
static short set_bezier_auto(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked, bDopeSheet *ads, bAnimListElem *ale, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
static void mirror_bezier_yaxis_ex(BezTriple *bezt, const float center)
bool keyframe_region_circle_test(const KeyframeEdit_CircleData *data_circle, const float xy[2])
void bezt_remap_times(KeyframeEditData *ked, BezTriple *bezt)
static short set_bezt_quint(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked, FCurve *fcu, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
static short set_bezt_sine(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short set_bezt_circle(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
KeyframeEditFunc ANIM_editkeyframes_snap(short mode)
static short act_keyframes_loop(KeyframeEditData *ked, bAction *act, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
static short ob_keyframes_loop(KeyframeEditData *ked, bDopeSheet *ads, Object *ob, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
static short snap_bezier_nearestsec(KeyframeEditData *ked, BezTriple *bezt)
static short mirror_bezier_marker(KeyframeEditData *ked, BezTriple *bezt)
static short set_bezt_constant(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short selmap_build_bezier_less(KeyframeEditData *ked, BezTriple *bezt)
static short ok_bezier_region(KeyframeEditData *ked, BezTriple *bezt)
void ANIM_animdata_keyframe_callback(bAnimContext *ac, eAnimFilter_Flags filter, KeyframeEditFunc callback_fn)
short bezt_calc_average(KeyframeEditData *ked, BezTriple *bezt)
static short ok_bezier_selected(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short ok_bezier_valuerange(KeyframeEditData *ked, BezTriple *bezt)
static short mirror_bezier_time(KeyframeEditData *ked, BezTriple *bezt)
static short ok_bezier_channel_lasso(KeyframeEditData *ked, BezTriple *bezt)
static short snap_bezier_nearest(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short set_easingtype_easeout(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short ok_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt)
KeyframeEditFunc ANIM_editkeyframes_handles(short mode)
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
static ulong * next
IMETHOD Vector diff(const Vector &a, const Vector &b, double dt=1)
return ret
unsigned char uint8_t
Definition: stdint.h:81
struct Object * object
float vec[3][3]
float cfra
Definition: BKE_fcurve.h:56
struct FCurve * next
bActionGroup * grp
BezTriple * bezt
unsigned int totvert
struct FCurve * fcu
eKeyframeIterFlags iterflags
struct Scene * scene
eKeyframeVertOk curflags
void * first
Definition: DNA_listBase.h:47
struct AnimData * adt
struct AnimData * adt
ListBase curves
struct bDopeSheet * ads
Definition: ED_anim_api.h:92
short datatype
Definition: ED_anim_api.h:75
void * data
Definition: ED_anim_api.h:73
struct bAnimListElem * next
Definition: ED_anim_api.h:135
void * key_data
Definition: ED_anim_api.h:154
struct AnimData * adt
Definition: ED_anim_api.h:170
struct ID * id
Definition: ED_anim_api.h:168