diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:17:24 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:21:24 +0300 |
commit | e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch) | |
tree | 8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/bmesh/operators/bmo_subdivide_edgering.c | |
parent | b3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff) |
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211.
For details on usage and instructions for migrating branches
without conflicts, see:
https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/bmesh/operators/bmo_subdivide_edgering.c')
-rw-r--r-- | source/blender/bmesh/operators/bmo_subdivide_edgering.c | 2044 |
1 files changed, 1019 insertions, 1025 deletions
diff --git a/source/blender/bmesh/operators/bmo_subdivide_edgering.c b/source/blender/bmesh/operators/bmo_subdivide_edgering.c index 8c5ee4ede3d..c6d2910d214 100644 --- a/source/blender/bmesh/operators/bmo_subdivide_edgering.c +++ b/source/blender/bmesh/operators/bmo_subdivide_edgering.c @@ -45,16 +45,15 @@ #include "intern/bmesh_operators_private.h" /* own include */ -#define VERT_SHARED (1 << 0) +#define VERT_SHARED (1 << 0) -#define EDGE_RING (1 << 0) -#define EDGE_RIM (1 << 1) -#define EDGE_IN_STACK (1 << 2) - -#define FACE_OUT (1 << 0) -#define FACE_SHARED (1 << 1) -#define FACE_IN_STACK (1 << 2) +#define EDGE_RING (1 << 0) +#define EDGE_RIM (1 << 1) +#define EDGE_IN_STACK (1 << 2) +#define FACE_OUT (1 << 0) +#define FACE_SHARED (1 << 1) +#define FACE_IN_STACK (1 << 2) /* -------------------------------------------------------------------- */ /* Specialized Utility Funcs */ @@ -62,138 +61,140 @@ #ifndef NDEBUG static uint bm_verts_tag_count(BMesh *bm) { - int count = 0; - BMIter iter; - BMVert *v; - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_TAG)) { - count++; - } - } - return count; + int count = 0; + BMIter iter; + BMVert *v; + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + count++; + } + } + return count; } #endif -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 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]) { - const float dot = dot_v3v3(no_a, no_b); - /* gives closest approx at a circle with 2 parallel handles */ - float fac = 1.333333f; - float len; - if (dot < 0.0f) { - /* scale down to 0.666 if we point directly at each other rough but ok */ - /* TODO, current blend from dot may not be optimal but its also a detail */ - const float t = 1.0f + dot; - fac = (fac * t) + (0.75f * (1.0f - t)); - } + const float dot = dot_v3v3(no_a, no_b); + /* gives closest approx at a circle with 2 parallel handles */ + float fac = 1.333333f; + float len; + if (dot < 0.0f) { + /* scale down to 0.666 if we point directly at each other rough but ok */ + /* TODO, current blend from dot may not be optimal but its also a detail */ + const float t = 1.0f + dot; + fac = (fac * t) + (0.75f * (1.0f - t)); + } #if 0 - len = len_v3v3(co_a, co_b); + len = len_v3v3(co_a, co_b); #else - /* 2d length projected on plane of normals */ - { - float co_a_ofs[3]; - cross_v3_v3v3(co_a_ofs, no_a, no_b); - if (len_squared_v3(co_a_ofs) > FLT_EPSILON) { - add_v3_v3(co_a_ofs, co_a); - closest_to_line_v3(co_a_ofs, co_b, co_a, co_a_ofs); - } - else { - copy_v3_v3(co_a_ofs, co_a); - } - len = len_v3v3(co_a_ofs, co_b); - } + /* 2d length projected on plane of normals */ + { + float co_a_ofs[3]; + cross_v3_v3v3(co_a_ofs, no_a, no_b); + if (len_squared_v3(co_a_ofs) > FLT_EPSILON) { + add_v3_v3(co_a_ofs, co_a); + closest_to_line_v3(co_a_ofs, co_b, co_a, co_a_ofs); + } + else { + copy_v3_v3(co_a_ofs, co_a); + } + len = len_v3v3(co_a_ofs, co_b); + } #endif - return (len * 0.5f) * fac; + return (len * 0.5f) * fac; } static void bm_edgeloop_vert_tag(struct BMEdgeLoopStore *el_store, const bool tag) { - LinkData *node = BM_edgeloop_verts_get(el_store)->first; - do { - BM_elem_flag_set((BMVert *)node->data, BM_ELEM_TAG, tag); - } while ((node = node->next)); + LinkData *node = BM_edgeloop_verts_get(el_store)->first; + do { + BM_elem_flag_set((BMVert *)node->data, BM_ELEM_TAG, tag); + } while ((node = node->next)); } -static void bmo_edgeloop_vert_tag(BMesh *bm, struct BMEdgeLoopStore *el_store, const short oflag, const bool tag) +static void bmo_edgeloop_vert_tag(BMesh *bm, + struct BMEdgeLoopStore *el_store, + const short oflag, + const bool tag) { - LinkData *node = BM_edgeloop_verts_get(el_store)->first; - do { - BMO_vert_flag_set(bm, (BMVert *)node->data, oflag, tag); - } while ((node = node->next)); + LinkData *node = BM_edgeloop_verts_get(el_store)->first; + do { + BMO_vert_flag_set(bm, (BMVert *)node->data, oflag, tag); + } while ((node = node->next)); } static bool bmo_face_is_vert_tag_all(BMesh *bm, BMFace *f, short oflag) { - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - if (!BMO_vert_flag_test(bm, l_iter->v, oflag)) { - return false; - } - } while ((l_iter = l_iter->next) != l_first); - return true; + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (!BMO_vert_flag_test(bm, l_iter->v, oflag)) { + return false; + } + } while ((l_iter = l_iter->next) != l_first); + return true; } static bool bm_vert_is_tag_edge_connect(BMesh *bm, BMVert *v) { - BMIter eiter; - BMEdge *e; - - BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (BMO_edge_flag_test(bm, e, EDGE_RING)) { - BMVert *v_other = BM_edge_other_vert(e, v); - if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) { - return true; - } - } - } - return false; + BMIter eiter; + BMEdge *e; + + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + if (BMO_edge_flag_test(bm, e, EDGE_RING)) { + BMVert *v_other = BM_edge_other_vert(e, v); + if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) { + return true; + } + } + } + return false; } /* for now we need full overlap, * supporting partial overlap could be done but gets complicated * when trimming endpoints is not enough to ensure consistency. */ -static bool bm_edgeloop_check_overlap_all( - BMesh *bm, - struct BMEdgeLoopStore *el_store_a, - struct BMEdgeLoopStore *el_store_b) +static bool bm_edgeloop_check_overlap_all(BMesh *bm, + struct BMEdgeLoopStore *el_store_a, + struct BMEdgeLoopStore *el_store_b) { - bool has_overlap = true; - LinkData *node; + bool has_overlap = true; + LinkData *node; - ListBase *lb_a = BM_edgeloop_verts_get(el_store_a); - ListBase *lb_b = BM_edgeloop_verts_get(el_store_b); + ListBase *lb_a = BM_edgeloop_verts_get(el_store_a); + ListBase *lb_b = BM_edgeloop_verts_get(el_store_b); - bm_edgeloop_vert_tag(el_store_a, false); - bm_edgeloop_vert_tag(el_store_b, true); + bm_edgeloop_vert_tag(el_store_a, false); + bm_edgeloop_vert_tag(el_store_b, true); - for (node = lb_a->first; node; node = node->next) { - if (bm_vert_is_tag_edge_connect(bm, node->data) == false) { - has_overlap = false; - goto finally; - } - } + for (node = lb_a->first; node; node = node->next) { + if (bm_vert_is_tag_edge_connect(bm, node->data) == false) { + has_overlap = false; + goto finally; + } + } - bm_edgeloop_vert_tag(el_store_a, true); - bm_edgeloop_vert_tag(el_store_b, false); + bm_edgeloop_vert_tag(el_store_a, true); + bm_edgeloop_vert_tag(el_store_b, false); - for (node = lb_b->first; node; node = node->next) { - if (bm_vert_is_tag_edge_connect(bm, node->data) == false) { - has_overlap = false; - goto finally; - } - } + for (node = lb_b->first; node; node = node->next) { + if (bm_vert_is_tag_edge_connect(bm, node->data) == false) { + has_overlap = false; + goto finally; + } + } finally: - bm_edgeloop_vert_tag(el_store_a, false); - bm_edgeloop_vert_tag(el_store_b, false); - return has_overlap; - + bm_edgeloop_vert_tag(el_store_a, false); + bm_edgeloop_vert_tag(el_store_b, false); + return has_overlap; } /* -------------------------------------------------------------------- */ @@ -201,114 +202,111 @@ finally: /* key (ordered loop pointers) */ static GSet *bm_edgering_pair_calc(BMesh *bm, ListBase *eloops_rim) { - /** - * Method for for finding pairs: - * - * - first create (vert -> eloop) mapping. - * - loop over all eloops. - * - take first vertex of the eloop (any vertex will do) - * - loop over all edges of the vertex. - * - use the edge-verts and (vert -> eloop) map - * to create a pair of eloop pointers, add these to a hash. - * - * \note, each loop pair will be found twice. - * could sort and optimize this but not really so important. - */ - - GSet *eloop_pair_gs = BLI_gset_pair_new(__func__); - GHash *vert_eloop_gh = BLI_ghash_ptr_new(__func__); - - struct BMEdgeLoopStore *el_store; - - /* create vert -> eloop map */ - for (el_store = eloops_rim->first; el_store; el_store = BM_EDGELOOP_NEXT(el_store)) { - LinkData *node = BM_edgeloop_verts_get(el_store)->first; - do { - BLI_ghash_insert(vert_eloop_gh, node->data, el_store); - } while ((node = node->next)); - } - - - /* collect eloop pairs */ - for (el_store = eloops_rim->first; el_store; el_store = BM_EDGELOOP_NEXT(el_store)) { - BMIter eiter; - BMEdge *e; - - BMVert *v = ((LinkData *)BM_edgeloop_verts_get(el_store)->first)->data; - - BM_ITER_ELEM (e, &eiter, (BMVert *)v, BM_EDGES_OF_VERT) { - if (BMO_edge_flag_test(bm, e, EDGE_RING)) { - struct BMEdgeLoopStore *el_store_other; - BMVert *v_other = BM_edge_other_vert(e, v); - GHashPair pair_test; - - el_store_other = BLI_ghash_lookup(vert_eloop_gh, v_other); - - /* in rare cases we cant find a match */ - if (el_store_other) { - pair_test.first = el_store; - pair_test.second = el_store_other; - - if (pair_test.first > pair_test.second) { - SWAP(const void *, pair_test.first, pair_test.second); - } - - void **pair_key_p; - if (!BLI_gset_ensure_p_ex(eloop_pair_gs, &pair_test, &pair_key_p)) { - *pair_key_p = BLI_ghashutil_pairalloc(pair_test.first, pair_test.second); - } - } - } - } - } - - BLI_ghash_free(vert_eloop_gh, NULL, NULL); - - if (BLI_gset_len(eloop_pair_gs) == 0) { - BLI_gset_free(eloop_pair_gs, NULL); - eloop_pair_gs = NULL; - } - - return eloop_pair_gs; + /** + * Method for for finding pairs: + * + * - first create (vert -> eloop) mapping. + * - loop over all eloops. + * - take first vertex of the eloop (any vertex will do) + * - loop over all edges of the vertex. + * - use the edge-verts and (vert -> eloop) map + * to create a pair of eloop pointers, add these to a hash. + * + * \note, each loop pair will be found twice. + * could sort and optimize this but not really so important. + */ + + GSet *eloop_pair_gs = BLI_gset_pair_new(__func__); + GHash *vert_eloop_gh = BLI_ghash_ptr_new(__func__); + + struct BMEdgeLoopStore *el_store; + + /* create vert -> eloop map */ + for (el_store = eloops_rim->first; el_store; el_store = BM_EDGELOOP_NEXT(el_store)) { + LinkData *node = BM_edgeloop_verts_get(el_store)->first; + do { + BLI_ghash_insert(vert_eloop_gh, node->data, el_store); + } while ((node = node->next)); + } + + /* collect eloop pairs */ + for (el_store = eloops_rim->first; el_store; el_store = BM_EDGELOOP_NEXT(el_store)) { + BMIter eiter; + BMEdge *e; + + BMVert *v = ((LinkData *)BM_edgeloop_verts_get(el_store)->first)->data; + + BM_ITER_ELEM (e, &eiter, (BMVert *)v, BM_EDGES_OF_VERT) { + if (BMO_edge_flag_test(bm, e, EDGE_RING)) { + struct BMEdgeLoopStore *el_store_other; + BMVert *v_other = BM_edge_other_vert(e, v); + GHashPair pair_test; + + el_store_other = BLI_ghash_lookup(vert_eloop_gh, v_other); + + /* in rare cases we cant find a match */ + if (el_store_other) { + pair_test.first = el_store; + pair_test.second = el_store_other; + + if (pair_test.first > pair_test.second) { + SWAP(const void *, pair_test.first, pair_test.second); + } + + void **pair_key_p; + if (!BLI_gset_ensure_p_ex(eloop_pair_gs, &pair_test, &pair_key_p)) { + *pair_key_p = BLI_ghashutil_pairalloc(pair_test.first, pair_test.second); + } + } + } + } + } + + BLI_ghash_free(vert_eloop_gh, NULL, NULL); + + if (BLI_gset_len(eloop_pair_gs) == 0) { + BLI_gset_free(eloop_pair_gs, NULL); + eloop_pair_gs = NULL; + } + + return eloop_pair_gs; } - /* -------------------------------------------------------------------- */ /* Subdivide an edge 'n' times and return an open edgeloop */ -static void bm_edge_subdiv_as_loop(BMesh *bm, ListBase *eloops, BMEdge *e, BMVert *v_a, const int cuts) +static void bm_edge_subdiv_as_loop( + BMesh *bm, ListBase *eloops, BMEdge *e, BMVert *v_a, const int cuts) { - struct BMEdgeLoopStore *eloop; - BMVert **v_arr = BLI_array_alloca(v_arr, cuts + 2); - BMVert *v_b; - BLI_assert(BM_vert_in_edge(e, v_a)); - - v_b = BM_edge_other_vert(e, v_a); - - BM_edge_split_n(bm, e, cuts, &v_arr[1]); - if (v_a == e->v1) { - v_arr[0] = v_a; - v_arr[cuts + 1] = v_b; - } - else { - v_arr[0] = v_b; - v_arr[cuts + 1] = v_a; - } - - eloop = BM_edgeloop_from_verts(v_arr, cuts + 2, false); - - if (v_a == e->v1) { - BM_edgeloop_flip(bm, eloop); - } - - BLI_addtail(eloops, eloop); + struct BMEdgeLoopStore *eloop; + BMVert **v_arr = BLI_array_alloca(v_arr, cuts + 2); + BMVert *v_b; + BLI_assert(BM_vert_in_edge(e, v_a)); + + v_b = BM_edge_other_vert(e, v_a); + + BM_edge_split_n(bm, e, cuts, &v_arr[1]); + if (v_a == e->v1) { + v_arr[0] = v_a; + v_arr[cuts + 1] = v_b; + } + else { + v_arr[0] = v_b; + v_arr[cuts + 1] = v_a; + } + + eloop = BM_edgeloop_from_verts(v_arr, cuts + 2, false); + + if (v_a == e->v1) { + BM_edgeloop_flip(bm, eloop); + } + + BLI_addtail(eloops, eloop); } - /* -------------------------------------------------------------------- */ /* LoopPair Cache (struct and util funcs) */ - /** * Use for finding spline handle direction from surrounding faces. * @@ -321,64 +319,64 @@ static void bm_edge_subdiv_as_loop(BMesh *bm, ListBase *eloops, BMEdge *e, BMVer */ static void bm_vert_calc_surface_tangent(BMesh *bm, BMVert *v, float r_no[3]) { - BMIter eiter; - BMEdge *e; - - /* get outer normal, fallback to inner (if this vertex is on a boundary) */ - bool found_outer = false, found_inner = false, found_outer_tag = false; - - float no_outer[3] = {0.0f}, no_inner[3] = {0.0f}; - - /* first find rim edges, typically we will only add 2 normals */ - BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (UNLIKELY(BM_edge_is_wire(e))) { - /* pass - this may confuse things */ - } - else if (BMO_edge_flag_test(bm, e, EDGE_RIM)) { - BMIter liter; - BMLoop *l; - BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) { - /* use unmarked (surrounding) faces to create surface tangent */ - float no[3]; - // BM_face_normal_update(l->f); - BM_edge_calc_face_tangent(e, l, no); - if (BMO_face_flag_test(bm, l->f, FACE_SHARED)) { - add_v3_v3(no_inner, no); - found_inner = true; - } - else { - add_v3_v3(no_outer, no); - found_outer = true; - - /* other side is used too, blend midway */ - if (BMO_face_flag_test(bm, l->f, FACE_OUT)) { - found_outer_tag = true; - } - } - } - } - } - - /* detect if this vertex is in-between 2 loops (when blending multiple), - * if so - take both inner and outer into account */ - - if (found_inner && found_outer_tag) { - /* blend between the 2 */ - negate_v3(no_outer); - normalize_v3(no_outer); - normalize_v3(no_inner); - add_v3_v3v3(r_no, no_outer, no_inner); - normalize_v3(r_no); - } - else if (found_outer) { - negate_v3(no_outer); - normalize_v3_v3(r_no, no_outer); - } - else { - /* we always have inner geometry */ - BLI_assert(found_inner == true); - normalize_v3_v3(r_no, no_inner); - } + BMIter eiter; + BMEdge *e; + + /* get outer normal, fallback to inner (if this vertex is on a boundary) */ + bool found_outer = false, found_inner = false, found_outer_tag = false; + + float no_outer[3] = {0.0f}, no_inner[3] = {0.0f}; + + /* first find rim edges, typically we will only add 2 normals */ + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + if (UNLIKELY(BM_edge_is_wire(e))) { + /* pass - this may confuse things */ + } + else if (BMO_edge_flag_test(bm, e, EDGE_RIM)) { + BMIter liter; + BMLoop *l; + BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) { + /* use unmarked (surrounding) faces to create surface tangent */ + float no[3]; + // BM_face_normal_update(l->f); + BM_edge_calc_face_tangent(e, l, no); + if (BMO_face_flag_test(bm, l->f, FACE_SHARED)) { + add_v3_v3(no_inner, no); + found_inner = true; + } + else { + add_v3_v3(no_outer, no); + found_outer = true; + + /* other side is used too, blend midway */ + if (BMO_face_flag_test(bm, l->f, FACE_OUT)) { + found_outer_tag = true; + } + } + } + } + } + + /* detect if this vertex is in-between 2 loops (when blending multiple), + * if so - take both inner and outer into account */ + + if (found_inner && found_outer_tag) { + /* blend between the 2 */ + negate_v3(no_outer); + normalize_v3(no_outer); + normalize_v3(no_inner); + add_v3_v3v3(r_no, no_outer, no_inner); + normalize_v3(r_no); + } + else if (found_outer) { + negate_v3(no_outer); + normalize_v3_v3(r_no, no_outer); + } + else { + /* we always have inner geometry */ + BLI_assert(found_inner == true); + normalize_v3_v3(r_no, no_inner); + } } /** @@ -387,21 +385,21 @@ static void bm_vert_calc_surface_tangent(BMesh *bm, BMVert *v, float r_no[3]) */ static void bm_faces_share_tag_flush(BMesh *bm, BMEdge **e_arr, const uint e_arr_len) { - uint i; - - for (i = 0; i < e_arr_len; i++) { - BMEdge *e = e_arr[i]; - BMLoop *l_iter, *l_first; - - l_iter = l_first = e->l; - do { - if (!BMO_face_flag_test(bm, l_iter->f, FACE_SHARED)) { - if (bmo_face_is_vert_tag_all(bm, l_iter->f, VERT_SHARED)) { - BMO_face_flag_enable(bm, l_iter->f, FACE_SHARED); - } - } - } while ((l_iter = l_iter->radial_next) != l_first); - } + uint i; + + for (i = 0; i < e_arr_len; i++) { + BMEdge *e = e_arr[i]; + BMLoop *l_iter, *l_first; + + l_iter = l_first = e->l; + do { + if (!BMO_face_flag_test(bm, l_iter->f, FACE_SHARED)) { + if (bmo_face_is_vert_tag_all(bm, l_iter->f, VERT_SHARED)) { + BMO_face_flag_enable(bm, l_iter->f, FACE_SHARED); + } + } + } while ((l_iter = l_iter->radial_next) != l_first); + } } /** @@ -409,17 +407,17 @@ static void bm_faces_share_tag_flush(BMesh *bm, BMEdge **e_arr, const uint e_arr */ static void bm_faces_share_tag_clear(BMesh *bm, BMEdge **e_arr_iter, const uint e_arr_len_iter) { - uint i; + uint i; - for (i = 0; i < e_arr_len_iter; i++) { - BMEdge *e = e_arr_iter[i]; - BMLoop *l_iter, *l_first; + for (i = 0; i < e_arr_len_iter; i++) { + BMEdge *e = e_arr_iter[i]; + BMLoop *l_iter, *l_first; - l_iter = l_first = e->l; - do { - BMO_face_flag_disable(bm, l_iter->f, FACE_SHARED); - } while ((l_iter = l_iter->radial_next) != l_first); - } + l_iter = l_first = e->l; + do { + BMO_face_flag_disable(bm, l_iter->f, FACE_SHARED); + } while ((l_iter = l_iter->radial_next) != l_first); + } } /** @@ -430,388 +428,392 @@ static void bm_faces_share_tag_clear(BMesh *bm, BMEdge **e_arr_iter, const uint * but may be extended for other uses. */ typedef struct LoopPairStore { - /* handle array for splines */ - float (*nors_a)[3]; - float (*nors_b)[3]; - - /* since we don't have reliable index values into the array, - * store a map (BMVert -> index) */ - GHash *nors_gh_a; - GHash *nors_gh_b; + /* handle array for splines */ + float (*nors_a)[3]; + float (*nors_b)[3]; + + /* since we don't have reliable index values into the array, + * store a map (BMVert -> index) */ + GHash *nors_gh_a; + GHash *nors_gh_b; } LoopPairStore; -static LoopPairStore *bm_edgering_pair_store_create( - BMesh *bm, - struct BMEdgeLoopStore *el_store_a, - struct BMEdgeLoopStore *el_store_b, - const int interp_mode) +static LoopPairStore *bm_edgering_pair_store_create(BMesh *bm, + struct BMEdgeLoopStore *el_store_a, + struct BMEdgeLoopStore *el_store_b, + const int interp_mode) { - LoopPairStore *lpair = MEM_mallocN(sizeof(*lpair), __func__); - - if (interp_mode == SUBD_RING_INTERP_SURF) { - const uint len_a = BM_edgeloop_length_get(el_store_a); - const uint len_b = BM_edgeloop_length_get(el_store_b); - const uint e_arr_a_len = len_a - (BM_edgeloop_is_closed(el_store_a) ? 0 : 1); - const uint e_arr_b_len = len_b - (BM_edgeloop_is_closed(el_store_b) ? 0 : 1); - BMEdge **e_arr_a = BLI_array_alloca(e_arr_a, e_arr_a_len); - BMEdge **e_arr_b = BLI_array_alloca(e_arr_b, e_arr_b_len); - uint i; - - struct BMEdgeLoopStore *el_store_pair[2] = {el_store_a, el_store_b}; - uint side_index; - float (*nors_pair[2])[3]; - GHash *nors_gh_pair[2]; - - BM_edgeloop_edges_get(el_store_a, e_arr_a); - BM_edgeloop_edges_get(el_store_b, e_arr_b); - - lpair->nors_a = MEM_mallocN(sizeof(*lpair->nors_a) * len_a, __func__); - lpair->nors_b = MEM_mallocN(sizeof(*lpair->nors_b) * len_b, __func__); - - nors_pair[0] = lpair->nors_a; - nors_pair[1] = lpair->nors_b; - - lpair->nors_gh_a = BLI_ghash_ptr_new(__func__); - lpair->nors_gh_b = BLI_ghash_ptr_new(__func__); - - nors_gh_pair[0] = lpair->nors_gh_a; - nors_gh_pair[1] = lpair->nors_gh_b; - - /* now calculate nor */ - - /* all other verts must _not_ be tagged */ - bmo_edgeloop_vert_tag(bm, el_store_a, VERT_SHARED, true); - bmo_edgeloop_vert_tag(bm, el_store_b, VERT_SHARED, true); - - /* tag all faces that are in-between both loops */ - bm_faces_share_tag_flush(bm, e_arr_a, e_arr_a_len); - bm_faces_share_tag_flush(bm, e_arr_b, e_arr_b_len); - - /* now we have all data we need, calculate vertex spline nor! */ - for (side_index = 0; side_index < 2; side_index++) { - /* iter vars */ - struct BMEdgeLoopStore *el_store = el_store_pair[side_index]; - ListBase *lb = BM_edgeloop_verts_get(el_store); - GHash *nors_gh_iter = nors_gh_pair[side_index]; - float (*nor)[3] = nors_pair[side_index]; - - LinkData *v_iter; - - for (v_iter = lb->first, i = 0; v_iter; v_iter = v_iter->next, i++) { - BMVert *v = v_iter->data; - bm_vert_calc_surface_tangent(bm, v, nor[i]); - BLI_ghash_insert(nors_gh_iter, v, POINTER_FROM_UINT(i)); - } - } - - /* cleanup verts share */ - bmo_edgeloop_vert_tag(bm, el_store_a, VERT_SHARED, false); - bmo_edgeloop_vert_tag(bm, el_store_b, VERT_SHARED, false); - - /* cleanup faces share */ - bm_faces_share_tag_clear(bm, e_arr_a, e_arr_a_len); - bm_faces_share_tag_clear(bm, e_arr_b, e_arr_b_len); - } - return lpair; + LoopPairStore *lpair = MEM_mallocN(sizeof(*lpair), __func__); + + if (interp_mode == SUBD_RING_INTERP_SURF) { + const uint len_a = BM_edgeloop_length_get(el_store_a); + const uint len_b = BM_edgeloop_length_get(el_store_b); + const uint e_arr_a_len = len_a - (BM_edgeloop_is_closed(el_store_a) ? 0 : 1); + const uint e_arr_b_len = len_b - (BM_edgeloop_is_closed(el_store_b) ? 0 : 1); + BMEdge **e_arr_a = BLI_array_alloca(e_arr_a, e_arr_a_len); + BMEdge **e_arr_b = BLI_array_alloca(e_arr_b, e_arr_b_len); + uint i; + + struct BMEdgeLoopStore *el_store_pair[2] = {el_store_a, el_store_b}; + uint side_index; + float(*nors_pair[2])[3]; + GHash *nors_gh_pair[2]; + + BM_edgeloop_edges_get(el_store_a, e_arr_a); + BM_edgeloop_edges_get(el_store_b, e_arr_b); + + lpair->nors_a = MEM_mallocN(sizeof(*lpair->nors_a) * len_a, __func__); + lpair->nors_b = MEM_mallocN(sizeof(*lpair->nors_b) * len_b, __func__); + + nors_pair[0] = lpair->nors_a; + nors_pair[1] = lpair->nors_b; + + lpair->nors_gh_a = BLI_ghash_ptr_new(__func__); + lpair->nors_gh_b = BLI_ghash_ptr_new(__func__); + + nors_gh_pair[0] = lpair->nors_gh_a; + nors_gh_pair[1] = lpair->nors_gh_b; + + /* now calculate nor */ + + /* all other verts must _not_ be tagged */ + bmo_edgeloop_vert_tag(bm, el_store_a, VERT_SHARED, true); + bmo_edgeloop_vert_tag(bm, el_store_b, VERT_SHARED, true); + + /* tag all faces that are in-between both loops */ + bm_faces_share_tag_flush(bm, e_arr_a, e_arr_a_len); + bm_faces_share_tag_flush(bm, e_arr_b, e_arr_b_len); + + /* now we have all data we need, calculate vertex spline nor! */ + for (side_index = 0; side_index < 2; side_index++) { + /* iter vars */ + struct BMEdgeLoopStore *el_store = el_store_pair[side_index]; + ListBase *lb = BM_edgeloop_verts_get(el_store); + GHash *nors_gh_iter = nors_gh_pair[side_index]; + float(*nor)[3] = nors_pair[side_index]; + + LinkData *v_iter; + + for (v_iter = lb->first, i = 0; v_iter; v_iter = v_iter->next, i++) { + BMVert *v = v_iter->data; + bm_vert_calc_surface_tangent(bm, v, nor[i]); + BLI_ghash_insert(nors_gh_iter, v, POINTER_FROM_UINT(i)); + } + } + + /* cleanup verts share */ + bmo_edgeloop_vert_tag(bm, el_store_a, VERT_SHARED, false); + bmo_edgeloop_vert_tag(bm, el_store_b, VERT_SHARED, false); + + /* cleanup faces share */ + bm_faces_share_tag_clear(bm, e_arr_a, e_arr_a_len); + bm_faces_share_tag_clear(bm, e_arr_b, e_arr_b_len); + } + return lpair; } -static void bm_edgering_pair_store_free( - LoopPairStore *lpair, - const int interp_mode) +static void bm_edgering_pair_store_free(LoopPairStore *lpair, const int interp_mode) { - if (interp_mode == SUBD_RING_INTERP_SURF) { - MEM_freeN(lpair->nors_a); - MEM_freeN(lpair->nors_b); - - BLI_ghash_free(lpair->nors_gh_a, NULL, NULL); - BLI_ghash_free(lpair->nors_gh_b, NULL, NULL); - } - MEM_freeN(lpair); + if (interp_mode == SUBD_RING_INTERP_SURF) { + MEM_freeN(lpair->nors_a); + MEM_freeN(lpair->nors_b); + + BLI_ghash_free(lpair->nors_gh_a, NULL, NULL); + BLI_ghash_free(lpair->nors_gh_b, NULL, NULL); + } + MEM_freeN(lpair); } - /* -------------------------------------------------------------------- */ /* Interpolation Function */ -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_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) { - const int resolu = cuts + 2; - const int dims = 3; - bool is_a_no_valid, is_b_no_valid; - int i; - - float el_store_a_co[3], el_store_b_co[3]; - float el_store_a_no[3], el_store_b_no[3]; - - struct BMEdgeLoopStore *el_store_ring; - - float (*coord_array_main)[3] = NULL; - - BM_edgeloop_calc_center(bm, el_store_a); - BM_edgeloop_calc_center(bm, el_store_b); - - is_a_no_valid = BM_edgeloop_calc_normal(bm, el_store_a); - is_b_no_valid = BM_edgeloop_calc_normal(bm, el_store_b); - - copy_v3_v3(el_store_a_co, BM_edgeloop_center_get(el_store_a)); - copy_v3_v3(el_store_b_co, BM_edgeloop_center_get(el_store_b)); - - /* correct normals need to be flipped to face each other - * we know both normals point in the same direction so one will need flipping */ - { - float el_dir[3]; - float no[3]; - sub_v3_v3v3(el_dir, el_store_a_co, el_store_b_co); - normalize_v3_v3(no, el_dir); - - if (is_a_no_valid == false) { - is_a_no_valid = BM_edgeloop_calc_normal_aligned(bm, el_store_a, no); - } - if (is_b_no_valid == false) { - is_b_no_valid = BM_edgeloop_calc_normal_aligned(bm, el_store_b, no); - } - (void)is_a_no_valid, (void)is_b_no_valid; - - copy_v3_v3(el_store_a_no, BM_edgeloop_normal_get(el_store_a)); - copy_v3_v3(el_store_b_no, BM_edgeloop_normal_get(el_store_b)); - - if (dot_v3v3(el_store_a_no, el_dir) > 0.0f) { - negate_v3(el_store_a_no); - } - if (dot_v3v3(el_store_b_no, el_dir) < 0.0f) { - negate_v3(el_store_b_no); - } - - } - /* now normals are correct, don't touch! */ - - - /* calculate the center spline, multiple */ - if ((interp_mode == SUBD_RING_INTERP_PATH) || falloff_cache) { - float handle_a[3], handle_b[3]; - float handle_len; - - handle_len = bezier_handle_calc_length_v3(el_store_a_co, el_store_a_no, - el_store_b_co, el_store_b_no) * smooth; - - mul_v3_v3fl(handle_a, el_store_a_no, handle_len); - mul_v3_v3fl(handle_b, el_store_b_no, handle_len); - - add_v3_v3(handle_a, el_store_a_co); - add_v3_v3(handle_b, el_store_b_co); - - coord_array_main = MEM_mallocN(dims * (resolu) * sizeof(float), __func__); - - for (i = 0; i < dims; i++) { - BKE_curve_forward_diff_bezier(el_store_a_co[i], handle_a[i], handle_b[i], el_store_b_co[i], - ((float *)coord_array_main) + i, resolu - 1, sizeof(float) * dims); - } - } - - switch (interp_mode) { - case SUBD_RING_INTERP_LINEAR: - { - if (falloff_cache) { - float (*coord_array)[3] = MEM_mallocN(dims * (resolu) * sizeof(float), __func__); - for (i = 0; i < resolu; i++) { - interp_v3_v3v3(coord_array[i], el_store_a_co, el_store_b_co, (float)i / (float)(resolu - 1)); - } - - for (el_store_ring = eloops_ring->first; - el_store_ring; - el_store_ring = BM_EDGELOOP_NEXT(el_store_ring)) - { - ListBase *lb_ring = BM_edgeloop_verts_get(el_store_ring); - LinkData *v_iter; - - for (v_iter = lb_ring->first, i = 0; v_iter; v_iter = v_iter->next, i++) { - if (i > 0 && i < resolu - 1) { - /* shape */ - if (falloff_cache) { - interp_v3_v3v3(((BMVert *)v_iter->data)->co, - coord_array[i], ((BMVert *)v_iter->data)->co, falloff_cache[i]); - } - } - } - } - - MEM_freeN(coord_array); - - } - - break; - } - case SUBD_RING_INTERP_PATH: - { - float (*direction_array)[3] = MEM_mallocN(dims * (resolu) * sizeof(float), __func__); - float (*quat_array)[4] = MEM_mallocN(resolu * sizeof(*quat_array), __func__); - float (*tri_array)[3][3] = MEM_mallocN(resolu * sizeof(*tri_array), __func__); - float (*tri_sta)[3], (*tri_end)[3], (*tri_tmp)[3]; - - /* very similar to make_bevel_list_3D_minimum_twist */ - - /* calculate normals */ - copy_v3_v3(direction_array[0], el_store_a_no); - negate_v3_v3(direction_array[resolu - 1], el_store_b_no); - for (i = 1; i < resolu - 1; i++) { - bisect_v3_v3v3v3(direction_array[i], - coord_array_main[i - 1], coord_array_main[i], coord_array_main[i + 1]); - } - - vec_to_quat(quat_array[0], direction_array[0], 5, 1); - normalize_qt(quat_array[0]); - - for (i = 1; i < resolu; i++) { - float angle = angle_normalized_v3v3(direction_array[i - 1], direction_array[i]); - // BLI_assert(angle < DEG2RADF(90.0f)); - if (angle > 0.0f) { /* otherwise we can keep as is */ - float cross_tmp[3]; - float q[4]; - cross_v3_v3v3(cross_tmp, direction_array[i - 1], direction_array[i]); - axis_angle_to_quat(q, cross_tmp, angle); - mul_qt_qtqt(quat_array[i], q, quat_array[i - 1]); - normalize_qt(quat_array[i]); - } - else { - copy_qt_qt(quat_array[i], quat_array[i - 1]); - } - } - - /* init base tri */ - for (i = 0; i < resolu; i++) { - int j; - - const float shape_size = falloff_cache ? falloff_cache[i] : 1.0f; - - tri_tmp = tri_array[i]; - - /* create the triangle and transform */ - for (j = 0; j < 3; j++) { - zero_v3(tri_tmp[j]); - if (j == 1) { tri_tmp[j][0] = shape_size; } - else if (j == 2) { tri_tmp[j][1] = shape_size; } - mul_qt_v3(quat_array[i], tri_tmp[j]); - add_v3_v3(tri_tmp[j], coord_array_main[i]); - } - } - - tri_sta = tri_array[0]; - tri_end = tri_array[resolu - 1]; - - for (el_store_ring = eloops_ring->first; - el_store_ring; - el_store_ring = BM_EDGELOOP_NEXT(el_store_ring)) - { - ListBase *lb_ring = BM_edgeloop_verts_get(el_store_ring); - LinkData *v_iter; - - BMVert *v_a = ((LinkData *)lb_ring->first)->data; - BMVert *v_b = ((LinkData *)lb_ring->last)->data; - - /* skip first and last */ - for (v_iter = ((LinkData *)lb_ring->first)->next, i = 1; - v_iter != lb_ring->last; - v_iter = v_iter->next, i++) - { - float co_a[3], co_b[3]; - - tri_tmp = tri_array[i]; - - transform_point_by_tri_v3(co_a, v_a->co, UNPACK3(tri_tmp), UNPACK3(tri_sta)); - transform_point_by_tri_v3(co_b, v_b->co, UNPACK3(tri_tmp), UNPACK3(tri_end)); - - interp_v3_v3v3(((BMVert *)v_iter->data)->co, co_a, co_b, (float)i / (float)(resolu - 1)); - } - } - - MEM_freeN(direction_array); - MEM_freeN(quat_array); - MEM_freeN(tri_array); - break; - } - case SUBD_RING_INTERP_SURF: - { - float (*coord_array)[3] = MEM_mallocN(dims * (resolu) * sizeof(float), __func__); - - /* calculate a bezier handle per edge ring */ - for (el_store_ring = eloops_ring->first; - el_store_ring; - el_store_ring = BM_EDGELOOP_NEXT(el_store_ring)) - { - ListBase *lb_ring = BM_edgeloop_verts_get(el_store_ring); - LinkData *v_iter; - - BMVert *v_a = ((LinkData *)lb_ring->first)->data; - BMVert *v_b = ((LinkData *)lb_ring->last)->data; - - float co_a[3], no_a[3], handle_a[3], co_b[3], no_b[3], handle_b[3]; - float handle_len; - - copy_v3_v3(co_a, v_a->co); - copy_v3_v3(co_b, v_b->co); - - /* don't calculate normals here else we get into feedback loop - * when subdividing 2+ connected edge rings */ + const int resolu = cuts + 2; + const int dims = 3; + bool is_a_no_valid, is_b_no_valid; + int i; + + float el_store_a_co[3], el_store_b_co[3]; + float el_store_a_no[3], el_store_b_no[3]; + + struct BMEdgeLoopStore *el_store_ring; + + float(*coord_array_main)[3] = NULL; + + BM_edgeloop_calc_center(bm, el_store_a); + BM_edgeloop_calc_center(bm, el_store_b); + + is_a_no_valid = BM_edgeloop_calc_normal(bm, el_store_a); + is_b_no_valid = BM_edgeloop_calc_normal(bm, el_store_b); + + copy_v3_v3(el_store_a_co, BM_edgeloop_center_get(el_store_a)); + copy_v3_v3(el_store_b_co, BM_edgeloop_center_get(el_store_b)); + + /* correct normals need to be flipped to face each other + * we know both normals point in the same direction so one will need flipping */ + { + float el_dir[3]; + float no[3]; + sub_v3_v3v3(el_dir, el_store_a_co, el_store_b_co); + normalize_v3_v3(no, el_dir); + + if (is_a_no_valid == false) { + is_a_no_valid = BM_edgeloop_calc_normal_aligned(bm, el_store_a, no); + } + if (is_b_no_valid == false) { + is_b_no_valid = BM_edgeloop_calc_normal_aligned(bm, el_store_b, no); + } + (void)is_a_no_valid, (void)is_b_no_valid; + + copy_v3_v3(el_store_a_no, BM_edgeloop_normal_get(el_store_a)); + copy_v3_v3(el_store_b_no, BM_edgeloop_normal_get(el_store_b)); + + if (dot_v3v3(el_store_a_no, el_dir) > 0.0f) { + negate_v3(el_store_a_no); + } + if (dot_v3v3(el_store_b_no, el_dir) < 0.0f) { + negate_v3(el_store_b_no); + } + } + /* now normals are correct, don't touch! */ + + /* calculate the center spline, multiple */ + if ((interp_mode == SUBD_RING_INTERP_PATH) || falloff_cache) { + float handle_a[3], handle_b[3]; + float handle_len; + + handle_len = bezier_handle_calc_length_v3( + el_store_a_co, el_store_a_no, el_store_b_co, el_store_b_no) * + smooth; + + mul_v3_v3fl(handle_a, el_store_a_no, handle_len); + mul_v3_v3fl(handle_b, el_store_b_no, handle_len); + + add_v3_v3(handle_a, el_store_a_co); + add_v3_v3(handle_b, el_store_b_co); + + coord_array_main = MEM_mallocN(dims * (resolu) * sizeof(float), __func__); + + for (i = 0; i < dims; i++) { + BKE_curve_forward_diff_bezier(el_store_a_co[i], + handle_a[i], + handle_b[i], + el_store_b_co[i], + ((float *)coord_array_main) + i, + resolu - 1, + sizeof(float) * dims); + } + } + + switch (interp_mode) { + case SUBD_RING_INTERP_LINEAR: { + if (falloff_cache) { + float(*coord_array)[3] = MEM_mallocN(dims * (resolu) * sizeof(float), __func__); + for (i = 0; i < resolu; i++) { + interp_v3_v3v3( + coord_array[i], el_store_a_co, el_store_b_co, (float)i / (float)(resolu - 1)); + } + + for (el_store_ring = eloops_ring->first; el_store_ring; + el_store_ring = BM_EDGELOOP_NEXT(el_store_ring)) { + ListBase *lb_ring = BM_edgeloop_verts_get(el_store_ring); + LinkData *v_iter; + + for (v_iter = lb_ring->first, i = 0; v_iter; v_iter = v_iter->next, i++) { + if (i > 0 && i < resolu - 1) { + /* shape */ + if (falloff_cache) { + interp_v3_v3v3(((BMVert *)v_iter->data)->co, + coord_array[i], + ((BMVert *)v_iter->data)->co, + falloff_cache[i]); + } + } + } + } + + MEM_freeN(coord_array); + } + + break; + } + case SUBD_RING_INTERP_PATH: { + float(*direction_array)[3] = MEM_mallocN(dims * (resolu) * sizeof(float), __func__); + float(*quat_array)[4] = MEM_mallocN(resolu * sizeof(*quat_array), __func__); + float(*tri_array)[3][3] = MEM_mallocN(resolu * sizeof(*tri_array), __func__); + float(*tri_sta)[3], (*tri_end)[3], (*tri_tmp)[3]; + + /* very similar to make_bevel_list_3D_minimum_twist */ + + /* calculate normals */ + copy_v3_v3(direction_array[0], el_store_a_no); + negate_v3_v3(direction_array[resolu - 1], el_store_b_no); + for (i = 1; i < resolu - 1; i++) { + bisect_v3_v3v3v3(direction_array[i], + coord_array_main[i - 1], + coord_array_main[i], + coord_array_main[i + 1]); + } + + vec_to_quat(quat_array[0], direction_array[0], 5, 1); + normalize_qt(quat_array[0]); + + for (i = 1; i < resolu; i++) { + float angle = angle_normalized_v3v3(direction_array[i - 1], direction_array[i]); + // BLI_assert(angle < DEG2RADF(90.0f)); + if (angle > 0.0f) { /* otherwise we can keep as is */ + float cross_tmp[3]; + float q[4]; + cross_v3_v3v3(cross_tmp, direction_array[i - 1], direction_array[i]); + axis_angle_to_quat(q, cross_tmp, angle); + mul_qt_qtqt(quat_array[i], q, quat_array[i - 1]); + normalize_qt(quat_array[i]); + } + else { + copy_qt_qt(quat_array[i], quat_array[i - 1]); + } + } + + /* init base tri */ + for (i = 0; i < resolu; i++) { + int j; + + const float shape_size = falloff_cache ? falloff_cache[i] : 1.0f; + + tri_tmp = tri_array[i]; + + /* create the triangle and transform */ + for (j = 0; j < 3; j++) { + zero_v3(tri_tmp[j]); + if (j == 1) { + tri_tmp[j][0] = shape_size; + } + else if (j == 2) { + tri_tmp[j][1] = shape_size; + } + mul_qt_v3(quat_array[i], tri_tmp[j]); + add_v3_v3(tri_tmp[j], coord_array_main[i]); + } + } + + tri_sta = tri_array[0]; + tri_end = tri_array[resolu - 1]; + + for (el_store_ring = eloops_ring->first; el_store_ring; + el_store_ring = BM_EDGELOOP_NEXT(el_store_ring)) { + ListBase *lb_ring = BM_edgeloop_verts_get(el_store_ring); + LinkData *v_iter; + + BMVert *v_a = ((LinkData *)lb_ring->first)->data; + BMVert *v_b = ((LinkData *)lb_ring->last)->data; + + /* skip first and last */ + for (v_iter = ((LinkData *)lb_ring->first)->next, i = 1; v_iter != lb_ring->last; + v_iter = v_iter->next, i++) { + float co_a[3], co_b[3]; + + tri_tmp = tri_array[i]; + + transform_point_by_tri_v3(co_a, v_a->co, UNPACK3(tri_tmp), UNPACK3(tri_sta)); + transform_point_by_tri_v3(co_b, v_b->co, UNPACK3(tri_tmp), UNPACK3(tri_end)); + + interp_v3_v3v3(((BMVert *)v_iter->data)->co, co_a, co_b, (float)i / (float)(resolu - 1)); + } + } + + MEM_freeN(direction_array); + MEM_freeN(quat_array); + MEM_freeN(tri_array); + break; + } + case SUBD_RING_INTERP_SURF: { + float(*coord_array)[3] = MEM_mallocN(dims * (resolu) * sizeof(float), __func__); + + /* calculate a bezier handle per edge ring */ + for (el_store_ring = eloops_ring->first; el_store_ring; + el_store_ring = BM_EDGELOOP_NEXT(el_store_ring)) { + ListBase *lb_ring = BM_edgeloop_verts_get(el_store_ring); + LinkData *v_iter; + + BMVert *v_a = ((LinkData *)lb_ring->first)->data; + BMVert *v_b = ((LinkData *)lb_ring->last)->data; + + float co_a[3], no_a[3], handle_a[3], co_b[3], no_b[3], handle_b[3]; + float handle_len; + + copy_v3_v3(co_a, v_a->co); + copy_v3_v3(co_b, v_b->co); + + /* don't calculate normals here else we get into feedback loop + * when subdividing 2+ connected edge rings */ #if 0 - bm_vert_calc_surface_tangent(bm, v_a, no_a); - bm_vert_calc_surface_tangent(bm, v_b, no_b); + bm_vert_calc_surface_tangent(bm, v_a, no_a); + bm_vert_calc_surface_tangent(bm, v_b, no_b); #else - { - const uint index_a = POINTER_AS_UINT(BLI_ghash_lookup(lpair->nors_gh_a, v_a)); - const uint index_b = POINTER_AS_UINT(BLI_ghash_lookup(lpair->nors_gh_b, v_b)); + { + const uint index_a = POINTER_AS_UINT(BLI_ghash_lookup(lpair->nors_gh_a, v_a)); + const uint index_b = POINTER_AS_UINT(BLI_ghash_lookup(lpair->nors_gh_b, v_b)); - BLI_assert(BLI_ghash_haskey(lpair->nors_gh_a, v_a)); - BLI_assert(BLI_ghash_haskey(lpair->nors_gh_b, v_b)); + BLI_assert(BLI_ghash_haskey(lpair->nors_gh_a, v_a)); + BLI_assert(BLI_ghash_haskey(lpair->nors_gh_b, v_b)); - copy_v3_v3(no_a, lpair->nors_a[index_a]); - copy_v3_v3(no_b, lpair->nors_b[index_b]); - } + copy_v3_v3(no_a, lpair->nors_a[index_a]); + copy_v3_v3(no_b, lpair->nors_b[index_b]); + } #endif - handle_len = bezier_handle_calc_length_v3(co_a, no_a, co_b, no_b) * smooth; - - mul_v3_v3fl(handle_a, no_a, handle_len); - mul_v3_v3fl(handle_b, no_b, handle_len); - - add_v3_v3(handle_a, co_a); - add_v3_v3(handle_b, co_b); - - for (i = 0; i < dims; i++) { - BKE_curve_forward_diff_bezier(co_a[i], handle_a[i], handle_b[i], co_b[i], - ((float *)coord_array) + i, resolu - 1, sizeof(float) * dims); - } - - /* skip first and last */ - for (v_iter = ((LinkData *)lb_ring->first)->next, i = 1; - v_iter != lb_ring->last; - v_iter = v_iter->next, i++) - { - if (i > 0 && i < resolu - 1) { - copy_v3_v3(((BMVert *)v_iter->data)->co, coord_array[i]); - - /* shape */ - if (falloff_cache) { - interp_v3_v3v3(((BMVert *)v_iter->data)->co, - coord_array_main[i], ((BMVert *)v_iter->data)->co, falloff_cache[i]); - } - } - } - } - - MEM_freeN(coord_array); - - break; - } - } - - if (coord_array_main) { - MEM_freeN(coord_array_main); - } + handle_len = bezier_handle_calc_length_v3(co_a, no_a, co_b, no_b) * smooth; + + mul_v3_v3fl(handle_a, no_a, handle_len); + mul_v3_v3fl(handle_b, no_b, handle_len); + + add_v3_v3(handle_a, co_a); + add_v3_v3(handle_b, co_b); + + for (i = 0; i < dims; i++) { + BKE_curve_forward_diff_bezier(co_a[i], + handle_a[i], + handle_b[i], + co_b[i], + ((float *)coord_array) + i, + resolu - 1, + sizeof(float) * dims); + } + + /* skip first and last */ + for (v_iter = ((LinkData *)lb_ring->first)->next, i = 1; v_iter != lb_ring->last; + v_iter = v_iter->next, i++) { + if (i > 0 && i < resolu - 1) { + copy_v3_v3(((BMVert *)v_iter->data)->co, coord_array[i]); + + /* shape */ + if (falloff_cache) { + interp_v3_v3v3(((BMVert *)v_iter->data)->co, + coord_array_main[i], + ((BMVert *)v_iter->data)->co, + falloff_cache[i]); + } + } + } + } + + MEM_freeN(coord_array); + + break; + } + } + + if (coord_array_main) { + MEM_freeN(coord_array_main); + } } /** @@ -819,418 +821,410 @@ static void bm_edgering_pair_interpolate( */ static void bm_face_slice(BMesh *bm, BMLoop *l, const int cuts) { - /* TODO, interpolate edge data */ - BMLoop *l_new = l; - int i; - - for (i = 0; i < cuts; i++) { - /* no chance of double */ - BM_face_split(bm, l_new->f, l_new->prev, l_new->next->next, &l_new, NULL, false); - if (l_new->f->len < l_new->radial_next->f->len) { - l_new = l_new->radial_next; - } - BMO_face_flag_enable(bm, l_new->f, FACE_OUT); - BMO_face_flag_enable(bm, l_new->radial_next->f, FACE_OUT); - } + /* TODO, interpolate edge data */ + BMLoop *l_new = l; + int i; + + for (i = 0; i < cuts; i++) { + /* no chance of double */ + BM_face_split(bm, l_new->f, l_new->prev, l_new->next->next, &l_new, NULL, false); + if (l_new->f->len < l_new->radial_next->f->len) { + l_new = l_new->radial_next; + } + BMO_face_flag_enable(bm, l_new->f, FACE_OUT); + BMO_face_flag_enable(bm, l_new->radial_next->f, FACE_OUT); + } } static bool bm_edgering_pair_order_is_flipped(BMesh *UNUSED(bm), struct BMEdgeLoopStore *el_store_a, - struct BMEdgeLoopStore *el_store_b ) + struct BMEdgeLoopStore *el_store_b) { - ListBase *lb_a = BM_edgeloop_verts_get(el_store_a); - ListBase *lb_b = BM_edgeloop_verts_get(el_store_b); - - LinkData *v_iter_a_first = lb_a->first; - LinkData *v_iter_b_first = lb_b->first; - - LinkData *v_iter_a_step = v_iter_a_first; - LinkData *v_iter_b_step = v_iter_b_first; - - /* we _must_ have same starting edge shared */ - BLI_assert(BM_edge_exists(v_iter_a_first->data, v_iter_b_first->data)); - - /* step around any fan-faces on both sides */ - do { - v_iter_a_step = v_iter_a_step->next; - } while (v_iter_a_step && - ((BM_edge_exists(v_iter_a_step->data, v_iter_b_first->data)) || - (BM_edge_exists(v_iter_a_step->data, v_iter_b_first->next->data)))); - do { - v_iter_b_step = v_iter_b_step->next; - } while (v_iter_b_step && - ((BM_edge_exists(v_iter_b_step->data, v_iter_a_first->data)) || - (BM_edge_exists(v_iter_b_step->data, v_iter_a_first->next->data)))); - - v_iter_a_step = v_iter_a_step ? v_iter_a_step->prev : lb_a->last; - v_iter_b_step = v_iter_b_step ? v_iter_b_step->prev : lb_b->last; - - return !(BM_edge_exists(v_iter_a_step->data, v_iter_b_step->data) || - BM_edge_exists(v_iter_a_first->next->data, v_iter_b_step->data) || - BM_edge_exists(v_iter_b_first->next->data, v_iter_a_step->data)); + ListBase *lb_a = BM_edgeloop_verts_get(el_store_a); + ListBase *lb_b = BM_edgeloop_verts_get(el_store_b); + + LinkData *v_iter_a_first = lb_a->first; + LinkData *v_iter_b_first = lb_b->first; + + LinkData *v_iter_a_step = v_iter_a_first; + LinkData *v_iter_b_step = v_iter_b_first; + + /* we _must_ have same starting edge shared */ + BLI_assert(BM_edge_exists(v_iter_a_first->data, v_iter_b_first->data)); + + /* step around any fan-faces on both sides */ + do { + v_iter_a_step = v_iter_a_step->next; + } while (v_iter_a_step && ((BM_edge_exists(v_iter_a_step->data, v_iter_b_first->data)) || + (BM_edge_exists(v_iter_a_step->data, v_iter_b_first->next->data)))); + do { + v_iter_b_step = v_iter_b_step->next; + } while (v_iter_b_step && ((BM_edge_exists(v_iter_b_step->data, v_iter_a_first->data)) || + (BM_edge_exists(v_iter_b_step->data, v_iter_a_first->next->data)))); + + v_iter_a_step = v_iter_a_step ? v_iter_a_step->prev : lb_a->last; + v_iter_b_step = v_iter_b_step ? v_iter_b_step->prev : lb_b->last; + + return !(BM_edge_exists(v_iter_a_step->data, v_iter_b_step->data) || + BM_edge_exists(v_iter_a_first->next->data, v_iter_b_step->data) || + BM_edge_exists(v_iter_b_first->next->data, v_iter_a_step->data)); } /** * Takes 2 edge loops that share edges, * sort their verts and rotates the list so the lined up. */ -static void bm_edgering_pair_order( - BMesh *bm, - struct BMEdgeLoopStore *el_store_a, - struct BMEdgeLoopStore *el_store_b) +static void bm_edgering_pair_order(BMesh *bm, + struct BMEdgeLoopStore *el_store_a, + struct BMEdgeLoopStore *el_store_b) { - ListBase *lb_a = BM_edgeloop_verts_get(el_store_a); - ListBase *lb_b = BM_edgeloop_verts_get(el_store_b); - - LinkData *node; - - bm_edgeloop_vert_tag(el_store_a, false); - bm_edgeloop_vert_tag(el_store_b, true); - - /* before going much further, get ourselves in order - * - align loops (not strictly necessary but handy) - * - ensure winding is set for both loops */ - if (BM_edgeloop_is_closed(el_store_a) && BM_edgeloop_is_closed(el_store_b)) { - BMIter eiter; - BMEdge *e; - BMVert *v_other; - - node = lb_a->first; - - BM_ITER_ELEM (e, &eiter, (BMVert *)node->data, BM_EDGES_OF_VERT) { - if (BMO_edge_flag_test(bm, e, EDGE_RING)) { - v_other = BM_edge_other_vert(e, (BMVert *)node->data); - if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) { - break; - } - else { - v_other = NULL; - } - } - } - BLI_assert(v_other != NULL); - - for (node = lb_b->first; node; node = node->next) { - if (node->data == v_other) { - break; - } - } - BLI_assert(node != NULL); - - BLI_listbase_rotate_first(lb_b, node); - - /* now check we are winding the same way */ - if (bm_edgering_pair_order_is_flipped(bm, el_store_a, el_store_b)) { - BM_edgeloop_flip(bm, el_store_b); - /* re-ensure the first node */ - BLI_listbase_rotate_first(lb_b, node); - } - - /* sanity checks that we are aligned & winding now */ - BLI_assert(bm_edgering_pair_order_is_flipped(bm, el_store_a, el_store_b) == false); - } - else { - /* if we dont share and edge - flip */ - BMEdge *e = BM_edge_exists(((LinkData *)lb_a->first)->data, - ((LinkData *)lb_b->first)->data); - if (e == NULL || !BMO_edge_flag_test(bm, e, EDGE_RING)) { - BM_edgeloop_flip(bm, el_store_b); - } - } - - /* for cases with multiple loops */ - bm_edgeloop_vert_tag(el_store_b, false); + ListBase *lb_a = BM_edgeloop_verts_get(el_store_a); + ListBase *lb_b = BM_edgeloop_verts_get(el_store_b); + + LinkData *node; + + bm_edgeloop_vert_tag(el_store_a, false); + bm_edgeloop_vert_tag(el_store_b, true); + + /* before going much further, get ourselves in order + * - align loops (not strictly necessary but handy) + * - ensure winding is set for both loops */ + if (BM_edgeloop_is_closed(el_store_a) && BM_edgeloop_is_closed(el_store_b)) { + BMIter eiter; + BMEdge *e; + BMVert *v_other; + + node = lb_a->first; + + BM_ITER_ELEM (e, &eiter, (BMVert *)node->data, BM_EDGES_OF_VERT) { + if (BMO_edge_flag_test(bm, e, EDGE_RING)) { + v_other = BM_edge_other_vert(e, (BMVert *)node->data); + if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) { + break; + } + else { + v_other = NULL; + } + } + } + BLI_assert(v_other != NULL); + + for (node = lb_b->first; node; node = node->next) { + if (node->data == v_other) { + break; + } + } + BLI_assert(node != NULL); + + BLI_listbase_rotate_first(lb_b, node); + + /* now check we are winding the same way */ + if (bm_edgering_pair_order_is_flipped(bm, el_store_a, el_store_b)) { + BM_edgeloop_flip(bm, el_store_b); + /* re-ensure the first node */ + BLI_listbase_rotate_first(lb_b, node); + } + + /* sanity checks that we are aligned & winding now */ + BLI_assert(bm_edgering_pair_order_is_flipped(bm, el_store_a, el_store_b) == false); + } + else { + /* if we dont share and edge - flip */ + BMEdge *e = BM_edge_exists(((LinkData *)lb_a->first)->data, ((LinkData *)lb_b->first)->data); + if (e == NULL || !BMO_edge_flag_test(bm, e, EDGE_RING)) { + BM_edgeloop_flip(bm, el_store_b); + } + } + + /* for cases with multiple loops */ + bm_edgeloop_vert_tag(el_store_b, false); } - /** * Take 2 edge loops, do a subdivision on connecting edges. * * \note loops are _not_ aligned. */ -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 void bm_edgering_pair_subdiv(BMesh *bm, + struct BMEdgeLoopStore *el_store_a, + struct BMEdgeLoopStore *el_store_b, + ListBase *eloops_ring, + const int cuts) { - ListBase *lb_a = BM_edgeloop_verts_get(el_store_a); - // ListBase *lb_b = BM_edgeloop_verts_get(el_store_b); - const int stack_max = max_ii(BM_edgeloop_length_get(el_store_a), - BM_edgeloop_length_get(el_store_b)) * 2; - BMEdge **edges_ring_arr = BLI_array_alloca(edges_ring_arr, stack_max); - BMFace **faces_ring_arr = BLI_array_alloca(faces_ring_arr, stack_max); - STACK_DECLARE(edges_ring_arr); - STACK_DECLARE(faces_ring_arr); - struct BMEdgeLoopStore *el_store_ring; - LinkData *node; - BMEdge *e; - BMFace *f; - - STACK_INIT(edges_ring_arr, stack_max); - STACK_INIT(faces_ring_arr, stack_max); - - bm_edgeloop_vert_tag(el_store_a, false); - bm_edgeloop_vert_tag(el_store_b, true); - - for (node = lb_a->first; node; node = node->next) { - BMIter eiter; - - BM_ITER_ELEM (e, &eiter, (BMVert *)node->data, BM_EDGES_OF_VERT) { - if (!BMO_edge_flag_test(bm, e, EDGE_IN_STACK)) { - BMVert *v_other = BM_edge_other_vert(e, (BMVert *)node->data); - if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) { - BMIter fiter; - - BMO_edge_flag_enable(bm, e, EDGE_IN_STACK); - STACK_PUSH(edges_ring_arr, e); - - /* add faces to the stack */ - BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { - if (BMO_face_flag_test(bm, f, FACE_OUT)) { - if (!BMO_face_flag_test(bm, f, FACE_IN_STACK)) { - BMO_face_flag_enable(bm, f, FACE_IN_STACK); - STACK_PUSH(faces_ring_arr, f); - } - } - } - } - } - } - } - - while ((e = STACK_POP(edges_ring_arr))) { - /* found opposite edge */ - BMVert *v_other; - - BMO_edge_flag_disable(bm, e, EDGE_IN_STACK); - - /* unrelated to subdiv, but if we _don't_ clear flag, multiple rings fail */ - BMO_edge_flag_disable(bm, e, EDGE_RING); - - v_other = BM_elem_flag_test(e->v1, BM_ELEM_TAG) ? e->v1 : e->v2; - bm_edge_subdiv_as_loop(bm, eloops_ring, e, v_other, cuts); - } - - while ((f = STACK_POP(faces_ring_arr))) { - BMLoop *l_iter, *l_first; - - BMO_face_flag_disable(bm, f, FACE_IN_STACK); - - /* Check each edge of the face */ - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - if (BMO_edge_flag_test(bm, l_iter->e, EDGE_RIM)) { - bm_face_slice(bm, l_iter, cuts); - break; - } - } while ((l_iter = l_iter->next) != l_first); - } - - - /* clear tags so subdiv verts don't get tagged too */ - for (el_store_ring = eloops_ring->first; - el_store_ring; - el_store_ring = BM_EDGELOOP_NEXT(el_store_ring)) - { - bm_edgeloop_vert_tag(el_store_ring, false); - } - - /* cleanup after */ - bm_edgeloop_vert_tag(el_store_b, false); + ListBase *lb_a = BM_edgeloop_verts_get(el_store_a); + // ListBase *lb_b = BM_edgeloop_verts_get(el_store_b); + const int stack_max = max_ii(BM_edgeloop_length_get(el_store_a), + BM_edgeloop_length_get(el_store_b)) * + 2; + BMEdge **edges_ring_arr = BLI_array_alloca(edges_ring_arr, stack_max); + BMFace **faces_ring_arr = BLI_array_alloca(faces_ring_arr, stack_max); + STACK_DECLARE(edges_ring_arr); + STACK_DECLARE(faces_ring_arr); + struct BMEdgeLoopStore *el_store_ring; + LinkData *node; + BMEdge *e; + BMFace *f; + + STACK_INIT(edges_ring_arr, stack_max); + STACK_INIT(faces_ring_arr, stack_max); + + bm_edgeloop_vert_tag(el_store_a, false); + bm_edgeloop_vert_tag(el_store_b, true); + + for (node = lb_a->first; node; node = node->next) { + BMIter eiter; + + BM_ITER_ELEM (e, &eiter, (BMVert *)node->data, BM_EDGES_OF_VERT) { + if (!BMO_edge_flag_test(bm, e, EDGE_IN_STACK)) { + BMVert *v_other = BM_edge_other_vert(e, (BMVert *)node->data); + if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) { + BMIter fiter; + + BMO_edge_flag_enable(bm, e, EDGE_IN_STACK); + STACK_PUSH(edges_ring_arr, e); + + /* add faces to the stack */ + BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { + if (BMO_face_flag_test(bm, f, FACE_OUT)) { + if (!BMO_face_flag_test(bm, f, FACE_IN_STACK)) { + BMO_face_flag_enable(bm, f, FACE_IN_STACK); + STACK_PUSH(faces_ring_arr, f); + } + } + } + } + } + } + } + + while ((e = STACK_POP(edges_ring_arr))) { + /* found opposite edge */ + BMVert *v_other; + + BMO_edge_flag_disable(bm, e, EDGE_IN_STACK); + + /* unrelated to subdiv, but if we _don't_ clear flag, multiple rings fail */ + BMO_edge_flag_disable(bm, e, EDGE_RING); + + v_other = BM_elem_flag_test(e->v1, BM_ELEM_TAG) ? e->v1 : e->v2; + bm_edge_subdiv_as_loop(bm, eloops_ring, e, v_other, cuts); + } + + while ((f = STACK_POP(faces_ring_arr))) { + BMLoop *l_iter, *l_first; + + BMO_face_flag_disable(bm, f, FACE_IN_STACK); + + /* Check each edge of the face */ + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (BMO_edge_flag_test(bm, l_iter->e, EDGE_RIM)) { + bm_face_slice(bm, l_iter, cuts); + break; + } + } while ((l_iter = l_iter->next) != l_first); + } + + /* clear tags so subdiv verts don't get tagged too */ + for (el_store_ring = eloops_ring->first; el_store_ring; + el_store_ring = BM_EDGELOOP_NEXT(el_store_ring)) { + bm_edgeloop_vert_tag(el_store_ring, false); + } + + /* cleanup after */ + bm_edgeloop_vert_tag(el_store_b, false); } -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_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) { - ListBase eloops_ring = {NULL}; - bm_edgering_pair_order(bm, el_store_a, el_store_b); - bm_edgering_pair_subdiv(bm, el_store_a, el_store_b, &eloops_ring, cuts); - bm_edgering_pair_interpolate(bm, lpair, el_store_a, el_store_b, &eloops_ring, - interp_mode, cuts, smooth, falloff_cache); - BM_mesh_edgeloops_free(&eloops_ring); + ListBase eloops_ring = {NULL}; + bm_edgering_pair_order(bm, el_store_a, el_store_b); + bm_edgering_pair_subdiv(bm, el_store_a, el_store_b, &eloops_ring, cuts); + bm_edgering_pair_interpolate( + bm, lpair, el_store_a, el_store_b, &eloops_ring, interp_mode, cuts, smooth, falloff_cache); + BM_mesh_edgeloops_free(&eloops_ring); } static bool bm_edge_rim_test_cb(BMEdge *e, void *bm_v) { - BMesh *bm = bm_v; - return BMO_edge_flag_test_bool(bm, e, EDGE_RIM); + BMesh *bm = bm_v; + return BMO_edge_flag_test_bool(bm, e, EDGE_RIM); } - /* keep this operator fast, its used in a modifier */ void bmo_subdivide_edgering_exec(BMesh *bm, BMOperator *op) { - ListBase eloops_rim = {NULL}; - BMOIter siter; - BMEdge *e; - int count; - bool changed = false; - - const int cuts = BMO_slot_int_get(op->slots_in, "cuts"); - const int interp_mode = BMO_slot_int_get(op->slots_in, "interp_mode"); - const float smooth = BMO_slot_float_get(op->slots_in, "smooth"); - const int resolu = cuts + 2; - - /* optional 'shape' */ - const int profile_shape = BMO_slot_int_get(op->slots_in, "profile_shape"); - const float profile_shape_factor = BMO_slot_float_get(op->slots_in, "profile_shape_factor"); - float *falloff_cache = (profile_shape_factor != 0.0f) ? BLI_array_alloca(falloff_cache, cuts + 2) : NULL; - - BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, EDGE_RING); - - BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false); - - /* -------------------------------------------------------------------- */ - /* flag outer edges (loops defined as edges on the bounds of the edge ring) */ - - BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { - BMIter fiter; - BMFace *f; - - BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { - /* could support ngons, other areas would need updating too, see T48926. */ - if ((f->len <= 4) && !BMO_face_flag_test(bm, f, FACE_OUT)) { - BMIter liter; - BMLoop *l; - bool ok = false; - - /* check at least 2 edges in the face are rings */ - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - if (BMO_edge_flag_test(bm, l->e, EDGE_RING) && e != l->e) { - ok = true; - break; - } - } - - if (ok) { - BMO_face_flag_enable(bm, f, FACE_OUT); - - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - if (!BMO_edge_flag_test(bm, l->e, EDGE_RING)) { - BMO_edge_flag_enable(bm, l->e, EDGE_RIM); - } - } - } - } - } - } - - - /* -------------------------------------------------------------------- */ - /* Cache falloff for each step (symmetrical) */ - - if (falloff_cache) { - int i; - for (i = 0; i < resolu; i++) { - float shape_size = 1.0f; - float fac = (float)i / (float)(resolu - 1); - fac = fabsf(1.0f - 2.0f * fabsf(0.5f - fac)); - fac = bmesh_subd_falloff_calc(profile_shape, fac); - shape_size += fac * profile_shape_factor; - - falloff_cache[i] = shape_size; - } - } - - - /* -------------------------------------------------------------------- */ - /* Execute subdivision on all ring pairs */ - - count = BM_mesh_edgeloops_find(bm, &eloops_rim, bm_edge_rim_test_cb, (void *)bm); - - if (count < 2) { - BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, - "No edge rings found"); - goto cleanup; - } - else if (count == 2) { - /* this case could be removed, - * but simple to avoid 'bm_edgering_pair_calc' in this case since theres only one. */ - struct BMEdgeLoopStore *el_store_a = eloops_rim.first; - struct BMEdgeLoopStore *el_store_b = eloops_rim.last; - LoopPairStore *lpair; - - if (bm_edgeloop_check_overlap_all(bm, el_store_a, el_store_b)) { - lpair = bm_edgering_pair_store_create(bm, el_store_a, el_store_b, interp_mode); - } - else { - lpair = NULL; - } - - if (lpair) { - bm_edgering_pair_ringsubd(bm, lpair, el_store_a, el_store_b, - interp_mode, cuts, smooth, falloff_cache); - bm_edgering_pair_store_free(lpair, interp_mode); - changed = true; - } - else { - BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, - "Edge-ring pair isn't connected"); - goto cleanup; - } - } - else { - GSetIterator gs_iter; - int i; - - GSet *eloop_pairs_gs = bm_edgering_pair_calc(bm, &eloops_rim); - LoopPairStore **lpair_arr; - - if (eloop_pairs_gs == NULL) { - BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, - "Edge-rings are not connected"); - goto cleanup; - } - - lpair_arr = BLI_array_alloca(lpair_arr, BLI_gset_len(eloop_pairs_gs)); - - /* first cache pairs */ - GSET_ITER_INDEX (gs_iter, eloop_pairs_gs, i) { - GHashPair *eloop_pair = BLI_gsetIterator_getKey(&gs_iter); - struct BMEdgeLoopStore *el_store_a = (void *)eloop_pair->first; - struct BMEdgeLoopStore *el_store_b = (void *)eloop_pair->second; - LoopPairStore *lpair; - - if (bm_edgeloop_check_overlap_all(bm, el_store_a, el_store_b)) { - lpair = bm_edgering_pair_store_create(bm, el_store_a, el_store_b, interp_mode); - } - else { - lpair = NULL; - } - lpair_arr[i] = lpair; - - BLI_assert(bm_verts_tag_count(bm) == 0); - } - - GSET_ITER_INDEX (gs_iter, eloop_pairs_gs, i) { - GHashPair *eloop_pair = BLI_gsetIterator_getKey(&gs_iter); - struct BMEdgeLoopStore *el_store_a = (void *)eloop_pair->first; - struct BMEdgeLoopStore *el_store_b = (void *)eloop_pair->second; - LoopPairStore *lpair = lpair_arr[i]; - - if (lpair) { - bm_edgering_pair_ringsubd(bm, lpair, el_store_a, el_store_b, - interp_mode, cuts, smooth, falloff_cache); - bm_edgering_pair_store_free(lpair, interp_mode); - changed = true; - } - - BLI_assert(bm_verts_tag_count(bm) == 0); - } - BLI_gset_free(eloop_pairs_gs, MEM_freeN); - } + ListBase eloops_rim = {NULL}; + BMOIter siter; + BMEdge *e; + int count; + bool changed = false; + + const int cuts = BMO_slot_int_get(op->slots_in, "cuts"); + const int interp_mode = BMO_slot_int_get(op->slots_in, "interp_mode"); + const float smooth = BMO_slot_float_get(op->slots_in, "smooth"); + const int resolu = cuts + 2; + + /* optional 'shape' */ + const int profile_shape = BMO_slot_int_get(op->slots_in, "profile_shape"); + const float profile_shape_factor = BMO_slot_float_get(op->slots_in, "profile_shape_factor"); + float *falloff_cache = (profile_shape_factor != 0.0f) ? + BLI_array_alloca(falloff_cache, cuts + 2) : + NULL; + + BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, EDGE_RING); + + BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false); + + /* -------------------------------------------------------------------- */ + /* flag outer edges (loops defined as edges on the bounds of the edge ring) */ + + BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { + BMIter fiter; + BMFace *f; + + BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { + /* could support ngons, other areas would need updating too, see T48926. */ + if ((f->len <= 4) && !BMO_face_flag_test(bm, f, FACE_OUT)) { + BMIter liter; + BMLoop *l; + bool ok = false; + + /* check at least 2 edges in the face are rings */ + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + if (BMO_edge_flag_test(bm, l->e, EDGE_RING) && e != l->e) { + ok = true; + break; + } + } + + if (ok) { + BMO_face_flag_enable(bm, f, FACE_OUT); + + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + if (!BMO_edge_flag_test(bm, l->e, EDGE_RING)) { + BMO_edge_flag_enable(bm, l->e, EDGE_RIM); + } + } + } + } + } + } + + /* -------------------------------------------------------------------- */ + /* Cache falloff for each step (symmetrical) */ + + if (falloff_cache) { + int i; + for (i = 0; i < resolu; i++) { + float shape_size = 1.0f; + float fac = (float)i / (float)(resolu - 1); + fac = fabsf(1.0f - 2.0f * fabsf(0.5f - fac)); + fac = bmesh_subd_falloff_calc(profile_shape, fac); + shape_size += fac * profile_shape_factor; + + falloff_cache[i] = shape_size; + } + } + + /* -------------------------------------------------------------------- */ + /* Execute subdivision on all ring pairs */ + + count = BM_mesh_edgeloops_find(bm, &eloops_rim, bm_edge_rim_test_cb, (void *)bm); + + if (count < 2) { + BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, "No edge rings found"); + goto cleanup; + } + else if (count == 2) { + /* this case could be removed, + * but simple to avoid 'bm_edgering_pair_calc' in this case since theres only one. */ + struct BMEdgeLoopStore *el_store_a = eloops_rim.first; + struct BMEdgeLoopStore *el_store_b = eloops_rim.last; + LoopPairStore *lpair; + + if (bm_edgeloop_check_overlap_all(bm, el_store_a, el_store_b)) { + lpair = bm_edgering_pair_store_create(bm, el_store_a, el_store_b, interp_mode); + } + else { + lpair = NULL; + } + + if (lpair) { + bm_edgering_pair_ringsubd( + bm, lpair, el_store_a, el_store_b, interp_mode, cuts, smooth, falloff_cache); + bm_edgering_pair_store_free(lpair, interp_mode); + changed = true; + } + else { + BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, "Edge-ring pair isn't connected"); + goto cleanup; + } + } + else { + GSetIterator gs_iter; + int i; + + GSet *eloop_pairs_gs = bm_edgering_pair_calc(bm, &eloops_rim); + LoopPairStore **lpair_arr; + + if (eloop_pairs_gs == NULL) { + BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, "Edge-rings are not connected"); + goto cleanup; + } + + lpair_arr = BLI_array_alloca(lpair_arr, BLI_gset_len(eloop_pairs_gs)); + + /* first cache pairs */ + GSET_ITER_INDEX(gs_iter, eloop_pairs_gs, i) + { + GHashPair *eloop_pair = BLI_gsetIterator_getKey(&gs_iter); + struct BMEdgeLoopStore *el_store_a = (void *)eloop_pair->first; + struct BMEdgeLoopStore *el_store_b = (void *)eloop_pair->second; + LoopPairStore *lpair; + + if (bm_edgeloop_check_overlap_all(bm, el_store_a, el_store_b)) { + lpair = bm_edgering_pair_store_create(bm, el_store_a, el_store_b, interp_mode); + } + else { + lpair = NULL; + } + lpair_arr[i] = lpair; + + BLI_assert(bm_verts_tag_count(bm) == 0); + } + + GSET_ITER_INDEX(gs_iter, eloop_pairs_gs, i) + { + GHashPair *eloop_pair = BLI_gsetIterator_getKey(&gs_iter); + struct BMEdgeLoopStore *el_store_a = (void *)eloop_pair->first; + struct BMEdgeLoopStore *el_store_b = (void *)eloop_pair->second; + LoopPairStore *lpair = lpair_arr[i]; + + if (lpair) { + bm_edgering_pair_ringsubd( + bm, lpair, el_store_a, el_store_b, interp_mode, cuts, smooth, falloff_cache); + bm_edgering_pair_store_free(lpair, interp_mode); + changed = true; + } + + BLI_assert(bm_verts_tag_count(bm) == 0); + } + BLI_gset_free(eloop_pairs_gs, MEM_freeN); + } cleanup: - BM_mesh_edgeloops_free(&eloops_rim); + BM_mesh_edgeloops_free(&eloops_rim); - /* flag output */ - if (changed) { - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, FACE_OUT); - } + /* flag output */ + if (changed) { + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, FACE_OUT); + } } |