Blender V4.3
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 = *static_cast<GreasePencil *>(BKE_id_new(ctx.bmain, ID_GP, "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 = *static_cast<GreasePencil *>(BKE_id_new(ctx.bmain, ID_GP, "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 = *static_cast<GreasePencil *>(BKE_id_new(ctx.bmain, ID_GP, "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 = reinterpret_cast<GreasePencil *>(
97 BKE_id_new_nomain(ID_GP, "Grease Pencil test"));
98
99 /* Regression test for #129900: unused drawing at the end causes crash. */
100
101 grease_pencil->add_empty_drawings(2);
102 reinterpret_cast<const GreasePencilDrawing *>(grease_pencil->drawing(0))->wrap().remove_user();
103 reinterpret_cast<const GreasePencilDrawing *>(grease_pencil->drawing(1))->wrap().remove_user();
104
105 Layer &layer_a = grease_pencil->add_layer("LayerA");
106 layer_a.add_frame(10)->drawing_index = 0;
107 const GreasePencilDrawingBase *used_drawing = grease_pencil->drawings()[0];
108 grease_pencil->update_drawing_users_for_layer(layer_a);
109
110 EXPECT_EQ(layer_a.frames().size(), 1);
111 EXPECT_EQ(layer_a.frames().lookup(10).drawing_index, 0);
112 /* Test DNA storage data too. */
113 layer_a.prepare_for_dna_write();
114 EXPECT_EQ(layer_a.frames_storage.num, 1);
116
117 grease_pencil->remove_drawings_with_no_users();
118 EXPECT_EQ(grease_pencil->drawings().size(), 1);
119 EXPECT_EQ(grease_pencil->drawings()[0], used_drawing);
120
121 BKE_id_free(nullptr, grease_pencil);
122}
123
124/* --------------------------------------------------------------------------------------------- */
125/* Layer Tree Tests. */
126
129 {
130 this->root_group_ptr = MEM_new<greasepencil::LayerGroup>(__func__);
131 this->active_node = nullptr;
132
134
135 this->drawing_array = nullptr;
136 this->drawing_array_num = 0;
137
138 this->runtime = MEM_new<GreasePencilRuntime>(__func__);
139 }
140
142 {
143 CustomData_free(&this->layers_data, this->layers().size());
144 MEM_delete(&this->root_group());
145 MEM_delete(this->runtime);
146 this->runtime = nullptr;
147 }
148};
149
150TEST(greasepencil, layer_tree_empty)
151{
152 GreasePencilHelper grease_pencil;
153 EXPECT_EQ(grease_pencil.root_group().num_nodes_total(), 0);
154}
155
156TEST(greasepencil, layer_tree_build_simple)
157{
158 GreasePencilHelper grease_pencil;
159
160 LayerGroup &group = grease_pencil.add_layer_group(grease_pencil.root_group(), "Group1");
161 grease_pencil.add_layer(group, "Layer1");
162 grease_pencil.add_layer(group, "Layer2");
163 EXPECT_EQ(grease_pencil.root_group().num_nodes_total(), 3);
164}
165
167 StringRefNull names[7] = {"Group1", "Layer1", "Layer2", "Group2", "Layer3", "Layer4", "Layer5"};
168 const bool is_layer[7] = {false, true, true, false, true, true, true};
170
172 {
173 LayerGroup &group = grease_pencil.add_layer_group(grease_pencil.root_group(), names[0]);
174 grease_pencil.add_layer(group, names[1]);
175 grease_pencil.add_layer(group, names[2]);
176
177 LayerGroup &group2 = grease_pencil.add_layer_group(group, names[3]);
178 grease_pencil.add_layer(group2, names[4]);
179 grease_pencil.add_layer(group2, names[5]);
180
181 grease_pencil.add_layer(names[6]);
182 }
183};
184
185TEST(greasepencil, layer_tree_pre_order_iteration)
186{
188
189 Span<const TreeNode *> children = ex.grease_pencil.nodes();
190 for (const int i : children.index_range()) {
191 const TreeNode &child = *children[i];
192 EXPECT_STREQ(child.name().data(), ex.names[i].data());
193 }
194}
195
196TEST(greasepencil, layer_tree_pre_order_iteration2)
197{
199
200 Span<const Layer *> layers = ex.grease_pencil.layers();
201 char name[64];
202 for (const int i : layers.index_range()) {
203 const Layer &layer = *layers[i];
204 SNPRINTF(name, "%s%d", "Layer", i + 1);
205 EXPECT_STREQ(layer.name().data(), name);
206 }
207}
208
209TEST(greasepencil, layer_tree_total_size)
210{
212 EXPECT_EQ(ex.grease_pencil.root_group().num_nodes_total(), 7);
213}
214
215TEST(greasepencil, layer_tree_node_types)
216{
218 Span<const TreeNode *> children = ex.grease_pencil.nodes();
219 for (const int i : children.index_range()) {
220 const TreeNode &child = *children[i];
221 EXPECT_EQ(child.is_layer(), ex.is_layer[i]);
222 EXPECT_EQ(child.is_group(), !ex.is_layer[i]);
223 }
224}
225
226TEST(greasepencil, layer_tree_remove_active_node)
227{
229 TreeNode *node = ex.grease_pencil.find_node_by_name("Layer2");
230 ex.grease_pencil.set_active_node(node);
231
232 ex.grease_pencil.remove_layer(node->as_layer());
233 node = ex.grease_pencil.get_active_node();
234 EXPECT_TRUE(node != nullptr);
235 EXPECT_TRUE(node->is_layer());
236 EXPECT_TRUE(node->as_layer().name() == "Layer1");
237
238 ex.grease_pencil.remove_layer(node->as_layer());
239 node = ex.grease_pencil.get_active_node();
240 EXPECT_TRUE(node != nullptr);
241 EXPECT_TRUE(node->is_group());
242 EXPECT_TRUE(node->as_group().name() == "Group2");
243
244 ex.grease_pencil.remove_group(node->as_group());
245 node = ex.grease_pencil.get_active_node();
246 EXPECT_TRUE(node != nullptr);
247 EXPECT_TRUE(node->is_group());
248 EXPECT_TRUE(node->as_group().name() == "Group1");
249
250 ex.grease_pencil.remove_group(node->as_group());
251 node = ex.grease_pencil.get_active_node();
252 EXPECT_TRUE(node != nullptr);
253 EXPECT_TRUE(node->is_layer());
254 EXPECT_TRUE(node->as_layer().name() == "Layer5");
255
256 ex.grease_pencil.remove_layer(node->as_layer());
257 node = ex.grease_pencil.get_active_node();
258 EXPECT_TRUE(node == nullptr);
259}
260
261TEST(greasepencil, layer_tree_is_child_of)
262{
264
265 EXPECT_FALSE(ex.grease_pencil.root_group().is_child_of(ex.grease_pencil.root_group()));
266
267 const LayerGroup &group1 = ex.grease_pencil.find_node_by_name("Group1")->as_group();
268 const LayerGroup &group2 = ex.grease_pencil.find_node_by_name("Group2")->as_group();
269 const Layer &layer1 = ex.grease_pencil.find_node_by_name("Layer1")->as_layer();
270 const Layer &layer3 = ex.grease_pencil.find_node_by_name("Layer3")->as_layer();
271 const Layer &layer5 = ex.grease_pencil.find_node_by_name("Layer5")->as_layer();
272
273 EXPECT_TRUE(layer1.is_child_of(ex.grease_pencil.root_group()));
274 EXPECT_TRUE(layer1.is_child_of(group1));
275 EXPECT_TRUE(layer3.is_child_of(group1));
276 EXPECT_FALSE(layer5.is_child_of(group1));
277
278 EXPECT_TRUE(layer3.is_child_of(group2));
279 EXPECT_FALSE(layer1.is_child_of(group2));
280
281 EXPECT_TRUE(layer5.is_child_of(ex.grease_pencil.root_group()));
282}
283
284TEST(greasepencil, layer_tree_remove_group)
285{
286 /* Regression test for #130034. */
287 GreasePencilHelper grease_pencil;
288 LayerGroup &group1 = grease_pencil.add_layer_group(grease_pencil.root_group(), "Group1");
289 LayerGroup &group2 = grease_pencil.add_layer_group(group1, "Group2");
290 LayerGroup &group3 = grease_pencil.add_layer_group(group2, "Group3");
291 grease_pencil.add_layer(group3, "Layer");
292 grease_pencil.add_layer("Layer2");
293
294 /* Remove Group with children. */
295 grease_pencil.remove_group(group1, false);
296 EXPECT_EQ(grease_pencil.nodes().size(), 1);
297 EXPECT_EQ(grease_pencil.layers().size(), 1);
298 EXPECT_TRUE(grease_pencil.find_node_by_name("Layer2") != nullptr);
299}
300
301/* --------------------------------------------------------------------------------------------- */
302/* Frames Tests. */
303
310 const FramesMapKeyT sorted_keys[5] = {0, 5, 10, 12, 16};
311 GreasePencilFrame sorted_values[5] = {{0}, {1}, {-1}, {2}, {-1}};
313
315 {
316 for (int i = 0; i < 5; i++) {
317 layer.frames_for_write().add(this->sorted_keys[i], this->sorted_values[i]);
318 }
319 /* Mark the first keyframe as an implicit hold. */
320 layer.frame_at(0)->flag |= GP_FRAME_IMPLICIT_HOLD;
321 }
322};
323
324TEST(greasepencil, frame_is_end)
325{
327 EXPECT_TRUE(ex.layer.frames().lookup(10).is_end());
328}
329
330TEST(greasepencil, frame_is_implicit_hold)
331{
333 EXPECT_TRUE(ex.layer.frames().lookup(0).is_implicit_hold());
334}
335
336TEST(greasepencil, drawing_index_at)
337{
339 EXPECT_EQ(ex.layer.drawing_index_at(-100), -1);
340 EXPECT_EQ(ex.layer.drawing_index_at(100), -1);
344}
345
346TEST(greasepencil, add_frame)
347{
349 EXPECT_FALSE(ex.layer.add_frame(0) != nullptr);
350 ex.layer.add_frame(10)->drawing_index = 3;
354}
355
356TEST(greasepencil, add_frame_duration_fail)
357{
359 EXPECT_FALSE(ex.layer.add_frame(0, 10) != nullptr);
360}
361
362TEST(greasepencil, add_frame_duration_override_start_null_frame)
363{
365 ex.layer.add_frame(10, 2)->drawing_index = 3;
369}
370
371TEST(greasepencil, add_frame_duration_check_duration)
372{
374 ex.layer.add_frame(17, 10)->drawing_index = 3;
375 Span<FramesMapKeyT> sorted_keys = ex.layer.sorted_keys();
376 EXPECT_EQ(sorted_keys.size(), 7);
377 EXPECT_EQ(sorted_keys[6] - sorted_keys[5], 10);
378}
379
380TEST(greasepencil, get_frame_duration_at)
381{
383 /* Before first frame. */
385 /* Implicit hold. */
388
391
392 /* No keyframe at frame 10. */
394
396
397 /* After last frame. */
400}
401
402TEST(greasepencil, add_frame_duration_override_null_frames)
403{
404 Layer layer;
405 layer.frames_for_write().add(0, {1});
406 layer.frames_for_write().add(1, {-1});
407 layer.frames_for_write().add(2, {-1});
408 layer.frames_for_write().add(3, {-1});
409
410 layer.add_frame(1, 10)->drawing_index = 3;
411 EXPECT_EQ(layer.drawing_index_at(0), 1);
412 EXPECT_EQ(layer.drawing_index_at(1), 3);
413 EXPECT_EQ(layer.drawing_index_at(11), -1);
414 Span<FramesMapKeyT> sorted_keys = layer.sorted_keys();
415 EXPECT_EQ(sorted_keys.size(), 3);
416 EXPECT_EQ(sorted_keys[0], 0);
417 EXPECT_EQ(sorted_keys[1], 1);
418 EXPECT_EQ(sorted_keys[2], 11);
419}
420
421TEST(greasepencil, remove_frame_single)
422{
423 Layer layer;
424 layer.add_frame(0)->drawing_index = 1;
425 layer.remove_frame(0);
426 EXPECT_EQ(layer.frames().size(), 0);
427}
428
429TEST(greasepencil, remove_frame_first)
430{
431 Layer layer;
432 layer.add_frame(0)->drawing_index = 1;
433 layer.add_frame(5)->drawing_index = 2;
434 layer.remove_frame(0);
435 EXPECT_EQ(layer.frames().size(), 1);
436 EXPECT_EQ(layer.frames().lookup(5).drawing_index, 2);
437}
438
439TEST(greasepencil, remove_frame_last)
440{
441 Layer layer;
442 layer.add_frame(0)->drawing_index = 1;
443 layer.add_frame(5)->drawing_index = 2;
444 layer.remove_frame(5);
445 EXPECT_EQ(layer.frames().size(), 1);
446 EXPECT_EQ(layer.frames().lookup(0).drawing_index, 1);
447}
448
449TEST(greasepencil, remove_frame_implicit_hold)
450{
451 Layer layer;
452 layer.add_frame(0, 4)->drawing_index = 1;
453 layer.add_frame(5)->drawing_index = 2;
454 layer.remove_frame(5);
455 EXPECT_EQ(layer.frames().size(), 2);
456 EXPECT_EQ(layer.frames().lookup(0).drawing_index, 1);
457 EXPECT_TRUE(layer.frames().lookup(4).is_end());
458}
459
460TEST(greasepencil, remove_frame_fixed_duration_end)
461{
462 Layer layer;
463 layer.add_frame(0, 5)->drawing_index = 1;
464 layer.add_frame(5)->drawing_index = 2;
465 layer.remove_frame(0);
466 EXPECT_EQ(layer.frames().size(), 1);
467 EXPECT_EQ(layer.frames().lookup(5).drawing_index, 2);
468}
469
470TEST(greasepencil, remove_frame_fixed_duration_overwrite_end)
471{
472 Layer layer;
473 layer.add_frame(0, 5)->drawing_index = 1;
474 layer.add_frame(5)->drawing_index = 2;
475 layer.remove_frame(5);
476 EXPECT_EQ(layer.frames().size(), 2);
477 EXPECT_EQ(layer.frames().lookup(0).drawing_index, 1);
478 EXPECT_TRUE(layer.frames().lookup(5).is_end());
479}
480
481TEST(greasepencil, remove_drawings_no_change)
482{
483 GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(
484 BKE_id_new_nomain(ID_GP, "Grease Pencil test"));
485
486 grease_pencil->add_empty_drawings(3);
487
488 Layer &layer_a = grease_pencil->add_layer("LayerA");
489 Layer &layer_b = grease_pencil->add_layer("LayerB");
490 layer_b.add_frame(10)->drawing_index = 0;
491 layer_b.add_frame(20)->drawing_index = 1;
492 layer_b.add_frame(30)->drawing_index = 2;
493
494 EXPECT_EQ(layer_a.frames().size(), 0);
495 EXPECT_EQ(layer_b.frames().size(), 3);
496 EXPECT_EQ(layer_b.frames().lookup(10).drawing_index, 0);
497 EXPECT_EQ(layer_b.frames().lookup(20).drawing_index, 1);
498 EXPECT_EQ(layer_b.frames().lookup(30).drawing_index, 2);
499 /* Test DNA storage data too. */
500 layer_a.prepare_for_dna_write();
501 layer_b.prepare_for_dna_write();
502 EXPECT_EQ(layer_a.frames_storage.num, 0);
503 EXPECT_EQ(layer_b.frames_storage.num, 3);
507
508 grease_pencil->remove_layer(layer_a);
509 EXPECT_EQ(layer_b.frames().size(), 3);
510 EXPECT_EQ(layer_b.frames().lookup(10).drawing_index, 0);
511 EXPECT_EQ(layer_b.frames().lookup(20).drawing_index, 1);
512 EXPECT_EQ(layer_b.frames().lookup(30).drawing_index, 2);
513 /* Test DNA storage data too. */
514 layer_b.prepare_for_dna_write();
515 EXPECT_EQ(layer_b.frames_storage.num, 3);
519
520 BKE_id_free(nullptr, grease_pencil);
521}
522
523TEST(greasepencil, remove_drawings_with_no_users)
524{
525 GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(
526 BKE_id_new_nomain(ID_GP, "Grease Pencil test"));
527
528 /* Test drawing index correctness: Removing users from drawings should remove those drawings, and
529 * all index references should get updated to match the changed drawing indices. */
530
531 grease_pencil->add_empty_drawings(5);
532
533 Layer &layer_a = grease_pencil->add_layer("LayerA");
534 layer_a.add_frame(10)->drawing_index = 0;
535 layer_a.add_frame(20)->drawing_index = 1;
536 layer_a.add_frame(30)->drawing_index = 2;
537 Layer &layer_b = grease_pencil->add_layer("LayerB");
538 layer_b.add_frame(10)->drawing_index = 3;
539 layer_b.add_frame(30)->drawing_index = 4;
540
541 EXPECT_EQ(layer_a.frames().size(), 3);
542 EXPECT_EQ(layer_a.frames().lookup(10).drawing_index, 0);
543 EXPECT_EQ(layer_a.frames().lookup(20).drawing_index, 1);
544 EXPECT_EQ(layer_a.frames().lookup(30).drawing_index, 2);
545 EXPECT_EQ(layer_b.frames().size(), 2);
546 EXPECT_EQ(layer_b.frames().lookup(10).drawing_index, 3);
547 EXPECT_EQ(layer_b.frames().lookup(30).drawing_index, 4);
548 /* Test DNA storage data too. */
549 layer_a.prepare_for_dna_write();
550 layer_b.prepare_for_dna_write();
551 EXPECT_EQ(layer_a.frames_storage.num, 3);
555 EXPECT_EQ(layer_b.frames_storage.num, 2);
558
559 /* Drawings 0,1,2 get removed, drawings 3,4 move up (order changes). */
560 grease_pencil->remove_layer(layer_a);
561 EXPECT_EQ(layer_b.frames().size(), 2);
562 EXPECT_EQ(layer_b.frames().lookup(10).drawing_index, 1);
563 EXPECT_EQ(layer_b.frames().lookup(30).drawing_index, 0);
564 /* Test DNA storage data too. */
565 layer_b.prepare_for_dna_write();
566 EXPECT_EQ(layer_b.frames_storage.num, 2);
569
570 BKE_id_free(nullptr, grease_pencil);
571}
572
573} // 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, int totelem)
Low-level operations for grease pencil.
void BKE_idtype_init()
Definition idtype.cc:127
void BKE_id_free(Main *bmain, void *idv)
void * BKE_id_new(Main *bmain, short type, const char *name)
Definition lib_id.cc:1482
void * BKE_id_new_nomain(short type, const char *name)
Definition lib_id.cc:1487
Main * BKE_main_new(void)
Definition main.cc:45
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:597
@ ID_GP
@ 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:271
const Value & lookup(const Key &key) const
Definition BLI_map.hh:506
int64_t size() const
Definition BLI_map.hh:927
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
constexpr const char * data() const
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()
TEST(greasepencil, create_grease_pencil_id)
float wrap(float value, float max, float min)
Definition node_math.h:71
GreasePencilLayerFramesMapStorage frames_storage
GreasePencilLayerTreeNode * active_node
GreasePencilLayerTreeGroup * root_group_ptr
GreasePencilRuntimeHandle * runtime
GreasePencilDrawingBase ** drawing_array