Blender V5.0
grease_pencil_material.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
10
11#include "BKE_attribute.hh"
12#include "BKE_context.hh"
13#include "BKE_curves.hh"
14#include "BKE_grease_pencil.hh"
15#include "BKE_material.hh"
16
17#include "BLI_vector.hh"
18
19#include "DEG_depsgraph.hh"
20
21#include "ED_grease_pencil.hh"
22
23#include "RNA_access.hh"
24#include "RNA_define.hh"
25
26#include "WM_api.hh"
27
29
30/* -------------------------------------------------------------------- */
33
35{
37 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
38
39 bool changed = false;
40 for (const int i : IndexRange(object->totcol)) {
41 if (Material *ma = BKE_gpencil_material(object, i + 1)) {
42 MaterialGPencilStyle &gp_style = *ma->gp_style;
43 gp_style.flag &= ~GP_MATERIAL_HIDE;
45 changed = true;
46 }
47 }
48
49 if (changed) {
51 WM_event_add_notifier(C, NC_GEOM | ND_DATA | NA_EDITED, &grease_pencil);
52 }
53
54 return OPERATOR_FINISHED;
55}
56
58{
59 /* Identifiers. */
60 ot->name = "Show All Materials";
61 ot->idname = "GREASE_PENCIL_OT_material_reveal";
62 ot->description = "Unhide all hidden Grease Pencil materials";
63
64 /* Callbacks. */
67
69}
70
72
73/* -------------------------------------------------------------------- */
76
78{
80 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
81 const bool invert = RNA_boolean_get(op->ptr, "invert");
82
83 bool changed = false;
84 const int material_index = object->actcol - 1;
85
86 for (const int i : IndexRange(object->totcol)) {
87 if (invert && i == material_index) {
88 continue;
89 }
90 if (!invert && i != material_index) {
91 continue;
92 }
93 if (Material *ma = BKE_object_material_get(object, i + 1)) {
94 MaterialGPencilStyle &gp_style = *ma->gp_style;
95 gp_style.flag |= GP_MATERIAL_HIDE;
97 changed = true;
98 }
99 }
100
101 if (changed) {
102 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
103 WM_event_add_notifier(C, NC_GEOM | ND_DATA | NA_EDITED, &grease_pencil);
104 }
105
106 return OPERATOR_FINISHED;
107}
108
110{
111 /* Identifiers. */
112 ot->name = "Hide Materials";
113 ot->idname = "GREASE_PENCIL_OT_material_hide";
114 ot->description = "Hide active/inactive Grease Pencil material(s)";
115
116 /* Callbacks. */
119
121
122 /* props */
124 ot->srna, "invert", false, "Invert", "Hide inactive materials instead of the active one");
125}
126
128
129/* -------------------------------------------------------------------- */
132
134{
136 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
137
138 bool changed = false;
139 for (const int i : IndexRange(object->totcol)) {
140 if (Material *ma = BKE_object_material_get(object, i + 1)) {
141 MaterialGPencilStyle &gp_style = *ma->gp_style;
142 gp_style.flag |= GP_MATERIAL_LOCKED;
144 changed = true;
145 }
146 }
147
148 if (changed) {
149 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
150 WM_event_add_notifier(C, NC_GEOM | ND_DATA | NA_EDITED, &grease_pencil);
151 }
152
153 return OPERATOR_FINISHED;
154}
155
157{
158 /* Identifiers. */
159 ot->name = "Lock All Materials";
160 ot->idname = "GREASE_PENCIL_OT_material_lock_all";
161 ot->description =
162 "Lock all Grease Pencil materials to prevent them from being accidentally modified";
163
164 /* Callbacks. */
167
169}
170
172
173/* -------------------------------------------------------------------- */
176
178{
180 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
181
182 bool changed = false;
183 for (const int i : IndexRange(object->totcol)) {
184 if (Material *ma = BKE_object_material_get(object, i + 1)) {
185 MaterialGPencilStyle &gp_style = *ma->gp_style;
186 gp_style.flag &= ~GP_MATERIAL_LOCKED;
188 changed = true;
189 }
190 }
191
192 if (changed) {
193 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
194 WM_event_add_notifier(C, NC_GEOM | ND_DATA | NA_EDITED, &grease_pencil);
195 }
196
197 return OPERATOR_FINISHED;
198}
199
201{
202 /* Identifiers. */
203 ot->name = "Unlock All Materials";
204 ot->idname = "GREASE_PENCIL_OT_material_unlock_all";
205 ot->description = "Unlock all Grease Pencil materials so that they can be edited";
206
207 /* Callbacks. */
210
212}
213
215
216/* -------------------------------------------------------------------- */
219
221{
223 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
224
225 bool changed = false;
226 for (const int material_index : IndexRange(object->totcol)) {
227 if (!BKE_object_material_slot_used(object, material_index + 1)) {
228 if (Material *ma = BKE_object_material_get(object, material_index + 1)) {
229 MaterialGPencilStyle &gp_style = *ma->gp_style;
232 changed = true;
233 }
234 }
235 }
236 if (changed) {
237 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
238 WM_event_add_notifier(C, NC_GEOM | ND_DATA | NA_EDITED, &grease_pencil);
239 }
240
241 return OPERATOR_FINISHED;
242}
243
245{
246 /* Identifiers. */
247 ot->name = "Lock Unused Materials";
248 ot->idname = "GREASE_PENCIL_OT_material_lock_unused";
249 ot->description = "Lock and hide any material not used";
250
251 /* Callbacks. */
254
256}
257
259
260/* -------------------------------------------------------------------- */
263
265 wmOperator * /*op*/)
266{
267 using namespace blender;
268 using namespace blender::bke;
269
270 const Scene *scene = CTX_data_scene(C);
272 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
273
274 bool changed = false;
275 const Vector<MutableDrawingInfo> drawings = retrieve_editable_drawings(*scene, grease_pencil);
276
277 Set<int> materials_used;
278
279 for (const MutableDrawingInfo &info : drawings) {
280 IndexMaskMemory memory;
282 *object, info.drawing, info.layer_index, memory);
283 if (strokes.is_empty()) {
284 return OPERATOR_CANCELLED;
285 }
286
287 AttributeAccessor attributes = info.drawing.strokes().attributes();
288 const VArray<int> material_indices = *attributes.lookup_or_default<int>(
289 "material_index", AttrDomain::Curve, 0);
290
291 if (const std::optional<int> single = material_indices.get_if_single()) {
292 materials_used.add(*single);
293 }
294 else {
295 strokes.foreach_index([&](const int i) { materials_used.add(material_indices[i]); });
296 }
297 };
298
299 /* The material lock must be done outside of the drawing loop to prevent
300 * 'retrieve_editable_and_selected_strokes' from returning an incorrect IndexMask.
301 */
302 for (const int i : IndexRange(object->totcol)) {
303 if (!materials_used.contains(i)) {
304 if (Material *ma = BKE_object_material_get(object, i + 1)) {
305 MaterialGPencilStyle &gp_style = *ma->gp_style;
306 gp_style.flag |= GP_MATERIAL_LOCKED;
308 changed = true;
309 }
310 }
311 }
312
313 if (changed) {
314 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
315 WM_event_add_notifier(C, NC_GEOM | ND_DATA | NA_EDITED, &grease_pencil);
316 }
317
318 return OPERATOR_FINISHED;
319}
320
322{
323 /* Identifiers. */
324 ot->name = "Lock Unselected Materials";
325 ot->idname = "GREASE_PENCIL_OT_material_lock_unselected";
326 ot->description = "Lock any material not used in any selected stroke";
327
328 /* Callbacks. */
331
333}
334
336
337/* -------------------------------------------------------------------- */
340
342{
343 using namespace blender;
344 using namespace blender::bke;
345
346 Main *bmain = CTX_data_main(C);
347 const bool only_active = RNA_boolean_get(op->ptr, "only_active");
349 Material *ma_active = BKE_object_material_get(ob_src, ob_src->actcol);
350 if (ma_active == nullptr) {
351 return OPERATOR_CANCELLED;
352 }
353
354 CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
355 if ((ob == ob_src) || (ob->type != OB_GREASE_PENCIL)) {
356 continue;
357 }
358 /* Duplicate materials. */
359 for (const int i : IndexRange(ob_src->totcol)) {
360 Material *ma_src = BKE_object_material_get(ob_src, i + 1);
361 if (only_active && ma_src != ma_active) {
362 continue;
363 }
364
365 if (ma_src == nullptr) {
366 continue;
367 }
368
369 BKE_object_material_ensure(bmain, ob, ma_src);
370 }
371
373 }
375
377
378 return OPERATOR_FINISHED;
379}
380
382{
383 PropertyRNA *prop;
384
385 /* Identifiers. */
386 ot->name = "Copy Materials to Selected Object";
387 ot->idname = "GREASE_PENCIL_OT_material_copy_to_object";
388 ot->description = "Append Materials of the active Grease Pencil to other object";
389
390 /* Callbacks. */
393
395
396 prop = RNA_def_boolean(ot->srna,
397 "only_active",
398 true,
399 "Only Active",
400 "Append only active material, uncheck to append all materials");
401
403}
404
406{
408 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob->data);
409 Material *active_ma = BKE_gpencil_material(ob, ob->actcol);
411 MaterialGPencilStyle *gp_style;
412
413 int flags = GP_MATERIAL_LOCKED;
414 bool isolate = false;
415
416 if (RNA_boolean_get(op->ptr, "affect_visibility")) {
417 flags |= GP_MATERIAL_HIDE;
418 }
419
420 if (active_material == nullptr) {
421 return OPERATOR_CANCELLED;
422 }
423
424 /* Test whether to isolate or clear all flags */
425 Material *ma = nullptr;
426 short *totcol = BKE_object_material_len_p(ob);
427 for (short i = 0; i < *totcol; i++) {
428 ma = BKE_gpencil_material(ob, i + 1);
429 /* Skip if this is the active one */
430 if (ELEM(ma, nullptr, active_ma)) {
431 continue;
432 }
433
434 /* If the flags aren't set, that means that the color is
435 * not alone, so we have some colors to isolate still
436 */
437 gp_style = ma->gp_style;
438 if ((gp_style->flag & flags) == 0) {
439 isolate = true;
440 break;
441 }
442 }
443
444 /* Set/Clear flags as appropriate */
445 if (isolate) {
446 /* Set flags on all "other" colors */
447 for (short i = 0; i < *totcol; i++) {
448 ma = BKE_gpencil_material(ob, i + 1);
449 if (ma == nullptr) {
450 continue;
451 }
452 gp_style = ma->gp_style;
453 if (gp_style == active_material) {
454 continue;
455 }
456 gp_style->flag |= flags;
458 }
459 }
460 else {
461 /* Clear flags - Restore everything else */
462 for (short i = 0; i < *totcol; i++) {
463 ma = BKE_gpencil_material(ob, i + 1);
464 if (ma == nullptr) {
465 continue;
466 }
467 gp_style = ma->gp_style;
468 gp_style->flag &= ~flags;
470 }
471 }
472
473 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
475
476 return OPERATOR_FINISHED;
477}
478
480{
481 /* identifiers */
482 ot->name = "Isolate Material";
483 ot->idname = "GREASE_PENCIL_OT_material_isolate";
484 ot->description =
485 "Toggle whether the active material is the only one that is editable and/or visible";
486
487 /* callbacks */
490
491 /* flags */
493
494 /* properties */
495 RNA_def_boolean(ot->srna,
496 "affect_visibility",
497 false,
498 "Affect Visibility",
499 "In addition to toggling "
500 "the editability, also affect the visibility");
501}
502
504
505} // namespace blender::ed::greasepencil
506
#define CTX_DATA_BEGIN(C, Type, instance, member)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
#define CTX_DATA_END
Low-level operations for curves.
Low-level operations for grease pencil.
General operations, lookup, etc. for materials.
short * BKE_object_material_len_p(Object *ob)
MaterialGPencilStyle * BKE_gpencil_material_settings(Object *ob, short act)
Material * BKE_gpencil_material(Object *ob, short act)
bool BKE_object_material_slot_used(Object *object, short actcol)
int BKE_object_material_ensure(Main *bmain, Object *ob, Material *material)
Material * BKE_object_material_get(Object *ob, short act)
#define ELEM(...)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1118
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
@ GP_MATERIAL_LOCKED
@ GP_MATERIAL_HIDE
@ OB_GREASE_PENCIL
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ PROP_SKIP_SAVE
Definition RNA_types.hh:344
@ PROP_HIDDEN
Definition RNA_types.hh:338
#define C
Definition RandGen.cpp:29
#define NC_GEOM
Definition WM_types.hh:393
#define ND_DATA
Definition WM_types.hh:509
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define NA_EDITED
Definition WM_types.hh:584
#define NC_GPENCIL
Definition WM_types.hh:399
bool contains(const Key &key) const
Definition BLI_set.hh:310
bool add(const Key &key)
Definition BLI_set.hh:248
std::optional< T > get_if_single() const
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, AttrType data_type, const void *default_value=nullptr) const
void foreach_index(Fn &&fn) const
void ED_operatortypes_grease_pencil_material()
CCL_NAMESPACE_BEGIN ccl_device float invert(const float color, const float factor)
Definition invert.h:11
bool active_grease_pencil_poll(bContext *C)
IndexMask retrieve_editable_and_selected_strokes(Object &object, const bke::greasepencil::Drawing &drawing, int layer_index, IndexMaskMemory &memory)
static void GREASE_PENCIL_OT_material_lock_unused(wmOperatorType *ot)
static void GREASE_PENCIL_OT_material_copy_to_object(wmOperatorType *ot)
static void GREASE_PENCIL_OT_material_unlock_all(wmOperatorType *ot)
static void GREASE_PENCIL_OT_material_lock_unselected(wmOperatorType *ot)
static void GREASE_PENCIL_OT_material_isolate(wmOperatorType *ot)
static void GREASE_PENCIL_OT_material_lock_all(wmOperatorType *ot)
static wmOperatorStatus grease_pencil_material_lock_unused_exec(bContext *C, wmOperator *)
static wmOperatorStatus material_isolate_exec(bContext *C, wmOperator *op)
static void GREASE_PENCIL_OT_material_hide(wmOperatorType *ot)
static wmOperatorStatus grease_pencil_material_unlock_all_exec(bContext *C, wmOperator *)
static wmOperatorStatus grease_pencil_material_reveal_exec(bContext *C, wmOperator *)
static wmOperatorStatus grease_pencil_material_lock_unselected_exec(bContext *C, wmOperator *)
static wmOperatorStatus grease_pencil_material_copy_to_object_exec(bContext *C, wmOperator *op)
static wmOperatorStatus grease_pencil_material_lock_all_exec(bContext *C, wmOperator *)
bool active_grease_pencil_material_poll(bContext *C)
Vector< MutableDrawingInfo > retrieve_editable_drawings(const Scene &scene, GreasePencil &grease_pencil)
static void GREASE_PENCIL_OT_material_reveal(wmOperatorType *ot)
static wmOperatorStatus grease_pencil_material_hide_exec(bContext *C, wmOperator *op)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
struct MaterialGPencilStyle * gp_style
struct PointerRNA * ptr
i
Definition text_draw.cc:230
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4237
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))