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