Blender V5.0
bone_collections_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 "BLI_listbase.h"
6#include "BLI_string.h"
7
8#include "BLT_translation.hh"
9
10#include "BKE_global.hh"
11#include "BKE_idtype.hh"
12#include "BKE_lib_id.hh"
13#include "BKE_main.hh"
14
17
18#include "testing/testing.h"
19
21
22TEST(ANIM_bone_collections, bonecoll_new_free)
23{
24 BoneCollection *bcoll = ANIM_bonecoll_new("some name");
25 EXPECT_NE(nullptr, bcoll);
26 EXPECT_EQ("some name", std::string(bcoll->name));
27 EXPECT_TRUE(BLI_listbase_is_empty(&bcoll->bones));
30 bcoll->flags);
31 ANIM_bonecoll_free(bcoll);
32}
33
34TEST(ANIM_bone_collections, bonecoll_default_name)
35{
36 {
38 EXPECT_EQ(DATA_("Bones"), std::string(bcoll->name));
39 ANIM_bonecoll_free(bcoll);
40 }
41
42 {
43 BoneCollection *bcoll = ANIM_bonecoll_new(nullptr);
44 EXPECT_EQ(DATA_("Bones"), std::string(bcoll->name));
45 ANIM_bonecoll_free(bcoll);
46 }
47}
48
49class ArmatureBoneCollections : public testing::Test {
50 protected:
52 Bone bone1 = {}, bone2 = {}, bone3 = {};
54
55 void SetUp() override
56 {
58 G_MAIN = bmain;
59 STRNCPY(arm.id.name, "ARArmature");
60 STRNCPY(bone1.name, "bone1");
61 STRNCPY(bone2.name, "bone2");
62 STRNCPY(bone3.name, "bone3");
63
64 BLI_addtail(&arm.bonebase, &bone1); /* bone1 is root bone. */
65 BLI_addtail(&arm.bonebase, &bone2); /* bone2 is root bone. */
66 BLI_addtail(&bone2.childbase, &bone3); /* bone3 has bone2 as parent. */
67
69 }
70
71 void TearDown() override
72 {
73 /* Avoid freeing the bones, as they are part of this struct and not owned by
74 * the armature. */
75 BLI_listbase_clear(&arm.bonebase);
76
79
81 G_MAIN = nullptr;
82 }
83};
84
85TEST_F(ArmatureBoneCollections, armature_owned_collections)
86{
87 BoneCollection *bcoll1 = ANIM_armature_bonecoll_new(&arm, "collection");
88 BoneCollection *bcoll2 = ANIM_armature_bonecoll_new(&arm, "collection");
89
90 EXPECT_EQ(std::string("collection"), std::string(bcoll1->name));
91 EXPECT_EQ(std::string("collection.001"), std::string(bcoll2->name));
92
95}
96
97TEST_F(ArmatureBoneCollections, collection_hierarchy_creation)
98{
99 /* Implicit root: */
100 BoneCollection *bcoll_root_0 = ANIM_armature_bonecoll_new(&arm, "wortel");
101 /* Explicit root: */
102 BoneCollection *bcoll_root_1 = ANIM_armature_bonecoll_new(&arm, "wortel", -1);
103
104 ASSERT_EQ(0, armature_bonecoll_find_index(&arm, bcoll_root_0));
105 ASSERT_EQ(1, armature_bonecoll_find_index(&arm, bcoll_root_1));
106
107 /* Child of bcoll at index 0: */
108 BoneCollection *bcoll_child_of_0 = ANIM_armature_bonecoll_new(&arm, "koter", 0);
109 /* Child of bcoll at index 1: */
110 BoneCollection *bcoll_child_of_1 = ANIM_armature_bonecoll_new(&arm, "koter", 1);
111
112 ASSERT_EQ(4, arm.collection_array_num);
113 EXPECT_EQ(0, armature_bonecoll_find_index(&arm, bcoll_root_0));
114 EXPECT_EQ(1, armature_bonecoll_find_index(&arm, bcoll_root_1));
115 EXPECT_EQ(2, armature_bonecoll_find_index(&arm, bcoll_child_of_0));
116 EXPECT_EQ(3, armature_bonecoll_find_index(&arm, bcoll_child_of_1));
117
118 /* Add another child of bcoll_root_0, which should push bcoll_child_of_1 further down the array.
119 */
120 BoneCollection *bcoll_another_child_of_0 = ANIM_armature_bonecoll_new(&arm, "koter", 0);
121 ASSERT_EQ(5, arm.collection_array_num);
122 EXPECT_EQ(0, armature_bonecoll_find_index(&arm, bcoll_root_0));
123 EXPECT_EQ(1, armature_bonecoll_find_index(&arm, bcoll_root_1));
124 EXPECT_EQ(2, armature_bonecoll_find_index(&arm, bcoll_child_of_0));
125 EXPECT_EQ(3, armature_bonecoll_find_index(&arm, bcoll_another_child_of_0));
126 EXPECT_EQ(4, armature_bonecoll_find_index(&arm, bcoll_child_of_1));
127
128 /* Make sure the names remain unique within the entire Armature, and not just between siblings
129 * (i.e. a unique 'path' is not strong enough). */
130 EXPECT_EQ(std::string("wortel"), std::string(bcoll_root_0->name));
131 EXPECT_EQ(std::string("wortel.001"), std::string(bcoll_root_1->name));
132 EXPECT_EQ(std::string("koter"), std::string(bcoll_child_of_0->name));
133 EXPECT_EQ(std::string("koter.001"), std::string(bcoll_child_of_1->name));
134 EXPECT_EQ(std::string("koter.002"), std::string(bcoll_another_child_of_0->name));
135
136 /* Test the internal hierarchy bookkeeping. */
137 EXPECT_EQ(2, arm.collection_root_count);
138 EXPECT_EQ(2, bcoll_root_0->child_count);
139 EXPECT_EQ(1, bcoll_root_1->child_count);
140 EXPECT_EQ(0, bcoll_child_of_0->child_count);
141 EXPECT_EQ(0, bcoll_another_child_of_0->child_count);
142 EXPECT_EQ(0, bcoll_child_of_1->child_count);
143
144 EXPECT_EQ(2, bcoll_root_0->child_index);
145 EXPECT_EQ(4, bcoll_root_1->child_index);
146 EXPECT_EQ(0, bcoll_child_of_0->child_index);
147 EXPECT_EQ(0, bcoll_another_child_of_0->child_index);
148 EXPECT_EQ(0, bcoll_child_of_1->child_index);
149
150 /* TODO: test with deeper hierarchy. */
151}
152
153TEST_F(ArmatureBoneCollections, collection_hierarchy_removal)
154{
155 /* Set up a small hierarchy. */
156 BoneCollection *bcoll_root_0 = ANIM_armature_bonecoll_new(&arm, "root_0");
157 BoneCollection *bcoll_root_1 = ANIM_armature_bonecoll_new(&arm, "root_1");
158 BoneCollection *bcoll_r0_child0 = ANIM_armature_bonecoll_new(&arm, "r0_child0", 0);
159 BoneCollection *bcoll_r1_child0 = ANIM_armature_bonecoll_new(&arm, "r1_child0", 1);
160 BoneCollection *bcoll_r0_child1 = ANIM_armature_bonecoll_new(&arm, "r0_child1", 0);
161 BoneCollection *bcoll_r0_child2 = ANIM_armature_bonecoll_new(&arm, "r0_child2", 0);
162
163 ASSERT_EQ(2, arm.collection_root_count);
164 ASSERT_EQ(6, arm.collection_array_num);
165 ASSERT_STREQ(bcoll_root_0->name, arm.collection_array[0]->name);
166 ASSERT_STREQ(bcoll_root_1->name, arm.collection_array[1]->name);
167 ASSERT_STREQ(bcoll_r0_child0->name, arm.collection_array[2]->name);
168 ASSERT_STREQ(bcoll_r0_child1->name, arm.collection_array[3]->name);
169 ASSERT_STREQ(bcoll_r0_child2->name, arm.collection_array[4]->name);
170 ASSERT_STREQ(bcoll_r1_child0->name, arm.collection_array[5]->name);
171
172 ASSERT_EQ(2, arm.collection_array[0]->child_index);
173 ASSERT_EQ(5, arm.collection_array[1]->child_index);
174 ASSERT_EQ(0, arm.collection_array[2]->child_index);
175 ASSERT_EQ(0, arm.collection_array[3]->child_index);
176 ASSERT_EQ(0, arm.collection_array[4]->child_index);
177 ASSERT_EQ(0, arm.collection_array[5]->child_index);
178
179 ASSERT_EQ(3, arm.collection_array[0]->child_count);
180 ASSERT_EQ(1, arm.collection_array[1]->child_count);
181 ASSERT_EQ(0, arm.collection_array[2]->child_count);
182 ASSERT_EQ(0, arm.collection_array[3]->child_count);
183 ASSERT_EQ(0, arm.collection_array[4]->child_count);
184 ASSERT_EQ(0, arm.collection_array[5]->child_count);
185
186 /* Remove the middle child of root_0. */
187 ANIM_armature_bonecoll_remove(&arm, bcoll_r0_child1);
188
189 ASSERT_EQ(2, arm.collection_root_count);
190 ASSERT_EQ(5, arm.collection_array_num);
191 EXPECT_STREQ(bcoll_root_0->name, arm.collection_array[0]->name);
192 EXPECT_STREQ(bcoll_root_1->name, arm.collection_array[1]->name);
193 EXPECT_STREQ(bcoll_r0_child0->name, arm.collection_array[2]->name);
194 EXPECT_STREQ(bcoll_r0_child2->name, arm.collection_array[3]->name);
195 EXPECT_STREQ(bcoll_r1_child0->name, arm.collection_array[4]->name);
196
197 EXPECT_EQ(2, arm.collection_array[0]->child_index);
198 EXPECT_EQ(4, arm.collection_array[1]->child_index);
199 EXPECT_EQ(0, arm.collection_array[2]->child_index);
200 EXPECT_EQ(0, arm.collection_array[3]->child_index);
201 EXPECT_EQ(0, arm.collection_array[4]->child_index);
202
203 EXPECT_EQ(2, arm.collection_array[0]->child_count);
204 EXPECT_EQ(1, arm.collection_array[1]->child_count);
205 EXPECT_EQ(0, arm.collection_array[2]->child_count);
206 EXPECT_EQ(0, arm.collection_array[3]->child_count);
207 EXPECT_EQ(0, arm.collection_array[4]->child_count);
208
209 /* Remove the first child of root_0. */
210 ANIM_armature_bonecoll_remove(&arm, bcoll_r0_child0);
211
212 ASSERT_EQ(2, arm.collection_root_count);
213 ASSERT_EQ(4, arm.collection_array_num);
214 EXPECT_STREQ(bcoll_root_0->name, arm.collection_array[0]->name);
215 EXPECT_STREQ(bcoll_root_1->name, arm.collection_array[1]->name);
216 EXPECT_STREQ(bcoll_r0_child2->name, arm.collection_array[2]->name);
217 EXPECT_STREQ(bcoll_r1_child0->name, arm.collection_array[3]->name);
218
219 EXPECT_EQ(2, arm.collection_array[0]->child_index);
220 EXPECT_EQ(3, arm.collection_array[1]->child_index);
221 EXPECT_EQ(0, arm.collection_array[2]->child_index);
222 EXPECT_EQ(0, arm.collection_array[3]->child_index);
223
224 EXPECT_EQ(1, arm.collection_array[0]->child_count);
225 EXPECT_EQ(1, arm.collection_array[1]->child_count);
226 EXPECT_EQ(0, arm.collection_array[2]->child_count);
227 EXPECT_EQ(0, arm.collection_array[3]->child_count);
228
229 /* Remove root_1 itself, which should make its only child a new root. */
230 ANIM_armature_bonecoll_remove(&arm, bcoll_root_1);
231
232 ASSERT_EQ(2, arm.collection_root_count);
233 ASSERT_EQ(3, arm.collection_array_num);
234 EXPECT_STREQ(bcoll_root_0->name, arm.collection_array[0]->name);
235 EXPECT_STREQ(bcoll_r1_child0->name, arm.collection_array[1]->name);
236 EXPECT_STREQ(bcoll_r0_child2->name, arm.collection_array[2]->name);
237
238 EXPECT_EQ(2, arm.collection_array[0]->child_index);
239 EXPECT_EQ(0, arm.collection_array[1]->child_index);
240 EXPECT_EQ(0, arm.collection_array[2]->child_index);
241
242 EXPECT_EQ(1, arm.collection_array[0]->child_count);
243 EXPECT_EQ(0, arm.collection_array[1]->child_count);
244 EXPECT_EQ(0, arm.collection_array[2]->child_count);
245}
246
247TEST_F(ArmatureBoneCollections, collection_hierarchy_removal__more_complex_remove_inner_child)
248{
249 /* Set up a slightly bigger hierarchy. Contrary to the other tests these are
250 * actually declared in array order. */
251 BoneCollection *bcoll_root_0 = ANIM_armature_bonecoll_new(&arm, "root_0");
252 BoneCollection *bcoll_root_1 = ANIM_armature_bonecoll_new(&arm, "root_1");
253 BoneCollection *bcoll_r0_child0 = ANIM_armature_bonecoll_new(&arm, "r0_child0", 0);
254 BoneCollection *bcoll_r0_child1 = ANIM_armature_bonecoll_new(&arm, "r0_child1", 0);
255 BoneCollection *bcoll_r0_child2 = ANIM_armature_bonecoll_new(&arm, "r0_child2", 0);
256 BoneCollection *bcoll_r0c0_child0 = ANIM_armature_bonecoll_new(&arm, "r0c0_child0", 2);
257 BoneCollection *bcoll_r0c0_child1 = ANIM_armature_bonecoll_new(&arm, "r0c0_child1", 2);
258 BoneCollection *bcoll_r0c0_child2 = ANIM_armature_bonecoll_new(&arm, "r0c0_child2", 2);
259
260 ASSERT_EQ(2, arm.collection_root_count);
261 ASSERT_EQ(8, arm.collection_array_num);
262 ASSERT_STREQ(bcoll_root_0->name, arm.collection_array[0]->name);
263 ASSERT_STREQ(bcoll_root_1->name, arm.collection_array[1]->name);
264 ASSERT_STREQ(bcoll_r0_child0->name, arm.collection_array[2]->name); /* Children of root_0. */
265 ASSERT_STREQ(bcoll_r0_child1->name, arm.collection_array[3]->name);
266 ASSERT_STREQ(bcoll_r0_child2->name, arm.collection_array[4]->name);
267 ASSERT_STREQ(bcoll_r0c0_child0->name, arm.collection_array[5]->name); /* Kids of r0_child0. */
268 ASSERT_STREQ(bcoll_r0c0_child1->name, arm.collection_array[6]->name);
269 ASSERT_STREQ(bcoll_r0c0_child2->name, arm.collection_array[7]->name);
270
271 ASSERT_EQ(2, arm.collection_array[0]->child_index);
272 ASSERT_EQ(0, arm.collection_array[1]->child_index);
273 ASSERT_EQ(5, arm.collection_array[2]->child_index);
274 ASSERT_EQ(0, arm.collection_array[3]->child_index);
275 ASSERT_EQ(0, arm.collection_array[4]->child_index);
276 ASSERT_EQ(0, arm.collection_array[5]->child_index);
277 ASSERT_EQ(0, arm.collection_array[6]->child_index);
278 ASSERT_EQ(0, arm.collection_array[7]->child_index);
279
280 ASSERT_EQ(3, arm.collection_array[0]->child_count);
281 ASSERT_EQ(0, arm.collection_array[1]->child_count);
282 ASSERT_EQ(3, arm.collection_array[2]->child_count);
283 ASSERT_EQ(0, arm.collection_array[3]->child_count);
284 ASSERT_EQ(0, arm.collection_array[4]->child_count);
285 ASSERT_EQ(0, arm.collection_array[5]->child_count);
286 ASSERT_EQ(0, arm.collection_array[6]->child_count);
287 ASSERT_EQ(0, arm.collection_array[7]->child_count);
288
289 /* Remove bcoll_r0_child0, which should make all of its children a child of root_0. */
290 ANIM_armature_bonecoll_remove(&arm, bcoll_r0_child0);
291
292 ASSERT_EQ(2, arm.collection_root_count);
293 ASSERT_EQ(7, arm.collection_array_num);
294 EXPECT_STREQ(bcoll_root_0->name, arm.collection_array[0]->name);
295 EXPECT_STREQ(bcoll_root_1->name, arm.collection_array[1]->name);
296 EXPECT_STREQ(bcoll_r0c0_child0->name, arm.collection_array[2]->name); /* Children of root_0. */
297 EXPECT_STREQ(bcoll_r0c0_child1->name, arm.collection_array[3]->name);
298 EXPECT_STREQ(bcoll_r0c0_child2->name, arm.collection_array[4]->name);
299 EXPECT_STREQ(bcoll_r0_child1->name, arm.collection_array[5]->name);
300 EXPECT_STREQ(bcoll_r0_child2->name, arm.collection_array[6]->name);
301
302 EXPECT_EQ(2, arm.collection_array[0]->child_index);
303 EXPECT_EQ(0, arm.collection_array[1]->child_index);
304 EXPECT_EQ(0, arm.collection_array[2]->child_index);
305 EXPECT_EQ(0, arm.collection_array[3]->child_index);
306 EXPECT_EQ(0, arm.collection_array[4]->child_index);
307 EXPECT_EQ(0, arm.collection_array[5]->child_index);
308 EXPECT_EQ(0, arm.collection_array[6]->child_count);
309
310 EXPECT_EQ(5, arm.collection_array[0]->child_count);
311 EXPECT_EQ(0, arm.collection_array[1]->child_count);
312 EXPECT_EQ(0, arm.collection_array[2]->child_count);
313 EXPECT_EQ(0, arm.collection_array[3]->child_count);
314 EXPECT_EQ(0, arm.collection_array[4]->child_count);
315 EXPECT_EQ(0, arm.collection_array[5]->child_count);
316 EXPECT_EQ(0, arm.collection_array[6]->child_count);
317
318 /* Remove root_0, which should make all of its children new roots. */
319 ANIM_armature_bonecoll_remove(&arm, bcoll_root_0);
320
321 ASSERT_EQ(6, arm.collection_root_count);
322 ASSERT_EQ(6, arm.collection_array_num);
323 EXPECT_STREQ(bcoll_r0c0_child0->name, arm.collection_array[0]->name);
324 EXPECT_STREQ(bcoll_r0c0_child1->name, arm.collection_array[1]->name);
325 EXPECT_STREQ(bcoll_r0c0_child2->name, arm.collection_array[2]->name);
326 EXPECT_STREQ(bcoll_r0_child1->name, arm.collection_array[3]->name);
327 EXPECT_STREQ(bcoll_r0_child2->name, arm.collection_array[4]->name);
328 EXPECT_STREQ(bcoll_root_1->name, arm.collection_array[5]->name);
329
330 EXPECT_EQ(0, arm.collection_array[0]->child_index);
331 EXPECT_EQ(0, arm.collection_array[1]->child_index);
332 EXPECT_EQ(0, arm.collection_array[2]->child_index);
333 EXPECT_EQ(0, arm.collection_array[3]->child_index);
334 EXPECT_EQ(0, arm.collection_array[4]->child_index);
335 EXPECT_EQ(0, arm.collection_array[5]->child_index);
336
337 EXPECT_EQ(0, arm.collection_array[0]->child_count);
338 EXPECT_EQ(0, arm.collection_array[1]->child_count);
339 EXPECT_EQ(0, arm.collection_array[2]->child_count);
340 EXPECT_EQ(0, arm.collection_array[3]->child_count);
341 EXPECT_EQ(0, arm.collection_array[4]->child_count);
342 EXPECT_EQ(0, arm.collection_array[5]->child_count);
343}
344
345TEST_F(ArmatureBoneCollections, collection_hierarchy_removal__more_complex_remove_root)
346{
347 /* Set up a slightly bigger hierarchy. Contrary to the other tests these are
348 * actually declared in array order. */
349 BoneCollection *bcoll_root_0 = ANIM_armature_bonecoll_new(&arm, "root_0");
350 BoneCollection *bcoll_root_1 = ANIM_armature_bonecoll_new(&arm, "root_1");
351 BoneCollection *bcoll_r0_child0 = ANIM_armature_bonecoll_new(&arm, "r0_child0", 0);
352 BoneCollection *bcoll_r0_child1 = ANIM_armature_bonecoll_new(&arm, "r0_child1", 0);
353 BoneCollection *bcoll_r0_child2 = ANIM_armature_bonecoll_new(&arm, "r0_child2", 0);
354 BoneCollection *bcoll_r0c0_child0 = ANIM_armature_bonecoll_new(&arm, "r0c0_child0", 2);
355 BoneCollection *bcoll_r0c0_child1 = ANIM_armature_bonecoll_new(&arm, "r0c0_child1", 2);
356 BoneCollection *bcoll_r0c0_child2 = ANIM_armature_bonecoll_new(&arm, "r0c0_child2", 2);
357
358 ASSERT_EQ(2, arm.collection_root_count);
359 ASSERT_EQ(8, arm.collection_array_num);
360 ASSERT_STREQ(bcoll_root_0->name, arm.collection_array[0]->name);
361 ASSERT_STREQ(bcoll_root_1->name, arm.collection_array[1]->name);
362 ASSERT_STREQ(bcoll_r0_child0->name, arm.collection_array[2]->name); /* Children of root_0. */
363 ASSERT_STREQ(bcoll_r0_child1->name, arm.collection_array[3]->name);
364 ASSERT_STREQ(bcoll_r0_child2->name, arm.collection_array[4]->name);
365 ASSERT_STREQ(bcoll_r0c0_child0->name, arm.collection_array[5]->name); /* Kids of r0_child0. */
366 ASSERT_STREQ(bcoll_r0c0_child1->name, arm.collection_array[6]->name);
367 ASSERT_STREQ(bcoll_r0c0_child2->name, arm.collection_array[7]->name);
368
369 ASSERT_EQ(2, arm.collection_array[0]->child_index);
370 ASSERT_EQ(0, arm.collection_array[1]->child_index);
371 ASSERT_EQ(5, arm.collection_array[2]->child_index);
372 ASSERT_EQ(0, arm.collection_array[3]->child_index);
373 ASSERT_EQ(0, arm.collection_array[4]->child_index);
374 ASSERT_EQ(0, arm.collection_array[5]->child_index);
375 ASSERT_EQ(0, arm.collection_array[6]->child_index);
376 ASSERT_EQ(0, arm.collection_array[7]->child_index);
377
378 ASSERT_EQ(3, arm.collection_array[0]->child_count);
379 ASSERT_EQ(0, arm.collection_array[1]->child_count);
380 ASSERT_EQ(3, arm.collection_array[2]->child_count);
381 ASSERT_EQ(0, arm.collection_array[3]->child_count);
382 ASSERT_EQ(0, arm.collection_array[4]->child_count);
383 ASSERT_EQ(0, arm.collection_array[5]->child_count);
384 ASSERT_EQ(0, arm.collection_array[6]->child_count);
385 ASSERT_EQ(0, arm.collection_array[7]->child_count);
386
387 /* Remove root_0, which should make all of its children new roots. */
388 ANIM_armature_bonecoll_remove(&arm, bcoll_root_0);
389
390 ASSERT_EQ(4, arm.collection_root_count);
391 ASSERT_EQ(7, arm.collection_array_num);
392 ASSERT_STREQ(bcoll_r0_child0->name, arm.collection_array[0]->name);
393 ASSERT_STREQ(bcoll_r0_child1->name, arm.collection_array[1]->name);
394 ASSERT_STREQ(bcoll_r0_child2->name, arm.collection_array[2]->name);
395 ASSERT_STREQ(bcoll_root_1->name, arm.collection_array[3]->name);
396 ASSERT_STREQ(bcoll_r0c0_child0->name, arm.collection_array[4]->name); /* Kids of r0_child0. */
397 ASSERT_STREQ(bcoll_r0c0_child1->name, arm.collection_array[5]->name);
398 ASSERT_STREQ(bcoll_r0c0_child2->name, arm.collection_array[6]->name);
399
400 EXPECT_EQ(4, arm.collection_array[0]->child_index);
401 EXPECT_EQ(0, arm.collection_array[1]->child_index);
402 EXPECT_EQ(0, arm.collection_array[2]->child_index);
403 EXPECT_EQ(0, arm.collection_array[3]->child_index);
404 EXPECT_EQ(0, arm.collection_array[4]->child_index);
405 EXPECT_EQ(0, arm.collection_array[5]->child_index);
406 EXPECT_EQ(0, arm.collection_array[6]->child_count);
407
408 EXPECT_EQ(3, arm.collection_array[0]->child_count);
409 EXPECT_EQ(0, arm.collection_array[1]->child_count);
410 EXPECT_EQ(0, arm.collection_array[2]->child_count);
411 EXPECT_EQ(0, arm.collection_array[3]->child_count);
412 EXPECT_EQ(0, arm.collection_array[4]->child_count);
413 EXPECT_EQ(0, arm.collection_array[5]->child_count);
414 EXPECT_EQ(0, arm.collection_array[6]->child_count);
415}
416
418{
419 /* Set up a small hierarchy. */
420 BoneCollection *bcoll_root_0 = ANIM_armature_bonecoll_new(&arm, "root_0");
421 BoneCollection *bcoll_root_1 = ANIM_armature_bonecoll_new(&arm, "root_1");
422 BoneCollection *bcoll_r0_child0 = ANIM_armature_bonecoll_new(&arm, "r0_child0", 0);
423 BoneCollection *bcoll_r1_child0 = ANIM_armature_bonecoll_new(&arm, "r1_child0", 1);
424 BoneCollection *bcoll_r0_child1 = ANIM_armature_bonecoll_new(&arm, "r0_child1", 0);
425 BoneCollection *bcoll_r0c0_child0 = ANIM_armature_bonecoll_new(&arm, "r0c0_child0", 2);
426
427 ASSERT_EQ(2, arm.collection_root_count);
428 ASSERT_EQ(6, arm.collection_array_num);
429 ASSERT_STREQ(bcoll_root_0->name, arm.collection_array[0]->name);
430 ASSERT_STREQ(bcoll_root_1->name, arm.collection_array[1]->name);
431 ASSERT_STREQ(bcoll_r0_child0->name, arm.collection_array[2]->name);
432 ASSERT_STREQ(bcoll_r0_child1->name, arm.collection_array[3]->name);
433 ASSERT_STREQ(bcoll_r1_child0->name, arm.collection_array[4]->name);
434 ASSERT_STREQ(bcoll_r0c0_child0->name, arm.collection_array[5]->name);
435
436 ASSERT_EQ(2, arm.collection_array[0]->child_index);
437 ASSERT_EQ(4, arm.collection_array[1]->child_index);
438 ASSERT_EQ(5, arm.collection_array[2]->child_index);
439 ASSERT_EQ(0, arm.collection_array[3]->child_index);
440 ASSERT_EQ(0, arm.collection_array[4]->child_index);
441 ASSERT_EQ(0, arm.collection_array[5]->child_index);
442
443 ASSERT_EQ(2, arm.collection_array[0]->child_count);
444 ASSERT_EQ(1, arm.collection_array[1]->child_count);
445 ASSERT_EQ(1, arm.collection_array[2]->child_count);
446 ASSERT_EQ(0, arm.collection_array[3]->child_count);
447 ASSERT_EQ(0, arm.collection_array[4]->child_count);
448 ASSERT_EQ(0, arm.collection_array[5]->child_count);
449
452
459}
460
461TEST_F(ArmatureBoneCollections, collection_hierarchy_visibility)
462{
463 /* Set up a small hierarchy. */
464 BoneCollection *bcoll_root0 = ANIM_armature_bonecoll_new(&arm, "root0");
465 BoneCollection *bcoll_root1 = ANIM_armature_bonecoll_new(&arm, "root1");
466 const int root0_index = armature_bonecoll_find_index(&arm, bcoll_root0);
467 BoneCollection *bcoll_r0_child0 = ANIM_armature_bonecoll_new(&arm, "r0_child0", root0_index);
468 BoneCollection *bcoll_r0_child1 = ANIM_armature_bonecoll_new(&arm, "r0_child1", root0_index);
469 const int child0_index = armature_bonecoll_find_index(&arm, bcoll_r0_child0);
470 BoneCollection *bcoll_c0_child0 = ANIM_armature_bonecoll_new(&arm, "c0_child0", child0_index);
471
472 /* Initially, all bone collections should be marked as visible. */
473 EXPECT_TRUE(bcoll_root0->flags & BONE_COLLECTION_VISIBLE);
474 EXPECT_TRUE(bcoll_root1->flags & BONE_COLLECTION_VISIBLE);
475 EXPECT_TRUE(bcoll_r0_child0->flags & BONE_COLLECTION_VISIBLE);
476 EXPECT_TRUE(bcoll_r0_child1->flags & BONE_COLLECTION_VISIBLE);
477 EXPECT_TRUE(bcoll_c0_child0->flags & BONE_COLLECTION_VISIBLE);
478
479 /* Initially, all bone collections should have visible ancestors. */
480 EXPECT_TRUE(bcoll_root0->flags & BONE_COLLECTION_ANCESTORS_VISIBLE);
481 EXPECT_TRUE(bcoll_root1->flags & BONE_COLLECTION_ANCESTORS_VISIBLE);
482 EXPECT_TRUE(bcoll_r0_child0->flags & BONE_COLLECTION_ANCESTORS_VISIBLE);
483 EXPECT_TRUE(bcoll_r0_child1->flags & BONE_COLLECTION_ANCESTORS_VISIBLE);
484 EXPECT_TRUE(bcoll_c0_child0->flags & BONE_COLLECTION_ANCESTORS_VISIBLE);
485
486 /* Mark root_0 as invisible, this should also update its children. */
487 ANIM_bonecoll_hide(&arm, bcoll_root0);
488
489 EXPECT_FALSE(bcoll_root0->flags & BONE_COLLECTION_VISIBLE);
490 EXPECT_TRUE(bcoll_root1->flags & BONE_COLLECTION_VISIBLE);
491 EXPECT_TRUE(bcoll_r0_child0->flags & BONE_COLLECTION_VISIBLE);
492 EXPECT_TRUE(bcoll_r0_child1->flags & BONE_COLLECTION_VISIBLE);
493 EXPECT_TRUE(bcoll_c0_child0->flags & BONE_COLLECTION_VISIBLE);
494
495 EXPECT_TRUE(bcoll_root0->flags & BONE_COLLECTION_ANCESTORS_VISIBLE);
496 EXPECT_TRUE(bcoll_root1->flags & BONE_COLLECTION_ANCESTORS_VISIBLE);
497 EXPECT_FALSE(bcoll_r0_child0->flags & BONE_COLLECTION_ANCESTORS_VISIBLE);
498 EXPECT_FALSE(bcoll_r0_child1->flags & BONE_COLLECTION_ANCESTORS_VISIBLE);
499 EXPECT_FALSE(bcoll_c0_child0->flags & BONE_COLLECTION_ANCESTORS_VISIBLE);
500
501 /* Move r0_child0 to root1, that should change its BONE_COLLECTION_ANCESTORS_VISIBLE */
502 const int root1_index = armature_bonecoll_find_index(&arm, bcoll_root1);
503 armature_bonecoll_move_to_parent(&arm, child0_index, 0, root0_index, root1_index);
504
505 EXPECT_FALSE(bcoll_root0->flags & BONE_COLLECTION_VISIBLE);
506 EXPECT_TRUE(bcoll_root1->flags & BONE_COLLECTION_VISIBLE);
507 EXPECT_TRUE(bcoll_r0_child0->flags & BONE_COLLECTION_VISIBLE);
508 EXPECT_TRUE(bcoll_r0_child1->flags & BONE_COLLECTION_VISIBLE);
509 EXPECT_TRUE(bcoll_c0_child0->flags & BONE_COLLECTION_VISIBLE);
510
511 EXPECT_TRUE(bcoll_root0->flags & BONE_COLLECTION_ANCESTORS_VISIBLE);
512 EXPECT_TRUE(bcoll_root1->flags & BONE_COLLECTION_ANCESTORS_VISIBLE);
513 EXPECT_TRUE(bcoll_r0_child0->flags & BONE_COLLECTION_ANCESTORS_VISIBLE)
514 << "The child that was moved to a visible root should be affected";
515 EXPECT_FALSE(bcoll_r0_child1->flags & BONE_COLLECTION_ANCESTORS_VISIBLE)
516 << "The child that wasn't moved should not be affected.";
517 EXPECT_TRUE(bcoll_c0_child0->flags & BONE_COLLECTION_ANCESTORS_VISIBLE)
518 << "The grandchild that was indirectly moved to a visible root should be affected";
519
520 /* Add a new child to root0, it should have the right flags. */
521 BoneCollection *bcoll_r0_child2 = ANIM_armature_bonecoll_new(&arm, "r0_child2", root0_index);
522 EXPECT_TRUE(bcoll_r0_child2->flags & BONE_COLLECTION_VISIBLE);
523 EXPECT_FALSE(bcoll_r0_child2->flags & BONE_COLLECTION_ANCESTORS_VISIBLE);
524}
525
526TEST_F(ArmatureBoneCollections, bones_assign_unassign)
527{
528 BoneCollection *bcoll = ANIM_armature_bonecoll_new(&arm, "collection");
529
530 ANIM_armature_bonecoll_assign(bcoll, &bone1);
531 ANIM_armature_bonecoll_assign(bcoll, &bone2);
532
533 ASSERT_EQ(2, BLI_listbase_count(&bcoll->bones)) << "expecting two bones in collection";
534 EXPECT_EQ(&bone1, static_cast<BoneCollectionMember *>(BLI_findlink(&bcoll->bones, 0))->bone);
535 EXPECT_EQ(&bone2, static_cast<BoneCollectionMember *>(BLI_findlink(&bcoll->bones, 1))->bone);
536
537 EXPECT_EQ(bcoll, static_cast<BoneCollectionReference *>(bone1.runtime.collections.first)->bcoll)
538 << "expecting back-reference to collection in bone1 runtime data";
539 EXPECT_EQ(bcoll, static_cast<BoneCollectionReference *>(bone2.runtime.collections.first)->bcoll)
540 << "expecting back-reference to collection in bone2 runtime data";
541
542 ANIM_armature_bonecoll_unassign(bcoll, &bone1);
543 ANIM_armature_bonecoll_unassign(bcoll, &bone2);
544
545 EXPECT_EQ(0, BLI_listbase_count(&bone1.runtime.collections))
546 << "expecting back-references in bone1 runtime data to be cleared when unassigned";
547 EXPECT_EQ(0, BLI_listbase_count(&bone2.runtime.collections))
548 << "expecting back-references in bone2 runtime data to be cleared when unassigned";
549
551}
552
553TEST_F(ArmatureBoneCollections, bones_assign_remove)
554{
555 BoneCollection *bcoll = ANIM_armature_bonecoll_new(&arm, "collection");
556
557 ANIM_armature_bonecoll_assign(bcoll, &bone1);
558 ANIM_armature_bonecoll_assign(bcoll, &bone2);
560
561 EXPECT_EQ(0, BLI_listbase_count(&bone1.runtime.collections))
562 << "expecting back-references in bone1 runtime data to be cleared when the collection is "
563 "removed";
564 EXPECT_EQ(0, BLI_listbase_count(&bone2.runtime.collections))
565 << "expecting back-references in bone2 runtime data to be cleared when the collection is "
566 "removed";
567}
568
569TEST_F(ArmatureBoneCollections, active_set_clear_by_pointer)
570{
571 BoneCollection *bcoll1 = ANIM_armature_bonecoll_new(&arm, "Bones 1");
572 BoneCollection *bcoll2 = ANIM_armature_bonecoll_new(&arm, "Bones 2");
573 BoneCollection *bcoll3 = ANIM_bonecoll_new("Alien Bones");
574
576 EXPECT_EQ(0, arm.runtime.active_collection_index);
577 EXPECT_EQ(bcoll1, arm.runtime.active_collection);
578 EXPECT_STREQ(bcoll1->name, arm.active_collection_name);
579
581 EXPECT_EQ(-1, arm.runtime.active_collection_index);
582 EXPECT_EQ(nullptr, arm.runtime.active_collection);
583 EXPECT_STREQ("", arm.active_collection_name);
584
586 EXPECT_EQ(1, arm.runtime.active_collection_index);
587 EXPECT_EQ(bcoll2, arm.runtime.active_collection);
588 EXPECT_STREQ(bcoll2->name, arm.active_collection_name);
589
591 EXPECT_EQ(-1, arm.runtime.active_collection_index);
592 EXPECT_EQ(nullptr, arm.runtime.active_collection);
593 EXPECT_STREQ("", arm.active_collection_name);
594
595 ANIM_bonecoll_free(bcoll3);
596}
597
598TEST_F(ArmatureBoneCollections, active_set_clear_by_index)
599{
600 BoneCollection *bcoll1 = ANIM_armature_bonecoll_new(&arm, "Bones 1");
601 BoneCollection *bcoll2 = ANIM_armature_bonecoll_new(&arm, "Bones 2");
602
604 EXPECT_EQ(0, arm.runtime.active_collection_index);
605 EXPECT_EQ(bcoll1, arm.runtime.active_collection);
606 EXPECT_STREQ(bcoll1->name, arm.active_collection_name);
607
609 EXPECT_EQ(-1, arm.runtime.active_collection_index);
610 EXPECT_EQ(nullptr, arm.runtime.active_collection);
611 EXPECT_STREQ("", arm.active_collection_name);
612
614 EXPECT_EQ(1, arm.runtime.active_collection_index);
615 EXPECT_EQ(bcoll2, arm.runtime.active_collection);
616 EXPECT_STREQ(bcoll2->name, arm.active_collection_name);
617
619 EXPECT_EQ(-1, arm.runtime.active_collection_index);
620 EXPECT_EQ(nullptr, arm.runtime.active_collection);
621 EXPECT_STREQ("", arm.active_collection_name);
622}
623
625{
626 BoneCollection *bcoll1 = ANIM_armature_bonecoll_new(&arm, "Bones 1");
627 BoneCollection *bcoll2 = ANIM_armature_bonecoll_new(&arm, "Bones 2");
628
631
632 EXPECT_TRUE(ANIM_armature_bonecoll_is_editable(&arm, bcoll1))
633 << "Expecting local armature to be editable";
634
635 /* Fake that the armature is linked from another blend file. */
636 Library fake_lib = {};
637 arm.id.lib = &fake_lib;
638 EXPECT_FALSE(ANIM_armature_bonecoll_is_editable(&arm, bcoll1))
639 << "Expecting local armature to not be editable";
640
641 /* Fake that the armature is an override, but linked from another blend file. */
642 IDOverrideLibrary fake_override = {};
643 bArmature fake_reference = {};
644 fake_override.reference = &fake_reference.id;
645 arm.id.override_library = &fake_override;
646 EXPECT_FALSE(ANIM_armature_bonecoll_is_editable(&arm, bcoll1))
647 << "Expecting linked armature override to not be editable";
648
649 /* Fake that the armature is a local override. */
650 arm.id.lib = nullptr;
652 EXPECT_FALSE(ANIM_armature_bonecoll_is_editable(&arm, bcoll1))
653 << "Expecting linked bone collection on local armature override to not be editable";
654 EXPECT_TRUE(ANIM_armature_bonecoll_is_editable(&arm, bcoll2))
655 << "Expecting local bone collection on local armature override to be editable";
656}
657
658TEST_F(ArmatureBoneCollections, bcoll_move_to_index__roots)
659{
660 BoneCollection *bcoll1 = ANIM_armature_bonecoll_new(&arm, "collection");
661 BoneCollection *bcoll2 = ANIM_armature_bonecoll_new(&arm, "collection");
662 BoneCollection *bcoll3 = ANIM_armature_bonecoll_new(&arm, "collection");
663 BoneCollection *bcoll4 = ANIM_armature_bonecoll_new(&arm, "collection");
664
665 EXPECT_EQ(arm.collection_array[0], bcoll1);
666 EXPECT_EQ(arm.collection_array[1], bcoll2);
667 EXPECT_EQ(arm.collection_array[2], bcoll3);
668 EXPECT_EQ(arm.collection_array[3], bcoll4);
669
670 EXPECT_TRUE(ANIM_armature_bonecoll_move_to_index(&arm, 2, 1));
671
672 EXPECT_EQ(arm.collection_array[0], bcoll1);
673 EXPECT_EQ(arm.collection_array[1], bcoll3);
674 EXPECT_EQ(arm.collection_array[2], bcoll2);
675 EXPECT_EQ(arm.collection_array[3], bcoll4);
676
677 EXPECT_TRUE(ANIM_armature_bonecoll_move_to_index(&arm, 0, 3));
678
679 EXPECT_EQ(arm.collection_array[0], bcoll3);
680 EXPECT_EQ(arm.collection_array[1], bcoll2);
681 EXPECT_EQ(arm.collection_array[2], bcoll4);
682 EXPECT_EQ(arm.collection_array[3], bcoll1);
683
684 /* Out of bounds should not be accepted. */
685 EXPECT_FALSE(ANIM_armature_bonecoll_move_to_index(&arm, 0, 327));
686
687 EXPECT_EQ(arm.collection_array[0], bcoll3);
688 EXPECT_EQ(arm.collection_array[1], bcoll2);
689 EXPECT_EQ(arm.collection_array[2], bcoll4);
690 EXPECT_EQ(arm.collection_array[3], bcoll1);
691}
692
693TEST_F(ArmatureBoneCollections, bcoll_move_to_index__siblings)
694{
695 BoneCollection *root = ANIM_armature_bonecoll_new(&arm, "root");
696 BoneCollection *child0 = ANIM_armature_bonecoll_new(&arm, "child0", 0);
697 BoneCollection *child1 = ANIM_armature_bonecoll_new(&arm, "child1", 0);
698 BoneCollection *child2 = ANIM_armature_bonecoll_new(&arm, "child2", 0);
699 BoneCollection *child1_0 = ANIM_armature_bonecoll_new(&arm, "child1_0", 2);
700
701 ASSERT_STREQ(root->name, arm.collection_array[0]->name);
702 ASSERT_STREQ(child0->name, arm.collection_array[1]->name);
703 ASSERT_STREQ(child1->name, arm.collection_array[2]->name);
704 ASSERT_STREQ(child2->name, arm.collection_array[3]->name);
705 ASSERT_STREQ(child1_0->name, arm.collection_array[4]->name);
706
707 /* Move child2 to child0, i.e. a move 'to the left'. */
708 EXPECT_TRUE(ANIM_armature_bonecoll_move_to_index(&arm, 3, 1));
709
710 EXPECT_STREQ(root->name, arm.collection_array[0]->name);
711 EXPECT_STREQ(child2->name, arm.collection_array[1]->name);
712 EXPECT_STREQ(child0->name, arm.collection_array[2]->name);
713 EXPECT_STREQ(child1->name, arm.collection_array[3]->name);
714 EXPECT_STREQ(child1_0->name, arm.collection_array[4]->name);
715
716 /* Move child2 to child1, i.e. a move 'to the right'. */
717 EXPECT_TRUE(ANIM_armature_bonecoll_move_to_index(&arm, 1, 3));
718
719 EXPECT_STREQ(root->name, arm.collection_array[0]->name);
720 EXPECT_STREQ(child0->name, arm.collection_array[1]->name);
721 EXPECT_STREQ(child1->name, arm.collection_array[2]->name);
722 EXPECT_STREQ(child2->name, arm.collection_array[3]->name);
723 EXPECT_STREQ(child1_0->name, arm.collection_array[4]->name);
724
725 /* Move child2 to root, should not be allowed. */
726 EXPECT_FALSE(ANIM_armature_bonecoll_move_to_index(&arm, 3, 0));
727
728 EXPECT_STREQ(root->name, arm.collection_array[0]->name);
729 EXPECT_STREQ(child0->name, arm.collection_array[1]->name);
730 EXPECT_STREQ(child1->name, arm.collection_array[2]->name);
731 EXPECT_STREQ(child2->name, arm.collection_array[3]->name);
732 EXPECT_STREQ(child1_0->name, arm.collection_array[4]->name);
733
734 /* Move child1_0 to child_2, should not be allowed. */
735 EXPECT_FALSE(ANIM_armature_bonecoll_move_to_index(&arm, 4, 3));
736
737 EXPECT_STREQ(root->name, arm.collection_array[0]->name);
738 EXPECT_STREQ(child0->name, arm.collection_array[1]->name);
739 EXPECT_STREQ(child1->name, arm.collection_array[2]->name);
740 EXPECT_STREQ(child2->name, arm.collection_array[3]->name);
741 EXPECT_STREQ(child1_0->name, arm.collection_array[4]->name);
742}
743
744TEST_F(ArmatureBoneCollections, bcoll_move_to_parent)
745{
746 /* Set up a small hierarchy. */
747 BoneCollection *bcoll_root_0 = ANIM_armature_bonecoll_new(&arm, "root_0");
748 BoneCollection *bcoll_root_1 = ANIM_armature_bonecoll_new(&arm, "root_1");
749 BoneCollection *bcoll_r0_child0 = ANIM_armature_bonecoll_new(&arm, "r0_child0", 0);
750 BoneCollection *bcoll_r1_child0 = ANIM_armature_bonecoll_new(&arm, "r1_child0", 1);
751 BoneCollection *bcoll_r0_child1 = ANIM_armature_bonecoll_new(&arm, "r0_child1", 0);
752 BoneCollection *bcoll_r0_child2 = ANIM_armature_bonecoll_new(&arm, "r0_child2", 0);
753
754 ASSERT_EQ(2, arm.collection_root_count);
755 ASSERT_EQ(6, arm.collection_array_num);
756 ASSERT_STREQ(bcoll_root_0->name, arm.collection_array[0]->name);
757 ASSERT_STREQ(bcoll_root_1->name, arm.collection_array[1]->name);
758 ASSERT_STREQ(bcoll_r0_child0->name, arm.collection_array[2]->name);
759 ASSERT_STREQ(bcoll_r0_child1->name, arm.collection_array[3]->name);
760 ASSERT_STREQ(bcoll_r0_child2->name, arm.collection_array[4]->name);
761 ASSERT_STREQ(bcoll_r1_child0->name, arm.collection_array[5]->name);
762
763 ASSERT_EQ(2, arm.collection_array[0]->child_index);
764 ASSERT_EQ(5, arm.collection_array[1]->child_index);
765 ASSERT_EQ(0, arm.collection_array[2]->child_index);
766 ASSERT_EQ(0, arm.collection_array[3]->child_index);
767 ASSERT_EQ(0, arm.collection_array[4]->child_index);
768 ASSERT_EQ(0, arm.collection_array[5]->child_index);
769
770 ASSERT_EQ(3, arm.collection_array[0]->child_count);
771 ASSERT_EQ(1, arm.collection_array[1]->child_count);
772 ASSERT_EQ(0, arm.collection_array[2]->child_count);
773 ASSERT_EQ(0, arm.collection_array[3]->child_count);
774 ASSERT_EQ(0, arm.collection_array[4]->child_count);
775 ASSERT_EQ(0, arm.collection_array[5]->child_count);
776
777 /* Move the middle child of root_0 to root_1. */
778 EXPECT_EQ(5, armature_bonecoll_move_to_parent(&arm, 3, bcoll_root_1->child_count, 0, 1));
779
780 ASSERT_EQ(2, arm.collection_root_count);
781 ASSERT_EQ(6, arm.collection_array_num);
782 EXPECT_STREQ(bcoll_root_0->name, arm.collection_array[0]->name);
783 EXPECT_STREQ(bcoll_root_1->name, arm.collection_array[1]->name);
784 EXPECT_STREQ(bcoll_r0_child0->name, arm.collection_array[2]->name);
785 EXPECT_STREQ(bcoll_r0_child2->name, arm.collection_array[3]->name);
786 EXPECT_STREQ(bcoll_r1_child0->name, arm.collection_array[4]->name);
787 EXPECT_STREQ(bcoll_r0_child1->name, arm.collection_array[5]->name);
788
789 EXPECT_EQ(2, arm.collection_array[0]->child_index);
790 EXPECT_EQ(4, arm.collection_array[1]->child_index);
791 EXPECT_EQ(0, arm.collection_array[2]->child_index);
792 EXPECT_EQ(0, arm.collection_array[3]->child_index);
793 EXPECT_EQ(0, arm.collection_array[4]->child_index);
794 EXPECT_EQ(0, arm.collection_array[5]->child_index);
795
796 EXPECT_EQ(2, arm.collection_array[0]->child_count);
797 EXPECT_EQ(2, arm.collection_array[1]->child_count);
798 EXPECT_EQ(0, arm.collection_array[2]->child_count);
799 EXPECT_EQ(0, arm.collection_array[3]->child_count);
800 EXPECT_EQ(0, arm.collection_array[4]->child_count);
801 EXPECT_EQ(0, arm.collection_array[5]->child_count);
802
803 /* Move the first child of root_1 to root_0. This shouldn't change its index. */
804 EXPECT_EQ(4, armature_bonecoll_move_to_parent(&arm, 4, bcoll_root_0->child_count, 1, 0));
805
806 ASSERT_EQ(2, arm.collection_root_count);
807 ASSERT_EQ(6, arm.collection_array_num);
808 EXPECT_STREQ(bcoll_root_0->name, arm.collection_array[0]->name);
809 EXPECT_STREQ(bcoll_root_1->name, arm.collection_array[1]->name);
810 EXPECT_STREQ(bcoll_r0_child0->name, arm.collection_array[2]->name);
811 EXPECT_STREQ(bcoll_r0_child2->name, arm.collection_array[3]->name);
812 EXPECT_STREQ(bcoll_r1_child0->name, arm.collection_array[4]->name);
813 EXPECT_STREQ(bcoll_r0_child1->name, arm.collection_array[5]->name);
814
815 EXPECT_EQ(2, arm.collection_array[0]->child_index);
816 EXPECT_EQ(5, arm.collection_array[1]->child_index);
817 EXPECT_EQ(0, arm.collection_array[2]->child_index);
818 EXPECT_EQ(0, arm.collection_array[3]->child_index);
819 EXPECT_EQ(0, arm.collection_array[4]->child_index);
820 EXPECT_EQ(0, arm.collection_array[5]->child_index);
821
822 EXPECT_EQ(3, arm.collection_array[0]->child_count);
823 EXPECT_EQ(1, arm.collection_array[1]->child_count);
824 EXPECT_EQ(0, arm.collection_array[2]->child_count);
825 EXPECT_EQ(0, arm.collection_array[3]->child_count);
826 EXPECT_EQ(0, arm.collection_array[4]->child_count);
827 EXPECT_EQ(0, arm.collection_array[5]->child_count);
828
829 /* Move the final child of root_1 to root_0. This shouldn't change its index
830 * again, but leave root_1 without children. */
831 EXPECT_EQ(5, armature_bonecoll_move_to_parent(&arm, 5, bcoll_root_0->child_count, 1, 0));
832
833 ASSERT_EQ(2, arm.collection_root_count);
834 ASSERT_EQ(6, arm.collection_array_num);
835 EXPECT_STREQ(bcoll_root_0->name, arm.collection_array[0]->name);
836 EXPECT_STREQ(bcoll_root_1->name, arm.collection_array[1]->name);
837 EXPECT_STREQ(bcoll_r0_child0->name, arm.collection_array[2]->name);
838 EXPECT_STREQ(bcoll_r0_child2->name, arm.collection_array[3]->name);
839 EXPECT_STREQ(bcoll_r1_child0->name, arm.collection_array[4]->name);
840 EXPECT_STREQ(bcoll_r0_child1->name, arm.collection_array[5]->name);
841
842 EXPECT_EQ(2, arm.collection_array[0]->child_index);
843 EXPECT_EQ(0, arm.collection_array[1]->child_index);
844 EXPECT_EQ(0, arm.collection_array[2]->child_index);
845 EXPECT_EQ(0, arm.collection_array[3]->child_index);
846 EXPECT_EQ(0, arm.collection_array[4]->child_index);
847 EXPECT_EQ(0, arm.collection_array[5]->child_index);
848
849 EXPECT_EQ(4, arm.collection_array[0]->child_count);
850 EXPECT_EQ(0, arm.collection_array[1]->child_count);
851 EXPECT_EQ(0, arm.collection_array[2]->child_count);
852 EXPECT_EQ(0, arm.collection_array[3]->child_count);
853 EXPECT_EQ(0, arm.collection_array[4]->child_count);
854 EXPECT_EQ(0, arm.collection_array[5]->child_count);
855
856 /* Move the first child of root_0 (bcoll_r0_child0) to bcoll_r0_child2. */
857 EXPECT_EQ(5, armature_bonecoll_move_to_parent(&arm, 2, bcoll_r0_child2->child_count, 0, 3));
858
859 ASSERT_EQ(2, arm.collection_root_count);
860 ASSERT_EQ(6, arm.collection_array_num);
861 EXPECT_STREQ(bcoll_root_0->name, arm.collection_array[0]->name);
862 EXPECT_STREQ(bcoll_root_1->name, arm.collection_array[1]->name);
863 EXPECT_STREQ(bcoll_r0_child2->name, arm.collection_array[2]->name);
864 EXPECT_STREQ(bcoll_r1_child0->name, arm.collection_array[3]->name);
865 EXPECT_STREQ(bcoll_r0_child1->name, arm.collection_array[4]->name);
866 EXPECT_STREQ(bcoll_r0_child0->name, arm.collection_array[5]->name);
867
868 EXPECT_EQ(2, arm.collection_array[0]->child_index);
869 EXPECT_EQ(0, arm.collection_array[1]->child_index);
870 EXPECT_EQ(5, arm.collection_array[2]->child_index);
871 EXPECT_EQ(0, arm.collection_array[3]->child_index);
872 EXPECT_EQ(0, arm.collection_array[4]->child_index);
873 EXPECT_EQ(0, arm.collection_array[5]->child_index);
874
875 EXPECT_EQ(3, arm.collection_array[0]->child_count);
876 EXPECT_EQ(0, arm.collection_array[1]->child_count);
877 EXPECT_EQ(1, arm.collection_array[2]->child_count);
878 EXPECT_EQ(0, arm.collection_array[3]->child_count);
879 EXPECT_EQ(0, arm.collection_array[4]->child_count);
880 EXPECT_EQ(0, arm.collection_array[5]->child_count);
881}
882
883TEST_F(ArmatureBoneCollections, bcoll_move_to_parent__root_unroot)
884{
885 /* Set up a small hierarchy. */
886 BoneCollection *bcoll_root_0 = ANIM_armature_bonecoll_new(&arm, "root_0");
887 BoneCollection *bcoll_root_1 = ANIM_armature_bonecoll_new(&arm, "root_1");
888 BoneCollection *bcoll_r0_child0 = ANIM_armature_bonecoll_new(&arm, "r0_child0", 0);
889 BoneCollection *bcoll_r1_child0 = ANIM_armature_bonecoll_new(&arm, "r1_child0", 1);
890 BoneCollection *bcoll_r0_child1 = ANIM_armature_bonecoll_new(&arm, "r0_child1", 0);
891 BoneCollection *bcoll_r0_child2 = ANIM_armature_bonecoll_new(&arm, "r0_child2", 0);
892
893 ASSERT_EQ(2, arm.collection_root_count);
894 ASSERT_EQ(6, arm.collection_array_num);
895 ASSERT_STREQ(bcoll_root_0->name, arm.collection_array[0]->name);
896 ASSERT_STREQ(bcoll_root_1->name, arm.collection_array[1]->name);
897 ASSERT_STREQ(bcoll_r0_child0->name, arm.collection_array[2]->name);
898 ASSERT_STREQ(bcoll_r0_child1->name, arm.collection_array[3]->name);
899 ASSERT_STREQ(bcoll_r0_child2->name, arm.collection_array[4]->name);
900 ASSERT_STREQ(bcoll_r1_child0->name, arm.collection_array[5]->name);
901
902 ASSERT_EQ(2, arm.collection_array[0]->child_index);
903 ASSERT_EQ(5, arm.collection_array[1]->child_index);
904 ASSERT_EQ(0, arm.collection_array[2]->child_index);
905 ASSERT_EQ(0, arm.collection_array[3]->child_index);
906 ASSERT_EQ(0, arm.collection_array[4]->child_index);
907 ASSERT_EQ(0, arm.collection_array[5]->child_index);
908
909 ASSERT_EQ(3, arm.collection_array[0]->child_count);
910 ASSERT_EQ(1, arm.collection_array[1]->child_count);
911 ASSERT_EQ(0, arm.collection_array[2]->child_count);
912 ASSERT_EQ(0, arm.collection_array[3]->child_count);
913 ASSERT_EQ(0, arm.collection_array[4]->child_count);
914 ASSERT_EQ(0, arm.collection_array[5]->child_count);
915
916 /* Make a leaf node (bcoll_r0_child1) a root. */
917 EXPECT_EQ(2, armature_bonecoll_move_to_parent(&arm, 3, arm.collection_root_count, 0, -1));
918
919 ASSERT_EQ(3, arm.collection_root_count);
920 ASSERT_EQ(6, arm.collection_array_num);
921 EXPECT_STREQ(bcoll_root_0->name, arm.collection_array[0]->name);
922 EXPECT_STREQ(bcoll_root_1->name, arm.collection_array[1]->name);
923 EXPECT_STREQ(bcoll_r0_child1->name, arm.collection_array[2]->name); /* Became a root. */
924 EXPECT_STREQ(bcoll_r0_child0->name, arm.collection_array[3]->name);
925 EXPECT_STREQ(bcoll_r0_child2->name, arm.collection_array[4]->name);
926 EXPECT_STREQ(bcoll_r1_child0->name, arm.collection_array[5]->name);
927
928 EXPECT_EQ(3, arm.collection_array[0]->child_index);
929 EXPECT_EQ(5, arm.collection_array[1]->child_index);
930 EXPECT_EQ(0, arm.collection_array[2]->child_index);
931 EXPECT_EQ(0, arm.collection_array[3]->child_index);
932 EXPECT_EQ(0, arm.collection_array[4]->child_index);
933 EXPECT_EQ(0, arm.collection_array[5]->child_index);
934
935 EXPECT_EQ(2, arm.collection_array[0]->child_count);
936 EXPECT_EQ(1, arm.collection_array[1]->child_count);
937 EXPECT_EQ(0, arm.collection_array[2]->child_count);
938 EXPECT_EQ(0, arm.collection_array[3]->child_count);
939 EXPECT_EQ(0, arm.collection_array[4]->child_count);
940 EXPECT_EQ(0, arm.collection_array[5]->child_count);
941
942 /* Make a root node (root_1) a child of root_0. */
943 EXPECT_EQ(4, armature_bonecoll_move_to_parent(&arm, 1, bcoll_root_0->child_count, -1, 0));
944
945 ASSERT_EQ(2, arm.collection_root_count);
946 ASSERT_EQ(6, arm.collection_array_num);
947 EXPECT_STREQ(bcoll_root_0->name, arm.collection_array[0]->name);
948 EXPECT_STREQ(bcoll_r0_child1->name, arm.collection_array[1]->name); /* Actually a root. */
949 EXPECT_STREQ(bcoll_r0_child0->name, arm.collection_array[2]->name);
950 EXPECT_STREQ(bcoll_r0_child2->name, arm.collection_array[3]->name);
951 EXPECT_STREQ(bcoll_root_1->name, arm.collection_array[4]->name); /* Became a child. */
952 EXPECT_STREQ(bcoll_r1_child0->name, arm.collection_array[5]->name);
953
954 EXPECT_EQ(2, arm.collection_array[0]->child_index);
955 EXPECT_EQ(0, arm.collection_array[1]->child_index);
956 EXPECT_EQ(0, arm.collection_array[2]->child_index);
957 EXPECT_EQ(0, arm.collection_array[3]->child_index);
958 EXPECT_EQ(5, arm.collection_array[4]->child_index);
959 EXPECT_EQ(0, arm.collection_array[5]->child_index);
960
961 EXPECT_EQ(3, arm.collection_array[0]->child_count);
962 EXPECT_EQ(0, arm.collection_array[1]->child_count);
963 EXPECT_EQ(0, arm.collection_array[2]->child_count);
964 EXPECT_EQ(0, arm.collection_array[3]->child_count);
965 EXPECT_EQ(1, arm.collection_array[4]->child_count);
966 EXPECT_EQ(0, arm.collection_array[5]->child_count);
967
968 /* TODO: test with circular parenthood. */
969}
970
971TEST_F(ArmatureBoneCollections, bcoll_move_to_parent__within_siblings)
972{
973 /* Set up a small hierarchy. */
974 auto *bcoll_root_0 = ANIM_armature_bonecoll_new(&arm, "root_0");
975 auto *bcoll_root_1 = ANIM_armature_bonecoll_new(&arm, "root_1");
976 auto *bcoll_r1_child0 = ANIM_armature_bonecoll_new(&arm, "r1_child0", 1);
977 auto *bcoll_r0_child0 = ANIM_armature_bonecoll_new(&arm, "r0_child0", 0);
978 auto *bcoll_r0_child1 = ANIM_armature_bonecoll_new(&arm, "r0_child1", 0);
979 auto *bcoll_r0_child2 = ANIM_armature_bonecoll_new(&arm, "r0_child2", 0);
980 auto *bcoll_r0_child3 = ANIM_armature_bonecoll_new(&arm, "r0_child3", 0);
981
982 ASSERT_EQ(2, arm.collection_root_count);
983 ASSERT_EQ(7, arm.collection_array_num);
984 ASSERT_STREQ(bcoll_root_0->name, arm.collection_array[0]->name);
985 ASSERT_STREQ(bcoll_root_1->name, arm.collection_array[1]->name);
986 ASSERT_STREQ(bcoll_r1_child0->name, arm.collection_array[2]->name); /* Children root_1. */
987 ASSERT_STREQ(bcoll_r0_child0->name, arm.collection_array[3]->name); /* Children root_0. */
988 ASSERT_STREQ(bcoll_r0_child1->name, arm.collection_array[4]->name);
989 ASSERT_STREQ(bcoll_r0_child2->name, arm.collection_array[5]->name);
990 ASSERT_STREQ(bcoll_r0_child3->name, arm.collection_array[6]->name);
991
992 ASSERT_EQ(3, arm.collection_array[0]->child_index);
993 ASSERT_EQ(2, arm.collection_array[1]->child_index);
994 ASSERT_EQ(0, arm.collection_array[2]->child_index);
995 ASSERT_EQ(0, arm.collection_array[3]->child_index);
996 ASSERT_EQ(0, arm.collection_array[4]->child_index);
997 ASSERT_EQ(0, arm.collection_array[5]->child_index);
998 ASSERT_EQ(0, arm.collection_array[6]->child_index);
999
1000 ASSERT_EQ(4, arm.collection_array[0]->child_count);
1001 ASSERT_EQ(1, arm.collection_array[1]->child_count);
1002 ASSERT_EQ(0, arm.collection_array[2]->child_count);
1003 ASSERT_EQ(0, arm.collection_array[3]->child_count);
1004 ASSERT_EQ(0, arm.collection_array[4]->child_count);
1005 ASSERT_EQ(0, arm.collection_array[5]->child_count);
1006 ASSERT_EQ(0, arm.collection_array[6]->child_count);
1007
1008 /* First half of the test, move 3 children from root_1 to root_0. */
1009
1010 /* Move r0_child0 to become 1st child of root_1, before r1_child0. */
1011 EXPECT_EQ(2,
1013 3, /* From index. */
1014 0, /* To child number. */
1015 0, /* From parent. */
1016 1 /* To parent. */
1017 ));
1018
1019 ASSERT_EQ(2, arm.collection_root_count);
1020 ASSERT_EQ(7, arm.collection_array_num);
1021 EXPECT_STREQ(bcoll_root_0->name, arm.collection_array[0]->name);
1022 EXPECT_STREQ(bcoll_root_1->name, arm.collection_array[1]->name);
1023 EXPECT_STREQ(bcoll_r0_child0->name, arm.collection_array[2]->name); /* Children root_1. */
1024 EXPECT_STREQ(bcoll_r1_child0->name, arm.collection_array[3]->name);
1025 EXPECT_STREQ(bcoll_r0_child1->name, arm.collection_array[4]->name); /* Children root_0. */
1026 EXPECT_STREQ(bcoll_r0_child2->name, arm.collection_array[5]->name);
1027 EXPECT_STREQ(bcoll_r0_child3->name, arm.collection_array[6]->name);
1028
1029 EXPECT_EQ(4, arm.collection_array[0]->child_index);
1030 EXPECT_EQ(2, arm.collection_array[1]->child_index);
1031 EXPECT_EQ(0, arm.collection_array[2]->child_index);
1032 EXPECT_EQ(0, arm.collection_array[3]->child_index);
1033 EXPECT_EQ(0, arm.collection_array[4]->child_index);
1034 EXPECT_EQ(0, arm.collection_array[5]->child_index);
1035 EXPECT_EQ(0, arm.collection_array[6]->child_index);
1036
1037 EXPECT_EQ(3, arm.collection_array[0]->child_count);
1038 EXPECT_EQ(2, arm.collection_array[1]->child_count);
1039 EXPECT_EQ(0, arm.collection_array[2]->child_count);
1040 EXPECT_EQ(0, arm.collection_array[3]->child_count);
1041 EXPECT_EQ(0, arm.collection_array[4]->child_count);
1042 EXPECT_EQ(0, arm.collection_array[5]->child_count);
1043 EXPECT_EQ(0, arm.collection_array[6]->child_count);
1044
1045 /* Move r0_child1 to become the 2nd child of root_1. */
1046 EXPECT_EQ(3,
1048 4, /* From index. */
1049 1, /* To child number. */
1050 0, /* From parent. */
1051 1 /* To parent. */
1052 ));
1053
1054 ASSERT_EQ(2, arm.collection_root_count);
1055 ASSERT_EQ(7, arm.collection_array_num);
1056 EXPECT_STREQ(bcoll_root_0->name, arm.collection_array[0]->name);
1057 EXPECT_STREQ(bcoll_root_1->name, arm.collection_array[1]->name);
1058 EXPECT_STREQ(bcoll_r0_child0->name, arm.collection_array[2]->name); /* Children root_1. */
1059 EXPECT_STREQ(bcoll_r0_child1->name, arm.collection_array[3]->name);
1060 EXPECT_STREQ(bcoll_r1_child0->name, arm.collection_array[4]->name);
1061 EXPECT_STREQ(bcoll_r0_child2->name, arm.collection_array[5]->name); /* Children root_0. */
1062 EXPECT_STREQ(bcoll_r0_child3->name, arm.collection_array[6]->name);
1063
1064 EXPECT_EQ(5, arm.collection_array[0]->child_index);
1065 EXPECT_EQ(2, arm.collection_array[1]->child_index);
1066 EXPECT_EQ(0, arm.collection_array[2]->child_index);
1067 EXPECT_EQ(0, arm.collection_array[3]->child_index);
1068 EXPECT_EQ(0, arm.collection_array[4]->child_index);
1069 EXPECT_EQ(0, arm.collection_array[5]->child_index);
1070 EXPECT_EQ(0, arm.collection_array[6]->child_index);
1071
1072 EXPECT_EQ(2, arm.collection_array[0]->child_count);
1073 EXPECT_EQ(3, arm.collection_array[1]->child_count);
1074 EXPECT_EQ(0, arm.collection_array[2]->child_count);
1075 EXPECT_EQ(0, arm.collection_array[3]->child_count);
1076 EXPECT_EQ(0, arm.collection_array[4]->child_count);
1077 EXPECT_EQ(0, arm.collection_array[5]->child_count);
1078 EXPECT_EQ(0, arm.collection_array[6]->child_count);
1079
1080 /* Move r0_child3 to become the last child of root_1. */
1081 EXPECT_EQ(5,
1083 6, /* From index. */
1084 3, /* To child number. */
1085 0, /* From parent. */
1086 1 /* To parent. */
1087 ));
1088
1089 ASSERT_EQ(2, arm.collection_root_count);
1090 ASSERT_EQ(7, arm.collection_array_num);
1091 EXPECT_STREQ(bcoll_root_0->name, arm.collection_array[0]->name);
1092 EXPECT_STREQ(bcoll_root_1->name, arm.collection_array[1]->name);
1093 EXPECT_STREQ(bcoll_r0_child0->name, arm.collection_array[2]->name); /* Children root_1. */
1094 EXPECT_STREQ(bcoll_r0_child1->name, arm.collection_array[3]->name);
1095 EXPECT_STREQ(bcoll_r1_child0->name, arm.collection_array[4]->name);
1096 EXPECT_STREQ(bcoll_r0_child3->name, arm.collection_array[5]->name);
1097 EXPECT_STREQ(bcoll_r0_child2->name, arm.collection_array[6]->name); /* Children root_0. */
1098
1099 EXPECT_EQ(6, arm.collection_array[0]->child_index);
1100 EXPECT_EQ(2, arm.collection_array[1]->child_index);
1101 EXPECT_EQ(0, arm.collection_array[2]->child_index);
1102 EXPECT_EQ(0, arm.collection_array[3]->child_index);
1103 EXPECT_EQ(0, arm.collection_array[4]->child_index);
1104 EXPECT_EQ(0, arm.collection_array[5]->child_index);
1105 EXPECT_EQ(0, arm.collection_array[6]->child_index);
1106
1107 EXPECT_EQ(1, arm.collection_array[0]->child_count);
1108 EXPECT_EQ(4, arm.collection_array[1]->child_count);
1109 EXPECT_EQ(0, arm.collection_array[2]->child_count);
1110 EXPECT_EQ(0, arm.collection_array[3]->child_count);
1111 EXPECT_EQ(0, arm.collection_array[4]->child_count);
1112 EXPECT_EQ(0, arm.collection_array[5]->child_count);
1113 EXPECT_EQ(0, arm.collection_array[6]->child_count);
1114
1115 /* 2nd half of the test: move the children back to root_0 to test moving in
1116 * the other direction. */
1117
1118 /* Move r0_child3 to become the first child of root_0. */
1119 EXPECT_EQ(5,
1121 5, /* From index. */
1122 0, /* To child number. */
1123 1, /* From parent. */
1124 0 /* To parent. */
1125 ));
1126
1127 ASSERT_EQ(2, arm.collection_root_count);
1128 ASSERT_EQ(7, arm.collection_array_num);
1129 EXPECT_STREQ(bcoll_root_0->name, arm.collection_array[0]->name);
1130 EXPECT_STREQ(bcoll_root_1->name, arm.collection_array[1]->name);
1131 EXPECT_STREQ(bcoll_r0_child0->name, arm.collection_array[2]->name); /* Children root_1. */
1132 EXPECT_STREQ(bcoll_r0_child1->name, arm.collection_array[3]->name);
1133 EXPECT_STREQ(bcoll_r1_child0->name, arm.collection_array[4]->name);
1134 EXPECT_STREQ(bcoll_r0_child3->name, arm.collection_array[5]->name); /* Children root_0. */
1135 EXPECT_STREQ(bcoll_r0_child2->name, arm.collection_array[6]->name);
1136
1137 EXPECT_EQ(5, arm.collection_array[0]->child_index);
1138 EXPECT_EQ(2, arm.collection_array[1]->child_index);
1139 EXPECT_EQ(0, arm.collection_array[2]->child_index);
1140 EXPECT_EQ(0, arm.collection_array[3]->child_index);
1141 EXPECT_EQ(0, arm.collection_array[4]->child_index);
1142 EXPECT_EQ(0, arm.collection_array[5]->child_index);
1143 EXPECT_EQ(0, arm.collection_array[6]->child_index);
1144
1145 EXPECT_EQ(2, arm.collection_array[0]->child_count);
1146 EXPECT_EQ(3, arm.collection_array[1]->child_count);
1147 EXPECT_EQ(0, arm.collection_array[2]->child_count);
1148 EXPECT_EQ(0, arm.collection_array[3]->child_count);
1149 EXPECT_EQ(0, arm.collection_array[4]->child_count);
1150 EXPECT_EQ(0, arm.collection_array[5]->child_count);
1151 EXPECT_EQ(0, arm.collection_array[6]->child_count);
1152
1153 /* Move r0_child0 to become the last child of root_0. */
1154 EXPECT_EQ(6,
1156 2, /* From index. */
1157 2, /* To child number. */
1158 1, /* From parent. */
1159 0 /* To parent. */
1160 ));
1161
1162 ASSERT_EQ(2, arm.collection_root_count);
1163 ASSERT_EQ(7, arm.collection_array_num);
1164 EXPECT_STREQ(bcoll_root_0->name, arm.collection_array[0]->name);
1165 EXPECT_STREQ(bcoll_root_1->name, arm.collection_array[1]->name);
1166 EXPECT_STREQ(bcoll_r0_child1->name, arm.collection_array[2]->name); /* Children root_1. */
1167 EXPECT_STREQ(bcoll_r1_child0->name, arm.collection_array[3]->name);
1168 EXPECT_STREQ(bcoll_r0_child3->name, arm.collection_array[4]->name); /* Children root_0. */
1169 EXPECT_STREQ(bcoll_r0_child2->name, arm.collection_array[5]->name);
1170 EXPECT_STREQ(bcoll_r0_child0->name, arm.collection_array[6]->name);
1171
1172 EXPECT_EQ(4, arm.collection_array[0]->child_index);
1173 EXPECT_EQ(2, arm.collection_array[1]->child_index);
1174 EXPECT_EQ(0, arm.collection_array[2]->child_index);
1175 EXPECT_EQ(0, arm.collection_array[3]->child_index);
1176 EXPECT_EQ(0, arm.collection_array[4]->child_index);
1177 EXPECT_EQ(0, arm.collection_array[5]->child_index);
1178 EXPECT_EQ(0, arm.collection_array[6]->child_index);
1179
1180 EXPECT_EQ(3, arm.collection_array[0]->child_count);
1181 EXPECT_EQ(2, arm.collection_array[1]->child_count);
1182 EXPECT_EQ(0, arm.collection_array[2]->child_count);
1183 EXPECT_EQ(0, arm.collection_array[3]->child_count);
1184 EXPECT_EQ(0, arm.collection_array[4]->child_count);
1185 EXPECT_EQ(0, arm.collection_array[5]->child_count);
1186 EXPECT_EQ(0, arm.collection_array[6]->child_count);
1187
1188 /* Move r0_child1 to become the 3rd child of root_0. */
1189 EXPECT_EQ(5,
1191 2, /* From index. */
1192 2, /* To child number. */
1193 1, /* From parent. */
1194 0 /* To parent. */
1195 ));
1196
1197 ASSERT_EQ(2, arm.collection_root_count);
1198 ASSERT_EQ(7, arm.collection_array_num);
1199 EXPECT_STREQ(bcoll_root_0->name, arm.collection_array[0]->name);
1200 EXPECT_STREQ(bcoll_root_1->name, arm.collection_array[1]->name);
1201 EXPECT_STREQ(bcoll_r1_child0->name, arm.collection_array[2]->name); /* Children root_1. */
1202 EXPECT_STREQ(bcoll_r0_child3->name, arm.collection_array[3]->name); /* Children root_0. */
1203 EXPECT_STREQ(bcoll_r0_child2->name, arm.collection_array[4]->name);
1204 EXPECT_STREQ(bcoll_r0_child1->name, arm.collection_array[5]->name);
1205 EXPECT_STREQ(bcoll_r0_child0->name, arm.collection_array[6]->name);
1206
1207 EXPECT_EQ(3, arm.collection_array[0]->child_index);
1208 EXPECT_EQ(2, arm.collection_array[1]->child_index);
1209 EXPECT_EQ(0, arm.collection_array[2]->child_index);
1210 EXPECT_EQ(0, arm.collection_array[3]->child_index);
1211 EXPECT_EQ(0, arm.collection_array[4]->child_index);
1212 EXPECT_EQ(0, arm.collection_array[5]->child_index);
1213 EXPECT_EQ(0, arm.collection_array[6]->child_index);
1214
1215 EXPECT_EQ(4, arm.collection_array[0]->child_count);
1216 EXPECT_EQ(1, arm.collection_array[1]->child_count);
1217 EXPECT_EQ(0, arm.collection_array[2]->child_count);
1218 EXPECT_EQ(0, arm.collection_array[3]->child_count);
1219 EXPECT_EQ(0, arm.collection_array[4]->child_count);
1220 EXPECT_EQ(0, arm.collection_array[5]->child_count);
1221 EXPECT_EQ(0, arm.collection_array[6]->child_count);
1222}
1223
1224TEST_F(ArmatureBoneCollections, internal__bonecolls_rotate_block)
1225{
1226 /* Set up a small hierarchy. */
1227 BoneCollection *bcoll_root_0 = ANIM_armature_bonecoll_new(&arm, "root_0");
1228 BoneCollection *bcoll_root_1 = ANIM_armature_bonecoll_new(&arm, "root_1");
1229 BoneCollection *bcoll_r0_child0 = ANIM_armature_bonecoll_new(&arm, "r0_child0", 0);
1230 BoneCollection *bcoll_r1_child0 = ANIM_armature_bonecoll_new(&arm, "r1_child0", 1);
1231 BoneCollection *bcoll_r0_child1 = ANIM_armature_bonecoll_new(&arm, "r0_child1", 0);
1232 BoneCollection *bcoll_r0_child2 = ANIM_armature_bonecoll_new(&arm, "r0_child2", 0);
1233
1234 /* The tests below compare the collection names, instead of their pointers, so
1235 * that we get human-readable messages on failure. */
1236
1237 /* Unnecessary assertions, just to make it easier to understand in which order
1238 * the array starts out. */
1239 ASSERT_EQ(6, arm.collection_array_num);
1240 ASSERT_STREQ(bcoll_root_0->name, arm.collection_array[0]->name);
1241 ASSERT_STREQ(bcoll_root_1->name, arm.collection_array[1]->name);
1242 ASSERT_STREQ(bcoll_r0_child0->name, arm.collection_array[2]->name);
1243 ASSERT_STREQ(bcoll_r0_child1->name, arm.collection_array[3]->name);
1244 ASSERT_STREQ(bcoll_r0_child2->name, arm.collection_array[4]->name);
1245 ASSERT_STREQ(bcoll_r1_child0->name, arm.collection_array[5]->name);
1246
1247 ASSERT_EQ(2, arm.collection_array[0]->child_index);
1248 ASSERT_EQ(5, arm.collection_array[1]->child_index);
1249 ASSERT_EQ(0, arm.collection_array[2]->child_index);
1250 ASSERT_EQ(0, arm.collection_array[3]->child_index);
1251 ASSERT_EQ(0, arm.collection_array[4]->child_index);
1252 ASSERT_EQ(0, arm.collection_array[5]->child_index);
1253
1254 /* Move [0,1,2] to [1,2,3]. */
1255 internal::bonecolls_rotate_block(&arm, 0, 3, 1);
1256 ASSERT_EQ(6, arm.collection_array_num) << "array size should not change";
1257 EXPECT_STREQ(bcoll_r0_child1->name, arm.collection_array[0]->name);
1258 EXPECT_STREQ(bcoll_root_0->name, arm.collection_array[1]->name);
1259 EXPECT_STREQ(bcoll_root_1->name, arm.collection_array[2]->name);
1260 EXPECT_STREQ(bcoll_r0_child0->name, arm.collection_array[3]->name);
1261 EXPECT_STREQ(bcoll_r0_child2->name, arm.collection_array[4]->name);
1262 EXPECT_STREQ(bcoll_r1_child0->name, arm.collection_array[5]->name);
1263
1264 EXPECT_EQ(0, arm.collection_array[0]->child_index);
1265 EXPECT_EQ(3, arm.collection_array[1]->child_index);
1266 EXPECT_EQ(5, arm.collection_array[2]->child_index);
1267 EXPECT_EQ(0, arm.collection_array[3]->child_index);
1268 EXPECT_EQ(0, arm.collection_array[4]->child_index);
1269 EXPECT_EQ(0, arm.collection_array[5]->child_index);
1270
1271 /* Move [4,5] to [3,4]. */
1272 internal::bonecolls_rotate_block(&arm, 4, 2, -1);
1273 ASSERT_EQ(6, arm.collection_array_num) << "array size should not change";
1274 EXPECT_STREQ(bcoll_r0_child1->name, arm.collection_array[0]->name);
1275 EXPECT_STREQ(bcoll_root_0->name, arm.collection_array[1]->name);
1276 EXPECT_STREQ(bcoll_root_1->name, arm.collection_array[2]->name);
1277 EXPECT_STREQ(bcoll_r0_child2->name, arm.collection_array[3]->name);
1278 EXPECT_STREQ(bcoll_r1_child0->name, arm.collection_array[4]->name);
1279 EXPECT_STREQ(bcoll_r0_child0->name, arm.collection_array[5]->name);
1280
1281 EXPECT_EQ(0, arm.collection_array[0]->child_index);
1282 EXPECT_EQ(3, arm.collection_array[1]->child_index);
1283 EXPECT_EQ(4, arm.collection_array[2]->child_index);
1284 EXPECT_EQ(0, arm.collection_array[3]->child_index);
1285 EXPECT_EQ(0, arm.collection_array[4]->child_index);
1286 EXPECT_EQ(0, arm.collection_array[5]->child_index);
1287}
1288
1289class ArmatureBoneCollectionsTestList : public testing::Test {
1290 protected:
1292
1298
1299 void SetUp() override
1300 {
1301 STRNCPY(arm.id.name, "ARArmature");
1302
1304 child0 = ANIM_armature_bonecoll_new(&arm, "child0", 0);
1305 child1 = ANIM_armature_bonecoll_new(&arm, "child1", 0);
1306 child2 = ANIM_armature_bonecoll_new(&arm, "child2", 0);
1307 child1_0 = ANIM_armature_bonecoll_new(&arm, "child1_0", 2);
1308
1309 ASSERT_STREQ(root->name, arm.collection_array[0]->name);
1310 ASSERT_STREQ(child0->name, arm.collection_array[1]->name);
1311 ASSERT_STREQ(child1->name, arm.collection_array[2]->name);
1312 ASSERT_STREQ(child2->name, arm.collection_array[3]->name);
1313 ASSERT_STREQ(child1_0->name, arm.collection_array[4]->name);
1314 }
1315
1316 void TearDown() override
1317 {
1320 }
1321
1322 testing::AssertionResult expect_bcolls(std::vector<std::string> expect_names)
1323 {
1324 std::vector<std::string> actual_names;
1325 for (const BoneCollection *bcoll : arm.collections_span()) {
1326 actual_names.emplace_back(bcoll->name);
1327 }
1328
1329 if (expect_names == actual_names) {
1330 return testing::AssertionSuccess();
1331 }
1332
1333 testing::AssertionResult failure = testing::AssertionFailure();
1334
1335 failure << "Expected bone collections differ from actual ones:" << std::endl;
1336
1337 /* This is what you get when C++ doesn't even have a standard library
1338 * function to do something like `expect_names.join(", ")`. */
1339 failure << "Expected collections: [";
1340 for (int i = 0; i < expect_names.size() - 1; i++) {
1341 failure << expect_names[i] << ", ";
1342 }
1343 failure << expect_names.back() << "]" << std::endl;
1344
1345 failure << "Actual collections : [";
1346 for (int i = 0; i < actual_names.size() - 1; i++) {
1347 failure << actual_names[i] << ", ";
1348 }
1349 failure << actual_names.back() << "]" << std::endl;
1350
1352
1353 return failure;
1354 }
1355};
1356
1357TEST_F(ArmatureBoneCollectionsTestList, move_before_after_index__before_first_sibling)
1358{
1359 /* Set the active index to be one of the affected bone collections. */
1361 ASSERT_EQ(3, arm.runtime.active_collection_index);
1362
1364 EXPECT_TRUE(expect_bcolls({"root", "child2", "child0", "child1", "child1_0"}));
1366
1367 /* The three indicators of the active collection should still be in sync. */
1368 EXPECT_EQ(1, arm.runtime.active_collection_index);
1369 EXPECT_EQ(child2, arm.runtime.active_collection);
1370 EXPECT_STREQ("child2", arm.active_collection_name);
1371}
1372
1373TEST_F(ArmatureBoneCollectionsTestList, move_before_after_index__after_first_sibling)
1374{
1376 EXPECT_TRUE(expect_bcolls({"root", "child0", "child2", "child1", "child1_0"}));
1378}
1379
1380TEST_F(ArmatureBoneCollectionsTestList, move_before_after_index__before_last_sibling)
1381{
1382 /* Set the active index to be one of the affected bone collections. */
1384 ASSERT_EQ(2, arm.runtime.active_collection_index);
1385
1387 EXPECT_TRUE(expect_bcolls({"root", "child1", "child0", "child2", "child1_0"}));
1389
1390 /* The three indicators of the active collection should still be in sync. */
1391 EXPECT_EQ(1, arm.runtime.active_collection_index);
1392 EXPECT_EQ(child1, arm.runtime.active_collection);
1393 EXPECT_STREQ("child1", arm.active_collection_name);
1394}
1395
1396TEST_F(ArmatureBoneCollectionsTestList, move_before_after_index__after_last_sibling)
1397{
1399 EXPECT_TRUE(expect_bcolls({"root", "child1", "child2", "child0", "child1_0"}));
1401}
1402
1403TEST_F(ArmatureBoneCollectionsTestList, move_before_after_index__other_parent_before__move_left)
1404{
1406 EXPECT_TRUE(expect_bcolls({"root", "child1_0", "child0", "child1", "child2"}));
1408}
1409
1410TEST_F(ArmatureBoneCollectionsTestList, move_before_after_index__other_parent_after__move_left)
1411{
1413 EXPECT_TRUE(expect_bcolls({"root", "child0", "child1_0", "child1", "child2"}));
1415}
1416
1417TEST_F(ArmatureBoneCollectionsTestList, move_before_after_index__other_parent_before__move_right)
1418{
1420 EXPECT_TRUE(expect_bcolls({"root", "child1", "child2", "child0", "child1_0"}));
1422}
1423
1424TEST_F(ArmatureBoneCollectionsTestList, move_before_after_index__other_parent_after__move_right)
1425{
1427 EXPECT_TRUE(expect_bcolls({"root", "child1", "child2", "child1_0", "child0"}));
1429}
1430
1431TEST_F(ArmatureBoneCollectionsTestList, move_before_after_index__to_root__before)
1432{
1434 EXPECT_TRUE(expect_bcolls({"child1_0", "root", "child0", "child1", "child2"}));
1436}
1437
1438TEST_F(ArmatureBoneCollectionsTestList, move_before_after_index__to_root__after)
1439{
1441 EXPECT_TRUE(expect_bcolls({"root", "child1_0", "child0", "child1", "child2"}));
1443}
1444
1446{
1447 /* Test with only one root. */
1449 EXPECT_TRUE(expect_bcolls({"root", "child0", "child1", "child2", "child1_0"}));
1450
1451 /* Move to "after the last child", which is the one root itself. */
1453 EXPECT_TRUE(expect_bcolls({"root", "child0", "child1", "child2", "child1_0"}));
1455 EXPECT_TRUE(expect_bcolls({"root", "child0", "child1", "child2", "child1_0"}));
1456
1457 /* Going beyond the number of children is not allowed. */
1459 EXPECT_TRUE(expect_bcolls({"root", "child0", "child1", "child2", "child1_0"}));
1460
1461 /* Add two roots to be able to play. */
1462 ANIM_armature_bonecoll_new(&arm, "root1");
1463 ANIM_armature_bonecoll_new(&arm, "root2");
1464 EXPECT_TRUE(expect_bcolls({"root", "root1", "root2", "child0", "child1", "child2", "child1_0"}));
1465
1466 /* Move the old root in between the two new ones. */
1468 EXPECT_TRUE(expect_bcolls({"root1", "root", "root2", "child0", "child1", "child2", "child1_0"}));
1469
1470 /* And to the last one. */
1472 EXPECT_TRUE(expect_bcolls({"root1", "root2", "root", "child0", "child1", "child2", "child1_0"}));
1473}
1474
1475TEST_F(ArmatureBoneCollectionsTestList, child_number_set__siblings)
1476{
1477 /* Move child0 to itself. */
1478 EXPECT_EQ(1, armature_bonecoll_child_number_set(&arm, child0, 0));
1479 EXPECT_TRUE(expect_bcolls({"root", "child0", "child1", "child2", "child1_0"}));
1480
1481 /* Move child2 to itself. */
1482 EXPECT_EQ(3, armature_bonecoll_child_number_set(&arm, child2, -1));
1483 EXPECT_TRUE(expect_bcolls({"root", "child0", "child1", "child2", "child1_0"}));
1484
1485 /* Going beyond the number of children is not allowed. */
1486 EXPECT_EQ(-1, armature_bonecoll_child_number_set(&arm, child0, 3));
1487 EXPECT_TRUE(expect_bcolls({"root", "child0", "child1", "child2", "child1_0"}));
1488
1489 /* Move child0 to in between child1 and child2. */
1490 EXPECT_EQ(2, armature_bonecoll_child_number_set(&arm, child0, 1));
1491 EXPECT_TRUE(expect_bcolls({"root", "child1", "child0", "child2", "child1_0"}));
1492
1493 /* Move child0 to the last spot. */
1494 EXPECT_EQ(3, armature_bonecoll_child_number_set(&arm, child0, 2));
1495 EXPECT_TRUE(expect_bcolls({"root", "child1", "child2", "child0", "child1_0"}));
1496}
1497
1499{
1500 EXPECT_FALSE(arm.flag & ARM_BCOLL_SOLO_ACTIVE) << "By default no solo'ing should be active";
1501
1502 /* Enable solo. */
1503 EXPECT_FALSE(child1->flags & BONE_COLLECTION_SOLO);
1504 ANIM_armature_bonecoll_solo_set(&arm, child1, true);
1505 EXPECT_TRUE(child1->flags & BONE_COLLECTION_SOLO);
1506 EXPECT_TRUE(arm.flag & ARM_BCOLL_SOLO_ACTIVE);
1507
1508 /* Enable solo on another bone collection. */
1509 EXPECT_FALSE(child1_0->flags & BONE_COLLECTION_SOLO);
1510 ANIM_armature_bonecoll_solo_set(&arm, child1_0, true);
1511 EXPECT_TRUE(child1_0->flags & BONE_COLLECTION_SOLO);
1512 EXPECT_TRUE(arm.flag & ARM_BCOLL_SOLO_ACTIVE);
1513
1514 /* Disable the first solo flag. */
1515 EXPECT_TRUE(child1->flags & BONE_COLLECTION_SOLO);
1516 ANIM_armature_bonecoll_solo_set(&arm, child1, false);
1517 EXPECT_FALSE(child1->flags & BONE_COLLECTION_SOLO);
1518 EXPECT_TRUE(arm.flag & ARM_BCOLL_SOLO_ACTIVE);
1519
1520 /* Disable the second solo flag. This should also disable the ARM_BCOLL_SOLO_ACTIVE flag. */
1521 EXPECT_TRUE(child1_0->flags & BONE_COLLECTION_SOLO);
1522 ANIM_armature_bonecoll_solo_set(&arm, child1_0, false);
1523 EXPECT_FALSE(child1_0->flags & BONE_COLLECTION_SOLO);
1524 EXPECT_FALSE(arm.flag & ARM_BCOLL_SOLO_ACTIVE);
1525}
1526
1528 protected:
1530
1536
1537 void SetUp() override
1538 {
1540
1541 /* TODO: make this clone `arm` into `dst_arm`, instead of assuming the below
1542 * code is still in sync with the super-class. */
1543 STRNCPY(dst_arm.id.name, "ARArmatureDST");
1544
1550
1551 ASSERT_STREQ(dst_root->name, dst_arm.collection_array[0]->name);
1552 ASSERT_STREQ(dst_child0->name, dst_arm.collection_array[1]->name);
1553 ASSERT_STREQ(dst_child1->name, dst_arm.collection_array[2]->name);
1554 ASSERT_STREQ(dst_child2->name, dst_arm.collection_array[3]->name);
1555 ASSERT_STREQ(dst_child1_0->name, dst_arm.collection_array[4]->name);
1556
1559 }
1560
1566};
1567
1569{
1570 /* Mimic that a new root, two children, and two grandchildren were added via library overrides.
1571 * These were saved in `arm`, and now need to be copied into `dst_arm`. */
1572 BoneCollection *src_root = ANIM_armature_bonecoll_new(&arm, "new_root");
1573 const int root_index = armature_bonecoll_find_index(&arm, src_root);
1574 BoneCollection *src_child1 = ANIM_armature_bonecoll_new(&arm, "new_child1", root_index);
1575 ANIM_armature_bonecoll_new(&arm, "new_child2", root_index);
1576 const int child1_index = armature_bonecoll_find_index(&arm, src_child1);
1577 ANIM_armature_bonecoll_new(&arm, "new_gchild1", child1_index);
1578 ANIM_armature_bonecoll_new(&arm, "new_gchild2", child1_index);
1579
1580 /* Copy the root. This should be the only change that's recorded by a library override operation.
1581 * It should also copy the entire subtree of that root. */
1582 const BoneCollection *anchor = dst_arm.collection_array[0];
1583 ASSERT_STREQ("root", anchor->name);
1585 &dst_arm, &arm, anchor, src_root);
1586
1587 /* Check the array order. */
1588 EXPECT_TRUE(expect_bcolls({"root",
1589 "new_root",
1590 "child0",
1591 "child1",
1592 "child2",
1593 "child1_0",
1594 "new_child1",
1595 "new_child2",
1596 "new_gchild1",
1597 "new_gchild2"}));
1598
1599 /* Check that the copied root is actually stored in the destination armature array. */
1600 const int new_root_index = armature_bonecoll_find_index(&dst_arm, copy_root);
1601 EXPECT_EQ(1, new_root_index);
1602
1603 /* Check the hierarchy. */
1604 const int new_child1_index = ANIM_armature_bonecoll_get_index_by_name(&dst_arm, "new_child1");
1605 EXPECT_TRUE(armature_bonecoll_is_root(&dst_arm, new_root_index));
1606 EXPECT_TRUE(armature_bonecoll_is_child_of(&dst_arm, new_root_index, new_child1_index));
1608 &dst_arm, new_root_index, ANIM_armature_bonecoll_get_index_by_name(&dst_arm, "new_child2")));
1610 &dst_arm,
1611 new_child1_index,
1612 ANIM_armature_bonecoll_get_index_by_name(&dst_arm, "new_gchild1")));
1614 &dst_arm,
1615 new_child1_index,
1616 ANIM_armature_bonecoll_get_index_by_name(&dst_arm, "new_gchild2")));
1617
1618 if (HasFailure()) {
1620 }
1621}
1622
1623} // namespace blender::animrig::tests
C++ functions to deal with Armature collections (i.e. the successor of bone layers).
void ANIM_armature_bonecoll_active_set(bArmature *armature, BoneCollection *bcoll)
bool ANIM_armature_bonecoll_is_editable(const bArmature *armature, const BoneCollection *bcoll)
BoneCollection * ANIM_armature_bonecoll_insert_copy_after(bArmature *armature_dst, const bArmature *armature_src, const BoneCollection *anchor_in_dst, const BoneCollection *bcoll_to_copy)
int ANIM_armature_bonecoll_move_before_after_index(bArmature *armature, int from_index, int to_index, MoveLocation before_after)
void ANIM_bonecoll_hide(bArmature *armature, BoneCollection *bcoll)
void ANIM_armature_bonecoll_active_name_set(bArmature *armature, const char *name)
BoneCollection * ANIM_bonecoll_new(const char *name) ATTR_WARN_UNUSED_RESULT
void ANIM_bonecoll_free(BoneCollection *bcoll, bool do_id_user_count=true)
bool ANIM_armature_bonecoll_assign(BoneCollection *bcoll, Bone *bone)
void ANIM_armature_bonecoll_remove(bArmature *armature, BoneCollection *bcoll)
bool ANIM_armature_bonecoll_unassign(BoneCollection *bcoll, Bone *bone)
bool ANIM_armature_bonecoll_move_to_index(bArmature *armature, int from_index, int to_index)
void ANIM_armature_bonecoll_solo_set(bArmature *armature, BoneCollection *bcoll, bool is_solo)
int ANIM_armature_bonecoll_get_index_by_name(bArmature *armature, const char *name) ATTR_WARN_UNUSED_RESULT
BoneCollection * ANIM_armature_bonecoll_new(bArmature *armature, const char *name, int parent_index=-1)
void ANIM_armature_bonecoll_active_index_set(bArmature *armature, int bone_collection_index)
void BKE_armature_bone_hash_make(bArmature *arm)
#define G_MAIN
void BKE_idtype_init()
Definition idtype.cc:121
void BKE_libblock_free_datablock(ID *id, int flag) ATTR_NONNULL()
Main * BKE_main_new()
Definition main.cc:89
void BKE_main_free(Main *bmain)
Definition main.cc:192
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:534
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
#define DATA_(msgid)
@ BONE_COLLECTION_VISIBLE
@ BONE_COLLECTION_SELECTABLE
@ BONE_COLLECTION_ANCESTORS_VISIBLE
@ BONE_COLLECTION_SOLO
@ BONE_COLLECTION_OVERRIDE_LIBRARY_LOCAL
@ ARM_BCOLL_SOLO_ACTIVE
Internal C++ functions to deal with bone collections. These are mostly here for internal use in bone_...
testing::AssertionResult expect_bcolls(std::vector< std::string > expect_names)
void bonecolls_rotate_block(bArmature *armature, const int start_index, const int count, const int direction)
void bonecolls_debug_list(const bArmature *armature)
TEST_F(ActionIteratorsTest, iterate_all_fcurves_of_slot)
TEST(action, low_level_initialisation)
bool armature_bonecoll_is_root(const bArmature *armature, int bcoll_index)
int armature_bonecoll_find_index(const bArmature *armature, const ::BoneCollection *bcoll)
int armature_bonecoll_find_parent_index(const bArmature *armature, int bcoll_index)
int armature_bonecoll_child_number_set(bArmature *armature, ::BoneCollection *bcoll, int new_child_number)
int armature_bonecoll_move_to_parent(bArmature *armature, int from_bcoll_index, int to_child_num, int from_parent_index, int to_parent_index)
bool armature_bonecoll_is_child_of(const bArmature *armature, int potential_parent_index, int potential_child_index)
struct BoneCollection * bcoll
struct ID * reference
Definition DNA_ID.h:334
struct Library * lib
Definition DNA_ID.h:420
IDOverrideLibrary * override_library
Definition DNA_ID.h:494
ID id
Definition DNA_ID.h:550
i
Definition text_draw.cc:230