Blender  V2.93
bmo_inset.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 
24 #include "MEM_guardedalloc.h"
25 
26 #include "BLI_alloca.h"
27 #include "BLI_math.h"
28 #include "BLI_memarena.h"
29 #include "BLI_utildefines_stack.h"
30 
31 #include "BKE_customdata.h"
32 
33 #include "bmesh.h"
34 
35 #include "intern/bmesh_operators_private.h" /* own include */
36 
37 /* Merge loop-data that diverges, see: T41445 */
38 #define USE_LOOP_CUSTOMDATA_MERGE
39 
40 #define ELE_NEW 1
41 
42 /* -------------------------------------------------------------------- */
55 /* just enough of a face to store interpolation data we can use once the inset is done */
56 typedef struct InterpFace {
58  void **blocks_l;
59  void **blocks_v;
60  float (*cos_2d)[2];
61  float axis_mat[3][3];
63 
64 /* basically a clone of #BM_vert_interp_from_face */
65 static void bm_interp_face_store(InterpFace *iface, BMesh *bm, BMFace *f, MemArena *interp_arena)
66 {
67  BMLoop *l_iter, *l_first;
68  void **blocks_l = iface->blocks_l = BLI_memarena_alloc(interp_arena,
69  sizeof(*iface->blocks_l) * f->len);
70  void **blocks_v = iface->blocks_v = BLI_memarena_alloc(interp_arena,
71  sizeof(*iface->blocks_v) * f->len);
72  float(*cos_2d)[2] = iface->cos_2d = BLI_memarena_alloc(interp_arena,
73  sizeof(*iface->cos_2d) * f->len);
74  void *axis_mat = iface->axis_mat;
75  int i;
76 
78 
79  axis_dominant_v3_to_m3(axis_mat, f->no);
80 
81  iface->f = f;
82 
83  i = 0;
84  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
85  do {
86  mul_v2_m3v3(cos_2d[i], axis_mat, l_iter->v->co);
87  blocks_l[i] = NULL;
88  CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, l_iter->head.data, &blocks_l[i]);
89  /* if we were not modifying the loops later we would do... */
90  // blocks[i] = l_iter->head.data;
91 
92  blocks_v[i] = NULL;
93  CustomData_bmesh_copy_data(&bm->vdata, &bm->vdata, l_iter->v->head.data, &blocks_v[i]);
94 
95  /* use later for index lookups */
96  BM_elem_index_set(l_iter, i); /* set_dirty */
97  } while ((void)i++, (l_iter = l_iter->next) != l_first);
99 }
100 static void bm_interp_face_free(InterpFace *iface, BMesh *bm)
101 {
102  void **blocks_l = iface->blocks_l;
103  void **blocks_v = iface->blocks_v;
104  int i;
105 
106  for (i = 0; i < iface->f->len; i++) {
107  CustomData_bmesh_free_block(&bm->ldata, &blocks_l[i]);
108  CustomData_bmesh_free_block(&bm->vdata, &blocks_v[i]);
109  }
110 }
111 
112 #ifdef USE_LOOP_CUSTOMDATA_MERGE
118  BMEdge *e_connect,
119  BMLoop *l_a_outer,
120  BMLoop *l_b_outer,
121  BMLoop *l_a_inner,
122  BMLoop *l_b_inner)
123 {
146  const bool is_flip = (l_a_inner->next == l_a_outer);
147  BMLoop *l_a_inner_inset, *l_b_inner_inset;
148  BMEdge *e_a, *e_b;
149  int layer_n;
150 
151  /* paranoid sanity checks */
152  BLI_assert(l_a_outer->v == l_b_outer->v);
153  BLI_assert(l_a_inner->v == l_b_inner->v);
154 
155  BLI_assert(l_b_inner->f != l_a_inner->f);
156 
157  BLI_assert(l_a_outer->f == l_a_inner->f);
158  BLI_assert(l_b_outer->f == l_b_inner->f);
159 
160  (void)e_connect;
161  BLI_assert(BM_edge_in_face(e_connect, l_a_inner->f));
162  BLI_assert(BM_edge_in_face(e_connect, l_b_inner->f));
163 
164  if (is_flip) {
165  e_a = l_a_inner->prev->e;
166  e_b = l_b_inner->e;
167  }
168  else {
169  e_a = l_a_inner->e;
170  e_b = l_b_inner->prev->e;
171  }
172 
173  l_a_inner_inset = BM_edge_other_loop(e_a, l_a_inner);
174  l_b_inner_inset = BM_edge_other_loop(e_b, l_b_inner);
175  BLI_assert(l_a_inner_inset->v == l_b_inner_inset->v);
176 
177  /* check if there is no chance of diversion */
178  if (l_a_inner_inset->f == l_b_inner_inset->f) {
179  return;
180  }
181 
182  for (layer_n = 0; layer_n < bm->ldata.totlayer; layer_n++) {
183  const int type = bm->ldata.layers[layer_n].type;
184  const int offset = bm->ldata.layers[layer_n].offset;
185  if (!CustomData_layer_has_math(&bm->ldata, layer_n)) {
186  continue;
187  }
188 
189  /* check we begin with merged data */
191  BM_ELEM_CD_GET_VOID_P(l_a_outer, offset),
192  BM_ELEM_CD_GET_VOID_P(l_b_outer, offset)) == true)
193 
194  /* Epsilon for comparing UV's is too big, gives noticeable problems. */
195 # if 0
196  &&
197  /* check if the data ends up diverged */
199  BM_ELEM_CD_GET_VOID_P(l_a_inner, offset),
200  BM_ELEM_CD_GET_VOID_P(l_b_inner, offset)) == false)
201 # endif
202  ) {
203  /* no need to allocate a temp block:
204  * a = (a + b);
205  * a *= 0.5f;
206  * b = a;
207  */
208  const void *data_src;
209 
211  BM_ELEM_CD_GET_VOID_P(l_a_inner_inset, offset),
212  BM_ELEM_CD_GET_VOID_P(l_b_inner_inset, offset),
213  CDT_MIX_MIX,
214  0.5f);
216  BM_ELEM_CD_GET_VOID_P(l_a_inner_inset, offset),
217  BM_ELEM_CD_GET_VOID_P(l_b_inner_inset, offset));
218 
219  /* use this as a reference (could be 'l_b_inner_inset' too) */
220  data_src = BM_ELEM_CD_GET_VOID_P(l_a_inner_inset, offset);
221 
222  /* check if the 2 faces share an edge */
223  if (is_flip ? (l_b_inner_inset->e == l_a_inner_inset->prev->e) :
224  (l_a_inner_inset->e == l_b_inner_inset->prev->e)) {
225  /* simple case, we have all loops already */
226  }
227  else {
228  /* compare with (l_a_inner / l_b_inner) and assign the blended value if they match */
229  BMIter iter;
230  BMLoop *l_iter;
231  const void *data_cmp_a = BM_ELEM_CD_GET_VOID_P(l_b_inner, offset);
232  const void *data_cmp_b = BM_ELEM_CD_GET_VOID_P(l_a_inner, offset);
233  BM_ITER_ELEM (l_iter, &iter, l_a_inner_inset->v, BM_LOOPS_OF_VERT) {
234  if (BM_elem_flag_test(l_iter->f, BM_ELEM_TAG)) {
235  if (!ELEM(l_iter, l_a_inner, l_b_inner, l_a_inner_inset, l_b_inner_inset)) {
236  void *data_dst = BM_ELEM_CD_GET_VOID_P(l_iter, offset);
237 
238  if (CustomData_data_equals(type, data_dst, data_cmp_a) ||
239  CustomData_data_equals(type, data_dst, data_cmp_b)) {
240  CustomData_data_copy_value(type, data_src, data_dst);
241  }
242  }
243  }
244  }
245  }
246 
247  CustomData_data_copy_value(type, data_src, BM_ELEM_CD_GET_VOID_P(l_b_inner, offset));
248  CustomData_data_copy_value(type, data_src, BM_ELEM_CD_GET_VOID_P(l_a_inner, offset));
249  }
250  }
251 }
252 #endif /* USE_LOOP_CUSTOMDATA_MERGE */
253 
256 /* -------------------------------------------------------------------- */
263  BMFace *f,
264  MemArena *interp_arena,
265  const float thickness,
266  const float depth,
267  const bool use_even_offset,
268  const bool use_relative_offset,
269  const bool use_interpolate)
270 {
271  InterpFace *iface = NULL;
272 
273  /* stores verts split away from the face (aligned with face verts) */
275  /* store edge normals (aligned with face-loop-edges) */
276  float(*edge_nors)[3] = BLI_array_alloca(edge_nors, f->len);
277  float(*coords)[3] = BLI_array_alloca(coords, f->len);
278 
279  BMLoop *l_iter, *l_first;
280  BMLoop *l_other;
281  uint i;
282  float e_length_prev;
283 
284  l_first = BM_FACE_FIRST_LOOP(f);
285 
286  /* split off all loops */
287  l_iter = l_first;
288  i = 0;
289  do {
290  BMVert *v_other = l_iter->v;
291  BMVert *v_sep = BM_face_loop_separate(bm, l_iter);
292  if (v_sep == v_other) {
293  v_other = BM_vert_create(bm, l_iter->v->co, l_iter->v, BM_CREATE_NOP);
294  }
295  verts[i] = v_other;
296 
297  /* unrelated to splitting, but calc here */
298  BM_edge_calc_face_tangent(l_iter->e, l_iter, edge_nors[i]);
299  } while ((void)i++, ((l_iter = l_iter->next) != l_first));
300 
301  /* build rim faces */
302  l_iter = l_first;
303  i = 0;
304  do {
305  BMFace *f_new_outer;
306  BMVert *v_other = verts[i];
307  BMVert *v_other_next = verts[(i + 1) % f->len];
308 
309  BMEdge *e_other = BM_edge_create(bm, v_other, v_other_next, l_iter->e, BM_CREATE_NO_DOUBLE);
310  (void)e_other;
311 
312  f_new_outer = BM_face_create_quad_tri(
313  bm, v_other, v_other_next, l_iter->next->v, l_iter->v, f, BM_CREATE_NOP);
314  BMO_face_flag_enable(bm, f_new_outer, ELE_NEW);
315 
316  /* copy loop data */
317  l_other = l_iter->radial_next;
318  BM_elem_attrs_copy(bm, bm, l_iter->next, l_other->prev);
319  BM_elem_attrs_copy(bm, bm, l_iter, l_other->next->next);
320 
321  if (use_interpolate == false) {
322  BM_elem_attrs_copy(bm, bm, l_iter->next, l_other);
323  BM_elem_attrs_copy(bm, bm, l_iter, l_other->next);
324  }
325  } while ((void)i++, ((l_iter = l_iter->next) != l_first));
326 
327  /* hold interpolation values */
328  if (use_interpolate) {
329  iface = BLI_memarena_alloc(interp_arena, sizeof(*iface));
330  bm_interp_face_store(iface, bm, f, interp_arena);
331  }
332 
333  /* Calculate translation vector for new */
334  l_iter = l_first;
335  i = 0;
336 
337  if (depth != 0.0f) {
338  e_length_prev = BM_edge_calc_length(l_iter->prev->e);
339  }
340 
341  do {
342  const float *eno_prev = edge_nors[(i ? i : f->len) - 1];
343  const float *eno_next = edge_nors[i];
344  float tvec[3];
345  float v_new_co[3];
346 
347  add_v3_v3v3(tvec, eno_prev, eno_next);
348  normalize_v3(tvec);
349 
350  copy_v3_v3(v_new_co, l_iter->v->co);
351 
352  if (use_even_offset) {
353  mul_v3_fl(tvec, shell_v3v3_mid_normalized_to_dist(eno_prev, eno_next));
354  }
355 
356  /* Modify vertices and their normals */
357  if (use_relative_offset) {
358  mul_v3_fl(tvec,
359  (BM_edge_calc_length(l_iter->e) + BM_edge_calc_length(l_iter->prev->e)) / 2.0f);
360  }
361 
362  madd_v3_v3fl(v_new_co, tvec, thickness);
363 
364  /* Set normal, add depth and write new vertex position*/
365  copy_v3_v3(l_iter->v->no, f->no);
366 
367  if (depth != 0.0f) {
368  const float e_length = BM_edge_calc_length(l_iter->e);
369  const float fac = depth * (use_relative_offset ? ((e_length_prev + e_length) * 0.5f) : 1.0f);
370  e_length_prev = e_length;
371 
372  madd_v3_v3fl(v_new_co, f->no, fac);
373  }
374 
375  copy_v3_v3(coords[i], v_new_co);
376  } while ((void)i++, ((l_iter = l_iter->next) != l_first));
377 
378  /* update the coords */
379  l_iter = l_first;
380  i = 0;
381  do {
382  copy_v3_v3(l_iter->v->co, coords[i]);
383  } while ((void)i++, ((l_iter = l_iter->next) != l_first));
384 
385  if (use_interpolate) {
387  iface->f,
388  iface->f,
389  true,
390  (const void **)iface->blocks_l,
391  (const void **)iface->blocks_v,
392  iface->cos_2d,
393  iface->axis_mat);
394 
395  /* build rim faces */
396  l_iter = l_first;
397  do {
398  /* copy loop data */
399  l_other = l_iter->radial_next;
400 
401  BM_elem_attrs_copy(bm, bm, l_iter->next, l_other);
402  BM_elem_attrs_copy(bm, bm, l_iter, l_other->next);
403  } while ((l_iter = l_iter->next) != l_first);
404 
405  bm_interp_face_free(iface, bm);
406  }
407 }
408 
416 {
417  BMFace *f;
418 
419  BMOIter oiter;
420  MemArena *interp_arena = NULL;
421 
422  const float thickness = BMO_slot_float_get(op->slots_in, "thickness");
423  const float depth = BMO_slot_float_get(op->slots_in, "depth");
424  const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset");
425  const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset");
426  const bool use_interpolate = BMO_slot_bool_get(op->slots_in, "use_interpolate");
427 
428  /* Only tag faces in slot */
430 
432 
433  if (use_interpolate) {
434  interp_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
435  }
436 
437  BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) {
439  f,
440  interp_arena,
441  thickness,
442  depth,
443  use_even_offset,
444  use_relative_offset,
445  use_interpolate);
446 
447  if (use_interpolate) {
448  BLI_memarena_clear(interp_arena);
449  }
450  }
451 
452  /* we could flag new edges/verts too, is it useful? */
454 
455  if (use_interpolate) {
456  BLI_memarena_free(interp_arena);
457  }
458 }
459 
462 /* -------------------------------------------------------------------- */
468 typedef struct SplitEdgeInfo {
469  float no[3];
470  float length;
475 
485 {
486  if (LIKELY(l != NULL)) {
487  int tot_tag = 0;
488  int tot_untag = 0;
489  BMLoop *l_iter;
490  BMLoop *l_tag = NULL;
491  l_iter = l;
492  do {
493  if (BM_elem_flag_test(l_iter->f, BM_ELEM_TAG)) {
494  /* more than one tagged face - bail out early! */
495  if (tot_tag == 1) {
496  return NULL;
497  }
498  l_tag = l_iter;
499  tot_tag++;
500  }
501  else {
502  tot_untag++;
503  }
504 
505  } while ((l_iter = l_iter->radial_next) != l);
506 
507  return ((tot_tag == 1) && (tot_untag >= 1)) ? l_tag : NULL;
508  }
509  return NULL;
510 }
511 
513 {
514  BMIter iter;
515  BMEdge *e;
516 
517  float len = 0.0f;
518  int tot = 0;
519 
520  BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
521  const int i = BM_elem_index_get(e);
522  if (i != -1) {
523  len += edge_info[i].length;
524  tot++;
525  }
526  }
527 
528  if (tot != 0) {
529  return len / (float)tot;
530  }
531  return -1.0f;
532 }
533 
549  SplitEdgeInfo *edge_info,
550  BMesh *bm,
551  void **vert_lengths_p)
552 {
553  struct {
561  float length_accum;
570  int count;
571  } *vert_lengths = *vert_lengths_p;
572 
573  /* Only run this once, if needed. */
574  if (UNLIKELY(vert_lengths == NULL)) {
575  BMVert **vert_stack = MEM_mallocN(sizeof(*vert_stack) * bm->totvert, __func__);
576  STACK_DECLARE(vert_stack);
577  STACK_INIT(vert_stack, bm->totvert);
578 
579  vert_lengths = MEM_callocN(sizeof(*vert_lengths) * bm->totvert, __func__);
580 
581  /* Needed for 'vert_lengths' lookup from connected vertices. */
583 
584  {
585  BMIter iter;
586  BMEdge *e;
587  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
588  if (BM_elem_index_get(e) != -1) {
589  for (int i = 0; i < 2; i++) {
590  BMVert *v = *((&e->v1) + i);
592  const int v_index = BM_elem_index_get(v);
593  if (vert_lengths[v_index].count == 0) {
594  STACK_PUSH(vert_stack, v);
595  /* Needed for the first pass, avoid a separate loop to handle the first pass. */
596  vert_lengths[v_index].count = 1;
597  /* We know the edge lengths exist in this case, should never be -1. */
598  vert_lengths[v_index].length_accum = bm_edge_info_average_length(v, edge_info);
599  BLI_assert(vert_lengths[v_index].length_accum != -1.0f);
600  }
601  }
602  }
603  }
604  }
605  }
606 
607  /* While there are vertices without their accumulated lengths divided by the count. */
608  while (STACK_SIZE(vert_stack) != 0) {
609  int stack_index = STACK_SIZE(vert_stack);
610  while (stack_index--) {
611  BMVert *v = vert_stack[stack_index];
612  STACK_REMOVE(vert_stack, stack_index);
613  const int v_index = BM_elem_index_get(v);
614 
615  BLI_assert(vert_lengths[v_index].count > 0);
616  vert_lengths[v_index].length_accum /= (float)vert_lengths[v_index].count;
617  vert_lengths[v_index].count = -1; /* Ignore in future passes. */
618 
619  BMIter iter;
620  BMEdge *e;
621  BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
623  continue;
624  }
625  BMVert *v_other = BM_edge_other_vert(e, v);
626  if (!BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
627  continue;
628  }
629  int v_other_index = BM_elem_index_get(v_other);
630  if (vert_lengths[v_other_index].count >= 0) {
631  if (vert_lengths[v_other_index].count == 0) {
632  STACK_PUSH(vert_stack, v_other);
633  }
634  BLI_assert(vert_lengths[v_index].length_accum >= 0.0f);
635  vert_lengths[v_other_index].count += 1;
636  vert_lengths[v_other_index].length_accum += vert_lengths[v_index].length_accum;
637  }
638  }
639  }
640  }
641  MEM_freeN(vert_stack);
642  *vert_lengths_p = vert_lengths;
643  }
644 
645  BLI_assert(vert_lengths[BM_elem_index_get(v_lookup)].length_accum >= 0.0f);
646  return vert_lengths[BM_elem_index_get(v_lookup)].length_accum;
647 }
648 
650  BMVert *v,
651  SplitEdgeInfo *edge_info,
652 
653  /* Needed for 'bm_edge_info_average_length_fallback' */
654  BMesh *bm,
655  void **vert_lengths_p)
656 {
657 
658  const float length = bm_edge_info_average_length(v, edge_info);
659  if (length != -1.0f) {
660  return length;
661  }
662  return bm_edge_info_average_length_fallback(v, edge_info, bm, vert_lengths_p);
663 }
664 
666 {
667  /*
668  * Implementation:
669  *
670  * - Set all faces as tagged/untagged based on selection.
671  * - Find all edges that have 1 tagged, 1 untagged face.
672  * - Separate these edges and tag vertices, set their index to point to the original edge.
673  * - Build faces between old/new edges.
674  * - Inset the new edges into their faces.
675  */
676 
677  const bool use_outset = BMO_slot_bool_get(op->slots_in, "use_outset");
678  const bool use_boundary = BMO_slot_bool_get(op->slots_in, "use_boundary") &&
679  (use_outset == false);
680  const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset");
681  const bool use_even_boundary = use_even_offset; /* could make own option */
682  const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset");
683  const bool use_edge_rail = BMO_slot_bool_get(op->slots_in, "use_edge_rail");
684  const bool use_interpolate = BMO_slot_bool_get(op->slots_in, "use_interpolate");
685  const float thickness = BMO_slot_float_get(op->slots_in, "thickness");
686  const float depth = BMO_slot_float_get(op->slots_in, "depth");
687 #ifdef USE_LOOP_CUSTOMDATA_MERGE
688  const bool has_math_ldata = (use_interpolate && CustomData_has_math(&bm->ldata));
689 #endif
690 
691  int edge_info_len = 0;
692 
693  BMIter iter;
694  SplitEdgeInfo *edge_info;
695  SplitEdgeInfo *es;
696 
697  /* Interpolation Vars */
698  /* an array aligned with faces but only fill items which are used. */
699  InterpFace **iface_array = NULL;
700  int iface_array_len;
701  MemArena *interp_arena = NULL;
702 
703  /* BMVert original location storage */
704  const bool use_vert_coords_orig = use_edge_rail;
705  MemArena *vert_coords_orig = NULL;
706  GHash *vert_coords = NULL;
707 
708  BMVert *v;
709  BMEdge *e;
710  BMFace *f;
711  int i, k;
712 
713  if (use_interpolate) {
714  interp_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
715  /* warning, we could be more clever here and not over alloc */
716  iface_array = MEM_callocN(sizeof(*iface_array) * bm->totface, __func__);
717  iface_array_len = bm->totface;
718  }
719 
720  if (use_outset == false) {
723  }
724  else {
727  BMO_slot_buffer_hflag_disable(bm, op->slots_in, "faces_exclude", BM_FACE, BM_ELEM_TAG, false);
728  }
729 
730  /* first count all inset edges we will split */
731  /* fill in array and initialize tagging */
732  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
733  if (
734  /* tag if boundary is enabled */
735  (use_boundary && BM_edge_is_boundary(e) && BM_elem_flag_test(e->l->f, BM_ELEM_TAG)) ||
736 
737  /* tag if edge is an interior edge in between a tagged and untagged face */
739  /* tag */
743 
744  BM_elem_index_set(e, edge_info_len); /* set_dirty! */
745  edge_info_len++;
746  }
747  else {
751 
752  BM_elem_index_set(e, -1); /* set_dirty! */
753  }
754  }
756 
757  edge_info = MEM_mallocN(edge_info_len * sizeof(SplitEdgeInfo), __func__);
758 
759  /* fill in array and initialize tagging */
760  es = edge_info;
761  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
762  i = BM_elem_index_get(e);
763  if (i != -1) {
764  /* calc edge-split info */
766  es->e_old = e;
767  es++;
768  /* initialize no and e_new after */
769  }
770  }
771 
772  if (use_vert_coords_orig) {
773  vert_coords_orig = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
774  vert_coords = BLI_ghash_ptr_new(__func__);
775  }
776 
777  /* util macros */
778 #define VERT_ORIG_STORE(_v) \
779  { \
780  float *_co = BLI_memarena_alloc(vert_coords_orig, sizeof(float[3])); \
781  copy_v3_v3(_co, (_v)->co); \
782  BLI_ghash_insert(vert_coords, _v, _co); \
783  } \
784  (void)0
785 #define VERT_ORIG_GET(_v) (const float *)BLI_ghash_lookup_default(vert_coords, (_v), (_v)->co)
786  /* memory for the coords isn't given back to the arena,
787  * acceptable in this case since it runs a fixed number of times. */
788 #define VERT_ORIG_REMOVE(_v) BLI_ghash_remove(vert_coords, (_v), NULL, NULL)
789 
790  for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
791  if ((es->l = bm_edge_is_mixed_face_tag(es->e_old->l))) {
792  /* do nothing */
793  }
794  else {
795  es->l = es->e_old->l; /* must be a boundary */
796  }
797 
798  /* run the separate arg */
799  if (!BM_edge_is_boundary(es->e_old)) {
800  bmesh_kernel_edge_separate(bm, es->e_old, es->l, false);
801  }
802 
803  /* calc edge-split info */
804  es->e_new = es->l->e;
805  BM_edge_calc_face_tangent(es->e_new, es->l, es->no);
806 
807  if (es->e_new == es->e_old) { /* happens on boundary edges */
808  /* Take care here, we're creating this double edge which _must_
809  * have its verts replaced later on. */
810  es->e_old = BM_edge_create(bm, es->e_new->v1, es->e_new->v2, es->e_new, BM_CREATE_NOP);
811  }
812 
813  /* store index back to original in 'edge_info' */
814  BM_elem_index_set(es->e_new, i);
816 
817  /* important to tag again here */
820 
821  /* initialize interpolation vars */
822  /* this could go in its own loop,
823  * only use the 'es->l->f' so we don't store loops for faces which have no mixed selection
824  *
825  * note: faces on the other side of the inset will be interpolated too since this is hard to
826  * detect, just allow it even though it will cause some redundant interpolation */
827  if (use_interpolate) {
828  BMIter viter;
829  BM_ITER_ELEM (v, &viter, es->l->e, BM_VERTS_OF_EDGE) {
830  BMIter fiter;
831  BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) {
832  const int j = BM_elem_index_get(f);
833  if (iface_array[j] == NULL) {
834  InterpFace *iface = BLI_memarena_alloc(interp_arena, sizeof(*iface));
835  bm_interp_face_store(iface, bm, f, interp_arena);
836  iface_array[j] = iface;
837  }
838  }
839  }
840  }
841  /* done interpolation */
842  }
843 
844  /* show edge normals for debugging */
845 #if 0
846  for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
847  float tvec[3];
848  BMVert *v1, *v2;
849 
850  mid_v3_v3v3(tvec, es->e_new->v1->co, es->e_new->v2->co);
851 
854  madd_v3_v3fl(v2->co, es->no, 0.1f);
855  BM_edge_create(bm, v1, v2, NULL, 0);
856  }
857 #endif
858 
859  /* Execute the split and position verts, it would be most obvious to loop
860  * over verts here but don't do this since we will be splitting them off
861  * (iterating stuff you modify is bad juju)
862  * instead loop over edges then their verts. */
863  for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
864  for (int j = 0; j < 2; j++) {
865  v = (j == 0) ? es->e_new->v1 : es->e_new->v2;
866 
867  /* end confusing part - just pretend this is a typical loop on verts */
868 
869  /* only split of tagged verts - used by separated edges */
870 
871  /* comment the first part because we know this verts in a tagged face */
872  if (/* v->e && */ BM_elem_flag_test(v, BM_ELEM_TAG)) {
873  BMVert **vout;
874  int r_vout_len;
875  BMVert *v_glue = NULL;
876 
877  /* disable touching twice, this _will_ happen if the flags not disabled */
879 
880  bmesh_kernel_vert_separate(bm, v, &vout, &r_vout_len, false);
881  v = NULL; /* don't use again */
882 
883  /* in some cases the edge doesn't split off */
884  if (r_vout_len == 1) {
885  if (use_vert_coords_orig) {
886  VERT_ORIG_STORE(vout[0]);
887  }
888  MEM_freeN(vout);
889  continue;
890  }
891 
892  for (k = 0; k < r_vout_len; k++) {
893  BMVert *v_split = vout[k]; /* only to avoid vout[k] all over */
894 
895  /* need to check if this vertex is from a */
896  int vert_edge_tag_tot = 0;
897  int vecpair[2];
898 
899  if (use_vert_coords_orig) {
900  VERT_ORIG_STORE(v_split);
901  }
902 
903  /* find adjacent */
904  BM_ITER_ELEM (e, &iter, v_split, BM_EDGES_OF_VERT) {
905  if (BM_elem_flag_test(e, BM_ELEM_TAG) && e->l &&
906  BM_elem_flag_test(e->l->f, BM_ELEM_TAG)) {
907  if (vert_edge_tag_tot < 2) {
908  vecpair[vert_edge_tag_tot] = BM_elem_index_get(e);
909  BLI_assert(vecpair[vert_edge_tag_tot] != -1);
910  }
911 
912  vert_edge_tag_tot++;
913  }
914  }
915 
916  if (vert_edge_tag_tot != 0) {
917  float tvec[3];
918 
919  if (vert_edge_tag_tot >= 2) { /* 2 edge users - common case */
920  /* now there are 2 cases to check for,
921  *
922  * if both edges use the same face OR both faces have the same normal,
923  * ...then we can calculate an edge that fits nicely between the 2 edge normals.
924  *
925  * Otherwise use the shared edge OR the corner defined by these 2 face normals,
926  * when both edges faces are adjacent this works best but even when this vertex
927  * fans out faces it should work ok.
928  */
929 
930  SplitEdgeInfo *e_info_a = &edge_info[vecpair[0]];
931  SplitEdgeInfo *e_info_b = &edge_info[vecpair[1]];
932 
933  BMFace *f_a = e_info_a->l->f;
934  BMFace *f_b = e_info_b->l->f;
935 
936  /* set to true when we're not in-between (e_info_a->no, e_info_b->no) exactly
937  * in this case use a check the angle of the tvec when calculating shell thickness */
938  bool is_mid = true;
939 
940  /* we use this as either the normal OR to find the right direction for the
941  * cross product between both face normals */
942  add_v3_v3v3(tvec, e_info_a->no, e_info_b->no);
943 
944  if (use_edge_rail == false) {
945  /* pass */
946  }
947  else if (f_a != f_b) {
948  /* these lookups are very quick */
949  BMLoop *l_other_a = BM_loop_other_vert_loop(e_info_a->l, v_split);
950  BMLoop *l_other_b = BM_loop_other_vert_loop(e_info_b->l, v_split);
951 
952  if (l_other_a->v == l_other_b->v) {
953  /* both edges faces are adjacent, but we don't need to know the shared edge
954  * having both verts is enough. */
955  const float *co_other;
956 
957  /* note that we can't use 'l_other_a->v' directly since it
958  * may be inset and give a feedback loop. */
959  if (use_vert_coords_orig) {
960  co_other = VERT_ORIG_GET(l_other_a->v);
961  }
962  else {
963  co_other = l_other_a->v->co;
964  }
965 
966  sub_v3_v3v3(tvec, co_other, v_split->co);
967  is_mid = false;
968  }
969 
970  /* Disable since this gives odd results at times, see T39288. */
971 #if 0
972  else if (compare_v3v3(f_a->no, f_b->no, 0.001f) == false) {
973  /* epsilon increased to fix T32329. */
974 
975  /* faces don't touch,
976  * just get cross product of their normals, its *good enough*
977  */
978  float tno[3];
979  cross_v3_v3v3(tno, f_a->no, f_b->no);
980  if (dot_v3v3(tvec, tno) < 0.0f) {
981  negate_v3(tno);
982  }
983  copy_v3_v3(tvec, tno);
984  is_mid = false;
985  }
986 #endif
987  }
988  normalize_v3(tvec);
989 
990  /* scale by edge angle */
991  if (use_even_offset) {
992  if (is_mid) {
993  mul_v3_fl(tvec, shell_v3v3_mid_normalized_to_dist(e_info_a->no, e_info_b->no));
994  }
995  else {
996  /* use the largest angle */
997  mul_v3_fl(
998  tvec,
1000  len_squared_v3v3(tvec, e_info_a->no) >
1001  len_squared_v3v3(tvec, e_info_b->no) ?
1002  e_info_a->no :
1003  e_info_b->no));
1004  }
1005  }
1006 
1007  /* scale relative to edge lengths */
1008  if (use_relative_offset) {
1009  mul_v3_fl(tvec,
1010  (edge_info[vecpair[0]].length + edge_info[vecpair[1]].length) / 2.0f);
1011  }
1012  }
1013  else if (vert_edge_tag_tot == 1) { /* 1 edge user - boundary vert, not so common */
1014  const float *e_no_a = edge_info[vecpair[0]].no;
1015 
1016  if (use_even_boundary) {
1017 
1043  BMEdge *e_other;
1044  BMVert *v_other;
1045  /* loop will always be either next of prev */
1046  BMLoop *l = v_split->e->l;
1047  if (l->prev->v == v_split) {
1048  l = l->prev;
1049  }
1050  else if (l->next->v == v_split) {
1051  l = l->next;
1052  }
1053  else if (l->v == v_split) {
1054  /* pass */
1055  }
1056  else {
1057  /* should never happen */
1058  BLI_assert(0);
1059  }
1060 
1061  /* find the edge which is _not_ being split here */
1062  if (!BM_elem_flag_test(l->e, BM_ELEM_TAG)) {
1063  e_other = l->e;
1064  }
1065  else if (!BM_elem_flag_test(l->prev->e, BM_ELEM_TAG)) {
1066  e_other = l->prev->e;
1067  }
1068  else {
1069  BLI_assert(0);
1070  e_other = NULL;
1071  }
1072 
1073  v_other = BM_edge_other_vert(e_other, v_split);
1074  sub_v3_v3v3(tvec, v_other->co, v_split->co);
1075  normalize_v3(tvec);
1076 
1077  if (use_even_offset) {
1078  mul_v3_fl(tvec, shell_v3v3_normalized_to_dist(e_no_a, tvec));
1079  }
1080  }
1081  else {
1082  copy_v3_v3(tvec, e_no_a);
1083  }
1084 
1085  /* use_even_offset - doesn't apply here */
1086 
1087  /* scale relative to edge length */
1088  if (use_relative_offset) {
1089  mul_v3_fl(tvec, edge_info[vecpair[0]].length);
1090  }
1091  }
1092  else {
1093  /* should never happen */
1094  BLI_assert(0);
1095  zero_v3(tvec);
1096  }
1097 
1098  /* apply the offset */
1099  madd_v3_v3fl(v_split->co, tvec, thickness);
1100  }
1101 
1102  /* this saves expensive/slow glue check for common cases */
1103  if (r_vout_len > 2) {
1104  bool ok = true;
1105  /* last step, NULL this vertex if has a tagged face */
1106  BM_ITER_ELEM (f, &iter, v_split, BM_FACES_OF_VERT) {
1107  if (BM_elem_flag_test(f, BM_ELEM_TAG)) {
1108  ok = false;
1109  break;
1110  }
1111  }
1112 
1113  if (ok) {
1114  if (v_glue == NULL) {
1115  v_glue = v_split;
1116  }
1117  else {
1118  if (BM_vert_splice(bm, v_glue, v_split)) {
1119  if (use_vert_coords_orig) {
1120  VERT_ORIG_REMOVE(v_split);
1121  }
1122  }
1123  }
1124  }
1125  }
1126  /* end glue */
1127  }
1128  MEM_freeN(vout);
1129  }
1130  }
1131  }
1132 
1133  if (use_vert_coords_orig) {
1134  BLI_memarena_free(vert_coords_orig);
1135  BLI_ghash_free(vert_coords, NULL, NULL);
1136  }
1137 
1138  if (use_interpolate) {
1139  for (i = 0; i < iface_array_len; i++) {
1140  if (iface_array[i]) {
1141  InterpFace *iface = iface_array[i];
1143  iface->f,
1144  iface->f,
1145  true,
1146  (const void **)iface->blocks_l,
1147  (const void **)iface->blocks_v,
1148  iface->cos_2d,
1149  iface->axis_mat);
1150  }
1151  }
1152  }
1153 
1154  /* create faces */
1155  for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
1156  BMVert *varr[4] = {NULL};
1157  int j;
1158  /* get the verts in the correct order */
1159  BM_edge_ordered_verts_ex(es->e_new, &varr[1], &varr[0], es->l);
1160 #if 0
1161  if (varr[0] == es->e_new->v1) {
1162  varr[2] = es->e_old->v2;
1163  varr[3] = es->e_old->v1;
1164  }
1165  else {
1166  varr[2] = es->e_old->v1;
1167  varr[3] = es->e_old->v2;
1168  }
1169  j = 4;
1170 #else
1171  /* slightly trickier check - since we can't assume the verts are split */
1172  j = 2; /* 2 edges are set */
1173  if (varr[0] == es->e_new->v1) {
1174  if (es->e_old->v2 != es->e_new->v2) {
1175  varr[j++] = es->e_old->v2;
1176  }
1177  if (es->e_old->v1 != es->e_new->v1) {
1178  varr[j++] = es->e_old->v1;
1179  }
1180  }
1181  else {
1182  if (es->e_old->v1 != es->e_new->v1) {
1183  varr[j++] = es->e_old->v1;
1184  }
1185  if (es->e_old->v2 != es->e_new->v2) {
1186  varr[j++] = es->e_old->v2;
1187  }
1188  }
1189 
1190  if (j == 2) {
1191  /* can't make face! */
1192  continue;
1193  }
1194 #endif
1195  /* no need to check doubles, we KNOW there won't be any */
1196  /* yes - reverse face is correct in this case */
1197  f = BM_face_create_verts(bm, varr, j, es->l->f, BM_CREATE_NOP, true);
1199 
1200  /* Copy for loop data, otherwise UV's and vcols are no good.
1201  * tiny speedup here we could be more clever and copy from known adjacent data
1202  * also - we could attempt to interpolate the loop data,
1203  * this would be much slower but more useful too. */
1204  if (0) {
1205  /* Don't use this because face boundaries have no adjacent loops and won't be filled in.
1206  * instead copy from the opposite side with the code below */
1208  }
1209  else {
1210  /* 2 inner loops on the edge between the new face and the original */
1211  BMLoop *l_a;
1212  BMLoop *l_b;
1213  BMLoop *l_a_other;
1214  BMLoop *l_b_other;
1215 
1216  l_a = BM_FACE_FIRST_LOOP(f);
1217  l_b = l_a->next;
1218 
1219  /* we know this side has a radial_next because of the order of created verts in the quad */
1220  l_a_other = BM_edge_other_loop(l_a->e, l_a);
1221  l_b_other = BM_edge_other_loop(l_a->e, l_b);
1222  BM_elem_attrs_copy(bm, bm, l_a_other, l_a);
1223  BM_elem_attrs_copy(bm, bm, l_b_other, l_b);
1224 
1225  BLI_assert(l_a->f != l_a_other->f);
1226  BLI_assert(l_b->f != l_b_other->f);
1227 
1228  /* step around to the opposite side of the quad - warning, this may have no other edges! */
1229  l_a = l_a->next->next;
1230  l_b = l_a->next;
1231 
1253  /* swap a<->b intentionally */
1254  if (use_interpolate) {
1255  InterpFace *iface = iface_array[BM_elem_index_get(es->l->f)];
1256  const int i_a = BM_elem_index_get(l_a_other);
1257  const int i_b = BM_elem_index_get(l_b_other);
1261  CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, iface->blocks_l[i_b], &l_a->head.data);
1262 
1263 #ifdef USE_LOOP_CUSTOMDATA_MERGE
1264  if (has_math_ldata) {
1265  BMEdge *e_connect;
1266 
1267  /* connecting edge 'a' */
1268  e_connect = l_a->prev->e;
1269  if (BM_edge_is_manifold(e_connect)) {
1271  e_connect,
1272  l_a,
1273  BM_edge_other_loop(e_connect, l_a),
1274  l_a->prev,
1275  BM_edge_other_loop(e_connect, l_a->prev));
1276  }
1277 
1278  /* connecting edge 'b' */
1279  e_connect = l_b->e;
1280  if (BM_edge_is_manifold(e_connect)) {
1281  /* swap arg order to maintain winding */
1283  e_connect,
1284  l_b,
1285  BM_edge_other_loop(e_connect, l_b),
1286  l_b->next,
1287  BM_edge_other_loop(e_connect, l_b->next));
1288  }
1289  }
1290 #endif /* USE_LOOP_CUSTOMDATA_MERGE */
1291  }
1292  else {
1293  BM_elem_attrs_copy(bm, bm, l_a_other, l_b);
1294  BM_elem_attrs_copy(bm, bm, l_b_other, l_a);
1295  }
1296  }
1297  }
1298 
1299  if (use_interpolate) {
1300  for (i = 0; i < iface_array_len; i++) {
1301  if (iface_array[i]) {
1302  bm_interp_face_free(iface_array[i], bm);
1303  }
1304  }
1305 
1306  BLI_memarena_free(interp_arena);
1307  MEM_freeN(iface_array);
1308  }
1309 
1310  /* we could flag new edges/verts too, is it useful? */
1312 
1313  /* cheap feature to add depth to the inset */
1314  if (depth != 0.0f) {
1315  float(*varr_co)[3];
1316  BMOIter oiter;
1317 
1318  /* We need to re-calculate tagged normals,
1319  * but for this purpose we can copy tagged verts from the faces they inset from. */
1320  for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
1321  zero_v3(es->e_new->v1->no);
1322  zero_v3(es->e_new->v2->no);
1323  }
1324  for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
1325  const float *no = es->l->f->no;
1326  add_v3_v3(es->e_new->v1->no, no);
1327  add_v3_v3(es->e_new->v2->no, no);
1328  }
1329  for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
1330  /* annoying, avoid normalizing twice */
1331  if (len_squared_v3(es->e_new->v1->no) != 1.0f) {
1332  normalize_v3(es->e_new->v1->no);
1333  }
1334  if (len_squared_v3(es->e_new->v2->no) != 1.0f) {
1335  normalize_v3(es->e_new->v2->no);
1336  }
1337  }
1338  /* done correcting edge verts normals */
1339 
1340  /* untag verts */
1342 
1343  /* tag face verts */
1344  BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) {
1345  BMLoop *l_iter, *l_first;
1346  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1347  do {
1348  BM_elem_flag_enable(l_iter->v, BM_ELEM_TAG);
1349  BM_elem_flag_enable(l_iter->e, BM_ELEM_TAG);
1350  } while ((l_iter = l_iter->next) != l_first);
1351  }
1352 
1353  /* do in 2 passes so moving the verts doesn't feed back into face angle checks
1354  * which BM_vert_calc_shell_factor uses. */
1355 
1356  /* over allocate */
1357  varr_co = MEM_callocN(sizeof(*varr_co) * bm->totvert, __func__);
1358  void *vert_lengths_p = NULL;
1359 
1360  BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
1362  const float fac =
1363  depth *
1364  (use_relative_offset ?
1366  v,
1367  edge_info,
1368  /* Variables needed for filling interior values for vertex lengths. */
1369  bm,
1370  &vert_lengths_p) :
1371  1.0f) *
1372  (use_even_boundary ? BM_vert_calc_shell_factor(v) : 1.0f);
1373  madd_v3_v3v3fl(varr_co[i], v->co, v->no, fac);
1374  }
1375  }
1376 
1377  if (vert_lengths_p != NULL) {
1378  MEM_freeN(vert_lengths_p);
1379  }
1380 
1381  BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
1383  copy_v3_v3(v->co, varr_co[i]);
1384  }
1385  }
1386  MEM_freeN(varr_co);
1387  }
1388 
1389  MEM_freeN(edge_info);
1390 }
1391 
typedef float(TangentPoint)[2]
CustomData interface, see also DNA_customdata_types.h.
bool CustomData_has_math(const struct CustomData *data)
Definition: customdata.c:3843
void CustomData_data_mix_value(int type, const void *source, void *dest, const int mixmode, const float mixfactor)
Definition: customdata.c:3911
@ CDT_MIX_MIX
bool CustomData_data_equals(int type, const void *data1, const void *data2)
Definition: customdata.c:3929
void CustomData_data_copy_value(int type, const void *source, void *dest)
Definition: customdata.c:3893
void CustomData_bmesh_copy_data(const struct CustomData *source, struct CustomData *dest, void *src_block, void **dest_block)
void CustomData_bmesh_free_block_data(struct CustomData *data, void *block)
Definition: customdata.c:3633
bool CustomData_layer_has_math(const struct CustomData *data, int layer_n)
Definition: customdata.c:3820
void CustomData_bmesh_free_block(struct CustomData *data, void **block)
Definition: customdata.c:3606
#define BLI_array_alloca(arr, realsize)
Definition: BLI_alloca.h:36
#define BLI_assert(a)
Definition: BLI_assert.h:58
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:1008
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
MINLINE float shell_v3v3_normalized_to_dist(const float a[3], const float b[3])
MINLINE float shell_v3v3_mid_normalized_to_dist(const float a[3], const float b[3])
void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3])
Normal to x,y matrix.
Definition: math_geom.c:3752
void mul_v2_m3v3(float r[2], const float M[3][3], const float a[3])
Definition: math_matrix.c:921
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE bool compare_v3v3(const float a[3], const float b[3], const float limit) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v3(float r[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 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])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void negate_v3(float r[3])
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
Definition: math_vector.c:270
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
MINLINE void zero_v3(float r[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1)
Definition: BLI_memarena.c:109
#define BLI_MEMARENA_STD_BUFSIZE
Definition: BLI_memarena.h:36
void * BLI_memarena_alloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
Definition: BLI_memarena.c:131
void BLI_memarena_clear(MemArena *ma) ATTR_NONNULL(1)
Definition: BLI_memarena.c:185
struct MemArena * BLI_memarena_new(const size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2) ATTR_MALLOC
Definition: BLI_memarena.c:79
unsigned int uint
Definition: BLI_sys_types.h:83
#define UNLIKELY(x)
#define ELEM(...)
#define LIKELY(x)
#define STACK_PUSH(stack, val)
#define STACK_DECLARE(stack)
#define STACK_INIT(stack, tot)
#define STACK_SIZE(stack)
#define STACK_REMOVE(stack, i)
_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 type
_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.
@ BM_LOOP
Definition: bmesh_class.h:385
@ BM_FACE
Definition: bmesh_class.h:386
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_EDGE
Definition: bmesh_class.h:384
@ BM_ELEM_TAG
Definition: bmesh_class.h:484
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:553
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
Definition: bmesh_class.h:530
void BM_face_copy_shared(BMesh *bm, BMFace *f, BMLoopFilterFunc filter_fn, void *user_data)
copies face loop data from shared adjacent faces.
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
void bmesh_kernel_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep, const bool copy_select)
Separate Edge.
Definition: bmesh_core.c:2641
bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src)
Splice Vert.
Definition: bmesh_core.c:2284
void bmesh_kernel_vert_separate(BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len, const bool copy_select)
Separate Vert.
Definition: bmesh_core.c:2331
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_index_set(ele, index)
Definition: bmesh_inline.h:125
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:28
void BM_face_interp_from_face_ex(BMesh *bm, BMFace *f_dst, const BMFace *f_src, const bool do_vertex, const void **blocks_l, const void **blocks_v, float(*cos_2d)[2], float axis_mat[3][3])
Data Interp From Face.
Definition: bmesh_interp.c:180
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
@ BM_FACES_OF_VERT
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_VERTS_OF_EDGE
@ BM_LOOPS_OF_VERT
@ BM_EDGES_OF_VERT
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_elem_hflag_enable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.c:2152
BMVert * BM_face_loop_separate(BMesh *bm, BMLoop *l_sep)
Rip a single face from a vertex fan.
Definition: bmesh_mods.c:1097
void BMO_slot_buffer_hflag_enable(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char htype, const char hflag, const bool do_flush)
BMO_FLAG_BUFFER.
float BMO_slot_float_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
void BMO_slot_buffer_hflag_disable(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char htype, const char hflag, const bool do_flush)
BMO_FLAG_BUFFER.
#define BMO_face_flag_enable(bm, e, oflag)
#define BMO_ITER(ele, iter, slot_args, slot_name, restrict_flag)
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 BM_edge_ordered_verts_ex(const BMEdge *edge, BMVert **r_v1, BMVert **r_v2, const BMLoop *edge_loop)
Definition: bmesh_query.c:1453
bool BM_edge_in_face(const BMEdge *e, const BMFace *f)
Definition: bmesh_query.c:555
float BM_vert_calc_shell_factor(const BMVert *v)
Definition: bmesh_query.c:1850
bool BM_face_is_normal_valid(const BMFace *f)
Definition: bmesh_query.c:2533
BMLoop * BM_loop_other_vert_loop(BMLoop *l, BMVert *v)
Other Loop in Face Sharing a Vert.
Definition: bmesh_query.c:135
float BM_edge_calc_length(const BMEdge *e)
Definition: bmesh_query.c:713
BMLoop * BM_edge_other_loop(BMEdge *e, BMLoop *l)
Definition: bmesh_query.c:587
void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, float r_tangent[3])
BMESH EDGE/FACE TANGENT.
Definition: bmesh_query.c:1803
BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) 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 BMLoop * l_b
ATTR_WARN_UNUSED_RESULT const BMVert * v
static void bm_loop_customdata_merge(BMesh *bm, BMEdge *e_connect, BMLoop *l_a_outer, BMLoop *l_b_outer, BMLoop *l_a_inner, BMLoop *l_b_inner)
Definition: bmo_inset.c:117
void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
Definition: bmo_inset.c:665
#define ELE_NEW
Definition: bmo_inset.c:40
static void bm_interp_face_store(InterpFace *iface, BMesh *bm, BMFace *f, MemArena *interp_arena)
Definition: bmo_inset.c:65
struct InterpFace InterpFace
#define VERT_ORIG_REMOVE(_v)
static void bm_interp_face_free(InterpFace *iface, BMesh *bm)
Definition: bmo_inset.c:100
static float bm_edge_info_average_length_with_fallback(BMVert *v, SplitEdgeInfo *edge_info, BMesh *bm, void **vert_lengths_p)
Definition: bmo_inset.c:649
void bmo_inset_individual_exec(BMesh *bm, BMOperator *op)
Definition: bmo_inset.c:415
static BMLoop * bm_edge_is_mixed_face_tag(BMLoop *l)
Definition: bmo_inset.c:484
static float bm_edge_info_average_length_fallback(BMVert *v_lookup, SplitEdgeInfo *edge_info, BMesh *bm, void **vert_lengths_p)
Definition: bmo_inset.c:548
static float bm_edge_info_average_length(BMVert *v, SplitEdgeInfo *edge_info)
Definition: bmo_inset.c:512
#define VERT_ORIG_GET(_v)
static void bmo_face_inset_individual(BMesh *bm, BMFace *f, MemArena *interp_arena, const float thickness, const float depth, const bool use_even_offset, const bool use_relative_offset, const bool use_interpolate)
Definition: bmo_inset.c:262
struct SplitEdgeInfo SplitEdgeInfo
#define VERT_ORIG_STORE(_v)
SIMD_FORCE_INLINE btScalar length(const btQuaternion &q)
Return the length of a quaternion.
Definition: btQuaternion.h:895
static float verts[][3]
int count
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
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
void * data
Definition: bmesh_class.h:63
BMHeader head
Definition: bmesh_class.h:157
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 BMLoop * prev
Definition: bmesh_class.h:245
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
char elem_index_dirty
Definition: bmesh_class.h:305
CustomData vdata
Definition: bmesh_class.h:337
CustomData ldata
Definition: bmesh_class.h:337
int totface
Definition: bmesh_class.h:297
CustomDataLayer * layers
float axis_mat[3][3]
Definition: bmo_inset.c:61
void ** blocks_v
Definition: bmo_inset.c:59
void ** blocks_l
Definition: bmo_inset.c:58
BMFace * f
Definition: bmo_inset.c:57
float(* cos_2d)[2]
Definition: bmo_inset.c:60
float length
Definition: bmo_inset.c:470
BMLoop * l
Definition: bmo_inset.c:473
float no[3]
Definition: bmo_inset.c:469
BMEdge * e_new
Definition: bmo_inset.c:472
BMEdge * e_old
Definition: bmo_inset.c:471
uint len