Blender  V3.3
bmo_subdivide_edgering.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
20 #include "MEM_guardedalloc.h"
21 
22 #include "BLI_alloca.h"
23 #include "BLI_listbase.h"
24 #include "BLI_math.h"
25 #include "BLI_utildefines.h"
26 #include "BLI_utildefines_stack.h"
27 
28 #include "BKE_curve.h"
29 
30 #include "bmesh.h"
31 
32 #include "intern/bmesh_operators_private.h" /* own include */
33 
34 #define VERT_SHARED (1 << 0)
35 
36 #define EDGE_RING (1 << 0)
37 #define EDGE_RIM (1 << 1)
38 #define EDGE_IN_STACK (1 << 2)
39 
40 #define FACE_OUT (1 << 0)
41 #define FACE_SHARED (1 << 1)
42 #define FACE_IN_STACK (1 << 2)
43 
44 /* -------------------------------------------------------------------- */
45 /* Specialized Utility Funcs */
46 
47 #ifndef NDEBUG
49 {
50  int count = 0;
51  BMIter iter;
52  BMVert *v;
53  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
55  count++;
56  }
57  }
58  return count;
59 }
60 #endif
61 
62 static float bezier_handle_calc_length_v3(const float co_a[3],
63  const float no_a[3],
64  const float co_b[3],
65  const float no_b[3])
66 {
67  const float dot = dot_v3v3(no_a, no_b);
68  /* gives closest approx at a circle with 2 parallel handles */
69  float fac = 1.333333f;
70  float len;
71  if (dot < 0.0f) {
72  /* Scale down to 0.666 if we point directly at each other rough but ok. */
73  /* TODO: current blend from dot may not be optimal but its also a detail. */
74  const float t = 1.0f + dot;
75  fac = (fac * t) + (0.75f * (1.0f - t));
76  }
77 
78 #if 0
79  len = len_v3v3(co_a, co_b);
80 #else
81  /* 2d length projected on plane of normals */
82  {
83  float co_a_ofs[3];
84  cross_v3_v3v3(co_a_ofs, no_a, no_b);
85  if (len_squared_v3(co_a_ofs) > FLT_EPSILON) {
86  add_v3_v3(co_a_ofs, co_a);
87  closest_to_line_v3(co_a_ofs, co_b, co_a, co_a_ofs);
88  }
89  else {
90  copy_v3_v3(co_a_ofs, co_a);
91  }
92  len = len_v3v3(co_a_ofs, co_b);
93  }
94 #endif
95 
96  return (len * 0.5f) * fac;
97 }
98 
99 static void bm_edgeloop_vert_tag(struct BMEdgeLoopStore *el_store, const bool tag)
100 {
102  do {
103  BM_elem_flag_set((BMVert *)node->data, BM_ELEM_TAG, tag);
104  } while ((node = node->next));
105 }
106 
108  struct BMEdgeLoopStore *el_store,
109  const short oflag,
110  const bool tag)
111 {
113  do {
114  BMO_vert_flag_set(bm, (BMVert *)node->data, oflag, tag);
115  } while ((node = node->next));
116 }
117 
118 static bool bmo_face_is_vert_tag_all(BMesh *bm, BMFace *f, short oflag)
119 {
120  BMLoop *l_iter, *l_first;
121  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
122  do {
123  if (!BMO_vert_flag_test(bm, l_iter->v, oflag)) {
124  return false;
125  }
126  } while ((l_iter = l_iter->next) != l_first);
127  return true;
128 }
129 
131 {
132  BMIter eiter;
133  BMEdge *e;
134 
135  BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
136  if (BMO_edge_flag_test(bm, e, EDGE_RING)) {
137  BMVert *v_other = BM_edge_other_vert(e, v);
138  if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
139  return true;
140  }
141  }
142  }
143  return false;
144 }
145 
146 /* for now we need full overlap,
147  * supporting partial overlap could be done but gets complicated
148  * when trimming endpoints is not enough to ensure consistency.
149  */
151  struct BMEdgeLoopStore *el_store_a,
152  struct BMEdgeLoopStore *el_store_b)
153 {
154  bool has_overlap = true;
155  LinkData *node;
156 
157  ListBase *lb_a = BM_edgeloop_verts_get(el_store_a);
158  ListBase *lb_b = BM_edgeloop_verts_get(el_store_b);
159 
160  bm_edgeloop_vert_tag(el_store_a, false);
161  bm_edgeloop_vert_tag(el_store_b, true);
162 
163  for (node = lb_a->first; node; node = node->next) {
164  if (bm_vert_is_tag_edge_connect(bm, node->data) == false) {
165  has_overlap = false;
166  goto finally;
167  }
168  }
169 
170  bm_edgeloop_vert_tag(el_store_a, true);
171  bm_edgeloop_vert_tag(el_store_b, false);
172 
173  for (node = lb_b->first; node; node = node->next) {
174  if (bm_vert_is_tag_edge_connect(bm, node->data) == false) {
175  has_overlap = false;
176  goto finally;
177  }
178  }
179 
180 finally:
181  bm_edgeloop_vert_tag(el_store_a, false);
182  bm_edgeloop_vert_tag(el_store_b, false);
183  return has_overlap;
184 }
185 
186 /* -------------------------------------------------------------------- */
187 /* Edge Loop Pairs */
188 /* key (ordered loop pointers) */
190 {
205  GSet *eloop_pair_gs = BLI_gset_pair_new(__func__);
206  GHash *vert_eloop_gh = BLI_ghash_ptr_new(__func__);
207 
208  struct BMEdgeLoopStore *el_store;
209 
210  /* create vert -> eloop map */
211  for (el_store = eloops_rim->first; el_store; el_store = BM_EDGELOOP_NEXT(el_store)) {
213  do {
214  BLI_ghash_insert(vert_eloop_gh, node->data, el_store);
215  } while ((node = node->next));
216  }
217 
218  /* collect eloop pairs */
219  for (el_store = eloops_rim->first; el_store; el_store = BM_EDGELOOP_NEXT(el_store)) {
220  BMIter eiter;
221  BMEdge *e;
222 
223  BMVert *v = ((LinkData *)BM_edgeloop_verts_get(el_store)->first)->data;
224 
225  BM_ITER_ELEM (e, &eiter, (BMVert *)v, BM_EDGES_OF_VERT) {
226  if (BMO_edge_flag_test(bm, e, EDGE_RING)) {
227  struct BMEdgeLoopStore *el_store_other;
228  BMVert *v_other = BM_edge_other_vert(e, v);
229  GHashPair pair_test;
230 
231  el_store_other = BLI_ghash_lookup(vert_eloop_gh, v_other);
232 
233  /* in rare cases we can't find a match */
234  if (el_store_other) {
235  pair_test.first = el_store;
236  pair_test.second = el_store_other;
237 
238  if (pair_test.first > pair_test.second) {
239  SWAP(const void *, pair_test.first, pair_test.second);
240  }
241 
242  void **pair_key_p;
243  if (!BLI_gset_ensure_p_ex(eloop_pair_gs, &pair_test, &pair_key_p)) {
244  *pair_key_p = BLI_ghashutil_pairalloc(pair_test.first, pair_test.second);
245  }
246  }
247  }
248  }
249  }
250 
251  BLI_ghash_free(vert_eloop_gh, NULL, NULL);
252 
253  if (BLI_gset_len(eloop_pair_gs) == 0) {
254  BLI_gset_free(eloop_pair_gs, NULL);
255  eloop_pair_gs = NULL;
256  }
257 
258  return eloop_pair_gs;
259 }
260 
261 /* -------------------------------------------------------------------- */
262 /* Subdivide an edge 'n' times and return an open edgeloop */
263 
265  BMesh *bm, ListBase *eloops, BMEdge *e, BMVert *v_a, const int cuts)
266 {
267  struct BMEdgeLoopStore *eloop;
268  BMVert **v_arr = BLI_array_alloca(v_arr, cuts + 2);
269  BMVert *v_b;
271 
272  v_b = BM_edge_other_vert(e, v_a);
273 
274  BM_edge_split_n(bm, e, cuts, &v_arr[1]);
275  if (v_a == e->v1) {
276  v_arr[0] = v_a;
277  v_arr[cuts + 1] = v_b;
278  }
279  else {
280  v_arr[0] = v_b;
281  v_arr[cuts + 1] = v_a;
282  }
283 
284  eloop = BM_edgeloop_from_verts(v_arr, cuts + 2, false);
285 
286  if (v_a == e->v1) {
287  BM_edgeloop_flip(bm, eloop);
288  }
289 
290  BLI_addtail(eloops, eloop);
291 }
292 
293 /* -------------------------------------------------------------------- */
294 /* LoopPair Cache (struct and util funcs) */
295 
306 static void bm_vert_calc_surface_tangent(BMesh *bm, BMVert *v, float r_no[3])
307 {
308  BMIter eiter;
309  BMEdge *e;
310 
311  /* get outer normal, fallback to inner (if this vertex is on a boundary) */
312  bool found_outer = false, found_inner = false, found_outer_tag = false;
313 
314  float no_outer[3] = {0.0f}, no_inner[3] = {0.0f};
315 
316  /* first find rim edges, typically we will only add 2 normals */
317  BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
318  if (UNLIKELY(BM_edge_is_wire(e))) {
319  /* pass - this may confuse things */
320  }
321  else if (BMO_edge_flag_test(bm, e, EDGE_RIM)) {
322  BMIter liter;
323  BMLoop *l;
324  BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) {
325  /* use unmarked (surrounding) faces to create surface tangent */
326  float no[3];
327  // BM_face_normal_update(l->f);
329  if (BMO_face_flag_test(bm, l->f, FACE_SHARED)) {
330  add_v3_v3(no_inner, no);
331  found_inner = true;
332  }
333  else {
334  add_v3_v3(no_outer, no);
335  found_outer = true;
336 
337  /* other side is used too, blend midway */
338  if (BMO_face_flag_test(bm, l->f, FACE_OUT)) {
339  found_outer_tag = true;
340  }
341  }
342  }
343  }
344  }
345 
346  /* detect if this vertex is in-between 2 loops (when blending multiple),
347  * if so - take both inner and outer into account */
348 
349  if (found_inner && found_outer_tag) {
350  /* blend between the 2 */
351  negate_v3(no_outer);
352  normalize_v3(no_outer);
353  normalize_v3(no_inner);
354  add_v3_v3v3(r_no, no_outer, no_inner);
355  normalize_v3(r_no);
356  }
357  else if (found_outer) {
358  negate_v3(no_outer);
359  normalize_v3_v3(r_no, no_outer);
360  }
361  else {
362  /* we always have inner geometry */
363  BLI_assert(found_inner == true);
364  normalize_v3_v3(r_no, no_inner);
365  }
366 }
367 
372 static void bm_faces_share_tag_flush(BMesh *bm, BMEdge **e_arr, const uint e_arr_len)
373 {
374  uint i;
375 
376  for (i = 0; i < e_arr_len; i++) {
377  BMEdge *e = e_arr[i];
378  BMLoop *l_iter, *l_first;
379 
380  l_iter = l_first = e->l;
381  do {
382  if (!BMO_face_flag_test(bm, l_iter->f, FACE_SHARED)) {
383  if (bmo_face_is_vert_tag_all(bm, l_iter->f, VERT_SHARED)) {
385  }
386  }
387  } while ((l_iter = l_iter->radial_next) != l_first);
388  }
389 }
390 
394 static void bm_faces_share_tag_clear(BMesh *bm, BMEdge **e_arr_iter, const uint e_arr_len_iter)
395 {
396  uint i;
397 
398  for (i = 0; i < e_arr_len_iter; i++) {
399  BMEdge *e = e_arr_iter[i];
400  BMLoop *l_iter, *l_first;
401 
402  l_iter = l_first = e->l;
403  do {
405  } while ((l_iter = l_iter->radial_next) != l_first);
406  }
407 }
408 
416 typedef struct LoopPairStore {
417  /* handle array for splines */
418  float (*nors_a)[3];
419  float (*nors_b)[3];
420 
421  /* since we don't have reliable index values into the array,
422  * store a map (BMVert -> index) */
426 
428  struct BMEdgeLoopStore *el_store_a,
429  struct BMEdgeLoopStore *el_store_b,
430  const int interp_mode)
431 {
432  LoopPairStore *lpair = MEM_mallocN(sizeof(*lpair), __func__);
433 
434  if (interp_mode == SUBD_RING_INTERP_SURF) {
435  const uint len_a = BM_edgeloop_length_get(el_store_a);
436  const uint len_b = BM_edgeloop_length_get(el_store_b);
437  const uint e_arr_a_len = len_a - (BM_edgeloop_is_closed(el_store_a) ? 0 : 1);
438  const uint e_arr_b_len = len_b - (BM_edgeloop_is_closed(el_store_b) ? 0 : 1);
439  BMEdge **e_arr_a = BLI_array_alloca(e_arr_a, e_arr_a_len);
440  BMEdge **e_arr_b = BLI_array_alloca(e_arr_b, e_arr_b_len);
441  uint i;
442 
443  struct BMEdgeLoopStore *el_store_pair[2] = {el_store_a, el_store_b};
444  uint side_index;
445  float(*nors_pair[2])[3];
446  GHash *nors_gh_pair[2];
447 
448  BM_edgeloop_edges_get(el_store_a, e_arr_a);
449  BM_edgeloop_edges_get(el_store_b, e_arr_b);
450 
451  lpair->nors_a = MEM_mallocN(sizeof(*lpair->nors_a) * len_a, __func__);
452  lpair->nors_b = MEM_mallocN(sizeof(*lpair->nors_b) * len_b, __func__);
453 
454  nors_pair[0] = lpair->nors_a;
455  nors_pair[1] = lpair->nors_b;
456 
457  lpair->nors_gh_a = BLI_ghash_ptr_new(__func__);
458  lpair->nors_gh_b = BLI_ghash_ptr_new(__func__);
459 
460  nors_gh_pair[0] = lpair->nors_gh_a;
461  nors_gh_pair[1] = lpair->nors_gh_b;
462 
463  /* now calculate nor */
464 
465  /* all other verts must _not_ be tagged */
466  bmo_edgeloop_vert_tag(bm, el_store_a, VERT_SHARED, true);
467  bmo_edgeloop_vert_tag(bm, el_store_b, VERT_SHARED, true);
468 
469  /* tag all faces that are in-between both loops */
470  bm_faces_share_tag_flush(bm, e_arr_a, e_arr_a_len);
471  bm_faces_share_tag_flush(bm, e_arr_b, e_arr_b_len);
472 
473  /* now we have all data we need, calculate vertex spline nor! */
474  for (side_index = 0; side_index < 2; side_index++) {
475  /* iter vars */
476  struct BMEdgeLoopStore *el_store = el_store_pair[side_index];
477  ListBase *lb = BM_edgeloop_verts_get(el_store);
478  GHash *nors_gh_iter = nors_gh_pair[side_index];
479  float(*nor)[3] = nors_pair[side_index];
480 
481  LinkData *v_iter;
482 
483  for (v_iter = lb->first, i = 0; v_iter; v_iter = v_iter->next, i++) {
484  BMVert *v = v_iter->data;
486  BLI_ghash_insert(nors_gh_iter, v, POINTER_FROM_UINT(i));
487  }
488  }
489 
490  /* cleanup verts share */
491  bmo_edgeloop_vert_tag(bm, el_store_a, VERT_SHARED, false);
492  bmo_edgeloop_vert_tag(bm, el_store_b, VERT_SHARED, false);
493 
494  /* cleanup faces share */
495  bm_faces_share_tag_clear(bm, e_arr_a, e_arr_a_len);
496  bm_faces_share_tag_clear(bm, e_arr_b, e_arr_b_len);
497  }
498  return lpair;
499 }
500 
501 static void bm_edgering_pair_store_free(LoopPairStore *lpair, const int interp_mode)
502 {
503  if (interp_mode == SUBD_RING_INTERP_SURF) {
504  MEM_freeN(lpair->nors_a);
505  MEM_freeN(lpair->nors_b);
506 
507  BLI_ghash_free(lpair->nors_gh_a, NULL, NULL);
508  BLI_ghash_free(lpair->nors_gh_b, NULL, NULL);
509  }
510  MEM_freeN(lpair);
511 }
512 
513 /* -------------------------------------------------------------------- */
514 /* Interpolation Function */
515 
517  LoopPairStore *lpair,
518  struct BMEdgeLoopStore *el_store_a,
519  struct BMEdgeLoopStore *el_store_b,
520  ListBase *eloops_ring,
521  const int interp_mode,
522  const int cuts,
523  const float smooth,
524  const float *falloff_cache)
525 {
526  const int resolu = cuts + 2;
527  const int dims = 3;
528  bool is_a_no_valid, is_b_no_valid;
529  int i;
530 
531  float el_store_a_co[3], el_store_b_co[3];
532  float el_store_a_no[3], el_store_b_no[3];
533 
534  struct BMEdgeLoopStore *el_store_ring;
535 
536  float(*coord_array_main)[3] = NULL;
537 
538  BM_edgeloop_calc_center(bm, el_store_a);
539  BM_edgeloop_calc_center(bm, el_store_b);
540 
541  is_a_no_valid = BM_edgeloop_calc_normal(bm, el_store_a);
542  is_b_no_valid = BM_edgeloop_calc_normal(bm, el_store_b);
543 
544  copy_v3_v3(el_store_a_co, BM_edgeloop_center_get(el_store_a));
545  copy_v3_v3(el_store_b_co, BM_edgeloop_center_get(el_store_b));
546 
547  /* correct normals need to be flipped to face each other
548  * we know both normals point in the same direction so one will need flipping */
549  {
550  float el_dir[3];
551  float no[3];
552  sub_v3_v3v3(el_dir, el_store_a_co, el_store_b_co);
553  normalize_v3_v3(no, el_dir);
554 
555  if (is_a_no_valid == false) {
556  is_a_no_valid = BM_edgeloop_calc_normal_aligned(bm, el_store_a, no);
557  }
558  if (is_b_no_valid == false) {
559  is_b_no_valid = BM_edgeloop_calc_normal_aligned(bm, el_store_b, no);
560  }
561  (void)is_a_no_valid, (void)is_b_no_valid;
562 
563  copy_v3_v3(el_store_a_no, BM_edgeloop_normal_get(el_store_a));
564  copy_v3_v3(el_store_b_no, BM_edgeloop_normal_get(el_store_b));
565 
566  if (dot_v3v3(el_store_a_no, el_dir) > 0.0f) {
567  negate_v3(el_store_a_no);
568  }
569  if (dot_v3v3(el_store_b_no, el_dir) < 0.0f) {
570  negate_v3(el_store_b_no);
571  }
572  }
573  /* now normals are correct, don't touch! */
574 
575  /* Calculate the center spline, multiple. */
576  if ((interp_mode == SUBD_RING_INTERP_PATH) || falloff_cache) {
577  float handle_a[3], handle_b[3];
578  float handle_len;
579 
580  handle_len = bezier_handle_calc_length_v3(
581  el_store_a_co, el_store_a_no, el_store_b_co, el_store_b_no) *
582  smooth;
583 
584  mul_v3_v3fl(handle_a, el_store_a_no, handle_len);
585  mul_v3_v3fl(handle_b, el_store_b_no, handle_len);
586 
587  add_v3_v3(handle_a, el_store_a_co);
588  add_v3_v3(handle_b, el_store_b_co);
589 
590  coord_array_main = MEM_mallocN(dims * (resolu) * sizeof(float), __func__);
591 
592  for (i = 0; i < dims; i++) {
593  BKE_curve_forward_diff_bezier(el_store_a_co[i],
594  handle_a[i],
595  handle_b[i],
596  el_store_b_co[i],
597  ((float *)coord_array_main) + i,
598  resolu - 1,
599  sizeof(float) * dims);
600  }
601  }
602 
603  switch (interp_mode) {
605  if (falloff_cache) {
606  float(*coord_array)[3] = MEM_mallocN(dims * (resolu) * sizeof(float), __func__);
607  for (i = 0; i < resolu; i++) {
609  coord_array[i], el_store_a_co, el_store_b_co, (float)i / (float)(resolu - 1));
610  }
611 
612  for (el_store_ring = eloops_ring->first; el_store_ring;
613  el_store_ring = BM_EDGELOOP_NEXT(el_store_ring)) {
614  ListBase *lb_ring = BM_edgeloop_verts_get(el_store_ring);
615  LinkData *v_iter;
616 
617  for (v_iter = lb_ring->first, i = 0; v_iter; v_iter = v_iter->next, i++) {
618  if (i > 0 && i < resolu - 1) {
619  /* shape */
620  if (falloff_cache) {
621  interp_v3_v3v3(((BMVert *)v_iter->data)->co,
622  coord_array[i],
623  ((BMVert *)v_iter->data)->co,
624  falloff_cache[i]);
625  }
626  }
627  }
628  }
629 
630  MEM_freeN(coord_array);
631  }
632 
633  break;
634  }
635  case SUBD_RING_INTERP_PATH: {
636  float(*direction_array)[3] = MEM_mallocN(dims * (resolu) * sizeof(float), __func__);
637  float(*quat_array)[4] = MEM_mallocN(resolu * sizeof(*quat_array), __func__);
638  float(*tri_array)[3][3] = MEM_mallocN(resolu * sizeof(*tri_array), __func__);
639  float(*tri_sta)[3], (*tri_end)[3], (*tri_tmp)[3];
640 
641  /* very similar to make_bevel_list_3D_minimum_twist */
642 
643  /* calculate normals */
644  copy_v3_v3(direction_array[0], el_store_a_no);
645  negate_v3_v3(direction_array[resolu - 1], el_store_b_no);
646  for (i = 1; i < resolu - 1; i++) {
647  bisect_v3_v3v3v3(direction_array[i],
648  coord_array_main[i - 1],
649  coord_array_main[i],
650  coord_array_main[i + 1]);
651  }
652 
653  vec_to_quat(quat_array[0], direction_array[0], 5, 1);
654  normalize_qt(quat_array[0]);
655 
656  for (i = 1; i < resolu; i++) {
657  float angle = angle_normalized_v3v3(direction_array[i - 1], direction_array[i]);
658  // BLI_assert(angle < DEG2RADF(90.0f));
659  if (angle > 0.0f) { /* otherwise we can keep as is */
660  float cross_tmp[3];
661  float q[4];
662  cross_v3_v3v3(cross_tmp, direction_array[i - 1], direction_array[i]);
663  axis_angle_to_quat(q, cross_tmp, angle);
664  mul_qt_qtqt(quat_array[i], q, quat_array[i - 1]);
665  normalize_qt(quat_array[i]);
666  }
667  else {
668  copy_qt_qt(quat_array[i], quat_array[i - 1]);
669  }
670  }
671 
672  /* init base tri */
673  for (i = 0; i < resolu; i++) {
674  int j;
675 
676  const float shape_size = falloff_cache ? falloff_cache[i] : 1.0f;
677 
678  tri_tmp = tri_array[i];
679 
680  /* create the triangle and transform */
681  for (j = 0; j < 3; j++) {
682  zero_v3(tri_tmp[j]);
683  if (j == 1) {
684  tri_tmp[j][0] = shape_size;
685  }
686  else if (j == 2) {
687  tri_tmp[j][1] = shape_size;
688  }
689  mul_qt_v3(quat_array[i], tri_tmp[j]);
690  add_v3_v3(tri_tmp[j], coord_array_main[i]);
691  }
692  }
693 
694  tri_sta = tri_array[0];
695  tri_end = tri_array[resolu - 1];
696 
697  for (el_store_ring = eloops_ring->first; el_store_ring;
698  el_store_ring = BM_EDGELOOP_NEXT(el_store_ring)) {
699  ListBase *lb_ring = BM_edgeloop_verts_get(el_store_ring);
700  LinkData *v_iter;
701 
702  BMVert *v_a = ((LinkData *)lb_ring->first)->data;
703  BMVert *v_b = ((LinkData *)lb_ring->last)->data;
704 
705  /* skip first and last */
706  for (v_iter = ((LinkData *)lb_ring->first)->next, i = 1; v_iter != lb_ring->last;
707  v_iter = v_iter->next, i++) {
708  float co_a[3], co_b[3];
709 
710  tri_tmp = tri_array[i];
711 
712  transform_point_by_tri_v3(co_a, v_a->co, UNPACK3(tri_tmp), UNPACK3(tri_sta));
713  transform_point_by_tri_v3(co_b, v_b->co, UNPACK3(tri_tmp), UNPACK3(tri_end));
714 
715  interp_v3_v3v3(((BMVert *)v_iter->data)->co, co_a, co_b, (float)i / (float)(resolu - 1));
716  }
717  }
718 
719  MEM_freeN(direction_array);
720  MEM_freeN(quat_array);
721  MEM_freeN(tri_array);
722  break;
723  }
724  case SUBD_RING_INTERP_SURF: {
725  float(*coord_array)[3] = MEM_mallocN(dims * (resolu) * sizeof(float), __func__);
726 
727  /* calculate a bezier handle per edge ring */
728  for (el_store_ring = eloops_ring->first; el_store_ring;
729  el_store_ring = BM_EDGELOOP_NEXT(el_store_ring)) {
730  ListBase *lb_ring = BM_edgeloop_verts_get(el_store_ring);
731  LinkData *v_iter;
732 
733  BMVert *v_a = ((LinkData *)lb_ring->first)->data;
734  BMVert *v_b = ((LinkData *)lb_ring->last)->data;
735 
736  float co_a[3], no_a[3], handle_a[3], co_b[3], no_b[3], handle_b[3];
737  float handle_len;
738 
739  copy_v3_v3(co_a, v_a->co);
740  copy_v3_v3(co_b, v_b->co);
741 
742  /* don't calculate normals here else we get into feedback loop
743  * when subdividing 2+ connected edge rings */
744 #if 0
745  bm_vert_calc_surface_tangent(bm, v_a, no_a);
746  bm_vert_calc_surface_tangent(bm, v_b, no_b);
747 #else
748  {
749  const uint index_a = POINTER_AS_UINT(BLI_ghash_lookup(lpair->nors_gh_a, v_a));
750  const uint index_b = POINTER_AS_UINT(BLI_ghash_lookup(lpair->nors_gh_b, v_b));
751 
752  BLI_assert(BLI_ghash_haskey(lpair->nors_gh_a, v_a));
753  BLI_assert(BLI_ghash_haskey(lpair->nors_gh_b, v_b));
754 
755  copy_v3_v3(no_a, lpair->nors_a[index_a]);
756  copy_v3_v3(no_b, lpair->nors_b[index_b]);
757  }
758 #endif
759  handle_len = bezier_handle_calc_length_v3(co_a, no_a, co_b, no_b) * smooth;
760 
761  mul_v3_v3fl(handle_a, no_a, handle_len);
762  mul_v3_v3fl(handle_b, no_b, handle_len);
763 
764  add_v3_v3(handle_a, co_a);
765  add_v3_v3(handle_b, co_b);
766 
767  for (i = 0; i < dims; i++) {
769  handle_a[i],
770  handle_b[i],
771  co_b[i],
772  ((float *)coord_array) + i,
773  resolu - 1,
774  sizeof(float) * dims);
775  }
776 
777  /* skip first and last */
778  for (v_iter = ((LinkData *)lb_ring->first)->next, i = 1; v_iter != lb_ring->last;
779  v_iter = v_iter->next, i++) {
780  if (i > 0 && i < resolu - 1) {
781  copy_v3_v3(((BMVert *)v_iter->data)->co, coord_array[i]);
782 
783  /* shape */
784  if (falloff_cache) {
785  interp_v3_v3v3(((BMVert *)v_iter->data)->co,
786  coord_array_main[i],
787  ((BMVert *)v_iter->data)->co,
788  falloff_cache[i]);
789  }
790  }
791  }
792  }
793 
794  MEM_freeN(coord_array);
795 
796  break;
797  }
798  }
799 
800  if (coord_array_main) {
801  MEM_freeN(coord_array_main);
802  }
803 }
804 
808 static void bm_face_slice(BMesh *bm, BMLoop *l, const int cuts)
809 {
810  /* TODO: interpolate edge data. */
811  BMLoop *l_new = l;
812  int i;
813 
814  for (i = 0; i < cuts; i++) {
815  /* no chance of double */
816  BM_face_split(bm, l_new->f, l_new->prev, l_new->next->next, &l_new, NULL, false);
817  if (l_new == NULL) {
818  /* This happens when l_new->prev and l_new->next->next are adjacent. Since
819  * this sets l_new to NULL, we cannot continue this for-loop. */
820  break;
821  }
822  if (l_new->f->len < l_new->radial_next->f->len) {
823  l_new = l_new->radial_next;
824  }
825  BMO_face_flag_enable(bm, l_new->f, FACE_OUT);
827  }
828 }
829 
831  struct BMEdgeLoopStore *el_store_a,
832  struct BMEdgeLoopStore *el_store_b)
833 {
834  ListBase *lb_a = BM_edgeloop_verts_get(el_store_a);
835  ListBase *lb_b = BM_edgeloop_verts_get(el_store_b);
836 
837  LinkData *v_iter_a_first = lb_a->first;
838  LinkData *v_iter_b_first = lb_b->first;
839 
840  LinkData *v_iter_a_step = v_iter_a_first;
841  LinkData *v_iter_b_step = v_iter_b_first;
842 
843  /* we _must_ have same starting edge shared */
844  BLI_assert(BM_edge_exists(v_iter_a_first->data, v_iter_b_first->data));
845 
846  /* step around any fan-faces on both sides */
847  do {
848  v_iter_a_step = v_iter_a_step->next;
849  } while (v_iter_a_step && (BM_edge_exists(v_iter_a_step->data, v_iter_b_first->data) ||
850  BM_edge_exists(v_iter_a_step->data, v_iter_b_first->next->data)));
851  do {
852  v_iter_b_step = v_iter_b_step->next;
853  } while (v_iter_b_step && (BM_edge_exists(v_iter_b_step->data, v_iter_a_first->data) ||
854  BM_edge_exists(v_iter_b_step->data, v_iter_a_first->next->data)));
855 
856  v_iter_a_step = v_iter_a_step ? v_iter_a_step->prev : lb_a->last;
857  v_iter_b_step = v_iter_b_step ? v_iter_b_step->prev : lb_b->last;
858 
859  return !(BM_edge_exists(v_iter_a_step->data, v_iter_b_step->data) ||
860  BM_edge_exists(v_iter_a_first->next->data, v_iter_b_step->data) ||
861  BM_edge_exists(v_iter_b_first->next->data, v_iter_a_step->data));
862 }
863 
869  struct BMEdgeLoopStore *el_store_a,
870  struct BMEdgeLoopStore *el_store_b)
871 {
872  ListBase *lb_a = BM_edgeloop_verts_get(el_store_a);
873  ListBase *lb_b = BM_edgeloop_verts_get(el_store_b);
874 
875  LinkData *node;
876 
877  bm_edgeloop_vert_tag(el_store_a, false);
878  bm_edgeloop_vert_tag(el_store_b, true);
879 
880  /* before going much further, get ourselves in order
881  * - align loops (not strictly necessary but handy)
882  * - ensure winding is set for both loops */
883  if (BM_edgeloop_is_closed(el_store_a) && BM_edgeloop_is_closed(el_store_b)) {
884  BMIter eiter;
885  BMEdge *e;
886  BMVert *v_other;
887 
888  node = lb_a->first;
889 
890  BM_ITER_ELEM (e, &eiter, (BMVert *)node->data, BM_EDGES_OF_VERT) {
891  if (BMO_edge_flag_test(bm, e, EDGE_RING)) {
892  v_other = BM_edge_other_vert(e, (BMVert *)node->data);
893  if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
894  break;
895  }
896  v_other = NULL;
897  }
898  }
899  BLI_assert(v_other != NULL);
900 
901  for (node = lb_b->first; node; node = node->next) {
902  if (node->data == v_other) {
903  break;
904  }
905  }
906  BLI_assert(node != NULL);
907 
909 
910  /* now check we are winding the same way */
911  if (bm_edgering_pair_order_is_flipped(bm, el_store_a, el_store_b)) {
912  BM_edgeloop_flip(bm, el_store_b);
913  /* re-ensure the first node */
915  }
916 
917  /* sanity checks that we are aligned & winding now */
918  BLI_assert(bm_edgering_pair_order_is_flipped(bm, el_store_a, el_store_b) == false);
919  }
920  else {
921  /* If we don't share and edge - flip. */
922  BMEdge *e = BM_edge_exists(((LinkData *)lb_a->first)->data, ((LinkData *)lb_b->first)->data);
923  if (e == NULL || !BMO_edge_flag_test(bm, e, EDGE_RING)) {
924  BM_edgeloop_flip(bm, el_store_b);
925  }
926  }
927 
928  /* for cases with multiple loops */
929  bm_edgeloop_vert_tag(el_store_b, false);
930 }
931 
938  struct BMEdgeLoopStore *el_store_a,
939  struct BMEdgeLoopStore *el_store_b,
940  ListBase *eloops_ring,
941  const int cuts)
942 {
943  ListBase *lb_a = BM_edgeloop_verts_get(el_store_a);
944  // ListBase *lb_b = BM_edgeloop_verts_get(el_store_b);
945  const int stack_max = max_ii(BM_edgeloop_length_get(el_store_a),
946  BM_edgeloop_length_get(el_store_b)) *
947  2;
948  BMEdge **edges_ring_arr = BLI_array_alloca(edges_ring_arr, stack_max);
949  BMFace **faces_ring_arr = BLI_array_alloca(faces_ring_arr, stack_max);
950  STACK_DECLARE(edges_ring_arr);
951  STACK_DECLARE(faces_ring_arr);
952  struct BMEdgeLoopStore *el_store_ring;
953  LinkData *node;
954  BMEdge *e;
955  BMFace *f;
956 
957  STACK_INIT(edges_ring_arr, stack_max);
958  STACK_INIT(faces_ring_arr, stack_max);
959 
960  bm_edgeloop_vert_tag(el_store_a, false);
961  bm_edgeloop_vert_tag(el_store_b, true);
962 
963  for (node = lb_a->first; node; node = node->next) {
964  BMIter eiter;
965 
966  BM_ITER_ELEM (e, &eiter, (BMVert *)node->data, BM_EDGES_OF_VERT) {
968  BMVert *v_other = BM_edge_other_vert(e, (BMVert *)node->data);
969  if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
970  BMIter fiter;
971 
973  STACK_PUSH(edges_ring_arr, e);
974 
975  /* add faces to the stack */
976  BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
977  if (BMO_face_flag_test(bm, f, FACE_OUT)) {
978  if (!BMO_face_flag_test(bm, f, FACE_IN_STACK)) {
980  STACK_PUSH(faces_ring_arr, f);
981  }
982  }
983  }
984  }
985  }
986  }
987  }
988 
989  while ((e = STACK_POP(edges_ring_arr))) {
990  /* found opposite edge */
991  BMVert *v_other;
992 
994 
995  /* unrelated to subdiv, but if we _don't_ clear flag, multiple rings fail */
997 
998  v_other = BM_elem_flag_test(e->v1, BM_ELEM_TAG) ? e->v1 : e->v2;
999  bm_edge_subdiv_as_loop(bm, eloops_ring, e, v_other, cuts);
1000  }
1001 
1002  while ((f = STACK_POP(faces_ring_arr))) {
1003  BMLoop *l_iter, *l_first;
1004 
1006 
1007  /* Check each edge of the face */
1008  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1009  do {
1010  if (BMO_edge_flag_test(bm, l_iter->e, EDGE_RIM)) {
1011  bm_face_slice(bm, l_iter, cuts);
1012  break;
1013  }
1014  } while ((l_iter = l_iter->next) != l_first);
1015  }
1016 
1017  /* Clear tags so subdiv verts don't get tagged too. */
1018  for (el_store_ring = eloops_ring->first; el_store_ring;
1019  el_store_ring = BM_EDGELOOP_NEXT(el_store_ring)) {
1020  bm_edgeloop_vert_tag(el_store_ring, false);
1021  }
1022 
1023  /* cleanup after */
1024  bm_edgeloop_vert_tag(el_store_b, false);
1025 }
1026 
1028  LoopPairStore *lpair,
1029  struct BMEdgeLoopStore *el_store_a,
1030  struct BMEdgeLoopStore *el_store_b,
1031  const int interp_mode,
1032  const int cuts,
1033  const float smooth,
1034  const float *falloff_cache)
1035 {
1036  ListBase eloops_ring = {NULL};
1037  bm_edgering_pair_order(bm, el_store_a, el_store_b);
1038  bm_edgering_pair_subdiv(bm, el_store_a, el_store_b, &eloops_ring, cuts);
1040  bm, lpair, el_store_a, el_store_b, &eloops_ring, interp_mode, cuts, smooth, falloff_cache);
1041  BM_mesh_edgeloops_free(&eloops_ring);
1042 }
1043 
1044 static bool bm_edge_rim_test_cb(BMEdge *e, void *bm_v)
1045 {
1046  BMesh *bm = bm_v;
1048 }
1049 
1051 {
1052  /* NOTE: keep this operator fast, its used in a modifier. */
1053 
1054  ListBase eloops_rim = {NULL};
1055  BMOIter siter;
1056  BMEdge *e;
1057  int count;
1058  bool changed = false;
1059 
1060  const int cuts = BMO_slot_int_get(op->slots_in, "cuts");
1061  const int interp_mode = BMO_slot_int_get(op->slots_in, "interp_mode");
1062  const float smooth = BMO_slot_float_get(op->slots_in, "smooth");
1063  const int resolu = cuts + 2;
1064 
1065  /* optional 'shape' */
1066  const int profile_shape = BMO_slot_int_get(op->slots_in, "profile_shape");
1067  const float profile_shape_factor = BMO_slot_float_get(op->slots_in, "profile_shape_factor");
1068  float *falloff_cache = (profile_shape_factor != 0.0f) ?
1069  BLI_array_alloca(falloff_cache, cuts + 2) :
1070  NULL;
1071 
1073 
1075 
1076  /* -------------------------------------------------------------------- */
1077  /* flag outer edges (loops defined as edges on the bounds of the edge ring) */
1078 
1079  BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) {
1080  BMIter fiter;
1081  BMFace *f;
1082 
1083  BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
1084  /* could support ngons, other areas would need updating too, see T48926. */
1085  if ((f->len <= 4) && !BMO_face_flag_test(bm, f, FACE_OUT)) {
1086  BMIter liter;
1087  BMLoop *l;
1088  bool ok = false;
1089 
1090  /* check at least 2 edges in the face are rings */
1091  BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
1092  if (BMO_edge_flag_test(bm, l->e, EDGE_RING) && e != l->e) {
1093  ok = true;
1094  break;
1095  }
1096  }
1097 
1098  if (ok) {
1100 
1101  BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
1102  if (!BMO_edge_flag_test(bm, l->e, EDGE_RING)) {
1104  }
1105  }
1106  }
1107  }
1108  }
1109  }
1110 
1111  /* -------------------------------------------------------------------- */
1112  /* Cache falloff for each step (symmetrical) */
1113 
1114  if (falloff_cache) {
1115  int i;
1116  for (i = 0; i < resolu; i++) {
1117  float shape_size = 1.0f;
1118  float fac = (float)i / (float)(resolu - 1);
1119  fac = fabsf(1.0f - 2.0f * fabsf(0.5f - fac));
1120  fac = bmesh_subd_falloff_calc(profile_shape, fac);
1121  shape_size += fac * profile_shape_factor;
1122 
1123  falloff_cache[i] = shape_size;
1124  }
1125  }
1126 
1127  /* -------------------------------------------------------------------- */
1128  /* Execute subdivision on all ring pairs */
1129 
1130  count = BM_mesh_edgeloops_find(bm, &eloops_rim, bm_edge_rim_test_cb, (void *)bm);
1131 
1132  if (count < 2) {
1133  BMO_error_raise(bm, op, BMO_ERROR_CANCEL, "No edge rings found");
1134  goto cleanup;
1135  }
1136  else if (count == 2) {
1137  /* this case could be removed,
1138  * but simple to avoid 'bm_edgering_pair_calc' in this case since there's only one. */
1139  struct BMEdgeLoopStore *el_store_a = eloops_rim.first;
1140  struct BMEdgeLoopStore *el_store_b = eloops_rim.last;
1141  LoopPairStore *lpair;
1142 
1143  if (bm_edgeloop_check_overlap_all(bm, el_store_a, el_store_b)) {
1144  lpair = bm_edgering_pair_store_create(bm, el_store_a, el_store_b, interp_mode);
1145  }
1146  else {
1147  lpair = NULL;
1148  }
1149 
1150  if (lpair) {
1152  bm, lpair, el_store_a, el_store_b, interp_mode, cuts, smooth, falloff_cache);
1153  bm_edgering_pair_store_free(lpair, interp_mode);
1154  changed = true;
1155  }
1156  else {
1157  BMO_error_raise(bm, op, BMO_ERROR_CANCEL, "Edge-ring pair isn't connected");
1158  goto cleanup;
1159  }
1160  }
1161  else {
1162  GSetIterator gs_iter;
1163  int i;
1164 
1165  GSet *eloop_pairs_gs = bm_edgering_pair_calc(bm, &eloops_rim);
1166  LoopPairStore **lpair_arr;
1167 
1168  if (eloop_pairs_gs == NULL) {
1169  BMO_error_raise(bm, op, BMO_ERROR_CANCEL, "Edge-rings are not connected");
1170  goto cleanup;
1171  }
1172 
1173  lpair_arr = BLI_array_alloca(lpair_arr, BLI_gset_len(eloop_pairs_gs));
1174 
1175  /* first cache pairs */
1176  GSET_ITER_INDEX (gs_iter, eloop_pairs_gs, i) {
1177  GHashPair *eloop_pair = BLI_gsetIterator_getKey(&gs_iter);
1178  struct BMEdgeLoopStore *el_store_a = (void *)eloop_pair->first;
1179  struct BMEdgeLoopStore *el_store_b = (void *)eloop_pair->second;
1180  LoopPairStore *lpair;
1181 
1182  if (bm_edgeloop_check_overlap_all(bm, el_store_a, el_store_b)) {
1183  lpair = bm_edgering_pair_store_create(bm, el_store_a, el_store_b, interp_mode);
1184  }
1185  else {
1186  lpair = NULL;
1187  }
1188  lpair_arr[i] = lpair;
1189 
1191  }
1192 
1193  GSET_ITER_INDEX (gs_iter, eloop_pairs_gs, i) {
1194  GHashPair *eloop_pair = BLI_gsetIterator_getKey(&gs_iter);
1195  struct BMEdgeLoopStore *el_store_a = (void *)eloop_pair->first;
1196  struct BMEdgeLoopStore *el_store_b = (void *)eloop_pair->second;
1197  LoopPairStore *lpair = lpair_arr[i];
1198 
1199  if (lpair) {
1201  bm, lpair, el_store_a, el_store_b, interp_mode, cuts, smooth, falloff_cache);
1202  bm_edgering_pair_store_free(lpair, interp_mode);
1203  changed = true;
1204  }
1205 
1207  }
1208  BLI_gset_free(eloop_pairs_gs, MEM_freeN);
1209  }
1210 
1211 cleanup:
1212  BM_mesh_edgeloops_free(&eloops_rim);
1213 
1214  /* flag output */
1215  if (changed) {
1217  }
1218 }
typedef float(TangentPoint)[2]
void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride)
Definition: curve.cc:1717
#define BLI_array_alloca(arr, realsize)
Definition: BLI_alloca.h:22
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define GSET_ITER_INDEX(gs_iter_, gset_, i_)
Definition: BLI_ghash.h:475
struct GSet GSet
Definition: BLI_ghash.h:340
bool BLI_ghash_haskey(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:822
bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key)
Definition: BLI_ghash.c:974
GHashPair * BLI_ghashutil_pairalloc(const void *first, const void *second)
unsigned int BLI_gset_len(const GSet *gs) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:957
GSet * BLI_gset_pair_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:734
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition: BLI_ghash.c:710
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:863
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition: BLI_ghash.c:1037
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
BLI_INLINE void * BLI_gsetIterator_getKey(GSetIterator *gsi)
Definition: BLI_ghash.h:458
void BLI_listbase_rotate_first(struct ListBase *lb, void *vlink) ATTR_NONNULL(1
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
MINLINE int max_ii(int a, int b)
void transform_point_by_tri_v3(float pt_tar[3], float const pt_src[3], const float tri_tar_p1[3], const float tri_tar_p2[3], const float tri_tar_p3[3], const float tri_src_p1[3], const float tri_src_p2[3], const float tri_src_p3[3])
Definition: math_geom.c:3862
float closest_to_line_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3])
Definition: math_geom.c:3176
void axis_angle_to_quat(float r[4], const float axis[3], float angle)
void vec_to_quat(float q[4], const float vec[3], short axis, short upflag)
float normalize_qt(float q[4])
void mul_qt_v3(const float q[4], float r[3])
Definition: math_rotation.c:59
void mul_qt_qtqt(float q[4], const float a[4], const float b[4])
Definition: math_rotation.c:46
void copy_qt_qt(float q[4], const float a[4])
Definition: math_rotation.c:33
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v3(float r[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3_v3(float r[3], const float a[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
Definition: math_vector.c:29
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])
MINLINE float normalize_v3_v3(float r[3], const float a[3])
MINLINE void zero_v3(float r[3])
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:445
MINLINE void add_v3_v3(float r[3], const float a[3])
void bisect_v3_v3v3v3(float r[3], const float a[3], const float b[3], const float c[3])
Definition: math_vector.c:680
unsigned int uint
Definition: BLI_sys_types.h:67
#define SWAP(type, a, b)
#define POINTER_AS_UINT(i)
#define UNUSED(x)
#define UNPACK3(a)
#define UNLIKELY(x)
#define POINTER_FROM_UINT(i)
#define STACK_POP(stack)
#define STACK_PUSH(stack, val)
#define STACK_DECLARE(stack)
#define STACK_INIT(stack, stack_num)
_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 GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
Read Guarded memory(de)allocation.
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:622
@ 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
const float * BM_edgeloop_center_get(struct BMEdgeLoopStore *el_store)
void BM_mesh_edgeloops_free(ListBase *eloops)
BMEdgeLoopStore * BM_edgeloop_from_verts(BMVert **v_arr, const int v_arr_tot, bool is_closed)
int BM_mesh_edgeloops_find(BMesh *bm, ListBase *r_eloops, bool(*test_fn)(BMEdge *, void *user_data), void *user_data)
int BM_edgeloop_length_get(BMEdgeLoopStore *el_store)
bool BM_edgeloop_is_closed(BMEdgeLoopStore *el_store)
void BM_edgeloop_edges_get(struct BMEdgeLoopStore *el_store, BMEdge **e_arr)
ListBase * BM_edgeloop_verts_get(BMEdgeLoopStore *el_store)
bool BM_edgeloop_calc_normal(BMesh *UNUSED(bm), BMEdgeLoopStore *el_store)
bool BM_edgeloop_calc_normal_aligned(BMesh *UNUSED(bm), BMEdgeLoopStore *el_store, const float no_align[3])
const float * BM_edgeloop_normal_get(struct BMEdgeLoopStore *el_store)
void BM_edgeloop_flip(BMesh *UNUSED(bm), BMEdgeLoopStore *el_store)
void BM_edgeloop_calc_center(BMesh *UNUSED(bm), BMEdgeLoopStore *el_store)
#define BM_EDGELOOP_NEXT(el_store)
@ BMO_ERROR_CANCEL
Definition: bmesh_error.h:21
void BMO_error_raise(BMesh *bm, BMOperator *owner, eBMOpErrorLevel level, const char *msg) ATTR_NONNULL(1
#define BM_elem_flag_set(ele, hflag, val)
Definition: bmesh_inline.h:16
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:12
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_FACES_OF_EDGE
@ BM_VERTS_OF_MESH
@ BM_LOOPS_OF_EDGE
@ BM_EDGES_OF_VERT
@ BM_LOOPS_OF_FACE
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
BMVert * BM_edge_split_n(BMesh *bm, BMEdge *e, int numcuts, BMVert **r_varr)
Split an edge multiple times evenly.
Definition: bmesh_mods.c:563
BMFace * BM_face_split(BMesh *bm, BMFace *f, BMLoop *l_a, BMLoop *l_b, BMLoop **r_l, BMEdge *example, const bool no_double)
Face Split.
Definition: bmesh_mods.c:179
#define BMO_edge_flag_test_bool(bm, e, oflag)
void BMO_slot_buffer_flag_enable(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, short oflag)
BMO_FLAG_BUFFER.
#define BMO_edge_flag_test(bm, e, oflag)
#define BMO_edge_flag_enable(bm, e, oflag)
float BMO_slot_float_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
#define BMO_vert_flag_set(bm, e, oflag, val)
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)
#define BMO_vert_flag_test(bm, e, oflag)
int BMO_slot_int_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
#define BMO_face_flag_disable(bm, e, oflag)
#define BMO_edge_flag_disable(bm, e, oflag)
#define BMO_face_flag_test(bm, e, oflag)
ATTR_WARN_UNUSED_RESULT const BMFlagLayer const short oflag
@ SUBD_RING_INTERP_SURF
@ SUBD_RING_INTERP_PATH
@ SUBD_RING_INTERP_LINEAR
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
Definition: bmesh_query.c:1553
float bmesh_subd_falloff_calc(const int falloff, float val)
Definition: bmesh_query.c:2452
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 BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_vert_in_edge(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
struct LoopPairStore LoopPairStore
static void bm_edgering_pair_order(BMesh *bm, struct BMEdgeLoopStore *el_store_a, struct BMEdgeLoopStore *el_store_b)
void bmo_subdivide_edgering_exec(BMesh *bm, BMOperator *op)
#define FACE_OUT
static bool bm_edge_rim_test_cb(BMEdge *e, void *bm_v)
static float bezier_handle_calc_length_v3(const float co_a[3], const float no_a[3], const float co_b[3], const float no_b[3])
static void bm_edge_subdiv_as_loop(BMesh *bm, ListBase *eloops, BMEdge *e, BMVert *v_a, const int cuts)
static void bm_faces_share_tag_flush(BMesh *bm, BMEdge **e_arr, const uint e_arr_len)
#define FACE_IN_STACK
static uint bm_verts_tag_count(BMesh *bm)
static bool bmo_face_is_vert_tag_all(BMesh *bm, BMFace *f, short oflag)
static void bm_edgering_pair_ringsubd(BMesh *bm, LoopPairStore *lpair, struct BMEdgeLoopStore *el_store_a, struct BMEdgeLoopStore *el_store_b, const int interp_mode, const int cuts, const float smooth, const float *falloff_cache)
static void bm_faces_share_tag_clear(BMesh *bm, BMEdge **e_arr_iter, const uint e_arr_len_iter)
static void bm_face_slice(BMesh *bm, BMLoop *l, const int cuts)
static bool bm_edgeloop_check_overlap_all(BMesh *bm, struct BMEdgeLoopStore *el_store_a, struct BMEdgeLoopStore *el_store_b)
static void bm_vert_calc_surface_tangent(BMesh *bm, BMVert *v, float r_no[3])
#define EDGE_RING
static void bm_edgering_pair_store_free(LoopPairStore *lpair, const int interp_mode)
static void bm_edgering_pair_interpolate(BMesh *bm, LoopPairStore *lpair, struct BMEdgeLoopStore *el_store_a, struct BMEdgeLoopStore *el_store_b, ListBase *eloops_ring, const int interp_mode, const int cuts, const float smooth, const float *falloff_cache)
static void bm_edgeloop_vert_tag(struct BMEdgeLoopStore *el_store, const bool tag)
static bool bm_vert_is_tag_edge_connect(BMesh *bm, BMVert *v)
#define EDGE_IN_STACK
static bool bm_edgering_pair_order_is_flipped(BMesh *UNUSED(bm), struct BMEdgeLoopStore *el_store_a, struct BMEdgeLoopStore *el_store_b)
static void bm_edgering_pair_subdiv(BMesh *bm, struct BMEdgeLoopStore *el_store_a, struct BMEdgeLoopStore *el_store_b, ListBase *eloops_ring, const int cuts)
static GSet * bm_edgering_pair_calc(BMesh *bm, ListBase *eloops_rim)
#define FACE_SHARED
#define VERT_SHARED
static void bmo_edgeloop_vert_tag(BMesh *bm, struct BMEdgeLoopStore *el_store, const short oflag, const bool tag)
#define EDGE_RIM
static LoopPairStore * bm_edgering_pair_store_create(BMesh *bm, struct BMEdgeLoopStore *el_store_a, struct BMEdgeLoopStore *el_store_b, const int interp_mode)
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Definition: btVector3.h:356
OperationNode * node
SyclQueue void void size_t num_bytes void
int len
Definition: draw_manager.c:108
uint nor
int count
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
static ulong * next
#define fabsf(x)
Definition: metal/compat.h:219
T dot(const vec_base< T, Size > &a, const vec_base< T, Size > &b)
smooth(Type::FLOAT, "mask_weight")
int len
Definition: bmesh_class.h:267
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
const void * second
Definition: BLI_ghash.h:605
const void * first
Definition: BLI_ghash.h:604
void * data
Definition: DNA_listBase.h:26
struct LinkData * next
Definition: DNA_listBase.h:25
struct LinkData * prev
Definition: DNA_listBase.h:25
void * last
Definition: DNA_listBase.h:31
void * first
Definition: DNA_listBase.h:31