svn merge ^/trunk/blender -r42080:42095
[blender.git] / source / blender / modifiers / intern / MOD_weightvgproximity.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software  Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2011 by Bastien Montagne.
19  * All rights reserved.
20  *
21  * Contributor(s): None yet.
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  *
25  */
26
27 /** \file blender/modifiers/intern/MOD_weightvgproximity.c
28  *  \ingroup modifiers
29  */
30
31 #include "BLI_editVert.h"
32 #include "BLI_math.h"
33 #include "BLI_string.h"
34 #include "BLI_utildefines.h"
35
36 #include "DNA_mesh_types.h"
37 #include "DNA_meshdata_types.h"
38 #include "DNA_modifier_types.h"
39 #include "DNA_object_types.h"
40
41 #include "BKE_cdderivedmesh.h"
42 #include "BKE_deform.h"
43 #include "BKE_mesh.h"
44 #include "BKE_modifier.h"
45 #include "BKE_shrinkwrap.h"       /* For SpaceTransform stuff. */
46 #include "BKE_texture.h"          /* Texture masking. */
47
48 #include "depsgraph_private.h"
49 #include "MEM_guardedalloc.h"
50 #include "MOD_util.h"
51 #include "MOD_weightvg_util.h"
52
53 /**************************************
54  * Util functions.                    *
55  **************************************/
56
57 /* Util macro. */
58 #define OUT_OF_MEMORY() ((void)printf("WeightVGProximity: Out of memory.\n"))
59
60 /**
61  * Find nearest vertex and/or edge and/or face, for each vertex (adapted from shrinkwrap.c).
62  */
63 static void get_vert2geom_distance(int numVerts, float (*v_cos)[3],
64                                    float *dist_v, float *dist_e, float *dist_f,
65                                    DerivedMesh *target, const SpaceTransform *loc2trgt)
66 {
67         int i;
68         BVHTreeFromMesh treeData_v = NULL_BVHTreeFromMesh;
69         BVHTreeFromMesh treeData_e = NULL_BVHTreeFromMesh;
70         BVHTreeFromMesh treeData_f = NULL_BVHTreeFromMesh;
71         BVHTreeNearest  nearest_v  = NULL_BVHTreeNearest;
72         BVHTreeNearest  nearest_e  = NULL_BVHTreeNearest;
73         BVHTreeNearest  nearest_f  = NULL_BVHTreeNearest;
74
75         if (dist_v) {
76                 /* Create a bvh-tree of the given target's verts. */
77                 bvhtree_from_mesh_verts(&treeData_v, target, 0.0, 2, 6);
78                 if(treeData_v.tree == NULL) {
79                         OUT_OF_MEMORY();
80                         return;
81                 }
82         }
83         if (dist_e) {
84                 /* Create a bvh-tree of the given target's edges. */
85                 bvhtree_from_mesh_edges(&treeData_e, target, 0.0, 2, 6);
86                 if(treeData_e.tree == NULL) {
87                         OUT_OF_MEMORY();
88                         return;
89                 }
90         }
91         if (dist_f) {
92                 /* Create a bvh-tree of the given target's faces. */
93                 bvhtree_from_mesh_faces(&treeData_f, target, 0.0, 2, 6);
94                 if(treeData_f.tree == NULL) {
95                         OUT_OF_MEMORY();
96                         return;
97                 }
98         }
99
100         /* Setup nearest. */
101         nearest_v.index = nearest_e.index = nearest_f.index = -1;
102         /*nearest_v.dist  = nearest_e.dist  = nearest_f.dist  = FLT_MAX;*/
103         /* Find the nearest vert/edge/face. */
104 #ifndef __APPLE__
105 #pragma omp parallel for default(none) private(i) firstprivate(nearest_v,nearest_e,nearest_f) \
106                          shared(treeData_v,treeData_e,treeData_f,numVerts,v_cos,dist_v,dist_e, \
107                                 dist_f,loc2trgt) \
108                          schedule(static)
109 #endif
110         for (i = 0; i < numVerts; ++i) {
111                 float tmp_co[3];
112
113                 /* Convert the vertex to tree coordinates. */
114                 copy_v3_v3(tmp_co, v_cos[i]);
115                 space_transform_apply(loc2trgt, tmp_co);
116
117                 /* Use local proximity heuristics (to reduce the nearest search).
118                  *
119                  * If we already had an hit before, we assume this vertex is going to have a close hit to
120                  * that other vertex, so we can initiate the "nearest.dist" with the expected value to that
121                  * last hit.
122                  * This will lead in prunning of the search tree.
123                  */
124                 if (dist_v) {
125                         nearest_v.dist = nearest_v.index != -1 ? len_squared_v3v3(tmp_co, nearest_v.co) : FLT_MAX;
126                         /* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */
127                         BLI_bvhtree_find_nearest(treeData_v.tree, tmp_co, &nearest_v, treeData_v.nearest_callback, &treeData_v);
128                         dist_v[i] = sqrtf(nearest_v.dist);
129                 }
130                 if (dist_e) {
131                         nearest_e.dist = nearest_e.index != -1 ? len_squared_v3v3(tmp_co, nearest_e.co) : FLT_MAX;
132                         /* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */
133                         BLI_bvhtree_find_nearest(treeData_e.tree, tmp_co, &nearest_e, treeData_e.nearest_callback, &treeData_e);
134                         dist_e[i] = sqrtf(nearest_e.dist);
135                 }
136                 if (dist_f) {
137                         nearest_f.dist = nearest_f.index != -1 ? len_squared_v3v3(tmp_co, nearest_f.co) : FLT_MAX;
138                         /* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */
139                         BLI_bvhtree_find_nearest(treeData_f.tree, tmp_co, &nearest_f, treeData_f.nearest_callback, &treeData_f);
140                         dist_f[i] = sqrtf(nearest_f.dist);
141                 }
142         }
143
144         if (dist_v)
145                 free_bvhtree_from_mesh(&treeData_v);
146         if (dist_e)
147                 free_bvhtree_from_mesh(&treeData_e);
148         if (dist_f)
149                 free_bvhtree_from_mesh(&treeData_f);
150 }
151
152 /**
153  * Returns the real distance between a vertex and another reference object.
154  * Note that it works in final world space (i.e. with constraints etc. applied).
155  */
156 static void get_vert2ob_distance(int numVerts, float (*v_cos)[3], float *dist,
157                                  Object* ob, Object* obr)
158 {
159         /* Vertex and ref object coordinates. */
160         float v_wco[3];
161         unsigned int i= numVerts;
162
163         while(i-- > 0) {
164                 /* Get world-coordinates of the vertex (constraints and anim included). */
165                 mul_v3_m4v3(v_wco, ob->obmat, v_cos[i]);
166                 /* Return distance between both coordinates. */
167                 dist[i] = len_v3v3(v_wco, obr->obmat[3]);
168         }
169 }
170
171 /**
172  * Returns the real distance between an object and another reference object.
173  * Note that it works in final world space (i.e. with constraints etc. applied).
174  */
175 static float get_ob2ob_distance(const Object* ob, const Object* obr)
176 {
177         return len_v3v3(ob->obmat[3], obr->obmat[3]); 
178 }
179
180 /**
181  * Maps distances to weights, with an optionnal “smoothing” mapping.
182  */
183 void do_map(float *weights, const int nidx, const float min_d, const float max_d, short mode)
184 {
185         const float range_inv= 1.0f / (max_d - min_d); /* invert since multiplication is faster */
186         unsigned int i= nidx;
187         if(max_d == min_d) {
188                 while (i-- > 0) {
189                         weights[i] = (weights[i] >= max_d) ? 1.0f : 0.0f; /* "Step" behavior... */
190                 }
191         }
192         else if(max_d > min_d) {
193                 while (i-- > 0) {
194                         if     (weights[i] >= max_d) weights[i]= 1.0f; /* most likely case first */
195                         else if(weights[i] <= min_d) weights[i]= 0.0f;
196                         else                         weights[i]= (weights[i] - min_d) * range_inv;
197                 }
198         }
199         else {
200                 while (i-- > 0) {
201                         if     (weights[i] <= max_d) weights[i]= 1.0f; /* most likely case first */
202                         else if(weights[i] >= min_d) weights[i]= 0.0f;
203                         else                         weights[i]= (weights[i] - min_d) * range_inv;
204                 }
205         }
206
207         if(!ELEM(mode, MOD_WVG_MAPPING_NONE, MOD_WVG_MAPPING_CURVE)) {
208                 weightvg_do_map(nidx, weights, mode, NULL);
209         }
210 }
211
212 /**************************************
213  * Modifiers functions.               *
214  **************************************/
215 static void initData(ModifierData *md)
216 {
217         WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData*) md;
218
219         wmd->proximity_mode       = MOD_WVG_PROXIMITY_OBJECT;
220         wmd->proximity_flags      = MOD_WVG_PROXIMITY_GEOM_VERTS;
221
222         wmd->falloff_type         = MOD_WVG_MAPPING_NONE;
223
224         wmd->mask_constant        = 1.0f;
225         wmd->mask_tex_use_channel = MOD_WVG_MASK_TEX_USE_INT; /* Use intensity by default. */
226         wmd->mask_tex_mapping     = MOD_DISP_MAP_LOCAL;
227         wmd->max_dist             = 1.0f; /* vert arbitrary distance, but don't use 0 */
228 }
229
230 static void copyData(ModifierData *md, ModifierData *target)
231 {
232         WeightVGProximityModifierData *wmd  = (WeightVGProximityModifierData*) md;
233         WeightVGProximityModifierData *twmd = (WeightVGProximityModifierData*) target;
234
235         BLI_strncpy(twmd->defgrp_name, wmd->defgrp_name, sizeof(twmd->defgrp_name));
236         twmd->proximity_mode         = wmd->proximity_mode;
237         twmd->proximity_flags        = wmd->proximity_flags;
238         twmd->proximity_ob_target    = wmd->proximity_ob_target;
239
240         twmd->falloff_type           = wmd->falloff_type;
241
242         twmd->mask_constant          = wmd->mask_constant;
243         BLI_strncpy(twmd->mask_defgrp_name, wmd->mask_defgrp_name, sizeof(twmd->mask_defgrp_name));
244         twmd->mask_texture           = wmd->mask_texture;
245         twmd->mask_tex_use_channel   = wmd->mask_tex_use_channel;
246         twmd->mask_tex_mapping       = wmd->mask_tex_mapping;
247         twmd->mask_tex_map_obj       = wmd->mask_tex_map_obj;
248         BLI_strncpy(twmd->mask_tex_uvlayer_name, wmd->mask_tex_uvlayer_name, sizeof(twmd->mask_tex_uvlayer_name));
249         twmd->min_dist               = wmd->min_dist;
250         twmd->max_dist               = wmd->max_dist;
251 }
252
253 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
254 {
255         WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData*) md;
256         CustomDataMask dataMask = 0;
257
258         /* We need vertex groups! */
259         dataMask |= CD_MASK_MDEFORMVERT;
260
261         /* Ask for UV coordinates if we need them. */
262         if(wmd->mask_tex_mapping == MOD_DISP_MAP_UV)
263                 dataMask |= CD_MASK_MTFACE;
264
265         return dataMask;
266 }
267
268 static int dependsOnTime(ModifierData *md)
269 {
270         WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData*) md;
271
272         if(wmd->mask_texture)
273                 return BKE_texture_dependsOnTime(wmd->mask_texture);
274         return 0;
275 }
276
277 static void foreachObjectLink(ModifierData *md, Object *ob,
278                               void (*walk)(void *userData, Object *ob, Object **obpoin),
279                               void *userData)
280 {
281         WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData*) md;
282         walk(userData, ob, &wmd->proximity_ob_target);
283         walk(userData, ob, &wmd->mask_tex_map_obj);
284 }
285
286 static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
287 {
288         WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData*) md;
289
290         walk(userData, ob, (ID **)&wmd->mask_texture);
291
292         foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
293 }
294
295 static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData)
296 {
297         walk(userData, ob, md, "mask_texture");
298 }
299
300 static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UNUSED(scene),
301                            Object *UNUSED(ob), DagNode *obNode)
302 {
303         WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData*) md;
304         DagNode *curNode;
305
306         if (wmd->proximity_ob_target) {
307                 curNode = dag_get_node(forest, wmd->proximity_ob_target);
308                 dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA,
309                                  "WeightVGProximity Modifier");
310         }
311
312         if(wmd->mask_tex_map_obj && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
313                 curNode = dag_get_node(forest, wmd->mask_tex_map_obj);
314
315                 dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA,
316                                  "WeightVGProximity Modifier");
317         }
318
319         if(wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL)
320                 dag_add_relation(forest, obNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA,
321                                  "WeightVGProximity Modifier");
322 }
323
324 static int isDisabled(ModifierData *md, int UNUSED(useRenderParams))
325 {
326         WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData*) md;
327         /* If no vertex group, bypass. */
328         if (wmd->defgrp_name[0] == '\0') return 1;
329         /* If no target object, bypass. */
330         return (wmd->proximity_ob_target == NULL);
331 }
332
333 static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData,
334                                   int UNUSED(useRenderParams), int UNUSED(isFinalCalc))
335 {
336         WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData*) md;
337         DerivedMesh *dm = derivedData, *ret = NULL;
338 #if 0
339         Mesh *ob_m = NULL;
340 #endif
341         MDeformVert *dvert = NULL;
342         MDeformWeight **dw, **tdw;
343         int numVerts;
344         float (*v_cos)[3] = NULL; /* The vertices coordinates. */
345         Object *obr = NULL; /* Our target object. */
346         int defgrp_idx;
347         float *tw = NULL;
348         float *org_w = NULL;
349         float *new_w =NULL;
350         int *tidx, *indices = NULL;
351         int numIdx = 0;
352         int i;
353         char rel_ret = 0; /* Boolean, whether we have to release ret dm or not, when not using it! */
354
355         /* Get number of verts. */
356         numVerts = dm->getNumVerts(dm);
357
358         /* Check if we can just return the original mesh.
359          * Must have verts and therefore verts assigned to vgroups to do anything useful!
360          */
361         if ((numVerts == 0) || (ob->defbase.first == NULL))
362                 return dm;
363
364         /* Get our target object. */
365         obr = wmd->proximity_ob_target;
366         if (obr == NULL)
367                 return dm;
368
369         /* Get vgroup idx from its name. */
370         defgrp_idx = defgroup_name_index(ob, wmd->defgrp_name);
371         if (defgrp_idx < 0)
372                 return dm;
373
374         /* XXX All this to avoid copying dm when not needed... However, it nearly doubles compute
375          *     time! See scene 5 of the WeighVG test file...
376          */
377 #if 0
378         /* Get actual dverts (ie vertex group data). */
379         dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
380         /* If no dverts, return unmodified data... */
381         if (dvert == NULL)
382                 return dm;
383
384         /* Get org mesh, only to test whether affected cdata layer has already been copied
385          * somewhere up in the modifiers stack.
386          */
387         ob_m = get_mesh(ob);
388         if (ob_m == NULL)
389                 return dm;
390
391         /* Create a copy of our dmesh, only if our affected cdata layer is the same as org mesh. */
392         if (dvert == CustomData_get_layer(&ob_m->vdata, CD_MDEFORMVERT)) {
393                 /* XXX Seems to create problems with weightpaint mode???
394                  *     I'm missing something here, I guess...
395                  */
396 //              DM_set_only_copy(dm, CD_MASK_MDEFORMVERT); /* Only copy defgroup layer. */
397                 ret = CDDM_copy(dm);
398                 dvert = ret->getVertDataArray(ret, CD_MDEFORMVERT);
399                 if (dvert == NULL) {
400                         ret->release(ret);
401                         return dm;
402                 }
403                 rel_ret = 1;
404         }
405         else
406                 ret = dm;
407 #else
408         ret = CDDM_copy(dm, 0);
409         rel_ret = 1;
410         dvert = ret->getVertDataArray(ret, CD_MDEFORMVERT);
411         if (dvert == NULL) {
412                 if (rel_ret)
413                         ret->release(ret);
414                 return dm;
415         }
416 #endif
417
418         /* Find out which vertices to work on (all vertices in vgroup), and get their relevant weight.
419          */
420         tidx = MEM_mallocN(sizeof(int) * numVerts, "WeightVGProximity Modifier, tidx");
421         tw = MEM_mallocN(sizeof(float) * numVerts, "WeightVGProximity Modifier, tw");
422         tdw = MEM_mallocN(sizeof(MDeformWeight*) * numVerts, "WeightVGProximity Modifier, tdw");
423         for (i = 0; i < numVerts; i++) {
424                 MDeformWeight *_dw = defvert_find_index(&dvert[i], defgrp_idx);
425                 if(_dw) {
426                         tidx[numIdx] = i;
427                         tw[numIdx] = _dw->weight;
428                         tdw[numIdx++] = _dw;
429                 }
430         }
431         /* If no vertices found, return org data! */
432         if(numIdx == 0) {
433                 MEM_freeN(tidx);
434                 MEM_freeN(tw);
435                 MEM_freeN(tdw);
436                 if (rel_ret)
437                         ret->release(ret);
438                 return dm;
439         }
440         indices = MEM_mallocN(sizeof(int) * numIdx, "WeightVGProximity Modifier, indices");
441         memcpy(indices, tidx, sizeof(int) * numIdx);
442         org_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGProximity Modifier, org_w");
443         new_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGProximity Modifier, new_w");
444         memcpy(org_w, tw, sizeof(float) * numIdx);
445         dw = MEM_mallocN(sizeof(MDeformWeight*) * numIdx, "WeightVGProximity Modifier, dw");
446         memcpy(dw, tdw, sizeof(MDeformWeight*) * numIdx);
447         MEM_freeN(tidx);
448         MEM_freeN(tw);
449         MEM_freeN(tdw);
450
451         /* Get our vertex coordinates. */
452         v_cos = MEM_mallocN(sizeof(float[3]) * numIdx, "WeightVGProximity Modifier, v_cos");
453         for (i = 0; i < numIdx; i++)
454                 ret->getVertCo(ret, indices[i], v_cos[i]);
455
456         /* Compute wanted distances. */
457         if (wmd->proximity_mode == MOD_WVG_PROXIMITY_OBJECT) {
458                 const float dist = get_ob2ob_distance(ob, obr);
459                 for(i = 0; i < numIdx; i++)
460                         new_w[i] = dist;
461         }
462         else if (wmd->proximity_mode == MOD_WVG_PROXIMITY_GEOMETRY) {
463                 const short use_trgt_verts = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_VERTS);
464                 const short use_trgt_edges = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_EDGES);
465                 const short use_trgt_faces = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_FACES);
466
467                 if (use_trgt_verts || use_trgt_edges || use_trgt_faces) {
468                         DerivedMesh *target_dm = obr->derivedFinal;
469                         short free_target_dm = FALSE;
470                         if (!target_dm) {
471                                 if (ELEM3(obr->type, OB_CURVE, OB_SURF, OB_FONT))
472                                         target_dm = CDDM_from_curve(obr);
473                                 else if (obr->type == OB_MESH) {
474                                         Mesh *me = (Mesh*)obr->data;
475                                         if (me->edit_btmesh)
476                                                 target_dm = CDDM_from_BMEditMesh(me->edit_btmesh, me, 0);
477                                         else
478                                                 target_dm = CDDM_from_mesh(me, obr);
479                                 }
480                                 free_target_dm = TRUE;
481                         }
482
483                         /* We must check that we do have a valid target_dm! */
484                         if (target_dm) {
485                                 SpaceTransform loc2trgt;
486                                 float *dists_v = use_trgt_verts ? MEM_mallocN(sizeof(float) * numIdx, "WeightVGProximity Modifier, dists_v") : NULL;
487                                 float *dists_e = use_trgt_edges ? MEM_mallocN(sizeof(float) * numIdx, "WeightVGProximity Modifier, dists_e") : NULL;
488                                 float *dists_f = use_trgt_faces ? MEM_mallocN(sizeof(float) * numIdx, "WeightVGProximity Modifier, dists_f") : NULL;
489
490                                 space_transform_setup(&loc2trgt, ob, obr);
491                                 get_vert2geom_distance(numIdx, v_cos, dists_v, dists_e, dists_f,
492                                                        target_dm, &loc2trgt);
493                                 for(i = 0; i < numIdx; i++) {
494                                         new_w[i] = dists_v ? dists_v[i] : FLT_MAX;
495                                         if(dists_e)
496                                                 new_w[i] = minf(dists_e[i], new_w[i]);
497                                         if(dists_f)
498                                                 new_w[i] = minf(dists_f[i], new_w[i]);
499                                 }
500                                 if(free_target_dm) target_dm->release(target_dm);
501                                 if(dists_v) MEM_freeN(dists_v);
502                                 if(dists_e) MEM_freeN(dists_e);
503                                 if(dists_f) MEM_freeN(dists_f);
504                         }
505                         /* Else, fall back to default obj2vert behavior. */
506                         else {
507                                 get_vert2ob_distance(numIdx, v_cos, new_w, ob, obr);
508                         }
509                 }
510                 else {
511                         get_vert2ob_distance(numIdx, v_cos, new_w, ob, obr);
512                 }
513         }
514
515         /* Map distances to weights. */
516         do_map(new_w, numIdx, wmd->min_dist, wmd->max_dist, wmd->falloff_type);
517
518         /* Do masking. */
519         weightvg_do_mask(numIdx, indices, org_w, new_w, ob, ret, wmd->mask_constant,
520                          wmd->mask_defgrp_name, wmd->mask_texture, wmd->mask_tex_use_channel,
521                          wmd->mask_tex_mapping, wmd->mask_tex_map_obj, wmd->mask_tex_uvlayer_name);
522
523         /* Update vgroup. Note we never add nor remove vertices from vgroup here. */
524         weightvg_update_vg(dvert, defgrp_idx, dw, numIdx, indices, org_w, FALSE, 0.0f, FALSE, 0.0f);
525
526         /* Freeing stuff. */
527         MEM_freeN(org_w);
528         MEM_freeN(new_w);
529         MEM_freeN(dw);
530         MEM_freeN(indices);
531         MEM_freeN(v_cos);
532
533         /* Return the vgroup-modified mesh. */
534         return ret;
535 }
536
537 static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
538                                     struct BMEditMesh *UNUSED(editData),
539                                     DerivedMesh *derivedData)
540 {
541         return applyModifier(md, ob, derivedData, 0, 1);
542 }
543
544
545 ModifierTypeInfo modifierType_WeightVGProximity = {
546         /* name */              "VertexWeightProximity",
547         /* structName */        "WeightVGProximityModifierData",
548         /* structSize */        sizeof(WeightVGProximityModifierData),
549         /* type */              eModifierTypeType_Nonconstructive,
550         /* flags */             eModifierTypeFlag_AcceptsMesh
551 /*                             |eModifierTypeFlag_SupportsMapping*/
552                                |eModifierTypeFlag_SupportsEditmode,
553
554         /* copyData */          copyData,
555         /* deformVerts */       NULL,
556         /* deformMatrices */    NULL,
557         /* deformVertsEM */     NULL,
558         /* deformMatricesEM */  NULL,
559         /* applyModifier */     applyModifier,
560         /* applyModifierEM */   applyModifierEM,
561         /* initData */          initData,
562         /* requiredDataMask */  requiredDataMask,
563         /* freeData */          NULL,
564         /* isDisabled */        isDisabled,
565         /* updateDepgraph */    updateDepgraph,
566         /* dependsOnTime */     dependsOnTime,
567         /* dependsOnNormals */  NULL,
568         /* foreachObjectLink */ foreachObjectLink,
569         /* foreachIDLink */     foreachIDLink,
570         /* foreachTexLink */    foreachTexLink,
571 };