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