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