Blender V4.3
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
10
11#include "BKE_attribute.hh"
12#include "BKE_context.hh"
13#include "BKE_curves_utils.hh"
14#include "BKE_grease_pencil.hh"
15#include "BKE_material.h"
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/* -------------------------------------------------------------------- */
35{
36 Object *object = CTX_data_active_object(C);
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
73/* -------------------------------------------------------------------- */
78{
79 Object *object = CTX_data_active_object(C);
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
129/* -------------------------------------------------------------------- */
134{
135 Object *object = CTX_data_active_object(C);
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
173/* -------------------------------------------------------------------- */
178{
179 Object *object = CTX_data_active_object(C);
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
216/* -------------------------------------------------------------------- */
221{
222 Object *object = CTX_data_active_object(C);
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
260/* -------------------------------------------------------------------- */
265{
266 using namespace blender;
267 using namespace blender::bke;
268
269 const Scene *scene = CTX_data_scene(C);
270 Object *object = CTX_data_active_object(C);
271 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
272
273 bool changed = false;
274 const Vector<MutableDrawingInfo> drawings = retrieve_editable_drawings(*scene, grease_pencil);
275
276 Set<int> materials_used;
277
278 for (const MutableDrawingInfo &info : drawings) {
279 IndexMaskMemory memory;
281 *object, info.drawing, info.layer_index, memory);
282 if (strokes.is_empty()) {
283 return OPERATOR_CANCELLED;
284 }
285
286 AttributeAccessor attributes = info.drawing.strokes().attributes();
287 const VArray<int> material_indices = *attributes.lookup_or_default<int>(
288 "material_index", AttrDomain::Curve, 0);
289
290 if (const std::optional<int> single = material_indices.get_if_single()) {
291 materials_used.add(*single);
292 }
293 else {
294 strokes.foreach_index([&](const int i) { materials_used.add(material_indices[i]); });
295 }
296 };
297
298 /* The material lock must be done outside of the drawing loop to prevent
299 * 'retrieve_editable_and_selected_strokes' from returning an incorrect IndexMask.
300 */
301 for (const int i : IndexRange(object->totcol)) {
302 if (!materials_used.contains(i)) {
303 if (Material *ma = BKE_object_material_get(object, i + 1)) {
304 MaterialGPencilStyle &gp_style = *ma->gp_style;
305 gp_style.flag |= GP_MATERIAL_LOCKED;
307 changed = true;
308 }
309 }
310 }
311
312 if (changed) {
313 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
314 WM_event_add_notifier(C, NC_GEOM | ND_DATA | NA_EDITED, &grease_pencil);
315 }
316
317 return OPERATOR_FINISHED;
318}
319
321{
322 /* Identifiers. */
323 ot->name = "Lock Unselected Materials";
324 ot->idname = "GREASE_PENCIL_OT_material_lock_unselected";
325 ot->description = "Lock any material not used in any selected stroke";
326
327 /* Callbacks. */
330
332}
333
336/* -------------------------------------------------------------------- */
341{
342 using namespace blender;
343 using namespace blender::bke;
344
345 Main *bmain = CTX_data_main(C);
346 const bool only_active = RNA_boolean_get(op->ptr, "only_active");
347 Object *ob_src = CTX_data_active_object(C);
348 Material *ma_active = BKE_object_material_get(ob_src, ob_src->actcol);
349 if (ma_active == nullptr) {
350 return OPERATOR_CANCELLED;
351 }
352
353 CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
354 if ((ob == ob_src) || (ob->type != OB_GREASE_PENCIL)) {
355 continue;
356 }
357 /* Duplicate materials. */
358 for (const int i : IndexRange(ob_src->totcol)) {
359 Material *ma_src = BKE_object_material_get(ob_src, i + 1);
360 if (only_active && ma_src != ma_active) {
361 continue;
362 }
363
364 if (ma_src == nullptr) {
365 continue;
366 }
367
368 BKE_object_material_ensure(bmain, ob, ma_src);
369 }
370
372 }
374
376
377 return OPERATOR_FINISHED;
378}
379
381{
382 PropertyRNA *prop;
383
384 /* Identifiers. */
385 ot->name = "Copy Materials to Selected Object";
386 ot->idname = "GREASE_PENCIL_OT_material_copy_to_object";
387 ot->description = "Append Materials of the active Grease Pencil to other object";
388
389 /* Callbacks. */
392
394
395 prop = RNA_def_boolean(ot->srna,
396 "only_active",
397 true,
398 "Only Active",
399 "Append only active material, uncheck to append all materials");
400
402}
403
405{
407 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob->data);
408 Material *active_ma = BKE_gpencil_material(ob, ob->actcol);
410 MaterialGPencilStyle *gp_style;
411
412 int flags = GP_MATERIAL_LOCKED;
413 bool isolate = false;
414
415 if (RNA_boolean_get(op->ptr, "affect_visibility")) {
416 flags |= GP_MATERIAL_HIDE;
417 }
418
419 if (active_material == nullptr) {
420 return OPERATOR_CANCELLED;
421 }
422
423 /* Test whether to isolate or clear all flags */
424 Material *ma = nullptr;
425 short *totcol = BKE_object_material_len_p(ob);
426 for (short i = 0; i < *totcol; i++) {
427 ma = BKE_gpencil_material(ob, i + 1);
428 /* Skip if this is the active one */
429 if (ELEM(ma, nullptr, active_ma)) {
430 continue;
431 }
432
433 /* If the flags aren't set, that means that the color is
434 * not alone, so we have some colors to isolate still
435 */
436 gp_style = ma->gp_style;
437 if ((gp_style->flag & flags) == 0) {
438 isolate = true;
439 break;
440 }
441 }
442
443 /* Set/Clear flags as appropriate */
444 if (isolate) {
445 /* Set flags on all "other" colors */
446 for (short i = 0; i < *totcol; i++) {
447 ma = BKE_gpencil_material(ob, i + 1);
448 if (ma == nullptr) {
449 continue;
450 }
451 gp_style = ma->gp_style;
452 if (gp_style == active_material) {
453 continue;
454 }
455 gp_style->flag |= flags;
457 }
458 }
459 else {
460 /* Clear flags - Restore everything else */
461 for (short i = 0; i < *totcol; i++) {
462 ma = BKE_gpencil_material(ob, i + 1);
463 if (ma == nullptr) {
464 continue;
465 }
466 gp_style = ma->gp_style;
467 gp_style->flag &= ~flags;
469 }
470 }
471
472 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
474
475 return OPERATOR_FINISHED;
476}
477
479{
480 /* identifiers */
481 ot->name = "Isolate Material";
482 ot->idname = "GREASE_PENCIL_OT_material_isolate";
483 ot->description =
484 "Toggle whether the active material is the only one that is editable and/or visible";
485
486 /* callbacks */
489
490 /* flags */
492
493 /* properties */
495 "affect_visibility",
496 false,
497 "Affect Visibility",
498 "In addition to toggling "
499 "the editability, also affect the visibility");
500}
501
504} // namespace blender::ed::greasepencil
505
507{
508 using namespace blender::ed::greasepencil;
509 WM_operatortype_append(GREASE_PENCIL_OT_material_reveal);
510 WM_operatortype_append(GREASE_PENCIL_OT_material_hide);
511 WM_operatortype_append(GREASE_PENCIL_OT_material_lock_all);
512 WM_operatortype_append(GREASE_PENCIL_OT_material_unlock_all);
513 WM_operatortype_append(GREASE_PENCIL_OT_material_lock_unused);
514 WM_operatortype_append(GREASE_PENCIL_OT_material_lock_unselected);
515 WM_operatortype_append(GREASE_PENCIL_OT_material_copy_to_object);
516 WM_operatortype_append(GREASE_PENCIL_OT_material_isolate);
517}
#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.
struct Material * BKE_gpencil_material(struct Object *ob, short act)
struct Material * BKE_object_material_get(struct Object *ob, short act)
bool BKE_object_material_slot_used(struct Object *object, short actcol)
short * BKE_object_material_len_p(struct Object *ob)
int BKE_object_material_ensure(Main *bmain, Object *ob, Material *material)
struct MaterialGPencilStyle * BKE_gpencil_material_settings(struct 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:1085
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
@ GP_MATERIAL_LOCKED
@ GP_MATERIAL_HIDE
@ OB_GREASE_PENCIL
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
@ PROP_HIDDEN
Definition RNA_types.hh:239
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define NC_GEOM
Definition WM_types.hh:360
#define ND_DATA
Definition WM_types.hh:475
#define NA_EDITED
Definition WM_types.hh:550
#define NC_GPENCIL
Definition WM_types.hh:366
bool contains(const Key &key) const
Definition BLI_set.hh:291
bool add(const Key &key)
Definition BLI_set.hh:248
std::optional< T > get_if_single() const
void foreach_index(Fn &&fn) const
void ED_operatortypes_grease_pencil_material()
CCL_NAMESPACE_BEGIN ccl_device float invert(float color, float factor)
Definition invert.h:9
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 int grease_pencil_material_lock_all_exec(bContext *C, wmOperator *)
static int grease_pencil_material_lock_unselected_exec(bContext *C, wmOperator *)
static int grease_pencil_material_hide_exec(bContext *C, wmOperator *op)
static int grease_pencil_material_unlock_all_exec(bContext *C, wmOperator *)
static void GREASE_PENCIL_OT_material_hide(wmOperatorType *ot)
static int grease_pencil_material_reveal_exec(bContext *C, wmOperator *)
static int material_isolate_exec(bContext *C, wmOperator *op)
static int grease_pencil_material_copy_to_object_exec(bContext *C, wmOperator *op)
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 int grease_pencil_material_lock_unused_exec(bContext *C, wmOperator *)
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
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
StructRNA * srna
Definition WM_types.hh:1080
struct PointerRNA * ptr
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4125
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))