Blender  V2.93
gpencil_data.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2008, Blender Foundation
17  * This is a new part of Blender
18  */
19 
26 #include <math.h>
27 #include <stddef.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 
32 #include "MEM_guardedalloc.h"
33 
34 #include "BLI_blenlib.h"
35 #include "BLI_ghash.h"
36 #include "BLI_math.h"
37 #include "BLI_string_utils.h"
38 #include "BLI_utildefines.h"
39 
40 #include "BLT_translation.h"
41 
42 #include "DNA_anim_types.h"
43 #include "DNA_brush_types.h"
44 #include "DNA_gpencil_types.h"
45 #include "DNA_material_types.h"
46 #include "DNA_meshdata_types.h"
47 #include "DNA_modifier_types.h"
48 #include "DNA_object_types.h"
49 #include "DNA_scene_types.h"
50 #include "DNA_screen_types.h"
51 #include "DNA_space_types.h"
52 #include "DNA_view3d_types.h"
53 
54 #include "BKE_anim_data.h"
55 #include "BKE_animsys.h"
56 #include "BKE_brush.h"
57 #include "BKE_context.h"
58 #include "BKE_deform.h"
59 #include "BKE_fcurve_driver.h"
60 #include "BKE_gpencil.h"
61 #include "BKE_gpencil_modifier.h"
62 #include "BKE_lib_id.h"
63 #include "BKE_main.h"
64 #include "BKE_material.h"
65 #include "BKE_modifier.h"
66 #include "BKE_object.h"
67 #include "BKE_paint.h"
68 #include "BKE_report.h"
69 #include "BKE_scene.h"
70 
71 #include "UI_interface.h"
72 #include "UI_resources.h"
73 
74 #include "WM_api.h"
75 #include "WM_types.h"
76 
77 #include "RNA_access.h"
78 #include "RNA_define.h"
79 #include "RNA_enum_types.h"
80 
81 #include "ED_gpencil.h"
82 #include "ED_object.h"
83 
84 #include "DEG_depsgraph.h"
85 #include "DEG_depsgraph_build.h"
86 #include "DEG_depsgraph_query.h"
87 
88 #include "gpencil_intern.h"
89 
90 /* ************************************************ */
91 /* Datablock Operators */
92 
93 /* ******************* Add New Data ************************ */
95 {
96 
97  /* the base line we have is that we have somewhere to add Grease Pencil data */
99 }
100 
101 /* add new datablock - wrapper around API */
103 {
104  PointerRNA gpd_owner = {NULL};
105  bGPdata **gpd_ptr = ED_annotation_data_get_pointers(C, &gpd_owner);
106 
107  if (gpd_ptr == NULL) {
108  BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
109  return OPERATOR_CANCELLED;
110  }
111 
112  /* decrement user count and add new datablock */
113  /* TODO: if a datablock exists,
114  * we should make a copy of it instead of starting fresh (as in other areas) */
115  Main *bmain = CTX_data_main(C);
116 
117  /* decrement user count of old GP datablock */
118  if (*gpd_ptr) {
119  bGPdata *gpd = (*gpd_ptr);
120  id_us_min(&gpd->id);
121  }
122 
123  /* Add new datablock, with a single layer ready to use
124  * (so users don't have to perform an extra step). */
125  bGPdata *gpd = BKE_gpencil_data_addnew(bmain, DATA_("Annotations"));
126  *gpd_ptr = gpd;
127 
128  /* tag for annotations */
129  gpd->flag |= GP_DATA_ANNOTATIONS;
130 
131  /* add new layer (i.e. a "note") */
132  BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("Note"), true);
133 
134  /* notifiers */
136 
137  return OPERATOR_FINISHED;
138 }
139 
141 {
142  /* identifiers */
143  ot->name = "Annotation Add New";
144  ot->idname = "GPENCIL_OT_annotation_add";
145  ot->description = "Add new Annotation data-block";
147 
148  /* callbacks */
151 }
152 
153 /* ******************* Unlink Data ************************ */
154 
155 /* poll callback for adding data/layers - special */
157 {
159 
160  /* only unlink annotation datablocks */
161  if ((gpd_ptr != NULL) && (*gpd_ptr != NULL)) {
162  bGPdata *gpd = (*gpd_ptr);
163  if ((gpd->flag & GP_DATA_ANNOTATIONS) == 0) {
164  return false;
165  }
166  }
167  /* if we have access to some active data, make sure there's a datablock before enabling this */
168  return (gpd_ptr && *gpd_ptr);
169 }
170 
171 /* unlink datablock - wrapper around API */
173 {
175 
176  if (gpd_ptr == NULL) {
177  BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
178  return OPERATOR_CANCELLED;
179  }
180  /* just unlink datablock now, decreasing its user count */
181  bGPdata *gpd = (*gpd_ptr);
182 
183  id_us_min(&gpd->id);
184  *gpd_ptr = NULL;
185 
186  /* notifiers */
188 
189  return OPERATOR_FINISHED;
190 }
191 
193 {
194  /* identifiers */
195  ot->name = "Annotation Unlink";
196  ot->idname = "GPENCIL_OT_data_unlink";
197  ot->description = "Unlink active Annotation data-block";
199 
200  /* callbacks */
203 }
204 
205 /* ************************************************ */
206 /* Layer Operators */
207 
208 /* ******************* Add New Layer ************************ */
209 
210 /* add new layer - wrapper around API */
212 {
213  const bool is_annotation = STREQ(op->idname, "GPENCIL_OT_layer_annotation_add");
214 
215  PointerRNA gpd_owner = {NULL};
216  Main *bmain = CTX_data_main(C);
218  bGPdata *gpd = NULL;
219 
220  if (is_annotation) {
221  bGPdata **gpd_ptr = ED_annotation_data_get_pointers(C, &gpd_owner);
222  /* if there's no existing Grease-Pencil data there, add some */
223  if (gpd_ptr == NULL) {
224  BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
225  return OPERATOR_CANCELLED;
226  }
227  /* Annotations */
228  if (*gpd_ptr == NULL) {
229  *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("Annotations"));
230  }
231 
232  /* mark as annotation */
233  (*gpd_ptr)->flag |= GP_DATA_ANNOTATIONS;
234  BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("Note"), true);
235  gpd = *gpd_ptr;
236  }
237  else {
238  /* GP Object */
240  if ((ob != NULL) && (ob->type == OB_GPENCIL)) {
241  gpd = (bGPdata *)ob->data;
242  bGPDlayer *gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
243  /* Add a new frame to make it visible in Dopesheet. */
244  if (gpl != NULL) {
246  }
247  }
248  }
249 
250  /* notifiers */
251  if (gpd) {
252  DEG_id_tag_update(&gpd->id,
254  }
256 
257  return OPERATOR_FINISHED;
258 }
259 
261 {
262  /* identifiers */
263  ot->name = "Add New Layer";
264  ot->idname = "GPENCIL_OT_layer_add";
265  ot->description = "Add new layer or note for the active data-block";
266 
268 
269  /* callbacks */
272 }
273 
275 {
277 }
278 
280 {
281  /* identifiers */
282  ot->name = "Add New Annotation Layer";
283  ot->idname = "GPENCIL_OT_layer_annotation_add";
284  ot->description = "Add new Annotation layer or note for the active data-block";
285 
287 
288  /* callbacks */
291 }
292 /* ******************* Remove Active Layer ************************* */
293 
295 {
296  const bool is_annotation = STREQ(op->idname, "GPENCIL_OT_layer_annotation_remove");
297 
298  bGPdata *gpd = (!is_annotation) ? ED_gpencil_data_get_active(C) :
301 
302  /* sanity checks */
303  if (ELEM(NULL, gpd, gpl)) {
304  return OPERATOR_CANCELLED;
305  }
306 
307  if (gpl->flag & GP_LAYER_LOCKED) {
308  BKE_report(op->reports, RPT_ERROR, "Cannot delete locked layers");
309  return OPERATOR_CANCELLED;
310  }
311 
312  /* make the layer before this the new active layer
313  * - use the one after if this is the first
314  * - if this is the only layer, this naturally becomes NULL
315  */
316  if (gpl->prev) {
318  }
319  else {
321  }
322 
323  /* delete the layer now... */
324  BKE_gpencil_layer_delete(gpd, gpl);
325 
326  /* Reorder masking. */
328 
329  /* notifiers */
333 
334  return OPERATOR_FINISHED;
335 }
336 
338 {
339  /* identifiers */
340  ot->name = "Remove Layer";
341  ot->idname = "GPENCIL_OT_layer_remove";
342  ot->description = "Remove active Grease Pencil layer";
343 
345 
346  /* callbacks */
349 }
350 
352 {
355 
356  return (gpl != NULL);
357 }
358 
360 {
361  /* identifiers */
362  ot->name = "Remove Annotation Layer";
363  ot->idname = "GPENCIL_OT_layer_annotation_remove";
364  ot->description = "Remove active Annotation layer";
365 
367 
368  /* callbacks */
371 }
372 /* ******************* Move Layer Up/Down ************************** */
373 
374 enum {
377 };
378 
380 {
381  const bool is_annotation = STREQ(op->idname, "GPENCIL_OT_layer_annotation_move");
382 
383  bGPdata *gpd = (!is_annotation) ? ED_gpencil_data_get_active(C) :
386 
387  const int direction = RNA_enum_get(op->ptr, "type") * -1;
388 
389  /* sanity checks */
390  if (ELEM(NULL, gpd, gpl)) {
391  return OPERATOR_CANCELLED;
392  }
393 
394  BLI_assert(ELEM(direction, -1, 0, 1)); /* we use value below */
395  if (BLI_listbase_link_move(&gpd->layers, gpl, direction)) {
396  /* Reorder masking. */
398 
401  }
402 
403  return OPERATOR_FINISHED;
404 }
405 
407 {
408  static const EnumPropertyItem slot_move[] = {
409  {GP_LAYER_MOVE_UP, "UP", 0, "Up", ""},
410  {GP_LAYER_MOVE_DOWN, "DOWN", 0, "Down", ""},
411  {0, NULL, 0, NULL, NULL},
412  };
413 
414  /* identifiers */
415  ot->name = "Move Grease Pencil Layer";
416  ot->idname = "GPENCIL_OT_layer_move";
417  ot->description = "Move the active Grease Pencil layer up/down in the list";
418 
419  /* api callbacks */
422 
423  /* flags */
425 
426  ot->prop = RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", "");
427 }
428 
430 {
431  static const EnumPropertyItem slot_move[] = {
432  {GP_LAYER_MOVE_UP, "UP", 0, "Up", ""},
433  {GP_LAYER_MOVE_DOWN, "DOWN", 0, "Down", ""},
434  {0, NULL, 0, NULL, NULL},
435  };
436 
437  /* identifiers */
438  ot->name = "Move Annotation Layer";
439  ot->idname = "GPENCIL_OT_layer_annotation_move";
440  ot->description = "Move the active Annotation layer up/down in the list";
441 
442  /* api callbacks */
445 
446  /* flags */
448 
449  ot->prop = RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", "");
450 }
451 /* ********************* Duplicate Layer ************************** */
452 enum {
455 };
456 
458 {
461  bGPDlayer *new_layer;
462  const int mode = RNA_enum_get(op->ptr, "mode");
463  const bool dup_strokes = (bool)(mode == GP_LAYER_DUPLICATE_ALL);
464  /* sanity checks */
465  if (ELEM(NULL, gpd, gpl)) {
466  return OPERATOR_CANCELLED;
467  }
468 
469  /* Make copy of layer, and add it immediately after or before the existing layer. */
470  new_layer = BKE_gpencil_layer_duplicate(gpl, true, dup_strokes);
471  if (dup_strokes) {
472  BLI_insertlinkafter(&gpd->layers, gpl, new_layer);
473  }
474  else {
475  /* For empty strokes is better add below. */
476  BLI_insertlinkbefore(&gpd->layers, gpl, new_layer);
477  }
478 
479  /* ensure new layer has a unique name, and is now the active layer */
480  BLI_uniquename(&gpd->layers,
481  new_layer,
482  DATA_("GP_Layer"),
483  '.',
484  offsetof(bGPDlayer, info),
485  sizeof(new_layer->info));
486  BKE_gpencil_layer_active_set(gpd, new_layer);
487 
488  /* notifiers */
492 
493  return OPERATOR_FINISHED;
494 }
495 
497 {
498  static const EnumPropertyItem copy_mode[] = {
499  {GP_LAYER_DUPLICATE_ALL, "ALL", 0, "All Data", ""},
500  {GP_LAYER_DUPLICATE_EMPTY, "EMPTY", 0, "Empty Keyframes", ""},
501  {0, NULL, 0, NULL, NULL},
502  };
503 
504  /* identifiers */
505  ot->name = "Duplicate Layer";
506  ot->idname = "GPENCIL_OT_layer_duplicate";
507  ot->description = "Make a copy of the active Grease Pencil layer";
508 
509  /* callbacks */
512 
513  /* flags */
515 
516  RNA_def_enum(ot->srna, "mode", copy_mode, GP_LAYER_DUPLICATE_ALL, "Mode", "");
517 }
518 
519 /* ********************* Duplicate Layer in a new object ************************** */
520 enum {
523 };
524 
526 {
527  ViewLayer *view_layer = CTX_data_view_layer(C);
529  if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
530  return false;
531  }
532 
533  bGPdata *gpd = (bGPdata *)ob->data;
535 
536  if (gpl == NULL) {
537  return false;
538  }
539 
540  /* check there are more grease pencil objects */
541  LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
542  if ((base->object != ob) && (base->object->type == OB_GPENCIL)) {
543  return true;
544  }
545  }
546 
547  return false;
548 }
549 
551 {
552  Main *bmain = CTX_data_main(C);
554  char name[MAX_ID_NAME - 2];
555  RNA_string_get(op->ptr, "object", name);
556 
557  if (name[0] == '\0') {
558  return OPERATOR_CANCELLED;
559  }
560 
561  Object *ob_dst = (Object *)BKE_scene_object_find_by_name(scene, name);
562 
563  int mode = RNA_enum_get(op->ptr, "mode");
564 
565  Object *ob_src = CTX_data_active_object(C);
566  bGPdata *gpd_src = (bGPdata *)ob_src->data;
567  bGPDlayer *gpl_src = BKE_gpencil_layer_active_get(gpd_src);
568 
569  /* Sanity checks. */
570  if (ELEM(NULL, gpd_src, gpl_src, ob_dst)) {
571  return OPERATOR_CANCELLED;
572  }
573  /* Cannot copy itself and check destination type. */
574  if ((ob_src == ob_dst) || (ob_dst->type != OB_GPENCIL)) {
575  return OPERATOR_CANCELLED;
576  }
577 
578  bGPdata *gpd_dst = (bGPdata *)ob_dst->data;
579 
580  /* Create new layer. */
581  bGPDlayer *gpl_dst = BKE_gpencil_layer_addnew(gpd_dst, gpl_src->info, true);
582  /* Need to copy some variables (not all). */
583  gpl_dst->onion_flag = gpl_src->onion_flag;
584  gpl_dst->thickness = gpl_src->thickness;
585  gpl_dst->line_change = gpl_src->line_change;
586  copy_v4_v4(gpl_dst->tintcolor, gpl_src->tintcolor);
587  gpl_dst->opacity = gpl_src->opacity;
588 
589  /* Create all frames. */
590  LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) {
591 
592  if ((mode == GP_LAYER_COPY_OBJECT_ACT_FRAME) && (gpf_src != gpl_src->actframe)) {
593  continue;
594  }
595 
596  /* Create new frame. */
597  bGPDframe *gpf_dst = BKE_gpencil_frame_addnew(gpl_dst, gpf_src->framenum);
598 
599  /* Copy strokes. */
600  LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) {
601 
602  /* Make copy of source stroke. */
603  bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true, true);
604 
605  /* Check if material is in destination object,
606  * otherwise add the slot with the material. */
607  Material *ma_src = BKE_object_material_get(ob_src, gps_src->mat_nr + 1);
608  if (ma_src != NULL) {
609  int idx = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma_src);
610 
611  /* Reassign the stroke material to the right slot in destination object. */
612  gps_dst->mat_nr = idx;
613  }
614 
615  /* Add new stroke to frame. */
616  BLI_addtail(&gpf_dst->strokes, gps_dst);
617  }
618  }
619 
620  /* notifiers */
621  DEG_id_tag_update(&gpd_dst->id,
625 
626  return OPERATOR_FINISHED;
627 }
628 
630 {
631  static const EnumPropertyItem copy_mode[] = {
632  {GP_LAYER_COPY_OBJECT_ALL_FRAME, "ALL", 0, "All Frames", ""},
633  {GP_LAYER_COPY_OBJECT_ACT_FRAME, "ACTIVE", 0, "Active Frame", ""},
634  {0, NULL, 0, NULL, NULL},
635  };
636 
637  /* identifiers */
638  ot->name = "Duplicate Layer to New Object";
639  ot->idname = "GPENCIL_OT_layer_duplicate_object";
640  ot->description = "Make a copy of the active Grease Pencil layer to new object";
641 
642  /* callbacks */
645 
646  /* flags */
648 
650  ot->srna, "object", NULL, MAX_ID_NAME - 2, "Object", "Name of the destination object");
652 
653  RNA_def_enum(ot->srna, "mode", copy_mode, GP_LAYER_COPY_OBJECT_ALL_FRAME, "Mode", "");
654 }
655 
656 /* ********************* Duplicate Frame ************************** */
657 enum {
660 };
661 
663 {
665  bGPDlayer *gpl_active = BKE_gpencil_layer_active_get(gpd);
667 
668  int mode = RNA_enum_get(op->ptr, "mode");
669 
670  /* sanity checks */
671  if (ELEM(NULL, gpd, gpl_active)) {
672  return OPERATOR_CANCELLED;
673  }
674 
675  if (mode == 0) {
676  BKE_gpencil_frame_addcopy(gpl_active, CFRA);
677  }
678  else {
679  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
680  if ((gpl->flag & GP_LAYER_LOCKED) == 0) {
682  }
683  }
684  }
685  /* notifiers */
688 
689  return OPERATOR_FINISHED;
690 }
691 
693 {
694  static const EnumPropertyItem duplicate_mode[] = {
695  {GP_FRAME_DUP_ACTIVE, "ACTIVE", 0, "Active", "Duplicate frame in active layer only"},
696  {GP_FRAME_DUP_ALL, "ALL", 0, "All", "Duplicate active frames in all layers"},
697  {0, NULL, 0, NULL, NULL},
698  };
699 
700  /* identifiers */
701  ot->name = "Duplicate Frame";
702  ot->idname = "GPENCIL_OT_frame_duplicate";
703  ot->description = "Make a copy of the active Grease Pencil Frame";
704 
705  /* callbacks */
708 
709  /* flags */
711 
712  ot->prop = RNA_def_enum(ot->srna, "mode", duplicate_mode, GP_FRAME_DUP_ACTIVE, "Mode", "");
713 }
714 
715 /* ********************* Clean Fill Boundaries on Frame ************************** */
716 enum {
719 };
720 
722 {
723  bool changed = false;
725  int mode = RNA_enum_get(op->ptr, "mode");
726 
727  CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
728  bGPDframe *init_gpf = gpl->actframe;
729  if (mode == GP_FRAME_CLEAN_FILL_ALL) {
730  init_gpf = gpl->frames.first;
731  }
732 
733  for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
734  if ((gpf == gpl->actframe) || (mode == GP_FRAME_CLEAN_FILL_ALL)) {
735 
736  if (gpf == NULL) {
737  continue;
738  }
739 
740  /* simply delete strokes which are no fill */
741  LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
742  /* skip strokes that are invalid for current view */
743  if (ED_gpencil_stroke_can_use(C, gps) == false) {
744  continue;
745  }
746 
747  /* free stroke */
748  if (gps->flag & GP_STROKE_NOFILL) {
749  /* free stroke memory arrays, then stroke itself */
750  if (gps->points) {
751  MEM_freeN(gps->points);
752  }
753  if (gps->dvert) {
755  MEM_freeN(gps->dvert);
756  }
757  MEM_SAFE_FREE(gps->triangles);
758  BLI_freelinkN(&gpf->strokes, gps);
759 
760  changed = true;
761  }
762  }
763  }
764  }
765  }
766  CTX_DATA_END;
767 
768  /* notifiers */
769  if (changed) {
772  }
773 
774  return OPERATOR_FINISHED;
775 }
776 
778 {
779  static const EnumPropertyItem duplicate_mode[] = {
780  {GP_FRAME_CLEAN_FILL_ACTIVE, "ACTIVE", 0, "Active Frame Only", "Clean active frame only"},
781  {GP_FRAME_CLEAN_FILL_ALL, "ALL", 0, "All Frames", "Clean all frames in all layers"},
782  {0, NULL, 0, NULL, NULL},
783  };
784 
785  /* identifiers */
786  ot->name = "Clean Fill Boundaries";
787  ot->idname = "GPENCIL_OT_frame_clean_fill";
788  ot->description = "Remove 'no fill' boundary strokes";
789 
790  /* callbacks */
793 
794  /* flags */
796 
797  ot->prop = RNA_def_enum(ot->srna, "mode", duplicate_mode, GP_FRAME_DUP_ACTIVE, "Mode", "");
798 }
799 
800 /* ********************* Clean Loose Boundaries on Frame ************************** */
802 {
803  bool changed = false;
805  int limit = RNA_int_get(op->ptr, "limit");
806  const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
807 
808  CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
809  bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
810 
811  for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
812  if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
813  if (gpf == NULL) {
814  continue;
815  }
816 
817  /* simply delete strokes which are no loose */
818  LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
819  /* skip strokes that are invalid for current view */
820  if (ED_gpencil_stroke_can_use(C, gps) == false) {
821  continue;
822  }
823 
824  /* free stroke */
825  if (gps->totpoints <= limit) {
826  /* free stroke memory arrays, then stroke itself */
827  if (gps->points) {
828  MEM_freeN(gps->points);
829  }
830  if (gps->dvert) {
832  MEM_freeN(gps->dvert);
833  }
834  MEM_SAFE_FREE(gps->triangles);
835  BLI_freelinkN(&gpf->strokes, gps);
836 
837  changed = true;
838  }
839  }
840  }
841 
842  /* if not multiedit, exit loop*/
843  if (!is_multiedit) {
844  break;
845  }
846  }
847  }
848  CTX_DATA_END;
849 
850  /* notifiers */
851  if (changed) {
854  }
855 
856  return OPERATOR_FINISHED;
857 }
858 
860 {
861  /* identifiers */
862  ot->name = "Clean Loose Points";
863  ot->idname = "GPENCIL_OT_frame_clean_loose";
864  ot->description = "Remove loose points";
865 
866  /* callbacks */
869 
870  /* flags */
872 
874  "limit",
875  1,
876  1,
877  INT_MAX,
878  "Limit",
879  "Number of points to consider stroke as loose",
880  1,
881  INT_MAX);
882 }
883 
884 /* ********************* Clean Duplicated Frames ************************** */
885 static bool gpencil_frame_is_equal(bGPDframe *gpf_a, bGPDframe *gpf_b)
886 {
887  if ((gpf_a == NULL) || (gpf_b == NULL)) {
888  return false;
889  }
890  /* If the number of strokes is different, cannot be equal. */
891  int totstrokes_a = BLI_listbase_count(&gpf_a->strokes);
892  int totstrokes_b = BLI_listbase_count(&gpf_b->strokes);
893  if ((totstrokes_a == 0) || (totstrokes_b == 0) || (totstrokes_a != totstrokes_b)) {
894  return false;
895  }
896  /* Loop all strokes and check. */
897  bGPDstroke *gps_a = gpf_a->strokes.first;
898  bGPDstroke *gps_b = gpf_b->strokes.first;
899  for (int i = 0; i < totstrokes_a; i++) {
900  /* If the number of points is different, cannot be equal. */
901  if (gps_a->totpoints != gps_b->totpoints) {
902  return false;
903  }
904  /* Check other variables. */
905  if (!equals_v4v4(gps_a->vert_color_fill, gps_b->vert_color_fill)) {
906  return false;
907  }
908  if (gps_a->thickness != gps_b->thickness) {
909  return false;
910  }
911  if (gps_a->mat_nr != gps_b->mat_nr) {
912  return false;
913  }
914  if (gps_a->caps[0] != gps_b->caps[0]) {
915  return false;
916  }
917  if (gps_a->caps[1] != gps_b->caps[1]) {
918  return false;
919  }
920  if (gps_a->hardeness != gps_b->hardeness) {
921  return false;
922  }
923  if (!equals_v2v2(gps_a->aspect_ratio, gps_b->aspect_ratio)) {
924  return false;
925  }
926  if (gps_a->uv_rotation != gps_b->uv_rotation) {
927  return false;
928  }
929  if (!equals_v2v2(gps_a->uv_translation, gps_b->uv_translation)) {
930  return false;
931  }
932  if (gps_a->uv_scale != gps_b->uv_scale) {
933  return false;
934  }
935 
936  /* Loop points and check if equals or not. */
937  for (int p = 0; p < gps_a->totpoints; p++) {
938  bGPDspoint *pt_a = &gps_a->points[p];
939  bGPDspoint *pt_b = &gps_b->points[p];
940  if (!equals_v3v3(&pt_a->x, &pt_b->x)) {
941  return false;
942  }
943  if (pt_a->pressure != pt_b->pressure) {
944  return false;
945  }
946  if (pt_a->strength != pt_b->strength) {
947  return false;
948  }
949  if (pt_a->uv_fac != pt_b->uv_fac) {
950  return false;
951  }
952  if (pt_a->uv_rot != pt_b->uv_rot) {
953  return false;
954  }
955  if (!equals_v4v4(pt_a->vert_color, pt_b->vert_color)) {
956  return false;
957  }
958  }
959 
960  /* Look at next pair of strokes. */
961  gps_a = gps_a->next;
962  gps_b = gps_b->next;
963  }
964 
965  return true;
966 }
967 
969 {
970 #define SELECTED 1
971 
972  bool changed = false;
974  bGPdata *gpd = (bGPdata *)ob->data;
975  const int type = RNA_enum_get(op->ptr, "type");
976 
977  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
978  /* Only editable and visible layers are considered. */
979  if (BKE_gpencil_layer_is_editable(gpl) && (gpl->frames.first != NULL)) {
980  bGPDframe *gpf = gpl->frames.first;
981 
982  if ((type == SELECTED) && ((gpf->flag & GP_FRAME_SELECT) == 0)) {
983  continue;
984  }
985 
986  while (gpf != NULL) {
987  if (gpencil_frame_is_equal(gpf, gpf->next)) {
988  /* Remove frame. */
990  /* Tag for recalc. */
991  changed = true;
992  }
993  else {
994  gpf = gpf->next;
995  }
996  }
997  }
998  }
999 
1000  /* notifiers */
1001  if (changed) {
1004  }
1005 
1006  return OPERATOR_FINISHED;
1007 }
1008 
1010 {
1011  static const EnumPropertyItem clean_type[] = {
1012  {0, "ALL", 0, "All Frames", ""},
1013  {1, "SELECTED", 0, "Selected Frames", ""},
1014  {0, NULL, 0, NULL, NULL},
1015  };
1016 
1017  /* identifiers */
1018  ot->name = "Clean Duplicated Frames";
1019  ot->idname = "GPENCIL_OT_frame_clean_duplicate";
1020  ot->description = "Remove any duplicated frame";
1021 
1022  /* callbacks */
1025 
1026  /* flags */
1028 
1029  ot->prop = RNA_def_enum(ot->srna, "type", clean_type, 0, "Type", "");
1030 }
1031 
1032 /* *********************** Hide Layers ******************************** */
1033 
1035 {
1038  bool unselected = RNA_boolean_get(op->ptr, "unselected");
1039 
1040  /* sanity checks */
1041  if (ELEM(NULL, gpd, layer)) {
1042  return OPERATOR_CANCELLED;
1043  }
1044 
1045  if (unselected) {
1046  /* hide unselected */
1047  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
1048  if (gpl != layer) {
1049  gpl->flag |= GP_LAYER_HIDE;
1050  }
1051  else {
1052  /* Be sure the active layer is unhidden. */
1053  gpl->flag &= ~GP_LAYER_HIDE;
1054  }
1055  }
1056  }
1057  else {
1058  /* hide selected/active */
1059  layer->flag |= GP_LAYER_HIDE;
1060  }
1061 
1062  /* notifiers */
1065 
1066  return OPERATOR_FINISHED;
1067 }
1068 
1070 {
1071  /* identifiers */
1072  ot->name = "Hide Layer(s)";
1073  ot->idname = "GPENCIL_OT_hide";
1074  ot->description = "Hide selected/unselected Grease Pencil layers";
1075 
1076  /* callbacks */
1078  ot->poll = gpencil_active_layer_poll; /* NOTE: we need an active layer to play with */
1079 
1080  /* flags */
1082 
1083  /* props */
1085  ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected layers");
1086 }
1087 
1088 /* ********************** Show All Layers ***************************** */
1089 
1090 /* poll callback for showing layers */
1092 {
1093  return ED_gpencil_data_get_active(C) != NULL;
1094 }
1095 
1097 {
1098  bGPDstroke *gps;
1099  for (gps = frame->strokes.first; gps; gps = gps->next) {
1100 
1101  /* only deselect strokes that are valid in this view */
1102  if (ED_gpencil_stroke_can_use(C, gps)) {
1103 
1104  /* (de)select points */
1105  int i;
1106  bGPDspoint *pt;
1107  for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
1109  }
1110 
1111  /* (de)select stroke */
1113  }
1114  }
1115 }
1116 
1118 {
1120  const bool select = RNA_boolean_get(op->ptr, "select");
1121 
1122  /* sanity checks */
1123  if (gpd == NULL) {
1124  return OPERATOR_CANCELLED;
1125  }
1126 
1127  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
1128  if (gpl->flag & GP_LAYER_HIDE) {
1129  gpl->flag &= ~GP_LAYER_HIDE;
1130 
1131  /* select or deselect if requested, only on hidden layers */
1132  if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
1133  if (select) {
1134  /* select all strokes on active frame only (same as select all operator) */
1135  if (gpl->actframe) {
1136  gpencil_reveal_select_frame(C, gpl->actframe, true);
1137  }
1138  }
1139  else {
1140  /* deselect strokes on all frames (same as deselect all operator) */
1141  bGPDframe *gpf;
1142  for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
1143  gpencil_reveal_select_frame(C, gpf, false);
1144  }
1145  }
1146  }
1147  }
1148  }
1149 
1150  /* notifiers */
1153 
1154  return OPERATOR_FINISHED;
1155 }
1156 
1158 {
1159  /* identifiers */
1160  ot->name = "Show All Layers";
1161  ot->idname = "GPENCIL_OT_reveal";
1162  ot->description = "Show all Grease Pencil layers";
1163 
1164  /* callbacks */
1167 
1168  /* flags */
1170 
1171  /* props */
1172  RNA_def_boolean(ot->srna, "select", true, "Select", "");
1173 }
1174 
1175 /* ***************** Lock/Unlock All Layers ************************ */
1176 
1178 {
1180 
1181  /* sanity checks */
1182  if (gpd == NULL) {
1183  return OPERATOR_CANCELLED;
1184  }
1185 
1186  /* make all layers non-editable */
1187  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
1188  gpl->flag |= GP_LAYER_LOCKED;
1189  }
1190 
1191  /* notifiers */
1194 
1195  return OPERATOR_FINISHED;
1196 }
1197 
1199 {
1200  /* identifiers */
1201  ot->name = "Lock All Layers";
1202  ot->idname = "GPENCIL_OT_lock_all";
1203  ot->description =
1204  "Lock all Grease Pencil layers to prevent them from being accidentally modified";
1205 
1206  /* callbacks */
1209 
1210  /* flags */
1212 }
1213 
1214 /* -------------------------- */
1215 
1217 {
1219 
1220  /* sanity checks */
1221  if (gpd == NULL) {
1222  return OPERATOR_CANCELLED;
1223  }
1224 
1225  /* make all layers editable again */
1226  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
1227  gpl->flag &= ~GP_LAYER_LOCKED;
1228  }
1229 
1230  /* notifiers */
1233 
1234  return OPERATOR_FINISHED;
1235 }
1236 
1238 {
1239  /* identifiers */
1240  ot->name = "Unlock All Layers";
1241  ot->idname = "GPENCIL_OT_unlock_all";
1242  ot->description = "Unlock all Grease Pencil layers so that they can be edited";
1243 
1244  /* callbacks */
1247 
1248  /* flags */
1250 }
1251 
1252 /* ********************** Isolate Layer **************************** */
1253 
1255 {
1258  int flags = GP_LAYER_LOCKED;
1259  bool isolate = false;
1260 
1261  if (RNA_boolean_get(op->ptr, "affect_visibility")) {
1262  flags |= GP_LAYER_HIDE;
1263  }
1264 
1265  if (ELEM(NULL, gpd, layer)) {
1266  BKE_report(op->reports, RPT_ERROR, "No active layer to isolate");
1267  return OPERATOR_CANCELLED;
1268  }
1269 
1270  /* Test whether to isolate or clear all flags */
1271  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
1272  /* Skip if this is the active layer */
1273  if (gpl == layer) {
1274  continue;
1275  }
1276 
1277  /* If the flags aren't set, that means that the layer is
1278  * not alone, so we have some layers to isolate still
1279  */
1280  if ((gpl->flag & flags) == 0) {
1281  isolate = true;
1282  break;
1283  }
1284  }
1285 
1286  /* Set/Clear flags as appropriate */
1287  /* TODO: Include onion-skinning on this list? */
1288  if (isolate) {
1289  /* Set flags on all "other" layers */
1290  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
1291  if (gpl == layer) {
1292  continue;
1293  }
1294  gpl->flag |= flags;
1295  }
1296  }
1297  else {
1298  /* Clear flags - Restore everything else */
1299  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
1300  gpl->flag &= ~flags;
1301  }
1302  }
1303 
1304  /* notifiers */
1307 
1308  return OPERATOR_FINISHED;
1309 }
1310 
1312 {
1313  /* identifiers */
1314  ot->name = "Isolate Layer";
1315  ot->idname = "GPENCIL_OT_layer_isolate";
1316  ot->description =
1317  "Toggle whether the active layer is the only one that can be edited and/or visible";
1318 
1319  /* callbacks */
1322 
1323  /* flags */
1325 
1326  /* properties */
1328  "affect_visibility",
1329  false,
1330  "Affect Visibility",
1331  "In addition to toggling the editability, also affect the visibility");
1332 }
1333 
1334 /* ********************** Merge Layer with the next layer **************************** */
1335 
1337 {
1339  bGPDlayer *gpl_src = BKE_gpencil_layer_active_get(gpd);
1340  bGPDlayer *gpl_dst = gpl_src->prev;
1341 
1342  if (ELEM(NULL, gpd, gpl_dst, gpl_src)) {
1343  BKE_report(op->reports, RPT_ERROR, "No layers to merge");
1344  return OPERATOR_CANCELLED;
1345  }
1346 
1347  /* Collect frames of gpl_dst in hash table to avoid O(n^2) lookups. */
1348  GHash *gh_frames_dst = BLI_ghash_int_new_ex(__func__, 64);
1349  LISTBASE_FOREACH (bGPDframe *, gpf_dst, &gpl_dst->frames) {
1350  BLI_ghash_insert(gh_frames_dst, POINTER_FROM_INT(gpf_dst->framenum), gpf_dst);
1351  }
1352 
1353  /* Read all frames from merge layer and add any missing in destination layer,
1354  * copying all previous strokes to keep the image equals.
1355  * Need to do it in a separated loop to avoid strokes accumulation. */
1356  LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) {
1357  /* Try to find frame in destination layer hash table. */
1358  bGPDframe *gpf_dst = BLI_ghash_lookup(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum));
1359  if (!gpf_dst) {
1360  gpf_dst = BKE_gpencil_layer_frame_get(gpl_dst, gpf_src->framenum, GP_GETFRAME_ADD_COPY);
1361  BLI_ghash_insert(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum), gpf_dst);
1362  }
1363  }
1364 
1365  /* Read all frames from merge layer and add strokes. */
1366  LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) {
1367  /* Try to find frame in destination layer hash table. */
1368  bGPDframe *gpf_dst = BLI_ghash_lookup(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum));
1369  /* Add to tail all strokes. */
1370  if (gpf_dst) {
1371  BLI_movelisttolist(&gpf_dst->strokes, &gpf_src->strokes);
1372  }
1373  }
1374 
1375  /* Add Masks to destination layer. */
1377  /* Don't add merged layers or missing layer names. */
1378  if (!BKE_gpencil_layer_named_get(gpd, mask->name) || STREQ(mask->name, gpl_src->info) ||
1379  STREQ(mask->name, gpl_dst->info)) {
1380  continue;
1381  }
1382  if (!BKE_gpencil_layer_mask_named_get(gpl_dst, mask->name)) {
1383  bGPDlayer_Mask *mask_new = MEM_dupallocN(mask);
1384  BLI_addtail(&gpl_dst->mask_layers, mask_new);
1385  gpl_dst->act_mask++;
1386  }
1387  }
1388  /* Set destination layer as active. */
1389  BKE_gpencil_layer_active_set(gpd, gpl_dst);
1390 
1391  /* Now delete next layer */
1392  BKE_gpencil_layer_delete(gpd, gpl_src);
1393  BLI_ghash_free(gh_frames_dst, NULL, NULL);
1394 
1395  /* Reorder masking. */
1396  BKE_gpencil_layer_mask_sort(gpd, gpl_dst);
1397 
1398  /* notifiers */
1402 
1403  return OPERATOR_FINISHED;
1404 }
1405 
1407 {
1408  /* identifiers */
1409  ot->name = "Merge Down";
1410  ot->idname = "GPENCIL_OT_layer_merge";
1411  ot->description = "Merge the current layer with the layer below";
1412 
1413  /* callbacks */
1416 
1417  /* flags */
1419 }
1420 
1421 /* ********************** Change Layer ***************************** */
1422 
1424 {
1425  uiPopupMenu *pup;
1426  uiLayout *layout;
1427 
1428  /* call the menu, which will call this operator again, hence the canceled */
1429  pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
1430  layout = UI_popup_menu_layout(pup);
1431  uiItemsEnumO(layout, "GPENCIL_OT_layer_change", "layer");
1432  UI_popup_menu_end(C, pup);
1433 
1434  return OPERATOR_INTERFACE;
1435 }
1436 
1438 {
1440  bGPDlayer *gpl = NULL;
1441  int layer_num = RNA_enum_get(op->ptr, "layer");
1442 
1443  /* Get layer or create new one */
1444  if (layer_num == -1) {
1445  /* Create layer */
1446  gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
1447  }
1448  else {
1449  /* Try to get layer */
1450  gpl = BLI_findlink(&gpd->layers, layer_num);
1451 
1452  if (gpl == NULL) {
1453  BKE_reportf(
1454  op->reports, RPT_ERROR, "Cannot change to non-existent layer (index = %d)", layer_num);
1455  return OPERATOR_CANCELLED;
1456  }
1457  }
1458 
1459  /* Set active layer */
1460  BKE_gpencil_layer_active_set(gpd, gpl);
1461 
1462  /* updates */
1466 
1467  return OPERATOR_FINISHED;
1468 }
1469 
1471 {
1472  /* identifiers */
1473  ot->name = "Change Layer";
1474  ot->idname = "GPENCIL_OT_layer_change";
1475  ot->description = "Change active Grease Pencil layer";
1476 
1477  /* callbacks */
1481 
1482  /* flags */
1484 
1485  /* gp layer to use (dynamic enum) */
1486  ot->prop = RNA_def_enum(ot->srna, "layer", DummyRNA_DEFAULT_items, 0, "Grease Pencil Layer", "");
1488 }
1489 
1491 {
1493  bGPdata *gpd = (bGPdata *)ob->data;
1494  int layer_num = RNA_int_get(op->ptr, "layer");
1495 
1496  /* Try to get layer */
1497  bGPDlayer *gpl = BLI_findlink(&gpd->layers, layer_num);
1498 
1499  if (gpl == NULL) {
1500  BKE_reportf(
1501  op->reports, RPT_ERROR, "Cannot change to non-existent layer (index = %d)", layer_num);
1502  return OPERATOR_CANCELLED;
1503  }
1504 
1505  /* Set active layer */
1506  BKE_gpencil_layer_active_set(gpd, gpl);
1507 
1508  /* updates */
1512 
1513  return OPERATOR_FINISHED;
1514 }
1515 
1517 {
1518  /* identifiers */
1519  ot->name = "Active Layer";
1520  ot->idname = "GPENCIL_OT_layer_active";
1521  ot->description = "Active Grease Pencil layer";
1522 
1523  /* callbacks */
1526 
1527  /* flags */
1529 
1530  /* GPencil layer to use. */
1531  ot->prop = RNA_def_int(ot->srna, "layer", 0, 0, INT_MAX, "Grease Pencil Layer", "", 0, INT_MAX);
1533 }
1534 /* ************************************************ */
1535 
1536 /* ******************* Arrange Stroke Up/Down in drawing order ************************** */
1537 
1538 enum {
1543 };
1544 
1546 {
1549  bGPDlayer *gpl_act = BKE_gpencil_layer_active_get(gpd);
1550 
1551  /* sanity checks */
1552  if (ELEM(NULL, gpd, gpl_act, gpl_act->actframe)) {
1553  return OPERATOR_CANCELLED;
1554  }
1555 
1556  const int direction = RNA_enum_get(op->ptr, "direction");
1557  const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
1558  bGPDstroke *gps_target = NULL;
1559 
1560  bool changed = false;
1561  CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
1562  /* temp listbase to store selected strokes */
1563  ListBase selected = {NULL};
1564 
1565  bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
1566  bGPDstroke *gps = NULL;
1567 
1568  for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
1569  if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
1570  if (gpf == NULL) {
1571  continue;
1572  }
1573  /* verify if any selected stroke is in the extreme of the stack and select to move */
1574  for (gps = gpf->strokes.first; gps; gps = gps->next) {
1575  /* only if selected */
1576  if (gps->flag & GP_STROKE_SELECT) {
1577  /* skip strokes that are invalid for current view */
1578  if (ED_gpencil_stroke_can_use(C, gps) == false) {
1579  continue;
1580  }
1581  /* check if the color is editable */
1582  if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
1583  continue;
1584  }
1585  bool gpf_lock = false;
1586  /* some stroke is already at front*/
1587  if (ELEM(direction, GP_STROKE_MOVE_TOP, GP_STROKE_MOVE_UP)) {
1588  if (gps == gpf->strokes.last) {
1589  gpf_lock = true;
1590  gps_target = gps;
1591  }
1592  }
1593  /* Some stroke is already at bottom. */
1594  if (ELEM(direction, GP_STROKE_MOVE_BOTTOM, GP_STROKE_MOVE_DOWN)) {
1595  if (gps == gpf->strokes.first) {
1596  gpf_lock = true;
1597  gps_target = gps;
1598  }
1599  }
1600  /* add to list (if not locked) */
1601  if (!gpf_lock) {
1602  BLI_addtail(&selected, BLI_genericNodeN(gps));
1603  }
1604  }
1605  }
1606 
1607  const int target_index = (gps_target) ? BLI_findindex(&gpf->strokes, gps_target) : -1;
1608  int prev_index = target_index;
1609  /* Now do the movement of the stroke */
1610  switch (direction) {
1611  /* Bring to Front */
1612  case GP_STROKE_MOVE_TOP:
1613  LISTBASE_FOREACH (LinkData *, link, &selected) {
1614  gps = link->data;
1615  BLI_remlink(&gpf->strokes, gps);
1616  if (gps_target) {
1617  BLI_insertlinkbefore(&gpf->strokes, gps_target, gps);
1618  }
1619  else {
1620  BLI_addtail(&gpf->strokes, gps);
1621  }
1622  changed = true;
1623  }
1624  break;
1625  /* Bring Forward */
1626  case GP_STROKE_MOVE_UP:
1627  LISTBASE_FOREACH_BACKWARD (LinkData *, link, &selected) {
1628  gps = link->data;
1629  if (gps_target) {
1630  int gps_index = BLI_findindex(&gpf->strokes, gps);
1631  if (gps_index + 1 >= prev_index) {
1632  prev_index = gps_index;
1633  continue;
1634  }
1635  prev_index = gps_index;
1636  }
1637  BLI_listbase_link_move(&gpf->strokes, gps, 1);
1638  changed = true;
1639  }
1640  break;
1641  /* Send Backward */
1642  case GP_STROKE_MOVE_DOWN:
1643  LISTBASE_FOREACH (LinkData *, link, &selected) {
1644  gps = link->data;
1645  if (gps_target) {
1646  int gps_index = BLI_findindex(&gpf->strokes, gps);
1647  if (gps_index - 1 <= prev_index) {
1648  prev_index = gps_index;
1649  continue;
1650  }
1651  prev_index = gps_index;
1652  }
1653  BLI_listbase_link_move(&gpf->strokes, gps, -1);
1654  changed = true;
1655  }
1656  break;
1657  /* Send to Back */
1658  case GP_STROKE_MOVE_BOTTOM:
1659  LISTBASE_FOREACH_BACKWARD (LinkData *, link, &selected) {
1660  gps = link->data;
1661  BLI_remlink(&gpf->strokes, gps);
1662  if (gps_target) {
1663  BLI_insertlinkafter(&gpf->strokes, gps_target, gps);
1664  }
1665  else {
1666  BLI_addhead(&gpf->strokes, gps);
1667  }
1668  changed = true;
1669  }
1670  break;
1671  default:
1672  BLI_assert(0);
1673  break;
1674  }
1675  BLI_freelistN(&selected);
1676  }
1677 
1678  /* if not multiedit, exit loop*/
1679  if (!is_multiedit) {
1680  break;
1681  }
1682  }
1683  }
1684  CTX_DATA_END;
1685 
1686  if (changed) {
1687  /* notifiers */
1690  }
1691 
1692  return OPERATOR_FINISHED;
1693 }
1694 
1696 {
1697  static const EnumPropertyItem slot_move[] = {
1698  {GP_STROKE_MOVE_TOP, "TOP", 0, "Bring to Front", ""},
1699  {GP_STROKE_MOVE_UP, "UP", 0, "Bring Forward", ""},
1700  {GP_STROKE_MOVE_DOWN, "DOWN", 0, "Send Backward", ""},
1701  {GP_STROKE_MOVE_BOTTOM, "BOTTOM", 0, "Send to Back", ""},
1702  {0, NULL, 0, NULL, NULL}};
1703 
1704  /* identifiers */
1705  ot->name = "Arrange Stroke";
1706  ot->idname = "GPENCIL_OT_stroke_arrange";
1707  ot->description = "Arrange selected strokes up/down in the display order of the active layer";
1708 
1709  /* callbacks */
1712 
1713  /* flags */
1715 
1716  /* properties */
1717  ot->prop = RNA_def_enum(ot->srna, "direction", slot_move, GP_STROKE_MOVE_UP, "Direction", "");
1718 }
1719 
1720 /* ******************* Move Stroke to new color ************************** */
1721 
1723 {
1724  Main *bmain = CTX_data_main(C);
1725  Material *ma = NULL;
1726  char name[MAX_ID_NAME - 2];
1727  RNA_string_get(op->ptr, "material", name);
1728 
1731  if (name[0] == '\0') {
1732  ma = BKE_gpencil_material(ob, ob->actcol);
1733  }
1734  else {
1735  ma = (Material *)BKE_libblock_find_name(bmain, ID_MA, name);
1736  if (ma == NULL) {
1737  return OPERATOR_CANCELLED;
1738  }
1739  }
1740  /* try to find slot */
1741  int idx = BKE_gpencil_object_material_index_get(ob, ma);
1742  if (idx < 0) {
1743  return OPERATOR_CANCELLED;
1744  }
1745 
1746  /* sanity checks */
1747  if (ELEM(NULL, gpd)) {
1748  return OPERATOR_CANCELLED;
1749  }
1750 
1751  const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
1752  if (ELEM(NULL, ma)) {
1753  return OPERATOR_CANCELLED;
1754  }
1755 
1756  bool changed = false;
1757  /* loop all strokes */
1758  CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
1759  bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
1760 
1761  for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
1762  if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
1763  if (gpf == NULL) {
1764  continue;
1765  }
1766 
1767  LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
1768  /* only if selected */
1769  if (gps->flag & GP_STROKE_SELECT) {
1770  /* skip strokes that are invalid for current view */
1771  if (ED_gpencil_stroke_can_use(C, gps) == false) {
1772  continue;
1773  }
1774  /* check if the color is editable */
1775  if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
1776  continue;
1777  }
1778 
1779  /* assign new color */
1780  gps->mat_nr = idx;
1781 
1782  changed = true;
1783  }
1784  }
1785  }
1786  /* if not multiedit, exit loop*/
1787  if (!is_multiedit) {
1788  break;
1789  }
1790  }
1791  }
1792  CTX_DATA_END;
1793 
1794  if (changed) {
1795  /* notifiers */
1798  }
1799 
1800  return OPERATOR_FINISHED;
1801 }
1802 
1804 {
1805  /* identifiers */
1806  ot->name = "Change Stroke Color";
1807  ot->idname = "GPENCIL_OT_stroke_change_color";
1808  ot->description = "Move selected strokes to active material";
1809 
1810  /* callbacks */
1813 
1814  /* flags */
1816 
1817  RNA_def_string(ot->srna, "material", NULL, MAX_ID_NAME - 2, "Material", "Name of the material");
1818 }
1819 
1820 /* ******************* Lock color of non selected Strokes colors ************************** */
1821 
1823 {
1826  short *totcol = BKE_object_material_len_p(ob);
1827 
1828  /* sanity checks */
1829  if (ELEM(NULL, gpd)) {
1830  return OPERATOR_CANCELLED;
1831  }
1832 
1833  /* first lock all colors */
1834  for (short i = 0; i < *totcol; i++) {
1835  Material *tmp_ma = BKE_object_material_get(ob, i + 1);
1836  if (tmp_ma) {
1837  tmp_ma->gp_style->flag |= GP_MATERIAL_LOCKED;
1839  }
1840  }
1841 
1842  bool changed = false;
1843  /* loop all selected strokes and unlock any color */
1844  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
1845  /* only editable and visible layers are considered */
1846  if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
1847  for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
1848  /* only if selected */
1849  if (gps->flag & GP_STROKE_SELECT) {
1850  /* skip strokes that are invalid for current view */
1851  if (ED_gpencil_stroke_can_use(C, gps) == false) {
1852  continue;
1853  }
1854  /* unlock color */
1855  Material *tmp_ma = BKE_object_material_get(ob, gps->mat_nr + 1);
1856  if (tmp_ma) {
1857  tmp_ma->gp_style->flag &= ~GP_MATERIAL_LOCKED;
1859  }
1860 
1861  changed = true;
1862  }
1863  }
1864  }
1865  }
1866 
1867  if (changed) {
1868  /* updates */
1870 
1871  /* copy on write tag is needed, or else no refresh happens */
1873 
1874  /* notifiers */
1877  }
1878 
1879  return OPERATOR_FINISHED;
1880 }
1881 
1883 {
1884  /* identifiers */
1885  ot->name = "Lock Unused Materials";
1886  ot->idname = "GPENCIL_OT_material_lock_unused";
1887  ot->description = "Lock any material not used in any selected stroke";
1888 
1889  /* api callbacks */
1892 
1893  /* flags */
1895 }
1896 
1897 /* ************************************************ */
1898 /* Drawing Brushes Operators */
1899 
1900 /* ******************* Brush resets ************************** */
1902 {
1903  Main *bmain = CTX_data_main(C);
1905  const enum eContextObjectMode mode = CTX_data_mode_enum(C);
1906  Brush *brush = NULL;
1907 
1908  switch (mode) {
1909  case CTX_MODE_PAINT_GPENCIL: {
1910  Paint *paint = &ts->gp_paint->paint;
1911  brush = paint->brush;
1912  if (brush && brush->gpencil_settings) {
1914  }
1915  break;
1916  }
1917  case CTX_MODE_SCULPT_GPENCIL: {
1918  Paint *paint = &ts->gp_sculptpaint->paint;
1919  brush = paint->brush;
1920  if (brush && brush->gpencil_settings) {
1922  }
1923  break;
1924  }
1925  case CTX_MODE_WEIGHT_GPENCIL: {
1926  Paint *paint = &ts->gp_weightpaint->paint;
1927  brush = paint->brush;
1928  if (brush && brush->gpencil_settings) {
1930  }
1931  break;
1932  }
1933  case CTX_MODE_VERTEX_GPENCIL: {
1934  Paint *paint = &ts->gp_vertexpaint->paint;
1935  brush = paint->brush;
1936  if (brush && brush->gpencil_settings) {
1938  }
1939  break;
1940  }
1941  default:
1942  break;
1943  }
1944 
1945  /* notifiers */
1947 
1948  return OPERATOR_FINISHED;
1949 }
1950 
1952 {
1953  /* identifiers */
1954  ot->name = "Reset Brush";
1955  ot->idname = "GPENCIL_OT_brush_reset";
1956  ot->description = "Reset brush to default parameters";
1957 
1958  /* api callbacks */
1960 
1961  /* flags */
1963 }
1964 
1966  Paint *UNUSED(paint),
1967  const enum eContextObjectMode mode,
1968  char tool)
1969 {
1970  Brush *brush_next = NULL;
1971  for (Brush *brush = bmain->brushes.first; brush; brush = brush_next) {
1972  brush_next = brush->id.next;
1973 
1974  if (brush->gpencil_settings == NULL) {
1975  continue;
1976  }
1977 
1978  if ((mode == CTX_MODE_PAINT_GPENCIL) && (brush->gpencil_tool == tool)) {
1979  return brush;
1980  }
1981 
1982  if ((mode == CTX_MODE_SCULPT_GPENCIL) && (brush->gpencil_sculpt_tool == tool)) {
1983  return brush;
1984  }
1985 
1986  if ((mode == CTX_MODE_WEIGHT_GPENCIL) && (brush->gpencil_weight_tool == tool)) {
1987  return brush;
1988  }
1989 
1990  if ((mode == CTX_MODE_VERTEX_GPENCIL) && (brush->gpencil_vertex_tool == tool)) {
1991  return brush;
1992  }
1993  }
1994 
1995  return NULL;
1996 }
1997 
1999  Paint *paint,
2000  const enum eContextObjectMode mode)
2001 {
2002  Brush *brush_active = paint->brush;
2003  Brush *brush_next = NULL;
2004  for (Brush *brush = bmain->brushes.first; brush; brush = brush_next) {
2005  brush_next = brush->id.next;
2006 
2007  if ((brush->gpencil_settings == NULL) && (brush->ob_mode != OB_MODE_PAINT_GPENCIL)) {
2008  continue;
2009  }
2010 
2011  short preset = (brush->gpencil_settings) ? brush->gpencil_settings->preset_type :
2013 
2014  if (preset != GP_BRUSH_PRESET_UNKNOWN) {
2015  /* Verify to delete only the brushes of the current mode. */
2016  if (mode == CTX_MODE_PAINT_GPENCIL) {
2017  if ((preset < GP_BRUSH_PRESET_AIRBRUSH) || (preset > GP_BRUSH_PRESET_TINT)) {
2018  continue;
2019  }
2020  if ((brush_active) && (brush_active->gpencil_tool != brush->gpencil_tool)) {
2021  continue;
2022  }
2023  }
2024 
2025  if (mode == CTX_MODE_SCULPT_GPENCIL) {
2026  if ((preset < GP_BRUSH_PRESET_SMOOTH_STROKE) || (preset > GP_BRUSH_PRESET_CLONE_STROKE)) {
2027  continue;
2028  }
2029  if ((brush_active) && (brush_active->gpencil_sculpt_tool != brush->gpencil_sculpt_tool)) {
2030  continue;
2031  }
2032  }
2033 
2034  if (mode == CTX_MODE_WEIGHT_GPENCIL) {
2035  if (preset != GP_BRUSH_PRESET_DRAW_WEIGHT) {
2036  continue;
2037  }
2038  if ((brush_active) && (brush_active->gpencil_weight_tool != brush->gpencil_weight_tool)) {
2039  continue;
2040  }
2041  }
2042 
2043  if (mode == CTX_MODE_VERTEX_GPENCIL) {
2044  if ((preset < GP_BRUSH_PRESET_VERTEX_DRAW) || (preset > GP_BRUSH_PRESET_VERTEX_REPLACE)) {
2045  continue;
2046  }
2047  if ((brush_active) && (brush_active->gpencil_vertex_tool != brush->gpencil_vertex_tool)) {
2048  continue;
2049  }
2050  }
2051  }
2052 
2053  /* Before delete, un-pin any material of the brush. */
2054  if ((brush->gpencil_settings) && (brush->gpencil_settings->material != NULL)) {
2055  brush->gpencil_settings->material = NULL;
2056  brush->gpencil_settings->flag &= ~GP_BRUSH_MATERIAL_PINNED;
2057  }
2058 
2059  BKE_brush_delete(bmain, brush);
2060  }
2061 }
2062 
2064 {
2065  Main *bmain = CTX_data_main(C);
2067  const enum eContextObjectMode mode = CTX_data_mode_enum(C);
2068  Paint *paint = NULL;
2069 
2070  switch (mode) {
2071  case CTX_MODE_PAINT_GPENCIL: {
2072  paint = &ts->gp_paint->paint;
2073  break;
2074  }
2075  case CTX_MODE_SCULPT_GPENCIL: {
2076  paint = &ts->gp_sculptpaint->paint;
2077  break;
2078  }
2079  case CTX_MODE_WEIGHT_GPENCIL: {
2080  paint = &ts->gp_weightpaint->paint;
2081  break;
2082  }
2083  case CTX_MODE_VERTEX_GPENCIL: {
2084  paint = &ts->gp_vertexpaint->paint;
2085  break;
2086  }
2087  default:
2088  break;
2089  }
2090 
2091  char tool = '0';
2092  if (paint) {
2093  Brush *brush_active = paint->brush;
2094  if (brush_active) {
2095  switch (mode) {
2096  case CTX_MODE_PAINT_GPENCIL: {
2097  tool = brush_active->gpencil_tool;
2098  break;
2099  }
2100  case CTX_MODE_SCULPT_GPENCIL: {
2101  tool = brush_active->gpencil_sculpt_tool;
2102  break;
2103  }
2104  case CTX_MODE_WEIGHT_GPENCIL: {
2105  tool = brush_active->gpencil_weight_tool;
2106  break;
2107  }
2108  case CTX_MODE_VERTEX_GPENCIL: {
2109  tool = brush_active->gpencil_vertex_tool;
2110  break;
2111  }
2112  default: {
2113  tool = brush_active->gpencil_tool;
2114  break;
2115  }
2116  }
2117  }
2118 
2119  gpencil_brush_delete_mode_brushes(bmain, paint, mode);
2120 
2121  switch (mode) {
2122  case CTX_MODE_PAINT_GPENCIL: {
2123  BKE_brush_gpencil_paint_presets(bmain, ts, true);
2124  break;
2125  }
2126  case CTX_MODE_SCULPT_GPENCIL: {
2127  BKE_brush_gpencil_sculpt_presets(bmain, ts, true);
2128  break;
2129  }
2130  case CTX_MODE_WEIGHT_GPENCIL: {
2131  BKE_brush_gpencil_weight_presets(bmain, ts, true);
2132  break;
2133  }
2134  case CTX_MODE_VERTEX_GPENCIL: {
2135  BKE_brush_gpencil_vertex_presets(bmain, ts, true);
2136  break;
2137  }
2138  default: {
2139  break;
2140  }
2141  }
2142 
2143  BKE_paint_toolslots_brush_validate(bmain, paint);
2144 
2145  /* Set Again the first brush of the mode. */
2146  Brush *deft_brush = gpencil_brush_get_first_by_mode(bmain, paint, mode, tool);
2147  if (deft_brush) {
2148  BKE_paint_brush_set(paint, deft_brush);
2149  }
2150  /* notifiers */
2151  DEG_relations_tag_update(bmain);
2153  }
2154 
2155  return OPERATOR_FINISHED;
2156 }
2157 
2159 {
2160  /* identifiers */
2161  ot->name = "Reset All Brushes";
2162  ot->idname = "GPENCIL_OT_brush_reset_all";
2163  ot->description = "Delete all mode brushes and recreate a default set";
2164 
2165  /* api callbacks */
2167 
2168  /* flags */
2170 }
2171 
2172 /*********************** Vertex Groups ***********************************/
2173 
2175 {
2177 
2178  if ((ob) && (ob->type == OB_GPENCIL)) {
2179  if (!ID_IS_LINKED(ob) && !ID_IS_LINKED(ob->data) && ob->defbase.first) {
2181  return true;
2182  }
2183  }
2184  }
2185 
2186  return false;
2187 }
2188 
2190 {
2192 
2193  if ((ob) && (ob->type == OB_GPENCIL)) {
2194  if (!ID_IS_LINKED(ob) && !ID_IS_LINKED(ob->data) && ob->defbase.first) {
2195  if (ob->mode == OB_MODE_WEIGHT_GPENCIL) {
2196  return true;
2197  }
2198  }
2199  }
2200 
2201  return false;
2202 }
2203 
2205 {
2208 
2209  /* sanity checks */
2210  if (ELEM(NULL, ts, ob, ob->data)) {
2211  return OPERATOR_CANCELLED;
2212  }
2213 
2215 
2216  /* notifiers */
2217  bGPdata *gpd = ob->data;
2220 
2221  return OPERATOR_FINISHED;
2222 }
2223 
2225 {
2226  /* identifiers */
2227  ot->name = "Assign to Vertex Group";
2228  ot->idname = "GPENCIL_OT_vertex_group_assign";
2229  ot->description = "Assign the selected vertices to the active vertex group";
2230 
2231  /* api callbacks */
2234 
2235  /* flags */
2237 }
2238 
2239 /* remove point from vertex group */
2241 {
2243 
2244  /* sanity checks */
2245  if (ELEM(NULL, ob, ob->data)) {
2246  return OPERATOR_CANCELLED;
2247  }
2248 
2250 
2251  /* notifiers */
2252  bGPdata *gpd = ob->data;
2255 
2256  return OPERATOR_FINISHED;
2257 }
2258 
2260 {
2261  /* identifiers */
2262  ot->name = "Remove from Vertex Group";
2263  ot->idname = "GPENCIL_OT_vertex_group_remove_from";
2264  ot->description = "Remove the selected vertices from active or all vertex group(s)";
2265 
2266  /* api callbacks */
2269 
2270  /* flags */
2272 }
2273 
2275 {
2277 
2278  /* sanity checks */
2279  if (ELEM(NULL, ob, ob->data)) {
2280  return OPERATOR_CANCELLED;
2281  }
2282 
2284 
2285  /* notifiers */
2286  bGPdata *gpd = ob->data;
2289 
2290  return OPERATOR_FINISHED;
2291 }
2292 
2294 {
2295  /* identifiers */
2296  ot->name = "Select Vertex Group";
2297  ot->idname = "GPENCIL_OT_vertex_group_select";
2298  ot->description = "Select all the vertices assigned to the active vertex group";
2299 
2300  /* api callbacks */
2303 
2304  /* flags */
2306 }
2307 
2309 {
2311 
2312  /* sanity checks */
2313  if (ELEM(NULL, ob, ob->data)) {
2314  return OPERATOR_CANCELLED;
2315  }
2316 
2318 
2319  /* notifiers */
2320  bGPdata *gpd = ob->data;
2323 
2324  return OPERATOR_FINISHED;
2325 }
2326 
2328 {
2329  /* identifiers */
2330  ot->name = "Deselect Vertex Group";
2331  ot->idname = "GPENCIL_OT_vertex_group_deselect";
2332  ot->description = "Deselect all selected vertices assigned to the active vertex group";
2333 
2334  /* api callbacks */
2337 
2338  /* flags */
2340 }
2341 
2342 /* invert */
2344 {
2347 
2348  /* sanity checks */
2349  if (ELEM(NULL, ts, ob, ob->data)) {
2350  return OPERATOR_CANCELLED;
2351  }
2352 
2353  MDeformVert *dvert;
2354  const int def_nr = ob->actdef - 1;
2355  bDeformGroup *defgroup = BLI_findlink(&ob->defbase, def_nr);
2356  if (defgroup == NULL) {
2357  return OPERATOR_CANCELLED;
2358  }
2359  if (defgroup->flag & DG_LOCK_WEIGHT) {
2360  BKE_report(op->reports, RPT_ERROR, "Current Vertex Group is locked");
2361  return OPERATOR_CANCELLED;
2362  }
2363 
2364  CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
2365  /* Verify the strokes has something to change. */
2366  if ((gps->totpoints == 0) || (gps->dvert == NULL)) {
2367  continue;
2368  }
2369 
2370  for (int i = 0; i < gps->totpoints; i++) {
2371  dvert = &gps->dvert[i];
2372  MDeformWeight *dw = BKE_defvert_find_index(dvert, def_nr);
2373  if (dw == NULL) {
2374  BKE_defvert_add_index_notest(dvert, def_nr, 1.0f);
2375  }
2376  else if (dw->weight == 1.0f) {
2377  BKE_defvert_remove_group(dvert, dw);
2378  }
2379  else {
2380  dw->weight = 1.0f - dw->weight;
2381  }
2382  }
2383  }
2384  CTX_DATA_END;
2385 
2386  /* notifiers */
2387  bGPdata *gpd = ob->data;
2390 
2391  return OPERATOR_FINISHED;
2392 }
2393 
2395 {
2396  /* identifiers */
2397  ot->name = "Invert Vertex Group";
2398  ot->idname = "GPENCIL_OT_vertex_group_invert";
2399  ot->description = "Invert weights to the active vertex group";
2400 
2401  /* api callbacks */
2404 
2405  /* flags */
2407 }
2408 
2409 /* smooth */
2411 {
2412  const float fac = RNA_float_get(op->ptr, "factor");
2413  const int repeat = RNA_int_get(op->ptr, "repeat");
2414 
2417 
2418  /* sanity checks */
2419  if (ELEM(NULL, ts, ob, ob->data)) {
2420  return OPERATOR_CANCELLED;
2421  }
2422 
2423  const int def_nr = ob->actdef - 1;
2424  bDeformGroup *defgroup = BLI_findlink(&ob->defbase, def_nr);
2425  if (defgroup == NULL) {
2426  return OPERATOR_CANCELLED;
2427  }
2428  if (defgroup->flag & DG_LOCK_WEIGHT) {
2429  BKE_report(op->reports, RPT_ERROR, "Current Vertex Group is locked");
2430  return OPERATOR_CANCELLED;
2431  }
2432 
2433  bGPDspoint *pta, *ptb, *ptc;
2434  MDeformVert *dverta, *dvertb;
2435 
2436  CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
2437  /* Verify the strokes has something to change. */
2438  if ((gps->totpoints == 0) || (gps->dvert == NULL)) {
2439  continue;
2440  }
2441 
2442  for (int s = 0; s < repeat; s++) {
2443  for (int i = 0; i < gps->totpoints; i++) {
2444  /* previous point */
2445  if (i > 0) {
2446  pta = &gps->points[i - 1];
2447  dverta = &gps->dvert[i - 1];
2448  }
2449  else {
2450  pta = &gps->points[i];
2451  dverta = &gps->dvert[i];
2452  }
2453  /* current */
2454  ptb = &gps->points[i];
2455  dvertb = &gps->dvert[i];
2456  /* next point */
2457  if (i + 1 < gps->totpoints) {
2458  ptc = &gps->points[i + 1];
2459  }
2460  else {
2461  ptc = &gps->points[i];
2462  }
2463 
2464  float wa = BKE_defvert_find_weight(dverta, def_nr);
2465  float wb = BKE_defvert_find_weight(dvertb, def_nr);
2466 
2467  /* the optimal value is the corresponding to the interpolation of the weight
2468  * at the distance of point b
2469  */
2470  const float opfac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
2471  const float optimal = interpf(wa, wb, opfac);
2472  /* Based on influence factor, blend between original and optimal */
2473  MDeformWeight *dw = BKE_defvert_ensure_index(dvertb, def_nr);
2474  if (dw) {
2475  dw->weight = interpf(wb, optimal, fac);
2476  CLAMP(dw->weight, 0.0, 1.0f);
2477  }
2478  }
2479  }
2480  }
2481  CTX_DATA_END;
2482 
2483  /* notifiers */
2484  bGPdata *gpd = ob->data;
2487 
2488  return OPERATOR_FINISHED;
2489 }
2490 
2492 {
2493  /* identifiers */
2494  ot->name = "Smooth Vertex Group";
2495  ot->idname = "GPENCIL_OT_vertex_group_smooth";
2496  ot->description = "Smooth weights to the active vertex group";
2497 
2498  /* api callbacks */
2501 
2502  /* flags */
2504 
2505  RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 1.0, "Factor", "", 0.0f, 1.0f);
2506  RNA_def_int(ot->srna, "repeat", 1, 1, 10000, "Iterations", "", 1, 200);
2507 }
2508 
2509 /* normalize */
2511 {
2514 
2515  /* sanity checks */
2516  if (ELEM(NULL, ts, ob, ob->data)) {
2517  return OPERATOR_CANCELLED;
2518  }
2519 
2520  MDeformVert *dvert = NULL;
2521  MDeformWeight *dw = NULL;
2522  const int def_nr = ob->actdef - 1;
2523  bDeformGroup *defgroup = BLI_findlink(&ob->defbase, def_nr);
2524  if (defgroup == NULL) {
2525  return OPERATOR_CANCELLED;
2526  }
2527  if (defgroup->flag & DG_LOCK_WEIGHT) {
2528  BKE_report(op->reports, RPT_ERROR, "Current Vertex Group is locked");
2529  return OPERATOR_CANCELLED;
2530  }
2531 
2532  CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
2533  /* Verify the strokes has something to change. */
2534  if ((gps->totpoints == 0) || (gps->dvert == NULL)) {
2535  continue;
2536  }
2537 
2538  /* look for max value */
2539  float maxvalue = 0.0f;
2540  for (int i = 0; i < gps->totpoints; i++) {
2541  dvert = &gps->dvert[i];
2542  dw = BKE_defvert_find_index(dvert, def_nr);
2543  if ((dw != NULL) && (dw->weight > maxvalue)) {
2544  maxvalue = dw->weight;
2545  }
2546  }
2547 
2548  /* normalize weights */
2549  if (maxvalue > 0.0f) {
2550  for (int i = 0; i < gps->totpoints; i++) {
2551  dvert = &gps->dvert[i];
2552  dw = BKE_defvert_find_index(dvert, def_nr);
2553  if (dw != NULL) {
2554  dw->weight = dw->weight / maxvalue;
2555  }
2556  }
2557  }
2558  }
2559  CTX_DATA_END;
2560 
2561  /* notifiers */
2562  bGPdata *gpd = ob->data;
2565 
2566  return OPERATOR_FINISHED;
2567 }
2568 
2570 {
2571  /* identifiers */
2572  ot->name = "Normalize Vertex Group";
2573  ot->idname = "GPENCIL_OT_vertex_group_normalize";
2574  ot->description = "Normalize weights to the active vertex group";
2575 
2576  /* api callbacks */
2579 
2580  /* flags */
2582 }
2583 
2584 /* normalize all */
2586 {
2589  bool lock_active = RNA_boolean_get(op->ptr, "lock_active");
2590 
2591  /* sanity checks */
2592  if (ELEM(NULL, ts, ob, ob->data)) {
2593  return OPERATOR_CANCELLED;
2594  }
2595 
2596  bDeformGroup *defgroup = NULL;
2597  MDeformVert *dvert = NULL;
2598  MDeformWeight *dw = NULL;
2599  const int def_nr = ob->actdef - 1;
2600  const int defbase_tot = BLI_listbase_count(&ob->defbase);
2601  if (defbase_tot == 0) {
2602  return OPERATOR_CANCELLED;
2603  }
2604 
2605  CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
2606  /* Verify the strokes has something to change. */
2607  if ((gps->totpoints == 0) || (gps->dvert == NULL)) {
2608  continue;
2609  }
2610 
2611  /* look for tot value */
2612  float *tot_values = MEM_callocN(gps->totpoints * sizeof(float), __func__);
2613 
2614  for (int i = 0; i < gps->totpoints; i++) {
2615  dvert = &gps->dvert[i];
2616  for (int v = 0; v < defbase_tot; v++) {
2617  defgroup = BLI_findlink(&ob->defbase, v);
2618  /* skip NULL or locked groups */
2619  if ((defgroup == NULL) || (defgroup->flag & DG_LOCK_WEIGHT)) {
2620  continue;
2621  }
2622 
2623  /* skip current */
2624  if ((lock_active) && (v == def_nr)) {
2625  continue;
2626  }
2627 
2628  dw = BKE_defvert_find_index(dvert, v);
2629  if (dw != NULL) {
2630  tot_values[i] += dw->weight;
2631  }
2632  }
2633  }
2634 
2635  /* normalize weights */
2636  for (int i = 0; i < gps->totpoints; i++) {
2637  if (tot_values[i] == 0.0f) {
2638  continue;
2639  }
2640 
2641  dvert = &gps->dvert[i];
2642  for (int v = 0; v < defbase_tot; v++) {
2643  defgroup = BLI_findlink(&ob->defbase, v);
2644  /* skip NULL or locked groups */
2645  if ((defgroup == NULL) || (defgroup->flag & DG_LOCK_WEIGHT)) {
2646  continue;
2647  }
2648 
2649  /* skip current */
2650  if ((lock_active) && (v == def_nr)) {
2651  continue;
2652  }
2653 
2654  dw = BKE_defvert_find_index(dvert, v);
2655  if (dw != NULL) {
2656  dw->weight = dw->weight / tot_values[i];
2657  }
2658  }
2659  }
2660 
2661  /* free temp array */
2662  MEM_SAFE_FREE(tot_values);
2663  }
2664  CTX_DATA_END;
2665 
2666  /* notifiers */
2667  bGPdata *gpd = ob->data;
2670 
2671  return OPERATOR_FINISHED;
2672 }
2673 
2675 {
2676  /* identifiers */
2677  ot->name = "Normalize All Vertex Group";
2678  ot->idname = "GPENCIL_OT_vertex_group_normalize_all";
2679  ot->description =
2680  "Normalize all weights of all vertex groups, "
2681  "so that for each vertex, the sum of all weights is 1.0";
2682 
2683  /* api callbacks */
2686 
2687  /* flags */
2689 
2690  /* props */
2692  "lock_active",
2693  true,
2694  "Lock Active",
2695  "Keep the values of the active group while normalizing others");
2696 }
2697 
2698 /****************************** Join ***********************************/
2699 
2700 /* userdata for joined_gpencil_fix_animdata_cb() */
2701 typedef struct tJoinGPencil_AdtFixData {
2704 
2707 
2712 static void gpencil_joined_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data)
2713 {
2715  ID *src_id = &afd->src_gpd->id;
2716  ID *dst_id = &afd->tar_gpd->id;
2717 
2718  GHashIterator gh_iter;
2719 
2720  /* Fix paths - If this is the target datablock, it will have some "dirty" paths */
2721  if ((id == src_id) && fcu->rna_path && strstr(fcu->rna_path, "layers[")) {
2722  GHASH_ITER (gh_iter, afd->names_map) {
2723  const char *old_name = BLI_ghashIterator_getKey(&gh_iter);
2724  const char *new_name = BLI_ghashIterator_getValue(&gh_iter);
2725 
2726  /* only remap if changed;
2727  * this still means there will be some waste if there aren't many drivers/keys */
2728  if (!STREQ(old_name, new_name) && strstr(fcu->rna_path, old_name)) {
2730  id, fcu->rna_path, "layers", old_name, new_name, 0, 0, false);
2731 
2732  /* we don't want to apply a second remapping on this F-Curve now,
2733  * so stop trying to fix names names
2734  */
2735  break;
2736  }
2737  }
2738  }
2739 
2740  /* Fix driver targets */
2741  if (fcu->driver) {
2742  /* Fix driver references to invalid ID's */
2743  LISTBASE_FOREACH (DriverVar *, dvar, &fcu->driver->variables) {
2744  /* Only change the used targets, since the others will need fixing manually anyway. */
2746  /* Change the ID's used. */
2747  if (dtar->id == src_id) {
2748  dtar->id = dst_id;
2749 
2750  /* Also check on the sub-target.
2751  * We duplicate the logic from #drivers_path_rename_fix() here, with our own
2752  * little twists so that we know that it isn't going to clobber the wrong data
2753  */
2754  if (dtar->rna_path && strstr(dtar->rna_path, "layers[")) {
2755  GHASH_ITER (gh_iter, afd->names_map) {
2756  const char *old_name = BLI_ghashIterator_getKey(&gh_iter);
2757  const char *new_name = BLI_ghashIterator_getValue(&gh_iter);
2758 
2759  /* Only remap if changed. */
2760  if (!STREQ(old_name, new_name)) {
2761  if ((dtar->rna_path) && strstr(dtar->rna_path, old_name)) {
2762  /* Fix up path */
2763  dtar->rna_path = BKE_animsys_fix_rna_path_rename(
2764  id, dtar->rna_path, "layers", old_name, new_name, 0, 0, false);
2765  break; /* no need to try any more names for layer path */
2766  }
2767  }
2768  }
2769  }
2770  }
2771  }
2773  }
2774  }
2775 }
2776 
2777 /* join objects called from OBJECT_OT_join */
2779 {
2780  Main *bmain = CTX_data_main(C);
2783  Object *ob_active = CTX_data_active_object(C);
2784  bGPdata *gpd_dst = NULL;
2785  bool ok = false;
2786 
2787  /* Ensure we're in right mode and that the active object is correct */
2788  if (!ob_active || ob_active->type != OB_GPENCIL) {
2789  return OPERATOR_CANCELLED;
2790  }
2791 
2792  bGPdata *gpd = (bGPdata *)ob_active->data;
2793  if ((!gpd) || GPENCIL_ANY_MODE(gpd)) {
2794  return OPERATOR_CANCELLED;
2795  }
2796 
2797  /* Ensure all rotations are applied before */
2798  CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
2799  if (ob_iter->type == OB_GPENCIL) {
2800  if ((ob_iter->rot[0] != 0) || (ob_iter->rot[1] != 0) || (ob_iter->rot[2] != 0)) {
2801  BKE_report(op->reports, RPT_ERROR, "Apply all rotations before join objects");
2802  return OPERATOR_CANCELLED;
2803  }
2804  }
2805  }
2806  CTX_DATA_END;
2807 
2808  CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
2809  if (ob_iter == ob_active) {
2810  ok = true;
2811  break;
2812  }
2813  }
2814  CTX_DATA_END;
2815 
2816  /* that way the active object is always selected */
2817  if (ok == false) {
2818  BKE_report(op->reports, RPT_WARNING, "Active object is not a selected grease pencil");
2819  return OPERATOR_CANCELLED;
2820  }
2821 
2822  gpd_dst = ob_active->data;
2823  Object *ob_dst = ob_active;
2824 
2825  /* loop and join all data */
2826  CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
2827  if ((ob_iter->type == OB_GPENCIL) && (ob_iter != ob_active)) {
2828  /* we assume that each datablock is not already used in active object */
2829  if (ob_active->data != ob_iter->data) {
2830  Object *ob_src = ob_iter;
2831  bGPdata *gpd_src = ob_iter->data;
2832 
2833  /* Apply all GP modifiers before */
2834  LISTBASE_FOREACH (GpencilModifierData *, md, &ob_iter->greasepencil_modifiers) {
2836  if (mti->bakeModifier) {
2837  mti->bakeModifier(bmain, depsgraph, md, ob_iter);
2838  }
2839  }
2840 
2841  /* copy vertex groups to the base one's */
2842  int old_idx = 0;
2843  LISTBASE_FOREACH (bDeformGroup *, dg, &ob_iter->defbase) {
2844  bDeformGroup *vgroup = MEM_dupallocN(dg);
2845  int idx = BLI_listbase_count(&ob_active->defbase);
2846  BKE_object_defgroup_unique_name(vgroup, ob_active);
2847  BLI_addtail(&ob_active->defbase, vgroup);
2848  /* update vertex groups in strokes in original data */
2849  LISTBASE_FOREACH (bGPDlayer *, gpl_src, &gpd->layers) {
2850  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl_src->frames) {
2851  LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
2852  MDeformVert *dvert;
2853  int i;
2854  if (gps->dvert == NULL) {
2855  continue;
2856  }
2857  for (i = 0, dvert = gps->dvert; i < gps->totpoints; i++, dvert++) {
2858  if ((dvert->dw != NULL) && (dvert->dw->def_nr == old_idx)) {
2859  dvert->dw->def_nr = idx;
2860  }
2861  }
2862  }
2863  }
2864  }
2865  old_idx++;
2866  }
2867  if (ob_active->defbase.first && ob_active->actdef == 0) {
2868  ob_active->actdef = 1;
2869  }
2870 
2871  /* add missing materials reading source materials and checking in destination object */
2872  short *totcol = BKE_object_material_len_p(ob_src);
2873 
2874  for (short i = 0; i < *totcol; i++) {
2875  Material *tmp_ma = BKE_gpencil_material(ob_src, i + 1);
2876  BKE_gpencil_object_material_ensure(bmain, ob_dst, tmp_ma);
2877  }
2878 
2879  /* duplicate bGPDlayers */
2880  tJoinGPencil_AdtFixData afd = {0};
2881  afd.src_gpd = gpd_src;
2882  afd.tar_gpd = gpd_dst;
2883  afd.names_map = BLI_ghash_str_new("joined_gp_layers_map");
2884 
2885  float imat[3][3], bmat[3][3];
2886  float offset_global[3];
2887  float offset_local[3];
2888 
2889  sub_v3_v3v3(offset_global, ob_active->loc, ob_iter->obmat[3]);
2890  copy_m3_m4(bmat, ob_active->obmat);
2891 
2892  /* Inverse transform for all selected curves in this object,
2893  * See #object_join_exec for detailed comment on why the safe version is used. */
2894  invert_m3_m3_safe_ortho(imat, bmat);
2895  mul_m3_v3(imat, offset_global);
2896  mul_v3_m3v3(offset_local, imat, offset_global);
2897 
2898  LISTBASE_FOREACH (bGPDlayer *, gpl_src, &gpd_src->layers) {
2899  bGPDlayer *gpl_new = BKE_gpencil_layer_duplicate(gpl_src, true, true);
2900  float diff_mat[4][4];
2901  float inverse_diff_mat[4][4];
2902 
2903  /* recalculate all stroke points */
2904  BKE_gpencil_layer_transform_matrix_get(depsgraph, ob_iter, gpl_src, diff_mat);
2905  invert_m4_m4_safe_ortho(inverse_diff_mat, diff_mat);
2906 
2907  Material *ma_src = NULL;
2908  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl_new->frames) {
2909  LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
2910 
2911  /* Reassign material. Look old material and try to find in destination. */
2912  ma_src = BKE_gpencil_material(ob_src, gps->mat_nr + 1);
2913  gps->mat_nr = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma_src);
2914 
2915  bGPDspoint *pt;
2916  int i;
2917  for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
2918  float mpt[3];
2919  mul_v3_m4v3(mpt, inverse_diff_mat, &pt->x);
2920  sub_v3_v3(mpt, offset_local);
2921  mul_v3_m4v3(&pt->x, diff_mat, mpt);
2922  }
2923  }
2924  }
2925 
2926  /* be sure name is unique in new object */
2927  BLI_uniquename(&gpd_dst->layers,
2928  gpl_new,
2929  DATA_("GP_Layer"),
2930  '.',
2931  offsetof(bGPDlayer, info),
2932  sizeof(gpl_new->info));
2933  BLI_ghash_insert(afd.names_map, BLI_strdup(gpl_src->info), gpl_new->info);
2934 
2935  /* add to destination datablock */
2936  BLI_addtail(&gpd_dst->layers, gpl_new);
2937  }
2938 
2939  /* Fix all the animation data */
2942 
2943  /* Only copy over animdata now, after all the remapping has been done,
2944  * so that we don't have to worry about ambiguities re which datablock
2945  * a layer came from!
2946  */
2947  if (ob_iter->adt) {
2948  if (ob_active->adt == NULL) {
2949  /* no animdata, so just use a copy of the whole thing */
2950  ob_active->adt = BKE_animdata_copy(bmain, ob_iter->adt, 0);
2951  }
2952  else {
2953  /* merge in data - we'll fix the drivers manually */
2955  bmain, &ob_active->id, &ob_iter->id, ADT_MERGECOPY_KEEP_DST, false);
2956  }
2957  }
2958 
2959  if (gpd_src->adt) {
2960  if (gpd_dst->adt == NULL) {
2961  /* no animdata, so just use a copy of the whole thing */
2962  gpd_dst->adt = BKE_animdata_copy(bmain, gpd_src->adt, 0);
2963  }
2964  else {
2965  /* merge in data - we'll fix the drivers manually */
2967  bmain, &gpd_dst->id, &gpd_src->id, ADT_MERGECOPY_KEEP_DST, false);
2968  }
2969  }
2970  DEG_id_tag_update(&gpd_src->id,
2972  }
2973 
2974  /* Free the old object */
2975  ED_object_base_free_and_unlink(bmain, scene, ob_iter);
2976  }
2977  }
2978  CTX_DATA_END;
2979 
2980  DEG_id_tag_update(&gpd_dst->id,
2982  DEG_relations_tag_update(bmain); /* because we removed object(s) */
2983 
2986 
2987  return OPERATOR_FINISHED;
2988 }
2989 
2990 /* Color Handle operator */
2992 {
2994  if (ob && ob->data && (ob->type == OB_GPENCIL)) {
2995  short *totcolp = BKE_object_material_len_p(ob);
2996  return *totcolp > 0;
2997  }
2998  return false;
2999 }
3000 
3001 /* **************** Lock and hide any color non used in current layer **************************
3002  */
3004 {
3007  MaterialGPencilStyle *gp_style = NULL;
3008 
3009  /* sanity checks */
3010  if (ELEM(NULL, gpd)) {
3011  return OPERATOR_CANCELLED;
3012  }
3013 
3014  /* first lock and hide all colors */
3015  Material *ma = NULL;
3016  short *totcol = BKE_object_material_len_p(ob);
3017  if (totcol == 0) {
3018  return OPERATOR_CANCELLED;
3019  }
3020 
3021  for (short i = 0; i < *totcol; i++) {
3022  ma = BKE_gpencil_material(ob, i + 1);
3023  if (ma) {
3024  gp_style = ma->gp_style;
3025  gp_style->flag |= GP_MATERIAL_LOCKED;
3026  gp_style->flag |= GP_MATERIAL_HIDE;
3028  }
3029  }
3030 
3031  /* loop all selected strokes and unlock any color used in active layer */
3032  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
3033  /* only editable and visible layers are considered */
3034  if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL) &&
3035  (gpl->flag & GP_LAYER_ACTIVE)) {
3036  for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
3037  /* skip strokes that are invalid for current view */
3038  if (ED_gpencil_stroke_can_use(C, gps) == false) {
3039  continue;
3040  }
3041 
3042  ma = BKE_gpencil_material(ob, gps->mat_nr + 1);
3044 
3045  gp_style = ma->gp_style;
3046  /* unlock/unhide color if not unlocked before */
3047  if (gp_style != NULL) {
3048  gp_style->flag &= ~GP_MATERIAL_LOCKED;
3049  gp_style->flag &= ~GP_MATERIAL_HIDE;
3050  }
3051  }
3052  }
3053  }
3054  /* updates */
3056 
3057  /* copy on write tag is needed, or else no refresh happens */
3059 
3060  /* notifiers */
3063 
3064  return OPERATOR_FINISHED;
3065 }
3066 
3068 {
3069  /* identifiers */
3070  ot->name = "Disable Unused Layer Colors";
3071  ot->idname = "GPENCIL_OT_lock_layer";
3072  ot->description = "Lock and hide any color not used in any layer";
3073 
3074  /* api callbacks */
3077 }
3078 
3079 /* ********************** Isolate gpencil_ color **************************** */
3080 
3082 {
3085  Material *active_ma = BKE_gpencil_material(ob, ob->actcol);
3087  MaterialGPencilStyle *gp_style;
3088 
3089  int flags = GP_MATERIAL_LOCKED;
3090  bool isolate = false;
3091 
3092  if (RNA_boolean_get(op->ptr, "affect_visibility")) {
3093  flags |= GP_MATERIAL_HIDE;
3094  }
3095 
3096  if (ELEM(NULL, gpd, active_color)) {
3097  BKE_report(op->reports, RPT_ERROR, "No active color to isolate");
3098  return OPERATOR_CANCELLED;
3099  }
3100 
3101  /* Test whether to isolate or clear all flags */
3102  Material *ma = NULL;
3103  short *totcol = BKE_object_material_len_p(ob);
3104  for (short i = 0; i < *totcol; i++) {
3105  ma = BKE_gpencil_material(ob, i + 1);
3106  /* Skip if this is the active one */
3107  if (ELEM(ma, NULL, active_ma)) {
3108  continue;
3109  }
3110 
3111  /* If the flags aren't set, that means that the color is
3112  * not alone, so we have some colors to isolate still
3113  */
3114  gp_style = ma->gp_style;
3115  if ((gp_style->flag & flags) == 0) {
3116  isolate = true;
3117  break;
3118  }
3119  }
3120 
3121  /* Set/Clear flags as appropriate */
3122  if (isolate) {
3123  /* Set flags on all "other" colors */
3124  for (short i = 0; i < *totcol; i++) {
3125  ma = BKE_gpencil_material(ob, i + 1);
3126  if (ma == NULL) {
3127  continue;
3128  }
3129  gp_style = ma->gp_style;
3130  if (gp_style == active_color) {
3131  continue;
3132  }
3133  gp_style->flag |= flags;
3135  }
3136  }
3137  else {
3138  /* Clear flags - Restore everything else */
3139  for (short i = 0; i < *totcol; i++) {
3140  ma = BKE_gpencil_material(ob, i + 1);
3141  if (ma == NULL) {
3142  continue;
3143  }
3144  gp_style = ma->gp_style;
3145  gp_style->flag &= ~flags;
3147  }
3148  }
3149 
3150  /* notifiers */
3152 
3153  /* copy on write tag is needed, or else no refresh happens */
3155 
3157 
3158  return OPERATOR_FINISHED;
3159 }
3160 
3162 {
3163  /* identifiers */
3164  ot->name = "Isolate Material";
3165  ot->idname = "GPENCIL_OT_material_isolate";
3166  ot->description =
3167  "Toggle whether the active material is the only one that is editable and/or visible";
3168 
3169  /* callbacks */
3172 
3173  /* flags */
3175 
3176  /* properties */
3178  "affect_visibility",
3179  false,
3180  "Affect Visibility",
3181  "In addition to toggling "
3182  "the editability, also affect the visibility");
3183 }
3184 
3185 /* *********************** Hide colors ******************************** */
3186 
3188 {
3190  bGPdata *gpd = (bGPdata *)ob->data;
3192 
3193  bool unselected = RNA_boolean_get(op->ptr, "unselected");
3194 
3195  Material *ma = NULL;
3196  short *totcol = BKE_object_material_len_p(ob);
3197  if (totcol == 0) {
3198  return OPERATOR_CANCELLED;
3199  }
3200 
3201  if (unselected) {
3202  /* hide unselected */
3203  MaterialGPencilStyle *color = NULL;
3204  for (short i = 0; i < *totcol; i++) {
3205  ma = BKE_gpencil_material(ob, i + 1);
3206  if (ma) {
3207  color = ma->gp_style;
3208  if (active_color != color) {
3209  color->flag |= GP_MATERIAL_HIDE;
3211  }
3212  }
3213  }
3214  }
3215  else {
3216  /* hide selected/active */
3217  active_color->flag |= GP_MATERIAL_HIDE;
3218  }
3219 
3220  /* updates */
3222 
3223  /* copy on write tag is needed, or else no refresh happens */
3225 
3226  /* notifiers */
3228 
3229  return OPERATOR_FINISHED;
3230 }
3231 
3233 {
3234  /* identifiers */
3235  ot->name = "Hide Material(s)";
3236  ot->idname = "GPENCIL_OT_material_hide";
3237  ot->description = "Hide selected/unselected Grease Pencil materials";
3238 
3239  /* callbacks */
3241  ot->poll = gpencil_active_material_poll; /* NOTE: we need an active color to play with */
3242 
3243  /* flags */
3245 
3246  /* props */
3248  ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected colors");
3249 }
3250 
3251 /* ********************** Show All Colors ***************************** */
3252 
3254 {
3256  bGPdata *gpd = (bGPdata *)ob->data;
3257  Material *ma = NULL;
3258  short *totcol = BKE_object_material_len_p(ob);
3259 
3260  if (totcol == 0) {
3261  return OPERATOR_CANCELLED;
3262  }
3263 
3264  /* make all colors visible */
3265  MaterialGPencilStyle *gp_style = NULL;
3266 
3267  for (short i = 0; i < *totcol; i++) {
3268  ma = BKE_gpencil_material(ob, i + 1);
3269  if (ma) {
3270  gp_style = ma->gp_style;
3271  gp_style->flag &= ~GP_MATERIAL_HIDE;
3273  }
3274  }
3275 
3276  /* updates */
3278 
3279  /* copy on write tag is needed, or else no refresh happens */
3281 
3282  /* notifiers */
3284 
3285  return OPERATOR_FINISHED;
3286 }
3287 
3289 {
3290  /* identifiers */
3291  ot->name = "Show All Materials";
3292  ot->idname = "GPENCIL_OT_material_reveal";
3293  ot->description = "Unhide all hidden Grease Pencil materials";
3294 
3295  /* callbacks */
3298 
3299  /* flags */
3301 }
3302 
3303 /* ***************** Lock/Unlock All colors ************************ */
3304 
3306 {
3307 
3309  bGPdata *gpd = (bGPdata *)ob->data;
3310  Material *ma = NULL;
3311  short *totcol = BKE_object_material_len_p(ob);
3312 
3313  if (totcol == 0) {
3314  return OPERATOR_CANCELLED;
3315  }
3316 
3317  /* make all layers non-editable */
3318  MaterialGPencilStyle *gp_style = NULL;
3319 
3320  for (short i = 0; i < *totcol; i++) {
3321  ma = BKE_gpencil_material(ob, i + 1);
3322  if (ma) {
3323  gp_style = ma->gp_style;
3324  gp_style->flag |= GP_MATERIAL_LOCKED;
3326  }
3327  }
3328 
3329  /* updates */
3331 
3332  /* copy on write tag is needed, or else no refresh happens */
3334 
3335  /* notifiers */
3337 
3338  return OPERATOR_FINISHED;
3339 }
3340 
3342 {
3343  /* identifiers */
3344  ot->name = "Lock All Materials";
3345  ot->idname = "GPENCIL_OT_material_lock_all";
3346  ot->description =
3347  "Lock all Grease Pencil materials to prevent them from being accidentally modified";
3348 
3349  /* callbacks */
3352 
3353  /* flags */
3355 }
3356 
3357 /* -------------------------- */
3358 
3360 {
3362  bGPdata *gpd = (bGPdata *)ob->data;
3363  Material *ma = NULL;
3364  short *totcol = BKE_object_material_len_p(ob);
3365 
3366  if (totcol == 0) {
3367  return OPERATOR_CANCELLED;
3368  }
3369 
3370  /* make all layers editable again*/
3371  MaterialGPencilStyle *gp_style = NULL;
3372 
3373  for (short i = 0; i < *totcol; i++) {
3374  ma = BKE_gpencil_material(ob, i + 1);
3375  if (ma) {
3376  gp_style = ma->gp_style;
3377  gp_style->flag &= ~GP_MATERIAL_LOCKED;
3379  }
3380  }
3381 
3382  /* updates */
3384 
3385  /* copy on write tag is needed, or else no refresh happens */
3387 
3388  /* notifiers */
3390 
3391  return OPERATOR_FINISHED;
3392 }
3393 
3395 {
3396  /* identifiers */
3397  ot->name = "Unlock All Materials";
3398  ot->idname = "GPENCIL_OT_material_unlock_all";
3399  ot->description = "Unlock all Grease Pencil materials so that they can be edited";
3400 
3401  /* callbacks */
3404 
3405  /* flags */
3407 }
3408 
3409 /* ***************** Select all strokes using color ************************ */
3410 
3412 {
3416  const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
3417  const bool deselected = RNA_boolean_get(op->ptr, "deselect");
3418 
3419  /* sanity checks */
3420  if (ELEM(NULL, gpd, gp_style)) {
3421  return OPERATOR_CANCELLED;
3422  }
3423 
3424  /* read all strokes and select*/
3425  CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
3426  bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
3427 
3428  for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
3429  if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
3430 
3431  /* verify something to do */
3432  LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
3433  /* skip strokes that are invalid for current view */
3434  if (ED_gpencil_stroke_can_use(C, gps) == false) {
3435  continue;
3436  }
3437  /* check if the color is editable */
3438  if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
3439  continue;
3440  }
3441 
3442  /* select */
3443  if (ob->actcol == gps->mat_nr + 1) {
3444  bGPDspoint *pt;
3445  int i;
3446 
3447  if (!deselected) {
3448  gps->flag |= GP_STROKE_SELECT;
3450  }
3451  else {
3452  gps->flag &= ~GP_STROKE_SELECT;
3454  }
3455  for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
3456  if (!deselected) {
3457  pt->flag |= GP_SPOINT_SELECT;
3458  }
3459  else {
3460  pt->flag &= ~GP_SPOINT_SELECT;
3461  }
3462  }
3463  }
3464  }
3465  }
3466  /* if not multiedit, exit loop*/
3467  if (!is_multiedit) {
3468  break;
3469  }
3470  }
3471  }
3472  CTX_DATA_END;
3473 
3474  /* copy on write tag is needed, or else no refresh happens */
3476 
3477  /* notifiers */
3479 
3480  return OPERATOR_FINISHED;
3481 }
3482 
3484 {
3485  /* identifiers */
3486  ot->name = "Select Material";
3487  ot->idname = "GPENCIL_OT_material_select";
3488  ot->description = "Select/Deselect all Grease Pencil strokes using current material";
3489 
3490  /* callbacks */
3493 
3494  /* flags */
3496 
3497  /* props */
3498  ot->prop = RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Unselect strokes");
3500 }
3501 
3502 /* ***************** Set active material ************************* */
3504 {
3506  int slot = RNA_enum_get(op->ptr, "slot");
3507 
3508  /* Try to get material */
3509  if ((slot < 1) || (slot > ob->totcol)) {
3510  BKE_reportf(
3511  op->reports, RPT_ERROR, "Cannot change to non-existent material (index = %d)", slot);
3512  return OPERATOR_CANCELLED;
3513  }
3514 
3515  /* Set active material. */
3516  ob->actcol = slot;
3517 
3518  /* updates */
3521 
3522  return OPERATOR_FINISHED;
3523 }
3524 
3526 {
3527  /* identifiers */
3528  ot->name = "Set Material";
3529  ot->idname = "GPENCIL_OT_material_set";
3530  ot->description = "Set active material";
3531 
3532  /* callbacks */
3535 
3536  /* flags */
3538 
3539  /* Material to use (dynamic enum) */
3540  ot->prop = RNA_def_enum(ot->srna, "slot", DummyRNA_DEFAULT_items, 0, "Material Slot", "");
3542 }
3543 
3544 /* ***************** Set selected stroke material the active material ************************ */
3545 
3547 {
3550 
3551  /* Sanity checks. */
3552  if (gpd == NULL) {
3553  BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
3554  return OPERATOR_CANCELLED;
3555  }
3556 
3557  bool changed = false;
3558  /* Loop all selected strokes. */
3559  GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
3560  if (gps->flag & GP_STROKE_SELECT) {
3561  /* Change Active material. */
3562  ob->actcol = gps->mat_nr + 1;
3563  changed = true;
3564  break;
3565  }
3566  }
3567  GP_EDITABLE_STROKES_END(gpstroke_iter);
3568 
3569  /* notifiers */
3570  if (changed) {
3572  }
3573 
3574  return OPERATOR_FINISHED;
3575 }
3576 
3578 {
3579  /* identifiers */
3580  ot->name = "Set active material";
3581  ot->idname = "GPENCIL_OT_set_active_material";
3582  ot->description = "Set the selected stroke material as the active material";
3583 
3584  /* callbacks */
3587 
3588  /* flags */
3590 }
3591 
3592 /* Parent GPencil object to Lattice */
3594  ReportList *reports,
3595  Object *ob,
3596  Object *ob_latt)
3597 {
3598  Main *bmain = CTX_data_main(C);
3600 
3601  if (ob == NULL) {
3602  return false;
3603  }
3604 
3605  /* if no lattice modifier, add a new one */
3607  if (md == NULL) {
3609  reports, bmain, scene, ob, "Lattice", eGpencilModifierType_Lattice);
3610  if (md == NULL) {
3611  BKE_report(reports, RPT_ERROR, "Unable to add a new Lattice modifier to object");
3612  return false;
3613  }
3615  }
3616 
3617  /* verify lattice */
3619  if (mmd->object == NULL) {
3620  mmd->object = ob_latt;
3621  }
3622  else {
3623  if (ob_latt != mmd->object) {
3624  BKE_report(reports,
3625  RPT_ERROR,
3626  "The existing Lattice modifier is already using a different Lattice object");
3627  return false;
3628  }
3629  }
3630 
3631  return true;
3632 }
3633 
3634 /* Masking operators */
3636 {
3638  if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
3639  return OPERATOR_CANCELLED;
3640  }
3641 
3642  bGPdata *gpd = (bGPdata *)ob->data;
3643  bGPDlayer *gpl_active = BKE_gpencil_layer_active_get(gpd);
3644  if (gpl_active == NULL) {
3645  return OPERATOR_CANCELLED;
3646  }
3647  char name[128];
3648  RNA_string_get(op->ptr, "name", name);
3649  bGPDlayer *gpl = BKE_gpencil_layer_named_get(gpd, name);
3650 
3651  if (gpl == NULL) {
3652  BKE_report(op->reports, RPT_ERROR, "Unable to find layer to add");
3653  return OPERATOR_CANCELLED;
3654  }
3655 
3656  if (gpl == gpl_active) {
3657  BKE_report(op->reports, RPT_ERROR, "Cannot add active layer as mask");
3658  return OPERATOR_CANCELLED;
3659  }
3660 
3661  if (BKE_gpencil_layer_mask_named_get(gpl_active, name)) {
3662  BKE_report(op->reports, RPT_ERROR, "Layer already added");
3663  return OPERATOR_CANCELLED;
3664  }
3665 
3666  if (gpl_active->act_mask == 256) {
3667  BKE_report(op->reports, RPT_ERROR, "Maximum number of masking layers reached");
3668  return OPERATOR_CANCELLED;
3669  }
3670 
3671  BKE_gpencil_layer_mask_add(gpl_active, name);
3672 
3673  /* Reorder masking. */
3674  BKE_gpencil_layer_mask_sort(gpd, gpl_active);
3675 
3676  /* notifiers */
3677  if (gpd) {
3678  DEG_id_tag_update(&gpd->id,
3680  }
3682 
3683  return OPERATOR_FINISHED;
3684 }
3685 
3687 {
3688  /* identifiers */
3689  ot->name = "Add New Mask Layer";
3690  ot->idname = "GPENCIL_OT_layer_mask_add";
3691  ot->description = "Add new layer as masking";
3692 
3694 
3695  /* callbacks */
3698 
3699  /* properties */
3700  RNA_def_string(ot->srna, "name", NULL, 128, "Layer", "Name of the layer");
3701 }
3702 
3704 {
3706  if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
3707  return OPERATOR_CANCELLED;
3708  }
3709 
3710  bGPdata *gpd = (bGPdata *)ob->data;
3712  if (gpl == NULL) {
3713  return OPERATOR_CANCELLED;
3714  }
3715  if (gpl->act_mask > 0) {
3716  bGPDlayer_Mask *mask = BLI_findlink(&gpl->mask_layers, gpl->act_mask - 1);
3717  if (mask != NULL) {
3719  if ((gpl->mask_layers.first != NULL) && (gpl->act_mask == 0)) {
3720  gpl->act_mask = 1;
3721  }
3722  }
3723  }
3724 
3725  /* Reorder masking. */
3726  BKE_gpencil_layer_mask_sort(gpd, gpl);
3727 
3728  /* notifiers */
3731 
3732  return OPERATOR_FINISHED;
3733 }
3734 
3736 {
3737  /* identifiers */
3738  ot->name = "Remove Mask Layer";
3739  ot->idname = "GPENCIL_OT_layer_mask_remove";
3740  ot->description = "Remove Layer Mask";
3741 
3743 
3744  /* callbacks */
3747 }
@ ADT_MERGECOPY_KEEP_DST
Definition: BKE_anim_data.h:92
void BKE_animdata_merge_copy(struct Main *bmain, struct ID *dst_id, struct ID *src_id, eAnimData_MergeCopy_Modes action_mode, bool fix_drivers)
Definition: anim_data.c:436
struct AnimData * BKE_animdata_copy(struct Main *bmain, struct AnimData *adt, const int flag)
Definition: anim_data.c:318
void BKE_fcurves_main_cb(struct Main *bmain, ID_FCurve_Edit_Callback func, void *user_data)
Definition: anim_data.c:1288
char * BKE_animsys_fix_rna_path_rename(struct ID *owner_id, char *old_path, const char *prefix, const char *oldName, const char *newName, int oldSubscript, int newSubscript, bool verify_paths)
Definition: anim_data.c:969
bool BKE_brush_delete(struct Main *bmain, struct Brush *brush)
Definition: brush.c:572
void BKE_brush_gpencil_paint_presets(struct Main *bmain, struct ToolSettings *ts, const bool reset)
Definition: brush.c:1308
void BKE_brush_gpencil_sculpt_presets(struct Main *bmain, struct ToolSettings *ts, const bool reset)
Definition: brush.c:1459
void BKE_brush_gpencil_weight_presets(struct Main *bmain, struct ToolSettings *ts, const bool reset)
Definition: brush.c:1534
void BKE_brush_gpencil_vertex_presets(struct Main *bmain, struct ToolSettings *ts, const bool reset)
Definition: brush.c:1412
void BKE_gpencil_brush_preset_set(struct Main *bmain, struct Brush *brush, const short type)
Definition: brush.c:669
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
#define CTX_DATA_BEGIN(C, Type, instance, member)
Definition: BKE_context.h:252
eContextObjectMode
Definition: BKE_context.h:114
@ CTX_MODE_WEIGHT_GPENCIL
Definition: BKE_context.h:132
@ CTX_MODE_VERTEX_GPENCIL
Definition: BKE_context.h:133
@ CTX_MODE_SCULPT_GPENCIL
Definition: BKE_context.h:131
@ CTX_MODE_PAINT_GPENCIL
Definition: BKE_context.h:129
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1044
struct bGPdata * CTX_data_gpencil_data(const bContext *C)
Definition: context.c:1371
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1424
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1279
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1018
struct ToolSettings * CTX_data_tool_settings(const bContext *C)
Definition: context.c:1208
#define CTX_DATA_END
Definition: BKE_context.h:260
enum eContextObjectMode CTX_data_mode_enum(const bContext *C)
Definition: context.c:1174
support for deformation groups and hooks.
struct MDeformWeight * BKE_defvert_ensure_index(struct MDeformVert *dv, const int defgroup)
Definition: deform.c:688
struct MDeformWeight * BKE_defvert_find_index(const struct MDeformVert *dv, const int defgroup)
float BKE_defvert_find_weight(const struct MDeformVert *dvert, const int defgroup)
Definition: deform.c:632
void BKE_object_defgroup_unique_name(struct bDeformGroup *dg, struct Object *ob)
Definition: deform.c:620
void BKE_defvert_remove_group(struct MDeformVert *dvert, struct MDeformWeight *dw)
Definition: deform.c:754
void BKE_defvert_add_index_notest(struct MDeformVert *dv, int defgroup, const float weight)
Definition: deform.c:726
#define DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar)
#define DRIVER_TARGETS_LOOPER_END
void BKE_gpencil_stroke_select_index_set(struct bGPdata *gpd, struct bGPDstroke *gps)
Definition: gpencil.c:1203
struct bGPDframe * BKE_gpencil_frame_addnew(struct bGPDlayer *gpl, int cframe)
Definition: gpencil.c:539
void BKE_gpencil_layer_active_set(struct bGPdata *gpd, struct bGPDlayer *active)
Definition: gpencil.c:1698
struct bGPDlayer_Mask * BKE_gpencil_layer_mask_named_get(struct bGPDlayer *gpl, const char *name)
Definition: gpencil.c:1510
void BKE_gpencil_layer_mask_sort(struct bGPdata *gpd, struct bGPDlayer *gpl)
Definition: gpencil.c:1588
struct bGPDlayer * BKE_gpencil_layer_active_get(struct bGPdata *gpd)
Definition: gpencil.c:1650
struct bGPDframe * BKE_gpencil_frame_addcopy(struct bGPDlayer *gpl, int cframe)
Definition: gpencil.c:598
void BKE_gpencil_free_stroke_weights(struct bGPDstroke *gps)
Definition: gpencil.c:370
int BKE_gpencil_object_material_ensure(struct Main *bmain, struct Object *ob, struct Material *material)
Definition: gpencil.c:1851
void BKE_gpencil_layer_mask_sort_all(struct bGPdata *gpd)
Definition: gpencil.c:1607
struct bGPDlayer * BKE_gpencil_layer_duplicate(const struct bGPDlayer *gpl_src, const bool dup_frames, const bool dup_strokes)
void BKE_gpencil_stroke_select_index_reset(struct bGPDstroke *gps)
Definition: gpencil.c:1210
void BKE_gpencil_layer_mask_remove(struct bGPDlayer *gpl, struct bGPDlayer_Mask *mask)
Definition: gpencil.c:1540
struct bGPDlayer_Mask * BKE_gpencil_layer_mask_add(struct bGPDlayer *gpl, const char *name)
Definition: gpencil.c:1524
bool BKE_gpencil_layer_is_editable(const struct bGPDlayer *gpl)
bool BKE_gpencil_layer_frame_delete(struct bGPDlayer *gpl, struct bGPDframe *gpf)
Definition: gpencil.c:1467
int BKE_gpencil_object_material_index_get(struct Object *ob, struct Material *ma)
Definition: gpencil.c:2437
struct bGPDlayer * BKE_gpencil_layer_named_get(struct bGPdata *gpd, const char *name)
Definition: gpencil.c:1496
struct bGPDframe * BKE_gpencil_layer_frame_get(struct bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew)
Definition: gpencil.c:1307
struct bGPdata * BKE_gpencil_data_addnew(struct Main *bmain, const char name[])
Definition: gpencil.c:742
void BKE_gpencil_layer_transform_matrix_get(const struct Depsgraph *depsgraph, struct Object *obact, struct bGPDlayer *gpl, float diff_mat[4][4])
struct bGPDstroke * BKE_gpencil_stroke_duplicate(struct bGPDstroke *gps_src, const bool dup_points, const bool dup_curve)
Definition: gpencil.c:957
void BKE_gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl)
Definition: gpencil.c:1760
struct bGPDlayer * BKE_gpencil_layer_addnew(struct bGPdata *gpd, const char *name, bool setactive)
Definition: gpencil.c:659
@ GP_GETFRAME_ADD_NEW
Definition: BKE_gpencil.h:190
@ GP_GETFRAME_ADD_COPY
Definition: BKE_gpencil.h:192
struct GpencilModifierData * BKE_gpencil_modifiers_findby_type(struct Object *ob, GpencilModifierType type)
const GpencilModifierTypeInfo * BKE_gpencil_modifier_get_info(GpencilModifierType type)
void id_us_min(struct ID *id)
Definition: lib_id.c:297
struct ID * BKE_libblock_find_name(struct Main *bmain, const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: lib_id.c:1333
General operations, lookup, etc. for materials.
struct MaterialGPencilStyle * BKE_gpencil_material_settings(struct Object *ob, short act)
Definition: material.c:713
struct Material * BKE_object_material_get(struct Object *ob, short act)
Definition: material.c:697
struct Material * BKE_gpencil_material(struct Object *ob, short act)
Definition: material.c:703
short * BKE_object_material_len_p(struct Object *ob)
Definition: material.c:356
General operations, lookup, etc. for blender objects.
void BKE_paint_brush_set(struct Paint *paint, struct Brush *br)
Definition: paint.c:609
void BKE_paint_toolslots_brush_validate(struct Main *bmain, struct Paint *paint)
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
void BKE_reportf(ReportList *reports, ReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
struct Object * BKE_scene_object_find_by_name(const struct Scene *scene, const char *name)
#define BLI_assert(a)
Definition: BLI_assert.h:58
BLI_INLINE void * BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.h:146
BLI_INLINE void * BLI_ghashIterator_getValue(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.h:150
GHash * BLI_ghash_str_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
#define GHASH_ITER(gh_iter_, ghash_)
Definition: BLI_ghash.h:169
GHash * BLI_ghash_int_new_ex(const char *info, const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition: BLI_ghash.c:756
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:1008
void * BLI_ghash_lookup(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:803
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:87
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:281
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:188
#define LISTBASE_FOREACH_BACKWARD(type, var, list)
Definition: BLI_listbase.h:184
struct LinkData * BLI_genericNodeN(void *data)
Definition: listbase.c:923
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:352
void void void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:547
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:133
void void void bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step) ATTR_NONNULL()
Definition: listbase.c:475
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:395
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE float interpf(float a, float b, float t)
float line_point_factor_v3(const float p[3], const float l1[3], const float l2[3])
Definition: math_geom.c:3449
void mul_m3_v3(const float M[3][3], float r[3])
Definition: math_matrix.c:930
void copy_m3_m4(float m1[3][3], const float m2[4][4])
Definition: math_matrix.c:105
void invert_m4_m4_safe_ortho(float Ainv[4][4], const float A[4][4])
Definition: math_matrix.c:3287
void invert_m3_m3_safe_ortho(float Ainv[3][3], const float A[3][3])
Definition: math_matrix.c:3298
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:742
void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3])
Definition: math_matrix.c:901
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE bool equals_v4v4(const float a[4], const float b[4]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE bool equals_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
MINLINE bool equals_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC
Definition: string.c:70
bool BLI_uniquename(struct ListBase *list, void *vlink, const char *defname, char delim, int name_offset, size_t len)
Definition: string_utils.c:381
#define POINTER_FROM_INT(i)
#define UNUSED(x)
#define SET_FLAG_FROM_TEST(value, test, flag)
#define ELEM(...)
#define STREQ(a, b)
#define DATA_(msgid)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:51
void DEG_id_tag_update(struct ID *id, int flag)
void DEG_relations_tag_update(struct Main *bmain)
@ ID_RECALC_TRANSFORM
Definition: DNA_ID.h:599
@ ID_RECALC_COPY_ON_WRITE
Definition: DNA_ID.h:654
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:611
#define ID_IS_LINKED(_id)
Definition: DNA_ID.h:426
#define MAX_ID_NAME
Definition: DNA_ID.h:269
@ ID_MA
Definition: DNA_ID_enums.h:63
@ GP_BRUSH_MATERIAL_PINNED
@ GP_BRUSH_PRESET_DRAW_WEIGHT
@ GP_BRUSH_PRESET_VERTEX_DRAW
@ GP_BRUSH_PRESET_VERTEX_REPLACE
@ GP_BRUSH_PRESET_SMOOTH_STROKE
@ GP_BRUSH_PRESET_AIRBRUSH
@ GP_BRUSH_PRESET_TINT
@ GP_BRUSH_PRESET_CLONE_STROKE
@ GP_BRUSH_PRESET_UNKNOWN
@ eGpencilModifierType_Lattice
@ GP_STROKE_NOFILL
@ GP_STROKE_SELECT
#define GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)
@ GP_LAYER_LOCKED
@ GP_LAYER_ACTIVE
@ GP_LAYER_HIDE
@ GP_FRAME_SELECT
@ GP_DATA_ANNOTATIONS
@ GP_DATA_STROKE_EDITMODE
#define GPENCIL_ANY_MODE(gpd)
@ GP_SPOINT_SELECT
@ GP_MATERIAL_LOCKED
@ GP_MATERIAL_HIDE
@ OB_MODE_EDIT_GPENCIL
@ OB_MODE_WEIGHT_GPENCIL
@ OB_MODE_SCULPT_GPENCIL
@ OB_MODE_PAINT_GPENCIL
Object is a sort of wrapper for general info.
#define DG_LOCK_WEIGHT
@ OB_GPENCIL
#define CFRA
@ OPERATOR_CANCELLED
@ OPERATOR_INTERFACE
@ OPERATOR_FINISHED
struct GpencilModifierData * ED_object_gpencil_modifier_add(struct ReportList *reports, struct Main *bmain, struct Scene *scene, struct Object *ob, const char *name, int type)
void ED_object_base_free_and_unlink(struct Main *bmain, struct Scene *scene, struct Object *ob)
Definition: object_add.c:1958
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
Group RGB to Bright Vector Camera CLAMP
@ PROP_SKIP_SAVE
Definition: RNA_types.h:204
@ PROP_HIDDEN
Definition: RNA_types.h:202
#define C
Definition: RandGen.cpp:39
struct uiLayout * UI_popup_menu_layout(uiPopupMenu *pup)
void uiItemsEnumO(uiLayout *layout, const char *opname, const char *propname)
void UI_popup_menu_end(struct bContext *C, struct uiPopupMenu *pup)
uiPopupMenu * UI_popup_menu_begin(struct bContext *C, const char *title, int icon) ATTR_NONNULL()
#define NC_BRUSH
Definition: WM_types.h:286
#define ND_OB_ACTIVE
Definition: WM_types.h:340
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
#define ND_DATA
Definition: WM_types.h:408
#define ND_SPACE_PROPERTIES
Definition: WM_types.h:424
#define NC_SCENE
Definition: WM_types.h:279
#define ND_LAYER_CONTENT
Definition: WM_types.h:354
#define NA_EDITED
Definition: WM_types.h:462
#define NC_GPENCIL
Definition: WM_types.h:300
#define NA_SELECTED
Definition: WM_types.h:467
ATTR_WARN_UNUSED_RESULT const BMVert * v
Scene scene
const Depsgraph * depsgraph
void * user_data
int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
static void gpencil_joined_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data)
void GPENCIL_OT_layer_change(wmOperatorType *ot)
void GPENCIL_OT_stroke_arrange(wmOperatorType *ot)
static bool gpencil_frame_is_equal(bGPDframe *gpf_a, bGPDframe *gpf_b)
Definition: gpencil_data.c:885
static int gpencil_layer_mask_remove_exec(bContext *C, wmOperator *UNUSED(op))
static int gpencil_layer_add_exec(bContext *C, wmOperator *op)
Definition: gpencil_data.c:211
void GPENCIL_OT_vertex_group_smooth(wmOperatorType *ot)
static int gpencil_material_select_exec(bContext *C, wmOperator *op)
static int gpencil_material_set_exec(bContext *C, wmOperator *op)
static bool gpencil_active_layer_annotation_poll(bContext *C)
Definition: gpencil_data.c:351
void GPENCIL_OT_layer_remove(wmOperatorType *ot)
Definition: gpencil_data.c:337
struct tJoinGPencil_AdtFixData tJoinGPencil_AdtFixData
void GPENCIL_OT_vertex_group_invert(wmOperatorType *ot)
static int gpencil_isolate_layer_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_layer_annotation_move(wmOperatorType *ot)
Definition: gpencil_data.c:429
static int gpencil_frame_clean_loose_exec(bContext *C, wmOperator *op)
Definition: gpencil_data.c:801
static int gpencil_hide_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_material_reveal(wmOperatorType *ot)
void GPENCIL_OT_layer_annotation_remove(wmOperatorType *ot)
Definition: gpencil_data.c:359
void GPENCIL_OT_frame_duplicate(wmOperatorType *ot)
Definition: gpencil_data.c:692
void GPENCIL_OT_layer_isolate(wmOperatorType *ot)
void GPENCIL_OT_lock_all(wmOperatorType *ot)
static int gpencil_frame_clean_duplicate_exec(bContext *C, wmOperator *op)
Definition: gpencil_data.c:968
static int gpencil_brush_reset_all_exec(bContext *C, wmOperator *UNUSED(op))
static int gpencil_layer_change_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
static int gpencil_material_hide_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_layer_mask_remove(wmOperatorType *ot)
#define SELECTED
void GPENCIL_OT_stroke_change_color(wmOperatorType *ot)
static int gpencil_lock_layer_exec(bContext *C, wmOperator *UNUSED(op))
void GPENCIL_OT_material_set(wmOperatorType *ot)
static bool gpencil_data_unlink_poll(bContext *C)
Definition: gpencil_data.c:156
static int gpencil_stroke_arrange_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_vertex_group_normalize_all(wmOperatorType *ot)
static bool gpencil_data_add_poll(bContext *C)
Definition: gpencil_data.c:94
@ GP_FRAME_DUP_ALL
Definition: gpencil_data.c:659
@ GP_FRAME_DUP_ACTIVE
Definition: gpencil_data.c:658
static int gpencil_unlock_all_exec(bContext *C, wmOperator *UNUSED(op))
@ GP_LAYER_MOVE_DOWN
Definition: gpencil_data.c:376
@ GP_LAYER_MOVE_UP
Definition: gpencil_data.c:375
static bool gpencil_add_annotation_poll(bContext *C)
Definition: gpencil_data.c:274
void GPENCIL_OT_material_lock_unused(wmOperatorType *ot)
void GPENCIL_OT_material_select(wmOperatorType *ot)
static int gpencil_brush_reset_exec(bContext *C, wmOperator *UNUSED(op))
@ GP_STROKE_MOVE_TOP
@ GP_STROKE_MOVE_BOTTOM
@ GP_STROKE_MOVE_UP
@ GP_STROKE_MOVE_DOWN
void GPENCIL_OT_frame_clean_fill(wmOperatorType *ot)
Definition: gpencil_data.c:777
static int gpencil_vertex_group_deselect_exec(bContext *C, wmOperator *UNUSED(op))
static int gpencil_layer_duplicate_object_exec(bContext *C, wmOperator *op)
Definition: gpencil_data.c:550
void GPENCIL_OT_brush_reset_all(wmOperatorType *ot)
void GPENCIL_OT_annotation_add(wmOperatorType *ot)
Definition: gpencil_data.c:140
static int gpencil_material_unlock_all_exec(bContext *C, wmOperator *UNUSED(op))
static bool gpencil_active_material_poll(bContext *C)
static int gpencil_layer_move_exec(bContext *C, wmOperator *op)
Definition: gpencil_data.c:379
static int gpencil_merge_layer_exec(bContext *C, wmOperator *op)
@ GP_LAYER_COPY_OBJECT_ACT_FRAME
Definition: gpencil_data.c:522
@ GP_LAYER_COPY_OBJECT_ALL_FRAME
Definition: gpencil_data.c:521
@ GP_LAYER_DUPLICATE_ALL
Definition: gpencil_data.c:453
@ GP_LAYER_DUPLICATE_EMPTY
Definition: gpencil_data.c:454
static void gpencil_reveal_select_frame(bContext *C, bGPDframe *frame, bool select)
void GPENCIL_OT_vertex_group_normalize(wmOperatorType *ot)
void GPENCIL_OT_layer_add(wmOperatorType *ot)
Definition: gpencil_data.c:260
static int gpencil_data_unlink_exec(bContext *C, wmOperator *op)
Definition: gpencil_data.c:172
static int gpencil_material_reveal_exec(bContext *C, wmOperator *UNUSED(op))
static int gpencil_vertex_group_normalize_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_layer_mask_add(wmOperatorType *ot)
void GPENCIL_OT_reveal(wmOperatorType *ot)
void GPENCIL_OT_layer_duplicate(wmOperatorType *ot)
Definition: gpencil_data.c:496
void GPENCIL_OT_vertex_group_assign(wmOperatorType *ot)
static int gpencil_frame_clean_fill_exec(bContext *C, wmOperator *op)
Definition: gpencil_data.c:721
static int gpencil_frame_duplicate_exec(bContext *C, wmOperator *op)
Definition: gpencil_data.c:662
void GPENCIL_OT_layer_merge(wmOperatorType *ot)
static bool gpencil_vertex_group_weight_poll(bContext *C)
static int gpencil_vertex_group_smooth_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_unlock_all(wmOperatorType *ot)
void GPENCIL_OT_material_lock_all(wmOperatorType *ot)
static int gpencil_stroke_change_color_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_data_unlink(wmOperatorType *ot)
Definition: gpencil_data.c:192
static int gpencil_material_lock_all_exec(bContext *C, wmOperator *UNUSED(op))
static int gpencil_layer_copy_exec(bContext *C, wmOperator *op)
Definition: gpencil_data.c:457
void GPENCIL_OT_brush_reset(wmOperatorType *ot)
static int gpencil_layer_remove_exec(bContext *C, wmOperator *op)
Definition: gpencil_data.c:294
void GPENCIL_OT_set_active_material(wmOperatorType *ot)
static int gpencil_layer_active_exec(bContext *C, wmOperator *op)
static int gpencil_set_active_material_exec(bContext *C, wmOperator *op)
static int gpencil_lock_all_exec(bContext *C, wmOperator *UNUSED(op))
static int gpencil_material_lock_unsused_exec(bContext *C, wmOperator *UNUSED(op))
static int gpencil_layer_mask_add_exec(bContext *C, wmOperator *op)
static int gpencil_vertex_group_normalize_all_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_frame_clean_loose(wmOperatorType *ot)
Definition: gpencil_data.c:859
void GPENCIL_OT_hide(wmOperatorType *ot)
void GPENCIL_OT_material_isolate(wmOperatorType *ot)
static int gpencil_vertex_group_remove_from_exec(bContext *C, wmOperator *UNUSED(op))
void GPENCIL_OT_vertex_group_select(wmOperatorType *ot)
static int gpencil_vertex_group_assign_exec(bContext *C, wmOperator *UNUSED(op))
static bool gpencil_layer_duplicate_object_poll(bContext *C)
Definition: gpencil_data.c:525
static int gpencil_data_add_exec(bContext *C, wmOperator *op)
Definition: gpencil_data.c:102
void GPENCIL_OT_vertex_group_deselect(wmOperatorType *ot)
void GPENCIL_OT_material_hide(wmOperatorType *ot)
static int gpencil_vertex_group_select_exec(bContext *C, wmOperator *UNUSED(op))
void GPENCIL_OT_layer_duplicate_object(wmOperatorType *ot)
Definition: gpencil_data.c:629
static Brush * gpencil_brush_get_first_by_mode(Main *bmain, Paint *UNUSED(paint), const enum eContextObjectMode mode, char tool)
void GPENCIL_OT_layer_annotation_add(wmOperatorType *ot)
Definition: gpencil_data.c:279
void GPENCIL_OT_layer_move(wmOperatorType *ot)
Definition: gpencil_data.c:406
static int gpencil_vertex_group_invert_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_material_unlock_all(wmOperatorType *ot)
static int gpencil_layer_change_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_lock_layer(wmOperatorType *ot)
@ GP_FRAME_CLEAN_FILL_ALL
Definition: gpencil_data.c:718
@ GP_FRAME_CLEAN_FILL_ACTIVE
Definition: gpencil_data.c:717
bool ED_gpencil_add_lattice_modifier(const bContext *C, ReportList *reports, Object *ob, Object *ob_latt)
static bool gpencil_reveal_poll(bContext *C)
static void gpencil_brush_delete_mode_brushes(Main *bmain, Paint *paint, const enum eContextObjectMode mode)
static int gpencil_material_isolate_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_vertex_group_remove_from(wmOperatorType *ot)
void GPENCIL_OT_frame_clean_duplicate(wmOperatorType *ot)
static bool gpencil_vertex_group_poll(bContext *C)
void GPENCIL_OT_layer_active(wmOperatorType *ot)
static int gpencil_reveal_exec(bContext *C, wmOperator *op)
const struct EnumPropertyItem * ED_gpencil_material_enum_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free)
#define GP_EDITABLE_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
const struct EnumPropertyItem * ED_gpencil_layers_with_new_enum_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free)
bool gpencil_active_layer_poll(struct bContext *C)
#define GP_EDITABLE_STROKES_END(gpstroke_iter)
bool gpencil_add_poll(struct bContext *C)
void ED_gpencil_vgroup_deselect(bContext *C, Object *ob)
bool ED_gpencil_stroke_material_editable(Object *ob, const bGPDlayer *gpl, const bGPDstroke *gps)
void ED_gpencil_vgroup_select(bContext *C, Object *ob)
void ED_gpencil_vgroup_remove(bContext *C, Object *ob)
bGPdata * ED_annotation_data_get_active(const bContext *C)
bool ED_gpencil_stroke_can_use(const bContext *C, const bGPDstroke *gps)
bGPdata * ED_gpencil_data_get_active(const bContext *C)
bGPdata ** ED_annotation_data_get_pointers(const bContext *C, PointerRNA *r_ptr)
void ED_gpencil_vgroup_assign(bContext *C, Object *ob, float weight)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:42
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
Definition: rna_access.c:6514
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6308
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6355
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6402
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:3825
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3481
PropertyRNA * RNA_def_string(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, int maxlen, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3675
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1512
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, int default_value, int hardmin, int hardmax, const char *ui_name, const char *ui_description, int softmin, int softmax)
Definition: rna_define.c:3585
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
Definition: rna_define.c:3819
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3771
const EnumPropertyItem DummyRNA_DEFAULT_items[]
Definition: rna_rna.c:45
char gpencil_weight_tool
char gpencil_vertex_tool
struct BrushGpencilSettings * gpencil_settings
char gpencil_sculpt_tool
char gpencil_tool
ListBase variables
char * rna_path
ChannelDriver * driver
void(* bakeModifier)(struct Main *bmain, struct Depsgraph *depsgraph, struct GpencilModifierData *md, struct Object *ob)
Definition: DNA_ID.h:273
void * next
Definition: DNA_ID.h:274
void * first
Definition: DNA_listBase.h:47
struct MDeformWeight * dw
unsigned int def_nr
Definition: BKE_main.h:116
ListBase brushes
Definition: BKE_main.h:171
struct MaterialGPencilStyle * gp_style
ListBase defbase
float loc[3]
unsigned short actdef
float obmat[4][4]
struct AnimData * adt
void * data
struct Brush * brush
GpWeightPaint * gp_weightpaint
GpPaint * gp_paint
GpSculptPaint * gp_sculptpaint
GpVertexPaint * gp_vertexpaint
ListBase object_bases
struct bGPDframe * next
ListBase strokes
char info[128]
struct bGPDlayer * next
bGPDframe * actframe
ListBase frames
ListBase mask_layers
struct bGPDlayer * prev
float vert_color[4]
struct bGPDstroke * prev
bGPDspoint * points
float uv_translation[2]
float aspect_ratio[2]
float vert_color_fill[4]
struct bGPDstroke * next
ListBase layers
struct AnimData * adt
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
PropertyRNA * prop
Definition: WM_types.h:814
struct ReportList * reports
struct wmOperatorType * type
struct PointerRNA * ptr
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: util_avxb.h:167
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
void WM_main_add_notifier(unsigned int type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition: wm_files.c:3156