Blender V4.3
animrig/intern/action_test.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
5#include "ANIM_action.hh"
6
7#include "BKE_action.hh"
8#include "BKE_anim_data.hh"
9#include "BKE_fcurve.hh"
10#include "BKE_idtype.hh"
11#include "BKE_lib_id.hh"
12#include "BKE_main.hh"
13#include "BKE_object.hh"
14
15#include "DNA_anim_types.h"
16#include "DNA_object_types.h"
17
18#include "RNA_access.hh"
19
20#include "BLI_listbase.h"
21#include "BLI_string.h"
22#include "BLI_string_utf8.h"
23
24#include <limits>
25
26#include "CLG_log.h"
27#include "testing/testing.h"
28
30class ActionLayersTest : public testing::Test {
31 public:
37
38 static void SetUpTestSuite()
39 {
40 /* BKE_id_free() hits a code path that uses CLOG, which crashes if not initialized properly. */
41 CLG_init();
42
43 /* To make id_can_have_animdata() and friends work, the `id_types` array needs to be set up. */
45 }
46
47 static void TearDownTestSuite()
48 {
49 CLG_exit();
50 }
51
52 void SetUp() override
53 {
55 action = static_cast<Action *>(BKE_id_new(bmain, ID_AC, "ACÄnimåtië"));
59 }
60
61 void TearDown() override
62 {
64 }
65};
66
68{
69 Layer &layer = action->layer_add("layer name");
70
71 EXPECT_EQ(action->layer(0), &layer);
72 EXPECT_EQ("layer name", std::string(layer.name));
73 EXPECT_EQ(1.0f, layer.influence) << "Expected DNA defaults to be used.";
74 EXPECT_EQ(0, action->layer_active_index)
75 << "Expected newly added layer to become the active layer.";
76 ASSERT_EQ(0, layer.strips().size()) << "Expected newly added layer to have no strip.";
77}
78
79TEST_F(ActionLayersTest, add_layer__reset_idroot)
80{
81 /* An empty Action is a valid legacy Action, and thus can have its idroot set to a non-zero
82 * value. If such an Action gets a layer, it no longer is a valid legacy Action, and thus its
83 * idtype should be reset to zero. */
84 action->idroot = ID_CA; /* Fake that this was assigned to a camera data-block. */
85 ASSERT_NE(0, action->idroot) << "action->idroot should not be zero at the start of this test.";
86
87 action->layer_add("layer name");
88
89 EXPECT_EQ(0, action->idroot)
90 << "action->idroot should get reset when the Action becomes layered.";
91}
92
94{
95 Layer &layer0 = action->layer_add("Test Læür nul");
96 Layer &layer1 = action->layer_add("Test Læür één");
97 Layer &layer2 = action->layer_add("Test Læür twee");
98
99 /* Add some strips to check that they are freed correctly too (implicitly by the
100 * memory leak checker). */
101 layer0.strip_add(*action, Strip::Type::Keyframe);
102 layer1.strip_add(*action, Strip::Type::Keyframe);
103 layer2.strip_add(*action, Strip::Type::Keyframe);
104
105 { /* Test removing a layer that is not owned. */
106 Action *other_anim = static_cast<Action *>(BKE_id_new(bmain, ID_AC, "ACOtherAnim"));
107 Layer &other_layer = other_anim->layer_add("Another Layer");
108 EXPECT_FALSE(action->layer_remove(other_layer))
109 << "Removing a layer not owned by the Action should be gracefully rejected";
110 BKE_id_free(bmain, &other_anim->id);
111 }
112
113 EXPECT_TRUE(action->layer_remove(layer1));
114 EXPECT_EQ(2, action->layers().size());
115 EXPECT_STREQ(layer0.name, action->layer(0)->name);
116 EXPECT_STREQ(layer2.name, action->layer(1)->name);
117
118 EXPECT_TRUE(action->layer_remove(layer2));
119 EXPECT_EQ(1, action->layers().size());
120 EXPECT_STREQ(layer0.name, action->layer(0)->name);
121
122 EXPECT_TRUE(action->layer_remove(layer0));
123 EXPECT_EQ(0, action->layers().size());
124}
125
127{
128 Layer &layer = action->layer_add("Test Læür");
129
130 Strip &strip = layer.strip_add(*action, Strip::Type::Keyframe);
131 ASSERT_EQ(1, layer.strips().size());
132 EXPECT_EQ(&strip, layer.strip(0));
133
134 constexpr float inf = std::numeric_limits<float>::infinity();
135 EXPECT_EQ(-inf, strip.frame_start) << "Expected strip to be infinite.";
136 EXPECT_EQ(inf, strip.frame_end) << "Expected strip to be infinite.";
137 EXPECT_EQ(0, strip.frame_offset) << "Expected infinite strip to have no offset.";
138
139 Strip &another_strip = layer.strip_add(*action, Strip::Type::Keyframe);
140 ASSERT_EQ(2, layer.strips().size());
141 EXPECT_EQ(&another_strip, layer.strip(1));
142
143 EXPECT_EQ(-inf, another_strip.frame_start) << "Expected strip to be infinite.";
144 EXPECT_EQ(inf, another_strip.frame_end) << "Expected strip to be infinite.";
145 EXPECT_EQ(0, another_strip.frame_offset) << "Expected infinite strip to have no offset.";
146
147 /* Add some keys to check that also the strip data is freed correctly. */
148 const KeyframeSettings settings = get_keyframe_settings(false);
149 Slot &slot = action->slot_add();
150 strip.data<StripKeyframeData>(*action).keyframe_insert(
151 bmain, slot, {"location", 0}, {1.0f, 47.0f}, settings);
152 another_strip.data<StripKeyframeData>(*action).keyframe_insert(
153 bmain, slot, {"location", 0}, {1.0f, 47.0f}, settings);
154}
155
157{
158 Layer &layer = action->layer_add("Test Læür");
159 Strip &strip0 = layer.strip_add(*action, Strip::Type::Keyframe);
160 Strip &strip1 = layer.strip_add(*action, Strip::Type::Keyframe);
161 Strip &strip2 = layer.strip_add(*action, Strip::Type::Keyframe);
162 Strip &strip3 = layer.strip_add(*action, Strip::Type::Keyframe);
163 StripKeyframeData &strip_data0 = strip0.data<StripKeyframeData>(*action);
164 StripKeyframeData &strip_data1 = strip1.data<StripKeyframeData>(*action);
165 StripKeyframeData &strip_data2 = strip2.data<StripKeyframeData>(*action);
166 StripKeyframeData &strip_data3 = strip3.data<StripKeyframeData>(*action);
167
168 /* Add some keys to check that also the strip data is freed correctly. */
169 const KeyframeSettings settings = get_keyframe_settings(false);
170 Slot &slot = action->slot_add();
171 strip_data0.keyframe_insert(bmain, slot, {"location", 0}, {1.0f, 47.0f}, settings);
172 strip_data1.keyframe_insert(bmain, slot, {"location", 0}, {1.0f, 48.0f}, settings);
173 strip_data2.keyframe_insert(bmain, slot, {"location", 0}, {1.0f, 49.0f}, settings);
174 strip_data3.keyframe_insert(bmain, slot, {"location", 0}, {1.0f, 50.0f}, settings);
175
176 EXPECT_EQ(4, action->strip_keyframe_data().size());
177 EXPECT_EQ(0, strip0.data_index);
178 EXPECT_EQ(1, strip1.data_index);
179 EXPECT_EQ(2, strip2.data_index);
180 EXPECT_EQ(3, strip3.data_index);
181
182 EXPECT_TRUE(layer.strip_remove(*action, strip1));
183 EXPECT_EQ(3, action->strip_keyframe_data().size());
184 EXPECT_EQ(3, layer.strips().size());
185 EXPECT_EQ(&strip0, layer.strip(0));
186 EXPECT_EQ(&strip2, layer.strip(1));
187 EXPECT_EQ(&strip3, layer.strip(2));
188 EXPECT_EQ(0, strip0.data_index);
189 EXPECT_EQ(2, strip2.data_index);
190 EXPECT_EQ(1, strip3.data_index); /* Swapped in when removing strip 1's data. */
191 EXPECT_EQ(&strip_data0, &strip0.data<StripKeyframeData>(*action));
192 EXPECT_EQ(&strip_data2, &strip2.data<StripKeyframeData>(*action));
193 EXPECT_EQ(&strip_data3, &strip3.data<StripKeyframeData>(*action));
194
195 EXPECT_TRUE(layer.strip_remove(*action, strip2));
196 EXPECT_EQ(2, action->strip_keyframe_data().size());
197 EXPECT_EQ(2, layer.strips().size());
198 EXPECT_EQ(&strip0, layer.strip(0));
199 EXPECT_EQ(&strip3, layer.strip(1));
200 EXPECT_EQ(0, strip0.data_index);
201 EXPECT_EQ(1, strip3.data_index);
202 EXPECT_EQ(&strip_data0, &strip0.data<StripKeyframeData>(*action));
203 EXPECT_EQ(&strip_data3, &strip3.data<StripKeyframeData>(*action));
204
205 EXPECT_TRUE(layer.strip_remove(*action, strip3));
206 EXPECT_EQ(1, action->strip_keyframe_data().size());
207 EXPECT_EQ(1, layer.strips().size());
208 EXPECT_EQ(&strip0, layer.strip(0));
209 EXPECT_EQ(0, strip0.data_index);
210 EXPECT_EQ(&strip_data0, &strip0.data<StripKeyframeData>(*action));
211
212 EXPECT_TRUE(layer.strip_remove(*action, strip0));
213 EXPECT_EQ(0, action->strip_keyframe_data().size());
214 EXPECT_EQ(0, layer.strips().size());
215
216 { /* Test removing a strip that is not owned. */
217 Layer &other_layer = action->layer_add("Another Layer");
218 Strip &other_strip = other_layer.strip_add(*action, Strip::Type::Keyframe);
219
220 EXPECT_FALSE(layer.strip_remove(*action, other_strip))
221 << "Removing a strip not owned by the layer should be gracefully rejected";
222 }
223}
224
225/* NOTE: this test creates strip instances in a bespoke way for the purpose of
226 * exercising the strip removal code, because at the time of writing we don't
227 * have a proper API for creating strip instances. When such an API is added,
228 * this test should be updated to use it. */
229TEST_F(ActionLayersTest, remove_strip_instances)
230{
231 Layer &layer = action->layer_add("Test Læür");
232 Strip &strip0 = layer.strip_add(*action, Strip::Type::Keyframe);
233 Strip &strip1 = layer.strip_add(*action, Strip::Type::Keyframe);
234 Strip &strip2 = layer.strip_add(*action, Strip::Type::Keyframe);
235
236 /* Make on of the strips an instance of another. */
237 strip0.data_index = strip1.data_index;
238
239 StripKeyframeData &strip_data_0_1 = strip0.data<StripKeyframeData>(*action);
240 StripKeyframeData &strip_data_2 = strip2.data<StripKeyframeData>(*action);
241
242 /* Add some keys to check that also the strip data is freed correctly. */
243 const KeyframeSettings settings = get_keyframe_settings(false);
244 Slot &slot = action->slot_add();
245 strip_data_0_1.keyframe_insert(bmain, slot, {"location", 0}, {1.0f, 47.0f}, settings);
246 strip_data_2.keyframe_insert(bmain, slot, {"location", 0}, {1.0f, 48.0f}, settings);
247
248 EXPECT_EQ(3, action->strip_keyframe_data().size());
249 EXPECT_EQ(1, strip0.data_index);
250 EXPECT_EQ(1, strip1.data_index);
251 EXPECT_EQ(2, strip2.data_index);
252
253 /* Removing an instance should not delete the underlying data as long as there
254 * is still another strip using it. */
255 EXPECT_TRUE(layer.strip_remove(*action, strip1));
256 EXPECT_EQ(3, action->strip_keyframe_data().size());
257 EXPECT_EQ(2, layer.strips().size());
258 EXPECT_EQ(&strip0, layer.strip(0));
259 EXPECT_EQ(&strip2, layer.strip(1));
260 EXPECT_EQ(1, strip0.data_index);
261 EXPECT_EQ(2, strip2.data_index);
262 EXPECT_EQ(&strip_data_0_1, &strip0.data<StripKeyframeData>(*action));
263 EXPECT_EQ(&strip_data_2, &strip2.data<StripKeyframeData>(*action));
264
265 /* Removing the last user of strip data should also delete the data. */
266 EXPECT_TRUE(layer.strip_remove(*action, strip0));
267 EXPECT_EQ(2, action->strip_keyframe_data().size());
268 EXPECT_EQ(1, layer.strips().size());
269 EXPECT_EQ(&strip2, layer.strip(0));
270 EXPECT_EQ(1, strip2.data_index);
271 EXPECT_EQ(&strip_data_2, &strip2.data<StripKeyframeData>(*action));
272}
273
275{
276 { /* Creating an 'unused' Slot should just be called 'Slot'. */
277 Slot &slot = action->slot_add();
278 EXPECT_EQ(1, action->last_slot_handle);
279 EXPECT_EQ(1, slot.handle);
280
281 EXPECT_STREQ("XXSlot", slot.name);
282 EXPECT_EQ(0, slot.idtype);
283 }
284
285 { /* Creating a Slot for a specific ID should name it after the ID. */
286 Slot &slot = action->slot_add_for_id(cube->id);
287 EXPECT_EQ(2, action->last_slot_handle);
288 EXPECT_EQ(2, slot.handle);
289
290 EXPECT_STREQ(cube->id.name, slot.name);
291 EXPECT_EQ(ID_OB, slot.idtype);
292 }
293}
294
295TEST_F(ActionLayersTest, add_slot__reset_idroot)
296{
297 /* An empty Action is a valid legacy Action, and thus can have its idroot set
298 * to a non-zero value. If such an Action gets a slot, it no longer is a
299 * valid legacy Action, and thus its idtype should be reset to zero. */
300 action->idroot = ID_CA; /* Fake that this was assigned to a camera data-block. */
301 ASSERT_NE(0, action->idroot) << "action->idroot should not be zero at the start of this test.";
302
303 action->slot_add();
304
305 EXPECT_EQ(0, action->idroot)
306 << "action->idroot should get reset when the Action becomes layered.";
307}
308
309TEST_F(ActionLayersTest, add_slot_multiple)
310{
311 Slot &slot_cube = action->slot_add();
312 Slot &slot_suzanne = action->slot_add();
313 EXPECT_TRUE(assign_action(action, cube->id));
315 EXPECT_TRUE(assign_action(action, suzanne->id));
316 EXPECT_EQ(assign_action_slot(&slot_suzanne, suzanne->id), ActionSlotAssignmentResult::OK);
317
318 EXPECT_EQ(2, action->last_slot_handle);
319 EXPECT_EQ(1, slot_cube.handle);
320 EXPECT_EQ(2, slot_suzanne.handle);
321}
322
324{
325 { /* Canary test: removing a just-created slot on an otherwise empty Action should work. */
326 Slot &slot = action->slot_add();
327 EXPECT_EQ(1, slot.handle);
328 EXPECT_EQ(1, action->last_slot_handle);
329
330 EXPECT_TRUE(action->slot_remove(slot));
331 EXPECT_EQ(1, action->last_slot_handle)
332 << "Removing a slot should not change the last-used slot handle.";
333 EXPECT_EQ(0, action->slot_array_num);
334 }
335
336 { /* Removing a non-existing slot should return false. */
337 Slot slot;
338 EXPECT_FALSE(action->slot_remove(slot));
339 }
340
341 { /* Removing a slot should remove its ChannelBag. */
342 Slot &slot = action->slot_add();
343 const slot_handle_t slot_handle = slot.handle;
344 EXPECT_EQ(2, slot.handle);
345 EXPECT_EQ(2, action->last_slot_handle);
346
347 /* Create an F-Curve in a ChannelBag for the slot. */
348 action->layer_keystrip_ensure();
349 StripKeyframeData &strip_data = action->layer(0)->strip(0)->data<StripKeyframeData>(*action);
350 ChannelBag &channelbag = strip_data.channelbag_for_slot_ensure(slot);
351 channelbag.fcurve_create_unique(bmain, {"location", 1});
352
353 /* Remove the slot. */
354 EXPECT_TRUE(action->slot_remove(slot));
355 EXPECT_EQ(2, action->last_slot_handle)
356 << "Removing a slot should not change the last-used slot handle.";
357 EXPECT_EQ(0, action->slot_array_num);
358
359 /* Check that its channelbag is gone. */
360 ChannelBag *found_cbag = strip_data.channelbag_for_slot(slot_handle);
361 EXPECT_EQ(found_cbag, nullptr);
362 }
363
364 { /* Removing one slot should leave the other two in place. */
365 Slot &slot1 = action->slot_add();
366 Slot &slot2 = action->slot_add();
367 Slot &slot3 = action->slot_add();
368 EXPECT_EQ(3, slot1.handle);
369 EXPECT_EQ(4, slot2.handle);
370 EXPECT_EQ(5, slot3.handle);
371 EXPECT_EQ(5, action->last_slot_handle);
372
373 /* For referencing the slot handle after the slot is removed. */
374 const slot_handle_t slot2_handle = slot2.handle;
375
376 /* Create a Channel-bag for each slot. */
377 action->layer_keystrip_ensure();
378 StripKeyframeData &strip_data = action->layer(0)->strip(0)->data<StripKeyframeData>(*action);
379 strip_data.channelbag_for_slot_ensure(slot1);
380 strip_data.channelbag_for_slot_ensure(slot2);
381 strip_data.channelbag_for_slot_ensure(slot3);
382
383 /* Remove the slot. */
384 EXPECT_TRUE(action->slot_remove(slot2));
385 EXPECT_EQ(5, action->last_slot_handle);
386
387 /* Check the correct slot + channel-bag are removed. */
388 EXPECT_EQ(action->slot_for_handle(slot1.handle), &slot1);
389 EXPECT_EQ(action->slot_for_handle(slot2_handle), nullptr);
390 EXPECT_EQ(action->slot_for_handle(slot3.handle), &slot3);
391
392 EXPECT_NE(strip_data.channelbag_for_slot(slot1.handle), nullptr);
393 EXPECT_EQ(strip_data.channelbag_for_slot(slot2_handle), nullptr);
394 EXPECT_NE(strip_data.channelbag_for_slot(slot3.handle), nullptr);
395 }
396
397 { /* Removing an in-use slot doesn't un-assign it from its users.
398 * This is not that important, but it covers the current behavior. */
399 Slot &slot = action->slot_add_for_id(cube->id);
400 ASSERT_EQ(assign_action_and_slot(action, &slot, cube->id), ActionSlotAssignmentResult::OK);
401
402 ASSERT_TRUE(slot.runtime_users().contains(&cube->id));
403 ASSERT_EQ(cube->adt->slot_handle, slot.handle);
404
405 const slot_handle_t removed_slot_handle = slot.handle;
406 ASSERT_TRUE(action->slot_remove(slot));
407 EXPECT_EQ(cube->adt->slot_handle, removed_slot_handle);
408 }
409
410 { /* Creating a slot after removing one should not reuse its handle. */
411 action->last_slot_handle = 3; /* To create independence between sub-tests. */
412 Slot &slot1 = action->slot_add();
413 ASSERT_EQ(4, slot1.handle);
414 ASSERT_EQ(4, action->last_slot_handle);
415 ASSERT_TRUE(action->slot_remove(slot1));
416
417 Slot &slot2 = action->slot_add();
418 EXPECT_EQ(5, slot2.handle);
419 EXPECT_EQ(5, action->last_slot_handle);
420 }
421}
422
423TEST_F(ActionLayersTest, action_assign_id)
424{
425 /* Assign to the only, 'virgin' Slot, should always work. */
426 Slot &slot_cube = action->slot_add();
427 ASSERT_NE(nullptr, slot_cube.runtime);
428 ASSERT_STREQ(slot_cube.name, "XXSlot");
429 ASSERT_EQ(assign_action_and_slot(action, &slot_cube, cube->id), ActionSlotAssignmentResult::OK);
430
431 EXPECT_EQ(slot_cube.handle, cube->adt->slot_handle);
432 EXPECT_STREQ(slot_cube.name, "OBSlot");
433 EXPECT_STREQ(slot_cube.name, cube->adt->slot_name)
434 << "The slot name should be copied to the adt";
435
436 EXPECT_TRUE(slot_cube.users(*bmain).contains(&cube->id))
437 << "Expecting Cube to be registered as animated by its slot.";
438
439 /* Assign another ID to the same Slot. */
440 ASSERT_EQ(assign_action_and_slot(action, &slot_cube, suzanne->id),
442 EXPECT_STREQ(slot_cube.name, "OBSlot");
443 EXPECT_STREQ(slot_cube.name, cube->adt->slot_name)
444 << "The slot name should be copied to the adt";
445
446 EXPECT_TRUE(slot_cube.users(*bmain).contains(&cube->id))
447 << "Expecting Suzanne to be registered as animated by the Cube slot.";
448
449 { /* Assign Cube to another action+slot without unassigning first. */
450 Action *another_anim = static_cast<Action *>(BKE_id_new(bmain, ID_AC, "ACOtherAnim"));
451 Slot &another_slot = another_anim->slot_add();
452 ASSERT_EQ(assign_action_and_slot(another_anim, &another_slot, cube->id),
454 EXPECT_FALSE(slot_cube.users(*bmain).contains(&cube->id))
455 << "Expecting Cube to no longer be registered as user of its old slot.";
456 EXPECT_TRUE(another_slot.users(*bmain).contains(&cube->id))
457 << "Expecting Cube to be registered as user of its new slot.";
458 }
459
460 { /* Assign Cube to another slot of the same Action, this should work. */
461 ASSERT_EQ(assign_action_and_slot(action, &slot_cube, cube->id),
463 const int user_count_pre = action->id.us;
464 Slot &slot_cube_2 = action->slot_add();
465 ASSERT_EQ(assign_action_and_slot(action, &slot_cube_2, cube->id),
467 ASSERT_EQ(action->id.us, user_count_pre)
468 << "Assigning to a different slot of the same Action should _not_ change the user "
469 "count of that Action";
470 EXPECT_FALSE(slot_cube.users(*bmain).contains(&cube->id))
471 << "Expecting Cube to no longer be registered as animated by the Cube slot.";
472 EXPECT_TRUE(slot_cube_2.users(*bmain).contains(&cube->id))
473 << "Expecting Cube to be registered as animated by the 'cube_2' slot.";
474 }
475
476 { /* Unassign the Action. */
477 const int user_count_pre = action->id.us;
478 EXPECT_TRUE(unassign_action(cube->id));
479 ASSERT_EQ(action->id.us, user_count_pre - 1)
480 << "Unassigning an Action should lower its user count";
481
482 ASSERT_EQ(2, action->slots().size()) << "Expecting the Action to have two Slots";
483 EXPECT_FALSE(action->slot(0)->users(*bmain).contains(&cube->id))
484 << "Expecting Cube to no longer be registered as animated by any slot.";
485 EXPECT_FALSE(action->slot(1)->users(*bmain).contains(&cube->id))
486 << "Expecting Cube to no longer be registered as animated by any slot.";
487 }
488
489 /* Assign Cube to another 'virgin' slot. This should not cause a name
490 * collision between the Slots. */
491 Slot &another_slot_cube = action->slot_add();
492 ASSERT_EQ(assign_action_and_slot(action, &another_slot_cube, cube->id),
494 EXPECT_EQ(another_slot_cube.handle, cube->adt->slot_handle);
495 EXPECT_STREQ("OBSlot.002", another_slot_cube.name) << "The slot should be uniquely named";
496 EXPECT_STREQ("OBSlot.002", cube->adt->slot_name) << "The slot name should be copied to the adt";
497 EXPECT_TRUE(another_slot_cube.users(*bmain).contains(&cube->id))
498 << "Expecting Cube to be registered as animated by the 'another_slot_cube' slot.";
499
500 /* Create an ID of another type. This should not be assignable to this slot. */
501 ID *mesh = static_cast<ID *>(BKE_id_new_nomain(ID_ME, "Mesh"));
502 ASSERT_TRUE(assign_action(action, *mesh));
504 << "Mesh should not be animatable by an Object slot";
505 EXPECT_FALSE(another_slot_cube.users(*bmain).contains(mesh))
506 << "Expecting Mesh to not be registered as animated by the 'slot_cube' slot.";
507 BKE_id_free(nullptr, mesh);
508}
509
511{
512 Slot &slot_cube = action->slot_add();
513 ASSERT_EQ(assign_action_and_slot(action, &slot_cube, cube->id), ActionSlotAssignmentResult::OK);
514 EXPECT_EQ(slot_cube.handle, cube->adt->slot_handle);
515 EXPECT_STREQ("OBSlot", slot_cube.name);
516 EXPECT_STREQ(slot_cube.name, cube->adt->slot_name)
517 << "The slot name should be copied to the adt";
518
519 action->slot_name_define(slot_cube, "New Slot Name");
520 EXPECT_STREQ("New Slot Name", slot_cube.name);
521 /* At this point the slot name will not have been copied to the cube
522 * AnimData. However, I don't want to test for that here, as it's not exactly
523 * desirable behavior, but more of a side-effect of the current
524 * implementation. */
525
526 action->slot_name_propagate(*bmain, slot_cube);
527 EXPECT_STREQ("New Slot Name", cube->adt->slot_name);
528
529 /* Finally, do another rename, do NOT call the propagate function, then
530 * unassign. This should still result in the correct slot name being stored
531 * on the ADT. */
532 action->slot_name_define(slot_cube, "Even Newer Name");
533 EXPECT_TRUE(unassign_action(cube->id));
534 EXPECT_STREQ("Even Newer Name", cube->adt->slot_name);
535}
536
537TEST_F(ActionLayersTest, slot_name_ensure_prefix)
538{
539 class AccessibleSlot : public Slot {
540 public:
541 void name_ensure_prefix()
542 {
543 Slot::name_ensure_prefix();
544 }
545 };
546
547 Slot &raw_slot = action->slot_add();
548 AccessibleSlot &slot = static_cast<AccessibleSlot &>(raw_slot);
549 ASSERT_STREQ("XXSlot", slot.name);
550 ASSERT_EQ(0, slot.idtype);
551
552 /* Check defaults, idtype zeroed. */
553 slot.name_ensure_prefix();
554 EXPECT_STREQ("XXSlot", slot.name);
555
556 /* idtype CA, default name. */
557 slot.idtype = ID_CA;
558 slot.name_ensure_prefix();
559 EXPECT_STREQ("CASlot", slot.name);
560
561 /* idtype ME, explicit name of other idtype. */
562 action->slot_name_define(slot, "CANewName");
563 slot.idtype = ID_ME;
564 slot.name_ensure_prefix();
565 EXPECT_STREQ("MENewName", slot.name);
566
567 /* Zeroing out idtype. */
568 slot.idtype = 0;
569 slot.name_ensure_prefix();
570 EXPECT_STREQ("XXNewName", slot.name);
571}
572
573TEST_F(ActionLayersTest, slot_name_prefix)
574{
575 Slot &slot = action->slot_add();
576 EXPECT_EQ("XX", slot.name_prefix_for_idtype());
577
578 slot.idtype = ID_CA;
579 EXPECT_EQ("CA", slot.name_prefix_for_idtype());
580}
581
582TEST_F(ActionLayersTest, rename_slot_name_collision)
583{
584 Slot &slot1 = action->slot_add();
585 Slot &slot2 = action->slot_add();
586
587 action->slot_name_define(slot1, "New Slot Name");
588 action->slot_name_define(slot2, "New Slot Name");
589 EXPECT_STREQ("New Slot Name", slot1.name);
590 EXPECT_STREQ("New Slot Name.001", slot2.name);
591}
592
593TEST_F(ActionLayersTest, find_suitable_slot)
594{
595 /* ===
596 * Empty case, no slots exist yet and the ID doesn't even have an AnimData. */
597 EXPECT_EQ(nullptr, action->find_suitable_slot_for(cube->id));
598
599 /* ===
600 * Slot exists with the same name & type as the ID, but the ID doesn't have any AnimData yet.
601 * These should nevertheless be matched up. */
602 Slot &slot = action->slot_add();
603 slot.handle = 327;
604 STRNCPY_UTF8(slot.name, "OBKüüübus");
605 slot.idtype = GS(cube->id.name);
606 EXPECT_EQ(&slot, action->find_suitable_slot_for(cube->id));
607
608 /* ===
609 * Slot exists with the same name & type as the ID, and the ID has an AnimData with the same
610 * slot name, but a different slot_handle. Since the Action has not yet been
611 * assigned to this ID, the slot_handle should be ignored, and the slot name used for
612 * matching. */
613
614 /* Create a slot with a handle that should be ignored.*/
615 Slot &other_slot = action->slot_add();
616 other_slot.handle = 47;
617
618 AnimData *adt = BKE_animdata_ensure_id(&cube->id);
619 adt->action = nullptr;
620 /* Configure adt to use the handle of one slot, and the name of the other. */
621 adt->slot_handle = other_slot.handle;
622 STRNCPY_UTF8(adt->slot_name, slot.name);
623 EXPECT_EQ(&slot, action->find_suitable_slot_for(cube->id));
624
625 /* ===
626 * Same situation as above (AnimData has name of one slot, but the handle of another),
627 * except that the Action has already been assigned. In this case the handle should take
628 * precedence. */
629 adt->action = action;
630 id_us_plus(&action->id);
631 EXPECT_EQ(&other_slot, action->find_suitable_slot_for(cube->id));
632
633 /* ===
634 * A slot exists, but doesn't match anything in the action data of the cube. This should fall
635 * back to using the ID name. */
636 adt->slot_handle = 161;
637 STRNCPY_UTF8(adt->slot_name, "¿¿What's this??");
638 EXPECT_EQ(&slot, action->find_suitable_slot_for(cube->id));
639}
640
642{
643 { /* Empty case, no slots exist yet. */
644 EXPECT_EQ(nullptr, action->slot_active_get());
645
646 action->slot_active_set(Slot::unassigned);
647 EXPECT_EQ(nullptr, action->slot_active_get());
648 }
649
650 { /* Single slot case. */
651 Slot &slot_cube = *assign_action_ensure_slot_for_keying(*action, cube->id);
652 EXPECT_EQ(nullptr, action->slot_active_get())
653 << "Adding the first slot should not change what is the active slot.";
654
655 action->slot_active_set(slot_cube.handle);
656 EXPECT_EQ(&slot_cube, action->slot_active_get())
657 << "It should be possible to activate the only available slot";
658 EXPECT_TRUE(slot_cube.is_active());
659
660 action->slot_active_set(Slot::unassigned);
661 EXPECT_EQ(nullptr, action->slot_active_get())
662 << "It should be possible to de-activate the only available slot";
663 EXPECT_FALSE(slot_cube.is_active());
664 }
665
666 {
667 /* Multiple slots case. */
668 Slot &slot_cube = *action->slot(0);
669 action->slot_active_set(slot_cube.handle);
670
671 Slot &slot_suz = *assign_action_ensure_slot_for_keying(*action, suzanne->id);
672 Slot &slot_bob = *assign_action_ensure_slot_for_keying(*action, bob->id);
673 EXPECT_EQ(&slot_cube, action->slot_active_get())
674 << "Adding a subsequent slot should not change what is the active slot.";
675 EXPECT_TRUE(slot_cube.is_active());
676
677 action->slot_active_set(slot_suz.handle);
678 EXPECT_EQ(&slot_suz, action->slot_active_get());
679 EXPECT_FALSE(slot_cube.is_active());
680 EXPECT_TRUE(slot_suz.is_active());
681 EXPECT_FALSE(slot_bob.is_active());
682
683 action->slot_active_set(slot_bob.handle);
684 EXPECT_EQ(&slot_bob, action->slot_active_get());
685 EXPECT_FALSE(slot_cube.is_active());
686 EXPECT_FALSE(slot_suz.is_active());
687 EXPECT_TRUE(slot_bob.is_active());
688
689 action->slot_active_set(Slot::unassigned);
690 EXPECT_EQ(nullptr, action->slot_active_get());
691 EXPECT_FALSE(slot_cube.is_active());
692 EXPECT_FALSE(slot_suz.is_active());
693 EXPECT_FALSE(slot_bob.is_active());
694 }
695}
696
698{
699 constexpr float inf = std::numeric_limits<float>::infinity();
700 Layer &layer0 = action->layer_add("Test Læür nul");
701 Strip &strip = layer0.strip_add(*action, Strip::Type::Keyframe);
702
703 strip.resize(-inf, inf);
704 EXPECT_TRUE(strip.contains_frame(0.0f));
705 EXPECT_TRUE(strip.contains_frame(-100000.0f));
706 EXPECT_TRUE(strip.contains_frame(100000.0f));
707 EXPECT_TRUE(strip.is_last_frame(inf));
708
709 strip.resize(1.0f, 2.0f);
710 EXPECT_FALSE(strip.contains_frame(0.0f))
711 << "Strip should not contain frames before its first frame";
712 EXPECT_TRUE(strip.contains_frame(1.0f)) << "Strip should contain its first frame.";
713 EXPECT_TRUE(strip.contains_frame(2.0f)) << "Strip should contain its last frame.";
714 EXPECT_FALSE(strip.contains_frame(2.0001f))
715 << "Strip should not contain frames after its last frame";
716
717 EXPECT_FALSE(strip.is_last_frame(1.0f));
718 EXPECT_FALSE(strip.is_last_frame(1.5f));
719 EXPECT_FALSE(strip.is_last_frame(1.9999f));
720 EXPECT_TRUE(strip.is_last_frame(2.0f));
721 EXPECT_FALSE(strip.is_last_frame(2.0001f));
722
723 /* Same test as above, but with much larger end frame number. This is 2 hours at 24 FPS. */
724 strip.resize(1.0f, 172800.0f);
725 EXPECT_TRUE(strip.contains_frame(172800.0f)) << "Strip should contain its last frame.";
726 EXPECT_FALSE(strip.contains_frame(172800.1f))
727 << "Strip should not contain frames after its last frame";
728
729 /* You can't get much closer to the end frame before it's considered equal. */
730 EXPECT_FALSE(strip.is_last_frame(172799.925f));
731 EXPECT_TRUE(strip.is_last_frame(172800.0f));
732 EXPECT_FALSE(strip.is_last_frame(172800.075f));
733}
734
735TEST_F(ActionLayersTest, KeyframeStrip__keyframe_insert)
736{
737 Slot &slot = action->slot_add();
738 ASSERT_EQ(assign_action_and_slot(action, &slot, cube->id), ActionSlotAssignmentResult::OK);
739 Layer &layer = action->layer_add("Kübus layer");
740
741 Strip &strip = layer.strip_add(*action, Strip::Type::Keyframe);
742 StripKeyframeData &strip_data = strip.data<StripKeyframeData>(*action);
743
744 const KeyframeSettings settings = get_keyframe_settings(false);
745 SingleKeyingResult result_loc_a = strip_data.keyframe_insert(
746 bmain, slot, {"location", 0}, {1.0f, 47.0f}, settings);
747 ASSERT_EQ(SingleKeyingResult::SUCCESS, result_loc_a)
748 << "Expected keyframe insertion to be successful";
749
750 /* Check the strip was created correctly, with the channels for the slot. */
751 ASSERT_EQ(1, strip_data.channelbags().size());
752 ChannelBag *channels = strip_data.channelbag(0);
753 EXPECT_EQ(slot.handle, channels->slot_handle);
754
755 /* Insert a second key, should insert into the same FCurve as before. */
756 SingleKeyingResult result_loc_b = strip_data.keyframe_insert(
757 bmain, slot, {"location", 0}, {5.0f, 47.1f}, settings);
759 ASSERT_EQ(1, channels->fcurves().size()) << "Expect insertion with the same (slot/rna "
760 "path/array index) tuple to go into the same FCurve";
761 EXPECT_EQ(2, channels->fcurves()[0]->totvert)
762 << "Expect insertion with the same (slot/rna path/array index) tuple to go into the same "
763 "FCurve";
764
765 EXPECT_EQ(47.0f, evaluate_fcurve(channels->fcurves()[0], 1.0f));
766 EXPECT_EQ(47.1f, evaluate_fcurve(channels->fcurves()[0], 5.0f));
767
768 /* Insert another key for another property, should create another FCurve. */
769 SingleKeyingResult result_rot = strip_data.keyframe_insert(
770 bmain, slot, {"rotation_quaternion", 0}, {1.0f, 0.25f}, settings);
772 ASSERT_EQ(2, channels->fcurves().size()) << "Expected a second FCurve to be created.";
773 EXPECT_EQ(2, channels->fcurves()[0]->totvert);
774 EXPECT_EQ(1, channels->fcurves()[1]->totvert);
775}
776
778{
779 EXPECT_TRUE(is_action_assignable_to(nullptr, ID_OB))
780 << "nullptr Actions should be assignable to any type.";
781 EXPECT_TRUE(is_action_assignable_to(nullptr, ID_CA))
782 << "nullptr Actions should be assignable to any type.";
783
784 EXPECT_TRUE(is_action_assignable_to(action, ID_OB))
785 << "Empty Actions should be assignable to any type.";
786 EXPECT_TRUE(is_action_assignable_to(action, ID_CA))
787 << "Empty Actions should be assignable to any type.";
788
789 /* Make the Action a legacy one. */
790 FCurve fake_fcurve;
791 BLI_addtail(&action->curves, &fake_fcurve);
792 ASSERT_FALSE(action->is_empty());
793 ASSERT_TRUE(action->is_action_legacy());
794 ASSERT_EQ(0, action->idroot);
795
796 EXPECT_TRUE(is_action_assignable_to(action, ID_OB))
797 << "Legacy Actions with idroot=0 should be assignable to any type.";
798 EXPECT_TRUE(is_action_assignable_to(action, ID_CA))
799 << "Legacy Actions with idroot=0 should be assignable to any type.";
800
801 /* Set the legacy idroot. */
802 action->idroot = ID_CA;
803 EXPECT_FALSE(is_action_assignable_to(action, ID_OB))
804 << "Legacy Actions with idroot=ID_CA should NOT be assignable to ID_OB.";
805 EXPECT_TRUE(is_action_assignable_to(action, ID_CA))
806 << "Legacy Actions with idroot=CA should be assignable to ID_CA.";
807
808 /* Make the Action a layered one. */
809 BLI_poptail(&action->curves);
810 action->layer_add("layer");
811 ASSERT_EQ(0, action->idroot) << "Adding a layer should clear the idroot.";
812
813 EXPECT_TRUE(is_action_assignable_to(action, ID_OB))
814 << "Layered Actions should be assignable to any type.";
815 EXPECT_TRUE(is_action_assignable_to(action, ID_CA))
816 << "Layered Actions should be assignable to any type.";
817}
818
819TEST_F(ActionLayersTest, action_slot_get_id_for_keying__empty_action)
820{
821 EXPECT_TRUE(assign_action(action, cube->id));
822
823 /* Double-check that the action is considered empty for the test. */
824 EXPECT_TRUE(action->is_empty());
825
826 /* A `primary_id` that uses the action should get returned. Every other case
827 * should return nullptr. */
828 EXPECT_EQ(&cube->id, action_slot_get_id_for_keying(*bmain, *action, 0, &cube->id));
829 EXPECT_EQ(nullptr, action_slot_get_id_for_keying(*bmain, *action, 0, nullptr));
830 EXPECT_EQ(nullptr, action_slot_get_id_for_keying(*bmain, *action, 0, &suzanne->id));
831}
832
833TEST_F(ActionLayersTest, action_slot_get_id_for_keying__legacy_action)
834{
835 FCurve *fcurve = action_fcurve_ensure(bmain, action, nullptr, nullptr, {"location", 0});
836 EXPECT_FALSE(fcurve == nullptr);
837
838 EXPECT_TRUE(assign_action(action, cube->id));
839
840 /* Double-check that the action is considered legacy for the test. */
841 EXPECT_TRUE(action->is_action_legacy());
842
843 /* A `primary_id` that uses the action should get returned. Every other case
844 * should return nullptr. */
845 EXPECT_EQ(&cube->id, action_slot_get_id_for_keying(*bmain, *action, 0, &cube->id));
846 EXPECT_EQ(nullptr, action_slot_get_id_for_keying(*bmain, *action, 0, nullptr));
847 EXPECT_EQ(nullptr, action_slot_get_id_for_keying(*bmain, *action, 0, &suzanne->id));
848}
849
850TEST_F(ActionLayersTest, action_slot_get_id_for_keying__layered_action)
851{
852 Slot &slot = action->slot_add();
853
854 /* Double-check that the action is considered layered for the test. */
855 EXPECT_TRUE(action->is_action_layered());
856
857 /* A slot with no users should never return a user. */
858 EXPECT_EQ(nullptr, action_slot_get_id_for_keying(*bmain, *action, slot.handle, nullptr));
859 EXPECT_EQ(nullptr, action_slot_get_id_for_keying(*bmain, *action, slot.handle, &cube->id));
860
861 /* A slot with precisely one user should always return that user. */
862 ASSERT_EQ(assign_action_and_slot(action, &slot, cube->id), ActionSlotAssignmentResult::OK);
863 EXPECT_EQ(&cube->id, action_slot_get_id_for_keying(*bmain, *action, slot.handle, nullptr));
864 EXPECT_EQ(&cube->id, action_slot_get_id_for_keying(*bmain, *action, slot.handle, &cube->id));
865 EXPECT_EQ(&cube->id, action_slot_get_id_for_keying(*bmain, *action, slot.handle, &suzanne->id));
866
867 /* A slot with more than one user should return the passed `primary_id` if it
868 * is among its users, and nullptr otherwise. */
869 ASSERT_EQ(assign_action_and_slot(action, &slot, suzanne->id), ActionSlotAssignmentResult::OK);
870 EXPECT_EQ(&cube->id, action_slot_get_id_for_keying(*bmain, *action, slot.handle, &cube->id));
871 EXPECT_EQ(&suzanne->id,
872 action_slot_get_id_for_keying(*bmain, *action, slot.handle, &suzanne->id));
873 EXPECT_EQ(nullptr, action_slot_get_id_for_keying(*bmain, *action, slot.handle, nullptr));
874 EXPECT_EQ(nullptr, action_slot_get_id_for_keying(*bmain, *action, slot.handle, &bob->id));
875}
876
877TEST_F(ActionLayersTest, conversion_to_layered)
878{
879 EXPECT_TRUE(action->is_empty());
880 FCurve *legacy_fcu_0 = action_fcurve_ensure(bmain, action, "Test", nullptr, {"location", 0});
881 FCurve *legacy_fcu_1 = action_fcurve_ensure(bmain, action, "Test", nullptr, {"location", 1});
882
883 KeyframeSettings settings;
884 settings.handle = HD_AUTO;
885 settings.interpolation = BEZT_IPO_BEZ;
886 settings.keyframe_type = BEZT_KEYTYPE_KEYFRAME;
887 insert_vert_fcurve(legacy_fcu_0, {0, 0}, settings, INSERTKEY_NOFLAGS);
888 insert_vert_fcurve(legacy_fcu_0, {1, 1}, settings, INSERTKEY_NOFLAGS);
889 add_fmodifier(&legacy_fcu_1->modifiers, FMODIFIER_TYPE_NOISE, legacy_fcu_1);
890
891 Action *converted = convert_to_layered_action(*bmain, *action);
892 ASSERT_TRUE(converted != action);
893 EXPECT_STREQ(converted->id.name, "ACACÄnimåtië_layered");
894 Strip *strip = converted->layer(0)->strip(0);
895 StripKeyframeData &strip_data = strip->data<StripKeyframeData>(*converted);
896 ChannelBag *bag = strip_data.channelbag(0);
897 ASSERT_EQ(bag->fcurve_array_num, 2);
898 ASSERT_EQ(bag->fcurve_array[0]->totvert, 2);
899
900 ASSERT_EQ(BLI_listbase_count(&action->groups), 1);
901 ASSERT_EQ(BLI_listbase_count(&converted->groups), 0);
902
903 ASSERT_EQ(bag->channel_groups().size(), 1);
904 bActionGroup *group = bag->channel_group(0);
905 ASSERT_EQ(group->fcurve_range_length, 2);
906 ASSERT_STREQ(group->name, "Test");
907
908 ASSERT_TRUE(bag->fcurve_array[0]->modifiers.first == nullptr);
909 ASSERT_TRUE(bag->fcurve_array[1]->modifiers.first != nullptr);
910
911 Action *long_name_action = static_cast<Action *>(BKE_id_new(
912 bmain, ID_AC, "name_for_an_action_that_is_exactly_64_chars_which_is_MAX_ID_NAME"));
913 action_fcurve_ensure(bmain, long_name_action, "Long", nullptr, {"location", 0});
914 converted = convert_to_layered_action(*bmain, *long_name_action);
915 /* AC gets added automatically by Blender, the long name is shortened to make space for
916 * "_layered". */
917 EXPECT_STREQ(converted->id.name,
918 "ACname_for_an_action_that_is_exactly_64_chars_which_is_MA_layered");
919}
920
921TEST_F(ActionLayersTest, conversion_to_layered_action_groups)
922{
923 EXPECT_TRUE(action->is_empty());
924 action_fcurve_ensure(bmain, action, "Test", nullptr, {"location", 0});
925 action_fcurve_ensure(bmain, action, "Test", nullptr, {"rotation_euler", 1});
926 action_fcurve_ensure(bmain, action, "Test_Two", nullptr, {"scale", 1});
927 action_fcurve_ensure(bmain, action, "Test_Three", nullptr, {"show_name", 1});
928 action_fcurve_ensure(bmain, action, "Test_Rename", nullptr, {"show_axis", 1});
929
930 bActionGroup *rename_group = static_cast<bActionGroup *>(BLI_findlink(&action->groups, 3));
931 ASSERT_NE(rename_group, nullptr);
932 ASSERT_STREQ(rename_group->name, "Test_Rename");
933 /* Forcing a duplicate name which was allowed by legacy actions. */
934 strcpy(rename_group->name, "Test");
935
936 Action *converted = convert_to_layered_action(*bmain, *action);
937 Strip *strip = converted->layer(0)->strip(0);
938 StripKeyframeData &strip_data = strip->data<StripKeyframeData>(*converted);
939 ChannelBag *bag = strip_data.channelbag(0);
940
941 ASSERT_EQ(BLI_listbase_count(&converted->groups), 0);
942 ASSERT_EQ(bag->channel_groups().size(), 4);
943
944 bActionGroup *test_group = bag->channel_group(0);
945 EXPECT_STREQ(test_group->name, "Test");
946 EXPECT_EQ(test_group->fcurve_range_length, 2);
947
948 bActionGroup *test_two_group = bag->channel_group(1);
949 EXPECT_STREQ(test_two_group->name, "Test_Two");
950 EXPECT_EQ(test_two_group->fcurve_range_length, 1);
951 EXPECT_STREQ(bag->fcurve_array[test_two_group->fcurve_range_start]->rna_path, "scale");
952
953 bActionGroup *test_three_group = bag->channel_group(2);
954 EXPECT_STREQ(test_three_group->name, "Test_Three");
955 EXPECT_EQ(test_three_group->fcurve_range_length, 1);
956 EXPECT_STREQ(bag->fcurve_array[test_three_group->fcurve_range_start]->rna_path, "show_name");
957
958 bActionGroup *test_rename_group = bag->channel_group(3);
959 EXPECT_STREQ(test_rename_group->name, "Test.001");
960 EXPECT_EQ(test_rename_group->fcurve_range_length, 1);
961 EXPECT_STREQ(bag->fcurve_array[test_rename_group->fcurve_range_start]->rna_path, "show_axis");
962
963 ASSERT_NE(converted, action);
964}
965
966TEST_F(ActionLayersTest, empty_to_layered)
967{
968 ASSERT_TRUE(action->is_empty());
969 Action *converted = convert_to_layered_action(*bmain, *action);
970 ASSERT_TRUE(converted != action);
971 ASSERT_TRUE(converted->is_action_layered());
972 ASSERT_FALSE(converted->is_action_legacy());
973}
974
975TEST_F(ActionLayersTest, action_move_slot)
976{
977 U.flag |= USER_DEVELOPER_UI;
978 U.experimental.use_animation_baklava = 1;
979
980 Action *action_2 = static_cast<Action *>(BKE_id_new(bmain, ID_AC, "Action 2"));
981 EXPECT_TRUE(action->is_empty());
982
983 Slot &slot_cube = action->slot_add();
984 Slot &slot_suzanne = action_2->slot_add();
986 EXPECT_EQ(assign_action_and_slot(action_2, &slot_suzanne, suzanne->id),
988
989 PointerRNA cube_rna_pointer = RNA_id_pointer_create(&cube->id);
990 PointerRNA suzanne_rna_pointer = RNA_id_pointer_create(&suzanne->id);
991
992 action_fcurve_ensure(bmain, action, "Test", &cube_rna_pointer, {"location", 0});
993 action_fcurve_ensure(bmain, action, "Test", &cube_rna_pointer, {"rotation_euler", 1});
994
995 action_fcurve_ensure(bmain, action_2, "Test_2", &suzanne_rna_pointer, {"location", 0});
996 action_fcurve_ensure(bmain, action_2, "Test_2", &suzanne_rna_pointer, {"rotation_euler", 1});
997
998 ASSERT_EQ(action->layer_array_num, 1);
999 ASSERT_EQ(action_2->layer_array_num, 1);
1000
1001 Layer *layer_1 = action->layer(0);
1002 Layer *layer_2 = action_2->layer(0);
1003
1004 ASSERT_EQ(layer_1->strip_array_num, 1);
1005 ASSERT_EQ(layer_2->strip_array_num, 1);
1006
1007 StripKeyframeData &strip_data_1 = layer_1->strip(0)->data<StripKeyframeData>(*action);
1008 StripKeyframeData &strip_data_2 = layer_2->strip(0)->data<StripKeyframeData>(*action_2);
1009
1010 ASSERT_EQ(strip_data_1.channelbag_array_num, 1);
1011 ASSERT_EQ(strip_data_2.channelbag_array_num, 1);
1012
1013 ChannelBag *bag_1 = strip_data_1.channelbag(0);
1014 ChannelBag *bag_2 = strip_data_2.channelbag(0);
1015
1016 ASSERT_EQ(bag_1->fcurve_array_num, 2);
1017 ASSERT_EQ(bag_2->fcurve_array_num, 2);
1018
1019 move_slot(*bmain, slot_suzanne, *action_2, *action);
1020
1021 ASSERT_EQ(strip_data_1.channelbag_array_num, 2);
1022 ASSERT_EQ(strip_data_2.channelbag_array_num, 0);
1023
1024 ASSERT_EQ(action->slot_array_num, 2);
1025 ASSERT_EQ(action_2->slot_array_num, 0);
1026
1027 /* Action should have been reassigned. */
1028 ASSERT_EQ(action, cube->adt->action);
1029 ASSERT_EQ(action, suzanne->adt->action);
1030}
1031
1032/*-----------------------------------------------------------*/
1033
1034/* Allocate fcu->bezt, and also return a unique_ptr to it for easily freeing the memory. */
1035static void allocate_keyframes(FCurve &fcu, const size_t num_keyframes)
1036{
1037 fcu.bezt = MEM_cnew_array<BezTriple>(num_keyframes, __func__);
1038}
1039
1040/* Append keyframe, assumes that fcu->bezt is allocated and has enough space. */
1041static void add_keyframe(FCurve &fcu, float x, float y)
1042{
1043 /* The insert_keyframe functions are in the editors, so we cannot link to those here. */
1044 BezTriple the_keyframe;
1045 memset(&the_keyframe, 0, sizeof(the_keyframe));
1046
1047 /* Copied from insert_vert_fcurve() in `keyframing.cc`. */
1048 the_keyframe.vec[0][0] = x - 1.0f;
1049 the_keyframe.vec[0][1] = y;
1050 the_keyframe.vec[1][0] = x;
1051 the_keyframe.vec[1][1] = y;
1052 the_keyframe.vec[2][0] = x + 1.0f;
1053 the_keyframe.vec[2][1] = y;
1054
1055 memcpy(&fcu.bezt[fcu.totvert], &the_keyframe, sizeof(the_keyframe));
1056 fcu.totvert++;
1057}
1058
1059static void add_fcurve_to_action(Action &action, FCurve &fcu)
1060{
1061#ifdef WITH_ANIM_BAKLAVA
1062 Slot &slot = action.slot_array_num > 0 ? *action.slot(0) : action.slot_add();
1063 action.layer_keystrip_ensure();
1064 StripKeyframeData &strip_data = action.layer(0)->strip(0)->data<StripKeyframeData>(action);
1065 ChannelBag &cbag = strip_data.channelbag_for_slot_ensure(slot);
1066 cbag.fcurve_append(fcu);
1067#else
1068 BLI_addhead(&action.curves, &fcu);
1069#endif /* WITH_ANIM_BAKLAVA */
1070}
1071
1072class ActionQueryTest : public testing::Test {
1073 public:
1075
1076 static void SetUpTestSuite()
1077 {
1078 /* BKE_id_free() hits a code path that uses CLOG, which crashes if not initialized properly. */
1079 CLG_init();
1080
1081 /* To make id_can_have_animdata() and friends work, the `id_types` array needs to be set up. */
1083 }
1084
1085 static void TearDownTestSuite()
1086 {
1087 CLG_exit();
1088 }
1089
1090 void SetUp() override
1091 {
1092 bmain = BKE_main_new();
1093 }
1094
1095 void TearDown() override
1096 {
1098 }
1099
1101 {
1102 return *static_cast<Action *>(BKE_id_new(bmain, ID_AC, "ACÄnimåtië"));
1103 }
1104};
1105
1106TEST_F(ActionQueryTest, BKE_action_frame_range_calc)
1107{
1108 /* No FCurves. */
1109 {
1110 const Action &empty = action_new();
1111 EXPECT_EQ((float2{0.0f, 0.0f}), empty.get_frame_range_of_keys(false));
1112 }
1113
1114 /* One curve with one key. */
1115 {
1116 FCurve &fcu = *MEM_cnew<FCurve>(__func__);
1117 allocate_keyframes(fcu, 1);
1118 add_keyframe(fcu, 1.0f, 2.0f);
1119
1120 Action &action = action_new();
1121 add_fcurve_to_action(action, fcu);
1122
1123 const float2 frame_range = action.get_frame_range_of_keys(false);
1124 EXPECT_FLOAT_EQ(frame_range[0], 1.0f);
1125 EXPECT_FLOAT_EQ(frame_range[1], 1.0f);
1126 }
1127
1128 /* Two curves with one key each on different frames. */
1129 {
1130 FCurve &fcu1 = *MEM_cnew<FCurve>(__func__);
1131 FCurve &fcu2 = *MEM_cnew<FCurve>(__func__);
1132 allocate_keyframes(fcu1, 1);
1133 allocate_keyframes(fcu2, 1);
1134 add_keyframe(fcu1, 1.0f, 2.0f);
1135 add_keyframe(fcu2, 1.5f, 2.0f);
1136
1137 Action &action = action_new();
1138 add_fcurve_to_action(action, fcu1);
1139 add_fcurve_to_action(action, fcu2);
1140
1141 const float2 frame_range = action.get_frame_range_of_keys(false);
1142 EXPECT_FLOAT_EQ(frame_range[0], 1.0f);
1143 EXPECT_FLOAT_EQ(frame_range[1], 1.5f);
1144 }
1145
1146 /* One curve with two keys. */
1147 {
1148 FCurve &fcu = *MEM_cnew<FCurve>(__func__);
1149 allocate_keyframes(fcu, 2);
1150 add_keyframe(fcu, 1.0f, 2.0f);
1151 add_keyframe(fcu, 1.5f, 2.0f);
1152
1153 Action &action = action_new();
1154 add_fcurve_to_action(action, fcu);
1155
1156 const float2 frame_range = action.get_frame_range_of_keys(false);
1157 EXPECT_FLOAT_EQ(frame_range[0], 1.0f);
1158 EXPECT_FLOAT_EQ(frame_range[1], 1.5f);
1159 }
1160
1161 /* TODO: action with fcurve modifiers. */
1162}
1163
1164/*-----------------------------------------------------------*/
1165
1166class ChannelBagTest : public testing::Test {
1167 public:
1169
1170 static void SetUpTestSuite() {}
1171
1172 static void TearDownTestSuite() {}
1173
1174 void SetUp() override
1175 {
1176 channel_bag = new ChannelBag();
1177 }
1178
1179 void TearDown() override
1180 {
1181 delete channel_bag;
1182 }
1183};
1184
1186{
1187 FCurve &fcu0 = channel_bag->fcurve_ensure(nullptr, {"fcu0", 0, std::nullopt, "group0"});
1188 FCurve &fcu1 = channel_bag->fcurve_ensure(nullptr, {"fcu1", 0, std::nullopt, "group0"});
1189 FCurve &fcu2 = channel_bag->fcurve_ensure(nullptr, {"fcu2", 0, std::nullopt, "group1"});
1190 FCurve &fcu3 = channel_bag->fcurve_ensure(nullptr, {"fcu3", 0, std::nullopt, "group1"});
1191 FCurve &fcu4 = channel_bag->fcurve_ensure(nullptr, {"fcu4", 0, std::nullopt, std::nullopt});
1192
1193 ASSERT_EQ(5, channel_bag->fcurves().size());
1194 ASSERT_EQ(2, channel_bag->channel_groups().size());
1195
1196 bActionGroup &group0 = *channel_bag->channel_group(0);
1197 bActionGroup &group1 = *channel_bag->channel_group(1);
1198
1199 /* Moving an fcurve to where it already is should be fine. */
1200 channel_bag->fcurve_move(fcu0, 0);
1201 EXPECT_EQ(&fcu0, channel_bag->fcurve(0));
1202 EXPECT_EQ(&fcu1, channel_bag->fcurve(1));
1203 EXPECT_EQ(&fcu2, channel_bag->fcurve(2));
1204 EXPECT_EQ(&fcu3, channel_bag->fcurve(3));
1205 EXPECT_EQ(&fcu4, channel_bag->fcurve(4));
1206 EXPECT_EQ(&group0, fcu0.grp);
1207 EXPECT_EQ(&group0, fcu1.grp);
1208 EXPECT_EQ(&group1, fcu2.grp);
1209 EXPECT_EQ(&group1, fcu3.grp);
1210 EXPECT_EQ(nullptr, fcu4.grp);
1211
1212 /* Move to first. */
1213 channel_bag->fcurve_move(fcu4, 0);
1214 EXPECT_EQ(0, group0.fcurve_range_start);
1215 EXPECT_EQ(2, group0.fcurve_range_length);
1216 EXPECT_EQ(2, group1.fcurve_range_start);
1217 EXPECT_EQ(2, group1.fcurve_range_length);
1218 EXPECT_EQ(&fcu4, channel_bag->fcurve(0));
1219 EXPECT_EQ(&fcu0, channel_bag->fcurve(1));
1220 EXPECT_EQ(&fcu1, channel_bag->fcurve(2));
1221 EXPECT_EQ(&fcu2, channel_bag->fcurve(3));
1222 EXPECT_EQ(&fcu3, channel_bag->fcurve(4));
1223 EXPECT_EQ(&group0, fcu4.grp);
1224 EXPECT_EQ(&group0, fcu0.grp);
1225 EXPECT_EQ(&group1, fcu1.grp);
1226 EXPECT_EQ(&group1, fcu2.grp);
1227 EXPECT_EQ(nullptr, fcu3.grp);
1228
1229 /* Move to last. */
1230 channel_bag->fcurve_move(fcu1, 4);
1231 EXPECT_EQ(0, group0.fcurve_range_start);
1232 EXPECT_EQ(2, group0.fcurve_range_length);
1233 EXPECT_EQ(2, group1.fcurve_range_start);
1234 EXPECT_EQ(2, group1.fcurve_range_length);
1235 EXPECT_EQ(&fcu4, channel_bag->fcurve(0));
1236 EXPECT_EQ(&fcu0, channel_bag->fcurve(1));
1237 EXPECT_EQ(&fcu2, channel_bag->fcurve(2));
1238 EXPECT_EQ(&fcu3, channel_bag->fcurve(3));
1239 EXPECT_EQ(&fcu1, channel_bag->fcurve(4));
1240 EXPECT_EQ(&group0, fcu4.grp);
1241 EXPECT_EQ(&group0, fcu0.grp);
1242 EXPECT_EQ(&group1, fcu2.grp);
1243 EXPECT_EQ(&group1, fcu3.grp);
1244 EXPECT_EQ(nullptr, fcu1.grp);
1245
1246 /* Move to middle. */
1247 channel_bag->fcurve_move(fcu4, 2);
1248 EXPECT_EQ(0, group0.fcurve_range_start);
1249 EXPECT_EQ(2, group0.fcurve_range_length);
1250 EXPECT_EQ(2, group1.fcurve_range_start);
1251 EXPECT_EQ(2, group1.fcurve_range_length);
1252 EXPECT_EQ(&fcu0, channel_bag->fcurve(0));
1253 EXPECT_EQ(&fcu2, channel_bag->fcurve(1));
1254 EXPECT_EQ(&fcu4, channel_bag->fcurve(2));
1255 EXPECT_EQ(&fcu3, channel_bag->fcurve(3));
1256 EXPECT_EQ(&fcu1, channel_bag->fcurve(4));
1257 EXPECT_EQ(&group0, fcu0.grp);
1258 EXPECT_EQ(&group0, fcu2.grp);
1259 EXPECT_EQ(&group1, fcu4.grp);
1260 EXPECT_EQ(&group1, fcu3.grp);
1261 EXPECT_EQ(nullptr, fcu1.grp);
1262}
1263
1264TEST_F(ChannelBagTest, channel_group_create)
1265{
1266 ASSERT_TRUE(channel_bag->channel_groups().is_empty());
1267
1268 bActionGroup &group0 = channel_bag->channel_group_create("Foo");
1269 ASSERT_EQ(channel_bag->channel_groups().size(), 1);
1270 EXPECT_EQ(StringRef{group0.name}, StringRef{"Foo"});
1271 EXPECT_EQ(group0.fcurve_range_start, 0);
1272 EXPECT_EQ(group0.fcurve_range_length, 0);
1273 EXPECT_EQ(&group0, channel_bag->channel_group(0));
1274
1275 /* Set for testing purposes. Does not reflect actual fcurves in this test. */
1276 group0.fcurve_range_length = 2;
1277
1278 bActionGroup &group1 = channel_bag->channel_group_create("Bar");
1279 ASSERT_EQ(channel_bag->channel_groups().size(), 2);
1280 EXPECT_EQ(StringRef{group1.name}, StringRef{"Bar"});
1281 EXPECT_EQ(group1.fcurve_range_start, 2);
1282 EXPECT_EQ(group1.fcurve_range_length, 0);
1283 EXPECT_EQ(&group0, channel_bag->channel_group(0));
1284 EXPECT_EQ(&group1, channel_bag->channel_group(1));
1285
1286 /* Set for testing purposes. Does not reflect actual fcurves in this test. */
1287 group1.fcurve_range_length = 1;
1288
1289 bActionGroup &group2 = channel_bag->channel_group_create("Yar");
1290 ASSERT_EQ(channel_bag->channel_groups().size(), 3);
1291 EXPECT_EQ(StringRef{group2.name}, StringRef{"Yar"});
1292 EXPECT_EQ(group2.fcurve_range_start, 3);
1293 EXPECT_EQ(group2.fcurve_range_length, 0);
1294 EXPECT_EQ(&group0, channel_bag->channel_group(0));
1295 EXPECT_EQ(&group1, channel_bag->channel_group(1));
1296 EXPECT_EQ(&group2, channel_bag->channel_group(2));
1297}
1298
1299TEST_F(ChannelBagTest, channel_group_remove)
1300{
1301 bActionGroup &group0 = channel_bag->channel_group_create("Group0");
1302 bActionGroup &group1 = channel_bag->channel_group_create("Group1");
1303 bActionGroup &group2 = channel_bag->channel_group_create("Group2");
1304
1305 FCurve &fcu0 = channel_bag->fcurve_ensure(nullptr, {"fcu0", 0, std::nullopt, "Group0"});
1306 FCurve &fcu1 = channel_bag->fcurve_ensure(nullptr, {"fcu1", 0, std::nullopt, "Group0"});
1307 FCurve &fcu2 = channel_bag->fcurve_ensure(nullptr, {"fcu2", 0, std::nullopt, "Group2"});
1308 FCurve &fcu3 = channel_bag->fcurve_ensure(nullptr, {"fcu3", 0, std::nullopt, "Group2"});
1309 FCurve &fcu4 = channel_bag->fcurve_ensure(nullptr, {"fcu4", 0, std::nullopt, std::nullopt});
1310
1311 ASSERT_EQ(3, channel_bag->channel_groups().size());
1312 ASSERT_EQ(5, channel_bag->fcurves().size());
1313
1314 /* Attempt to remove a group that's not in the channel bag. Shouldn't do
1315 * anything. */
1316 bActionGroup bogus;
1317 EXPECT_EQ(false, channel_bag->channel_group_remove(bogus));
1318 ASSERT_EQ(3, channel_bag->channel_groups().size());
1319 ASSERT_EQ(5, channel_bag->fcurves().size());
1320 EXPECT_EQ(&group0, channel_bag->channel_group(0));
1321 EXPECT_EQ(&group1, channel_bag->channel_group(1));
1322 EXPECT_EQ(&group2, channel_bag->channel_group(2));
1323 EXPECT_EQ(&fcu0, channel_bag->fcurve(0));
1324 EXPECT_EQ(&fcu1, channel_bag->fcurve(1));
1325 EXPECT_EQ(&fcu2, channel_bag->fcurve(2));
1326 EXPECT_EQ(&fcu3, channel_bag->fcurve(3));
1327 EXPECT_EQ(&fcu4, channel_bag->fcurve(4));
1328 EXPECT_EQ(&group0, fcu0.grp);
1329 EXPECT_EQ(&group0, fcu1.grp);
1330 EXPECT_EQ(&group2, fcu2.grp);
1331 EXPECT_EQ(&group2, fcu3.grp);
1332 EXPECT_EQ(nullptr, fcu4.grp);
1333
1334 /* Removing an empty group shouldn't affect the fcurves at all. */
1335 EXPECT_EQ(true, channel_bag->channel_group_remove(group1));
1336 ASSERT_EQ(2, channel_bag->channel_groups().size());
1337 ASSERT_EQ(5, channel_bag->fcurves().size());
1338 EXPECT_EQ(&group0, channel_bag->channel_group(0));
1339 EXPECT_EQ(&group2, channel_bag->channel_group(1));
1340 EXPECT_EQ(&fcu0, channel_bag->fcurve(0));
1341 EXPECT_EQ(&fcu1, channel_bag->fcurve(1));
1342 EXPECT_EQ(&fcu2, channel_bag->fcurve(2));
1343 EXPECT_EQ(&fcu3, channel_bag->fcurve(3));
1344 EXPECT_EQ(&fcu4, channel_bag->fcurve(4));
1345 EXPECT_EQ(&group0, fcu0.grp);
1346 EXPECT_EQ(&group0, fcu1.grp);
1347 EXPECT_EQ(&group2, fcu2.grp);
1348 EXPECT_EQ(&group2, fcu3.grp);
1349 EXPECT_EQ(nullptr, fcu4.grp);
1350
1351 /* Removing a group that's not at the end of the group array should move its
1352 * fcurves to be just after the grouped fcurves. */
1353 EXPECT_EQ(true, channel_bag->channel_group_remove(group0));
1354 ASSERT_EQ(1, channel_bag->channel_groups().size());
1355 ASSERT_EQ(5, channel_bag->fcurves().size());
1356 EXPECT_EQ(&group2, channel_bag->channel_group(0));
1357 EXPECT_EQ(&fcu2, channel_bag->fcurve(0));
1358 EXPECT_EQ(&fcu3, channel_bag->fcurve(1));
1359 EXPECT_EQ(&fcu0, channel_bag->fcurve(2));
1360 EXPECT_EQ(&fcu1, channel_bag->fcurve(3));
1361 EXPECT_EQ(&fcu4, channel_bag->fcurve(4));
1362 EXPECT_EQ(nullptr, fcu0.grp);
1363 EXPECT_EQ(nullptr, fcu1.grp);
1364 EXPECT_EQ(&group2, fcu2.grp);
1365 EXPECT_EQ(&group2, fcu3.grp);
1366 EXPECT_EQ(nullptr, fcu4.grp);
1367
1368 /* Removing a group at the end of the group array shouldn't move its
1369 * fcurves. */
1370 EXPECT_EQ(true, channel_bag->channel_group_remove(group2));
1371 ASSERT_EQ(0, channel_bag->channel_groups().size());
1372 ASSERT_EQ(5, channel_bag->fcurves().size());
1373 EXPECT_EQ(&fcu2, channel_bag->fcurve(0));
1374 EXPECT_EQ(&fcu3, channel_bag->fcurve(1));
1375 EXPECT_EQ(&fcu0, channel_bag->fcurve(2));
1376 EXPECT_EQ(&fcu1, channel_bag->fcurve(3));
1377 EXPECT_EQ(&fcu4, channel_bag->fcurve(4));
1378 EXPECT_EQ(nullptr, fcu0.grp);
1379 EXPECT_EQ(nullptr, fcu1.grp);
1380 EXPECT_EQ(nullptr, fcu2.grp);
1381 EXPECT_EQ(nullptr, fcu3.grp);
1382 EXPECT_EQ(nullptr, fcu4.grp);
1383}
1384
1385TEST_F(ChannelBagTest, channel_group_find)
1386{
1387 bActionGroup &group0a = channel_bag->channel_group_create("Foo");
1388 bActionGroup &group1a = channel_bag->channel_group_create("Bar");
1389 bActionGroup &group2a = channel_bag->channel_group_create("Yar");
1390
1391 bActionGroup *group0b = channel_bag->channel_group_find("Foo");
1392 bActionGroup *group1b = channel_bag->channel_group_find("Bar");
1393 bActionGroup *group2b = channel_bag->channel_group_find("Yar");
1394
1395 EXPECT_EQ(&group0a, group0b);
1396 EXPECT_EQ(&group1a, group1b);
1397 EXPECT_EQ(&group2a, group2b);
1398
1399 EXPECT_EQ(nullptr, channel_bag->channel_group_find("Wat"));
1400}
1401
1402TEST_F(ChannelBagTest, channel_group_ensure)
1403{
1404 bActionGroup &group0 = channel_bag->channel_group_create("Foo");
1405 bActionGroup &group1 = channel_bag->channel_group_create("Bar");
1406 EXPECT_EQ(channel_bag->channel_groups().size(), 2);
1407
1408 EXPECT_EQ(&group0, &channel_bag->channel_group_ensure("Foo"));
1409 EXPECT_EQ(channel_bag->channel_groups().size(), 2);
1410
1411 EXPECT_EQ(&group1, &channel_bag->channel_group_ensure("Bar"));
1412 EXPECT_EQ(channel_bag->channel_groups().size(), 2);
1413
1414 bActionGroup &group2 = channel_bag->channel_group_ensure("Yar");
1415 ASSERT_EQ(channel_bag->channel_groups().size(), 3);
1416 EXPECT_EQ(&group2, channel_bag->channel_group(2));
1417}
1418
1419TEST_F(ChannelBagTest, channel_group_fcurve_creation)
1420{
1421 FCurve &fcu0 = channel_bag->fcurve_ensure(nullptr, {"fcu0", 0, std::nullopt, std::nullopt});
1422 EXPECT_EQ(1, channel_bag->fcurves().size());
1423 EXPECT_TRUE(channel_bag->channel_groups().is_empty());
1424
1425 /* If an fcurve already exists, then ensuring it with a channel group in the
1426 * fcurve descriptor should NOT add it that group, nor should the group be
1427 * created if it doesn't already exist. */
1428 channel_bag->fcurve_ensure(nullptr, {"fcu0", 0, std::nullopt, "group0"});
1429 EXPECT_EQ(1, channel_bag->fcurves().size());
1430 EXPECT_EQ(nullptr, fcu0.grp);
1431 EXPECT_TRUE(channel_bag->channel_groups().is_empty());
1432
1433 /* Creating a new fcurve with a channel group in the fcurve descriptor should
1434 * create the group and put the fcurve in it. This also implies that the
1435 * fcurve will be added before any non-grouped fcurves in the array. */
1436 FCurve &fcu1 = channel_bag->fcurve_ensure(nullptr, {"fcu1", 0, std::nullopt, "group0"});
1437 ASSERT_EQ(2, channel_bag->fcurves().size());
1438 ASSERT_EQ(1, channel_bag->channel_groups().size());
1439 bActionGroup &group0 = *channel_bag->channel_group(0);
1440 EXPECT_EQ(&fcu1, channel_bag->fcurve(0));
1441 EXPECT_EQ(&fcu0, channel_bag->fcurve(1));
1442 EXPECT_EQ(&group0, fcu1.grp);
1443 EXPECT_EQ(nullptr, fcu0.grp);
1444 EXPECT_EQ(0, group0.fcurve_range_start);
1445 EXPECT_EQ(1, group0.fcurve_range_length);
1446
1447 /* Creating a new fcurve with a second channel group in the fcurve descriptor
1448 * should create the group and put the fcurve in it. This also implies that
1449 * the fcurve will be added before non-grouped fcurves, but after other
1450 * grouped ones. */
1451 FCurve &fcu2 = channel_bag->fcurve_ensure(nullptr, {"fcu2", 0, std::nullopt, "group1"});
1452 ASSERT_EQ(3, channel_bag->fcurves().size());
1453 ASSERT_EQ(2, channel_bag->channel_groups().size());
1454 EXPECT_EQ(&group0, channel_bag->channel_group(0));
1455 bActionGroup &group1 = *channel_bag->channel_group(1);
1456 EXPECT_EQ(&fcu1, channel_bag->fcurve(0));
1457 EXPECT_EQ(&fcu2, channel_bag->fcurve(1));
1458 EXPECT_EQ(&fcu0, channel_bag->fcurve(2));
1459 EXPECT_EQ(&group0, fcu1.grp);
1460 EXPECT_EQ(&group1, fcu2.grp);
1461 EXPECT_EQ(nullptr, fcu0.grp);
1462 EXPECT_EQ(0, group0.fcurve_range_start);
1463 EXPECT_EQ(1, group0.fcurve_range_length);
1464 EXPECT_EQ(1, group1.fcurve_range_start);
1465 EXPECT_EQ(1, group1.fcurve_range_length);
1466
1467 /* Creating a new fcurve with the first channel group again should put it at
1468 * the end of that group. */
1469 FCurve &fcu3 = channel_bag->fcurve_ensure(nullptr, {"fcu3", 0, std::nullopt, "group0"});
1470 ASSERT_EQ(4, channel_bag->fcurves().size());
1471 ASSERT_EQ(2, channel_bag->channel_groups().size());
1472 EXPECT_EQ(&group0, channel_bag->channel_group(0));
1473 EXPECT_EQ(&group1, channel_bag->channel_group(1));
1474 EXPECT_EQ(&fcu1, channel_bag->fcurve(0));
1475 EXPECT_EQ(&fcu3, channel_bag->fcurve(1));
1476 EXPECT_EQ(&fcu2, channel_bag->fcurve(2));
1477 EXPECT_EQ(&fcu0, channel_bag->fcurve(3));
1478 EXPECT_EQ(&group0, fcu1.grp);
1479 EXPECT_EQ(&group0, fcu3.grp);
1480 EXPECT_EQ(&group1, fcu2.grp);
1481 EXPECT_EQ(nullptr, fcu0.grp);
1482 EXPECT_EQ(0, group0.fcurve_range_start);
1483 EXPECT_EQ(2, group0.fcurve_range_length);
1484 EXPECT_EQ(2, group1.fcurve_range_start);
1485 EXPECT_EQ(1, group1.fcurve_range_length);
1486
1487 /* Finally, creating a new fcurve with the second channel group again should
1488 * also put it at the end of that group. */
1489 FCurve &fcu4 = channel_bag->fcurve_ensure(nullptr, {"fcu4", 0, std::nullopt, "group1"});
1490 ASSERT_EQ(5, channel_bag->fcurves().size());
1491 ASSERT_EQ(2, channel_bag->channel_groups().size());
1492 EXPECT_EQ(&group0, channel_bag->channel_group(0));
1493 EXPECT_EQ(&group1, channel_bag->channel_group(1));
1494 EXPECT_EQ(&fcu1, channel_bag->fcurve(0));
1495 EXPECT_EQ(&fcu3, channel_bag->fcurve(1));
1496 EXPECT_EQ(&fcu2, channel_bag->fcurve(2));
1497 EXPECT_EQ(&fcu4, channel_bag->fcurve(3));
1498 EXPECT_EQ(&fcu0, channel_bag->fcurve(4));
1499 EXPECT_EQ(&group0, fcu1.grp);
1500 EXPECT_EQ(&group0, fcu3.grp);
1501 EXPECT_EQ(&group1, fcu2.grp);
1502 EXPECT_EQ(&group1, fcu4.grp);
1503 EXPECT_EQ(nullptr, fcu0.grp);
1504 EXPECT_EQ(0, group0.fcurve_range_start);
1505 EXPECT_EQ(2, group0.fcurve_range_length);
1506 EXPECT_EQ(2, group1.fcurve_range_start);
1507 EXPECT_EQ(2, group1.fcurve_range_length);
1508}
1509
1510TEST_F(ChannelBagTest, channel_group_fcurve_removal)
1511{
1512 FCurve &fcu0 = channel_bag->fcurve_ensure(nullptr, {"fcu0", 0, std::nullopt, "group0"});
1513 FCurve &fcu1 = channel_bag->fcurve_ensure(nullptr, {"fcu1", 0, std::nullopt, "group0"});
1514 FCurve &fcu2 = channel_bag->fcurve_ensure(nullptr, {"fcu2", 0, std::nullopt, "group1"});
1515 FCurve &fcu3 = channel_bag->fcurve_ensure(nullptr, {"fcu3", 0, std::nullopt, "group1"});
1516 FCurve &fcu4 = channel_bag->fcurve_ensure(nullptr, {"fcu4", 0, std::nullopt, std::nullopt});
1517
1518 ASSERT_EQ(5, channel_bag->fcurves().size());
1519 ASSERT_EQ(2, channel_bag->channel_groups().size());
1520
1521 bActionGroup &group0 = *channel_bag->channel_group(0);
1522 bActionGroup &group1 = *channel_bag->channel_group(1);
1523
1524 EXPECT_EQ(0, group0.fcurve_range_start);
1525 EXPECT_EQ(2, group0.fcurve_range_length);
1526 EXPECT_EQ(2, group1.fcurve_range_start);
1527 EXPECT_EQ(2, group1.fcurve_range_length);
1528 EXPECT_EQ(&group0, fcu0.grp);
1529 EXPECT_EQ(&group0, fcu1.grp);
1530 EXPECT_EQ(&group1, fcu2.grp);
1531 EXPECT_EQ(&group1, fcu3.grp);
1532 EXPECT_EQ(nullptr, fcu4.grp);
1533
1534 channel_bag->fcurve_remove(fcu3);
1535 ASSERT_EQ(4, channel_bag->fcurves().size());
1536 ASSERT_EQ(2, channel_bag->channel_groups().size());
1537 EXPECT_EQ(&group0, channel_bag->channel_group(0));
1538 EXPECT_EQ(&group1, channel_bag->channel_group(1));
1539 EXPECT_EQ(0, group0.fcurve_range_start);
1540 EXPECT_EQ(2, group0.fcurve_range_length);
1541 EXPECT_EQ(2, group1.fcurve_range_start);
1542 EXPECT_EQ(1, group1.fcurve_range_length);
1543 EXPECT_EQ(&group0, fcu0.grp);
1544 EXPECT_EQ(&group0, fcu1.grp);
1545 EXPECT_EQ(&group1, fcu2.grp);
1546 EXPECT_EQ(nullptr, fcu4.grp);
1547
1548 channel_bag->fcurve_remove(fcu0);
1549 ASSERT_EQ(3, channel_bag->fcurves().size());
1550 ASSERT_EQ(2, channel_bag->channel_groups().size());
1551 EXPECT_EQ(&group0, channel_bag->channel_group(0));
1552 EXPECT_EQ(&group1, channel_bag->channel_group(1));
1553 EXPECT_EQ(0, group0.fcurve_range_start);
1554 EXPECT_EQ(1, group0.fcurve_range_length);
1555 EXPECT_EQ(1, group1.fcurve_range_start);
1556 EXPECT_EQ(1, group1.fcurve_range_length);
1557 EXPECT_EQ(&group0, fcu1.grp);
1558 EXPECT_EQ(&group1, fcu2.grp);
1559 EXPECT_EQ(nullptr, fcu4.grp);
1560
1561 channel_bag->fcurve_remove(fcu1);
1562 ASSERT_EQ(2, channel_bag->fcurves().size());
1563 ASSERT_EQ(1, channel_bag->channel_groups().size());
1564 EXPECT_EQ(&group1, channel_bag->channel_group(0));
1565 EXPECT_EQ(0, group1.fcurve_range_start);
1566 EXPECT_EQ(1, group1.fcurve_range_length);
1567 EXPECT_EQ(&group1, fcu2.grp);
1568 EXPECT_EQ(nullptr, fcu4.grp);
1569
1570 channel_bag->fcurve_remove(fcu4);
1571 ASSERT_EQ(1, channel_bag->fcurves().size());
1572 ASSERT_EQ(1, channel_bag->channel_groups().size());
1573 EXPECT_EQ(&group1, channel_bag->channel_group(0));
1574 EXPECT_EQ(0, group1.fcurve_range_start);
1575 EXPECT_EQ(1, group1.fcurve_range_length);
1576 EXPECT_EQ(&group1, fcu2.grp);
1577
1578 channel_bag->fcurve_remove(fcu2);
1579 ASSERT_EQ(0, channel_bag->fcurves().size());
1580 ASSERT_EQ(0, channel_bag->channel_groups().size());
1581}
1582
1583TEST_F(ChannelBagTest, channel_group_move)
1584{
1585 FCurve &fcu0 = channel_bag->fcurve_ensure(nullptr, {"fcu0", 0, std::nullopt, "group0"});
1586 FCurve &fcu1 = channel_bag->fcurve_ensure(nullptr, {"fcu1", 0, std::nullopt, "group1"});
1587 FCurve &fcu2 = channel_bag->fcurve_ensure(nullptr, {"fcu2", 0, std::nullopt, "group1"});
1588 FCurve &fcu3 = channel_bag->fcurve_ensure(nullptr, {"fcu3", 0, std::nullopt, "group2"});
1589 FCurve &fcu4 = channel_bag->fcurve_ensure(nullptr, {"fcu4", 0, std::nullopt, std::nullopt});
1590
1591 ASSERT_EQ(5, channel_bag->fcurves().size());
1592 ASSERT_EQ(3, channel_bag->channel_groups().size());
1593
1594 bActionGroup &group0 = *channel_bag->channel_group(0);
1595 bActionGroup &group1 = *channel_bag->channel_group(1);
1596 bActionGroup &group2 = *channel_bag->channel_group(2);
1597
1598 channel_bag->channel_group_move(group0, 2);
1599 EXPECT_EQ(&group1, channel_bag->channel_group(0));
1600 EXPECT_EQ(&group2, channel_bag->channel_group(1));
1601 EXPECT_EQ(&group0, channel_bag->channel_group(2));
1602 EXPECT_EQ(0, group1.fcurve_range_start);
1603 EXPECT_EQ(2, group1.fcurve_range_length);
1604 EXPECT_EQ(2, group2.fcurve_range_start);
1605 EXPECT_EQ(1, group2.fcurve_range_length);
1606 EXPECT_EQ(3, group0.fcurve_range_start);
1607 EXPECT_EQ(1, group0.fcurve_range_length);
1608 EXPECT_EQ(&fcu1, channel_bag->fcurve(0));
1609 EXPECT_EQ(&fcu2, channel_bag->fcurve(1));
1610 EXPECT_EQ(&fcu3, channel_bag->fcurve(2));
1611 EXPECT_EQ(&fcu0, channel_bag->fcurve(3));
1612 EXPECT_EQ(&fcu4, channel_bag->fcurve(4));
1613 EXPECT_EQ(&group1, fcu1.grp);
1614 EXPECT_EQ(&group1, fcu2.grp);
1615 EXPECT_EQ(&group2, fcu3.grp);
1616 EXPECT_EQ(&group0, fcu0.grp);
1617 EXPECT_EQ(nullptr, fcu4.grp);
1618
1619 channel_bag->channel_group_move(group1, 1);
1620 EXPECT_EQ(&group2, channel_bag->channel_group(0));
1621 EXPECT_EQ(&group1, channel_bag->channel_group(1));
1622 EXPECT_EQ(&group0, channel_bag->channel_group(2));
1623 EXPECT_EQ(0, group2.fcurve_range_start);
1624 EXPECT_EQ(1, group2.fcurve_range_length);
1625 EXPECT_EQ(1, group1.fcurve_range_start);
1626 EXPECT_EQ(2, group1.fcurve_range_length);
1627 EXPECT_EQ(3, group0.fcurve_range_start);
1628 EXPECT_EQ(1, group0.fcurve_range_length);
1629 EXPECT_EQ(&fcu3, channel_bag->fcurve(0));
1630 EXPECT_EQ(&fcu1, channel_bag->fcurve(1));
1631 EXPECT_EQ(&fcu2, channel_bag->fcurve(2));
1632 EXPECT_EQ(&fcu0, channel_bag->fcurve(3));
1633 EXPECT_EQ(&fcu4, channel_bag->fcurve(4));
1634 EXPECT_EQ(&group2, fcu3.grp);
1635 EXPECT_EQ(&group1, fcu1.grp);
1636 EXPECT_EQ(&group1, fcu2.grp);
1637 EXPECT_EQ(&group0, fcu0.grp);
1638 EXPECT_EQ(nullptr, fcu4.grp);
1639
1640 channel_bag->channel_group_move(group0, 0);
1641 EXPECT_EQ(&group0, channel_bag->channel_group(0));
1642 EXPECT_EQ(&group2, channel_bag->channel_group(1));
1643 EXPECT_EQ(&group1, channel_bag->channel_group(2));
1644 EXPECT_EQ(0, group0.fcurve_range_start);
1645 EXPECT_EQ(1, group0.fcurve_range_length);
1646 EXPECT_EQ(1, group2.fcurve_range_start);
1647 EXPECT_EQ(1, group2.fcurve_range_length);
1648 EXPECT_EQ(2, group1.fcurve_range_start);
1649 EXPECT_EQ(2, group1.fcurve_range_length);
1650 EXPECT_EQ(&fcu0, channel_bag->fcurve(0));
1651 EXPECT_EQ(&fcu3, channel_bag->fcurve(1));
1652 EXPECT_EQ(&fcu1, channel_bag->fcurve(2));
1653 EXPECT_EQ(&fcu2, channel_bag->fcurve(3));
1654 EXPECT_EQ(&fcu4, channel_bag->fcurve(4));
1655 EXPECT_EQ(&group0, fcu0.grp);
1656 EXPECT_EQ(&group2, fcu3.grp);
1657 EXPECT_EQ(&group1, fcu1.grp);
1658 EXPECT_EQ(&group1, fcu2.grp);
1659 EXPECT_EQ(nullptr, fcu4.grp);
1660}
1661
1662TEST_F(ChannelBagTest, channel_group_move_fcurve_into)
1663{
1664 FCurve &fcu0 = channel_bag->fcurve_ensure(nullptr, {"fcu0", 0, std::nullopt, std::nullopt});
1665 FCurve &fcu1 = channel_bag->fcurve_ensure(nullptr, {"fcu1", 0, std::nullopt, std::nullopt});
1666 FCurve &fcu2 = channel_bag->fcurve_ensure(nullptr, {"fcu2", 0, std::nullopt, std::nullopt});
1667 bActionGroup &group0 = channel_bag->channel_group_create("group0");
1668 bActionGroup &group1 = channel_bag->channel_group_create("group1");
1669
1670 ASSERT_EQ(3, channel_bag->fcurves().size());
1671 EXPECT_EQ(&fcu0, channel_bag->fcurve(0));
1672 EXPECT_EQ(&fcu1, channel_bag->fcurve(1));
1673 EXPECT_EQ(&fcu2, channel_bag->fcurve(2));
1674 ASSERT_EQ(2, channel_bag->channel_groups().size());
1675 EXPECT_EQ(&group0, channel_bag->channel_group(0));
1676 EXPECT_EQ(&group1, channel_bag->channel_group(1));
1677 EXPECT_EQ(0, group0.fcurve_range_start);
1678 EXPECT_EQ(0, group0.fcurve_range_length);
1679 EXPECT_EQ(0, group1.fcurve_range_start);
1680 EXPECT_EQ(0, group1.fcurve_range_length);
1681
1682 channel_bag->fcurve_assign_to_channel_group(fcu2, group1);
1683 EXPECT_EQ(&fcu2, channel_bag->fcurve(0));
1684 EXPECT_EQ(&fcu0, channel_bag->fcurve(1));
1685 EXPECT_EQ(&fcu1, channel_bag->fcurve(2));
1686 EXPECT_EQ(0, group0.fcurve_range_start);
1687 EXPECT_EQ(0, group0.fcurve_range_length);
1688 EXPECT_EQ(0, group1.fcurve_range_start);
1689 EXPECT_EQ(1, group1.fcurve_range_length);
1690
1691 channel_bag->fcurve_assign_to_channel_group(fcu1, group0);
1692 EXPECT_EQ(&fcu1, channel_bag->fcurve(0));
1693 EXPECT_EQ(&fcu2, channel_bag->fcurve(1));
1694 EXPECT_EQ(&fcu0, channel_bag->fcurve(2));
1695 EXPECT_EQ(0, group0.fcurve_range_start);
1696 EXPECT_EQ(1, group0.fcurve_range_length);
1697 EXPECT_EQ(1, group1.fcurve_range_start);
1698 EXPECT_EQ(1, group1.fcurve_range_length);
1699
1700 channel_bag->fcurve_assign_to_channel_group(fcu0, group1);
1701 EXPECT_EQ(&fcu1, channel_bag->fcurve(0));
1702 EXPECT_EQ(&fcu2, channel_bag->fcurve(1));
1703 EXPECT_EQ(&fcu0, channel_bag->fcurve(2));
1704 EXPECT_EQ(0, group0.fcurve_range_start);
1705 EXPECT_EQ(1, group0.fcurve_range_length);
1706 EXPECT_EQ(1, group1.fcurve_range_start);
1707 EXPECT_EQ(2, group1.fcurve_range_length);
1708
1709 channel_bag->fcurve_assign_to_channel_group(fcu0, group0);
1710 EXPECT_EQ(&fcu1, channel_bag->fcurve(0));
1711 EXPECT_EQ(&fcu0, channel_bag->fcurve(1));
1712 EXPECT_EQ(&fcu2, channel_bag->fcurve(2));
1713 EXPECT_EQ(0, group0.fcurve_range_start);
1714 EXPECT_EQ(2, group0.fcurve_range_length);
1715 EXPECT_EQ(2, group1.fcurve_range_start);
1716 EXPECT_EQ(1, group1.fcurve_range_length);
1717
1718 channel_bag->fcurve_assign_to_channel_group(fcu1, group1);
1719 EXPECT_EQ(&fcu0, channel_bag->fcurve(0));
1720 EXPECT_EQ(&fcu2, channel_bag->fcurve(1));
1721 EXPECT_EQ(&fcu1, channel_bag->fcurve(2));
1722 EXPECT_EQ(0, group0.fcurve_range_start);
1723 EXPECT_EQ(1, group0.fcurve_range_length);
1724 EXPECT_EQ(1, group1.fcurve_range_start);
1725 EXPECT_EQ(2, group1.fcurve_range_length);
1726}
1727
1728TEST_F(ChannelBagTest, channel_group_fcurve_ungroup)
1729{
1730 FCurve &fcu0 = channel_bag->fcurve_ensure(nullptr, {"fcu0", 0, std::nullopt, "group0"});
1731 FCurve &fcu1 = channel_bag->fcurve_ensure(nullptr, {"fcu1", 0, std::nullopt, "group0"});
1732 FCurve &fcu2 = channel_bag->fcurve_ensure(nullptr, {"fcu2", 0, std::nullopt, "group1"});
1733 FCurve &fcu3 = channel_bag->fcurve_ensure(nullptr, {"fcu3", 0, std::nullopt, "group1"});
1734 FCurve &fcu4 = channel_bag->fcurve_ensure(nullptr, {"fcu4", 0, std::nullopt, std::nullopt});
1735
1736 ASSERT_EQ(5, channel_bag->fcurves().size());
1737 ASSERT_EQ(2, channel_bag->channel_groups().size());
1738
1739 bActionGroup &group0 = *channel_bag->channel_group(0);
1740 bActionGroup &group1 = *channel_bag->channel_group(1);
1741
1742 /* Attempting to ungroup an fcurve that's not in the channel bag should fail. */
1743 FCurve bogus = {};
1744 EXPECT_FALSE(channel_bag->fcurve_ungroup(bogus));
1745
1746 /* Attempting to ungroup an fcurve that's already ungrouped is fine. */
1747 EXPECT_TRUE(channel_bag->fcurve_ungroup(fcu4));
1748
1749 /* Ungroup each fcurve until all are ungrouped. */
1750
1751 EXPECT_TRUE(channel_bag->fcurve_ungroup(fcu0));
1752 EXPECT_EQ(0, group0.fcurve_range_start);
1753 EXPECT_EQ(1, group0.fcurve_range_length);
1754 EXPECT_EQ(1, group1.fcurve_range_start);
1755 EXPECT_EQ(2, group1.fcurve_range_length);
1756 EXPECT_EQ(&fcu1, channel_bag->fcurve(0));
1757 EXPECT_EQ(&fcu2, channel_bag->fcurve(1));
1758 EXPECT_EQ(&fcu3, channel_bag->fcurve(2));
1759 EXPECT_EQ(&fcu4, channel_bag->fcurve(3));
1760 EXPECT_EQ(&fcu0, channel_bag->fcurve(4));
1761 EXPECT_EQ(&group0, fcu1.grp);
1762 EXPECT_EQ(&group1, fcu2.grp);
1763 EXPECT_EQ(&group1, fcu3.grp);
1764 EXPECT_EQ(nullptr, fcu4.grp);
1765 EXPECT_EQ(nullptr, fcu0.grp);
1766
1767 EXPECT_TRUE(channel_bag->fcurve_ungroup(fcu3));
1768 EXPECT_EQ(0, group0.fcurve_range_start);
1769 EXPECT_EQ(1, group0.fcurve_range_length);
1770 EXPECT_EQ(1, group1.fcurve_range_start);
1771 EXPECT_EQ(1, group1.fcurve_range_length);
1772 EXPECT_EQ(&fcu1, channel_bag->fcurve(0));
1773 EXPECT_EQ(&fcu2, channel_bag->fcurve(1));
1774 EXPECT_EQ(&fcu4, channel_bag->fcurve(2));
1775 EXPECT_EQ(&fcu0, channel_bag->fcurve(3));
1776 EXPECT_EQ(&fcu3, channel_bag->fcurve(4));
1777 EXPECT_EQ(&group0, fcu1.grp);
1778 EXPECT_EQ(&group1, fcu2.grp);
1779 EXPECT_EQ(nullptr, fcu4.grp);
1780 EXPECT_EQ(nullptr, fcu0.grp);
1781 EXPECT_EQ(nullptr, fcu3.grp);
1782
1783 EXPECT_TRUE(channel_bag->fcurve_ungroup(fcu1));
1784 EXPECT_EQ(1, channel_bag->channel_groups().size());
1785 EXPECT_EQ(&group1, channel_bag->channel_group(0));
1786 EXPECT_EQ(0, group1.fcurve_range_start);
1787 EXPECT_EQ(1, group1.fcurve_range_length);
1788 EXPECT_EQ(&fcu2, channel_bag->fcurve(0));
1789 EXPECT_EQ(&fcu4, channel_bag->fcurve(1));
1790 EXPECT_EQ(&fcu0, channel_bag->fcurve(2));
1791 EXPECT_EQ(&fcu3, channel_bag->fcurve(3));
1792 EXPECT_EQ(&fcu1, channel_bag->fcurve(4));
1793 EXPECT_EQ(&group1, fcu2.grp);
1794 EXPECT_EQ(nullptr, fcu4.grp);
1795 EXPECT_EQ(nullptr, fcu0.grp);
1796 EXPECT_EQ(nullptr, fcu3.grp);
1797 EXPECT_EQ(nullptr, fcu1.grp);
1798
1799 EXPECT_TRUE(channel_bag->fcurve_ungroup(fcu2));
1800 EXPECT_EQ(0, channel_bag->channel_groups().size());
1801 EXPECT_EQ(&fcu4, channel_bag->fcurve(0));
1802 EXPECT_EQ(&fcu0, channel_bag->fcurve(1));
1803 EXPECT_EQ(&fcu3, channel_bag->fcurve(2));
1804 EXPECT_EQ(&fcu1, channel_bag->fcurve(3));
1805 EXPECT_EQ(&fcu2, channel_bag->fcurve(4));
1806 EXPECT_EQ(nullptr, fcu4.grp);
1807 EXPECT_EQ(nullptr, fcu0.grp);
1808 EXPECT_EQ(nullptr, fcu3.grp);
1809 EXPECT_EQ(nullptr, fcu1.grp);
1810 EXPECT_EQ(nullptr, fcu2.grp);
1811}
1812
1813/*-----------------------------------------------------------*/
1814
1815class ActionFCurveMoveTest : public testing::Test {
1816 public:
1818
1819 static void SetUpTestSuite()
1820 {
1821 /* BKE_id_free() hits a code path that uses CLOG, which crashes if not initialized properly. */
1822 CLG_init();
1823
1824 /* To make id_can_have_animdata() and friends work, the `id_types` array needs to be set up. */
1826 }
1827
1828 static void TearDownTestSuite()
1829 {
1830 CLG_exit();
1831 }
1832
1833 void SetUp() override
1834 {
1835 bmain = BKE_main_new();
1836 }
1837
1838 void TearDown() override
1839 {
1841 }
1842
1843 static FCurve *fcurve_create(const StringRefNull rna_path, const int array_index)
1844 {
1845 FCurve *fcurve = BKE_fcurve_create();
1846 fcurve->rna_path = BLI_strdupn(rna_path.c_str(), array_index);
1847 return fcurve;
1848 };
1849};
1850
1851TEST_F(ActionFCurveMoveTest, test_fcurve_move_legacy)
1852{
1853 Action &action_src = action_add(*this->bmain, "SourceAction");
1854 Action &action_dst = action_add(*this->bmain, "DestinationAction");
1855
1856 /* Add F-Curves to source Action. */
1857 BLI_addtail(&action_src.curves, this->fcurve_create("source_prop", 0));
1858 FCurve *fcurve_to_move = this->fcurve_create("source_prop", 2);
1859 BLI_addtail(&action_src.curves, fcurve_to_move);
1860
1861 /* Add F-Curves to destination Action. */
1862 BLI_addtail(&action_dst.curves, this->fcurve_create("dest_prop", 0));
1863
1864 ASSERT_TRUE(action_src.is_action_legacy());
1865 ASSERT_TRUE(action_dst.is_action_legacy());
1866
1867 action_fcurve_move(action_dst, Slot::unassigned, action_src, *fcurve_to_move);
1868
1869 EXPECT_TRUE(action_src.is_action_legacy());
1870 EXPECT_TRUE(action_dst.is_action_legacy());
1871
1872 EXPECT_EQ(-1, BLI_findindex(&action_src.curves, fcurve_to_move))
1873 << "F-Curve should no longer exist in source Action";
1874 EXPECT_EQ(1, BLI_findindex(&action_dst.curves, fcurve_to_move))
1875 << "F-Curve should exist in destination Action";
1876
1877 EXPECT_EQ(1, BLI_listbase_count(&action_src.curves))
1878 << "Source Action should still have the other F-Curve";
1879 EXPECT_EQ(2, BLI_listbase_count(&action_dst.curves))
1880 << "Destination Action should have its original and the moved F-Curve";
1881}
1882
1883#ifdef WITH_ANIM_BAKLAVA
1884TEST_F(ActionFCurveMoveTest, test_fcurve_move_layered)
1885{
1886 Action &action_src = action_add(*this->bmain, "SourceAction");
1887 Action &action_dst = action_add(*this->bmain, "DestinationAction");
1888
1889 /* Add F-Curves to source Action. */
1890 Slot &slot_src = action_src.slot_add();
1891 action_src.layer_keystrip_ensure();
1892 StripKeyframeData &strip_data_src = action_src.layer(0)->strip(0)->data<StripKeyframeData>(
1893 action_src);
1894 ChannelBag &cbag_src = strip_data_src.channelbag_for_slot_ensure(slot_src);
1895
1896 cbag_src.fcurve_ensure(this->bmain, {"source_prop", 0});
1897 FCurve &fcurve_to_move = cbag_src.fcurve_ensure(this->bmain, {"source_prop", 2});
1898 bActionGroup &group_src = cbag_src.channel_group_create("Gröpje");
1899 cbag_src.fcurve_assign_to_channel_group(fcurve_to_move, group_src);
1900
1901 /* Add F-Curves to destination Action. */
1902 Slot &slot_dst = action_dst.slot_add();
1903 action_dst.layer_keystrip_ensure();
1904 StripKeyframeData &strip_data_dst = action_dst.layer(0)->strip(0)->data<StripKeyframeData>(
1905 action_dst);
1906 ChannelBag &cbag_dst = strip_data_dst.channelbag_for_slot_ensure(slot_dst);
1907
1908 cbag_dst.fcurve_ensure(this->bmain, {"dest_prop", 0});
1909
1910 ASSERT_TRUE(action_src.is_action_layered());
1911 ASSERT_TRUE(action_dst.is_action_layered());
1912
1913 action_fcurve_move(action_dst, slot_dst.handle, action_src, fcurve_to_move);
1914
1915 EXPECT_TRUE(action_src.is_action_layered());
1916 EXPECT_TRUE(action_dst.is_action_layered());
1917
1918 EXPECT_EQ(nullptr, cbag_src.fcurve_find({fcurve_to_move.rna_path, fcurve_to_move.array_index}))
1919 << "F-Curve should no longer exist in source Action";
1920 EXPECT_EQ(&fcurve_to_move,
1921 cbag_dst.fcurve_find({fcurve_to_move.rna_path, fcurve_to_move.array_index}))
1922 << "F-Curve should exist in destination Action";
1923
1924 EXPECT_EQ(1, cbag_src.fcurves().size()) << "Source Action should still have the other F-Curve";
1925 EXPECT_EQ(2, cbag_dst.fcurves().size())
1926 << "Destination Action should have its original and the moved F-Curve";
1927
1928 bActionGroup *group_dst = cbag_dst.channel_group_find("Gröpje");
1929 ASSERT_NE(nullptr, group_dst) << "Expected channel group to be created";
1930 ASSERT_EQ(group_dst, fcurve_to_move.grp) << "Expected group membership to move as well";
1931}
1932#endif
1933
1934} // namespace blender::animrig::tests
Functions and classes to work with Actions.
Blender kernel action and pose functionality.
AnimData * BKE_animdata_ensure_id(ID *id)
Definition anim_data.cc:103
FModifier * add_fmodifier(ListBase *modifiers, int type, FCurve *owner_fcu)
FCurve * BKE_fcurve_create(void)
float evaluate_fcurve(const FCurve *fcu, float evaltime)
void BKE_idtype_init()
Definition idtype.cc:127
void BKE_id_free(Main *bmain, void *idv)
void id_us_plus(ID *id)
Definition lib_id.cc:351
void * BKE_id_new(Main *bmain, short type, const char *name)
Definition lib_id.cc:1482
void * BKE_id_new_nomain(short type, const char *name)
Definition lib_id.cc:1487
Main * BKE_main_new(void)
Definition main.cc:45
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_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:90
void * BLI_poptail(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:260
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
char * BLI_strdupn(const char *str, size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition string.c:29
#define STRNCPY_UTF8(dst, src)
void CLG_exit(void)
Definition clog.c:706
void CLG_init(void)
Definition clog.c:699
@ ID_CA
@ ID_AC
@ ID_ME
@ ID_OB
@ INSERTKEY_NOFLAGS
@ FMODIFIER_TYPE_NOISE
@ HD_AUTO
@ BEZT_IPO_BEZ
@ BEZT_KEYTYPE_KEYFRAME
Object is a sort of wrapper for general info.
@ OB_EMPTY
@ USER_DEVELOPER_UI
unsigned int U
Definition btGjkEpa3.h:78
constexpr bool contains(const T &value) const
Definition BLI_span.hh:278
constexpr const char * c_str() const
bool contains(const T &value) const
const Layer * layer(int64_t index) const
const Slot * slot(int64_t index) const
float2 get_frame_range_of_keys(bool include_modifiers) const ATTR_WARN_UNUSED_RESULT
Layer & layer_add(std::optional< StringRefNull > name)
const bActionGroup * channel_group(int64_t index) const
FCurve & fcurve_ensure(Main *bmain, FCurveDescriptor fcurve_descriptor)
FCurve * fcurve_create_unique(Main *bmain, FCurveDescriptor fcurve_descriptor)
blender::Span< const bActionGroup * > channel_groups() const
const Strip * strip(int64_t index) const
Strip & strip_add(Action &owning_action, Strip::Type strip_type)
std::string name_prefix_for_idtype() const
Span< ID * > users(Main &bmain) const
static constexpr slot_handle_t unassigned
const ChannelBag * channelbag(int64_t index) const
ChannelBag & channelbag_for_slot_ensure(const Slot &slot)
SingleKeyingResult keyframe_insert(Main *bmain, const Slot &slot, FCurveDescriptor fcurve_descriptor, float2 time_value, const KeyframeSettings &settings, eInsertKeyFlags insert_key_flags=INSERTKEY_NOFLAGS)
const ChannelBag * channelbag_for_slot(const Slot &slot) const
blender::Span< const ChannelBag * > channelbags() const
bool is_last_frame(float frame_time) const
void resize(float frame_start, float frame_end)
const T & data(const Action &owning_action) const
bool contains_frame(float frame_time) const
static FCurve * fcurve_create(const StringRefNull rna_path, const int array_index)
#define GS(x)
Definition iris.cc:202
static void add_fcurve_to_action(Action &action, FCurve &fcu)
static void allocate_keyframes(FCurve &fcu, const size_t num_keyframes)
TEST_F(ActionIteratorsTest, iterate_all_fcurves_of_slot)
static void add_keyframe(FCurve &fcu, float x, float y)
KeyframeSettings get_keyframe_settings(bool from_userprefs)
Slot * assign_action_ensure_slot_for_keying(Action &action, ID &animated_id)
FCurve * action_fcurve_ensure(Main *bmain, bAction *act, const char group[], PointerRNA *ptr, FCurveDescriptor fcurve_descriptor)
void action_fcurve_move(Action &action_dst, slot_handle_t action_slot_dst, Action &action_src, FCurve &fcurve)
Action & action_add(Main &bmain, StringRefNull name)
ActionSlotAssignmentResult assign_action_and_slot(Action *action, Slot *slot_to_assign, ID &animated_id)
SingleKeyingResult insert_vert_fcurve(FCurve *fcu, const float2 position, const KeyframeSettings &settings, eInsertKeyFlags flag)
Main Key-framing API call.
ID * action_slot_get_id_for_keying(Main &bmain, Action &action, slot_handle_t slot_handle, ID *primary_id)
bool is_action_assignable_to(const bAction *dna_action, ID_Type id_code) ATTR_WARN_UNUSED_RESULT
decltype(::ActionSlot::handle) slot_handle_t
Action * convert_to_layered_action(Main &bmain, const Action &legacy_action)
bool unassign_action(ID &animated_id)
bool assign_action(bAction *action, ID &animated_id)
ActionSlotAssignmentResult assign_action_slot(Slot *slot_to_assign, ID &animated_id)
void move_slot(Main &bmain, Slot &slot, Action &from_action, Action &to_action)
PointerRNA RNA_id_pointer_create(ID *id)
struct FCurve ** fcurve_array
ActionSlotRuntimeHandle * runtime
bAction * action
int32_t slot_handle
char slot_name[66]
float vec[3][3]
bActionGroup * grp
char * rna_path
BezTriple * bezt
unsigned int totvert
ListBase modifiers
Definition DNA_ID.h:413
char name[66]
Definition DNA_ID.h:425
void * first
ListBase curves
ListBase groups