Blender V4.5
gpencil_legacy.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cmath>
10#include <cstddef>
11#include <cstdlib>
12#include <cstring>
13#include <optional>
14
15#include "CLG_log.h"
16
17#include "MEM_guardedalloc.h"
18
19#include "BLI_listbase.h"
20#include "BLI_math_matrix.h"
21#include "BLI_math_vector.h"
22#include "BLI_string_utf8.h"
23#include "BLI_string_utils.hh"
24
25#include "BLT_translation.hh"
26
27/* Allow using deprecated functionality for .blend file I/O. */
28#define DNA_DEPRECATED_ALLOW
29#include "DNA_scene_types.h"
30
31#include "DNA_brush_types.h"
33#include "DNA_material_types.h"
34#include "DNA_meshdata_types.h"
35#include "DNA_userdef_types.h"
36
37#include "BKE_action.hh"
38#include "BKE_anim_data.hh"
39#include "BKE_brush.hh"
40#include "BKE_collection.hh"
41#include "BKE_colortools.hh"
42#include "BKE_deform.hh"
44#include "BKE_gpencil_legacy.h"
45#include "BKE_icons.h"
46#include "BKE_idtype.hh"
47#include "BKE_image.hh"
48#include "BKE_lib_id.hh"
49#include "BKE_lib_query.hh"
50#include "BKE_main.hh"
51#include "BKE_material.hh"
52#include "BKE_paint.hh"
53
54#include "DEG_depsgraph.hh"
55
56#include "BLI_math_color.h"
57#include "BLI_string_utf8.h"
58
59#include "BLO_read_write.hh"
60
61static CLG_LogRef LOG = {"bke.gpencil"};
62
63static void greasepencil_copy_data(Main * /*bmain*/,
64 std::optional<Library *> /*owner_library*/,
65 ID *id_dst,
66 const ID *id_src,
67 const int /*flag*/)
68{
69 bGPdata *gpd_dst = (bGPdata *)id_dst;
70 const bGPdata *gpd_src = (const bGPdata *)id_src;
71
72 /* duplicate material array */
73 if (gpd_src->mat) {
74 gpd_dst->mat = static_cast<Material **>(MEM_dupallocN(gpd_src->mat));
75 }
76
78
79 /* copy layers */
80 BLI_listbase_clear(&gpd_dst->layers);
81 LISTBASE_FOREACH (bGPDlayer *, gpl_src, &gpd_src->layers) {
82 /* make a copy of source layer and its data */
83
84 /* TODO: here too could add unused flags... */
85 bGPDlayer *gpl_dst = BKE_gpencil_layer_duplicate(gpl_src, true, true);
86
87 /* Apply local layer transform to all frames. Calc the active frame is not enough
88 * because onion skin can use more frames. This is more slow but required here. */
89 if (gpl_dst->actframe != nullptr) {
90 bool transformed = (!is_zero_v3(gpl_dst->location) || !is_zero_v3(gpl_dst->rotation) ||
91 !is_one_v3(gpl_dst->scale));
92 if (transformed) {
94 gpl_dst->layer_mat, gpl_dst->location, gpl_dst->rotation, gpl_dst->scale);
95 bool do_onion = ((gpl_dst->onion_flag & GP_LAYER_ONIONSKIN) != 0);
96 bGPDframe *init_gpf = static_cast<bGPDframe *>((do_onion) ? gpl_dst->frames.first :
97 gpl_dst->actframe);
98 for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
99 LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
100 bGPDspoint *pt;
101 int i;
102 for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
103 mul_m4_v3(gpl_dst->layer_mat, &pt->x);
104 }
105 }
106 /* if not onion, exit loop. */
107 if (!do_onion) {
108 break;
109 }
110 }
111 }
112 }
113
114 BLI_addtail(&gpd_dst->layers, gpl_dst);
115 }
116}
117
119{
120 /* Really not ideal, but for now will do... In theory custom behaviors like not freeing cache
121 * should be handled through specific API, and not be part of the generic one. */
122 BKE_gpencil_free_data((bGPdata *)id, true);
123}
124
126{
127 bGPdata *gpencil = (bGPdata *)id;
128 /* materials */
129 for (int i = 0; i < gpencil->totcol; i++) {
131 }
132
133 LISTBASE_FOREACH (bGPDlayer *, gplayer, &gpencil->layers) {
135 }
136}
137
138static void greasepencil_blend_write(BlendWriter *writer, ID *id, const void *id_address)
139{
140 bGPdata *gpd = (bGPdata *)id;
141
142 /* Clean up, important in undo case to reduce false detection of changed data-blocks. */
143 /* XXX not sure why the whole run-time data is not cleared in reading code,
144 * for now mimicking it here. */
145 gpd->runtime.sbuffer = nullptr;
146 gpd->runtime.sbuffer_used = 0;
147 gpd->runtime.sbuffer_size = 0;
148
149 /* write gpd data block to file */
150 BLO_write_id_struct(writer, bGPdata, id_address, &gpd->id);
151 BKE_id_blend_write(writer, &gpd->id);
152
154
155 BLO_write_pointer_array(writer, gpd->totcol, gpd->mat);
156
157 /* write grease-pencil layers to file */
158 BLO_write_struct_list(writer, bGPDlayer, &gpd->layers);
159 LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
160 /* Write mask list. */
161 BLO_write_struct_list(writer, bGPDlayer_Mask, &gpl->mask_layers);
162 /* write this layer's frames to file */
163 BLO_write_struct_list(writer, bGPDframe, &gpl->frames);
164 LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
165 /* write strokes */
166 BLO_write_struct_list(writer, bGPDstroke, &gpf->strokes);
167 LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
168 BLO_write_struct_array(writer, bGPDspoint, gps->totpoints, gps->points);
169 BLO_write_struct_array(writer, bGPDtriangle, gps->tot_triangles, gps->triangles);
170 BKE_defvert_blend_write(writer, gps->totpoints, gps->dvert);
171 if (gps->editcurve != nullptr) {
172 bGPDcurve *gpc = gps->editcurve;
173 BLO_write_struct(writer, bGPDcurve, gpc);
175 writer, bGPDcurve_point, gpc->tot_curve_points, gpc->curve_points);
176 }
177 }
178 }
179 }
180}
181
183{
184 /* We must firstly have some grease-pencil data to link! */
185 if (gpd == nullptr) {
186 return;
187 }
188
189 /* Ensure full object-mode for linked grease pencil. */
190 if (ID_IS_LINKED(gpd)) {
196 }
197
198 /* init stroke buffer */
199 gpd->runtime.sbuffer = nullptr;
200 gpd->runtime.sbuffer_used = 0;
201 gpd->runtime.sbuffer_size = 0;
202
203 /* Relink palettes (old palettes deprecated, only to convert old files). */
204 BLO_read_struct_list(reader, bGPDpalette, &gpd->palettes);
205 if (gpd->palettes.first != nullptr) {
206 LISTBASE_FOREACH (bGPDpalette *, palette, &gpd->palettes) {
207 BLO_read_struct_list(reader, PaletteColor, &palette->colors);
208 }
209 }
210
212
213 /* Materials. */
214 BLO_read_pointer_array(reader, gpd->totcol, (void **)&gpd->mat);
215
216 /* Relink layers. */
217 BLO_read_struct_list(reader, bGPDlayer, &gpd->layers);
218
219 LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
220 /* Relink frames. */
221 BLO_read_struct_list(reader, bGPDframe, &gpl->frames);
222
223 BLO_read_struct(reader, bGPDframe, &gpl->actframe);
224
225 gpl->runtime.icon_id = 0;
226
227 /* Relink masks. */
228 BLO_read_struct_list(reader, bGPDlayer_Mask, &gpl->mask_layers);
229
230 LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
231 /* Relink strokes (and their points). */
232 BLO_read_struct_list(reader, bGPDstroke, &gpf->strokes);
233
234 LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
235 /* Relink stroke points array. */
236 BLO_read_struct_array(reader, bGPDspoint, gps->totpoints, &gps->points);
237 /* Relink geometry. */
238 BLO_read_struct_array(reader, bGPDtriangle, gps->tot_triangles, &gps->triangles);
239
240 /* Relink stroke edit curve. */
241 BLO_read_struct(reader, bGPDcurve, &gps->editcurve);
242 if (gps->editcurve != nullptr) {
243 /* Relink curve point array. */
244 bGPDcurve *gpc = gps->editcurve;
246 reader, bGPDcurve_point, gpc->tot_curve_points, &gps->editcurve->curve_points);
247 }
248
249 /* Relink weight data. */
250 if (gps->dvert) {
251 BLO_read_struct_array(reader, MDeformVert, gps->totpoints, &gps->dvert);
252 BKE_defvert_blend_read(reader, gps->totpoints, gps->dvert);
253 }
254 }
255 }
256 }
257}
258
260{
261 bGPdata *gpd = (bGPdata *)id;
262 BKE_gpencil_blend_read_data(reader, gpd);
263}
264
266 /*id_code*/ bGPdata::id_type,
267 /*id_filter*/ FILTER_ID_GD_LEGACY,
268 /*dependencies_id_types*/ FILTER_ID_MA,
269 /*main_listbase_index*/ INDEX_ID_GD_LEGACY,
270 /*struct_size*/ sizeof(bGPdata),
271 /*name*/ "GPencil",
272 /*name_plural*/ N_("grease_pencils"),
273 /*translation_context*/ BLT_I18NCONTEXT_ID_GPENCIL,
275 /*asset_type_info*/ nullptr,
276
277 /*init_data*/ nullptr,
278 /*copy_data*/ greasepencil_copy_data,
279 /*free_data*/ greasepencil_free_data,
280 /*make_local*/ nullptr,
281 /*foreach_id*/ greasepencil_foreach_id,
282 /*foreach_cache*/ nullptr,
283 /*foreach_path*/ nullptr,
284 /*owner_pointer_get*/ nullptr,
285
286 /*blend_write*/ greasepencil_blend_write,
287 /*blend_read_data*/ greasepencil_blend_read_data,
288 /*blend_read_after_liblink*/ nullptr,
289
290 /*blend_read_undo_preserve*/ nullptr,
291
292 /*lib_override_apply_post*/ nullptr,
293};
294
295/* ************************************************** */
296/* Memory Management */
297
299{
300 if (dvert == nullptr) {
301 return;
302 }
303 MEM_SAFE_FREE(dvert->dw);
304}
305
307{
308 if (gps == nullptr) {
309 return;
310 }
311
312 if (gps->dvert == nullptr) {
313 return;
314 }
315
316 for (int i = 0; i < gps->totpoints; i++) {
317 MDeformVert *dvert = &gps->dvert[i];
319 }
320}
321
323{
324 if (gps == nullptr) {
325 return;
326 }
327 bGPDcurve *editcurve = gps->editcurve;
328 if (editcurve == nullptr) {
329 return;
330 }
331 MEM_freeN(editcurve->curve_points);
332 MEM_freeN(editcurve);
333 gps->editcurve = nullptr;
334}
335
337{
338 if (gps == nullptr) {
339 return;
340 }
341 /* free stroke memory arrays, then stroke itself */
342 if (gps->points) {
343 MEM_freeN(gps->points);
344 }
345 if (gps->dvert) {
347 MEM_freeN(gps->dvert);
348 }
349 if (gps->triangles) {
350 MEM_freeN(gps->triangles);
351 }
352 if (gps->editcurve != nullptr) {
354 }
355
356 MEM_freeN(gps);
357}
358
360{
361 bool changed = (BLI_listbase_is_empty(&gpf->strokes) == false);
362
363 /* free strokes */
366 }
368
369 return changed;
370}
371
373{
374 bGPDframe *gpf_next;
375
376 /* error checking */
377 if (gpl == nullptr) {
378 return;
379 }
380
381 /* free frames */
382 for (bGPDframe *gpf = static_cast<bGPDframe *>(gpl->frames.first); gpf; gpf = gpf_next) {
383 gpf_next = gpf->next;
384
385 /* free strokes and their associated memory */
387 BLI_freelinkN(&gpl->frames, gpf);
388 }
389 gpl->actframe = nullptr;
390}
391
393{
394 /* Free masks. */
395 bGPDlayer_Mask *mask_next = nullptr;
396 for (bGPDlayer_Mask *mask = static_cast<bGPDlayer_Mask *>(gpl->mask_layers.first); mask;
397 mask = mask_next)
398 {
399 mask_next = mask->next;
401 }
402}
404{
405 bGPDlayer *gpl_next;
406
407 /* error checking */
408 if (list == nullptr) {
409 return;
410 }
411
412 /* delete layers */
413 for (bGPDlayer *gpl = static_cast<bGPDlayer *>(list->first); gpl; gpl = gpl_next) {
414 gpl_next = gpl->next;
415
416 /* free layers and their data */
418
419 /* Free masks. */
421
422 BLI_freelinkN(list, gpl);
423 }
424}
425
427{
428 LISTBASE_FOREACH_MUTABLE (bGPDpalette *, palette, list) {
429 BLI_freelistN(&palette->colors);
430 MEM_freeN(palette);
431 }
432 BLI_listbase_clear(list);
433}
434
435void BKE_gpencil_free_data(bGPdata *gpd, bool /*free_all*/)
436{
437 /* free layers */
440
441 /* materials */
442 MEM_SAFE_FREE(gpd->mat);
443
445}
446
451
452/* ************************************************** */
453/* Container Creation */
454
456{
457 bGPDframe *gpf = nullptr, *gf = nullptr;
458 short state = 0;
459
460 /* error checking */
461 if (gpl == nullptr) {
462 return nullptr;
463 }
464
465 /* allocate memory for this frame */
466 gpf = MEM_callocN<bGPDframe>("bGPDframe");
467 gpf->framenum = cframe;
468
469 /* find appropriate place to add frame */
470 if (gpl->frames.first) {
471 for (gf = static_cast<bGPDframe *>(gpl->frames.first); gf; gf = gf->next) {
472 /* check if frame matches one that is supposed to be added */
473 if (gf->framenum == cframe) {
474 state = -1;
475 break;
476 }
477
478 /* if current frame has already exceeded the frame to add, add before */
479 if (gf->framenum > cframe) {
480 BLI_insertlinkbefore(&gpl->frames, gf, gpf);
481 state = 1;
482 break;
483 }
484 }
485 }
486
487 /* check whether frame was added successfully */
488 if (state == -1) {
490 &LOG, "Frame (%d) existed already for this layer_active. Using existing frame", cframe);
491
492 /* free the newly created one, and use the old one instead */
493 MEM_freeN(gpf);
494
495 /* return existing frame instead... */
496 BLI_assert(gf != nullptr);
497 gpf = gf;
498 }
499 else if (state == 0) {
500 /* add to end then! */
501 BLI_addtail(&gpl->frames, gpf);
502 }
503
504 /* return frame */
505 return gpf;
506}
507
509{
510 bGPDframe *new_frame;
511 bool found = false;
512
513 /* Error checking/handling */
514 if (gpl == nullptr) {
515 /* no layer */
516 return nullptr;
517 }
518 if (gpl->actframe == nullptr) {
519 /* no active frame, so just create a new one from scratch */
520 return BKE_gpencil_frame_addnew(gpl, cframe);
521 }
522
523 /* Create a copy of the frame */
524 new_frame = BKE_gpencil_frame_duplicate(gpl->actframe, true);
525
526 /* Find frame to insert it before */
527 LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
528 if (gpf->framenum > cframe) {
529 /* Add it here */
530 BLI_insertlinkbefore(&gpl->frames, gpf, new_frame);
531
532 found = true;
533 break;
534 }
535 if (gpf->framenum == cframe) {
536 /* This only happens when we're editing with frame-lock on.
537 * - Delete the new frame and don't do anything else here.
538 */
539 BKE_gpencil_free_strokes(new_frame);
540 MEM_freeN(new_frame);
541 new_frame = nullptr;
542
543 found = true;
544 break;
545 }
546 }
547
548 if (found == false) {
549 /* Add new frame to the end */
550 BLI_addtail(&gpl->frames, new_frame);
551 }
552
553 /* Ensure that frame is set up correctly, and return it */
554 if (new_frame) {
555 new_frame->framenum = cframe;
556 gpl->actframe = new_frame;
557 }
558
559 return new_frame;
560}
561
563 const char *name,
564 const bool setactive,
565 const bool add_to_header)
566{
567 bGPDlayer *gpl = nullptr;
568 bGPDlayer *gpl_active = nullptr;
569
570 /* check that list is ok */
571 if (gpd == nullptr) {
572 return nullptr;
573 }
574
575 /* allocate memory for frame and add to end of list */
576 gpl = MEM_callocN<bGPDlayer>("bGPDlayer");
577
578 gpl_active = BKE_gpencil_layer_active_get(gpd);
579
580 /* Add to data-block. */
581 if (add_to_header) {
582 BLI_addhead(&gpd->layers, gpl);
583 }
584 else {
585 if (gpl_active == nullptr) {
586 BLI_addtail(&gpd->layers, gpl);
587 }
588 else {
589 /* if active layer, add after that layer */
590 BLI_insertlinkafter(&gpd->layers, gpl_active, gpl);
591 }
592 }
593 /* annotation vs GP Object behavior is slightly different */
594 if (gpd->flag & GP_DATA_ANNOTATIONS) {
595 /* set default color of new strokes for this layer */
596 copy_v4_v4(gpl->color, U.gpencil_new_layer_col);
597 gpl->opacity = 1.0f;
598
599 /* set default thickness of new strokes for this layer */
600 gpl->thickness = 3;
601
602 /* Onion colors */
603 ARRAY_SET_ITEMS(gpl->gcolor_prev, 0.302f, 0.851f, 0.302f);
604 ARRAY_SET_ITEMS(gpl->gcolor_next, 0.250f, 0.1f, 1.0f);
605 }
606 else {
607 /* thickness parameter represents "thickness change", not absolute thickness */
608 gpl->thickness = 0;
609 gpl->opacity = 1.0f;
610 /* default channel color */
611 ARRAY_SET_ITEMS(gpl->color, 0.2f, 0.2f, 0.2f);
612 /* Default vertex mix. */
613 gpl->vertex_paint_opacity = 1.0f;
614 /* Enable onion skin. */
616 }
617
618 /* auto-name */
619 STRNCPY_UTF8(gpl->info, DATA_(name));
621 gpl,
622 (gpd->flag & GP_DATA_ANNOTATIONS) ? DATA_("Note") : DATA_("GP_Layer"),
623 '.',
624 offsetof(bGPDlayer, info),
625 sizeof(gpl->info));
626
627 /* Enable always affected by scene lights. */
629
630 /* Init transform. */
631 zero_v3(gpl->location);
632 zero_v3(gpl->rotation);
633 copy_v3_fl(gpl->scale, 1.0f);
634 loc_eul_size_to_mat4(gpl->layer_mat, gpl->location, gpl->rotation, gpl->scale);
636
637 /* make this one the active one */
638 if (setactive) {
640 }
641
642 /* return layer */
643 return gpl;
644}
645
646bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[])
647{
648 bGPdata *gpd;
649
650 /* allocate memory for a new block */
651 gpd = static_cast<bGPdata *>(BKE_libblock_alloc(bmain, ID_GD_LEGACY, name, 0));
652
653 /* initial settings */
655
656 /* general flags */
657 gpd->flag |= GP_DATA_VIEWALIGN;
658 /* always enable object onion skin switch */
660 /* GP object specific settings */
661 ARRAY_SET_ITEMS(gpd->line_color, 0.6f, 0.6f, 0.6f, 0.5f);
662
664
668
669 /* use adaptive curve resolution by default */
671
672 gpd->zdepth_offset = 0.150f;
673
674 /* grid settings */
675 ARRAY_SET_ITEMS(gpd->grid.color, 0.5f, 0.5f, 0.5f); /* Color */
676 ARRAY_SET_ITEMS(gpd->grid.scale, 1.0f, 1.0f); /* Scale */
677 gpd->grid.lines = GP_DEFAULT_GRID_LINES; /* Number of lines */
678
679 /* Onion-skinning settings (data-block level) */
680 gpd->onion_keytype = -1; /* All by default. */
684 gpd->onion_factor = 0.5f;
685 ARRAY_SET_ITEMS(gpd->gcolor_prev, 0.145098f, 0.419608f, 0.137255f); /* green */
686 ARRAY_SET_ITEMS(gpd->gcolor_next, 0.125490f, 0.082353f, 0.529412f); /* blue */
687 gpd->gstep = 1;
688 gpd->gstep_next = 1;
689
690 return gpd;
691}
692
693/* ************************************************** */
694
695/* ************************************************** */
696/* Data Duplication */
697
699{
700 if (gps_src == nullptr) {
701 return;
702 }
703 BLI_assert(gps_src->totpoints == gps_dst->totpoints);
704
705 BKE_defvert_array_copy(gps_dst->dvert, gps_src->dvert, gps_src->totpoints);
706}
707
709 const bool dup_points,
710 const bool /*dup_curve*/)
711{
712 bGPDstroke *gps_dst = nullptr;
713
714 gps_dst = static_cast<bGPDstroke *>(MEM_dupallocN(gps_src));
715 gps_dst->prev = gps_dst->next = nullptr;
716 gps_dst->triangles = static_cast<bGPDtriangle *>(MEM_dupallocN(gps_src->triangles));
717
718 if (dup_points) {
719 gps_dst->points = static_cast<bGPDspoint *>(MEM_dupallocN(gps_src->points));
720
721 if (gps_src->dvert != nullptr) {
722 gps_dst->dvert = static_cast<MDeformVert *>(MEM_dupallocN(gps_src->dvert));
723 BKE_gpencil_stroke_weights_duplicate(gps_src, gps_dst);
724 }
725 else {
726 gps_dst->dvert = nullptr;
727 }
728 }
729 else {
730 gps_dst->points = nullptr;
731 gps_dst->dvert = nullptr;
732 }
733
734 gps_dst->editcurve = nullptr;
735
736 /* return new stroke */
737 return gps_dst;
738}
739
740bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src, const bool dup_strokes)
741{
742 bGPDstroke *gps_dst = nullptr;
743 bGPDframe *gpf_dst;
744
745 /* error checking */
746 if (gpf_src == nullptr) {
747 return nullptr;
748 }
749
750 /* make a copy of the source frame */
751 gpf_dst = static_cast<bGPDframe *>(MEM_dupallocN(gpf_src));
752 gpf_dst->prev = gpf_dst->next = nullptr;
753
754 /* Copy strokes. */
755 BLI_listbase_clear(&gpf_dst->strokes);
756 if (dup_strokes) {
757 LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) {
758 /* make copy of source stroke */
759 gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true, true);
760 BLI_addtail(&gpf_dst->strokes, gps_dst);
761 }
762 }
763
764 /* return new frame */
765 return gpf_dst;
766}
767
769 const bool dup_frames,
770 const bool dup_strokes)
771{
772 bGPDframe *gpf_dst;
773 bGPDlayer *gpl_dst;
774
775 /* error checking */
776 if (gpl_src == nullptr) {
777 return nullptr;
778 }
779
780 /* make a copy of source layer */
781 gpl_dst = static_cast<bGPDlayer *>(MEM_dupallocN(gpl_src));
782 gpl_dst->prev = gpl_dst->next = nullptr;
783
784 /* Copy masks. */
785 BKE_gpencil_layer_mask_copy(gpl_src, gpl_dst);
786
787 /* copy frames */
788 BLI_listbase_clear(&gpl_dst->frames);
789 if (dup_frames) {
790 LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) {
791 /* make a copy of source frame */
792 gpf_dst = BKE_gpencil_frame_duplicate(gpf_src, dup_strokes);
793 BLI_addtail(&gpl_dst->frames, gpf_dst);
794
795 /* if source frame was the current layer's 'active' frame, reassign that too */
796 if (gpf_src == gpl_dst->actframe) {
797 gpl_dst->actframe = gpf_dst;
798 }
799 }
800 }
801
802 /* return new layer */
803 return gpl_dst;
804}
805
806bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool internal_copy)
807{
808 bGPdata *gpd_dst;
809
810 /* Yuck and super-uber-hyper yuck!!!
811 * Should be replaceable with a no-main copy (LIB_ID_COPY_NO_MAIN etc.), but not sure about it,
812 * so for now keep old code for that one. */
813
814 /* error checking */
815 if (gpd_src == nullptr) {
816 return nullptr;
817 }
818
819 if (internal_copy) {
820 /* make a straight copy for undo buffers used during stroke drawing */
821 gpd_dst = static_cast<bGPdata *>(MEM_dupallocN(gpd_src));
822 }
823 else {
824 BLI_assert(bmain != nullptr);
825 gpd_dst = (bGPdata *)BKE_id_copy(bmain, &gpd_src->id);
826 }
827
828 /* Copy internal data (layers, etc.) */
829 greasepencil_copy_data(bmain, std::nullopt, &gpd_dst->id, &gpd_src->id, 0);
830
831 /* return new */
832 return gpd_dst;
833}
834
835/* ************************************************** */
836/* GP Layer API */
837
839{
840 /* Sanity check */
841 if (gpl == nullptr) {
842 return false;
843 }
844
845 /* Layer must be: Visible + Editable */
846 if ((gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) == 0) {
847 return true;
848 }
849
850 /* Something failed */
851 return false;
852}
853
855{
856 /* Search in reverse order, since this is often used for playback/adding,
857 * where it's less likely that we're interested in the earlier frames
858 */
860 if (gpf->framenum == cframe) {
861 return gpf;
862 }
863 }
864
865 return nullptr;
866}
867
869{
870 bGPDframe *gpf = nullptr;
871 bool found = false;
872
873 /* error checking */
874 if (gpl == nullptr) {
875 return nullptr;
876 }
877
878 /* check if there is already an active frame */
879 if (gpl->actframe) {
880 gpf = gpl->actframe;
881
882 /* do not allow any changes to layer's active frame if layer is locked from changes
883 * or if the layer has been set to stay on the current frame
884 */
885 if (gpl->flag & GP_LAYER_FRAMELOCK) {
886 return gpf;
887 }
888 /* do not allow any changes to actframe if frame has painting tag attached to it */
889 if (gpf->flag & GP_FRAME_PAINT) {
890 return gpf;
891 }
892
893 /* try to find matching frame */
894 if (gpf->framenum < cframe) {
895 for (; gpf; gpf = gpf->next) {
896 if (gpf->framenum == cframe) {
897 found = true;
898 break;
899 }
900 /* If this is the last frame or the next frame is at a later time, we found the right
901 * frame. */
902 if (!(gpf->next) || (gpf->next->framenum > cframe)) {
903 found = true;
904 break;
905 }
906 }
907
908 /* set the appropriate frame */
909 if (addnew) {
910 if ((found) && (gpf->framenum == cframe)) {
911 gpl->actframe = gpf;
912 }
913 else if (addnew == GP_GETFRAME_ADD_COPY) {
914 /* The #BKE_gpencil_frame_addcopy function copies the active frame of gpl,
915 * so we need to set the active frame before copying. */
916 gpl->actframe = gpf;
917 gpl->actframe = BKE_gpencil_frame_addcopy(gpl, cframe);
918 }
919 else {
920 gpl->actframe = BKE_gpencil_frame_addnew(gpl, cframe);
921 }
922 }
923 else if (found) {
924 gpl->actframe = gpf;
925 }
926 else {
927 gpl->actframe = static_cast<bGPDframe *>(gpl->frames.last);
928 }
929 }
930 else {
931 for (; gpf; gpf = gpf->prev) {
932 if (gpf->framenum <= cframe) {
933 found = true;
934 break;
935 }
936 }
937
938 /* set the appropriate frame */
939 if (addnew) {
940 if ((found) && (gpf->framenum == cframe)) {
941 gpl->actframe = gpf;
942 }
943 else if (addnew == GP_GETFRAME_ADD_COPY) {
944 /* The #BKE_gpencil_frame_addcopy function copies the active frame of gpl;
945 * so we need to set the active frame before copying. */
946 gpl->actframe = gpf;
947 gpl->actframe = BKE_gpencil_frame_addcopy(gpl, cframe);
948 }
949 else {
950 gpl->actframe = BKE_gpencil_frame_addnew(gpl, cframe);
951 }
952 }
953 else if (found) {
954 gpl->actframe = gpf;
955 }
956 else {
957 gpl->actframe = static_cast<bGPDframe *>(gpl->frames.first);
958 }
959 }
960 }
961 else if (gpl->frames.first) {
962 /* check which of the ends to start checking from */
963 const int first = ((bGPDframe *)(gpl->frames.first))->framenum;
964 const int last = ((bGPDframe *)(gpl->frames.last))->framenum;
965
966 if (abs(cframe - first) > abs(cframe - last)) {
967 /* find gp-frame which is less than or equal to cframe */
968 for (gpf = static_cast<bGPDframe *>(gpl->frames.last); gpf; gpf = gpf->prev) {
969 if (gpf->framenum <= cframe) {
970 found = true;
971 break;
972 }
973 }
974 }
975 else {
976 /* find gp-frame which is less than or equal to cframe */
977 for (gpf = static_cast<bGPDframe *>(gpl->frames.first); gpf; gpf = gpf->next) {
978 if (gpf->framenum <= cframe) {
979 found = true;
980 break;
981 }
982 }
983 }
984
985 /* set the appropriate frame */
986 if (addnew) {
987 if ((found) && (gpf->framenum == cframe)) {
988 gpl->actframe = gpf;
989 }
990 else {
991 gpl->actframe = BKE_gpencil_frame_addnew(gpl, cframe);
992 }
993 }
994 else if (found) {
995 gpl->actframe = gpf;
996 }
997 else {
998 /* If delete first frame, need to find one. */
999 if (gpl->frames.first != nullptr) {
1000 gpl->actframe = static_cast<bGPDframe *>(gpl->frames.first);
1001 }
1002 else {
1003 /* Unresolved erogenous situation! */
1004 CLOG_STR_ERROR(&LOG, "cannot find appropriate gp-frame");
1005 /* `gpl->actframe` should still be nullptr. */
1006 }
1007 }
1008 }
1009 else {
1010 /* currently no frames (add if allowed to) */
1011 if (addnew) {
1012 gpl->actframe = BKE_gpencil_frame_addnew(gpl, cframe);
1013 }
1014 else {
1015 /* don't do anything... this may be when no frames yet! */
1016 /* gpl->actframe should still be nullptr */
1017 }
1018 }
1019
1020 /* Don't select first frame if greater than current frame. */
1021 if ((gpl->actframe != nullptr) && (gpl->actframe == gpl->frames.first) &&
1022 (gpl->actframe->framenum > cframe))
1023 {
1024 gpl->actframe = nullptr;
1025 }
1026
1027 /* return */
1028 return gpl->actframe;
1029}
1030
1032{
1033 bool changed = false;
1034
1035 /* error checking */
1036 if (ELEM(nullptr, gpl, gpf)) {
1037 return false;
1038 }
1039
1040 /* if this frame was active, make the previous frame active instead
1041 * since it's tricky to set active frame otherwise
1042 */
1043 if (gpl->actframe == gpf) {
1044 gpl->actframe = gpf->prev;
1045 }
1046
1047 /* free the frame and its data */
1048 changed = BKE_gpencil_free_strokes(gpf);
1049 BLI_freelinkN(&gpl->frames, gpf);
1050
1051 return changed;
1052}
1053
1055{
1056 if (name[0] == '\0') {
1057 return nullptr;
1058 }
1059 return static_cast<bGPDlayer *>(BLI_findstring(&gpd->layers, name, offsetof(bGPDlayer, info)));
1060}
1061
1063{
1065 gpl->act_mask--;
1066 CLAMP_MIN(gpl->act_mask, 0);
1067}
1068
1069void BKE_gpencil_layer_mask_remove_ref(bGPdata *gpd, const char *name)
1070{
1071 bGPDlayer_Mask *mask_next;
1072
1073 LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
1074 for (bGPDlayer_Mask *mask = static_cast<bGPDlayer_Mask *>(gpl->mask_layers.first); mask;
1075 mask = mask_next)
1076 {
1077 mask_next = mask->next;
1078 if (STREQ(mask->name, name)) {
1080 }
1081 }
1082 }
1083}
1084
1085static int gpencil_cb_sort_masks(const void *arg1, const void *arg2)
1086{
1087 /* sort is inverted as layer list. */
1088 const bGPDlayer_Mask *mask1 = static_cast<const bGPDlayer_Mask *>(arg1);
1089 const bGPDlayer_Mask *mask2 = static_cast<const bGPDlayer_Mask *>(arg2);
1090 int val = 0;
1091
1092 if (mask1->sort_index < mask2->sort_index) {
1093 val = 1;
1094 }
1095 else if (mask1->sort_index > mask2->sort_index) {
1096 val = -1;
1097 }
1098
1099 return val;
1100}
1101
1103{
1104 /* Update sort index. */
1106 bGPDlayer *gpl_mask = BKE_gpencil_layer_named_get(gpd, mask->name);
1107 if (gpl_mask != nullptr) {
1108 mask->sort_index = BLI_findindex(&gpd->layers, gpl_mask);
1109 }
1110 else {
1111 mask->sort_index = 0;
1112 }
1113 }
1115}
1116
1118{
1119 LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
1121 }
1122}
1123
1125{
1127 LISTBASE_FOREACH (bGPDlayer_Mask *, mask_src, &gpl_src->mask_layers) {
1128 bGPDlayer_Mask *mask_dst = static_cast<bGPDlayer_Mask *>(MEM_dupallocN(mask_src));
1129 mask_dst->prev = mask_dst->next = nullptr;
1130 BLI_addtail(&gpl_dst->mask_layers, mask_dst);
1131 }
1132}
1133
1134static int gpencil_cb_cmp_frame(void *thunk, const void *a, const void *b)
1135{
1136 const bGPDframe *frame_a = static_cast<const bGPDframe *>(a);
1137 const bGPDframe *frame_b = static_cast<const bGPDframe *>(b);
1138
1139 if (frame_a->framenum < frame_b->framenum) {
1140 return -1;
1141 }
1142 if (frame_a->framenum > frame_b->framenum) {
1143 return 1;
1144 }
1145 if (thunk != nullptr) {
1146 *((bool *)thunk) = true;
1147 }
1148 /* Sort selected last. */
1149 if ((frame_a->flag & GP_FRAME_SELECT) && ((frame_b->flag & GP_FRAME_SELECT) == 0)) {
1150 return 1;
1151 }
1152 return 0;
1153}
1154
1155void BKE_gpencil_layer_frames_sort(bGPDlayer *gpl, bool *r_has_duplicate_frames)
1156{
1157 BLI_listbase_sort_r(&gpl->frames, gpencil_cb_cmp_frame, r_has_duplicate_frames);
1158}
1159
1161{
1162 /* error checking */
1163 if (ELEM(nullptr, gpd, gpd->layers.first)) {
1164 return nullptr;
1165 }
1166
1167 /* loop over layers until found (assume only one active) */
1168 LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
1169 if (gpl->flag & GP_LAYER_ACTIVE) {
1170 return gpl;
1171 }
1172 }
1173
1174 /* no active layer found */
1175 return nullptr;
1176}
1177
1179{
1180 /* error checking */
1181 if (ELEM(nullptr, gpd, gpd->layers.first, active)) {
1182 return;
1183 }
1184
1185 /* loop over layers deactivating all */
1186 LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
1187 gpl->flag &= ~GP_LAYER_ACTIVE;
1188 if (gpd->flag & GP_DATA_AUTOLOCK_LAYERS) {
1189 gpl->flag |= GP_LAYER_LOCKED;
1190 }
1191 }
1192
1193 /* set as active one */
1194 active->flag |= GP_LAYER_ACTIVE;
1195 if (gpd->flag & GP_DATA_AUTOLOCK_LAYERS) {
1196 active->flag &= ~GP_LAYER_LOCKED;
1197 }
1198}
1199
1200void BKE_gpencil_layer_autolock_set(bGPdata *gpd, const bool unlock)
1201{
1202 BLI_assert(gpd != nullptr);
1203
1204 if (gpd->flag & GP_DATA_AUTOLOCK_LAYERS) {
1205 bGPDlayer *layer_active = BKE_gpencil_layer_active_get(gpd);
1206
1207 /* Lock all other layers */
1208 LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
1209 /* unlock active layer */
1210 if (gpl == layer_active) {
1211 gpl->flag &= ~GP_LAYER_LOCKED;
1212 }
1213 else {
1214 gpl->flag |= GP_LAYER_LOCKED;
1215 }
1216 }
1217 }
1218 else {
1219 /* If disable is better unlock all layers by default or it looks there is
1220 * a problem in the UI because the user expects all layers will be unlocked
1221 */
1222 if (unlock) {
1223 LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
1224 gpl->flag &= ~GP_LAYER_LOCKED;
1225 }
1226 }
1227 }
1228}
1229
1231{
1232 /* error checking */
1233 if (ELEM(nullptr, gpd, gpl)) {
1234 return;
1235 }
1236
1237 /* free layer */
1239
1240 /* Free Masks. */
1242
1243 /* Remove any reference to that layer in masking lists. */
1245
1246 /* free icon providing preview of icon color */
1248
1249 BLI_freelinkN(&gpd->layers, gpl);
1250}
1251
1253{
1254 BLI_assert(brush);
1256 if (brush->gpencil_settings->material != ma) {
1257 if (brush->gpencil_settings->material) {
1259 }
1260 if (ma) {
1261 id_us_plus(&ma->id);
1262 }
1263 brush->gpencil_settings->material = ma;
1265 }
1266}
1267
1269{
1270 const char *hexcol[] = {
1271 "FFFFFF", "F2F2F2", "E6E6E6", "D9D9D9", "CCCCCC", "BFBFBF", "B2B2B2", "A6A6A6", "999999",
1272 "8C8C8C", "808080", "737373", "666666", "595959", "4C4C4C", "404040", "333333", "262626",
1273 "1A1A1A", "000000", "F2FC24", "FFEA00", "FEA711", "FE8B68", "FB3B02", "FE3521", "D00000",
1274 "A81F3D", "780422", "2B0000", "F1E2C5", "FEE4B3", "FEDABB", "FEC28E", "D88F57", "BD6340",
1275 "A2402B", "63352D", "6B2833", "34120C", "E7CB8F", "D1B38B", "C1B17F", "D7980B", "FFB100",
1276 "FE8B00", "FF6A00", "B74100", "5F3E1D", "3B2300", "FECADA", "FE65CB", "FE1392", "DD3062",
1277 "C04A6D", "891688", "4D2689", "441521", "2C1139", "241422", "FFFF7D", "FFFF00", "FF7F00",
1278 "FF7D7D", "FF7DFF", "FF00FE", "FF007F", "FF0000", "7F0000", "0A0A00", "F6FDFF", "E9F7FF",
1279 "CFE6FE", "AAC7FE", "77B3FE", "1E74FD", "0046AA", "2F4476", "003052", "0E0E25", "EEF5F0",
1280 "D6E5DE", "ACD8B9", "6CADC6", "42A9AF", "007F7F", "49675C", "2E4E4E", "1D3239", "0F1C21",
1281 "D8FFF4", "B8F4F5", "AECCB5", "76C578", "358757", "409B68", "468768", "1F512B", "2A3C37",
1282 "122E1D", "EFFFC9", "E6F385", "BCF51C", "D4DC18", "82D322", "5C7F00", "59932B", "297F00",
1283 "004320", "1C3322", "00FF7F", "00FF00", "7DFF7D", "7DFFFF", "00FFFF", "7D7DFF", "7F00FF",
1284 "0000FF", "3F007F", "00007F"};
1285
1286 ToolSettings *ts = scene->toolsettings;
1287 if (ts->gp_paint->paint.palette != nullptr) {
1288 return;
1289 }
1290
1291 /* Try to find the default palette. */
1292 const char *palette_id = "Palette";
1293 Palette *palette = static_cast<Palette *>(
1294 BLI_findstring(&bmain->palettes, palette_id, offsetof(ID, name) + 2));
1295
1296 if (palette == nullptr) {
1297 /* Fall back to the first palette. */
1298 palette = static_cast<Palette *>(bmain->palettes.first);
1299 }
1300
1301 if (palette == nullptr) {
1302 /* Fall back to creating a palette. */
1303 palette = BKE_palette_add(bmain, palette_id);
1304 id_us_min(&palette->id);
1305
1306 /* Create Colors. */
1307 for (int i = 0; i < ARRAY_SIZE(hexcol); i++) {
1308 PaletteColor *palcol = BKE_palette_color_add(palette);
1309 hex_to_rgb(hexcol[i], palcol->rgb, palcol->rgb + 1, palcol->rgb + 2);
1310 }
1311 }
1312
1313 BLI_assert(palette != nullptr);
1314 BKE_paint_palette_set(&ts->gp_paint->paint, palette);
1316}
1317
Blender kernel action and pose functionality.
void BKE_brush_tag_unsaved_changes(Brush *brush)
Definition brush.cc:720
support for deformation groups and hooks.
void BKE_defvert_blend_write(BlendWriter *writer, int count, const MDeformVert *dvlist)
Definition deform.cc:1639
void BKE_defbase_blend_write(BlendWriter *writer, const ListBase *defbase)
Definition deform.cc:1632
void BKE_defvert_array_copy(MDeformVert *dst, const MDeformVert *src, int totvert)
Definition deform.cc:1027
void BKE_defgroup_copy_list(ListBase *outbase, const ListBase *inbase)
Definition deform.cc:71
void BKE_defvert_blend_read(BlendDataReader *reader, int count, MDeformVert *mdverts)
Definition deform.cc:1656
eGP_GetFrame_Mode
@ GP_GETFRAME_ADD_COPY
bool BKE_icon_delete(int icon_id)
Definition icons.cc:455
@ IDTYPE_FLAGS_APPEND_IS_REUSABLE
Definition BKE_idtype.hh:44
IDTypeInfo IDType_ID_GD_LEGACY
void * BKE_libblock_alloc(Main *bmain, short type, const char *name, int flag) ATTR_WARN_UNUSED_RESULT
Definition lib_id.cc:1428
void id_us_plus(ID *id)
Definition lib_id.cc:353
ID * BKE_id_copy(Main *bmain, const ID *id)
Definition lib_id.cc:772
void id_us_min(ID *id)
Definition lib_id.cc:361
void BKE_id_blend_write(BlendWriter *writer, ID *id)
Definition lib_id.cc:2611
#define BKE_LIB_FOREACHID_PROCESS_IDSUPER(data_, id_super_, cb_flag_)
@ IDWALK_CB_USER
@ IDWALK_CB_NOP
General operations, lookup, etc. for materials.
PaletteColor * BKE_palette_color_add(Palette *palette)
Definition paint.cc:1390
Palette * BKE_palette_add(Main *bmain, const char *name)
Definition paint.cc:1384
void BKE_paint_palette_set(Paint *paint, Palette *palette)
Definition paint.cc:1348
#define BLI_assert(a)
Definition BLI_assert.h:46
int BLI_findindex(const ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:586
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
void * BLI_findstring(const ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:608
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void BLI_freelinkN(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:270
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
#define LISTBASE_FOREACH_BACKWARD(type, var, list)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:332
void BLI_addhead(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:91
void void BLI_listbase_sort(ListBase *listbase, int(*cmp)(const void *, const void *)) ATTR_NONNULL(1
void void void BLI_listbase_sort_r(ListBase *listbase, int(*cmp)(void *, const void *, const void *), void *thunk) ATTR_NONNULL(1
void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:371
void hex_to_rgb(const char *hexcol, float *r_r, float *r_g, float *r_b)
void mul_m4_v3(const float M[4][4], float r[3])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
void loc_eul_size_to_mat4(float R[4][4], const float loc[3], const float eul[3], const float size[3])
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE bool is_one_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE bool is_zero_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v3_fl(float r[3], float f)
MINLINE void zero_v3(float r[3])
#define STRNCPY_UTF8(dst, src)
void BLI_uniquename(const struct ListBase *list, void *vlink, const char *defname, char delim, int name_offset, size_t name_maxncpy) ATTR_NONNULL(1
#define ARRAY_SIZE(arr)
#define ARRAY_SET_ITEMS(...)
#define ELEM(...)
#define STREQ(a, b)
#define CLAMP_MIN(a, b)
#define BLO_write_id_struct(writer, struct_name, id_address, id)
#define BLO_write_struct(writer, struct_name, data_ptr)
#define BLO_write_struct_array(writer, struct_name, array_size, data_ptr)
#define BLO_read_struct_list(reader, struct_name, list)
#define BLO_read_struct_array(reader, struct_name, array_size, ptr_p)
#define BLO_write_struct_list(writer, struct_name, list_ptr)
#define BLO_read_struct(reader, struct_name, ptr_p)
void BLO_write_pointer_array(BlendWriter *writer, int64_t num, const void *data_ptr)
void BLO_read_pointer_array(BlendDataReader *reader, int64_t array_size, void **ptr_p)
Definition readfile.cc:5402
#define BLT_I18NCONTEXT_ID_GPENCIL
#define DATA_(msgid)
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:182
#define CLOG_STR_ERROR(clg_ref, str)
Definition CLG_log.h:188
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:962
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:982
@ INDEX_ID_GD_LEGACY
Definition DNA_ID.h:1199
@ ID_GD_LEGACY
@ GP_ONION_MODE_RELATIVE
#define GP_DEFAULT_CURVE_EDIT_CORNER_ANGLE
#define GP_DEFAULT_PIX_FACTOR
#define GP_DEFAULT_CURVE_RESOLUTION
#define GP_DEFAULT_GRID_LINES
#define GP_DEFAULT_CURVE_ERROR
@ GP_ONION_GHOST_NEXTCOL
@ GP_ONION_GHOST_PREVCOL
@ GP_DATA_SHOW_ONIONSKINS
@ GP_DATA_CURVE_ADAPTIVE_RESOLUTION
@ GP_DATA_STROKE_WEIGHTMODE
@ GP_DATA_STROKE_VERTEXMODE
@ GP_DATA_STROKE_PAINTMODE
@ GP_DATA_STROKE_SCULPTMODE
@ GP_DATA_AUTOLOCK_LAYERS
@ GP_DATA_STROKE_EDITMODE
Read Guarded memory(de)allocation.
#define U
BMesh const char void * data
#define offsetof(t, d)
static void greasepencil_copy_data(Main *, std::optional< Library * >, ID *id_dst, const ID *id_src, const int)
bGPDframe * BKE_gpencil_frame_addcopy(bGPDlayer *gpl, int cframe)
bGPDframe * BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src, const bool dup_strokes)
void BKE_gpencil_tag(bGPdata *gpd)
void BKE_gpencil_free_stroke_weights(bGPDstroke *gps)
bGPDframe * BKE_gpencil_layer_frame_get(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew)
bGPDstroke * BKE_gpencil_stroke_duplicate(bGPDstroke *gps_src, const bool dup_points, const bool)
void BKE_gpencil_layer_mask_copy(const bGPDlayer *gpl_src, bGPDlayer *gpl_dst)
bGPDlayer * BKE_gpencil_layer_named_get(bGPdata *gpd, const char *name)
bGPdata * BKE_gpencil_data_addnew(Main *bmain, const char name[])
bGPDlayer * BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src, const bool dup_frames, const bool dup_strokes)
void BKE_gpencil_free_frames(bGPDlayer *gpl)
static int gpencil_cb_sort_masks(const void *arg1, const void *arg2)
bGPDlayer * BKE_gpencil_layer_active_get(bGPdata *gpd)
void BKE_gpencil_free_point_weights(MDeformVert *dvert)
void BKE_gpencil_layer_mask_remove(bGPDlayer *gpl, bGPDlayer_Mask *mask)
bool BKE_gpencil_layer_is_editable(const bGPDlayer *gpl)
void BKE_gpencil_free_stroke_editcurve(bGPDstroke *gps)
void BKE_gpencil_layer_autolock_set(bGPdata *gpd, const bool unlock)
void BKE_gpencil_free_layers(ListBase *list)
void BKE_gpencil_stroke_weights_duplicate(bGPDstroke *gps_src, bGPDstroke *gps_dst)
static void greasepencil_blend_write(BlendWriter *writer, ID *id, const void *id_address)
static void greasepencil_free_data(ID *id)
bool BKE_gpencil_free_strokes(bGPDframe *gpf)
void BKE_gpencil_layer_frames_sort(bGPDlayer *gpl, bool *r_has_duplicate_frames)
void BKE_gpencil_palette_ensure(Main *bmain, Scene *scene)
void BKE_gpencil_free_legacy_palette_data(ListBase *list)
void BKE_gpencil_free_layer_masks(bGPDlayer *gpl)
bGPdata * BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool internal_copy)
static int gpencil_cb_cmp_frame(void *thunk, const void *a, const void *b)
bGPDframe * BKE_gpencil_layer_frame_find(bGPDlayer *gpl, int cframe)
static void greasepencil_foreach_id(ID *id, LibraryForeachIDData *data)
void BKE_gpencil_layer_mask_remove_ref(bGPdata *gpd, const char *name)
bGPDframe * BKE_gpencil_frame_addnew(bGPDlayer *gpl, int cframe)
void BKE_gpencil_blend_read_data(BlendDataReader *reader, bGPdata *gpd)
bool BKE_gpencil_layer_frame_delete(bGPDlayer *gpl, bGPDframe *gpf)
void BKE_gpencil_layer_mask_sort_all(bGPdata *gpd)
void BKE_gpencil_free_data(bGPdata *gpd, bool)
void BKE_gpencil_free_stroke(bGPDstroke *gps)
bGPDlayer * BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, const bool setactive, const bool add_to_header)
void BKE_gpencil_brush_material_set(Brush *brush, Material *ma)
static void greasepencil_blend_read_data(BlendDataReader *reader, ID *id)
void BKE_gpencil_layer_active_set(bGPdata *gpd, bGPDlayer *active)
void BKE_gpencil_layer_mask_sort(bGPdata *gpd, bGPDlayer *gpl)
void BKE_gpencil_layer_delete(bGPdata *gpd, bGPDlayer *gpl)
#define active
#define abs
#define FILTER_ID_GD_LEGACY
#define FILTER_ID_MA
#define MEM_SAFE_FREE(v)
#define ID_IS_LINKED(_id)
#define LOG(severity)
Definition log.h:32
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
static ulong state[N]
struct Material * material
struct BrushGpencilSettings * gpencil_settings
Definition DNA_ID.h:404
void * last
void * first
struct MDeformWeight * dw
ListBase palettes
Definition BKE_main.hh:273
struct Palette * palette
struct ToolSettings * toolsettings
GpVertexPaint * gp_vertexpaint
bGPDcurve_point * curve_points
struct bGPDframe * next
struct bGPDframe * prev
struct bGPDlayer_Mask * prev
struct bGPDlayer_Mask * next
struct bGPDlayer * next
bGPDlayer_Runtime runtime
struct bGPDlayer * prev
struct bGPDstroke * prev
bGPDtriangle * triangles
struct bGPDcurve * editcurve
struct MDeformVert * dvert
struct bGPDstroke * next
ListBase vertex_group_names
struct Material ** mat
bGPdata_Runtime runtime
i
Definition text_draw.cc:230
#define N_(msgid)