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