Blender V4.3
action_legacy_test.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4#include "ANIM_action.hh"
6
7#include "BKE_fcurve.hh"
8#include "BKE_idtype.hh"
9#include "BKE_lib_id.hh"
10#include "BKE_main.hh"
11#include "BKE_object.hh"
12
13#include "DNA_anim_types.h"
14#include "DNA_object_types.h"
15
16#include "BLI_listbase.h"
17
18#include "CLG_log.h"
19#include "testing/testing.h"
20
22class ActionLegacyTest : public testing::Test {
23 public:
25
26 static void SetUpTestSuite()
27 {
28 /* BKE_id_free() hits a code path that uses CLOG, which crashes if not initialized properly. */
29 CLG_init();
30
31 /* To make id_can_have_animdata() and friends work, the `id_types` array needs to be set up. */
33 }
34
35 static void TearDownTestSuite()
36 {
37 CLG_exit();
38 }
39
40 void SetUp() override
41 {
43 }
44
45 void TearDown() override
46 {
48 }
49
51 {
52 return static_cast<bAction *>(BKE_id_new(bmain, ID_AC, "ACAction"));
53 }
54
55 FCurve *fcurve_add_legacy(bAction *action, const StringRefNull rna_path, const int array_index)
56 {
57 FCurve *fcurve = static_cast<FCurve *>(MEM_callocN(sizeof(FCurve), __func__));
58 BKE_fcurve_rnapath_set(*fcurve, rna_path);
59 fcurve->array_index = array_index;
60 BLI_addtail(&action->curves, fcurve);
61 return fcurve;
62 }
63};
64
66{
67 { /* nil pointer. */
68 bAction *action = nullptr;
69 Vector<FCurve *> fcurves = legacy::fcurves_all(action);
70 EXPECT_TRUE(fcurves.is_empty());
71 }
72
73 { /* Empty Action. */
74 Vector<FCurve *> fcurves = legacy::fcurves_all(create_empty_action());
75 EXPECT_TRUE(fcurves.is_empty());
76 }
77
78 { /* Legacy Action. */
79 bAction *action = create_empty_action();
80
81 FCurve *fcurve = static_cast<FCurve *>(MEM_callocN(sizeof(FCurve), __func__));
82 BLI_addtail(&action->curves, fcurve);
83
84 Vector<FCurve *> fcurves_expect = {fcurve};
85 EXPECT_EQ(fcurves_expect, legacy::fcurves_all(action));
86 }
87}
88
89#ifdef WITH_ANIM_BAKLAVA
90TEST_F(ActionLegacyTest, fcurves_all_layered)
91{
92 Action &action = create_empty_action()->wrap();
93 Slot &slot1 = action.slot_add();
94 Slot &slot2 = action.slot_add();
95
96 action.layer_keystrip_ensure();
97 StripKeyframeData &key_data = action.layer(0)->strip(0)->data<StripKeyframeData>(action);
98
99 FCurve &fcurve1 = key_data.channelbag_for_slot_ensure(slot1).fcurve_ensure(bmain,
100 {"location", 1});
101 FCurve &fcurve2 = key_data.channelbag_for_slot_ensure(slot2).fcurve_ensure(bmain, {"scale", 2});
102
103 Vector<FCurve *> fcurves_expect = {&fcurve1, &fcurve2};
104 EXPECT_EQ(fcurves_expect, legacy::fcurves_all(&action));
105}
106#endif /* WITH_ANIM_BAKLAVA */
107
109{
110 { /* nil pointer. */
111 bAction *action = nullptr;
113 EXPECT_TRUE(fcurves.is_empty());
114 }
115
116 { /* Empty Action. */
117 Vector<FCurve *> fcurves = legacy::fcurves_for_action_slot(create_empty_action(),
119 EXPECT_TRUE(fcurves.is_empty());
120 }
121
122 { /* Legacy Action. */
123 bAction *action = create_empty_action();
124
125 FCurve *fcurve = static_cast<FCurve *>(MEM_callocN(sizeof(FCurve), __func__));
126 BLI_addtail(&action->curves, fcurve);
127
128 Vector<FCurve *> fcurves_expect = {fcurve};
130 }
131}
132
133#ifdef WITH_ANIM_BAKLAVA
134TEST_F(ActionLegacyTest, fcurves_for_action_slot_layered)
135{
136 Action &action = create_empty_action()->wrap();
137 Slot &slot1 = action.slot_add();
138 Slot &slot2 = action.slot_add();
139
140 action.layer_keystrip_ensure();
141 StripKeyframeData &key_data = action.layer(0)->strip(0)->data<StripKeyframeData>(action);
142
143 FCurve &fcurve1 = key_data.channelbag_for_slot_ensure(slot1).fcurve_ensure(bmain,
144 {"location", 1});
145 FCurve &fcurve2 = key_data.channelbag_for_slot_ensure(slot2).fcurve_ensure(bmain, {"scale", 2});
146
147 Vector<FCurve *> fcurve1_expect = {&fcurve1};
148 Vector<FCurve *> fcurve2_expect = {&fcurve2};
149 EXPECT_EQ(fcurve1_expect, legacy::fcurves_for_action_slot(&action, slot1.handle));
150 EXPECT_EQ(fcurve2_expect, legacy::fcurves_for_action_slot(&action, slot2.handle));
151}
152#endif /* WITH_ANIM_BAKLAVA */
153
154TEST_F(ActionLegacyTest, action_fcurves_remove_legacy)
155{
156 { /* Empty Action. */
157 bAction *action = create_empty_action();
158 EXPECT_FALSE(legacy::action_fcurves_remove(*action, Slot::unassigned, "rotation"));
159 }
160
161 { /* Legacy Action. */
162 bAction *action = create_empty_action();
163 FCurve *fcurve_loc_x = fcurve_add_legacy(action, "location", 0);
164 fcurve_add_legacy(action, "rotation_euler", 2);
165 fcurve_add_legacy(action, "rotation_mode", 0);
166 FCurve *fcurve_loc_y = fcurve_add_legacy(action, "location", 1);
167
168 EXPECT_TRUE(legacy::action_fcurves_remove(*action, Slot::unassigned, "rotation"));
169 Vector<FCurve *> fcurves_expect = {fcurve_loc_x, fcurve_loc_y};
170 EXPECT_EQ(fcurves_expect, legacy::fcurves_all(action));
171 }
172}
173
174#ifdef WITH_ANIM_BAKLAVA
175TEST_F(ActionLegacyTest, action_fcurves_remove_layered)
176{
177 /* Create an Action with two slots, to check that the 2nd slot is not affected
178 * by removal from the 1st. */
179 Action &action = create_empty_action()->wrap();
180 Slot &slot_1 = action.slot_add();
181 Slot &slot_2 = action.slot_add();
182
183 action.layer_keystrip_ensure();
184 StripKeyframeData *strip_data = action.strip_keyframe_data()[0];
185 ChannelBag &bag_1 = strip_data->channelbag_for_slot_ensure(slot_1);
186 ChannelBag &bag_2 = strip_data->channelbag_for_slot_ensure(slot_2);
187
188 /* Add some F-Curves to each channelbag. */
189 FCurve &fcurve_loc_x = bag_1.fcurve_ensure(nullptr, {"location", 0});
190 bag_1.fcurve_ensure(nullptr, {"rotation_euler", 2});
191 bag_1.fcurve_ensure(nullptr, {"rotation_mode", 0});
192 FCurve &fcurve_loc_y = bag_1.fcurve_ensure(nullptr, {"location", 1});
193
194 bag_2.fcurve_ensure(nullptr, {"location", 0});
195 bag_2.fcurve_ensure(nullptr, {"rotation_euler", 2});
196 bag_2.fcurve_ensure(nullptr, {"rotation_mode", 0});
197 bag_2.fcurve_ensure(nullptr, {"location", 1});
198
199 /* Check that removing from slot_1 works as expected. */
200 EXPECT_TRUE(legacy::action_fcurves_remove(action, slot_1.handle, "rotation"));
201
202 Vector<FCurve *> fcurves_bag_1_expect = {&fcurve_loc_x, &fcurve_loc_y};
203 EXPECT_EQ(fcurves_bag_1_expect, legacy::fcurves_for_action_slot(&action, slot_1.handle));
204
205 EXPECT_EQ(4, bag_2.fcurves().size())
206 << "Expected all F-Curves for slot 2 to be there after manipulating slot 1";
207}
208
209#endif /* WITH_ANIM_BAKLAVA */
210
211} // namespace blender::animrig::tests
Functions and classes to work with Actions.
Functions for backward compatibility with the legacy Action API.
void BKE_fcurve_rnapath_set(FCurve &fcu, blender::StringRef rna_path)
void BKE_idtype_init()
Definition idtype.cc:127
void * BKE_id_new(Main *bmain, short type, const char *name)
Definition lib_id.cc:1482
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.
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void CLG_exit(void)
Definition clog.c:706
void CLG_init(void)
Definition clog.c:699
@ ID_AC
Object is a sort of wrapper for general info.
bool is_empty() const
const Layer * layer(int64_t index) const
Span< const StripKeyframeData * > strip_keyframe_data() const
FCurve & fcurve_ensure(Main *bmain, FCurveDescriptor fcurve_descriptor)
blender::Span< const FCurve * > fcurves() const
const Strip * strip(int64_t index) const
static constexpr slot_handle_t unassigned
ChannelBag & channelbag_for_slot_ensure(const Slot &slot)
const T & data(const Action &owning_action) const
FCurve * fcurve_add_legacy(bAction *action, const StringRefNull rna_path, const int array_index)
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
Vector< FCurve * > fcurves_for_action_slot(bAction *action, slot_handle_t slot_handle)
Vector< const FCurve * > fcurves_all(const bAction *action)
bool action_fcurves_remove(bAction &action, slot_handle_t slot_handle, StringRefNull rna_path_prefix)
TEST_F(ActionIteratorsTest, iterate_all_fcurves_of_slot)
Span< FCurve * > fcurves_for_action_slot(Action &action, slot_handle_t slot_handle)
int array_index
ListBase curves