Blender  V2.93
bmo_extrude.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 
23 #include "MEM_guardedalloc.h"
24 
25 #include "DNA_meshdata_types.h"
26 
27 #include "BLI_buffer.h"
28 #include "BLI_math.h"
29 
30 #include "BKE_customdata.h"
31 
32 #include "bmesh.h"
33 
34 #include "intern/bmesh_operators_private.h" /* own include */
35 
36 #define USE_EDGE_REGION_FLAGS
37 
38 enum {
39  EXT_INPUT = 1,
40  EXT_KEEP = 2,
41  EXT_DEL = 4,
42  EXT_TAG = 8,
43 };
44 
45 #define VERT_MARK 1
46 #define EDGE_MARK 1
47 #define FACE_MARK 1
48 #define VERT_NONMAN 2
49 #define EDGE_NONMAN 2
50 
52 {
53  const bool use_select_history = BMO_slot_bool_get(op->slots_in, "use_select_history");
54  GHash *select_history_map = NULL;
55 
56  BMOIter siter;
57  BMFace *f_org;
58 
59  if (use_select_history) {
60  select_history_map = BM_select_history_map_create(bm);
61  }
62 
63  BMO_ITER (f_org, &siter, op->slots_in, "faces", BM_FACE) {
64  BMFace *f_new;
65  BMLoop *l_org, *l_org_first;
66  BMLoop *l_new;
67 
69 
70  f_new = BM_face_copy(bm, bm, f_org, true, true);
72 
73  if (select_history_map) {
74  BMEditSelection *ese;
75  ese = BLI_ghash_lookup(select_history_map, f_org);
76  if (ese) {
77  ese->ele = (BMElem *)f_new;
78  }
79  }
80 
81  l_org = l_org_first = BM_FACE_FIRST_LOOP(f_org);
82  l_new = BM_FACE_FIRST_LOOP(f_new);
83 
84  do {
85  BMFace *f_side;
86  BMLoop *l_side_iter;
87 
88  BM_elem_attrs_copy(bm, bm, l_org, l_new);
89 
90  f_side = BM_face_create_quad_tri(
91  bm, l_org->next->v, l_new->next->v, l_new->v, l_org->v, f_org, BM_CREATE_NOP);
92 
93  l_side_iter = BM_FACE_FIRST_LOOP(f_side);
94 
95  BM_elem_attrs_copy(bm, bm, l_org->next, l_side_iter);
96  l_side_iter = l_side_iter->next;
97  BM_elem_attrs_copy(bm, bm, l_org->next, l_side_iter);
98  l_side_iter = l_side_iter->next;
99  BM_elem_attrs_copy(bm, bm, l_org, l_side_iter);
100  l_side_iter = l_side_iter->next;
101  BM_elem_attrs_copy(bm, bm, l_org, l_side_iter);
102 
103  if (select_history_map) {
104  BMEditSelection *ese;
105 
106  ese = BLI_ghash_lookup(select_history_map, l_org->v);
107  if (ese) {
108  ese->ele = (BMElem *)l_new->v;
109  }
110  ese = BLI_ghash_lookup(select_history_map, l_org->e);
111  if (ese) {
112  ese->ele = (BMElem *)l_new->e;
113  }
114  }
115 
116  } while (((void)(l_new = l_new->next), (l_org = l_org->next)) != l_org_first);
117  }
118 
119  if (select_history_map) {
120  BLI_ghash_free(select_history_map, NULL, NULL);
121  }
122 
123  BMO_op_callf(bm, op->flag, "delete geom=%ff context=%i", EXT_DEL, DEL_ONLYFACES);
125 }
126 
138 {
139  /* edge we are extruded from */
140  BMLoop *l_first_0 = BM_FACE_FIRST_LOOP(f);
141  BMLoop *l_first_1 = l_first_0->next;
142  BMLoop *l_first_2 = l_first_1->next;
143  BMLoop *l_first_3 = l_first_2->next;
144 
145  BMLoop *l_other_0;
146  BMLoop *l_other_1;
147 
148  if (UNLIKELY(l_first_0 == l_first_0->radial_next)) {
149  return;
150  }
151 
152  l_other_0 = BM_edge_other_loop(l_first_0->e, l_first_0);
153  l_other_1 = BM_edge_other_loop(l_first_0->e, l_first_1);
154 
155  /* copy data */
156  BM_elem_attrs_copy(bm, bm, l_other_0->f, f);
157  BM_elem_flag_disable(f, BM_ELEM_HIDDEN); /* possibly we copy from a hidden face */
158 
159  BM_elem_attrs_copy(bm, bm, l_other_0, l_first_0);
160  BM_elem_attrs_copy(bm, bm, l_other_0, l_first_3);
161 
162  BM_elem_attrs_copy(bm, bm, l_other_1, l_first_1);
163  BM_elem_attrs_copy(bm, bm, l_other_1, l_first_2);
164 }
165 
166 /* Disable the skin root flag on the input vert, assumes that the vert
167  * data includes an CD_MVERT_SKIN layer */
169 {
170  MVertSkin *vs;
171 
173  vs->flag &= ~MVERT_SKIN_ROOT;
174 }
175 
177 {
178  BMOIter siter;
179  BMOperator dupeop;
180  BMFace *f;
181  BMEdge *e, *e_new;
182  const bool use_normal_flip = BMO_slot_bool_get(op->slots_in, "use_normal_flip");
183 
184  BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) {
188  }
189 
191  &dupeop,
192  op->flag,
193  "duplicate geom=%fve use_select_history=%b",
194  EXT_INPUT,
195  BMO_slot_bool_get(op->slots_in, "use_select_history"));
196 
197  BMO_op_exec(bm, &dupeop);
198 
199  /* disable root flag on all new skin nodes */
201  BMVert *v;
202  BMO_ITER (v, &siter, dupeop.slots_out, "geom.out", BM_VERT) {
204  }
205  }
206 
207  for (e = BMO_iter_new(&siter, dupeop.slots_out, "boundary_map.out", 0); e;
208  e = BMO_iter_step(&siter)) {
209  BMVert *f_verts[4];
210  e_new = BMO_iter_map_value_ptr(&siter);
211 
212  const bool edge_normal_flip = !(e->l && e->v1 != e->l->v);
213  if (edge_normal_flip == use_normal_flip) {
214  f_verts[0] = e->v1;
215  f_verts[1] = e->v2;
216  f_verts[2] = e_new->v2;
217  f_verts[3] = e_new->v1;
218  }
219  else {
220  f_verts[0] = e->v2;
221  f_verts[1] = e->v1;
222  f_verts[2] = e_new->v1;
223  f_verts[3] = e_new->v2;
224  }
225  /* not sure what to do about example face, pass NULL for now */
226  f = BM_face_create_verts(bm, f_verts, 4, NULL, BM_CREATE_NOP, true);
228 
229  if (BMO_edge_flag_test(bm, e, EXT_INPUT)) {
230  e = e_new;
231  }
232 
237  }
238 
239  BMO_op_finish(bm, &dupeop);
240 
242 }
243 
245 {
246  const bool use_select_history = BMO_slot_bool_get(op->slots_in, "use_select_history");
247  BMOIter siter;
248  BMVert *v, *dupev;
249  BMEdge *e;
250  const bool has_vskin = CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN);
251  GHash *select_history_map = NULL;
252 
253  if (use_select_history) {
254  select_history_map = BM_select_history_map_create(bm);
255  }
256 
257  for (v = BMO_iter_new(&siter, op->slots_in, "verts", BM_VERT); v; v = BMO_iter_step(&siter)) {
258  dupev = BM_vert_create(bm, v->co, v, BM_CREATE_NOP);
260 
261  if (has_vskin) {
263  }
264 
265  if (select_history_map) {
266  BMEditSelection *ese;
267  ese = BLI_ghash_lookup(select_history_map, v);
268  if (ese) {
269  ese->ele = (BMElem *)dupev;
270  }
271  }
272 
273  /* not essential, but ensures face normals from extruded edges are contiguous */
274  if (BM_vert_is_wire_endpoint(v)) {
275  if (v->e->v1 == v) {
276  SWAP(BMVert *, v, dupev);
277  }
278  }
279 
280  e = BM_edge_create(bm, v, dupev, NULL, BM_CREATE_NOP);
282  }
283 
284  if (select_history_map) {
285  BLI_ghash_free(select_history_map, NULL, NULL);
286  }
287 
290 }
291 
292 #ifdef USE_EDGE_REGION_FLAGS
297 static bool bm_extrude_region_edge_flag(const BMVert *v, char r_e_hflag[2])
298 {
299  BMEdge *e_iter;
300  const char hflag_enable = BM_ELEM_SEAM;
301  const char hflag_disable = BM_ELEM_SMOOTH;
302  bool ok = false;
303 
304  r_e_hflag[0] = 0x0;
305  r_e_hflag[1] = 0xff;
306 
307  /* clear flags on both disks */
308  e_iter = v->e;
309  do {
310  if (e_iter->l && !BM_edge_is_boundary(e_iter)) {
311  r_e_hflag[0] |= e_iter->head.hflag;
312  r_e_hflag[1] &= e_iter->head.hflag;
313  ok = true;
314  }
315  } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != v->e);
316 
317  if (ok) {
318  r_e_hflag[0] &= hflag_enable;
319  r_e_hflag[1] = hflag_disable & ~r_e_hflag[1];
320  }
321  return ok;
322 }
323 #endif /* USE_EDGE_REGION_FLAGS */
324 
326 {
327  BMOperator dupeop, delop;
328  BMOIter siter;
329  BMIter iter, fiter, viter;
330  BMEdge *e, *e_new;
331  BMVert *v;
332  BMFace *f;
333  bool found, delorig = false;
334  BMOpSlot *slot_facemap_out;
335  BMOpSlot *slot_edges_exclude;
336  const bool use_normal_flip = BMO_slot_bool_get(op->slots_in, "use_normal_flip");
337  const bool use_normal_from_adjacent = BMO_slot_bool_get(op->slots_in,
338  "use_normal_from_adjacent");
339  const bool use_dissolve_ortho_edges = BMO_slot_bool_get(op->slots_in,
340  "use_dissolve_ortho_edges");
341 
342  /* initialize our sub-operators */
344  &dupeop,
345  op->flag,
346  "duplicate use_select_history=%b",
347  BMO_slot_bool_get(op->slots_in, "use_select_history"));
348 
350 
351  /* if one flagged face is bordered by an un-flagged face, then we delete
352  * original geometry unless caller explicitly asked to keep it. */
353  if (!BMO_slot_bool_get(op->slots_in, "use_keep_orig")) {
354  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
355 
356  int edge_face_tot;
357 
358  if (!BMO_edge_flag_test(bm, e, EXT_INPUT)) {
359  continue;
360  }
361 
362  found = false; /* found a face that isn't input? */
363  edge_face_tot = 0; /* edge/face count */
364 
365  BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
366  if (!BMO_face_flag_test(bm, f, EXT_INPUT)) {
367  found = true;
368  delorig = true;
369  break;
370  }
371 
372  edge_face_tot++;
373  }
374 
375  if ((edge_face_tot > 1) && (found == false)) {
376  /* edge has a face user, that face isn't extrude input */
378  }
379  }
380  }
381 
382  /* calculate verts to delete */
383  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
384  if (v->e) { /* only deal with verts attached to geometry T33651. */
385  found = false;
386 
387  BM_ITER_ELEM (e, &viter, v, BM_EDGES_OF_VERT) {
389  found = true;
390  break;
391  }
392  }
393 
394  /* avoid an extra loop */
395  if (found == true) {
396  BM_ITER_ELEM (f, &viter, v, BM_FACES_OF_VERT) {
397  if (!BMO_face_flag_test(bm, f, EXT_INPUT)) {
398  found = true;
399  break;
400  }
401  }
402  }
403 
404  if (found == false) {
406  }
407  }
408  }
409 
410  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
411  if (BMO_face_flag_test(bm, f, EXT_INPUT)) {
413  }
414  }
415 
416  if (delorig == true) {
417  BMO_op_initf(bm, &delop, op->flag, "delete geom=%fvef context=%i", EXT_DEL, DEL_ONLYTAGGED);
418  }
419 
420  BMO_slot_copy(op, slots_in, "geom", &dupeop, slots_in, "geom");
421  BMO_op_exec(bm, &dupeop);
422 
423  /* disable root flag on all new skin nodes */
425  BMO_ITER (v, &siter, dupeop.slots_out, "geom.out", BM_VERT) {
427  }
428  }
429 
430  slot_facemap_out = BMO_slot_get(dupeop.slots_out, "face_map.out");
432  bm->act_face = BMO_slot_map_elem_get(slot_facemap_out, bm->act_face);
433  }
434 
435  if (delorig) {
436  BMO_op_exec(bm, &delop);
437  }
438 
439  /* if not delorig, reverse loops of original face */
440  if (!delorig) {
441  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
442  if (BMO_face_flag_test(bm, f, EXT_INPUT)) {
444  }
445  }
446  }
447 
448  BMVert **dissolve_verts = NULL;
449  int dissolve_verts_len = 0;
450  float average_normal[3];
451  if (use_dissolve_ortho_edges) {
452  /* Calc average normal. */
453  zero_v3(average_normal);
454  BMO_ITER (f, &siter, dupeop.slots_out, "geom.out", BM_FACE) {
455  add_v3_v3(average_normal, f->no);
456  }
457  if (normalize_v3(average_normal) == 0.0f) {
458  average_normal[2] = 1.0f;
459  }
460 
461  /* Allocate array to store possible vertices that will be dissolved. */
462  int boundary_verts_len = BMO_slot_map_count(dupeop.slots_out, "boundary_map.out");
463  dissolve_verts = MEM_mallocN((size_t)boundary_verts_len * sizeof(*dissolve_verts), __func__);
464  }
465 
466  BMO_slot_copy(&dupeop, slots_out, "geom.out", op, slots_out, "geom.out");
467 
468  slot_edges_exclude = BMO_slot_get(op->slots_in, "edges_exclude");
469  for (e = BMO_iter_new(&siter, dupeop.slots_out, "boundary_map.out", 0); e;
470  e = BMO_iter_step(&siter)) {
471  BMVert *f_verts[4];
472 #ifdef USE_EDGE_REGION_FLAGS
473  BMEdge *f_edges[4];
474 #endif
475 
476  /* this should always be wire, so this is mainly a speedup to avoid map lookup */
477  if (BM_edge_is_wire(e) && BMO_slot_map_contains(slot_edges_exclude, e)) {
478  BMVert *v1 = e->v1, *v2 = e->v2;
479 
480  /* The original edge was excluded,
481  * this would result in a standalone wire edge - see T30399. */
482  BM_edge_kill(bm, e);
483 
484  /* kill standalone vertices from this edge - see T32341. */
485  if (!v1->e) {
486  BM_vert_kill(bm, v1);
487  }
488  if (!v2->e) {
489  BM_vert_kill(bm, v2);
490  }
491 
492  continue;
493  }
494 
495  /* skip creating face for excluded edges see T35503. */
496  if (BMO_slot_map_contains(slot_edges_exclude, e)) {
497  /* simply skip creating the face */
498  continue;
499  }
500 
501  e_new = BMO_iter_map_value_ptr(&siter);
502 
503  if (!e_new) {
504  continue;
505  }
506 
507  BMFace *join_face = NULL;
508  if (use_dissolve_ortho_edges) {
509  if (BM_edge_is_boundary(e)) {
510  join_face = e->l->f;
511  if (fabs(dot_v3v3(average_normal, join_face->no)) > 0.0001f) {
512  join_face = NULL;
513  }
514  }
515  }
516 
517  bool edge_normal_flip;
518  if (use_normal_from_adjacent == false) {
519  /* Orient loop to give same normal as a loop of 'e_new'
520  * if it exists (will be one of the faces from the region),
521  * else same normal as a loop of e, if it exists. */
522  edge_normal_flip = !(e_new->l ? (e_new->l->v == e_new->v1) : (!e->l || !(e->l->v == e->v1)));
523  }
524  else {
525  /* Special case, needed for repetitive extrusions
526  * that use the normals from the previously created faces. */
527  edge_normal_flip = !(e->l && e->v1 != e->l->v);
528  }
529 
530  if (edge_normal_flip == use_normal_flip) {
531  f_verts[0] = e->v1;
532  f_verts[1] = e->v2;
533  f_verts[2] = e_new->v2;
534  f_verts[3] = e_new->v1;
535  }
536  else {
537  f_verts[0] = e->v2;
538  f_verts[1] = e->v1;
539  f_verts[2] = e_new->v1;
540  f_verts[3] = e_new->v2;
541  }
542 
543 #ifdef USE_EDGE_REGION_FLAGS
544  /* handle new edges */
545  f_edges[0] = e;
546  f_edges[2] = e_new;
547 
548  f_edges[1] = BM_edge_exists(f_verts[1], f_verts[2]);
549  if (f_edges[1] == NULL) {
550  char e_hflag[2];
551  bool e_hflag_ok = bm_extrude_region_edge_flag(f_verts[2], e_hflag);
552  f_edges[1] = BM_edge_create(bm, f_verts[1], f_verts[2], NULL, BM_CREATE_NOP);
553  if (e_hflag_ok) {
554  BM_elem_flag_enable(f_edges[1], e_hflag[0]);
555  BM_elem_flag_disable(f_edges[1], e_hflag[1]);
556  }
557  }
558 
559  f_edges[3] = BM_edge_exists(f_verts[3], f_verts[0]);
560  if (f_edges[3] == NULL) {
561  char e_hflag[2];
562  bool e_hflag_ok = bm_extrude_region_edge_flag(f_verts[3], e_hflag);
563  f_edges[3] = BM_edge_create(bm, f_verts[3], f_verts[0], NULL, BM_CREATE_NOP);
564  if (e_hflag_ok) {
565  BM_elem_flag_enable(f_edges[3], e_hflag[0]);
566  BM_elem_flag_disable(f_edges[3], e_hflag[1]);
567  }
568  }
569 
570  f = BM_face_create(bm, f_verts, f_edges, 4, NULL, BM_CREATE_NOP);
571 #else
572  f = BM_face_create_verts(bm, f_verts, 4, NULL, BM_CREATE_NOP, true);
573 #endif
574 
576  if (join_face) {
577  BMVert *v1 = e->v1;
578  BMVert *v2 = e->v2;
579  if (!BMO_elem_flag_test(bm, v1, EXT_TAG)) {
581  dissolve_verts[dissolve_verts_len++] = v1;
582  }
583  if (!BMO_elem_flag_test(bm, v2, EXT_TAG)) {
585  dissolve_verts[dissolve_verts_len++] = v2;
586  }
587  /* Tag the edges that can collapse. */
588  BMO_elem_flag_enable(bm, f_edges[0], EXT_TAG);
589  BMO_elem_flag_enable(bm, f_edges[1], EXT_TAG);
590  bmesh_kernel_join_face_kill_edge(bm, join_face, f, e);
591  }
592  }
593 
594  /* link isolated vert */
595  for (v = BMO_iter_new(&siter, dupeop.slots_out, "isovert_map.out", 0); v;
596  v = BMO_iter_step(&siter)) {
597  BMVert *v2 = BMO_iter_map_value_ptr(&siter);
598 
599  /* not essential, but ensures face normals from extruded edges are contiguous */
600  if (BM_vert_is_wire_endpoint(v)) {
601  if (v->e->v1 == v) {
602  SWAP(BMVert *, v, v2);
603  }
604  }
605 
607  }
608 
609  if (dissolve_verts) {
610  BMVert **v_iter = &dissolve_verts[0];
611  for (int i = dissolve_verts_len; i--; v_iter++) {
612  v = *v_iter;
613  e = v->e;
614  BMEdge *e_other = BM_DISK_EDGE_NEXT(e, v);
615  if ((e_other == e) || (BM_DISK_EDGE_NEXT(e_other, v) == e)) {
616  /* Loose edge or BMVert is edge pair. */
617  BM_edge_collapse(bm, BMO_elem_flag_test(bm, e, EXT_TAG) ? e : e_other, v, true, true);
618  }
619  else {
621  }
622  }
623  MEM_freeN(dissolve_verts);
624  }
625 
626  /* cleanup */
627  if (delorig) {
628  BMO_op_finish(bm, &delop);
629  }
630  BMO_op_finish(bm, &dupeop);
631 }
632 
633 /*
634  * Compute higher-quality vertex normals used by solidify.
635  * Only considers geometry in the marked solidify region.
636  * Note that this does not work so well for non-manifold
637  * regions.
638  */
640 {
641  BMIter viter, eiter, fiter;
642  BMVert *v;
643  BMEdge *e;
644  BMFace *f, *f1, *f2;
645  float edge_normal[3];
646  int i;
647 
648  /* can't use BM_edge_face_count because we need to count only marked faces */
649  int *edge_face_count = MEM_callocN(sizeof(int) * bm->totedge, __func__);
650 
651  BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
653  }
654 
656 
657  BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
658  if (!BMO_face_flag_test(bm, f, FACE_MARK)) {
659  continue;
660  }
661 
662  BM_ITER_ELEM (e, &eiter, f, BM_EDGES_OF_FACE) {
663 
664  /* And mark all edges and vertices on the
665  * marked faces */
669  edge_face_count[BM_elem_index_get(e)]++;
670  }
671  }
672 
673  BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
674  if (!BMO_edge_flag_test(bm, e, EDGE_MARK)) {
675  continue;
676  }
677 
678  i = edge_face_count[BM_elem_index_get(e)]++;
679 
680  if (i == 0 || i > 2) {
681  /* Edge & vertices are non-manifold even when considering
682  * only marked faces */
686  }
687  }
688  MEM_freeN(edge_face_count);
689  edge_face_count = NULL; /* don't re-use */
690 
691  BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
692  if (!BM_vert_is_manifold(v)) {
694  continue;
695  }
696 
697  if (BMO_vert_flag_test(bm, v, VERT_MARK)) {
698  zero_v3(v->no);
699  }
700  }
701 
702  BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
703 
704  /* If the edge is not part of a the solidify region
705  * its normal should not be considered */
706  if (!BMO_edge_flag_test(bm, e, EDGE_MARK)) {
707  continue;
708  }
709 
710  /* If the edge joins more than two marked faces high
711  * quality normal computation won't work */
713  continue;
714  }
715 
716  f1 = f2 = NULL;
717 
718  BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
719  if (BMO_face_flag_test(bm, f, FACE_MARK)) {
720  if (f1 == NULL) {
721  f1 = f;
722  }
723  else {
724  BLI_assert(f2 == NULL);
725  f2 = f;
726  }
727  }
728  }
729 
730  BLI_assert(f1 != NULL);
731 
732  if (f2 != NULL) {
733  const float angle = angle_normalized_v3v3(f1->no, f2->no);
734 
735  if (angle > 0.0f) {
736  /* two faces using this edge, calculate the edge normal
737  * using the angle between the faces as a weighting */
738  add_v3_v3v3(edge_normal, f1->no, f2->no);
739  normalize_v3_length(edge_normal, angle);
740  }
741  else {
742  /* can't do anything useful here!
743  * Set the face index for a vert in case it gets a zero normal */
746  continue;
747  }
748  }
749  else {
750  /* only one face attached to that edge */
751  /* an edge without another attached- the weight on this is undefined,
752  * M_PI_2 is 90d in radians and that seems good enough */
753  copy_v3_v3(edge_normal, f1->no);
754  mul_v3_fl(edge_normal, M_PI_2);
755  }
756 
757  add_v3_v3(e->v1->no, edge_normal);
758  add_v3_v3(e->v2->no, edge_normal);
759  }
760 
761  /* normalize accumulated vertex normal */
762  BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
763  if (!BMO_vert_flag_test(bm, v, VERT_MARK)) {
764  continue;
765  }
766 
768  /* use standard normals for vertices connected to non-manifold edges */
770  }
771  else if (normalize_v3(v->no) == 0.0f && !BM_elem_flag_test(v, BM_ELEM_TAG)) {
772  /* exceptional case, totally flat. use the normal
773  * of any marked face around the vertex */
774  BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) {
775  if (BMO_face_flag_test(bm, f, FACE_MARK)) {
776  break;
777  }
778  }
779  copy_v3_v3(v->no, f->no);
780  }
781  }
782 }
783 
784 static void solidify_add_thickness(BMesh *bm, const float dist)
785 {
786  BMFace *f;
787  BMVert *v;
788  BMLoop *l;
789  BMIter iter, loopIter;
790  float *vert_angles = MEM_callocN(sizeof(float) * bm->totvert * 2, "solidify"); /* 2 in 1 */
791  float *vert_accum = vert_angles + bm->totvert;
792  int i, index;
793 
796 
798 
799  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
800  if (BMO_face_flag_test(bm, f, FACE_MARK)) {
801 
802  /* array for passing verts to angle_poly_v3 */
803  float *face_angles = BLI_buffer_reinit_data(&face_angles_buf, float, f->len);
804  /* array for receiving angles from angle_poly_v3 */
805  float **verts = BLI_buffer_reinit_data(&verts_buf, float *, f->len);
806 
807  BM_ITER_ELEM_INDEX (l, &loopIter, f, BM_LOOPS_OF_FACE, i) {
808  verts[i] = l->v->co;
809  }
810 
811  angle_poly_v3(face_angles, (const float **)verts, f->len);
812 
813  i = 0;
814  BM_ITER_ELEM (l, &loopIter, f, BM_LOOPS_OF_FACE) {
815  v = l->v;
816  index = BM_elem_index_get(v);
817  vert_accum[index] += face_angles[i];
818  vert_angles[index] += shell_v3v3_normalized_to_dist(v->no, f->no) * face_angles[i];
819  i++;
820  }
821  }
822  }
823 
824  BLI_buffer_free(&face_angles_buf);
825  BLI_buffer_free(&verts_buf);
826 
827  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
828  index = BM_elem_index_get(v);
829  if (vert_accum[index]) { /* zero if unselected */
830  madd_v3_v3fl(v->co, v->no, dist * (vert_angles[index] / vert_accum[index]));
831  }
832  }
833 
834  MEM_freeN(vert_angles);
835 }
836 
838 {
839  BMOperator extrudeop;
840  BMOperator reverseop;
841  float thickness;
842 
843  thickness = BMO_slot_float_get(op->slots_in, "thickness");
844 
845  /* Flip original faces (so the shell is extruded inward) */
846  BMO_op_init(bm, &reverseop, op->flag, "reverse_faces");
847  BMO_slot_bool_set(reverseop.slots_in, "flip_multires", true);
848  BMO_slot_copy(op, slots_in, "geom", &reverseop, slots_in, "faces");
849  BMO_op_exec(bm, &reverseop);
850  BMO_op_finish(bm, &reverseop);
851 
852  /* Extrude the region */
853  BMO_op_initf(bm, &extrudeop, op->flag, "extrude_face_region use_keep_orig=%b", true);
854  BMO_slot_copy(op, slots_in, "geom", &extrudeop, slots_in, "geom");
855  BMO_op_exec(bm, &extrudeop);
856 
857  /* Push the verts of the extruded faces inward to create thickness */
858  BMO_slot_buffer_flag_enable(bm, extrudeop.slots_out, "geom.out", BM_FACE, FACE_MARK);
860  solidify_add_thickness(bm, thickness);
861 
862  BMO_slot_copy(&extrudeop, slots_out, "geom.out", op, slots_out, "geom.out");
863 
864  BMO_op_finish(bm, &extrudeop);
865 }
CustomData interface, see also DNA_customdata_types.h.
bool CustomData_has_layer(const struct CustomData *data, int type)
void * CustomData_bmesh_get(const struct CustomData *data, void *block, int type)
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BLI_buffer_reinit_data(buffer_, type_, new_count_)
Definition: BLI_buffer.h:61
@ BLI_BUFFER_NOP
Definition: BLI_buffer.h:35
#define BLI_buffer_declare_static(type_, name_, flag_, static_count_)
Definition: BLI_buffer.h:39
#define BLI_buffer_free(name_)
Definition: BLI_buffer.h:92
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:1008
void * BLI_ghash_lookup(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:803
#define M_PI_2
Definition: BLI_math_base.h:41
MINLINE float shell_v3v3_normalized_to_dist(const float a[3], const float b[3])
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE float normalize_v3(float r[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
void angle_poly_v3(float *angles, const float *verts[3], int len)
Definition: math_vector.c:639
MINLINE float normalize_v3_length(float r[3], const float unit_scale)
MINLINE void zero_v3(float r[3])
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:505
MINLINE void add_v3_v3(float r[3], const float a[3])
#define SWAP(type, a, b)
#define UNLIKELY(x)
@ CD_MVERT_SKIN
@ MVERT_SKIN_ROOT
_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.
#define BM_DISK_EDGE_NEXT(e, v)
Definition: bmesh_class.h:556
#define BM_DEFAULT_NGON_STACK_SIZE
Definition: bmesh_class.h:571
#define BM_ALL_NOLOOP
Definition: bmesh_class.h:411
@ BM_FACE
Definition: bmesh_class.h:386
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_EDGE
Definition: bmesh_class.h:384
@ BM_ELEM_HIDDEN
Definition: bmesh_class.h:472
@ BM_ELEM_SEAM
Definition: bmesh_class.h:473
@ BM_ELEM_SMOOTH
Definition: bmesh_class.h:477
@ BM_ELEM_TAG
Definition: bmesh_class.h:484
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:553
void BM_elem_attrs_copy(BMesh *bm_src, BMesh *bm_dst, const void *ele_src, void *ele_dst)
BMFace * BM_face_create_quad_tri(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4, const BMFace *f_example, const eBMCreateFlag create_flag)
Make Quad/Triangle.
BMVert * BM_vert_create(BMesh *bm, const float co[3], const BMVert *v_example, const eBMCreateFlag create_flag)
Main function for creating a new vertex.
Definition: bmesh_core.c:58
BMFace * BM_face_create_verts(BMesh *bm, BMVert **vert_arr, const int len, const BMFace *f_example, const eBMCreateFlag create_flag, const bool create_edges)
Definition: bmesh_core.c:500
BMFace * bmesh_kernel_join_face_kill_edge(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e)
Join Face Kill Edge (JFKE)
Definition: bmesh_core.c:2102
void BM_vert_kill(BMesh *bm, BMVert *v)
Definition: bmesh_core.c:1002
void BM_edge_kill(BMesh *bm, BMEdge *e)
Definition: bmesh_core.c:987
BMFace * BM_face_copy(BMesh *bm_dst, BMesh *bm_src, BMFace *f, const bool copy_verts, const bool copy_edges)
Definition: bmesh_core.c:303
BMFace * BM_face_create(BMesh *bm, BMVert **verts, BMEdge **edges, const int len, const BMFace *f_example, const eBMCreateFlag create_flag)
Definition: bmesh_core.c:428
BMEdge * BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *e_example, const eBMCreateFlag create_flag)
Main function for creating a new edge.
Definition: bmesh_core.c:147
@ BM_CREATE_NOP
Definition: bmesh_core.h:27
@ BM_CREATE_NO_DOUBLE
Definition: bmesh_core.h:29
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:124
#define BM_elem_flag_disable(ele, hflag)
Definition: bmesh_inline.h:29
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:28
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_FACES_OF_EDGE
@ BM_FACES_OF_VERT
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_FACES_OF_MESH
@ BM_EDGES_OF_VERT
@ BM_EDGES_OF_FACE
@ BM_LOOPS_OF_FACE
#define BM_ITER_ELEM_INDEX(ele, iter, data, itype, indexvar)
ATTR_WARN_UNUSED_RESULT BMesh * bm
GHash * BM_select_history_map_create(BMesh *bm)
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.c:2152
BMVert * BM_edge_collapse(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool do_del, const bool kill_degenerate_faces)
Definition: bmesh_mods.c:566
void * BMO_iter_new(BMOIter *iter, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char restrictmask)
New Iterator.
void BMO_slot_buffer_flag_enable(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char htype, const short oflag)
BMO_FLAG_BUFFER.
void BMO_slot_bool_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const bool i)
#define BMO_edge_flag_test(bm, e, oflag)
void * BMO_iter_step(BMOIter *iter)
#define BMO_edge_flag_enable(bm, e, oflag)
float BMO_slot_float_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
#define BMO_vert_flag_enable(bm, e, oflag)
void BMO_op_exec(BMesh *bm, BMOperator *op)
BMESH OPSTACK EXEC OP.
bool BMO_op_initf(BMesh *bm, BMOperator *op, const int flag, const char *fmt,...)
#define BMO_face_flag_enable(bm, e, oflag)
#define BMO_slot_copy(op_src, slots_src, slot_name_src, op_dst, slots_dst, slot_name_dst)
#define BMO_ITER(ele, iter, slot_args, slot_name, restrict_flag)
int BMO_slot_map_count(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
#define BMO_vert_flag_test(bm, e, oflag)
void BMO_op_finish(BMesh *bm, BMOperator *op)
BMESH OPSTACK FINISH OP.
void * BMO_iter_map_value_ptr(BMOIter *iter)
#define BMO_elem_flag_enable(bm, ele, oflag)
BMOpSlot * BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
BMESH OPSTACK GET SLOT.
@ DEL_ONLYTAGGED
@ DEL_ONLYFACES
#define BMO_elem_flag_test(bm, ele, oflag)
#define BMO_face_flag_test(bm, e, oflag)
void BMO_slot_buffer_from_enabled_flag(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char htype, const short oflag)
bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
void BMO_op_init(BMesh *bm, BMOperator *op, const int flag, const char *opname)
BMESH OPSTACK INIT OP.
bool BMO_op_callf(BMesh *bm, const int flag, const char *fmt,...)
void BM_vert_normal_update(BMVert *v)
void BM_face_normal_flip(BMesh *bm, BMFace *f)
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
Definition: bmesh_query.c:1995
bool BM_vert_is_manifold(const BMVert *v)
Definition: bmesh_query.c:943
BMLoop * BM_edge_other_loop(BMEdge *e, BMLoop *l)
Definition: bmesh_query.c:587
bool BM_vert_is_edge_pair(const BMVert *v)
Definition: bmesh_query.c:771
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
#define VERT_MARK
Definition: bmo_extrude.c:45
static void solidify_add_thickness(BMesh *bm, const float dist)
Definition: bmo_extrude.c:784
@ EXT_INPUT
Definition: bmo_extrude.c:39
@ EXT_TAG
Definition: bmo_extrude.c:42
@ EXT_KEEP
Definition: bmo_extrude.c:40
@ EXT_DEL
Definition: bmo_extrude.c:41
void bmo_extrude_discrete_faces_exec(BMesh *bm, BMOperator *op)
Definition: bmo_extrude.c:51
static void bm_extrude_copy_face_loop_attributes(BMesh *bm, BMFace *f)
Copy the loop pair from an adjacent face to both sides of this quad.
Definition: bmo_extrude.c:137
static bool bm_extrude_region_edge_flag(const BMVert *v, char r_e_hflag[2])
Definition: bmo_extrude.c:297
void bmo_extrude_edge_only_exec(BMesh *bm, BMOperator *op)
Definition: bmo_extrude.c:176
void bmo_extrude_vert_indiv_exec(BMesh *bm, BMOperator *op)
Definition: bmo_extrude.c:244
#define FACE_MARK
Definition: bmo_extrude.c:47
void bmo_solidify_face_region_exec(BMesh *bm, BMOperator *op)
Definition: bmo_extrude.c:837
#define EDGE_MARK
Definition: bmo_extrude.c:46
#define EDGE_NONMAN
Definition: bmo_extrude.c:49
#define VERT_NONMAN
Definition: bmo_extrude.c:48
static void bm_extrude_disable_skin_root(BMesh *bm, BMVert *v)
Definition: bmo_extrude.c:168
static void calc_solidify_normals(BMesh *bm)
Definition: bmo_extrude.c:639
void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
Definition: bmo_extrude.c:325
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Definition: btVector3.h:356
static float verts[][3]
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
BMHeader head
Definition: bmesh_class.h:123
BMVert * v1
Definition: bmesh_class.h:134
BMVert * v2
Definition: bmesh_class.h:134
struct BMLoop * l
Definition: bmesh_class.h:140
int len
Definition: bmesh_class.h:279
float no[3]
Definition: bmesh_class.h:280
char hflag
Definition: bmesh_class.h:78
void * data
Definition: bmesh_class.h:63
struct BMVert * v
Definition: bmesh_class.h:165
struct BMEdge * e
Definition: bmesh_class.h:176
struct BMLoop * radial_next
Definition: bmesh_class.h:216
struct BMFace * f
Definition: bmesh_class.h:183
struct BMLoop * next
Definition: bmesh_class.h:245
struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
float co[3]
Definition: bmesh_class.h:99
struct BMEdge * e
Definition: bmesh_class.h:109
float no[3]
Definition: bmesh_class.h:100
BMHeader head
Definition: bmesh_class.h:97
int totvert
Definition: bmesh_class.h:297
CustomData vdata
Definition: bmesh_class.h:337
int totedge
Definition: bmesh_class.h:297
BMFace * act_face
Definition: bmesh_class.h:366
ccl_device_inline float2 fabs(const float2 &a)