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