Blender V5.0
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"
43#include "BKE_gpencil_legacy.h"
44#include "BKE_icons.h"
45#include "BKE_idtype.hh"
46#include "BKE_image.hh"
47#include "BKE_lib_id.hh"
48#include "BKE_lib_query.hh"
49#include "BKE_main.hh"
50#include "BKE_material.hh"
51#include "BKE_paint.hh"
52
53#include "DEG_depsgraph.hh"
54
55#include "BLI_math_color.h"
56#include "BLI_string_utf8.h"
57
58#include "BLO_read_write.hh"
59
61
62static CLG_LogRef LOG = {"geom.gpencil"};
63
64static void greasepencil_copy_data(Main * /*bmain*/,
65 std::optional<Library *> /*owner_library*/,
66 ID *id_dst,
67 const ID *id_src,
68 const int /*flag*/)
69{
70 bGPdata *gpd_dst = (bGPdata *)id_dst;
71 const bGPdata *gpd_src = (const bGPdata *)id_src;
72
73 /* duplicate material array */
74 if (gpd_src->mat) {
75 gpd_dst->mat = static_cast<Material **>(MEM_dupallocN(gpd_src->mat));
76 }
77
79
80 /* copy layers */
81 BLI_listbase_clear(&gpd_dst->layers);
82 LISTBASE_FOREACH (bGPDlayer *, gpl_src, &gpd_src->layers) {
83 /* make a copy of source layer and its data */
84
85 /* TODO: here too could add unused flags... */
86 bGPDlayer *gpl_dst = BKE_gpencil_layer_duplicate(gpl_src, true, true);
87
88 /* Apply local layer transform to all frames. Calc the active frame is not enough
89 * because onion skin can use more frames. This is more slow but required here. */
90 if (gpl_dst->actframe != nullptr) {
91 bool transformed = (!is_zero_v3(gpl_dst->location) || !is_zero_v3(gpl_dst->rotation) ||
92 !is_one_v3(gpl_dst->scale));
93 if (transformed) {
95 gpl_dst->layer_mat, gpl_dst->location, gpl_dst->rotation, gpl_dst->scale);
96 bool do_onion = ((gpl_dst->onion_flag & GP_LAYER_ONIONSKIN) != 0);
97 bGPDframe *init_gpf = static_cast<bGPDframe *>((do_onion) ? gpl_dst->frames.first :
98 gpl_dst->actframe);
99 for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
100 LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
101 bGPDspoint *pt;
102 int i;
103 for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
104 mul_m4_v3(gpl_dst->layer_mat, &pt->x);
105 }
106 }
107 /* if not onion, exit loop. */
108 if (!do_onion) {
109 break;
110 }
111 }
112 }
113 }
114
115 BLI_addtail(&gpd_dst->layers, gpl_dst);
116 }
117}
118
120{
121 /* Really not ideal, but for now will do... In theory custom behaviors like not freeing cache
122 * should be handled through specific API, and not be part of the generic one. */
123 BKE_gpencil_free_data((bGPdata *)id, true);
124}
125
127{
128 bGPdata *gpencil = (bGPdata *)id;
129 /* materials */
130 for (int i = 0; i < gpencil->totcol; i++) {
132 }
133
134 LISTBASE_FOREACH (bGPDlayer *, gplayer, &gpencil->layers) {
136 }
137}
138
139static void greasepencil_blend_write(BlendWriter *writer, ID *id, const void *id_address)
140{
141 bGPdata *gpd = (bGPdata *)id;
142
143 /* Clean up, important in undo case to reduce false detection of changed data-blocks. */
144 /* XXX not sure why the whole run-time data is not cleared in reading code,
145 * for now mimicking it here. */
146 gpd->runtime.sbuffer = nullptr;
147 gpd->runtime.sbuffer_used = 0;
148 gpd->runtime.sbuffer_size = 0;
149
150 /* write gpd data block to file */
151 BLO_write_id_struct(writer, bGPdata, id_address, &gpd->id);
152 BKE_id_blend_write(writer, &gpd->id);
153
155
156 BLO_write_pointer_array(writer, gpd->totcol, gpd->mat);
157
158 /* write grease-pencil layers to file */
159 BLO_write_struct_list(writer, bGPDlayer, &gpd->layers);
160 LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
161 /* Write mask list. */
162 BLO_write_struct_list(writer, bGPDlayer_Mask, &gpl->mask_layers);
163 /* write this layer's frames to file */
164 BLO_write_struct_list(writer, bGPDframe, &gpl->frames);
165 LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
166 /* write strokes */
167 BLO_write_struct_list(writer, bGPDstroke, &gpf->strokes);
168 LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
169 BLO_write_struct_array(writer, bGPDspoint, gps->totpoints, gps->points);
170 BLO_write_struct_array(writer, bGPDtriangle, gps->tot_triangles, gps->triangles);
171 BKE_defvert_blend_write(writer, gps->totpoints, gps->dvert);
172 if (gps->editcurve != nullptr) {
173 bGPDcurve *gpc = gps->editcurve;
174 BLO_write_struct(writer, bGPDcurve, gpc);
176 writer, bGPDcurve_point, gpc->tot_curve_points, gpc->curve_points);
177 }
178 }
179 }
180 }
181}
182
184{
185 /* We must firstly have some grease-pencil data to link! */
186 if (gpd == nullptr) {
187 return;
188 }
189
190 /* Ensure full object-mode for linked grease pencil. */
191 if (ID_IS_LINKED(gpd)) {
197 }
198
199 /* init stroke buffer */
200 gpd->runtime.sbuffer = nullptr;
201 gpd->runtime.sbuffer_used = 0;
202 gpd->runtime.sbuffer_size = 0;
203
204 /* Relink palettes (old palettes deprecated, only to convert old files). */
205 BLO_read_struct_list(reader, bGPDpalette, &gpd->palettes);
206 if (gpd->palettes.first != nullptr) {
207 LISTBASE_FOREACH (bGPDpalette *, palette, &gpd->palettes) {
208 BLO_read_struct_list(reader, PaletteColor, &palette->colors);
209 }
210 }
211
213
214 /* Materials. */
215 BLO_read_pointer_array(reader, gpd->totcol, (void **)&gpd->mat);
216
217 /* Relink layers. */
218 BLO_read_struct_list(reader, bGPDlayer, &gpd->layers);
219
220 LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
221 /* Relink frames. */
222 BLO_read_struct_list(reader, bGPDframe, &gpl->frames);
223
224 BLO_read_struct(reader, bGPDframe, &gpl->actframe);
225
226 gpl->runtime.icon_id = 0;
227
228 /* Relink masks. */
229 BLO_read_struct_list(reader, bGPDlayer_Mask, &gpl->mask_layers);
230
231 LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
232 /* Relink strokes (and their points). */
233 BLO_read_struct_list(reader, bGPDstroke, &gpf->strokes);
234
235 LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
236 /* Relink stroke points array. */
237 BLO_read_struct_array(reader, bGPDspoint, gps->totpoints, &gps->points);
238 /* Relink geometry. */
239 BLO_read_struct_array(reader, bGPDtriangle, gps->tot_triangles, &gps->triangles);
240
241 /* Relink stroke edit curve. */
242 BLO_read_struct(reader, bGPDcurve, &gps->editcurve);
243 if (gps->editcurve != nullptr) {
244 /* Relink curve point array. */
245 bGPDcurve *gpc = gps->editcurve;
247 reader, bGPDcurve_point, gpc->tot_curve_points, &gps->editcurve->curve_points);
248 }
249
250 /* Relink weight data. */
251 if (gps->dvert) {
252 BLO_read_struct_array(reader, MDeformVert, gps->totpoints, &gps->dvert);
253 BKE_defvert_blend_read(reader, gps->totpoints, gps->dvert);
254 }
255 }
256 }
257 }
258}
259
261{
262 bGPdata *gpd = (bGPdata *)id;
263 BKE_gpencil_blend_read_data(reader, gpd);
264}
265
267 /*id_code*/ bGPdata::id_type,
268 /*id_filter*/ FILTER_ID_GD_LEGACY,
269 /*dependencies_id_types*/ FILTER_ID_MA,
270 /*main_listbase_index*/ INDEX_ID_GD_LEGACY,
271 /*struct_size*/ sizeof(bGPdata),
272 /*name*/ "Annotation",
273 /*name_plural*/ N_("annotations"),
274 /*translation_context*/ BLT_I18NCONTEXT_ID_GPENCIL,
276 /*asset_type_info*/ nullptr,
277
278 /*init_data*/ nullptr,
279 /*copy_data*/ greasepencil_copy_data,
280 /*free_data*/ greasepencil_free_data,
281 /*make_local*/ nullptr,
282 /*foreach_id*/ greasepencil_foreach_id,
283 /*foreach_cache*/ nullptr,
284 /*foreach_path*/ nullptr,
285 /*foreach_working_space_color*/ nullptr,
286 /*owner_pointer_get*/ nullptr,
287
288 /*blend_write*/ greasepencil_blend_write,
289 /*blend_read_data*/ greasepencil_blend_read_data,
290 /*blend_read_after_liblink*/ nullptr,
291
292 /*blend_read_undo_preserve*/ nullptr,
293
294 /*lib_override_apply_post*/ nullptr,
295};
296
297/* ************************************************** */
298/* Memory Management */
299
301{
302 if (dvert == nullptr) {
303 return;
304 }
305 MEM_SAFE_FREE(dvert->dw);
306}
307
309{
310 if (gps == nullptr) {
311 return;
312 }
313
314 if (gps->dvert == nullptr) {
315 return;
316 }
317
318 for (int i = 0; i < gps->totpoints; i++) {
319 MDeformVert *dvert = &gps->dvert[i];
321 }
322}
323
325{
326 if (gps == nullptr) {
327 return;
328 }
329 bGPDcurve *editcurve = gps->editcurve;
330 if (editcurve == nullptr) {
331 return;
332 }
333 MEM_freeN(editcurve->curve_points);
334 MEM_freeN(editcurve);
335 gps->editcurve = nullptr;
336}
337
339{
340 if (gps == nullptr) {
341 return;
342 }
343 /* free stroke memory arrays, then stroke itself */
344 if (gps->points) {
345 MEM_freeN(gps->points);
346 }
347 if (gps->dvert) {
349 MEM_freeN(gps->dvert);
350 }
351 if (gps->triangles) {
352 MEM_freeN(gps->triangles);
353 }
354 if (gps->editcurve != nullptr) {
356 }
357
358 MEM_freeN(gps);
359}
360
362{
363 bool changed = (BLI_listbase_is_empty(&gpf->strokes) == false);
364
365 /* free strokes */
368 }
370
371 return changed;
372}
373
375{
376 bGPDframe *gpf_next;
377
378 /* error checking */
379 if (gpl == nullptr) {
380 return;
381 }
382
383 /* free frames */
384 for (bGPDframe *gpf = static_cast<bGPDframe *>(gpl->frames.first); gpf; gpf = gpf_next) {
385 gpf_next = gpf->next;
386
387 /* free strokes and their associated memory */
389 BLI_freelinkN(&gpl->frames, gpf);
390 }
391 gpl->actframe = nullptr;
392}
393
395{
396 /* Free masks. */
397 bGPDlayer_Mask *mask_next = nullptr;
398 for (bGPDlayer_Mask *mask = static_cast<bGPDlayer_Mask *>(gpl->mask_layers.first); mask;
399 mask = mask_next)
400 {
401 mask_next = mask->next;
403 }
404}
406{
407 bGPDlayer *gpl_next;
408
409 /* error checking */
410 if (list == nullptr) {
411 return;
412 }
413
414 /* delete layers */
415 for (bGPDlayer *gpl = static_cast<bGPDlayer *>(list->first); gpl; gpl = gpl_next) {
416 gpl_next = gpl->next;
417
418 /* free layers and their data */
420
421 /* Free masks. */
423
424 BLI_freelinkN(list, gpl);
425 }
426}
427
429{
430 LISTBASE_FOREACH_MUTABLE (bGPDpalette *, palette, list) {
431 BLI_freelistN(&palette->colors);
432 MEM_freeN(palette);
433 }
434 BLI_listbase_clear(list);
435}
436
437void BKE_gpencil_free_data(bGPdata *gpd, bool /*free_all*/)
438{
439 /* free layers */
442
443 /* materials */
444 MEM_SAFE_FREE(gpd->mat);
445
447}
448
453
454/* ************************************************** */
455/* Container Creation */
456
458{
459 bGPDframe *gpf = nullptr, *gf = nullptr;
460 short state = 0;
461
462 /* error checking */
463 if (gpl == nullptr) {
464 return nullptr;
465 }
466
467 /* allocate memory for this frame */
468 gpf = MEM_callocN<bGPDframe>("bGPDframe");
469 gpf->framenum = cframe;
470
471 /* find appropriate place to add frame */
472 if (gpl->frames.first) {
473 for (gf = static_cast<bGPDframe *>(gpl->frames.first); gf; gf = gf->next) {
474 /* check if frame matches one that is supposed to be added */
475 if (gf->framenum == cframe) {
476 state = -1;
477 break;
478 }
479
480 /* if current frame has already exceeded the frame to add, add before */
481 if (gf->framenum > cframe) {
482 BLI_insertlinkbefore(&gpl->frames, gf, gpf);
483 state = 1;
484 break;
485 }
486 }
487 }
488
489 /* check whether frame was added successfully */
490 if (state == -1) {
492 &LOG, "Frame (%d) existed already for this layer_active. Using existing frame", cframe);
493
494 /* free the newly created one, and use the old one instead */
495 MEM_freeN(gpf);
496
497 /* return existing frame instead... */
498 BLI_assert(gf != nullptr);
499 gpf = gf;
500 }
501 else if (state == 0) {
502 /* add to end then! */
503 BLI_addtail(&gpl->frames, gpf);
504 }
505
506 /* return frame */
507 return gpf;
508}
509
511{
512 bGPDframe *new_frame;
513 bool found = false;
514
515 /* Error checking/handling */
516 if (gpl == nullptr) {
517 /* no layer */
518 return nullptr;
519 }
520 if (gpl->actframe == nullptr) {
521 /* no active frame, so just create a new one from scratch */
522 return BKE_gpencil_frame_addnew(gpl, cframe);
523 }
524
525 /* Create a copy of the frame */
526 new_frame = BKE_gpencil_frame_duplicate(gpl->actframe, true);
527
528 /* Find frame to insert it before */
529 LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
530 if (gpf->framenum > cframe) {
531 /* Add it here */
532 BLI_insertlinkbefore(&gpl->frames, gpf, new_frame);
533
534 found = true;
535 break;
536 }
537 if (gpf->framenum == cframe) {
538 /* This only happens when we're editing with frame-lock on.
539 * - Delete the new frame and don't do anything else here.
540 */
541 BKE_gpencil_free_strokes(new_frame);
542 MEM_freeN(new_frame);
543 new_frame = nullptr;
544
545 found = true;
546 break;
547 }
548 }
549
550 if (found == false) {
551 /* Add new frame to the end */
552 BLI_addtail(&gpl->frames, new_frame);
553 }
554
555 /* Ensure that frame is set up correctly, and return it */
556 if (new_frame) {
557 new_frame->framenum = cframe;
558 gpl->actframe = new_frame;
559 }
560
561 return new_frame;
562}
563
565 const char *name,
566 const bool setactive,
567 const bool add_to_header)
568{
569 bGPDlayer *gpl = nullptr;
570 bGPDlayer *gpl_active = nullptr;
571
572 /* check that list is ok */
573 if (gpd == nullptr) {
574 return nullptr;
575 }
576
577 /* allocate memory for frame and add to end of list */
578 gpl = MEM_callocN<bGPDlayer>("bGPDlayer");
579
580 gpl_active = BKE_gpencil_layer_active_get(gpd);
581
582 /* Add to data-block. */
583 if (add_to_header) {
584 BLI_addhead(&gpd->layers, gpl);
585 }
586 else {
587 if (gpl_active == nullptr) {
588 BLI_addtail(&gpd->layers, gpl);
589 }
590 else {
591 /* if active layer, add after that layer */
592 BLI_insertlinkafter(&gpd->layers, gpl_active, gpl);
593 }
594 }
595 /* annotation vs GP Object behavior is slightly different */
596 if (gpd->flag & GP_DATA_ANNOTATIONS) {
597 /* set default color of new strokes for this layer */
598 copy_v4_v4(gpl->color, U.gpencil_new_layer_col);
599 gpl->opacity = 1.0f;
600
601 /* set default thickness of new strokes for this layer */
602 gpl->thickness = 3;
603
604 /* Onion colors */
605 ARRAY_SET_ITEMS(gpl->gcolor_prev, 0.302f, 0.851f, 0.302f);
606 ARRAY_SET_ITEMS(gpl->gcolor_next, 0.250f, 0.1f, 1.0f);
607 }
608 else {
609 /* thickness parameter represents "thickness change", not absolute thickness */
610 gpl->thickness = 0;
611 gpl->opacity = 1.0f;
612 /* default channel color */
613 ARRAY_SET_ITEMS(gpl->color, 0.2f, 0.2f, 0.2f);
614 /* Default vertex mix. */
615 gpl->vertex_paint_opacity = 1.0f;
616 /* Enable onion skin. */
618 }
619
620 /* auto-name */
621 STRNCPY_UTF8(gpl->info, DATA_(name));
623 gpl,
624 (gpd->flag & GP_DATA_ANNOTATIONS) ? DATA_("Note") : DATA_("GP_Layer"),
625 '.',
626 offsetof(bGPDlayer, info),
627 sizeof(gpl->info));
628
629 /* Enable always affected by scene lights. */
631
632 /* Init transform. */
633 zero_v3(gpl->location);
634 zero_v3(gpl->rotation);
635 copy_v3_fl(gpl->scale, 1.0f);
636 loc_eul_size_to_mat4(gpl->layer_mat, gpl->location, gpl->rotation, gpl->scale);
638
639 /* make this one the active one */
640 if (setactive) {
642 }
643
644 /* return layer */
645 return gpl;
646}
647
649{
650 bGPdata *gpd;
651
652 /* allocate memory for a new block */
653 gpd = static_cast<bGPdata *>(BKE_libblock_alloc(bmain, ID_GD_LEGACY, name, 0));
654
655 /* initial settings */
657
658 /* general flags */
659 gpd->flag |= GP_DATA_VIEWALIGN;
660 /* always enable object onion skin switch */
662 /* GP object specific settings */
663 ARRAY_SET_ITEMS(gpd->line_color, 0.6f, 0.6f, 0.6f, 0.5f);
664
666
670
671 /* use adaptive curve resolution by default */
673
674 gpd->zdepth_offset = 0.150f;
675
676 /* grid settings */
677 ARRAY_SET_ITEMS(gpd->grid.color, 0.5f, 0.5f, 0.5f); /* Color */
678 ARRAY_SET_ITEMS(gpd->grid.scale, 1.0f, 1.0f); /* Scale */
679 gpd->grid.lines = GP_DEFAULT_GRID_LINES; /* Number of lines */
680
681 /* Onion-skinning settings (data-block level) */
682 gpd->onion_keytype = -1; /* All by default. */
686 gpd->onion_factor = 0.5f;
687 ARRAY_SET_ITEMS(gpd->gcolor_prev, 0.145098f, 0.419608f, 0.137255f); /* green */
688 ARRAY_SET_ITEMS(gpd->gcolor_next, 0.125490f, 0.082353f, 0.529412f); /* blue */
689 gpd->gstep = 1;
690 gpd->gstep_next = 1;
691
692 return gpd;
693}
694
695/* ************************************************** */
696
697/* ************************************************** */
698/* Data Duplication */
699
701{
702 if (gps_src == nullptr) {
703 return;
704 }
705 BLI_assert(gps_src->totpoints == gps_dst->totpoints);
706
707 BKE_defvert_array_copy(gps_dst->dvert, gps_src->dvert, gps_src->totpoints);
708}
709
711 const bool dup_points,
712 const bool /*dup_curve*/)
713{
714 bGPDstroke *gps_dst = nullptr;
715
716 gps_dst = static_cast<bGPDstroke *>(MEM_dupallocN(gps_src));
717 gps_dst->prev = gps_dst->next = nullptr;
718 gps_dst->triangles = static_cast<bGPDtriangle *>(MEM_dupallocN(gps_src->triangles));
719
720 if (dup_points) {
721 gps_dst->points = static_cast<bGPDspoint *>(MEM_dupallocN(gps_src->points));
722
723 if (gps_src->dvert != nullptr) {
724 gps_dst->dvert = static_cast<MDeformVert *>(MEM_dupallocN(gps_src->dvert));
725 BKE_gpencil_stroke_weights_duplicate(gps_src, gps_dst);
726 }
727 else {
728 gps_dst->dvert = nullptr;
729 }
730 }
731 else {
732 gps_dst->points = nullptr;
733 gps_dst->dvert = nullptr;
734 }
735
736 gps_dst->editcurve = nullptr;
737
738 /* return new stroke */
739 return gps_dst;
740}
741
742bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src, const bool dup_strokes)
743{
744 bGPDstroke *gps_dst = nullptr;
745 bGPDframe *gpf_dst;
746
747 /* error checking */
748 if (gpf_src == nullptr) {
749 return nullptr;
750 }
751
752 /* make a copy of the source frame */
753 gpf_dst = static_cast<bGPDframe *>(MEM_dupallocN(gpf_src));
754 gpf_dst->prev = gpf_dst->next = nullptr;
755
756 /* Copy strokes. */
757 BLI_listbase_clear(&gpf_dst->strokes);
758 if (dup_strokes) {
759 LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) {
760 /* make copy of source stroke */
761 gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true, true);
762 BLI_addtail(&gpf_dst->strokes, gps_dst);
763 }
764 }
765
766 /* return new frame */
767 return gpf_dst;
768}
769
771 const bool dup_frames,
772 const bool dup_strokes)
773{
774 bGPDframe *gpf_dst;
775 bGPDlayer *gpl_dst;
776
777 /* error checking */
778 if (gpl_src == nullptr) {
779 return nullptr;
780 }
781
782 /* make a copy of source layer */
783 gpl_dst = static_cast<bGPDlayer *>(MEM_dupallocN(gpl_src));
784 gpl_dst->prev = gpl_dst->next = nullptr;
785
786 /* copy frames */
787 BLI_listbase_clear(&gpl_dst->frames);
788 if (dup_frames) {
789 LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) {
790 /* make a copy of source frame */
791 gpf_dst = BKE_gpencil_frame_duplicate(gpf_src, dup_strokes);
792 BLI_addtail(&gpl_dst->frames, gpf_dst);
793
794 /* if source frame was the current layer's 'active' frame, reassign that too */
795 if (gpf_src == gpl_dst->actframe) {
796 gpl_dst->actframe = gpf_dst;
797 }
798 }
799 }
800
801 /* return new layer */
802 return gpl_dst;
803}
804
805bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool internal_copy)
806{
807 bGPdata *gpd_dst;
808
809 /* Yuck and super-uber-hyper yuck!!!
810 * Should be replaceable with a no-main copy (LIB_ID_COPY_NO_MAIN etc.), but not sure about it,
811 * so for now keep old code for that one. */
812
813 /* error checking */
814 if (gpd_src == nullptr) {
815 return nullptr;
816 }
817
818 if (internal_copy) {
819 /* make a straight copy for undo buffers used during stroke drawing */
820 gpd_dst = static_cast<bGPdata *>(MEM_dupallocN(gpd_src));
821 }
822 else {
823 BLI_assert(bmain != nullptr);
824 gpd_dst = (bGPdata *)BKE_id_copy(bmain, &gpd_src->id);
825 }
826
827 /* Copy internal data (layers, etc.) */
828 greasepencil_copy_data(bmain, std::nullopt, &gpd_dst->id, &gpd_src->id, 0);
829
830 /* return new */
831 return gpd_dst;
832}
833
834/* ************************************************** */
835/* GP Layer API */
836
838{
839 /* Sanity check */
840 if (gpl == nullptr) {
841 return false;
842 }
843
844 /* Layer must be: Visible + Editable */
845 if ((gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) == 0) {
846 return true;
847 }
848
849 /* Something failed */
850 return false;
851}
852
854{
855 /* Search in reverse order, since this is often used for playback/adding,
856 * where it's less likely that we're interested in the earlier frames
857 */
859 if (gpf->framenum == cframe) {
860 return gpf;
861 }
862 }
863
864 return nullptr;
865}
866
868{
869 bGPDframe *gpf = nullptr;
870 bool found = false;
871
872 /* error checking */
873 if (gpl == nullptr) {
874 return nullptr;
875 }
876
877 /* check if there is already an active frame */
878 if (gpl->actframe) {
879 gpf = gpl->actframe;
880
881 /* do not allow any changes to layer's active frame if layer is locked from changes
882 * or if the layer has been set to stay on the current frame
883 */
884 if (gpl->flag & GP_LAYER_FRAMELOCK) {
885 return gpf;
886 }
887 /* do not allow any changes to actframe if frame has painting tag attached to it */
888 if (gpf->flag & GP_FRAME_PAINT) {
889 return gpf;
890 }
891
892 /* try to find matching frame */
893 if (gpf->framenum < cframe) {
894 for (; gpf; gpf = gpf->next) {
895 if (gpf->framenum == cframe) {
896 found = true;
897 break;
898 }
899 /* If this is the last frame or the next frame is at a later time, we found the right
900 * frame. */
901 if (!(gpf->next) || (gpf->next->framenum > cframe)) {
902 found = true;
903 break;
904 }
905 }
906
907 /* set the appropriate frame */
908 if (addnew) {
909 if ((found) && (gpf->framenum == cframe)) {
910 gpl->actframe = gpf;
911 }
912 else if (addnew == GP_GETFRAME_ADD_COPY) {
913 /* The #BKE_gpencil_frame_addcopy function copies the active frame of gpl,
914 * so we need to set the active frame before copying. */
915 gpl->actframe = gpf;
916 gpl->actframe = BKE_gpencil_frame_addcopy(gpl, cframe);
917 }
918 else {
919 gpl->actframe = BKE_gpencil_frame_addnew(gpl, cframe);
920 }
921 }
922 else if (found) {
923 gpl->actframe = gpf;
924 }
925 else {
926 gpl->actframe = static_cast<bGPDframe *>(gpl->frames.last);
927 }
928 }
929 else {
930 for (; gpf; gpf = gpf->prev) {
931 if (gpf->framenum <= cframe) {
932 found = true;
933 break;
934 }
935 }
936
937 /* set the appropriate frame */
938 if (addnew) {
939 if ((found) && (gpf->framenum == cframe)) {
940 gpl->actframe = gpf;
941 }
942 else if (addnew == GP_GETFRAME_ADD_COPY) {
943 /* The #BKE_gpencil_frame_addcopy function copies the active frame of gpl;
944 * so we need to set the active frame before copying. */
945 gpl->actframe = gpf;
946 gpl->actframe = BKE_gpencil_frame_addcopy(gpl, cframe);
947 }
948 else {
949 gpl->actframe = BKE_gpencil_frame_addnew(gpl, cframe);
950 }
951 }
952 else if (found) {
953 gpl->actframe = gpf;
954 }
955 else {
956 gpl->actframe = static_cast<bGPDframe *>(gpl->frames.first);
957 }
958 }
959 }
960 else if (gpl->frames.first) {
961 /* check which of the ends to start checking from */
962 const int first = ((bGPDframe *)(gpl->frames.first))->framenum;
963 const int last = ((bGPDframe *)(gpl->frames.last))->framenum;
964
965 if (abs(cframe - first) > abs(cframe - last)) {
966 /* find gp-frame which is less than or equal to cframe */
967 for (gpf = static_cast<bGPDframe *>(gpl->frames.last); gpf; gpf = gpf->prev) {
968 if (gpf->framenum <= cframe) {
969 found = true;
970 break;
971 }
972 }
973 }
974 else {
975 /* find gp-frame which is less than or equal to cframe */
976 for (gpf = static_cast<bGPDframe *>(gpl->frames.first); gpf; gpf = gpf->next) {
977 if (gpf->framenum <= cframe) {
978 found = true;
979 break;
980 }
981 }
982 }
983
984 /* set the appropriate frame */
985 if (addnew) {
986 if ((found) && (gpf->framenum == cframe)) {
987 gpl->actframe = gpf;
988 }
989 else {
990 gpl->actframe = BKE_gpencil_frame_addnew(gpl, cframe);
991 }
992 }
993 else if (found) {
994 gpl->actframe = gpf;
995 }
996 else {
997 /* If delete first frame, need to find one. */
998 if (gpl->frames.first != nullptr) {
999 gpl->actframe = static_cast<bGPDframe *>(gpl->frames.first);
1000 }
1001 else {
1002 /* Unresolved erogenous situation! */
1003 CLOG_STR_ERROR(&LOG, "cannot find appropriate gp-frame");
1004 /* `gpl->actframe` should still be nullptr. */
1005 }
1006 }
1007 }
1008 else {
1009 /* currently no frames (add if allowed to) */
1010 if (addnew) {
1011 gpl->actframe = BKE_gpencil_frame_addnew(gpl, cframe);
1012 }
1013 else {
1014 /* don't do anything... this may be when no frames yet! */
1015 /* gpl->actframe should still be nullptr */
1016 }
1017 }
1018
1019 /* Don't select first frame if greater than current frame. */
1020 if ((gpl->actframe != nullptr) && (gpl->actframe == gpl->frames.first) &&
1021 (gpl->actframe->framenum > cframe))
1022 {
1023 gpl->actframe = nullptr;
1024 }
1025
1026 /* return */
1027 return gpl->actframe;
1028}
1029
1031{
1032 bool changed = false;
1033
1034 /* error checking */
1035 if (ELEM(nullptr, gpl, gpf)) {
1036 return false;
1037 }
1038
1039 /* if this frame was active, make the previous frame active instead
1040 * since it's tricky to set active frame otherwise
1041 */
1042 if (gpl->actframe == gpf) {
1043 gpl->actframe = gpf->prev;
1044 }
1045
1046 /* free the frame and its data */
1047 changed = BKE_gpencil_free_strokes(gpf);
1048 BLI_freelinkN(&gpl->frames, gpf);
1049
1050 return changed;
1051}
1052
1054{
1055 if (name[0] == '\0') {
1056 return nullptr;
1057 }
1058 return static_cast<bGPDlayer *>(BLI_findstring(&gpd->layers, name, offsetof(bGPDlayer, info)));
1059}
1060
1061static int gpencil_cb_cmp_frame(void *thunk, const void *a, const void *b)
1062{
1063 const bGPDframe *frame_a = static_cast<const bGPDframe *>(a);
1064 const bGPDframe *frame_b = static_cast<const bGPDframe *>(b);
1065
1066 if (frame_a->framenum < frame_b->framenum) {
1067 return -1;
1068 }
1069 if (frame_a->framenum > frame_b->framenum) {
1070 return 1;
1071 }
1072 if (thunk != nullptr) {
1073 *((bool *)thunk) = true;
1074 }
1075 /* Sort selected last. */
1076 if ((frame_a->flag & GP_FRAME_SELECT) && ((frame_b->flag & GP_FRAME_SELECT) == 0)) {
1077 return 1;
1078 }
1079 return 0;
1080}
1081
1082void BKE_gpencil_layer_frames_sort(bGPDlayer *gpl, bool *r_has_duplicate_frames)
1083{
1084 BLI_listbase_sort_r(&gpl->frames, gpencil_cb_cmp_frame, r_has_duplicate_frames);
1085}
1086
1088{
1089 /* error checking */
1090 if (ELEM(nullptr, gpd, gpd->layers.first)) {
1091 return nullptr;
1092 }
1093
1094 /* loop over layers until found (assume only one active) */
1095 LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
1096 if (gpl->flag & GP_LAYER_ACTIVE) {
1097 return gpl;
1098 }
1099 }
1100
1101 /* no active layer found */
1102 return nullptr;
1103}
1104
1106{
1107 /* error checking */
1108 if (ELEM(nullptr, gpd, gpd->layers.first, active)) {
1109 return;
1110 }
1111
1112 /* loop over layers deactivating all */
1113 LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
1114 gpl->flag &= ~GP_LAYER_ACTIVE;
1115 if (gpd->flag & GP_DATA_AUTOLOCK_LAYERS) {
1116 gpl->flag |= GP_LAYER_LOCKED;
1117 }
1118 }
1119
1120 /* set as active one */
1121 active->flag |= GP_LAYER_ACTIVE;
1122 if (gpd->flag & GP_DATA_AUTOLOCK_LAYERS) {
1123 active->flag &= ~GP_LAYER_LOCKED;
1124 }
1125}
1126
1128{
1129 /* error checking */
1130 if (ELEM(nullptr, gpd, gpl)) {
1131 return;
1132 }
1133
1134 /* free layer */
1136
1137 /* Free Masks. */
1139
1140 /* free icon providing preview of icon color */
1142
1143 BLI_freelinkN(&gpd->layers, gpl);
1144}
1145
1147{
1148 BLI_assert(brush);
1150 if (brush->gpencil_settings->material != ma) {
1151 if (brush->gpencil_settings->material) {
1153 }
1154 if (ma) {
1155 id_us_plus(&ma->id);
1156 }
1157 brush->gpencil_settings->material = ma;
1159 }
1160}
1161
1163{
1164 const char *hexcol[] = {
1165 "FFFFFF", "F2F2F2", "E6E6E6", "D9D9D9", "CCCCCC", "BFBFBF", "B2B2B2", "A6A6A6", "999999",
1166 "8C8C8C", "808080", "737373", "666666", "595959", "4C4C4C", "404040", "333333", "262626",
1167 "1A1A1A", "000000", "F2FC24", "FFEA00", "FEA711", "FE8B68", "FB3B02", "FE3521", "D00000",
1168 "A81F3D", "780422", "2B0000", "F1E2C5", "FEE4B3", "FEDABB", "FEC28E", "D88F57", "BD6340",
1169 "A2402B", "63352D", "6B2833", "34120C", "E7CB8F", "D1B38B", "C1B17F", "D7980B", "FFB100",
1170 "FE8B00", "FF6A00", "B74100", "5F3E1D", "3B2300", "FECADA", "FE65CB", "FE1392", "DD3062",
1171 "C04A6D", "891688", "4D2689", "441521", "2C1139", "241422", "FFFF7D", "FFFF00", "FF7F00",
1172 "FF7D7D", "FF7DFF", "FF00FE", "FF007F", "FF0000", "7F0000", "0A0A00", "F6FDFF", "E9F7FF",
1173 "CFE6FE", "AAC7FE", "77B3FE", "1E74FD", "0046AA", "2F4476", "003052", "0E0E25", "EEF5F0",
1174 "D6E5DE", "ACD8B9", "6CADC6", "42A9AF", "007F7F", "49675C", "2E4E4E", "1D3239", "0F1C21",
1175 "D8FFF4", "B8F4F5", "AECCB5", "76C578", "358757", "409B68", "468768", "1F512B", "2A3C37",
1176 "122E1D", "EFFFC9", "E6F385", "BCF51C", "D4DC18", "82D322", "5C7F00", "59932B", "297F00",
1177 "004320", "1C3322", "00FF7F", "00FF00", "7DFF7D", "7DFFFF", "00FFFF", "7D7DFF", "7F00FF",
1178 "0000FF", "3F007F", "00007F"};
1179
1180 ToolSettings *ts = scene->toolsettings;
1181 if (ts->gp_paint->paint.palette != nullptr) {
1182 return;
1183 }
1184
1185 /* Try to find the default palette. */
1186 const char *palette_id = "Palette";
1187 Palette *palette = static_cast<Palette *>(
1188 BLI_findstring(&bmain->palettes, palette_id, offsetof(ID, name) + 2));
1189
1190 if (palette == nullptr) {
1191 /* Fall back to the first palette. */
1192 palette = static_cast<Palette *>(bmain->palettes.first);
1193 }
1194
1195 if (palette == nullptr) {
1196 /* Fall back to creating a palette. */
1197 palette = BKE_palette_add(bmain, palette_id);
1198 id_us_min(&palette->id);
1199
1200 /* Create Colors. */
1201 for (int i = 0; i < ARRAY_SIZE(hexcol); i++) {
1202 PaletteColor *palcol = BKE_palette_color_add(palette);
1203 hex_to_rgb(hexcol[i], palcol->color, palcol->color + 1, palcol->color + 2);
1205 }
1206 }
1207
1208 BLI_assert(palette != nullptr);
1209 BKE_paint_palette_set(&ts->gp_paint->paint, palette);
1211}
1212
Blender kernel action and pose functionality.
void BKE_brush_tag_unsaved_changes(Brush *brush)
Definition brush.cc:764
support for deformation groups and hooks.
void BKE_defvert_blend_write(BlendWriter *writer, int count, const MDeformVert *dvlist)
Definition deform.cc:1602
void BKE_defbase_blend_write(BlendWriter *writer, const ListBase *defbase)
Definition deform.cc:1595
void BKE_defvert_array_copy(MDeformVert *dst, const MDeformVert *src, int totvert)
Definition deform.cc:1038
void BKE_defgroup_copy_list(ListBase *outbase, const ListBase *inbase)
Definition deform.cc:73
void BKE_defvert_blend_read(BlendDataReader *reader, int count, MDeformVert *mdverts)
Definition deform.cc:1619
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:47
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:1447
void id_us_plus(ID *id)
Definition lib_id.cc:358
ID * BKE_id_copy(Main *bmain, const ID *id)
Definition lib_id.cc:782
void id_us_min(ID *id)
Definition lib_id.cc:366
void BKE_id_blend_write(BlendWriter *writer, ID *id)
Definition lib_id.cc:2631
#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:1433
Palette * BKE_palette_add(Main *bmain, const char *name)
Definition paint.cc:1427
void BKE_paint_palette_set(Paint *paint, Palette *palette)
Definition paint.cc:1380
#define BLI_assert(a)
Definition BLI_assert.h:46
#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 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 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:5880
#define BLT_I18NCONTEXT_ID_GPENCIL
#define DATA_(msgid)
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:188
#define CLOG_STR_ERROR(clg_ref, str)
Definition CLG_log.h:196
void DEG_id_tag_update(ID *id, unsigned int flags)
#define FILTER_ID_GD_LEGACY
Definition DNA_ID.h:1202
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:1054
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
#define FILTER_ID_MA
Definition DNA_ID.h:1208
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:694
@ INDEX_ID_GD_LEGACY
Definition DNA_ID.h:1290
@ 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
BLI_INLINE void IMB_colormanagement_srgb_to_scene_linear_v3(float scene_linear[3], const float srgb[3])
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#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)
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)
bGPDlayer * BKE_gpencil_layer_active_get(bGPdata *gpd)
void BKE_gpencil_free_point_weights(MDeformVert *dvert)
bool BKE_gpencil_layer_is_editable(const bGPDlayer *gpl)
void BKE_gpencil_free_stroke_editcurve(bGPDstroke *gps)
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)
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_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_delete(bGPdata *gpd, bGPDlayer *gpl)
#define active
#define abs
#define LOG(level)
Definition log.h:97
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]
const char * name
struct Material * material
struct BrushGpencilSettings * gpencil_settings
Definition DNA_ID.h:414
void * last
void * first
struct MDeformWeight * dw
ListBase palettes
Definition BKE_main.hh:304
struct Palette * palette
struct ToolSettings * toolsettings
GpVertexPaint * gp_vertexpaint
bGPDcurve_point * curve_points
struct bGPDframe * next
struct bGPDframe * prev
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)