Blender  V3.3
MOD_gpencilmultiply.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 "MEM_guardedalloc.h"
11 
12 #include "DNA_defaults.h"
14 #include "DNA_gpencil_types.h"
15 #include "DNA_object_types.h"
16 #include "DNA_scene_types.h"
17 #include "DNA_screen_types.h"
18 
19 #include "BLI_listbase.h"
20 #include "BLI_math_vector.h"
21 #include "BLI_utildefines.h"
22 
23 #include "BLT_translation.h"
24 
25 #include "BKE_context.h"
26 #include "BKE_gpencil.h"
27 #include "BKE_gpencil_geom.h"
28 #include "BKE_gpencil_modifier.h"
29 #include "BKE_lib_query.h"
30 #include "BKE_main.h"
31 #include "BKE_modifier.h"
32 #include "BKE_screen.h"
33 
34 #include "DEG_depsgraph.h"
35 #include "DEG_depsgraph_build.h"
36 #include "DEG_depsgraph_query.h"
37 
38 #include "UI_interface.h"
39 #include "UI_resources.h"
40 
41 #include "RNA_access.h"
42 
44 #include "MOD_gpencil_ui_common.h"
45 #include "MOD_gpencil_util.h"
46 
47 static void initData(GpencilModifierData *md)
48 {
50 
51  BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(gpmd, modifier));
52 
54 }
55 
56 static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
57 {
59 }
60 
62  float *result, float *prev, float *curr, float *next, float *stroke_normal)
63 {
64  float vec[3], inter1[3], inter2[3];
65  ARRAY_SET_ITEMS(inter1, 0.0f, 0.0f, 0.0f);
66  ARRAY_SET_ITEMS(inter2, 0.0f, 0.0f, 0.0f);
67 
68  float minter[3];
69  if (prev) {
70  sub_v3_v3v3(vec, curr, prev);
71  cross_v3_v3v3(inter1, stroke_normal, vec);
72  }
73  if (next) {
74  sub_v3_v3v3(vec, next, curr);
75  cross_v3_v3v3(inter2, stroke_normal, vec);
76  }
77  if (!prev) {
78  normalize_v3(inter2);
79  copy_v3_v3(result, inter2);
80  return;
81  }
82  if (!next) {
83  normalize_v3(inter1);
84  copy_v3_v3(result, inter1);
85  return;
86  }
87  interp_v3_v3v3(minter, inter1, inter2, 0.5);
88  normalize_v3(minter);
89  copy_v3_v3(result, minter);
90 }
91 
92 static void duplicateStroke(Object *ob,
93  bGPDstroke *gps,
94  int count,
95  float dist,
96  float offset,
97  ListBase *results,
98  int fading,
99  float fading_center,
100  float fading_thickness,
101  float fading_opacity)
102 {
103  bGPdata *gpd = ob->data;
104  int i;
105  bGPDstroke *new_gps = NULL;
106  float stroke_normal[3];
107  bGPDspoint *pt;
108  float thickness_factor;
109  float opacity_factor;
110 
111  /* Apply object scale to offset distance. */
112  offset *= mat4_to_scale(ob->obmat);
113 
114  BKE_gpencil_stroke_normal(gps, stroke_normal);
115  if (len_v3(stroke_normal) < FLT_EPSILON) {
116  add_v3_fl(stroke_normal, 1);
117  normalize_v3(stroke_normal);
118  }
119 
120  float *t1_array = MEM_callocN(sizeof(float[3]) * gps->totpoints,
121  "duplicate_temp_result_array_1");
122  float *t2_array = MEM_callocN(sizeof(float[3]) * gps->totpoints,
123  "duplicate_temp_result_array_2");
124 
125  pt = gps->points;
126 
127  for (int j = 0; j < gps->totpoints; j++) {
128  float minter[3];
129  if (j == 0) {
130  minter_v3_v3v3v3_ref(minter, NULL, &pt[j].x, &pt[j + 1].x, stroke_normal);
131  }
132  else if (j == gps->totpoints - 1) {
133  minter_v3_v3v3v3_ref(minter, &pt[j - 1].x, &pt[j].x, NULL, stroke_normal);
134  }
135  else {
136  minter_v3_v3v3v3_ref(minter, &pt[j - 1].x, &pt[j].x, &pt[j + 1].x, stroke_normal);
137  }
138  mul_v3_fl(minter, dist);
139  add_v3_v3v3(&t1_array[j * 3], &pt[j].x, minter);
140  sub_v3_v3v3(&t2_array[j * 3], &pt[j].x, minter);
141  }
142 
143  /* This ensures the original stroke is the last one
144  * to be processed, since we duplicate its data. */
145  for (i = count - 1; i >= 0; i--) {
146  if (i != 0) {
147  new_gps = BKE_gpencil_stroke_duplicate(gps, true, true);
148  BLI_addtail(results, new_gps);
149  }
150  else {
151  new_gps = gps;
152  }
153 
154  pt = new_gps->points;
155 
156  float offset_fac = (count == 1) ? 0.5f : (i / (float)(count - 1));
157 
158  if (fading) {
159  thickness_factor = interpf(1.0f - fading_thickness, 1.0f, fabsf(offset_fac - fading_center));
160  opacity_factor = interpf(1.0f - fading_opacity, 1.0f, fabsf(offset_fac - fading_center));
161  }
162 
163  for (int j = 0; j < new_gps->totpoints; j++) {
164  float fac = interpf(1 + offset, offset, offset_fac);
165  interp_v3_v3v3(&pt[j].x, &t1_array[j * 3], &t2_array[j * 3], fac);
166  if (fading) {
167  pt[j].pressure = gps->points[j].pressure * thickness_factor;
168  pt[j].strength = gps->points[j].strength * opacity_factor;
169  }
170  }
171  }
172  /* Calc geometry data. */
173  if (new_gps != NULL) {
175  }
176  MEM_freeN(t1_array);
177  MEM_freeN(t2_array);
178 }
179 
180 /* -------------------------------- */
182 {
184  bGPDstroke *gps;
185  ListBase duplicates = {0};
186  for (gps = gpf->strokes.first; gps; gps = gps->next) {
188  mmd->layername,
189  mmd->material,
190  mmd->pass_index,
191  mmd->layer_pass,
192  1,
193  gpl,
194  gps,
199  continue;
200  }
201  if (mmd->duplications > 0) {
202  duplicateStroke(ob,
203  gps,
204  mmd->duplications,
205  mmd->distance,
206  mmd->offset,
207  &duplicates,
209  mmd->fading_center,
210  mmd->fading_thickness,
211  mmd->fading_opacity);
212  }
213  }
214  if (!BLI_listbase_is_empty(&duplicates)) {
215  BLI_movelisttolist(&gpf->strokes, &duplicates);
216  }
217 }
218 
219 static void bakeModifier(Main *UNUSED(bmain),
222  Object *ob)
223 {
224  bGPdata *gpd = ob->data;
225 
226  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
227  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
228  generate_geometry(md, ob, gpl, gpf);
229  }
230  }
231 }
232 
233 /* Generic "generateStrokes" callback */
235 {
237  bGPdata *gpd = (bGPdata *)ob->data;
238 
239  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
241  if (gpf == NULL) {
242  continue;
243  }
244  generate_geometry(md, ob, gpl, gpf);
245  }
246 }
247 
248 static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
249 {
251 
252  walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
253 }
254 
255 static void panel_draw(const bContext *UNUSED(C), Panel *panel)
256 {
257  uiLayout *col;
258  uiLayout *layout = panel->layout;
259 
261 
262  uiLayoutSetPropSep(layout, true);
263 
264  uiItemR(layout, ptr, "duplicates", 0, NULL, ICON_NONE);
265 
266  col = uiLayoutColumn(layout, false);
267  uiLayoutSetActive(layout, RNA_int_get(ptr, "duplicates") > 0);
268  uiItemR(col, ptr, "distance", 0, NULL, ICON_NONE);
269  uiItemR(col, ptr, "offset", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
270 
272 }
273 
274 static void fade_header_draw(const bContext *UNUSED(C), Panel *panel)
275 {
276  uiLayout *layout = panel->layout;
277 
279 
280  uiItemR(layout, ptr, "use_fade", 0, NULL, ICON_NONE);
281 }
282 
283 static void fade_panel_draw(const bContext *UNUSED(C), Panel *panel)
284 {
285  uiLayout *col;
286  uiLayout *layout = panel->layout;
287 
289 
290  uiLayoutSetPropSep(layout, true);
291 
292  uiLayoutSetActive(layout, RNA_boolean_get(ptr, "use_fade"));
293 
294  col = uiLayoutColumn(layout, false);
295  uiItemR(col, ptr, "fading_center", 0, NULL, ICON_NONE);
296  uiItemR(col, ptr, "fading_thickness", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
297  uiItemR(col, ptr, "fading_opacity", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
298 }
299 
300 static void mask_panel_draw(const bContext *UNUSED(C), Panel *panel)
301 {
302  gpencil_modifier_masking_panel_draw(panel, true, false);
303 }
304 
305 static void panelRegister(ARegionType *region_type)
306 {
310  region_type, "fade", "", fade_header_draw, fade_panel_draw, panel_type);
312  region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type);
313 }
314 
316  /* name */ N_("MultipleStrokes"),
317  /* structName */ "MultiplyGpencilModifierData",
318  /* structSize */ sizeof(MultiplyGpencilModifierData),
320  /* flags */ 0,
321 
322  /* copyData */ copyData,
323 
324  /* deformStroke */ NULL,
325  /* generateStrokes */ generateStrokes,
326  /* bakeModifier */ bakeModifier,
327  /* remapTime */ NULL,
328 
329  /* initData */ initData,
330  /* freeData */ NULL,
331  /* isDisabled */ NULL,
332  /* updateDepsgraph */ NULL,
333  /* dependsOnTime */ NULL,
334  /* foreachIDLink */ foreachIDLink,
335  /* foreachTexLink */ NULL,
336  /* panelRegister */ panelRegister,
337 };
struct bGPDstroke * BKE_gpencil_stroke_duplicate(struct bGPDstroke *gps_src, bool dup_points, bool dup_curve)
Definition: gpencil.c:855
void BKE_gpencil_stroke_normal(const struct bGPDstroke *gps, float r_normal[3])
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)
struct bGPDframe * BKE_gpencil_frame_retime_get(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct bGPDlayer *gpl)
@ eGpencilModifierTypeType_Gpencil
@ IDWALK_CB_USER
Definition: BKE_lib_query.h:73
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
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:269
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
void void void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
MINLINE float interpf(float a, float b, float t)
float mat4_to_scale(const float M[4][4])
Definition: math_matrix.c:2185
MINLINE void add_v3_fl(float r[3], float f)
MINLINE float normalize_v3(float r[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
Definition: math_vector.c:29
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
#define ARRAY_SET_ITEMS(...)
#define UNUSED(x)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
struct Scene * DEG_get_evaluated_scene(const struct Depsgraph *graph)
#define DNA_struct_default_get(struct_name)
Definition: DNA_defaults.h:29
@ GP_MULTIPLY_ENABLE_FADING
@ GP_MIRROR_INVERT_MATERIAL
@ GP_MIRROR_INVERT_LAYER
@ GP_MIRROR_INVERT_LAYERPASS
struct MultiplyGpencilModifierData MultiplyGpencilModifierData
@ eGpencilModifierType_Multiply
Object is a sort of wrapper for general info.
Read Guarded memory(de)allocation.
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)
bool is_stroke_affected_by_modifier(Object *ob, char *mlayername, Material *material, const int mpassindex, const int gpl_passindex, const int minpoints, bGPDlayer *gpl, bGPDstroke *gps, const bool inv1, const bool inv2, const bool inv3, const bool inv4)
static void fade_panel_draw(const bContext *UNUSED(C), Panel *panel)
static void duplicateStroke(Object *ob, bGPDstroke *gps, int count, float dist, float offset, ListBase *results, int fading, float fading_center, float fading_thickness, float fading_opacity)
GpencilModifierTypeInfo modifierType_Gpencil_Multiply
static void minter_v3_v3v3v3_ref(float *result, float *prev, float *curr, float *next, float *stroke_normal)
static void mask_panel_draw(const bContext *UNUSED(C), Panel *panel)
static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
static void generate_geometry(GpencilModifierData *md, Object *ob, bGPDlayer *gpl, bGPDframe *gpf)
static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
static void bakeModifier(Main *UNUSED(bmain), Depsgraph *UNUSED(depsgraph), GpencilModifierData *md, Object *ob)
static void panelRegister(ARegionType *region_type)
static void initData(GpencilModifierData *md)
static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Object *ob)
static void fade_header_draw(const bContext *UNUSED(C), Panel *panel)
#define C
Definition: RandGen.cpp:25
void uiLayoutSetActive(uiLayout *layout, bool active)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
@ UI_ITEM_R_SLIDER
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
Scene scene
const Depsgraph * depsgraph
uint col
int count
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
static ulong * next
#define fabsf(x)
Definition: metal/compat.h:219
SymEdge< T > * prev(const SymEdge< T > *se)
Definition: delaunay_2d.cc:105
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4910
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
Definition: DNA_ID.h:368
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
float obmat[4][4]
void * data
struct uiLayout * layout
ListBase strokes
bGPDspoint * points
struct bGPDstroke * next
ListBase layers
#define N_(msgid)
PointerRNA * ptr
Definition: wm_files.c:3480