Depsgraph: Add utility function for transform dependency
[blender.git] / source / blender / modifiers / intern / MOD_screw.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) 2005 by the Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file \ingroup modifiers
21  */
22
23
24 /* Screw modifier: revolves the edges about an axis */
25 #include <limits.h>
26
27 #include "DNA_mesh_types.h"
28 #include "DNA_meshdata_types.h"
29 #include "DNA_object_types.h"
30
31 #include "BLI_math.h"
32 #include "BLI_alloca.h"
33 #include "BLI_utildefines.h"
34
35 #include "BKE_library_query.h"
36 #include "BKE_mesh.h"
37
38 #include "DEG_depsgraph_build.h"
39 #include "DEG_depsgraph_query.h"
40
41 #include "MOD_modifiertypes.h"
42 #include "MEM_guardedalloc.h"
43
44 #include "BLI_strict_flags.h"
45
46 /* used for gathering edge connectivity */
47 typedef struct ScrewVertConnect {
48         float dist;  /* distance from the center axis */
49         float co[3]; /* location relative to the transformed axis */
50         float no[3]; /* calc normal of the vertex */
51         unsigned int v[2]; /* 2  verts on either side of this one */
52         MEdge *e[2]; /* edges on either side, a bit of a waste since each edge ref's 2 edges */
53         char flag;
54 } ScrewVertConnect;
55
56 typedef struct ScrewVertIter {
57         ScrewVertConnect *v_array;
58         ScrewVertConnect *v_poin;
59         unsigned int v, v_other;
60         MEdge *e;
61 } ScrewVertIter;
62
63 #define SV_UNUSED (UINT_MAX)
64 #define SV_INVALID ((UINT_MAX) - 1)
65 #define SV_IS_VALID(v) ((v) < SV_INVALID)
66
67 static void screwvert_iter_init(ScrewVertIter *iter, ScrewVertConnect *array, unsigned int v_init, unsigned int dir)
68 {
69         iter->v_array = array;
70         iter->v = v_init;
71
72         if (SV_IS_VALID(v_init)) {
73                 iter->v_poin = &array[v_init];
74                 iter->v_other = iter->v_poin->v[dir];
75                 iter->e = iter->v_poin->e[!dir];
76         }
77         else {
78                 iter->v_poin = NULL;
79                 iter->e = NULL;
80         }
81 }
82
83
84 static void screwvert_iter_step(ScrewVertIter *iter)
85 {
86         if (iter->v_poin->v[0] == iter->v_other) {
87                 iter->v_other = iter->v;
88                 iter->v = iter->v_poin->v[1];
89         }
90         else if (iter->v_poin->v[1] == iter->v_other) {
91                 iter->v_other = iter->v;
92                 iter->v = iter->v_poin->v[0];
93         }
94         if (SV_IS_VALID(iter->v)) {
95                 iter->v_poin = &iter->v_array[iter->v];
96                 iter->e = iter->v_poin->e[(iter->v_poin->e[0] == iter->e)];
97         }
98         else {
99                 iter->e = NULL;
100                 iter->v_poin = NULL;
101         }
102 }
103
104 static Mesh *mesh_remove_doubles_on_axis(
105         Mesh *result, MVert *mvert_new, const uint totvert, const uint step_tot,
106         const float axis_vec[3], const float axis_offset[3], const float merge_threshold)
107 {
108         const float merge_threshold_sq = SQUARE(merge_threshold);
109         const bool use_offset = axis_offset != NULL;
110         uint tot_doubles = 0;
111         for (uint i = 0; i < totvert; i += 1) {
112                 float axis_co[3];
113                 if (use_offset) {
114                         float offset_co[3];
115                         sub_v3_v3v3(offset_co, mvert_new[i].co, axis_offset);
116                         project_v3_v3v3_normalized(axis_co, offset_co, axis_vec);
117                         add_v3_v3(axis_co, axis_offset);
118                 }
119                 else {
120                         project_v3_v3v3_normalized(axis_co, mvert_new[i].co, axis_vec);
121                 }
122                 const float dist_sq = len_squared_v3v3(axis_co, mvert_new[i].co);
123                 if (dist_sq <= merge_threshold_sq) {
124                         mvert_new[i].flag |= ME_VERT_TMP_TAG;
125                         tot_doubles += 1;
126                         copy_v3_v3(mvert_new[i].co, axis_co);
127                 }
128         }
129
130         if (tot_doubles != 0) {
131                 uint tot = totvert * step_tot;
132                 int *full_doubles_map = MEM_malloc_arrayN(tot, sizeof(int), __func__);
133                 copy_vn_i(full_doubles_map, (int)tot, -1);
134
135                 uint tot_doubles_left = tot_doubles;
136                 for (uint i = 0; i < totvert; i += 1) {
137                         if (mvert_new[i].flag & ME_VERT_TMP_TAG) {
138                                 int *doubles_map = &full_doubles_map[totvert + i] ;
139                                 for (uint step = 1; step < step_tot; step += 1) {
140                                         *doubles_map = (int)i;
141                                         doubles_map += totvert;
142                                 }
143                                 tot_doubles_left -= 1;
144                                 if (tot_doubles_left == 0) {
145                                         break;
146                                 }
147                         }
148                 }
149                 result = BKE_mesh_merge_verts(result, full_doubles_map, (int)(tot_doubles * (step_tot - 1)), MESH_MERGE_VERTS_DUMP_IF_MAPPED);
150                 MEM_freeN(full_doubles_map);
151         }
152         return result;
153 }
154
155 static void initData(ModifierData *md)
156 {
157         ScrewModifierData *ltmd = (ScrewModifierData *) md;
158         ltmd->ob_axis = NULL;
159         ltmd->angle = (float)(M_PI * 2.0);
160         ltmd->axis = 2;
161         ltmd->flag = MOD_SCREW_SMOOTH_SHADING;
162         ltmd->steps = 16;
163         ltmd->render_steps = 16;
164         ltmd->iter = 1;
165         ltmd->merge_dist = 0.01f;
166 }
167
168 static Mesh *applyModifier(
169         ModifierData *md, const ModifierEvalContext *ctx,
170         Mesh *meshData)
171 {
172         Mesh *mesh = meshData;
173         Mesh *result;
174         ScrewModifierData *ltmd = (ScrewModifierData *) md;
175         const bool use_render_params = (ctx->flag & MOD_APPLY_RENDER) != 0;
176
177         int *origindex;
178         int mpoly_index = 0;
179         unsigned int step;
180         unsigned int i, j;
181         unsigned int i1, i2;
182         unsigned int step_tot = use_render_params ? ltmd->render_steps : ltmd->steps;
183         const bool do_flip = (ltmd->flag & MOD_SCREW_NORMAL_FLIP) != 0;
184
185         const int quad_ord[4] = {
186             do_flip ? 3 : 0,
187             do_flip ? 2 : 1,
188             do_flip ? 1 : 2,
189             do_flip ? 0 : 3,
190         };
191         const int quad_ord_ofs[4] = {
192             do_flip ? 2 : 0,
193             1,
194             do_flip ? 0 : 2,
195             3,
196         };
197
198         unsigned int maxVerts = 0, maxEdges = 0, maxPolys = 0;
199         const unsigned int totvert = (unsigned int)mesh->totvert;
200         const unsigned int totedge = (unsigned int)mesh->totedge;
201         const unsigned int totpoly = (unsigned int)mesh->totpoly;
202
203         unsigned int *edge_poly_map = NULL;  /* orig edge to orig poly */
204         unsigned int *vert_loop_map = NULL;  /* orig vert to orig loop */
205
206         /* UV Coords */
207         const unsigned int mloopuv_layers_tot = (unsigned int)CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV);
208         MLoopUV **mloopuv_layers = BLI_array_alloca(mloopuv_layers, mloopuv_layers_tot);
209         float uv_u_scale;
210         float uv_v_minmax[2] = {FLT_MAX, -FLT_MAX};
211         float uv_v_range_inv;
212         float uv_axis_plane[4];
213
214         char axis_char = 'X';
215         bool close;
216         float angle = ltmd->angle;
217         float screw_ofs = ltmd->screw_ofs;
218         float axis_vec[3] = {0.0f, 0.0f, 0.0f};
219         float tmp_vec1[3], tmp_vec2[3];
220         float mat3[3][3];
221         /* transform the coords by an object relative to this objects transformation */
222         float mtx_tx[4][4];
223         float mtx_tx_inv[4][4]; /* inverted */
224         float mtx_tmp_a[4][4];
225
226         unsigned int vc_tot_linked = 0;
227         short other_axis_1, other_axis_2;
228         const float *tmpf1, *tmpf2;
229
230         unsigned int edge_offset;
231
232         MPoly *mpoly_orig, *mpoly_new, *mp_new;
233         MLoop *mloop_orig, *mloop_new, *ml_new;
234         MEdge *medge_orig, *med_orig, *med_new, *med_new_firstloop, *medge_new;
235         MVert *mvert_new, *mvert_orig, *mv_orig, *mv_new, *mv_new_base;
236
237         Object *ob_axis = DEG_get_evaluated_object(ctx->depsgraph, ltmd->ob_axis);
238
239         ScrewVertConnect *vc, *vc_tmp, *vert_connect = NULL;
240
241         const char mpoly_flag = (ltmd->flag & MOD_SCREW_SMOOTH_SHADING) ? ME_SMOOTH : 0;
242
243         /* don't do anything? */
244         if (!totvert)
245                 return BKE_mesh_new_nomain_from_template(mesh, 0, 0, 0, 0, 0);
246
247         switch (ltmd->axis) {
248                 case 0:
249                         other_axis_1 = 1;
250                         other_axis_2 = 2;
251                         break;
252                 case 1:
253                         other_axis_1 = 0;
254                         other_axis_2 = 2;
255                         break;
256                 default: /* 2, use default to quiet warnings */
257                         other_axis_1 = 0;
258                         other_axis_2 = 1;
259                         break;
260         }
261
262         axis_vec[ltmd->axis] = 1.0f;
263
264         if (ob_axis != NULL) {
265                 /* calc the matrix relative to the axis object */
266                 invert_m4_m4(mtx_tmp_a, ctx->object->obmat);
267                 copy_m4_m4(mtx_tx_inv, ob_axis->obmat);
268                 mul_m4_m4m4(mtx_tx, mtx_tmp_a, mtx_tx_inv);
269
270                 /* calc the axis vec */
271                 mul_mat3_m4_v3(mtx_tx, axis_vec); /* only rotation component */
272                 normalize_v3(axis_vec);
273
274                 /* screw */
275                 if (ltmd->flag & MOD_SCREW_OBJECT_OFFSET) {
276                         /* find the offset along this axis relative to this objects matrix */
277                         float totlen = len_v3(mtx_tx[3]);
278
279                         if (totlen != 0.0f) {
280                                 float zero[3] = {0.0f, 0.0f, 0.0f};
281                                 float cp[3];
282                                 screw_ofs = closest_to_line_v3(cp, mtx_tx[3], zero, axis_vec);
283                         }
284                         else {
285                                 screw_ofs = 0.0f;
286                         }
287                 }
288
289                 /* angle */
290
291 #if 0   /* can't include this, not predictable enough, though quite fun. */
292                 if (ltmd->flag & MOD_SCREW_OBJECT_ANGLE) {
293                         float mtx3_tx[3][3];
294                         copy_m3_m4(mtx3_tx, mtx_tx);
295
296                         float vec[3] = {0, 1, 0};
297                         float cross1[3];
298                         float cross2[3];
299                         cross_v3_v3v3(cross1, vec, axis_vec);
300
301                         mul_v3_m3v3(cross2, mtx3_tx, cross1);
302                         {
303                                 float c1[3];
304                                 float c2[3];
305                                 float axis_tmp[3];
306
307                                 cross_v3_v3v3(c1, cross2, axis_vec);
308                                 cross_v3_v3v3(c2, axis_vec, c1);
309
310
311                                 angle = angle_v3v3(cross1, c2);
312
313                                 cross_v3_v3v3(axis_tmp, cross1, c2);
314                                 normalize_v3(axis_tmp);
315
316                                 if (len_v3v3(axis_tmp, axis_vec) > 1.0f)
317                                         angle = -angle;
318
319                         }
320                 }
321 #endif
322         }
323         else {
324                 /* exis char is used by i_rotate*/
325                 axis_char = (char)(axis_char + ltmd->axis); /* 'X' + axis */
326
327                 /* useful to be able to use the axis vec in some cases still */
328                 zero_v3(axis_vec);
329                 axis_vec[ltmd->axis] = 1.0f;
330         }
331
332         /* apply the multiplier */
333         angle *= (float)ltmd->iter;
334         screw_ofs *= (float)ltmd->iter;
335         uv_u_scale = 1.0f / (float)(step_tot);
336
337         /* multiplying the steps is a bit tricky, this works best */
338         step_tot = ((step_tot + 1) * ltmd->iter) - (ltmd->iter - 1);
339
340         /* will the screw be closed?
341          * Note! smaller then FLT_EPSILON * 100 gives problems with float precision so its never closed. */
342         if (fabsf(screw_ofs) <= (FLT_EPSILON * 100.0f) &&
343             fabsf(fabsf(angle) - ((float)M_PI * 2.0f)) <= (FLT_EPSILON * 100.0f))
344         {
345                 close = 1;
346                 step_tot--;
347                 if (step_tot < 3) step_tot = 3;
348
349                 maxVerts = totvert  * step_tot;   /* -1 because we're joining back up */
350                 maxEdges = (totvert * step_tot) + /* these are the edges between new verts */
351                            (totedge * step_tot);  /* -1 because vert edges join */
352                 maxPolys = totedge * step_tot;
353
354                 screw_ofs = 0.0f;
355         }
356         else {
357                 close = 0;
358                 if (step_tot < 3) step_tot = 3;
359
360                 maxVerts =  totvert  * step_tot; /* -1 because we're joining back up */
361                 maxEdges =  (totvert * (step_tot - 1)) + /* these are the edges between new verts */
362                            (totedge * step_tot);  /* -1 because vert edges join */
363                 maxPolys =  totedge * (step_tot - 1);
364         }
365
366         if ((ltmd->flag & MOD_SCREW_UV_STRETCH_U) == 0) {
367                 uv_u_scale = (uv_u_scale / (float)ltmd->iter) * (angle / ((float)M_PI * 2.0f));
368         }
369
370         result = BKE_mesh_new_nomain_from_template(mesh, (int)maxVerts, (int)maxEdges, 0, (int)maxPolys * 4, (int)maxPolys);
371
372         /* copy verts from mesh */
373         mvert_orig =    mesh->mvert;
374         medge_orig =    mesh->medge;
375
376         mvert_new =     result->mvert;
377         mpoly_new =     result->mpoly;
378         mloop_new =     result->mloop;
379         medge_new =     result->medge;
380
381         if (!CustomData_has_layer(&result->pdata, CD_ORIGINDEX)) {
382                 CustomData_add_layer(&result->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, (int)maxPolys);
383         }
384
385         origindex = CustomData_get_layer(&result->pdata, CD_ORIGINDEX);
386
387         CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, (int)totvert);
388
389         if (mloopuv_layers_tot) {
390                 float zero_co[3] = {0};
391                 plane_from_point_normal_v3(uv_axis_plane, zero_co, axis_vec);
392         }
393
394         if (mloopuv_layers_tot) {
395                 unsigned int uv_lay;
396                 for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) {
397                         mloopuv_layers[uv_lay] = CustomData_get_layer_n(&result->ldata, CD_MLOOPUV, (int)uv_lay);
398                 }
399
400                 if (ltmd->flag & MOD_SCREW_UV_STRETCH_V) {
401                         for (i = 0, mv_orig = mvert_orig; i < totvert; i++, mv_orig++) {
402                                 const float v = dist_signed_squared_to_plane_v3(mv_orig->co, uv_axis_plane);
403                                 uv_v_minmax[0] = min_ff(v, uv_v_minmax[0]);
404                                 uv_v_minmax[1] = max_ff(v, uv_v_minmax[1]);
405                         }
406                         uv_v_minmax[0] = sqrtf_signed(uv_v_minmax[0]);
407                         uv_v_minmax[1] = sqrtf_signed(uv_v_minmax[1]);
408                 }
409
410                 uv_v_range_inv = uv_v_minmax[1] - uv_v_minmax[0];
411                 uv_v_range_inv = uv_v_range_inv ? 1.0f / uv_v_range_inv : 0.0f;
412         }
413
414         /* Set the locations of the first set of verts */
415
416         mv_new = mvert_new;
417         mv_orig = mvert_orig;
418
419         /* Copy the first set of edges */
420         med_orig = medge_orig;
421         med_new = medge_new;
422         for (i = 0; i < totedge; i++, med_orig++, med_new++) {
423                 med_new->v1 = med_orig->v1;
424                 med_new->v2 = med_orig->v2;
425                 med_new->crease = med_orig->crease;
426                 med_new->flag = med_orig->flag &  ~ME_LOOSEEDGE;
427         }
428
429         /* build polygon -> edge map */
430         if (totpoly) {
431                 MPoly *mp_orig;
432
433                 mpoly_orig = mesh->mpoly;
434                 mloop_orig = mesh->mloop;
435                 edge_poly_map = MEM_malloc_arrayN(totedge, sizeof(*edge_poly_map), __func__);
436                 memset(edge_poly_map, 0xff, sizeof(*edge_poly_map) * totedge);
437
438                 vert_loop_map = MEM_malloc_arrayN(totvert, sizeof(*vert_loop_map), __func__);
439                 memset(vert_loop_map, 0xff, sizeof(*vert_loop_map) * totvert);
440
441                 for (i = 0, mp_orig = mpoly_orig; i < totpoly; i++, mp_orig++) {
442                         unsigned int loopstart = (unsigned int)mp_orig->loopstart;
443                         unsigned int loopend = loopstart + (unsigned int)mp_orig->totloop;
444
445                         MLoop *ml_orig = &mloop_orig[loopstart];
446                         unsigned int k;
447                         for (k = loopstart; k < loopend; k++, ml_orig++) {
448                                 edge_poly_map[ml_orig->e] = i;
449                                 vert_loop_map[ml_orig->v] = k;
450
451                                 /* also order edges based on faces */
452                                 if (medge_new[ml_orig->e].v1 != ml_orig->v) {
453                                         SWAP(unsigned int, medge_new[ml_orig->e].v1, medge_new[ml_orig->e].v2);
454                                 }
455                         }
456                 }
457         }
458
459         if (ltmd->flag & MOD_SCREW_NORMAL_CALC) {
460                 /*
461                  * Normal Calculation (for face flipping)
462                  * Sort edge verts for correct face flipping
463                  * NOT REALLY NEEDED but face flipping is nice.
464                  *
465                  * */
466
467
468                 /* Notice!
469                  *
470                  * Since we are only ordering the edges here it can avoid mallocing the
471                  * extra space by abusing the vert array before its filled with new verts.
472                  * The new array for vert_connect must be at least sizeof(ScrewVertConnect) * totvert
473                  * and the size of our resulting meshes array is sizeof(MVert) * totvert * 3
474                  * so its safe to use the second 2 thrids of MVert the array for vert_connect,
475                  * just make sure ScrewVertConnect struct is no more than twice as big as MVert,
476                  * at the moment there is no chance of that being a problem,
477                  * unless MVert becomes half its current size.
478                  *
479                  * once the edges are ordered, vert_connect is not needed and it can be used for verts
480                  *
481                  * This makes the modifier faster with one less alloc.
482                  */
483
484                 vert_connect = MEM_malloc_arrayN(totvert, sizeof(ScrewVertConnect), "ScrewVertConnect");
485                 //vert_connect = (ScrewVertConnect *) &medge_new[totvert];  /* skip the first slice of verts */
486                 vc = vert_connect;
487
488                 /* Copy Vert Locations */
489                 /* - We can do this in a later loop - only do here if no normal calc */
490                 if (!totedge) {
491                         for (i = 0; i < totvert; i++, mv_orig++, mv_new++) {
492                                 copy_v3_v3(mv_new->co, mv_orig->co);
493                                 normalize_v3_v3(vc->no, mv_new->co); /* no edges- this is really a dummy normal */
494                         }
495                 }
496                 else {
497                         /*printf("\n\n\n\n\nStarting Modifier\n");*/
498                         /* set edge users */
499                         med_new = medge_new;
500                         mv_new = mvert_new;
501
502                         if (ob_axis != NULL) {
503                                 /*mtx_tx is initialized early on */
504                                 for (i = 0; i < totvert; i++, mv_new++, mv_orig++, vc++) {
505                                         vc->co[0] = mv_new->co[0] = mv_orig->co[0];
506                                         vc->co[1] = mv_new->co[1] = mv_orig->co[1];
507                                         vc->co[2] = mv_new->co[2] = mv_orig->co[2];
508
509                                         vc->flag = 0;
510                                         vc->e[0] = vc->e[1] = NULL;
511                                         vc->v[0] = vc->v[1] = SV_UNUSED;
512
513                                         mul_m4_v3(mtx_tx, vc->co);
514                                         /* length in 2d, don't sqrt because this is only for comparison */
515                                         vc->dist = vc->co[other_axis_1] * vc->co[other_axis_1] +
516                                                    vc->co[other_axis_2] * vc->co[other_axis_2];
517
518                                         /* printf("location %f %f %f -- %f\n", vc->co[0], vc->co[1], vc->co[2], vc->dist);*/
519                                 }
520                         }
521                         else {
522                                 for (i = 0; i < totvert; i++, mv_new++, mv_orig++, vc++) {
523                                         vc->co[0] = mv_new->co[0] = mv_orig->co[0];
524                                         vc->co[1] = mv_new->co[1] = mv_orig->co[1];
525                                         vc->co[2] = mv_new->co[2] = mv_orig->co[2];
526
527                                         vc->flag = 0;
528                                         vc->e[0] = vc->e[1] = NULL;
529                                         vc->v[0] = vc->v[1] = SV_UNUSED;
530
531                                         /* length in 2d, don't sqrt because this is only for comparison */
532                                         vc->dist = vc->co[other_axis_1] * vc->co[other_axis_1] +
533                                                    vc->co[other_axis_2] * vc->co[other_axis_2];
534
535                                         /* printf("location %f %f %f -- %f\n", vc->co[0], vc->co[1], vc->co[2], vc->dist);*/
536                                 }
537                         }
538
539                         /* this loop builds connectivity info for verts */
540                         for (i = 0; i < totedge; i++, med_new++) {
541                                 vc = &vert_connect[med_new->v1];
542
543                                 if (vc->v[0] == SV_UNUSED) { /* unused */
544                                         vc->v[0] = med_new->v2;
545                                         vc->e[0] = med_new;
546                                 }
547                                 else if (vc->v[1] == SV_UNUSED) {
548                                         vc->v[1] = med_new->v2;
549                                         vc->e[1] = med_new;
550                                 }
551                                 else {
552                                         vc->v[0] = vc->v[1] = SV_INVALID; /* error value  - don't use, 3 edges on vert */
553                                 }
554
555                                 vc = &vert_connect[med_new->v2];
556
557                                 /* same as above but swap v1/2 */
558                                 if (vc->v[0] == SV_UNUSED) { /* unused */
559                                         vc->v[0] = med_new->v1;
560                                         vc->e[0] = med_new;
561                                 }
562                                 else if (vc->v[1] == SV_UNUSED) {
563                                         vc->v[1] = med_new->v1;
564                                         vc->e[1] = med_new;
565                                 }
566                                 else {
567                                         vc->v[0] = vc->v[1] = SV_INVALID; /* error value  - don't use, 3 edges on vert */
568                                 }
569                         }
570
571                         /* find the first vert */
572                         vc = vert_connect;
573                         for (i = 0; i < totvert; i++, vc++) {
574                                 /* Now do search for connected verts, order all edges and flip them
575                                  * so resulting faces are flipped the right way */
576                                 vc_tot_linked = 0; /* count the number of linked verts for this loop */
577                                 if (vc->flag == 0) {
578                                         unsigned int v_best = SV_UNUSED, ed_loop_closed = 0; /* vert and vert new */
579                                         ScrewVertIter lt_iter;
580                                         float fl = -1.0f;
581
582                                         /* compiler complains if not initialized, but it should be initialized below */
583                                         bool ed_loop_flip = false;
584
585                                         /*printf("Loop on connected vert: %i\n", i);*/
586
587                                         for (j = 0; j < 2; j++) {
588                                                 /*printf("\tSide: %i\n", j);*/
589                                                 screwvert_iter_init(&lt_iter, vert_connect, i, j);
590                                                 if (j == 1) {
591                                                         screwvert_iter_step(&lt_iter);
592                                                 }
593                                                 while (lt_iter.v_poin) {
594                                                         /*printf("\t\tVERT: %i\n", lt_iter.v);*/
595                                                         if (lt_iter.v_poin->flag) {
596                                                                 /*printf("\t\t\tBreaking Found end\n");*/
597                                                                 //endpoints[0] = endpoints[1] = SV_UNUSED;
598                                                                 ed_loop_closed = 1; /* circle */
599                                                                 break;
600                                                         }
601                                                         lt_iter.v_poin->flag = 1;
602                                                         vc_tot_linked++;
603                                                         /*printf("Testing 2 floats %f : %f\n", fl, lt_iter.v_poin->dist);*/
604                                                         if (fl <= lt_iter.v_poin->dist) {
605                                                                 fl = lt_iter.v_poin->dist;
606                                                                 v_best = lt_iter.v;
607                                                                 /*printf("\t\t\tVERT BEST: %i\n", v_best);*/
608                                                         }
609                                                         screwvert_iter_step(&lt_iter);
610                                                         if (!lt_iter.v_poin) {
611                                                                 /*printf("\t\t\tFound End Also Num %i\n", j);*/
612                                                                 /*endpoints[j] = lt_iter.v_other;*/ /* other is still valid */
613                                                                 break;
614                                                         }
615                                                 }
616                                         }
617
618                                         /* now we have a collection of used edges. flip their edges the right way*/
619                                         /*if (v_best != SV_UNUSED) - */
620
621                                         /*printf("Done Looking - vc_tot_linked: %i\n", vc_tot_linked);*/
622
623                                         if (vc_tot_linked > 1) {
624                                                 float vf_1, vf_2, vf_best;
625
626                                                 vc_tmp = &vert_connect[v_best];
627
628                                                 tmpf1 = vert_connect[vc_tmp->v[0]].co;
629                                                 tmpf2 = vert_connect[vc_tmp->v[1]].co;
630
631
632                                                 /* edge connects on each side! */
633                                                 if (SV_IS_VALID(vc_tmp->v[0]) && SV_IS_VALID(vc_tmp->v[1])) {
634                                                         /*printf("Verts on each side (%i %i)\n", vc_tmp->v[0], vc_tmp->v[1]);*/
635                                                         /* find out which is higher */
636
637                                                         vf_1 = tmpf1[ltmd->axis];
638                                                         vf_2 = tmpf2[ltmd->axis];
639                                                         vf_best = vc_tmp->co[ltmd->axis];
640
641                                                         if (vf_1 < vf_best && vf_best < vf_2) {
642                                                                 ed_loop_flip = 0;
643                                                         }
644                                                         else if (vf_1 > vf_best && vf_best > vf_2) {
645                                                                 ed_loop_flip = 1;
646                                                         }
647                                                         else {
648                                                                 /* not so simple to work out which edge is higher */
649                                                                 sub_v3_v3v3(tmp_vec1, tmpf1, vc_tmp->co);
650                                                                 sub_v3_v3v3(tmp_vec2, tmpf2, vc_tmp->co);
651                                                                 normalize_v3(tmp_vec1);
652                                                                 normalize_v3(tmp_vec2);
653
654                                                                 if (tmp_vec1[ltmd->axis] < tmp_vec2[ltmd->axis]) {
655                                                                         ed_loop_flip = 1;
656                                                                 }
657                                                                 else {
658                                                                         ed_loop_flip = 0;
659                                                                 }
660                                                         }
661                                                 }
662                                                 else if (SV_IS_VALID(vc_tmp->v[0])) { /*vertex only connected on 1 side */
663                                                         /*printf("Verts on ONE side (%i %i)\n", vc_tmp->v[0], vc_tmp->v[1]);*/
664                                                         if (tmpf1[ltmd->axis] < vc_tmp->co[ltmd->axis]) { /* best is above */
665                                                                 ed_loop_flip = 1;
666                                                         }
667                                                         else { /* best is below or even... in even case we can't know what to do. */
668                                                                 ed_loop_flip = 0;
669                                                         }
670
671                                                 }
672 #if 0
673                                                 else {
674                                                         printf("No Connected ___\n");
675                                                 }
676 #endif
677
678                                                 /*printf("flip direction %i\n", ed_loop_flip);*/
679
680
681                                                 /* switch the flip option if set
682                                                  * note: flip is now done at face level so copying vgroup slizes is easier */
683 #if 0
684                                                 if (do_flip)
685                                                         ed_loop_flip = !ed_loop_flip;
686 #endif
687
688                                                 if (angle < 0.0f)
689                                                         ed_loop_flip = !ed_loop_flip;
690
691                                                 /* if its closed, we only need 1 loop */
692                                                 for (j = ed_loop_closed; j < 2; j++) {
693                                                         /*printf("Ordering Side J %i\n", j);*/
694
695                                                         screwvert_iter_init(&lt_iter, vert_connect, v_best, j);
696                                                         /*printf("\n\nStarting - Loop\n");*/
697                                                         lt_iter.v_poin->flag = 1; /* so a non loop will traverse the other side */
698
699
700                                                         /* If this is the vert off the best vert and
701                                                          * the best vert has 2 edges connected too it
702                                                          * then swap the flip direction */
703                                                         if (j == 1 && SV_IS_VALID(vc_tmp->v[0]) && SV_IS_VALID(vc_tmp->v[1]))
704                                                                 ed_loop_flip = !ed_loop_flip;
705
706                                                         while (lt_iter.v_poin && lt_iter.v_poin->flag != 2) {
707                                                                 /*printf("\tOrdering Vert V %i\n", lt_iter.v);*/
708
709                                                                 lt_iter.v_poin->flag = 2;
710                                                                 if (lt_iter.e) {
711                                                                         if (lt_iter.v == lt_iter.e->v1) {
712                                                                                 if (ed_loop_flip == 0) {
713                                                                                         /*printf("\t\t\tFlipping 0\n");*/
714                                                                                         SWAP(unsigned int, lt_iter.e->v1, lt_iter.e->v2);
715                                                                                 }
716                                                                                 /* else {
717                                                                                     printf("\t\t\tFlipping Not 0\n");
718                                                                                    }*/
719                                                                         }
720                                                                         else if (lt_iter.v == lt_iter.e->v2) {
721                                                                                 if (ed_loop_flip == 1) {
722                                                                                         /*printf("\t\t\tFlipping 1\n");*/
723                                                                                         SWAP(unsigned int, lt_iter.e->v1, lt_iter.e->v2);
724                                                                                 }
725                                                                                 /* else {
726                                                                                     printf("\t\t\tFlipping Not 1\n");
727                                                                                    }*/
728                                                                         }
729                                                                         /* else {
730                                                                             printf("\t\tIncorrect edge topology");
731                                                                            }*/
732                                                                 }
733                                                                 /* else {
734                                                                     printf("\t\tNo Edge at this point\n");
735                                                                    }*/
736                                                                 screwvert_iter_step(&lt_iter);
737                                                         }
738                                                 }
739                                         }
740                                 }
741
742                                 /* *VERTEX NORMALS*
743                                  * we know the surrounding edges are ordered correctly now
744                                  * so its safe to create vertex normals.
745                                  *
746                                  * calculate vertex normals that can be propagated on lathing
747                                  * use edge connectivity work this out */
748                                 if (SV_IS_VALID(vc->v[0])) {
749                                         if (SV_IS_VALID(vc->v[1])) {
750                                                 /* 2 edges connedted */
751                                                 /* make 2 connecting vert locations relative to the middle vert */
752                                                 sub_v3_v3v3(tmp_vec1, mvert_new[vc->v[0]].co, mvert_new[i].co);
753                                                 sub_v3_v3v3(tmp_vec2, mvert_new[vc->v[1]].co, mvert_new[i].co);
754                                                 /* normalize so both edges have the same influence, no matter their length */
755                                                 normalize_v3(tmp_vec1);
756                                                 normalize_v3(tmp_vec2);
757
758                                                 /* vc_no_tmp1 - this line is the average direction of both connecting edges
759                                                  *
760                                                  * Use the edge order to make the subtraction, flip the normal the right way
761                                                  * edge should be there but check just in case... */
762                                                 if (vc->e[0]->v1 == i) {
763                                                         sub_v3_v3(tmp_vec1, tmp_vec2);
764                                                 }
765                                                 else {
766                                                         sub_v3_v3v3(tmp_vec1, tmp_vec2, tmp_vec1);
767                                                 }
768                                         }
769                                         else {
770                                                 /* only 1 edge connected - same as above except
771                                                  * don't need to average edge direction */
772                                                 if (vc->e[0]->v2 == i) {
773                                                         sub_v3_v3v3(tmp_vec1, mvert_new[i].co, mvert_new[vc->v[0]].co);
774                                                 }
775                                                 else {
776                                                         sub_v3_v3v3(tmp_vec1, mvert_new[vc->v[0]].co, mvert_new[i].co);
777                                                 }
778                                         }
779
780                                         /* tmp_vec2 - is a line 90d from the pivot to the vec
781                                          * This is used so the resulting normal points directly away from the middle */
782                                         cross_v3_v3v3(tmp_vec2, axis_vec, vc->co);
783
784                                         if (UNLIKELY(is_zero_v3(tmp_vec2))) {
785                                                 /* we're _on_ the axis, so copy it based on our winding */
786                                                 if (vc->e[0]->v2 == i) {
787                                                         negate_v3_v3(vc->no, axis_vec);
788                                                 }
789                                                 else {
790                                                         copy_v3_v3(vc->no, axis_vec);
791                                                 }
792                                         }
793                                         else {
794                                                 /* edge average vector and right angle to the pivot make the normal */
795                                                 cross_v3_v3v3(vc->no, tmp_vec1, tmp_vec2);
796                                         }
797
798                                 }
799                                 else {
800                                         copy_v3_v3(vc->no, vc->co);
801                                 }
802
803                                 /* we won't be looping on this data again so copy normals here */
804                                 if ((angle < 0.0f) != do_flip)
805                                         negate_v3(vc->no);
806
807                                 normalize_v3(vc->no);
808                                 normal_float_to_short_v3(mvert_new[i].no, vc->no);
809
810                                 /* Done with normals */
811                         }
812                 }
813         }
814         else {
815                 mv_orig = mvert_orig;
816                 mv_new = mvert_new;
817
818                 for (i = 0; i < totvert; i++, mv_new++, mv_orig++) {
819                         copy_v3_v3(mv_new->co, mv_orig->co);
820                 }
821         }
822         /* done with edge connectivity based normal flipping */
823
824         /* Add Faces */
825         for (step = 1; step < step_tot; step++) {
826                 const unsigned int varray_stride = totvert * step;
827                 float step_angle;
828                 float nor_tx[3];
829                 float mat[4][4];
830                 /* Rotation Matrix */
831                 step_angle = (angle / (float)(step_tot - (!close))) * (float)step;
832
833                 if (ob_axis != NULL) {
834                         axis_angle_normalized_to_mat3(mat3, axis_vec, step_angle);
835                 }
836                 else {
837                         axis_angle_to_mat3_single(mat3, axis_char, step_angle);
838                 }
839                 copy_m4_m3(mat, mat3);
840
841                 if (screw_ofs)
842                         madd_v3_v3fl(mat[3], axis_vec, screw_ofs * ((float)step / (float)(step_tot - 1)));
843
844                 /* copy a slice */
845                 CustomData_copy_data(&mesh->vdata, &result->vdata, 0, (int)varray_stride, (int)totvert);
846
847                 mv_new_base = mvert_new;
848                 mv_new = &mvert_new[varray_stride]; /* advance to the next slice */
849
850                 for (j = 0; j < totvert; j++, mv_new_base++, mv_new++) {
851                         /* set normal */
852                         if (vert_connect) {
853                                 mul_v3_m3v3(nor_tx, mat3, vert_connect[j].no);
854
855                                 /* set the normal now its transformed */
856                                 normal_float_to_short_v3(mv_new->no, nor_tx);
857                         }
858
859                         /* set location */
860                         copy_v3_v3(mv_new->co, mv_new_base->co);
861
862                         /* only need to set these if using non cleared memory */
863                         /*mv_new->mat_nr = mv_new->flag = 0;*/
864
865                         if (ob_axis != NULL) {
866                                 sub_v3_v3(mv_new->co, mtx_tx[3]);
867
868                                 mul_m4_v3(mat, mv_new->co);
869
870                                 add_v3_v3(mv_new->co, mtx_tx[3]);
871                         }
872                         else {
873                                 mul_m4_v3(mat, mv_new->co);
874                         }
875
876                         /* add the new edge */
877                         med_new->v1 = varray_stride + j;
878                         med_new->v2 = med_new->v1 - totvert;
879                         med_new->flag = ME_EDGEDRAW | ME_EDGERENDER;
880                         med_new++;
881                 }
882         }
883
884         /* we can avoid if using vert alloc trick */
885         if (vert_connect) {
886                 MEM_freeN(vert_connect);
887                 vert_connect = NULL;
888         }
889
890         if (close) {
891                 /* last loop of edges, previous loop doesn't account for the last set of edges */
892                 const unsigned int varray_stride = (step_tot - 1) * totvert;
893
894                 for (i = 0; i < totvert; i++) {
895                         med_new->v1 = i;
896                         med_new->v2 = varray_stride + i;
897                         med_new->flag = ME_EDGEDRAW | ME_EDGERENDER;
898                         med_new++;
899                 }
900         }
901
902         mp_new = mpoly_new;
903         ml_new = mloop_new;
904         med_new_firstloop = medge_new;
905
906         /* more of an offset in this case */
907         edge_offset = totedge + (totvert * (step_tot - (close ? 0 : 1)));
908
909         for (i = 0; i < totedge; i++, med_new_firstloop++) {
910                 const unsigned int step_last = step_tot - (close ? 1 : 2);
911                 const unsigned int mpoly_index_orig = totpoly ? edge_poly_map[i] : UINT_MAX;
912                 const bool has_mpoly_orig = (mpoly_index_orig != UINT_MAX);
913                 float uv_v_offset_a, uv_v_offset_b;
914
915                 const unsigned int mloop_index_orig[2] = {
916                     vert_loop_map ? vert_loop_map[medge_new[i].v1] : UINT_MAX,
917                     vert_loop_map ? vert_loop_map[medge_new[i].v2] : UINT_MAX,
918                 };
919                 const bool has_mloop_orig = mloop_index_orig[0] != UINT_MAX;
920
921                 short mat_nr;
922
923                 /* for each edge, make a cylinder of quads */
924                 i1 = med_new_firstloop->v1;
925                 i2 = med_new_firstloop->v2;
926
927                 if (has_mpoly_orig) {
928                         mat_nr = mpoly_orig[mpoly_index_orig].mat_nr;
929                 }
930                 else {
931                         mat_nr = 0;
932                 }
933
934                 if (has_mloop_orig == false && mloopuv_layers_tot) {
935                         uv_v_offset_a = dist_signed_to_plane_v3(mvert_new[medge_new[i].v1].co, uv_axis_plane);
936                         uv_v_offset_b = dist_signed_to_plane_v3(mvert_new[medge_new[i].v2].co, uv_axis_plane);
937
938                         if (ltmd->flag & MOD_SCREW_UV_STRETCH_V) {
939                                 uv_v_offset_a = (uv_v_offset_a - uv_v_minmax[0]) * uv_v_range_inv;
940                                 uv_v_offset_b = (uv_v_offset_b - uv_v_minmax[0]) * uv_v_range_inv;
941                         }
942                 }
943
944                 for (step = 0; step <= step_last; step++) {
945
946                         /* Polygon */
947                         if (has_mpoly_orig) {
948                                 CustomData_copy_data(&mesh->pdata, &result->pdata, (int)mpoly_index_orig, (int)mpoly_index, 1);
949                                 origindex[mpoly_index] = (int)mpoly_index_orig;
950                         }
951                         else {
952                                 origindex[mpoly_index] = ORIGINDEX_NONE;
953                                 mp_new->flag = mpoly_flag;
954                                 mp_new->mat_nr = mat_nr;
955                         }
956                         mp_new->loopstart = mpoly_index * 4;
957                         mp_new->totloop = 4;
958
959
960                         /* Loop-Custom-Data */
961                         if (has_mloop_orig) {
962                                 int l_index = (int)(ml_new - mloop_new);
963
964                                 CustomData_copy_data(&mesh->ldata, &result->ldata, (int)mloop_index_orig[0], l_index + 0, 1);
965                                 CustomData_copy_data(&mesh->ldata, &result->ldata, (int)mloop_index_orig[1], l_index + 1, 1);
966                                 CustomData_copy_data(&mesh->ldata, &result->ldata, (int)mloop_index_orig[1], l_index + 2, 1);
967                                 CustomData_copy_data(&mesh->ldata, &result->ldata, (int)mloop_index_orig[0], l_index + 3, 1);
968
969                                 if (mloopuv_layers_tot) {
970                                         unsigned int uv_lay;
971                                         const float uv_u_offset_a = (float)(step)     * uv_u_scale;
972                                         const float uv_u_offset_b = (float)(step + 1) * uv_u_scale;
973                                         for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) {
974                                                 MLoopUV *mluv = &mloopuv_layers[uv_lay][l_index];
975
976                                                 mluv[quad_ord[0]].uv[0] += uv_u_offset_a;
977                                                 mluv[quad_ord[1]].uv[0] += uv_u_offset_a;
978                                                 mluv[quad_ord[2]].uv[0] += uv_u_offset_b;
979                                                 mluv[quad_ord[3]].uv[0] += uv_u_offset_b;
980                                         }
981                                 }
982                         }
983                         else {
984                                 if (mloopuv_layers_tot) {
985                                         int l_index = (int)(ml_new - mloop_new);
986
987                                         unsigned int uv_lay;
988                                         const float uv_u_offset_a = (float)(step)     * uv_u_scale;
989                                         const float uv_u_offset_b = (float)(step + 1) * uv_u_scale;
990                                         for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) {
991                                                 MLoopUV *mluv = &mloopuv_layers[uv_lay][l_index];
992
993                                                 copy_v2_fl2(mluv[quad_ord[0]].uv, uv_u_offset_a, uv_v_offset_a);
994                                                 copy_v2_fl2(mluv[quad_ord[1]].uv, uv_u_offset_a, uv_v_offset_b);
995                                                 copy_v2_fl2(mluv[quad_ord[2]].uv, uv_u_offset_b, uv_v_offset_b);
996                                                 copy_v2_fl2(mluv[quad_ord[3]].uv, uv_u_offset_b, uv_v_offset_a);
997                                         }
998                                 }
999                         }
1000
1001                         /* Loop-Data */
1002                         if (!(close && step == step_last)) {
1003                                 /* regular segments */
1004                                 ml_new[quad_ord[0]].v = i1;
1005                                 ml_new[quad_ord[1]].v = i2;
1006                                 ml_new[quad_ord[2]].v = i2 + totvert;
1007                                 ml_new[quad_ord[3]].v = i1 + totvert;
1008
1009                                 ml_new[quad_ord_ofs[0]].e = step == 0 ? i : (edge_offset + step + (i * (step_tot - 1))) - 1;
1010                                 ml_new[quad_ord_ofs[1]].e = totedge + i2;
1011                                 ml_new[quad_ord_ofs[2]].e = edge_offset + step + (i * (step_tot - 1));
1012                                 ml_new[quad_ord_ofs[3]].e = totedge + i1;
1013
1014
1015                                 /* new vertical edge */
1016                                 if (step) { /* The first set is already done */
1017                                         med_new->v1 = i1;
1018                                         med_new->v2 = i2;
1019                                         med_new->flag = med_new_firstloop->flag;
1020                                         med_new->crease = med_new_firstloop->crease;
1021                                         med_new++;
1022                                 }
1023                                 i1 += totvert;
1024                                 i2 += totvert;
1025                         }
1026                         else {
1027                                 /* last segment */
1028                                 ml_new[quad_ord[0]].v = i1;
1029                                 ml_new[quad_ord[1]].v = i2;
1030                                 ml_new[quad_ord[2]].v = med_new_firstloop->v2;
1031                                 ml_new[quad_ord[3]].v = med_new_firstloop->v1;
1032
1033                                 ml_new[quad_ord_ofs[0]].e = (edge_offset + step + (i * (step_tot - 1))) - 1;
1034                                 ml_new[quad_ord_ofs[1]].e = totedge + i2;
1035                                 ml_new[quad_ord_ofs[2]].e = i;
1036                                 ml_new[quad_ord_ofs[3]].e = totedge + i1;
1037                         }
1038
1039                         mp_new++;
1040                         ml_new += 4;
1041                         mpoly_index++;
1042                 }
1043
1044                 /* new vertical edge */
1045                 med_new->v1 = i1;
1046                 med_new->v2 = i2;
1047                 med_new->flag = med_new_firstloop->flag & ~ME_LOOSEEDGE;
1048                 med_new->crease = med_new_firstloop->crease;
1049                 med_new++;
1050         }
1051
1052         /* validate loop edges */
1053 #if 0
1054         {
1055                 unsigned i = 0;
1056                 printf("\n");
1057                 for (; i < maxPolys * 4; i += 4) {
1058                         unsigned int ii;
1059                         ml_new = mloop_new + i;
1060                         ii = findEd(medge_new, maxEdges, ml_new[0].v, ml_new[1].v);
1061                         printf("%d %d -- ", ii, ml_new[0].e);
1062                         ml_new[0].e = ii;
1063
1064                         ii = findEd(medge_new, maxEdges, ml_new[1].v, ml_new[2].v);
1065                         printf("%d %d -- ", ii, ml_new[1].e);
1066                         ml_new[1].e = ii;
1067
1068                         ii = findEd(medge_new, maxEdges, ml_new[2].v, ml_new[3].v);
1069                         printf("%d %d -- ", ii, ml_new[2].e);
1070                         ml_new[2].e = ii;
1071
1072                         ii = findEd(medge_new, maxEdges, ml_new[3].v, ml_new[0].v);
1073                         printf("%d %d\n", ii, ml_new[3].e);
1074                         ml_new[3].e = ii;
1075
1076                 }
1077         }
1078 #endif
1079
1080         if (edge_poly_map) {
1081                 MEM_freeN(edge_poly_map);
1082         }
1083
1084         if (vert_loop_map) {
1085                 MEM_freeN(vert_loop_map);
1086         }
1087
1088         if ((ltmd->flag & MOD_SCREW_MERGE) && (screw_ofs == 0.0f)) {
1089                 Mesh *result_prev = result;
1090                 result = mesh_remove_doubles_on_axis(
1091                         result, mvert_new, totvert, step_tot,
1092                         axis_vec, ob_axis != NULL ? mtx_tx[3] : NULL, ltmd->merge_dist);
1093                 if (result != result_prev) {
1094                         result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
1095                 }
1096         }
1097
1098         if ((ltmd->flag & MOD_SCREW_NORMAL_CALC) == 0) {
1099                 result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
1100         }
1101
1102         return result;
1103 }
1104
1105 static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
1106 {
1107         ScrewModifierData *ltmd = (ScrewModifierData *)md;
1108         if (ltmd->ob_axis != NULL) {
1109                 DEG_add_object_relation(ctx->node, ltmd->ob_axis, DEG_OB_COMP_TRANSFORM, "Screw Modifier");
1110                 DEG_add_modifier_to_transform_relation(ctx->node, "Screw Modifier");
1111         }
1112 }
1113
1114 static void foreachObjectLink(
1115         ModifierData *md, Object *ob,
1116         ObjectWalkFunc walk, void *userData)
1117 {
1118         ScrewModifierData *ltmd = (ScrewModifierData *) md;
1119
1120         walk(userData, ob, &ltmd->ob_axis, IDWALK_CB_NOP);
1121 }
1122
1123 ModifierTypeInfo modifierType_Screw = {
1124         /* name */              "Screw",
1125         /* structName */        "ScrewModifierData",
1126         /* structSize */        sizeof(ScrewModifierData),
1127         /* type */              eModifierTypeType_Constructive,
1128
1129         /* flags */             eModifierTypeFlag_AcceptsMesh |
1130                                 eModifierTypeFlag_AcceptsCVs |
1131                                 eModifierTypeFlag_SupportsEditmode |
1132                                 eModifierTypeFlag_EnableInEditmode,
1133
1134         /* copyData */          modifier_copyData_generic,
1135
1136         /* deformVerts_DM */    NULL,
1137         /* deformMatrices_DM */ NULL,
1138         /* deformVertsEM_DM */  NULL,
1139         /* deformMatricesEM_DM*/NULL,
1140         /* applyModifier_DM */  NULL,
1141
1142         /* deformVerts */       NULL,
1143         /* deformMatrices */    NULL,
1144         /* deformVertsEM */     NULL,
1145         /* deformMatricesEM */  NULL,
1146         /* applyModifier */     applyModifier,
1147
1148         /* initData */          initData,
1149         /* requiredDataMask */  NULL,
1150         /* freeData */          NULL,
1151         /* isDisabled */        NULL,
1152         /* updateDepsgraph */   updateDepsgraph,
1153         /* dependsOnTime */     NULL,
1154         /* dependsOnNormals */  NULL,
1155         /* foreachObjectLink */ foreachObjectLink,
1156         /* foreachIDLink */     NULL,
1157         /* foreachTexLink */    NULL,
1158 };