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