Blender V4.3
animrig/intern/keyframing.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cmath>
10#include <string>
11
12#include <fmt/format.h>
13
14#include "ANIM_action.hh"
16#include "ANIM_action_legacy.hh"
17#include "ANIM_animdata.hh"
18#include "ANIM_fcurve.hh"
19#include "ANIM_keyframing.hh"
20#include "ANIM_rna.hh"
21#include "ANIM_visualkey.hh"
22
23#include "BKE_action.hh"
24#include "BKE_anim_data.hh"
25#include "BKE_animsys.h"
26#include "BKE_fcurve.hh"
27#include "BKE_idtype.hh"
28#include "BKE_lib_id.hh"
29#include "BKE_nla.hh"
30#include "BKE_report.hh"
31
32#include "DNA_scene_types.h"
33
34#include "BLI_bit_vector.hh"
35#include "BLI_dynstr.h"
36#include "BLI_math_base.h"
37#include "BLI_utildefines.h"
38#include "BLT_translation.hh"
39
40#include "DEG_depsgraph.hh"
42#include "DNA_anim_types.h"
43#include "MEM_guardedalloc.h"
44#include "RNA_access.hh"
45#include "RNA_path.hh"
46#include "RNA_prototypes.hh"
47
48#include "WM_types.hh"
49
50namespace blender::animrig {
51
53{
54 result_counter.fill(0);
55}
56
58{
59 result_counter[int(result)] += count;
60}
61
63{
64 for (int i = 0; i < result_counter.size(); i++) {
65 result_counter[i] += other.result_counter[i];
66 }
67}
68
70{
71 return result_counter[int(result)];
72}
73
75{
76 /* For loop starts at 1 to skip the SUCCESS flag. Assumes that SUCCESS is 0 and the rest of the
77 * enum are sequential values. */
78 static_assert(int(SingleKeyingResult::SUCCESS) == 0);
79 for (int i = 1; i < result_counter.size(); i++) {
80 if (result_counter[i] > 0) {
81 return true;
82 }
83 }
84 return false;
85}
86
88{
89 if (!this->has_errors() && this->get_count(SingleKeyingResult::SUCCESS) == 0) {
91 reports, RPT_WARNING, "No keys have been inserted and no errors have been reported.");
92 return;
93 }
94
97 const int error_count = this->get_count(SingleKeyingResult::UNKNOWN_FAILURE);
98 errors.append(
99 fmt::format(RPT_("There were {:d} keying failures for unknown reasons."), error_count));
100 }
101
103 const int error_count = this->get_count(SingleKeyingResult::CANNOT_CREATE_FCURVE);
104 errors.append(fmt::format(RPT_("Could not create {:d} F-Curve(s). This can happen when only "
105 "inserting to available F-Curves."),
106 error_count));
107 }
108
110 const int error_count = this->get_count(SingleKeyingResult::FCURVE_NOT_KEYFRAMEABLE);
111 errors.append(
112 fmt::format(RPT_("{:d} F-Curve(s) are not keyframeable. They might be locked or sampled."),
113 error_count));
114 }
115
117 const int error_count = this->get_count(SingleKeyingResult::NO_KEY_NEEDED);
118 errors.append(fmt::format(
119 RPT_("Due to the setting 'Only Insert Needed', {:d} keyframe(s) have not been inserted."),
120 error_count));
121 }
122
125 errors.append(
126 fmt::format(RPT_("Due to the NLA stack setup, {:d} keyframe(s) have not been inserted."),
127 error_count));
128 }
129
131 const int error_count = this->get_count(SingleKeyingResult::ID_NOT_EDITABLE);
132 errors.append(fmt::format(RPT_("Inserting keys on {:d} data-block(s) has been skipped because "
133 "they are not editable."),
134 error_count));
135 }
136
138 const int error_count = this->get_count(SingleKeyingResult::ID_NOT_ANIMATABLE);
139 errors.append(fmt::format(RPT_("Inserting keys on {:d} data-block(s) has been skipped because "
140 "they cannot be animated."),
141 error_count));
142 }
143
145 const int error_count = this->get_count(SingleKeyingResult::CANNOT_RESOLVE_PATH);
146 errors.append(fmt::format(RPT_("Inserting keys on {:d} data-block(s) has been skipped because "
147 "the RNA path wasn't valid for them."),
148 error_count));
149 }
150
152 const int error_count = this->get_count(SingleKeyingResult::NO_VALID_LAYER);
153 errors.append(fmt::format(RPT_("Inserting keys on {:d} data-block(s) has been skipped because "
154 "there were no layers that could accept the keys."),
155 error_count));
156 }
157
159 const int error_count = this->get_count(SingleKeyingResult::NO_VALID_STRIP);
160 errors.append(fmt::format(RPT_("Inserting keys on {:d} data-block(s) has been skipped because "
161 "there were no strips that could accept the keys."),
162 error_count));
163 }
164
166 const int error_count = this->get_count(SingleKeyingResult::NO_VALID_SLOT);
167 errors.append(fmt::format(RPT_("Inserting keys on {:d} data-block(s) has been skipped because "
168 "of missing action slots."),
169 error_count));
170 }
171
172 if (errors.is_empty()) {
173 BKE_report(reports, RPT_WARNING, "Encountered unhandled error during keyframing");
174 return;
175 }
176
177 if (errors.size() == 1) {
178 BKE_report(reports, report_level, errors[0].c_str());
179 return;
180 }
181
182 std::string error_message = RPT_("Inserting keyframes failed:");
183 for (const std::string &error : errors) {
184 error_message.append(fmt::format("\n- {}", error));
185 }
186 BKE_report(reports, report_level, error_message.c_str());
187}
188
189const std::optional<StringRefNull> default_channel_group_for_path(
190 const PointerRNA *animated_struct, const StringRef prop_rna_path)
191{
192 if (animated_struct->type == &RNA_PoseBone) {
193 bPoseChannel *pose_channel = static_cast<bPoseChannel *>(animated_struct->data);
194 BLI_assert(pose_channel->name != nullptr);
195 return pose_channel->name;
196 }
197
198 if (animated_struct->type == &RNA_Object) {
199 if (prop_rna_path.find("location") != StringRef::not_found ||
200 prop_rna_path.find("rotation") != StringRef::not_found ||
201 prop_rna_path.find("scale") != StringRef::not_found)
202 {
203 /* NOTE: Keep this label in sync with the "ID" case in
204 * keyingsets_utils.py :: get_transform_generators_base_info()
205 */
206 return "Object Transforms";
207 }
208 }
209
210 return std::nullopt;
211}
212
214{
215 /* Set additional flags for the F-Curve (i.e. only integer values). */
217 switch (RNA_property_type(prop)) {
218 case PROP_FLOAT:
219 /* Do nothing. */
220 break;
221 case PROP_INT:
222 /* Do integer (only 'whole' numbers) interpolation between all points. */
223 fcu->flag |= FCURVE_INT_VALUES;
224 break;
225 default:
226 /* Do 'discrete' (i.e. enum, boolean values which cannot take any intermediate
227 * values at all) interpolation between all points.
228 * - however, we must also ensure that evaluated values are only integers still.
229 */
231 break;
232 }
233}
234
235bool is_keying_flag(const Scene *scene, const eKeying_Flag flag)
236{
237 if (scene) {
238 return (scene->toolsettings->keying_flag & flag) || (U.keying_flag & flag);
239 }
240 return U.keying_flag & flag;
241}
242
244{
246
247 /* Visual keying. */
250 }
251
252 /* Cycle-aware keyframe insertion - preserve cycle period and flow. */
255 }
256
259 }
260
261 return flag;
262}
263
265{
266 return (insert_key_flags & (INSERTKEY_REPLACE | INSERTKEY_AVAILABLE)) == 0;
267}
268
270static void make_new_fcurve_cyclic(FCurve *fcu, const blender::float2 &action_range)
271{
272 /* The curve must contain one (newly-added) keyframe. */
273 if (fcu->totvert != 1 || !fcu->bezt) {
274 return;
275 }
276
277 const float period = action_range[1] - action_range[0];
278
279 if (period < 0.1f) {
280 return;
281 }
282
283 /* Move the keyframe into the range. */
284 const float frame_offset = fcu->bezt[0].vec[1][0] - action_range[0];
285 const float fix = floorf(frame_offset / period) * period;
286
287 fcu->bezt[0].vec[0][0] -= fix;
288 fcu->bezt[0].vec[1][0] -= fix;
289 fcu->bezt[0].vec[2][0] -= fix;
290
291 /* Duplicate and offset the keyframe. */
292 fcu->bezt = static_cast<BezTriple *>(MEM_reallocN(fcu->bezt, sizeof(BezTriple) * 2));
293 fcu->totvert = 2;
294
295 fcu->bezt[1] = fcu->bezt[0];
296 fcu->bezt[1].vec[0][0] += period;
297 fcu->bezt[1].vec[1][0] += period;
298 fcu->bezt[1].vec[2][0] += period;
299
300 if (!fcu->modifiers.first) {
302 }
303}
304
305/* Check indices that were intended to be remapped and report any failed remaps. */
308 PropertyRNA *prop,
309 const int index,
310 const int count,
311 const bool force_all,
312 const BitSpan successful_remaps)
313{
314
315 DynStr *ds_failed_indices = BLI_dynstr_new();
316
317 int total_failed = 0;
318 for (int i = 0; i < count; i++) {
319 const bool cur_index_evaluated = ELEM(index, i, -1) || force_all;
320 if (!cur_index_evaluated) {
321 /* `values[i]` was never intended to be remapped. */
322 continue;
323 }
324
325 if (successful_remaps[i]) {
326 /* `values[i]` successfully remapped. */
327 continue;
328 }
329
330 total_failed++;
331 /* Report that `values[i]` were intended to be remapped but failed remapping process. */
332 BLI_dynstr_appendf(ds_failed_indices, "%d, ", i);
333 }
334
335 if (total_failed == 0) {
336 BLI_dynstr_free(ds_failed_indices);
337 return;
338 }
339
340 char *str_failed_indices = BLI_dynstr_get_cstring(ds_failed_indices);
341 BLI_dynstr_free(ds_failed_indices);
342
343 BKE_reportf(reports,
345 "Could not insert %i keyframe(s) due to zero NLA influence, base value, or value "
346 "remapping failed: %s.%s for indices [%s]",
347 total_failed,
350 str_failed_indices);
351
352 MEM_freeN(str_failed_indices);
353}
354
355static Vector<float> get_keyframe_values(PointerRNA *ptr, PropertyRNA *prop, const bool visual_key)
356{
357 Vector<float> values;
358
359 if (visual_key && visualkey_can_use(ptr, prop)) {
360 /* Visual-keying is only available for object and pchan datablocks, as
361 * it works by keyframing using a value extracted from the final matrix
362 * instead of using the kt system to extract a value.
363 */
364 values = visualkey_get_values(ptr, prop);
365 }
366 else {
367 values = get_rna_values(ptr, prop);
368 }
369 return values;
370}
371
373 const MutableSpan<float> values,
374 const int index,
376 PropertyRNA &prop,
377 NlaKeyframingContext *nla_context,
378 const AnimationEvalContext *anim_eval_context,
379 ReportList *reports,
380 bool *force_all)
381{
382 BitVector<> successful_remaps(values.size(), false);
384 nla_context, &ptr, &prop, values, index, anim_eval_context, force_all, successful_remaps);
386 reports, ptr, &prop, index, values.size(), false, successful_remaps);
387 return successful_remaps;
388}
389
390static float nla_time_remap(float time,
391 const AnimationEvalContext *anim_eval_context,
392 PointerRNA *id_ptr,
393 AnimData *adt,
394 bAction *act,
395 ListBase *nla_cache,
396 NlaKeyframingContext **r_nla_context)
397{
398 if (adt && adt->action == act) {
400 nla_cache, id_ptr, adt, anim_eval_context);
401
402 const float remapped_frame = BKE_nla_tweakedit_remap(adt, time, NLATIME_CONVERT_UNMAP);
403 return remapped_frame;
404 }
405
406 *r_nla_context = nullptr;
407 return time;
408}
409
410/* Insert the specified keyframe value into a single F-Curve. */
412 FCurve *fcu, float cfra, float curval, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag)
413{
414 if (!BKE_fcurve_is_keyframable(fcu)) {
416 }
417
419 settings.keyframe_type = keytype;
420
421 return insert_vert_fcurve(fcu, {cfra, curval}, settings, flag);
422}
423
426 PropertyRNA *prop,
427 FCurve *fcu,
428 const AnimationEvalContext *anim_eval_context,
430 NlaKeyframingContext *nla_context,
432{
433
434 if (fcu == nullptr) {
435 BKE_report(reports, RPT_ERROR, "No F-Curve to add keyframes to");
436 return false;
437 }
438
439 if ((ptr.owner_id == nullptr) && (ptr.data == nullptr)) {
441 reports, RPT_ERROR, "No RNA pointer available to retrieve values for keyframing from");
442 return false;
443 }
444
445 if (prop == nullptr) {
446 PointerRNA tmp_ptr;
447
448 if (RNA_path_resolve_property(&ptr, fcu->rna_path, &tmp_ptr, &prop) == false) {
449 const char *idname = (ptr.owner_id) ? ptr.owner_id->name : RPT_("<No ID pointer>");
450
451 BKE_reportf(reports,
452 RPT_ERROR,
453 "Could not insert keyframe, as RNA path is invalid for the given ID (ID = %s, "
454 "path = %s)",
455 idname,
456 fcu->rna_path);
457 return false;
458 }
459
460 /* Property found, so overwrite 'ptr' to make later code easier. */
461 ptr = tmp_ptr;
462 }
463
464 /* Update F-Curve flags to ensure proper behavior for property type. */
466
467 const int index = fcu->array_index;
468 const bool visual_keyframing = flag & INSERTKEY_MATRIX;
469 Vector<float> values = get_keyframe_values(&ptr, prop, visual_keyframing);
470
472 values.as_mutable_span(),
473 index,
474 ptr,
475 *prop,
476 nla_context,
477 anim_eval_context,
478 reports,
479 nullptr);
480
481 float current_value = 0.0f;
482 if (index >= 0 && index < values.size()) {
483 current_value = values[index];
484 }
485
486 /* This happens if NLA rejects this insertion. */
487 if (!successful_remaps[index]) {
488 return false;
489 }
490
491 const float cfra = anim_eval_context->eval_time;
492 const SingleKeyingResult result = insert_keyframe_value(fcu, cfra, current_value, keytype, flag);
493
494 if (result != SingleKeyingResult::SUCCESS) {
495 BKE_reportf(reports,
496 RPT_ERROR,
497 "Failed to insert keys on F-Curve with path '%s[%d]', ensure that it is not "
498 "locked or sampled, and try removing F-Modifiers",
499 fcu->rna_path,
500 fcu->array_index);
501 }
502 return result == SingleKeyingResult::SUCCESS;
503}
504
508 PropertyRNA *prop,
509 bAction *act,
510 const char group[],
511 const char rna_path[],
512 int array_index,
513 const float fcurve_frame,
514 float curval,
517{
518 BLI_assert(rna_path != nullptr);
519
520 /* Make sure the F-Curve exists.
521 * - if we're replacing keyframes only, DO NOT create new F-Curves if they do not exist yet
522 * but still try to get the F-Curve if it exists...
523 */
524
526 action_fcurve_ensure(bmain, act, group, ptr, {rna_path, array_index}) :
527 fcurve_find_in_action(act, {rna_path, array_index});
528
529 /* We may not have a F-Curve when we're replacing only. */
530 if (!fcu) {
532 }
533
534 const bool is_new_curve = (fcu->totvert == 0);
535
536 /* If the curve has only one key, make it cyclic if appropriate. */
537 const bool is_cyclic_action = (flag & INSERTKEY_CYCLE_AWARE) && act->wrap().is_cyclic();
538
539 if (is_cyclic_action && fcu->totvert == 1) {
541 }
542
543 /* Update F-Curve flags to ensure proper behavior for property type. */
545
547 fcu, fcurve_frame, curval, keytype, flag);
548
549 /* If the curve is new, make it cyclic if appropriate. */
550 if (is_cyclic_action && is_new_curve) {
552 }
553
554 return result;
555}
556
557/* ************************************************** */
558/* KEYFRAME DELETION */
559
560/* Main Keyframing API call:
561 * Use this when validation of necessary animation data isn't necessary as it
562 * already exists. It will delete a keyframe at the current frame.
563 *
564 * The flag argument is used for special settings that alter the behavior of
565 * the keyframe deletion. These include the quick refresh options.
566 */
567
568static void deg_tag_after_keyframe_delete(Main *bmain, ID *id, AnimData *adt)
569{
570 if (adt->action == nullptr) {
571 /* In the case last f-curve was removed need to inform dependency graph
572 * about relations update, since it needs to get rid of animation operation
573 * for this data-block. */
576 }
577 else {
579 }
580}
581
582int delete_keyframe(Main *bmain, ReportList *reports, ID *id, const RNAPath &rna_path, float cfra)
583{
585
586 if (ELEM(nullptr, id, adt)) {
587 BKE_report(reports, RPT_ERROR, "No ID block and/or AnimData to delete keyframe from");
588 return 0;
589 }
590
592 PropertyRNA *prop;
594 if (RNA_path_resolve_property(&id_ptr, rna_path.path.c_str(), &ptr, &prop) == false) {
596 reports,
597 RPT_ERROR,
598 "Could not delete keyframe, as RNA path is invalid for the given ID (ID = %s, path = %s)",
599 id->name,
600 rna_path.path.c_str());
601 return 0;
602 }
603
604 if (!adt->action) {
605 BKE_reportf(reports, RPT_ERROR, "No action to delete keyframes from for ID = %s", id->name);
606 return 0;
607 }
608 bAction *act = adt->action;
610 int array_index = rna_path.index.value_or(0);
611 int array_index_max = array_index + 1;
612
613 if (!rna_path.index.has_value()) {
614 array_index_max = RNA_property_array_length(&ptr, prop);
615 /* For single properties, increase max_index so that the property itself gets included,
616 * but don't do this for standard arrays since that can cause corruption issues
617 * (extra unused curves).
618 */
619 if (array_index_max == array_index) {
620 array_index_max++;
621 }
622 }
623
624 Action &action = act->wrap();
625 Vector<FCurve *> modified_fcurves;
626 if (action.is_action_layered()) {
627 /* Just being defensive in the face of the NLA shenanigans above. This
628 * probably isn't necessary, but it doesn't hurt. */
629 BLI_assert(adt->action == act && action.slot_for_handle(adt->slot_handle) != nullptr);
630
631 Span<FCurve *> fcurves = fcurves_for_action_slot(action, adt->slot_handle);
632 /* This loop's clause is copied from the pre-existing code for legacy
633 * actions below, to ensure behavioral consistency between the two code
634 * paths. In the future when legacy actions are removed, we can restructure
635 * it to be clearer. */
636 for (; array_index < array_index_max; array_index++) {
637 FCurve *fcurve = fcurve_find(fcurves, {rna_path.path, array_index});
638 if (fcurve == nullptr) {
639 continue;
640 }
641 if (fcurve_delete_keyframe_at_time(fcurve, cfra)) {
642 modified_fcurves.append(fcurve);
643 }
644 }
645 }
646 else {
647 /* Will only loop once unless the array index was -1. */
648 for (; array_index < array_index_max; array_index++) {
649 FCurve *fcu = fcurve_find_in_action(act, {rna_path.path, array_index});
650
651 if (fcu == nullptr) {
652 continue;
653 }
654
655 if (BKE_fcurve_is_protected(fcu)) {
656 BKE_reportf(reports,
658 "Not deleting keyframe for locked F-Curve '%s' for %s '%s'",
659 fcu->rna_path,
660 BKE_idtype_idcode_to_name(GS(id->name)),
661 id->name + 2);
662 continue;
663 }
664
665 if (fcurve_delete_keyframe_at_time(fcu, cfra)) {
666 modified_fcurves.append(fcu);
667 }
668 }
669 }
670
671 if (!modified_fcurves.is_empty()) {
672 for (FCurve *fcurve : modified_fcurves) {
673 if (BKE_fcurve_is_empty(fcurve)) {
674 animdata_fcurve_delete(nullptr, adt, fcurve);
675 }
676 }
677 deg_tag_after_keyframe_delete(bmain, id, adt);
678 }
679
680 return modified_fcurves.size();
681}
682
683/* ************************************************** */
684/* KEYFRAME CLEAR */
685
686int clear_keyframe(Main *bmain, ReportList *reports, ID *id, const RNAPath &rna_path)
687{
689
690 if (ELEM(nullptr, id, adt)) {
691 BKE_report(reports, RPT_ERROR, "No ID block and/or AnimData to delete keyframe from");
692 return 0;
693 }
694
696 PropertyRNA *prop;
698 if (RNA_path_resolve_property(&id_ptr, rna_path.path.c_str(), &ptr, &prop) == false) {
700 reports,
701 RPT_ERROR,
702 "Could not clear keyframe, as RNA path is invalid for the given ID (ID = %s, path = %s)",
703 id->name,
704 rna_path.path.c_str());
705 return 0;
706 }
707
708 if (!adt->action) {
709 BKE_reportf(reports, RPT_ERROR, "No action to delete keyframes from for ID = %s", id->name);
710 return 0;
711 }
712 bAction *act = adt->action;
713
714 Action &action = act->wrap();
715 int key_count = 0;
716
717 if (action.is_action_layered()) {
718 if (adt->slot_handle) {
719 Vector<FCurve *> fcurves;
720 foreach_fcurve_in_action_slot(action, adt->slot_handle, [&](FCurve &fcurve) {
721 if (rna_path.index.has_value() && rna_path.index.value() != fcurve.array_index) {
722 return;
723 }
724 if (rna_path.path != fcurve.rna_path) {
725 return;
726 }
727 fcurves.append(&fcurve);
728 });
729
730 for (FCurve *fcu : fcurves) {
731 if (action_fcurve_remove(action, *fcu)) {
732 key_count++;
733 }
734 }
735 }
736 }
737 else {
738 int array_index = rna_path.index.value_or(0);
739 int array_index_max = array_index + 1;
740 if (!rna_path.index.has_value()) {
741 array_index_max = RNA_property_array_length(&ptr, prop);
742
743 /* For single properties, increase max_index so that the property itself gets included,
744 * but don't do this for standard arrays since that can cause corruption issues
745 * (extra unused curves).
746 */
747 if (array_index_max == array_index) {
748 array_index_max++;
749 }
750 }
751 /* Will only loop once unless the array index was -1. */
752 for (; array_index < array_index_max; array_index++) {
753 FCurve *fcu = fcurve_find_in_action(act, {rna_path.path, array_index});
754
755 if (fcu == nullptr) {
756 continue;
757 }
758
759 if (BKE_fcurve_is_protected(fcu)) {
760 BKE_reportf(reports,
762 "Not clearing all keyframes from locked F-Curve '%s' for %s '%s'",
763 fcu->rna_path,
764 BKE_idtype_idcode_to_name(GS(id->name)),
765 id->name + 2);
766 continue;
767 }
768
769 animdata_fcurve_delete(nullptr, adt, fcu);
770
771 key_count++;
772 }
773 }
774
775 if (key_count) {
776 deg_tag_after_keyframe_delete(bmain, id, adt);
777 }
778
779 return key_count;
780}
781
783 Main *bmain,
784 bAction *action,
786 PropertyRNA *prop,
787 const std::optional<StringRefNull> channel_group,
788 const std::string &rna_path,
789 const float frame,
790 const Span<float> values,
791 eInsertKeyFlags insert_key_flag,
793 const BitSpan keying_mask)
794{
795 BLI_assert(bmain != nullptr);
796 BLI_assert(action != nullptr);
797 BLI_assert(action->wrap().is_action_legacy());
798
799 const char *group;
800 if (channel_group.has_value()) {
801 group = channel_group->c_str();
802 }
803 else {
804 const std::optional<StringRefNull> default_group = default_channel_group_for_path(ptr,
805 rna_path);
806 group = default_group.has_value() ? default_group->c_str() : nullptr;
807 }
808
809 int property_array_index = 0;
810 CombinedKeyingResult combined_result;
811 for (float value : values) {
812 if (!keying_mask[property_array_index]) {
813 combined_result.add(SingleKeyingResult::UNABLE_TO_INSERT_TO_NLA_STACK);
814 property_array_index++;
815 continue;
816 }
817 const SingleKeyingResult keying_result = insert_keyframe_fcurve_value(bmain,
818 ptr,
819 prop,
820 action,
821 group,
822 rna_path.c_str(),
823 property_array_index,
824 frame,
825 value,
826 key_type,
827 insert_key_flag);
828 combined_result.add(keying_result);
829 property_array_index++;
830 }
831 return combined_result;
832}
833
838
840 Main *bmain,
841 Action &action,
842 Layer &layer,
843 const Slot &slot,
844 const std::string &rna_path,
845 const std::optional<PropertySubType> prop_subtype,
846 const std::optional<blender::StringRefNull> channel_group,
847 const KeyInsertData &key_data,
848 const KeyframeSettings &key_settings,
849 const eInsertKeyFlags insert_key_flags)
850{
852 BLI_assert(layer.strips().size() == 1);
853
854 Strip *strip = layer.strip(0);
855 return strip->data<StripKeyframeData>(action).keyframe_insert(
856 bmain,
857 slot,
858 {rna_path, key_data.array_index, prop_subtype, channel_group},
859 key_data.position,
860 key_settings,
861 insert_key_flags);
862}
863
865 Main *bmain,
866 Action &action,
867 PointerRNA *rna_pointer,
868 const std::optional<StringRefNull> channel_group,
869 const blender::Span<RNAPath> rna_paths,
870 const float scene_frame,
871 const KeyframeSettings &key_settings,
872 const eInsertKeyFlags insert_key_flags)
873{
875 ID &animated_id = *rna_pointer->owner_id;
877 ELEM(get_action(animated_id), &action, nullptr),
878 "The animated ID should not be using another Action than the one passed to this function");
879
880 Slot *slot = assign_action_ensure_slot_for_keying(action, animated_id);
882 slot,
883 "The conditions that would cause this Slot assigment to fail (such as the ID not being "
884 "animatible) should have been caught and handled by higher-level functions.");
885
886 action.layer_keystrip_ensure();
887
888 /* TODO: we currently assume this will always successfully find a layer.
889 * However, that may not be true in the future when we implement features like
890 * layer locking: if layers already exist, but they are all locked, then the
891 * default layer won't be added by the line above, but there also won't be any
892 * layers we can insert keys into. */
893 Layer *layer = action.get_layer_for_keyframing();
894 BLI_assert(layer != nullptr);
895
896 const bool use_visual_keyframing = insert_key_flags & INSERTKEY_MATRIX;
897
898 CombinedKeyingResult combined_result;
899 for (const RNAPath &rna_path : rna_paths) {
901 PropertyRNA *prop = nullptr;
902 const bool path_resolved = RNA_path_resolve_property(
903 rna_pointer, rna_path.path.c_str(), &ptr, &prop);
904 if (!path_resolved) {
905 std::fprintf(stderr,
906 "Failed to insert key on slot %s due to unresolved RNA path: %s\n",
907 slot->name,
908 rna_path.path.c_str());
909 combined_result.add(SingleKeyingResult::CANNOT_RESOLVE_PATH);
910 continue;
911 }
912 const std::optional<std::string> rna_path_id_to_prop = RNA_path_from_ID_to_property(&ptr,
913 prop);
914 BLI_assert(rna_path_id_to_prop.has_value());
915
916 const std::optional<blender::StringRefNull> this_rna_path_channel_group =
917 channel_group.has_value() ? *channel_group :
918 default_channel_group_for_path(&ptr, *rna_path_id_to_prop);
919
920 const PropertySubType prop_subtype = RNA_property_subtype(prop);
921 Vector<float> rna_values = get_keyframe_values(&ptr, prop, use_visual_keyframing);
922
923 for (const int property_index : rna_values.index_range()) {
924 /* If we're only keying one array element, skip all elements other than
925 * that one. index == -1 means 'all array elements' though, so that one is
926 * treated just like having no value here at all. */
927 if (rna_path.index.has_value() && *rna_path.index != -1 && *rna_path.index != property_index)
928 {
929 continue;
930 }
931
932 const KeyInsertData key_data = {{scene_frame, rna_values[property_index]}, property_index};
933 const SingleKeyingResult result = insert_key_layer(bmain,
934 action,
935 *layer,
936 *slot,
937 *rna_path_id_to_prop,
938 prop_subtype,
939 this_rna_path_channel_group,
940 key_data,
941 key_settings,
942 insert_key_flags);
943 combined_result.add(result);
944 }
945 }
946
948
949 return combined_result;
950}
951
953 PointerRNA *struct_pointer,
954 const std::optional<StringRefNull> channel_group,
955 const blender::Span<RNAPath> rna_paths,
956 const std::optional<float> scene_frame,
957 const AnimationEvalContext &anim_eval_context,
958 const eBezTriple_KeyframeType key_type,
959 const eInsertKeyFlags insert_key_flags)
960
961{
962 ID *id = struct_pointer->owner_id;
963 PointerRNA id_pointer = RNA_id_pointer_create(id);
964 CombinedKeyingResult combined_result;
965
966 /* Init animdata if none available yet. */
968 if (adt == nullptr) {
969 combined_result.add(SingleKeyingResult::ID_NOT_ANIMATABLE);
970 return combined_result;
971 }
972
973 if ((adt->action == nullptr) && (insert_key_flags & INSERTKEY_AVAILABLE)) {
974 combined_result.add(SingleKeyingResult::CANNOT_CREATE_FCURVE, rna_paths.size());
975 return combined_result;
976 }
977
978 bAction *dna_action = id_action_ensure(bmain, id);
979 BLI_assert(dna_action != nullptr);
980
981 if (!animrig::legacy::action_treat_as_legacy(*dna_action)) {
982 Action &action = dna_action->wrap();
984 (insert_key_flags & INSERTKEY_NO_USERPREF) == 0);
985 key_settings.keyframe_type = key_type;
986 return insert_key_layered_action(bmain,
987 action,
988 struct_pointer,
989 channel_group,
990 rna_paths,
991 scene_frame.value_or(anim_eval_context.eval_time),
992 key_settings,
993 insert_key_flags);
994 }
995
996 /* NOTE: keyframing functions can deal with the nla_context being a nullptr. */
997 ListBase nla_cache = {nullptr, nullptr};
998 NlaKeyframingContext *nla_context = nullptr;
999 const float nla_frame = nla_time_remap(scene_frame.value_or(anim_eval_context.eval_time),
1000 &anim_eval_context,
1001 &id_pointer,
1002 adt,
1003 dna_action,
1004 &nla_cache,
1005 &nla_context);
1006 const bool visual_keyframing = insert_key_flags & INSERTKEY_MATRIX;
1007
1008 for (const RNAPath &rna_path : rna_paths) {
1010 PropertyRNA *prop = nullptr;
1011 const bool path_resolved = RNA_path_resolve_property(
1012 struct_pointer, rna_path.path.c_str(), &ptr, &prop);
1013 if (!path_resolved) {
1014 combined_result.add(SingleKeyingResult::CANNOT_RESOLVE_PATH);
1015 continue;
1016 }
1017
1018 Vector<float> rna_values = get_keyframe_values(&ptr, prop, visual_keyframing);
1019 BitVector<> rna_values_mask(rna_values.size(), false);
1020 bool force_all;
1021
1022 /* NOTE: this function call is complex with interesting/non-obvious effects.
1023 * Please see its documentation for details. */
1025 struct_pointer,
1026 prop,
1027 rna_values.as_mutable_span(),
1028 rna_path.index.value_or(-1),
1029 &anim_eval_context,
1030 &force_all,
1031 rna_values_mask);
1032
1033 const std::optional<std::string> rna_path_id_to_prop = RNA_path_from_ID_to_property(&ptr,
1034 prop);
1035 if (!rna_path_id_to_prop.has_value()) {
1036 continue;
1037 }
1038
1039 /* Handle the `force_all` condition mentioned above, ensuring the
1040 * "all-or-nothing" behavior if needed.
1041 *
1042 * TODO: this currently doesn't account for the "Only Insert Available"
1043 * flag, which also needs to be accounted for to actually ensure
1044 * all-or-nothing behavior. This is because the function this part of the
1045 * code originally came from (see #122053) also didn't account for it.
1046 * Presumably that was an oversight, and should be addressed. But for now
1047 * we're faithfully reproducing the original behavior.
1048 */
1049 eInsertKeyFlags insert_key_flags_adjusted = insert_key_flags;
1050 if (force_all && (insert_key_flags & (INSERTKEY_REPLACE | INSERTKEY_AVAILABLE))) {
1051 /* Determine if at least one element would succeed getting keyed. */
1052 bool at_least_one_would_succeed = false;
1053 for (int i = 0; i < rna_values.size(); i++) {
1054 const FCurve *fcu = fcurve_find_in_action(dna_action, {*rna_path_id_to_prop, i});
1055 if (!fcu) {
1056 continue;
1057 }
1058
1059 /* We found an fcurve, and "Only Replace" is not on, so a key insertion
1060 * would succeed according to the two flags we're accounting for. */
1061 if (!(insert_key_flags & INSERTKEY_REPLACE)) {
1062 at_least_one_would_succeed = true;
1063 break;
1064 }
1065
1066 /* "Only Replace" *is* on, so a key insertion would succeed only if we
1067 * actually replace an existing keyframe. */
1068 bool replace;
1069 BKE_fcurve_bezt_binarysearch_index(fcu->bezt, nla_frame, fcu->totvert, &replace);
1070 if (replace) {
1071 at_least_one_would_succeed = true;
1072 break;
1073 }
1074 }
1075
1076 /* If at least one would succeed, then we disable all keying flags that
1077 * would prevent the other elements from getting keyed as well. */
1078 if (at_least_one_would_succeed) {
1079 insert_key_flags_adjusted &= ~(INSERTKEY_REPLACE | INSERTKEY_AVAILABLE);
1080 }
1081 }
1082
1084 dna_action,
1085 struct_pointer,
1086 prop,
1087 channel_group,
1088 rna_path_id_to_prop->c_str(),
1089 nla_frame,
1090 rna_values.as_span(),
1091 insert_key_flags_adjusted,
1092 key_type,
1093 rna_values_mask);
1094 combined_result.merge(result);
1095 }
1096
1098
1099 if (combined_result.get_count(SingleKeyingResult::SUCCESS) > 0) {
1101
1102 /* TODO: it's not entirely clear why the action we got wouldn't be the same
1103 * as the action in AnimData. Further, it's not clear why it would need to
1104 * be tagged for a depsgraph update regardless. This code is here because it
1105 * was part of the function this one was refactored from, but at some point
1106 * this should be investigated and either documented or removed. */
1107 if (!ELEM(adt->action, nullptr, dna_action)) {
1109 }
1110 }
1111
1112 return combined_result;
1113}
1114
1115} // namespace blender::animrig
Functions and classes to work with Actions.
Functionality to iterate an Action in various ways.
Functions for backward compatibility with the legacy Action API.
Functions to work with AnimData.
Functions to modify FCurves.
Functions to insert, delete or modify keyframes.
Helper functions for animation to interact with the RNA system.
Functions to work with the visual keying system.
Blender kernel action and pose functionality.
AnimData * BKE_animdata_ensure_id(ID *id)
Definition anim_data.cc:103
AnimData * BKE_animdata_from_id(const ID *id)
Definition anim_data.cc:89
void BKE_animsys_free_nla_keyframing_context_cache(struct ListBase *cache)
Definition anim_sys.cc:3913
void BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context, struct PointerRNA *prop_ptr, struct PropertyRNA *prop, const blender::MutableSpan< float > values, int index, const struct AnimationEvalContext *anim_eval_context, bool *r_force_all, blender::BitVector<> &r_values_mask)
struct NlaKeyframingContext * BKE_animsys_get_nla_keyframing_context(struct ListBase *cache, struct PointerRNA *ptr, struct AnimData *adt, const struct AnimationEvalContext *anim_eval_context)
bool BKE_fcurve_is_keyframable(const FCurve *fcu)
int BKE_fcurve_bezt_binarysearch_index(const BezTriple array[], float frame, int arraylen, bool *r_replace)
FModifier * add_fmodifier(ListBase *modifiers, int type, FCurve *owner_fcu)
bool BKE_fcurve_is_empty(const FCurve *fcu)
bool BKE_fcurve_is_protected(const FCurve *fcu)
const char * BKE_idtype_idcode_to_name(short idcode)
Definition idtype.cc:168
float BKE_nla_tweakedit_remap(AnimData *adt, float cframe, short mode)
@ NLATIME_CONVERT_UNMAP
Definition BKE_nla.hh:513
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
A dynamically sized string ADT.
char * BLI_dynstr_get_cstring(const DynStr *ds) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition BLI_dynstr.c:149
DynStr * BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_dynstr.c:37
void BLI_dynstr_free(DynStr *ds) ATTR_NONNULL()
Definition BLI_dynstr.c:174
void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format,...) ATTR_PRINTF_FORMAT(2
#define ELEM(...)
#define RPT_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_id_tag_update_ex(Main *bmain, ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
@ ID_RECALC_ANIMATION_NO_FLUSH
Definition DNA_ID.h:1143
eInsertKeyFlags
@ INSERTKEY_CYCLE_AWARE
@ INSERTKEY_REPLACE
@ INSERTKEY_MATRIX
@ INSERTKEY_NEEDED
@ INSERTKEY_NO_USERPREF
@ INSERTKEY_AVAILABLE
@ INSERTKEY_NOFLAGS
@ FMODIFIER_TYPE_CYCLES
@ FCURVE_INT_VALUES
@ FCURVE_DISCRETE_VALUES
eBezTriple_KeyframeType
@ MANUALKEY_FLAG_INSERTNEEDED
@ KEYING_FLAG_VISUALKEY
@ KEYING_FLAG_CYCLEAWARE
Read Guarded memory(de)allocation.
#define MEM_reallocN(vmemh, len)
@ PROP_FLOAT
Definition RNA_types.hh:67
@ PROP_INT
Definition RNA_types.hh:66
PropertySubType
Definition RNA_types.hh:135
unsigned int U
Definition btGjkEpa3.h:78
constexpr int64_t size() const
Definition BLI_span.hh:253
static constexpr int64_t not_found
constexpr int64_t find(char c, int64_t pos=0) const
int64_t size() const
void append(const T &value)
bool is_empty() const
IndexRange index_range() const
MutableSpan< T > as_mutable_span()
Span< T > as_span() const
Slot * slot_for_handle(slot_handle_t handle)
void merge(const CombinedKeyingResult &other)
int get_count(const SingleKeyingResult result) const
void generate_reports(ReportList *reports, eReportType report_level=RPT_ERROR)
void add(SingleKeyingResult result, int count=1)
const T & data(const Action &owning_action) const
double time
#define floorf(x)
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
int count
#define GS(x)
Definition iris.cc:202
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
static void error(const char *str)
bool action_treat_as_legacy(const bAction &action)
void foreach_fcurve_in_action_slot(Action &action, slot_handle_t handle, FunctionRef< void(FCurve &fcurve)> callback)
bool action_fcurve_remove(Action &action, FCurve &fcu)
void assert_baklava_phase_1_invariants(const Action &action)
static SingleKeyingResult insert_key_layer(Main *bmain, Action &action, Layer &layer, const Slot &slot, const std::string &rna_path, const std::optional< PropertySubType > prop_subtype, const std::optional< blender::StringRefNull > channel_group, const KeyInsertData &key_data, const KeyframeSettings &key_settings, const eInsertKeyFlags insert_key_flags)
static Vector< float > get_keyframe_values(PointerRNA *ptr, PropertyRNA *prop, const bool visual_key)
KeyframeSettings get_keyframe_settings(bool from_userprefs)
Slot * assign_action_ensure_slot_for_keying(Action &action, ID &animated_id)
bAction * id_action_ensure(Main *bmain, ID *id)
Definition animdata.cc:195
FCurve * action_fcurve_ensure(Main *bmain, bAction *act, const char group[], PointerRNA *ptr, FCurveDescriptor fcurve_descriptor)
void update_autoflags_fcurve_direct(FCurve *fcu, PropertyRNA *prop)
Vector< float > visualkey_get_values(PointerRNA *ptr, PropertyRNA *prop)
Definition visualkey.cc:197
bool visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop)
Definition visualkey.cc:37
static SingleKeyingResult insert_keyframe_value(FCurve *fcu, float cfra, float curval, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag)
static CombinedKeyingResult insert_key_legacy_action(Main *bmain, bAction *action, PointerRNA *ptr, PropertyRNA *prop, const std::optional< StringRefNull > channel_group, const std::string &rna_path, const float frame, const Span< float > values, eInsertKeyFlags insert_key_flag, eBezTriple_KeyframeType key_type, const BitSpan keying_mask)
Vector< float > get_rna_values(PointerRNA *ptr, PropertyRNA *prop)
Definition anim_rna.cc:16
static CombinedKeyingResult insert_key_layered_action(Main *bmain, Action &action, PointerRNA *rna_pointer, const std::optional< StringRefNull > channel_group, const blender::Span< RNAPath > rna_paths, const float scene_frame, const KeyframeSettings &key_settings, const eInsertKeyFlags insert_key_flags)
static void get_keyframe_values_create_reports(ReportList *reports, PointerRNA ptr, PropertyRNA *prop, const int index, const int count, const bool force_all, const BitSpan successful_remaps)
int clear_keyframe(Main *bmain, ReportList *reports, ID *id, const RNAPath &rna_path)
const FCurve * fcurve_find(Span< const FCurve * > fcurves, FCurveDescriptor fcurve_descriptor)
int delete_keyframe(Main *bmain, ReportList *reports, ID *id, const RNAPath &rna_path, float cfra)
Main Delete Key-Framing API call.
bool fcurve_delete_keyframe_at_time(FCurve *fcurve, float time)
CombinedKeyingResult insert_keyframes(Main *bmain, PointerRNA *struct_pointer, std::optional< StringRefNull > channel_group, const blender::Span< RNAPath > rna_paths, std::optional< float > scene_frame, const AnimationEvalContext &anim_eval_context, eBezTriple_KeyframeType key_type, eInsertKeyFlags insert_key_flags)
Main key-frame insertion API.
SingleKeyingResult insert_vert_fcurve(FCurve *fcu, const float2 position, const KeyframeSettings &settings, eInsertKeyFlags flag)
Main Key-framing API call.
Span< FCurve * > fcurves_for_action_slot(Action &action, slot_handle_t slot_handle)
static void make_new_fcurve_cyclic(FCurve *fcu, const blender::float2 &action_range)
Action * get_action(ID &animated_id)
static BitVector nla_map_keyframe_values_and_generate_reports(const MutableSpan< float > values, const int index, PointerRNA &ptr, PropertyRNA &prop, NlaKeyframingContext *nla_context, const AnimationEvalContext *anim_eval_context, ReportList *reports, bool *force_all)
const std::optional< StringRefNull > default_channel_group_for_path(const PointerRNA *animated_struct, const StringRef prop_rna_path)
FCurve * fcurve_find_in_action(bAction *act, FCurveDescriptor fcurve_descriptor)
static float nla_time_remap(float time, const AnimationEvalContext *anim_eval_context, PointerRNA *id_ptr, AnimData *adt, bAction *act, ListBase *nla_cache, NlaKeyframingContext **r_nla_context)
bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, const AnimationEvalContext *anim_eval_context, eBezTriple_KeyframeType keytype, NlaKeyframingContext *nla_context, eInsertKeyFlags flag)
Secondary Insert Key-framing API call.
bool is_keying_flag(const Scene *scene, eKeying_Flag flag)
bool key_insertion_may_create_fcurve(eInsertKeyFlags insert_key_flags)
static SingleKeyingResult insert_keyframe_fcurve_value(Main *bmain, PointerRNA *ptr, PropertyRNA *prop, bAction *act, const char group[], const char rna_path[], int array_index, const float fcurve_frame, float curval, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag)
static void deg_tag_after_keyframe_delete(Main *bmain, ID *id, AnimData *adt)
void animdata_fcurve_delete(bAnimContext *ac, AnimData *adt, FCurve *fcu)
Definition animdata.cc:253
eInsertKeyFlags get_keyframing_flags(Scene *scene)
PropertyType RNA_property_type(PropertyRNA *prop)
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
const char * RNA_property_ui_name(const PropertyRNA *prop)
PropertySubType RNA_property_subtype(PropertyRNA *prop)
PointerRNA RNA_id_pointer_create(ID *id)
std::optional< std::string > RNA_path_from_ID_to_property(const PointerRNA *ptr, PropertyRNA *prop)
Definition rna_path.cc:1166
bool RNA_path_resolve_property(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
Definition rna_path.cc:553
bAction * action
int32_t slot_handle
float vec[3][3]
char * rna_path
BezTriple * bezt
int array_index
unsigned int totvert
ListBase modifiers
Definition DNA_ID.h:413
char name[66]
Definition DNA_ID.h:425
void * first
ID * owner_id
Definition RNA_types.hh:40
StructRNA * type
Definition RNA_types.hh:41
void * data
Definition RNA_types.hh:42
std::optional< int > index
Definition RNA_path.hh:66
std::string path
Definition RNA_path.hh:59
float frame_start
eBezTriple_KeyframeType keyframe_type
PointerRNA * ptr
Definition wm_files.cc:4126
uint8_t flag
Definition wm_window.cc:138