Merge branch 'master' into blender2.8
[blender.git] / source / blender / modifiers / intern / MOD_laplaciansmooth.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) 2005 by the Blender Foundation.
19  * All rights reserved.
20  *
21  * Contributor(s): Alexander Pinzon
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  *
25  */
26
27 /** \file blender/modifiers/intern/MOD_laplaciansmooth.c
28  *  \ingroup modifiers
29  */
30
31
32 #include "DNA_meshdata_types.h"
33 #include "DNA_object_types.h"
34
35 #include "BLI_math.h"
36 #include "BLI_utildefines.h"
37
38 #include "MEM_guardedalloc.h"
39
40 #include "BKE_cdderivedmesh.h"
41 #include "BKE_deform.h"
42 #include "BKE_modifier.h"
43
44 #include "MOD_util.h"
45
46 #include "eigen_capi.h"
47
48 #if 0
49 #define MOD_LAPLACIANSMOOTH_MAX_EDGE_PERCENTAGE 1.8f
50 #define MOD_LAPLACIANSMOOTH_MIN_EDGE_PERCENTAGE 0.02f
51 #endif
52
53 struct BLaplacianSystem {
54         float *eweights;        /* Length weights per Edge */
55         float (*fweights)[3];   /* Cotangent weights per face */
56         float *ring_areas;      /* Total area per ring*/
57         float *vlengths;        /* Total sum of lengths(edges) per vertice*/
58         float *vweights;        /* Total sum of weights per vertice*/
59         int numEdges;           /* Number of edges*/
60         int numLoops;           /* Number of edges*/
61         int numPolys;           /* Number of faces*/
62         int numVerts;           /* Number of verts*/
63         short *numNeFa;         /* Number of neighboors faces around vertice*/
64         short *numNeEd;         /* Number of neighboors Edges around vertice*/
65         short *zerola;          /* Is zero area or length*/
66
67         /* Pointers to data*/
68         float (*vertexCos)[3];
69         const MPoly *mpoly;
70         const MLoop *mloop;
71         const MEdge *medges;
72         LinearSolver *context;
73
74         /*Data*/
75         float min_area;
76         float vert_centroid[3];
77 };
78 typedef struct BLaplacianSystem LaplacianSystem;
79
80 static CustomDataMask required_data_mask(Object *ob, ModifierData *md);
81 static bool is_disabled(ModifierData *md, int useRenderParams);
82 static float compute_volume(const float center[3], float (*vertexCos)[3], const MPoly *mpoly, int numPolys, const MLoop *mloop);
83 static LaplacianSystem *init_laplacian_system(int a_numEdges, int a_numPolys, int a_numLoops, int a_numVerts);
84 static void delete_laplacian_system(LaplacianSystem *sys);
85 static void fill_laplacian_matrix(LaplacianSystem *sys);
86 static void init_data(ModifierData *md);
87 static void init_laplacian_matrix(LaplacianSystem *sys);
88 static void memset_laplacian_system(LaplacianSystem *sys, int val);
89 static void volume_preservation(LaplacianSystem *sys, float vini, float vend, short flag);
90 static void validate_solution(LaplacianSystem *sys, short flag, float lambda, float lambda_border);
91
92 static void delete_laplacian_system(LaplacianSystem *sys)
93 {
94         MEM_SAFE_FREE(sys->eweights);
95         MEM_SAFE_FREE(sys->fweights);
96         MEM_SAFE_FREE(sys->numNeEd);
97         MEM_SAFE_FREE(sys->numNeFa);
98         MEM_SAFE_FREE(sys->ring_areas);
99         MEM_SAFE_FREE(sys->vlengths);
100         MEM_SAFE_FREE(sys->vweights);
101         MEM_SAFE_FREE(sys->zerola);
102
103         if (sys->context) {
104                 EIG_linear_solver_delete(sys->context);
105         }
106         sys->vertexCos = NULL;
107         sys->mpoly = NULL;
108         sys->mloop = NULL;
109         sys->medges = NULL;
110         MEM_freeN(sys);
111 }
112
113 static void memset_laplacian_system(LaplacianSystem *sys, int val)
114 {
115         memset(sys->eweights,     val, sizeof(float) * sys->numEdges);
116         memset(sys->fweights,     val, sizeof(float[3]) * sys->numLoops);
117         memset(sys->numNeEd,      val, sizeof(short) * sys->numVerts);
118         memset(sys->numNeFa,      val, sizeof(short) * sys->numVerts);
119         memset(sys->ring_areas,   val, sizeof(float) * sys->numVerts);
120         memset(sys->vlengths,     val, sizeof(float) * sys->numVerts);
121         memset(sys->vweights,     val, sizeof(float) * sys->numVerts);
122         memset(sys->zerola,       val, sizeof(short) * sys->numVerts);
123 }
124
125 static LaplacianSystem *init_laplacian_system(int a_numEdges, int a_numPolys, int a_numLoops, int a_numVerts)
126 {
127         LaplacianSystem *sys;
128         sys = MEM_callocN(sizeof(LaplacianSystem), "ModLaplSmoothSystem");
129         sys->numEdges = a_numEdges;
130         sys->numPolys = a_numPolys;
131         sys->numLoops = a_numLoops;
132         sys->numVerts = a_numVerts;
133
134         sys->eweights =  MEM_calloc_arrayN(sys->numEdges, sizeof(float), __func__);
135         sys->fweights =  MEM_calloc_arrayN(sys->numLoops, sizeof(float[3]), __func__);
136         sys->numNeEd =  MEM_calloc_arrayN(sys->numVerts, sizeof(short), __func__);
137         sys->numNeFa =  MEM_calloc_arrayN(sys->numVerts, sizeof(short), __func__);
138         sys->ring_areas =  MEM_calloc_arrayN(sys->numVerts, sizeof(float), __func__);
139         sys->vlengths =  MEM_calloc_arrayN(sys->numVerts, sizeof(float), __func__);
140         sys->vweights =  MEM_calloc_arrayN(sys->numVerts, sizeof(float), __func__);
141         sys->zerola =  MEM_calloc_arrayN(sys->numVerts, sizeof(short), __func__);
142
143         return sys;
144 }
145
146 static float compute_volume(
147         const float center[3], float (*vertexCos)[3],
148         const MPoly *mpoly, int numPolys, const MLoop *mloop)
149 {
150         int i;
151         float vol = 0.0f;
152
153         for (i = 0; i < numPolys; i++) {
154                 const MPoly *mp = &mpoly[i];
155                 const MLoop *l_first = &mloop[mp->loopstart];
156                 const MLoop *l_prev = l_first + 1;
157                 const MLoop *l_curr = l_first + 2;
158                 const MLoop *l_term = l_first + mp->totloop;
159
160
161                 for (;
162                      l_curr != l_term;
163                      l_prev = l_curr, l_curr++)
164                 {
165                         vol += volume_tetrahedron_signed_v3(
166                                 center,
167                                 vertexCos[l_first->v],
168                                 vertexCos[l_prev->v],
169                                 vertexCos[l_curr->v]);
170                 }
171         }
172
173         return fabsf(vol);
174 }
175
176 static void volume_preservation(LaplacianSystem *sys, float vini, float vend, short flag)
177 {
178         float beta;
179         int i;
180
181         if (vend != 0.0f) {
182                 beta  = pow(vini / vend, 1.0f / 3.0f);
183                 for (i = 0; i < sys->numVerts; i++) {
184                         if (flag & MOD_LAPLACIANSMOOTH_X) {
185                                 sys->vertexCos[i][0] = (sys->vertexCos[i][0] - sys->vert_centroid[0]) * beta + sys->vert_centroid[0];
186                         }
187                         if (flag & MOD_LAPLACIANSMOOTH_Y) {
188                                 sys->vertexCos[i][1] = (sys->vertexCos[i][1] - sys->vert_centroid[1]) * beta + sys->vert_centroid[1];
189                         }
190                         if (flag & MOD_LAPLACIANSMOOTH_Z) {
191                                 sys->vertexCos[i][2] = (sys->vertexCos[i][2] - sys->vert_centroid[2]) * beta + sys->vert_centroid[2];
192                         }
193
194                 }
195         }
196 }
197
198 static void init_laplacian_matrix(LaplacianSystem *sys)
199 {
200         float *v1, *v2;
201         float w1, w2, w3;
202         float areaf;
203         int i;
204         unsigned int idv1, idv2;
205
206         for (i = 0; i < sys->numEdges; i++) {
207                 idv1 = sys->medges[i].v1;
208                 idv2 = sys->medges[i].v2;
209
210                 v1 = sys->vertexCos[idv1];
211                 v2 = sys->vertexCos[idv2];
212
213                 sys->numNeEd[idv1] = sys->numNeEd[idv1] + 1;
214                 sys->numNeEd[idv2] = sys->numNeEd[idv2] + 1;
215                 w1 = len_v3v3(v1, v2);
216                 if (w1 < sys->min_area) {
217                         sys->zerola[idv1] = 1;
218                         sys->zerola[idv2] = 1;
219                 }
220                 else {
221                         w1 = 1.0f / w1;
222                 }
223
224                 sys->eweights[i] = w1;
225         }
226
227         for (i = 0; i < sys->numPolys; i++) {
228                 const MPoly *mp = &sys->mpoly[i];
229                 const MLoop *l_next = &sys->mloop[mp->loopstart];
230                 const MLoop *l_term = l_next + mp->totloop;
231                 const MLoop *l_prev = l_term - 2;
232                 const MLoop *l_curr = l_term - 1;
233
234                 for (;
235                      l_next != l_term;
236                      l_prev = l_curr, l_curr = l_next, l_next++)
237                 {
238                         const float *v_prev = sys->vertexCos[l_prev->v];
239                         const float *v_curr = sys->vertexCos[l_curr->v];
240                         const float *v_next = sys->vertexCos[l_next->v];
241                         const unsigned int l_curr_index = l_curr - sys->mloop;
242
243                         sys->numNeFa[l_curr->v] += 1;
244
245                         areaf = area_tri_v3(v_prev, v_curr, v_next);
246
247                         if (areaf < sys->min_area) {
248                                 sys->zerola[l_curr->v] = 1;
249                         }
250
251                         sys->ring_areas[l_prev->v] += areaf;
252                         sys->ring_areas[l_curr->v] += areaf;
253                         sys->ring_areas[l_next->v] += areaf;
254
255                         w1 = cotangent_tri_weight_v3(v_curr, v_next, v_prev) / 2.0f;
256                         w2 = cotangent_tri_weight_v3(v_next, v_prev, v_curr) / 2.0f;
257                         w3 = cotangent_tri_weight_v3(v_prev, v_curr, v_next) / 2.0f;
258
259                         sys->fweights[l_curr_index][0] += w1;
260                         sys->fweights[l_curr_index][1] += w2;
261                         sys->fweights[l_curr_index][2] += w3;
262
263                         sys->vweights[l_curr->v] += w2 + w3;
264                         sys->vweights[l_next->v] += w1 + w3;
265                         sys->vweights[l_prev->v] += w1 + w2;
266                 }
267         }
268         for (i = 0; i < sys->numEdges; i++) {
269                 idv1 = sys->medges[i].v1;
270                 idv2 = sys->medges[i].v2;
271                 /* if is boundary, apply scale-dependent umbrella operator only with neighboors in boundary */
272                 if (sys->numNeEd[idv1] != sys->numNeFa[idv1] && sys->numNeEd[idv2] != sys->numNeFa[idv2]) {
273                         sys->vlengths[idv1] += sys->eweights[i];
274                         sys->vlengths[idv2] += sys->eweights[i];
275                 }
276         }
277
278 }
279
280 static void fill_laplacian_matrix(LaplacianSystem *sys)
281 {
282         int i;
283         unsigned int idv1, idv2;
284
285         for (i = 0; i < sys->numPolys; i++) {
286                 const MPoly *mp = &sys->mpoly[i];
287                 const MLoop *l_next = &sys->mloop[mp->loopstart];
288                 const MLoop *l_term = l_next + mp->totloop;
289                 const MLoop *l_prev = l_term - 2;
290                 const MLoop *l_curr = l_term - 1;
291
292                 for (;
293                      l_next != l_term;
294                      l_prev = l_curr, l_curr = l_next, l_next++)
295                 {
296                         const unsigned int l_curr_index = l_curr - sys->mloop;
297
298                         /* Is ring if number of faces == number of edges around vertice*/
299                         if (sys->numNeEd[l_curr->v] == sys->numNeFa[l_curr->v] && sys->zerola[l_curr->v] == 0) {
300                                 EIG_linear_solver_matrix_add(sys->context, l_curr->v, l_next->v, sys->fweights[l_curr_index][2] * sys->vweights[l_curr->v]);
301                                 EIG_linear_solver_matrix_add(sys->context, l_curr->v, l_prev->v, sys->fweights[l_curr_index][1] * sys->vweights[l_curr->v]);
302                         }
303                         if (sys->numNeEd[l_next->v] == sys->numNeFa[l_next->v] && sys->zerola[l_next->v] == 0) {
304                                 EIG_linear_solver_matrix_add(sys->context, l_next->v, l_curr->v, sys->fweights[l_curr_index][2] * sys->vweights[l_next->v]);
305                                 EIG_linear_solver_matrix_add(sys->context, l_next->v, l_prev->v, sys->fweights[l_curr_index][0] * sys->vweights[l_next->v]);
306                         }
307                         if (sys->numNeEd[l_prev->v] == sys->numNeFa[l_prev->v] && sys->zerola[l_prev->v] == 0) {
308                                 EIG_linear_solver_matrix_add(sys->context, l_prev->v, l_curr->v, sys->fweights[l_curr_index][1] * sys->vweights[l_prev->v]);
309                                 EIG_linear_solver_matrix_add(sys->context, l_prev->v, l_next->v, sys->fweights[l_curr_index][0] * sys->vweights[l_prev->v]);
310                         }
311                 }
312         }
313
314         for (i = 0; i < sys->numEdges; i++) {
315                 idv1 = sys->medges[i].v1;
316                 idv2 = sys->medges[i].v2;
317                 /* Is boundary */
318                 if (sys->numNeEd[idv1] != sys->numNeFa[idv1] &&
319                     sys->numNeEd[idv2] != sys->numNeFa[idv2] &&
320                     sys->zerola[idv1] == 0 &&
321                     sys->zerola[idv2] == 0)
322                 {
323                         EIG_linear_solver_matrix_add(sys->context, idv1, idv2, sys->eweights[i] * sys->vlengths[idv1]);
324                         EIG_linear_solver_matrix_add(sys->context, idv2, idv1, sys->eweights[i] * sys->vlengths[idv2]);
325                 }
326         }
327 }
328
329 static void validate_solution(LaplacianSystem *sys, short flag, float lambda, float lambda_border)
330 {
331         int i;
332         float lam;
333         float vini, vend;
334
335         if (flag & MOD_LAPLACIANSMOOTH_PRESERVE_VOLUME) {
336                 vini = compute_volume(sys->vert_centroid, sys->vertexCos, sys->mpoly, sys->numPolys, sys->mloop);
337         }
338         for (i = 0; i < sys->numVerts; i++) {
339                 if (sys->zerola[i] == 0) {
340                         lam = sys->numNeEd[i] == sys->numNeFa[i] ? (lambda >= 0.0f ? 1.0f : -1.0f) : (lambda_border >= 0.0f ? 1.0f : -1.0f);
341                         if (flag & MOD_LAPLACIANSMOOTH_X) {
342                                 sys->vertexCos[i][0] += lam * ((float)EIG_linear_solver_variable_get(sys->context, 0, i) - sys->vertexCos[i][0]);
343                         }
344                         if (flag & MOD_LAPLACIANSMOOTH_Y) {
345                                 sys->vertexCos[i][1] += lam * ((float)EIG_linear_solver_variable_get(sys->context, 1, i) - sys->vertexCos[i][1]);
346                         }
347                         if (flag & MOD_LAPLACIANSMOOTH_Z) {
348                                 sys->vertexCos[i][2] += lam * ((float)EIG_linear_solver_variable_get(sys->context, 2, i) - sys->vertexCos[i][2]);
349                         }
350                 }
351         }
352         if (flag & MOD_LAPLACIANSMOOTH_PRESERVE_VOLUME) {
353                 vend = compute_volume(sys->vert_centroid, sys->vertexCos, sys->mpoly, sys->numPolys, sys->mloop);
354                 volume_preservation(sys, vini, vend, flag);
355         }
356 }
357
358 static void laplaciansmoothModifier_do(
359         LaplacianSmoothModifierData *smd, Object *ob, DerivedMesh *dm,
360         float (*vertexCos)[3], int numVerts)
361 {
362         LaplacianSystem *sys;
363         MDeformVert *dvert = NULL;
364         MDeformVert *dv = NULL;
365         float w, wpaint;
366         int i, iter;
367         int defgrp_index;
368
369         sys = init_laplacian_system(dm->getNumEdges(dm), dm->getNumPolys(dm), dm->getNumLoops(dm), numVerts);
370         if (!sys) {
371                 return;
372         }
373
374         sys->mpoly = dm->getPolyArray(dm);
375         sys->mloop = dm->getLoopArray(dm);
376         sys->medges = dm->getEdgeArray(dm);
377         sys->vertexCos = vertexCos;
378         sys->min_area = 0.00001f;
379         modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index);
380
381         sys->vert_centroid[0] = 0.0f;
382         sys->vert_centroid[1] = 0.0f;
383         sys->vert_centroid[2] = 0.0f;
384         memset_laplacian_system(sys, 0);
385
386         sys->context = EIG_linear_least_squares_solver_new(numVerts, numVerts, 3);
387
388         init_laplacian_matrix(sys);
389
390         for (iter = 0; iter < smd->repeat; iter++) {
391                 for (i = 0; i < numVerts; i++) {
392                         EIG_linear_solver_variable_set(sys->context, 0, i, vertexCos[i][0]);
393                         EIG_linear_solver_variable_set(sys->context, 1, i, vertexCos[i][1]);
394                         EIG_linear_solver_variable_set(sys->context, 2, i, vertexCos[i][2]);
395                         if (iter == 0) {
396                                 add_v3_v3(sys->vert_centroid, vertexCos[i]);
397                         }
398                 }
399                 if (iter == 0 && numVerts > 0) {
400                         mul_v3_fl(sys->vert_centroid, 1.0f / (float)numVerts);
401                 }
402
403                 dv = dvert;
404                 for (i = 0; i < numVerts; i++) {
405                         EIG_linear_solver_right_hand_side_add(sys->context, 0, i, vertexCos[i][0]);
406                         EIG_linear_solver_right_hand_side_add(sys->context, 1, i, vertexCos[i][1]);
407                         EIG_linear_solver_right_hand_side_add(sys->context, 2, i, vertexCos[i][2]);
408                         if (iter == 0) {
409                                 if (dv) {
410                                         wpaint = defvert_find_weight(dv, defgrp_index);
411                                         dv++;
412                                 }
413                                 else {
414                                         wpaint = 1.0f;
415                                 }
416
417                                 if (sys->zerola[i] == 0) {
418                                         if (smd->flag & MOD_LAPLACIANSMOOTH_NORMALIZED) {
419                                                 w = sys->vweights[i];
420                                                 sys->vweights[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda) * wpaint / w;
421                                                 w = sys->vlengths[i];
422                                                 sys->vlengths[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda_border) * wpaint * 2.0f / w;
423                                                 if (sys->numNeEd[i] == sys->numNeFa[i]) {
424                                                         EIG_linear_solver_matrix_add(sys->context, i, i,  1.0f + fabsf(smd->lambda) * wpaint);
425                                                 }
426                                                 else {
427                                                         EIG_linear_solver_matrix_add(sys->context, i, i,  1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f);
428                                                 }
429                                         }
430                                         else {
431                                                 w = sys->vweights[i] * sys->ring_areas[i];
432                                                 sys->vweights[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda) * wpaint / (4.0f * w);
433                                                 w = sys->vlengths[i];
434                                                 sys->vlengths[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda_border) * wpaint * 2.0f / w;
435
436                                                 if (sys->numNeEd[i] == sys->numNeFa[i]) {
437                                                         EIG_linear_solver_matrix_add(sys->context, i, i,  1.0f + fabsf(smd->lambda) * wpaint / (4.0f * sys->ring_areas[i]));
438                                                 }
439                                                 else {
440                                                         EIG_linear_solver_matrix_add(sys->context, i, i,  1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f);
441                                                 }
442                                         }
443                                 }
444                                 else {
445                                         EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f);
446                                 }
447                         }
448                 }
449
450                 if (iter == 0) {
451                         fill_laplacian_matrix(sys);
452                 }
453
454                 if (EIG_linear_solver_solve(sys->context)) {
455                         validate_solution(sys, smd->flag, smd->lambda, smd->lambda_border);
456                 }
457         }
458         EIG_linear_solver_delete(sys->context);
459         sys->context = NULL;
460
461         delete_laplacian_system(sys);
462 }
463
464 static void init_data(ModifierData *md)
465 {
466         LaplacianSmoothModifierData *smd = (LaplacianSmoothModifierData *) md;
467         smd->lambda = 0.01f;
468         smd->lambda_border = 0.01f;
469         smd->repeat = 1;
470         smd->flag = MOD_LAPLACIANSMOOTH_X | MOD_LAPLACIANSMOOTH_Y | MOD_LAPLACIANSMOOTH_Z | MOD_LAPLACIANSMOOTH_PRESERVE_VOLUME | MOD_LAPLACIANSMOOTH_NORMALIZED;
471         smd->defgrp_name[0] = '\0';
472 }
473
474 static bool is_disabled(ModifierData *md, int UNUSED(useRenderParams))
475 {
476         LaplacianSmoothModifierData *smd = (LaplacianSmoothModifierData *) md;
477         short flag;
478
479         flag = smd->flag & (MOD_LAPLACIANSMOOTH_X | MOD_LAPLACIANSMOOTH_Y | MOD_LAPLACIANSMOOTH_Z);
480
481         /* disable if modifier is off for X, Y and Z or if factor is 0 */
482         if (flag == 0) return 1;
483
484         return 0;
485 }
486
487 static CustomDataMask required_data_mask(Object *UNUSED(ob), ModifierData *md)
488 {
489         LaplacianSmoothModifierData *smd = (LaplacianSmoothModifierData *)md;
490         CustomDataMask dataMask = 0;
491
492         /* ask for vertexgroups if we need them */
493         if (smd->defgrp_name[0]) dataMask |= CD_MASK_MDEFORMVERT;
494
495         return dataMask;
496 }
497
498 static void deformVerts(ModifierData *md, const ModifierEvalContext *ctx, DerivedMesh *derivedData,
499                         float (*vertexCos)[3], int numVerts)
500 {
501         DerivedMesh *dm;
502
503         if (numVerts == 0)
504                 return;
505
506         dm = get_dm(ctx->object, NULL, derivedData, NULL, false, false);
507
508         laplaciansmoothModifier_do((LaplacianSmoothModifierData *)md, ctx->object, dm,
509                                    vertexCos, numVerts);
510
511         if (dm != derivedData)
512                 dm->release(dm);
513 }
514
515 static void deformVertsEM(
516         ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *editData,
517         DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
518 {
519         DerivedMesh *dm;
520
521         if (numVerts == 0)
522                 return;
523
524         dm = get_dm(ctx->object, editData, derivedData, NULL, false, false);
525
526         laplaciansmoothModifier_do((LaplacianSmoothModifierData *)md, ctx->object, dm,
527                                    vertexCos, numVerts);
528
529         if (dm != derivedData)
530                 dm->release(dm);
531 }
532
533
534 ModifierTypeInfo modifierType_LaplacianSmooth = {
535         /* name */              "Laplacian Smooth",
536         /* structName */        "LaplacianSmoothModifierData",
537         /* structSize */        sizeof(LaplacianSmoothModifierData),
538         /* type */              eModifierTypeType_OnlyDeform,
539         /* flags */             eModifierTypeFlag_AcceptsMesh |
540                                 eModifierTypeFlag_SupportsEditmode,
541
542         /* copyData */          modifier_copyData_generic,
543
544         /* deformVerts_DM */    deformVerts,
545         /* deformMatrices_DM */ NULL,
546         /* deformVertsEM_DM */  deformVertsEM,
547         /* deformMatricesEM_DM*/NULL,
548         /* applyModifier_DM */  NULL,
549         /* applyModifierEM_DM */NULL,
550
551         /* deformVerts */       NULL,
552         /* deformMatrices */    NULL,
553         /* deformVertsEM */     NULL,
554         /* deformMatricesEM */  NULL,
555         /* applyModifier */     NULL,
556         /* applyModifierEM */   NULL,
557
558         /* initData */          init_data,
559         /* requiredDataMask */  required_data_mask,
560         /* freeData */          NULL,
561         /* isDisabled */        is_disabled,
562         /* updateDepsgraph */   NULL,
563         /* dependsOnTime */     NULL,
564         /* dependsOnNormals */  NULL,
565         /* foreachObjectLink */ NULL,
566         /* foreachIDLink */     NULL,
567         /* foreachTexLink */    NULL,
568 };