Blender  V2.93
MOD_gpencilmultiply.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 "DNA_defaults.h"
30 #include "DNA_gpencil_types.h"
31 #include "DNA_object_types.h"
32 #include "DNA_scene_types.h"
33 #include "DNA_screen_types.h"
34 
35 #include "BLI_blenlib.h"
36 #include "BLI_math.h"
37 #include "BLI_utildefines.h"
38 
39 #include "BKE_context.h"
40 #include "BKE_gpencil.h"
41 #include "BKE_gpencil_geom.h"
42 #include "BKE_gpencil_modifier.h"
43 #include "BKE_lib_query.h"
44 #include "BKE_main.h"
45 #include "BKE_modifier.h"
46 #include "BKE_screen.h"
47 
48 #include "DEG_depsgraph.h"
49 #include "DEG_depsgraph_build.h"
50 #include "DEG_depsgraph_query.h"
51 
52 #include "UI_interface.h"
53 #include "UI_resources.h"
54 
55 #include "RNA_access.h"
56 
58 #include "MOD_gpencil_ui_common.h"
59 #include "MOD_gpencil_util.h"
60 
61 static void initData(GpencilModifierData *md)
62 {
64 
65  BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(gpmd, modifier));
66 
68 }
69 
70 static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
71 {
73 }
74 
76  float *result, float *prev, float *curr, float *next, float *stroke_normal)
77 {
78  float vec[3], inter1[3], inter2[3];
79  ARRAY_SET_ITEMS(inter1, 0.0f, 0.0f, 0.0f);
80  ARRAY_SET_ITEMS(inter2, 0.0f, 0.0f, 0.0f);
81 
82  float minter[3];
83  if (prev) {
84  sub_v3_v3v3(vec, curr, prev);
85  cross_v3_v3v3(inter1, stroke_normal, vec);
86  }
87  if (next) {
88  sub_v3_v3v3(vec, next, curr);
89  cross_v3_v3v3(inter2, stroke_normal, vec);
90  }
91  if (!prev) {
92  normalize_v3(inter2);
93  copy_v3_v3(result, inter2);
94  return;
95  }
96  if (!next) {
97  normalize_v3(inter1);
98  copy_v3_v3(result, inter1);
99  return;
100  }
101  interp_v3_v3v3(minter, inter1, inter2, 0.5);
102  normalize_v3(minter);
103  copy_v3_v3(result, minter);
104 }
105 
106 static void duplicateStroke(Object *ob,
107  bGPDstroke *gps,
108  int count,
109  float dist,
110  float offset,
111  ListBase *results,
112  int fading,
113  float fading_center,
114  float fading_thickness,
115  float fading_opacity)
116 {
117  bGPdata *gpd = ob->data;
118  int i;
119  bGPDstroke *new_gps = NULL;
120  float stroke_normal[3];
121  bGPDspoint *pt;
122  float thickness_factor;
123  float opacity_factor;
124 
125  /* Apply object scale to offset distance. */
126  offset *= mat4_to_scale(ob->obmat);
127 
128  BKE_gpencil_stroke_normal(gps, stroke_normal);
129  if (len_v3(stroke_normal) < FLT_EPSILON) {
130  add_v3_fl(stroke_normal, 1);
131  normalize_v3(stroke_normal);
132  }
133 
134  float *t1_array = MEM_callocN(sizeof(float[3]) * gps->totpoints,
135  "duplicate_temp_result_array_1");
136  float *t2_array = MEM_callocN(sizeof(float[3]) * gps->totpoints,
137  "duplicate_temp_result_array_2");
138 
139  pt = gps->points;
140 
141  for (int j = 0; j < gps->totpoints; j++) {
142  float minter[3];
143  if (j == 0) {
144  minter_v3_v3v3v3_ref(minter, NULL, &pt[j].x, &pt[j + 1].x, stroke_normal);
145  }
146  else if (j == gps->totpoints - 1) {
147  minter_v3_v3v3v3_ref(minter, &pt[j - 1].x, &pt[j].x, NULL, stroke_normal);
148  }
149  else {
150  minter_v3_v3v3v3_ref(minter, &pt[j - 1].x, &pt[j].x, &pt[j + 1].x, stroke_normal);
151  }
152  mul_v3_fl(minter, dist);
153  add_v3_v3v3(&t1_array[j * 3], &pt[j].x, minter);
154  sub_v3_v3v3(&t2_array[j * 3], &pt[j].x, minter);
155  }
156 
157  /* This ensures the original stroke is the last one
158  * to be processed, since we duplicate its data. */
159  for (i = count - 1; i >= 0; i--) {
160  if (i != 0) {
161  new_gps = BKE_gpencil_stroke_duplicate(gps, true, true);
162  BLI_addtail(results, new_gps);
163  }
164  else {
165  new_gps = gps;
166  }
167 
168  pt = new_gps->points;
169 
170  float offset_fac = (count == 1) ? 0.5f : (i / (float)(count - 1));
171 
172  if (fading) {
173  thickness_factor = interpf(1.0f - fading_thickness, 1.0f, fabsf(offset_fac - fading_center));
174  opacity_factor = interpf(1.0f - fading_opacity, 1.0f, fabsf(offset_fac - fading_center));
175  }
176 
177  for (int j = 0; j < new_gps->totpoints; j++) {
178  float fac = interpf(1 + offset, offset, offset_fac);
179  interp_v3_v3v3(&pt[j].x, &t1_array[j * 3], &t2_array[j * 3], fac);
180  if (fading) {
181  pt[j].pressure = gps->points[j].pressure * thickness_factor;
182  pt[j].strength = gps->points[j].strength * opacity_factor;
183  }
184  }
185  }
186  /* Calc geometry data. */
187  if (new_gps != NULL) {
189  }
190  MEM_freeN(t1_array);
191  MEM_freeN(t2_array);
192 }
193 
194 static void bakeModifier(Main *UNUSED(bmain),
197  Object *ob)
198 {
199  bGPdata *gpd = ob->data;
200 
201  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
202  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
203  ListBase duplicates = {0};
205  bGPDstroke *gps;
206  for (gps = gpf->strokes.first; gps; gps = gps->next) {
208  mmd->layername,
209  mmd->material,
210  mmd->pass_index,
211  mmd->layer_pass,
212  1,
213  gpl,
214  gps,
219  continue;
220  }
221  if (mmd->duplications > 0) {
222  duplicateStroke(ob,
223  gps,
224  mmd->duplications,
225  mmd->distance,
226  mmd->offset,
227  &duplicates,
229  mmd->fading_center,
230  mmd->fading_thickness,
231  mmd->fading_opacity);
232  }
233  }
234  if (!BLI_listbase_is_empty(&duplicates)) {
235  BLI_movelisttolist(&gpf->strokes, &duplicates);
236  }
237  }
238  }
239 }
240 
241 /* -------------------------------- */
243 {
245  bGPDstroke *gps;
246  ListBase duplicates = {0};
247  for (gps = gpf->strokes.first; gps; gps = gps->next) {
249  mmd->layername,
250  mmd->material,
251  mmd->pass_index,
252  mmd->layer_pass,
253  1,
254  gpl,
255  gps,
260  continue;
261  }
262  if (mmd->duplications > 0) {
263  duplicateStroke(ob,
264  gps,
265  mmd->duplications,
266  mmd->distance,
267  mmd->offset,
268  &duplicates,
270  mmd->fading_center,
271  mmd->fading_thickness,
272  mmd->fading_opacity);
273  }
274  }
275  if (!BLI_listbase_is_empty(&duplicates)) {
276  BLI_movelisttolist(&gpf->strokes, &duplicates);
277  }
278 }
279 
280 /* Generic "generateStrokes" callback */
282 {
284  bGPdata *gpd = (bGPdata *)ob->data;
285 
286  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
288  if (gpf == NULL) {
289  continue;
290  }
291  generate_geometry(md, ob, gpl, gpf);
292  }
293 }
294 
295 static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
296 {
298 
299  walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
300 }
301 
302 static void panel_draw(const bContext *UNUSED(C), Panel *panel)
303 {
304  uiLayout *col;
305  uiLayout *layout = panel->layout;
306 
308 
309  uiLayoutSetPropSep(layout, true);
310 
311  uiItemR(layout, ptr, "duplicates", 0, NULL, ICON_NONE);
312 
313  col = uiLayoutColumn(layout, false);
314  uiLayoutSetActive(layout, RNA_int_get(ptr, "duplicates") > 0);
315  uiItemR(col, ptr, "distance", 0, NULL, ICON_NONE);
316  uiItemR(col, ptr, "offset", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
317 
319 }
320 
321 static void fade_header_draw(const bContext *UNUSED(C), Panel *panel)
322 {
323  uiLayout *layout = panel->layout;
324 
326 
327  uiItemR(layout, ptr, "use_fade", 0, NULL, ICON_NONE);
328 }
329 
330 static void fade_panel_draw(const bContext *UNUSED(C), Panel *panel)
331 {
332  uiLayout *col;
333  uiLayout *layout = panel->layout;
334 
336 
337  uiLayoutSetPropSep(layout, true);
338 
339  uiLayoutSetActive(layout, RNA_boolean_get(ptr, "use_fade"));
340 
341  col = uiLayoutColumn(layout, false);
342  uiItemR(col, ptr, "fading_center", 0, NULL, ICON_NONE);
343  uiItemR(col, ptr, "fading_thickness", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
344  uiItemR(col, ptr, "fading_opacity", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
345 }
346 
347 static void mask_panel_draw(const bContext *UNUSED(C), Panel *panel)
348 {
349  gpencil_modifier_masking_panel_draw(panel, true, false);
350 }
351 
352 static void panelRegister(ARegionType *region_type)
353 {
357  region_type, "fade", "", fade_header_draw, fade_panel_draw, panel_type);
359  region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type);
360 }
361 
363  /* name */ "MultipleStrokes",
364  /* structName */ "MultiplyGpencilModifierData",
365  /* structSize */ sizeof(MultiplyGpencilModifierData),
367  /* flags */ 0,
368 
369  /* copyData */ copyData,
370 
371  /* deformStroke */ NULL,
372  /* generateStrokes */ generateStrokes,
373  /* bakeModifier */ bakeModifier,
374  /* remapTime */ NULL,
375 
376  /* initData */ initData,
377  /* freeData */ NULL,
378  /* isDisabled */ NULL,
379  /* updateDepsgraph */ NULL,
380  /* dependsOnTime */ NULL,
381  /* foreachIDLink */ foreachIDLink,
382  /* foreachTexLink */ NULL,
383  /* panelRegister */ panelRegister,
384 };
struct bGPDstroke * BKE_gpencil_stroke_duplicate(struct bGPDstroke *gps_src, const bool dup_points, const bool dup_curve)
Definition: gpencil.c:957
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:87
void(* IDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag)
Definition: BKE_modifier.h:120
#define BLI_assert(a)
Definition: BLI_assert.h:58
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:124
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
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:110
MINLINE float interpf(float a, float b, float t)
float mat4_to_scale(const float M[4][4])
Definition: math_matrix.c:2196
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], const float t)
Definition: math_vector.c:49
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])
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:51
struct Scene * DEG_get_evaluated_scene(const struct Depsgraph *graph)
#define DNA_struct_default_get(struct_name)
Definition: DNA_defaults.h:44
@ 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:39
void uiLayoutSetActive(uiLayout *layout, bool active)
@ UI_ITEM_R_SLIDER
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
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
#define fabsf(x)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
static ulong * next
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6308
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
Definition: DNA_ID.h:273
void * first
Definition: DNA_listBase.h:47
Definition: BKE_main.h:116
float obmat[4][4]
void * data
struct uiLayout * layout
ListBase strokes
bGPDspoint * points
struct bGPDstroke * next
ListBase layers
PointerRNA * ptr
Definition: wm_files.c:3157