Blender V4.5
keyframes_general_test.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2025 Blender Authors
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include "testing/testing.h"
6
8
9#include "BLI_listbase.h"
10#include "BLI_string.h"
11
12#include "BKE_armature.hh"
13#include "BKE_fcurve.hh"
14#include "BKE_idtype.hh"
15#include "BKE_lib_id.hh"
16#include "BKE_main.hh"
17#include "BKE_object.hh"
18
19#include "DNA_anim_types.h"
20#include "DNA_object_types.h"
21
22#include "ED_keyframes_edit.hh"
23
24using namespace blender::animrig;
25
27
28namespace {
29
30/* std::unique_ptr for FCurve. */
31struct fcurve_deleter {
32 void operator()(FCurve *fcurve) const
33 {
34 /* If this F-Curve was registered as "bone", remove it from that registration as well. */
35 keyframe_copy_buffer->bone_fcurves.remove(fcurve);
36
37 BKE_fcurve_free(fcurve);
38 }
39};
40using FCurvePtr = std::unique_ptr<FCurve, fcurve_deleter>;
41
46FCurvePtr fake_fcurve(const char *rna_path, const int array_index)
47{
48 FCurve *fcurve = BKE_fcurve_create();
49
50 if (rna_path) {
51 fcurve->rna_path = BLI_strdup(rna_path);
52 }
53 fcurve->array_index = array_index;
54
55 return FCurvePtr(fcurve);
56}
57
65FCurvePtr fake_fcurve_in_buffer(const char *rna_path,
66 const int array_index,
67 const bool is_bone,
68 const slot_handle_t slot_handle = Slot::unassigned,
69 ID *owner_id = nullptr)
70{
71 FCurvePtr fcurve_ptr = fake_fcurve(rna_path, array_index);
72
73 if (is_bone) {
74 keyframe_copy_buffer->bone_fcurves.add(fcurve_ptr.get());
75 }
76
77 if (owner_id) {
78 keyframe_copy_buffer->slot_animated_ids.add_overwrite(slot_handle, owner_id);
79 }
80 return fcurve_ptr;
81}
82
83} // namespace
84
90struct keyframes_paste : public testing::Test {
91 static void SetUpTestSuite()
92 {
94 }
95
96 static void TearDownTestSuite()
97 {
99 }
100};
101
103{
104 EXPECT_EQ(std::nullopt, flip_names("whatever")) << "not a bone prefix";
105
106 EXPECT_EQ("pose.bones[\"head\"]", flip_names("pose.bones[\"head\"]"))
107 << "unflippable name should remain unchanged";
108 EXPECT_EQ("pose.bones[\"Arm_L\"]", flip_names("pose.bones[\"Arm_R\"]"))
109 << "flippable name should be flipped";
110
111 EXPECT_EQ("pose.bones[\"Arm_L\"].rotation_euler",
112 flip_names("pose.bones[\"Arm_R\"].rotation_euler"))
113 << "flippable name should be flipped";
114}
115
117{
118 constexpr slot_handle_t unassigned = Slot::unassigned;
119
120 { /* NULL RNA paths. */
122 FCurvePtr fcurve_target = fake_fcurve(nullptr, 0);
123 FCurvePtr fcurve_in_buffer = fake_fcurve_in_buffer(nullptr, 0, false);
124
125 /* Little wrapper for #pastebuf_match_path_full() to make it easier to see
126 * the differences between the test-cases. */
127 auto call = [&](const bool from_single, const bool to_single, const bool flip) {
129 nullptr, *fcurve_target, *fcurve_in_buffer, unassigned, from_single, to_single, flip);
130 };
131
132 /* This only matches when `to_single` is true. */
133 EXPECT_FALSE(call(false, false, false));
134 EXPECT_FALSE(call(false, false, true));
135 EXPECT_TRUE(call(false, true, false));
136 EXPECT_TRUE(call(false, true, true));
137 EXPECT_FALSE(call(true, false, false));
138 EXPECT_FALSE(call(true, false, true));
139 EXPECT_TRUE(call(true, true, false));
140 EXPECT_TRUE(call(true, true, true));
141 }
142
143 { /* Many to many, no flipping. */
145 FCurvePtr fcurve = fake_fcurve("location", 0);
146
147 EXPECT_TRUE(pastebuf_match_path_full(nullptr,
148 *fcurve,
149 *fake_fcurve_in_buffer("location", 0, false),
150 unassigned,
151 false,
152 false,
153 false));
154 EXPECT_FALSE(pastebuf_match_path_full(nullptr,
155 *fcurve,
156 *fake_fcurve_in_buffer("location", 1, false),
157 unassigned,
158 false,
159 false,
160 false))
161 << "array index mismatch";
162 EXPECT_FALSE(pastebuf_match_path_full(nullptr,
163 *fcurve,
164 *fake_fcurve_in_buffer("rotation_euler", 0, false),
165 unassigned,
166 false,
167 false,
168 false))
169 << "rna path mismatch";
170 }
171
172 /* Many to many, Flipping bone names. */
173 {
175 const bool from_single = false;
176 const bool to_single = false;
177 const bool flip = true;
178
179 FCurvePtr fcurve = fake_fcurve("pose.bones[\"hand.L\"].location", 0);
180
181 EXPECT_FALSE(pastebuf_match_path_full(
182 nullptr,
183 *fcurve,
184 *fake_fcurve_in_buffer("pose.bones[\"hand.L\"].location", 0, true),
185 unassigned,
186 from_single,
187 to_single,
188 flip))
189 << "original path match, is bone";
190 EXPECT_TRUE(pastebuf_match_path_full(
191 nullptr,
192 *fcurve,
193 *fake_fcurve_in_buffer("pose.bones[\"hand.R\"].location", 0, true),
194 unassigned,
195 from_single,
196 to_single,
197 flip))
198 << "flipped path match, is bone";
199
200 EXPECT_FALSE(pastebuf_match_path_full(
201 nullptr,
202 *fcurve,
203 *fake_fcurve_in_buffer("pose.bones[\"hand.R\"].location", 0, false),
204 unassigned,
205 from_single,
206 to_single,
207 flip))
208 << "flipped path match, is NOT bone";
209 EXPECT_TRUE(pastebuf_match_path_full(
210 nullptr,
211 *fcurve,
212 *fake_fcurve_in_buffer("pose.bones[\"hand.L\"].location", 0, false),
213 unassigned,
214 from_single,
215 to_single,
216 flip))
217 << "original path match, is NOT bone";
218
219 EXPECT_FALSE(pastebuf_match_path_full(nullptr,
220 *fcurve,
221 *fake_fcurve_in_buffer("location", 0, false),
222 unassigned,
223 from_single,
224 to_single,
225 flip))
226 << "rna path mismatch";
227
228 EXPECT_FALSE(pastebuf_match_path_full(
229 nullptr,
230 *fcurve,
231 *fake_fcurve_in_buffer("pose.bones[\"hand.R\"].location", 1, true),
232 unassigned,
233 from_single,
234 to_single,
235 flip))
236 << "flipped path match, but array index mismatch";
237 }
238
239 /* Many to single (so only array index matters), Flipping bone names requested (but won't happen
240 * because 'to single'). */
241 {
243 const bool from_single = false;
244 const bool to_single = true;
245 const bool flip = true;
246
247 FCurvePtr fcurve = fake_fcurve("pose.bones[\"hand.L\"].location", 0);
248
249 EXPECT_TRUE(pastebuf_match_path_full(
250 nullptr,
251 *fcurve,
252 *fake_fcurve_in_buffer("pose.bones[\"hand.L\"].location", 0, true),
253 unassigned,
254 from_single,
255 to_single,
256 flip))
257 << "original path match, is bone";
258 EXPECT_TRUE(pastebuf_match_path_full(
259 nullptr,
260 *fcurve,
261 *fake_fcurve_in_buffer("pose.bones[\"hand.R\"].location", 0, true),
262 unassigned,
263 from_single,
264 to_single,
265 flip))
266 << "flipped path match, is bone";
267
268 EXPECT_TRUE(pastebuf_match_path_full(nullptr,
269 *fcurve,
270 *fake_fcurve_in_buffer("location", 0, false),
271 unassigned,
272 from_single,
273 to_single,
274 flip))
275 << "rna path mismatch, ACI is NOT bone";
276
277 EXPECT_TRUE(pastebuf_match_path_full(
278 nullptr,
279 *fcurve,
280 *fake_fcurve_in_buffer("pose.bones[\"nose\"].rotation_euler", 0, true),
281 unassigned,
282 from_single,
283 to_single,
284 flip))
285 << "rna path mismatch, ACI is bone";
286
287 EXPECT_FALSE(pastebuf_match_path_full(
288 nullptr,
289 *fcurve,
290 *fake_fcurve_in_buffer("pose.bones[\"hand.L\"].location", 1, true),
291 unassigned,
292 from_single,
293 to_single,
294 flip))
295 << "original path match, but array index mismatch";
296
297 EXPECT_FALSE(pastebuf_match_path_full(
298 nullptr,
299 *fcurve,
300 *fake_fcurve_in_buffer("pose.bones[\"hand.R\"].location", 1, true),
301 unassigned,
302 from_single,
303 to_single,
304 flip))
305 << "flipped path match, but array index mismatch";
306 }
307
308 { /* Single (so array indices won't matter) to Many, Flipping bone names requested. */
310 const bool from_single = true;
311 const bool to_single = false;
312 const bool flip = true;
313
314 FCurvePtr fcurve = fake_fcurve("pose.bones[\"hand.L\"].location", 0);
315
316 EXPECT_FALSE(pastebuf_match_path_full(
317 nullptr,
318 *fcurve,
319 *fake_fcurve_in_buffer("pose.bones[\"hand.L\"].location", 0, true),
320 unassigned,
321 from_single,
322 to_single,
323 flip))
324 << "original path match, is bone";
325 EXPECT_TRUE(pastebuf_match_path_full(
326 nullptr,
327 *fcurve,
328 *fake_fcurve_in_buffer("pose.bones[\"hand.R\"].location", 0, true),
329 unassigned,
330 from_single,
331 to_single,
332 flip))
333 << "flipped path match, is bone";
334
335 EXPECT_FALSE(pastebuf_match_path_full(nullptr,
336 *fcurve,
337 *fake_fcurve_in_buffer("location", 0, false),
338 unassigned,
339 from_single,
340 to_single,
341 flip))
342 << "rna path mismatch, ACI is NOT bone";
343
344 EXPECT_FALSE(pastebuf_match_path_full(
345 nullptr,
346 *fcurve,
347 *fake_fcurve_in_buffer("pose.bones[\"nose\"].rotation_euler", 0, true),
348 unassigned,
349 from_single,
350 to_single,
351 flip))
352 << "rna path mismatch, ACI is bone";
353
354 EXPECT_FALSE(pastebuf_match_path_full(
355 nullptr,
356 *fcurve,
357 *fake_fcurve_in_buffer("pose.bones[\"hand.L\"].location", 1, true),
358 unassigned,
359 from_single,
360 to_single,
361 flip))
362 << "original path match, but array index mismatch";
363
364 EXPECT_TRUE(pastebuf_match_path_full(
365 nullptr,
366 *fcurve,
367 *fake_fcurve_in_buffer("pose.bones[\"hand.R\"].location", 1, true),
368 unassigned,
369 from_single,
370 to_single,
371 flip))
372 << "flipped path match, but array index mismatch";
373 }
374
375 {
376 /* Single (so array indices won't matter) to Many, NOT flipping bone names. */
378 const bool from_single = true;
379 const bool to_single = false;
380 const bool flip = false;
381
382 FCurvePtr fcurve = fake_fcurve("pose.bones[\"hand.L\"].location", 0);
383
384 EXPECT_TRUE(pastebuf_match_path_full(
385 nullptr,
386 *fcurve,
387 *fake_fcurve_in_buffer("pose.bones[\"hand.L\"].location", 0, true),
388 unassigned,
389 from_single,
390 to_single,
391 flip))
392 << "original path match, is bone";
393 EXPECT_FALSE(pastebuf_match_path_full(
394 nullptr,
395 *fcurve,
396 *fake_fcurve_in_buffer("pose.bones[\"hand.R\"].location", 0, true),
397 unassigned,
398 from_single,
399 to_single,
400 flip))
401 << "flipped path match, is bone";
402
403 EXPECT_FALSE(pastebuf_match_path_full(nullptr,
404 *fcurve,
405 *fake_fcurve_in_buffer("location", 0, false),
406 unassigned,
407 from_single,
408 to_single,
409 flip))
410 << "rna path mismatch, ACI is NOT bone";
411
412 EXPECT_FALSE(pastebuf_match_path_full(
413 nullptr,
414 *fcurve,
415 *fake_fcurve_in_buffer("pose.bones[\"nose\"].rotation_euler", 0, true),
416 unassigned,
417 from_single,
418 to_single,
419 flip))
420 << "rna path mismatch, ACI is bone";
421
422 EXPECT_TRUE(pastebuf_match_path_full(
423 nullptr,
424 *fcurve,
425 *fake_fcurve_in_buffer("pose.bones[\"hand.L\"].location", 1, true),
426 unassigned,
427 from_single,
428 to_single,
429 flip))
430 << "original path match, but array index mismatch";
431
432 EXPECT_FALSE(pastebuf_match_path_full(
433 nullptr,
434 *fcurve,
435 *fake_fcurve_in_buffer("pose.bones[\"hand.R\"].location", 1, true),
436 unassigned,
437 from_single,
438 to_single,
439 flip))
440 << "flipped path match, but array index mismatch";
441 }
442
443 /* Single to Single (so nothing should matter), Flipping bone names requested. */
444 {
446 const bool from_single = true;
447 const bool to_single = true;
448 const bool flip = true;
449
450 FCurvePtr fcurve = fake_fcurve("pose.bones[\"hand.L\"].location", 0);
451
452 EXPECT_TRUE(pastebuf_match_path_full(
453 nullptr,
454 *fcurve,
455 *fake_fcurve_in_buffer("pose.bones[\"hand.L\"].location", 0, true),
456 unassigned,
457 from_single,
458 to_single,
459 flip))
460 << "original path match, is bone";
461 EXPECT_TRUE(pastebuf_match_path_full(
462 nullptr,
463 *fcurve,
464 *fake_fcurve_in_buffer("pose.bones[\"hand.R\"].location", 0, true),
465 unassigned,
466 from_single,
467 to_single,
468 flip))
469 << "flipped path match, is bone";
470
471 EXPECT_TRUE(pastebuf_match_path_full(nullptr,
472 *fcurve,
473 *fake_fcurve_in_buffer("location", 0, false),
474 unassigned,
475 from_single,
476 to_single,
477 flip))
478 << "rna path mismatch, ACI is NOT bone";
479
480 EXPECT_TRUE(pastebuf_match_path_full(
481 nullptr,
482 *fcurve,
483 *fake_fcurve_in_buffer("pose.bones[\"nose\"].rotation_euler", 0, true),
484 unassigned,
485 from_single,
486 to_single,
487 flip))
488 << "rna path mismatch, ACI is bone";
489
490 EXPECT_TRUE(pastebuf_match_path_full(
491 nullptr,
492 *fcurve,
493 *fake_fcurve_in_buffer("pose.bones[\"hand.R\"].location", 1, true),
494 unassigned,
495 from_single,
496 to_single,
497 flip))
498 << "flipped path match, but array index mismatch";
499
500 EXPECT_TRUE(pastebuf_match_path_full(
501 nullptr,
502 *fcurve,
503 *fake_fcurve_in_buffer("pose.bones[\"hand.L\"].location", 1, true),
504 unassigned,
505 from_single,
506 to_single,
507 flip))
508 << "original path match, but array index mismatch";
509 }
510}
511
513{
514 constexpr slot_handle_t unassigned = Slot::unassigned;
515
516 Main *bmain = BKE_main_new();
517 ID *arm_ob_id;
518
519 { /* Set up an armature, to test matching on property names. */
521
522 bArmature *armature = BKE_armature_add(bmain, "Armature");
523 for (const auto &bone_name : {"hand.L", "hand.R", "middle"}) {
524 Bone *bone = MEM_callocN<Bone>(__func__);
525 STRNCPY(bone->name, bone_name);
526 BLI_addtail(&armature->bonebase, bone);
527 }
528
529 Object *armature_object = BKE_object_add_only_object(bmain, OB_ARMATURE, "Armature");
530 armature_object->data = armature;
531 BKE_pose_ensure(bmain, armature_object, armature, false);
532
533 arm_ob_id = &armature_object->id;
534 }
535
536 /* Wrapper function to create an F-Curve in the copy buffer, animating the armature object. */
537 const auto fake_armob_fcurve =
538 [&](const char *rna_path, const int array_index, const bool is_bone) {
539 return fake_fcurve_in_buffer(rna_path, array_index, is_bone, unassigned, arm_ob_id);
540 };
541
542 { /* From Single Channel, so array indices are ignored. */
544 const bool from_single = true;
545 const bool to_single = false; /* Doesn't matter, function under test doesn't use this. */
546 const bool flip = false; /* Doesn't matter, function under test doesn't use this. */
547
548 FCurvePtr fcurve = fake_fcurve("pose.bones[\"hand.L\"].location", 0);
549
551 bmain,
552 *fcurve,
553 *fake_armob_fcurve("pose.bones[\"hand.L\"].location", 0, true),
554 unassigned,
555 from_single,
556 to_single,
557 flip))
558 << "original path match, is bone";
559
561 bmain,
562 *fcurve,
563 *fake_armob_fcurve("pose.bones[\"hand.R\"].location", 0, true),
564 unassigned,
565 from_single,
566 to_single,
567 flip))
568 << "flipped path match, is bone";
569
571 bmain,
572 *fcurve,
573 *fake_armob_fcurve("pose.bones[\"hand.L\"].location", 2, true),
574 unassigned,
575 from_single,
576 to_single,
577 flip))
578 << "original path match, other array index";
579
580 EXPECT_FALSE(pastebuf_match_path_property(
581 bmain,
582 *fcurve,
583 *fake_armob_fcurve("pose.bones[\"hand.L\"].rotation_euler", 0, true),
584 unassigned,
585 from_single,
586 to_single,
587 flip))
588 << "same bone, other property";
589
590 EXPECT_FALSE(pastebuf_match_path_property(bmain,
591 *fcurve,
592 *fake_armob_fcurve("rotation_euler", 0, false),
593 unassigned,
594 from_single,
595 to_single,
596 flip))
597 << "other struct, same property name";
598
599 EXPECT_FALSE(pastebuf_match_path_property(
600 bmain,
601 *fcurve,
602 *fake_armob_fcurve("pose.bones[\"missing\"].location", 0, true),
603 unassigned,
604 from_single,
605 to_single,
606 flip))
607 << "nonexistent bone, but same property name";
608
609 /* This just tests the current functionality. This may not necessarily be
610 * correct / desired behavior. */
611 FCurvePtr fcurve_with_long_rna_path = fake_fcurve(
612 "pose.bones[\"hand.L\"].weirdly_long_location", 0);
614 bmain,
615 *fcurve,
616 *fake_armob_fcurve("pose.bones[\"hand.L\"].location", 0, true),
617 unassigned,
618 from_single,
619 to_single,
620 flip))
621 << "property name suffix-match";
622 }
623
624 { /* From Multiple Channels, so array indices matter. */
626 const bool from_single = false;
627 const bool to_single = false; /* Doesn't matter, function under test doesn't use this. */
628 const bool flip = false; /* Doesn't matter, function under test doesn't use this. */
629
630 FCurvePtr fcurve = fake_fcurve("pose.bones[\"hand.L\"].location", 0);
631
633 bmain,
634 *fcurve,
635 *fake_armob_fcurve("pose.bones[\"hand.L\"].location", 0, true),
636 unassigned,
637 from_single,
638 to_single,
639 flip))
640 << "original path match, is bone";
641
643 bmain,
644 *fcurve,
645 *fake_armob_fcurve("pose.bones[\"hand.R\"].location", 0, true),
646 unassigned,
647 from_single,
648 to_single,
649 flip))
650 << "flipped path match, is bone";
651
652 EXPECT_FALSE(pastebuf_match_path_property(
653 bmain,
654 *fcurve,
655 *fake_armob_fcurve("pose.bones[\"hand.L\"].location", 2, true),
656 unassigned,
657 from_single,
658 to_single,
659 flip))
660 << "original path match, other array index";
661
662 EXPECT_FALSE(pastebuf_match_path_property(
663 bmain,
664 *fcurve,
665 *fake_armob_fcurve("pose.bones[\"hand.L\"].rotation_euler", 0, true),
666 unassigned,
667 from_single,
668 to_single,
669 flip))
670 << "same bone, other property";
671
672 EXPECT_FALSE(pastebuf_match_path_property(bmain,
673 *fcurve,
674 *fake_armob_fcurve("rotation_euler", 0, false),
675 unassigned,
676 from_single,
677 to_single,
678 flip))
679 << "other struct, same property name";
680
681 EXPECT_FALSE(pastebuf_match_path_property(
682 bmain,
683 *fcurve,
684 *fake_armob_fcurve("pose.bones[\"missing\"].location", 0, true),
685 unassigned,
686 from_single,
687 to_single,
688 flip))
689 << "nonexistent bone, but same property name";
690
691 /* This just tests the current functionality. This may not necessarily be
692 * correct / desired behavior. */
693 FCurvePtr fcurve_with_long_rna_path = fake_fcurve(
694 "pose.bones[\"hand.L\"].weirdly_long_location", 0);
696 bmain,
697 *fcurve,
698 *fake_armob_fcurve("pose.bones[\"hand.L\"].location", 0, true),
699 unassigned,
700 from_single,
701 to_single,
702 flip))
703 << "property name suffix-match";
704 }
705
706 { /* Resilience against deleted IDs. */
708 FCurvePtr fcurve = fake_fcurve("pose.bones[\"hand.L\"].location", 0);
709 Object *object_not_in_main = BKE_object_add_only_object(nullptr, OB_EMPTY, "non-main");
710
711 EXPECT_FALSE(pastebuf_match_path_property(
712 bmain,
713 *fcurve,
714 *fake_fcurve_in_buffer(
715 "pose.bones[\"hand.L\"].location", 0, true, unassigned, &object_not_in_main->id),
716 unassigned,
717 false,
718 false,
719 false))
720 << "copying from deleted ID";
721
722 BKE_id_free(nullptr, &object_not_in_main->id);
723 }
724
725 BKE_main_free(bmain);
726}
727
729{
730 constexpr slot_handle_t unassigned = Slot::unassigned;
732 FCurvePtr fcurve = fake_fcurve("some_prop", 1);
733
734 EXPECT_TRUE(pastebuf_match_index_only(nullptr,
735 *fcurve,
736 *fake_fcurve_in_buffer("location", 1, false),
737 unassigned,
738 false,
739 false,
740 false));
741 EXPECT_FALSE(pastebuf_match_index_only(nullptr,
742 *fcurve,
743 *fake_fcurve_in_buffer("location", 2, false),
744 unassigned,
745 false,
746 false,
747 false));
748}
749
750} // namespace blender::ed::animation::tests
void BKE_pose_ensure(Main *bmain, Object *ob, bArmature *arm, bool do_id_user)
Definition armature.cc:2932
bArmature * BKE_armature_add(Main *bmain, const char *name)
Definition armature.cc:538
FCurve * BKE_fcurve_create()
void BKE_fcurve_free(FCurve *fcu)
void BKE_idtype_init()
Definition idtype.cc:122
void BKE_id_free(Main *bmain, void *idv)
Main * BKE_main_new()
Definition main.cc:48
void BKE_main_free(Main *bmain)
Definition main.cc:175
General operations, lookup, etc. for blender objects.
Object * BKE_object_add_only_object(Main *bmain, int type, const char *name) ATTR_RETURNS_NONNULL
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.cc:41
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
Object is a sort of wrapper for general info.
@ OB_EMPTY
@ OB_ARMATURE
SIMD_FORCE_INLINE btVector3 operator()(const btVector3 &x) const
Return the transform of the vector.
Definition btTransform.h:90
static constexpr slot_handle_t unassigned
void ANIM_fcurves_copybuf_reset()
void ANIM_fcurves_copybuf_free()
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
TEST_F(ActionIteratorsTest, iterate_all_fcurves_of_slot)
decltype(::ActionSlot::handle) slot_handle_t
KeyframeCopyBuffer * keyframe_copy_buffer
bool pastebuf_match_index_only(Main *, const FCurve &fcurve_to_match, const FCurve &fcurve_in_copy_buffer, blender::animrig::slot_handle_t, const bool from_single, const bool, const bool)
bool pastebuf_match_path_full(Main *, const FCurve &fcurve_to_match, const FCurve &fcurve_in_copy_buffer, blender::animrig::slot_handle_t, const bool from_single, const bool to_single, const bool flip)
bool pastebuf_match_path_property(Main *bmain, const FCurve &fcurve_to_match, const FCurve &fcurve_in_copy_buffer, blender::animrig::slot_handle_t slot_handle_in_copy_buffer, const bool from_single, const bool, const bool)
std::optional< std::string > flip_names(const blender::StringRefNull rna_path)
char name[64]
char * rna_path
int array_index
Definition DNA_ID.h:404