Blender  V3.3
MOD_gpencillineart.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2017 Blender Foundation. */
3 
8 #include <stdio.h>
9 
10 #include "BLI_math_vector.h"
11 #include "BLI_utildefines.h"
12 
13 #include "BLT_translation.h"
14 
15 #include "DNA_collection_types.h"
16 #include "DNA_defaults.h"
18 #include "DNA_gpencil_types.h"
19 #include "DNA_material_types.h"
20 #include "DNA_object_types.h"
21 #include "DNA_scene_types.h"
22 #include "DNA_screen_types.h"
23 
24 #include "BKE_collection.h"
25 #include "BKE_context.h"
26 #include "BKE_global.h"
27 #include "BKE_gpencil.h"
28 #include "BKE_gpencil_modifier.h"
29 #include "BKE_lib_query.h"
30 #include "BKE_main.h"
31 #include "BKE_screen.h"
32 
33 #include "UI_interface.h"
34 #include "UI_resources.h"
35 
36 #include "BKE_modifier.h"
37 #include "RNA_access.h"
38 
39 #include "DEG_depsgraph.h"
40 #include "DEG_depsgraph_query.h"
41 
42 #include "MOD_gpencil_lineart.h"
44 #include "MOD_gpencil_ui_common.h"
45 #include "lineart/MOD_lineart.h"
46 
47 #include "WM_api.h"
48 #include "WM_types.h"
49 
50 static void initData(GpencilModifierData *md)
51 {
53 
54  BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(gpmd, modifier));
55 
57 }
58 
59 static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
60 {
62 }
63 
66 {
68 
69  if (G.debug_value == 4000) {
70  printf("LRT: Generating from modifier.\n");
71  }
72 
74  lmd->cache,
75  depsgraph,
76  ob,
77  gpl,
78  gpf,
79  lmd->source_type,
80  lmd->source_type == LRT_SOURCE_OBJECT ? (void *)lmd->source_object :
81  (void *)lmd->source_collection,
82  lmd->level_start,
83  lmd->use_multiple_levels ? lmd->level_end : lmd->level_start,
85  lmd->edge_types,
86  lmd->mask_switches,
87  lmd->material_mask_bits,
88  lmd->intersection_mask,
89  lmd->thickness,
90  lmd->opacity,
91  lmd->shadow_selection,
94  lmd->vgname,
95  lmd->flags,
96  lmd->calculation_flags);
97 }
98 
100 {
102 
103  if ((lmd->target_layer[0] == '\0') || (lmd->target_material == NULL)) {
104  return true;
105  }
106 
107  if (lmd->source_type == LRT_SOURCE_OBJECT && !lmd->source_object) {
108  return true;
109  }
110 
111  if (lmd->source_type == LRT_SOURCE_COLLECTION && !lmd->source_collection) {
112  return true;
113  }
114 
115  /* Preventing calculation in depsgraph when baking frames. */
116  if (lmd->flags & LRT_GPENCIL_IS_BAKED) {
117  return true;
118  }
119 
120  return false;
121 }
123 {
125  bGPdata *gpd = ob->data;
126 
127  /* Guard early, don't trigger calculation when no grease-pencil frame is present.
128  * Probably should disable in the #isModifierDisabled() function
129  * but we need additional argument for depsgraph and `gpd`. */
131  if (gpl == NULL) {
132  return;
133  }
134  /* Need to call this or we don't get active frame (user may haven't selected any one). */
136  bGPDframe *gpf = gpl->actframe;
137  if (gpf == NULL) {
138  return;
139  }
140 
141  /* Check all parameters required are filled. */
142  if (isModifierDisabled(md)) {
143  return;
144  }
145 
146  LineartCache *local_lc = gpd->runtime.lineart_cache;
147  if (!gpd->runtime.lineart_cache) {
149  depsgraph, lmd, &gpd->runtime.lineart_cache, (!(ob->dtx & OB_DRAW_IN_FRONT)));
151  }
152  else {
153  if (!(lmd->flags & LRT_GPENCIL_USE_CACHE)) {
155  depsgraph, lmd, &local_lc, (!(ob->dtx & OB_DRAW_IN_FRONT)));
157  }
159  lmd->cache = local_lc;
160  }
161 
162  generate_strokes_actual(md, depsgraph, ob, gpl, gpf);
163 
164  if (!(lmd->flags & LRT_GPENCIL_USE_CACHE)) {
165  /* Clear local cache. */
166  if (local_lc != gpd->runtime.lineart_cache) {
167  MOD_lineart_clear_cache(&local_lc);
168  }
169  /* Restore the original cache pointer so the modifiers below still have access to the "global"
170  * cache. */
171  lmd->cache = gpd->runtime.lineart_cache;
172  }
173 
175 }
176 
177 static void bakeModifier(Main *UNUSED(bmain),
180  Object *ob)
181 {
182  bGPdata *gpd = ob->data;
184 
186  if (gpl == NULL) {
187  return;
188  }
189  bGPDframe *gpf = gpl->actframe;
190  if (gpf == NULL) {
191  return;
192  }
193 
194  if (!gpd->runtime.lineart_cache) {
195  /* Only calculate for this modifier, thus no need to get maximum values from all line art
196  * modifiers in the stack. */
197  lmd->edge_types_override = lmd->edge_types;
198  lmd->level_end_override = lmd->level_end;
200 
202  depsgraph, lmd, &gpd->runtime.lineart_cache, (!(ob->dtx & OB_DRAW_IN_FRONT)));
204  }
205 
206  generate_strokes_actual(md, depsgraph, ob, gpl, gpf);
207 
209 }
210 
211 static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
212 {
213  return isModifierDisabled(md);
214 }
215 
218  const int mode)
219 {
220  if (!c) {
221  return;
222  }
223  bool default_add = true;
224  /* Do not do nested collection usage check, this is consistent with lineart calculation, because
225  * collection usage doesn't have a INHERIT mode. This might initially be derived from the fact
226  * that an object can be inside multiple collections, but might be irrelevant now with the way
227  * objects are iterated. Keep this logic for now. */
228  if (c->lineart_usage & COLLECTION_LRT_EXCLUDE) {
229  default_add = false;
230  }
232  if (ELEM(ob->type, OB_MESH, OB_MBALL, OB_CURVES_LEGACY, OB_SURF, OB_FONT)) {
233  if ((ob->lineart.usage == OBJECT_LRT_INHERIT && default_add) ||
234  ob->lineart.usage != OBJECT_LRT_EXCLUDE) {
235  DEG_add_object_relation(ctx->node, ob, DEG_OB_COMP_GEOMETRY, "Line Art Modifier");
236  DEG_add_object_relation(ctx->node, ob, DEG_OB_COMP_TRANSFORM, "Line Art Modifier");
237  }
238  }
239  if (ob->type == OB_EMPTY && (ob->transflag & OB_DUPLICOLLECTION)) {
240  add_this_collection(ob->instance_collection, ctx, mode);
241  }
242  }
244 }
245 
248  const int mode)
249 {
250  DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Line Art Modifier");
251 
253 
254  /* Always add whole master collection because line art will need the whole scene for
255  * visibility computation. Line art exclusion is handled inside #add_this_collection. */
256  add_this_collection(ctx->scene->master_collection, ctx, mode);
257 
260  ctx->node, lmd->source_camera, DEG_OB_COMP_TRANSFORM, "Line Art Modifier");
262  ctx->node, lmd->source_camera, DEG_OB_COMP_PARAMETERS, "Line Art Modifier");
263  }
264  else if (ctx->scene->camera) {
266  ctx->node, ctx->scene->camera, DEG_OB_COMP_TRANSFORM, "Line Art Modifier");
268  ctx->node, ctx->scene->camera, DEG_OB_COMP_PARAMETERS, "Line Art Modifier");
269  }
270  if (lmd->light_contour_object) {
272  ctx->node, lmd->light_contour_object, DEG_OB_COMP_TRANSFORM, "Line Art Modifier");
273  }
274 }
275 
276 static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
277 {
279 
280  walk(userData, ob, (ID **)&lmd->target_material, IDWALK_CB_USER);
281  walk(userData, ob, (ID **)&lmd->source_collection, IDWALK_CB_NOP);
282 
283  walk(userData, ob, (ID **)&lmd->source_object, IDWALK_CB_NOP);
284  walk(userData, ob, (ID **)&lmd->source_camera, IDWALK_CB_NOP);
285  walk(userData, ob, (ID **)&lmd->light_contour_object, IDWALK_CB_NOP);
286 }
287 
288 static void panel_draw(const bContext *UNUSED(C), Panel *panel)
289 {
290  uiLayout *layout = panel->layout;
291 
292  PointerRNA ob_ptr;
294 
295  PointerRNA obj_data_ptr = RNA_pointer_get(&ob_ptr, "data");
296 
297  const int source_type = RNA_enum_get(ptr, "source_type");
298  const bool is_baked = RNA_boolean_get(ptr, "is_baked");
299 
300  uiLayoutSetPropSep(layout, true);
301  uiLayoutSetEnabled(layout, !is_baked);
302 
304  uiItemR(layout, ptr, "use_cache", 0, NULL, ICON_NONE);
305  }
306 
307  uiItemR(layout, ptr, "source_type", 0, NULL, ICON_NONE);
308 
309  if (source_type == LRT_SOURCE_OBJECT) {
310  uiItemR(layout, ptr, "source_object", 0, NULL, ICON_OBJECT_DATA);
311  }
312  else if (source_type == LRT_SOURCE_COLLECTION) {
313  uiLayout *sub = uiLayoutRow(layout, true);
314  uiItemR(sub, ptr, "source_collection", 0, NULL, ICON_OUTLINER_COLLECTION);
315  uiItemR(sub, ptr, "use_invert_collection", 0, "", ICON_ARROW_LEFTRIGHT);
316  }
317  else {
318  /* Source is Scene. */
319  }
320  uiItemPointerR(layout, ptr, "target_layer", &obj_data_ptr, "layers", NULL, ICON_GREASEPENCIL);
321 
322  /* Material has to be used by grease pencil object already, it was possible to assign materials
323  * without this requirement in earlier versions of blender. */
324  bool material_valid = false;
325  PointerRNA material_ptr = RNA_pointer_get(ptr, "target_material");
326  if (!RNA_pointer_is_null(&material_ptr)) {
327  Material *current_material = material_ptr.data;
328  Object *ob = ob_ptr.data;
329  material_valid = BKE_gpencil_object_material_index_get(ob, current_material) != -1;
330  }
331  uiLayout *row = uiLayoutRow(layout, true);
332  uiLayoutSetRedAlert(row, !material_valid);
334  row, ptr, "target_material", &obj_data_ptr, "materials", NULL, ICON_SHADING_TEXTURE);
335 
336  uiLayout *col = uiLayoutColumn(layout, false);
337  uiItemR(col, ptr, "thickness", UI_ITEM_R_SLIDER, IFACE_("Line Thickness"), ICON_NONE);
338  uiItemR(col, ptr, "opacity", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
339 
341 }
342 
343 static void edge_types_panel_draw(const bContext *UNUSED(C), Panel *panel)
344 {
345  uiLayout *layout = panel->layout;
346  PointerRNA ob_ptr;
348 
349  const bool is_baked = RNA_boolean_get(ptr, "is_baked");
350  const bool use_cache = RNA_boolean_get(ptr, "use_cache");
351  const bool is_first = BKE_gpencil_is_first_lineart_in_stack(ob_ptr.data, ptr->data);
352  const bool has_light = RNA_pointer_get(ptr, "light_contour_object").data != NULL;
353 
354  uiLayoutSetEnabled(layout, !is_baked);
355 
356  uiLayoutSetPropSep(layout, true);
357 
358  uiLayout *sub = uiLayoutRow(layout, false);
359  uiLayoutSetActive(sub, has_light);
360  uiItemR(sub, ptr, "shadow_region_filtering", 0, IFACE_("Illumination Filtering"), ICON_NONE);
361 
362  uiLayout *col = uiLayoutColumn(layout, true);
363 
364  sub = uiLayoutRowWithHeading(col, false, IFACE_("Create"));
365  uiItemR(sub, ptr, "use_contour", 0, "", ICON_NONE);
366 
367  uiLayout *entry = uiLayoutRow(sub, true);
368  uiLayoutSetActive(entry, RNA_boolean_get(ptr, "use_contour"));
369  uiItemR(entry, ptr, "silhouette_filtering", 0, "", ICON_NONE);
370 
371  const int silhouette_filtering = RNA_enum_get(ptr, "silhouette_filtering");
372  if (silhouette_filtering != LRT_SILHOUETTE_FILTER_NONE) {
373  uiItemR(entry, ptr, "use_invert_silhouette", 0, "", ICON_ARROW_LEFTRIGHT);
374  }
375 
376  sub = uiLayoutRow(col, false);
377  if (use_cache && !is_first) {
378  uiItemR(sub, ptr, "use_crease", 0, IFACE_("Crease (Angle Cached)"), ICON_NONE);
379  }
380  else {
381  uiItemR(sub, ptr, "use_crease", 0, "", ICON_NONE);
382  uiItemR(sub,
383  ptr,
384  "crease_threshold",
386  NULL,
387  ICON_NONE);
388  }
389 
390  uiItemR(col, ptr, "use_intersection", 0, IFACE_("Intersections"), ICON_NONE);
391  uiItemR(col, ptr, "use_material", 0, IFACE_("Material Borders"), ICON_NONE);
392  uiItemR(col, ptr, "use_edge_mark", 0, IFACE_("Edge Marks"), ICON_NONE);
393  uiItemR(col, ptr, "use_loose", 0, IFACE_("Loose"), ICON_NONE);
394 
395  entry = uiLayoutColumn(col, false);
396  uiLayoutSetActive(entry, has_light);
397 
398  sub = uiLayoutRow(entry, false);
399  uiItemR(sub, ptr, "use_light_contour", 0, IFACE_("Light Contour"), ICON_NONE);
400 
401  uiItemR(entry, ptr, "use_shadow", 0, IFACE_("Cast Shadow"), ICON_NONE);
402 
403  uiItemL(layout, IFACE_("Options"), ICON_NONE);
404 
405  sub = uiLayoutColumn(layout, false);
406  if (use_cache && !is_first) {
407  uiItemL(sub, IFACE_("Type overlapping cached"), ICON_INFO);
408  }
409  else {
410  uiItemR(sub,
411  ptr,
412  "use_overlap_edge_type_support",
413  0,
414  IFACE_("Allow Overlapping Types"),
415  ICON_NONE);
416  }
417 }
418 
419 static void options_light_reference_draw(const bContext *UNUSED(C), Panel *panel)
420 {
421  uiLayout *layout = panel->layout;
422  PointerRNA ob_ptr;
424 
425  const bool is_baked = RNA_boolean_get(ptr, "is_baked");
426  const bool use_cache = RNA_boolean_get(ptr, "use_cache");
427  const bool has_light = RNA_pointer_get(ptr, "light_contour_object").data != NULL;
428  const bool is_first = BKE_gpencil_is_first_lineart_in_stack(ob_ptr.data, ptr->data);
429 
430  uiLayoutSetPropSep(layout, true);
431  uiLayoutSetEnabled(layout, !is_baked);
432 
433  if (use_cache && !is_first) {
434  uiItemL(layout, "Cached from the first line art modifier.", ICON_INFO);
435  return;
436  }
437 
438  uiItemR(layout, ptr, "light_contour_object", 0, NULL, ICON_NONE);
439 
440  uiLayout *remaining = uiLayoutColumn(layout, false);
441  uiLayoutSetActive(remaining, has_light);
442 
443  uiItemR(remaining, ptr, "shadow_camera_size", 0, NULL, ICON_NONE);
444 
445  uiLayout *col = uiLayoutColumn(remaining, true);
446  uiItemR(col, ptr, "shadow_camera_near", 0, "Near", ICON_NONE);
447  uiItemR(col, ptr, "shadow_camera_far", 0, "Far", ICON_NONE);
448 }
449 
450 static void options_panel_draw(const bContext *UNUSED(C), Panel *panel)
451 {
452  uiLayout *layout = panel->layout;
453  PointerRNA ob_ptr;
455 
456  const bool is_baked = RNA_boolean_get(ptr, "is_baked");
457  const bool use_cache = RNA_boolean_get(ptr, "use_cache");
458  const bool is_first = BKE_gpencil_is_first_lineart_in_stack(ob_ptr.data, ptr->data);
459 
460  uiLayoutSetPropSep(layout, true);
461  uiLayoutSetEnabled(layout, !is_baked);
462 
463  if (use_cache && !is_first) {
464  uiItemL(layout, TIP_("Cached from the first line art modifier"), ICON_INFO);
465  return;
466  }
467 
468  uiLayout *row = uiLayoutRowWithHeading(layout, false, IFACE_("Custom Camera"));
469  uiItemR(row, ptr, "use_custom_camera", 0, "", 0);
470  uiLayout *subrow = uiLayoutRow(row, true);
471  uiLayoutSetActive(subrow, RNA_boolean_get(ptr, "use_custom_camera"));
472  uiLayoutSetPropSep(subrow, true);
473  uiItemR(subrow, ptr, "source_camera", 0, "", ICON_OBJECT_DATA);
474 
475  uiLayout *col = uiLayoutColumn(layout, true);
476 
477  uiItemR(col, ptr, "use_edge_overlap", 0, IFACE_("Overlapping Edges As Contour"), ICON_NONE);
478  uiItemR(col, ptr, "use_object_instances", 0, NULL, ICON_NONE);
479  uiItemR(col, ptr, "use_clip_plane_boundaries", 0, NULL, ICON_NONE);
480  uiItemR(col, ptr, "use_crease_on_smooth", 0, IFACE_("Crease On Smooth"), ICON_NONE);
481  uiItemR(col, ptr, "use_crease_on_sharp", 0, IFACE_("Crease On Sharp"), ICON_NONE);
482  uiItemR(col, ptr, "use_back_face_culling", 0, IFACE_("Force Backface Culling"), ICON_NONE);
483 }
484 
485 static void occlusion_panel_draw(const bContext *UNUSED(C), Panel *panel)
486 {
487  uiLayout *layout = panel->layout;
488  PointerRNA ob_ptr;
490 
491  const bool is_baked = RNA_boolean_get(ptr, "is_baked");
492 
493  const bool use_multiple_levels = RNA_boolean_get(ptr, "use_multiple_levels");
494  const bool show_in_front = RNA_boolean_get(&ob_ptr, "show_in_front");
495 
496  uiLayoutSetPropSep(layout, true);
497  uiLayoutSetEnabled(layout, !is_baked);
498 
499  if (!show_in_front) {
500  uiItemL(layout, TIP_("Object is not in front"), ICON_INFO);
501  }
502 
503  layout = uiLayoutColumn(layout, false);
504  uiLayoutSetActive(layout, show_in_front);
505 
506  uiItemR(layout, ptr, "use_multiple_levels", 0, IFACE_("Range"), ICON_NONE);
507 
508  if (use_multiple_levels) {
509  uiLayout *col = uiLayoutColumn(layout, true);
510  uiItemR(col, ptr, "level_start", 0, NULL, ICON_NONE);
511  uiItemR(col, ptr, "level_end", 0, IFACE_("End"), ICON_NONE);
512  }
513  else {
514  uiItemR(layout, ptr, "level_start", 0, IFACE_("Level"), ICON_NONE);
515  }
516 }
517 
519 {
520  const bool use_multiple_levels = RNA_boolean_get(ptr, "use_multiple_levels");
521  const int level_start = RNA_int_get(ptr, "level_start");
522  const int level_end = RNA_int_get(ptr, "level_end");
523  if (use_multiple_levels) {
524  return (MAX2(level_start, level_end) > 0);
525  }
526  return (level_start > 0);
527 }
528 
530 {
531  uiLayout *layout = panel->layout;
532  PointerRNA ob_ptr;
534 
535  const bool is_baked = RNA_boolean_get(ptr, "is_baked");
536  const bool show_in_front = RNA_boolean_get(&ob_ptr, "show_in_front");
537 
538  uiLayoutSetEnabled(layout, !is_baked);
539  uiLayoutSetActive(layout, show_in_front && anything_showing_through(ptr));
540 
541  uiItemR(layout, ptr, "use_material_mask", 0, IFACE_("Material Mask"), ICON_NONE);
542 }
543 
544 static void material_mask_panel_draw(const bContext *UNUSED(C), Panel *panel)
545 {
546  uiLayout *layout = panel->layout;
548 
549  const bool is_baked = RNA_boolean_get(ptr, "is_baked");
550  uiLayoutSetEnabled(layout, !is_baked);
552 
553  uiLayoutSetPropSep(layout, true);
554 
555  uiLayoutSetEnabled(layout, RNA_boolean_get(ptr, "use_material_mask"));
556 
557  uiLayout *col = uiLayoutColumn(layout, true);
558  uiLayout *sub = uiLayoutRowWithHeading(col, true, IFACE_("Masks"));
559 
560  PropertyRNA *prop = RNA_struct_find_property(ptr, "use_material_mask_bits");
561  for (int i = 0; i < 8; i++) {
562  uiItemFullR(sub, ptr, prop, i, 0, UI_ITEM_R_TOGGLE, " ", ICON_NONE);
563  if (i == 3) {
564  sub = uiLayoutRow(col, true);
565  }
566  }
567 
568  uiItemR(layout, ptr, "use_material_mask_match", 0, IFACE_("Exact Match"), ICON_NONE);
569 }
570 
571 static void intersection_panel_draw(const bContext *UNUSED(C), Panel *panel)
572 {
573  uiLayout *layout = panel->layout;
575 
576  const bool is_baked = RNA_boolean_get(ptr, "is_baked");
577  uiLayoutSetEnabled(layout, !is_baked);
578 
579  uiLayoutSetPropSep(layout, true);
580 
581  uiLayoutSetActive(layout, RNA_boolean_get(ptr, "use_intersection"));
582 
583  uiLayout *col = uiLayoutColumn(layout, true);
584  uiLayout *sub = uiLayoutRowWithHeading(col, true, IFACE_("Collection Masks"));
585 
586  PropertyRNA *prop = RNA_struct_find_property(ptr, "use_intersection_mask");
587  for (int i = 0; i < 8; i++) {
588  uiItemFullR(sub, ptr, prop, i, 0, UI_ITEM_R_TOGGLE, " ", ICON_NONE);
589  if (i == 3) {
590  sub = uiLayoutRow(col, true);
591  }
592  }
593 
594  uiItemR(layout, ptr, "use_intersection_match", 0, IFACE_("Exact Match"), ICON_NONE);
595 }
596 
597 static void face_mark_panel_draw_header(const bContext *UNUSED(C), Panel *panel)
598 {
599  uiLayout *layout = panel->layout;
600  PointerRNA ob_ptr;
602 
603  const bool is_baked = RNA_boolean_get(ptr, "is_baked");
604  const bool use_cache = RNA_boolean_get(ptr, "use_cache");
605  const bool is_first = BKE_gpencil_is_first_lineart_in_stack(ob_ptr.data, ptr->data);
606 
607  if (!use_cache || is_first) {
608  uiLayoutSetEnabled(layout, !is_baked);
609  uiItemR(layout, ptr, "use_face_mark", 0, IFACE_("Face Mark Filtering"), ICON_NONE);
610  }
611  else {
612  uiItemL(layout, IFACE_("Face Mark Filtering"), ICON_NONE);
613  }
614 }
615 
616 static void face_mark_panel_draw(const bContext *UNUSED(C), Panel *panel)
617 {
618  uiLayout *layout = panel->layout;
619  PointerRNA ob_ptr;
621 
622  const bool is_baked = RNA_boolean_get(ptr, "is_baked");
623  const bool use_mark = RNA_boolean_get(ptr, "use_face_mark");
624  const bool use_cache = RNA_boolean_get(ptr, "use_cache");
625  const bool is_first = BKE_gpencil_is_first_lineart_in_stack(ob_ptr.data, ptr->data);
626 
627  uiLayoutSetEnabled(layout, !is_baked);
628 
629  if (use_cache && !is_first) {
630  uiItemL(layout, TIP_("Cached from the first line art modifier"), ICON_INFO);
631  return;
632  }
633 
634  uiLayoutSetPropSep(layout, true);
635 
636  uiLayoutSetActive(layout, use_mark);
637 
638  uiItemR(layout, ptr, "use_face_mark_invert", 0, NULL, ICON_NONE);
639  uiItemR(layout, ptr, "use_face_mark_boundaries", 0, NULL, ICON_NONE);
640  uiItemR(layout, ptr, "use_face_mark_keep_contour", 0, NULL, ICON_NONE);
641 }
642 
643 static void chaining_panel_draw(const bContext *UNUSED(C), Panel *panel)
644 {
645  PointerRNA ob_ptr;
647 
648  uiLayout *layout = panel->layout;
649 
650  const bool is_baked = RNA_boolean_get(ptr, "is_baked");
651  const bool use_cache = RNA_boolean_get(ptr, "use_cache");
652  const bool is_first = BKE_gpencil_is_first_lineart_in_stack(ob_ptr.data, ptr->data);
653  const bool is_geom = RNA_boolean_get(ptr, "use_geometry_space_chain");
654 
655  uiLayoutSetPropSep(layout, true);
656  uiLayoutSetEnabled(layout, !is_baked);
657 
658  if (use_cache && !is_first) {
659  uiItemL(layout, TIP_("Cached from the first line art modifier"), ICON_INFO);
660  return;
661  }
662 
663  uiLayout *col = uiLayoutColumnWithHeading(layout, true, IFACE_("Chain"));
664  uiItemR(col, ptr, "use_fuzzy_intersections", 0, NULL, ICON_NONE);
665  uiItemR(col, ptr, "use_fuzzy_all", 0, NULL, ICON_NONE);
666  uiItemR(col, ptr, "use_loose_edge_chain", 0, IFACE_("Loose Edges"), ICON_NONE);
667  uiItemR(col, ptr, "use_loose_as_contour", 0, IFACE_("Loose Edges As Contour"), ICON_NONE);
668  uiItemR(col, ptr, "use_detail_preserve", 0, NULL, ICON_NONE);
669  uiItemR(col, ptr, "use_geometry_space_chain", 0, IFACE_("Geometry Space"), ICON_NONE);
670 
671  uiItemR(layout,
672  ptr,
673  "chaining_image_threshold",
674  0,
675  is_geom ? IFACE_("Geometry Threshold") : NULL,
676  ICON_NONE);
677 
678  uiItemR(layout, ptr, "smooth_tolerance", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
679  uiItemR(layout, ptr, "split_angle", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
680 }
681 
682 static void vgroup_panel_draw(const bContext *UNUSED(C), Panel *panel)
683 {
684  PointerRNA ob_ptr;
686 
687  uiLayout *layout = panel->layout;
688 
689  const bool is_baked = RNA_boolean_get(ptr, "is_baked");
690  const bool use_cache = RNA_boolean_get(ptr, "use_cache");
691  const bool is_first = BKE_gpencil_is_first_lineart_in_stack(ob_ptr.data, ptr->data);
692 
693  uiLayoutSetPropSep(layout, true);
694  uiLayoutSetEnabled(layout, !is_baked);
695 
696  if (use_cache && !is_first) {
697  uiItemL(layout, TIP_("Cached from the first line art modifier"), ICON_INFO);
698  return;
699  }
700 
701  uiLayout *col = uiLayoutColumn(layout, true);
702 
703  uiLayout *row = uiLayoutRow(col, true);
704 
705  uiItemR(row, ptr, "source_vertex_group", 0, IFACE_("Filter Source"), ICON_GROUP_VERTEX);
706  uiItemR(row, ptr, "invert_source_vertex_group", UI_ITEM_R_TOGGLE, "", ICON_ARROW_LEFTRIGHT);
707 
708  uiItemR(col, ptr, "use_output_vertex_group_match_by_name", 0, NULL, ICON_NONE);
709 
710  const bool match_output = RNA_boolean_get(ptr, "use_output_vertex_group_match_by_name");
711  if (!match_output) {
713  col, ptr, "vertex_group", &ob_ptr, "vertex_groups", IFACE_("Target"), ICON_NONE);
714  }
715 }
716 
717 static void bake_panel_draw(const bContext *UNUSED(C), Panel *panel)
718 {
719  uiLayout *layout = panel->layout;
720  PointerRNA ob_ptr;
722 
723  const bool is_baked = RNA_boolean_get(ptr, "is_baked");
724 
725  uiLayoutSetPropSep(layout, true);
726 
727  if (is_baked) {
728  uiLayout *col = uiLayoutColumn(layout, false);
729  uiLayoutSetPropSep(col, false);
730  uiItemL(col, TIP_("Modifier has baked data"), ICON_NONE);
731  uiItemR(
732  col, ptr, "is_baked", UI_ITEM_R_TOGGLE, IFACE_("Continue Without Clearing"), ICON_NONE);
733  }
734 
735  uiLayout *col = uiLayoutColumn(layout, false);
736  uiLayoutSetEnabled(col, !is_baked);
737  uiItemO(col, NULL, ICON_NONE, "OBJECT_OT_lineart_bake_strokes");
738  uiItemO(col, NULL, ICON_NONE, "OBJECT_OT_lineart_bake_strokes_all");
739 
740  col = uiLayoutColumn(layout, false);
741  uiItemO(col, NULL, ICON_NONE, "OBJECT_OT_lineart_clear");
742  uiItemO(col, NULL, ICON_NONE, "OBJECT_OT_lineart_clear_all");
743 }
744 
745 static void composition_panel_draw(const bContext *UNUSED(C), Panel *panel)
746 {
747  PointerRNA ob_ptr;
749 
750  uiLayout *layout = panel->layout;
751 
752  const bool show_in_front = RNA_boolean_get(&ob_ptr, "show_in_front");
753 
754  uiLayoutSetPropSep(layout, true);
755 
756  uiItemR(layout, ptr, "overscan", 0, NULL, ICON_NONE);
757  uiItemR(layout, ptr, "use_image_boundary_trimming", 0, NULL, ICON_NONE);
758 
759  if (show_in_front) {
760  uiItemL(layout, TIP_("Object is shown in front"), ICON_ERROR);
761  }
762 
763  uiLayout *col = uiLayoutColumn(layout, false);
764  uiLayoutSetActive(col, !show_in_front);
765 
766  uiItemR(col, ptr, "stroke_depth_offset", UI_ITEM_R_SLIDER, IFACE_("Depth Offset"), ICON_NONE);
767  uiItemR(
768  col, ptr, "use_offset_towards_custom_camera", 0, IFACE_("Towards Custom Camera"), ICON_NONE);
769 }
770 
771 static void panelRegister(ARegionType *region_type)
772 {
775 
777  region_type, "edge_types", "Edge Types", NULL, edge_types_panel_draw, panel_type);
779  "light_reference",
780  "Light Reference",
781  NULL,
783  panel_type);
785  region_type, "geometry", "Geometry Processing", NULL, options_panel_draw, panel_type);
787  region_type, "occlusion", "Occlusion", NULL, occlusion_panel_draw, panel_type);
789  "material_mask",
790  "",
793  occlusion_panel);
795  region_type, "intersection", "Intersection", NULL, intersection_panel_draw, panel_type);
797  region_type, "face_mark", "", face_mark_panel_draw_header, face_mark_panel_draw, panel_type);
799  region_type, "chaining", "Chaining", NULL, chaining_panel_draw, panel_type);
801  region_type, "vgroup", "Vertex Weight Transfer", NULL, vgroup_panel_draw, panel_type);
803  region_type, "composition", "Composition", NULL, composition_panel_draw, panel_type);
805  region_type, "bake", "Bake", NULL, bake_panel_draw, panel_type);
806 }
807 
809  /* name. */ "Line Art",
810  /* structName. */ "LineartGpencilModifierData",
811  /* structSize. */ sizeof(LineartGpencilModifierData),
814 
815  /* copyData. */ copyData,
816 
817  /* deformStroke. */ NULL,
818  /* generateStrokes. */ generateStrokes,
819  /* bakeModifier. */ bakeModifier,
820  /* remapTime. */ NULL,
821 
822  /* initData. */ initData,
823  /* freeData. */ NULL,
824  /* isDisabled. */ isDisabled,
825  /* updateDepsgraph. */ updateDepsgraph,
826  /* dependsOnTime. */ NULL,
827  /* foreachIDLink. */ foreachIDLink,
828  /* foreachTexLink. */ NULL,
829  /* panelRegister. */ panelRegister,
830 };
#define FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(_collection, _object, _mode)
#define FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END
void BKE_gpencil_frame_active_set(struct Depsgraph *depsgraph, struct bGPdata *gpd)
int BKE_gpencil_object_material_index_get(struct Object *ob, struct Material *ma)
Definition: gpencil.c:2199
struct bGPDlayer * BKE_gpencil_layer_get_by_name(struct bGPdata *gpd, char *name, int first_if_not_found)
Definition: gpencil.c:1576
void BKE_gpencil_modifier_copydata_generic(const struct GpencilModifierData *md_src, struct GpencilModifierData *md_dst)
@ eGpencilModifierTypeFlag_SupportsEditmode
@ eGpencilModifierTypeType_Gpencil
bool BKE_gpencil_is_first_lineart_in_stack(const struct Object *ob, const struct GpencilModifierData *md)
@ IDWALK_CB_USER
Definition: BKE_lib_query.h:73
@ IDWALK_CB_NOP
Definition: BKE_lib_query.h:33
void(* IDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag)
Definition: BKE_modifier.h:107
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define UNUSED(x)
#define MAX2(a, b)
#define ELEM(...)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define TIP_(msgid)
#define IFACE_(msgid)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
void DEG_add_object_relation(struct DepsNodeHandle *node_handle, struct Object *object, eDepsObjectComponentType component, const char *description)
@ DEG_OB_COMP_GEOMETRY
@ DEG_OB_COMP_TRANSFORM
@ DEG_OB_COMP_PARAMETERS
Object groups, one object can be in many groups at once.
@ COLLECTION_LRT_EXCLUDE
#define DNA_struct_default_get(struct_name)
Definition: DNA_defaults.h:29
@ LRT_SILHOUETTE_FILTER_NONE
struct LineartGpencilModifierData LineartGpencilModifierData
@ eGpencilModifierType_Lineart
@ LRT_USE_CUSTOM_CAMERA
Object is a sort of wrapper for general info.
@ OB_MBALL
@ OB_EMPTY
@ OB_SURF
@ OB_FONT
@ OB_MESH
@ OB_CURVES_LEGACY
@ OB_DRAW_IN_FRONT
@ OB_DUPLICOLLECTION
@ OBJECT_LRT_EXCLUDE
@ OBJECT_LRT_INHERIT
PointerRNA * gpencil_modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void gpencil_modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
PanelType * gpencil_modifier_subpanel_register(ARegionType *region_type, const char *name, const char *label, PanelDrawFn draw_header, PanelDrawFn draw, PanelType *parent)
PanelType * gpencil_modifier_panel_register(ARegionType *region_type, GpencilModifierType type, PanelDrawFn draw)
static void face_mark_panel_draw(const bContext *UNUSED(C), Panel *panel)
static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
static void chaining_panel_draw(const bContext *UNUSED(C), Panel *panel)
static void intersection_panel_draw(const bContext *UNUSED(C), Panel *panel)
static void face_mark_panel_draw_header(const bContext *UNUSED(C), Panel *panel)
static bool isModifierDisabled(GpencilModifierData *md)
static void edge_types_panel_draw(const bContext *UNUSED(C), Panel *panel)
static void occlusion_panel_draw(const bContext *UNUSED(C), Panel *panel)
static bool anything_showing_through(PointerRNA *ptr)
static void vgroup_panel_draw(const bContext *UNUSED(C), Panel *panel)
static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
static void bakeModifier(Main *UNUSED(bmain), Depsgraph *depsgraph, GpencilModifierData *md, Object *ob)
static void bake_panel_draw(const bContext *UNUSED(C), Panel *panel)
static void add_this_collection(Collection *c, const ModifierUpdateDepsgraphContext *ctx, const int mode)
static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
static void options_light_reference_draw(const bContext *UNUSED(C), Panel *panel)
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
static void material_mask_panel_draw_header(const bContext *UNUSED(C), Panel *panel)
static void panelRegister(ARegionType *region_type)
static void initData(GpencilModifierData *md)
static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Object *ob)
GpencilModifierTypeInfo modifierType_Gpencil_Lineart
static void material_mask_panel_draw(const bContext *UNUSED(C), Panel *panel)
static void generate_strokes_actual(GpencilModifierData *md, Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, bGPDframe *gpf)
static void options_panel_draw(const bContext *UNUSED(C), Panel *panel)
static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx, const int mode)
static void composition_panel_draw(const bContext *UNUSED(C), Panel *panel)
#define C
Definition: RandGen.cpp:25
uiLayout * uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading)
void uiLayoutSetActive(uiLayout *layout, bool active)
uiLayout * uiLayoutColumnWithHeading(uiLayout *layout, bool align, const char *heading)
void uiLayoutSetEnabled(uiLayout *layout, bool enabled)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiItemL(uiLayout *layout, const char *name, int icon)
void uiLayoutSetRedAlert(uiLayout *layout, bool redalert)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
@ UI_ITEM_R_TOGGLE
@ UI_ITEM_R_FORCE_BLANK_DECORATE
@ UI_ITEM_R_SLIDER
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname)
void uiItemFullR(uiLayout *layout, struct PointerRNA *ptr, struct PropertyRNA *prop, int index, int value, int flag, const char *name, int icon)
void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, struct PointerRNA *searchptr, const char *searchpropname, const char *name, int icon)
#define NA_EDITED
Definition: WM_types.h:523
#define NC_GPENCIL
Definition: WM_types.h:349
const Depsgraph * depsgraph
uint col
void MOD_lineart_chain_clear_picked_flag(LineartCache *lc)
void MOD_lineart_clear_cache(struct LineartCache **lc)
Definition: lineart_cpu.c:3539
void MOD_lineart_destroy_render_data(LineartGpencilModifierData *lmd)
Definition: lineart_cpu.c:3517
bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, LineartGpencilModifierData *lmd, LineartCache **cached_result, bool enable_stroke_depth_offset)
Definition: lineart_cpu.c:4957
void MOD_lineart_gpencil_generate(LineartCache *cache, Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, bGPDframe *gpf, int8_t source_type, void *source_reference, int level_start, int level_end, int mat_nr, int16_t edge_types, uchar mask_switches, uchar material_mask_bits, uchar intersection_mask, int16_t thickness, float opacity, uchar shadow_selection, uchar silhouette_mode, const char *source_vgname, const char *vgname, int modifier_flags, int modifier_calculation_flags)
Definition: lineart_cpu.c:5368
#define G(x, y, z)
static unsigned c
Definition: RandGen.cpp:83
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5167
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:717
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4910
bool RNA_pointer_is_null(const PointerRNA *ptr)
Definition: rna_access.c:164
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5004
Definition: DNA_ID.h:368
Definition: BKE_main.h:121
struct DepsNodeHandle * node
Definition: BKE_modifier.h:134
void * data
struct uiLayout * layout
void * data
Definition: RNA_types.h:38
struct Collection * master_collection
struct Object * camera
bGPDframe * actframe
struct LineartCache * lineart_cache
bGPdata_Runtime runtime
void WM_main_add_notifier(unsigned int type, void *reference)
PointerRNA * ptr
Definition: wm_files.c:3480