1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
17  * All rights reserved.
18  */
19 
20 /** \file
21  * \ingroup edanimation
22  */
23 
24 #include <float.h>
25 #include <math.h>
26 #include <stddef.h>
27 #include <stdio.h>
28 #include <string.h>
29 
30 #include "MEM_guardedalloc.h"
31 
32 #include "BLI_blenlib.h"
33 #include "BLI_math.h"
34 #include "BLI_utildefines.h"
35 
36 #include "BLT_translation.h"
37 
38 #include "DNA_anim_types.h"
39 #include "DNA_armature_types.h"
40 #include "DNA_constraint_types.h"
41 #include "DNA_key_types.h"
42 #include "DNA_material_types.h"
43 #include "DNA_object_types.h"
44 #include "DNA_rigidbody_types.h"
45 #include "DNA_scene_types.h"
46 
47 #include "BKE_action.h"
48 #include "BKE_anim_data.h"
49 #include "BKE_animsys.h"
50 #include "BKE_armature.h"
51 #include "BKE_context.h"
52 #include "BKE_fcurve.h"
53 #include "BKE_fcurve_driver.h"
54 #include "BKE_global.h"
55 #include "BKE_idtype.h"
56 #include "BKE_key.h"
57 #include "BKE_main.h"
58 #include "BKE_material.h"
59 #include "BKE_nla.h"
60 #include "BKE_report.h"
61 
62 #include "DEG_depsgraph.h"
63 #include "DEG_depsgraph_build.h"
64 #include "DEG_depsgraph_query.h"
65 
66 #include "ED_anim_api.h"
67 #include "ED_keyframes_edit.h"
68 #include "ED_keyframing.h"
69 #include "ED_object.h"
70 #include "ED_screen.h"
71 
72 #include "UI_interface.h"
73 #include "UI_resources.h"
74 
75 #include "WM_api.h"
76 #include "WM_types.h"
77 
78 #include "RNA_access.h"
79 #include "RNA_define.h"
80 #include "RNA_enum_types.h"
81 
82 #include "anim_intern.h"
83 
84 static KeyingSet *keyingset_get_from_op_with_error(wmOperator *op,
85                                                    PropertyRNA *prop,
86                                                    Scene *scene);
87 
88 /* ************************************************** */
89 /* Keyframing Setting Wrangling */
90 
91 /* Get the active settings for keyframing settings from context (specifically the given scene) */
ANIM_get_keyframing_flags(Scene * scene,const bool use_autokey_mode)92 eInsertKeyFlags ANIM_get_keyframing_flags(Scene *scene, const bool use_autokey_mode)
93 {
94   eInsertKeyFlags flag = INSERTKEY_NOFLAGS;
95 
96   /* standard flags */
97   {
98     /* visual keying */
99     if (IS_AUTOKEY_FLAG(scene, AUTOMATKEY)) {
100       flag |= INSERTKEY_MATRIX;
101     }
102 
103     /* only needed */
104     if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) {
105       flag |= INSERTKEY_NEEDED;
106     }
107 
108     /* default F-Curve color mode - RGB from XYZ indices */
109     if (IS_AUTOKEY_FLAG(scene, XYZ2RGB)) {
110       flag |= INSERTKEY_XYZ2RGB;
111     }
112   }
113 
114   /* only if including settings from the autokeying mode... */
115   if (use_autokey_mode) {
116     /* keyframing mode - only replace existing keyframes */
117     if (IS_AUTOKEY_MODE(scene, EDITKEYS)) {
118       flag |= INSERTKEY_REPLACE;
119     }
120 
121     /* cycle-aware keyframe insertion - preserve cycle period and flow */
122     if (IS_AUTOKEY_FLAG(scene, CYCLEAWARE)) {
123       flag |= INSERTKEY_CYCLE_AWARE;
124     }
125   }
126 
127   return flag;
128 }
129 
130 /* ******************************************* */
131 /* Animation Data Validation */
132 
133 /* Get (or add relevant data to be able to do so) the Active Action for the given
134  * Animation Data block, given an ID block where the Animation Data should reside.
135  */
ED_id_action_ensure(Main * bmain,ID * id)136 bAction *ED_id_action_ensure(Main *bmain, ID *id)
137 {
138   AnimData *adt;
139 
140   /* init animdata if none available yet */
141   adt = BKE_animdata_from_id(id);
142   if (adt == NULL) {
143     adt = BKE_animdata_add_id(id);
144   }
145   if (adt == NULL) {
146     /* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */
147     printf("ERROR: Couldn't add AnimData (ID = %s)\n", (id) ? (id->name) : "<None>");
148     return NULL;
149   }
150 
151   /* init action if none available yet */
152   /* TODO: need some wizardry to handle NLA stuff correct */
153   if (adt->action == NULL) {
154     /* init action name from name of ID block */
155     char actname[sizeof(id->name) - 2];
156     BLI_snprintf(actname, sizeof(actname), "%sAction", id->name + 2);
157 
158     /* create action */
159     adt->action = BKE_action_add(bmain, actname);
160 
161     /* set ID-type from ID-block that this is going to be assigned to
162      * so that users can't accidentally break actions by assigning them
163      * to the wrong places
164      */
165     BKE_animdata_action_ensure_idroot(id, adt->action);
166 
167     /* Tag depsgraph to be rebuilt to include time dependency. */
168     DEG_relations_tag_update(bmain);
169   }
170 
171   DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH);
172 
173   /* return the action */
174   return adt->action;
175 }
176 
177 /**
178  * Find the F-Curve from the Active Action,
179  * for the given Animation Data block. This assumes that all the destinations are valid.
180  */
ED_action_fcurve_find(struct bAction * act,const char rna_path[],const int array_index)181 FCurve *ED_action_fcurve_find(struct bAction *act, const char rna_path[], const int array_index)
182 {
183   /* Sanity checks. */
184   if (ELEM(NULL, act, rna_path)) {
185     return NULL;
186   }
187   return BKE_fcurve_find(&act->curves, rna_path, array_index);
188 }
189 
190 /**
191  * Get (or add relevant data to be able to do so) F-Curve from the Active Action,
192  * for the given Animation Data block. This assumes that all the destinations are valid.
193  */
ED_action_fcurve_ensure(struct Main * bmain,struct bAction * act,const char group[],struct PointerRNA * ptr,const char rna_path[],const int array_index)194 FCurve *ED_action_fcurve_ensure(struct Main *bmain,
195                                 struct bAction *act,
196                                 const char group[],
197                                 struct PointerRNA *ptr,
198                                 const char rna_path[],
199                                 const int array_index)
200 {
201   bActionGroup *agrp;
202   FCurve *fcu;
203 
204   /* Sanity checks. */
205   if (ELEM(NULL, act, rna_path)) {
206     return NULL;
207   }
208 
209   /* try to find f-curve matching for this setting
210    * - add if not found and allowed to add one
211    *   TODO: add auto-grouping support? how this works will need to be resolved
212    */
213   fcu = BKE_fcurve_find(&act->curves, rna_path, array_index);
214 
215   if (fcu == NULL) {
216     /* use default settings to make a F-Curve */
217     fcu = BKE_fcurve_create();
218 
219     fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED);
220     fcu->auto_smoothing = U.auto_smoothing_new;
221     if (BLI_listbase_is_empty(&act->curves)) {
222       fcu->flag |= FCURVE_ACTIVE; /* first one added active */
223     }
224 
225     /* store path - make copy, and store that */
226     fcu->rna_path = BLI_strdup(rna_path);
227     fcu->array_index = array_index;
228 
229     /* if a group name has been provided, try to add or find a group, then add F-Curve to it */
230     if (group) {
231       /* try to find group */
232       agrp = BKE_action_group_find_name(act, group);
233 
234       /* no matching groups, so add one */
235       if (agrp == NULL) {
236         agrp = action_groups_add_new(act, group);
237 
238         /* sync bone group colors if applicable */
239         if (ptr && (ptr->type == &RNA_PoseBone)) {
240           Object *ob = (Object *)ptr->owner_id;
241           bPoseChannel *pchan = ptr->data;
242           bPose *pose = ob->pose;
243           bActionGroup *grp;
244 
245           /* find bone group (if present), and use the color from that */
246           grp = (bActionGroup *)BLI_findlink(&pose->agroups, (pchan->agrp_index - 1));
247           if (grp) {
248             agrp->customCol = grp->customCol;
249             action_group_colors_sync(agrp, grp);
250           }
251         }
252       }
253 
254       /* add F-Curve to group */
255       action_groups_add_channel(act, agrp, fcu);
256     }
257     else {
258       /* just add F-Curve to end of Action's list */
259       BLI_addtail(&act->curves, fcu);
260     }
261 
262     /* New f-curve was added, meaning it's possible that it affects
263      * dependency graph component which wasn't previously animated.
264      */
265     DEG_relations_tag_update(bmain);
266   }
267 
268   /* return the F-Curve */
269   return fcu;
270 }
271 
272 /* Helper for update_autoflags_fcurve() */
update_autoflags_fcurve_direct(FCurve * fcu,PropertyRNA * prop)273 static void update_autoflags_fcurve_direct(FCurve *fcu, PropertyRNA *prop)
274 {
275   /* set additional flags for the F-Curve (i.e. only integer values) */
276   fcu->flag &= ~(FCURVE_INT_VALUES | FCURVE_DISCRETE_VALUES);
277   switch (RNA_property_type(prop)) {
278     case PROP_FLOAT:
279       /* do nothing */
280       break;
281     case PROP_INT:
282       /* do integer (only 'whole' numbers) interpolation between all points */
283       fcu->flag |= FCURVE_INT_VALUES;
284       break;
285     default:
286       /* do 'discrete' (i.e. enum, boolean values which cannot take any intermediate
287        * values at all) interpolation between all points
288        *    - however, we must also ensure that evaluated values are only integers still
289        */
290       fcu->flag |= (FCURVE_DISCRETE_VALUES | FCURVE_INT_VALUES);
291       break;
292   }
293 }
294 
295 /* Update integer/discrete flags of the FCurve (used when creating/inserting keyframes,
296  * but also through RNA when editing an ID prop, see T37103).
297  */
update_autoflags_fcurve(FCurve * fcu,bContext * C,ReportList * reports,PointerRNA * ptr)298 void update_autoflags_fcurve(FCurve *fcu, bContext *C, ReportList *reports, PointerRNA *ptr)
299 {
300   PointerRNA tmp_ptr;
301   PropertyRNA *prop;
302   int old_flag = fcu->flag;
303 
304   if ((ptr->owner_id == NULL) && (ptr->data == NULL)) {
305     BKE_report(reports, RPT_ERROR, "No RNA pointer available to retrieve values for this fcurve");
306     return;
307   }
308 
309   /* try to get property we should be affecting */
310   if (RNA_path_resolve_property(ptr, fcu->rna_path, &tmp_ptr, &prop) == false) {
311     /* property not found... */
312     const char *idname = (ptr->owner_id) ? ptr->owner_id->name : TIP_("<No ID pointer>");
313 
314     BKE_reportf(reports,
315                 RPT_ERROR,
316                 "Could not update flags for this fcurve, as RNA path is invalid for the given ID "
317                 "(ID = %s, path = %s)",
318                 idname,
319                 fcu->rna_path);
320     return;
321   }
322 
323   /* update F-Curve flags */
324   update_autoflags_fcurve_direct(fcu, prop);
325 
326   if (old_flag != fcu->flag) {
327     /* Same as if keyframes had been changed */
328     WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
329   }
330 }
331 
332 /* ************************************************** */
333 /* KEYFRAME INSERTION */
334 
335 /* Move the point where a key is about to be inserted to be inside the main cycle range.
336  * Returns the type of the cycle if it is enabled and valid.
337  */
remap_cyclic_keyframe_location(FCurve * fcu,float * px,float * py)338 static eFCU_Cycle_Type remap_cyclic_keyframe_location(FCurve *fcu, float *px, float *py)
339 {
340   if (fcu->totvert < 2 || !fcu->bezt) {
341     return FCU_CYCLE_NONE;
342   }
343 
344   eFCU_Cycle_Type type = BKE_fcurve_get_cycle_type(fcu);
345 
346   if (type == FCU_CYCLE_NONE) {
347     return FCU_CYCLE_NONE;
348   }
349 
350   BezTriple *first = &fcu->bezt[0], *last = &fcu->bezt[fcu->totvert - 1];
351   float start = first->vec[1][0], end = last->vec[1][0];
352 
353   if (start >= end) {
354     return FCU_CYCLE_NONE;
355   }
356 
357   if (*px < start || *px > end) {
358     float period = end - start;
359     float step = floorf((*px - start) / period);
360     *px -= step * period;
361 
362     if (type == FCU_CYCLE_OFFSET) {
363       /* Nasty check to handle the case when the modes are different better. */
364       FMod_Cycles *data = ((FModifier *)fcu->modifiers.first)->data;
365       short mode = (step >= 0) ? data->after_mode : data->before_mode;
366 
367       if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
368         *py -= step * (last->vec[1][1] - first->vec[1][1]);
369       }
370     }
371   }
372 
373   return type;
374 }
375 
376 /* -------------- BezTriple Insertion -------------------- */
377 
378 /* Change the Y position of a keyframe to match the input, adjusting handles. */
replace_bezt_keyframe_ypos(BezTriple * dst,const BezTriple * bezt)379 static void replace_bezt_keyframe_ypos(BezTriple *dst, const BezTriple *bezt)
380 {
381   /* just change the values when replacing, so as to not overwrite handles */
382   float dy = bezt->vec[1][1] - dst->vec[1][1];
383 
384   /* just apply delta value change to the handle values */
385   dst->vec[0][1] += dy;
386   dst->vec[1][1] += dy;
387   dst->vec[2][1] += dy;
388 
389   dst->f1 = bezt->f1;
390   dst->f2 = bezt->f2;
391   dst->f3 = bezt->f3;
392 
393   /* TODO: perform some other operations? */
394 }
395 
396 /* This function adds a given BezTriple to an F-Curve. It will allocate
397  * memory for the array if needed, and will insert the BezTriple into a
398  * suitable place in chronological order.
399  *
400  * NOTE: any recalculate of the F-Curve that needs to be done will need to
401  *      be done by the caller.
402  */
insert_bezt_fcurve(FCurve * fcu,const BezTriple * bezt,eInsertKeyFlags flag)403 int insert_bezt_fcurve(FCurve *fcu, const BezTriple *bezt, eInsertKeyFlags flag)
404 {
405   int i = 0;
406 
407   /* are there already keyframes? */
408   if (fcu->bezt) {
409     bool replace;
410     i = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, bezt->vec[1][0], fcu->totvert, &replace);
411 
412     /* replace an existing keyframe? */
413     if (replace) {
414       /* sanity check: 'i' may in rare cases exceed arraylen */
415       if ((i >= 0) && (i < fcu->totvert)) {
416         if (flag & INSERTKEY_OVERWRITE_FULL) {
417           fcu->bezt[i] = *bezt;
418         }
419         else {
420           replace_bezt_keyframe_ypos(&fcu->bezt[i], bezt);
421         }
422 
423         if (flag & INSERTKEY_CYCLE_AWARE) {
424           /* If replacing an end point of a cyclic curve without offset,
425            * modify the other end too. */
426           if ((i == 0 || i == fcu->totvert - 1) &&
427               BKE_fcurve_get_cycle_type(fcu) == FCU_CYCLE_PERFECT) {
428             replace_bezt_keyframe_ypos(&fcu->bezt[i == 0 ? fcu->totvert - 1 : 0], bezt);
429           }
430         }
431       }
432     }
433     /* keyframing modes allow to not replace keyframe */
434     else if ((flag & INSERTKEY_REPLACE) == 0) {
435       /* insert new - if we're not restricted to replacing keyframes only */
436       BezTriple *newb = MEM_callocN((fcu->totvert + 1) * sizeof(BezTriple), "beztriple");
437 
438       /* Add the beztriples that should occur before the beztriple to be pasted
439        * (originally in fcu). */
440       if (i > 0) {
441         memcpy(newb, fcu->bezt, i * sizeof(BezTriple));
442       }
443 
444       /* add beztriple to paste at index i */
445       *(newb + i) = *bezt;
446 
447       /* add the beztriples that occur after the beztriple to be pasted (originally in fcu) */
448       if (i < fcu->totvert) {
449         memcpy(newb + i + 1, fcu->bezt + i, (fcu->totvert - i) * sizeof(BezTriple));
450       }
451 
452       /* replace (+ free) old with new, only if necessary to do so */
453       MEM_freeN(fcu->bezt);
454       fcu->bezt = newb;
455 
456       fcu->totvert++;
457     }
458     else {
459       return -1;
460     }
461   }
462   /* no keyframes already, but can only add if...
463    * 1) keyframing modes say that keyframes can only be replaced, so adding new ones won't know
464    * 2) there are no samples on the curve
465    *    NOTE: maybe we may want to allow this later when doing samples -> bezt conversions,
466    *    but for now, having both is asking for trouble
467    */
468   else if ((flag & INSERTKEY_REPLACE) == 0 && (fcu->fpt == NULL)) {
469     /* create new keyframes array */
470     fcu->bezt = MEM_callocN(sizeof(BezTriple), "beztriple");
471     *(fcu->bezt) = *bezt;
472     fcu->totvert = 1;
473   }
474   /* cannot add anything */
475   else {
476     /* return error code -1 to prevent any misunderstandings */
477     return -1;
478   }
479 
480   /* we need to return the index, so that some tools which do post-processing can
481    * detect where we added the BezTriple in the array
482    */
483   return i;
484 }
485 
486 /** Update the FCurve to allow insertion of `bezt` without modifying the curve shape.
487  *
488  * Checks whether it is necessary to apply Bezier subdivision due to involvement of non-auto
489  * handles. If necessary, changes `bezt` handles from Auto to Aligned.
490  *
491  * \param bezt: key being inserted
492  * \param prev: keyframe before that key
493  * \param next: keyframe after that key
494  */
subdivide_nonauto_handles(const FCurve * fcu,BezTriple * bezt,BezTriple * prev,BezTriple * next)495 static void subdivide_nonauto_handles(const FCurve *fcu,
496                                       BezTriple *bezt,
497                                       BezTriple *prev,
498                                       BezTriple *next)
499 {
500   if (prev->ipo != BEZT_IPO_BEZ || bezt->ipo != BEZT_IPO_BEZ) {
501     return;
502   }
503 
504   /* Don't change Vector handles, or completely auto regions. */
505   const bool bezt_auto = BEZT_IS_AUTOH(bezt) || (bezt->h1 == HD_VECT && bezt->h2 == HD_VECT);
506   const bool prev_auto = BEZT_IS_AUTOH(prev) || (prev->h2 == HD_VECT);
507   const bool next_auto = BEZT_IS_AUTOH(next) || (next->h1 == HD_VECT);
508   if (bezt_auto && prev_auto && next_auto) {
509     return;
510   }
511 
512   /* Subdivide the curve. */
513   float delta;
514   if (!BKE_fcurve_bezt_subdivide_handles(bezt, prev, next, &delta)) {
515     return;
516   }
517 
518   /* Decide when to force auto to manual. */
519   if (!BEZT_IS_AUTOH(bezt)) {
520     return;
521   }
522   if ((prev_auto || next_auto) && fcu->auto_smoothing == FCURVE_SMOOTH_CONT_ACCEL) {
523     const float hx = bezt->vec[1][0] - bezt->vec[0][0];
524     const float dx = bezt->vec[1][0] - prev->vec[1][0];
525 
526     /* This mode always uses 1/3 of key distance for handle x size. */
527     const bool auto_works_well = fabsf(hx - dx / 3.0f) < 0.001f;
528     if (auto_works_well) {
529       return;
530     }
531   }
532 
533   /* Turn off auto mode. */
534   bezt->h1 = bezt->h2 = HD_ALIGN;
535 }
536 
537 /**
538  * This function is a wrapper for #insert_bezt_fcurve(), and should be used when
539  * adding a new keyframe to a curve, when the keyframe doesn't exist anywhere else yet.
540  * It returns the index at which the keyframe was added.
541  *
542  * \param keyframe_type: The type of keyframe (#eBezTriple_KeyframeType).
543  * \param flag: Optional flags (eInsertKeyFlags) for controlling how keys get added
544  * and/or whether updates get done.
545  */
insert_vert_fcurve(FCurve * fcu,float x,float y,eBezTriple_KeyframeType keyframe_type,eInsertKeyFlags flag)546 int insert_vert_fcurve(
547     FCurve *fcu, float x, float y, eBezTriple_KeyframeType keyframe_type, eInsertKeyFlags flag)
548 {
549   BezTriple beztr = {{{0}}};
550   uint oldTot = fcu->totvert;
551   int a;
552 
553   /* set all three points, for nicer start position
554    * NOTE: +/- 1 on vec.x for left and right handles is so that 'free' handles work ok...
555    */
556   beztr.vec[0][0] = x - 1.0f;
557   beztr.vec[0][1] = y;
558   beztr.vec[1][0] = x;
559   beztr.vec[1][1] = y;
560   beztr.vec[2][0] = x + 1.0f;
561   beztr.vec[2][1] = y;
562   beztr.f1 = beztr.f2 = beztr.f3 = SELECT;
563 
564   /* set default handle types and interpolation mode */
565   if (flag & INSERTKEY_NO_USERPREF) {
566     /* for Py-API, we want scripts to have predictable behavior,
567      * hence the option to not depend on the userpref defaults
568      */
569     beztr.h1 = beztr.h2 = HD_AUTO_ANIM;
570     beztr.ipo = BEZT_IPO_BEZ;
571   }
572   else {
573     /* for UI usage - defaults should come from the userprefs and/or toolsettings */
574     beztr.h1 = beztr.h2 = U.keyhandles_new; /* use default handle type here */
575 
576     /* use default interpolation mode, with exceptions for int/discrete values */
577     beztr.ipo = U.ipo_new;
578   }
579 
580   /* interpolation type used is constrained by the type of values the curve can take */
581   if (fcu->flag & FCURVE_DISCRETE_VALUES) {
582     beztr.ipo = BEZT_IPO_CONST;
583   }
584   else if ((beztr.ipo == BEZT_IPO_BEZ) && (fcu->flag & FCURVE_INT_VALUES)) {
585     beztr.ipo = BEZT_IPO_LIN;
586   }
587 
588   /* set keyframe type value (supplied), which should come from the scene settings in most cases */
589   BEZKEYTYPE(&beztr) = keyframe_type;
590 
591   /* set default values for "easing" interpolation mode settings
592    * NOTE: Even if these modes aren't currently used, if users switch
593    *       to these later, we want these to work in a sane way out of
594    *       the box.
595    */
596 
597   /* "back" easing - this value used to be used when overshoot=0, but that
598    *                 introduced discontinuities in how the param worked. */
599   beztr.back = 1.70158f;
600 
601   /* "elastic" easing - values here were hand-optimized for a default duration of
602    *                    ~10 frames (typical mograph motion length) */
603   beztr.amplitude = 0.8f;
604   beztr.period = 4.1f;
605 
606   /* add temp beztriple to keyframes */
607   a = insert_bezt_fcurve(fcu, &beztr, flag);
608   BKE_fcurve_active_keyframe_set(fcu, &fcu->bezt[a]);
609 
610   /* what if 'a' is a negative index?
611    * for now, just exit to prevent any segfaults
612    */
613   if (a < 0) {
614     return -1;
615   }
616 
617   /* set handletype and interpolation */
618   if ((fcu->totvert > 2) && (flag & INSERTKEY_REPLACE) == 0) {
619     BezTriple *bezt = (fcu->bezt + a);
620 
621     /* Set interpolation from previous (if available),
622      * but only if we didn't just replace some keyframe:
623      * - Replacement is indicated by no-change in number of verts.
624      * - When replacing, the user may have specified some interpolation that should be kept.
625      */
626     if (fcu->totvert > oldTot) {
627       if (a > 0) {
628         bezt->ipo = (bezt - 1)->ipo;
629       }
630       else if (a < fcu->totvert - 1) {
631         bezt->ipo = (bezt + 1)->ipo;
632       }
633 
634       if (0 < a && a < (fcu->totvert - 1) && (flag & INSERTKEY_OVERWRITE_FULL) == 0) {
635         subdivide_nonauto_handles(fcu, bezt, bezt - 1, bezt + 1);
636       }
637     }
638   }
639 
640   /* don't recalculate handles if fast is set
641    * - this is a hack to make importers faster
642    * - we may calculate twice (due to autohandle needing to be calculated twice)
643    */
644   if ((flag & INSERTKEY_FAST) == 0) {
645     calchandles_fcurve(fcu);
646   }
647 
648   /* return the index at which the keyframe was added */
649   return a;
650 }
651 
652 /* -------------- 'Smarter' Keyframing Functions -------------------- */
653 /* return codes for new_key_needed */
654 enum {
655   KEYNEEDED_DONTADD = 0,
656   KEYNEEDED_JUSTADD,
657   KEYNEEDED_DELPREV,
658   KEYNEEDED_DELNEXT,
659 } /*eKeyNeededStatus*/;
660 
661 /* This helper function determines whether a new keyframe is needed */
662 /* Cases where keyframes should not be added:
663  * 1. Keyframe to be added between two keyframes with similar values
664  * 2. Keyframe to be added on frame where two keyframes are already situated
665  * 3. Keyframe lies at point that intersects the linear line between two keyframes
666  */
new_key_needed(FCurve * fcu,float cFrame,float nValue)667 static short new_key_needed(FCurve *fcu, float cFrame, float nValue)
668 {
669   /* safety checking */
670   if (fcu == NULL) {
671     return KEYNEEDED_JUSTADD;
672   }
673   int totCount = fcu->totvert;
674   if (totCount == 0) {
675     return KEYNEEDED_JUSTADD;
676   }
677 
678   /* loop through checking if any are the same */
679   BezTriple *bezt = fcu->bezt;
680   BezTriple *prev = NULL;
681   for (int i = 0; i < totCount; i++) {
682     float prevPosi = 0.0f, prevVal = 0.0f;
683     float beztPosi = 0.0f, beztVal = 0.0f;
684 
685     /* get current time+value */
686     beztPosi = bezt->vec[1][0];
687     beztVal = bezt->vec[1][1];
688 
689     if (prev) {
690       /* there is a keyframe before the one currently being examined */
691 
692       /* get previous time+value */
693       prevPosi = prev->vec[1][0];
694       prevVal = prev->vec[1][1];
695 
696       /* keyframe to be added at point where there are already two similar points? */
697       if (IS_EQF(prevPosi, cFrame) && IS_EQF(beztPosi, cFrame) && IS_EQF(beztPosi, prevPosi)) {
698         return KEYNEEDED_DONTADD;
699       }
700 
701       /* keyframe between prev+current points ? */
702       if ((prevPosi <= cFrame) && (cFrame <= beztPosi)) {
703         /* is the value of keyframe to be added the same as keyframes on either side ? */
704         if (IS_EQF(prevVal, nValue) && IS_EQF(beztVal, nValue) && IS_EQF(prevVal, beztVal)) {
705           return KEYNEEDED_DONTADD;
706         }
707 
708         float realVal;
709 
710         /* get real value of curve at that point */
711         realVal = evaluate_fcurve(fcu, cFrame);
712 
713         /* compare whether it's the same as proposed */
714         if (IS_EQF(realVal, nValue)) {
715           return KEYNEEDED_DONTADD;
716         }
717         return KEYNEEDED_JUSTADD;
718       }
719 
720       /* new keyframe before prev beztriple? */
721       if (cFrame < prevPosi) {
722         /* A new keyframe will be added. However, whether the previous beztriple
723          * stays around or not depends on whether the values of previous/current
724          * beztriples and new keyframe are the same.
725          */
726         if (IS_EQF(prevVal, nValue) && IS_EQF(beztVal, nValue) && IS_EQF(prevVal, beztVal)) {
727           return KEYNEEDED_DELNEXT;
728         }
729 
730         return KEYNEEDED_JUSTADD;
731       }
732     }
733     else {
734       /* just add a keyframe if there's only one keyframe
735        * and the new one occurs before the existing one does.
736        */
737       if ((cFrame < beztPosi) && (totCount == 1)) {
738         return KEYNEEDED_JUSTADD;
739       }
740     }
741 
742     /* continue. frame to do not yet passed (or other conditions not met) */
743     if (i < (totCount - 1)) {
744       prev = bezt;
745       bezt++;
746     }
747     else {
748       break;
749     }
750   }
751 
752   /* Frame in which to add a new-keyframe occurs after all other keys
753    * -> If there are at least two existing keyframes, then if the values of the
754    *    last two keyframes and the new-keyframe match, the last existing keyframe
755    *    gets deleted as it is no longer required.
756    * -> Otherwise, a keyframe is just added. 1.0 is added so that fake-2nd-to-last
757    *    keyframe is not equal to last keyframe.
758    */
759   bezt = (fcu->bezt + (fcu->totvert - 1));
760   float valA = bezt->vec[1][1];
761   float valB;
762   if (prev) {
763     valB = prev->vec[1][1];
764   }
765   else {
766     valB = bezt->vec[1][1] + 1.0f;
767   }
768 
769   if (IS_EQF(valA, nValue) && IS_EQF(valA, valB)) {
770     return KEYNEEDED_DELPREV;
771   }
772 
773   return KEYNEEDED_JUSTADD;
774 }
775 
776 /* ------------------ RNA Data-Access Functions ------------------ */
777 
778 /* Try to read value using RNA-properties obtained already */
setting_get_rna_values(PointerRNA * ptr,PropertyRNA * prop,float * buffer,int buffer_size,int * r_count)779 static float *setting_get_rna_values(
780     PointerRNA *ptr, PropertyRNA *prop, float *buffer, int buffer_size, int *r_count)
781 {
782   BLI_assert(buffer_size >= 1);
783 
784   float *values = buffer;
785 
786   if (RNA_property_array_check(prop)) {
787     int length = *r_count = RNA_property_array_length(ptr, prop);
788     bool *tmp_bool;
789     int *tmp_int;
790 
791     if (length > buffer_size) {
792       values = MEM_malloc_arrayN(sizeof(float), length, __func__);
793     }
794 
795     switch (RNA_property_type(prop)) {
796       case PROP_BOOLEAN:
797         tmp_bool = MEM_malloc_arrayN(sizeof(*tmp_bool), length, __func__);
798         RNA_property_boolean_get_array(ptr, prop, tmp_bool);
799         for (int i = 0; i < length; i++) {
800           values[i] = (float)tmp_bool[i];
801         }
802         MEM_freeN(tmp_bool);
803         break;
804       case PROP_INT:
805         tmp_int = MEM_malloc_arrayN(sizeof(*tmp_int), length, __func__);
806         RNA_property_int_get_array(ptr, prop, tmp_int);
807         for (int i = 0; i < length; i++) {
808           values[i] = (float)tmp_int[i];
809         }
810         MEM_freeN(tmp_int);
811         break;
812       case PROP_FLOAT:
813         RNA_property_float_get_array(ptr, prop, values);
814         break;
815       default:
816         memset(values, 0, sizeof(float) * length);
817     }
818   }
819   else {
820     *r_count = 1;
821 
822     switch (RNA_property_type(prop)) {
823       case PROP_BOOLEAN:
824         *values = (float)RNA_property_boolean_get(ptr, prop);
825         break;
826       case PROP_INT:
827         *values = (float)RNA_property_int_get(ptr, prop);
828         break;
829       case PROP_FLOAT:
830         *values = RNA_property_float_get(ptr, prop);
831         break;
832       case PROP_ENUM:
833         *values = (float)RNA_property_enum_get(ptr, prop);
834         break;
835       default:
836         *values = 0.0f;
837     }
838   }
839 
840   return values;
841 }
842 
843 /* ------------------ 'Visual' Keyframing Functions ------------------ */
844 
845 /* internal status codes for visualkey_can_use */
846 enum {
847   VISUALKEY_NONE = 0,
848   VISUALKEY_LOC,
849   VISUALKEY_ROT,
850   VISUALKEY_SCA,
851 };
852 
853 /* This helper function determines if visual-keyframing should be used when
854  * inserting keyframes for the given channel. As visual-keyframing only works
855  * on Object and Pose-Channel blocks, this should only get called for those
856  * blocktypes, when using "standard" keying but 'Visual Keying' option in Auto-Keying
857  * settings is on.
858  */
visualkey_can_use(PointerRNA * ptr,PropertyRNA * prop)859 static bool visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop)
860 {
861   bConstraint *con = NULL;
862   short searchtype = VISUALKEY_NONE;
863   bool has_rigidbody = false;
864   bool has_parent = false;
865   const char *identifier = NULL;
866 
867   /* validate data */
868   if (ELEM(NULL, ptr, ptr->data, prop)) {
869     return false;
870   }
871 
872   /* get first constraint and determine type of keyframe constraints to check for
873    * - constraints can be on either Objects or PoseChannels, so we only check if the
874    *   ptr->type is RNA_Object or RNA_PoseBone, which are the RNA wrapping-info for
875    *   those structs, allowing us to identify the owner of the data
876    */
877   if (ptr->type == &RNA_Object) {
878     /* Object */
879     Object *ob = ptr->data;
880     RigidBodyOb *rbo = ob->rigidbody_object;
881 
882     con = ob->constraints.first;
883     identifier = RNA_property_identifier(prop);
884     has_parent = (ob->parent != NULL);
885 
886     /* active rigidbody objects only, as only those are affected by sim */
887     has_rigidbody = ((rbo) && (rbo->type == RBO_TYPE_ACTIVE));
888   }
889   else if (ptr->type == &RNA_PoseBone) {
890     /* Pose Channel */
891     bPoseChannel *pchan = ptr->data;
892 
893     con = pchan->constraints.first;
894     identifier = RNA_property_identifier(prop);
895     has_parent = (pchan->parent != NULL);
896   }
897 
898   /* check if any data to search using */
899   if (ELEM(NULL, con, identifier) && (has_parent == false) && (has_rigidbody == false)) {
900     return false;
901   }
902 
903   /* location or rotation identifiers only... */
904   if (identifier == NULL) {
905     printf("%s failed: NULL identifier\n", __func__);
906     return false;
907   }
908 
909   if (strstr(identifier, "location")) {
910     searchtype = VISUALKEY_LOC;
911   }
912   else if (strstr(identifier, "rotation")) {
913     searchtype = VISUALKEY_ROT;
914   }
915   else if (strstr(identifier, "scale")) {
916     searchtype = VISUALKEY_SCA;
917   }
918   else {
919     printf("%s failed: identifier - '%s'\n", __func__, identifier);
920     return false;
921   }
922 
923   /* only search if a searchtype and initial constraint are available */
924   if (searchtype) {
925     /* parent or rigidbody are always matching */
926     if (has_parent || has_rigidbody) {
927       return true;
928     }
929 
930     /* constraints */
931     for (; con; con = con->next) {
932       /* only consider constraint if it is not disabled, and has influence */
933       if (con->flag & CONSTRAINT_DISABLE) {
934         continue;
935       }
936       if (con->enforce == 0.0f) {
937         continue;
938       }
939 
940       /* some constraints may alter these transforms */
941       switch (con->type) {
942         /* multi-transform constraints */
943         case CONSTRAINT_TYPE_CHILDOF:
944         case CONSTRAINT_TYPE_ARMATURE:
945           return true;
946         case CONSTRAINT_TYPE_TRANSFORM:
947         case CONSTRAINT_TYPE_TRANSLIKE:
948           return true;
949         case CONSTRAINT_TYPE_FOLLOWPATH:
950           return true;
951         case CONSTRAINT_TYPE_KINEMATIC:
952           return true;
953 
954         /* single-transform constraints  */
955         case CONSTRAINT_TYPE_TRACKTO:
956           if (searchtype == VISUALKEY_ROT) {
957             return true;
958           }
959           break;
960         case CONSTRAINT_TYPE_DAMPTRACK:
961           if (searchtype == VISUALKEY_ROT) {
962             return true;
963           }
964           break;
965         case CONSTRAINT_TYPE_ROTLIMIT:
966           if (searchtype == VISUALKEY_ROT) {
967             return true;
968           }
969           break;
970         case CONSTRAINT_TYPE_LOCLIMIT:
971           if (searchtype == VISUALKEY_LOC) {
972             return true;
973           }
974           break;
975         case CONSTRAINT_TYPE_SIZELIMIT:
976           if (searchtype == VISUALKEY_SCA) {
977             return true;
978           }
979           break;
980         case CONSTRAINT_TYPE_DISTLIMIT:
981           if (searchtype == VISUALKEY_LOC) {
982             return true;
983           }
984           break;
985         case CONSTRAINT_TYPE_ROTLIKE:
986           if (searchtype == VISUALKEY_ROT) {
987             return true;
988           }
989           break;
990         case CONSTRAINT_TYPE_LOCLIKE:
991           if (searchtype == VISUALKEY_LOC) {
992             return true;
993           }
994           break;
995         case CONSTRAINT_TYPE_SIZELIKE:
996           if (searchtype == VISUALKEY_SCA) {
997             return true;
998           }
999           break;
1000         case CONSTRAINT_TYPE_LOCKTRACK:
1001           if (searchtype == VISUALKEY_ROT) {
1002             return true;
1003           }
1004           break;
1005         case CONSTRAINT_TYPE_MINMAX:
1006           if (searchtype == VISUALKEY_LOC) {
1007             return true;
1008           }
1009           break;
1010 
1011         default:
1012           break;
1013       }
1014     }
1015   }
1016 
1017   /* when some condition is met, this function returns, so that means we've got nothing */
1018   return false;
1019 }
1020 
1021 /* This helper function extracts the value to use for visual-keyframing
1022  * In the event that it is not possible to perform visual keying, try to fall-back
1023  * to using the default method. Assumes that all data it has been passed is valid.
1024  */
visualkey_get_values(PointerRNA * ptr,PropertyRNA * prop,float * buffer,int buffer_size,int * r_count)1025 static float *visualkey_get_values(
1026     PointerRNA *ptr, PropertyRNA *prop, float *buffer, int buffer_size, int *r_count)
1027 {
1028   BLI_assert(buffer_size >= 4);
1029 
1030   const char *identifier = RNA_property_identifier(prop);
1031   float tmat[4][4];
1032   int rotmode;
1033 
1034   /* handle for Objects or PoseChannels only
1035    * - only Location, Rotation or Scale keyframes are supported currently
1036    * - constraints can be on either Objects or PoseChannels, so we only check if the
1037    *   ptr->type is RNA_Object or RNA_PoseBone, which are the RNA wrapping-info for
1038    *       those structs, allowing us to identify the owner of the data
1039    * - assume that array_index will be sane
1040    */
1041   if (ptr->type == &RNA_Object) {
1042     Object *ob = ptr->data;
1043     /* Loc code is specific... */
1044     if (strstr(identifier, "location")) {
1045       copy_v3_v3(buffer, ob->obmat[3]);
1046       *r_count = 3;
1047       return buffer;
1048     }
1049 
1050     copy_m4_m4(tmat, ob->obmat);
1051     rotmode = ob->rotmode;
1052   }
1053   else if (ptr->type == &RNA_PoseBone) {
1054     bPoseChannel *pchan = ptr->data;
1055 
1056     BKE_armature_mat_pose_to_bone(pchan, pchan->pose_mat, tmat);
1057     rotmode = pchan->rotmode;
1058 
1059     /* Loc code is specific... */
1060     if (strstr(identifier, "location")) {
1061       /* only use for non-connected bones */
1062       if ((pchan->bone->parent == NULL) || !(pchan->bone->flag & BONE_CONNECTED)) {
1063         copy_v3_v3(buffer, tmat[3]);
1064         *r_count = 3;
1065         return buffer;
1066       }
1067     }
1068   }
1069   else {
1070     return setting_get_rna_values(ptr, prop, buffer, buffer_size, r_count);
1071   }
1072 
1073   /* Rot/Scale code are common! */
1074   if (strstr(identifier, "rotation_euler")) {
1075     mat4_to_eulO(buffer, rotmode, tmat);
1076 
1077     *r_count = 3;
1078     return buffer;
1079   }
1080 
1081   if (strstr(identifier, "rotation_quaternion")) {
1082     float mat3[3][3];
1083 
1084     copy_m3_m4(mat3, tmat);
1085     mat3_to_quat_is_ok(buffer, mat3);
1086 
1087     *r_count = 4;
1088     return buffer;
1089   }
1090 
1091   if (strstr(identifier, "rotation_axis_angle")) {
1092     /* w = 0, x,y,z = 1,2,3 */
1093     mat4_to_axis_angle(buffer + 1, buffer, tmat);
1094 
1095     *r_count = 4;
1096     return buffer;
1097   }
1098 
1099   if (strstr(identifier, "scale")) {
1100     mat4_to_size(buffer, tmat);
1101 
1102     *r_count = 3;
1103     return buffer;
1104   }
1105 
1106   /* as the function hasn't returned yet, read value from system in the default way */
1107   return setting_get_rna_values(ptr, prop, buffer, buffer_size, r_count);
1108 }
1109 
1110 /* ------------------------- Insert Key API ------------------------- */
1111 
1112 /**
1113  * Retrieve current property values to keyframe,
1114  * possibly applying NLA correction when necessary.
1115  */
get_keyframe_values(ReportList * reports,PointerRNA ptr,PropertyRNA * prop,int index,struct NlaKeyframingContext * nla_context,eInsertKeyFlags flag,float * buffer,int buffer_size,int * r_count,bool * r_force_all)1116 static float *get_keyframe_values(ReportList *reports,
1117                                   PointerRNA ptr,
1118                                   PropertyRNA *prop,
1119                                   int index,
1120                                   struct NlaKeyframingContext *nla_context,
1121                                   eInsertKeyFlags flag,
1122                                   float *buffer,
1123                                   int buffer_size,
1124                                   int *r_count,
1125                                   bool *r_force_all)
1126 {
1127   float *values;
1128 
1129   if ((flag & INSERTKEY_MATRIX) && (visualkey_can_use(&ptr, prop))) {
1130     /* visual-keying is only available for object and pchan datablocks, as
1131      * it works by keyframing using a value extracted from the final matrix
1132      * instead of using the kt system to extract a value.
1133      */
1134     values = visualkey_get_values(&ptr, prop, buffer, buffer_size, r_count);
1135   }
1136   else {
1137     /* read value from system */
1138     values = setting_get_rna_values(&ptr, prop, buffer, buffer_size, r_count);
1139   }
1140 
1141   /* adjust the value for NLA factors */
1142   if (!BKE_animsys_nla_remap_keyframe_values(
1143           nla_context, &ptr, prop, values, *r_count, index, r_force_all)) {
1144     BKE_report(
1145         reports, RPT_ERROR, "Could not insert keyframe due to zero NLA influence or base value");
1146 
1147     if (values != buffer) {
1148       MEM_freeN(values);
1149     }
1150     return NULL;
1151   }
1152 
1153   return values;
1154 }
1155 
1156 /* Insert the specified keyframe value into a single F-Curve. */
insert_keyframe_value(ReportList * reports,PointerRNA * ptr,PropertyRNA * prop,FCurve * fcu,const AnimationEvalContext * anim_eval_context,float curval,eBezTriple_KeyframeType keytype,eInsertKeyFlags flag)1157 static bool insert_keyframe_value(ReportList *reports,
1158                                   PointerRNA *ptr,
1159                                   PropertyRNA *prop,
1160                                   FCurve *fcu,
1161                                   const AnimationEvalContext *anim_eval_context,
1162                                   float curval,
1163                                   eBezTriple_KeyframeType keytype,
1164                                   eInsertKeyFlags flag)
1165 {
1166   /* F-Curve not editable? */
1167   if (BKE_fcurve_is_keyframable(fcu) == 0) {
1168     BKE_reportf(
1169         reports,
1170         RPT_ERROR,
1171         "F-Curve with path '%s[%d]' cannot be keyframed, ensure that it is not locked or sampled, "
1172         "and try removing F-Modifiers",
1173         fcu->rna_path,
1174         fcu->array_index);
1175     return false;
1176   }
1177 
1178   float cfra = anim_eval_context->eval_time;
1179 
1180   /* adjust frame on which to add keyframe */
1181   if ((flag & INSERTKEY_DRIVER) && (fcu->driver)) {
1182     PathResolvedRNA anim_rna;
1183 
1184     if (RNA_path_resolved_create(ptr, prop, fcu->array_index, &anim_rna)) {
1185       /* for making it easier to add corrective drivers... */
1186       cfra = evaluate_driver(&anim_rna, fcu->driver, fcu->driver, anim_eval_context);
1187     }
1188     else {
1189       cfra = 0.0f;
1190     }
1191   }
1192 
1193   /* adjust coordinates for cycle aware insertion */
1194   if (flag & INSERTKEY_CYCLE_AWARE) {
1195     if (remap_cyclic_keyframe_location(fcu, &cfra, &curval) != FCU_CYCLE_PERFECT) {
1196       /* inhibit action from insert_vert_fcurve unless it's a perfect cycle */
1197       flag &= ~INSERTKEY_CYCLE_AWARE;
1198     }
1199   }
1200 
1201   /* only insert keyframes where they are needed */
1202   if (flag & INSERTKEY_NEEDED) {
1203     short insert_mode;
1204 
1205     /* check whether this curve really needs a new keyframe */
1206     insert_mode = new_key_needed(fcu, cfra, curval);
1207 
1208     /* only return success if keyframe added */
1209     if (insert_mode == KEYNEEDED_DONTADD) {
1210       return false;
1211     }
1212 
1213     /* insert new keyframe at current frame */
1214     if (insert_vert_fcurve(fcu, cfra, curval, keytype, flag) < 0) {
1215       return false;
1216     }
1217 
1218     /* delete keyframe immediately before/after newly added */
1219     switch (insert_mode) {
1220       case KEYNEEDED_DELPREV:
1221         delete_fcurve_key(fcu, fcu->totvert - 2, 1);
1222         break;
1223       case KEYNEEDED_DELNEXT:
1224         delete_fcurve_key(fcu, 1, 1);
1225         break;
1226     }
1227 
1228     return true;
1229   }
1230 
1231   /* just insert keyframe */
1232   return insert_vert_fcurve(fcu, cfra, curval, keytype, flag) >= 0;
1233 }
1234 
1235 /* Secondary Keyframing API call:
1236  * Use this when validation of necessary animation data is not necessary,
1237  * since an RNA-pointer to the necessary data being keyframed,
1238  * and a pointer to the F-Curve to use have both been provided.
1239  *
1240  * This function can't keyframe quaternion channels on some NLA strip types.
1241  *
1242  * keytype is the "keyframe type" (eBezTriple_KeyframeType), as shown in the Dope Sheet.
1243  *
1244  * The flag argument is used for special settings that alter the behavior of
1245  * the keyframe insertion. These include the 'visual' keyframing modes, quick refresh,
1246  * and extra keyframe filtering.
1247  */
insert_keyframe_direct(ReportList * reports,PointerRNA ptr,PropertyRNA * prop,FCurve * fcu,const AnimationEvalContext * anim_eval_context,eBezTriple_KeyframeType keytype,struct NlaKeyframingContext * nla_context,eInsertKeyFlags flag)1248 bool insert_keyframe_direct(ReportList *reports,
1249                             PointerRNA ptr,
1250                             PropertyRNA *prop,
1251                             FCurve *fcu,
1252                             const AnimationEvalContext *anim_eval_context,
1253                             eBezTriple_KeyframeType keytype,
1254                             struct NlaKeyframingContext *nla_context,
1255                             eInsertKeyFlags flag)
1256 {
1257   float curval = 0.0f;
1258 
1259   /* no F-Curve to add keyframe to? */
1260   if (fcu == NULL) {
1261     BKE_report(reports, RPT_ERROR, "No F-Curve to add keyframes to");
1262     return false;
1263   }
1264 
1265   /* if no property given yet, try to validate from F-Curve info */
1266   if ((ptr.owner_id == NULL) && (ptr.data == NULL)) {
1267     BKE_report(
1268         reports, RPT_ERROR, "No RNA pointer available to retrieve values for keyframing from");
1269     return false;
1270   }
1271   if (prop == NULL) {
1272     PointerRNA tmp_ptr;
1273 
1274     /* try to get property we should be affecting */
1275     if (RNA_path_resolve_property(&ptr, fcu->rna_path, &tmp_ptr, &prop) == false) {
1276       /* property not found... */
1277       const char *idname = (ptr.owner_id) ? ptr.owner_id->name : TIP_("<No ID pointer>");
1278 
1279       BKE_reportf(reports,
1280                   RPT_ERROR,
1281                   "Could not insert keyframe, as RNA path is invalid for the given ID (ID = %s, "
1282                   "path = %s)",
1283                   idname,
1284                   fcu->rna_path);
1285       return false;
1286     }
1287 
1288     /* property found, so overwrite 'ptr' to make later code easier */
1289     ptr = tmp_ptr;
1290   }
1291 
1292   /* update F-Curve flags to ensure proper behavior for property type */
1293   update_autoflags_fcurve_direct(fcu, prop);
1294 
1295   /* Obtain the value to insert. */
1296   float value_buffer[RNA_MAX_ARRAY_LENGTH];
1297   int value_count;
1298   int index = fcu->array_index;
1299 
1300   float *values = get_keyframe_values(reports,
1301                                       ptr,
1302                                       prop,
1303                                       index,
1304                                       nla_context,
1305                                       flag,
1306                                       value_buffer,
1307                                       RNA_MAX_ARRAY_LENGTH,
1308                                       &value_count,
1309                                       NULL);
1310 
1311   if (values == NULL) {
1312     /* This happens if NLA rejects this insertion. */
1313     return false;
1314   }
1315 
1316   if (index >= 0 && index < value_count) {
1317     curval = values[index];
1318   }
1319 
1320   if (values != value_buffer) {
1321     MEM_freeN(values);
1322   }
1323 
1324   return insert_keyframe_value(reports, &ptr, prop, fcu, anim_eval_context, curval, keytype, flag);
1325 }
1326 
1327 /* Find or create the FCurve based on the given path, and insert the specified value into it. */
insert_keyframe_fcurve_value(Main * bmain,ReportList * reports,PointerRNA * ptr,PropertyRNA * prop,bAction * act,const char group[],const char rna_path[],int array_index,const AnimationEvalContext * anim_eval_context,float curval,eBezTriple_KeyframeType keytype,eInsertKeyFlags flag)1328 static bool insert_keyframe_fcurve_value(Main *bmain,
1329                                          ReportList *reports,
1330                                          PointerRNA *ptr,
1331                                          PropertyRNA *prop,
1332                                          bAction *act,
1333                                          const char group[],
1334                                          const char rna_path[],
1335                                          int array_index,
1336                                          const AnimationEvalContext *anim_eval_context,
1337                                          float curval,
1338                                          eBezTriple_KeyframeType keytype,
1339                                          eInsertKeyFlags flag)
1340 {
1341   /* make sure the F-Curve exists
1342    * - if we're replacing keyframes only, DO NOT create new F-Curves if they do not exist yet
1343    *   but still try to get the F-Curve if it exists...
1344    */
1345   bool can_create_curve = (flag & (INSERTKEY_REPLACE | INSERTKEY_AVAILABLE)) == 0;
1346   FCurve *fcu = can_create_curve ?
1347                     ED_action_fcurve_ensure(bmain, act, group, ptr, rna_path, array_index) :
1348                     ED_action_fcurve_find(act, rna_path, array_index);
1349 
1350   /* we may not have a F-Curve when we're replacing only... */
1351   if (fcu) {
1352     /* set color mode if the F-Curve is new (i.e. without any keyframes) */
1353     if ((fcu->totvert == 0) && (flag & INSERTKEY_XYZ2RGB)) {
1354       /* for Loc/Rot/Scale and also Color F-Curves, the color of the F-Curve in the Graph Editor,
1355        * is determined by the array index for the F-Curve
1356        */
1357       PropertySubType prop_subtype = RNA_property_subtype(prop);
1358       if (ELEM(prop_subtype, PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) {
1359         fcu->color_mode = FCURVE_COLOR_AUTO_RGB;
1360       }
1361       else if (ELEM(prop_subtype, PROP_QUATERNION)) {
1362         fcu->color_mode = FCURVE_COLOR_AUTO_YRGB;
1363       }
1364     }
1365 
1366     /* update F-Curve flags to ensure proper behavior for property type */
1367     update_autoflags_fcurve_direct(fcu, prop);
1368 
1369     /* insert keyframe */
1370     return insert_keyframe_value(
1371         reports, ptr, prop, fcu, anim_eval_context, curval, keytype, flag);
1372   }
1373 
1374   return false;
1375 }
1376 
nla_time_remap(const AnimationEvalContext * anim_eval_context,PointerRNA * id_ptr,AnimData * adt,bAction * act,ListBase * nla_cache,NlaKeyframingContext ** r_nla_context)1377 static AnimationEvalContext nla_time_remap(const AnimationEvalContext *anim_eval_context,
1378                                            PointerRNA *id_ptr,
1379                                            AnimData *adt,
1380                                            bAction *act,
1381                                            ListBase *nla_cache,
1382                                            NlaKeyframingContext **r_nla_context)
1383 {
1384   if (adt && adt->action == act) {
1385     /* Get NLA context for value remapping. */
1386     *r_nla_context = BKE_animsys_get_nla_keyframing_context(
1387         nla_cache, id_ptr, adt, anim_eval_context, false);
1388 
1389     /* Apply NLA-mapping to frame. */
1390     const float remapped_frame = BKE_nla_tweakedit_remap(
1391         adt, anim_eval_context->eval_time, NLATIME_CONVERT_UNMAP);
1392     return BKE_animsys_eval_context_construct_at(anim_eval_context, remapped_frame);
1393   }
1394 
1395   *r_nla_context = NULL;
1396   return *anim_eval_context;
1397 }
1398 
1399 /**
1400  * Main Keyframing API call
1401  *
1402  * Use this when validation of necessary animation data is necessary, since it may not exist yet.
1403  *
1404  * The flag argument is used for special settings that alter the behavior of
1405  * the keyframe insertion. These include the 'visual' keyframing modes, quick refresh,
1406  * and extra keyframe filtering.
1407  *
1408  * index of -1 keys all array indices
1409  *
1410  * \return The number of key-frames inserted.
1411  */
insert_keyframe(Main * bmain,ReportList * reports,ID * id,bAction * act,const char group[],const char rna_path[],int array_index,const AnimationEvalContext * anim_eval_context,eBezTriple_KeyframeType keytype,ListBase * nla_cache,eInsertKeyFlags flag)1412 int insert_keyframe(Main *bmain,
1413                     ReportList *reports,
1414                     ID *id,
1415                     bAction *act,
1416                     const char group[],
1417                     const char rna_path[],
1418                     int array_index,
1419                     const AnimationEvalContext *anim_eval_context,
1420                     eBezTriple_KeyframeType keytype,
1421                     ListBase *nla_cache,
1422                     eInsertKeyFlags flag)
1423 {
1424   PointerRNA id_ptr, ptr;
1425   PropertyRNA *prop = NULL;
1426   AnimData *adt;
1427   ListBase tmp_nla_cache = {NULL, NULL};
1428   NlaKeyframingContext *nla_context = NULL;
1429   int ret = 0;
1430 
1431   /* validate pointer first - exit if failure */
1432   if (id == NULL) {
1433     BKE_reportf(reports, RPT_ERROR, "No ID block to insert keyframe in (path = %s)", rna_path);
1434     return 0;
1435   }
1436 
1437   RNA_id_pointer_create(id, &id_ptr);
1438   if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) {
1439     BKE_reportf(
1440         reports,
1441         RPT_ERROR,
1442         "Could not insert keyframe, as RNA path is invalid for the given ID (ID = %s, path = %s)",
1443         (id) ? id->name : TIP_("<Missing ID block>"),
1444         rna_path);
1445     return 0;
1446   }
1447 
1448   /* if no action is provided, keyframe to the default one attached to this ID-block */
1449   if (act == NULL) {
1450     /* get action to add F-Curve+keyframe to */
1451     act = ED_id_action_ensure(bmain, id);
1452 
1453     if (act == NULL) {
1454       BKE_reportf(reports,
1455                   RPT_ERROR,
1456                   "Could not insert keyframe, as this type does not support animation data (ID = "
1457                   "%s, path = %s)",
1458                   id->name,
1459                   rna_path);
1460       return 0;
1461     }
1462   }
1463 
1464   /* apply NLA-mapping to frame to use (if applicable) */
1465   adt = BKE_animdata_from_id(id);
1466   const AnimationEvalContext remapped_context = nla_time_remap(
1467       anim_eval_context, &id_ptr, adt, act, nla_cache ? nla_cache : &tmp_nla_cache, &nla_context);
1468 
1469   /* Obtain values to insert. */
1470   float value_buffer[RNA_MAX_ARRAY_LENGTH];
1471   int value_count;
1472   bool force_all;
1473 
1474   float *values = get_keyframe_values(reports,
1475                                       ptr,
1476                                       prop,
1477                                       array_index,
1478                                       nla_context,
1479                                       flag,
1480                                       value_buffer,
1481                                       RNA_MAX_ARRAY_LENGTH,
1482                                       &value_count,
1483                                       &force_all);
1484 
1485   if (values != NULL) {
1486     /* Key the entire array. */
1487     if (array_index == -1 || force_all) {
1488       /* In force mode, if any of the curves succeeds, drop the replace mode and restart. */
1489       if (force_all && (flag & (INSERTKEY_REPLACE | INSERTKEY_AVAILABLE)) != 0) {
1490         int exclude = -1;
1491 
1492         for (array_index = 0; array_index < value_count; array_index++) {
1493           if (insert_keyframe_fcurve_value(bmain,
1494                                            reports,
1495                                            &ptr,
1496                                            prop,
1497                                            act,
1498                                            group,
1499                                            rna_path,
1500                                            array_index,
1501                                            &remapped_context,
1502                                            values[array_index],
1503                                            keytype,
1504                                            flag)) {
1505             ret++;
1506             exclude = array_index;
1507             break;
1508           }
1509         }
1510 
1511         if (exclude != -1) {
1512           flag &= ~(INSERTKEY_REPLACE | INSERTKEY_AVAILABLE);
1513 
1514           for (array_index = 0; array_index < value_count; array_index++) {
1515             if (array_index != exclude) {
1516               ret += insert_keyframe_fcurve_value(bmain,
1517                                                   reports,
1518                                                   &ptr,
1519                                                   prop,
1520                                                   act,
1521                                                   group,
1522                                                   rna_path,
1523                                                   array_index,
1524                                                   &remapped_context,
1525                                                   values[array_index],
1526                                                   keytype,
1527                                                   flag);
1528             }
1529           }
1530         }
1531       }
1532       /* Simply insert all channels. */
1533       else {
1534         for (array_index = 0; array_index < value_count; array_index++) {
1535           ret += insert_keyframe_fcurve_value(bmain,
1536                                               reports,
1537                                               &ptr,
1538                                               prop,
1539                                               act,
1540                                               group,
1541                                               rna_path,
1542                                               array_index,
1543                                               &remapped_context,
1544                                               values[array_index],
1545                                               keytype,
1546                                               flag);
1547         }
1548       }
1549     }
1550     /* Key a single index. */
1551     else {
1552       if (array_index >= 0 && array_index < value_count) {
1553         ret += insert_keyframe_fcurve_value(bmain,
1554                                             reports,
1555                                             &ptr,
1556                                             prop,
1557                                             act,
1558                                             group,
1559                                             rna_path,
1560                                             array_index,
1561                                             &remapped_context,
1562                                             values[array_index],
1563                                             keytype,
1564                                             flag);
1565       }
1566     }
1567 
1568     if (values != value_buffer) {
1569       MEM_freeN(values);
1570     }
1571   }
1572 
1573   BKE_animsys_free_nla_keyframing_context_cache(&tmp_nla_cache);
1574 
1575   if (ret) {
1576     if (act != NULL) {
1577       DEG_id_tag_update(&act->id, ID_RECALC_ANIMATION_NO_FLUSH);
1578     }
1579     if (adt != NULL && adt->action != NULL && adt->action != act) {
1580       DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH);
1581     }
1582   }
1583 
1584   return ret;
1585 }
1586 
1587 /* ************************************************** */
1588 /* KEYFRAME DELETION */
1589 
1590 /* Main Keyframing API call:
1591  * Use this when validation of necessary animation data isn't necessary as it
1592  * already exists. It will delete a keyframe at the current frame.
1593  *
1594  * The flag argument is used for special settings that alter the behavior of
1595  * the keyframe deletion. These include the quick refresh options.
1596  */
1597 
1598 /**
1599  * \note caller needs to run #BKE_nla_tweakedit_remap to get NLA relative frame.
1600  *       caller should also check #BKE_fcurve_is_protected before keying.
1601  */
delete_keyframe_fcurve(AnimData * adt,FCurve * fcu,float cfra)1602 static bool delete_keyframe_fcurve(AnimData *adt, FCurve *fcu, float cfra)
1603 {
1604   bool found;
1605   int i;
1606 
1607   /* try to find index of beztriple to get rid of */
1608   i = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, cfra, fcu->totvert, &found);
1609   if (found) {
1610     /* delete the key at the index (will sanity check + do recalc afterwards) */
1611     delete_fcurve_key(fcu, i, 1);
1612 
1613     /* Only delete curve too if it won't be doing anything anymore */
1614     if (BKE_fcurve_is_empty(fcu)) {
1615       ANIM_fcurve_delete_from_animdata(NULL, adt, fcu);
1616     }
1617 
1618     /* return success */
1619     return true;
1620   }
1621   return false;
1622 }
1623 
deg_tag_after_keyframe_delete(Main * bmain,ID * id,AnimData * adt)1624 static void deg_tag_after_keyframe_delete(Main *bmain, ID *id, AnimData *adt)
1625 {
1626   if (adt->action == NULL) {
1627     /* In the case last f-curve was removed need to inform dependency graph
1628      * about relations update, since it needs to get rid of animation operation
1629      * for this data-block. */
1630     DEG_id_tag_update_ex(bmain, id, ID_RECALC_ANIMATION_NO_FLUSH);
1631     DEG_relations_tag_update(bmain);
1632   }
1633   else {
1634     DEG_id_tag_update_ex(bmain, &adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH);
1635   }
1636 }
1637 
1638 /**
1639  * \return The number of key-frames deleted.
1640  */
delete_keyframe(Main * bmain,ReportList * reports,ID * id,bAction * act,const char rna_path[],int array_index,float cfra)1641 int delete_keyframe(Main *bmain,
1642                     ReportList *reports,
1643                     ID *id,
1644                     bAction *act,
1645                     const char rna_path[],
1646                     int array_index,
1647                     float cfra)
1648 {
1649   AnimData *adt = BKE_animdata_from_id(id);
1650   PointerRNA id_ptr, ptr;
1651   PropertyRNA *prop;
1652   int array_index_max = array_index + 1;
1653   int ret = 0;
1654 
1655   /* sanity checks */
1656   if (ELEM(NULL, id, adt)) {
1657     BKE_report(reports, RPT_ERROR, "No ID block and/or AnimData to delete keyframe from");
1658     return 0;
1659   }
1660 
1661   /* validate pointer first - exit if failure */
1662   RNA_id_pointer_create(id, &id_ptr);
1663   if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) {
1664     BKE_reportf(
1665         reports,
1666         RPT_ERROR,
1667         "Could not delete keyframe, as RNA path is invalid for the given ID (ID = %s, path = %s)",
1668         id->name,
1669         rna_path);
1670     return 0;
1671   }
1672 
1673   /* get F-Curve
1674    * Note: here is one of the places where we don't want new Action + F-Curve added!
1675    *      so 'add' var must be 0
1676    */
1677   if (act == NULL) {
1678     /* if no action is provided, use the default one attached to this ID-block
1679      * - if it doesn't exist, then we're out of options...
1680      */
1681     if (adt->action) {
1682       act = adt->action;
1683 
1684       /* apply NLA-mapping to frame to use (if applicable) */
1685       cfra = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
1686     }
1687     else {
1688       BKE_reportf(reports, RPT_ERROR, "No action to delete keyframes from for ID = %s", id->name);
1689       return 0;
1690     }
1691   }
1692 
1693   /* key entire array convenience method */
1694   if (array_index == -1) {
1695     array_index = 0;
1696     array_index_max = RNA_property_array_length(&ptr, prop);
1697 
1698     /* for single properties, increase max_index so that the property itself gets included,
1699      * but don't do this for standard arrays since that can cause corruption issues
1700      * (extra unused curves)
1701      */
1702     if (array_index_max == array_index) {
1703       array_index_max++;
1704     }
1705   }
1706 
1707   /* will only loop once unless the array index was -1 */
1708   for (; array_index < array_index_max; array_index++) {
1709     FCurve *fcu = ED_action_fcurve_find(act, rna_path, array_index);
1710 
1711     /* check if F-Curve exists and/or whether it can be edited */
1712     if (fcu == NULL) {
1713       continue;
1714     }
1715 
1716     if (BKE_fcurve_is_protected(fcu)) {
1717       BKE_reportf(reports,
1718                   RPT_WARNING,
1719                   "Not deleting keyframe for locked F-Curve '%s' for %s '%s'",
1720                   fcu->rna_path,
1721                   BKE_idtype_idcode_to_name(GS(id->name)),
1722                   id->name + 2);
1723       continue;
1724     }
1725 
1726     ret += delete_keyframe_fcurve(adt, fcu, cfra);
1727   }
1728   if (ret) {
1729     deg_tag_after_keyframe_delete(bmain, id, adt);
1730   }
1731   /* return success/failure */
1732   return ret;
1733 }
1734 
1735 /* ************************************************** */
1736 /* KEYFRAME CLEAR */
1737 
1738 /**
1739  * Main Keyframing API call:
1740  * Use this when validation of necessary animation data isn't necessary as it
1741  * already exists. It will clear the current buttons fcurve(s).
1742  *
1743  * The flag argument is used for special settings that alter the behavior of
1744  * the keyframe deletion. These include the quick refresh options.
1745  *
1746  * \return The number of f-curves removed.
1747  */
clear_keyframe(Main * bmain,ReportList * reports,ID * id,bAction * act,const char rna_path[],int array_index,eInsertKeyFlags UNUSED (flag))1748 static int clear_keyframe(Main *bmain,
1749                           ReportList *reports,
1750                           ID *id,
1751                           bAction *act,
1752                           const char rna_path[],
1753                           int array_index,
1754                           eInsertKeyFlags UNUSED(flag))
1755 {
1756   AnimData *adt = BKE_animdata_from_id(id);
1757   PointerRNA id_ptr, ptr;
1758   PropertyRNA *prop;
1759   int array_index_max = array_index + 1;
1760   int ret = 0;
1761 
1762   /* sanity checks */
1763   if (ELEM(NULL, id, adt)) {
1764     BKE_report(reports, RPT_ERROR, "No ID block and/or AnimData to delete keyframe from");
1765     return 0;
1766   }
1767 
1768   /* validate pointer first - exit if failure */
1769   RNA_id_pointer_create(id, &id_ptr);
1770   if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) {
1771     BKE_reportf(
1772         reports,
1773         RPT_ERROR,
1774         "Could not clear keyframe, as RNA path is invalid for the given ID (ID = %s, path = %s)",
1775         id->name,
1776         rna_path);
1777     return 0;
1778   }
1779 
1780   /* get F-Curve
1781    * Note: here is one of the places where we don't want new Action + F-Curve added!
1782    *      so 'add' var must be 0
1783    */
1784   if (act == NULL) {
1785     /* if no action is provided, use the default one attached to this ID-block
1786      * - if it doesn't exist, then we're out of options...
1787      */
1788     if (adt->action) {
1789       act = adt->action;
1790     }
1791     else {
1792       BKE_reportf(reports, RPT_ERROR, "No action to delete keyframes from for ID = %s", id->name);
1793       return 0;
1794     }
1795   }
1796 
1797   /* key entire array convenience method */
1798   if (array_index == -1) {
1799     array_index = 0;
1800     array_index_max = RNA_property_array_length(&ptr, prop);
1801 
1802     /* for single properties, increase max_index so that the property itself gets included,
1803      * but don't do this for standard arrays since that can cause corruption issues
1804      * (extra unused curves)
1805      */
1806     if (array_index_max == array_index) {
1807       array_index_max++;
1808     }
1809   }
1810 
1811   /* will only loop once unless the array index was -1 */
1812   for (; array_index < array_index_max; array_index++) {
1813     FCurve *fcu = ED_action_fcurve_find(act, rna_path, array_index);
1814 
1815     /* check if F-Curve exists and/or whether it can be edited */
1816     if (fcu == NULL) {
1817       continue;
1818     }
1819 
1820     if (BKE_fcurve_is_protected(fcu)) {
1821       BKE_reportf(reports,
1822                   RPT_WARNING,
1823                   "Not clearing all keyframes from locked F-Curve '%s' for %s '%s'",
1824                   fcu->rna_path,
1825                   BKE_idtype_idcode_to_name(GS(id->name)),
1826                   id->name + 2);
1827       continue;
1828     }
1829 
1830     ANIM_fcurve_delete_from_animdata(NULL, adt, fcu);
1831 
1832     /* return success */
1833     ret++;
1834   }
1835   if (ret) {
1836     deg_tag_after_keyframe_delete(bmain, id, adt);
1837   }
1838   /* return success/failure */
1839   return ret;
1840 }
1841 
1842 /* ******************************************* */
1843 /* KEYFRAME MODIFICATION */
1844 
1845 /* mode for commonkey_modifykey */
1846 enum {
1847   COMMONKEY_MODE_INSERT = 0,
1848   COMMONKEY_MODE_DELETE,
1849 } /*eCommonModifyKey_Modes*/;
1850 
1851 /* Polling callback for use with ANIM_*_keyframe() operators
1852  * This is based on the standard ED_operator_areaactive callback,
1853  * except that it does special checks for a few spacetypes too...
1854  */
modify_key_op_poll(bContext * C)1855 static bool modify_key_op_poll(bContext *C)
1856 {
1857   ScrArea *area = CTX_wm_area(C);
1858   Scene *scene = CTX_data_scene(C);
1859 
1860   /* if no area or active scene */
1861   if (ELEM(NULL, area, scene)) {
1862     return false;
1863   }
1864 
1865   /* should be fine */
1866   return true;
1867 }
1868 
1869 /* Insert Key Operator ------------------------ */
1870 
insert_key_exec(bContext * C,wmOperator * op)1871 static int insert_key_exec(bContext *C, wmOperator *op)
1872 {
1873   Scene *scene = CTX_data_scene(C);
1874   Object *obedit = CTX_data_edit_object(C);
1875   bool ob_edit_mode = false;
1876 
1877   float cfra = (float)CFRA; /* XXX for now, don't bother about all the yucky offset crap */
1878   int num_channels;
1879 
1880   KeyingSet *ks = keyingset_get_from_op_with_error(op, op->type->prop, scene);
1881   if (ks == NULL) {
1882     return OPERATOR_CANCELLED;
1883   }
1884 
1885   /* exit the edit mode to make sure that those object data properties that have been
1886    * updated since the last switching to the edit mode will be keyframed correctly
1887    */
1888   if (obedit && ANIM_keyingset_find_id(ks, (ID *)obedit->data)) {
1889     ED_object_mode_set(C, OB_MODE_OBJECT);
1890     ob_edit_mode = true;
1891   }
1892 
1893   /* try to insert keyframes for the channels specified by KeyingSet */
1894   num_channels = ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
1895   if (G.debug & G_DEBUG) {
1896     BKE_reportf(op->reports,
1897                 RPT_INFO,
1898                 "Keying set '%s' - successfully added %d keyframes",
1899                 ks->name,
1900                 num_channels);
1901   }
1902 
1903   /* restore the edit mode if necessary */
1904   if (ob_edit_mode) {
1905     ED_object_mode_set(C, OB_MODE_EDIT);
1906   }
1907 
1908   /* report failure or do updates? */
1909   if (num_channels < 0) {
1910     BKE_report(op->reports, RPT_ERROR, "No suitable context info for active keying set");
1911     return OPERATOR_CANCELLED;
1912   }
1913 
1914   if (num_channels > 0) {
1915     /* if the appropriate properties have been set, make a note that we've inserted something */
1916     if (RNA_boolean_get(op->ptr, "confirm_success")) {
1917       BKE_reportf(op->reports,
1918                   RPT_INFO,
1919                   "Successfully added %d keyframes for keying set '%s'",
1920                   num_channels,
1921                   ks->name);
1922     }
1923 
1924     /* send notifiers that keyframes have been changed */
1925     WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL);
1926   }
1927   else {
1928     BKE_report(op->reports, RPT_WARNING, "Keying set failed to insert any keyframes");
1929   }
1930 
1931   return OPERATOR_FINISHED;
1932 }
1933 
ANIM_OT_keyframe_insert(wmOperatorType * ot)1934 void ANIM_OT_keyframe_insert(wmOperatorType *ot)
1935 {
1936   PropertyRNA *prop;
1937 
1938   /* identifiers */
1939   ot->name = "Insert Keyframe";
1940   ot->idname = "ANIM_OT_keyframe_insert";
1941   ot->description =
1942       "Insert keyframes on the current frame for all properties in the specified Keying Set";
1943 
1944   /* callbacks */
1945   ot->exec = insert_key_exec;
1946   ot->poll = modify_key_op_poll;
1947 
1948   /* flags */
1949   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1950 
1951   /* keyingset to use (dynamic enum) */
1952   prop = RNA_def_enum(
1953       ot->srna, "type", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use");
1954   RNA_def_enum_funcs(prop, ANIM_keying_sets_enum_itemf);
1955   RNA_def_property_flag(prop, PROP_HIDDEN);
1956   ot->prop = prop;
1957 
1958   /* confirm whether a keyframe was added by showing a popup
1959    * - by default, this is enabled, since this operator is assumed to be called independently
1960    */
1961   prop = RNA_def_boolean(ot->srna,
1962                          "confirm_success",
1963                          1,
1964                          "Confirm Successful Insert",
1965                          "Show a popup when the keyframes get successfully added");
1966   RNA_def_property_flag(prop, PROP_HIDDEN);
1967 }
1968 
1969 /* Clone of 'ANIM_OT_keyframe_insert' which uses a name for the keying set instead of an enum. */
ANIM_OT_keyframe_insert_by_name(wmOperatorType * ot)1970 void ANIM_OT_keyframe_insert_by_name(wmOperatorType *ot)
1971 {
1972   PropertyRNA *prop;
1973 
1974   /* identifiers */
1975   ot->name = "Insert Keyframe (by name)";
1976   ot->idname = "ANIM_OT_keyframe_insert_by_name";
1977   ot->description = "Alternate access to 'Insert Keyframe' for keymaps to use";
1978 
1979   /* callbacks */
1980   ot->exec = insert_key_exec;
1981   ot->poll = modify_key_op_poll;
1982 
1983   /* flags */
1984   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1985 
1986   /* keyingset to use (idname) */
1987   prop = RNA_def_string_file_path(ot->srna, "type", "Type", MAX_ID_NAME - 2, "", "");
1988   RNA_def_property_flag(prop, PROP_HIDDEN);
1989   ot->prop = prop;
1990 
1991   /* confirm whether a keyframe was added by showing a popup
1992    * - by default, this is enabled, since this operator is assumed to be called independently
1993    */
1994   prop = RNA_def_boolean(ot->srna,
1995                          "confirm_success",
1996                          1,
1997                          "Confirm Successful Insert",
1998                          "Show a popup when the keyframes get successfully added");
1999   RNA_def_property_flag(prop, PROP_HIDDEN);
2000 }
2001 
2002 /* Insert Key Operator (With Menu) ------------------------ */
2003 /* This operator checks if a menu should be shown for choosing the KeyingSet to use,
2004  * then calls the menu if necessary before
2005  */
2006 
insert_key_menu_invoke(bContext * C,wmOperator * op,const wmEvent * UNUSED (event))2007 static int insert_key_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2008 {
2009   Scene *scene = CTX_data_scene(C);
2010 
2011   /* if prompting or no active Keying Set, show the menu */
2012   if ((scene->active_keyingset == 0) || RNA_boolean_get(op->ptr, "always_prompt")) {
2013     uiPopupMenu *pup;
2014     uiLayout *layout;
2015 
2016     /* call the menu, which will call this operator again, hence the canceled */
2017     pup = UI_popup_menu_begin(C, WM_operatortype_name(op->type, op->ptr), ICON_NONE);
2018     layout = UI_popup_menu_layout(pup);
2019     uiItemsEnumO(layout, "ANIM_OT_keyframe_insert_menu", "type");
2020     UI_popup_menu_end(C, pup);
2021 
2022     return OPERATOR_INTERFACE;
2023   }
2024 
2025   /* just call the exec() on the active keyingset */
2026   RNA_enum_set(op->ptr, "type", 0);
2027   RNA_boolean_set(op->ptr, "confirm_success", true);
2028 
2029   return op->type->exec(C, op);
2030 }
2031 
ANIM_OT_keyframe_insert_menu(wmOperatorType * ot)2032 void ANIM_OT_keyframe_insert_menu(wmOperatorType *ot)
2033 {
2034   PropertyRNA *prop;
2035 
2036   /* identifiers */
2037   ot->name = "Insert Keyframe Menu";
2038   ot->idname = "ANIM_OT_keyframe_insert_menu";
2039   ot->description =
2040       "Insert Keyframes for specified Keying Set, with menu of available Keying Sets if undefined";
2041 
2042   /* callbacks */
2043   ot->invoke = insert_key_menu_invoke;
2044   ot->exec = insert_key_exec;
2045   ot->poll = ED_operator_areaactive;
2046 
2047   /* flags */
2048   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2049 
2050   /* keyingset to use (dynamic enum) */
2051   prop = RNA_def_enum(
2052       ot->srna, "type", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use");
2053   RNA_def_enum_funcs(prop, ANIM_keying_sets_enum_itemf);
2054   RNA_def_property_flag(prop, PROP_HIDDEN);
2055   ot->prop = prop;
2056 
2057   /* confirm whether a keyframe was added by showing a popup
2058    * - by default, this is disabled so that if a menu is shown, this doesn't come up too
2059    */
2060   /* XXX should this just be always on? */
2061   prop = RNA_def_boolean(ot->srna,
2062                          "confirm_success",
2063                          0,
2064                          "Confirm Successful Insert",
2065                          "Show a popup when the keyframes get successfully added");
2066   RNA_def_property_flag(prop, PROP_HIDDEN);
2067 
2068   /* whether the menu should always be shown
2069    * - by default, the menu should only be shown when there is no active Keying Set (2.5 behavior),
2070    *   although in some cases it might be useful to always shown (pre 2.5 behavior)
2071    */
2072   prop = RNA_def_boolean(ot->srna, "always_prompt", 0, "Always Show Menu", "");
2073   RNA_def_property_flag(prop, PROP_HIDDEN);
2074 }
2075 
2076 /* Delete Key Operator ------------------------ */
2077 
delete_key_exec(bContext * C,wmOperator * op)2078 static int delete_key_exec(bContext *C, wmOperator *op)
2079 {
2080   Scene *scene = CTX_data_scene(C);
2081   float cfra = (float)CFRA; /* XXX for now, don't bother about all the yucky offset crap */
2082   int num_channels;
2083 
2084   KeyingSet *ks = keyingset_get_from_op_with_error(op, op->type->prop, scene);
2085   if (ks == NULL) {
2086     return OPERATOR_CANCELLED;
2087   }
2088 
2089   const int prop_type = RNA_property_type(op->type->prop);
2090   if (prop_type == PROP_ENUM) {
2091     int type = RNA_property_enum_get(op->ptr, op->type->prop);
2092     ks = ANIM_keyingset_get_from_enum_type(scene, type);
2093     if (ks == NULL) {
2094       BKE_report(op->reports, RPT_ERROR, "No active Keying Set");
2095       return OPERATOR_CANCELLED;
2096     }
2097   }
2098   else if (prop_type == PROP_STRING) {
2099     char type_id[MAX_ID_NAME - 2];
2100     RNA_property_string_get(op->ptr, op->type->prop, type_id);
2101     ks = ANIM_keyingset_get_from_idname(scene, type_id);
2102 
2103     if (ks == NULL) {
2104       BKE_reportf(op->reports, RPT_ERROR, "Active Keying Set '%s' not found", type_id);
2105       return OPERATOR_CANCELLED;
2106     }
2107   }
2108   else {
2109     BLI_assert(0);
2110   }
2111 
2112   /* report failure */
2113   if (ks == NULL) {
2114     BKE_report(op->reports, RPT_ERROR, "No active Keying Set");
2115     return OPERATOR_CANCELLED;
2116   }
2117 
2118   /* try to delete keyframes for the channels specified by KeyingSet */
2119   num_channels = ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_DELETE, cfra);
2120   if (G.debug & G_DEBUG) {
2121     printf("KeyingSet '%s' - Successfully removed %d Keyframes\n", ks->name, num_channels);
2122   }
2123 
2124   /* report failure or do updates? */
2125   if (num_channels < 0) {
2126     BKE_report(op->reports, RPT_ERROR, "No suitable context info for active keying set");
2127     return OPERATOR_CANCELLED;
2128   }
2129 
2130   if (num_channels > 0) {
2131     /* if the appropriate properties have been set, make a note that we've inserted something */
2132     if (RNA_boolean_get(op->ptr, "confirm_success")) {
2133       BKE_reportf(op->reports,
2134                   RPT_INFO,
2135                   "Successfully removed %d keyframes for keying set '%s'",
2136                   num_channels,
2137                   ks->name);
2138     }
2139 
2140     /* send notifiers that keyframes have been changed */
2141     WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL);
2142   }
2143   else {
2144     BKE_report(op->reports, RPT_WARNING, "Keying set failed to remove any keyframes");
2145   }
2146 
2147   return OPERATOR_FINISHED;
2148 }
2149 
ANIM_OT_keyframe_delete(wmOperatorType * ot)2150 void ANIM_OT_keyframe_delete(wmOperatorType *ot)
2151 {
2152   PropertyRNA *prop;
2153 
2154   /* identifiers */
2155   ot->name = "Delete Keying-Set Keyframe";
2156   ot->idname = "ANIM_OT_keyframe_delete";
2157   ot->description =
2158       "Delete keyframes on the current frame for all properties in the specified Keying Set";
2159 
2160   /* callbacks */
2161   ot->exec = delete_key_exec;
2162   ot->poll = modify_key_op_poll;
2163 
2164   /* flags */
2165   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2166 
2167   /* keyingset to use (dynamic enum) */
2168   prop = RNA_def_enum(
2169       ot->srna, "type", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use");
2170   RNA_def_enum_funcs(prop, ANIM_keying_sets_enum_itemf);
2171   RNA_def_property_flag(prop, PROP_HIDDEN);
2172   ot->prop = prop;
2173 
2174   /* confirm whether a keyframe was added by showing a popup
2175    * - by default, this is enabled, since this operator is assumed to be called independently
2176    */
2177   RNA_def_boolean(ot->srna,
2178                   "confirm_success",
2179                   1,
2180                   "Confirm Successful Delete",
2181                   "Show a popup when the keyframes get successfully removed");
2182 }
2183 
ANIM_OT_keyframe_delete_by_name(wmOperatorType * ot)2184 void ANIM_OT_keyframe_delete_by_name(wmOperatorType *ot)
2185 {
2186   PropertyRNA *prop;
2187 
2188   /* identifiers */
2189   ot->name = "Delete Keying-Set Keyframe (by name)";
2190   ot->idname = "ANIM_OT_keyframe_delete_by_name";
2191   ot->description = "Alternate access to 'Delete Keyframe' for keymaps to use";
2192 
2193   /* callbacks */
2194   ot->exec = delete_key_exec;
2195   ot->poll = modify_key_op_poll;
2196 
2197   /* flags */
2198   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2199 
2200   /* keyingset to use (idname) */
2201   prop = RNA_def_string_file_path(ot->srna, "type", "Type", MAX_ID_NAME - 2, "", "");
2202   RNA_def_property_flag(prop, PROP_HIDDEN);
2203   ot->prop = prop;
2204 
2205   /* confirm whether a keyframe was added by showing a popup
2206    * - by default, this is enabled, since this operator is assumed to be called independently
2207    */
2208   RNA_def_boolean(ot->srna,
2209                   "confirm_success",
2210                   1,
2211                   "Confirm Successful Delete",
2212                   "Show a popup when the keyframes get successfully removed");
2213 }
2214 
2215 /* Delete Key Operator ------------------------ */
2216 /* NOTE: Although this version is simpler than the more generic version for KeyingSets,
2217  * it is more useful for animators working in the 3D view.
2218  */
2219 
clear_anim_v3d_exec(bContext * C,wmOperator * UNUSED (op))2220 static int clear_anim_v3d_exec(bContext *C, wmOperator *UNUSED(op))
2221 {
2222   bool changed = false;
2223 
2224   CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
2225     /* just those in active action... */
2226     if ((ob->adt) && (ob->adt->action)) {
2227       AnimData *adt = ob->adt;
2228       bAction *act = adt->action;
2229       FCurve *fcu, *fcn;
2230 
2231       for (fcu = act->curves.first; fcu; fcu = fcn) {
2232         bool can_delete = false;
2233 
2234         fcn = fcu->next;
2235 
2236         /* in pose mode, only delete the F-Curve if it belongs to a selected bone */
2237         if (ob->mode & OB_MODE_POSE) {
2238           if ((fcu->rna_path) && strstr(fcu->rna_path, "pose.bones[")) {
2239             bPoseChannel *pchan;
2240             char *bone_name;
2241 
2242             /* get bone-name, and check if this bone is selected */
2243             bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones[");
2244             pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
2245             if (bone_name) {
2246               MEM_freeN(bone_name);
2247             }
2248 
2249             /* delete if bone is selected*/
2250             if ((pchan) && (pchan->bone)) {
2251               if (pchan->bone->flag & BONE_SELECTED) {
2252                 can_delete = true;
2253               }
2254             }
2255           }
2256         }
2257         else {
2258           /* object mode - all of Object's F-Curves are affected */
2259           can_delete = true;
2260         }
2261 
2262         /* delete F-Curve completely */
2263         if (can_delete) {
2264           ANIM_fcurve_delete_from_animdata(NULL, adt, fcu);
2265           DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
2266           changed = true;
2267         }
2268       }
2269 
2270       /* Delete the action itself if it is empty. */
2271       if (ANIM_remove_empty_action_from_animdata(adt)) {
2272         changed = true;
2273       }
2274     }
2275   }
2276   CTX_DATA_END;
2277 
2278   if (!changed) {
2279     return OPERATOR_CANCELLED;
2280   }
2281 
2282   /* send updates */
2283   WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL);
2284 
2285   return OPERATOR_FINISHED;
2286 }
2287 
ANIM_OT_keyframe_clear_v3d(wmOperatorType * ot)2288 void ANIM_OT_keyframe_clear_v3d(wmOperatorType *ot)
2289 {
2290   /* identifiers */
2291   ot->name = "Remove Animation";
2292   ot->description = "Remove all keyframe animation for selected objects";
2293   ot->idname = "ANIM_OT_keyframe_clear_v3d";
2294 
2295   /* callbacks */
2296   ot->invoke = WM_operator_confirm;
2297   ot->exec = clear_anim_v3d_exec;
2298 
2299   ot->poll = ED_operator_areaactive;
2300 
2301   /* flags */
2302   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2303 }
2304 
delete_key_v3d_exec(bContext * C,wmOperator * op)2305 static int delete_key_v3d_exec(bContext *C, wmOperator *op)
2306 {
2307   Scene *scene = CTX_data_scene(C);
2308   float cfra = (float)CFRA;
2309 
2310   int selected_objects_len = 0;
2311   int selected_objects_success_len = 0;
2312   int success_multi = 0;
2313 
2314   CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
2315     ID *id = &ob->id;
2316     int success = 0;
2317 
2318     selected_objects_len += 1;
2319 
2320     /* just those in active action... */
2321     if ((ob->adt) && (ob->adt->action)) {
2322       AnimData *adt = ob->adt;
2323       bAction *act = adt->action;
2324       FCurve *fcu, *fcn;
2325       const float cfra_unmap = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
2326 
2327       for (fcu = act->curves.first; fcu; fcu = fcn) {
2328         fcn = fcu->next;
2329 
2330         /* don't touch protected F-Curves */
2331         if (BKE_fcurve_is_protected(fcu)) {
2332           BKE_reportf(op->reports,
2333                       RPT_WARNING,
2334                       "Not deleting keyframe for locked F-Curve '%s', object '%s'",
2335                       fcu->rna_path,
2336                       id->name + 2);
2337           continue;
2338         }
2339 
2340         /* Special exception for bones, as this makes this operator more convenient to use
2341          * NOTE: This is only done in pose mode.
2342          * In object mode, we're dealing with the entire object.
2343          */
2344         if ((ob->mode & OB_MODE_POSE) && strstr(fcu->rna_path, "pose.bones[\"")) {
2345           bPoseChannel *pchan;
2346           char *bone_name;
2347 
2348           /* get bone-name, and check if this bone is selected */
2349           bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones[");
2350           pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
2351           if (bone_name) {
2352             MEM_freeN(bone_name);
2353           }
2354 
2355           /* skip if bone is not selected */
2356           if ((pchan) && (pchan->bone)) {
2357             /* bones are only selected/editable if visible... */
2358             bArmature *arm = (bArmature *)ob->data;
2359 
2360             /* skipping - not visible on currently visible layers */
2361             if ((arm->layer & pchan->bone->layer) == 0) {
2362               continue;
2363             }
2364             /* skipping - is currently hidden */
2365             if (pchan->bone->flag & BONE_HIDDEN_P) {
2366               continue;
2367             }
2368 
2369             /* selection flag... */
2370             if ((pchan->bone->flag & BONE_SELECTED) == 0) {
2371               continue;
2372             }
2373           }
2374         }
2375 
2376         /* delete keyframes on current frame
2377          * WARNING: this can delete the next F-Curve, hence the "fcn" copying
2378          */
2379         success += delete_keyframe_fcurve(adt, fcu, cfra_unmap);
2380       }
2381       DEG_id_tag_update(&ob->adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH);
2382     }
2383 
2384     /* Only for reporting. */
2385     if (success) {
2386       selected_objects_success_len += 1;
2387       success_multi += success;
2388     }
2389 
2390     DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
2391   }
2392   CTX_DATA_END;
2393 
2394   /* report success (or failure) */
2395   if (selected_objects_success_len) {
2396     BKE_reportf(op->reports,
2397                 RPT_INFO,
2398                 "%d object(s) successfully had %d keyframes removed",
2399                 selected_objects_success_len,
2400                 success_multi);
2401   }
2402   else {
2403     BKE_reportf(
2404         op->reports, RPT_ERROR, "No keyframes removed from %d object(s)", selected_objects_len);
2405   }
2406 
2407   /* send updates */
2408   WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL);
2409 
2410   return OPERATOR_FINISHED;
2411 }
2412 
ANIM_OT_keyframe_delete_v3d(wmOperatorType * ot)2413 void ANIM_OT_keyframe_delete_v3d(wmOperatorType *ot)
2414 {
2415   /* identifiers */
2416   ot->name = "Delete Keyframe";
2417   ot->description = "Remove keyframes on current frame for selected objects and bones";
2418   ot->idname = "ANIM_OT_keyframe_delete_v3d";
2419 
2420   /* callbacks */
2421   ot->invoke = WM_operator_confirm;
2422   ot->exec = delete_key_v3d_exec;
2423 
2424   ot->poll = ED_operator_areaactive;
2425 
2426   /* flags */
2427   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2428 }
2429 
2430 /* Insert Key Button Operator ------------------------ */
2431 
insert_key_button_exec(bContext * C,wmOperator * op)2432 static int insert_key_button_exec(bContext *C, wmOperator *op)
2433 {
2434   Main *bmain = CTX_data_main(C);
2435   Scene *scene = CTX_data_scene(C);
2436   ToolSettings *ts = scene->toolsettings;
2437   PointerRNA ptr = {NULL};
2438   PropertyRNA *prop = NULL;
2439   char *path;
2440   uiBut *but;
2441   const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(
2442       CTX_data_depsgraph_pointer(C), (float)CFRA);
2443   bool changed = false;
2444   int index;
2445   const bool all = RNA_boolean_get(op->ptr, "all");
2446   eInsertKeyFlags flag = INSERTKEY_NOFLAGS;
2447 
2448   /* flags for inserting keyframes */
2449   flag = ANIM_get_keyframing_flags(scene, true);
2450 
2451   /* try to insert keyframe using property retrieved from UI */
2452   if (!(but = UI_context_active_but_prop_get(C, &ptr, &prop, &index))) {
2453     /* pass event on if no active button found */
2454     return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
2455   }
2456 
2457   if ((ptr.owner_id && ptr.data && prop) && RNA_property_animateable(&ptr, prop)) {
2458     if (ptr.type == &RNA_NlaStrip) {
2459       /* Handle special properties for NLA Strips, whose F-Curves are stored on the
2460        * strips themselves. These are stored separately or else the properties will
2461        * not have any effect.
2462        */
2463       NlaStrip *strip = ptr.data;
2464       FCurve *fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), index);
2465 
2466       if (fcu) {
2467         changed = insert_keyframe_direct(
2468             op->reports, ptr, prop, fcu, &anim_eval_context, ts->keyframe_type, NULL, 0);
2469       }
2470       else {
2471         BKE_report(op->reports,
2472                    RPT_ERROR,
2473                    "This property cannot be animated as it will not get updated correctly");
2474       }
2475     }
2476     else if (UI_but_flag_is_set(but, UI_BUT_DRIVEN)) {
2477       /* Driven property - Find driver */
2478       FCurve *fcu;
2479       bool driven, special;
2480 
2481       fcu = BKE_fcurve_find_by_rna_context_ui(C, &ptr, prop, index, NULL, NULL, &driven, &special);
2482 
2483       if (fcu && driven) {
2484         changed = insert_keyframe_direct(op->reports,
2485                                          ptr,
2486                                          prop,
2487                                          fcu,
2488                                          &anim_eval_context,
2489                                          ts->keyframe_type,
2490                                          NULL,
2491                                          INSERTKEY_DRIVER);
2492       }
2493     }
2494     else {
2495       /* standard properties */
2496       path = RNA_path_from_ID_to_property(&ptr, prop);
2497 
2498       if (path) {
2499         const char *identifier = RNA_property_identifier(prop);
2500         const char *group = NULL;
2501 
2502         /* Special exception for keyframing transforms:
2503          * Set "group" for this manually, instead of having them appearing at the bottom
2504          * (ungrouped) part of the channels list.
2505          * Leaving these ungrouped is not a nice user behavior in this case.
2506          *
2507          * TODO: Perhaps we can extend this behavior in future for other properties...
2508          */
2509         if (ptr.type == &RNA_PoseBone) {
2510           bPoseChannel *pchan = ptr.data;
2511           group = pchan->name;
2512         }
2513         else if ((ptr.type == &RNA_Object) &&
2514                  (strstr(identifier, "location") || strstr(identifier, "rotation") ||
2515                   strstr(identifier, "scale"))) {
2516           /* NOTE: Keep this label in sync with the "ID" case in
2517            * keyingsets_utils.py :: get_transform_generators_base_info()
2518            */
2519           group = "Object Transforms";
2520         }
2521 
2522         if (all) {
2523           /* -1 indicates operating on the entire array (or the property itself otherwise) */
2524           index = -1;
2525         }
2526 
2527         changed = (insert_keyframe(bmain,
2528                                    op->reports,
2529                                    ptr.owner_id,
2530                                    NULL,
2531                                    group,
2532                                    path,
2533                                    index,
2534                                    &anim_eval_context,
2535                                    ts->keyframe_type,
2536                                    NULL,
2537                                    flag) != 0);
2538 
2539         MEM_freeN(path);
2540       }
2541       else {
2542         BKE_report(op->reports,
2543                    RPT_WARNING,
2544                    "Failed to resolve path to property, "
2545                    "try manually specifying this using a Keying Set instead");
2546       }
2547     }
2548   }
2549   else {
2550     if (prop && !RNA_property_animateable(&ptr, prop)) {
2551       BKE_reportf(op->reports,
2552                   RPT_WARNING,
2553                   "\"%s\" property cannot be animated",
2554                   RNA_property_identifier(prop));
2555     }
2556     else {
2557       BKE_reportf(op->reports,
2558                   RPT_WARNING,
2559                   "Button doesn't appear to have any property information attached (ptr.data = "
2560                   "%p, prop = %p)",
2561                   ptr.data,
2562                   (void *)prop);
2563     }
2564   }
2565 
2566   if (changed) {
2567     ID *id = ptr.owner_id;
2568     AnimData *adt = BKE_animdata_from_id(id);
2569     if (adt->action != NULL) {
2570       DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH);
2571     }
2572     DEG_id_tag_update(id, ID_RECALC_ANIMATION_NO_FLUSH);
2573 
2574     /* send updates */
2575     UI_context_update_anim_flag(C);
2576 
2577     /* send notifiers that keyframes have been changed */
2578     WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL);
2579   }
2580 
2581   return (changed) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
2582 }
2583 
ANIM_OT_keyframe_insert_button(wmOperatorType * ot)2584 void ANIM_OT_keyframe_insert_button(wmOperatorType *ot)
2585 {
2586   /* identifiers */
2587   ot->name = "Insert Keyframe (Buttons)";
2588   ot->idname = "ANIM_OT_keyframe_insert_button";
2589   ot->description = "Insert a keyframe for current UI-active property";
2590 
2591   /* callbacks */
2592   ot->exec = insert_key_button_exec;
2593   ot->poll = modify_key_op_poll;
2594 
2595   /* flags */
2596   ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
2597 
2598   /* properties */
2599   RNA_def_boolean(ot->srna, "all", 1, "All", "Insert a keyframe for all element of the array");
2600 }
2601 
2602 /* Delete Key Button Operator ------------------------ */
2603 
delete_key_button_exec(bContext * C,wmOperator * op)2604 static int delete_key_button_exec(bContext *C, wmOperator *op)
2605 {
2606   Scene *scene = CTX_data_scene(C);
2607   PointerRNA ptr = {NULL};
2608   PropertyRNA *prop = NULL;
2609   Main *bmain = CTX_data_main(C);
2610   char *path;
2611   float cfra = (float)CFRA; /* XXX for now, don't bother about all the yucky offset crap */
2612   bool changed = false;
2613   int index;
2614   const bool all = RNA_boolean_get(op->ptr, "all");
2615 
2616   /* try to insert keyframe using property retrieved from UI */
2617   if (!UI_context_active_but_prop_get(C, &ptr, &prop, &index)) {
2618     /* pass event on if no active button found */
2619     return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
2620   }
2621 
2622   if (ptr.owner_id && ptr.data && prop) {
2623     if (BKE_nlastrip_has_curves_for_property(&ptr, prop)) {
2624       /* Handle special properties for NLA Strips, whose F-Curves are stored on the
2625        * strips themselves. These are stored separately or else the properties will
2626        * not have any effect.
2627        */
2628       ID *id = ptr.owner_id;
2629       NlaStrip *strip = ptr.data;
2630       FCurve *fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), 0);
2631 
2632       if (fcu) {
2633         if (BKE_fcurve_is_protected(fcu)) {
2634           BKE_reportf(
2635               op->reports,
2636               RPT_WARNING,
2637               "Not deleting keyframe for locked F-Curve for NLA Strip influence on %s - %s '%s'",
2638               strip->name,
2639               BKE_idtype_idcode_to_name(GS(id->name)),
2640               id->name + 2);
2641         }
2642         else {
2643           /* remove the keyframe directly
2644            * NOTE: cannot use delete_keyframe_fcurve(), as that will free the curve,
2645            *       and delete_keyframe() expects the FCurve to be part of an action
2646            */
2647           bool found = false;
2648           int i;
2649 
2650           /* try to find index of beztriple to get rid of */
2651           i = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, cfra, fcu->totvert, &found);
2652           if (found) {
2653             /* delete the key at the index (will sanity check + do recalc afterwards) */
2654             delete_fcurve_key(fcu, i, 1);
2655             changed = true;
2656           }
2657         }
2658       }
2659     }
2660     else {
2661       /* standard properties */
2662       path = RNA_path_from_ID_to_property(&ptr, prop);
2663 
2664       if (path) {
2665         if (all) {
2666           /* -1 indicates operating on the entire array (or the property itself otherwise) */
2667           index = -1;
2668         }
2669 
2670         changed = delete_keyframe(bmain, op->reports, ptr.owner_id, NULL, path, index, cfra) != 0;
2671         MEM_freeN(path);
2672       }
2673       else if (G.debug & G_DEBUG) {
2674         printf("Button Delete-Key: no path to property\n");
2675       }
2676     }
2677   }
2678   else if (G.debug & G_DEBUG) {
2679     printf("ptr.data = %p, prop = %p\n", ptr.data, (void *)prop);
2680   }
2681 
2682   if (changed) {
2683     /* send updates */
2684     UI_context_update_anim_flag(C);
2685 
2686     /* send notifiers that keyframes have been changed */
2687     WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL);
2688   }
2689 
2690   return (changed) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
2691 }
2692 
ANIM_OT_keyframe_delete_button(wmOperatorType * ot)2693 void ANIM_OT_keyframe_delete_button(wmOperatorType *ot)
2694 {
2695   /* identifiers */
2696   ot->name = "Delete Keyframe (Buttons)";
2697   ot->idname = "ANIM_OT_keyframe_delete_button";
2698   ot->description = "Delete current keyframe of current UI-active property";
2699 
2700   /* callbacks */
2701   ot->exec = delete_key_button_exec;
2702   ot->poll = modify_key_op_poll;
2703 
2704   /* flags */
2705   ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
2706 
2707   /* properties */
2708   RNA_def_boolean(ot->srna, "all", 1, "All", "Delete keyframes from all elements of the array");
2709 }
2710 
2711 /* Clear Key Button Operator ------------------------ */
2712 
clear_key_button_exec(bContext * C,wmOperator * op)2713 static int clear_key_button_exec(bContext *C, wmOperator *op)
2714 {
2715   PointerRNA ptr = {NULL};
2716   PropertyRNA *prop = NULL;
2717   Main *bmain = CTX_data_main(C);
2718   char *path;
2719   bool changed = false;
2720   int index;
2721   const bool all = RNA_boolean_get(op->ptr, "all");
2722 
2723   /* try to insert keyframe using property retrieved from UI */
2724   if (!UI_context_active_but_prop_get(C, &ptr, &prop, &index)) {
2725     /* pass event on if no active button found */
2726     return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
2727   }
2728 
2729   if (ptr.owner_id && ptr.data && prop) {
2730     path = RNA_path_from_ID_to_property(&ptr, prop);
2731 
2732     if (path) {
2733       if (all) {
2734         /* -1 indicates operating on the entire array (or the property itself otherwise) */
2735         index = -1;
2736       }
2737 
2738       changed |= (clear_keyframe(bmain, op->reports, ptr.owner_id, NULL, path, index, 0) != 0);
2739       MEM_freeN(path);
2740     }
2741     else if (G.debug & G_DEBUG) {
2742       printf("Button Clear-Key: no path to property\n");
2743     }
2744   }
2745   else if (G.debug & G_DEBUG) {
2746     printf("ptr.data = %p, prop = %p\n", ptr.data, (void *)prop);
2747   }
2748 
2749   if (changed) {
2750     /* send updates */
2751     UI_context_update_anim_flag(C);
2752 
2753     /* send notifiers that keyframes have been changed */
2754     WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL);
2755   }
2756 
2757   return (changed) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
2758 }
2759 
ANIM_OT_keyframe_clear_button(wmOperatorType * ot)2760 void ANIM_OT_keyframe_clear_button(wmOperatorType *ot)
2761 {
2762   /* identifiers */
2763   ot->name = "Clear Keyframe (Buttons)";
2764   ot->idname = "ANIM_OT_keyframe_clear_button";
2765   ot->description = "Clear all keyframes on the currently active property";
2766 
2767   /* callbacks */
2768   ot->exec = clear_key_button_exec;
2769   ot->poll = modify_key_op_poll;
2770 
2771   /* flags */
2772   ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
2773 
2774   /* properties */
2775   RNA_def_boolean(ot->srna, "all", 1, "All", "Clear keyframes from all elements of the array");
2776 }
2777 
2778 /* ******************************************* */
2779 /* AUTO KEYFRAME */
2780 
autokeyframe_cfra_can_key(const Scene * scene,ID * id)2781 bool autokeyframe_cfra_can_key(const Scene *scene, ID *id)
2782 {
2783   float cfra = (float)CFRA; /* XXX for now, this will do */
2784 
2785   /* only filter if auto-key mode requires this */
2786   if (IS_AUTOKEY_ON(scene) == 0) {
2787     return false;
2788   }
2789 
2790   if (IS_AUTOKEY_MODE(scene, EDITKEYS)) {
2791     /* Replace Mode:
2792      * For whole block, only key if there's a keyframe on that frame already
2793      * This is a valid assumption when we're blocking + tweaking
2794      */
2795     return id_frame_has_keyframe(id, cfra, ANIMFILTER_KEYS_LOCAL);
2796   }
2797 
2798   /* Normal Mode (or treat as being normal mode):
2799    *
2800    * Just in case the flags aren't set properly (i.e. only on/off is set, without a mode)
2801    * let's set the "normal" flag too, so that it will all be sane everywhere...
2802    */
2803   scene->toolsettings->autokey_mode = AUTOKEY_MODE_NORMAL;
2804 
2805   /* Can insert anytime we like... */
2806   return true;
2807 }
2808 
2809 /* ******************************************* */
2810 /* KEYFRAME DETECTION */
2811 
2812 /* --------------- API/Per-Datablock Handling ------------------- */
2813 
2814 /* Checks if some F-Curve has a keyframe for a given frame */
fcurve_frame_has_keyframe(FCurve * fcu,float frame,short filter)2815 bool fcurve_frame_has_keyframe(FCurve *fcu, float frame, short filter)
2816 {
2817   /* quick sanity check */
2818   if (ELEM(NULL, fcu, fcu->bezt)) {
2819     return false;
2820   }
2821 
2822   /* we either include all regardless of muting, or only non-muted  */
2823   if ((filter & ANIMFILTER_KEYS_MUTED) || (fcu->flag & FCURVE_MUTED) == 0) {
2824     bool replace;
2825     int i = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, frame, fcu->totvert, &replace);
2826 
2827     /* BKE_fcurve_bezt_binarysearch_index will set replace to be 0 or 1
2828      * - obviously, 1 represents a match
2829      */
2830     if (replace) {
2831       /* sanity check: 'i' may in rare cases exceed arraylen */
2832       if ((i >= 0) && (i < fcu->totvert)) {
2833         return true;
2834       }
2835     }
2836   }
2837 
2838   return false;
2839 }
2840 
2841 /* Returns whether the current value of a given property differs from the interpolated value. */
fcurve_is_changed(PointerRNA ptr,PropertyRNA * prop,FCurve * fcu,const AnimationEvalContext * anim_eval_context)2842 bool fcurve_is_changed(PointerRNA ptr,
2843                        PropertyRNA *prop,
2844                        FCurve *fcu,
2845                        const AnimationEvalContext *anim_eval_context)
2846 {
2847   PathResolvedRNA anim_rna;
2848   anim_rna.ptr = ptr;
2849   anim_rna.prop = prop;
2850   anim_rna.prop_index = fcu->array_index;
2851 
2852   float buffer[RNA_MAX_ARRAY_LENGTH];
2853   int count, index = fcu->array_index;
2854   float *values = setting_get_rna_values(&ptr, prop, buffer, RNA_MAX_ARRAY_LENGTH, &count);
2855 
2856   float fcurve_val = calculate_fcurve(&anim_rna, fcu, anim_eval_context);
2857   float cur_val = (index >= 0 && index < count) ? values[index] : 0.0f;
2858 
2859   if (values != buffer) {
2860     MEM_freeN(values);
2861   }
2862 
2863   return !compare_ff_relative(fcurve_val, cur_val, FLT_EPSILON, 64);
2864 }
2865 
2866 /**
2867  * Checks whether an Action has a keyframe for a given frame
2868  * Since we're only concerned whether a keyframe exists,
2869  * we can simply loop until a match is found.
2870  */
action_frame_has_keyframe(bAction * act,float frame,short filter)2871 static bool action_frame_has_keyframe(bAction *act, float frame, short filter)
2872 {
2873   FCurve *fcu;
2874 
2875   /* can only find if there is data */
2876   if (act == NULL) {
2877     return false;
2878   }
2879 
2880   /* if only check non-muted, check if muted */
2881   if ((filter & ANIMFILTER_KEYS_MUTED) || (act->flag & ACT_MUTED)) {
2882     return false;
2883   }
2884 
2885   /* loop over F-Curves, using binary-search to try to find matches
2886    * - this assumes that keyframes are only beztriples
2887    */
2888   for (fcu = act->curves.first; fcu; fcu = fcu->next) {
2889     /* only check if there are keyframes (currently only of type BezTriple) */
2890     if (fcu->bezt && fcu->totvert) {
2891       if (fcurve_frame_has_keyframe(fcu, frame, filter)) {
2892         return true;
2893       }
2894     }
2895   }
2896 
2897   /* nothing found */
2898   return false;
2899 }
2900 
2901 /* Checks whether an Object has a keyframe for a given frame */
object_frame_has_keyframe(Object * ob,float frame,short filter)2902 static bool object_frame_has_keyframe(Object *ob, float frame, short filter)
2903 {
2904   /* error checking */
2905   if (ob == NULL) {
2906     return false;
2907   }
2908 
2909   /* check own animation data - specifically, the action it contains */
2910   if ((ob->adt) && (ob->adt->action)) {
2911     /* T41525 - When the active action is a NLA strip being edited,
2912      * we need to correct the frame number to "look inside" the
2913      * remapped action
2914      */
2915     float ob_frame = BKE_nla_tweakedit_remap(ob->adt, frame, NLATIME_CONVERT_UNMAP);
2916 
2917     if (action_frame_has_keyframe(ob->adt->action, ob_frame, filter)) {
2918       return true;
2919     }
2920   }
2921 
2922   /* try shapekey keyframes (if available, and allowed by filter) */
2923   if (!(filter & ANIMFILTER_KEYS_LOCAL) && !(filter & ANIMFILTER_KEYS_NOSKEY)) {
2924     Key *key = BKE_key_from_object(ob);
2925 
2926     /* shapekeys can have keyframes ('Relative Shape Keys')
2927      * or depend on time (old 'Absolute Shape Keys')
2928      */
2929 
2930     /* 1. test for relative (with keyframes) */
2931     if (id_frame_has_keyframe((ID *)key, frame, filter)) {
2932       return true;
2933     }
2934 
2935     /* 2. test for time */
2936     /* TODO... yet to be implemented (this feature may evolve before then anyway) */
2937   }
2938 
2939   /* try materials */
2940   if (!(filter & ANIMFILTER_KEYS_LOCAL) && !(filter & ANIMFILTER_KEYS_NOMAT)) {
2941     /* if only active, then we can skip a lot of looping */
2942     if (filter & ANIMFILTER_KEYS_ACTIVE) {
2943       Material *ma = BKE_object_material_get(ob, (ob->actcol + 1));
2944 
2945       /* we only retrieve the active material... */
2946       if (id_frame_has_keyframe((ID *)ma, frame, filter)) {
2947         return true;
2948       }
2949     }
2950     else {
2951       int a;
2952 
2953       /* loop over materials */
2954       for (a = 0; a < ob->totcol; a++) {
2955         Material *ma = BKE_object_material_get(ob, a + 1);
2956 
2957         if (id_frame_has_keyframe((ID *)ma, frame, filter)) {
2958           return true;
2959         }
2960       }
2961     }
2962   }
2963 
2964   /* nothing found */
2965   return false;
2966 }
2967 
2968 /* --------------- API ------------------- */
2969 
2970 /* Checks whether a keyframe exists for the given ID-block one the given frame */
id_frame_has_keyframe(ID * id,float frame,short filter)2971 bool id_frame_has_keyframe(ID *id, float frame, short filter)
2972 {
2973   /* sanity checks */
2974   if (id == NULL) {
2975     return false;
2976   }
2977 
2978   /* perform special checks for 'macro' types */
2979   switch (GS(id->name)) {
2980     case ID_OB: /* object */
2981       return object_frame_has_keyframe((Object *)id, frame, filter);
2982 #if 0
2983     /* XXX TODO... for now, just use 'normal' behavior */
2984     case ID_SCE: /* scene */
2985       break;
2986 #endif
2987     default: /* 'normal type' */
2988     {
2989       AnimData *adt = BKE_animdata_from_id(id);
2990 
2991       /* only check keyframes in active action */
2992       if (adt) {
2993         return action_frame_has_keyframe(adt->action, frame, filter);
2994       }
2995       break;
2996     }
2997   }
2998 
2999   /* no keyframe found */
3000   return false;
3001 }
3002 
3003 /* ************************************************** */
3004 
ED_autokeyframe_object(bContext * C,Scene * scene,Object * ob,KeyingSet * ks)3005 bool ED_autokeyframe_object(bContext *C, Scene *scene, Object *ob, KeyingSet *ks)
3006 {
3007   /* auto keyframing */
3008   if (autokeyframe_cfra_can_key(scene, &ob->id)) {
3009     ListBase dsources = {NULL, NULL};
3010 
3011     /* Now insert the key-frame(s) using the Keying Set:
3012      * 1) Add data-source override for the Object.
3013      * 2) Insert key-frames.
3014      * 3) Free the extra info.
3015      */
3016     ANIM_relative_keyingset_add_source(&dsources, &ob->id, NULL, NULL);
3017     ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
3018     BLI_freelistN(&dsources);
3019 
3020     return true;
3021   }
3022   return false;
3023 }
3024 
ED_autokeyframe_pchan(bContext * C,Scene * scene,Object * ob,bPoseChannel * pchan,KeyingSet * ks)3025 bool ED_autokeyframe_pchan(
3026     bContext *C, Scene *scene, Object *ob, bPoseChannel *pchan, KeyingSet *ks)
3027 {
3028   if (autokeyframe_cfra_can_key(scene, &ob->id)) {
3029     ListBase dsources = {NULL, NULL};
3030 
3031     /* Now insert the keyframe(s) using the Keying Set:
3032      * 1) Add data-source override for the pose-channel.
3033      * 2) Insert key-frames.
3034      * 3) Free the extra info.
3035      */
3036     ANIM_relative_keyingset_add_source(&dsources, &ob->id, &RNA_PoseBone, pchan);
3037     ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
3038     BLI_freelistN(&dsources);
3039 
3040     /* clear any unkeyed tags */
3041     if (pchan->bone) {
3042       pchan->bone->flag &= ~BONE_UNKEYED;
3043     }
3044 
3045     return true;
3046   }
3047 
3048   /* add unkeyed tags */
3049   if (pchan->bone) {
3050     pchan->bone->flag |= BONE_UNKEYED;
3051   }
3052 
3053   return false;
3054 }
3055 
3056 /**
3057  * Use for auto-keyframing from the UI.
3058  */
ED_autokeyframe_property(bContext * C,Scene * scene,PointerRNA * ptr,PropertyRNA * prop,int rnaindex,float cfra)3059 bool ED_autokeyframe_property(
3060     bContext *C, Scene *scene, PointerRNA *ptr, PropertyRNA *prop, int rnaindex, float cfra)
3061 {
3062   Main *bmain = CTX_data_main(C);
3063   Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
3064   const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph,
3065                                                                                     cfra);
3066   ID *id;
3067   bAction *action;
3068   FCurve *fcu;
3069   bool driven;
3070   bool special;
3071   bool changed = false;
3072 
3073   /* for entire array buttons we check the first component, it's not perfect
3074    * but works well enough in typical cases */
3075   const int rnaindex_check = (rnaindex == -1) ? 0 : rnaindex;
3076   fcu = BKE_fcurve_find_by_rna_context_ui(
3077       C, ptr, prop, rnaindex_check, NULL, &action, &driven, &special);
3078 
3079   if (fcu == NULL) {
3080     return changed;
3081   }
3082 
3083   if (special) {
3084     /* NLA Strip property */
3085     if (IS_AUTOKEY_ON(scene)) {
3086       ReportList *reports = CTX_wm_reports(C);
3087       ToolSettings *ts = scene->toolsettings;
3088 
3089       changed = insert_keyframe_direct(
3090           reports, *ptr, prop, fcu, &anim_eval_context, ts->keyframe_type, NULL, 0);
3091       WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
3092     }
3093   }
3094   else if (driven) {
3095     /* Driver - Try to insert keyframe using the driver's input as the frame,
3096      * making it easier to set up corrective drivers
3097      */
3098     if (IS_AUTOKEY_ON(scene)) {
3099       ReportList *reports = CTX_wm_reports(C);
3100       ToolSettings *ts = scene->toolsettings;
3101 
3102       changed = insert_keyframe_direct(
3103           reports, *ptr, prop, fcu, &anim_eval_context, ts->keyframe_type, NULL, INSERTKEY_DRIVER);
3104       WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
3105     }
3106   }
3107   else {
3108     id = ptr->owner_id;
3109 
3110     /* TODO: this should probably respect the keyingset only option for anim */
3111     if (autokeyframe_cfra_can_key(scene, id)) {
3112       ReportList *reports = CTX_wm_reports(C);
3113       ToolSettings *ts = scene->toolsettings;
3114       const eInsertKeyFlags flag = ANIM_get_keyframing_flags(scene, true);
3115 
3116       /* Note: We use rnaindex instead of fcu->array_index,
3117        *       because a button may control all items of an array at once.
3118        *       E.g., color wheels (see T42567). */
3119       BLI_assert((fcu->array_index == rnaindex) || (rnaindex == -1));
3120       changed = insert_keyframe(bmain,
3121                                 reports,
3122                                 id,
3123                                 action,
3124                                 ((fcu->grp) ? (fcu->grp->name) : (NULL)),
3125                                 fcu->rna_path,
3126                                 rnaindex,
3127                                 &anim_eval_context,
3128                                 ts->keyframe_type,
3129                                 NULL,
3130                                 flag) != 0;
3131 
3132       WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
3133     }
3134   }
3135   return changed;
3136 }
3137 
3138 /* -------------------------------------------------------------------- */
3139 /** \name Internal Utilities
3140  * \{ */
3141 
3142 /** Use for insert/delete key-frame. */
keyingset_get_from_op_with_error(wmOperator * op,PropertyRNA * prop,Scene * scene)3143 static KeyingSet *keyingset_get_from_op_with_error(wmOperator *op, PropertyRNA *prop, Scene *scene)
3144 {
3145   KeyingSet *ks = NULL;
3146   const int prop_type = RNA_property_type(prop);
3147   if (prop_type == PROP_ENUM) {
3148     int type = RNA_property_enum_get(op->ptr, prop);
3149     ks = ANIM_keyingset_get_from_enum_type(scene, type);
3150     if (ks == NULL) {
3151       BKE_report(op->reports, RPT_ERROR, "No active Keying Set");
3152     }
3153   }
3154   else if (prop_type == PROP_STRING) {
3155     char type_id[MAX_ID_NAME - 2];
3156     RNA_property_string_get(op->ptr, prop, type_id);
3157     ks = ANIM_keyingset_get_from_idname(scene, type_id);
3158 
3159     if (ks == NULL) {
3160       BKE_reportf(op->reports, RPT_ERROR, "Keying set '%s' not found", type_id);
3161     }
3162   }
3163   else {
3164     BLI_assert(0);
3165   }
3166   return ks;
3167 }
3168 
3169 /** \} */
3170