Blender  V2.93
MOD_gpencilhook.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 "BLI_listbase.h"
27 #include "BLI_utildefines.h"
28 
29 #include "BLI_math.h"
30 
31 #include "BLT_translation.h"
32 
33 #include "DNA_defaults.h"
35 #include "DNA_gpencil_types.h"
36 #include "DNA_meshdata_types.h"
37 #include "DNA_modifier_types.h"
38 #include "DNA_object_types.h"
39 #include "DNA_scene_types.h"
40 #include "DNA_screen_types.h"
41 
42 #include "BKE_action.h"
43 #include "BKE_colortools.h"
44 #include "BKE_context.h"
45 #include "BKE_deform.h"
46 #include "BKE_gpencil_geom.h"
47 #include "BKE_gpencil_modifier.h"
48 #include "BKE_lib_query.h"
49 #include "BKE_main.h"
50 #include "BKE_modifier.h"
51 #include "BKE_scene.h"
52 #include "BKE_screen.h"
53 
54 #include "UI_interface.h"
55 #include "UI_resources.h"
56 
57 #include "RNA_access.h"
58 
60 #include "MOD_gpencil_ui_common.h"
61 #include "MOD_gpencil_util.h"
62 
63 #include "DEG_depsgraph.h"
64 #include "DEG_depsgraph_build.h"
65 #include "DEG_depsgraph_query.h"
66 
67 /* temp struct to hold data */
68 struct GPHookData_cb {
70 
72  float falloff;
73  float falloff_sq;
74  float fac_orig;
75 
78 
79  float cent[3];
80 
81  float mat_uniform[3][3];
82  float mat[4][4];
83 };
84 
85 static void initData(GpencilModifierData *md)
86 {
88 
89  BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(gpmd, modifier));
90 
92 
93  gpmd->curfalloff = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
95 }
96 
97 static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
98 {
101 
102  if (tgmd->curfalloff != NULL) {
104  tgmd->curfalloff = NULL;
105  }
106 
108 
110 }
111 
112 /* Calculate the factor of falloff. */
113 static float gpencil_hook_falloff(const struct GPHookData_cb *tData, const float len_sq)
114 {
115  BLI_assert(tData->falloff_sq);
116  if (len_sq > tData->falloff_sq) {
117  return 0.0f;
118  }
119  if (len_sq > 0.0f) {
120  float fac;
121 
122  if (tData->falloff_type == eGPHook_Falloff_Const) {
123  fac = 1.0f;
124  goto finally;
125  }
126  else if (tData->falloff_type == eGPHook_Falloff_InvSquare) {
127  /* avoid sqrt below */
128  fac = 1.0f - (len_sq / tData->falloff_sq);
129  goto finally;
130  }
131 
132  fac = 1.0f - (sqrtf(len_sq) / tData->falloff);
133 
134  switch (tData->falloff_type) {
136  fac = BKE_curvemapping_evaluateF(tData->curfalloff, 0, fac);
137  break;
139  fac = fac * fac;
140  break;
142  fac = 3.0f * fac * fac - 2.0f * fac * fac * fac;
143  break;
145  fac = sqrtf(fac);
146  break;
148  /* pass */
149  break;
151  fac = sqrtf(2 * fac - fac * fac);
152  break;
153  default:
154  break;
155  }
156 
157  finally:
158  return fac * tData->fac_orig;
159  }
160  else {
161  return tData->fac_orig;
162  }
163 }
164 
165 /* apply point deformation */
166 static void gpencil_hook_co_apply(struct GPHookData_cb *tData, float weight, bGPDspoint *pt)
167 {
168  float fac;
169 
170  if (tData->use_falloff) {
171  float len_sq;
172 
173  if (tData->use_uniform) {
174  float co_uniform[3];
175  mul_v3_m3v3(co_uniform, tData->mat_uniform, &pt->x);
176  len_sq = len_squared_v3v3(tData->cent, co_uniform);
177  }
178  else {
179  len_sq = len_squared_v3v3(tData->cent, &pt->x);
180  }
181 
182  fac = gpencil_hook_falloff(tData, len_sq);
183  }
184  else {
185  fac = tData->fac_orig;
186  }
187 
188  if (fac) {
189  float co_tmp[3];
190  mul_v3_m4v3(co_tmp, tData->mat, &pt->x);
191  interp_v3_v3v3(&pt->x, &pt->x, co_tmp, fac * weight);
192  }
193 }
194 
195 /* deform stroke */
198  Object *ob,
199  bGPDlayer *gpl,
200  bGPDframe *UNUSED(gpf),
201  bGPDstroke *gps)
202 {
204  if (!mmd->object) {
205  return;
206  }
207 
208  const int def_nr = BKE_object_defgroup_name_index(ob, mmd->vgname);
209 
211  float dmat[4][4];
212  struct GPHookData_cb tData;
213 
215  mmd->layername,
216  mmd->material,
217  mmd->pass_index,
218  mmd->layer_pass,
219  1,
220  gpl,
221  gps,
222  mmd->flag & GP_HOOK_INVERT_LAYER,
223  mmd->flag & GP_HOOK_INVERT_PASS,
225  mmd->flag & GP_HOOK_INVERT_MATERIAL)) {
226  return;
227  }
228  bGPdata *gpd = ob->data;
229 
230  /* init struct */
231  tData.curfalloff = mmd->curfalloff;
232  tData.falloff_type = mmd->falloff_type;
233  tData.falloff = (mmd->falloff_type == eHook_Falloff_None) ? 0.0f : mmd->falloff;
234  tData.falloff_sq = square_f(tData.falloff);
235  tData.fac_orig = mmd->force;
236  tData.use_falloff = (tData.falloff_sq != 0.0f);
237  tData.use_uniform = (mmd->flag & GP_HOOK_UNIFORM_SPACE) != 0;
238 
239  if (tData.use_uniform) {
240  copy_m3_m4(tData.mat_uniform, mmd->parentinv);
241  mul_v3_m3v3(tData.cent, tData.mat_uniform, mmd->cent);
242  }
243  else {
244  unit_m3(tData.mat_uniform);
245  copy_v3_v3(tData.cent, mmd->cent);
246  }
247 
248  /* get world-space matrix of target, corrected for the space the verts are in */
249  if (mmd->subtarget[0] && pchan) {
250  /* bone target if there's a matching pose-channel */
251  mul_m4_m4m4(dmat, mmd->object->obmat, pchan->pose_mat);
252  }
253  else {
254  /* just object target */
255  copy_m4_m4(dmat, mmd->object->obmat);
256  }
257  invert_m4_m4(ob->imat, ob->obmat);
258  mul_m4_series(tData.mat, ob->imat, dmat, mmd->parentinv);
259 
260  /* loop points and apply deform */
261  for (int i = 0; i < gps->totpoints; i++) {
262  bGPDspoint *pt = &gps->points[i];
263  MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL;
264 
265  /* verify vertex group */
266  const float weight = get_modifier_point_weight(
267  dvert, (mmd->flag & GP_HOOK_INVERT_VGROUP) != 0, def_nr);
268  if (weight < 0.0f) {
269  continue;
270  }
271  gpencil_hook_co_apply(&tData, weight, pt);
272  }
273  /* Calc geometry data. */
275 }
276 
277 /* FIXME: Ideally we be doing this on a copy of the main depsgraph
278  * (i.e. one where we don't have to worry about restoring state)
279  */
280 static void bakeModifier(Main *UNUSED(bmain),
283  Object *ob)
284 {
287  bGPdata *gpd = ob->data;
288  int oldframe = (int)DEG_get_ctime(depsgraph);
289 
290  if (mmd->object == NULL) {
291  return;
292  }
293 
294  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
295  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
296  /* apply hook effects on this frame
297  * NOTE: this assumes that we don't want hook animation on non-keyframed frames
298  */
299  CFRA = gpf->framenum;
301 
302  /* compute hook effects on this frame */
303  LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
304  deformStroke(md, depsgraph, ob, gpl, gpf, gps);
305  }
306  }
307  }
308 
309  /* return frame state and DB to original state */
310  CFRA = oldframe;
312 }
313 
315 {
317 
318  if (mmd->curfalloff) {
320  }
321 }
322 
323 static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
324 {
326 
327  return !mmd->object;
328 }
329 
332  const int UNUSED(mode))
333 {
335  if (lmd->object != NULL) {
336  DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_GEOMETRY, "Hook Modifier");
337  DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
338  }
339  DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
340 }
341 
342 static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
343 {
345 
346  walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
347  walk(userData, ob, (ID **)&mmd->object, IDWALK_CB_NOP);
348 }
349 
350 static void panel_draw(const bContext *UNUSED(C), Panel *panel)
351 {
352  uiLayout *sub, *row, *col;
353  uiLayout *layout = panel->layout;
354 
355  PointerRNA ob_ptr;
357 
358  PointerRNA hook_object_ptr = RNA_pointer_get(ptr, "object");
359  bool has_vertex_group = RNA_string_length(ptr, "vertex_group") != 0;
360 
361  uiLayoutSetPropSep(layout, true);
362 
363  col = uiLayoutColumn(layout, false);
364  uiItemR(col, ptr, "object", 0, NULL, ICON_NONE);
365  if (!RNA_pointer_is_null(&hook_object_ptr) &&
366  RNA_enum_get(&hook_object_ptr, "type") == OB_ARMATURE) {
367  PointerRNA hook_object_data_ptr = RNA_pointer_get(&hook_object_ptr, "data");
369  col, ptr, "subtarget", &hook_object_data_ptr, "bones", IFACE_("Bone"), ICON_NONE);
370  }
371 
372  row = uiLayoutRow(layout, true);
373  uiItemPointerR(row, ptr, "vertex_group", &ob_ptr, "vertex_groups", NULL, ICON_NONE);
374  sub = uiLayoutRow(row, true);
375  uiLayoutSetActive(sub, has_vertex_group);
376  uiLayoutSetPropSep(sub, false);
377  uiItemR(sub, ptr, "invert_vertex", 0, "", ICON_ARROW_LEFTRIGHT);
378 
379  uiItemR(layout, ptr, "strength", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
380 
382 }
383 
384 static void falloff_panel_draw(const bContext *UNUSED(C), Panel *panel)
385 {
386  uiLayout *row;
387  uiLayout *layout = panel->layout;
388 
390 
391  bool use_falloff = RNA_enum_get(ptr, "falloff_type") != eWarp_Falloff_None;
392 
393  uiLayoutSetPropSep(layout, true);
394 
395  uiItemR(layout, ptr, "falloff_type", 0, IFACE_("Type"), ICON_NONE);
396 
397  row = uiLayoutRow(layout, false);
399  uiItemR(row, ptr, "falloff_radius", 0, NULL, ICON_NONE);
400 
401  uiItemR(layout, ptr, "use_falloff_uniform", 0, NULL, ICON_NONE);
402 
403  if (RNA_enum_get(ptr, "falloff_type") == eWarp_Falloff_Curve) {
404  uiTemplateCurveMapping(layout, ptr, "falloff_curve", 0, false, false, false, false);
405  }
406 }
407 
408 static void mask_panel_draw(const bContext *UNUSED(C), Panel *panel)
409 {
410  gpencil_modifier_masking_panel_draw(panel, true, false);
411 }
412 
413 static void panelRegister(ARegionType *region_type)
414 {
416  region_type, eGpencilModifierType_Hook, panel_draw);
418  region_type, "falloff", "Falloff", NULL, falloff_panel_draw, panel_type);
420  region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type);
421 }
422 
424  /* name */ "Hook",
425  /* structName */ "HookGpencilModifierData",
426  /* structSize */ sizeof(HookGpencilModifierData),
429 
430  /* copyData */ copyData,
431 
432  /* deformStroke */ deformStroke,
433  /* generateStrokes */ NULL,
434  /* bakeModifier */ bakeModifier,
435  /* remapTime */ NULL,
436 
437  /* initData */ initData,
438  /* freeData */ freeData,
439  /* isDisabled */ isDisabled,
440  /* updateDepsgraph */ updateDepsgraph,
441  /* dependsOnTime */ NULL,
442  /* foreachIDLink */ foreachIDLink,
443  /* foreachTexLink */ NULL,
444  /* panelRegister */ panelRegister,
445 };
Blender kernel action and pose functionality.
struct bPoseChannel * BKE_pose_channel_find_name(const struct bPose *pose, const char *name)
void BKE_curvemapping_init(struct CurveMapping *cumap)
Definition: colortools.c:1200
struct CurveMapping * BKE_curvemapping_copy(const struct CurveMapping *cumap)
float BKE_curvemapping_evaluateF(const struct CurveMapping *cumap, int cur, float value)
void BKE_curvemapping_free(struct CurveMapping *cumap)
Definition: colortools.c:119
struct CurveMapping * BKE_curvemapping_add(int tot, float minx, float miny, float maxx, float maxy)
Definition: colortools.c:88
support for deformation groups and hooks.
int BKE_object_defgroup_name_index(const struct Object *ob, const char *name)
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)
@ eGpencilModifierTypeFlag_SupportsEditmode
@ eGpencilModifierTypeType_Gpencil
@ IDWALK_CB_USER
Definition: BKE_lib_query.h:87
@ IDWALK_CB_NOP
Definition: BKE_lib_query.h:47
void(* IDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag)
Definition: BKE_modifier.h:120
void BKE_scene_graph_update_for_newframe(struct Depsgraph *depsgraph)
Definition: scene.c:2794
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
MINLINE float square_f(float a)
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:262
void unit_m3(float m[3][3])
Definition: math_matrix.c:58
void copy_m3_m4(float m1[3][3], const float m2[4][4])
Definition: math_matrix.c:105
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1278
#define mul_m4_series(...)
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:95
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:742
void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3])
Definition: math_matrix.c:901
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], const float t)
Definition: math_vector.c:49
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v3_v3(float r[3], const float a[3])
unsigned int uint
Definition: BLI_sys_types.h:83
#define UNUSED(x)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define IFACE_(msgid)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:51
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
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
@ GP_HOOK_INVERT_MATERIAL
@ GP_HOOK_INVERT_LAYERPASS
@ eGPHook_Falloff_InvSquare
@ eGPHook_Falloff_Smooth
@ eGPHook_Falloff_Linear
@ eGPHook_Falloff_Sphere
struct HookGpencilModifierData HookGpencilModifierData
@ eGpencilModifierType_Hook
@ eWarp_Falloff_Curve
@ eWarp_Falloff_None
@ eHook_Falloff_None
Object is a sort of wrapper for general info.
@ OB_ARMATURE
#define CFRA
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)
float get_modifier_point_weight(MDeformVert *dvert, bool inverse, int def_nr)
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 deformStroke(GpencilModifierData *md, Depsgraph *UNUSED(depsgraph), Object *ob, bGPDlayer *gpl, bGPDframe *UNUSED(gpf), bGPDstroke *gps)
static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
static void falloff_panel_draw(const bContext *UNUSED(C), Panel *panel)
static void freeData(GpencilModifierData *md)
GpencilModifierTypeInfo modifierType_Gpencil_Hook
static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx, const int UNUSED(mode))
static float gpencil_hook_falloff(const struct GPHookData_cb *tData, const float len_sq)
static void mask_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 copyData(const GpencilModifierData *md, GpencilModifierData *target)
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
static void panelRegister(ARegionType *region_type)
static void initData(GpencilModifierData *md)
static void gpencil_hook_co_apply(struct GPHookData_cb *tData, float weight, bGPDspoint *pt)
#define C
Definition: RandGen.cpp:39
void uiLayoutSetActive(uiLayout *layout, bool active)
@ UI_ITEM_R_SLIDER
void uiTemplateCurveMapping(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int type, bool levels, bool brush, bool neg_slope, bool tone)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, 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)
Scene scene
const Depsgraph * depsgraph
uint col
#define sqrtf(x)
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6562
int RNA_string_length(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6539
bool RNA_pointer_is_null(const PointerRNA *ptr)
Definition: rna_access.c:174
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6402
float mat_uniform[3][3]
float mat[4][4]
struct CurveMapping * curfalloff
Definition: DNA_ID.h:273
Definition: BKE_main.h:116
struct DepsNodeHandle * node
Definition: BKE_modifier.h:147
struct bPose * pose
float imat[4][4]
float obmat[4][4]
void * data
struct uiLayout * layout
ListBase frames
bGPDspoint * points
struct MDeformVert * dvert
ListBase layers
float pose_mat[4][4]
PointerRNA * ptr
Definition: wm_files.c:3157