Blender V5.0
graph_edit.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include <cfloat>
12#include <cmath>
13#include <cstdlib>
14#include <cstring>
15
16#ifdef WITH_AUDASPACE
17# include <AUD_Special.h>
18#endif
19
20#include "MEM_guardedalloc.h"
21
22#include "BLI_fileops.h"
23#include "BLI_listbase.h"
24#include "BLI_math_rotation.h"
25#include "BLI_utildefines.h"
26
27#include "DNA_anim_types.h"
28#include "DNA_scene_types.h"
29
30#include "RNA_access.hh"
31#include "RNA_define.hh"
32#include "RNA_enum_types.hh"
33#include "RNA_prototypes.hh"
34
35#include "BLT_translation.hh"
36
37#include "BKE_animsys.h"
38#include "BKE_context.hh"
39#include "BKE_fcurve.hh"
40#include "BKE_global.hh"
41#include "BKE_nla.hh"
42#include "BKE_report.hh"
43#include "BKE_scene.hh"
44
45#include "DEG_depsgraph.hh"
47
48#include "UI_interface_icons.hh"
49#include "UI_view2d.hh"
50
51#include "ANIM_animdata.hh"
52#include "ANIM_fcurve.hh"
53#include "ANIM_keyframing.hh"
54#include "ED_anim_api.hh"
55#include "ED_keyframes_edit.hh"
56#include "ED_keyframing.hh"
57#include "ED_markers.hh"
58#include "ED_screen.hh"
59#include "ED_transform.hh"
60
61#include "WM_api.hh"
62#include "WM_types.hh"
63
64#include "graph_intern.hh"
65
66/* -------------------------------------------------------------------- */
69
70/* Mode defines for insert keyframes tool. */
77
78/* RNA mode types for insert keyframes tool. */
81 "ALL",
82 0,
83 "All Channels",
84 "Insert a keyframe on all visible and editable F-Curves using each curve's current value"},
86 "SEL",
87 0,
88 "Only Selected Channels",
89 "Insert a keyframe on selected F-Curves using each curve's current value"},
91 "ACTIVE",
92 0,
93 "Only Active F-Curve",
94 "Insert a keyframe on the active F-Curve using the curve's current value"},
96 "CURSOR_ACTIVE",
97 0,
98 "Active Channels at Cursor",
99 "Insert a keyframe for the active F-Curve at the cursor point"},
101 "CURSOR_SEL",
102 0,
103 "Selected Channels at Cursor",
104 "Insert a keyframe for selected F-Curves at the cursor point"},
105 {0, nullptr, 0, nullptr, nullptr},
106};
107
108/* This function is responsible for snapping keyframes to frame-times. */
110{
111 using namespace blender::animrig;
112 ListBase anim_data = {nullptr, nullptr};
113 int filter;
114 size_t num_items;
115
116 ReportList *reports = ac->reports;
117 SpaceGraph *sipo = (SpaceGraph *)ac->sl;
118 Scene *scene = ac->scene;
119 ToolSettings *ts = scene->toolsettings;
120
121 /* Filter data. */
124 if (mode & GRAPHKEYS_INSERTKEY_SEL) {
126 }
127 else if (mode & GRAPHKEYS_INSERTKEY_ACTIVE) {
129 }
130
131 num_items = ANIM_animdata_filter(
132 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
133 if (num_items == 0) {
134 if (mode & GRAPHKEYS_INSERTKEY_ACTIVE) {
135 BKE_report(reports,
136 RPT_ERROR,
137 "No active F-Curve to add a keyframe to. Select an editable F-Curve first");
138 }
139 else if (mode & GRAPHKEYS_INSERTKEY_SEL) {
140 BKE_report(reports, RPT_ERROR, "No selected F-Curves to add keyframes to");
141 }
142 else {
143 BKE_report(reports, RPT_ERROR, "No channels to add keyframes to");
144 }
145
146 return;
147 }
148
149 /* Init key-framing flag. */
153
154 /* Insert keyframes. */
155 if (mode & GRAPHKEYS_INSERTKEY_CURSOR) {
156 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
157 FCurve *fcu = (FCurve *)ale->key_data;
158
159 short mapping_flag = ANIM_get_normalization_flags(ac->sl);
160 float offset;
161 float unit_scale = ANIM_unit_mapping_get_factor(
162 ac->scene, ale->id, static_cast<FCurve *>(ale->key_data), mapping_flag, &offset);
163
164 float x, y;
165
166 /* perform time remapping for x-coordinate (if necessary) */
167 if ((sipo) && (sipo->mode == SIPO_MODE_DRIVERS)) {
168 x = sipo->cursorTime;
169 }
170 else {
172 }
173
174 /* Normalize units of cursor's value. */
175 if (sipo) {
176 y = (sipo->cursorVal / unit_scale) - offset;
177 }
178 else {
179 y = 0.0f;
180 }
181
182 /* Insert keyframe directly into the F-Curve. */
183 insert_vert_fcurve(fcu, {x, y}, settings, eInsertKeyFlags(0));
184
185 ale->update |= ANIM_UPDATE_DEFAULT;
186 }
187 }
188 else {
190 ac->depsgraph, float(scene->r.cfra));
191 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
192 FCurve *fcu = (FCurve *)ale->key_data;
193
194 /* Read value from property the F-Curve represents, or from the curve only?
195 *
196 * - ale->id != nullptr:
197 * Typically, this means that we have enough info to try resolving the path.
198 * - ale->owner != nullptr:
199 * If this is set, then the path may not be resolvable from the ID alone,
200 * so it's easier for now to just read the F-Curve directly.
201 * (TODO: add the full-blown PointerRNA relative parsing case here... (Joshua Leung 2015))
202 * - fcu->driver != nullptr:
203 * If this is set, then it's a driver. If we don't check for this, we'd end
204 * up adding the keyframes on a new F-Curve in the action data instead.
205 */
206 const std::optional<blender::StringRefNull> channel_group = fcu->grp ? std::optional(
207 fcu->grp->name) :
208 std::nullopt;
209 if (ale->id && !ale->owner && !fcu->driver) {
210 PointerRNA id_rna_pointer = RNA_id_pointer_create(ale->id);
212 &id_rna_pointer,
213 channel_group,
214 {{fcu->rna_path, {}, fcu->array_index}},
215 std::nullopt,
216 anim_eval_context,
218 flag);
219 if (result.get_count(SingleKeyingResult::SUCCESS) == 0) {
220 result.generate_reports(reports);
221 }
222 }
223 else {
224 /* Adjust current frame for NLA-mapping. */
225 float cfra;
226 if ((sipo) && (sipo->mode == SIPO_MODE_DRIVERS)) {
227 cfra = sipo->cursorTime;
228 }
229 else {
230 cfra = ANIM_nla_tweakedit_remap(ale, float(scene->r.cfra), NLATIME_CONVERT_UNMAP);
231 }
232
233 const float curval = evaluate_fcurve_only_curve(fcu, cfra);
234 insert_vert_fcurve(fcu, {cfra, curval}, settings, eInsertKeyFlags(0));
235 }
236
237 ale->update |= ANIM_UPDATE_DEFAULT;
238 }
239 }
240
241 ANIM_animdata_update(ac, &anim_data);
242 ANIM_animdata_freelist(&anim_data);
243}
244
245/* ------------------- */
246
248{
249 bAnimContext ac;
251
252 /* Get editor data. */
253 if (ANIM_animdata_get_context(C, &ac) == 0) {
254 return OPERATOR_CANCELLED;
255 }
256
258
259 /* Which channels to affect? */
260 mode = eGraphKeys_InsertKey_Types(RNA_enum_get(op->ptr, "type"));
261
262 /* Insert keyframes. */
263 insert_graph_keys(&ac, mode);
264
265 /* Set notifier that keyframes have changed. */
267
268 return OPERATOR_FINISHED;
269}
270
272{
273 /* Identifiers */
274 ot->name = "Insert Keyframes";
275 ot->idname = "GRAPH_OT_keyframe_insert";
276 ot->description = "Insert keyframes for the specified channels";
277
278 /* API callbacks */
279 ot->invoke = WM_menu_invoke;
282
283 /* Flags */
285
286 /* Id-props */
287 ot->prop = RNA_def_enum(ot->srna, "type", prop_graphkeys_insertkey_types, 0, "Type", "");
288}
289
291
292/* -------------------------------------------------------------------- */
295
297{
298 using namespace blender::animrig;
299 bAnimContext ac;
300 bAnimListElem *ale;
301 FCurve *fcu;
302
303 /* Get animation context. */
304 if (ANIM_animdata_get_context(C, &ac) == 0) {
305 return OPERATOR_CANCELLED;
306 }
307
308 /* Get active F-Curve 'anim-list-element'. */
309 ale = get_active_fcurve_channel(&ac);
310 if (ELEM(nullptr, ale, ale->data)) {
311 if (ale) {
312 MEM_freeN(ale);
313 }
314 return OPERATOR_CANCELLED;
315 }
316 fcu = static_cast<FCurve *>(ale->data);
317
318 /* When there are F-Modifiers on the curve, only allow adding
319 * keyframes if these will be visible after doing so...
320 */
321 if (BKE_fcurve_is_keyframable(fcu)) {
322 ListBase anim_data;
324
325 /* Preserve selection? */
326 if (RNA_boolean_get(op->ptr, "extend") == false) {
327 /* Deselect all keyframes first,
328 * so that we can immediately start manipulating the newly added one(s)
329 * - only affect the keyframes themselves, as we don't want channels popping in and out. */
330 deselect_graph_keys(&ac, false, SELECT_SUBTRACT, false);
331 }
332
333 /* Get frame and value from props.
334 *
335 * We apply inverse NLA-mapping to `frame` to get correct time in un-scaled
336 * action. */
337 const float frame = ANIM_nla_tweakedit_remap(
338 ale, RNA_float_get(op->ptr, "frame"), NLATIME_CONVERT_UNMAP);
339 float val = RNA_float_get(op->ptr, "value");
340
341 /* Apply inverse unit-mapping to value to get correct value for F-Curves. */
342 {
343 const short mapping_flag = ANIM_get_normalization_flags(ac.sl);
344 float offset;
345 const float scale = ANIM_unit_mapping_get_factor(
346 ac.scene, ale->id, fcu, mapping_flag | ANIM_UNITCONV_RESTORE, &offset);
347
348 val = val * scale - offset;
349 }
350
353
354 /* Insert keyframe on the specified frame + value. */
355 insert_vert_fcurve(fcu, {frame, val}, settings, eInsertKeyFlags(0));
356
357 ale->update |= ANIM_UPDATE_DEPS;
358
359 BLI_listbase_clear(&anim_data);
360 BLI_addtail(&anim_data, ale);
361
362 ANIM_animdata_update(&ac, &anim_data);
363 }
364 else {
365 /* Warn about why this can't happen. */
366 if (fcu->fpt) {
367 BKE_report(op->reports, RPT_ERROR, "Keyframes cannot be added to sampled F-Curves");
368 }
369 else if (fcu->flag & FCURVE_PROTECTED) {
370 BKE_report(op->reports, RPT_ERROR, "Active F-Curve is not editable");
371 }
372 else {
373 BKE_report(op->reports, RPT_ERROR, "Remove F-Modifiers from F-Curve to add keyframes");
374 }
375 }
376
377 /* Free temp data. */
378 MEM_freeN(ale);
379
380 /* Set notifier that keyframes have changed. */
382
383 /* Done */
384 return OPERATOR_FINISHED;
385}
386
388 wmOperator *op,
389 const wmEvent *event)
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->xy[0] - region->winrct.xmin);
407 mval[1] = (event->xy[1] - 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 PropertyRNA *prop;
421
422 /* Identifiers */
423 ot->name = "Click-Insert Keyframes";
424 ot->idname = "GRAPH_OT_click_insert";
425 ot->description = "Insert new keyframe at the cursor position for the active F-Curve";
426
427 /* API callbacks */
431
432 /* Flags */
434
435 /* Properties */
436 RNA_def_float(ot->srna,
437 "frame",
438 1.0f,
439 -FLT_MAX,
440 FLT_MAX,
441 "Frame Number",
442 "Frame to insert keyframe on",
443 0,
444 100);
446 ot->srna, "value", 1.0f, -FLT_MAX, FLT_MAX, "Value", "Value for keyframe on", 0, 100);
447
448 prop = RNA_def_boolean(ot->srna,
449 "extend",
450 false,
451 "Extend",
452 "Extend selection instead of deselecting everything first");
454}
455
457
458/* -------------------------------------------------------------------- */
463
465{
466 ListBase anim_data = {nullptr, nullptr};
467 int filter;
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 */
475
477 &anim_data,
479 ac->data,
480 eAnimCont_Types(ac->datatype)) == 0)
481 {
483 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
484 }
485
486 /* Copy keyframes. */
487 const bool ok = copy_animedit_keys(ac, &anim_data);
488
489 /* Clean up. */
490 ANIM_animdata_freelist(&anim_data);
491
492 return ok;
493}
494
496 const eKeyPasteOffset offset_mode,
497 const eKeyPasteValueOffset value_offset_mode,
498 const eKeyMergeMode merge_mode,
499 const bool flip)
500{
501 /* TODO: deduplicate this function and `paste_action_keys()` in `action_edit.cc`, */
502
503 /* Determine paste context. */
504 KeyframePasteContext paste_context{};
505 paste_context.offset_mode = offset_mode;
506 paste_context.value_offset_mode = value_offset_mode;
507 paste_context.merge_mode = merge_mode;
508 paste_context.flip = flip;
509 paste_context.num_slots_selected = 0; /* Graph editor doesn't show slots. */
510
511 /* Find F-Curves to paste into, in two stages.
512 * - First time we try to filter more strictly, allowing only selected channels
513 * to allow copying animation between channels
514 * - Second time, we loosen things up if nothing was found the first time, allowing
515 * users to just paste keyframes back into the original curve again #31670.
516 */
517 ListBase anim_data = {nullptr, nullptr};
518 {
522 ac, &anim_data, filter | ANIMFILTER_SEL, ac->data, ac->datatype);
523 if (paste_context.num_fcurves_selected == 0) {
524 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
525 }
526 }
527
528 /* Paste keyframes. */
529 const eKeyPasteError ok = paste_animedit_keys(ac, &anim_data, paste_context);
530
531 /* Clean up. */
532 ANIM_animdata_freelist(&anim_data);
533
534 return ok;
535}
536
537/* ------------------- */
538
540{
541 bAnimContext ac;
542
543 /* Get editor data. */
544 if (ANIM_animdata_get_context(C, &ac) == 0) {
545 return OPERATOR_CANCELLED;
546 }
547
548 /* Copy keyframes. */
549 if (!copy_graph_keys(&ac)) {
550 BKE_report(op->reports, RPT_ERROR, "No keyframes copied to the internal clipboard");
551 return OPERATOR_CANCELLED;
552 }
553
554 /* Just return - no operator needed here (no changes). */
555 return OPERATOR_FINISHED;
556}
557
559{
560 /* Identifiers */
561 ot->name = "Copy Keyframes";
562 ot->idname = "GRAPH_OT_copy";
563 ot->description = "Copy selected keyframes to the internal clipboard";
564
565 /* API callbacks */
566 ot->exec = graphkeys_copy_exec;
568
569 /* Flags */
571}
572
574{
575 bAnimContext ac;
576
577 const eKeyPasteOffset offset_mode = eKeyPasteOffset(RNA_enum_get(op->ptr, "offset"));
578 const eKeyPasteValueOffset value_offset_mode = eKeyPasteValueOffset(
579 RNA_enum_get(op->ptr, "value_offset"));
580 const eKeyMergeMode merge_mode = eKeyMergeMode(RNA_enum_get(op->ptr, "merge"));
581 const bool flipped = RNA_boolean_get(op->ptr, "flipped");
582
583 /* Get editor data. */
584 if (ANIM_animdata_get_context(C, &ac) == 0) {
585 return OPERATOR_CANCELLED;
586 }
587
588 /* Ac.reports by default will be the global reports list, which won't show warnings. */
589 ac.reports = op->reports;
590
591 const eKeyPasteError kf_empty = paste_graph_keys(
592 &ac, offset_mode, value_offset_mode, merge_mode, flipped);
593 switch (kf_empty) {
595 break;
596
598 BKE_report(op->reports, RPT_ERROR, "No selected F-Curves to paste into");
599 return OPERATOR_CANCELLED;
600
602 BKE_report(op->reports, RPT_ERROR, "No data in the internal clipboard to paste");
603 return OPERATOR_CANCELLED;
604 }
605
606 /* Set notifier that keyframes have changed. */
608
609 return OPERATOR_FINISHED;
610}
611
612static std::string graphkeys_paste_get_description(bContext * /*C*/,
613 wmOperatorType * /*ot*/,
615{
616 /* Custom description if the 'flipped' option is used. */
617 if (RNA_boolean_get(ptr, "flipped")) {
618 return TIP_("Paste keyframes from mirrored bones if they exist");
619 }
620
621 /* Use the default description in the other cases. */
622 return "";
623}
624
626{
627 PropertyRNA *prop;
628
629 /* Identifiers */
630 ot->name = "Paste Keyframes";
631 ot->idname = "GRAPH_OT_paste";
632 ot->description =
633 "Paste keyframes from the internal clipboard for the selected channels, starting on the "
634 "current "
635 "frame";
636
637 /* API callbacks */
638
639 // ot->invoke = WM_operator_props_popup; /* better wait for graph redo panel */
640 ot->get_description = graphkeys_paste_get_description;
641 ot->exec = graphkeys_paste_exec;
643
644 /* Flags */
646
647 /* Props */
648 RNA_def_enum(ot->srna,
649 "offset",
652 "Frame Offset",
653 "Paste time offset of keys");
654 RNA_def_enum(ot->srna,
655 "value_offset",
658 "Value Offset",
659 "Paste keys with a value offset");
660 RNA_def_enum(ot->srna,
661 "merge",
664 "Type",
665 "Method of merging pasted keys and existing");
666 prop = RNA_def_boolean(
667 ot->srna, "flipped", false, "Flipped", "Paste keyframes from mirrored bones if they exist");
669}
670
672
673/* -------------------------------------------------------------------- */
676
678{
679 ListBase anim_data = {nullptr, nullptr};
680 int filter;
681 bool changed = false;
682
683 /* Filter data. */
687 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
688
689 /* Loop through filtered data and delete selected keys. */
690 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
691 changed |= duplicate_fcurve_keys((FCurve *)ale->key_data);
692
693 ale->update |= ANIM_UPDATE_DEFAULT;
694 }
695
696 ANIM_animdata_update(ac, &anim_data);
697 ANIM_animdata_freelist(&anim_data);
698
699 return changed;
700}
701
702/* ------------------- */
703
705{
706 bAnimContext ac;
707
708 /* Get editor data. */
709 if (ANIM_animdata_get_context(C, &ac) == 0) {
710 return OPERATOR_CANCELLED;
711 }
712
713 /* Duplicate keyframes. */
714 if (!duplicate_graph_keys(&ac)) {
715 return OPERATOR_CANCELLED;
716 }
717
718 /* Set notifier that keyframes have changed. */
720
721 return OPERATOR_FINISHED;
722}
723
725{
726 /* Identifiers */
727 ot->name = "Duplicate Keyframes";
728 ot->idname = "GRAPH_OT_duplicate";
729 ot->description = "Make a copy of all selected keyframes";
730
731 /* API callbacks */
734
735 /* Flags */
737
738 /* To give to transform. */
739 RNA_def_enum(ot->srna,
740 "mode",
743 "Mode",
744 "");
745}
746
748
749/* -------------------------------------------------------------------- */
752
754{
755 ListBase anim_data = {nullptr, nullptr};
756 int filter;
757 bool changed_final = false;
758
759 /* Filter data. */
763 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
764
765 /* Loop through filtered data and delete selected keys. */
766 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
767 FCurve *fcu = (FCurve *)ale->key_data;
768 AnimData *adt = ale->adt;
769 bool changed;
770
771 /* Delete selected keyframes only. */
772 changed = BKE_fcurve_delete_keys_selected(fcu);
773
774 if (changed) {
775 ale->update |= ANIM_UPDATE_DEFAULT;
776 changed_final = true;
777 }
778
779 /* Only delete curve too if it won't be doing anything anymore. */
780 if (BKE_fcurve_is_empty(fcu)) {
782 ale->key_data = nullptr;
783 }
784 }
785
786 ANIM_animdata_update(ac, &anim_data);
787 ANIM_animdata_freelist(&anim_data);
788
789 return changed_final;
790}
791
792/* ------------------- */
793
795{
796 bAnimContext ac;
797
798 /* Get editor data. */
799 if (ANIM_animdata_get_context(C, &ac) == 0) {
800 return OPERATOR_CANCELLED;
801 }
802
803 /* Delete keyframes. */
804 if (!delete_graph_keys(&ac)) {
805 return OPERATOR_CANCELLED;
806 }
807
808 /* Set notifier that keyframes have changed. */
810
811 return OPERATOR_FINISHED;
812}
813
815 wmOperator *op,
816 const wmEvent * /*event*/)
817{
818 if (RNA_boolean_get(op->ptr, "confirm")) {
820 op,
821 IFACE_("Delete selected keyframes?"),
822 nullptr,
823 IFACE_("Delete"),
825 false);
826 }
827 return graphkeys_delete_exec(C, op);
828}
829
831{
832 /* Identifiers */
833 ot->name = "Delete Keyframes";
834 ot->idname = "GRAPH_OT_delete";
835 ot->description = "Remove all selected keyframes";
836
837 /* API callbacks */
838 ot->invoke = graphkeys_delete_invoke;
841
842 /* Flags */
845}
846
848
849/* -------------------------------------------------------------------- */
852
853static void clean_graph_keys(bAnimContext *ac, float thresh, bool clean_chan)
854{
855 ListBase anim_data = {nullptr, nullptr};
856 int filter;
857
858 /* Filter data. */
861 if (clean_chan) {
863 }
865 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
866
867 const bool only_selected_keys = !clean_chan;
868 /* Loop through filtered data and clean curves. */
869 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
870 clean_fcurve(ale, thresh, clean_chan, only_selected_keys);
871
872 ale->update |= ANIM_UPDATE_DEFAULT;
873 }
874
875 ANIM_animdata_update(ac, &anim_data);
876 ANIM_animdata_freelist(&anim_data);
877}
878
879/* ------------------- */
880
882{
883 bAnimContext ac;
884 float thresh;
885 bool clean_chan;
886
887 /* Get editor data. */
888 if (ANIM_animdata_get_context(C, &ac) == 0) {
889 return OPERATOR_CANCELLED;
890 }
891
892 /* Get cleaning threshold. */
893 thresh = RNA_float_get(op->ptr, "threshold");
894 clean_chan = RNA_boolean_get(op->ptr, "channels");
895 /* Clean keyframes. */
896 clean_graph_keys(&ac, thresh, clean_chan);
897
898 /* Set notifier that keyframes have changed. */
900
901 return OPERATOR_FINISHED;
902}
903
905{
906 /* Identifiers */
907 ot->name = "Clean Keyframes";
908 ot->idname = "GRAPH_OT_clean";
909 ot->description = "Simplify F-Curves by removing closely spaced keyframes";
910
911 /* API callbacks */
912 // ot->invoke = ???; /* XXX we need that number popup for this! */
913 ot->exec = graphkeys_clean_exec;
915
916 /* Flags */
918
919 /* Properties */
920 ot->prop = RNA_def_float(
921 ot->srna, "threshold", 0.001f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 1000.0f);
922 RNA_def_boolean(ot->srna, "channels", false, "Channels", "");
923}
924
926
927/* -------------------------------------------------------------------- */
932
933/* Bake each F-Curve into a set of samples. */
934static void convert_keys_to_samples(bAnimContext *ac, int start, int end)
935{
936 ListBase anim_data = {nullptr, nullptr};
937 int filter;
938
939 /* Filter data. */
943 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
944
945 /* Loop through filtered data and add keys between selected keyframes on every frame. */
946 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
947 FCurve *fcu = (FCurve *)ale->key_data;
948 ChannelDriver *driver = fcu->driver;
949
950 /* Disable driver so that it don't muck up the sampling process. */
951 fcu->driver = nullptr;
952
953 /* Create samples. */
954 fcurve_store_samples(fcu, nullptr, start, end, fcurve_samplingcb_evalcurve);
955
956 /* Restore driver. */
957 fcu->driver = driver;
958
959 ale->update |= ANIM_UPDATE_DEPS;
960 }
961
962 ANIM_animdata_update(ac, &anim_data);
963 ANIM_animdata_freelist(&anim_data);
964}
965
966/* ------------------- */
967
969{
970 bAnimContext ac;
971 Scene *scene = nullptr;
972 int start, end;
973
974 /* Get editor data. */
975 if (ANIM_animdata_get_context(C, &ac) == 0) {
976 return OPERATOR_CANCELLED;
977 }
978
979 /* For now, init start/end from preview-range extents. */
980 /* TODO: add properties for this. (Joshua Leung 2009) */
981 scene = ac.scene;
982 start = PSFRA;
983 end = PEFRA;
984
985 /* Sample keyframes. */
986 convert_keys_to_samples(&ac, start, end);
987
988 /* Set notifier that keyframes have changed. */
989 /* NOTE: some distinction between order/number of keyframes and type should be made? */
991
992 return OPERATOR_FINISHED;
993}
994
996{
997 /* Identifiers */
998 ot->name = "Keys to Samples";
999 ot->idname = "GRAPH_OT_keys_to_samples";
1000 ot->description =
1001 "Convert selected channels to an uneditable set of samples to save storage space";
1002
1003 /* API callbacks */
1006
1007 /* Flags */
1008 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1009
1010 /* TODO: add props for start/end frames (Joshua Leung 2009) */
1011}
1012
1014
1015/* -------------------------------------------------------------------- */
1020
1021/* Convert F-Points into F-Curves. */
1022static void convert_samples_to_keys(bAnimContext *ac, int start, int end)
1023{
1024 ListBase anim_data = {nullptr, nullptr};
1025
1026 /* Filter data. */
1030 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
1031
1032 /* Loop through filtered data and add keys between selected keyframes on every frame. */
1033 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1034 FCurve *fcu = (FCurve *)ale->key_data;
1035
1036 fcurve_samples_to_keyframes(fcu, start, end);
1037
1038 ale->update |= ANIM_UPDATE_DEPS;
1039 }
1040
1041 ANIM_animdata_update(ac, &anim_data);
1042 ANIM_animdata_freelist(&anim_data);
1043}
1044
1045/* ------------------- */
1046
1048{
1049 bAnimContext ac;
1050 Scene *scene = nullptr;
1051 int start, end;
1052
1053 /* Get editor data. */
1054 if (ANIM_animdata_get_context(C, &ac) == 0) {
1055 return OPERATOR_CANCELLED;
1056 }
1057
1058 scene = ac.scene;
1059 start = PSFRA;
1060 end = PEFRA;
1061
1062 convert_samples_to_keys(&ac, start, end);
1063
1064 /* Set notifier that keyframes have changed. */
1065 /* NOTE: some distinction between order/number of keyframes and type should be made? */
1067
1068 return OPERATOR_FINISHED;
1069}
1070
1072{
1073 /* Identifiers */
1074 ot->name = "Samples to Keys";
1075 ot->idname = "GRAPH_OT_samples_to_keys";
1076 ot->description = "Convert selected channels from samples to keyframes";
1077
1078 /* API callbacks */
1081
1082 /* Flags */
1083 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1084}
1085
1086#ifdef WITH_AUDASPACE
1087
1089
1090/* -------------------------------------------------------------------- */
1095
1096/* ------------------- */
1097
1098/* Custom data storage passed to the F-Sample-ing function,
1099 * which provides the necessary info for baking the sound.
1100 */
1101struct tSoundBakeInfo {
1102 float *samples;
1103 int length;
1104 int cfra;
1105};
1106
1107/* ------------------- */
1108
1109/* Sampling callback used to determine the value from the sound to
1110 * save in the F-Curve at the specified frame.
1111 */
1112static float fcurve_samplingcb_sound(FCurve * /*fcu*/, void *data, float evaltime)
1113{
1114 tSoundBakeInfo *sbi = (tSoundBakeInfo *)data;
1115
1116 int position = evaltime - sbi->cfra;
1117 if ((position < 0) || (position >= sbi->length)) {
1118 return 0.0f;
1119 }
1120
1121 return sbi->samples[position];
1122}
1123
1124/* ------------------- */
1125
1127{
1128 bAnimContext ac;
1129 ListBase anim_data = {nullptr, nullptr};
1130 int filter;
1131
1132 tSoundBakeInfo sbi;
1133 Scene *scene = nullptr;
1134 int start, end;
1135
1136 char filepath[FILE_MAX];
1137
1138 /* Get editor data. */
1139 if (ANIM_animdata_get_context(C, &ac) == 0) {
1140 return OPERATOR_CANCELLED;
1141 }
1142
1143 RNA_string_get(op->ptr, "filepath", filepath);
1144
1145 if (!BLI_is_file(filepath)) {
1146 BKE_reportf(op->reports, RPT_ERROR, "File not found '%s'", filepath);
1147 return OPERATOR_CANCELLED;
1148 }
1149
1150 scene = ac.scene; /* Current scene. */
1151
1152 /* Store necessary data for the baking steps. */
1153 sbi.samples = AUD_readSoundBuffer(filepath,
1154 RNA_float_get(op->ptr, "low"),
1155 RNA_float_get(op->ptr, "high"),
1156 RNA_float_get(op->ptr, "attack"),
1157 RNA_float_get(op->ptr, "release"),
1158 RNA_float_get(op->ptr, "threshold"),
1159 RNA_boolean_get(op->ptr, "use_accumulate"),
1160 RNA_boolean_get(op->ptr, "use_additive"),
1161 RNA_boolean_get(op->ptr, "use_square"),
1162 RNA_float_get(op->ptr, "sthreshold"),
1163 scene->frames_per_second(),
1164 &sbi.length,
1165 0);
1166
1167 if (sbi.samples == nullptr) {
1168 BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
1169 return OPERATOR_CANCELLED;
1170 }
1171
1172 /* Determine extents of the baking. */
1173 sbi.cfra = start = scene->r.cfra;
1174 end = scene->r.cfra + sbi.length - 1;
1175
1176 /* Filter anim channels. */
1180 &ac, &anim_data, eAnimFilter_Flags(filter), ac.data, eAnimCont_Types(ac.datatype));
1181
1182 /* Loop through all selected F-Curves, replacing its data with the sound samples. */
1183 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1184 FCurve *fcu = (FCurve *)ale->key_data;
1185
1186 /* Sample the sound. */
1187 fcurve_store_samples(fcu, &sbi, start, end, fcurve_samplingcb_sound);
1188
1189 ale->update |= ANIM_UPDATE_DEFAULT;
1190 }
1191
1192 /* Free sample data. */
1193 free(sbi.samples);
1194
1195 /* Validate keyframes after editing. */
1196 ANIM_animdata_update(&ac, &anim_data);
1197 ANIM_animdata_freelist(&anim_data);
1198
1199 /* Set notifier that 'keyframes' have changed. */
1201
1202 return OPERATOR_FINISHED;
1203}
1204
1205#else /* WITH_AUDASPACE */
1206
1208{
1209 BKE_report(op->reports, RPT_ERROR, "Compiled without sound support");
1210
1211 return OPERATOR_CANCELLED;
1212}
1213
1214#endif /* WITH_AUDASPACE */
1215
1217 wmOperator *op,
1218 const wmEvent *event)
1219{
1220 bAnimContext ac;
1221
1222 /* Verify editor data. */
1223 if (ANIM_animdata_get_context(C, &ac) == 0) {
1224 return OPERATOR_CANCELLED;
1225 }
1226
1227 return WM_operator_filesel(C, op, event);
1228}
1229
1231{
1232 /* Identifiers */
1233 ot->name = "Sound to Samples";
1234 ot->idname = "GRAPH_OT_sound_to_samples";
1235 ot->description = "Bakes a sound wave to samples on selected channels";
1236
1237 /* API callbacks */
1241
1242 /* Flags */
1243 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1244
1245 /* Properties */
1253 RNA_def_float(ot->srna,
1254 "low",
1255 0.0f,
1256 0.0,
1257 100000.0,
1258 "Lowest Frequency",
1259 "Cutoff frequency of a high-pass filter that is applied to the audio data",
1260 0.1,
1261 1000.00);
1262 RNA_def_float(ot->srna,
1263 "high",
1264 100000.0,
1265 0.0,
1266 100000.0,
1267 "Highest Frequency",
1268 "Cutoff frequency of a low-pass filter that is applied to the audio data",
1269 0.1,
1270 1000.00);
1271 RNA_def_float(ot->srna,
1272 "attack",
1273 0.005,
1274 0.0,
1275 2.0,
1276 "Attack Time",
1277 "Value for the envelope calculation that tells how fast the envelope can rise "
1278 "(the lower the value the steeper it can rise)",
1279 0.01,
1280 0.1);
1281 RNA_def_float(ot->srna,
1282 "release",
1283 0.2,
1284 0.0,
1285 5.0,
1286 "Release Time",
1287 "Value for the envelope calculation that tells how fast the envelope can fall "
1288 "(the lower the value the steeper it can fall)",
1289 0.01,
1290 0.2);
1291 RNA_def_float(ot->srna,
1292 "threshold",
1293 0.0,
1294 0.0,
1295 1.0,
1296 "Threshold",
1297 "Minimum amplitude value needed to influence the envelope",
1298 0.01,
1299 0.1);
1300 RNA_def_boolean(ot->srna,
1301 "use_accumulate",
1302 false,
1303 "Accumulate",
1304 "Only the positive differences of the envelope amplitudes are summarized to "
1305 "produce the output");
1306 RNA_def_boolean(ot->srna,
1307 "use_additive",
1308 false,
1309 "Additive",
1310 "The amplitudes of the envelope are summarized (or, when Accumulate is enabled, "
1311 "both positive and negative differences are accumulated)");
1312 RNA_def_boolean(ot->srna,
1313 "use_square",
1314 false,
1315 "Square",
1316 "The output is a square curve (negative values always result in -1, and "
1317 "positive ones in 1)");
1318 RNA_def_float(ot->srna,
1319 "sthreshold",
1320 0.1,
1321 0.0,
1322 1.0,
1323 "Square Threshold",
1324 "Square only: all values with an absolute amplitude lower than that result in 0",
1325 0.01,
1326 0.1);
1327}
1328
1330
1331/* -------------------------------------------------------------------- */
1337
1338/* Evaluates the curves between each selected keyframe on each frame, and keys the value. */
1340{
1341 ListBase anim_data = {nullptr, nullptr};
1342 int filter;
1343
1344 /* filter data */
1348 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
1349
1350 /* Loop through filtered data and add keys between selected keyframes on every frame. */
1351 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1353
1354 ale->update |= ANIM_UPDATE_DEPS;
1355 }
1356
1357 ANIM_animdata_update(ac, &anim_data);
1358 ANIM_animdata_freelist(&anim_data);
1359}
1360
1361/* ------------------- */
1362
1364{
1365 bAnimContext ac;
1366
1367 /* Get editor data. */
1368 if (ANIM_animdata_get_context(C, &ac) == 0) {
1369 return OPERATOR_CANCELLED;
1370 }
1371
1372 /* Bake keyframes. */
1373 bake_graph_keys(&ac);
1374
1375 /* Set notifier that keyframes have changed. */
1377
1378 return OPERATOR_FINISHED;
1379}
1380
1382{
1383 /* Identifiers */
1384 ot->name = "Bake Keyframes";
1385 ot->idname = "GRAPH_OT_bake_keys";
1386 ot->description = "Add keyframes on every frame between the selected keyframes";
1387
1388 /* API callbacks */
1389 ot->exec = graphkeys_bake_exec;
1391
1392 /* Flags */
1393 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1394}
1395
1397
1398/* ************************************************************************** */
1399/* EXTRAPOLATION MODE AND KEYFRAME HANDLE SETTINGS */
1400
1401/* -------------------------------------------------------------------- */
1404
1405/* Defines for make/clear cyclic extrapolation tools. */
1406#define MAKE_CYCLIC_EXPO -1
1407#define CLEAR_CYCLIC_EXPO -2
1408
1409/* Defines for set extrapolation-type for selected keyframes tool. */
1412 "CONSTANT",
1413 0,
1414 "Constant Extrapolation",
1415 "Values on endpoint keyframes are held"},
1417 "LINEAR",
1418 0,
1419 "Linear Extrapolation",
1420 "Straight-line slope of end segments are extended past the endpoint keyframes"},
1421
1423 "MAKE_CYCLIC",
1424 0,
1425 "Make Cyclic (F-Modifier)",
1426 "Add Cycles F-Modifier if one does not exist already"},
1428 "CLEAR_CYCLIC",
1429 0,
1430 "Clear Cyclic (F-Modifier)",
1431 "Remove Cycles F-Modifier if not needed anymore"},
1432 {0, nullptr, 0, nullptr, nullptr},
1433};
1434
1435/* This function is responsible for setting extrapolation mode for keyframes. */
1436static void setexpo_graph_keys(bAnimContext *ac, short mode)
1437{
1438 ListBase anim_data = {nullptr, nullptr};
1439 int filter;
1440
1441 /* Filter data. */
1445 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
1446
1447 /* Loop through setting mode per F-Curve. */
1448 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1449 FCurve *fcu = (FCurve *)ale->data;
1450
1451 if (mode >= 0) {
1452 /* Just set mode setting. */
1453 fcu->extend = mode;
1454
1455 ale->update |= ANIM_UPDATE_HANDLES;
1456 }
1457 else {
1458 /* Shortcuts for managing Cycles F-Modifiers to make it easier to toggle cyclic animation
1459 * without having to go through FModifier UI in Graph Editor to do so.
1460 */
1461 if (mode == MAKE_CYCLIC_EXPO) {
1462 /* Only add if one doesn't exist. */
1464 /* TODO: add some more preset versions which set different extrapolation options?
1465 * (Joshua Leung 2011) */
1467 }
1468 }
1469 else if (mode == CLEAR_CYCLIC_EXPO) {
1470 /* Remove all the modifiers fitting this description. */
1471 FModifier *fcm, *fcn = nullptr;
1472
1473 for (fcm = static_cast<FModifier *>(fcu->modifiers.first); fcm; fcm = fcn) {
1474 fcn = fcm->next;
1475
1476 if (fcm->type == FMODIFIER_TYPE_CYCLES) {
1477 remove_fmodifier(&fcu->modifiers, fcm);
1478 }
1479 }
1480 }
1481 }
1482
1483 ale->update |= ANIM_UPDATE_DEPS;
1484 }
1485
1486 ANIM_animdata_update(ac, &anim_data);
1487 ANIM_animdata_freelist(&anim_data);
1488}
1489
1490/* ------------------- */
1491
1493{
1494 bAnimContext ac;
1495 short mode;
1496
1497 /* Get editor data. */
1498 if (ANIM_animdata_get_context(C, &ac) == 0) {
1499 return OPERATOR_CANCELLED;
1500 }
1501
1502 /* Get handle setting mode. */
1503 mode = RNA_enum_get(op->ptr, "type");
1504
1505 /* Set handle type. */
1506 setexpo_graph_keys(&ac, mode);
1507
1508 /* Set notifier that keyframe properties have changed. */
1510
1511 return OPERATOR_FINISHED;
1512}
1513
1515{
1516 /* Identifiers */
1517 ot->name = "Set F-Curve Extrapolation";
1518 ot->idname = "GRAPH_OT_extrapolation_type";
1519 ot->description = "Set extrapolation mode for selected F-Curves";
1520
1521 /* API callbacks */
1522 ot->invoke = WM_menu_invoke;
1523 ot->exec = graphkeys_expo_exec;
1525
1526 /* Flags */
1527 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1528
1529 /* Id-props */
1530 ot->prop = RNA_def_enum(ot->srna, "type", prop_graphkeys_expo_types, 0, "Type", "");
1531}
1532
1534
1535/* -------------------------------------------------------------------- */
1538
1539/* This function is responsible for setting interpolation mode for keyframes. */
1540static void setipo_graph_keys(bAnimContext *ac, short mode)
1541{
1542 ListBase anim_data = {nullptr, nullptr};
1543 int filter;
1545
1546 /* Filter data. */
1550 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
1551
1552 /* Loop through setting BezTriple interpolation
1553 * NOTE: we do not supply KeyframeEditData to the looper yet.
1554 * Currently that's not necessary here.
1555 */
1556 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1558 nullptr, static_cast<FCurve *>(ale->key_data), nullptr, set_cb, BKE_fcurve_handles_recalc);
1559
1560 ale->update |= ANIM_UPDATE_DEFAULT_NOHANDLES;
1561 }
1562
1563 ANIM_animdata_update(ac, &anim_data);
1564 ANIM_animdata_freelist(&anim_data);
1565}
1566
1567/* ------------------- */
1568
1570{
1571 bAnimContext ac;
1572 short mode;
1573
1574 /* Get editor data. */
1575 if (ANIM_animdata_get_context(C, &ac) == 0) {
1576 return OPERATOR_CANCELLED;
1577 }
1578
1579 /* Get handle setting mode. */
1580 mode = RNA_enum_get(op->ptr, "type");
1581
1582 /* Set handle type. */
1583 setipo_graph_keys(&ac, mode);
1584
1585 /* Set notifier that keyframe properties have changed. */
1587
1588 return OPERATOR_FINISHED;
1589}
1590
1592{
1593 /* Identifiers */
1594 ot->name = "Set Keyframe Interpolation";
1595 ot->idname = "GRAPH_OT_interpolation_type";
1596 ot->description =
1597 "Set interpolation mode for the F-Curve segments starting from the selected keyframes";
1598
1599 /* API callbacks */
1600 ot->invoke = WM_menu_invoke;
1601 ot->exec = graphkeys_ipo_exec;
1603
1604 /* Flags */
1605 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1606
1607 /* Id-props */
1608 ot->prop = RNA_def_enum(
1609 ot->srna, "type", rna_enum_beztriple_interpolation_mode_items, 0, "Type", "");
1611}
1612
1614
1615/* -------------------------------------------------------------------- */
1618
1619static void seteasing_graph_keys(bAnimContext *ac, short mode)
1620{
1621 ListBase anim_data = {nullptr, nullptr};
1622 int filter;
1624
1625 /* Filter data. */
1629 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
1630
1631 /* Loop through setting BezTriple easing.
1632 * NOTE: we do not supply KeyframeEditData to the looper yet.
1633 * Currently that's not necessary here.
1634 */
1635 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1637 nullptr, static_cast<FCurve *>(ale->key_data), nullptr, set_cb, BKE_fcurve_handles_recalc);
1638
1639 ale->update |= ANIM_UPDATE_DEFAULT_NOHANDLES;
1640 }
1641
1642 ANIM_animdata_update(ac, &anim_data);
1643 ANIM_animdata_freelist(&anim_data);
1644}
1645
1647{
1648 bAnimContext ac;
1649 short mode;
1650
1651 /* Get editor data. */
1652 if (ANIM_animdata_get_context(C, &ac) == 0) {
1653 return OPERATOR_CANCELLED;
1654 }
1655
1656 /* Get handle setting mode. */
1657 mode = RNA_enum_get(op->ptr, "type");
1658
1659 /* Set handle type. */
1660 seteasing_graph_keys(&ac, mode);
1661
1662 /* Set notifier that keyframe properties have changed. */
1664
1665 return OPERATOR_FINISHED;
1666}
1667
1669{
1670 /* Identifiers */
1671 ot->name = "Set Keyframe Easing Type";
1672 ot->idname = "GRAPH_OT_easing_type";
1673 ot->description =
1674 "Set easing type for the F-Curve segments starting from the selected keyframes";
1675
1676 /* API callbacks */
1677 ot->invoke = WM_menu_invoke;
1678 ot->exec = graphkeys_easing_exec;
1680
1681 /* Flags */
1682 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1683
1684 /* Id-props */
1685 ot->prop = RNA_def_enum(
1686 ot->srna, "type", rna_enum_beztriple_interpolation_easing_items, 0, "Type", "");
1687}
1688
1690
1691/* -------------------------------------------------------------------- */
1694
1695/* This function is responsible for setting handle-type of selected keyframes. */
1696static void sethandles_graph_keys(bAnimContext *ac, short mode)
1697{
1698 ListBase anim_data = {nullptr, nullptr};
1699 int filter;
1700
1703
1704 /* Filter data. */
1708 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
1709
1710 /* Loop through setting flags for handles.
1711 * NOTE: we do not supply KeyframeEditData to the looper yet.
1712 * Currently that's not necessary here.
1713 */
1714 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1715 FCurve *fcu = (FCurve *)ale->key_data;
1716
1717 /* Any selected keyframes for editing? */
1718 if (ANIM_fcurve_keyframes_loop(nullptr, fcu, nullptr, sel_cb, nullptr)) {
1719 /* Change type of selected handles. */
1720 ANIM_fcurve_keyframes_loop(nullptr, fcu, nullptr, edit_cb, BKE_fcurve_handles_recalc);
1721
1722 ale->update |= ANIM_UPDATE_DEFAULT;
1723 }
1724 }
1725
1726 ANIM_animdata_update(ac, &anim_data);
1727 ANIM_animdata_freelist(&anim_data);
1728}
1729/* ------------------- */
1730
1732{
1733 bAnimContext ac;
1734 short mode;
1735
1736 /* Get editor data. */
1737 if (ANIM_animdata_get_context(C, &ac) == 0) {
1738 return OPERATOR_CANCELLED;
1739 }
1740
1741 /* Get handle setting mode. */
1742 mode = RNA_enum_get(op->ptr, "type");
1743
1744 /* Set handle type. */
1745 sethandles_graph_keys(&ac, mode);
1746
1747 /* Set notifier that keyframe properties have changed. */
1749
1750 return OPERATOR_FINISHED;
1751}
1752
1754{
1755 /* Identifiers */
1756 ot->name = "Set Keyframe Handle Type";
1757 ot->idname = "GRAPH_OT_handle_type";
1758 ot->description = "Set type of handle for selected keyframes";
1759
1760 /* API callbacks */
1761 ot->invoke = WM_menu_invoke;
1764
1765 /* Flags */
1766 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1767
1768 /* Id-props */
1769 ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_keyframe_handle_type_items, 0, "Type", "");
1770}
1771
1773
1774/* ************************************************************************** */
1775/* EULER FILTER */
1776
1777/* -------------------------------------------------------------------- */
1785
1786/* Set of three euler-rotation F-Curves. */
1797
1798static bool keyframe_time_differs(BezTriple *keyframes[3])
1799{
1800 const float precision = 1e-5;
1801 return fabs(keyframes[0]->vec[1][0] - keyframes[1]->vec[1][0]) > precision ||
1802 fabs(keyframes[1]->vec[1][0] - keyframes[2]->vec[1][0]) > precision ||
1803 fabs(keyframes[0]->vec[1][0] - keyframes[2]->vec[1][0]) > precision;
1804}
1805
1806/* Find groups of `rotation_euler` channels. */
1808 const ListBase /*bAnimListElem*/ *anim_data, ReportList *reports, int *r_num_groups)
1809{
1810 ListBase euler_groups = {nullptr, nullptr};
1811 tEulerFilter *euf = nullptr;
1812 *r_num_groups = 0;
1813
1814 LISTBASE_FOREACH (bAnimListElem *, ale, anim_data) {
1815 FCurve *const fcu = (FCurve *)ale->data;
1816
1817 /* Check if this is an appropriate F-Curve:
1818 * - Only rotation curves.
1819 * - For pose-channel curves, make sure we're only using the euler curves.
1820 */
1821 if (strstr(fcu->rna_path, "rotation_euler") == nullptr) {
1822 continue;
1823 }
1824 if (ELEM(fcu->array_index, 0, 1, 2) == 0) {
1825 BKE_reportf(reports,
1827 "Euler Rotation F-Curve has invalid index (ID='%s', Path='%s', Index=%d)",
1828 (ale->id) ? ale->id->name : RPT_("<No ID>"),
1829 fcu->rna_path,
1830 fcu->array_index);
1831 continue;
1832 }
1833
1834 /* Assume that this animation channel will be touched by the Euler filter. Doing this here
1835 * saves another loop over the animation data. */
1836 ale->update |= ANIM_UPDATE_DEFAULT;
1837
1838 /* Optimization: assume that XYZ curves will always be stored consecutively,
1839 * so if the paths or the ID's don't match up, then a curve needs to be added
1840 * to a new group.
1841 */
1842 if ((euf) && (euf->id == ale->id) && STREQ(euf->rna_path, fcu->rna_path)) {
1843 /* This should be fine to add to the existing group then. */
1844 euf->fcurves[fcu->array_index] = fcu;
1845 continue;
1846 }
1847
1848 /* Just add to a new block. */
1849 euf = MEM_callocN<tEulerFilter>("tEulerFilter");
1850 BLI_addtail(&euler_groups, euf);
1851 ++*r_num_groups;
1852
1853 euf->id = ale->id;
1854 /* This should be safe, since we're only using it for a short time. */
1855 euf->rna_path = fcu->rna_path;
1856 euf->fcurves[fcu->array_index] = fcu;
1857 }
1858
1859 return euler_groups;
1860}
1861
1862/* Perform discontinuity filter based on conversion to matrix and back.
1863 * Return true if the curves were filtered (which may have been a no-op), false otherwise. */
1865{
1866 /* Sanity check: ensure that there are enough F-Curves to work on in this group. */
1867 if (ELEM(nullptr, euf->fcurves[0], euf->fcurves[1], euf->fcurves[2])) {
1868 /* Report which components are missing. */
1869 BKE_reportf(reports,
1870 RPT_INFO,
1871 "Missing %s%s%s component(s) of euler rotation for ID='%s' and RNA-Path='%s'",
1872 (euf->fcurves[0] == nullptr) ? "X" : "",
1873 (euf->fcurves[1] == nullptr) ? "Y" : "",
1874 (euf->fcurves[2] == nullptr) ? "Z" : "",
1875 euf->id->name,
1876 euf->rna_path);
1877 return false;
1878 }
1879
1880 FCurve *fcu_rot_x = euf->fcurves[0];
1881 FCurve *fcu_rot_y = euf->fcurves[1];
1882 FCurve *fcu_rot_z = euf->fcurves[2];
1883 if (fcu_rot_x->totvert != fcu_rot_y->totvert || fcu_rot_y->totvert != fcu_rot_z->totvert) {
1884 BKE_reportf(reports,
1885 RPT_INFO,
1886 "XYZ rotations not equally keyed for ID='%s' and RNA-Path='%s'",
1887 euf->id->name,
1888 euf->rna_path);
1889 return false;
1890 }
1891
1892 if (fcu_rot_x->totvert < 2) {
1893 /* Empty curves and single keyframes are trivially "filtered". */
1894 return false;
1895 }
1896
1897 float filtered_euler[3] = {
1898 fcu_rot_x->bezt[0].vec[1][1],
1899 fcu_rot_y->bezt[0].vec[1][1],
1900 fcu_rot_z->bezt[0].vec[1][1],
1901 };
1902
1903 for (int keyframe_index = 1; keyframe_index < fcu_rot_x->totvert; ++keyframe_index) {
1904 BezTriple *keyframes[3] = {
1905 &fcu_rot_x->bezt[keyframe_index],
1906 &fcu_rot_y->bezt[keyframe_index],
1907 &fcu_rot_z->bezt[keyframe_index],
1908 };
1909
1910 if (keyframe_time_differs(keyframes)) {
1911 /* The X-coordinates of the keyframes are different, so we cannot correct this key. */
1912 continue;
1913 }
1914
1915 const float unfiltered_euler[3] = {
1916 keyframes[0]->vec[1][1],
1917 keyframes[1]->vec[1][1],
1918 keyframes[2]->vec[1][1],
1919 };
1920
1921 /* The conversion back from matrix to Euler angles actually performs the filtering. */
1922 float matrix[3][3];
1923 eul_to_mat3(matrix, unfiltered_euler);
1924 mat3_normalized_to_compatible_eul(filtered_euler, filtered_euler, matrix);
1925
1926 /* TODO(Sybren): it might be a nice touch to compare `filtered_euler` with `unfiltered_euler`,
1927 * to see if there was actually a change. This could improve reporting for the artist. */
1928
1929 BKE_fcurve_keyframe_move_value_with_handles(keyframes[0], filtered_euler[0]);
1930 BKE_fcurve_keyframe_move_value_with_handles(keyframes[1], filtered_euler[1]);
1931 BKE_fcurve_keyframe_move_value_with_handles(keyframes[2], filtered_euler[2]);
1932 }
1933
1934 return true;
1935}
1936
1937/* Remove 360-degree flips from a single FCurve.
1938 * Return true if the curve was modified, false otherwise. */
1940{
1941 /* Simple method: just treat any difference between keys of greater than 180 degrees as being a
1942 * flip. */
1943 BezTriple *bezt, *prev;
1944 uint i;
1945
1946 /* Skip if not enough verts to do a decent analysis. */
1947 if (fcu->totvert <= 2) {
1948 return false;
1949 }
1950
1951 /* Skip baked FCurves. */
1952 if (fcu->bezt == nullptr) {
1953 return false;
1954 }
1955
1956 /* `prev` follows bezt, bezt = "current" point to be fixed. */
1957 /* Our method depends on determining a "difference" from the previous vert. */
1958 bool is_modified = false;
1959 for (i = 1, prev = fcu->bezt, bezt = fcu->bezt + 1; i < fcu->totvert; i++, prev = bezt++) {
1960 const float sign = (prev->vec[1][1] > bezt->vec[1][1]) ? 1.0f : -1.0f;
1961
1962 /* >= 180 degree flip? */
1963 if ((sign * (prev->vec[1][1] - bezt->vec[1][1])) < float(M_PI)) {
1964 continue;
1965 }
1966
1967 /* 360 degrees to add/subtract frame value until difference
1968 * is acceptably small that there's no more flip. */
1969 const float fac = sign * 2.0f * float(M_PI);
1970
1971 while ((sign * (prev->vec[1][1] - bezt->vec[1][1])) >= float(M_PI)) {
1972 bezt->vec[0][1] += fac;
1973 bezt->vec[1][1] += fac;
1974 bezt->vec[2][1] += fac;
1975 }
1976
1977 is_modified = true;
1978 }
1979
1980 return is_modified;
1981}
1982
1983static void euler_filter_perform_filter(ListBase /*tEulerFilter*/ *eulers,
1984 ReportList *reports,
1985 int *r_curves_filtered,
1986 int *r_curves_seen)
1987{
1988 *r_curves_filtered = 0;
1989 *r_curves_seen = 0;
1990
1991 LISTBASE_FOREACH (tEulerFilter *, euf, eulers) {
1992 int curves_filtered_this_group = 0;
1993
1994 if (euler_filter_multi_channel(euf, reports)) {
1995 curves_filtered_this_group = 3;
1996 }
1997
1998 for (int channel_index = 0; channel_index < 3; channel_index++) {
1999 FCurve *fcu = euf->fcurves[channel_index];
2000 if (fcu == nullptr) {
2001 continue;
2002 }
2003 ++*r_curves_seen;
2004
2005 if (euler_filter_single_channel(fcu)) {
2006 ++curves_filtered_this_group;
2007 }
2008 }
2009
2010 *r_curves_filtered += min_ii(3, curves_filtered_this_group);
2011 }
2012}
2013
2015{
2016 /* Get editor data. */
2017 bAnimContext ac;
2018 if (ANIM_animdata_get_context(C, &ac) == 0) {
2019 return OPERATOR_CANCELLED;
2020 }
2021
2022 /* The process is done in two passes:
2023 * 1) Sets of three related rotation curves are identified from the selected channels,
2024 * and are stored as a single 'operation unit' for the next step.
2025 * 2) Each set of three F-Curves is processed for each keyframe, with the values being
2026 * processed as necessary.
2027 */
2028
2029 /* Step 1: extract only the rotation f-curves. */
2032 ListBase anim_data = {nullptr, nullptr};
2034 &ac, &anim_data, eAnimFilter_Flags(filter), ac.data, eAnimCont_Types(ac.datatype));
2035
2036 int groups = 0;
2037 ListBase eulers = euler_filter_group_channels(&anim_data, op->reports, &groups);
2038 BLI_assert(BLI_listbase_count(&eulers) == groups);
2039
2040 if (groups == 0) {
2041 ANIM_animdata_freelist(&anim_data);
2042 BKE_report(op->reports, RPT_WARNING, "No Euler Rotation F-Curves to fix up");
2043 return OPERATOR_CANCELLED;
2044 }
2045
2046 /* Step 2: go through each set of curves, processing the values at each keyframe.
2047 * - It is assumed that there must be a full set of keyframes at each keyframe position.
2048 */
2049 int curves_filtered;
2050 int curves_seen;
2051 euler_filter_perform_filter(&eulers, op->reports, &curves_filtered, &curves_seen);
2052
2053 BLI_freelistN(&eulers);
2054 ANIM_animdata_update(&ac, &anim_data);
2055 ANIM_animdata_freelist(&anim_data);
2056
2057 if (curves_filtered == 0) {
2058 if (curves_seen < 3) {
2059 /* Showing the entire error message makes no sense when the artist is only trying to filter
2060 * one or two curves. */
2061 BKE_report(op->reports, RPT_WARNING, "No Euler Rotations could be corrected");
2062 }
2063 else {
2064 BKE_report(op->reports,
2065 RPT_ERROR,
2066 "No Euler Rotations could be corrected, ensure each rotation has keys for all "
2067 "components, "
2068 "and that F-Curves for these are in consecutive XYZ order and selected");
2069 }
2070 return OPERATOR_CANCELLED;
2071 }
2072
2073 if (curves_filtered != curves_seen) {
2074 BLI_assert(curves_filtered < curves_seen);
2075 BKE_reportf(op->reports,
2076 RPT_INFO,
2077 "%d of %d rotation channels were filtered (see the Info window for details)",
2078 curves_filtered,
2079 curves_seen);
2080 }
2081 else if (curves_seen == 1) {
2082 BKE_report(op->reports, RPT_INFO, "The rotation channel was filtered");
2083 }
2084 else {
2085 BKE_reportf(op->reports, RPT_INFO, "All %d rotation channels were filtered", curves_seen);
2086 }
2087
2088 /* Set notifier that keyframes have changed. */
2090
2091 /* Done at last. */
2092 return OPERATOR_FINISHED;
2093}
2094
2096{
2097 /* Identifiers */
2098 ot->name = "Euler Discontinuity Filter";
2099 ot->idname = "GRAPH_OT_euler_filter";
2100 ot->description =
2101 "Fix large jumps and flips in the selected "
2102 "Euler Rotation F-Curves arising from rotation "
2103 "values being clipped when baking physics";
2104
2105 /* API callbacks */
2108
2109 /* Flags */
2110 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2111}
2112
2114
2115/* ************************************************************************** */
2116/* SNAPPING */
2117
2118/* -------------------------------------------------------------------- */
2121
2123{
2124 /* Prevent changes during render. */
2125 if (G.is_rendering) {
2126 return false;
2127 }
2128
2130}
2131
2133{
2134 ListBase anim_data = {nullptr, nullptr};
2135 int filter;
2136 KeyframeEditData ked;
2137
2138 /* Init edit data. */
2139 memset(&ked, 0, sizeof(KeyframeEditData));
2140
2141 /* Loop over action data, averaging values. */
2145 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
2146
2147 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
2148 short mapping_flag = ANIM_get_normalization_flags(ac->sl);
2149 KeyframeEditData current_ked;
2150 float offset;
2151 float unit_scale = ANIM_unit_mapping_get_factor(ac->scene,
2152 ale->id,
2153 static_cast<FCurve *>(ale->key_data),
2154 mapping_flag | ANIM_UNITCONV_ONLYKEYS,
2155 &offset);
2156
2157 memset(&current_ked, 0, sizeof(current_ked));
2158
2160 ale, static_cast<FCurve *>(ale->key_data), false, true);
2162 &current_ked, static_cast<FCurve *>(ale->key_data), nullptr, bezt_calc_average, nullptr);
2163 ANIM_nla_mapping_apply_if_needed_fcurve(ale, static_cast<FCurve *>(ale->key_data), true, true);
2164
2165 if (current_ked.i1 == 0) {
2166 continue;
2167 }
2168
2169 ked.f1 += current_ked.f1;
2170 ked.i1 += current_ked.i1;
2171 ked.f2 += (current_ked.f2 + offset * current_ked.i1) * unit_scale;
2172 ked.i2 += current_ked.i2;
2173 }
2174
2175 ANIM_animdata_freelist(&anim_data);
2176
2177 return ked;
2178}
2179
2180/* Snap current-frame indicator to 'average time' of selected keyframe. */
2182{
2183 bAnimContext ac;
2184
2185 /* Get editor data. */
2186 if (ANIM_animdata_get_context(C, &ac) == 0) {
2187 return OPERATOR_CANCELLED;
2188 }
2189
2190 const KeyframeEditData keyframe_sum = sum_selected_keyframes(&ac);
2191 const float sum_time = keyframe_sum.f1;
2192 const float sum_value = keyframe_sum.f2;
2193 const int num_keyframes = keyframe_sum.i1;
2194
2195 if (num_keyframes == 0) {
2196 return OPERATOR_FINISHED;
2197 }
2198
2199 /* Set the new current frame and cursor values, based on the average time and value. */
2200 SpaceGraph *sipo = (SpaceGraph *)ac.sl;
2201 Scene *scene = ac.scene;
2202
2203 /* Take the average values, rounding to the nearest int as necessary for int results. */
2204 if (sipo->mode == SIPO_MODE_DRIVERS) {
2205 /* Drivers Mode - Affects cursor (float) */
2206 sipo->cursorTime = sum_time / float(num_keyframes);
2207 }
2208 else {
2209 /* Animation Mode - Affects current frame (int) */
2210 scene->r.cfra = round_fl_to_int(sum_time / num_keyframes);
2211 scene->r.subframe = 0.0f;
2212 }
2213 sipo->cursorVal = sum_value / float(num_keyframes);
2214
2215 /* Set notifier that things have changed. */
2217
2218 return OPERATOR_FINISHED;
2219}
2220
2222{
2223 /* Identifiers */
2224 ot->name = "Jump to Keyframes";
2225 ot->idname = "GRAPH_OT_frame_jump";
2226 ot->description = "Place the cursor on the midpoint of selected keyframes";
2227
2228 /* API callbacks */
2231
2232 /* Flags */
2233 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2234}
2235
2237{
2238 BKE_report(op->reports, RPT_WARNING, "Deprecated operator, use screen.keyframe_jump instead");
2239 /* The op->ptr can be passed to the operator because it has an identically named property. */
2240 return WM_operator_name_call(
2241 C, "SCREEN_OT_keyframe_jump", blender::wm::OpCallContext::InvokeDefault, op->ptr, nullptr);
2242}
2243
2245{
2246 ot->name = "Jump to Keyframe";
2247 ot->description = "Jump to previous/next keyframe";
2248 ot->idname = "GRAPH_OT_keyframe_jump";
2249
2250 ot->exec = keyframe_jump_exec;
2251
2253 ot->flag = OPTYPE_UNDO_GROUPED;
2254 ot->undo_group = "Frame Change";
2255
2256 /* properties */
2257 RNA_def_boolean(ot->srna, "next", true, "Next Keyframe", "");
2258}
2259
2260/* snap 2D cursor value to the average value of selected keyframe */
2262{
2263 bAnimContext ac;
2264
2265 if (ANIM_animdata_get_context(C, &ac) == 0) {
2266 return OPERATOR_CANCELLED;
2267 }
2268
2269 const KeyframeEditData keyframe_sum = sum_selected_keyframes(&ac);
2270 const float sum_value = keyframe_sum.f2;
2271 const int num_keyframes = keyframe_sum.i1;
2272
2273 if (num_keyframes == 0) {
2274 return OPERATOR_FINISHED;
2275 }
2276
2277 SpaceGraph *sipo = (SpaceGraph *)ac.sl;
2278 sipo->cursorVal = sum_value / float(num_keyframes);
2279 // WM_event_add_notifier(C, NC_SCENE | ND_FRAME, ac.scene);
2281
2282 return OPERATOR_FINISHED;
2283}
2284
2286{
2287 /* Identifiers. */
2288 ot->name = "Snap Cursor Value to Selected";
2289 ot->idname = "GRAPH_OT_snap_cursor_value";
2290 ot->description = "Place the cursor value on the average value of selected keyframes";
2291
2292 /* API callbacks. */
2295
2296 /* Flags */
2297 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2298}
2299
2301
2302/* -------------------------------------------------------------------- */
2305
2306/* Defines for snap keyframes tool. */
2309 "CFRA",
2310 0,
2311 "Selection to Current Frame",
2312 "Snap selected keyframes to the current frame"},
2314 "VALUE",
2315 0,
2316 "Selection to Cursor Value",
2317 "Set values of selected keyframes to the cursor value (Y/Horizontal component)"},
2319 "NEAREST_FRAME",
2320 0,
2321 "Selection to Nearest Frame",
2322 "Snap selected keyframes to the nearest (whole) frame (use to fix accidental subframe "
2323 "offsets)"},
2325 "NEAREST_SECOND",
2326 0,
2327 "Selection to Nearest Second",
2328 "Snap selected keyframes to the nearest second"},
2330 "NEAREST_MARKER",
2331 0,
2332 "Selection to Nearest Marker",
2333 "Snap selected keyframes to the nearest marker"},
2335 "HORIZONTAL",
2336 0,
2337 "Flatten Handles",
2338 "Flatten handles for a smoother transition"},
2339 {0, nullptr, 0, nullptr, nullptr},
2340};
2341
2342/* This function is responsible for snapping keyframes to frame-times. */
2343static void snap_graph_keys(bAnimContext *ac, short mode)
2344{
2345 ListBase anim_data = {nullptr, nullptr};
2346 int filter;
2347
2348 SpaceGraph *sipo = (SpaceGraph *)ac->sl;
2349 KeyframeEditData ked;
2350 KeyframeEditFunc edit_cb;
2351 float cursor_value = 0.0f;
2352
2353 /* Filter data. */
2357 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
2358
2359 /* Init custom data for iterating over keyframes. */
2360 memset(&ked, 0, sizeof(KeyframeEditData));
2361 ked.scene = ac->scene;
2362 if (mode == GRAPHKEYS_SNAP_NEAREST_MARKER) {
2363 ked.list.first = (ac->markers) ? ac->markers->first : nullptr;
2364 ked.list.last = (ac->markers) ? ac->markers->last : nullptr;
2365 }
2366 else if (mode == GRAPHKEYS_SNAP_VALUE) {
2367 cursor_value = (sipo) ? sipo->cursorVal : 0.0f;
2368 }
2369 else if (mode == GRAPHKEYS_SNAP_CFRA) {
2370 /* In drivers mode, use the cursor value instead
2371 * (We need to use a different callback for that though)
2372 */
2373 if (sipo->mode == SIPO_MODE_DRIVERS) {
2374 ked.f1 = sipo->cursorTime;
2375 mode = SNAP_KEYS_TIME;
2376 }
2377 }
2378
2379 /* Get beztriple editing callbacks. */
2380 edit_cb = ANIM_editkeyframes_snap(mode);
2381
2382 /* Snap keyframes. */
2383 const bool use_handle = (sipo->flag & SIPO_NOHANDLES) == 0;
2384 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
2385 /* Normalize cursor value (for normalized F-Curves display). */
2386 if (mode == GRAPHKEYS_SNAP_VALUE) {
2387 short mapping_flag = ANIM_get_normalization_flags(ac->sl);
2388 float offset;
2389 float unit_scale = ANIM_unit_mapping_get_factor(
2390 ac->scene, ale->id, static_cast<FCurve *>(ale->key_data), mapping_flag, &offset);
2391
2392 ked.f1 = (cursor_value / unit_scale) - offset;
2393 }
2394
2395 /* Perform snapping. */
2397 ale, static_cast<FCurve *>(ale->key_data), false, false);
2399 &ked, static_cast<FCurve *>(ale->key_data), nullptr, edit_cb, BKE_fcurve_handles_recalc);
2401 static_cast<FCurve *>(ale->key_data), BEZT_FLAG_TEMP_TAG, use_handle);
2403 ale, static_cast<FCurve *>(ale->key_data), true, false);
2404
2405 ale->update |= ANIM_UPDATE_DEFAULT;
2406 }
2407
2408 ANIM_animdata_update(ac, &anim_data);
2409 ANIM_animdata_freelist(&anim_data);
2410}
2411
2412/* ------------------- */
2413
2415{
2416 bAnimContext ac;
2417 short mode;
2418
2419 /* Get editor data. */
2420 if (ANIM_animdata_get_context(C, &ac) == 0) {
2421 return OPERATOR_CANCELLED;
2422 }
2423
2424 /* Get snapping mode. */
2425 mode = RNA_enum_get(op->ptr, "type");
2426
2427 /* Snap keyframes. */
2428 snap_graph_keys(&ac, mode);
2429
2430 /* Set notifier that keyframes have changed. */
2432
2433 return OPERATOR_FINISHED;
2434}
2435
2437{
2438 bAnimContext ac;
2439 ListBase anim_data = {nullptr, nullptr};
2440
2441 /* Get editor data. */
2442 if (ANIM_animdata_get_context(C, &ac) == 0) {
2443 return false;
2444 }
2445
2446 /* Filter data. */
2450 &ac, &anim_data, eAnimFilter_Flags(filter), ac.data, eAnimCont_Types(ac.datatype));
2451
2452 /* Check if any of the visible and editable f-curves have at least one selected control point. */
2453 bool has_selected_control_points = false;
2454 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
2455 const FCurve *fcu = static_cast<const FCurve *>(ale->key_data);
2457 has_selected_control_points = true;
2458 break;
2459 }
2460 }
2461
2462 ANIM_animdata_freelist(&anim_data);
2463
2464 return has_selected_control_points;
2465}
2466
2468 wmOperator *op,
2469 const wmEvent *event)
2470{
2472 BKE_report(op->reports, RPT_ERROR, "No control points are selected");
2473 return OPERATOR_CANCELLED;
2474 }
2475
2476 return WM_menu_invoke(C, op, event);
2477}
2478
2480{
2481 /* Identifiers */
2482 ot->name = "Snap Keys";
2483 ot->idname = "GRAPH_OT_snap";
2484 ot->description = "Snap selected keyframes to the chosen times/values";
2485
2486 /* API callbacks */
2488 ot->exec = graphkeys_snap_exec;
2490
2491 /* Flags */
2492 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2493
2494 /* Id-props */
2495 ot->prop = RNA_def_enum(ot->srna, "type", prop_graphkeys_snap_types, 0, "Type", "");
2496}
2497
2499
2500/* -------------------------------------------------------------------- */
2503
2504/* Defines for equalize handles tool. */
2506 {GRAPHKEYS_EQUALIZE_LEFT, "LEFT", 0, "Left", "Equalize selected keyframes' left handles"},
2507 {GRAPHKEYS_EQUALIZE_RIGHT, "RIGHT", 0, "Right", "Equalize selected keyframes' right handles"},
2508 {GRAPHKEYS_EQUALIZE_BOTH, "BOTH", 0, "Both", "Equalize both of a keyframe's handles"},
2509 {0, nullptr, 0, nullptr, nullptr},
2510};
2511
2512/* ------------------- */
2513
2514/* Equalize selected keyframes' bezier handles. */
2515static void equalize_graph_keys(bAnimContext *ac, int mode, float handle_length, bool flatten)
2516{
2517 /* Filter data. */
2520 ListBase anim_data = {nullptr, nullptr};
2522 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
2523
2524 /* Equalize keyframes. */
2525 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
2526 ANIM_fcurve_equalize_keyframes_loop(static_cast<FCurve *>(ale->key_data),
2528 handle_length,
2529 flatten);
2530 ale->update |= ANIM_UPDATE_DEFAULT;
2531 }
2532
2533 ANIM_animdata_update(ac, &anim_data);
2534 ANIM_animdata_freelist(&anim_data);
2535}
2536
2538{
2539 bAnimContext ac;
2540
2541 /* Get editor data. */
2542 if (ANIM_animdata_get_context(C, &ac) == 0) {
2543 return OPERATOR_CANCELLED;
2544 }
2545
2546 /* Get equalize mode. */
2547 int mode = RNA_enum_get(op->ptr, "side");
2548 float handle_length = RNA_float_get(op->ptr, "handle_length");
2549 bool flatten = RNA_boolean_get(op->ptr, "flatten");
2550
2551 /* Equalize graph keyframes. */
2552 equalize_graph_keys(&ac, mode, handle_length, flatten);
2553
2555
2556 return OPERATOR_FINISHED;
2557}
2558
2560{
2561 /* Identifiers */
2562 ot->name = "Equalize Handles";
2563 ot->idname = "GRAPH_OT_equalize_handles";
2564 ot->description =
2565 "Ensure selected keyframes' handles have equal length, optionally making them horizontal. "
2566 "Automatic, Automatic Clamped, or Vector handle types will be converted to Aligned";
2567 /* API callbacks */
2571
2572 /* Flags */
2573 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2574
2575 /* Properties */
2576 ot->prop = RNA_def_enum(ot->srna,
2577 "side",
2579 0,
2580 "Side",
2581 "Side of the keyframes' Bézier handles to affect");
2582 RNA_def_float(ot->srna,
2583 "handle_length",
2584 5.0f,
2585 0.1f,
2586 FLT_MAX,
2587 "Handle Length",
2588 "Length to make selected keyframes' Bézier handles",
2589 1.0f,
2590 50.0f);
2592 ot->srna,
2593 "flatten",
2594 false,
2595 "Flatten",
2596 "Make the values of the selected keyframes' handles the same as their respective keyframes");
2597}
2598
2600
2601/* -------------------------------------------------------------------- */
2604
2605/* Defines for mirror keyframes tool. */
2608 "CFRA",
2609 0,
2610 "By Times Over Current Frame",
2611 "Flip times of selected keyframes using the current frame as the mirror line"},
2613 "VALUE",
2614 0,
2615 "By Values Over Cursor Value",
2616 "Flip values of selected keyframes using the cursor value (Y/Horizontal component) as the "
2617 "mirror line"},
2619 "YAXIS",
2620 0,
2621 "By Times Over Zero Time",
2622 "Flip times of selected keyframes, effectively reversing the order they appear in"},
2624 "XAXIS",
2625 0,
2626 "By Values Over Zero Value",
2627 "Flip values of selected keyframes (i.e. negative values become positive, and vice versa)"},
2629 "MARKER",
2630 0,
2631 "By Times Over First Selected Marker",
2632 "Flip times of selected keyframes using the first selected marker as the reference point"},
2633 {0, nullptr, 0, nullptr, nullptr},
2634};
2635
2636/* This function is responsible for mirroring keyframes. */
2637static void mirror_graph_keys(bAnimContext *ac, short mode)
2638{
2639 ListBase anim_data = {nullptr, nullptr};
2640 int filter;
2641
2642 SpaceGraph *sipo = (SpaceGraph *)ac->sl;
2643 KeyframeEditData ked;
2644 KeyframeEditFunc edit_cb;
2645 float cursor_value = 0.0f;
2646
2647 /* Init custom data for looping over keyframes. */
2648 memset(&ked, 0, sizeof(KeyframeEditData));
2649 ked.scene = ac->scene;
2650
2651 /* Store mode-specific custom data... */
2652 if (mode == GRAPHKEYS_MIRROR_MARKER) {
2653 TimeMarker *marker = nullptr;
2654
2655 /* Find first selected marker. */
2657
2658 /* Store marker's time (if available). */
2659 if (marker) {
2660 ked.f1 = float(marker->frame);
2661 }
2662 else {
2663 return;
2664 }
2665 }
2666 else if (mode == GRAPHKEYS_MIRROR_VALUE) {
2667 cursor_value = (sipo) ? sipo->cursorVal : 0.0f;
2668 }
2669 else if (mode == GRAPHKEYS_MIRROR_CFRA) {
2670 /* In drivers mode, use the cursor value instead
2671 * (We need to use a different callback for that though)
2672 */
2673 if (sipo->mode == SIPO_MODE_DRIVERS) {
2674 ked.f1 = sipo->cursorTime;
2675 mode = MIRROR_KEYS_TIME;
2676 }
2677 }
2678
2679 /* Get beztriple editing callbacks. */
2680 edit_cb = ANIM_editkeyframes_mirror(mode);
2681
2682 /* Filter data. */
2686 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
2687
2688 /* Mirror keyframes. */
2689 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
2690 /* Apply unit corrections. */
2691 if (mode == GRAPHKEYS_MIRROR_VALUE) {
2692 short mapping_flag = ANIM_get_normalization_flags(ac->sl);
2693 float offset;
2694 float unit_scale = ANIM_unit_mapping_get_factor(ac->scene,
2695 ale->id,
2696 static_cast<FCurve *>(ale->key_data),
2697 mapping_flag | ANIM_UNITCONV_ONLYKEYS,
2698 &offset);
2699
2700 ked.f1 = (cursor_value - offset) / unit_scale;
2701 }
2702
2703 /* Perform actual mirroring. */
2705 ale, static_cast<FCurve *>(ale->key_data), false, false);
2707 &ked, static_cast<FCurve *>(ale->key_data), nullptr, edit_cb, BKE_fcurve_handles_recalc);
2709 ale, static_cast<FCurve *>(ale->key_data), true, false);
2710
2711 ale->update |= ANIM_UPDATE_DEFAULT;
2712 }
2713
2714 ANIM_animdata_update(ac, &anim_data);
2715 ANIM_animdata_freelist(&anim_data);
2716}
2717
2718/* ------------------- */
2719
2721{
2722 bAnimContext ac;
2723 short mode;
2724
2725 /* Get editor data. */
2726 if (ANIM_animdata_get_context(C, &ac) == 0) {
2727 return OPERATOR_CANCELLED;
2728 }
2729
2730 /* Get mirroring mode. */
2731 mode = RNA_enum_get(op->ptr, "type");
2732
2733 /* Mirror keyframes. */
2734 mirror_graph_keys(&ac, mode);
2735
2736 /* Set notifier that keyframes have changed. */
2738
2739 return OPERATOR_FINISHED;
2740}
2741
2743{
2744 /* Identifiers */
2745 ot->name = "Mirror Keys";
2746 ot->idname = "GRAPH_OT_mirror";
2747 ot->description = "Flip selected keyframes over the selected mirror line";
2748
2749 /* API callbacks */
2750 ot->invoke = WM_menu_invoke;
2751 ot->exec = graphkeys_mirror_exec;
2753
2754 /* Flags */
2755 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2756
2757 /* Id-props */
2758 ot->prop = RNA_def_enum(ot->srna, "type", prop_graphkeys_mirror_types, 0, "Type", "");
2759}
2760
2762
2763/* -------------------------------------------------------------------- */
2766
2768{
2769 bAnimContext ac;
2770 ListBase anim_data = {nullptr, nullptr};
2771 int filter;
2772
2773 /* Get editor data. */
2774 if (ANIM_animdata_get_context(C, &ac) == 0) {
2775 return OPERATOR_CANCELLED;
2776 }
2777
2778 /* Filter data. */
2782 &ac, &anim_data, eAnimFilter_Flags(filter), ac.data, eAnimCont_Types(ac.datatype));
2783
2784 /* Smooth keyframes. */
2785 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
2786 /* For now, we can only smooth by flattening handles AND smoothing curve values.
2787 * Perhaps the mode argument could be removed, as that functionality is offered through
2788 * Snap->Flatten Handles anyway.
2789 */
2790 smooth_fcurve(static_cast<FCurve *>(ale->key_data));
2791
2792 ale->update |= ANIM_UPDATE_DEFAULT;
2793 }
2794
2795 ANIM_animdata_update(&ac, &anim_data);
2796 ANIM_animdata_freelist(&anim_data);
2797
2798 /* Set notifier that keyframes have changed. */
2800
2801 return OPERATOR_FINISHED;
2802}
2803
2805{
2806 /* Identifiers */
2807 ot->name = "Smooth Keys";
2808 ot->idname = "GRAPH_OT_smooth";
2809 ot->description = "Apply weighted moving means to make selected F-Curves less bumpy";
2810
2811 /* API callbacks */
2812 ot->exec = graphkeys_smooth_exec;
2814
2815 /* Flags */
2816 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2817}
2818
2820
2821/* ************************************************************************** */
2822/* F-CURVE MODIFIERS */
2823
2824/* -------------------------------------------------------------------- */
2827
2829 PointerRNA * /*ptr*/,
2830 PropertyRNA * /*prop*/,
2831 bool *r_free)
2832{
2833 EnumPropertyItem *item = nullptr;
2834 int totitem = 0;
2835 int i = 0;
2836
2837 if (C == nullptr) {
2839 }
2840
2841 /* Start from 1 to skip the 'Invalid' modifier type. */
2842 for (i = 1; i < FMODIFIER_NUM_TYPES; i++) {
2844 int index;
2845
2846 /* Check if modifier is valid for this context. */
2847 if (fmi == nullptr) {
2848 continue;
2849 }
2850
2852 if (index != -1) { /* Not all types are implemented yet... */
2853 RNA_enum_item_add(&item, &totitem, &rna_enum_fmodifier_type_items[index]);
2854 }
2855 }
2856
2857 RNA_enum_item_end(&item, &totitem);
2858 *r_free = true;
2859
2860 return item;
2861}
2862
2864{
2865 bAnimContext ac;
2866 ListBase anim_data = {nullptr, nullptr};
2867 int filter;
2868 short type;
2869
2870 /* Get editor data. */
2871 if (ANIM_animdata_get_context(C, &ac) == 0) {
2872 return OPERATOR_CANCELLED;
2873 }
2874
2875 /* Get type of modifier to add. */
2876 type = RNA_enum_get(op->ptr, "type");
2877
2878 /* Filter data. */
2881 if (RNA_boolean_get(op->ptr, "only_active")) {
2882 /* FIXME: enforce in this case only a single channel to get handled? */
2884 }
2885 else {
2887 }
2889 &ac, &anim_data, eAnimFilter_Flags(filter), ac.data, eAnimCont_Types(ac.datatype));
2890
2891 /* Add f-modifier to each curve. */
2892 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
2893 FCurve *fcu = (FCurve *)ale->data;
2894 FModifier *fcm;
2895
2896 /* Add F-Modifier of specified type to active F-Curve, and make it the active one. */
2897 fcm = add_fmodifier(&fcu->modifiers, type, fcu);
2898 if (fcm) {
2899 set_active_fmodifier(&fcu->modifiers, fcm);
2900 }
2901 else {
2902 BKE_report(op->reports, RPT_ERROR, "Modifier could not be added (see console for details)");
2903 break;
2904 }
2905
2906 ale->update |= ANIM_UPDATE_DEPS;
2907 }
2908
2909 ANIM_animdata_update(&ac, &anim_data);
2910 ANIM_animdata_freelist(&anim_data);
2911
2912 /* Set notifier that things have changed. */
2914
2915 return OPERATOR_FINISHED;
2916}
2917
2919{
2920 PropertyRNA *prop;
2921
2922 /* Identifiers */
2923 ot->name = "Add F-Curve Modifier";
2924 ot->idname = "GRAPH_OT_fmodifier_add";
2925 ot->description = "Add F-Modifier to the active/selected F-Curves";
2926
2927 /* API callbacks */
2928 ot->invoke = WM_menu_invoke;
2931
2932 /* Flags */
2933 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2934
2935 /* Id-props */
2936 prop = RNA_def_enum(ot->srna, "type", rna_enum_fmodifier_type_items, 0, "Type", "");
2939 ot->prop = prop;
2940
2942 ot->srna, "only_active", false, "Only Active", "Only add F-Modifier to active F-Curve");
2943}
2944
2946
2947/* -------------------------------------------------------------------- */
2950
2952{
2953 bAnimContext ac;
2954 bAnimListElem *ale;
2955 bool ok = false;
2956
2957 /* Get editor data. */
2958 if (ANIM_animdata_get_context(C, &ac) == 0) {
2959 return OPERATOR_CANCELLED;
2960 }
2961
2962 /* Clear buffer first. */
2964
2965 /* Get the active F-Curve. */
2966 ale = get_active_fcurve_channel(&ac);
2967
2968 /* If this exists, call the copy F-Modifiers API function. */
2969 if (ale && ale->data) {
2970 FCurve *fcu = (FCurve *)ale->data;
2971
2972 /* TODO: When 'active' vs 'all' boolean is added, change last param! (Joshua Leung 2010) */
2973 ok = ANIM_fmodifiers_copy_to_buf(&fcu->modifiers, false);
2974
2975 /* Free temp data now. */
2976 MEM_freeN(ale);
2977 }
2978
2979 /* Successful or not? */
2980 if (ok == 0) {
2981 BKE_report(op->reports, RPT_ERROR, "No F-Modifiers available to be copied");
2982 return OPERATOR_CANCELLED;
2983 }
2984 return OPERATOR_FINISHED;
2985}
2986
2988{
2989 /* Identifiers */
2990 ot->name = "Copy F-Modifiers";
2991 ot->idname = "GRAPH_OT_fmodifier_copy";
2992 ot->description = "Copy the F-Modifier(s) of the active F-Curve";
2993
2994 /* API callbacks */
2997
2998 /* Flags */
2999 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3000
3001/* Id-props */
3002#if 0
3003 ot->prop = RNA_def_boolean(ot->srna,
3004 "all",
3005 1,
3006 "All F-Modifiers",
3007 "Copy all the F-Modifiers, instead of just the active one");
3008#endif
3009}
3010
3012
3013/* -------------------------------------------------------------------- */
3016
3018{
3019 bAnimContext ac;
3020
3021 ListBase anim_data = {nullptr, nullptr};
3022 int filter;
3023
3024 const bool replace = RNA_boolean_get(op->ptr, "replace");
3025 bool ok = false;
3026
3027 /* Get editor data. */
3028 if (ANIM_animdata_get_context(C, &ac) == 0) {
3029 return OPERATOR_CANCELLED;
3030 }
3031
3032 /* Filter data. */
3033 if (RNA_boolean_get(op->ptr, "only_active")) {
3034 /* This should be the default (for buttons) - Just paste to the active FCurve. */
3037 }
3038 else {
3039 /* This is only if the operator gets called from a hotkey or search -
3040 * Paste to all visible curves. */
3043 }
3044
3046 &ac, &anim_data, eAnimFilter_Flags(filter), ac.data, eAnimCont_Types(ac.datatype));
3047
3048 /* Paste modifiers. */
3049 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
3050 FCurve *fcu = (FCurve *)ale->data;
3051 int tot;
3052
3053 tot = ANIM_fmodifiers_paste_from_buf(&fcu->modifiers, replace, fcu);
3054
3055 if (tot) {
3056 ale->update |= ANIM_UPDATE_DEPS;
3057 ok = true;
3058 }
3059 }
3060
3061 if (ok) {
3062 ANIM_animdata_update(&ac, &anim_data);
3063 }
3064 ANIM_animdata_freelist(&anim_data);
3065
3066 /* Successful or not? */
3067 if (ok) {
3068 /* Set notifier that keyframes have changed. */
3070
3071 return OPERATOR_FINISHED;
3072 }
3073
3074 BKE_report(op->reports, RPT_ERROR, "No F-Modifiers to paste");
3075 return OPERATOR_CANCELLED;
3076}
3077
3079{
3080 /* Identifiers */
3081 ot->name = "Paste F-Modifiers";
3082 ot->idname = "GRAPH_OT_fmodifier_paste";
3083 ot->description = "Add copied F-Modifiers to the selected F-Curves";
3084
3085 /* API callbacks */
3088
3089 /* Flags */
3090 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3091
3092 /* Properties */
3094 ot->srna, "only_active", false, "Only Active", "Only paste F-Modifiers on active F-Curve");
3096 ot->srna,
3097 "replace",
3098 false,
3099 "Replace Existing",
3100 "Replace existing F-Modifiers, instead of just appending to the end of the existing list");
3101}
3102
3104
3105/* ************************************************************************** */
3106/* Drivers */
3107
3108/* -------------------------------------------------------------------- */
3111
3113{
3114 bool ok = false;
3115
3116 PointerRNA ptr = CTX_data_pointer_get_type(C, "active_editable_fcurve", &RNA_FCurve);
3117
3118 /* If this exists, call the copy driver vars API function. */
3119 FCurve *fcu = static_cast<FCurve *>(ptr.data);
3120
3121 if (fcu) {
3122 ok = ANIM_driver_vars_copy(op->reports, fcu);
3123 }
3124
3125 /* Successful or not? */
3126 if (ok) {
3127 return OPERATOR_FINISHED;
3128 }
3129 return OPERATOR_CANCELLED;
3130}
3131
3133{
3134 /* Identifiers */
3135 ot->name = "Copy Driver Variables";
3136 ot->idname = "GRAPH_OT_driver_variables_copy";
3137 ot->description = "Copy the driver variables of the active driver";
3138
3139 /* API callbacks */
3142
3143 /* Flags */
3144 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3145}
3146
3148
3149/* -------------------------------------------------------------------- */
3152
3154{
3155 const bool replace = RNA_boolean_get(op->ptr, "replace");
3156 bool ok = false;
3157
3158 PointerRNA ptr = CTX_data_pointer_get_type(C, "active_editable_fcurve", &RNA_FCurve);
3159
3160 /* If this exists, call the paste driver vars API function. */
3161 FCurve *fcu = static_cast<FCurve *>(ptr.data);
3162
3163 if (fcu) {
3164 ok = ANIM_driver_vars_paste(op->reports, fcu, replace);
3165 }
3166
3167 /* Successful or not? */
3168 if (ok) {
3169 /* Rebuild depsgraph, now that there are extra dependencies here. */
3171
3172 /* Set notifier that keyframes have changed. */
3174
3175 return OPERATOR_FINISHED;
3176 }
3177 return OPERATOR_CANCELLED;
3178}
3179
3181{
3182 /* Identifiers */
3183 ot->name = "Paste Driver Variables";
3184 ot->idname = "GRAPH_OT_driver_variables_paste";
3185 ot->description = "Add copied driver variables to the active driver";
3186
3187 /* API callbacks */
3190
3191 /* Flags */
3192 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3193
3194 /* Properties */
3195 RNA_def_boolean(ot->srna,
3196 "replace",
3197 false,
3198 "Replace Existing",
3199 "Replace existing driver variables, instead of just appending to the end of the "
3200 "existing list");
3201}
3202
3204
3205/* -------------------------------------------------------------------- */
3208
3210{
3211 bAnimContext ac;
3212 ListBase anim_data = {nullptr, nullptr};
3213 int filter;
3214 bool ok = false;
3215 uint deleted = 0;
3216
3217 /* Get editor data. */
3218 if (ANIM_animdata_get_context(C, &ac) == 0) {
3219 return OPERATOR_CANCELLED;
3220 }
3221
3222 /* NOTE: We might need a scene update to evaluate the driver flags. */
3223
3224 /* Filter data. */
3228 &ac, &anim_data, eAnimFilter_Flags(filter), ac.data, eAnimCont_Types(ac.datatype));
3229
3230 /* Find invalid drivers. */
3231 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
3232 FCurve *fcu = (FCurve *)ale->data;
3233 if (ELEM(nullptr, fcu, fcu->driver)) {
3234 continue;
3235 }
3236 if (!(fcu->driver->flag & DRIVER_FLAG_INVALID)) {
3237 continue;
3238 }
3239
3240 ok |= ANIM_remove_driver(ale->id, fcu->rna_path, fcu->array_index);
3241 if (!ok) {
3242 break;
3243 }
3244 deleted += 1;
3246 }
3247
3248 /* Cleanup. */
3249 ANIM_animdata_freelist(&anim_data);
3250
3251 if (deleted > 0) {
3252 /* Notify the world of any changes. */
3255 BKE_reportf(op->reports, RPT_INFO, "Deleted %u drivers", deleted);
3256 }
3257 else {
3258 BKE_report(op->reports, RPT_INFO, "No drivers deleted");
3259 }
3260
3261 /* Successful or not? */
3262 if (!ok) {
3263 return OPERATOR_CANCELLED;
3264 }
3265
3266 return OPERATOR_FINISHED;
3267}
3268
3270{
3271 bAnimContext ac;
3272 ScrArea *area = CTX_wm_area(C);
3273
3274 /* Firstly, check if in Graph Editor. */
3275 if ((area == nullptr) || (area->spacetype != SPACE_GRAPH)) {
3276 return false;
3277 }
3278
3279 /* Try to init Anim-Context stuff ourselves and check. */
3280 return ANIM_animdata_get_context(C, &ac) != 0;
3281}
3282
3284{
3285 /* Identifiers */
3286 ot->name = "Delete Invalid Drivers";
3287 ot->idname = "GRAPH_OT_driver_delete_invalid";
3288 ot->description = "Delete all visible drivers considered invalid";
3289
3290 /* API callbacks */
3293
3294 /* Flags */
3295 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3296}
3297
Functions to work with AnimData.
Functions to modify FCurves.
Functions to insert, delete or modify keyframes.
AnimationEvalContext BKE_animsys_eval_context_construct(struct Depsgraph *depsgraph, float eval_time) ATTR_WARN_UNUSED_RESULT
Definition anim_sys.cc:738
PointerRNA CTX_data_pointer_get_type(const bContext *C, const char *member, StructRNA *type)
ScrArea * CTX_wm_area(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
bool BKE_fcurve_is_keyframable(const FCurve *fcu)
const FModifierTypeInfo * get_fmodifier_typeinfo(int type)
void BKE_fcurve_handles_recalc(FCurve *fcu)
void fcurve_samples_to_keyframes(FCurve *fcu, int start, int end)
FModifier * add_fmodifier(ListBase *modifiers, int type, FCurve *owner_fcu)
bool remove_fmodifier(ListBase *modifiers, FModifier *fcm)
bool list_has_suitable_fmodifier(const ListBase *modifiers, int mtype, short acttype)
void set_active_fmodifier(ListBase *modifiers, FModifier *fcm)
float evaluate_fcurve_only_curve(const FCurve *fcu, float evaltime)
bool BKE_fcurve_is_empty(const FCurve *fcu)
bool BKE_fcurve_delete_keys_selected(FCurve *fcu)
void BKE_fcurve_keyframe_move_value_with_handles(BezTriple *keyframe, float new_value)
void BKE_fcurve_merge_duplicate_keys(FCurve *fcu, const int sel_flag, const bool use_handle)
bool BKE_fcurve_has_selected_control_points(const FCurve *fcu)
void fcurve_store_samples(FCurve *fcu, void *data, int start, int end, FcuSampleFunc sample_cb)
float fcurve_samplingcb_evalcurve(FCurve *fcu, void *data, float evaltime)
@ NLATIME_CONVERT_UNMAP
Definition BKE_nla.hh:549
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
@ RPT_INFO
Definition BKE_report.hh:35
@ RPT_ERROR
Definition BKE_report.hh:39
@ RPT_WARNING
Definition BKE_report.hh:38
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
#define BLI_assert(a)
Definition BLI_assert.h:46
File and directory operations.
bool BLI_is_file(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:448
void BLI_kdtree_nd_ free(KDTree *tree)
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
MINLINE int round_fl_to_int(float a)
MINLINE int min_ii(int a, int b)
#define M_PI
void mat3_normalized_to_compatible_eul(float eul[3], const float oldrot[3], float mat[3][3])
void eul_to_mat3(float mat[3][3], const float eul[3])
#define FILE_MAX
unsigned int uint
#define ELEM(...)
#define STREQ(a, b)
#define BLT_I18NCONTEXT_ID_ACTION
#define RPT_(msgid)
#define TIP_(msgid)
#define IFACE_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
@ ID_RECALC_ANIMATION
Definition DNA_ID.h:1077
eInsertKeyFlags
@ FMODIFIER_TYPE_CYCLES
@ FMODIFIER_NUM_TYPES
@ DRIVER_FLAG_INVALID
@ FCURVE_PROTECTED
@ FCURVE_EXTRAPOLATE_CONSTANT
@ FCURVE_EXTRAPOLATE_LINEAR
@ BEZT_FLAG_TEMP_TAG
eBezTriple_KeyframeType
#define PSFRA
#define PEFRA
@ FILE_SORT_DEFAULT
@ FILE_SPECIAL
@ FILE_TYPE_MOVIE
@ FILE_TYPE_SOUND
@ FILE_TYPE_FOLDER
@ SPACE_GRAPH
@ SIPO_MODE_DRIVERS
@ SIPO_NOHANDLES
@ FILE_DEFAULTDISPLAY
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
#define ANIM_UPDATE_DEFAULT_NOHANDLES
#define ANIM_UPDATE_DEFAULT
@ ANIM_UPDATE_DEPS
@ ANIM_UPDATE_HANDLES
eAnimCont_Types
eAnimFilter_Flags
@ ANIMFILTER_ACTIVE
@ ANIMFILTER_FOREDIT
@ ANIMFILTER_DATA_VISIBLE
@ ANIMFILTER_CURVE_VISIBLE
@ ANIMFILTER_NODUPLIS
@ ANIMFILTER_FCURVESONLY
@ ANIMFILTER_SEL
@ ANIM_UNITCONV_ONLYKEYS
@ ANIM_UNITCONV_RESTORE
@ MIRROR_KEYS_TIME
eEditKeyframes_Equalize
@ KEYFRAME_PASTE_MERGE_MIX
eKeyPasteValueOffset
@ KEYFRAME_PASTE_VALUE_OFFSET_NONE
eKeyPasteOffset
@ KEYFRAME_PASTE_OFFSET_CFRA_START
@ BEZT_OK_SELECTED
@ SNAP_KEYS_TIME
short(*)(KeyframeEditData *ked, BezTriple *bezt) KeyframeEditFunc
@ SELECT_SUBTRACT
@ KEYFRAME_PASTE_NOTHING_TO_PASTE
@ KEYFRAME_PASTE_OK
@ KEYFRAME_PASTE_NOWHERE_TO_PASTE
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:618
Read Guarded memory(de)allocation.
@ PROP_SKIP_SAVE
Definition RNA_types.hh:344
#define C
Definition RandGen.cpp:29
@ ALERT_ICON_NONE
void UI_view2d_region_to_view(const View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
Definition view2d.cc:1668
@ WM_FILESEL_SHOW_PROPS
Definition WM_api.hh:1127
@ WM_FILESEL_FILEPATH
Definition WM_api.hh:1124
@ FILE_OPENFILE
Definition WM_api.hh:1133
#define NC_ANIMATION
Definition WM_types.hh:388
#define NC_SCENE
Definition WM_types.hh:378
#define NA_ADDED
Definition WM_types.hh:586
@ OPTYPE_UNDO_GROUPED
Definition WM_types.hh:207
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define NA_EDITED
Definition WM_types.hh:584
#define ND_KEYFRAME_PROP
Definition WM_types.hh:495
#define ND_FRAME
Definition WM_types.hh:434
#define NA_REMOVED
Definition WM_types.hh:587
#define ND_KEYFRAME
Definition WM_types.hh:494
#define MAKE_CYCLIC_EXPO
#define CLEAR_CYCLIC_EXPO
void ANIM_animdata_freelist(ListBase *anim_data)
Definition anim_deps.cc:463
void ANIM_deselect_keys_in_animation_editors(bContext *C)
Definition anim_deps.cc:478
void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
Definition anim_deps.cc:356
short ANIM_get_normalization_flags(SpaceLink *space_link)
Definition anim_draw.cc:415
void ANIM_nla_mapping_apply_if_needed_fcurve(bAnimListElem *ale, FCurve *fcu, const bool restore, const bool only_keys)
Definition anim_draw.cc:401
float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short flag, float *r_offset)
Definition anim_draw.cc:624
float ANIM_nla_tweakedit_remap(bAnimListElem *ale, const float cframe, const eNlaTime_ConvertModes mode)
Definition anim_draw.cc:324
bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, const eAnimFilter_Flags filter_mode, void *data, const eAnimCont_Types datatype)
TimeMarker * ED_markers_get_first_selected(ListBase *markers)
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
float evaltime
SIMD_FORCE_INLINE btScalar length() const
Return the length of the vector.
Definition btVector3.h:257
nullptr float
bool ANIM_driver_vars_copy(ReportList *reports, FCurve *fcu)
Definition drivers.cc:690
bool ANIM_driver_vars_paste(ReportList *reports, FCurve *fcu, bool replace)
Definition drivers.cc:712
bool ANIM_remove_driver(ID *id, const char rna_path[], int array_index)
Main Driver Management API calls.
Definition drivers.cc:505
bool ANIM_fmodifiers_paste_from_buf(ListBase *modifiers, bool replace, FCurve *curve)
void ANIM_fmodifiers_copybuf_free()
bool ANIM_fmodifiers_copy_to_buf(ListBase *modifiers, bool active)
#define filter
constexpr T sign(T) RET
static wmOperatorStatus graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
static const EnumPropertyItem prop_graphkeys_insertkey_types[]
Definition graph_edit.cc:79
void GRAPH_OT_delete(wmOperatorType *ot)
static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode)
static wmOperatorStatus graphkeys_click_insert_exec(bContext *C, wmOperator *op)
static wmOperatorStatus graphkeys_snap_cursor_value_exec(bContext *C, wmOperator *)
void GRAPH_OT_click_insert(wmOperatorType *ot)
void GRAPH_OT_fmodifier_paste(wmOperatorType *ot)
void GRAPH_OT_smooth(wmOperatorType *ot)
static const EnumPropertyItem prop_graphkeys_equalize_handles_sides[]
static void clean_graph_keys(bAnimContext *ac, float thresh, bool clean_chan)
static wmOperatorStatus graphkeys_sound_to_samples_exec(bContext *, wmOperator *op)
static void mirror_graph_keys(bAnimContext *ac, short mode)
static KeyframeEditData sum_selected_keyframes(bAnimContext *ac)
static wmOperatorStatus graphkeys_clean_exec(bContext *C, wmOperator *op)
static wmOperatorStatus graphkeys_mirror_exec(bContext *C, wmOperator *op)
static bool copy_graph_keys(bAnimContext *ac)
void GRAPH_OT_equalize_handles(wmOperatorType *ot)
static wmOperatorStatus graphkeys_bake_exec(bContext *C, wmOperator *)
static bool euler_filter_multi_channel(tEulerFilter *euf, ReportList *reports)
void GRAPH_OT_keyframe_jump(wmOperatorType *ot)
static bool graph_driver_delete_invalid_poll(bContext *C)
void GRAPH_OT_snap_cursor_value(wmOperatorType *ot)
static wmOperatorStatus graphkeys_ipo_exec(bContext *C, wmOperator *op)
static void euler_filter_perform_filter(ListBase *eulers, ReportList *reports, int *r_curves_filtered, int *r_curves_seen)
static void sethandles_graph_keys(bAnimContext *ac, short mode)
void GRAPH_OT_bake_keys(wmOperatorType *ot)
static bool euler_filter_single_channel(FCurve *fcu)
static bool keyframe_time_differs(BezTriple *keyframes[3])
static wmOperatorStatus graph_driver_delete_invalid_exec(bContext *C, wmOperator *op)
void GRAPH_OT_mirror(wmOperatorType *ot)
static wmOperatorStatus graph_fmodifier_add_exec(bContext *C, wmOperator *op)
static void bake_graph_keys(bAnimContext *ac)
static wmOperatorStatus graph_driver_vars_copy_exec(bContext *C, wmOperator *op)
static bool graph_has_selected_control_points(bContext *C)
static wmOperatorStatus graphkeys_sound_to_samples_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void snap_graph_keys(bAnimContext *ac, short mode)
void GRAPH_OT_keys_to_samples(wmOperatorType *ot)
void GRAPH_OT_fmodifier_copy(wmOperatorType *ot)
void GRAPH_OT_samples_to_keys(wmOperatorType *ot)
static const EnumPropertyItem prop_graphkeys_mirror_types[]
static wmOperatorStatus graphkeys_snap_exec(bContext *C, wmOperator *op)
void GRAPH_OT_handle_type(wmOperatorType *ot)
static std::string graphkeys_paste_get_description(bContext *, wmOperatorType *, PointerRNA *ptr)
static void equalize_graph_keys(bAnimContext *ac, int mode, float handle_length, bool flatten)
static wmOperatorStatus graphkeys_delete_invoke(bContext *C, wmOperator *op, const wmEvent *)
static wmOperatorStatus graphkeys_insertkey_exec(bContext *C, wmOperator *op)
void GRAPH_OT_frame_jump(wmOperatorType *ot)
static wmOperatorStatus graphkeys_equalize_handles_exec(bContext *C, wmOperator *op)
void GRAPH_OT_driver_variables_copy(wmOperatorType *ot)
static wmOperatorStatus graph_driver_vars_paste_exec(bContext *C, wmOperator *op)
void GRAPH_OT_extrapolation_type(wmOperatorType *ot)
static bool delete_graph_keys(bAnimContext *ac)
static wmOperatorStatus graphkeys_delete_exec(bContext *C, wmOperator *)
void GRAPH_OT_sound_to_samples(wmOperatorType *ot)
static wmOperatorStatus graphkeys_handletype_exec(bContext *C, wmOperator *op)
void GRAPH_OT_driver_variables_paste(wmOperatorType *ot)
static wmOperatorStatus graphkeys_expo_exec(bContext *C, wmOperator *op)
void GRAPH_OT_interpolation_type(wmOperatorType *ot)
static wmOperatorStatus graphkeys_duplicate_exec(bContext *C, wmOperator *)
static wmOperatorStatus graphkeys_paste_exec(bContext *C, wmOperator *op)
static void setexpo_graph_keys(bAnimContext *ac, short mode)
eGraphKeys_InsertKey_Types
Definition graph_edit.cc:71
@ GRAPHKEYS_INSERTKEY_CURSOR
Definition graph_edit.cc:74
@ GRAPHKEYS_INSERTKEY_ACTIVE
Definition graph_edit.cc:75
@ GRAPHKEYS_INSERTKEY_ALL
Definition graph_edit.cc:72
@ GRAPHKEYS_INSERTKEY_SEL
Definition graph_edit.cc:73
static eKeyPasteError paste_graph_keys(bAnimContext *ac, const eKeyPasteOffset offset_mode, const eKeyPasteValueOffset value_offset_mode, const eKeyMergeMode merge_mode, const bool flip)
static wmOperatorStatus graphkeys_copy_exec(bContext *C, wmOperator *op)
static wmOperatorStatus graph_fmodifier_paste_exec(bContext *C, wmOperator *op)
static void convert_keys_to_samples(bAnimContext *ac, int start, int end)
static wmOperatorStatus graphkeys_smooth_exec(bContext *C, wmOperator *)
static const EnumPropertyItem prop_graphkeys_expo_types[]
static const EnumPropertyItem * graph_fmodifier_itemf(bContext *C, PointerRNA *, PropertyRNA *, bool *r_free)
void GRAPH_OT_easing_type(wmOperatorType *ot)
void GRAPH_OT_copy(wmOperatorType *ot)
static void setipo_graph_keys(bAnimContext *ac, short mode)
void GRAPH_OT_driver_delete_invalid(wmOperatorType *ot)
static void convert_samples_to_keys(bAnimContext *ac, int start, int end)
void GRAPH_OT_keyframe_insert(wmOperatorType *ot)
static wmOperatorStatus graphkeys_click_insert_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static wmOperatorStatus graphkeys_framejump_exec(bContext *C, wmOperator *)
static wmOperatorStatus graphkeys_keys_to_samples_exec(bContext *C, wmOperator *)
static wmOperatorStatus graph_fmodifier_copy_exec(bContext *C, wmOperator *op)
void GRAPH_OT_duplicate(wmOperatorType *ot)
static void seteasing_graph_keys(bAnimContext *ac, short mode)
void GRAPH_OT_euler_filter(wmOperatorType *ot)
static bool graphkeys_framejump_poll(bContext *C)
void GRAPH_OT_clean(wmOperatorType *ot)
static wmOperatorStatus graphkeys_samples_to_keys_exec(bContext *C, wmOperator *)
static wmOperatorStatus graphkeys_easing_exec(bContext *C, wmOperator *op)
void GRAPH_OT_snap(wmOperatorType *ot)
static wmOperatorStatus graphkeys_selected_control_points_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static bool duplicate_graph_keys(bAnimContext *ac)
static wmOperatorStatus keyframe_jump_exec(bContext *C, wmOperator *op)
static ListBase euler_filter_group_channels(const ListBase *anim_data, ReportList *reports, int *r_num_groups)
void GRAPH_OT_fmodifier_add(wmOperatorType *ot)
static const EnumPropertyItem prop_graphkeys_snap_types[]
void GRAPH_OT_paste(wmOperatorType *ot)
bool graphop_visible_keyframes_poll(bContext *C)
@ GRAPHKEYS_MIRROR_XAXIS
@ GRAPHKEYS_MIRROR_CFRA
@ GRAPHKEYS_MIRROR_VALUE
@ GRAPHKEYS_MIRROR_YAXIS
@ GRAPHKEYS_MIRROR_MARKER
bool graphop_active_editable_fcurve_ctx_poll(bContext *C)
bAnimListElem * get_active_fcurve_channel(bAnimContext *ac)
@ GRAPHKEYS_SNAP_NEAREST_MARKER
@ GRAPHKEYS_SNAP_VALUE
@ GRAPHKEYS_SNAP_NEAREST_SECOND
@ GRAPHKEYS_SNAP_HORIZONTAL
@ GRAPHKEYS_SNAP_CFRA
@ GRAPHKEYS_SNAP_NEAREST_FRAME
bool graphop_editable_keyframes_poll(bContext *C)
@ GRAPHKEYS_EQUALIZE_RIGHT
@ GRAPHKEYS_EQUALIZE_BOTH
@ GRAPHKEYS_EQUALIZE_LEFT
bool graphop_active_fcurve_poll(bContext *C)
void deselect_graph_keys(bAnimContext *ac, bool test, eEditKeyframes_Select sel, bool do_channels)
bool graphop_selected_fcurve_poll(bContext *C)
KeyframeEditFunc ANIM_editkeyframes_mirror(short mode)
KeyframeEditFunc ANIM_editkeyframes_easing(short mode)
KeyframeEditFunc ANIM_editkeyframes_ipo(short mode)
void ANIM_fcurve_equalize_keyframes_loop(FCurve *fcu, const eEditKeyframes_Equalize mode, const float handle_length, const bool flatten)
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)
const EnumPropertyItem rna_enum_keyframe_paste_offset_items[]
const EnumPropertyItem rna_enum_keyframe_paste_merge_items[]
bool copy_animedit_keys(bAnimContext *ac, ListBase *anim_data)
const EnumPropertyItem rna_enum_keyframe_paste_offset_value_items[]
void clean_fcurve(bAnimListElem *ale, float thresh, bool cleardefault, const bool only_selected_keys)
eKeyPasteError paste_animedit_keys(bAnimContext *ac, ListBase *anim_data, const KeyframePasteContext &paste_context)
void smooth_fcurve(FCurve *fcu)
bool duplicate_fcurve_keys(FCurve *fcu)
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float2 fabs(const float2 a)
#define G(x, y, z)
void animdata_fcurve_delete(AnimData *adt, FCurve *fcu)
Definition animdata.cc:251
KeyframeSettings get_keyframe_settings(bool from_userprefs)
CombinedKeyingResult insert_keyframes(Main *bmain, PointerRNA *struct_pointer, std::optional< StringRefNull > channel_group, const blender::Span< RNAPath > rna_paths, std::optional< float > scene_frame, const AnimationEvalContext &anim_eval_context, eBezTriple_KeyframeType key_type, eInsertKeyFlags insert_key_flags)
Main key-frame insertion API.
SingleKeyingResult insert_vert_fcurve(FCurve *fcu, const float2 position, const KeyframeSettings &settings, eInsertKeyFlags flag)
Main Key-framing API call.
void bake_fcurve_segments(FCurve *fcu)
eInsertKeyFlags get_keyframing_flags(Scene *scene)
float RNA_float_get(PointerRNA *ptr, const char *name)
std::string RNA_string_get(PointerRNA *ptr, const char *name)
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
int RNA_enum_from_value(const EnumPropertyItem *item, const int value)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PointerRNA RNA_id_pointer_create(ID *id)
const EnumPropertyItem rna_enum_beztriple_interpolation_mode_items[]
Definition rna_curve.cc:64
const EnumPropertyItem rna_enum_keyframe_handle_type_items[]
Definition rna_curve.cc:36
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
void RNA_enum_item_end(EnumPropertyItem **items, int *totitem)
void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
const EnumPropertyItem rna_enum_fmodifier_type_items[]
Definition rna_fcurve.cc:29
const EnumPropertyItem rna_enum_beztriple_interpolation_easing_items[]
static wmOperatorStatus keyframe_jump_exec(bContext *C, wmOperator *op)
#define FLT_MAX
Definition stdcycles.h:14
float vec[3][3]
bActionGroup * grp
char * rna_path
FPoint * fpt
ChannelDriver * driver
BezTriple * bezt
short extend
int array_index
unsigned int totvert
ListBase modifiers
struct FModifier * next
Definition DNA_ID.h:414
char name[258]
Definition DNA_ID.h:432
eKeyPasteValueOffset value_offset_mode
eKeyPasteOffset offset_mode
void * last
void * first
struct ToolSettings * toolsettings
struct RenderData r
SpaceLink * sl
ListBase * markers
eAnimCont_Types datatype
ReportList * reports
ARegion * region
Depsgraph * depsgraph
eAnim_Update_Flags update
eBezTriple_KeyframeType keyframe_type
int ymin
int xmin
tEulerFilter * next
const char * rna_path
FCurve * fcurves[3]
tEulerFilter * prev
struct ReportList * reports
struct PointerRNA * ptr
i
Definition text_draw.cc:230
const EnumPropertyItem rna_enum_transform_mode_type_items[]
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorStatus WM_operator_name_call(bContext *C, const char *opstring, blender::wm::OpCallContext context, PointerRNA *properties, const wmEvent *event)
PointerRNA * ptr
Definition wm_files.cc:4238
wmOperatorType * ot
Definition wm_files.cc:4237
void WM_operator_properties_confirm_or_exec(wmOperatorType *ot)
void WM_operator_properties_filesel(wmOperatorType *ot, const int filter, const short type, const eFileSel_Action action, const eFileSel_Flag flag, const short display, const short sort)
wmOperatorStatus WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *)
wmOperatorStatus WM_operator_confirm_ex(bContext *C, wmOperator *op, const char *title, const char *message, const char *confirm_text, int icon, bool cancel_default)
wmOperatorStatus WM_operator_filesel(bContext *C, wmOperator *op, const wmEvent *)
uint8_t flag
Definition wm_window.cc:145