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