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