Blender V4.5
grease_pencil_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 "testing/testing.h"
6
7#include "BLI_string.h"
8
9#include "BKE_curves.hh"
10#include "BKE_customdata.hh"
11#include "BKE_grease_pencil.hh"
12#include "BKE_idtype.hh"
13#include "BKE_lib_id.hh"
14#include "BKE_main.hh"
15
16using namespace blender::bke::greasepencil;
17
19
20/* --------------------------------------------------------------------------------------------- */
21/* Grease Pencil ID Tests. */
22
23/* NOTE: Using a struct with constructor and destructor instead of a fixture here, to have all the
24 * tests in the same group (`greasepencil`). */
38
39TEST(greasepencil, create_grease_pencil_id)
40{
42
43 GreasePencil &grease_pencil = *BKE_id_new<GreasePencil>(ctx.bmain, "GP");
44 EXPECT_EQ(grease_pencil.drawings().size(), 0);
45 EXPECT_EQ(grease_pencil.root_group().num_nodes_total(), 0);
46}
47
48/* --------------------------------------------------------------------------------------------- */
49/* Drawing Array Tests. */
50
51TEST(greasepencil, add_empty_drawings)
52{
54 GreasePencil &grease_pencil = *BKE_id_new<GreasePencil>(ctx.bmain, "GP");
55 grease_pencil.add_empty_drawings(3);
56 EXPECT_EQ(grease_pencil.drawings().size(), 3);
57}
58
59TEST(greasepencil, remove_drawings)
60{
62 GreasePencil &grease_pencil = *BKE_id_new<GreasePencil>(ctx.bmain, "GP");
63 grease_pencil.add_empty_drawings(3);
64
65 GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(grease_pencil.drawing(1));
66 drawing->wrap().strokes_for_write().resize(0, 10);
67
68 Layer &layer1 = grease_pencil.add_layer("Layer1");
69 Layer &layer2 = grease_pencil.add_layer("Layer2");
70
71 layer1.add_frame(0)->drawing_index = 0;
72 layer1.add_frame(10)->drawing_index = 1;
73 layer1.add_frame(20)->drawing_index = 2;
74
75 layer2.add_frame(0)->drawing_index = 1;
76 drawing->wrap().add_user();
77
78 grease_pencil.remove_frames(layer1, {10});
79 grease_pencil.remove_frames(layer2, {0});
80 EXPECT_EQ(grease_pencil.drawings().size(), 2);
81
82 static int expected_frames_size[] = {2, 0};
83 static int expected_frames_pairs_layer0[][2] = {{0, 0}, {20, 1}};
84
85 Span<const Layer *> layers = grease_pencil.layers();
86 EXPECT_EQ(layers[0]->frames().size(), expected_frames_size[0]);
87 EXPECT_EQ(layers[1]->frames().size(), expected_frames_size[1]);
88 EXPECT_EQ(layers[0]->frames().lookup(expected_frames_pairs_layer0[0][0]).drawing_index,
89 expected_frames_pairs_layer0[0][1]);
90 EXPECT_EQ(layers[0]->frames().lookup(expected_frames_pairs_layer0[1][0]).drawing_index,
91 expected_frames_pairs_layer0[1][1]);
92}
93
94TEST(greasepencil, remove_drawings_last_unused)
95{
96 GreasePencil *grease_pencil = BKE_id_new_nomain<GreasePencil>("Grease Pencil test");
97
98 /* Regression test for #129900: unused drawing at the end causes crash. */
99
100 grease_pencil->add_empty_drawings(2);
101 reinterpret_cast<const GreasePencilDrawing *>(grease_pencil->drawing(0))->wrap().remove_user();
102 reinterpret_cast<const GreasePencilDrawing *>(grease_pencil->drawing(1))->wrap().remove_user();
103
104 Layer &layer_a = grease_pencil->add_layer("LayerA");
105 layer_a.add_frame(10)->drawing_index = 0;
106 const GreasePencilDrawingBase *used_drawing = grease_pencil->drawings()[0];
107 grease_pencil->update_drawing_users_for_layer(layer_a);
108
109 EXPECT_EQ(layer_a.frames().size(), 1);
110 EXPECT_EQ(layer_a.frames().lookup(10).drawing_index, 0);
111 /* Test DNA storage data too. */
112 layer_a.prepare_for_dna_write();
113 EXPECT_EQ(layer_a.frames_storage.num, 1);
115
116 grease_pencil->remove_drawings_with_no_users();
117 EXPECT_EQ(grease_pencil->drawings().size(), 1);
118 EXPECT_EQ(grease_pencil->drawings()[0], used_drawing);
119
120 BKE_id_free(nullptr, grease_pencil);
121}
122
123/* --------------------------------------------------------------------------------------------- */
124/* Layer Tree Tests. */
125
128 {
129 this->root_group_ptr = MEM_new<greasepencil::LayerGroup>(__func__);
130 this->active_node = nullptr;
131
133
134 this->drawing_array = nullptr;
135 this->drawing_array_num = 0;
136
137 this->runtime = MEM_new<GreasePencilRuntime>(__func__);
138 }
139
141 {
143 MEM_delete(&this->root_group());
144 MEM_delete(this->runtime);
145 this->runtime = nullptr;
146 }
147};
148
149TEST(greasepencil, layer_tree_empty)
150{
151 GreasePencilHelper grease_pencil;
152 EXPECT_EQ(grease_pencil.root_group().num_nodes_total(), 0);
153}
154
155TEST(greasepencil, layer_tree_build_simple)
156{
157 GreasePencilHelper grease_pencil;
158
159 LayerGroup &group = grease_pencil.add_layer_group(grease_pencil.root_group(), "Group1");
160 grease_pencil.add_layer(group, "Layer1");
161 grease_pencil.add_layer(group, "Layer2");
162 EXPECT_EQ(grease_pencil.root_group().num_nodes_total(), 3);
163}
164
166 StringRefNull names[7] = {"Group1", "Layer1", "Layer2", "Group2", "Layer3", "Layer4", "Layer5"};
167 const bool is_layer[7] = {false, true, true, false, true, true, true};
169
171 {
172 LayerGroup &group = grease_pencil.add_layer_group(grease_pencil.root_group(), names[0]);
173 grease_pencil.add_layer(group, names[1]);
174 grease_pencil.add_layer(group, names[2]);
175
176 LayerGroup &group2 = grease_pencil.add_layer_group(group, names[3]);
177 grease_pencil.add_layer(group2, names[4]);
178 grease_pencil.add_layer(group2, names[5]);
179
180 grease_pencil.add_layer(names[6]);
181 }
182};
183
184TEST(greasepencil, layer_tree_pre_order_iteration)
185{
187
188 Span<const TreeNode *> children = ex.grease_pencil.nodes();
189 for (const int i : children.index_range()) {
190 const TreeNode &child = *children[i];
191 EXPECT_STREQ(child.name().data(), ex.names[i].data());
192 }
193}
194
195TEST(greasepencil, layer_tree_pre_order_iteration2)
196{
198
199 Span<const Layer *> layers = ex.grease_pencil.layers();
200 char name[64];
201 for (const int i : layers.index_range()) {
202 const Layer &layer = *layers[i];
203 SNPRINTF(name, "%s%d", "Layer", i + 1);
204 EXPECT_STREQ(layer.name().data(), name);
205 }
206}
207
208TEST(greasepencil, layer_tree_total_size)
209{
211 EXPECT_EQ(ex.grease_pencil.root_group().num_nodes_total(), 7);
212}
213
214TEST(greasepencil, layer_tree_node_types)
215{
217 Span<const TreeNode *> children = ex.grease_pencil.nodes();
218 for (const int i : children.index_range()) {
219 const TreeNode &child = *children[i];
220 EXPECT_EQ(child.is_layer(), ex.is_layer[i]);
221 EXPECT_EQ(child.is_group(), !ex.is_layer[i]);
222 }
223}
224
225TEST(greasepencil, layer_tree_remove_active_node)
226{
228 TreeNode *node = ex.grease_pencil.find_node_by_name("Layer2");
229 ex.grease_pencil.set_active_node(node);
230
231 ex.grease_pencil.remove_layer(node->as_layer());
232 node = ex.grease_pencil.get_active_node();
233 EXPECT_TRUE(node != nullptr);
234 EXPECT_TRUE(node->is_layer());
235 EXPECT_TRUE(node->as_layer().name() == "Layer1");
236
237 ex.grease_pencil.remove_layer(node->as_layer());
238 node = ex.grease_pencil.get_active_node();
239 EXPECT_TRUE(node != nullptr);
240 EXPECT_TRUE(node->is_group());
241 EXPECT_TRUE(node->as_group().name() == "Group2");
242
243 ex.grease_pencil.remove_group(node->as_group());
244 node = ex.grease_pencil.get_active_node();
245 EXPECT_TRUE(node != nullptr);
246 EXPECT_TRUE(node->is_group());
247 EXPECT_TRUE(node->as_group().name() == "Group1");
248
249 ex.grease_pencil.remove_group(node->as_group());
250 node = ex.grease_pencil.get_active_node();
251 EXPECT_TRUE(node != nullptr);
252 EXPECT_TRUE(node->is_layer());
253 EXPECT_TRUE(node->as_layer().name() == "Layer5");
254
255 ex.grease_pencil.remove_layer(node->as_layer());
256 node = ex.grease_pencil.get_active_node();
257 EXPECT_TRUE(node == nullptr);
258}
259
260TEST(greasepencil, layer_tree_is_child_of)
261{
263
264 EXPECT_FALSE(ex.grease_pencil.root_group().is_child_of(ex.grease_pencil.root_group()));
265
266 const LayerGroup &group1 = ex.grease_pencil.find_node_by_name("Group1")->as_group();
267 const LayerGroup &group2 = ex.grease_pencil.find_node_by_name("Group2")->as_group();
268 const Layer &layer1 = ex.grease_pencil.find_node_by_name("Layer1")->as_layer();
269 const Layer &layer3 = ex.grease_pencil.find_node_by_name("Layer3")->as_layer();
270 const Layer &layer5 = ex.grease_pencil.find_node_by_name("Layer5")->as_layer();
271
272 EXPECT_TRUE(layer1.is_child_of(ex.grease_pencil.root_group()));
273 EXPECT_TRUE(layer1.is_child_of(group1));
274 EXPECT_TRUE(layer3.is_child_of(group1));
275 EXPECT_FALSE(layer5.is_child_of(group1));
276
277 EXPECT_TRUE(layer3.is_child_of(group2));
278 EXPECT_FALSE(layer1.is_child_of(group2));
279
280 EXPECT_TRUE(layer5.is_child_of(ex.grease_pencil.root_group()));
281}
282
283TEST(greasepencil, layer_tree_remove_group)
284{
285 /* Regression test for #130034. */
286 GreasePencilHelper grease_pencil;
287 LayerGroup &group1 = grease_pencil.add_layer_group(grease_pencil.root_group(), "Group1");
288 LayerGroup &group2 = grease_pencil.add_layer_group(group1, "Group2");
289 LayerGroup &group3 = grease_pencil.add_layer_group(group2, "Group3");
290 grease_pencil.add_layer(group3, "Layer");
291 grease_pencil.add_layer("Layer2");
292
293 /* Remove Group with children. */
294 grease_pencil.remove_group(group1, false);
295 EXPECT_EQ(grease_pencil.nodes().size(), 1);
296 EXPECT_EQ(grease_pencil.layers().size(), 1);
297 EXPECT_TRUE(grease_pencil.find_node_by_name("Layer2") != nullptr);
298}
299
300/* --------------------------------------------------------------------------------------------- */
301/* Frames Tests. */
302
309 const FramesMapKeyT sorted_keys[5] = {0, 5, 10, 12, 16};
310 GreasePencilFrame sorted_values[5] = {{0}, {1}, {-1}, {2}, {-1}};
312
314 {
315 for (int i = 0; i < 5; i++) {
316 layer.frames_for_write().add(this->sorted_keys[i], this->sorted_values[i]);
317 }
318 /* Mark the first keyframe as an implicit hold. */
319 layer.frame_at(0)->flag |= GP_FRAME_IMPLICIT_HOLD;
320 }
321};
322
323TEST(greasepencil, frame_is_end)
324{
326 EXPECT_TRUE(ex.layer.frames().lookup(10).is_end());
327}
328
329TEST(greasepencil, frame_is_implicit_hold)
330{
332 EXPECT_TRUE(ex.layer.frames().lookup(0).is_implicit_hold());
333}
334
335TEST(greasepencil, drawing_index_at)
336{
338 EXPECT_EQ(ex.layer.drawing_index_at(-100), -1);
339 EXPECT_EQ(ex.layer.drawing_index_at(100), -1);
343}
344
346{
348 EXPECT_FALSE(ex.layer.add_frame(0) != nullptr);
349 ex.layer.add_frame(10)->drawing_index = 3;
353}
354
355TEST(greasepencil, add_frame_duration_fail)
356{
358 EXPECT_FALSE(ex.layer.add_frame(0, 10) != nullptr);
359}
360
361TEST(greasepencil, add_frame_duration_override_start_null_frame)
362{
364 ex.layer.add_frame(10, 2)->drawing_index = 3;
368}
369
370TEST(greasepencil, add_frame_duration_check_duration)
371{
373 ex.layer.add_frame(17, 10)->drawing_index = 3;
374 Span<FramesMapKeyT> sorted_keys = ex.layer.sorted_keys();
375 EXPECT_EQ(sorted_keys.size(), 7);
376 EXPECT_EQ(sorted_keys[6] - sorted_keys[5], 10);
377}
378
379TEST(greasepencil, get_frame_duration_at)
380{
382 /* Before first frame. */
384 /* Implicit hold. */
387
390
391 /* No keyframe at frame 10. */
393
395
396 /* After last frame. */
399}
400
401TEST(greasepencil, add_frame_duration_override_null_frames)
402{
403 Layer layer;
404 layer.frames_for_write().add(0, {1});
405 layer.frames_for_write().add(1, {-1});
406 layer.frames_for_write().add(2, {-1});
407 layer.frames_for_write().add(3, {-1});
408
409 layer.add_frame(1, 10)->drawing_index = 3;
410 EXPECT_EQ(layer.drawing_index_at(0), 1);
411 EXPECT_EQ(layer.drawing_index_at(1), 3);
412 EXPECT_EQ(layer.drawing_index_at(11), -1);
413 Span<FramesMapKeyT> sorted_keys = layer.sorted_keys();
414 EXPECT_EQ(sorted_keys.size(), 3);
415 EXPECT_EQ(sorted_keys[0], 0);
416 EXPECT_EQ(sorted_keys[1], 1);
417 EXPECT_EQ(sorted_keys[2], 11);
418}
419
420TEST(greasepencil, remove_frame_single)
421{
422 Layer layer;
423 layer.add_frame(0)->drawing_index = 1;
424 layer.remove_frame(0);
425 EXPECT_EQ(layer.frames().size(), 0);
426}
427
428TEST(greasepencil, remove_frame_first)
429{
430 Layer layer;
431 layer.add_frame(0)->drawing_index = 1;
432 layer.add_frame(5)->drawing_index = 2;
433 layer.remove_frame(0);
434 EXPECT_EQ(layer.frames().size(), 1);
435 EXPECT_EQ(layer.frames().lookup(5).drawing_index, 2);
436}
437
438TEST(greasepencil, remove_frame_last)
439{
440 Layer layer;
441 layer.add_frame(0)->drawing_index = 1;
442 layer.add_frame(5)->drawing_index = 2;
443 layer.remove_frame(5);
444 EXPECT_EQ(layer.frames().size(), 1);
445 EXPECT_EQ(layer.frames().lookup(0).drawing_index, 1);
446}
447
448TEST(greasepencil, remove_frame_implicit_hold)
449{
450 Layer layer;
451 layer.add_frame(0, 4)->drawing_index = 1;
452 layer.add_frame(5)->drawing_index = 2;
453 layer.remove_frame(5);
454 EXPECT_EQ(layer.frames().size(), 2);
455 EXPECT_EQ(layer.frames().lookup(0).drawing_index, 1);
456 EXPECT_TRUE(layer.frames().lookup(4).is_end());
457}
458
459TEST(greasepencil, remove_frame_fixed_duration_end)
460{
461 Layer layer;
462 layer.add_frame(0, 5)->drawing_index = 1;
463 layer.add_frame(5)->drawing_index = 2;
464 layer.remove_frame(0);
465 EXPECT_EQ(layer.frames().size(), 1);
466 EXPECT_EQ(layer.frames().lookup(5).drawing_index, 2);
467}
468
469TEST(greasepencil, remove_frame_fixed_duration_overwrite_end)
470{
471 Layer layer;
472 layer.add_frame(0, 5)->drawing_index = 1;
473 layer.add_frame(5)->drawing_index = 2;
474 layer.remove_frame(5);
475 EXPECT_EQ(layer.frames().size(), 2);
476 EXPECT_EQ(layer.frames().lookup(0).drawing_index, 1);
477 EXPECT_TRUE(layer.frames().lookup(5).is_end());
478}
479
480TEST(greasepencil, remove_drawings_no_change)
481{
482 GreasePencil *grease_pencil = BKE_id_new_nomain<GreasePencil>("Grease Pencil test");
483
484 grease_pencil->add_empty_drawings(3);
485
486 Layer &layer_a = grease_pencil->add_layer("LayerA");
487 Layer &layer_b = grease_pencil->add_layer("LayerB");
488 layer_b.add_frame(10)->drawing_index = 0;
489 layer_b.add_frame(20)->drawing_index = 1;
490 layer_b.add_frame(30)->drawing_index = 2;
491
492 EXPECT_EQ(layer_a.frames().size(), 0);
493 EXPECT_EQ(layer_b.frames().size(), 3);
494 EXPECT_EQ(layer_b.frames().lookup(10).drawing_index, 0);
495 EXPECT_EQ(layer_b.frames().lookup(20).drawing_index, 1);
496 EXPECT_EQ(layer_b.frames().lookup(30).drawing_index, 2);
497 /* Test DNA storage data too. */
498 layer_a.prepare_for_dna_write();
499 layer_b.prepare_for_dna_write();
500 EXPECT_EQ(layer_a.frames_storage.num, 0);
501 EXPECT_EQ(layer_b.frames_storage.num, 3);
505
506 grease_pencil->remove_layer(layer_a);
507 EXPECT_EQ(layer_b.frames().size(), 3);
508 EXPECT_EQ(layer_b.frames().lookup(10).drawing_index, 0);
509 EXPECT_EQ(layer_b.frames().lookup(20).drawing_index, 1);
510 EXPECT_EQ(layer_b.frames().lookup(30).drawing_index, 2);
511 /* Test DNA storage data too. */
512 layer_b.prepare_for_dna_write();
513 EXPECT_EQ(layer_b.frames_storage.num, 3);
517
518 BKE_id_free(nullptr, grease_pencil);
519}
520
521TEST(greasepencil, remove_drawings_with_no_users)
522{
523 GreasePencil *grease_pencil = BKE_id_new_nomain<GreasePencil>("Grease Pencil test");
524
525 /* Test drawing index correctness: Removing users from drawings should remove those drawings, and
526 * all index references should get updated to match the changed drawing indices. */
527
528 grease_pencil->add_empty_drawings(5);
529
530 Layer &layer_a = grease_pencil->add_layer("LayerA");
531 layer_a.add_frame(10)->drawing_index = 0;
532 layer_a.add_frame(20)->drawing_index = 1;
533 layer_a.add_frame(30)->drawing_index = 2;
534 Layer &layer_b = grease_pencil->add_layer("LayerB");
535 layer_b.add_frame(10)->drawing_index = 3;
536 layer_b.add_frame(30)->drawing_index = 4;
537
538 EXPECT_EQ(layer_a.frames().size(), 3);
539 EXPECT_EQ(layer_a.frames().lookup(10).drawing_index, 0);
540 EXPECT_EQ(layer_a.frames().lookup(20).drawing_index, 1);
541 EXPECT_EQ(layer_a.frames().lookup(30).drawing_index, 2);
542 EXPECT_EQ(layer_b.frames().size(), 2);
543 EXPECT_EQ(layer_b.frames().lookup(10).drawing_index, 3);
544 EXPECT_EQ(layer_b.frames().lookup(30).drawing_index, 4);
545 /* Test DNA storage data too. */
546 layer_a.prepare_for_dna_write();
547 layer_b.prepare_for_dna_write();
548 EXPECT_EQ(layer_a.frames_storage.num, 3);
552 EXPECT_EQ(layer_b.frames_storage.num, 2);
555
556 /* Drawings 0,1,2 get removed, drawings 3,4 move up (order changes). */
557 grease_pencil->remove_layer(layer_a);
558 EXPECT_EQ(layer_b.frames().size(), 2);
559 EXPECT_EQ(layer_b.frames().lookup(10).drawing_index, 1);
560 EXPECT_EQ(layer_b.frames().lookup(30).drawing_index, 0);
561 /* Test DNA storage data too. */
562 layer_b.prepare_for_dna_write();
563 EXPECT_EQ(layer_b.frames_storage.num, 2);
566
567 BKE_id_free(nullptr, grease_pencil);
568}
569
570} // namespace blender::bke::greasepencil::tests
Low-level operations for curves.
CustomData interface, see also DNA_customdata_types.h.
void CustomData_reset(CustomData *data)
void CustomData_free(CustomData *data)
Low-level operations for grease pencil.
void BKE_idtype_init()
Definition idtype.cc:122
void BKE_id_free(Main *bmain, void *idv)
void * BKE_id_new(Main *bmain, short type, const char *name)
Definition lib_id.cc:1495
void * BKE_id_new_nomain(short type, const char *name)
Definition lib_id.cc:1500
Main * BKE_main_new()
Definition main.cc:48
void BKE_main_free(Main *bmain)
Definition main.cc:175
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:599
@ GP_FRAME_IMPLICIT_HOLD
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:295
const Value & lookup(const Key &key) const
Definition BLI_map.hh:545
int64_t size() const
Definition BLI_map.hh:976
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr const char * data() const
bool remove_frame(FramesMapKeyT key)
const Map< FramesMapKeyT, GreasePencilFrame > & frames() const
GreasePencilFrame * add_frame(FramesMapKeyT key, int duration=0)
int drawing_index_at(const int frame_number) const
int get_frame_duration_at(const int frame_number) const
Span< FramesMapKeyT > sorted_keys() const
Map< FramesMapKeyT, GreasePencilFrame > & frames_for_write()
const LayerGroup & as_group() const
TEST(greasepencil, create_grease_pencil_id)
GreasePencilLayerFramesMapStorage frames_storage
GreasePencilLayerTreeNode * active_node
GreasePencilLayerTreeGroup * root_group_ptr
GreasePencilRuntimeHandle * runtime
GreasePencilDrawingBase ** drawing_array
i
Definition text_draw.cc:230