Blender  V3.3
lineart_ops.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2019 Blender Foundation. All rights reserved. */
3 
8 #include <stdlib.h>
9 
10 #include "MEM_guardedalloc.h"
11 
12 #include "BLI_linklist.h"
13 #include "BLI_math.h"
14 #include "BLI_utildefines.h"
15 
16 #include "BKE_context.h"
17 #include "BKE_global.h"
18 #include "BKE_gpencil.h"
19 #include "BKE_gpencil_modifier.h"
20 #include "BKE_report.h"
21 #include "BKE_scene.h"
22 
23 #include "DEG_depsgraph_query.h"
24 
25 #include "WM_api.h"
26 #include "WM_types.h"
27 
29 #include "DNA_gpencil_types.h"
30 #include "DNA_scene_types.h"
31 
32 #include "MOD_gpencil_lineart.h"
33 #include "MOD_lineart.h"
34 
36 {
38 
40 
42 
43  /* Toggle on and off the baked flag as we are only interested in if something else is disabling
44  * it. We can assume that the guard function has already toggled this on for all modifiers that
45  * are sent here. */
46  lmd->flags &= (~LRT_GPENCIL_IS_BAKED);
47  bool disabled = info->isDisabled(md, 0);
49 
50  return disabled;
51 }
52 
53 static bool clear_strokes(Object *ob, GpencilModifierData *md, int frame)
54 {
56  return false;
57  }
59  bGPdata *gpd = ob->data;
60 
62  if (!gpl) {
63  return false;
64  }
65  bGPDframe *gpf = BKE_gpencil_layer_frame_find(gpl, frame);
66 
67  if (!gpf) {
68  /* No greasepencil frame found. */
69  return false;
70  }
71 
73  return true;
74 }
75 
76 static bool bake_strokes(Object *ob,
77  Depsgraph *dg,
78  LineartCache **lc,
80  int frame,
81  bool is_first)
82 {
83  /* Modifier data sanity check. */
84  if (lineart_mod_is_disabled(md)) {
85  return false;
86  }
87 
89  bGPdata *gpd = ob->data;
90 
92  if (!gpl) {
93  return false;
94  }
95  bool only_use_existing_gp_frames = false;
96  bGPDframe *gpf = (only_use_existing_gp_frames ?
97  BKE_gpencil_layer_frame_find(gpl, frame) :
99 
100  if (!gpf) {
101  /* No greasepencil frame created or found. */
102  return false;
103  }
104  LineartCache *local_lc = *lc;
105  if (!(*lc)) {
106  MOD_lineart_compute_feature_lines(dg, lmd, lc, (!(ob->dtx & OB_DRAW_IN_FRONT)));
108  }
109  else {
110  if (is_first || (!(lmd->flags & LRT_GPENCIL_USE_CACHE))) {
111  MOD_lineart_compute_feature_lines(dg, lmd, &local_lc, (!(ob->dtx & OB_DRAW_IN_FRONT)));
113  }
115  lmd->cache = local_lc;
116  }
117 
119  lmd->cache,
120  dg,
121  ob,
122  gpl,
123  gpf,
124  lmd->source_type,
125  lmd->source_type == LRT_SOURCE_OBJECT ? (void *)lmd->source_object :
126  (void *)lmd->source_collection,
127  lmd->level_start,
128  lmd->use_multiple_levels ? lmd->level_end : lmd->level_start,
130  lmd->edge_types,
131  lmd->mask_switches,
132  lmd->material_mask_bits,
133  lmd->intersection_mask,
134  lmd->thickness,
135  lmd->opacity,
136  lmd->shadow_selection,
138  lmd->source_vertex_group,
139  lmd->vgname,
140  lmd->flags,
141  lmd->calculation_flags);
142 
143  if (!(lmd->flags & LRT_GPENCIL_USE_CACHE)) {
144  /* Clear local cache. */
145  if (!is_first) {
146  MOD_lineart_clear_cache(&local_lc);
147  }
148  /* Restore the original cache pointer so the modifiers below still have access to the "global"
149  * cache. */
150  lmd->cache = gpd->runtime.lineart_cache;
151  }
152 
153  return true;
154 }
155 
156 typedef struct LineartBakeJob {
158  void *owner;
159  short *stop, *do_update;
160  float *progress;
161 
162  /* C or ob must have one != NULL. */
167  int frame;
174 
176 {
177  bool touched = false;
178  if (ob->type != OB_GPENCIL || G.is_break) {
179  return false;
180  }
181 
182  if (bj->overwrite_frames) {
184  if (md->type == eGpencilModifierType_Lineart) {
185  if (clear_strokes(ob, md, frame)) {
186  touched = true;
187  }
188  }
189  }
190  }
191 
193 
194  LineartCache *lc = NULL;
195  bool is_first = true;
197  if (md->type != eGpencilModifierType_Lineart) {
198  continue;
199  }
200  BKE_gpencil_set_lineart_modifier_limits(md, &info, is_first);
201  if (bake_strokes(ob, bj->dg, &lc, md, frame, is_first)) {
202  touched = true;
203  is_first = false;
204  }
205  }
207 
208  return touched;
209 }
210 
212 {
213  for (LinkNode *l = bj->objects; l; l = l->next) {
214  Object *ob = l->link;
216  if (md->type == eGpencilModifierType_Lineart) {
218  lmd->flags |= LRT_GPENCIL_IS_BAKED;
219  }
220  }
221  }
222 }
223 
224 static void lineart_gpencil_bake_startjob(void *customdata,
225  short *stop,
226  short *do_update,
227  float *progress)
228 {
229  LineartBakeJob *bj = (LineartBakeJob *)customdata;
230  bj->stop = stop;
231  bj->do_update = do_update;
232  bj->progress = progress;
233 
235 
236  for (int frame = bj->frame_begin; frame <= bj->frame_end; frame += bj->frame_increment) {
237 
238  if (G.is_break) {
239  G.is_break = false;
240  break;
241  }
242 
243  BKE_scene_frame_set(bj->scene, frame);
245 
246  for (LinkNode *l = bj->objects; l; l = l->next) {
247  Object *ob = l->link;
248  if (lineart_gpencil_bake_single_target(bj, ob, frame)) {
251  }
252  }
253 
254  /* Update and refresh the progress bar. */
255  *bj->progress = (float)(frame - bj->frame_begin) / (bj->frame_end - bj->frame_begin);
256  *bj->do_update = true;
257  }
258 
259  /* This need to be reset manually. */
260  G.is_break = false;
261 
262  /* Restore original frame. */
265 }
266 
267 static void lineart_gpencil_bake_endjob(void *customdata)
268 {
269  LineartBakeJob *bj = customdata;
270 
272 
274 
275  for (LinkNode *l = bj->objects; l; l = l->next) {
277  }
278 
280 }
281 
283  wmOperator *op,
284  bool bake_all_targets,
285  bool do_background)
286 {
287  LineartBakeJob *bj = MEM_callocN(sizeof(LineartBakeJob), "LineartBakeJob");
288 
289  if (!bake_all_targets) {
291  if (!ob || ob->type != OB_GPENCIL) {
292  WM_report(RPT_ERROR, "No active object or active object isn't a GPencil object.");
293  return OPERATOR_FINISHED;
294  }
295  BLI_linklist_prepend(&bj->objects, ob);
296  }
297  else {
298  /* #CTX_DATA_BEGIN is not available for iterating in objects while using the job system. */
299  CTX_DATA_BEGIN (C, Object *, ob, visible_objects) {
300  if (ob->type == OB_GPENCIL) {
301  LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
302  if (md->type == eGpencilModifierType_Lineart) {
303  BLI_linklist_prepend(&bj->objects, ob);
304  break;
305  }
306  }
307  }
308  }
309  CTX_DATA_END;
310  }
311  bj->C = C;
313  bj->scene = scene;
315  bj->frame_begin = scene->r.sfra;
316  bj->frame_end = scene->r.efra;
317  bj->frame_orig = scene->r.cfra;
319  bj->overwrite_frames = true;
320 
321  if (do_background) {
322  wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
323  CTX_wm_window(C),
324  scene,
325  "Line Art",
328 
329  WM_jobs_customdata_set(wm_job, bj, MEM_freeN);
333 
335 
336  WM_jobs_start(CTX_wm_manager(C), wm_job);
337 
339 
340  return OPERATOR_RUNNING_MODAL;
341  }
342 
343  float pseduo_progress;
344  short pseduo_do_update;
345  lineart_gpencil_bake_startjob(bj, NULL, &pseduo_do_update, &pseduo_progress);
346 
348  MEM_freeN(bj);
349 
350  return OPERATOR_FINISHED;
351 }
352 
354  wmOperator *op,
355  const wmEvent *UNUSED(event))
356 {
357  return lineart_gpencil_bake_common(C, op, true, true);
358 }
360 {
361  return lineart_gpencil_bake_common(C, op, true, false);
362 }
364  wmOperator *op,
365  const wmEvent *UNUSED(event))
366 {
367  return lineart_gpencil_bake_common(C, op, false, true);
368 }
370 {
371  return lineart_gpencil_bake_common(C, op, false, false);
372 }
374  wmOperator *op,
375  const wmEvent *UNUSED(event))
376 {
377  Scene *scene = (Scene *)op->customdata;
378 
379  /* no running blender, remove handler and pass through. */
382  }
383 
384  return OPERATOR_PASS_THROUGH;
385 }
386 
388 {
389  /* TODO: move these checks to an operator poll function. */
390  if ((ob == NULL) || ob->type != OB_GPENCIL) {
391  return;
392  }
394  if (md->type != eGpencilModifierType_Lineart) {
395  continue;
396  }
398  bGPdata *gpd = ob->data;
399 
401  if (!gpl) {
402  continue;
403  }
405  BKE_gpencil_frame_addnew(gpl, 0);
406 
408 
409  lmd->flags &= (~LRT_GPENCIL_IS_BAKED);
410  }
412 }
413 
415 {
417 
419 
421 
422  return OPERATOR_FINISHED;
423 }
425 {
426  CTX_DATA_BEGIN (C, Object *, ob, visible_objects) {
429  }
430  CTX_DATA_END;
431 
432  BKE_report(op->reports, RPT_INFO, "All line art objects are now cleared");
433 
434  return OPERATOR_FINISHED;
435 }
436 
438 {
439  ot->name = "Bake Line Art";
440  ot->description = "Bake Line Art for current GPencil object";
441  ot->idname = "OBJECT_OT_lineart_bake_strokes";
442 
446 }
447 
449 {
450  ot->name = "Bake Line Art (All)";
451  ot->description = "Bake all Grease Pencil objects that have a line art modifier";
452  ot->idname = "OBJECT_OT_lineart_bake_strokes_all";
453 
457 }
458 
460 {
461  ot->name = "Clear Baked Line Art";
462  ot->description = "Clear all strokes in current GPencil object";
463  ot->idname = "OBJECT_OT_lineart_clear";
464 
466 }
467 
469 {
470  ot->name = "Clear Baked Line Art (All)";
471  ot->description = "Clear all strokes in all Grease Pencil objects that have a line art modifier";
472  ot->idname = "OBJECT_OT_lineart_clear_all";
473 
475 }
476 
478 {
483 }
typedef float(TangentPoint)[2]
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:713
#define CTX_DATA_BEGIN(C, Type, instance, member)
Definition: BKE_context.h:269
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1353
struct Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Definition: context.c:1505
#define CTX_DATA_END
Definition: BKE_context.h:278
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:723
struct bGPDframe * BKE_gpencil_frame_addnew(struct bGPDlayer *gpl, int cframe)
Definition: gpencil.c:514
void BKE_gpencil_free_frames(struct bGPDlayer *gpl)
Definition: gpencil.c:427
bool BKE_gpencil_layer_frame_delete(struct bGPDlayer *gpl, struct bGPDframe *gpf)
Definition: gpencil.c:1396
int BKE_gpencil_object_material_index_get(struct Object *ob, struct Material *ma)
Definition: gpencil.c:2199
struct bGPDframe * BKE_gpencil_layer_frame_find(struct bGPDlayer *gpl, int cframe)
Definition: gpencil.c:1216
struct bGPDlayer * BKE_gpencil_layer_get_by_name(struct bGPdata *gpd, char *name, int first_if_not_found)
Definition: gpencil.c:1576
struct bGPDframe * BKE_gpencil_layer_frame_get(struct bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew)
Definition: gpencil.c:1232
@ GP_GETFRAME_ADD_NEW
Definition: BKE_gpencil.h:341
GpencilLineartLimitInfo BKE_gpencil_get_lineart_modifier_limits(const struct Object *ob)
void BKE_gpencil_set_lineart_modifier_limits(struct GpencilModifierData *md, const struct GpencilLineartLimitInfo *info, bool is_first_lineart)
const GpencilModifierTypeInfo * BKE_gpencil_modifier_get_info(GpencilModifierType type)
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
void BKE_scene_graph_update_for_newframe(struct Depsgraph *depsgraph)
Definition: scene.cc:2728
void BKE_scene_frame_set(struct Scene *scene, float frame)
Definition: scene.cc:2420
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
#define UNUSED(x)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
@ eGpencilModifierMode_Render
@ eGpencilModifierMode_Realtime
@ eGpencilModifierType_Lineart
@ OB_GPENCIL
@ OB_DRAW_IN_FRONT
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:25
@ WM_JOB_PROGRESS
Definition: WM_api.h:1339
@ WM_JOB_TYPE_LINEART
Definition: WM_api.h:1373
#define ND_DATA
Definition: WM_types.h:456
#define NC_SCENE
Definition: WM_types.h:328
#define NA_EDITED
Definition: WM_types.h:523
#define ND_FRAME
Definition: WM_types.h:382
#define NC_GPENCIL
Definition: WM_types.h:349
ATTR_WARN_UNUSED_RESULT const BMLoop * l
Scene scene
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
static bool lineart_mod_is_disabled(GpencilModifierData *md)
Definition: lineart_ops.c:35
void OBJECT_OT_lineart_bake_strokes_all(wmOperatorType *ot)
Definition: lineart_ops.c:448
static int lineart_gpencil_bake_strokes_all_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: lineart_ops.c:353
static int lineart_gpencil_clear_strokes_exec(bContext *C, wmOperator *UNUSED(op))
Definition: lineart_ops.c:414
static void lineart_gpencil_bake_endjob(void *customdata)
Definition: lineart_ops.c:267
static bool clear_strokes(Object *ob, GpencilModifierData *md, int frame)
Definition: lineart_ops.c:53
void OBJECT_OT_lineart_bake_strokes(wmOperatorType *ot)
Definition: lineart_ops.c:437
static void lineart_gpencil_guard_modifiers(LineartBakeJob *bj)
Definition: lineart_ops.c:211
static int lineart_gpencil_bake_strokes_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: lineart_ops.c:363
void OBJECT_OT_lineart_clear_all(wmOperatorType *ot)
Definition: lineart_ops.c:468
void OBJECT_OT_lineart_clear(wmOperatorType *ot)
Definition: lineart_ops.c:459
static int lineart_gpencil_clear_strokes_all_exec(bContext *C, wmOperator *op)
Definition: lineart_ops.c:424
static int lineart_gpencil_bake_strokes_exec(bContext *C, wmOperator *op)
Definition: lineart_ops.c:369
static bool lineart_gpencil_bake_single_target(LineartBakeJob *bj, Object *ob, int frame)
Definition: lineart_ops.c:175
static void lineart_gpencil_bake_startjob(void *customdata, short *stop, short *do_update, float *progress)
Definition: lineart_ops.c:224
static bool bake_strokes(Object *ob, Depsgraph *dg, LineartCache **lc, GpencilModifierData *md, int frame, bool is_first)
Definition: lineart_ops.c:76
static int lineart_gpencil_bake_common(bContext *C, wmOperator *op, bool bake_all_targets, bool do_background)
Definition: lineart_ops.c:282
void WM_operatortypes_lineart(void)
Definition: lineart_ops.c:477
static int lineart_gpencil_bake_strokes_all_exec(bContext *C, wmOperator *op)
Definition: lineart_ops.c:359
static int lineart_gpencil_bake_strokes_commom_modal(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: lineart_ops.c:373
static void lineart_gpencil_clear_strokes_exec_common(Object *ob)
Definition: lineart_ops.c:387
struct LineartBakeJob LineartBakeJob
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
#define G(x, y, z)
struct BMLoop * next
Definition: bmesh_class.h:233
bool(* isDisabled)(struct GpencilModifierData *md, int userRenderParams)
Definition: DNA_ID.h:368
LinkNode * objects
Definition: lineart_ops.c:164
Depsgraph * dg
Definition: lineart_ops.c:166
float * progress
Definition: lineart_ops.c:160
bool overwrite_frames
Definition: lineart_ops.c:172
wmWindowManager * wm
Definition: lineart_ops.c:157
bContext * C
Definition: lineart_ops.c:163
short * do_update
Definition: lineart_ops.c:159
ListBase greasepencil_modifiers
void * data
struct RenderData r
struct LineartCache * lineart_cache
bGPdata_Runtime runtime
Definition: wm_jobs.c:57
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:919
const char * name
Definition: WM_types.h:888
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:935
const char * idname
Definition: WM_types.h:890
const char * description
Definition: WM_types.h:893
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
struct ReportList * reports
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_main_add_notifier(unsigned int type, void *reference)
void WM_report(eReportType type, const char *message)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
void WM_set_locked_interface(wmWindowManager *wm, bool lock)
wmOperatorType * ot
Definition: wm_files.c:3479
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition: wm_jobs.c:437
void WM_jobs_callbacks(wmJob *wm_job, wm_jobs_start_callback startjob, void(*initjob)(void *), void(*update)(void *), void(*endjob)(void *))
Definition: wm_jobs.c:351
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
Definition: wm_jobs.c:214
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *))
Definition: wm_jobs.c:323
void WM_jobs_timer(wmJob *wm_job, double timestep, unsigned int note, unsigned int endnote)
Definition: wm_jobs.c:339
wmJob * WM_jobs_get(wmWindowManager *wm, wmWindow *win, const void *owner, const char *name, int flag, int job_type)
Definition: wm_jobs.c:184
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))