Blender  V2.93
MOD_gpencilbuild.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) 2017, Blender Foundation
17  * This is a new part of Blender
18  */
19 
24 #include <stdio.h>
25 
26 #include "MEM_guardedalloc.h"
27 
28 #include "BLI_utildefines.h"
29 
30 #include "BLI_blenlib.h"
31 #include "BLI_math.h"
32 
33 #include "BLT_translation.h"
34 
35 #include "DNA_defaults.h"
37 #include "DNA_gpencil_types.h"
38 #include "DNA_meshdata_types.h"
39 #include "DNA_object_types.h"
40 #include "DNA_scene_types.h"
41 #include "DNA_screen_types.h"
42 
43 #include "BKE_context.h"
44 #include "BKE_gpencil.h"
45 #include "BKE_gpencil_geom.h"
46 #include "BKE_gpencil_modifier.h"
47 #include "BKE_screen.h"
48 
49 #include "UI_interface.h"
50 #include "UI_resources.h"
51 
52 #include "RNA_access.h"
53 
54 #include "DEG_depsgraph.h"
55 #include "DEG_depsgraph_query.h"
56 
58 #include "MOD_gpencil_ui_common.h"
59 
60 static void initData(GpencilModifierData *md)
61 {
63 
64  BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(gpmd, modifier));
65 
67 }
68 
69 static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
70 {
72 }
73 
75 {
76  return true;
77 }
78 
79 /* ******************************************** */
80 /* Build Modifier - Stroke generation logic
81  *
82  * There are two modes for how the strokes are sequenced (at a macro-level):
83  * - Sequential Mode - Strokes appear/disappear one after the other. Only a single one changes at a
84  * time.
85  * - Concurrent Mode - Multiple strokes appear/disappear at once.
86  *
87  * Assumptions:
88  * - Stroke points are generally equally spaced. This implies that we can just add/remove points,
89  * without worrying about distances between them / adding extra interpolated points between
90  * an visible point and one about to be added/removed (or any similar tapering effects).
91  *
92  * - All strokes present are fully visible (i.e. we don't have to ignore any)
93  */
94 
95 /* Remove a particular stroke */
96 static void clear_stroke(bGPDframe *gpf, bGPDstroke *gps)
97 {
98  BLI_remlink(&gpf->strokes, gps);
100 }
101 
102 /* Clear all strokes in frame */
104 {
105  bGPDstroke *gps, *gps_next;
106  for (gps = gpf->strokes.first; gps; gps = gps_next) {
107  gps_next = gps->next;
108  clear_stroke(gpf, gps);
109  }
111 }
112 
113 /* Reduce the number of points in the stroke
114  *
115  * Note: This won't be called if all points are present/removed
116  */
117 static void reduce_stroke_points(bGPdata *gpd,
118  bGPDstroke *gps,
119  const int num_points,
120  const eBuildGpencil_Transition transition)
121 {
122  bGPDspoint *new_points = MEM_callocN(sizeof(bGPDspoint) * num_points, __func__);
123  MDeformVert *new_dvert = NULL;
124  if ((gps->dvert != NULL) && (num_points > 0)) {
125  new_dvert = MEM_callocN(sizeof(MDeformVert) * num_points, __func__);
126  }
127 
128  /* Which end should points be removed from */
129  switch (transition) {
130  case GP_BUILD_TRANSITION_GROW: /* Show in forward order =
131  * Remove ungrown-points from end of stroke. */
132  case GP_BUILD_TRANSITION_SHRINK: /* Hide in reverse order =
133  * Remove dead-points from end of stroke. */
134  {
135  /* copy over point data */
136  memcpy(new_points, gps->points, sizeof(bGPDspoint) * num_points);
137  if ((gps->dvert != NULL) && (num_points > 0)) {
138  memcpy(new_dvert, gps->dvert, sizeof(MDeformVert) * num_points);
139 
140  /* free unused point weights */
141  for (int i = num_points; i < gps->totpoints; i++) {
142  MDeformVert *dvert = &gps->dvert[i];
144  }
145  }
146  break;
147  }
148 
149  /* Hide in forward order = Remove points from start of stroke */
151  /* num_points is the number of points left after reducing.
152  * We need to know how many to remove
153  */
154  const int offset = gps->totpoints - num_points;
155 
156  /* copy over point data */
157  memcpy(new_points, gps->points + offset, sizeof(bGPDspoint) * num_points);
158  if ((gps->dvert != NULL) && (num_points > 0)) {
159  memcpy(new_dvert, gps->dvert + offset, sizeof(MDeformVert) * num_points);
160 
161  /* free unused weights */
162  for (int i = 0; i < offset; i++) {
163  MDeformVert *dvert = &gps->dvert[i];
165  }
166  }
167  break;
168  }
169 
170  default:
171  printf("ERROR: Unknown transition %d in %s()\n", (int)transition, __func__);
172  break;
173  }
174 
175  /* replace stroke geometry */
176  MEM_SAFE_FREE(gps->points);
177  MEM_SAFE_FREE(gps->dvert);
178  gps->points = new_points;
179  gps->dvert = new_dvert;
180  gps->totpoints = num_points;
181 
182  /* Calc geometry data. */
184 }
185 
186 /* --------------------------------------------- */
187 
188 /* Stroke Data Table Entry - This represents one stroke being generated */
189 typedef struct tStrokeBuildDetails {
191 
192  /* Indices - first/last indices for the stroke's points (overall) */
194 
195  /* Number of points - Cache for more convenient access */
198 
199 /* Sequential - Show strokes one after the other */
201  bGPdata *gpd,
202  bGPDframe *gpf,
203  float fac)
204 {
205  const size_t tot_strokes = BLI_listbase_count(&gpf->strokes);
206  bGPDstroke *gps;
207  size_t i;
208 
209  /* 1) Compute proportion of time each stroke should occupy */
210  /* NOTE: This assumes that the total number of points won't overflow! */
211  tStrokeBuildDetails *table = MEM_callocN(sizeof(tStrokeBuildDetails) * tot_strokes, __func__);
212  size_t totpoints = 0;
213 
214  /* 1.1) First pass - Tally up points */
215  for (gps = gpf->strokes.first, i = 0; gps; gps = gps->next, i++) {
216  tStrokeBuildDetails *cell = &table[i];
217 
218  cell->gps = gps;
219  cell->totpoints = gps->totpoints;
220 
221  totpoints += cell->totpoints;
222  }
223 
224  /* 1.2) Second pass - Compute the overall indices for points */
225  for (i = 0; i < tot_strokes; i++) {
226  tStrokeBuildDetails *cell = &table[i];
227 
228  if (i == 0) {
229  cell->start_idx = 0;
230  }
231  else {
232  cell->start_idx = (cell - 1)->end_idx;
233  }
234  cell->end_idx = cell->start_idx + cell->totpoints - 1;
235  }
236 
237  /* 2) Determine the global indices for points that should be visible */
238  size_t first_visible = 0;
239  size_t last_visible = 0;
240 
241  switch (mmd->transition) {
242  /* Show in forward order
243  * - As fac increases, the number of visible points increases
244  */
246  first_visible = 0; /* always visible */
247  last_visible = (size_t)roundf(totpoints * fac);
248  break;
249 
250  /* Hide in reverse order
251  * - As fac increases, the number of points visible at the end decreases
252  */
254  first_visible = 0; /* always visible (until last point removed) */
255  last_visible = (size_t)(totpoints * (1.0f - fac));
256  break;
257 
258  /* Hide in forward order
259  * - As fac increases, the early points start getting hidden
260  */
262  first_visible = (size_t)(totpoints * fac);
263  last_visible = totpoints; /* i.e. visible until the end, unless first overlaps this */
264  break;
265  }
266 
267  /* 3) Go through all strokes, deciding which to keep, and/or how much of each to keep */
268  for (i = 0; i < tot_strokes; i++) {
269  tStrokeBuildDetails *cell = &table[i];
270 
271  /* Determine what portion of the stroke is visible */
272  if ((cell->end_idx < first_visible) || (cell->start_idx > last_visible)) {
273  /* Not visible at all - Either ended before */
274  clear_stroke(gpf, cell->gps);
275  }
276  else {
277  /* Some proportion of stroke is visible */
278  if ((first_visible <= cell->start_idx) && (last_visible >= cell->end_idx)) {
279  /* Do nothing - whole stroke is visible */
280  }
281  else if (first_visible > cell->start_idx) {
282  /* Starts partway through this stroke */
283  int num_points = cell->end_idx - first_visible;
284  reduce_stroke_points(gpd, cell->gps, num_points, mmd->transition);
285  }
286  else {
287  /* Ends partway through this stroke */
288  int num_points = last_visible - cell->start_idx;
289  reduce_stroke_points(gpd, cell->gps, num_points, mmd->transition);
290  }
291  }
292  }
293 
294  /* Free table */
295  MEM_freeN(table);
296 }
297 
298 /* --------------------------------------------- */
299 
300 /* Concurrent - Show multiple strokes at once */
302  bGPdata *gpd,
303  bGPDframe *gpf,
304  float fac)
305 {
306  bGPDstroke *gps, *gps_next;
307  int max_points = 0;
308 
309  const bool reverse = (mmd->transition != GP_BUILD_TRANSITION_GROW);
310 
311  /* 1) Determine the longest stroke, to figure out when short strokes should start */
312  /* FIXME: A *really* long stroke here could dwarf everything else, causing bad timings */
313  for (gps = gpf->strokes.first; gps; gps = gps->next) {
314  if (gps->totpoints > max_points) {
315  max_points = gps->totpoints;
316  }
317  }
318  if (max_points == 0) {
319  printf("ERROR: Strokes are all empty (GP Build Modifier: %s)\n", __func__);
320  return;
321  }
322 
323  /* 2) For each stroke, determine how it should be handled */
324  for (gps = gpf->strokes.first; gps; gps = gps_next) {
325  gps_next = gps->next;
326 
327  /* Relative Length of Stroke - Relative to the longest stroke,
328  * what proportion of the available time should this stroke use
329  */
330  const float relative_len = (float)gps->totpoints / (float)max_points;
331 
332  /* Determine how many points should be left in the stroke */
333  int num_points = 0;
334 
335  switch (mmd->time_alignment) {
336  case GP_BUILD_TIMEALIGN_START: /* all start on frame 1 */
337  {
338  /* Build effect occurs over when fac = 0, to fac = relative_len */
339  if (fac <= relative_len) {
340  /* Scale fac to fit relative_len */
341  const float scaled_fac = fac / MAX2(relative_len, PSEUDOINVERSE_EPSILON);
342 
343  if (reverse) {
344  num_points = (int)roundf((1.0f - scaled_fac) * gps->totpoints);
345  }
346  else {
347  num_points = (int)roundf(scaled_fac * gps->totpoints);
348  }
349  }
350  else {
351  /* Build effect has ended */
352  if (reverse) {
353  num_points = 0;
354  }
355  else {
356  num_points = gps->totpoints;
357  }
358  }
359 
360  break;
361  }
362  case GP_BUILD_TIMEALIGN_END: /* all end on same frame */
363  {
364  /* Build effect occurs over 1.0 - relative_len, to 1.0 (i.e. over the end of the range)
365  */
366  const float start_fac = 1.0f - relative_len;
367 
368  if (fac >= start_fac) {
369  const float scaled_fac = (fac - start_fac) / MAX2(relative_len, PSEUDOINVERSE_EPSILON);
370 
371  if (reverse) {
372  num_points = (int)roundf((1.0f - scaled_fac) * gps->totpoints);
373  }
374  else {
375  num_points = (int)roundf(scaled_fac * gps->totpoints);
376  }
377  }
378  else {
379  /* Build effect hasn't started */
380  if (reverse) {
381  num_points = gps->totpoints;
382  }
383  else {
384  num_points = 0;
385  }
386  }
387 
388  break;
389  }
390  }
391 
392  /* Modify the stroke geometry */
393  if (num_points <= 0) {
394  /* Nothing Left - Delete the stroke */
395  clear_stroke(gpf, gps);
396  }
397  else if (num_points < gps->totpoints) {
398  /* Remove some points */
399  reduce_stroke_points(gpd, gps, num_points, mmd->transition);
400  }
401  }
402 }
403 
404 /* --------------------------------------------- */
405 static void generate_geometry(
407 {
409  const bool reverse = (mmd->transition != GP_BUILD_TRANSITION_GROW);
410  const bool is_percentage = (mmd->flag & GP_BUILD_PERCENTAGE);
411 
412  const float ctime = DEG_get_ctime(depsgraph);
413 
414  /* Early exit if it's an empty frame */
415  if (gpf->strokes.first == NULL) {
416  return;
417  }
418 
419  /* Omit layer if filter by layer */
420  if (mmd->layername[0] != '\0') {
421  if ((mmd->flag & GP_BUILD_INVERT_LAYER) == 0) {
422  if (!STREQ(mmd->layername, gpl->info)) {
423  return;
424  }
425  }
426  else {
427  if (STREQ(mmd->layername, gpl->info)) {
428  return;
429  }
430  }
431  }
432  /* verify layer pass */
433  if (mmd->layer_pass > 0) {
434  if ((mmd->flag & GP_BUILD_INVERT_LAYERPASS) == 0) {
435  if (gpl->pass_index != mmd->layer_pass) {
436  return;
437  }
438  }
439  else {
440  if (gpl->pass_index == mmd->layer_pass) {
441  return;
442  }
443  }
444  }
445 
446  /* Early exit if outside of the frame range for this modifier
447  * (e.g. to have one forward, and one backwards modifier)
448  */
449  if (mmd->flag & GP_BUILD_RESTRICT_TIME) {
450  if ((ctime < mmd->start_frame) || (ctime > mmd->end_frame)) {
451  return;
452  }
453  }
454 
455  /* Compute start and end frames for the animation effect
456  * By default, the upper bound is given by the "maximum length" setting
457  */
458  float start_frame = gpf->framenum + mmd->start_delay;
459  float end_frame = start_frame + mmd->length;
460 
461  if (gpf->next) {
462  /* Use the next frame or upper bound as end frame, whichever is lower/closer */
463  end_frame = MIN2(end_frame, gpf->next->framenum);
464  }
465 
466  /* Early exit if current frame is outside start/end bounds */
467  /* NOTE: If we're beyond the next/previous frames (if existent),
468  * then we wouldn't have this problem anyway... */
469  if (ctime < start_frame) {
470  /* Before Start - Animation hasn't started. Display initial state. */
471  if (reverse) {
472  /* 1) Reverse = Start with all, end with nothing.
473  * ==> Do nothing (everything already present)
474  */
475  }
476  else {
477  /* 2) Forward Order = Start with nothing, end with the full frame.
478  * ==> Free all strokes, and return an empty frame
479  */
481  }
482 
483  /* Early exit */
484  return;
485  }
486  if (ctime >= end_frame) {
487  /* Past End - Animation finished. Display final result. */
488  if (reverse) {
489  /* 1) Reverse = Start with all, end with nothing.
490  * ==> Free all strokes, and return an empty frame
491  */
493  }
494  else {
495  /* 2) Forward Order = Start with nothing, end with the full frame.
496  * ==> Do Nothing (everything already present)
497  */
498  }
499 
500  /* Early exit */
501  return;
502  }
503 
504  /* Determine how far along we are between the keyframes */
505  float fac = is_percentage ? mmd->percentage_fac :
506  (ctime - start_frame) / (end_frame - start_frame);
507 
508  /* Time management mode */
509  switch (mmd->mode) {
511  build_sequential(mmd, gpd, gpf, fac);
512  break;
513 
515  build_concurrent(mmd, gpd, gpf, fac);
516  break;
517 
518  default:
519  printf("Unsupported build mode (%d) for GP Build Modifier: '%s'\n",
520  mmd->mode,
521  mmd->modifier.name);
522  break;
523  }
524 }
525 
526 /* Entry-point for Build Modifier */
528 {
530  bGPdata *gpd = (bGPdata *)ob->data;
531 
532  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
534  if (gpf == NULL) {
535  continue;
536  }
537  generate_geometry(md, depsgraph, gpd, gpl, gpf);
538  }
539 }
540 
541 static void panel_draw(const bContext *UNUSED(C), Panel *panel)
542 {
543  uiLayout *row, *sub;
544  uiLayout *layout = panel->layout;
545 
546  PointerRNA ob_ptr;
548 
549  int mode = RNA_enum_get(ptr, "mode");
550 
551  uiLayoutSetPropSep(layout, true);
552 
553  uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
554  if (mode == GP_BUILD_MODE_CONCURRENT) {
555  uiItemR(layout, ptr, "concurrent_time_alignment", 0, NULL, ICON_NONE);
556  }
557 
558  uiItemS(layout);
559 
560  uiItemR(layout, ptr, "transition", 0, NULL, ICON_NONE);
561  uiItemR(layout, ptr, "start_delay", 0, NULL, ICON_NONE);
562  uiItemR(layout, ptr, "length", 0, IFACE_("Frames"), ICON_NONE);
563 
564  uiItemS(layout);
565 
566  row = uiLayoutRowWithHeading(layout, true, IFACE_("Use Factor"));
567  uiLayoutSetPropDecorate(row, false);
568  uiItemR(row, ptr, "use_percentage", 0, "", ICON_NONE);
569  sub = uiLayoutRow(row, true);
570  uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_percentage"));
571  uiItemR(sub, ptr, "percentage_factor", 0, "", ICON_NONE);
572  uiItemDecoratorR(row, ptr, "percentage_factor", 0);
573 
574  /* Check for incompatible time modifier. */
575  Object *ob = ob_ptr.data;
578  BKE_gpencil_modifier_set_error(md, "Build and Time Offset modifiers are incompatible");
579  }
580 
582 }
583 
584 static void frame_range_header_draw(const bContext *UNUSED(C), Panel *panel)
585 {
586  uiLayout *layout = panel->layout;
587 
589 
590  uiItemR(layout, ptr, "use_restrict_frame_range", 0, IFACE_("Custom Range"), ICON_NONE);
591 }
592 
593 static void frame_range_panel_draw(const bContext *UNUSED(C), Panel *panel)
594 {
595  uiLayout *col;
596  uiLayout *layout = panel->layout;
597 
599 
600  uiLayoutSetPropSep(layout, true);
601 
602  col = uiLayoutColumn(layout, false);
603  uiItemR(col, ptr, "frame_start", 0, IFACE_("Start"), ICON_NONE);
604  uiItemR(col, ptr, "frame_end", 0, IFACE_("End"), ICON_NONE);
605 }
606 
607 static void mask_panel_draw(const bContext *UNUSED(C), Panel *panel)
608 {
609  gpencil_modifier_masking_panel_draw(panel, false, false);
610 }
611 
612 static void panelRegister(ARegionType *region_type)
613 {
615  region_type, eGpencilModifierType_Build, panel_draw);
617  region_type, "frame_range", "", frame_range_header_draw, frame_range_panel_draw, panel_type);
619  region_type, "_mask", "Influence", NULL, mask_panel_draw, panel_type);
620 }
621 
622 /* ******************************************** */
623 
625  /* name */ "Build",
626  /* structName */ "BuildGpencilModifierData",
627  /* structSize */ sizeof(BuildGpencilModifierData),
630 
631  /* copyData */ copyData,
632 
633  /* deformStroke */ NULL,
634  /* generateStrokes */ generateStrokes,
635  /* bakeModifier */ NULL,
636  /* remapTime */ NULL,
637 
638  /* initData */ initData,
639  /* freeData */ NULL,
640  /* isDisabled */ NULL,
641  /* updateDepsgraph */ NULL,
642  /* dependsOnTime */ dependsOnTime,
643  /* foreachIDLink */ NULL,
644  /* foreachTexLink */ NULL,
645  /* panelRegister */ panelRegister,
646 };
typedef float(TangentPoint)[2]
void BKE_gpencil_free_point_weights(struct MDeformVert *dvert)
Definition: gpencil.c:362
void BKE_gpencil_free_stroke(struct bGPDstroke *gps)
Definition: gpencil.c:401
void BKE_gpencil_stroke_geometry_update(struct bGPdata *gpd, struct bGPDstroke *gps)
void BKE_gpencil_modifier_copydata_generic(const struct GpencilModifierData *md_src, struct GpencilModifierData *md_dst)
void BKE_gpencil_modifier_set_error(struct GpencilModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(2
@ eGpencilModifierTypeFlag_NoApply
struct bGPDframe * BKE_gpencil_frame_retime_get(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct bGPDlayer *gpl)
@ eGpencilModifierTypeType_Gpencil
struct GpencilModifierData * BKE_gpencil_modifiers_findby_type(struct Object *ob, GpencilModifierType type)
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:128
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:133
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define PSEUDOINVERSE_EPSILON
#define UNUSED(x)
#define MAX2(a, b)
#define MIN2(a, b)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define STREQ(a, b)
#define IFACE_(msgid)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:51
float DEG_get_ctime(const Depsgraph *graph)
struct Scene * DEG_get_evaluated_scene(const struct Depsgraph *graph)
#define DNA_struct_default_get(struct_name)
Definition: DNA_defaults.h:44
struct BuildGpencilModifierData BuildGpencilModifierData
@ GP_BUILD_TRANSITION_FADE
@ GP_BUILD_TRANSITION_SHRINK
@ GP_BUILD_TRANSITION_GROW
@ GP_BUILD_MODE_SEQUENTIAL
@ GP_BUILD_MODE_CONCURRENT
@ GP_BUILD_TIMEALIGN_START
@ GP_BUILD_TIMEALIGN_END
@ GP_BUILD_RESTRICT_TIME
@ GP_BUILD_INVERT_LAYERPASS
@ eGpencilModifierType_Time
@ eGpencilModifierType_Build
Object is a sort of wrapper for general info.
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
PointerRNA * gpencil_modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void gpencil_modifier_masking_panel_draw(Panel *panel, bool use_material, bool use_vertex)
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 frame_range_header_draw(const bContext *UNUSED(C), Panel *panel)
static void generate_geometry(GpencilModifierData *md, Depsgraph *depsgraph, bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf)
static bool dependsOnTime(GpencilModifierData *UNUSED(md))
static void reduce_stroke_points(bGPdata *gpd, bGPDstroke *gps, const int num_points, const eBuildGpencil_Transition transition)
static void frame_range_panel_draw(const bContext *UNUSED(C), Panel *panel)
struct tStrokeBuildDetails tStrokeBuildDetails
static void mask_panel_draw(const bContext *UNUSED(C), Panel *panel)
static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
static void build_sequential(BuildGpencilModifierData *mmd, bGPdata *gpd, bGPDframe *gpf, float fac)
static void clear_stroke(bGPDframe *gpf, bGPDstroke *gps)
static void panelRegister(ARegionType *region_type)
static void build_concurrent(BuildGpencilModifierData *mmd, bGPdata *gpd, bGPDframe *gpf, float fac)
static void gpf_clear_all_strokes(bGPDframe *gpf)
static void initData(GpencilModifierData *md)
static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Object *ob)
GpencilModifierTypeInfo modifierType_Gpencil_Build
#define C
Definition: RandGen.cpp:39
uiLayout * uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading)
void uiLayoutSetActive(uiLayout *layout, bool active)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemS(uiLayout *layout)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
void uiItemDecoratorR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int index)
Scene scene
const Depsgraph * depsgraph
uint col
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
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
void * first
Definition: DNA_listBase.h:47
void * data
struct uiLayout * layout
void * data
Definition: RNA_types.h:52
struct bGPDframe * next
ListBase strokes
char info[128]
bGPDspoint * points
struct MDeformVert * dvert
struct bGPDstroke * next
ListBase layers
PointerRNA * ptr
Definition: wm_files.c:3157