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 {
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
struct bActionGroup bActionGroup
@ 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
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a producing a negative Combine Generate a color from its and blue channels(Deprecated)") DefNode(ShaderNode
#define U
constexpr bool contains(const T &value) const
Definition BLI_span.hh:278
bool contains(const T &value) const
constexpr const char * c_str() 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
bool strip_remove(Action &owning_action, Strip &strip)
blender::Span< const Strip * > strips() 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)
VecBase< float, 2 > float2
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