Gizmo: match the DOF gizmo size with the non-gizmo indicator
[blender.git] / source / blender / modifiers / intern / MOD_weightvgedit.c
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) 2011 by Bastien Montagne.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup modifiers
22  */
23
24 #include "BLI_utildefines.h"
25
26 #include "BLI_ghash.h"
27 #include "BLI_listbase.h"
28 #include "BLI_rand.h"
29
30 #include "DNA_color_types.h" /* CurveMapping. */
31 #include "DNA_mesh_types.h"
32 #include "DNA_meshdata_types.h"
33 #include "DNA_modifier_types.h"
34 #include "DNA_object_types.h"
35
36 #include "BKE_colortools.h" /* CurveMapping. */
37 #include "BKE_deform.h"
38 #include "BKE_library_query.h"
39 #include "BKE_modifier.h"
40 #include "BKE_texture.h" /* Texture masking. */
41
42 #include "DEG_depsgraph_build.h"
43 #include "DEG_depsgraph_query.h"
44
45 #include "MEM_guardedalloc.h"
46
47 #include "MOD_weightvg_util.h"
48 #include "MOD_modifiertypes.h"
49
50 /**************************************
51  * Modifiers functions.               *
52  **************************************/
53 static void initData(ModifierData *md)
54 {
55   WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md;
56   wmd->edit_flags = 0;
57   wmd->falloff_type = MOD_WVG_MAPPING_NONE;
58   wmd->default_weight = 0.0f;
59
60   wmd->cmap_curve = BKE_curvemapping_add(1, 0.0, 0.0, 1.0, 1.0);
61   BKE_curvemapping_initialize(wmd->cmap_curve);
62
63   wmd->rem_threshold = 0.01f;
64   wmd->add_threshold = 0.01f;
65
66   wmd->mask_constant = 1.0f;
67   wmd->mask_tex_use_channel = MOD_WVG_MASK_TEX_USE_INT; /* Use intensity by default. */
68   wmd->mask_tex_mapping = MOD_DISP_MAP_LOCAL;
69 }
70
71 static void freeData(ModifierData *md)
72 {
73   WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md;
74   BKE_curvemapping_free(wmd->cmap_curve);
75 }
76
77 static void copyData(const ModifierData *md, ModifierData *target, const int flag)
78 {
79   const WeightVGEditModifierData *wmd = (const WeightVGEditModifierData *)md;
80   WeightVGEditModifierData *twmd = (WeightVGEditModifierData *)target;
81
82   modifier_copyData_generic(md, target, flag);
83
84   twmd->cmap_curve = BKE_curvemapping_copy(wmd->cmap_curve);
85 }
86
87 static void requiredDataMask(Object *UNUSED(ob),
88                              ModifierData *md,
89                              CustomData_MeshMasks *r_cddata_masks)
90 {
91   WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md;
92
93   /* We need vertex groups! */
94   r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
95
96   /* Ask for UV coordinates if we need them. */
97   if (wmd->mask_tex_mapping == MOD_DISP_MAP_UV) {
98     r_cddata_masks->fmask |= CD_MASK_MTFACE;
99   }
100
101   /* No need to ask for CD_PREVIEW_MLOOPCOL... */
102 }
103
104 static bool dependsOnTime(ModifierData *md)
105 {
106   WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md;
107
108   if (wmd->mask_texture) {
109     return BKE_texture_dependsOnTime(wmd->mask_texture);
110   }
111   return false;
112 }
113
114 static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
115 {
116   WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md;
117   walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_CB_NOP);
118 }
119
120 static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
121 {
122   WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md;
123
124   walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_CB_USER);
125
126   foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
127 }
128
129 static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData)
130 {
131   walk(userData, ob, md, "mask_texture");
132 }
133
134 static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
135 {
136   WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md;
137   if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
138     DEG_add_object_relation(
139         ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGEdit Modifier");
140     DEG_add_modifier_to_transform_relation(ctx->node, "WeightVGEdit Modifier");
141   }
142   else if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
143     DEG_add_modifier_to_transform_relation(ctx->node, "WeightVGEdit Modifier");
144   }
145   if (wmd->mask_texture != NULL) {
146     DEG_add_generic_id_relation(ctx->node, &wmd->mask_texture->id, "WeightVGEdit Modifier");
147   }
148 }
149
150 static bool isDisabled(const struct Scene *UNUSED(scene),
151                        ModifierData *md,
152                        bool UNUSED(useRenderParams))
153 {
154   WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md;
155   /* If no vertex group, bypass. */
156   return (wmd->defgrp_name[0] == '\0');
157 }
158
159 static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
160 {
161   BLI_assert(mesh != NULL);
162
163   WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md;
164
165   MDeformVert *dvert = NULL;
166   MDeformWeight **dw = NULL;
167   float *org_w; /* Array original weights. */
168   float *new_w; /* Array new weights. */
169   int i;
170
171   /* Flags. */
172   const bool do_add = (wmd->edit_flags & MOD_WVG_EDIT_ADD2VG) != 0;
173   const bool do_rem = (wmd->edit_flags & MOD_WVG_EDIT_REMFVG) != 0;
174   /* Only do weight-preview in Object, Sculpt and Pose modes! */
175 #if 0
176   const bool do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview);
177 #endif
178
179   /* Get number of verts. */
180   const int numVerts = mesh->totvert;
181
182   /* Check if we can just return the original mesh.
183    * Must have verts and therefore verts assigned to vgroups to do anything useful!
184    */
185   if ((numVerts == 0) || BLI_listbase_is_empty(&ctx->object->defbase)) {
186     return mesh;
187   }
188
189   /* Get vgroup idx from its name. */
190   const int defgrp_index = defgroup_name_index(ctx->object, wmd->defgrp_name);
191   if (defgrp_index == -1) {
192     return mesh;
193   }
194
195   const bool has_mdef = CustomData_has_layer(&mesh->vdata, CD_MDEFORMVERT);
196   /* If no vertices were ever added to an object's vgroup, dvert might be NULL. */
197   if (!has_mdef) {
198     /* If this modifier is not allowed to add vertices, just return. */
199     if (!do_add) {
200       return mesh;
201     }
202   }
203
204   if (has_mdef) {
205     dvert = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MDEFORMVERT, numVerts);
206   }
207   else {
208     /* Add a valid data layer! */
209     dvert = CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, numVerts);
210   }
211   /* Ultimate security check. */
212   if (!dvert) {
213     return mesh;
214   }
215   mesh->dvert = dvert;
216
217   /* Get org weights, assuming 0.0 for vertices not in given vgroup. */
218   org_w = MEM_malloc_arrayN(numVerts, sizeof(float), "WeightVGEdit Modifier, org_w");
219   new_w = MEM_malloc_arrayN(numVerts, sizeof(float), "WeightVGEdit Modifier, new_w");
220   dw = MEM_malloc_arrayN(numVerts, sizeof(MDeformWeight *), "WeightVGEdit Modifier, dw");
221   for (i = 0; i < numVerts; i++) {
222     dw[i] = defvert_find_index(&dvert[i], defgrp_index);
223     if (dw[i]) {
224       org_w[i] = new_w[i] = dw[i]->weight;
225     }
226     else {
227       org_w[i] = new_w[i] = wmd->default_weight;
228     }
229   }
230
231   /* Do mapping. */
232   if (wmd->falloff_type != MOD_WVG_MAPPING_NONE) {
233     RNG *rng = NULL;
234
235     if (wmd->falloff_type == MOD_WVG_MAPPING_RANDOM) {
236       rng = BLI_rng_new_srandom(BLI_ghashutil_strhash(ctx->object->id.name + 2));
237     }
238
239     weightvg_do_map(numVerts, new_w, wmd->falloff_type, wmd->cmap_curve, rng);
240
241     if (rng) {
242       BLI_rng_free(rng);
243     }
244   }
245
246   /* Do masking. */
247   struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
248   weightvg_do_mask(ctx,
249                    numVerts,
250                    NULL,
251                    org_w,
252                    new_w,
253                    ctx->object,
254                    mesh,
255                    wmd->mask_constant,
256                    wmd->mask_defgrp_name,
257                    scene,
258                    wmd->mask_texture,
259                    wmd->mask_tex_use_channel,
260                    wmd->mask_tex_mapping,
261                    wmd->mask_tex_map_obj,
262                    wmd->mask_tex_uvlayer_name);
263
264   /* Update/add/remove from vgroup. */
265   weightvg_update_vg(dvert,
266                      defgrp_index,
267                      dw,
268                      numVerts,
269                      NULL,
270                      org_w,
271                      do_add,
272                      wmd->add_threshold,
273                      do_rem,
274                      wmd->rem_threshold);
275
276   /* If weight preview enabled... */
277 #if 0 /* XXX Currently done in mod stack :/ */
278   if (do_prev) {
279     DM_update_weight_mcol(ob, dm, 0, org_w, 0, NULL);
280   }
281 #endif
282
283   /* Freeing stuff. */
284   MEM_freeN(org_w);
285   MEM_freeN(new_w);
286   MEM_freeN(dw);
287
288   /* Return the vgroup-modified mesh. */
289   return mesh;
290 }
291
292 ModifierTypeInfo modifierType_WeightVGEdit = {
293     /* name */ "VertexWeightEdit",
294     /* structName */ "WeightVGEditModifierData",
295     /* structSize */ sizeof(WeightVGEditModifierData),
296     /* type */ eModifierTypeType_NonGeometrical,
297     /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
298         eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_UsesPreview,
299
300     /* copyData */ copyData,
301
302     /* deformVerts */ NULL,
303     /* deformMatrices */ NULL,
304     /* deformVertsEM */ NULL,
305     /* deformMatricesEM */ NULL,
306     /* applyModifier */ applyModifier,
307
308     /* initData */ initData,
309     /* requiredDataMask */ requiredDataMask,
310     /* freeData */ freeData,
311     /* isDisabled */ isDisabled,
312     /* updateDepsgraph */ updateDepsgraph,
313     /* dependsOnTime */ dependsOnTime,
314     /* dependsOnNormals */ NULL,
315     /* foreachObjectLink */ foreachObjectLink,
316     /* foreachIDLink */ foreachIDLink,
317     /* foreachTexLink */ foreachTexLink,
318     /* freeRuntimeData */ NULL,
319 };