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