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