Blender  V2.93
graph_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) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19 
24 #include <float.h>
25 #include <math.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #ifdef WITH_AUDASPACE
30 # include <AUD_Special.h>
31 #endif
32 
33 #include "MEM_guardedalloc.h"
34 
35 #include "BLI_blenlib.h"
36 #include "BLI_math.h"
37 #include "BLI_utildefines.h"
38 
39 #include "DNA_anim_types.h"
40 #include "DNA_scene_types.h"
41 
42 #include "RNA_access.h"
43 #include "RNA_define.h"
44 #include "RNA_enum_types.h"
45 
46 #include "BLT_translation.h"
47 
48 #include "BKE_animsys.h"
49 #include "BKE_context.h"
50 #include "BKE_fcurve.h"
51 #include "BKE_global.h"
52 #include "BKE_nla.h"
53 #include "BKE_report.h"
54 
55 #include "DEG_depsgraph_build.h"
56 
57 #include "UI_interface.h"
58 #include "UI_view2d.h"
59 
60 #include "ED_anim_api.h"
61 #include "ED_keyframes_edit.h"
62 #include "ED_keyframing.h"
63 #include "ED_markers.h"
64 #include "ED_screen.h"
65 #include "ED_transform.h"
66 
67 #include "WM_api.h"
68 #include "WM_types.h"
69 
70 #include "graph_intern.h"
71 
72 /* ************************************************************************** */
73 /* INSERT DUPLICATE AND BAKE KEYFRAMES */
74 
75 /* -------------------------------------------------------------------- */
79 /* Mode defines for insert keyframes tool. */
86 
87 /* RNA mode types for insert keyframes tool. */
90  "ALL",
91  0,
92  "All Channels",
93  "Insert a keyframe on all visible and editable F-Curves using each curve's current value"},
95  "SEL",
96  0,
97  "Only Selected Channels",
98  "Insert a keyframe on selected F-Curves using each curve's current value"},
100  "CURSOR_ACTIVE",
101  0,
102  "Active Channels at Cursor",
103  "Insert a keyframe for the active F-Curve at the cursor point"},
105  "CURSOR_SEL",
106  0,
107  "Selected Channels at Cursor",
108  "Insert a keyframe for selected F-Curves at the cursor point"},
109  {0, NULL, 0, NULL, NULL},
110 };
111 
112 /* This function is responsible for snapping keyframes to frame-times. */
114 {
115  ListBase anim_data = {NULL, NULL};
116  ListBase nla_cache = {NULL, NULL};
117  bAnimListElem *ale;
118  int filter;
119  size_t num_items;
120 
121  ReportList *reports = ac->reports;
122  SpaceGraph *sipo = (SpaceGraph *)ac->sl;
123  Scene *scene = ac->scene;
125  eInsertKeyFlags flag = 0;
126 
127  /* Filter data. */
130  if (mode & GRAPHKEYS_INSERTKEY_SEL) {
132  }
133  else if (mode & GRAPHKEYS_INSERTKEY_ACTIVE) {
135  }
136 
137  num_items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
138  if (num_items == 0) {
139  if (mode & GRAPHKEYS_INSERTKEY_ACTIVE) {
140  BKE_report(reports,
141  RPT_ERROR,
142  "No active F-Curve to add a keyframe to. Select an editable F-Curve first");
143  }
144  else if (mode & GRAPHKEYS_INSERTKEY_SEL) {
145  BKE_report(reports, RPT_ERROR, "No selected F-Curves to add keyframes to");
146  }
147  else {
148  BKE_report(reports, RPT_ERROR, "No channels to add keyframes to");
149  }
150 
151  return;
152  }
153 
154  /* Init key-framing flag. */
155  flag = ANIM_get_keyframing_flags(scene, true);
156 
157  /* Insert keyframes. */
158  if (mode & GRAPHKEYS_INSERTKEY_CURSOR) {
159  for (ale = anim_data.first; ale; ale = ale->next) {
160  AnimData *adt = ANIM_nla_mapping_get(ac, ale);
161  FCurve *fcu = (FCurve *)ale->key_data;
162 
163  short mapping_flag = ANIM_get_normalization_flags(ac);
164  float offset;
165  float unit_scale = ANIM_unit_mapping_get_factor(
166  ac->scene, ale->id, ale->key_data, mapping_flag, &offset);
167 
168  float x, y;
169 
170  /* perform time remapping for x-coordinate (if necessary) */
171  if ((sipo) && (sipo->mode == SIPO_MODE_DRIVERS)) {
172  x = sipo->cursorTime;
173  }
174  else if (adt) {
176  }
177  else {
178  x = (float)CFRA;
179  }
180 
181  /* Normalize units of cursor's value. */
182  if (sipo) {
183  y = (sipo->cursorVal / unit_scale) - offset;
184  }
185  else {
186  y = 0.0f;
187  }
188 
189  /* Insert keyframe directly into the F-Curve. */
190  insert_vert_fcurve(fcu, x, y, ts->keyframe_type, 0);
191 
192  ale->update |= ANIM_UPDATE_DEFAULT;
193  }
194  }
195  else {
197  ac->depsgraph, (float)CFRA);
198  for (ale = anim_data.first; ale; ale = ale->next) {
199  FCurve *fcu = (FCurve *)ale->key_data;
200 
201  /* Read value from property the F-Curve represents, or from the curve only?
202  *
203  * - ale->id != NULL:
204  * Typically, this means that we have enough info to try resolving the path.
205  * - ale->owner != NULL:
206  * If this is set, then the path may not be resolvable from the ID alone,
207  * so it's easier for now to just read the F-Curve directly.
208  * (TODO: add the full-blown PointerRNA relative parsing case here... (Joshua Leung 2015))
209  * - fcu->driver != NULL:
210  * If this is set, then it's a driver. If we don't check for this, we'd end
211  * up adding the keyframes on a new F-Curve in the action data instead.
212  */
213  if (ale->id && !ale->owner && !fcu->driver) {
215  reports,
216  ale->id,
217  NULL,
218  ((fcu->grp) ? (fcu->grp->name) : (NULL)),
219  fcu->rna_path,
220  fcu->array_index,
221  &anim_eval_context,
222  ts->keyframe_type,
223  &nla_cache,
224  flag);
225  }
226  else {
227  AnimData *adt = ANIM_nla_mapping_get(ac, ale);
228 
229  /* Adjust current frame for NLA-mapping. */
230  float cfra = (float)CFRA;
231  if ((sipo) && (sipo->mode == SIPO_MODE_DRIVERS)) {
232  cfra = sipo->cursorTime;
233  }
234  else if (adt) {
236  }
237 
238  const float curval = evaluate_fcurve_only_curve(fcu, cfra);
239  insert_vert_fcurve(fcu, cfra, curval, ts->keyframe_type, 0);
240  }
241 
242  ale->update |= ANIM_UPDATE_DEFAULT;
243  }
244  }
245 
247 
248  ANIM_animdata_update(ac, &anim_data);
249  ANIM_animdata_freelist(&anim_data);
250 }
251 
252 /* ------------------- */
253 
255 {
256  bAnimContext ac;
258 
259  /* Get editor data. */
260  if (ANIM_animdata_get_context(C, &ac) == 0) {
261  return OPERATOR_CANCELLED;
262  }
263 
264  /* Which channels to affect?. */
265  mode = RNA_enum_get(op->ptr, "type");
266 
267  /* Insert keyframes. */
268  insert_graph_keys(&ac, mode);
269 
270  /* Set notifier that keyframes have changed. */
272 
273  return OPERATOR_FINISHED;
274 }
275 
277 {
278  /* Identifiers */
279  ot->name = "Insert Keyframes";
280  ot->idname = "GRAPH_OT_keyframe_insert";
281  ot->description = "Insert keyframes for the specified channels";
282 
283  /* API callbacks */
287 
288  /* Flags */
290 
291  /* Id-props */
292  ot->prop = RNA_def_enum(ot->srna, "type", prop_graphkeys_insertkey_types, 0, "Type", "");
293 }
294 
297 /* -------------------------------------------------------------------- */
302 {
303  bAnimContext ac;
304  bAnimListElem *ale;
305  AnimData *adt;
306  FCurve *fcu;
307  float frame, val;
308 
309  /* Get animation context. */
310  if (ANIM_animdata_get_context(C, &ac) == 0) {
311  return OPERATOR_CANCELLED;
312  }
313 
314  /* Get active F-Curve 'anim-list-element'. */
315  ale = get_active_fcurve_channel(&ac);
316  if (ELEM(NULL, ale, ale->data)) {
317  if (ale) {
318  MEM_freeN(ale);
319  }
320  return OPERATOR_CANCELLED;
321  }
322  fcu = ale->data;
323 
324  /* When there are F-Modifiers on the curve, only allow adding
325  * keyframes if these will be visible after doing so...
326  */
327  if (BKE_fcurve_is_keyframable(fcu)) {
328  ListBase anim_data;
329  ToolSettings *ts = ac.scene->toolsettings;
330 
331  short mapping_flag = ANIM_get_normalization_flags(&ac);
332  float scale, offset;
333 
334  /* Preserve selection? */
335  if (RNA_boolean_get(op->ptr, "extend") == false) {
336  /* Deselect all keyframes first,
337  * so that we can immediately start manipulating the newly added one(s)
338  * - only affect the keyframes themselves, as we don't want channels popping in and out. */
339  deselect_graph_keys(&ac, false, SELECT_SUBTRACT, false);
340  }
341 
342  /* Get frame and value from props. */
343  frame = RNA_float_get(op->ptr, "frame");
344  val = RNA_float_get(op->ptr, "value");
345 
346  /* Apply inverse NLA-mapping to frame to get correct time in un-scaled action. */
347  adt = ANIM_nla_mapping_get(&ac, ale);
348  frame = BKE_nla_tweakedit_remap(adt, frame, NLATIME_CONVERT_UNMAP);
349 
350  /* Apply inverse unit-mapping to value to get correct value for F-Curves. */
352  ac.scene, ale->id, fcu, mapping_flag | ANIM_UNITCONV_RESTORE, &offset);
353 
354  val = val * scale - offset;
355 
356  /* Insert keyframe on the specified frame + value. */
357  insert_vert_fcurve(fcu, frame, val, ts->keyframe_type, 0);
358 
359  ale->update |= ANIM_UPDATE_DEPS;
360 
361  BLI_listbase_clear(&anim_data);
362  BLI_addtail(&anim_data, ale);
363 
364  ANIM_animdata_update(&ac, &anim_data);
365  }
366  else {
367  /* Warn about why this can't happen. */
368  if (fcu->fpt) {
369  BKE_report(op->reports, RPT_ERROR, "Keyframes cannot be added to sampled F-Curves");
370  }
371  else if (fcu->flag & FCURVE_PROTECTED) {
372  BKE_report(op->reports, RPT_ERROR, "Active F-Curve is not editable");
373  }
374  else {
375  BKE_report(op->reports, RPT_ERROR, "Remove F-Modifiers from F-Curve to add keyframes");
376  }
377  }
378 
379  /* Free temp data. */
380  MEM_freeN(ale);
381 
382  /* Set notifier that keyframes have changed. */
384 
385  /* Done */
386  return OPERATOR_FINISHED;
387 }
388 
390 {
391  bAnimContext ac;
392  ARegion *region;
393  View2D *v2d;
394  int mval[2];
395  float x, y;
396 
397  /* Get animation context. */
398  if (ANIM_animdata_get_context(C, &ac) == 0) {
399  return OPERATOR_CANCELLED;
400  }
401 
402  /* Store mouse coordinates in View2D space, into the operator's properties. */
403  region = ac.region;
404  v2d = &region->v2d;
405 
406  mval[0] = (event->x - region->winrct.xmin);
407  mval[1] = (event->y - region->winrct.ymin);
408 
409  UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
410 
411  RNA_float_set(op->ptr, "frame", x);
412  RNA_float_set(op->ptr, "value", y);
413 
414  /* Run exec now. */
415  return graphkeys_click_insert_exec(C, op);
416 }
417 
419 {
420  /* Identifiers */
421  ot->name = "Click-Insert Keyframes";
422  ot->idname = "GRAPH_OT_click_insert";
423  ot->description = "Insert new keyframe at the cursor position for the active F-Curve";
424 
425  /* API callbacks */
429 
430  /* Flags */
432 
433  /* Properties */
435  "frame",
436  1.0f,
437  -FLT_MAX,
438  FLT_MAX,
439  "Frame Number",
440  "Frame to insert keyframe on",
441  0,
442  100);
444  ot->srna, "value", 1.0f, -FLT_MAX, FLT_MAX, "Value", "Value for keyframe on", 0, 100);
445 
447  "extend",
448  false,
449  "Extend",
450  "Extend selection instead of deselecting everything first");
451 }
452 
455 /* -------------------------------------------------------------------- */
461 static short copy_graph_keys(bAnimContext *ac)
462 {
463  ListBase anim_data = {NULL, NULL};
464  int filter, ok = 0;
465 
466  /* Clear buffer first. */
468 
469  /* Filter data
470  * - First time we try to filter more strictly, allowing only selected channels
471  * to allow copying animation between channels.
472  */
474 
475  if (ANIM_animdata_filter(ac, &anim_data, filter | ANIMFILTER_SEL, ac->data, ac->datatype) == 0) {
476  ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
477  }
478 
479  /* Copy keyframes. */
480  ok = copy_animedit_keys(ac, &anim_data);
481 
482  /* Clean up. */
483  ANIM_animdata_freelist(&anim_data);
484 
485  return ok;
486 }
487 
489  const eKeyPasteOffset offset_mode,
490  const eKeyMergeMode merge_mode,
491  bool flip)
492 {
493  ListBase anim_data = {NULL, NULL};
494  int filter, ok = 0;
495 
496  /* Filter data
497  * - First time we try to filter more strictly, allowing only selected channels
498  * to allow copying animation between channels
499  * - Second time, we loosen things up if nothing was found the first time, allowing
500  * users to just paste keyframes back into the original curve again T31670.
501  */
504 
505  if (ANIM_animdata_filter(ac, &anim_data, filter | ANIMFILTER_SEL, ac->data, ac->datatype) == 0) {
506  ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
507  }
508 
509  /* Paste keyframes. */
510  ok = paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode, flip);
511 
512  /* Clean up. */
513  ANIM_animdata_freelist(&anim_data);
514 
515  return ok;
516 }
517 
518 /* ------------------- */
519 
521 {
522  bAnimContext ac;
523 
524  /* Get editor data. */
525  if (ANIM_animdata_get_context(C, &ac) == 0) {
526  return OPERATOR_CANCELLED;
527  }
528 
529  /* Copy keyframes. */
530  if (copy_graph_keys(&ac)) {
531  BKE_report(op->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer");
532  return OPERATOR_CANCELLED;
533  }
534 
535  /* Just return - no operator needed here (no changes). */
536  return OPERATOR_FINISHED;
537 }
538 
540 {
541  /* Identifiers */
542  ot->name = "Copy Keyframes";
543  ot->idname = "GRAPH_OT_copy";
544  ot->description = "Copy selected keyframes to the copy/paste buffer";
545 
546  /* API callbacks */
549 
550  /* Flags */
552 }
553 
555 {
556  bAnimContext ac;
557 
558  const eKeyPasteOffset offset_mode = RNA_enum_get(op->ptr, "offset");
559  const eKeyMergeMode merge_mode = RNA_enum_get(op->ptr, "merge");
560  const bool flipped = RNA_boolean_get(op->ptr, "flipped");
561 
562  /* Get editor data. */
563  if (ANIM_animdata_get_context(C, &ac) == 0) {
564  return OPERATOR_CANCELLED;
565  }
566 
567  /* Ac.reports by default will be the global reports list, which won't show warnings. */
568  ac.reports = op->reports;
569 
570  /* Paste keyframes - non-zero return means an error occurred while trying to paste. */
571  if (paste_graph_keys(&ac, offset_mode, merge_mode, flipped)) {
572  return OPERATOR_CANCELLED;
573  }
574 
575  /* Set notifier that keyframes have changed. */
577 
578  return OPERATOR_FINISHED;
579 }
580 
582  wmOperatorType *UNUSED(op),
583  PointerRNA *ptr)
584 {
585  /* Custom description if the 'flipped' option is used. */
586  if (RNA_boolean_get(ptr, "flipped")) {
587  return BLI_strdup("Paste keyframes from mirrored bones if they exist");
588  }
589 
590  /* Use the default description in the other cases. */
591  return NULL;
592 }
593 
595 {
596  PropertyRNA *prop;
597 
598  /* Identifiers */
599  ot->name = "Paste Keyframes";
600  ot->idname = "GRAPH_OT_paste";
601  ot->description =
602  "Paste keyframes from copy/paste buffer for the selected channels, starting on the current "
603  "frame";
604 
605  /* API callbacks */
606 
607  // ot->invoke = WM_operator_props_popup; /* better wait for graph redo panel */
611 
612  /* Flags */
614 
615  /* Props */
617  "offset",
620  "Offset",
621  "Paste time offset of keys");
623  "merge",
626  "Type",
627  "Method of merging pasted keys and existing");
628  prop = RNA_def_boolean(
629  ot->srna, "flipped", false, "Flipped", "Paste keyframes from mirrored bones if they exist");
631 }
632 
635 /* -------------------------------------------------------------------- */
640 {
641  ListBase anim_data = {NULL, NULL};
642  bAnimListElem *ale;
643  int filter;
644 
645  /* Filter data. */
648  ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
649 
650  /* Loop through filtered data and delete selected keys. */
651  for (ale = anim_data.first; ale; ale = ale->next) {
653 
654  ale->update |= ANIM_UPDATE_DEFAULT;
655  }
656 
657  ANIM_animdata_update(ac, &anim_data);
658  ANIM_animdata_freelist(&anim_data);
659 }
660 
661 /* ------------------- */
662 
664 {
665  bAnimContext ac;
666 
667  /* Get editor data. */
668  if (ANIM_animdata_get_context(C, &ac) == 0) {
669  return OPERATOR_CANCELLED;
670  }
671 
672  /* Duplicate keyframes. */
674 
675  /* Set notifier that keyframes have changed. */
677 
678  return OPERATOR_FINISHED;
679 }
680 
682 {
683  /* Identifiers */
684  ot->name = "Duplicate Keyframes";
685  ot->idname = "GRAPH_OT_duplicate";
686  ot->description = "Make a copy of all selected keyframes";
687 
688  /* API callbacks */
691 
692  /* Flags */
694 
695  /* To give to transform. */
697 }
698 
701 /* -------------------------------------------------------------------- */
706 {
707  ListBase anim_data = {NULL, NULL};
708  bAnimListElem *ale;
709  int filter;
710  bool changed_final = false;
711 
712  /* Filter data. */
715  ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
716 
717  /* Loop through filtered data and delete selected keys. */
718  for (ale = anim_data.first; ale; ale = ale->next) {
719  FCurve *fcu = (FCurve *)ale->key_data;
720  AnimData *adt = ale->adt;
721  bool changed;
722 
723  /* Delete selected keyframes only. */
724  changed = delete_fcurve_keys(fcu);
725 
726  if (changed) {
727  ale->update |= ANIM_UPDATE_DEFAULT;
728  changed_final = true;
729  }
730 
731  /* Only delete curve too if it won't be doing anything anymore. */
732  if (BKE_fcurve_is_empty(fcu)) {
733  ANIM_fcurve_delete_from_animdata(ac, adt, fcu);
734  ale->key_data = NULL;
735  }
736  }
737 
738  ANIM_animdata_update(ac, &anim_data);
739  ANIM_animdata_freelist(&anim_data);
740 
741  return changed_final;
742 }
743 
744 /* ------------------- */
745 
747 {
748  bAnimContext ac;
749 
750  /* Get editor data. */
751  if (ANIM_animdata_get_context(C, &ac) == 0) {
752  return OPERATOR_CANCELLED;
753  }
754 
755  /* Delete keyframes. */
756  if (!delete_graph_keys(&ac)) {
757  return OPERATOR_CANCELLED;
758  }
759 
760  /* Set notifier that keyframes have changed. */
762 
763  return OPERATOR_FINISHED;
764 }
765 
767 {
768  /* Identifiers */
769  ot->name = "Delete Keyframes";
770  ot->idname = "GRAPH_OT_delete";
771  ot->description = "Remove all selected keyframes";
772 
773  /* API callbacks */
777 
778  /* Flags */
781 }
782 
785 /* -------------------------------------------------------------------- */
789 static void clean_graph_keys(bAnimContext *ac, float thresh, bool clean_chan)
790 {
791  ListBase anim_data = {NULL, NULL};
792  bAnimListElem *ale;
793  int filter;
794 
795  /* Filter data. */
798  ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
799 
800  /* Loop through filtered data and clean curves. */
801  for (ale = anim_data.first; ale; ale = ale->next) {
802  clean_fcurve(ac, ale, thresh, clean_chan);
803 
804  ale->update |= ANIM_UPDATE_DEFAULT;
805  }
806 
807  ANIM_animdata_update(ac, &anim_data);
808  ANIM_animdata_freelist(&anim_data);
809 }
810 
811 /* ------------------- */
812 
814 {
815  bAnimContext ac;
816  float thresh;
817  bool clean_chan;
818 
819  /* Get editor data. */
820  if (ANIM_animdata_get_context(C, &ac) == 0) {
821  return OPERATOR_CANCELLED;
822  }
823 
824  /* Get cleaning threshold. */
825  thresh = RNA_float_get(op->ptr, "threshold");
826  clean_chan = RNA_boolean_get(op->ptr, "channels");
827  /* Clean keyframes. */
828  clean_graph_keys(&ac, thresh, clean_chan);
829 
830  /* Set notifier that keyframes have changed. */
832 
833  return OPERATOR_FINISHED;
834 }
835 
837 {
838  /* Identifiers */
839  ot->name = "Clean Keyframes";
840  ot->idname = "GRAPH_OT_clean";
841  ot->description = "Simplify F-Curves by removing closely spaced keyframes";
842 
843  /* API callbacks */
844  // ot->invoke = ???; /* XXX we need that number popup for this! */
847 
848  /* Flags */
850 
851  /* Properties */
852  ot->prop = RNA_def_float(
853  ot->srna, "threshold", 0.001f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 1000.0f);
854  RNA_def_boolean(ot->srna, "channels", false, "Channels", "");
855 }
856 
859 /* -------------------------------------------------------------------- */
865 /* Bake each F-Curve into a set of samples. */
866 static void bake_graph_curves(bAnimContext *ac, int start, int end)
867 {
868  ListBase anim_data = {NULL, NULL};
869  bAnimListElem *ale;
870  int filter;
871 
872  /* Filter data. */
875  ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
876 
877  /* Loop through filtered data and add keys between selected keyframes on every frame. */
878  for (ale = anim_data.first; ale; ale = ale->next) {
879  FCurve *fcu = (FCurve *)ale->key_data;
880  ChannelDriver *driver = fcu->driver;
881 
882  /* Disable driver so that it don't muck up the sampling process. */
883  fcu->driver = NULL;
884 
885  /* Create samples. */
887 
888  /* Restore driver. */
889  fcu->driver = driver;
890 
891  ale->update |= ANIM_UPDATE_DEPS;
892  }
893 
894  ANIM_animdata_update(ac, &anim_data);
895  ANIM_animdata_freelist(&anim_data);
896 }
897 
898 /* ------------------- */
899 
901 {
902  bAnimContext ac;
903  Scene *scene = NULL;
904  int start, end;
905 
906  /* Get editor data. */
907  if (ANIM_animdata_get_context(C, &ac) == 0) {
908  return OPERATOR_CANCELLED;
909  }
910 
911  /* For now, init start/end from preview-range extents. */
912  /* TODO: add properties for this. (Joshua Leung 2009) */
913  scene = ac.scene;
914  start = PSFRA;
915  end = PEFRA;
916 
917  /* Bake keyframes. */
918  bake_graph_curves(&ac, start, end);
919 
920  /* Set notifier that keyframes have changed. */
921  /* NOTE: some distinction between order/number of keyframes and type should be made? */
923 
924  return OPERATOR_FINISHED;
925 }
926 
928 {
929  /* Identifiers */
930  ot->name = "Bake Curve";
931  ot->idname = "GRAPH_OT_bake";
932  ot->description = "Bake selected F-Curves to a set of sampled points defining a similar curve";
933 
934  /* API callbacks */
935  ot->invoke = WM_operator_confirm; /* FIXME */
938 
939  /* Flags */
941 
942  /* TODO: add props for start/end frames (Joshua Leung 2009) */
943 }
944 
947 /* -------------------------------------------------------------------- */
953 /* Un-Bake F-Points into F-Curves. */
954 static void unbake_graph_curves(bAnimContext *ac, int start, int end)
955 {
956  ListBase anim_data = {NULL, NULL};
957  bAnimListElem *ale;
958 
959  /* Filter data. */
962  ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
963 
964  /* Loop through filtered data and add keys between selected keyframes on every frame. */
965  for (ale = anim_data.first; ale; ale = ale->next) {
966  FCurve *fcu = (FCurve *)ale->key_data;
967 
968  fcurve_samples_to_keyframes(fcu, start, end);
969 
970  ale->update |= ANIM_UPDATE_DEPS;
971  }
972 
973  ANIM_animdata_update(ac, &anim_data);
974  ANIM_animdata_freelist(&anim_data);
975 }
976 
977 /* ------------------- */
978 
980 {
981  bAnimContext ac;
982  Scene *scene = NULL;
983  int start, end;
984 
985  /* Get editor data. */
986  if (ANIM_animdata_get_context(C, &ac) == 0) {
987  return OPERATOR_CANCELLED;
988  }
989 
990  scene = ac.scene;
991  start = PSFRA;
992  end = PEFRA;
993 
994  /* Unbake keyframes. */
995  unbake_graph_curves(&ac, start, end);
996 
997  /* Set notifier that keyframes have changed. */
998  /* NOTE: some distinction between order/number of keyframes and type should be made? */
1000 
1001  return OPERATOR_FINISHED;
1002 }
1003 
1005 {
1006  /* Identifiers */
1007  ot->name = "Un-Bake Curve";
1008  ot->idname = "GRAPH_OT_unbake";
1009  ot->description = "Un-Bake selected F-Points to F-Curves";
1010 
1011  /* API callbacks */
1014 
1015  /* Flags */
1017 }
1018 
1019 #ifdef WITH_AUDASPACE
1020 
1023 /* -------------------------------------------------------------------- */
1029 /* ------------------- */
1030 
1031 /* Custom data storage passed to the F-Sample-ing function,
1032  * which provides the necessary info for baking the sound.
1033  */
1034 typedef struct tSoundBakeInfo {
1035  float *samples;
1036  int length;
1037  int cfra;
1038 } tSoundBakeInfo;
1039 
1040 /* ------------------- */
1041 
1042 /* Sampling callback used to determine the value from the sound to
1043  * save in the F-Curve at the specified frame.
1044  */
1045 static float fcurve_samplingcb_sound(FCurve *UNUSED(fcu), void *data, float evaltime)
1046 {
1047  tSoundBakeInfo *sbi = (tSoundBakeInfo *)data;
1048 
1049  int position = evaltime - sbi->cfra;
1050  if ((position < 0) || (position >= sbi->length)) {
1051  return 0.0f;
1052  }
1053 
1054  return sbi->samples[position];
1055 }
1056 
1057 /* ------------------- */
1058 
1060 {
1061  bAnimContext ac;
1062  ListBase anim_data = {NULL, NULL};
1063  bAnimListElem *ale;
1064  int filter;
1065 
1066  tSoundBakeInfo sbi;
1067  Scene *scene = NULL;
1068  int start, end;
1069 
1070  char path[FILE_MAX];
1071 
1072  /* Get editor data. */
1073  if (ANIM_animdata_get_context(C, &ac) == 0) {
1074  return OPERATOR_CANCELLED;
1075  }
1076 
1077  RNA_string_get(op->ptr, "filepath", path);
1078 
1079  if (!BLI_is_file(path)) {
1080  BKE_reportf(op->reports, RPT_ERROR, "File not found '%s'", path);
1081  return OPERATOR_CANCELLED;
1082  }
1083 
1084  scene = ac.scene; /* Current scene. */
1085 
1086  /* Store necessary data for the baking steps. */
1087  sbi.samples = AUD_readSoundBuffer(path,
1088  RNA_float_get(op->ptr, "low"),
1089  RNA_float_get(op->ptr, "high"),
1090  RNA_float_get(op->ptr, "attack"),
1091  RNA_float_get(op->ptr, "release"),
1092  RNA_float_get(op->ptr, "threshold"),
1093  RNA_boolean_get(op->ptr, "use_accumulate"),
1094  RNA_boolean_get(op->ptr, "use_additive"),
1095  RNA_boolean_get(op->ptr, "use_square"),
1096  RNA_float_get(op->ptr, "sthreshold"),
1097  FPS,
1098  &sbi.length);
1099 
1100  if (sbi.samples == NULL) {
1101  BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
1102  return OPERATOR_CANCELLED;
1103  }
1104 
1105  /* Determine extents of the baking. */
1106  sbi.cfra = start = CFRA;
1107  end = CFRA + sbi.length - 1;
1108 
1109  /* Filter anim channels. */
1112  ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1113 
1114  /* Loop through all selected F-Curves, replacing its data with the sound samples. */
1115  for (ale = anim_data.first; ale; ale = ale->next) {
1116  FCurve *fcu = (FCurve *)ale->key_data;
1117 
1118  /* Sample the sound. */
1119  fcurve_store_samples(fcu, &sbi, start, end, fcurve_samplingcb_sound);
1120 
1121  ale->update |= ANIM_UPDATE_DEFAULT;
1122  }
1123 
1124  /* Free sample data. */
1125  free(sbi.samples);
1126 
1127  /* Validate keyframes after editing. */
1128  ANIM_animdata_update(&ac, &anim_data);
1129  ANIM_animdata_freelist(&anim_data);
1130 
1131  /* Set notifier that 'keyframes' have changed. */
1133 
1134  return OPERATOR_FINISHED;
1135 }
1136 
1137 #else /* WITH_AUDASPACE */
1138 
1140 {
1141  BKE_report(op->reports, RPT_ERROR, "Compiled without sound support");
1142 
1143  return OPERATOR_CANCELLED;
1144 }
1145 
1146 #endif /* WITH_AUDASPACE */
1147 
1149 {
1150  bAnimContext ac;
1151 
1152  /* Verify editor data. */
1153  if (ANIM_animdata_get_context(C, &ac) == 0) {
1154  return OPERATOR_CANCELLED;
1155  }
1156 
1157  return WM_operator_filesel(C, op, event);
1158 }
1159 
1161 {
1162  /* Identifiers */
1163  ot->name = "Bake Sound to F-Curves";
1164  ot->idname = "GRAPH_OT_sound_bake";
1165  ot->description = "Bakes a sound wave to selected F-Curves";
1166 
1167  /* API callbacks */
1171 
1172  /* Flags */
1174 
1175  /* Properties */
1178  FILE_SPECIAL,
1179  FILE_OPENFILE,
1184  "low",
1185  0.0f,
1186  0.0,
1187  100000.0,
1188  "Lowest Frequency",
1189  "Cutoff frequency of a high-pass filter that is applied to the audio data",
1190  0.1,
1191  1000.00);
1193  "high",
1194  100000.0,
1195  0.0,
1196  100000.0,
1197  "Highest Frequency",
1198  "Cutoff frequency of a low-pass filter that is applied to the audio data",
1199  0.1,
1200  1000.00);
1202  "attack",
1203  0.005,
1204  0.0,
1205  2.0,
1206  "Attack Time",
1207  "Value for the hull curve calculation that tells how fast the hull curve can rise "
1208  "(the lower the value the steeper it can rise)",
1209  0.01,
1210  0.1);
1212  "release",
1213  0.2,
1214  0.0,
1215  5.0,
1216  "Release Time",
1217  "Value for the hull curve calculation that tells how fast the hull curve can fall "
1218  "(the lower the value the steeper it can fall)",
1219  0.01,
1220  0.2);
1222  "threshold",
1223  0.0,
1224  0.0,
1225  1.0,
1226  "Threshold",
1227  "Minimum amplitude value needed to influence the hull curve",
1228  0.01,
1229  0.1);
1231  "use_accumulate",
1232  0,
1233  "Accumulate",
1234  "Only the positive differences of the hull curve amplitudes are summarized to "
1235  "produce the output");
1237  ot->srna,
1238  "use_additive",
1239  0,
1240  "Additive",
1241  "The amplitudes of the hull curve are summarized (or, when Accumulate is enabled, "
1242  "both positive and negative differences are accumulated)");
1244  "use_square",
1245  0,
1246  "Square",
1247  "The output is a square curve (negative values always result in -1, and "
1248  "positive ones in 1)");
1250  "sthreshold",
1251  0.1,
1252  0.0,
1253  1.0,
1254  "Square Threshold",
1255  "Square only: all values with an absolute amplitude lower than that result in 0",
1256  0.01,
1257  0.1);
1258 }
1259 
1262 /* -------------------------------------------------------------------- */
1269 /* Evaluates the curves between each selected keyframe on each frame, and keys the value. */
1271 {
1272  ListBase anim_data = {NULL, NULL};
1273  bAnimListElem *ale;
1274  int filter;
1275 
1276  /* filter data */
1279  ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1280 
1281  /* Loop through filtered data and add keys between selected keyframes on every frame. */
1282  for (ale = anim_data.first; ale; ale = ale->next) {
1283  sample_fcurve((FCurve *)ale->key_data);
1284 
1285  ale->update |= ANIM_UPDATE_DEPS;
1286  }
1287 
1288  ANIM_animdata_update(ac, &anim_data);
1289  ANIM_animdata_freelist(&anim_data);
1290 }
1291 
1292 /* ------------------- */
1293 
1295 {
1296  bAnimContext ac;
1297 
1298  /* Get editor data. */
1299  if (ANIM_animdata_get_context(C, &ac) == 0) {
1300  return OPERATOR_CANCELLED;
1301  }
1302 
1303  /* Sample keyframes. */
1304  sample_graph_keys(&ac);
1305 
1306  /* Set notifier that keyframes have changed. */
1308 
1309  return OPERATOR_FINISHED;
1310 }
1311 
1313 {
1314  /* Identifiers */
1315  ot->name = "Sample Keyframes";
1316  ot->idname = "GRAPH_OT_sample";
1317  ot->description = "Add keyframes on every frame between the selected keyframes";
1318 
1319  /* API callbacks */
1322 
1323  /* Flags */
1325 }
1326 
1329 /* ************************************************************************** */
1330 /* EXTRAPOLATION MODE AND KEYFRAME HANDLE SETTINGS */
1331 
1332 /* -------------------------------------------------------------------- */
1336 /* Defines for make/clear cyclic extrapolation tools. */
1337 #define MAKE_CYCLIC_EXPO -1
1338 #define CLEAR_CYCLIC_EXPO -2
1339 
1340 /* Defines for set extrapolation-type for selected keyframes tool. */
1343  "CONSTANT",
1344  0,
1345  "Constant Extrapolation",
1346  "Values on endpoint keyframes are held"},
1348  "LINEAR",
1349  0,
1350  "Linear Extrapolation",
1351  "Straight-line slope of end segments are extended past the endpoint keyframes"},
1352 
1354  "MAKE_CYCLIC",
1355  0,
1356  "Make Cyclic (F-Modifier)",
1357  "Add Cycles F-Modifier if one doesn't exist already"},
1359  "CLEAR_CYCLIC",
1360  0,
1361  "Clear Cyclic (F-Modifier)",
1362  "Remove Cycles F-Modifier if not needed anymore"},
1363  {0, NULL, 0, NULL, NULL},
1364 };
1365 
1366 /* This function is responsible for setting extrapolation mode for keyframes. */
1367 static void setexpo_graph_keys(bAnimContext *ac, short mode)
1368 {
1369  ListBase anim_data = {NULL, NULL};
1370  bAnimListElem *ale;
1371  int filter;
1372 
1373  /* Filter data. */
1376  ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1377 
1378  /* Loop through setting mode per F-Curve. */
1379  for (ale = anim_data.first; ale; ale = ale->next) {
1380  FCurve *fcu = (FCurve *)ale->data;
1381 
1382  if (mode >= 0) {
1383  /* Just set mode setting. */
1384  fcu->extend = mode;
1385 
1386  ale->update |= ANIM_UPDATE_HANDLES;
1387  }
1388  else {
1389  /* Shortcuts for managing Cycles F-Modifiers to make it easier to toggle cyclic animation
1390  * without having to go through FModifier UI in Graph Editor to do so.
1391  */
1392  if (mode == MAKE_CYCLIC_EXPO) {
1393  /* Only add if one doesn't exist. */
1395  /* TODO: add some more preset versions which set different extrapolation options?
1396  * (Joshua Leung 2011) */
1398  }
1399  }
1400  else if (mode == CLEAR_CYCLIC_EXPO) {
1401  /* Remove all the modifiers fitting this description. */
1402  FModifier *fcm, *fcn = NULL;
1403 
1404  for (fcm = fcu->modifiers.first; fcm; fcm = fcn) {
1405  fcn = fcm->next;
1406 
1407  if (fcm->type == FMODIFIER_TYPE_CYCLES) {
1408  remove_fmodifier(&fcu->modifiers, fcm);
1409  }
1410  }
1411  }
1412  }
1413 
1414  ale->update |= ANIM_UPDATE_DEPS;
1415  }
1416 
1417  ANIM_animdata_update(ac, &anim_data);
1418  ANIM_animdata_freelist(&anim_data);
1419 }
1420 
1421 /* ------------------- */
1422 
1424 {
1425  bAnimContext ac;
1426  short mode;
1427 
1428  /* Get editor data. */
1429  if (ANIM_animdata_get_context(C, &ac) == 0) {
1430  return OPERATOR_CANCELLED;
1431  }
1432 
1433  /* Get handle setting mode. */
1434  mode = RNA_enum_get(op->ptr, "type");
1435 
1436  /* Set handle type. */
1437  setexpo_graph_keys(&ac, mode);
1438 
1439  /* Set notifier that keyframe properties have changed. */
1441 
1442  return OPERATOR_FINISHED;
1443 }
1444 
1446 {
1447  /* Identifiers */
1448  ot->name = "Set Keyframe Extrapolation";
1449  ot->idname = "GRAPH_OT_extrapolation_type";
1450  ot->description = "Set extrapolation mode for selected F-Curves";
1451 
1452  /* API callbacks */
1456 
1457  /* Flags */
1459 
1460  /* Id-props */
1461  ot->prop = RNA_def_enum(ot->srna, "type", prop_graphkeys_expo_types, 0, "Type", "");
1462 }
1463 
1466 /* -------------------------------------------------------------------- */
1470 /* This function is responsible for setting interpolation mode for keyframes. */
1471 static void setipo_graph_keys(bAnimContext *ac, short mode)
1472 {
1473  ListBase anim_data = {NULL, NULL};
1474  bAnimListElem *ale;
1475  int filter;
1477 
1478  /* Filter data. */
1481  ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1482 
1483  /* Loop through setting BezTriple interpolation
1484  * Note: we do not supply KeyframeEditData to the looper yet.
1485  * Currently that's not necessary here.
1486  */
1487  for (ale = anim_data.first; ale; ale = ale->next) {
1489 
1491  }
1492 
1493  ANIM_animdata_update(ac, &anim_data);
1494  ANIM_animdata_freelist(&anim_data);
1495 }
1496 
1497 /* ------------------- */
1498 
1500 {
1501  bAnimContext ac;
1502  short mode;
1503 
1504  /* Get editor data. */
1505  if (ANIM_animdata_get_context(C, &ac) == 0) {
1506  return OPERATOR_CANCELLED;
1507  }
1508 
1509  /* Get handle setting mode. */
1510  mode = RNA_enum_get(op->ptr, "type");
1511 
1512  /* Set handle type. */
1513  setipo_graph_keys(&ac, mode);
1514 
1515  /* Set notifier that keyframe properties have changed. */
1517 
1518  return OPERATOR_FINISHED;
1519 }
1520 
1522 {
1523  /* Identifiers */
1524  ot->name = "Set Keyframe Interpolation";
1525  ot->idname = "GRAPH_OT_interpolation_type";
1526  ot->description =
1527  "Set interpolation mode for the F-Curve segments starting from the selected keyframes";
1528 
1529  /* API callbacks */
1533 
1534  /* Flags */
1536 
1537  /* Id-props */
1538  ot->prop = RNA_def_enum(
1539  ot->srna, "type", rna_enum_beztriple_interpolation_mode_items, 0, "Type", "");
1540 }
1541 
1544 /* -------------------------------------------------------------------- */
1548 static void seteasing_graph_keys(bAnimContext *ac, short mode)
1549 {
1550  ListBase anim_data = {NULL, NULL};
1551  bAnimListElem *ale;
1552  int filter;
1554 
1555  /* Filter data. */
1558  ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1559 
1560  /* Loop through setting BezTriple easing.
1561  * Note: we do not supply KeyframeEditData to the looper yet.
1562  * Currently that's not necessary here.
1563  */
1564  for (ale = anim_data.first; ale; ale = ale->next) {
1566 
1568  }
1569 
1570  ANIM_animdata_update(ac, &anim_data);
1571  ANIM_animdata_freelist(&anim_data);
1572 }
1573 
1575 {
1576  bAnimContext ac;
1577  short mode;
1578 
1579  /* Get editor data. */
1580  if (ANIM_animdata_get_context(C, &ac) == 0) {
1581  return OPERATOR_CANCELLED;
1582  }
1583 
1584  /* Get handle setting mode. */
1585  mode = RNA_enum_get(op->ptr, "type");
1586 
1587  /* Set handle type. */
1588  seteasing_graph_keys(&ac, mode);
1589 
1590  /* Set notifier that keyframe properties have changed. */
1592 
1593  return OPERATOR_FINISHED;
1594 }
1595 
1597 {
1598  /* Identifiers */
1599  ot->name = "Set Keyframe Easing Type";
1600  ot->idname = "GRAPH_OT_easing_type";
1601  ot->description =
1602  "Set easing type for the F-Curve segments starting from the selected keyframes";
1603 
1604  /* API callbacks */
1608 
1609  /* Flags */
1611 
1612  /* Id-props */
1613  ot->prop = RNA_def_enum(
1614  ot->srna, "type", rna_enum_beztriple_interpolation_easing_items, 0, "Type", "");
1615 }
1616 
1619 /* -------------------------------------------------------------------- */
1623 /* This function is responsible for setting handle-type of selected keyframes. */
1624 static void sethandles_graph_keys(bAnimContext *ac, short mode)
1625 {
1626  ListBase anim_data = {NULL, NULL};
1627  bAnimListElem *ale;
1628  int filter;
1629 
1632 
1633  /* Filter data. */
1636  ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1637 
1638  /* Loop through setting flags for handles.
1639  * Note: we do not supply KeyframeEditData to the looper yet.
1640  * Currently that's not necessary here.
1641  */
1642  for (ale = anim_data.first; ale; ale = ale->next) {
1643  FCurve *fcu = (FCurve *)ale->key_data;
1644 
1645  /* Any selected keyframes for editing? */
1646  if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, sel_cb, NULL)) {
1647  /* Change type of selected handles. */
1649 
1650  ale->update |= ANIM_UPDATE_DEFAULT;
1651  }
1652  }
1653 
1654  ANIM_animdata_update(ac, &anim_data);
1655  ANIM_animdata_freelist(&anim_data);
1656 }
1657 /* ------------------- */
1658 
1660 {
1661  bAnimContext ac;
1662  short mode;
1663 
1664  /* Get editor data. */
1665  if (ANIM_animdata_get_context(C, &ac) == 0) {
1666  return OPERATOR_CANCELLED;
1667  }
1668 
1669  /* Get handle setting mode. */
1670  mode = RNA_enum_get(op->ptr, "type");
1671 
1672  /* Set handle type. */
1673  sethandles_graph_keys(&ac, mode);
1674 
1675  /* Set notifier that keyframe properties have changed. */
1677 
1678  return OPERATOR_FINISHED;
1679 }
1680 
1682 {
1683  /* Identifiers */
1684  ot->name = "Set Keyframe Handle Type";
1685  ot->idname = "GRAPH_OT_handle_type";
1686  ot->description = "Set type of handle for selected keyframes";
1687 
1688  /* API callbacks */
1692 
1693  /* Flags */
1695 
1696  /* Id-props */
1697  ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_keyframe_handle_type_items, 0, "Type", "");
1698 }
1699 
1702 /* ************************************************************************** */
1703 /* EULER FILTER */
1704 
1705 /* -------------------------------------------------------------------- */
1714 /* Set of three euler-rotation F-Curves. */
1715 typedef struct tEulerFilter {
1717 
1719  ID *id;
1723  const char *rna_path;
1725 
1726 static bool keyframe_time_differs(BezTriple *keyframes[3])
1727 {
1728  const float precision = 1e-5;
1729  return fabs(keyframes[0]->vec[1][0] - keyframes[1]->vec[1][0]) > precision ||
1730  fabs(keyframes[1]->vec[1][0] - keyframes[2]->vec[1][0]) > precision ||
1731  fabs(keyframes[0]->vec[1][0] - keyframes[2]->vec[1][0]) > precision;
1732 }
1733 
1734 /* Find groups of `rotation_euler` channels. */
1735 static ListBase /*tEulerFilter*/ euler_filter_group_channels(
1736  const ListBase /*bAnimListElem*/ *anim_data, ReportList *reports, int *r_num_groups)
1737 {
1738  ListBase euler_groups = {NULL, NULL};
1739  tEulerFilter *euf = NULL;
1740  *r_num_groups = 0;
1741 
1742  LISTBASE_FOREACH (bAnimListElem *, ale, anim_data) {
1743  FCurve *const fcu = (FCurve *)ale->data;
1744 
1745  /* Check if this is an appropriate F-Curve:
1746  * - Only rotation curves.
1747  * - For pchan curves, make sure we're only using the euler curves.
1748  */
1749  if (strstr(fcu->rna_path, "rotation_euler") == NULL) {
1750  continue;
1751  }
1752  if (ELEM(fcu->array_index, 0, 1, 2) == 0) {
1753  BKE_reportf(reports,
1754  RPT_WARNING,
1755  "Euler Rotation F-Curve has invalid index (ID='%s', Path='%s', Index=%d)",
1756  (ale->id) ? ale->id->name : TIP_("<No ID>"),
1757  fcu->rna_path,
1758  fcu->array_index);
1759  continue;
1760  }
1761 
1762  /* Assume that this animation channel will be touched by the Euler filter. Doing this here
1763  * saves another loop over the animation data. */
1764  ale->update |= ANIM_UPDATE_DEFAULT;
1765 
1766  /* Optimization: assume that xyz curves will always be stored consecutively,
1767  * so if the paths or the ID's don't match up, then a curve needs to be added
1768  * to a new group.
1769  */
1770  if ((euf) && (euf->id == ale->id) && (STREQ(euf->rna_path, fcu->rna_path))) {
1771  /* This should be fine to add to the existing group then. */
1772  euf->fcurves[fcu->array_index] = fcu;
1773  continue;
1774  }
1775 
1776  /* Just add to a new block. */
1777  euf = MEM_callocN(sizeof(tEulerFilter), "tEulerFilter");
1778  BLI_addtail(&euler_groups, euf);
1779  ++*r_num_groups;
1780 
1781  euf->id = ale->id;
1782  /* This should be safe, since we're only using it for a short time. */
1783  euf->rna_path = fcu->rna_path;
1784  euf->fcurves[fcu->array_index] = fcu;
1785  }
1786 
1787  return euler_groups;
1788 }
1789 
1790 /* Perform discontinuity filter based on conversion to matrix and back.
1791  * Return true if the curves were filtered (which may have been a no-op), false otherwise. */
1793 {
1794  /* Sanity check: ensure that there are enough F-Curves to work on in this group. */
1795  if (ELEM(NULL, euf->fcurves[0], euf->fcurves[1], euf->fcurves[2])) {
1796  /* Report which components are missing. */
1797  BKE_reportf(reports,
1798  RPT_INFO,
1799  "Missing %s%s%s component(s) of euler rotation for ID='%s' and RNA-Path='%s'",
1800  (euf->fcurves[0] == NULL) ? "X" : "",
1801  (euf->fcurves[1] == NULL) ? "Y" : "",
1802  (euf->fcurves[2] == NULL) ? "Z" : "",
1803  euf->id->name,
1804  euf->rna_path);
1805  return false;
1806  }
1807 
1808  FCurve *fcu_rot_x = euf->fcurves[0];
1809  FCurve *fcu_rot_y = euf->fcurves[1];
1810  FCurve *fcu_rot_z = euf->fcurves[2];
1811  if (fcu_rot_x->totvert != fcu_rot_y->totvert || fcu_rot_y->totvert != fcu_rot_z->totvert) {
1812  BKE_reportf(reports,
1813  RPT_INFO,
1814  "XYZ rotations not equally keyed for ID='%s' and RNA-Path='%s'",
1815  euf->id->name,
1816  euf->rna_path);
1817  return false;
1818  }
1819 
1820  if (fcu_rot_x->totvert < 2) {
1821  /* Empty curves and single keyframes are trivially "filtered". */
1822  return false;
1823  }
1824 
1825  float filtered_euler[3] = {
1826  fcu_rot_x->bezt[0].vec[1][1],
1827  fcu_rot_y->bezt[0].vec[1][1],
1828  fcu_rot_z->bezt[0].vec[1][1],
1829  };
1830 
1831  for (int keyframe_index = 1; keyframe_index < fcu_rot_x->totvert; ++keyframe_index) {
1832  BezTriple *keyframes[3] = {
1833  &fcu_rot_x->bezt[keyframe_index],
1834  &fcu_rot_y->bezt[keyframe_index],
1835  &fcu_rot_z->bezt[keyframe_index],
1836  };
1837 
1838  if (keyframe_time_differs(keyframes)) {
1839  /* The X-coordinates of the keyframes are different, so we cannot correct this key. */
1840  continue;
1841  }
1842 
1843  const float unfiltered_euler[3] = {
1844  keyframes[0]->vec[1][1],
1845  keyframes[1]->vec[1][1],
1846  keyframes[2]->vec[1][1],
1847  };
1848 
1849  /* The conversion back from matrix to Euler angles actually performs the filtering. */
1850  float matrix[3][3];
1851  eul_to_mat3(matrix, unfiltered_euler);
1852  mat3_normalized_to_compatible_eul(filtered_euler, filtered_euler, matrix);
1853 
1854  /* TODO(Sybren): it might be a nice touch to compare `filtered_euler` with `unfiltered_euler`,
1855  * to see if there was actually a change. This could improve reporting for the artist. */
1856 
1857  BKE_fcurve_keyframe_move_value_with_handles(keyframes[0], filtered_euler[0]);
1858  BKE_fcurve_keyframe_move_value_with_handles(keyframes[1], filtered_euler[1]);
1859  BKE_fcurve_keyframe_move_value_with_handles(keyframes[2], filtered_euler[2]);
1860  }
1861 
1862  return true;
1863 }
1864 
1865 /* Remove 360-degree flips from a single FCurve.
1866  * Return true if the curve was modified, false otherwise. */
1868 {
1869  /* Simple method: just treat any difference between keys of greater than 180 degrees as being a
1870  * flip. */
1871  BezTriple *bezt, *prev;
1872  uint i;
1873 
1874  /* Skip if not enough verts to do a decent analysis. */
1875  if (fcu->totvert <= 2) {
1876  return false;
1877  }
1878 
1879  /* Prev follows bezt, bezt = "current" point to be fixed. */
1880  /* Our method depends on determining a "difference" from the previous vert. */
1881  bool is_modified = false;
1882  for (i = 1, prev = fcu->bezt, bezt = fcu->bezt + 1; i < fcu->totvert; i++, prev = bezt++) {
1883  const float sign = (prev->vec[1][1] > bezt->vec[1][1]) ? 1.0f : -1.0f;
1884 
1885  /* >= 180 degree flip? */
1886  if ((sign * (prev->vec[1][1] - bezt->vec[1][1])) < (float)M_PI) {
1887  continue;
1888  }
1889 
1890  /* 360 degrees to add/subtract frame value until difference
1891  * is acceptably small that there's no more flip. */
1892  const float fac = sign * 2.0f * (float)M_PI;
1893 
1894  while ((sign * (prev->vec[1][1] - bezt->vec[1][1])) >= (float)M_PI) {
1895  bezt->vec[0][1] += fac;
1896  bezt->vec[1][1] += fac;
1897  bezt->vec[2][1] += fac;
1898  }
1899 
1900  is_modified = true;
1901  }
1902 
1903  return is_modified;
1904 }
1905 
1906 static void euler_filter_perform_filter(ListBase /*tEulerFilter*/ *eulers,
1907  ReportList *reports,
1908  int *r_curves_filtered,
1909  int *r_curves_seen)
1910 {
1911  *r_curves_filtered = 0;
1912  *r_curves_seen = 0;
1913 
1914  LISTBASE_FOREACH (tEulerFilter *, euf, eulers) {
1915  int curves_filtered_this_group = 0;
1916 
1917  if (euler_filter_multi_channel(euf, reports)) {
1918  curves_filtered_this_group = 3;
1919  }
1920 
1921  for (int channel_index = 0; channel_index < 3; channel_index++) {
1922  FCurve *fcu = euf->fcurves[channel_index];
1923  if (fcu == NULL) {
1924  continue;
1925  }
1926  ++*r_curves_seen;
1927 
1928  if (euler_filter_single_channel(fcu)) {
1929  ++curves_filtered_this_group;
1930  }
1931  }
1932 
1933  *r_curves_filtered += min_ii(3, curves_filtered_this_group);
1934  }
1935 }
1936 
1938 {
1939  /* Get editor data. */
1940  bAnimContext ac;
1941  if (ANIM_animdata_get_context(C, &ac) == 0) {
1942  return OPERATOR_CANCELLED;
1943  }
1944 
1945  /* The process is done in two passes:
1946  * 1) Sets of three related rotation curves are identified from the selected channels,
1947  * and are stored as a single 'operation unit' for the next step.
1948  * 2) Each set of three F-Curves is processed for each keyframe, with the values being
1949  * processed as necessary.
1950  */
1951 
1952  /* Step 1: extract only the rotation f-curves. */
1955  ListBase anim_data = {NULL, NULL};
1956  ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1957 
1958  int groups = 0;
1959  ListBase eulers = euler_filter_group_channels(&anim_data, op->reports, &groups);
1960  BLI_assert(BLI_listbase_count(&eulers) == groups);
1961 
1962  if (groups == 0) {
1963  ANIM_animdata_freelist(&anim_data);
1964  BKE_report(op->reports, RPT_WARNING, "No Euler Rotation F-Curves to fix up");
1965  return OPERATOR_CANCELLED;
1966  }
1967 
1968  /* Step 2: go through each set of curves, processing the values at each keyframe.
1969  * - It is assumed that there must be a full set of keyframes at each keyframe position.
1970  */
1971  int curves_filtered;
1972  int curves_seen;
1973  euler_filter_perform_filter(&eulers, op->reports, &curves_filtered, &curves_seen);
1974 
1975  BLI_freelistN(&eulers);
1976  ANIM_animdata_update(&ac, &anim_data);
1977  ANIM_animdata_freelist(&anim_data);
1978 
1979  if (curves_filtered == 0) {
1980  if (curves_seen < 3) {
1981  /* Showing the entire error message makes no sense when the artist is only trying to filter
1982  * one or two curves. */
1983  BKE_report(op->reports, RPT_WARNING, "No Euler Rotations could be corrected");
1984  }
1985  else {
1986  BKE_report(op->reports,
1987  RPT_ERROR,
1988  "No Euler Rotations could be corrected, ensure each rotation has keys for all "
1989  "components, "
1990  "and that F-Curves for these are in consecutive XYZ order and selected");
1991  }
1992  return OPERATOR_CANCELLED;
1993  }
1994 
1995  if (curves_filtered != curves_seen) {
1996  BLI_assert(curves_filtered < curves_seen);
1997  BKE_reportf(op->reports,
1998  RPT_INFO,
1999  "%d of %d rotation channels were filtered (see the Info window for details)",
2000  curves_filtered,
2001  curves_seen);
2002  }
2003  else if (curves_seen == 1) {
2004  BKE_report(op->reports, RPT_INFO, "The rotation channel was filtered");
2005  }
2006  else {
2007  BKE_reportf(op->reports, RPT_INFO, "All %d rotation channels were filtered", curves_seen);
2008  }
2009 
2010  /* Set notifier that keyframes have changed. */
2012 
2013  /* Done at last. */
2014  return OPERATOR_FINISHED;
2015 }
2016 
2018 {
2019  /* Identifiers */
2020  ot->name = "Euler Discontinuity Filter";
2021  ot->idname = "GRAPH_OT_euler_filter";
2022  ot->description =
2023  "Fix large jumps and flips in the selected "
2024  "Euler Rotation F-Curves arising from rotation "
2025  "values being clipped when baking physics";
2026 
2027  /* API callbacks */
2030 
2031  /* Flags */
2033 }
2034 
2037 /* ************************************************************************** */
2038 /* SNAPPING */
2039 
2040 /* -------------------------------------------------------------------- */
2045 {
2046  /* Prevent changes during render. */
2047  if (G.is_rendering) {
2048  return false;
2049  }
2050 
2052 }
2053 
2055 {
2056  ListBase anim_data = {NULL, NULL};
2057  bAnimListElem *ale;
2058  int filter;
2059  KeyframeEditData ked;
2060 
2061  /* Init edit data. */
2062  memset(&ked, 0, sizeof(KeyframeEditData));
2063 
2064  /* Loop over action data, averaging values. */
2066  ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
2067 
2068  for (ale = anim_data.first; ale; ale = ale->next) {
2069  AnimData *adt = ANIM_nla_mapping_get(ac, ale);
2070  short mapping_flag = ANIM_get_normalization_flags(ac);
2071  KeyframeEditData current_ked;
2072  float offset;
2073  float unit_scale = ANIM_unit_mapping_get_factor(
2074  ac->scene, ale->id, ale->key_data, mapping_flag | ANIM_UNITCONV_ONLYKEYS, &offset);
2075 
2076  memset(&current_ked, 0, sizeof(current_ked));
2077 
2078  if (adt) {
2079  ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
2081  ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
2082  }
2083  else {
2085  }
2086 
2087  ked.f1 += current_ked.f1;
2088  ked.i1 += current_ked.i1;
2089  ked.f2 += (current_ked.f2 + offset) * unit_scale;
2090  ked.i2 += current_ked.i2;
2091  }
2092 
2093  ANIM_animdata_freelist(&anim_data);
2094 
2095  return ked;
2096 }
2097 
2098 /* Snap current-frame indicator to 'average time' of selected keyframe. */
2100 {
2101  bAnimContext ac;
2102 
2103  /* Get editor data. */
2104  if (ANIM_animdata_get_context(C, &ac) == 0) {
2105  return OPERATOR_CANCELLED;
2106  }
2107 
2108  const KeyframeEditData keyframe_sum = sum_selected_keyframes(&ac);
2109  const float sum_time = keyframe_sum.f1;
2110  const float sum_value = keyframe_sum.f2;
2111  const int num_keyframes = keyframe_sum.i1;
2112 
2113  if (num_keyframes == 0) {
2114  return OPERATOR_FINISHED;
2115  }
2116 
2117  /* Set the new current frame and cursor values, based on the average time and value. */
2118  SpaceGraph *sipo = (SpaceGraph *)ac.sl;
2119  Scene *scene = ac.scene;
2120 
2121  /* Take the average values, rounding to the nearest int as necessary for int results. */
2122  if (sipo->mode == SIPO_MODE_DRIVERS) {
2123  /* Drivers Mode - Affects cursor (float) */
2124  sipo->cursorTime = sum_time / (float)num_keyframes;
2125  }
2126  else {
2127  /* Animation Mode - Affects current frame (int) */
2128  CFRA = round_fl_to_int(sum_time / num_keyframes);
2129  SUBFRA = 0.0f;
2130  }
2131  sipo->cursorVal = sum_value / (float)num_keyframes;
2132 
2133  /* Set notifier that things have changed. */
2135 
2136  return OPERATOR_FINISHED;
2137 }
2138 
2140 {
2141  /* Identifiers */
2142  ot->name = "Jump to Keyframes";
2143  ot->idname = "GRAPH_OT_frame_jump";
2144  ot->description = "Place the cursor on the midpoint of selected keyframes";
2145 
2146  /* API callbacks */
2149 
2150  /* Flags */
2152 }
2153 
2154 /* snap 2D cursor value to the average value of selected keyframe */
2156 {
2157  bAnimContext ac;
2158 
2159  if (ANIM_animdata_get_context(C, &ac) == 0) {
2160  return OPERATOR_CANCELLED;
2161  }
2162 
2163  const KeyframeEditData keyframe_sum = sum_selected_keyframes(&ac);
2164  const float sum_value = keyframe_sum.f2;
2165  const int num_keyframes = keyframe_sum.i1;
2166 
2167  if (num_keyframes == 0) {
2168  return OPERATOR_FINISHED;
2169  }
2170 
2171  SpaceGraph *sipo = (SpaceGraph *)ac.sl;
2172  sipo->cursorVal = sum_value / (float)num_keyframes;
2173  // WM_event_add_notifier(C, NC_SCENE | ND_FRAME, ac.scene);
2175 
2176  return OPERATOR_FINISHED;
2177 }
2178 
2180 {
2181  /* Identifiers. */
2182  ot->name = "Snap Cursor Value to Selected";
2183  ot->idname = "GRAPH_OT_snap_cursor_value";
2184  ot->description = "Place the cursor value on the average value of selected keyframes";
2185 
2186  /* API callbacks. */
2189 
2190  /* Flags */
2192 }
2193 
2196 /* -------------------------------------------------------------------- */
2200 /* Defines for snap keyframes tool. */
2203  "CFRA",
2204  0,
2205  "Selection to Current Frame",
2206  "Snap selected keyframes to the current frame"},
2208  "VALUE",
2209  0,
2210  "Selection to Cursor Value",
2211  "Set values of selected keyframes to the cursor value (Y/Horizontal component)"},
2213  "NEAREST_FRAME",
2214  0,
2215  "Selection to Nearest Frame",
2216  "Snap selected keyframes to the nearest (whole) frame (use to fix accidental subframe "
2217  "offsets)"},
2219  "NEAREST_SECOND",
2220  0,
2221  "Selection to Nearest Second",
2222  "Snap selected keyframes to the nearest second"},
2224  "NEAREST_MARKER",
2225  0,
2226  "Selection to Nearest Marker",
2227  "Snap selected keyframes to the nearest marker"},
2229  "HORIZONTAL",
2230  0,
2231  "Flatten Handles",
2232  "Flatten handles for a smoother transition"},
2233  {0, NULL, 0, NULL, NULL},
2234 };
2235 
2236 /* This function is responsible for snapping keyframes to frame-times. */
2237 static void snap_graph_keys(bAnimContext *ac, short mode)
2238 {
2239  ListBase anim_data = {NULL, NULL};
2240  bAnimListElem *ale;
2241  int filter;
2242 
2243  SpaceGraph *sipo = (SpaceGraph *)ac->sl;
2244  KeyframeEditData ked;
2245  KeyframeEditFunc edit_cb;
2246  float cursor_value = 0.0f;
2247 
2248  /* Filter data. */
2251  ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
2252 
2253  /* Init custom data for iterating over keyframes. */
2254  memset(&ked, 0, sizeof(KeyframeEditData));
2255  ked.scene = ac->scene;
2256  if (mode == GRAPHKEYS_SNAP_NEAREST_MARKER) {
2257  ked.list.first = (ac->markers) ? ac->markers->first : NULL;
2258  ked.list.last = (ac->markers) ? ac->markers->last : NULL;
2259  }
2260  else if (mode == GRAPHKEYS_SNAP_VALUE) {
2261  cursor_value = (sipo) ? sipo->cursorVal : 0.0f;
2262  }
2263  else if (mode == GRAPHKEYS_SNAP_CFRA) {
2264  /* In drivers mode, use the cursor value instead
2265  * (We need to use a different callback for that though)
2266  */
2267  if (sipo->mode == SIPO_MODE_DRIVERS) {
2268  ked.f1 = sipo->cursorTime;
2269  mode = SNAP_KEYS_TIME;
2270  }
2271  }
2272 
2273  /* Get beztriple editing callbacks. */
2274  edit_cb = ANIM_editkeyframes_snap(mode);
2275 
2276  /* Snap keyframes. */
2277  for (ale = anim_data.first; ale; ale = ale->next) {
2278  AnimData *adt = ANIM_nla_mapping_get(ac, ale);
2279 
2280  /* Normalize cursor value (for normalized F-Curves display). */
2281  if (mode == GRAPHKEYS_SNAP_VALUE) {
2282  short mapping_flag = ANIM_get_normalization_flags(ac);
2283  float offset;
2284  float unit_scale = ANIM_unit_mapping_get_factor(
2285  ac->scene, ale->id, ale->key_data, mapping_flag, &offset);
2286 
2287  ked.f1 = (cursor_value / unit_scale) - offset;
2288  }
2289 
2290  /* Perform snapping. */
2291  if (adt) {
2292  ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
2294  ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
2295  }
2296  else {
2298  }
2299 
2300  ale->update |= ANIM_UPDATE_DEFAULT;
2301  }
2302 
2303  ANIM_animdata_update(ac, &anim_data);
2304  ANIM_animdata_freelist(&anim_data);
2305 }
2306 
2307 /* ------------------- */
2308 
2310 {
2311  bAnimContext ac;
2312  short mode;
2313 
2314  /* Get editor data. */
2315  if (ANIM_animdata_get_context(C, &ac) == 0) {
2316  return OPERATOR_CANCELLED;
2317  }
2318 
2319  /* Get snapping mode. */
2320  mode = RNA_enum_get(op->ptr, "type");
2321 
2322  /* Snap keyframes. */
2323  snap_graph_keys(&ac, mode);
2324 
2325  /* Set notifier that keyframes have changed. */
2327 
2328  return OPERATOR_FINISHED;
2329 }
2330 
2332 {
2333  /* Identifiers */
2334  ot->name = "Snap Keys";
2335  ot->idname = "GRAPH_OT_snap";
2336  ot->description = "Snap selected keyframes to the chosen times/values";
2337 
2338  /* API callbacks */
2342 
2343  /* Flags */
2345 
2346  /* Id-props */
2347  ot->prop = RNA_def_enum(ot->srna, "type", prop_graphkeys_snap_types, 0, "Type", "");
2348 }
2349 
2352 /* -------------------------------------------------------------------- */
2356 /* Defines for mirror keyframes tool. */
2359  "CFRA",
2360  0,
2361  "By Times Over Current Frame",
2362  "Flip times of selected keyframes using the current frame as the mirror line"},
2364  "VALUE",
2365  0,
2366  "By Values Over Cursor Value",
2367  "Flip values of selected keyframes using the cursor value (Y/Horizontal component) as the "
2368  "mirror line"},
2370  "YAXIS",
2371  0,
2372  "By Times Over Zero Time",
2373  "Flip times of selected keyframes, effectively reversing the order they appear in"},
2375  "XAXIS",
2376  0,
2377  "By Values Over Zero Value",
2378  "Flip values of selected keyframes (i.e. negative values become positive, and vice versa)"},
2380  "MARKER",
2381  0,
2382  "By Times Over First Selected Marker",
2383  "Flip times of selected keyframes using the first selected marker as the reference point"},
2384  {0, NULL, 0, NULL, NULL},
2385 };
2386 
2387 /* This function is responsible for mirroring keyframes. */
2388 static void mirror_graph_keys(bAnimContext *ac, short mode)
2389 {
2390  ListBase anim_data = {NULL, NULL};
2391  bAnimListElem *ale;
2392  int filter;
2393 
2394  SpaceGraph *sipo = (SpaceGraph *)ac->sl;
2395  KeyframeEditData ked;
2396  KeyframeEditFunc edit_cb;
2397  float cursor_value = 0.0f;
2398 
2399  /* Init custom data for looping over keyframes. */
2400  memset(&ked, 0, sizeof(KeyframeEditData));
2401  ked.scene = ac->scene;
2402 
2403  /* Store mode-specific custom data... */
2404  if (mode == GRAPHKEYS_MIRROR_MARKER) {
2405  TimeMarker *marker = NULL;
2406 
2407  /* Find first selected marker. */
2408  marker = ED_markers_get_first_selected(ac->markers);
2409 
2410  /* Store marker's time (if available). */
2411  if (marker) {
2412  ked.f1 = (float)marker->frame;
2413  }
2414  else {
2415  return;
2416  }
2417  }
2418  else if (mode == GRAPHKEYS_MIRROR_VALUE) {
2419  cursor_value = (sipo) ? sipo->cursorVal : 0.0f;
2420  }
2421  else if (mode == GRAPHKEYS_MIRROR_CFRA) {
2422  /* In drivers mode, use the cursor value instead
2423  * (We need to use a different callback for that though)
2424  */
2425  if (sipo->mode == SIPO_MODE_DRIVERS) {
2426  ked.f1 = sipo->cursorTime;
2427  mode = MIRROR_KEYS_TIME;
2428  }
2429  }
2430 
2431  /* Get beztriple editing callbacks. */
2432  edit_cb = ANIM_editkeyframes_mirror(mode);
2433 
2434  /* Filter data. */
2437  ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
2438 
2439  /* Mirror keyframes. */
2440  for (ale = anim_data.first; ale; ale = ale->next) {
2441  AnimData *adt = ANIM_nla_mapping_get(ac, ale);
2442 
2443  /* Apply unit corrections. */
2444  if (mode == GRAPHKEYS_MIRROR_VALUE) {
2445  short mapping_flag = ANIM_get_normalization_flags(ac);
2446  float offset;
2447  float unit_scale = ANIM_unit_mapping_get_factor(
2448  ac->scene, ale->id, ale->key_data, mapping_flag | ANIM_UNITCONV_ONLYKEYS, &offset);
2449 
2450  ked.f1 = (cursor_value + offset) * unit_scale;
2451  }
2452 
2453  /* Perform actual mirroring. */
2454  if (adt) {
2455  ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
2457  ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
2458  }
2459  else {
2461  }
2462 
2463  ale->update |= ANIM_UPDATE_DEFAULT;
2464  }
2465 
2466  ANIM_animdata_update(ac, &anim_data);
2467  ANIM_animdata_freelist(&anim_data);
2468 }
2469 
2470 /* ------------------- */
2471 
2473 {
2474  bAnimContext ac;
2475  short mode;
2476 
2477  /* Get editor data. */
2478  if (ANIM_animdata_get_context(C, &ac) == 0) {
2479  return OPERATOR_CANCELLED;
2480  }
2481 
2482  /* Get mirroring mode. */
2483  mode = RNA_enum_get(op->ptr, "type");
2484 
2485  /* Mirror keyframes. */
2486  mirror_graph_keys(&ac, mode);
2487 
2488  /* Set notifier that keyframes have changed. */
2490 
2491  return OPERATOR_FINISHED;
2492 }
2493 
2495 {
2496  /* Identifiers */
2497  ot->name = "Mirror Keys";
2498  ot->idname = "GRAPH_OT_mirror";
2499  ot->description = "Flip selected keyframes over the selected mirror line";
2500 
2501  /* API callbacks */
2505 
2506  /* Flags */
2508 
2509  /* Id-props */
2510  ot->prop = RNA_def_enum(ot->srna, "type", prop_graphkeys_mirror_types, 0, "Type", "");
2511 }
2512 
2515 /* -------------------------------------------------------------------- */
2520 {
2521  bAnimContext ac;
2522  ListBase anim_data = {NULL, NULL};
2523  bAnimListElem *ale;
2524  int filter;
2525 
2526  /* Get editor data. */
2527  if (ANIM_animdata_get_context(C, &ac) == 0) {
2528  return OPERATOR_CANCELLED;
2529  }
2530 
2531  /* Filter data. */
2534  ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
2535 
2536  /* Smooth keyframes. */
2537  for (ale = anim_data.first; ale; ale = ale->next) {
2538  /* For now, we can only smooth by flattening handles AND smoothing curve values.
2539  * Perhaps the mode argument could be removed, as that functionality is offered through
2540  * Snap->Flatten Handles anyway.
2541  */
2542  smooth_fcurve(ale->key_data);
2543 
2544  ale->update |= ANIM_UPDATE_DEFAULT;
2545  }
2546 
2547  ANIM_animdata_update(&ac, &anim_data);
2548  ANIM_animdata_freelist(&anim_data);
2549 
2550  /* Set notifier that keyframes have changed. */
2552 
2553  return OPERATOR_FINISHED;
2554 }
2555 
2557 {
2558  /* Identifiers */
2559  ot->name = "Smooth Keys";
2560  ot->idname = "GRAPH_OT_smooth";
2561  ot->description = "Apply weighted moving means to make selected F-Curves less bumpy";
2562 
2563  /* API callbacks */
2566 
2567  /* Flags */
2569 }
2570 
2573 /* ************************************************************************** */
2574 /* F-CURVE MODIFIERS */
2575 
2576 /* -------------------------------------------------------------------- */
2581  PointerRNA *UNUSED(ptr),
2582  PropertyRNA *UNUSED(prop),
2583  bool *r_free)
2584 {
2585  EnumPropertyItem *item = NULL;
2586  int totitem = 0;
2587  int i = 0;
2588 
2589  if (C == NULL) {
2591  }
2592 
2593  /* Start from 1 to skip the 'Invalid' modifier type. */
2594  for (i = 1; i < FMODIFIER_NUM_TYPES; i++) {
2595  const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(i);
2596  int index;
2597 
2598  /* Check if modifier is valid for this context. */
2599  if (fmi == NULL) {
2600  continue;
2601  }
2602 
2604  if (index != -1) { /* Not all types are implemented yet... */
2605  RNA_enum_item_add(&item, &totitem, &rna_enum_fmodifier_type_items[index]);
2606  }
2607  }
2608 
2609  RNA_enum_item_end(&item, &totitem);
2610  *r_free = true;
2611 
2612  return item;
2613 }
2614 
2616 {
2617  bAnimContext ac;
2618  ListBase anim_data = {NULL, NULL};
2619  bAnimListElem *ale;
2620  int filter;
2621  short type;
2622 
2623  /* Get editor data. */
2624  if (ANIM_animdata_get_context(C, &ac) == 0) {
2625  return OPERATOR_CANCELLED;
2626  }
2627 
2628  /* Get type of modifier to add. */
2629  type = RNA_enum_get(op->ptr, "type");
2630 
2631  /* Filter data. */
2633  if (RNA_boolean_get(op->ptr, "only_active")) {
2634  /* FIXME: enforce in this case only a single channel to get handled? */
2636  }
2637  else {
2639  }
2640  ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
2641 
2642  /* Add f-modifier to each curve. */
2643  for (ale = anim_data.first; ale; ale = ale->next) {
2644  FCurve *fcu = (FCurve *)ale->data;
2645  FModifier *fcm;
2646 
2647  /* Add F-Modifier of specified type to active F-Curve, and make it the active one. */
2648  fcm = add_fmodifier(&fcu->modifiers, type, fcu);
2649  if (fcm) {
2650  set_active_fmodifier(&fcu->modifiers, fcm);
2651  }
2652  else {
2653  BKE_report(op->reports, RPT_ERROR, "Modifier could not be added (see console for details)");
2654  break;
2655  }
2656 
2657  ale->update |= ANIM_UPDATE_DEPS;
2658  }
2659 
2660  ANIM_animdata_update(&ac, &anim_data);
2661  ANIM_animdata_freelist(&anim_data);
2662 
2663  /* Set notifier that things have changed. */
2665 
2666  return OPERATOR_FINISHED;
2667 }
2668 
2670 {
2671  PropertyRNA *prop;
2672 
2673  /* Identifiers */
2674  ot->name = "Add F-Curve Modifier";
2675  ot->idname = "GRAPH_OT_fmodifier_add";
2676  ot->description = "Add F-Modifier to the active/selected F-Curves";
2677 
2678  /* API callbacks */
2682 
2683  /* Flags */
2685 
2686  /* Id-props */
2687  prop = RNA_def_enum(ot->srna, "type", rna_enum_fmodifier_type_items, 0, "Type", "");
2690  ot->prop = prop;
2691 
2693  ot->srna, "only_active", 1, "Only Active", "Only add F-Modifier to active F-Curve");
2694 }
2695 
2698 /* -------------------------------------------------------------------- */
2703 {
2704  bAnimContext ac;
2705  bAnimListElem *ale;
2706  bool ok = false;
2707 
2708  /* Get editor data. */
2709  if (ANIM_animdata_get_context(C, &ac) == 0) {
2710  return OPERATOR_CANCELLED;
2711  }
2712 
2713  /* Clear buffer first. */
2715 
2716  /* Get the active F-Curve. */
2717  ale = get_active_fcurve_channel(&ac);
2718 
2719  /* If this exists, call the copy F-Modifiers API function. */
2720  if (ale && ale->data) {
2721  FCurve *fcu = (FCurve *)ale->data;
2722 
2723  /* TODO: When 'active' vs 'all' boolean is added, change last param! (Joshua Leung 2010) */
2724  ok = ANIM_fmodifiers_copy_to_buf(&fcu->modifiers, 0);
2725 
2726  /* Free temp data now. */
2727  MEM_freeN(ale);
2728  }
2729 
2730  /* Successful or not? */
2731  if (ok == 0) {
2732  BKE_report(op->reports, RPT_ERROR, "No F-Modifiers available to be copied");
2733  return OPERATOR_CANCELLED;
2734  }
2735  return OPERATOR_FINISHED;
2736 }
2737 
2739 {
2740  /* Identifiers */
2741  ot->name = "Copy F-Modifiers";
2742  ot->idname = "GRAPH_OT_fmodifier_copy";
2743  ot->description = "Copy the F-Modifier(s) of the active F-Curve";
2744 
2745  /* API callbacks */
2748 
2749  /* Flags */
2751 
2752  /* Id-props */
2753 #if 0
2755  "all",
2756  1,
2757  "All F-Modifiers",
2758  "Copy all the F-Modifiers, instead of just the active one");
2759 #endif
2760 }
2761 
2764 /* -------------------------------------------------------------------- */
2769 {
2770  bAnimContext ac;
2771 
2772  ListBase anim_data = {NULL, NULL};
2773  bAnimListElem *ale;
2774  int filter;
2775 
2776  const bool replace = RNA_boolean_get(op->ptr, "replace");
2777  bool ok = false;
2778 
2779  /* Get editor data. */
2780  if (ANIM_animdata_get_context(C, &ac) == 0) {
2781  return OPERATOR_CANCELLED;
2782  }
2783 
2784  /* Filter data. */
2785  if (RNA_boolean_get(op->ptr, "only_active")) {
2786  /* This should be the default (for buttons) - Just paste to the active FCurve. */
2789  }
2790  else {
2791  /* This is only if the operator gets called from a hotkey or search -
2792  * Paste to all visible curves. */
2795  }
2796 
2797  ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
2798 
2799  /* Paste modifiers. */
2800  for (ale = anim_data.first; ale; ale = ale->next) {
2801  FCurve *fcu = (FCurve *)ale->data;
2802  int tot;
2803 
2804  tot = ANIM_fmodifiers_paste_from_buf(&fcu->modifiers, replace, fcu);
2805 
2806  if (tot) {
2807  ale->update |= ANIM_UPDATE_DEPS;
2808  ok = true;
2809  }
2810  }
2811 
2812  if (ok) {
2813  ANIM_animdata_update(&ac, &anim_data);
2814  }
2815  ANIM_animdata_freelist(&anim_data);
2816 
2817  /* Successful or not?. */
2818  if (ok) {
2819  /* Set notifier that keyframes have changed. */
2821 
2822  return OPERATOR_FINISHED;
2823  }
2824 
2825  BKE_report(op->reports, RPT_ERROR, "No F-Modifiers to paste");
2826  return OPERATOR_CANCELLED;
2827 }
2828 
2830 {
2831  /* Identifiers */
2832  ot->name = "Paste F-Modifiers";
2833  ot->idname = "GRAPH_OT_fmodifier_paste";
2834  ot->description = "Add copied F-Modifiers to the selected F-Curves";
2835 
2836  /* API callbacks */
2839 
2840  /* Flags */
2842 
2843  /* Properties */
2845  ot->srna, "only_active", false, "Only Active", "Only paste F-Modifiers on active F-Curve");
2847  ot->srna,
2848  "replace",
2849  false,
2850  "Replace Existing",
2851  "Replace existing F-Modifiers, instead of just appending to the end of the existing list");
2852 }
2853 
2856 /* ************************************************************************** */
2857 /* Drivers */
2858 
2859 /* -------------------------------------------------------------------- */
2864 {
2865  bool ok = false;
2866 
2867  PointerRNA ptr = CTX_data_pointer_get_type(C, "active_editable_fcurve", &RNA_FCurve);
2868 
2869  /* If this exists, call the copy driver vars API function. */
2870  FCurve *fcu = ptr.data;
2871 
2872  if (fcu) {
2873  ok = ANIM_driver_vars_copy(op->reports, fcu);
2874  }
2875 
2876  /* Successful or not?. */
2877  if (ok) {
2878  return OPERATOR_FINISHED;
2879  }
2880  return OPERATOR_CANCELLED;
2881 }
2882 
2884 {
2885  /* Identifiers */
2886  ot->name = "Copy Driver Variables";
2887  ot->idname = "GRAPH_OT_driver_variables_copy";
2888  ot->description = "Copy the driver variables of the active driver";
2889 
2890  /* API callbacks */
2893 
2894  /* Flags */
2896 }
2897 
2900 /* -------------------------------------------------------------------- */
2905 {
2906  const bool replace = RNA_boolean_get(op->ptr, "replace");
2907  bool ok = false;
2908 
2909  PointerRNA ptr = CTX_data_pointer_get_type(C, "active_editable_fcurve", &RNA_FCurve);
2910 
2911  /* If this exists, call the paste driver vars API function. */
2912  FCurve *fcu = ptr.data;
2913 
2914  if (fcu) {
2915  ok = ANIM_driver_vars_paste(op->reports, fcu, replace);
2916  }
2917 
2918  /* Successful or not?. */
2919  if (ok) {
2920  /* Rebuild depsgraph, now that there are extra deps here. */
2922 
2923  /* Set notifier that keyframes have changed. */
2925 
2926  return OPERATOR_FINISHED;
2927  }
2928  return OPERATOR_CANCELLED;
2929 }
2930 
2932 {
2933  /* Identifiers */
2934  ot->name = "Paste Driver Variables";
2935  ot->idname = "GRAPH_OT_driver_variables_paste";
2936  ot->description = "Add copied driver variables to the active driver";
2937 
2938  /* API callbacks */
2941 
2942  /* Flags */
2944 
2945  /* Properties */
2947  "replace",
2948  false,
2949  "Replace Existing",
2950  "Replace existing driver variables, instead of just appending to the end of the "
2951  "existing list");
2952 }
2953 
2956 /* -------------------------------------------------------------------- */
2961 {
2962  bAnimContext ac;
2963  ListBase anim_data = {NULL, NULL};
2964  bAnimListElem *ale;
2965  int filter;
2966  bool ok = false;
2967  uint deleted = 0;
2968 
2969  /* Get editor data. */
2970  if (ANIM_animdata_get_context(C, &ac) == 0) {
2971  return OPERATOR_CANCELLED;
2972  }
2973 
2974  /* NOTE: We might need a scene update to evaluate the driver flags. */
2975 
2976  /* Filter data. */
2978  ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
2979 
2980  /* Find invalid drivers. */
2981  for (ale = anim_data.first; ale; ale = ale->next) {
2982  FCurve *fcu = (FCurve *)ale->data;
2983  if (ELEM(NULL, fcu, fcu->driver)) {
2984  continue;
2985  }
2986  if (!(fcu->driver->flag & DRIVER_FLAG_INVALID)) {
2987  continue;
2988  }
2989 
2990  ok |= ANIM_remove_driver(op->reports, ale->id, fcu->rna_path, fcu->array_index, 0);
2991  if (!ok) {
2992  break;
2993  }
2994  deleted += 1;
2995  }
2996 
2997  /* Cleanup. */
2998  ANIM_animdata_freelist(&anim_data);
2999 
3000  if (deleted > 0) {
3001  /* Notify the world of any changes. */
3004  WM_reportf(RPT_INFO, "Deleted %u drivers", deleted);
3005  }
3006  else {
3007  WM_report(RPT_INFO, "No drivers deleted");
3008  }
3009 
3010  /* Successful or not?*/
3011  if (!ok) {
3012  return OPERATOR_CANCELLED;
3013  }
3014 
3015  return OPERATOR_FINISHED;
3016 }
3017 
3019 {
3020  bAnimContext ac;
3021  ScrArea *area = CTX_wm_area(C);
3022 
3023  /* Firstly, check if in Graph Editor. */
3024  if ((area == NULL) || (area->spacetype != SPACE_GRAPH)) {
3025  return false;
3026  }
3027 
3028  /* Try to init Anim-Context stuff ourselves and check. */
3029  return ANIM_animdata_get_context(C, &ac) != 0;
3030 }
3031 
3033 {
3034  /* Identifiers */
3035  ot->name = "Delete Invalid Drivers";
3036  ot->idname = "GRAPH_OT_driver_delete_invalid";
3037  ot->description = "Delete all visible drivers considered invalid";
3038 
3039  /* API callbacks */
3042 
3043  /* Flags */
3045 }
3046 
typedef float(TangentPoint)[2]
void BKE_animsys_free_nla_keyframing_context_cache(struct ListBase *cache)
Definition: anim_sys.c:2756
AnimationEvalContext BKE_animsys_eval_context_construct(struct Depsgraph *depsgraph, float eval_time)
Definition: anim_sys.c:637
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:714
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
PointerRNA CTX_data_pointer_get_type(const bContext *C, const char *member, StructRNA *type)
Definition: context.c:456
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:725
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1018
void BKE_fcurve_keyframe_move_value_with_handles(struct BezTriple *keyframe, float new_value)
Definition: fcurve.c:947
float evaluate_fcurve_only_curve(struct FCurve *fcu, float evaltime)
Definition: fcurve.c:2193
bool BKE_fcurve_is_empty(struct FCurve *fcu)
Definition: fcurve.c:2250
void fcurve_store_samples(struct FCurve *fcu, void *data, int start, int end, FcuSampleFunc sample_cb)
Definition: fcurve.c:1108
void set_active_fmodifier(ListBase *modifiers, struct FModifier *fcm)
Definition: fmodifier.c:1311
bool BKE_fcurve_is_keyframable(struct FCurve *fcu)
Definition: fcurve.c:1031
bool remove_fmodifier(ListBase *modifiers, struct FModifier *fcm)
Definition: fmodifier.c:1226
void fcurve_samples_to_keyframes(struct FCurve *fcu, const int start, const int end)
Definition: fcurve.c:1156
const FModifierTypeInfo * get_fmodifier_typeinfo(const int type)
Definition: fmodifier.c:1072
void calchandles_fcurve(struct FCurve *fcu)
Definition: fcurve.c:1391
struct FModifier * add_fmodifier(ListBase *modifiers, int type, struct FCurve *owner_fcu)
Definition: fmodifier.c:1114
bool list_has_suitable_fmodifier(ListBase *modifiers, int mtype, short acttype)
Definition: fmodifier.c:1337
float fcurve_samplingcb_evalcurve(struct FCurve *fcu, void *data, float evaltime)
@ NLATIME_CONVERT_UNMAP
Definition: BKE_nla.h:153
float BKE_nla_tweakedit_remap(struct AnimData *adt, float cframe, short mode)
Definition: nla.c:582
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
void BKE_reportf(ReportList *reports, ReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
#define BLI_assert(a)
Definition: BLI_assert.h:58
bool BLI_is_file(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: storage.c:444
void BLI_kdtree_nd_() free(KDTree *tree)
Definition: kdtree_impl.h:116
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:128
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:547
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE int round_fl_to_int(float a)
MINLINE int min_ii(int a, int b)
#define M_PI
Definition: BLI_math_base.h:38
void eul_to_mat3(float mat[3][3], const float eul[3])
void mat3_normalized_to_compatible_eul(float eul[3], const float old[3], float mat[3][3])
#define FILE_MAX
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC
Definition: string.c:70
unsigned int uint
Definition: BLI_sys_types.h:83
#define UNUSED(x)
#define ELEM(...)
#define STREQ(a, b)
#define BLT_I18NCONTEXT_ID_ACTION
#define TIP_(msgid)
void DEG_relations_tag_update(struct Main *bmain)
eInsertKeyFlags
@ FMODIFIER_TYPE_CYCLES
@ FMODIFIER_NUM_TYPES
@ DRIVER_FLAG_INVALID
@ FCURVE_PROTECTED
@ FCURVE_EXTRAPOLATE_CONSTANT
@ FCURVE_EXTRAPOLATE_LINEAR
#define SUBFRA
#define CFRA
#define PSFRA
#define FPS
#define PEFRA
@ FILE_SORT_DEFAULT
@ FILE_SPECIAL
@ FILE_TYPE_MOVIE
@ FILE_TYPE_SOUND
@ FILE_TYPE_FOLDER
@ SPACE_GRAPH
@ SIPO_MODE_DRIVERS
@ FILE_OPENFILE
@ FILE_DEFAULTDISPLAY
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
#define ANIM_UPDATE_DEFAULT_NOHANDLES
Definition: ED_anim_api.h:282
#define ANIM_UPDATE_DEFAULT
Definition: ED_anim_api.h:281
@ ANIM_UPDATE_DEPS
Definition: ED_anim_api.h:275
@ ANIM_UPDATE_HANDLES
Definition: ED_anim_api.h:277
@ ANIMFILTER_ACTIVE
Definition: ED_anim_api.h:306
@ ANIMFILTER_FOREDIT
Definition: ED_anim_api.h:315
@ ANIMFILTER_DATA_VISIBLE
Definition: ED_anim_api.h:295
@ ANIMFILTER_CURVE_VISIBLE
Definition: ED_anim_api.h:300
@ ANIMFILTER_NODUPLIS
Definition: ED_anim_api.h:328
@ ANIMFILTER_SEL
Definition: ED_anim_api.h:311
@ ANIM_UNITCONV_ONLYKEYS
Definition: ED_anim_api.h:763
@ ANIM_UNITCONV_RESTORE
Definition: ED_anim_api.h:761
@ MIRROR_KEYS_TIME
eKeyMergeMode
@ KEYFRAME_PASTE_MERGE_MIX
eKeyPasteOffset
@ KEYFRAME_PASTE_OFFSET_CFRA_START
@ BEZT_OK_SELECTED
short(* KeyframeEditFunc)(KeyframeEditData *ked, struct BezTriple *bezt)
@ SNAP_KEYS_TIME
@ SELECT_SUBTRACT
void ED_region_tag_redraw(struct ARegion *region)
Definition: area.c:667
@ TFM_TRANSLATION
Definition: ED_transform.h:46
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
Read Guarded memory(de)allocation.
StructRNA RNA_FCurve
@ PROP_SKIP_SAVE
Definition: RNA_types.h:204
#define C
Definition: RandGen.cpp:39
void UI_view2d_region_to_view(const struct View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
#define WM_FILESEL_SHOW_PROPS
Definition: WM_api.h:540
#define WM_FILESEL_FILEPATH
Definition: WM_api.h:537
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
#define NC_ANIMATION
Definition: WM_types.h:289
#define NC_SCENE
Definition: WM_types.h:279
#define NA_ADDED
Definition: WM_types.h:464
#define NA_EDITED
Definition: WM_types.h:462
#define ND_KEYFRAME_PROP
Definition: WM_types.h:395
#define ND_FRAME
Definition: WM_types.h:334
#define NA_REMOVED
Definition: WM_types.h:465
#define ND_KEYFRAME
Definition: WM_types.h:394
void ANIM_fcurve_delete_from_animdata(bAnimContext *ac, AnimData *adt, FCurve *fcu)
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
void ANIM_nla_mapping_apply_fcurve(AnimData *adt, FCurve *fcu, bool restore, bool only_keys)
Definition: anim_draw.c:257
float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short flag, float *r_offset)
Definition: anim_draw.c:453
short ANIM_get_normalization_flags(bAnimContext *ac)
Definition: anim_draw.c:285
bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
Definition: anim_filter.c:405
size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, eAnimFilter_Flags filter_mode, void *data, eAnimCont_Types datatype)
Definition: anim_filter.c:3442
TimeMarker * ED_markers_get_first_selected(ListBase *markers)
Definition: anim_markers.c:379
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
float evaltime
Definition: bpy_driver.c:181
SIMD_FORCE_INLINE btScalar length(const btQuaternion &q)
Return the length of a quaternion.
Definition: btQuaternion.h:895
Scene scene
bool ANIM_remove_driver(ReportList *UNUSED(reports), ID *id, const char rna_path[], int array_index, short UNUSED(flag))
Definition: drivers.c:552
bool ANIM_driver_vars_copy(ReportList *reports, FCurve *fcu)
Definition: drivers.c:762
bool ANIM_driver_vars_paste(ReportList *reports, FCurve *fcu, bool replace)
Definition: drivers.c:785
bool ANIM_fmodifiers_paste_from_buf(ListBase *modifiers, bool replace, FCurve *curve)
void ANIM_fmodifiers_copybuf_free(void)
Definition: fmodifier_ui.c:976
bool ANIM_fmodifiers_copy_to_buf(ListBase *modifiers, bool active)
Definition: fmodifier_ui.c:986
static int graph_fmodifier_paste_exec(bContext *C, wmOperator *op)
Definition: graph_edit.c:2768
static const EnumPropertyItem prop_graphkeys_insertkey_types[]
Definition: graph_edit.c:88
void GRAPH_OT_delete(wmOperatorType *ot)
Definition: graph_edit.c:766
static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode)
Definition: graph_edit.c:113
static int graphkeys_sample_exec(bContext *C, wmOperator *UNUSED(op))
Definition: graph_edit.c:1294
void GRAPH_OT_click_insert(wmOperatorType *ot)
Definition: graph_edit.c:418
static int graphkeys_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
Definition: graph_edit.c:663
struct tEulerFilter tEulerFilter
void GRAPH_OT_fmodifier_paste(wmOperatorType *ot)
Definition: graph_edit.c:2829
void GRAPH_OT_smooth(wmOperatorType *ot)
Definition: graph_edit.c:2556
static void clean_graph_keys(bAnimContext *ac, float thresh, bool clean_chan)
Definition: graph_edit.c:789
static void mirror_graph_keys(bAnimContext *ac, short mode)
Definition: graph_edit.c:2388
static KeyframeEditData sum_selected_keyframes(bAnimContext *ac)
Definition: graph_edit.c:2054
static int graphkeys_easing_exec(bContext *C, wmOperator *op)
Definition: graph_edit.c:1574
static int graphkeys_expo_exec(bContext *C, wmOperator *op)
Definition: graph_edit.c:1423
static bool euler_filter_multi_channel(tEulerFilter *euf, ReportList *reports)
Definition: graph_edit.c:1792
static bool graph_driver_delete_invalid_poll(bContext *C)
Definition: graph_edit.c:3018
static int graphkeys_insertkey_exec(bContext *C, wmOperator *op)
Definition: graph_edit.c:254
void GRAPH_OT_snap_cursor_value(wmOperatorType *ot)
Definition: graph_edit.c:2179
static void euler_filter_perform_filter(ListBase *eulers, ReportList *reports, int *r_curves_filtered, int *r_curves_seen)
Definition: graph_edit.c:1906
static int graphkeys_click_insert_exec(bContext *C, wmOperator *op)
Definition: graph_edit.c:301
static void sethandles_graph_keys(bAnimContext *ac, short mode)
Definition: graph_edit.c:1624
static bool euler_filter_single_channel(FCurve *fcu)
Definition: graph_edit.c:1867
static int graphkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op))
Definition: graph_edit.c:2099
static int graphkeys_mirror_exec(bContext *C, wmOperator *op)
Definition: graph_edit.c:2472
static bool keyframe_time_differs(BezTriple *keyframes[3])
Definition: graph_edit.c:1726
static short paste_graph_keys(bAnimContext *ac, const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode, bool flip)
Definition: graph_edit.c:488
void GRAPH_OT_mirror(wmOperatorType *ot)
Definition: graph_edit.c:2494
void GRAPH_OT_sample(wmOperatorType *ot)
Definition: graph_edit.c:1312
void GRAPH_OT_bake(wmOperatorType *ot)
Definition: graph_edit.c:927
static void snap_graph_keys(bAnimContext *ac, short mode)
Definition: graph_edit.c:2237
void GRAPH_OT_fmodifier_copy(wmOperatorType *ot)
Definition: graph_edit.c:2738
static const EnumPropertyItem prop_graphkeys_mirror_types[]
Definition: graph_edit.c:2357
void GRAPH_OT_handle_type(wmOperatorType *ot)
Definition: graph_edit.c:1681
static int graphkeys_delete_exec(bContext *C, wmOperator *UNUSED(op))
Definition: graph_edit.c:746
static void sample_graph_keys(bAnimContext *ac)
Definition: graph_edit.c:1270
void GRAPH_OT_frame_jump(wmOperatorType *ot)
Definition: graph_edit.c:2139
void GRAPH_OT_driver_variables_copy(wmOperatorType *ot)
Definition: graph_edit.c:2883
void GRAPH_OT_extrapolation_type(wmOperatorType *ot)
Definition: graph_edit.c:1445
static bool delete_graph_keys(bAnimContext *ac)
Definition: graph_edit.c:705
#define MAKE_CYCLIC_EXPO
Definition: graph_edit.c:1337
static void duplicate_graph_keys(bAnimContext *ac)
Definition: graph_edit.c:639
static int graphkeys_ipo_exec(bContext *C, wmOperator *op)
Definition: graph_edit.c:1499
void GRAPH_OT_unbake(wmOperatorType *ot)
Definition: graph_edit.c:1004
static void unbake_graph_curves(bAnimContext *ac, int start, int end)
Definition: graph_edit.c:954
void GRAPH_OT_driver_variables_paste(wmOperatorType *ot)
Definition: graph_edit.c:2931
static int graphkeys_snap_cursor_value_exec(bContext *C, wmOperator *UNUSED(op))
Definition: graph_edit.c:2155
void GRAPH_OT_interpolation_type(wmOperatorType *ot)
Definition: graph_edit.c:1521
static int graphkeys_bake_exec(bContext *C, wmOperator *UNUSED(op))
Definition: graph_edit.c:900
static int graph_driver_vars_copy_exec(bContext *C, wmOperator *op)
Definition: graph_edit.c:2863
static void setexpo_graph_keys(bAnimContext *ac, short mode)
Definition: graph_edit.c:1367
eGraphKeys_InsertKey_Types
Definition: graph_edit.c:80
@ GRAPHKEYS_INSERTKEY_CURSOR
Definition: graph_edit.c:83
@ GRAPHKEYS_INSERTKEY_ACTIVE
Definition: graph_edit.c:84
@ GRAPHKEYS_INSERTKEY_ALL
Definition: graph_edit.c:81
@ GRAPHKEYS_INSERTKEY_SEL
Definition: graph_edit.c:82
static const EnumPropertyItem prop_graphkeys_expo_types[]
Definition: graph_edit.c:1341
static int graph_fmodifier_copy_exec(bContext *C, wmOperator *op)
Definition: graph_edit.c:2702
static int graph_driver_delete_invalid_exec(bContext *C, wmOperator *op)
Definition: graph_edit.c:2960
static int graphkeys_click_insert_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition: graph_edit.c:389
void GRAPH_OT_easing_type(wmOperatorType *ot)
Definition: graph_edit.c:1596
static int graph_driver_vars_paste_exec(bContext *C, wmOperator *op)
Definition: graph_edit.c:2904
static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
Definition: graph_edit.c:1937
static int graph_fmodifier_add_exec(bContext *C, wmOperator *op)
Definition: graph_edit.c:2615
static int graphkeys_smooth_exec(bContext *C, wmOperator *UNUSED(op))
Definition: graph_edit.c:2519
void GRAPH_OT_copy(wmOperatorType *ot)
Definition: graph_edit.c:539
static int graphkeys_paste_exec(bContext *C, wmOperator *op)
Definition: graph_edit.c:554
static char * graphkeys_paste_description(bContext *UNUSED(C), wmOperatorType *UNUSED(op), PointerRNA *ptr)
Definition: graph_edit.c:581
static void setipo_graph_keys(bAnimContext *ac, short mode)
Definition: graph_edit.c:1471
void GRAPH_OT_driver_delete_invalid(wmOperatorType *ot)
Definition: graph_edit.c:3032
void GRAPH_OT_keyframe_insert(wmOperatorType *ot)
Definition: graph_edit.c:276
void GRAPH_OT_sound_bake(wmOperatorType *ot)
Definition: graph_edit.c:1160
static int graphkeys_copy_exec(bContext *C, wmOperator *op)
Definition: graph_edit.c:520
void GRAPH_OT_duplicate(wmOperatorType *ot)
Definition: graph_edit.c:681
static void seteasing_graph_keys(bAnimContext *ac, short mode)
Definition: graph_edit.c:1548
static int graphkeys_handletype_exec(bContext *C, wmOperator *op)
Definition: graph_edit.c:1659
static int graphkeys_sound_bake_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition: graph_edit.c:1148
void GRAPH_OT_euler_filter(wmOperatorType *ot)
Definition: graph_edit.c:2017
static bool graphkeys_framejump_poll(bContext *C)
Definition: graph_edit.c:2044
static int graphkeys_sound_bake_exec(bContext *UNUSED(C), wmOperator *op)
Definition: graph_edit.c:1139
static short copy_graph_keys(bAnimContext *ac)
Definition: graph_edit.c:461
void GRAPH_OT_clean(wmOperatorType *ot)
Definition: graph_edit.c:836
static int graphkeys_clean_exec(bContext *C, wmOperator *op)
Definition: graph_edit.c:813
static int graphkeys_snap_exec(bContext *C, wmOperator *op)
Definition: graph_edit.c:2309
#define CLEAR_CYCLIC_EXPO
Definition: graph_edit.c:1338
void GRAPH_OT_snap(wmOperatorType *ot)
Definition: graph_edit.c:2331
static const EnumPropertyItem * graph_fmodifier_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
Definition: graph_edit.c:2580
static int graphkeys_unbake_exec(bContext *C, wmOperator *UNUSED(op))
Definition: graph_edit.c:979
static void bake_graph_curves(bAnimContext *ac, int start, int end)
Definition: graph_edit.c:866
static ListBase euler_filter_group_channels(const ListBase *anim_data, ReportList *reports, int *r_num_groups)
Definition: graph_edit.c:1735
void GRAPH_OT_fmodifier_add(wmOperatorType *ot)
Definition: graph_edit.c:2669
static const EnumPropertyItem prop_graphkeys_snap_types[]
Definition: graph_edit.c:2201
void GRAPH_OT_paste(wmOperatorType *ot)
Definition: graph_edit.c:594
@ GRAPHKEYS_MIRROR_XAXIS
Definition: graph_intern.h:139
@ GRAPHKEYS_MIRROR_CFRA
Definition: graph_intern.h:137
@ GRAPHKEYS_MIRROR_VALUE
Definition: graph_intern.h:141
@ GRAPHKEYS_MIRROR_YAXIS
Definition: graph_intern.h:138
@ GRAPHKEYS_MIRROR_MARKER
Definition: graph_intern.h:140
bool graphop_active_fcurve_poll(struct bContext *C)
Definition: graph_utils.c:239
@ GRAPHKEYS_SNAP_NEAREST_MARKER
Definition: graph_intern.h:128
@ GRAPHKEYS_SNAP_VALUE
Definition: graph_intern.h:130
@ GRAPHKEYS_SNAP_NEAREST_SECOND
Definition: graph_intern.h:127
@ GRAPHKEYS_SNAP_HORIZONTAL
Definition: graph_intern.h:129
@ GRAPHKEYS_SNAP_CFRA
Definition: graph_intern.h:125
@ GRAPHKEYS_SNAP_NEAREST_FRAME
Definition: graph_intern.h:126
bool graphop_active_editable_fcurve_ctx_poll(struct bContext *C)
Definition: graph_utils.c:283
struct bAnimListElem * get_active_fcurve_channel(struct bAnimContext *ac)
Definition: graph_utils.c:104
bool graphop_selected_fcurve_poll(struct bContext *C)
Definition: graph_utils.c:291
bool graphop_visible_keyframes_poll(struct bContext *C)
Definition: graph_utils.c:131
bool graphop_editable_keyframes_poll(struct bContext *C)
Definition: graph_utils.c:184
void deselect_graph_keys(struct bAnimContext *ac, bool test, short sel, bool do_channels)
Definition: graph_select.c:354
DO_INLINE void filter(lfVector *V, fmatrix3x3 *S)
KeyframeEditFunc ANIM_editkeyframes_mirror(short mode)
KeyframeEditFunc ANIM_editkeyframes_easing(short mode)
KeyframeEditFunc ANIM_editkeyframes_ipo(short mode)
short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked, FCurve *fcu, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
KeyframeEditFunc ANIM_editkeyframes_snap(short mode)
short bezt_calc_average(KeyframeEditData *ked, BezTriple *bezt)
KeyframeEditFunc ANIM_editkeyframes_handles(short mode)
void duplicate_fcurve_keys(FCurve *fcu)
const EnumPropertyItem rna_enum_keyframe_paste_offset_items[]
short paste_animedit_keys(bAnimContext *ac, ListBase *anim_data, const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode, bool flip)
short copy_animedit_keys(bAnimContext *ac, ListBase *anim_data)
const EnumPropertyItem rna_enum_keyframe_paste_merge_items[]
void sample_fcurve(FCurve *fcu)
void smooth_fcurve(FCurve *fcu)
void ANIM_fcurves_copybuf_free(void)
bool delete_fcurve_keys(FCurve *fcu)
void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, bool cleardefault)
int insert_vert_fcurve(FCurve *fcu, float x, float y, eBezTriple_KeyframeType keyframe_type, eInsertKeyFlags flag)
Definition: keyframing.c:547
eInsertKeyFlags ANIM_get_keyframing_flags(Scene *scene, const bool use_autokey_mode)
Definition: keyframing.c:92
int insert_keyframe(Main *bmain, ReportList *reports, ID *id, bAction *act, const char group[], const char rna_path[], int array_index, const AnimationEvalContext *anim_eval_context, eBezTriple_KeyframeType keytype, ListBase *nla_cache, eInsertKeyFlags flag)
Definition: keyframing.c:1413
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
double sign(double arg)
Definition: utility.h:250
static void area(int d1, int d2, int e1, int e2, float weights[2])
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
Definition: rna_access.c:6514
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6355
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
Definition: rna_access.c:6366
int RNA_enum_from_value(const EnumPropertyItem *item, const int value)
Definition: rna_access.c:1902
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6402
const EnumPropertyItem rna_enum_beztriple_interpolation_mode_items[]
Definition: rna_curve.c:82
const EnumPropertyItem rna_enum_keyframe_handle_type_items[]
Definition: rna_curve.c:53
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:3825
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3481
void RNA_enum_item_end(EnumPropertyItem **items, int *totitem)
Definition: rna_define.c:4470
void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item)
Definition: rna_define.c:4416
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context)
Definition: rna_define.c:2870
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1512
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
Definition: rna_define.c:3819
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3771
const EnumPropertyItem rna_enum_fmodifier_type_items[]
Definition: rna_fcurve.c:45
const EnumPropertyItem rna_enum_beztriple_interpolation_easing_items[]
Definition: rna_fcurve.c:124
float vec[3][3]
bActionGroup * grp
char * rna_path
FPoint * fpt
ChannelDriver * driver
BezTriple * bezt
short extend
int array_index
short flag
unsigned int totvert
ListBase modifiers
struct FModifier * next
Definition: DNA_ID.h:273
char name[66]
Definition: DNA_ID.h:283
void * last
Definition: DNA_listBase.h:47
void * first
Definition: DNA_listBase.h:47
void * data
Definition: RNA_types.h:52
struct ToolSettings * toolsettings
ListBase * markers
Definition: ED_anim_api.h:105
struct ARegion * region
Definition: ED_anim_api.h:89
struct Scene * scene
Definition: ED_anim_api.h:97
short datatype
Definition: ED_anim_api.h:75
void * data
Definition: ED_anim_api.h:73
struct ReportList * reports
Definition: ED_anim_api.h:108
struct Main * bmain
Definition: ED_anim_api.h:95
struct SpaceLink * sl
Definition: ED_anim_api.h:87
struct Depsgraph * depsgraph
Definition: ED_anim_api.h:101
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
int ymin
Definition: DNA_vec_types.h:80
int xmin
Definition: DNA_vec_types.h:79
const char * rna_path
Definition: graph_edit.c:1723
FCurve * fcurves[3]
Definition: graph_edit.c:1721
struct tEulerFilter * prev
Definition: graph_edit.c:1716
struct tEulerFilter * next
Definition: graph_edit.c:1716
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
const char * idname
Definition: WM_types.h:723
char *(* get_description)(struct bContext *C, struct wmOperatorType *, struct PointerRNA *)
Definition: WM_types.h:799
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
PropertyRNA * prop
Definition: WM_types.h:814
struct ReportList * reports
struct PointerRNA * ptr
const EnumPropertyItem rna_enum_transform_mode_types[]
ccl_device_inline float2 fabs(const float2 &a)
#define G(x, y, z)
void WM_report(ReportType type, const char *message)
void WM_reportf(ReportType type, const char *format,...)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition: wm_files.c:3157
wmOperatorType * ot
Definition: wm_files.c:3156
void WM_operator_properties_confirm_or_exec(wmOperatorType *ot)
void WM_operator_properties_filesel(wmOperatorType *ot, int filter, short type, short action, short flag, short display, short sort)
int WM_operator_confirm(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
int WM_operator_confirm_or_exec(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
int WM_operator_filesel(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: wm_operators.c:982