Blender V5.0
animrig/intern/nla_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#include "ANIM_nla.hh"
7
8#include "BKE_action.hh"
9#include "BKE_anim_data.hh"
10#include "BKE_idtype.hh"
11#include "BKE_lib_id.hh"
12#include "BKE_main.hh"
13#include "BKE_nla.hh"
14#include "BKE_object.hh"
15
16#include "DNA_anim_types.h"
17#include "DNA_object_types.h"
18
19#include "BLI_listbase.h"
20
21#include "CLG_log.h"
22#include "testing/testing.h"
23
25
26class NLASlottedActionTest : public testing::Test {
27 public:
31
32 static void SetUpTestSuite()
33 {
34 /* BKE_id_free() hits a code path that uses CLOG, which crashes if not initialized properly. */
35 CLG_init();
36
37 /* To make id_can_have_animdata() and friends work, the `id_types` array needs to be set up. */
39 }
40
41 static void TearDownTestSuite()
42 {
43 CLG_exit();
44 }
45
46 void SetUp() override
47 {
49 action = BKE_id_new<Action>(bmain, "ACÄnimåtië");
50 action->id.us = 0; /* Nothing references this yet. */
52 cube->id.us = 0; /* Nothing references this yet. */
53 }
54
55 void TearDown() override
56 {
58 }
59};
60
61TEST_F(NLASlottedActionTest, assign_slot_to_nla_strip)
62{
63 ASSERT_EQ(action->id.us, 0);
64
65 AnimData *adt = BKE_animdata_ensure_id(&cube->id);
66 NlaTrack *track = BKE_nlatrack_new_tail(&adt->nla_tracks, false);
67
68 /* Create a strip. This automatically assigns the Action, but for now with the old flow. */
69 NlaStrip *strip = BKE_nlastrip_new(action, cube->id);
70 BKE_nlatrack_add_strip(track, strip, false);
71
73 EXPECT_STREQ(strip->last_slot_identifier, "");
74
75 /* Unassign the Action that was automatically assigned via BKE_nlastrip_new(). */
76 nla::unassign_action(*strip, cube->id);
77 EXPECT_EQ(strip->act, nullptr);
78 EXPECT_EQ(action->id.us, 0);
79
80 /* Assign an Action with a never-assigned slot. This should be picked automatically. */
81 Slot &virgin_slot = action->slot_add();
82
83 /* Assign the Action. */
84 EXPECT_TRUE(nla::assign_action(*strip, *action, cube->id));
85 EXPECT_EQ(strip->action_slot_handle, virgin_slot.handle);
86 EXPECT_STREQ(strip->last_slot_identifier, virgin_slot.identifier);
87 EXPECT_EQ(action->id.us, 1);
88 EXPECT_EQ(strip->act, action);
89 EXPECT_EQ(virgin_slot.idtype, GS(cube->id.name));
90
91 /* Unassign the Action. */
92 nla::unassign_action(*strip, cube->id);
93 EXPECT_EQ(strip->act, nullptr);
94 EXPECT_EQ(action->id.us, 0);
95
96 /* Create a slot for this ID, and make the NLA strip forget what slot it was assigned to before.
97 * Assigning the Action should now auto-pick the slot with the ID name. */
98 Slot &slot = action->slot_add_for_id(cube->id);
99 strip->last_slot_identifier[0] = '\0';
100 EXPECT_TRUE(nla::assign_action(*strip, *action, cube->id));
101 EXPECT_EQ(strip->action_slot_handle, slot.handle);
102 EXPECT_STREQ(strip->last_slot_identifier, slot.identifier);
103 EXPECT_EQ(action->id.us, 1);
104 EXPECT_EQ(strip->act, action);
105 EXPECT_TRUE(slot.runtime_users().contains(&cube->id));
106
107 /* Unassign the slot, but keep the Action assigned. */
110 EXPECT_STREQ(strip->last_slot_identifier, slot.identifier);
111 EXPECT_EQ(action->id.us, 1);
112 EXPECT_EQ(strip->act, action);
113 EXPECT_FALSE(slot.runtime_users().contains(&cube->id));
114
115 /* Unassign the Action, then reassign it. It should pick the same slot again. */
116 nla::unassign_action(*strip, cube->id);
117 EXPECT_TRUE(nla::assign_action(*strip, *action, cube->id));
118 EXPECT_EQ(strip->action_slot_handle, slot.handle);
119 EXPECT_TRUE(slot.runtime_users().contains(&cube->id));
120}
121
122TEST_F(NLASlottedActionTest, assign_slot_to_multiple_strips)
123{
124 AnimData *adt = BKE_animdata_ensure_id(&cube->id);
125 NlaTrack *track = BKE_nlatrack_new_tail(&adt->nla_tracks, false);
126
127 /* Create two strips. This automatically assigns the Action, but for now with
128 * the old flow (so no slots). */
129 NlaStrip *strip1 = BKE_nlastrip_new(action, cube->id);
130 strip1->start = 1;
131 strip1->end = 4;
132 NlaStrip *strip2 = BKE_nlastrip_new(action, cube->id);
133 strip1->start = 47;
134 strip1->end = 327;
135 ASSERT_TRUE(BKE_nlatrack_add_strip(track, strip1, false));
136 ASSERT_TRUE(BKE_nlatrack_add_strip(track, strip2, false));
137 ASSERT_EQ(1, BLI_listbase_count(&adt->nla_tracks));
138 ASSERT_EQ(2, BLI_listbase_count(&track->strips));
139
140 nla::unassign_action(*strip1, cube->id);
141 nla::unassign_action(*strip2, cube->id);
142
143 /* Create a virgin slot, it should be auto-picked. */
144 Slot &slot = action->slot_add();
145 EXPECT_TRUE(nla::assign_action(*strip1, *action, cube->id));
146 EXPECT_EQ(strip1->action_slot_handle, slot.handle);
147 EXPECT_STREQ(strip1->last_slot_identifier, slot.identifier);
148 EXPECT_EQ(slot.idtype, ID_OB);
149
150 /* Assign another slot 'manually'. */
151 Slot &other_slot = action->slot_add();
152 EXPECT_EQ(nla::assign_action_slot(*strip1, &other_slot, cube->id),
154 EXPECT_EQ(strip1->action_slot_handle, other_slot.handle);
155
156 /* Assign the Action + slot to the second strip. */
157 EXPECT_TRUE(nla::assign_action(*strip2, *action, cube->id));
159
160 /* The cube should be registered as user of the slot. */
161 EXPECT_TRUE(slot.runtime_users().contains(&cube->id));
162
163 nla::unassign_action(*strip1, cube->id);
164
165 /* The cube should still be registered as user of the slot, as there is a 2nd
166 * strip that references it. */
167 EXPECT_TRUE(slot.runtime_users().contains(&cube->id));
168
169 /* Remove the last use of this slot. */
170 nla::unassign_action(*strip2, cube->id);
171 EXPECT_FALSE(slot.runtime_users().contains(&cube->id));
172}
173
174} // namespace blender::animrig::nla::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:97
void BKE_idtype_init()
Definition idtype.cc:121
void * BKE_id_new(Main *bmain, short type, const char *name)
Definition lib_id.cc:1514
Main * BKE_main_new()
Definition main.cc:89
void BKE_main_free(Main *bmain)
Definition main.cc:192
bool BKE_nlatrack_add_strip(NlaTrack *nlt, NlaStrip *strip, bool is_liboverride)
NlaStrip * BKE_nlastrip_new(bAction *act, ID &animated_id)
NlaTrack * BKE_nlatrack_new_tail(ListBase *nla_tracks, const bool is_liboverride)
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)
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
void CLG_exit()
Definition clog.cc:880
void CLG_init()
Definition clog.cc:873
@ ID_OB
Object is a sort of wrapper for general info.
@ OB_EMPTY
bool contains(const T &value) const
static constexpr slot_handle_t unassigned
#define GS(x)
TEST_F(NLASlottedActionTest, assign_slot_to_nla_strip)
void unassign_action(NlaStrip &strip, ID &animated_id)
bool assign_action(NlaStrip &strip, Action &action, ID &animated_id)
ActionSlotAssignmentResult assign_action_slot(NlaStrip &strip, Slot *slot_to_assign, ID &animated_id)
char identifier[258]
ListBase nla_tracks
char last_slot_identifier[258]
int32_t action_slot_handle
bAction * act
ListBase strips