Depsgraph: Add utility function for transform dependency
[blender.git] / source / blender / modifiers / intern / MOD_weightvgproximity.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 \ingroup modifiers
21  */
22
23 #include "BLI_utildefines.h"
24 #include "BLI_ghash.h"
25 #include "BLI_listbase.h"
26 #include "BLI_math.h"
27 #include "BLI_rand.h"
28 #include "BLI_task.h"
29
30 #include "DNA_mesh_types.h"
31 #include "DNA_meshdata_types.h"
32 #include "DNA_modifier_types.h"
33 #include "DNA_object_types.h"
34
35 #include "BKE_bvhutils.h"
36 #include "BKE_curve.h"
37 #include "BKE_customdata.h"
38 #include "BKE_deform.h"
39 #include "BKE_library.h"
40 #include "BKE_library_query.h"
41 #include "BKE_mesh.h"
42 #include "BKE_modifier.h"
43 #include "BKE_texture.h"          /* Texture masking. */
44
45 #include "DEG_depsgraph_build.h"
46 #include "DEG_depsgraph_query.h"
47
48 #include "MEM_guardedalloc.h"
49
50 #include "MOD_weightvg_util.h"
51 #include "MOD_modifiertypes.h"
52 #include "MOD_util.h"
53
54 //#define USE_TIMEIT
55
56 #ifdef USE_TIMEIT
57 #  include "PIL_time.h"
58 #  include "PIL_time_utildefines.h"
59 #endif
60
61 /**************************************
62  * Util functions.                    *
63  **************************************/
64
65 /* Util macro. */
66 #define OUT_OF_MEMORY() ((void)printf("WeightVGProximity: Out of memory.\n"))
67
68 typedef struct Vert2GeomData {
69         /* Read-only data */
70         float (*v_cos)[3];
71
72         const SpaceTransform *loc2trgt;
73
74         BVHTreeFromMesh *treeData[3];
75
76         /* Write data, but not needing locking (two different threads will never write same index). */
77         float *dist[3];
78 } Vert2GeomData;
79
80 /* Data which is localized to each computed chunk (i.e. thread-safe, and with continuous subset of index range). */
81 typedef struct Vert2GeomDataChunk {
82         /* Read-only data */
83         float last_hit_co[3][3];
84         bool is_init[3];
85 } Vert2GeomDataChunk;
86
87 /**
88  * Callback used by BLI_task 'for loop' helper.
89  */
90 static void vert2geom_task_cb_ex(
91         void *__restrict userdata,
92         const int iter,
93         const ParallelRangeTLS *__restrict tls)
94 {
95         Vert2GeomData *data = userdata;
96         Vert2GeomDataChunk *data_chunk = tls->userdata_chunk;
97
98         float tmp_co[3];
99         int i;
100
101         /* Convert the vertex to tree coordinates. */
102         copy_v3_v3(tmp_co, data->v_cos[iter]);
103         BLI_space_transform_apply(data->loc2trgt, tmp_co);
104
105         for (i = 0; i < ARRAY_SIZE(data->dist); i++) {
106                 if (data->dist[i]) {
107                         BVHTreeNearest nearest = {0};
108
109                         /* Note that we use local proximity heuristics (to reduce the nearest search).
110                          *
111                          * If we already had an hit before in same chunk of tasks (i.e. previous vertex by index),
112                          * we assume this vertex is going to have a close hit to that other vertex, so we can initiate
113                          * the "nearest.dist" with the expected value to that last hit.
114                          * This will lead in pruning of the search tree.
115                          */
116                         nearest.dist_sq = data_chunk->is_init[i] ? len_squared_v3v3(tmp_co, data_chunk->last_hit_co[i]) : FLT_MAX;
117                         nearest.index = -1;
118
119                         /* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */
120                         BLI_bvhtree_find_nearest(data->treeData[i]->tree, tmp_co, &nearest,
121                                                  data->treeData[i]->nearest_callback, data->treeData[i]);
122                         data->dist[i][iter] = sqrtf(nearest.dist_sq);
123
124                         if (nearest.index != -1) {
125                                 copy_v3_v3(data_chunk->last_hit_co[i], nearest.co);
126                                 data_chunk->is_init[i] = true;
127                         }
128                 }
129         }
130 }
131
132 /**
133  * Find nearest vertex and/or edge and/or face, for each vertex (adapted from shrinkwrap.c).
134  */
135 static void get_vert2geom_distance(
136         int numVerts, float (*v_cos)[3],
137         float *dist_v, float *dist_e, float *dist_f,
138         Mesh *target, const SpaceTransform *loc2trgt)
139 {
140         Vert2GeomData data = {0};
141         Vert2GeomDataChunk data_chunk = {{{0}}};
142
143         BVHTreeFromMesh treeData_v = {NULL};
144         BVHTreeFromMesh treeData_e = {NULL};
145         BVHTreeFromMesh treeData_f = {NULL};
146
147         if (dist_v) {
148                 /* Create a bvh-tree of the given target's verts. */
149                 BKE_bvhtree_from_mesh_get(&treeData_v, target, BVHTREE_FROM_VERTS, 2);
150                 if (treeData_v.tree == NULL) {
151                         OUT_OF_MEMORY();
152                         return;
153                 }
154         }
155         if (dist_e) {
156                 /* Create a bvh-tree of the given target's edges. */
157                 BKE_bvhtree_from_mesh_get(&treeData_e, target, BVHTREE_FROM_EDGES, 2);
158                 if (treeData_e.tree == NULL) {
159                         OUT_OF_MEMORY();
160                         return;
161                 }
162         }
163         if (dist_f) {
164                 /* Create a bvh-tree of the given target's faces. */
165                 BKE_bvhtree_from_mesh_get(&treeData_f, target, BVHTREE_FROM_LOOPTRI, 2);
166                 if (treeData_f.tree == NULL) {
167                         OUT_OF_MEMORY();
168                         return;
169                 }
170         }
171
172         data.v_cos = v_cos;
173         data.loc2trgt = loc2trgt;
174         data.treeData[0] = &treeData_v;
175         data.treeData[1] = &treeData_e;
176         data.treeData[2] = &treeData_f;
177         data.dist[0] = dist_v;
178         data.dist[1] = dist_e;
179         data.dist[2] = dist_f;
180
181         ParallelRangeSettings settings;
182         BLI_parallel_range_settings_defaults(&settings);
183         settings.use_threading = (numVerts > 10000);
184         settings.userdata_chunk = &data_chunk;
185         settings.userdata_chunk_size = sizeof(data_chunk);
186         BLI_task_parallel_range(
187                 0, numVerts,
188                 &data,
189                 vert2geom_task_cb_ex,
190                 &settings);
191
192         if (dist_v)
193                 free_bvhtree_from_mesh(&treeData_v);
194         if (dist_e)
195                 free_bvhtree_from_mesh(&treeData_e);
196         if (dist_f)
197                 free_bvhtree_from_mesh(&treeData_f);
198 }
199
200 /**
201  * Returns the real distance between a vertex and another reference object.
202  * Note that it works in final world space (i.e. with constraints etc. applied).
203  */
204 static void get_vert2ob_distance(
205         int numVerts, float (*v_cos)[3], float *dist,
206         Object *ob, Object *obr)
207 {
208         /* Vertex and ref object coordinates. */
209         float v_wco[3];
210         unsigned int i = numVerts;
211
212         while (i-- > 0) {
213                 /* Get world-coordinates of the vertex (constraints and anim included). */
214                 mul_v3_m4v3(v_wco, ob->obmat, v_cos[i]);
215                 /* Return distance between both coordinates. */
216                 dist[i] = len_v3v3(v_wco, obr->obmat[3]);
217         }
218 }
219
220 /**
221  * Returns the real distance between an object and another reference object.
222  * Note that it works in final world space (i.e. with constraints etc. applied).
223  */
224 static float get_ob2ob_distance(const Object *ob, const Object *obr)
225 {
226         return len_v3v3(ob->obmat[3], obr->obmat[3]);
227 }
228
229 /**
230  * Maps distances to weights, with an optional "smoothing" mapping.
231  */
232 static void do_map(Object *ob, float *weights, const int nidx, const float min_d, const float max_d, short mode)
233 {
234         const float range_inv = 1.0f / (max_d - min_d); /* invert since multiplication is faster */
235         unsigned int i = nidx;
236         if (max_d == min_d) {
237                 while (i-- > 0) {
238                         weights[i] = (weights[i] >= max_d) ? 1.0f : 0.0f; /* "Step" behavior... */
239                 }
240         }
241         else if (max_d > min_d) {
242                 while (i-- > 0) {
243                         if     (weights[i] >= max_d) weights[i] = 1.0f;  /* most likely case first */
244                         else if (weights[i] <= min_d) weights[i] = 0.0f;
245                         else weights[i] = (weights[i] - min_d) * range_inv;
246                 }
247         }
248         else {
249                 while (i-- > 0) {
250                         if     (weights[i] <= max_d) weights[i] = 1.0f;  /* most likely case first */
251                         else if (weights[i] >= min_d) weights[i] = 0.0f;
252                         else weights[i] = (weights[i] - min_d) * range_inv;
253                 }
254         }
255
256         if (!ELEM(mode, MOD_WVG_MAPPING_NONE, MOD_WVG_MAPPING_CURVE)) {
257                 RNG *rng = NULL;
258
259                 if (mode == MOD_WVG_MAPPING_RANDOM) {
260                         rng = BLI_rng_new_srandom(BLI_ghashutil_strhash(ob->id.name + 2));
261                 }
262
263                 weightvg_do_map(nidx, weights, mode, NULL, rng);
264
265                 if (rng) {
266                         BLI_rng_free(rng);
267                 }
268         }
269 }
270
271 /**************************************
272  * Modifiers functions.               *
273  **************************************/
274 static void initData(ModifierData *md)
275 {
276         WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md;
277
278         wmd->proximity_mode       = MOD_WVG_PROXIMITY_OBJECT;
279         wmd->proximity_flags      = MOD_WVG_PROXIMITY_GEOM_VERTS;
280
281         wmd->falloff_type         = MOD_WVG_MAPPING_NONE;
282
283         wmd->mask_constant        = 1.0f;
284         wmd->mask_tex_use_channel = MOD_WVG_MASK_TEX_USE_INT; /* Use intensity by default. */
285         wmd->mask_tex_mapping     = MOD_DISP_MAP_LOCAL;
286         wmd->max_dist             = 1.0f; /* vert arbitrary distance, but don't use 0 */
287 }
288
289 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
290 {
291         WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md;
292         CustomDataMask dataMask = 0;
293
294         /* We need vertex groups! */
295         dataMask |= CD_MASK_MDEFORMVERT;
296
297         /* Ask for UV coordinates if we need them. */
298         if (wmd->mask_tex_mapping == MOD_DISP_MAP_UV)
299                 dataMask |= CD_MASK_MTFACE;
300
301         /* No need to ask for CD_PREVIEW_MLOOPCOL... */
302
303         return dataMask;
304 }
305
306 static bool dependsOnTime(ModifierData *md)
307 {
308         WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md;
309
310         if (wmd->mask_texture)
311                 return BKE_texture_dependsOnTime(wmd->mask_texture);
312         return 0;
313 }
314
315 static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
316 {
317         WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md;
318         walk(userData, ob, &wmd->proximity_ob_target, IDWALK_CB_NOP);
319         walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_CB_NOP);
320 }
321
322 static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
323 {
324         WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md;
325
326         walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_CB_USER);
327
328         foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
329 }
330
331 static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData)
332 {
333         walk(userData, ob, md, "mask_texture");
334 }
335
336 static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
337 {
338         WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *)md;
339         if (wmd->proximity_ob_target != NULL) {
340                 DEG_add_object_relation(ctx->node, wmd->proximity_ob_target, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier");
341                 DEG_add_object_relation(ctx->node, wmd->proximity_ob_target, DEG_OB_COMP_GEOMETRY, "WeightVGProximity Modifier");
342         }
343         if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
344                 DEG_add_object_relation(ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier");
345                 DEG_add_object_relation(ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_GEOMETRY, "WeightVGProximity Modifier");
346         }
347         if (wmd->mask_texture != NULL) {
348                 DEG_add_generic_id_relation(ctx->node, &wmd->mask_texture->id, "WeightVGProximity Modifier");
349         }
350         DEG_add_modifier_to_transform_relation(ctx->node, "WeightVGProximity Modifier");
351         DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_GEOMETRY, "WeightVGProximity Modifier");
352 }
353
354 static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
355 {
356         WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md;
357         /* If no vertex group, bypass. */
358         if (wmd->defgrp_name[0] == '\0') return 1;
359         /* If no target object, bypass. */
360         return (wmd->proximity_ob_target == NULL);
361 }
362
363 static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
364 {
365         BLI_assert(mesh != NULL);
366
367         WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md;
368         MDeformVert *dvert = NULL;
369         MDeformWeight **dw, **tdw;
370         float (*v_cos)[3] = NULL; /* The vertices coordinates. */
371         Object *ob = ctx->object;
372         Object *obr = NULL; /* Our target object. */
373         int defgrp_index;
374         float *tw = NULL;
375         float *org_w = NULL;
376         float *new_w = NULL;
377         int *tidx, *indices = NULL;
378         int numIdx = 0;
379         int i;
380         /* Flags. */
381 #if 0
382         const bool do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview) != 0;
383 #endif
384
385 #ifdef USE_TIMEIT
386         TIMEIT_START(perf);
387 #endif
388
389         /* Get number of verts. */
390         const int numVerts = mesh->totvert;
391
392         /* Check if we can just return the original mesh.
393          * Must have verts and therefore verts assigned to vgroups to do anything useful!
394          */
395         if ((numVerts == 0) || BLI_listbase_is_empty(&ctx->object->defbase)) {
396                 return mesh;
397         }
398
399         /* Get our target object. */
400         obr = DEG_get_evaluated_object(ctx->depsgraph, wmd->proximity_ob_target);
401         if (obr == NULL) {
402                 return mesh;
403         }
404
405         /* Get vgroup idx from its name. */
406         defgrp_index = defgroup_name_index(ob, wmd->defgrp_name);
407         if (defgrp_index == -1) {
408                 return mesh;
409         }
410
411         const bool has_mdef = CustomData_has_layer(&mesh->vdata, CD_MDEFORMVERT);
412         /* If no vertices were ever added to an object's vgroup, dvert might be NULL. */
413         /* As this modifier never add vertices to vgroup, just return. */
414         if (!has_mdef) {
415                 return mesh;
416         }
417
418         dvert = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MDEFORMVERT, numVerts);
419         /* Ultimate security check. */
420         if (!dvert) {
421                 return mesh;
422         }
423         mesh->dvert = dvert;
424
425         /* Find out which vertices to work on (all vertices in vgroup), and get their relevant weight. */
426         tidx = MEM_malloc_arrayN(numVerts, sizeof(int), "WeightVGProximity Modifier, tidx");
427         tw = MEM_malloc_arrayN(numVerts, sizeof(float), "WeightVGProximity Modifier, tw");
428         tdw = MEM_malloc_arrayN(numVerts, sizeof(MDeformWeight *), "WeightVGProximity Modifier, tdw");
429         for (i = 0; i < numVerts; i++) {
430                 MDeformWeight *_dw = defvert_find_index(&dvert[i], defgrp_index);
431                 if (_dw) {
432                         tidx[numIdx] = i;
433                         tw[numIdx] = _dw->weight;
434                         tdw[numIdx++] = _dw;
435                 }
436         }
437         /* If no vertices found, return org data! */
438         if (numIdx == 0) {
439                 MEM_freeN(tidx);
440                 MEM_freeN(tw);
441                 MEM_freeN(tdw);
442                 return mesh;
443         }
444         if (numIdx != numVerts) {
445                 indices = MEM_malloc_arrayN(numIdx, sizeof(int), "WeightVGProximity Modifier, indices");
446                 memcpy(indices, tidx, sizeof(int) * numIdx);
447                 org_w = MEM_malloc_arrayN(numIdx, sizeof(float), "WeightVGProximity Modifier, org_w");
448                 memcpy(org_w, tw, sizeof(float) * numIdx);
449                 dw = MEM_malloc_arrayN(numIdx, sizeof(MDeformWeight *), "WeightVGProximity Modifier, dw");
450                 memcpy(dw, tdw, sizeof(MDeformWeight *) * numIdx);
451                 MEM_freeN(tw);
452                 MEM_freeN(tdw);
453         }
454         else {
455                 org_w = tw;
456                 dw = tdw;
457         }
458         new_w = MEM_malloc_arrayN(numIdx, sizeof(float), "WeightVGProximity Modifier, new_w");
459         MEM_freeN(tidx);
460
461         /* Get our vertex coordinates. */
462         if (numIdx != numVerts) {
463                 float (*tv_cos)[3] = BKE_mesh_vertexCos_get(mesh, NULL);
464                 v_cos = MEM_malloc_arrayN(numIdx, sizeof(float[3]), "WeightVGProximity Modifier, v_cos");
465                 for (i = 0; i < numIdx; i++) {
466                         copy_v3_v3(v_cos[i], tv_cos[indices[i]]);
467                 }
468                 MEM_freeN(tv_cos);
469         }
470         else {
471                 v_cos = BKE_mesh_vertexCos_get(mesh, NULL);
472         }
473
474         /* Compute wanted distances. */
475         if (wmd->proximity_mode == MOD_WVG_PROXIMITY_OBJECT) {
476                 const float dist = get_ob2ob_distance(ob, obr);
477                 for (i = 0; i < numIdx; i++) {
478                         new_w[i] = dist;
479                 }
480         }
481         else if (wmd->proximity_mode == MOD_WVG_PROXIMITY_GEOMETRY) {
482                 const bool use_trgt_verts = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_VERTS) != 0;
483                 const bool use_trgt_edges = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_EDGES) != 0;
484                 const bool use_trgt_faces = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_FACES) != 0;
485
486                 if (use_trgt_verts || use_trgt_edges || use_trgt_faces) {
487                         Mesh *target_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(obr, false);
488
489                         /* We must check that we do have a valid target_mesh! */
490                         if (target_mesh != NULL) {
491                                 SpaceTransform loc2trgt;
492                                 float *dists_v = use_trgt_verts ? MEM_malloc_arrayN(numIdx, sizeof(float), "dists_v") : NULL;
493                                 float *dists_e = use_trgt_edges ? MEM_malloc_arrayN(numIdx, sizeof(float), "dists_e") : NULL;
494                                 float *dists_f = use_trgt_faces ? MEM_malloc_arrayN(numIdx, sizeof(float), "dists_f") : NULL;
495
496                                 BLI_SPACE_TRANSFORM_SETUP(&loc2trgt, ob, obr);
497                                 get_vert2geom_distance(numIdx, v_cos, dists_v, dists_e, dists_f,
498                                                        target_mesh, &loc2trgt);
499                                 for (i = 0; i < numIdx; i++) {
500                                         new_w[i] = dists_v ? dists_v[i] : FLT_MAX;
501                                         if (dists_e)
502                                                 new_w[i] = min_ff(dists_e[i], new_w[i]);
503                                         if (dists_f)
504                                                 new_w[i] = min_ff(dists_f[i], new_w[i]);
505                                 }
506
507                                 MEM_SAFE_FREE(dists_v);
508                                 MEM_SAFE_FREE(dists_e);
509                                 MEM_SAFE_FREE(dists_f);
510                         }
511                         /* Else, fall back to default obj2vert behavior. */
512                         else {
513                                 get_vert2ob_distance(numIdx, v_cos, new_w, ob, obr);
514                         }
515                 }
516                 else {
517                         get_vert2ob_distance(numIdx, v_cos, new_w, ob, obr);
518                 }
519         }
520
521         /* Map distances to weights. */
522         do_map(ob, new_w, numIdx, wmd->min_dist, wmd->max_dist, wmd->falloff_type);
523
524         /* Do masking. */
525         struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
526         weightvg_do_mask(ctx, numIdx, indices, org_w, new_w, ob, mesh, wmd->mask_constant,
527                          wmd->mask_defgrp_name, scene, wmd->mask_texture,
528                          wmd->mask_tex_use_channel, wmd->mask_tex_mapping,
529                          wmd->mask_tex_map_obj, wmd->mask_tex_uvlayer_name);
530
531         /* Update vgroup. Note we never add nor remove vertices from vgroup here. */
532         weightvg_update_vg(dvert, defgrp_index, dw, numIdx, indices, org_w, false, 0.0f, false, 0.0f);
533
534         /* If weight preview enabled... */
535 #if 0 /* XXX Currently done in mod stack :/ */
536         if (do_prev)
537                 DM_update_weight_mcol(ob, dm, 0, org_w, numIdx, indices);
538 #endif
539
540         /* Freeing stuff. */
541         MEM_freeN(org_w);
542         MEM_freeN(new_w);
543         MEM_freeN(dw);
544         MEM_freeN(v_cos);
545         MEM_SAFE_FREE(indices);
546
547 #ifdef USE_TIMEIT
548         TIMEIT_END(perf);
549 #endif
550
551         /* Return the vgroup-modified mesh. */
552         return mesh;
553 }
554
555
556 ModifierTypeInfo modifierType_WeightVGProximity = {
557         /* name */              "VertexWeightProximity",
558         /* structName */        "WeightVGProximityModifierData",
559         /* structSize */        sizeof(WeightVGProximityModifierData),
560         /* type */              eModifierTypeType_NonGeometrical,
561         /* flags */             eModifierTypeFlag_AcceptsMesh |
562                                 eModifierTypeFlag_SupportsMapping |
563                                 eModifierTypeFlag_SupportsEditmode |
564                                 eModifierTypeFlag_UsesPreview,
565
566         /* copyData */          modifier_copyData_generic,
567
568         /* deformVerts_DM */    NULL,
569         /* deformMatrices_DM */ NULL,
570         /* deformVertsEM_DM */  NULL,
571         /* deformMatricesEM_DM*/NULL,
572         /* applyModifier_DM */  NULL,
573
574         /* deformVerts */       NULL,
575         /* deformMatrices */    NULL,
576         /* deformVertsEM */     NULL,
577         /* deformMatricesEM */  NULL,
578         /* applyModifier */     applyModifier,
579
580         /* initData */          initData,
581         /* requiredDataMask */  requiredDataMask,
582         /* freeData */          NULL,
583         /* isDisabled */        isDisabled,
584         /* updateDepsgraph */   updateDepsgraph,
585         /* dependsOnTime */     dependsOnTime,
586         /* dependsOnNormals */  NULL,
587         /* foreachObjectLink */ foreachObjectLink,
588         /* foreachIDLink */     foreachIDLink,
589         /* foreachTexLink */    foreachTexLink,
590 };