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 | |
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')
38 files changed, 13074 insertions, 12999 deletions
diff --git a/source/blender/bmesh/operators/bmo_beautify.c b/source/blender/bmesh/operators/bmo_beautify.c index 4efa3d98262..36122e06e9b 100644 --- a/source/blender/bmesh/operators/bmo_beautify.c +++ b/source/blender/bmesh/operators/bmo_beautify.c @@ -29,50 +29,51 @@ #include "bmesh_tools.h" #include "intern/bmesh_operators_private.h" -#define ELE_NEW 1 -#define FACE_MARK 2 +#define ELE_NEW 1 +#define FACE_MARK 2 void bmo_beautify_fill_exec(BMesh *bm, BMOperator *op) { - BMIter iter; - BMOIter siter; - BMFace *f; - BMEdge *e; - const bool use_restrict_tag = BMO_slot_bool_get(op->slots_in, "use_restrict_tag"); - const short flag = (use_restrict_tag ? VERT_RESTRICT_TAG : 0); - const short method = (short)BMO_slot_int_get(op->slots_in, "method"); + BMIter iter; + BMOIter siter; + BMFace *f; + BMEdge *e; + const bool use_restrict_tag = BMO_slot_bool_get(op->slots_in, "use_restrict_tag"); + const short flag = (use_restrict_tag ? VERT_RESTRICT_TAG : 0); + const short method = (short)BMO_slot_int_get(op->slots_in, "method"); - BMEdge **edge_array; - int edge_array_len = 0; - BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) { - if (f->len == 3) { - BMO_face_flag_enable(bm, f, FACE_MARK); - } - } + BMEdge **edge_array; + int edge_array_len = 0; + BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) { + if (f->len == 3) { + BMO_face_flag_enable(bm, f, FACE_MARK); + } + } - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - BM_elem_flag_disable(e, BM_ELEM_TAG); - } + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + BM_elem_flag_disable(e, BM_ELEM_TAG); + } - /* will over alloc if some edges can't be rotated */ - edge_array = MEM_mallocN(sizeof(*edge_array) * (size_t)BMO_slot_buffer_count(op->slots_in, "edges"), __func__); + /* will over alloc if some edges can't be rotated */ + edge_array = MEM_mallocN( + sizeof(*edge_array) * (size_t)BMO_slot_buffer_count(op->slots_in, "edges"), __func__); - BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { + BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { - /* edge is manifold and can be rotated */ - if (BM_edge_rotate_check(e) && - /* faces are tagged */ - BMO_face_flag_test(bm, e->l->f, FACE_MARK) && - BMO_face_flag_test(bm, e->l->radial_next->f, FACE_MARK)) - { - edge_array[edge_array_len] = e; - edge_array_len++; - } - } + /* edge is manifold and can be rotated */ + if (BM_edge_rotate_check(e) && + /* faces are tagged */ + BMO_face_flag_test(bm, e->l->f, FACE_MARK) && + BMO_face_flag_test(bm, e->l->radial_next->f, FACE_MARK)) { + edge_array[edge_array_len] = e; + edge_array_len++; + } + } - BM_mesh_beautify_fill(bm, edge_array, edge_array_len, flag, method, ELE_NEW, FACE_MARK | ELE_NEW); + BM_mesh_beautify_fill( + bm, edge_array, edge_array_len, flag, method, ELE_NEW, FACE_MARK | ELE_NEW); - MEM_freeN(edge_array); + MEM_freeN(edge_array); - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_EDGE | BM_FACE, ELE_NEW); + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_EDGE | BM_FACE, ELE_NEW); } diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 19c377d18a9..33be9559db3 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -29,52 +29,68 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) { - const float offset = BMO_slot_float_get(op->slots_in, "offset"); - const int offset_type = BMO_slot_int_get(op->slots_in, "offset_type"); - const int seg = BMO_slot_int_get(op->slots_in, "segments"); - const bool vonly = BMO_slot_bool_get(op->slots_in, "vertex_only"); - const float profile = BMO_slot_float_get(op->slots_in, "profile"); - const bool clamp_overlap = BMO_slot_bool_get(op->slots_in, "clamp_overlap"); - const int material = BMO_slot_int_get(op->slots_in, "material"); - const bool loop_slide = BMO_slot_bool_get(op->slots_in, "loop_slide"); - const bool mark_seam = BMO_slot_bool_get(op->slots_in, "mark_seam"); - const bool mark_sharp = BMO_slot_bool_get(op->slots_in, "mark_sharp"); - const bool harden_normals = BMO_slot_bool_get(op->slots_in, "harden_normals"); - const int face_strength_mode = BMO_slot_int_get(op->slots_in, "face_strength_mode"); - const int miter_outer = BMO_slot_int_get(op->slots_in, "miter_outer"); - const int miter_inner = BMO_slot_int_get(op->slots_in, "miter_inner"); - const float spread = BMO_slot_float_get(op->slots_in, "spread"); - const float smoothresh = BMO_slot_float_get(op->slots_in, "smoothresh"); + const float offset = BMO_slot_float_get(op->slots_in, "offset"); + const int offset_type = BMO_slot_int_get(op->slots_in, "offset_type"); + const int seg = BMO_slot_int_get(op->slots_in, "segments"); + const bool vonly = BMO_slot_bool_get(op->slots_in, "vertex_only"); + const float profile = BMO_slot_float_get(op->slots_in, "profile"); + const bool clamp_overlap = BMO_slot_bool_get(op->slots_in, "clamp_overlap"); + const int material = BMO_slot_int_get(op->slots_in, "material"); + const bool loop_slide = BMO_slot_bool_get(op->slots_in, "loop_slide"); + const bool mark_seam = BMO_slot_bool_get(op->slots_in, "mark_seam"); + const bool mark_sharp = BMO_slot_bool_get(op->slots_in, "mark_sharp"); + const bool harden_normals = BMO_slot_bool_get(op->slots_in, "harden_normals"); + const int face_strength_mode = BMO_slot_int_get(op->slots_in, "face_strength_mode"); + const int miter_outer = BMO_slot_int_get(op->slots_in, "miter_outer"); + const int miter_inner = BMO_slot_int_get(op->slots_in, "miter_inner"); + const float spread = BMO_slot_float_get(op->slots_in, "spread"); + const float smoothresh = BMO_slot_float_get(op->slots_in, "smoothresh"); - if (offset > 0) { - BMOIter siter; - BMEdge *e; - BMVert *v; + if (offset > 0) { + BMOIter siter; + BMEdge *e; + BMVert *v; - /* first flush 'geom' into flags, this makes it possible to check connected data, - * BM_FACE is cleared so we can put newly created faces into a bmesh slot. */ - BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); + /* first flush 'geom' into flags, this makes it possible to check connected data, + * BM_FACE is cleared so we can put newly created faces into a bmesh slot. */ + BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); - BMO_ITER (v, &siter, op->slots_in, "geom", BM_VERT) { - BM_elem_flag_enable(v, BM_ELEM_TAG); - } + BMO_ITER (v, &siter, op->slots_in, "geom", BM_VERT) { + BM_elem_flag_enable(v, BM_ELEM_TAG); + } - BMO_ITER (e, &siter, op->slots_in, "geom", BM_EDGE) { - if (BM_edge_is_manifold(e)) { - BM_elem_flag_enable(e, BM_ELEM_TAG); - /* in case verts were not also included in the geom */ - BM_elem_flag_enable(e->v1, BM_ELEM_TAG); - BM_elem_flag_enable(e->v2, BM_ELEM_TAG); - } - } + BMO_ITER (e, &siter, op->slots_in, "geom", BM_EDGE) { + if (BM_edge_is_manifold(e)) { + BM_elem_flag_enable(e, BM_ELEM_TAG); + /* in case verts were not also included in the geom */ + BM_elem_flag_enable(e->v1, BM_ELEM_TAG); + BM_elem_flag_enable(e->v2, BM_ELEM_TAG); + } + } - BM_mesh_bevel( - bm, offset, offset_type, seg, profile, vonly, false, clamp_overlap, NULL, -1, material, - loop_slide, mark_seam, mark_sharp, harden_normals, face_strength_mode, - miter_outer, miter_inner, spread, smoothresh); + BM_mesh_bevel(bm, + offset, + offset_type, + seg, + profile, + vonly, + false, + clamp_overlap, + NULL, + -1, + material, + loop_slide, + mark_seam, + mark_sharp, + harden_normals, + face_strength_mode, + miter_outer, + miter_inner, + spread, + smoothresh); - BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG); - BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "edges.out", BM_EDGE, BM_ELEM_TAG); - BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "verts.out", BM_VERT, BM_ELEM_TAG); - } + BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG); + BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "edges.out", BM_EDGE, BM_ELEM_TAG); + BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "verts.out", BM_VERT, BM_ELEM_TAG); + } } diff --git a/source/blender/bmesh/operators/bmo_bisect_plane.c b/source/blender/bmesh/operators/bmo_bisect_plane.c index 800f5bac715..f3062cac85c 100644 --- a/source/blender/bmesh/operators/bmo_bisect_plane.c +++ b/source/blender/bmesh/operators/bmo_bisect_plane.c @@ -37,71 +37,69 @@ void bmo_bisect_plane_exec(BMesh *bm, BMOperator *op) { - const float dist = BMO_slot_float_get(op->slots_in, "dist"); - const bool use_snap_center = BMO_slot_bool_get(op->slots_in, "use_snap_center"); - const bool clear_outer = BMO_slot_bool_get(op->slots_in, "clear_outer"); - const bool clear_inner = BMO_slot_bool_get(op->slots_in, "clear_inner"); - - float plane_co[3]; - float plane_no[3]; - float plane[4]; - - BMO_slot_vec_get(op->slots_in, "plane_co", plane_co); - BMO_slot_vec_get(op->slots_in, "plane_no", plane_no); - - if (is_zero_v3(plane_no)) { - BMO_error_raise(bm, op, BMERR_MESH_ERROR, "Zero normal given"); - return; - } - - plane_from_point_normal_v3(plane, plane_co, plane_no); - - /* tag geometry to bisect */ - BM_mesh_elem_hflag_disable_all(bm, BM_EDGE | BM_FACE, BM_ELEM_TAG, false); - BMO_slot_buffer_hflag_enable(bm, op->slots_in, "geom", BM_EDGE | BM_FACE, BM_ELEM_TAG, false); - - BMO_slot_buffer_flag_enable(bm, op->slots_in, "geom", BM_ALL_NOLOOP, ELE_INPUT); - - - BM_mesh_bisect_plane(bm, plane, use_snap_center, true, - ELE_CUT, ELE_NEW, dist); - - - if (clear_outer || clear_inner) { - /* Use an array of vertices because 'geom' contains both vers and edges that may use them. - * Removing a vert may remove and edge which is later checked by BMO_ITER. - * over-alloc the total possible vert count */ - const int vert_arr_max = min_ii(bm->totvert, BMO_slot_buffer_count(op->slots_in, "geom")); - BMVert **vert_arr = MEM_mallocN(sizeof(*vert_arr) * (size_t)vert_arr_max, __func__); - BMOIter siter; - BMVert *v; - float plane_inner[4]; - float plane_outer[4]; - - STACK_DECLARE(vert_arr); - - copy_v3_v3(plane_outer, plane); - copy_v3_v3(plane_inner, plane); - plane_outer[3] = plane[3] - dist; - plane_inner[3] = plane[3] + dist; - - STACK_INIT(vert_arr, vert_arr_max); - - BMO_ITER (v, &siter, op->slots_in, "geom", BM_VERT) { - if ((clear_outer && plane_point_side_v3(plane_outer, v->co) > 0.0f) || - (clear_inner && plane_point_side_v3(plane_inner, v->co) < 0.0f)) - { - STACK_PUSH(vert_arr, v); - } - } - - while ((v = STACK_POP(vert_arr))) { - BM_vert_kill(bm, v); - } - - MEM_freeN(vert_arr); - } - - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, ELE_NEW | ELE_INPUT); - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom_cut.out", BM_VERT | BM_EDGE, ELE_CUT); + const float dist = BMO_slot_float_get(op->slots_in, "dist"); + const bool use_snap_center = BMO_slot_bool_get(op->slots_in, "use_snap_center"); + const bool clear_outer = BMO_slot_bool_get(op->slots_in, "clear_outer"); + const bool clear_inner = BMO_slot_bool_get(op->slots_in, "clear_inner"); + + float plane_co[3]; + float plane_no[3]; + float plane[4]; + + BMO_slot_vec_get(op->slots_in, "plane_co", plane_co); + BMO_slot_vec_get(op->slots_in, "plane_no", plane_no); + + if (is_zero_v3(plane_no)) { + BMO_error_raise(bm, op, BMERR_MESH_ERROR, "Zero normal given"); + return; + } + + plane_from_point_normal_v3(plane, plane_co, plane_no); + + /* tag geometry to bisect */ + BM_mesh_elem_hflag_disable_all(bm, BM_EDGE | BM_FACE, BM_ELEM_TAG, false); + BMO_slot_buffer_hflag_enable(bm, op->slots_in, "geom", BM_EDGE | BM_FACE, BM_ELEM_TAG, false); + + BMO_slot_buffer_flag_enable(bm, op->slots_in, "geom", BM_ALL_NOLOOP, ELE_INPUT); + + BM_mesh_bisect_plane(bm, plane, use_snap_center, true, ELE_CUT, ELE_NEW, dist); + + if (clear_outer || clear_inner) { + /* Use an array of vertices because 'geom' contains both vers and edges that may use them. + * Removing a vert may remove and edge which is later checked by BMO_ITER. + * over-alloc the total possible vert count */ + const int vert_arr_max = min_ii(bm->totvert, BMO_slot_buffer_count(op->slots_in, "geom")); + BMVert **vert_arr = MEM_mallocN(sizeof(*vert_arr) * (size_t)vert_arr_max, __func__); + BMOIter siter; + BMVert *v; + float plane_inner[4]; + float plane_outer[4]; + + STACK_DECLARE(vert_arr); + + copy_v3_v3(plane_outer, plane); + copy_v3_v3(plane_inner, plane); + plane_outer[3] = plane[3] - dist; + plane_inner[3] = plane[3] + dist; + + STACK_INIT(vert_arr, vert_arr_max); + + BMO_ITER (v, &siter, op->slots_in, "geom", BM_VERT) { + if ((clear_outer && plane_point_side_v3(plane_outer, v->co) > 0.0f) || + (clear_inner && plane_point_side_v3(plane_inner, v->co) < 0.0f)) { + STACK_PUSH(vert_arr, v); + } + } + + while ((v = STACK_POP(vert_arr))) { + BM_vert_kill(bm, v); + } + + MEM_freeN(vert_arr); + } + + BMO_slot_buffer_from_enabled_flag( + bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, ELE_NEW | ELE_INPUT); + BMO_slot_buffer_from_enabled_flag( + bm, op, op->slots_out, "geom_cut.out", BM_VERT | BM_EDGE, ELE_CUT); } diff --git a/source/blender/bmesh/operators/bmo_bridge.c b/source/blender/bmesh/operators/bmo_bridge.c index 84b5f44a43f..39ccc0c631e 100644 --- a/source/blender/bmesh/operators/bmo_bridge.c +++ b/source/blender/bmesh/operators/bmo_bridge.c @@ -28,32 +28,33 @@ #include "intern/bmesh_operators_private.h" /* own include */ -#define EDGE_MARK 4 -#define EDGE_OUT 8 -#define FACE_OUT 16 +#define EDGE_MARK 4 +#define EDGE_OUT 8 +#define FACE_OUT 16 /* el_a and el_b _must_ be same size */ -static void bm_bridge_splice_loops(BMesh *bm, LinkData *el_a, LinkData *el_b, const float merge_factor) +static void bm_bridge_splice_loops(BMesh *bm, + LinkData *el_a, + LinkData *el_b, + const float merge_factor) { - BMOperator op_weld; - BMOpSlot *slot_targetmap; + BMOperator op_weld; + BMOpSlot *slot_targetmap; - BMO_op_init(bm, &op_weld, 0, "weld_verts"); + BMO_op_init(bm, &op_weld, 0, "weld_verts"); - slot_targetmap = BMO_slot_get(op_weld.slots_in, "targetmap"); + slot_targetmap = BMO_slot_get(op_weld.slots_in, "targetmap"); - do { - BMVert *v_a = el_a->data, *v_b = el_b->data; - BM_data_interp_from_verts(bm, v_a, v_b, v_b, merge_factor); - interp_v3_v3v3(v_b->co, v_a->co, v_b->co, merge_factor); - BLI_assert(v_a != v_b); - BMO_slot_map_elem_insert(&op_weld, slot_targetmap, v_a, v_b); - } while ((void) - (el_b = el_b->next), - (el_a = el_a->next)); + do { + BMVert *v_a = el_a->data, *v_b = el_b->data; + BM_data_interp_from_verts(bm, v_a, v_b, v_b, merge_factor); + interp_v3_v3v3(v_b->co, v_a->co, v_b->co, merge_factor); + BLI_assert(v_a != v_b); + BMO_slot_map_elem_insert(&op_weld, slot_targetmap, v_a, v_b); + } while ((void)(el_b = el_b->next), (el_a = el_a->next)); - BMO_op_exec(bm, &op_weld); - BMO_op_finish(bm, &op_weld); + BMO_op_exec(bm, &op_weld); + BMO_op_finish(bm, &op_weld); } /* get the 2 loops matching 2 verts. @@ -61,557 +62,581 @@ static void bm_bridge_splice_loops(BMesh *bm, LinkData *el_a, LinkData *el_b, co * if that fails just get any loop thats on the vert (the first one) */ static void bm_vert_loop_pair(BMesh *bm, BMVert *v1, BMVert *v2, BMLoop **l1, BMLoop **l2) { - BMEdge *e = BM_edge_exists(v1, v2); - BMLoop *l = e->l; - - if (l) { - if (l->v == v1) { - *l1 = l; - *l2 = l->next; - } - else { - *l2 = l; - *l1 = l->next; - } - } - else { - /* fallback to _any_ loop */ - *l1 = BM_iter_at_index(bm, BM_LOOPS_OF_VERT, v1, 0); - *l2 = BM_iter_at_index(bm, BM_LOOPS_OF_VERT, v2, 0); - } + BMEdge *e = BM_edge_exists(v1, v2); + BMLoop *l = e->l; + + if (l) { + if (l->v == v1) { + *l1 = l; + *l2 = l->next; + } + else { + *l2 = l; + *l1 = l->next; + } + } + else { + /* fallback to _any_ loop */ + *l1 = BM_iter_at_index(bm, BM_LOOPS_OF_VERT, v1, 0); + *l2 = BM_iter_at_index(bm, BM_LOOPS_OF_VERT, v2, 0); + } } /* el_b can have any offset */ -static float bm_edgeloop_offset_length( - LinkData *el_a, LinkData *el_b, - LinkData *el_b_first, const float len_max) +static float bm_edgeloop_offset_length(LinkData *el_a, + LinkData *el_b, + LinkData *el_b_first, + const float len_max) { - float len = 0.0f; - BLI_assert(el_a->prev == NULL); /* must be first */ - do { - len += len_v3v3(((BMVert *)el_a->data)->co, ((BMVert *)el_b->data)->co); - } while ((void) - (el_b = el_b->next ? el_b->next : el_b_first), - (el_a = el_a->next) && (len < len_max)); - return len; + float len = 0.0f; + BLI_assert(el_a->prev == NULL); /* must be first */ + do { + len += len_v3v3(((BMVert *)el_a->data)->co, ((BMVert *)el_b->data)->co); + } while ((void)(el_b = el_b->next ? el_b->next : el_b_first), + (el_a = el_a->next) && (len < len_max)); + return len; } -static void bm_bridge_best_rotation(struct BMEdgeLoopStore *el_store_a, struct BMEdgeLoopStore *el_store_b) +static void bm_bridge_best_rotation(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 *el_a = lb_a->first; - LinkData *el_b = lb_b->first; - LinkData *el_b_first = el_b; - LinkData *el_b_best = NULL; - - float len_best = FLT_MAX; - - for (; el_b; el_b = el_b->next) { - const float len = bm_edgeloop_offset_length(el_a, el_b, el_b_first, len_best); - if (len < len_best) { - el_b_best = el_b; - len_best = len; - } - } - - if (el_b_best) { - BLI_listbase_rotate_first(lb_b, el_b_best); - } + ListBase *lb_a = BM_edgeloop_verts_get(el_store_a); + ListBase *lb_b = BM_edgeloop_verts_get(el_store_b); + LinkData *el_a = lb_a->first; + LinkData *el_b = lb_b->first; + LinkData *el_b_first = el_b; + LinkData *el_b_best = NULL; + + float len_best = FLT_MAX; + + for (; el_b; el_b = el_b->next) { + const float len = bm_edgeloop_offset_length(el_a, el_b, el_b_first, len_best); + if (len < len_best) { + el_b_best = el_b; + len_best = len; + } + } + + if (el_b_best) { + BLI_listbase_rotate_first(lb_b, el_b_best); + } } static void bm_face_edges_tag_out(BMesh *bm, BMFace *f) { - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - BMO_edge_flag_enable(bm, l_iter->e, EDGE_OUT); - } while ((l_iter = l_iter->next) != l_first); + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BMO_edge_flag_enable(bm, l_iter->e, EDGE_OUT); + } while ((l_iter = l_iter->next) != l_first); } static bool bm_edge_test_cb(BMEdge *e, void *bm_v) { - return BMO_edge_flag_test((BMesh *)bm_v, e, EDGE_MARK); + return BMO_edge_flag_test((BMesh *)bm_v, e, EDGE_MARK); } -static void bridge_loop_pair( - BMesh *bm, - struct BMEdgeLoopStore *el_store_a, - struct BMEdgeLoopStore *el_store_b, - const bool use_merge, const float merge_factor, const int twist_offset) +static void bridge_loop_pair(BMesh *bm, + struct BMEdgeLoopStore *el_store_a, + struct BMEdgeLoopStore *el_store_b, + const bool use_merge, + const float merge_factor, + const int twist_offset) { - const float eps = 0.00001f; - LinkData *el_a_first, *el_b_first; - const bool is_closed = BM_edgeloop_is_closed(el_store_a) && BM_edgeloop_is_closed(el_store_b); - int el_store_a_len, el_store_b_len; - bool el_store_b_free = false; - float el_dir[3]; - float dot_a, dot_b; - const bool use_edgeout = true; - - el_store_a_len = BM_edgeloop_length_get((struct BMEdgeLoopStore *)el_store_a); - el_store_b_len = BM_edgeloop_length_get((struct BMEdgeLoopStore *)el_store_b); - - if (el_store_a_len < el_store_b_len) { - SWAP(int, el_store_a_len, el_store_b_len); - SWAP(struct BMEdgeLoopStore *, el_store_a, el_store_b); - } - - if (use_merge) { - BLI_assert((el_store_a_len == el_store_b_len)); - } - - if (el_store_a_len != el_store_b_len) { - BM_mesh_elem_hflag_disable_all(bm, BM_FACE | BM_EDGE, BM_ELEM_TAG, false); - } - - sub_v3_v3v3(el_dir, BM_edgeloop_center_get(el_store_a), BM_edgeloop_center_get(el_store_b)); - - if (is_closed) { - /* if all loops are closed this will calculate twice for all loops */ - BM_edgeloop_calc_normal(bm, el_store_a); - BM_edgeloop_calc_normal(bm, el_store_b); - } - else { - ListBase *lb_a = BM_edgeloop_verts_get(el_store_a); - ListBase *lb_b = BM_edgeloop_verts_get(el_store_b); - - /* normalizing isn't strictly needed but without we may get very large values */ - float no[3]; - float dir_a_orig[3], dir_b_orig[3]; - float dir_a[3], dir_b[3]; - const float *test_a, *test_b; - - sub_v3_v3v3(dir_a_orig, - ((BMVert *)(((LinkData *)lb_a->first)->data))->co, - ((BMVert *)(((LinkData *)lb_a->last)->data))->co); - sub_v3_v3v3(dir_b_orig, - ((BMVert *)(((LinkData *)lb_b->first)->data))->co, - ((BMVert *)(((LinkData *)lb_b->last)->data))->co); - - /* make the directions point out from the normals, 'no' is used as a temp var */ - cross_v3_v3v3(no, dir_a_orig, el_dir); cross_v3_v3v3(dir_a, no, el_dir); - cross_v3_v3v3(no, dir_b_orig, el_dir); cross_v3_v3v3(dir_b, no, el_dir); - - if (LIKELY(!is_zero_v3(dir_a) && !is_zero_v3(dir_b))) { - test_a = dir_a; - test_b = dir_b; - } - else { - /** - * This is a corner case: - * - * <pre> - * (loop a) (loop b) - * +--------+ +--------+ - * </pre> - * - * When loops are aligned to the direction between the loops values of 'dir_a/b' is degenerate, - * in this case compare the original directions (before they were corrected by 'el_dir'), see: T43013 - */ - test_a = dir_a_orig; - test_b = dir_b_orig; - } - - if (dot_v3v3(test_a, test_b) < 0.0f) { - BM_edgeloop_flip(bm, el_store_b); - } - - normalize_v3_v3(no, el_dir); - BM_edgeloop_calc_normal_aligned(bm, el_store_a, no); - BM_edgeloop_calc_normal_aligned(bm, el_store_b, no); - } - - dot_a = dot_v3v3(BM_edgeloop_normal_get(el_store_a), el_dir); - dot_b = dot_v3v3(BM_edgeloop_normal_get(el_store_b), el_dir); - - if (UNLIKELY((len_squared_v3(el_dir) < eps) || - ((fabsf(dot_a) < eps) && (fabsf(dot_b) < eps)))) - { - /* in this case there is no depth between the two loops, - * eg: 2x 2d circles, one scaled smaller, - * in this case 'el_dir' cant be used, just ensure we have matching flipping. */ - if (dot_v3v3(BM_edgeloop_normal_get(el_store_a), - BM_edgeloop_normal_get(el_store_b)) < 0.0f) - { - BM_edgeloop_flip(bm, el_store_b); - } - } - else if ((dot_a < 0.0f) != (dot_b < 0.0f)) { - BM_edgeloop_flip(bm, el_store_b); - } - - /* we only care about flipping if we make faces */ - if (use_merge == false) { - float no[3]; - - add_v3_v3v3(no, BM_edgeloop_normal_get(el_store_a), BM_edgeloop_normal_get(el_store_b)); - - if (dot_v3v3(no, el_dir) < 0.0f) { - BM_edgeloop_flip(bm, el_store_a); - BM_edgeloop_flip(bm, el_store_b); - } - - /* vote on winding (so new face winding is based on existing connected faces) */ - if (bm->totface) { - struct BMEdgeLoopStore *estore_pair[2] = {el_store_a, el_store_b}; - int i; - int winding_votes[2] = {0, 0}; - int winding_dir = 1; - for (i = 0; i < 2; i++, winding_dir = -winding_dir) { - LinkData *el; - for (el = BM_edgeloop_verts_get(estore_pair[i])->first; el; el = el->next) { - LinkData *el_next = BM_EDGELINK_NEXT(estore_pair[i], el); - if (el_next) { - BMEdge *e = BM_edge_exists(el->data, el_next->data); - if (e && BM_edge_is_boundary(e)) { - winding_votes[i] += ((e->l->v == el->data) ? winding_dir : -winding_dir); - } - } - } - } - - if (winding_votes[0] || winding_votes[1]) { - bool flip[2] = {false, false}; - - /* for direction aligned loops we can't rely on the directly we have, - * use the winding defined by the connected faces (see T48356). */ - if (fabsf(dot_a) < eps) { - if (winding_votes[0] < 0) { - flip[0] = !flip[0]; - winding_votes[0] *= -1; - - } - } - if (fabsf(dot_b) < eps) { - if (winding_votes[1] < 0) { - flip[1] = !flip[1]; - winding_votes[1] *= -1; - } - } - - /* when both loops contradict the winding, flip them so surrounding geometry matches */ - if ((winding_votes[0] + winding_votes[1]) < 0) { - flip[0] = !flip[0]; - flip[1] = !flip[1]; - - /* valid but unused */ + const float eps = 0.00001f; + LinkData *el_a_first, *el_b_first; + const bool is_closed = BM_edgeloop_is_closed(el_store_a) && BM_edgeloop_is_closed(el_store_b); + int el_store_a_len, el_store_b_len; + bool el_store_b_free = false; + float el_dir[3]; + float dot_a, dot_b; + const bool use_edgeout = true; + + el_store_a_len = BM_edgeloop_length_get((struct BMEdgeLoopStore *)el_store_a); + el_store_b_len = BM_edgeloop_length_get((struct BMEdgeLoopStore *)el_store_b); + + if (el_store_a_len < el_store_b_len) { + SWAP(int, el_store_a_len, el_store_b_len); + SWAP(struct BMEdgeLoopStore *, el_store_a, el_store_b); + } + + if (use_merge) { + BLI_assert((el_store_a_len == el_store_b_len)); + } + + if (el_store_a_len != el_store_b_len) { + BM_mesh_elem_hflag_disable_all(bm, BM_FACE | BM_EDGE, BM_ELEM_TAG, false); + } + + sub_v3_v3v3(el_dir, BM_edgeloop_center_get(el_store_a), BM_edgeloop_center_get(el_store_b)); + + if (is_closed) { + /* if all loops are closed this will calculate twice for all loops */ + BM_edgeloop_calc_normal(bm, el_store_a); + BM_edgeloop_calc_normal(bm, el_store_b); + } + else { + ListBase *lb_a = BM_edgeloop_verts_get(el_store_a); + ListBase *lb_b = BM_edgeloop_verts_get(el_store_b); + + /* normalizing isn't strictly needed but without we may get very large values */ + float no[3]; + float dir_a_orig[3], dir_b_orig[3]; + float dir_a[3], dir_b[3]; + const float *test_a, *test_b; + + sub_v3_v3v3(dir_a_orig, + ((BMVert *)(((LinkData *)lb_a->first)->data))->co, + ((BMVert *)(((LinkData *)lb_a->last)->data))->co); + sub_v3_v3v3(dir_b_orig, + ((BMVert *)(((LinkData *)lb_b->first)->data))->co, + ((BMVert *)(((LinkData *)lb_b->last)->data))->co); + + /* make the directions point out from the normals, 'no' is used as a temp var */ + cross_v3_v3v3(no, dir_a_orig, el_dir); + cross_v3_v3v3(dir_a, no, el_dir); + cross_v3_v3v3(no, dir_b_orig, el_dir); + cross_v3_v3v3(dir_b, no, el_dir); + + if (LIKELY(!is_zero_v3(dir_a) && !is_zero_v3(dir_b))) { + test_a = dir_a; + test_b = dir_b; + } + else { + /** + * This is a corner case: + * + * <pre> + * (loop a) (loop b) + * +--------+ +--------+ + * </pre> + * + * When loops are aligned to the direction between the loops values of 'dir_a/b' is degenerate, + * in this case compare the original directions (before they were corrected by 'el_dir'), see: T43013 + */ + test_a = dir_a_orig; + test_b = dir_b_orig; + } + + if (dot_v3v3(test_a, test_b) < 0.0f) { + BM_edgeloop_flip(bm, el_store_b); + } + + normalize_v3_v3(no, el_dir); + BM_edgeloop_calc_normal_aligned(bm, el_store_a, no); + BM_edgeloop_calc_normal_aligned(bm, el_store_b, no); + } + + dot_a = dot_v3v3(BM_edgeloop_normal_get(el_store_a), el_dir); + dot_b = dot_v3v3(BM_edgeloop_normal_get(el_store_b), el_dir); + + if (UNLIKELY((len_squared_v3(el_dir) < eps) || ((fabsf(dot_a) < eps) && (fabsf(dot_b) < eps)))) { + /* in this case there is no depth between the two loops, + * eg: 2x 2d circles, one scaled smaller, + * in this case 'el_dir' cant be used, just ensure we have matching flipping. */ + if (dot_v3v3(BM_edgeloop_normal_get(el_store_a), BM_edgeloop_normal_get(el_store_b)) < 0.0f) { + BM_edgeloop_flip(bm, el_store_b); + } + } + else if ((dot_a < 0.0f) != (dot_b < 0.0f)) { + BM_edgeloop_flip(bm, el_store_b); + } + + /* we only care about flipping if we make faces */ + if (use_merge == false) { + float no[3]; + + add_v3_v3v3(no, BM_edgeloop_normal_get(el_store_a), BM_edgeloop_normal_get(el_store_b)); + + if (dot_v3v3(no, el_dir) < 0.0f) { + BM_edgeloop_flip(bm, el_store_a); + BM_edgeloop_flip(bm, el_store_b); + } + + /* vote on winding (so new face winding is based on existing connected faces) */ + if (bm->totface) { + struct BMEdgeLoopStore *estore_pair[2] = {el_store_a, el_store_b}; + int i; + int winding_votes[2] = {0, 0}; + int winding_dir = 1; + for (i = 0; i < 2; i++, winding_dir = -winding_dir) { + LinkData *el; + for (el = BM_edgeloop_verts_get(estore_pair[i])->first; el; el = el->next) { + LinkData *el_next = BM_EDGELINK_NEXT(estore_pair[i], el); + if (el_next) { + BMEdge *e = BM_edge_exists(el->data, el_next->data); + if (e && BM_edge_is_boundary(e)) { + winding_votes[i] += ((e->l->v == el->data) ? winding_dir : -winding_dir); + } + } + } + } + + if (winding_votes[0] || winding_votes[1]) { + bool flip[2] = {false, false}; + + /* for direction aligned loops we can't rely on the directly we have, + * use the winding defined by the connected faces (see T48356). */ + if (fabsf(dot_a) < eps) { + if (winding_votes[0] < 0) { + flip[0] = !flip[0]; + winding_votes[0] *= -1; + } + } + if (fabsf(dot_b) < eps) { + if (winding_votes[1] < 0) { + flip[1] = !flip[1]; + winding_votes[1] *= -1; + } + } + + /* when both loops contradict the winding, flip them so surrounding geometry matches */ + if ((winding_votes[0] + winding_votes[1]) < 0) { + flip[0] = !flip[0]; + flip[1] = !flip[1]; + + /* valid but unused */ #if 0 - winding_votes[0] *= -1; - winding_votes[1] *= -1; + winding_votes[0] *= -1; + winding_votes[1] *= -1; #endif - } - - if (flip[0]) { - BM_edgeloop_flip(bm, el_store_a); - } - if (flip[1]) { - BM_edgeloop_flip(bm, el_store_b); - } - } - } - } - - if (el_store_a_len > el_store_b_len) { - el_store_b = BM_edgeloop_copy(el_store_b); - BM_edgeloop_expand(bm, el_store_b, el_store_a_len, false, NULL); - el_store_b_free = true; - } - - if (is_closed) { - bm_bridge_best_rotation(el_store_a, el_store_b); - - /* add twist */ - if (twist_offset != 0) { - const int len_b = BM_edgeloop_length_get(el_store_b); - ListBase *lb_b = BM_edgeloop_verts_get(el_store_b); - LinkData *el_b = BLI_rfindlink(lb_b, mod_i(twist_offset, len_b)); - BLI_listbase_rotate_first(lb_b, el_b); - } - } - - /* Assign after flipping is finalized */ - el_a_first = BM_edgeloop_verts_get(el_store_a)->first; - el_b_first = BM_edgeloop_verts_get(el_store_b)->first; - - - if (use_merge) { - bm_bridge_splice_loops(bm, el_a_first, el_b_first, merge_factor); - } - else { - LinkData *el_a = el_a_first; - LinkData *el_b = el_b_first; - - LinkData *el_a_next; - LinkData *el_b_next; - - - while (true) { - BMFace *f, *f_example; - BMLoop *l_iter; - BMVert *v_a, *v_b, *v_a_next, *v_b_next; - - BMLoop *l_a = NULL; - BMLoop *l_b = NULL; - BMLoop *l_a_next = NULL; - BMLoop *l_b_next = NULL; - - if (is_closed) { - el_a_next = BM_EDGELINK_NEXT(el_store_a, el_a); - el_b_next = BM_EDGELINK_NEXT(el_store_b, el_b); - } - else { - el_a_next = el_a->next; - el_b_next = el_b->next; - if (ELEM(NULL, el_a_next, el_b_next)) { - break; - } - } - - v_a = el_a->data; - v_b = el_b->data; - v_a_next = el_a_next->data; - v_b_next = el_b_next->data; - - /* get loop data - before making the face */ - if (v_b != v_b_next) { - bm_vert_loop_pair(bm, v_a, v_a_next, &l_a, &l_a_next); - bm_vert_loop_pair(bm, v_b, v_b_next, &l_b, &l_b_next); - } - else { - /* lazy, could be more clever here */ - bm_vert_loop_pair(bm, v_a, v_a_next, &l_a, &l_a_next); - l_b = l_b_next = BM_iter_at_index(bm, BM_LOOPS_OF_VERT, v_b, 0); - } - - if (l_a && l_a_next == NULL) { l_a_next = l_a; } - if (l_a_next && l_a == NULL) { l_a = l_a_next; } - if (l_b && l_b_next == NULL) { l_b_next = l_b; } - if (l_b_next && l_b == NULL) { l_b = l_b_next; } - f_example = l_a ? l_a->f : (l_b ? l_b->f : NULL); - - if (v_b != v_b_next) { - BMVert *v_arr[4] = {v_a, v_b, v_b_next, v_a_next}; - f = BM_face_exists(v_arr, 4); - if (f == NULL) { - /* copy if loop data if its is missing on one ring */ - f = BM_face_create_verts(bm, v_arr, 4, NULL, BM_CREATE_NOP, true); - - l_iter = BM_FACE_FIRST_LOOP(f); - if (l_b) { BM_elem_attrs_copy(bm, bm, l_b, l_iter); } l_iter = l_iter->next; - if (l_b_next) { BM_elem_attrs_copy(bm, bm, l_b_next, l_iter); } l_iter = l_iter->next; - if (l_a_next) { BM_elem_attrs_copy(bm, bm, l_a_next, l_iter); } l_iter = l_iter->next; - if (l_a) { BM_elem_attrs_copy(bm, bm, l_a, l_iter); } - } - } - else { - BMVert *v_arr[3] = {v_a, v_b, v_a_next}; - f = BM_face_exists(v_arr, 3); - if (f == NULL) { - /* fan-fill a triangle */ - f = BM_face_create_verts(bm, v_arr, 3, NULL, BM_CREATE_NOP, true); - - l_iter = BM_FACE_FIRST_LOOP(f); - if (l_b) { BM_elem_attrs_copy(bm, bm, l_b, l_iter); } l_iter = l_iter->next; - if (l_a_next) { BM_elem_attrs_copy(bm, bm, l_a_next, l_iter); } l_iter = l_iter->next; - if (l_a) { BM_elem_attrs_copy(bm, bm, l_a, l_iter); } - } - } - - if (f_example && (f_example != f)) { - BM_elem_attrs_copy(bm, bm, f_example, f); - } - BMO_face_flag_enable(bm, f, FACE_OUT); - BM_elem_flag_enable(f, BM_ELEM_TAG); - - /* tag all edges of the face, untag the loop edges after */ - if (use_edgeout) { - bm_face_edges_tag_out(bm, f); - } - - if (el_a_next == el_a_first) { - break; - } - - el_a = el_a_next; - el_b = el_b_next; - } - } - - if (el_store_a_len != el_store_b_len) { - struct BMEdgeLoopStore *estore_pair[2] = {el_store_a, el_store_b}; - int i; - - BMOperator op_sub; - /* when we have to bridge between different sized edge-loops, - * be clever and post-process for best results */ - - - /* triangulate inline */ - BMO_op_initf(bm, &op_sub, 0, - "triangulate faces=%hf", - BM_ELEM_TAG, true); - /* calc normals for input faces before executing */ - { - BMOIter siter; - BMFace *f; - BMO_ITER (f, &siter, op_sub.slots_in, "faces", BM_FACE) { - BM_face_normal_update(f); - } - } - BMO_op_exec(bm, &op_sub); - BMO_slot_buffer_flag_enable(bm, op_sub.slots_out, "faces.out", BM_FACE, FACE_OUT); - BMO_slot_buffer_hflag_enable(bm, op_sub.slots_out, "faces.out", BM_FACE, BM_ELEM_TAG, false); - BMO_op_finish(bm, &op_sub); - - - /* tag verts on each side so we can restrict rotation of edges to verts on the same side */ - for (i = 0; i < 2; i++) { - LinkData *el; - for (el = BM_edgeloop_verts_get(estore_pair[i])->first; el; el = el->next) { - BM_elem_flag_set((BMVert *)el->data, BM_ELEM_TAG, i); - } - } - - - BMO_op_initf(bm, &op_sub, 0, - "beautify_fill faces=%hf edges=ae use_restrict_tag=%b method=%i", - BM_ELEM_TAG, true, 1); - - if (use_edgeout) { - BMOIter siter; - BMFace *f; - BMO_ITER (f, &siter, op_sub.slots_in, "faces", BM_FACE) { - BMO_face_flag_enable(bm, f, FACE_OUT); - bm_face_edges_tag_out(bm, f); - } - } - - BMO_op_exec(bm, &op_sub); - /* there may also be tagged faces that didnt rotate, mark input */ - - if (use_edgeout) { - BMOIter siter; - BMFace *f; - BMO_ITER (f, &siter, op_sub.slots_out, "geom.out", BM_FACE) { - BMO_face_flag_enable(bm, f, FACE_OUT); - bm_face_edges_tag_out(bm, f); - } - } - else { - BMO_slot_buffer_flag_enable(bm, op_sub.slots_out, "geom.out", BM_FACE, FACE_OUT); - } - - BMO_op_finish(bm, &op_sub); - } - - if (use_edgeout && use_merge == false) { - /* we've enabled all face edges above, now disable all loop edges */ - struct BMEdgeLoopStore *estore_pair[2] = {el_store_a, el_store_b}; - int i; - for (i = 0; i < 2; i++) { - LinkData *el; - for (el = BM_edgeloop_verts_get(estore_pair[i])->first; el; el = el->next) { - LinkData *el_next = BM_EDGELINK_NEXT(estore_pair[i], el); - if (el_next) { - if (el->data != el_next->data) { - BMEdge *e = BM_edge_exists(el->data, el_next->data); - BMO_edge_flag_disable(bm, e, EDGE_OUT); - } - } - } - } - } - - if (el_store_b_free) { - BM_edgeloop_free(el_store_b); - } + } + + if (flip[0]) { + BM_edgeloop_flip(bm, el_store_a); + } + if (flip[1]) { + BM_edgeloop_flip(bm, el_store_b); + } + } + } + } + + if (el_store_a_len > el_store_b_len) { + el_store_b = BM_edgeloop_copy(el_store_b); + BM_edgeloop_expand(bm, el_store_b, el_store_a_len, false, NULL); + el_store_b_free = true; + } + + if (is_closed) { + bm_bridge_best_rotation(el_store_a, el_store_b); + + /* add twist */ + if (twist_offset != 0) { + const int len_b = BM_edgeloop_length_get(el_store_b); + ListBase *lb_b = BM_edgeloop_verts_get(el_store_b); + LinkData *el_b = BLI_rfindlink(lb_b, mod_i(twist_offset, len_b)); + BLI_listbase_rotate_first(lb_b, el_b); + } + } + + /* Assign after flipping is finalized */ + el_a_first = BM_edgeloop_verts_get(el_store_a)->first; + el_b_first = BM_edgeloop_verts_get(el_store_b)->first; + + if (use_merge) { + bm_bridge_splice_loops(bm, el_a_first, el_b_first, merge_factor); + } + else { + LinkData *el_a = el_a_first; + LinkData *el_b = el_b_first; + + LinkData *el_a_next; + LinkData *el_b_next; + + while (true) { + BMFace *f, *f_example; + BMLoop *l_iter; + BMVert *v_a, *v_b, *v_a_next, *v_b_next; + + BMLoop *l_a = NULL; + BMLoop *l_b = NULL; + BMLoop *l_a_next = NULL; + BMLoop *l_b_next = NULL; + + if (is_closed) { + el_a_next = BM_EDGELINK_NEXT(el_store_a, el_a); + el_b_next = BM_EDGELINK_NEXT(el_store_b, el_b); + } + else { + el_a_next = el_a->next; + el_b_next = el_b->next; + if (ELEM(NULL, el_a_next, el_b_next)) { + break; + } + } + + v_a = el_a->data; + v_b = el_b->data; + v_a_next = el_a_next->data; + v_b_next = el_b_next->data; + + /* get loop data - before making the face */ + if (v_b != v_b_next) { + bm_vert_loop_pair(bm, v_a, v_a_next, &l_a, &l_a_next); + bm_vert_loop_pair(bm, v_b, v_b_next, &l_b, &l_b_next); + } + else { + /* lazy, could be more clever here */ + bm_vert_loop_pair(bm, v_a, v_a_next, &l_a, &l_a_next); + l_b = l_b_next = BM_iter_at_index(bm, BM_LOOPS_OF_VERT, v_b, 0); + } + + if (l_a && l_a_next == NULL) { + l_a_next = l_a; + } + if (l_a_next && l_a == NULL) { + l_a = l_a_next; + } + if (l_b && l_b_next == NULL) { + l_b_next = l_b; + } + if (l_b_next && l_b == NULL) { + l_b = l_b_next; + } + f_example = l_a ? l_a->f : (l_b ? l_b->f : NULL); + + if (v_b != v_b_next) { + BMVert *v_arr[4] = {v_a, v_b, v_b_next, v_a_next}; + f = BM_face_exists(v_arr, 4); + if (f == NULL) { + /* copy if loop data if its is missing on one ring */ + f = BM_face_create_verts(bm, v_arr, 4, NULL, BM_CREATE_NOP, true); + + l_iter = BM_FACE_FIRST_LOOP(f); + if (l_b) { + BM_elem_attrs_copy(bm, bm, l_b, l_iter); + } + l_iter = l_iter->next; + if (l_b_next) { + BM_elem_attrs_copy(bm, bm, l_b_next, l_iter); + } + l_iter = l_iter->next; + if (l_a_next) { + BM_elem_attrs_copy(bm, bm, l_a_next, l_iter); + } + l_iter = l_iter->next; + if (l_a) { + BM_elem_attrs_copy(bm, bm, l_a, l_iter); + } + } + } + else { + BMVert *v_arr[3] = {v_a, v_b, v_a_next}; + f = BM_face_exists(v_arr, 3); + if (f == NULL) { + /* fan-fill a triangle */ + f = BM_face_create_verts(bm, v_arr, 3, NULL, BM_CREATE_NOP, true); + + l_iter = BM_FACE_FIRST_LOOP(f); + if (l_b) { + BM_elem_attrs_copy(bm, bm, l_b, l_iter); + } + l_iter = l_iter->next; + if (l_a_next) { + BM_elem_attrs_copy(bm, bm, l_a_next, l_iter); + } + l_iter = l_iter->next; + if (l_a) { + BM_elem_attrs_copy(bm, bm, l_a, l_iter); + } + } + } + + if (f_example && (f_example != f)) { + BM_elem_attrs_copy(bm, bm, f_example, f); + } + BMO_face_flag_enable(bm, f, FACE_OUT); + BM_elem_flag_enable(f, BM_ELEM_TAG); + + /* tag all edges of the face, untag the loop edges after */ + if (use_edgeout) { + bm_face_edges_tag_out(bm, f); + } + + if (el_a_next == el_a_first) { + break; + } + + el_a = el_a_next; + el_b = el_b_next; + } + } + + if (el_store_a_len != el_store_b_len) { + struct BMEdgeLoopStore *estore_pair[2] = {el_store_a, el_store_b}; + int i; + + BMOperator op_sub; + /* when we have to bridge between different sized edge-loops, + * be clever and post-process for best results */ + + /* triangulate inline */ + BMO_op_initf(bm, &op_sub, 0, "triangulate faces=%hf", BM_ELEM_TAG, true); + /* calc normals for input faces before executing */ + { + BMOIter siter; + BMFace *f; + BMO_ITER (f, &siter, op_sub.slots_in, "faces", BM_FACE) { + BM_face_normal_update(f); + } + } + BMO_op_exec(bm, &op_sub); + BMO_slot_buffer_flag_enable(bm, op_sub.slots_out, "faces.out", BM_FACE, FACE_OUT); + BMO_slot_buffer_hflag_enable(bm, op_sub.slots_out, "faces.out", BM_FACE, BM_ELEM_TAG, false); + BMO_op_finish(bm, &op_sub); + + /* tag verts on each side so we can restrict rotation of edges to verts on the same side */ + for (i = 0; i < 2; i++) { + LinkData *el; + for (el = BM_edgeloop_verts_get(estore_pair[i])->first; el; el = el->next) { + BM_elem_flag_set((BMVert *)el->data, BM_ELEM_TAG, i); + } + } + + BMO_op_initf(bm, + &op_sub, + 0, + "beautify_fill faces=%hf edges=ae use_restrict_tag=%b method=%i", + BM_ELEM_TAG, + true, + 1); + + if (use_edgeout) { + BMOIter siter; + BMFace *f; + BMO_ITER (f, &siter, op_sub.slots_in, "faces", BM_FACE) { + BMO_face_flag_enable(bm, f, FACE_OUT); + bm_face_edges_tag_out(bm, f); + } + } + + BMO_op_exec(bm, &op_sub); + /* there may also be tagged faces that didnt rotate, mark input */ + + if (use_edgeout) { + BMOIter siter; + BMFace *f; + BMO_ITER (f, &siter, op_sub.slots_out, "geom.out", BM_FACE) { + BMO_face_flag_enable(bm, f, FACE_OUT); + bm_face_edges_tag_out(bm, f); + } + } + else { + BMO_slot_buffer_flag_enable(bm, op_sub.slots_out, "geom.out", BM_FACE, FACE_OUT); + } + + BMO_op_finish(bm, &op_sub); + } + + if (use_edgeout && use_merge == false) { + /* we've enabled all face edges above, now disable all loop edges */ + struct BMEdgeLoopStore *estore_pair[2] = {el_store_a, el_store_b}; + int i; + for (i = 0; i < 2; i++) { + LinkData *el; + for (el = BM_edgeloop_verts_get(estore_pair[i])->first; el; el = el->next) { + LinkData *el_next = BM_EDGELINK_NEXT(estore_pair[i], el); + if (el_next) { + if (el->data != el_next->data) { + BMEdge *e = BM_edge_exists(el->data, el_next->data); + BMO_edge_flag_disable(bm, e, EDGE_OUT); + } + } + } + } + } + + if (el_store_b_free) { + BM_edgeloop_free(el_store_b); + } } void bmo_bridge_loops_exec(BMesh *bm, BMOperator *op) { - ListBase eloops = {NULL}; - LinkData *el_store; - - /* merge-bridge support */ - const bool use_pairs = BMO_slot_bool_get(op->slots_in, "use_pairs"); - const bool use_merge = BMO_slot_bool_get(op->slots_in, "use_merge"); - const float merge_factor = BMO_slot_float_get(op->slots_in, "merge_factor"); - const bool use_cyclic = BMO_slot_bool_get(op->slots_in, "use_cyclic") && (use_merge == false); - const int twist_offset = BMO_slot_int_get(op->slots_in, "twist_offset"); - int count; - bool changed = false; - - BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, EDGE_MARK); - - count = BM_mesh_edgeloops_find(bm, &eloops, bm_edge_test_cb, bm); - - BM_mesh_edgeloops_calc_center(bm, &eloops); - - if (count < 2) { - BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, - "Select at least two edge loops"); - goto cleanup; - } - - if (use_pairs && (count % 2)) { - BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, - "Select an even number of loops to bridge pairs"); - goto cleanup; - } - - if (use_merge) { - bool match = true; - const int eloop_len = BM_edgeloop_length_get(eloops.first); - for (el_store = eloops.first; el_store; el_store = el_store->next) { - if (eloop_len != BM_edgeloop_length_get((struct BMEdgeLoopStore *)el_store)) { - match = false; - break; - } - } - if (!match) { - BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, - "Selected loops must have equal edge counts"); - goto cleanup; - } - } - - if (count > 2) { - if (use_pairs) { - BM_mesh_edgeloops_calc_normal(bm, &eloops); - } - BM_mesh_edgeloops_calc_order(bm, &eloops, use_pairs); - } - - for (el_store = eloops.first; el_store; el_store = el_store->next) { - LinkData *el_store_next = el_store->next; - - if (el_store_next == NULL) { - if (use_cyclic && (count > 2)) { - el_store_next = eloops.first; - } - else { - break; - } - } - - bridge_loop_pair(bm, - (struct BMEdgeLoopStore *)el_store, - (struct BMEdgeLoopStore *)el_store_next, - use_merge, merge_factor, twist_offset); - if (use_pairs) { - el_store = el_store->next; - } - changed = true; - } + ListBase eloops = {NULL}; + LinkData *el_store; + + /* merge-bridge support */ + const bool use_pairs = BMO_slot_bool_get(op->slots_in, "use_pairs"); + const bool use_merge = BMO_slot_bool_get(op->slots_in, "use_merge"); + const float merge_factor = BMO_slot_float_get(op->slots_in, "merge_factor"); + const bool use_cyclic = BMO_slot_bool_get(op->slots_in, "use_cyclic") && (use_merge == false); + const int twist_offset = BMO_slot_int_get(op->slots_in, "twist_offset"); + int count; + bool changed = false; + + BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, EDGE_MARK); + + count = BM_mesh_edgeloops_find(bm, &eloops, bm_edge_test_cb, bm); + + BM_mesh_edgeloops_calc_center(bm, &eloops); + + if (count < 2) { + BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, "Select at least two edge loops"); + goto cleanup; + } + + if (use_pairs && (count % 2)) { + BMO_error_raise( + bm, op, BMERR_INVALID_SELECTION, "Select an even number of loops to bridge pairs"); + goto cleanup; + } + + if (use_merge) { + bool match = true; + const int eloop_len = BM_edgeloop_length_get(eloops.first); + for (el_store = eloops.first; el_store; el_store = el_store->next) { + if (eloop_len != BM_edgeloop_length_get((struct BMEdgeLoopStore *)el_store)) { + match = false; + break; + } + } + if (!match) { + BMO_error_raise( + bm, op, BMERR_INVALID_SELECTION, "Selected loops must have equal edge counts"); + goto cleanup; + } + } + + if (count > 2) { + if (use_pairs) { + BM_mesh_edgeloops_calc_normal(bm, &eloops); + } + BM_mesh_edgeloops_calc_order(bm, &eloops, use_pairs); + } + + for (el_store = eloops.first; el_store; el_store = el_store->next) { + LinkData *el_store_next = el_store->next; + + if (el_store_next == NULL) { + if (use_cyclic && (count > 2)) { + el_store_next = eloops.first; + } + else { + break; + } + } + + bridge_loop_pair(bm, + (struct BMEdgeLoopStore *)el_store, + (struct BMEdgeLoopStore *)el_store_next, + use_merge, + merge_factor, + twist_offset); + if (use_pairs) { + el_store = el_store->next; + } + changed = true; + } cleanup: - BM_mesh_edgeloops_free(&eloops); - - if (changed) { - if (use_merge == false) { - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, FACE_OUT); - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EDGE_OUT); - } - } + BM_mesh_edgeloops_free(&eloops); + + if (changed) { + if (use_merge == false) { + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, FACE_OUT); + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EDGE_OUT); + } + } } diff --git a/source/blender/bmesh/operators/bmo_connect.c b/source/blender/bmesh/operators/bmo_connect.c index d3cf3f2d945..e52467614ac 100644 --- a/source/blender/bmesh/operators/bmo_connect.c +++ b/source/blender/bmesh/operators/bmo_connect.c @@ -29,167 +29,163 @@ #include "intern/bmesh_operators_private.h" /* own include */ -#define VERT_INPUT 1 +#define VERT_INPUT 1 -#define EDGE_OUT 1 +#define EDGE_OUT 1 /* Edge spans 2 VERT_INPUT's, its a nop, * but include in "edges.out" */ -#define EDGE_OUT_ADJ 2 +#define EDGE_OUT_ADJ 2 -#define FACE_TAG 2 -#define FACE_EXCLUDE 4 +#define FACE_TAG 2 +#define FACE_EXCLUDE 4 static int bm_face_connect_verts(BMesh *bm, BMFace *f, const bool check_degenerate) { - const unsigned pair_split_max = f->len / 2; - BMLoop *(*loops_split)[2] = BLI_array_alloca(loops_split, pair_split_max); - STACK_DECLARE(loops_split); - BMVert *(*verts_pair)[2] = BLI_array_alloca(verts_pair, pair_split_max); - STACK_DECLARE(verts_pair); - - BMLoop *l_tag_prev = NULL, *l_tag_first = NULL; - BMLoop *l_iter, *l_first; - uint i; - - STACK_INIT(loops_split, pair_split_max); - STACK_INIT(verts_pair, pair_split_max); - - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - if (BMO_vert_flag_test(bm, l_iter->v, VERT_INPUT) && - /* ensure this vertex isnt part of a contiguous group */ - ((BMO_vert_flag_test(bm, l_iter->prev->v, VERT_INPUT) == 0) || - (BMO_vert_flag_test(bm, l_iter->next->v, VERT_INPUT) == 0))) - { - if (!l_tag_prev) { - l_tag_prev = l_tag_first = l_iter; - continue; - } - - if (!BM_loop_is_adjacent(l_tag_prev, l_iter)) { - BMEdge *e; - e = BM_edge_exists(l_tag_prev->v, l_iter->v); - if (e == NULL || !BMO_edge_flag_test(bm, e, EDGE_OUT)) { - BMLoop **l_pair = STACK_PUSH_RET(loops_split); - l_pair[0] = l_tag_prev; - l_pair[1] = l_iter; - } - } - - l_tag_prev = l_iter; - } - } while ((l_iter = l_iter->next) != l_first); - - if (STACK_SIZE(loops_split) == 0) { - return 0; - } - - if (!BM_loop_is_adjacent(l_tag_first, l_tag_prev) && - /* ensure we don't add the same pair twice */ - (((loops_split[0][0] == l_tag_first) && - (loops_split[0][1] == l_tag_prev)) == 0)) - { - BMLoop **l_pair = STACK_PUSH_RET(loops_split); - l_pair[0] = l_tag_first; - l_pair[1] = l_tag_prev; - } - - if (check_degenerate) { - BM_face_splits_check_legal(bm, f, loops_split, STACK_SIZE(loops_split)); - } - else { - BM_face_splits_check_optimal(f, loops_split, STACK_SIZE(loops_split)); - } - - for (i = 0; i < STACK_SIZE(loops_split); i++) { - BMVert **v_pair; - if (loops_split[i][0] == NULL) { - continue; - } - - v_pair = STACK_PUSH_RET(verts_pair); - v_pair[0] = loops_split[i][0]->v; - v_pair[1] = loops_split[i][1]->v; - } - - for (i = 0; i < STACK_SIZE(verts_pair); i++) { - BMFace *f_new; - BMLoop *l_new; - BMLoop *l_a, *l_b; - - if ((l_a = BM_face_vert_share_loop(f, verts_pair[i][0])) && - (l_b = BM_face_vert_share_loop(f, verts_pair[i][1]))) - { - f_new = BM_face_split(bm, f, l_a, l_b, &l_new, NULL, false); - } - else { - f_new = NULL; - l_new = NULL; - } - - f = f_new; - - if (!l_new || !f_new) { - return -1; - } - // BMO_face_flag_enable(bm, f_new, FACE_NEW); - BMO_edge_flag_enable(bm, l_new->e, EDGE_OUT); - } - - return 1; + const unsigned pair_split_max = f->len / 2; + BMLoop *(*loops_split)[2] = BLI_array_alloca(loops_split, pair_split_max); + STACK_DECLARE(loops_split); + BMVert *(*verts_pair)[2] = BLI_array_alloca(verts_pair, pair_split_max); + STACK_DECLARE(verts_pair); + + BMLoop *l_tag_prev = NULL, *l_tag_first = NULL; + BMLoop *l_iter, *l_first; + uint i; + + STACK_INIT(loops_split, pair_split_max); + STACK_INIT(verts_pair, pair_split_max); + + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (BMO_vert_flag_test(bm, l_iter->v, VERT_INPUT) && + /* ensure this vertex isnt part of a contiguous group */ + ((BMO_vert_flag_test(bm, l_iter->prev->v, VERT_INPUT) == 0) || + (BMO_vert_flag_test(bm, l_iter->next->v, VERT_INPUT) == 0))) { + if (!l_tag_prev) { + l_tag_prev = l_tag_first = l_iter; + continue; + } + + if (!BM_loop_is_adjacent(l_tag_prev, l_iter)) { + BMEdge *e; + e = BM_edge_exists(l_tag_prev->v, l_iter->v); + if (e == NULL || !BMO_edge_flag_test(bm, e, EDGE_OUT)) { + BMLoop **l_pair = STACK_PUSH_RET(loops_split); + l_pair[0] = l_tag_prev; + l_pair[1] = l_iter; + } + } + + l_tag_prev = l_iter; + } + } while ((l_iter = l_iter->next) != l_first); + + if (STACK_SIZE(loops_split) == 0) { + return 0; + } + + if (!BM_loop_is_adjacent(l_tag_first, l_tag_prev) && + /* ensure we don't add the same pair twice */ + (((loops_split[0][0] == l_tag_first) && (loops_split[0][1] == l_tag_prev)) == 0)) { + BMLoop **l_pair = STACK_PUSH_RET(loops_split); + l_pair[0] = l_tag_first; + l_pair[1] = l_tag_prev; + } + + if (check_degenerate) { + BM_face_splits_check_legal(bm, f, loops_split, STACK_SIZE(loops_split)); + } + else { + BM_face_splits_check_optimal(f, loops_split, STACK_SIZE(loops_split)); + } + + for (i = 0; i < STACK_SIZE(loops_split); i++) { + BMVert **v_pair; + if (loops_split[i][0] == NULL) { + continue; + } + + v_pair = STACK_PUSH_RET(verts_pair); + v_pair[0] = loops_split[i][0]->v; + v_pair[1] = loops_split[i][1]->v; + } + + for (i = 0; i < STACK_SIZE(verts_pair); i++) { + BMFace *f_new; + BMLoop *l_new; + BMLoop *l_a, *l_b; + + if ((l_a = BM_face_vert_share_loop(f, verts_pair[i][0])) && + (l_b = BM_face_vert_share_loop(f, verts_pair[i][1]))) { + f_new = BM_face_split(bm, f, l_a, l_b, &l_new, NULL, false); + } + else { + f_new = NULL; + l_new = NULL; + } + + f = f_new; + + if (!l_new || !f_new) { + return -1; + } + // BMO_face_flag_enable(bm, f_new, FACE_NEW); + BMO_edge_flag_enable(bm, l_new->e, EDGE_OUT); + } + + return 1; } - void bmo_connect_verts_exec(BMesh *bm, BMOperator *op) { - BMOIter siter; - BMVert *v; - BMFace *f; - const bool check_degenerate = BMO_slot_bool_get(op->slots_in, "check_degenerate"); - BLI_LINKSTACK_DECLARE(faces, BMFace *); - - BLI_LINKSTACK_INIT(faces); - - /* tag so we won't touch ever (typically hidden faces) */ - BMO_slot_buffer_flag_enable(bm, op->slots_in, "faces_exclude", BM_FACE, FACE_EXCLUDE); - - /* add all faces connected to verts */ - BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) { - BMIter iter; - BMLoop *l_iter; - - BMO_vert_flag_enable(bm, v, VERT_INPUT); - BM_ITER_ELEM (l_iter, &iter, v, BM_LOOPS_OF_VERT) { - f = l_iter->f; - if (!BMO_face_flag_test(bm, f, FACE_EXCLUDE)) { - if (!BMO_face_flag_test(bm, f, FACE_TAG)) { - BMO_face_flag_enable(bm, f, FACE_TAG); - if (f->len > 3) { - BLI_LINKSTACK_PUSH(faces, f); - } - } - } - - /* flag edges even if these are not newly created - * this way cut-pairs that include co-linear edges will get - * predictable output. */ - if (BMO_vert_flag_test(bm, l_iter->prev->v, VERT_INPUT)) { - BMO_edge_flag_enable(bm, l_iter->prev->e, EDGE_OUT_ADJ); - } - if (BMO_vert_flag_test(bm, l_iter->next->v, VERT_INPUT)) { - BMO_edge_flag_enable(bm, l_iter->e, EDGE_OUT_ADJ); - } - } - } - - /* connect faces */ - while ((f = BLI_LINKSTACK_POP(faces))) { - if (bm_face_connect_verts(bm, f, check_degenerate) == -1) { - BMO_error_raise(bm, op, BMERR_CONNECTVERT_FAILED, NULL); - } - } - - BLI_LINKSTACK_FREE(faces); - - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EDGE_OUT | EDGE_OUT_ADJ); + BMOIter siter; + BMVert *v; + BMFace *f; + const bool check_degenerate = BMO_slot_bool_get(op->slots_in, "check_degenerate"); + BLI_LINKSTACK_DECLARE(faces, BMFace *); + + BLI_LINKSTACK_INIT(faces); + + /* tag so we won't touch ever (typically hidden faces) */ + BMO_slot_buffer_flag_enable(bm, op->slots_in, "faces_exclude", BM_FACE, FACE_EXCLUDE); + + /* add all faces connected to verts */ + BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) { + BMIter iter; + BMLoop *l_iter; + + BMO_vert_flag_enable(bm, v, VERT_INPUT); + BM_ITER_ELEM (l_iter, &iter, v, BM_LOOPS_OF_VERT) { + f = l_iter->f; + if (!BMO_face_flag_test(bm, f, FACE_EXCLUDE)) { + if (!BMO_face_flag_test(bm, f, FACE_TAG)) { + BMO_face_flag_enable(bm, f, FACE_TAG); + if (f->len > 3) { + BLI_LINKSTACK_PUSH(faces, f); + } + } + } + + /* flag edges even if these are not newly created + * this way cut-pairs that include co-linear edges will get + * predictable output. */ + if (BMO_vert_flag_test(bm, l_iter->prev->v, VERT_INPUT)) { + BMO_edge_flag_enable(bm, l_iter->prev->e, EDGE_OUT_ADJ); + } + if (BMO_vert_flag_test(bm, l_iter->next->v, VERT_INPUT)) { + BMO_edge_flag_enable(bm, l_iter->e, EDGE_OUT_ADJ); + } + } + } + + /* connect faces */ + while ((f = BLI_LINKSTACK_POP(faces))) { + if (bm_face_connect_verts(bm, f, check_degenerate) == -1) { + BMO_error_raise(bm, op, BMERR_CONNECTVERT_FAILED, NULL); + } + } + + BLI_LINKSTACK_FREE(faces); + + BMO_slot_buffer_from_enabled_flag( + bm, op, op->slots_out, "edges.out", BM_EDGE, EDGE_OUT | EDGE_OUT_ADJ); } diff --git a/source/blender/bmesh/operators/bmo_connect_concave.c b/source/blender/bmesh/operators/bmo_connect_concave.c index 98527482f52..0d0c21774c3 100644 --- a/source/blender/bmesh/operators/bmo_connect_concave.c +++ b/source/blender/bmesh/operators/bmo_connect_concave.c @@ -43,178 +43,185 @@ #include "intern/bmesh_operators_private.h" /* own include */ -#define EDGE_OUT (1 << 0) -#define FACE_OUT (1 << 1) +#define EDGE_OUT (1 << 0) +#define FACE_OUT (1 << 1) static int bm_edge_length_cmp(const void *a_, const void *b_) { - const BMEdge *e_a = *(const void **)a_; - const BMEdge *e_b = *(const void **)b_; - - int e_a_concave = ((BM_elem_flag_test(e_a->v1, BM_ELEM_TAG)) && (BM_elem_flag_test(e_a->v2, BM_ELEM_TAG))); - int e_b_concave = ((BM_elem_flag_test(e_b->v1, BM_ELEM_TAG)) && (BM_elem_flag_test(e_b->v2, BM_ELEM_TAG))); - - /* merge edges between concave edges last since these - * are most likely to remain and be the main dividers */ - if (e_a_concave < e_b_concave) { return -1; } - else if (e_a_concave > e_b_concave) { return 1; } - else { - /* otherwise shortest edges last */ - const float e_a_len = BM_edge_calc_length_squared(e_a); - const float e_b_len = BM_edge_calc_length_squared(e_b); - if (e_a_len < e_b_len) { return 1; } - else if (e_a_len > e_b_len) { return -1; } - else { return 0; } - } + const BMEdge *e_a = *(const void **)a_; + const BMEdge *e_b = *(const void **)b_; + + int e_a_concave = ((BM_elem_flag_test(e_a->v1, BM_ELEM_TAG)) && + (BM_elem_flag_test(e_a->v2, BM_ELEM_TAG))); + int e_b_concave = ((BM_elem_flag_test(e_b->v1, BM_ELEM_TAG)) && + (BM_elem_flag_test(e_b->v2, BM_ELEM_TAG))); + + /* merge edges between concave edges last since these + * are most likely to remain and be the main dividers */ + if (e_a_concave < e_b_concave) { + return -1; + } + else if (e_a_concave > e_b_concave) { + return 1; + } + else { + /* otherwise shortest edges last */ + const float e_a_len = BM_edge_calc_length_squared(e_a); + const float e_b_len = BM_edge_calc_length_squared(e_b); + if (e_a_len < e_b_len) { + return 1; + } + else if (e_a_len > e_b_len) { + return -1; + } + else { + return 0; + } + } } -static bool bm_face_split_by_concave( - BMesh *bm, BMFace *f_base, const float eps, +static bool bm_face_split_by_concave(BMesh *bm, + BMFace *f_base, + const float eps, - MemArena *pf_arena, - struct Heap *pf_heap) + MemArena *pf_arena, + struct Heap *pf_heap) { - const int f_base_len = f_base->len; - int faces_array_tot = f_base_len - 3; - int edges_array_tot = f_base_len - 3; - BMFace **faces_array = BLI_array_alloca(faces_array, faces_array_tot); - BMEdge **edges_array = BLI_array_alloca(edges_array, edges_array_tot); - const int quad_method = 0, ngon_method = 0; /* beauty */ - LinkNode *faces_double = NULL; - - float normal[3]; - BLI_assert(f_base->len > 3); - - copy_v3_v3(normal, f_base->no); - - BM_face_triangulate( - bm, f_base, - faces_array, &faces_array_tot, - edges_array, &edges_array_tot, - &faces_double, - quad_method, ngon_method, false, - pf_arena, - pf_heap); - - BLI_assert(edges_array_tot <= f_base_len - 3); - - if (faces_array_tot) { - int i; - for (i = 0; i < faces_array_tot; i++) { - BMFace *f = faces_array[i]; - BMO_face_flag_enable(bm, f, FACE_OUT); - } - } - BMO_face_flag_enable(bm, f_base, FACE_OUT); - - if (edges_array_tot) { - int i; - - qsort(edges_array, edges_array_tot, sizeof(*edges_array), bm_edge_length_cmp); - - for (i = 0; i < edges_array_tot; i++) { - BMLoop *l_pair[2]; - BMEdge *e = edges_array[i]; - BMO_edge_flag_enable(bm, e, EDGE_OUT); - - if (BM_edge_is_contiguous(e) && - BM_edge_loop_pair(e, &l_pair[0], &l_pair[1])) - { - bool ok = true; - int j; - for (j = 0; j < 2; j++) { - BMLoop *l = l_pair[j]; - - /* check that merging the edge (on this side) - * wouldn't result in a convex face-loop. - * - * This is the (l->next, l->prev) we would have once joined. - */ - float cross[3]; - cross_tri_v3( - cross, - l->v->co, - l->radial_next->next->next->v->co, - l->prev->v->co - ); - - if (dot_v3v3(cross, normal) <= eps) { - ok = false; - break; - } - } - - if (ok) { - BMFace *f_new, *f_pair[2] = {l_pair[0]->f, l_pair[1]->f}; - f_new = BM_faces_join(bm, f_pair, 2, true); - if (f_new) { - BMO_face_flag_enable(bm, f_new, FACE_OUT); - } - } - } - } - } - - BLI_heap_clear(pf_heap, NULL); - - while (faces_double) { - LinkNode *next = faces_double->next; - BM_face_kill(bm, faces_double->link); - MEM_freeN(faces_double); - faces_double = next; - } - - return true; + const int f_base_len = f_base->len; + int faces_array_tot = f_base_len - 3; + int edges_array_tot = f_base_len - 3; + BMFace **faces_array = BLI_array_alloca(faces_array, faces_array_tot); + BMEdge **edges_array = BLI_array_alloca(edges_array, edges_array_tot); + const int quad_method = 0, ngon_method = 0; /* beauty */ + LinkNode *faces_double = NULL; + + float normal[3]; + BLI_assert(f_base->len > 3); + + copy_v3_v3(normal, f_base->no); + + BM_face_triangulate(bm, + f_base, + faces_array, + &faces_array_tot, + edges_array, + &edges_array_tot, + &faces_double, + quad_method, + ngon_method, + false, + pf_arena, + pf_heap); + + BLI_assert(edges_array_tot <= f_base_len - 3); + + if (faces_array_tot) { + int i; + for (i = 0; i < faces_array_tot; i++) { + BMFace *f = faces_array[i]; + BMO_face_flag_enable(bm, f, FACE_OUT); + } + } + BMO_face_flag_enable(bm, f_base, FACE_OUT); + + if (edges_array_tot) { + int i; + + qsort(edges_array, edges_array_tot, sizeof(*edges_array), bm_edge_length_cmp); + + for (i = 0; i < edges_array_tot; i++) { + BMLoop *l_pair[2]; + BMEdge *e = edges_array[i]; + BMO_edge_flag_enable(bm, e, EDGE_OUT); + + if (BM_edge_is_contiguous(e) && BM_edge_loop_pair(e, &l_pair[0], &l_pair[1])) { + bool ok = true; + int j; + for (j = 0; j < 2; j++) { + BMLoop *l = l_pair[j]; + + /* check that merging the edge (on this side) + * wouldn't result in a convex face-loop. + * + * This is the (l->next, l->prev) we would have once joined. + */ + float cross[3]; + cross_tri_v3(cross, l->v->co, l->radial_next->next->next->v->co, l->prev->v->co); + + if (dot_v3v3(cross, normal) <= eps) { + ok = false; + break; + } + } + + if (ok) { + BMFace *f_new, *f_pair[2] = {l_pair[0]->f, l_pair[1]->f}; + f_new = BM_faces_join(bm, f_pair, 2, true); + if (f_new) { + BMO_face_flag_enable(bm, f_new, FACE_OUT); + } + } + } + } + } + + BLI_heap_clear(pf_heap, NULL); + + while (faces_double) { + LinkNode *next = faces_double->next; + BM_face_kill(bm, faces_double->link); + MEM_freeN(faces_double); + faces_double = next; + } + + return true; } static bool bm_face_convex_tag_verts(BMFace *f) { - bool is_concave = false; - if (f->len > 3) { - const BMLoop *l_iter, *l_first; - - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - if (BM_loop_is_convex(l_iter) == false) { - is_concave = true; - BM_elem_flag_enable(l_iter->v, BM_ELEM_TAG); - } - else { - BM_elem_flag_disable(l_iter->v, BM_ELEM_TAG); - } - } while ((l_iter = l_iter->next) != l_first); - } - return is_concave; + bool is_concave = false; + if (f->len > 3) { + const BMLoop *l_iter, *l_first; + + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (BM_loop_is_convex(l_iter) == false) { + is_concave = true; + BM_elem_flag_enable(l_iter->v, BM_ELEM_TAG); + } + else { + BM_elem_flag_disable(l_iter->v, BM_ELEM_TAG); + } + } while ((l_iter = l_iter->next) != l_first); + } + return is_concave; } void bmo_connect_verts_concave_exec(BMesh *bm, BMOperator *op) { - BMOIter siter; - BMFace *f; - bool changed = false; - - MemArena *pf_arena; - Heap *pf_heap; - - pf_arena = BLI_memarena_new(BLI_POLYFILL_ARENA_SIZE, __func__); - pf_heap = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE); - - BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) { - if (f->len > 3 && bm_face_convex_tag_verts(f)) { - if (bm_face_split_by_concave( - bm, f, FLT_EPSILON, - pf_arena, pf_heap)) - { - changed = true; - } - } - } - - if (changed) { - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EDGE_OUT); - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, FACE_OUT); - } - - BLI_memarena_free(pf_arena); - BLI_heap_free(pf_heap, NULL); + BMOIter siter; + BMFace *f; + bool changed = false; + + MemArena *pf_arena; + Heap *pf_heap; + + pf_arena = BLI_memarena_new(BLI_POLYFILL_ARENA_SIZE, __func__); + pf_heap = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE); + + BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) { + if (f->len > 3 && bm_face_convex_tag_verts(f)) { + if (bm_face_split_by_concave(bm, f, FLT_EPSILON, pf_arena, pf_heap)) { + changed = true; + } + } + } + + if (changed) { + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EDGE_OUT); + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, FACE_OUT); + } + + BLI_memarena_free(pf_arena); + BLI_heap_free(pf_heap, NULL); } diff --git a/source/blender/bmesh/operators/bmo_connect_nonplanar.c b/source/blender/bmesh/operators/bmo_connect_nonplanar.c index 102892626f2..5be4826c7d3 100644 --- a/source/blender/bmesh/operators/bmo_connect_nonplanar.c +++ b/source/blender/bmesh/operators/bmo_connect_nonplanar.c @@ -29,153 +29,154 @@ #include "intern/bmesh_operators_private.h" /* own include */ -#define EDGE_OUT (1 << 0) -#define FACE_OUT (1 << 1) +#define EDGE_OUT (1 << 0) +#define FACE_OUT (1 << 1) /** * Calculates how non-planar the face subset is. */ static float bm_face_subset_calc_planar(BMLoop *l_first, BMLoop *l_last, const float no[3]) { - float axis_mat[3][3]; - float z_prev, z_curr; - float delta_z = 0.0f; + float axis_mat[3][3]; + float z_prev, z_curr; + float delta_z = 0.0f; - /* Newell's Method */ - BMLoop *l_iter = l_first; - BMLoop *l_term = l_last->next; + /* Newell's Method */ + BMLoop *l_iter = l_first; + BMLoop *l_term = l_last->next; - axis_dominant_v3_to_m3(axis_mat, no); + axis_dominant_v3_to_m3(axis_mat, no); - z_prev = dot_m3_v3_row_z(axis_mat, l_last->v->co); - do { - z_curr = dot_m3_v3_row_z(axis_mat, l_iter->v->co); - delta_z += fabsf(z_curr - z_prev); - z_prev = z_curr; - } while ((l_iter = l_iter->next) != l_term); + z_prev = dot_m3_v3_row_z(axis_mat, l_last->v->co); + do { + z_curr = dot_m3_v3_row_z(axis_mat, l_iter->v->co); + delta_z += fabsf(z_curr - z_prev); + z_prev = z_curr; + } while ((l_iter = l_iter->next) != l_term); - return delta_z; + return delta_z; } static bool bm_face_split_find(BMesh *bm, BMFace *f, BMLoop *l_pair[2], float *r_angle_cos) { - BMLoop *l_iter, *l_first; - BMLoop **l_arr = BLI_array_alloca(l_arr, f->len); - const uint f_len = f->len; - uint i_a, i_b; - bool found = false; - - /* angle finding */ - float err_best = FLT_MAX; - float angle_best_cos = -FLT_MAX; - - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - i_a = 0; - do { - l_arr[i_a++] = l_iter; - } while ((l_iter = l_iter->next) != l_first); - - /* now for the big search, O(N^2), however faces normally aren't so large */ - for (i_a = 0; i_a < f_len; i_a++) { - BMLoop *l_a = l_arr[i_a]; - for (i_b = i_a + 2; i_b < f_len; i_b++) { - BMLoop *l_b = l_arr[i_b]; - /* check these are not touching - * (we could be smarter here) */ - if (!BM_loop_is_adjacent(l_a, l_b)) { - /* first calculate normals */ - float no_a[3], no_b[3]; - - if (BM_face_calc_normal_subset(l_a, l_b, no_a) != 0.0f && - BM_face_calc_normal_subset(l_b, l_a, no_b) != 0.0f) - { - const float err_a = bm_face_subset_calc_planar(l_a, l_b, no_a); - const float err_b = bm_face_subset_calc_planar(l_b, l_a, no_b); - const float err_test = err_a + err_b; - - if (err_test < err_best) { - /* check we're legal (we could batch this) */ - BMLoop *l_split[2] = {l_a, l_b}; - BM_face_splits_check_legal(bm, f, &l_split, 1); - if (l_split[0]) { - err_best = err_test; - l_pair[0] = l_a; - l_pair[1] = l_b; - - angle_best_cos = dot_v3v3(no_a, no_b); - found = true; - } - } - } - } - } - } - - *r_angle_cos = angle_best_cos; - - return found; + BMLoop *l_iter, *l_first; + BMLoop **l_arr = BLI_array_alloca(l_arr, f->len); + const uint f_len = f->len; + uint i_a, i_b; + bool found = false; + + /* angle finding */ + float err_best = FLT_MAX; + float angle_best_cos = -FLT_MAX; + + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + i_a = 0; + do { + l_arr[i_a++] = l_iter; + } while ((l_iter = l_iter->next) != l_first); + + /* now for the big search, O(N^2), however faces normally aren't so large */ + for (i_a = 0; i_a < f_len; i_a++) { + BMLoop *l_a = l_arr[i_a]; + for (i_b = i_a + 2; i_b < f_len; i_b++) { + BMLoop *l_b = l_arr[i_b]; + /* check these are not touching + * (we could be smarter here) */ + if (!BM_loop_is_adjacent(l_a, l_b)) { + /* first calculate normals */ + float no_a[3], no_b[3]; + + if (BM_face_calc_normal_subset(l_a, l_b, no_a) != 0.0f && + BM_face_calc_normal_subset(l_b, l_a, no_b) != 0.0f) { + const float err_a = bm_face_subset_calc_planar(l_a, l_b, no_a); + const float err_b = bm_face_subset_calc_planar(l_b, l_a, no_b); + const float err_test = err_a + err_b; + + if (err_test < err_best) { + /* check we're legal (we could batch this) */ + BMLoop *l_split[2] = {l_a, l_b}; + BM_face_splits_check_legal(bm, f, &l_split, 1); + if (l_split[0]) { + err_best = err_test; + l_pair[0] = l_a; + l_pair[1] = l_b; + + angle_best_cos = dot_v3v3(no_a, no_b); + found = true; + } + } + } + } + } + } + + *r_angle_cos = angle_best_cos; + + return found; } -static bool bm_face_split_by_angle(BMesh *bm, BMFace *f, BMFace *r_f_pair[2], const float angle_limit_cos) +static bool bm_face_split_by_angle(BMesh *bm, + BMFace *f, + BMFace *r_f_pair[2], + const float angle_limit_cos) { - BMLoop *l_pair[2]; - float angle_cos; - - if (bm_face_split_find(bm, f, l_pair, &angle_cos) && (angle_cos < angle_limit_cos)) { - BMFace *f_new; - BMLoop *l_new; - - f_new = BM_face_split(bm, f, l_pair[0], l_pair[1], &l_new, NULL, false); - if (f_new) { - r_f_pair[0] = f; - r_f_pair[1] = f_new; - - BMO_face_flag_enable(bm, f, FACE_OUT); - BMO_face_flag_enable(bm, f_new, FACE_OUT); - BMO_edge_flag_enable(bm, l_new->e, EDGE_OUT); - return true; - } - } - - return false; - + BMLoop *l_pair[2]; + float angle_cos; + + if (bm_face_split_find(bm, f, l_pair, &angle_cos) && (angle_cos < angle_limit_cos)) { + BMFace *f_new; + BMLoop *l_new; + + f_new = BM_face_split(bm, f, l_pair[0], l_pair[1], &l_new, NULL, false); + if (f_new) { + r_f_pair[0] = f; + r_f_pair[1] = f_new; + + BMO_face_flag_enable(bm, f, FACE_OUT); + BMO_face_flag_enable(bm, f_new, FACE_OUT); + BMO_edge_flag_enable(bm, l_new->e, EDGE_OUT); + return true; + } + } + + return false; } void bmo_connect_verts_nonplanar_exec(BMesh *bm, BMOperator *op) { - BMOIter siter; - BMFace *f; - bool changed = false; - BLI_LINKSTACK_DECLARE(fstack, BMFace *); - - const float angle_limit_cos = cosf(BMO_slot_float_get(op->slots_in, "angle_limit")); - - BLI_LINKSTACK_INIT(fstack); - - BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) { - if (f->len > 3) { - BLI_LINKSTACK_PUSH(fstack, f); - } - } - - while ((f = BLI_LINKSTACK_POP(fstack))) { - BMFace *f_pair[2]; - if (bm_face_split_by_angle(bm, f, f_pair, angle_limit_cos)) { - int j; - for (j = 0; j < 2; j++) { - BM_face_normal_update(f_pair[j]); - if (f_pair[j]->len > 3) { - BLI_LINKSTACK_PUSH(fstack, f_pair[j]); - } - } - changed = true; - } - } - - BLI_LINKSTACK_FREE(fstack); - - if (changed) { - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EDGE_OUT); - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, FACE_OUT); - } + BMOIter siter; + BMFace *f; + bool changed = false; + BLI_LINKSTACK_DECLARE(fstack, BMFace *); + + const float angle_limit_cos = cosf(BMO_slot_float_get(op->slots_in, "angle_limit")); + + BLI_LINKSTACK_INIT(fstack); + + BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) { + if (f->len > 3) { + BLI_LINKSTACK_PUSH(fstack, f); + } + } + + while ((f = BLI_LINKSTACK_POP(fstack))) { + BMFace *f_pair[2]; + if (bm_face_split_by_angle(bm, f, f_pair, angle_limit_cos)) { + int j; + for (j = 0; j < 2; j++) { + BM_face_normal_update(f_pair[j]); + if (f_pair[j]->len > 3) { + BLI_LINKSTACK_PUSH(fstack, f_pair[j]); + } + } + changed = true; + } + } + + BLI_LINKSTACK_FREE(fstack); + + if (changed) { + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EDGE_OUT); + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, FACE_OUT); + } } diff --git a/source/blender/bmesh/operators/bmo_connect_pair.c b/source/blender/bmesh/operators/bmo_connect_pair.c index 41d574aa373..18568c364d6 100644 --- a/source/blender/bmesh/operators/bmo_connect_pair.c +++ b/source/blender/bmesh/operators/bmo_connect_pair.c @@ -59,21 +59,22 @@ /* any element we've walked over (only do it once!) */ #define ELE_TOUCHED 4 -#define FACE_WALK_TEST(f) (CHECK_TYPE_INLINE(f, BMFace *), \ - BMO_face_flag_test(pc->bm_bmoflag, f, FACE_EXCLUDE) == 0) -#define VERT_WALK_TEST(v) (CHECK_TYPE_INLINE(v, BMVert *), \ - BMO_vert_flag_test(pc->bm_bmoflag, v, VERT_EXCLUDE) == 0) +#define FACE_WALK_TEST(f) \ + (CHECK_TYPE_INLINE(f, BMFace *), BMO_face_flag_test(pc->bm_bmoflag, f, FACE_EXCLUDE) == 0) +#define VERT_WALK_TEST(v) \ + (CHECK_TYPE_INLINE(v, BMVert *), BMO_vert_flag_test(pc->bm_bmoflag, v, VERT_EXCLUDE) == 0) #if 0 -#define ELE_TOUCH_TEST(e) ( \ - CHECK_TYPE_ANY(e, BMVert *, BMEdge *, BMElem *, BMElemF *), \ - BMO_elem_flag_test(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED) \ -) +# define ELE_TOUCH_TEST(e) \ + (CHECK_TYPE_ANY(e, BMVert *, BMEdge *, BMElem *, BMElemF *), \ + BMO_elem_flag_test(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED)) #endif -#define ELE_TOUCH_MARK(e) { \ - CHECK_TYPE_ANY(e, BMVert *, BMEdge *, BMElem *, BMElemF *); \ - BMO_elem_flag_enable(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED); \ -} ((void)0) +#define ELE_TOUCH_MARK(e) \ + { \ + CHECK_TYPE_ANY(e, BMVert *, BMEdge *, BMElem *, BMElemF *); \ + BMO_elem_flag_enable(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED); \ + } \ + ((void)0) #define ELE_TOUCH_TEST_VERT(v) BMO_vert_flag_test(pc->bm_bmoflag, v, ELE_TOUCHED) // #define ELE_TOUCH_MARK_VERT(v) BMO_vert_flag_enable(pc->bm_bmoflag, (BMElemF *)v, ELE_TOUCHED) @@ -87,34 +88,34 @@ // #define DEBUG_PRINT typedef struct PathContext { - HeapSimple *states; - float matrix[3][3]; - float axis_sep; + HeapSimple *states; + float matrix[3][3]; + float axis_sep; - /* only to access BMO flags */ - BMesh *bm_bmoflag; + /* only to access BMO flags */ + BMesh *bm_bmoflag; - BMVert *v_a, *v_b; + BMVert *v_a, *v_b; - BLI_mempool *link_pool; + BLI_mempool *link_pool; } PathContext; /** * Single linked list where each item contains state and points to previous path item. */ typedef struct PathLink { - struct PathLink *next; - BMElem *ele; /* edge or vert */ - BMElem *ele_from; /* edge or face we came from (not 'next->ele') */ + struct PathLink *next; + BMElem *ele; /* edge or vert */ + BMElem *ele_from; /* edge or face we came from (not 'next->ele') */ } PathLink; typedef struct PathLinkState { - /* chain of links */ - struct PathLink *link_last; + /* chain of links */ + struct PathLink *link_last; - /* length along links */ - float dist; - float co_prev[3]; + /* length along links */ + float dist; + float co_prev[3]; } PathLinkState; /** @@ -133,91 +134,91 @@ typedef struct PathLinkState { * \{ */ typedef struct MinDistDir { - /* distance in both directions (FLT_MAX == uninitialized) */ - float dist_min[2]; - /* direction of the first intersection found */ - float dir[3]; + /* distance in both directions (FLT_MAX == uninitialized) */ + float dist_min[2]; + /* direction of the first intersection found */ + float dir[3]; } MinDistDir; -#define MIN_DIST_DIR_INIT {{FLT_MAX, FLT_MAX}} +#define MIN_DIST_DIR_INIT \ + { \ + { \ + FLT_MAX, FLT_MAX \ + } \ + } static int min_dist_dir_test(MinDistDir *mddir, const float dist_dir[3], const float dist_sq) { - if (mddir->dist_min[0] == FLT_MAX) { - return 0; - } - else { - if (dot_v3v3(dist_dir, mddir->dir) > 0.0f) { - if (dist_sq < mddir->dist_min[0]) { - return 0; - } - } - else { - if (dist_sq < mddir->dist_min[1]) { - return 1; - } - } - } - - return -1; + if (mddir->dist_min[0] == FLT_MAX) { + return 0; + } + else { + if (dot_v3v3(dist_dir, mddir->dir) > 0.0f) { + if (dist_sq < mddir->dist_min[0]) { + return 0; + } + } + else { + if (dist_sq < mddir->dist_min[1]) { + return 1; + } + } + } + + return -1; } static void min_dist_dir_update(MinDistDir *dist, const float dist_dir[3]) { - if (dist->dist_min[0] == FLT_MAX) { - copy_v3_v3(dist->dir, dist_dir); - } + if (dist->dist_min[0] == FLT_MAX) { + copy_v3_v3(dist->dir, dist_dir); + } } /** \} */ - -static int state_isect_co_pair( - const PathContext *pc, - const float co_a[3], const float co_b[3]) +static int state_isect_co_pair(const PathContext *pc, const float co_a[3], const float co_b[3]) { - const float diff_a = dot_m3_v3_row_x((float (*)[3])pc->matrix, co_a) - pc->axis_sep; - const float diff_b = dot_m3_v3_row_x((float (*)[3])pc->matrix, co_b) - pc->axis_sep; - - const int test_a = (fabsf(diff_a) < CONNECT_EPS) ? 0 : (diff_a < 0.0f) ? -1 : 1; - const int test_b = (fabsf(diff_b) < CONNECT_EPS) ? 0 : (diff_b < 0.0f) ? -1 : 1; - - if ((test_a && test_b) && (test_a != test_b)) { - return 1; /* on either side */ - } - else { - return 0; - } + const float diff_a = dot_m3_v3_row_x((float(*)[3])pc->matrix, co_a) - pc->axis_sep; + const float diff_b = dot_m3_v3_row_x((float(*)[3])pc->matrix, co_b) - pc->axis_sep; + + const int test_a = (fabsf(diff_a) < CONNECT_EPS) ? 0 : (diff_a < 0.0f) ? -1 : 1; + const int test_b = (fabsf(diff_b) < CONNECT_EPS) ? 0 : (diff_b < 0.0f) ? -1 : 1; + + if ((test_a && test_b) && (test_a != test_b)) { + return 1; /* on either side */ + } + else { + return 0; + } } -static int state_isect_co_exact( - const PathContext *pc, - const float co[3]) +static int state_isect_co_exact(const PathContext *pc, const float co[3]) { - const float diff = dot_m3_v3_row_x((float (*)[3])pc->matrix, co) - pc->axis_sep; - return (fabsf(diff) <= CONNECT_EPS); + const float diff = dot_m3_v3_row_x((float(*)[3])pc->matrix, co) - pc->axis_sep; + return (fabsf(diff) <= CONNECT_EPS); } -static float state_calc_co_pair_fac( - const PathContext *pc, - const float co_a[3], const float co_b[3]) +static float state_calc_co_pair_fac(const PathContext *pc, + const float co_a[3], + const float co_b[3]) { - float diff_a, diff_b, diff_tot; + float diff_a, diff_b, diff_tot; - diff_a = fabsf(dot_m3_v3_row_x((float (*)[3])pc->matrix, co_a) - pc->axis_sep); - diff_b = fabsf(dot_m3_v3_row_x((float (*)[3])pc->matrix, co_b) - pc->axis_sep); - diff_tot = (diff_a + diff_b); - return (diff_tot > FLT_EPSILON) ? (diff_a / diff_tot) : 0.5f; + diff_a = fabsf(dot_m3_v3_row_x((float(*)[3])pc->matrix, co_a) - pc->axis_sep); + diff_b = fabsf(dot_m3_v3_row_x((float(*)[3])pc->matrix, co_b) - pc->axis_sep); + diff_tot = (diff_a + diff_b); + return (diff_tot > FLT_EPSILON) ? (diff_a / diff_tot) : 0.5f; } -static void state_calc_co_pair( - const PathContext *pc, - const float co_a[3], const float co_b[3], - float r_co[3]) +static void state_calc_co_pair(const PathContext *pc, + const float co_a[3], + const float co_b[3], + float r_co[3]) { - const float fac = state_calc_co_pair_fac(pc, co_a, co_b); - interp_v3_v3v3(r_co, co_a, co_b, fac); + const float fac = state_calc_co_pair_fac(pc, co_a, co_b); + interp_v3_v3v3(r_co, co_a, co_b, fac); } #ifndef NDEBUG @@ -227,276 +228,268 @@ static void state_calc_co_pair( */ static bool state_link_find(const PathLinkState *state, BMElem *ele) { - PathLink *link = state->link_last; - BLI_assert(ELEM(ele->head.htype, BM_VERT, BM_EDGE, BM_FACE)); - if (link) { - do { - if (link->ele == ele) { - return true; - } - } while ((link = link->next)); - } - return false; + PathLink *link = state->link_last; + BLI_assert(ELEM(ele->head.htype, BM_VERT, BM_EDGE, BM_FACE)); + if (link) { + do { + if (link->ele == ele) { + return true; + } + } while ((link = link->next)); + } + return false; } #endif -static void state_link_add( - PathContext *pc, PathLinkState *state, - BMElem *ele, BMElem *ele_from) +static void state_link_add(PathContext *pc, PathLinkState *state, BMElem *ele, BMElem *ele_from) { - PathLink *step_new = BLI_mempool_alloc(pc->link_pool); - BLI_assert(ele != ele_from); - BLI_assert(state_link_find(state, ele) == false); + PathLink *step_new = BLI_mempool_alloc(pc->link_pool); + BLI_assert(ele != ele_from); + BLI_assert(state_link_find(state, ele) == false); - /* never walk onto this again */ - ELE_TOUCH_MARK(ele); + /* never walk onto this again */ + ELE_TOUCH_MARK(ele); #ifdef DEBUG_PRINT - printf("%s: adding to state %p, %.4f - ", __func__, state, state->dist); - if (ele->head.htype == BM_VERT) { - printf("vert %d, ", BM_elem_index_get(ele)); - } - else if (ele->head.htype == BM_EDGE) { - printf("edge %d, ", BM_elem_index_get(ele)); - } - else { - BLI_assert(0); - } - - if (ele_from == NULL) { - printf("from NULL\n"); - } - else if (ele_from->head.htype == BM_EDGE) { - printf("from edge %d\n", BM_elem_index_get(ele_from)); - } - else if (ele_from->head.htype == BM_FACE) { - printf("from face %d\n", BM_elem_index_get(ele_from)); - } - else { - BLI_assert(0); - } + printf("%s: adding to state %p, %.4f - ", __func__, state, state->dist); + if (ele->head.htype == BM_VERT) { + printf("vert %d, ", BM_elem_index_get(ele)); + } + else if (ele->head.htype == BM_EDGE) { + printf("edge %d, ", BM_elem_index_get(ele)); + } + else { + BLI_assert(0); + } + + if (ele_from == NULL) { + printf("from NULL\n"); + } + else if (ele_from->head.htype == BM_EDGE) { + printf("from edge %d\n", BM_elem_index_get(ele_from)); + } + else if (ele_from->head.htype == BM_FACE) { + printf("from face %d\n", BM_elem_index_get(ele_from)); + } + else { + BLI_assert(0); + } #endif - /* track distance */ - { - float co[3]; - if (ele->head.htype == BM_VERT) { - copy_v3_v3(co, ((BMVert *)ele)->co); - } - else if (ele->head.htype == BM_EDGE) { - state_calc_co_pair(pc, ((BMEdge *)ele)->v1->co, ((BMEdge *)ele)->v2->co, co); - } - else { - BLI_assert(0); - } - - /* tally distance */ - if (ele_from) { - state->dist += len_v3v3(state->co_prev, co); - } - copy_v3_v3(state->co_prev, co); - } - - step_new->ele = ele; - step_new->ele_from = ele_from; - step_new->next = state->link_last; - state->link_last = step_new; + /* track distance */ + { + float co[3]; + if (ele->head.htype == BM_VERT) { + copy_v3_v3(co, ((BMVert *)ele)->co); + } + else if (ele->head.htype == BM_EDGE) { + state_calc_co_pair(pc, ((BMEdge *)ele)->v1->co, ((BMEdge *)ele)->v2->co, co); + } + else { + BLI_assert(0); + } + + /* tally distance */ + if (ele_from) { + state->dist += len_v3v3(state->co_prev, co); + } + copy_v3_v3(state->co_prev, co); + } + + step_new->ele = ele; + step_new->ele_from = ele_from; + step_new->next = state->link_last; + state->link_last = step_new; } -static PathLinkState *state_dupe_add( - PathLinkState *state, const PathLinkState *state_orig) +static PathLinkState *state_dupe_add(PathLinkState *state, const PathLinkState *state_orig) { - state = MEM_mallocN(sizeof(*state), __func__); - *state = *state_orig; - return state; + state = MEM_mallocN(sizeof(*state), __func__); + *state = *state_orig; + return state; } -static PathLinkState *state_link_add_test( - PathContext *pc, PathLinkState *state, const PathLinkState *state_orig, - BMElem *ele, BMElem *ele_from) +static PathLinkState *state_link_add_test(PathContext *pc, + PathLinkState *state, + const PathLinkState *state_orig, + BMElem *ele, + BMElem *ele_from) { - const bool is_new = (state_orig->link_last != state->link_last); - if (is_new) { - state = state_dupe_add(state, state_orig); - } + const bool is_new = (state_orig->link_last != state->link_last); + if (is_new) { + state = state_dupe_add(state, state_orig); + } - state_link_add(pc, state, ele, ele_from); + state_link_add(pc, state, ele, ele_from); - /* after adding a link so we use the updated 'state->dist' */ - if (is_new) { - BLI_heapsimple_insert(pc->states, state->dist, state); - } + /* after adding a link so we use the updated 'state->dist' */ + if (is_new) { + BLI_heapsimple_insert(pc->states, state->dist, state); + } - return state; + return state; } /* walk around the face edges */ -static PathLinkState *state_step__face_edges( - PathContext *pc, - PathLinkState *state, const PathLinkState *state_orig, - BMLoop *l_iter, BMLoop *l_last, - MinDistDir *mddir) +static PathLinkState *state_step__face_edges(PathContext *pc, + PathLinkState *state, + const PathLinkState *state_orig, + BMLoop *l_iter, + BMLoop *l_last, + MinDistDir *mddir) { - BMLoop *l_iter_best[2] = {NULL, NULL}; - int i; - - do { - if (state_isect_co_pair(pc, l_iter->v->co, l_iter->next->v->co)) { - float dist_test; - float co_isect[3]; - float dist_dir[3]; - int index; - - state_calc_co_pair(pc, l_iter->v->co, l_iter->next->v->co, co_isect); - - sub_v3_v3v3(dist_dir, co_isect, state_orig->co_prev); - dist_test = len_squared_v3(dist_dir); - if ((index = min_dist_dir_test(mddir, dist_dir, dist_test)) != -1) { - BMElem *ele_next = (BMElem *)l_iter->e; - BMElem *ele_next_from = (BMElem *)l_iter->f; - - if (FACE_WALK_TEST((BMFace *)ele_next_from) && - (ELE_TOUCH_TEST_EDGE((BMEdge *)ele_next) == false)) - { - min_dist_dir_update(mddir, dist_dir); - mddir->dist_min[index] = dist_test; - l_iter_best[index] = l_iter; - } - } - } - } while ((l_iter = l_iter->next) != l_last); - - for (i = 0; i < 2; i++) { - if ((l_iter = l_iter_best[i])) { - BMElem *ele_next = (BMElem *)l_iter->e; - BMElem *ele_next_from = (BMElem *)l_iter->f; - state = state_link_add_test(pc, state, state_orig, ele_next, ele_next_from); - } - } - - return state; + BMLoop *l_iter_best[2] = {NULL, NULL}; + int i; + + do { + if (state_isect_co_pair(pc, l_iter->v->co, l_iter->next->v->co)) { + float dist_test; + float co_isect[3]; + float dist_dir[3]; + int index; + + state_calc_co_pair(pc, l_iter->v->co, l_iter->next->v->co, co_isect); + + sub_v3_v3v3(dist_dir, co_isect, state_orig->co_prev); + dist_test = len_squared_v3(dist_dir); + if ((index = min_dist_dir_test(mddir, dist_dir, dist_test)) != -1) { + BMElem *ele_next = (BMElem *)l_iter->e; + BMElem *ele_next_from = (BMElem *)l_iter->f; + + if (FACE_WALK_TEST((BMFace *)ele_next_from) && + (ELE_TOUCH_TEST_EDGE((BMEdge *)ele_next) == false)) { + min_dist_dir_update(mddir, dist_dir); + mddir->dist_min[index] = dist_test; + l_iter_best[index] = l_iter; + } + } + } + } while ((l_iter = l_iter->next) != l_last); + + for (i = 0; i < 2; i++) { + if ((l_iter = l_iter_best[i])) { + BMElem *ele_next = (BMElem *)l_iter->e; + BMElem *ele_next_from = (BMElem *)l_iter->f; + state = state_link_add_test(pc, state, state_orig, ele_next, ele_next_from); + } + } + + return state; } /* walk around the face verts */ -static PathLinkState *state_step__face_verts( - PathContext *pc, - PathLinkState *state, const PathLinkState *state_orig, - BMLoop *l_iter, BMLoop *l_last, - MinDistDir *mddir) +static PathLinkState *state_step__face_verts(PathContext *pc, + PathLinkState *state, + const PathLinkState *state_orig, + BMLoop *l_iter, + BMLoop *l_last, + MinDistDir *mddir) { - BMLoop *l_iter_best[2] = {NULL, NULL}; - int i; - - do { - if (state_isect_co_exact(pc, l_iter->v->co)) { - float dist_test; - const float *co_isect = l_iter->v->co; - float dist_dir[3]; - int index; - - sub_v3_v3v3(dist_dir, co_isect, state_orig->co_prev); - dist_test = len_squared_v3(dist_dir); - if ((index = min_dist_dir_test(mddir, dist_dir, dist_test)) != -1) { - BMElem *ele_next = (BMElem *)l_iter->v; - BMElem *ele_next_from = (BMElem *)l_iter->f; - - if (FACE_WALK_TEST((BMFace *)ele_next_from) && - (ELE_TOUCH_TEST_VERT((BMVert *)ele_next) == false)) - { - min_dist_dir_update(mddir, dist_dir); - mddir->dist_min[index] = dist_test; - l_iter_best[index] = l_iter; - } - } - } - } while ((l_iter = l_iter->next) != l_last); - - for (i = 0; i < 2; i++) { - if ((l_iter = l_iter_best[i])) { - BMElem *ele_next = (BMElem *)l_iter->v; - BMElem *ele_next_from = (BMElem *)l_iter->f; - state = state_link_add_test(pc, state, state_orig, ele_next, ele_next_from); - } - } - - return state; + BMLoop *l_iter_best[2] = {NULL, NULL}; + int i; + + do { + if (state_isect_co_exact(pc, l_iter->v->co)) { + float dist_test; + const float *co_isect = l_iter->v->co; + float dist_dir[3]; + int index; + + sub_v3_v3v3(dist_dir, co_isect, state_orig->co_prev); + dist_test = len_squared_v3(dist_dir); + if ((index = min_dist_dir_test(mddir, dist_dir, dist_test)) != -1) { + BMElem *ele_next = (BMElem *)l_iter->v; + BMElem *ele_next_from = (BMElem *)l_iter->f; + + if (FACE_WALK_TEST((BMFace *)ele_next_from) && + (ELE_TOUCH_TEST_VERT((BMVert *)ele_next) == false)) { + min_dist_dir_update(mddir, dist_dir); + mddir->dist_min[index] = dist_test; + l_iter_best[index] = l_iter; + } + } + } + } while ((l_iter = l_iter->next) != l_last); + + for (i = 0; i < 2; i++) { + if ((l_iter = l_iter_best[i])) { + BMElem *ele_next = (BMElem *)l_iter->v; + BMElem *ele_next_from = (BMElem *)l_iter->f; + state = state_link_add_test(pc, state, state_orig, ele_next, ele_next_from); + } + } + + return state; } static bool state_step(PathContext *pc, PathLinkState *state) { - PathLinkState state_orig = *state; - BMElem *ele = state->link_last->ele; - const void *ele_from = state->link_last->ele_from; - - if (ele->head.htype == BM_EDGE) { - BMEdge *e = (BMEdge *)ele; - - BMIter liter; - BMLoop *l_start; - - BM_ITER_ELEM (l_start, &liter, e, BM_LOOPS_OF_EDGE) { - if ((l_start->f != ele_from) && - FACE_WALK_TEST(l_start->f)) - { - MinDistDir mddir = MIN_DIST_DIR_INIT; - /* very similar to block below */ - state = state_step__face_edges(pc, state, &state_orig, - l_start->next, l_start, &mddir); - state = state_step__face_verts(pc, state, &state_orig, - l_start->next->next, l_start, &mddir); - } - } - } - else if (ele->head.htype == BM_VERT) { - BMVert *v = (BMVert *)ele; - - /* vert loops */ - { - BMIter liter; - BMLoop *l_start; - - BM_ITER_ELEM (l_start, &liter, v, BM_LOOPS_OF_VERT) { - if ((l_start->f != ele_from) && - FACE_WALK_TEST(l_start->f)) - { - MinDistDir mddir = MIN_DIST_DIR_INIT; - /* very similar to block above */ - state = state_step__face_edges(pc, state, &state_orig, - l_start->next, l_start->prev, &mddir); - if (l_start->f->len > 3) { - /* adjacent verts are handled in state_step__vert_edges */ - state = state_step__face_verts(pc, state, &state_orig, - l_start->next->next, l_start->prev, &mddir); - } - } - } - } - - /* vert edges */ - { - BMIter eiter; - BMEdge *e; - BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - BMVert *v_other = BM_edge_other_vert(e, v); - if (((BMElem *)e != ele_from) && - VERT_WALK_TEST(v_other)) - { - if (state_isect_co_exact(pc, v_other->co)) { - BMElem *ele_next = (BMElem *)v_other; - BMElem *ele_next_from = (BMElem *)e; - if (ELE_TOUCH_TEST_VERT((BMVert *)ele_next) == false) { - state = state_link_add_test(pc, state, &state_orig, ele_next, ele_next_from); - } - } - } - } - } - } - else { - BLI_assert(0); - } - return (state_orig.link_last != state->link_last); + PathLinkState state_orig = *state; + BMElem *ele = state->link_last->ele; + const void *ele_from = state->link_last->ele_from; + + if (ele->head.htype == BM_EDGE) { + BMEdge *e = (BMEdge *)ele; + + BMIter liter; + BMLoop *l_start; + + BM_ITER_ELEM (l_start, &liter, e, BM_LOOPS_OF_EDGE) { + if ((l_start->f != ele_from) && FACE_WALK_TEST(l_start->f)) { + MinDistDir mddir = MIN_DIST_DIR_INIT; + /* very similar to block below */ + state = state_step__face_edges(pc, state, &state_orig, l_start->next, l_start, &mddir); + state = state_step__face_verts( + pc, state, &state_orig, l_start->next->next, l_start, &mddir); + } + } + } + else if (ele->head.htype == BM_VERT) { + BMVert *v = (BMVert *)ele; + + /* vert loops */ + { + BMIter liter; + BMLoop *l_start; + + BM_ITER_ELEM (l_start, &liter, v, BM_LOOPS_OF_VERT) { + if ((l_start->f != ele_from) && FACE_WALK_TEST(l_start->f)) { + MinDistDir mddir = MIN_DIST_DIR_INIT; + /* very similar to block above */ + state = state_step__face_edges( + pc, state, &state_orig, l_start->next, l_start->prev, &mddir); + if (l_start->f->len > 3) { + /* adjacent verts are handled in state_step__vert_edges */ + state = state_step__face_verts( + pc, state, &state_orig, l_start->next->next, l_start->prev, &mddir); + } + } + } + } + + /* vert edges */ + { + BMIter eiter; + BMEdge *e; + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + BMVert *v_other = BM_edge_other_vert(e, v); + if (((BMElem *)e != ele_from) && VERT_WALK_TEST(v_other)) { + if (state_isect_co_exact(pc, v_other->co)) { + BMElem *ele_next = (BMElem *)v_other; + BMElem *ele_next_from = (BMElem *)e; + if (ELE_TOUCH_TEST_VERT((BMVert *)ele_next) == false) { + state = state_link_add_test(pc, state, &state_orig, ele_next, ele_next_from); + } + } + } + } + } + } + else { + BLI_assert(0); + } + return (state_orig.link_last != state->link_last); } /** @@ -504,239 +497,244 @@ static bool state_step(PathContext *pc, PathLinkState *state) */ static void bm_vert_pair_to_matrix(BMVert *v_pair[2], float r_unit_mat[3][3]) { - const float eps = 1e-8f; + const float eps = 1e-8f; - float basis_dir[3]; - float basis_tmp[3]; - float basis_nor[3]; + float basis_dir[3]; + float basis_tmp[3]; + float basis_nor[3]; - sub_v3_v3v3(basis_dir, v_pair[0]->co, v_pair[1]->co); - normalize_v3(basis_dir); + sub_v3_v3v3(basis_dir, v_pair[0]->co, v_pair[1]->co); + normalize_v3(basis_dir); #if 0 - add_v3_v3v3(basis_nor, v_pair[0]->no, v_pair[1]->no); - cross_v3_v3v3(basis_tmp, basis_nor, basis_dir); - cross_v3_v3v3(basis_nor, basis_tmp, basis_dir); + add_v3_v3v3(basis_nor, v_pair[0]->no, v_pair[1]->no); + cross_v3_v3v3(basis_tmp, basis_nor, basis_dir); + cross_v3_v3v3(basis_nor, basis_tmp, basis_dir); #else - /* align both normals to the directions before combining */ - { - float basis_nor_a[3]; - float basis_nor_b[3]; - - /* align normal to direction */ - project_plane_normalized_v3_v3v3(basis_nor_a, v_pair[0]->no, basis_dir); - project_plane_normalized_v3_v3v3(basis_nor_b, v_pair[1]->no, basis_dir); - - /* don't normalize before combining so as normals approach the direction, they have less effect (T46784). */ - - /* combine the normals */ - /* for flipped faces */ - if (dot_v3v3(basis_nor_a, basis_nor_b) < 0.0f) { - negate_v3(basis_nor_b); - } - add_v3_v3v3(basis_nor, basis_nor_a, basis_nor_b); - } + /* align both normals to the directions before combining */ + { + float basis_nor_a[3]; + float basis_nor_b[3]; + + /* align normal to direction */ + project_plane_normalized_v3_v3v3(basis_nor_a, v_pair[0]->no, basis_dir); + project_plane_normalized_v3_v3v3(basis_nor_b, v_pair[1]->no, basis_dir); + + /* don't normalize before combining so as normals approach the direction, they have less effect (T46784). */ + + /* combine the normals */ + /* for flipped faces */ + if (dot_v3v3(basis_nor_a, basis_nor_b) < 0.0f) { + negate_v3(basis_nor_b); + } + add_v3_v3v3(basis_nor, basis_nor_a, basis_nor_b); + } #endif - /* get third axis */ - normalize_v3(basis_nor); - cross_v3_v3v3(basis_tmp, basis_dir, basis_nor); - - - /* Try get the axis from surrounding faces, fallback to 'ortho_v3_v3' */ - if (UNLIKELY(normalize_v3(basis_tmp) < eps)) { - /* vertex normals are directly opposite */ - - /* find the loop with the lowest angle */ - struct { float nor[3]; float angle_cos; } axis_pair[2]; - int i; - - for (i = 0; i < 2; i++) { - BMIter liter; - BMLoop *l; - - zero_v2(axis_pair[i].nor); - axis_pair[i].angle_cos = -FLT_MAX; - - BM_ITER_ELEM (l, &liter, v_pair[i], BM_LOOPS_OF_VERT) { - float basis_dir_proj[3]; - float angle_cos_test; - - /* project basis dir onto the normal to find its closest angle */ - project_plane_normalized_v3_v3v3(basis_dir_proj, basis_dir, l->f->no); - - if (normalize_v3(basis_dir_proj) > eps) { - angle_cos_test = dot_v3v3(basis_dir_proj, basis_dir); - - if (angle_cos_test > axis_pair[i].angle_cos) { - axis_pair[i].angle_cos = angle_cos_test; - copy_v3_v3(axis_pair[i].nor, basis_dir_proj); - } - } - } - } - - /* create a new 'basis_nor' from the best direction. - * note: we could add the directions, - * but this more often gives 45d rotated matrix, so just use the best one. */ - copy_v3_v3(basis_nor, axis_pair[axis_pair[0].angle_cos < axis_pair[1].angle_cos].nor); - project_plane_normalized_v3_v3v3(basis_nor, basis_nor, basis_dir); - - cross_v3_v3v3(basis_tmp, basis_dir, basis_nor); - - /* last resort, pick _any_ ortho axis */ - if (UNLIKELY(normalize_v3(basis_tmp) < eps)) { - ortho_v3_v3(basis_nor, basis_dir); - normalize_v3(basis_nor); - cross_v3_v3v3(basis_tmp, basis_dir, basis_nor); - normalize_v3(basis_tmp); - } - } - - copy_v3_v3(r_unit_mat[0], basis_tmp); - copy_v3_v3(r_unit_mat[1], basis_dir); - copy_v3_v3(r_unit_mat[2], basis_nor); - if (invert_m3(r_unit_mat) == false) { - unit_m3(r_unit_mat); - } + /* get third axis */ + normalize_v3(basis_nor); + cross_v3_v3v3(basis_tmp, basis_dir, basis_nor); + + /* Try get the axis from surrounding faces, fallback to 'ortho_v3_v3' */ + if (UNLIKELY(normalize_v3(basis_tmp) < eps)) { + /* vertex normals are directly opposite */ + + /* find the loop with the lowest angle */ + struct { + float nor[3]; + float angle_cos; + } axis_pair[2]; + int i; + + for (i = 0; i < 2; i++) { + BMIter liter; + BMLoop *l; + + zero_v2(axis_pair[i].nor); + axis_pair[i].angle_cos = -FLT_MAX; + + BM_ITER_ELEM (l, &liter, v_pair[i], BM_LOOPS_OF_VERT) { + float basis_dir_proj[3]; + float angle_cos_test; + + /* project basis dir onto the normal to find its closest angle */ + project_plane_normalized_v3_v3v3(basis_dir_proj, basis_dir, l->f->no); + + if (normalize_v3(basis_dir_proj) > eps) { + angle_cos_test = dot_v3v3(basis_dir_proj, basis_dir); + + if (angle_cos_test > axis_pair[i].angle_cos) { + axis_pair[i].angle_cos = angle_cos_test; + copy_v3_v3(axis_pair[i].nor, basis_dir_proj); + } + } + } + } + + /* create a new 'basis_nor' from the best direction. + * note: we could add the directions, + * but this more often gives 45d rotated matrix, so just use the best one. */ + copy_v3_v3(basis_nor, axis_pair[axis_pair[0].angle_cos < axis_pair[1].angle_cos].nor); + project_plane_normalized_v3_v3v3(basis_nor, basis_nor, basis_dir); + + cross_v3_v3v3(basis_tmp, basis_dir, basis_nor); + + /* last resort, pick _any_ ortho axis */ + if (UNLIKELY(normalize_v3(basis_tmp) < eps)) { + ortho_v3_v3(basis_nor, basis_dir); + normalize_v3(basis_nor); + cross_v3_v3v3(basis_tmp, basis_dir, basis_nor); + normalize_v3(basis_tmp); + } + } + + copy_v3_v3(r_unit_mat[0], basis_tmp); + copy_v3_v3(r_unit_mat[1], basis_dir); + copy_v3_v3(r_unit_mat[2], basis_nor); + if (invert_m3(r_unit_mat) == false) { + unit_m3(r_unit_mat); + } } void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op) { - BMOpSlot *op_verts_slot = BMO_slot_get(op->slots_in, "verts"); + BMOpSlot *op_verts_slot = BMO_slot_get(op->slots_in, "verts"); - PathContext pc; - PathLinkState state_best = {NULL}; + PathContext pc; + PathLinkState state_best = {NULL}; - if (op_verts_slot->len != 2) { - /* fail! */ - return; - } + if (op_verts_slot->len != 2) { + /* fail! */ + return; + } - pc.bm_bmoflag = bm; - pc.v_a = ((BMVert **)op_verts_slot->data.p)[0]; - pc.v_b = ((BMVert **)op_verts_slot->data.p)[1]; + pc.bm_bmoflag = bm; + pc.v_a = ((BMVert **)op_verts_slot->data.p)[0]; + pc.v_b = ((BMVert **)op_verts_slot->data.p)[1]; - /* fail! */ - if (!(pc.v_a && pc.v_b)) { - return; - } + /* fail! */ + if (!(pc.v_a && pc.v_b)) { + return; + } #ifdef DEBUG_PRINT - printf("%s: v_a: %d\n", __func__, BM_elem_index_get(pc.v_a)); - printf("%s: v_b: %d\n", __func__, BM_elem_index_get(pc.v_b)); + printf("%s: v_a: %d\n", __func__, BM_elem_index_get(pc.v_a)); + printf("%s: v_b: %d\n", __func__, BM_elem_index_get(pc.v_b)); #endif - /* tag so we won't touch ever (typically hidden faces) */ - BMO_slot_buffer_flag_enable(bm, op->slots_in, "faces_exclude", BM_FACE, FACE_EXCLUDE); - BMO_slot_buffer_flag_enable(bm, op->slots_in, "verts_exclude", BM_VERT, VERT_EXCLUDE); - - /* setup context */ - { - pc.states = BLI_heapsimple_new(); - pc.link_pool = BLI_mempool_create(sizeof(PathLink), 0, 512, BLI_MEMPOOL_NOP); - } + /* tag so we won't touch ever (typically hidden faces) */ + BMO_slot_buffer_flag_enable(bm, op->slots_in, "faces_exclude", BM_FACE, FACE_EXCLUDE); + BMO_slot_buffer_flag_enable(bm, op->slots_in, "verts_exclude", BM_VERT, VERT_EXCLUDE); - /* calculate matrix */ - { - bm_vert_pair_to_matrix(&pc.v_a, pc.matrix); - pc.axis_sep = dot_m3_v3_row_x(pc.matrix, pc.v_a->co); - } + /* setup context */ + { + pc.states = BLI_heapsimple_new(); + pc.link_pool = BLI_mempool_create(sizeof(PathLink), 0, 512, BLI_MEMPOOL_NOP); + } - /* add first vertex */ - { - PathLinkState *state; - state = MEM_callocN(sizeof(*state), __func__); - state_link_add(&pc, state, (BMElem *)pc.v_a, NULL); - BLI_heapsimple_insert(pc.states, state->dist, state); - } + /* calculate matrix */ + { + bm_vert_pair_to_matrix(&pc.v_a, pc.matrix); + pc.axis_sep = dot_m3_v3_row_x(pc.matrix, pc.v_a->co); + } + /* add first vertex */ + { + PathLinkState *state; + state = MEM_callocN(sizeof(*state), __func__); + state_link_add(&pc, state, (BMElem *)pc.v_a, NULL); + BLI_heapsimple_insert(pc.states, state->dist, state); + } - while (!BLI_heapsimple_is_empty(pc.states)) { + while (!BLI_heapsimple_is_empty(pc.states)) { #ifdef DEBUG_PRINT - printf("\n%s: stepping %u\n", __func__, BLI_heapsimple_len(pc.states)); + printf("\n%s: stepping %u\n", __func__, BLI_heapsimple_len(pc.states)); #endif - while (!BLI_heapsimple_is_empty(pc.states)) { - PathLinkState *state = BLI_heapsimple_pop_min(pc.states); + while (!BLI_heapsimple_is_empty(pc.states)) { + PathLinkState *state = BLI_heapsimple_pop_min(pc.states); - /* either we insert this into 'pc.states' or its freed */ - bool continue_search; + /* either we insert this into 'pc.states' or its freed */ + bool continue_search; - if (state->link_last->ele == (BMElem *)pc.v_b) { - /* pass, wait until all are found */ + if (state->link_last->ele == (BMElem *)pc.v_b) { + /* pass, wait until all are found */ #ifdef DEBUG_PRINT - printf("%s: state %p loop found %.4f\n", __func__, state, state->dist); + printf("%s: state %p loop found %.4f\n", __func__, state, state->dist); #endif - state_best = *state; - - /* we're done, exit all loops */ - BLI_heapsimple_clear(pc.states, MEM_freeN); - continue_search = false; - } - else if (state_step(&pc, state)) { - continue_search = true; - } - else { - /* didn't reach the end, remove it, - * links are shared between states so just free the link_pool at the end */ + state_best = *state; + + /* we're done, exit all loops */ + BLI_heapsimple_clear(pc.states, MEM_freeN); + continue_search = false; + } + else if (state_step(&pc, state)) { + continue_search = true; + } + else { + /* didn't reach the end, remove it, + * links are shared between states so just free the link_pool at the end */ #ifdef DEBUG_PRINT - printf("%s: state %p removed\n", __func__, state); + printf("%s: state %p removed\n", __func__, state); #endif - continue_search = false; - } - - if (continue_search) { - BLI_heapsimple_insert(pc.states, state->dist, state); - } - else { - MEM_freeN(state); - } - } - } - - if (state_best.link_last) { - PathLink *link; - - /* find the best state */ - link = state_best.link_last; - do { - if (link->ele->head.htype == BM_EDGE) { - BMEdge *e = (BMEdge *)link->ele; - BMVert *v_new; - float e_fac = state_calc_co_pair_fac(&pc, e->v1->co, e->v2->co); - v_new = BM_edge_split(bm, e, e->v1, NULL, e_fac); - BMO_vert_flag_enable(bm, v_new, VERT_OUT); - } - else if (link->ele->head.htype == BM_VERT) { - BMVert *v = (BMVert *)link->ele; - BMO_vert_flag_enable(bm, v, VERT_OUT); - } - else { - BLI_assert(0); - } - } while ((link = link->next)); - } - - BMO_vert_flag_enable(bm, pc.v_a, VERT_OUT); - BMO_vert_flag_enable(bm, pc.v_b, VERT_OUT); - - BLI_mempool_destroy(pc.link_pool); - - BLI_heapsimple_free(pc.states, MEM_freeN); + continue_search = false; + } + + if (continue_search) { + BLI_heapsimple_insert(pc.states, state->dist, state); + } + else { + MEM_freeN(state); + } + } + } + + if (state_best.link_last) { + PathLink *link; + + /* find the best state */ + link = state_best.link_last; + do { + if (link->ele->head.htype == BM_EDGE) { + BMEdge *e = (BMEdge *)link->ele; + BMVert *v_new; + float e_fac = state_calc_co_pair_fac(&pc, e->v1->co, e->v2->co); + v_new = BM_edge_split(bm, e, e->v1, NULL, e_fac); + BMO_vert_flag_enable(bm, v_new, VERT_OUT); + } + else if (link->ele->head.htype == BM_VERT) { + BMVert *v = (BMVert *)link->ele; + BMO_vert_flag_enable(bm, v, VERT_OUT); + } + else { + BLI_assert(0); + } + } while ((link = link->next)); + } + + BMO_vert_flag_enable(bm, pc.v_a, VERT_OUT); + BMO_vert_flag_enable(bm, pc.v_b, VERT_OUT); + + BLI_mempool_destroy(pc.link_pool); + + BLI_heapsimple_free(pc.states, MEM_freeN); #if 1 - if (state_best.link_last) { - BMOperator op_sub; - BMO_op_initf(bm, &op_sub, 0, - "connect_verts verts=%fv faces_exclude=%s check_degenerate=%b", - VERT_OUT, op, "faces_exclude", true); - BMO_op_exec(bm, &op_sub); - BMO_slot_copy(&op_sub, slots_out, "edges.out", - op, slots_out, "edges.out"); - BMO_op_finish(bm, &op_sub); - } + if (state_best.link_last) { + BMOperator op_sub; + BMO_op_initf(bm, + &op_sub, + 0, + "connect_verts verts=%fv faces_exclude=%s check_degenerate=%b", + VERT_OUT, + op, + "faces_exclude", + true); + BMO_op_exec(bm, &op_sub); + BMO_slot_copy(&op_sub, slots_out, "edges.out", op, slots_out, "edges.out"); + BMO_op_finish(bm, &op_sub); + } #endif } diff --git a/source/blender/bmesh/operators/bmo_create.c b/source/blender/bmesh/operators/bmo_create.c index 001c3004ec9..c799b177843 100644 --- a/source/blender/bmesh/operators/bmo_create.c +++ b/source/blender/bmesh/operators/bmo_create.c @@ -28,8 +28,8 @@ #include "intern/bmesh_operators_private.h" /* own include */ -#define ELE_NEW 1 -#define ELE_OUT 2 +#define ELE_NEW 1 +#define ELE_OUT 2 /* This is what runs when pressing the F key * doing the best thing here isn't always easy create vs dissolve, its nice to support @@ -37,269 +37,273 @@ */ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op) { - BMOIter oiter; - BMHeader *h; - int totv = 0, tote = 0, totf = 0; - const short mat_nr = BMO_slot_int_get(op->slots_in, "mat_nr"); - const bool use_smooth = BMO_slot_bool_get(op->slots_in, "use_smooth"); - - /* count number of each element type we were passe */ - BMO_ITER (h, &oiter, op->slots_in, "geom", BM_VERT | BM_EDGE | BM_FACE) { - switch (h->htype) { - case BM_VERT: - BMO_vert_flag_enable(bm, (BMVert *)h, ELE_NEW); - totv++; - break; - case BM_EDGE: - BMO_edge_flag_enable(bm, (BMEdge *)h, ELE_NEW); - tote++; - break; - case BM_FACE: - BMO_face_flag_enable(bm, (BMFace *)h, ELE_NEW); - totf++; - break; - } - } - - /* --- Support Edge Creation --- - * simple case when we only have 2 verts selected. - */ - if (totv == 2 && tote == 0 && totf == 0) { - BMVert *verts[2]; - BMEdge *e; - - if (BMO_iter_as_array(op->slots_in, "geom", BM_VERT, (void **)verts, 2) == 2) { - /* create edge */ - e = BM_edge_create(bm, verts[0], verts[1], NULL, BM_CREATE_NO_DOUBLE); - BMO_edge_flag_enable(bm, e, ELE_OUT); - tote += 1; - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, ELE_OUT); - } - return; - } - - - /* --- Support for Special Case --- - * where there is a contiguous edge ring with one isolated vertex. - * - * This example shows 2 edges created from 3 verts - * with 1 free standing vertex. Dotted lines denote the 2 edges that are created. - * - * note that this works for any sided shape. - * - * +--------+ - * | . - * | . - * | . - * | . - * +........+ <-- starts out free standing. - * - */ - - /* Here we check for consistency and create 2 edges */ - if (totf == 0 && totv >= 4 && totv == tote + 2) { - /* find a free standing vertex and 2 endpoint verts */ - BMVert *v, *v_free = NULL, *v_a = NULL, *v_b = NULL; - bool ok = true; - - - BMO_ITER (v, &oiter, op->slots_in, "geom", BM_VERT) { - /* count how many flagged edges this vertex uses */ - const int tot_edges = BMO_iter_elem_count_flag(bm, BM_EDGES_OF_VERT, v, ELE_NEW, true); - if (tot_edges == 0) { - /* only accept 1 free vert */ - if (v_free == NULL) { v_free = v; } - else { ok = false; } /* only ever want one of these */ - } - else if (tot_edges == 1) { - if (v_a == NULL) { v_a = v; } - else if (v_b == NULL) { v_b = v; } - else { ok = false; } /* only ever want 2 of these */ - } - else if (tot_edges == 2) { - /* do nothing, regular case */ - } - else { - ok = false; /* if a vertex has 3+ edge users then cancel - this is only simple cases */ - } - - if (ok == false) { - break; - } - } - - if (ok == true && v_free && v_a && v_b) { - BMEdge *e; - - e = BM_edge_create(bm, v_free, v_a, NULL, BM_CREATE_NO_DOUBLE); - BMO_edge_flag_enable(bm, e, ELE_NEW); - - e = BM_edge_create(bm, v_free, v_b, NULL, BM_CREATE_NO_DOUBLE); - BMO_edge_flag_enable(bm, e, ELE_NEW); - tote += 2; - } - } - /* --- end special case support, continue as normal --- */ - - - /* -------------------------------------------------------------------- */ - /* EdgeNet Create */ - if (tote != 0) { - /* call edgenet prepare op so additional face creation cases work */ - - BMOperator op_sub; - BMO_op_initf(bm, &op_sub, op->flag, "edgenet_prepare edges=%fe", ELE_NEW); - BMO_op_exec(bm, &op_sub); - BMO_slot_buffer_flag_enable(bm, op_sub.slots_out, "edges.out", BM_EDGE, ELE_NEW); - BMO_op_finish(bm, &op_sub); - - BMO_op_initf(bm, &op_sub, op->flag, - "edgenet_fill edges=%fe mat_nr=%i use_smooth=%b sides=%i", - ELE_NEW, mat_nr, use_smooth, 10000); - - BMO_op_exec(bm, &op_sub); - - /* return if edge net create did something */ - if (BMO_slot_buffer_count(op_sub.slots_out, "faces.out")) { - BMO_slot_copy(&op_sub, slots_out, "faces.out", - op, slots_out, "faces.out"); - BMO_op_finish(bm, &op_sub); - return; - } - - BMO_op_finish(bm, &op_sub); - } - - - /* -------------------------------------------------------------------- */ - /* Dissolve Face */ - if (totf != 0) { /* should be (totf > 1)... see below */ - /* note: allow this to run on single faces so running on a single face - * won't go on to create a face, treating them as random */ - BMOperator op_sub; - BMO_op_initf(bm, &op_sub, op->flag, "dissolve_faces faces=%ff", ELE_NEW); - BMO_op_exec(bm, &op_sub); - - /* if we dissolved anything, then return */ - if (BMO_slot_buffer_count(op_sub.slots_out, "region.out")) { - BMO_slot_copy(&op_sub, slots_out, "region.out", - op, slots_out, "faces.out"); - BMO_op_finish(bm, &op_sub); - return; - } - - BMO_op_finish(bm, &op_sub); - } - - - /* -------------------------------------------------------------------- */ - /* Fill EdgeLoop's - fills isolated loops, different from edgenet */ - if (tote > 2) { - BMOperator op_sub; - /* note: in most cases 'edgenet_fill' will handle this case since in common cases - * users fill in empty spaces, however its possible to have an edge selection around - * existing geometry that makes 'edgenet_fill' fail. */ - BMO_op_initf(bm, &op_sub, op->flag, "edgeloop_fill edges=%fe", ELE_NEW); - BMO_op_exec(bm, &op_sub); - - /* return if edge loop fill did something */ - if (BMO_slot_buffer_count(op_sub.slots_out, "faces.out")) { - BMO_slot_copy(&op_sub, slots_out, "faces.out", - op, slots_out, "faces.out"); - BMO_op_finish(bm, &op_sub); - return; - } - - BMO_op_finish(bm, &op_sub); - } - - - - /* -------------------------------------------------------------------- */ - /* Continue with ad-hoc fill methods since operators fail, - * edge, vcloud... may add more */ - - if (0) { /* nice feature but perhaps it should be a different tool? */ - - /* tricky feature for making a line/edge from selection history... - * - * Rather then do nothing, when 5+ verts are selected, check if they are in our history, - * when this is so, we can make edges from them, but _not_ a face, - * if it is the intention to make a face the user can just hit F again since there will be edges next - * time around. - * - * if all history verts have ELE_NEW flagged and the total number of history verts == totv, - * then we know the history contains all verts here and we can continue... - */ - - BMEditSelection *ese; - int tot_ese_v = 0; - - for (ese = bm->selected.first; ese; ese = ese->next) { - if (ese->htype == BM_VERT) { - if (BMO_vert_flag_test(bm, (BMVert *)ese->ele, ELE_NEW)) { - tot_ese_v++; - } - else { - /* unflagged vert means we are not in sync */ - tot_ese_v = -1; - break; - } - } - } - - if (tot_ese_v == totv) { - BMVert *v_prev = NULL; - /* yes, all select-history verts are accounted for, now make edges */ - - for (ese = bm->selected.first; ese; ese = ese->next) { - if (ese->htype == BM_VERT) { - BMVert *v = (BMVert *)ese->ele; - if (v_prev) { - BMEdge *e = BM_edge_create(bm, v, v_prev, NULL, BM_CREATE_NO_DOUBLE); - BMO_edge_flag_enable(bm, e, ELE_OUT); - } - v_prev = v; - } - } - } - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, ELE_OUT); - /* done creating edges */ - - return; - } - - - /* -------------------------------------------------------------------- */ - /* Fill Vertex Cloud - * - * last resort when all else fails. - */ - if (totv > 2) { - /* TODO, some of these vertes may be connected by edges, - * this connectivity could be used rather than treating - * them as a bunch of isolated verts. */ - - BMVert **vert_arr = MEM_mallocN(sizeof(BMVert *) * totv, __func__); - BMFace *f; - - totv = BMO_iter_as_array(op->slots_in, "geom", BM_VERT, (void **)vert_arr, totv); - - BM_verts_sort_radial_plane(vert_arr, totv); - - /* create edges and find the winding (if faces are attached to any existing edges) */ - f = BM_face_create_ngon_verts(bm, vert_arr, totv, NULL, BM_CREATE_NO_DOUBLE, true, true); - - if (f) { - BMO_face_flag_enable(bm, f, ELE_OUT); - f->mat_nr = mat_nr; - if (use_smooth) { - BM_elem_flag_enable(f, BM_ELEM_SMOOTH); - } - BM_face_copy_shared(bm, f, NULL, NULL); - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, ELE_OUT); - } - - MEM_freeN(vert_arr); - } + BMOIter oiter; + BMHeader *h; + int totv = 0, tote = 0, totf = 0; + const short mat_nr = BMO_slot_int_get(op->slots_in, "mat_nr"); + const bool use_smooth = BMO_slot_bool_get(op->slots_in, "use_smooth"); + + /* count number of each element type we were passe */ + BMO_ITER (h, &oiter, op->slots_in, "geom", BM_VERT | BM_EDGE | BM_FACE) { + switch (h->htype) { + case BM_VERT: + BMO_vert_flag_enable(bm, (BMVert *)h, ELE_NEW); + totv++; + break; + case BM_EDGE: + BMO_edge_flag_enable(bm, (BMEdge *)h, ELE_NEW); + tote++; + break; + case BM_FACE: + BMO_face_flag_enable(bm, (BMFace *)h, ELE_NEW); + totf++; + break; + } + } + + /* --- Support Edge Creation --- + * simple case when we only have 2 verts selected. + */ + if (totv == 2 && tote == 0 && totf == 0) { + BMVert *verts[2]; + BMEdge *e; + + if (BMO_iter_as_array(op->slots_in, "geom", BM_VERT, (void **)verts, 2) == 2) { + /* create edge */ + e = BM_edge_create(bm, verts[0], verts[1], NULL, BM_CREATE_NO_DOUBLE); + BMO_edge_flag_enable(bm, e, ELE_OUT); + tote += 1; + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, ELE_OUT); + } + return; + } + + /* --- Support for Special Case --- + * where there is a contiguous edge ring with one isolated vertex. + * + * This example shows 2 edges created from 3 verts + * with 1 free standing vertex. Dotted lines denote the 2 edges that are created. + * + * note that this works for any sided shape. + * + * +--------+ + * | . + * | . + * | . + * | . + * +........+ <-- starts out free standing. + * + */ + + /* Here we check for consistency and create 2 edges */ + if (totf == 0 && totv >= 4 && totv == tote + 2) { + /* find a free standing vertex and 2 endpoint verts */ + BMVert *v, *v_free = NULL, *v_a = NULL, *v_b = NULL; + bool ok = true; + + BMO_ITER (v, &oiter, op->slots_in, "geom", BM_VERT) { + /* count how many flagged edges this vertex uses */ + const int tot_edges = BMO_iter_elem_count_flag(bm, BM_EDGES_OF_VERT, v, ELE_NEW, true); + if (tot_edges == 0) { + /* only accept 1 free vert */ + if (v_free == NULL) { + v_free = v; + } + else { + ok = false; + } /* only ever want one of these */ + } + else if (tot_edges == 1) { + if (v_a == NULL) { + v_a = v; + } + else if (v_b == NULL) { + v_b = v; + } + else { + ok = false; + } /* only ever want 2 of these */ + } + else if (tot_edges == 2) { + /* do nothing, regular case */ + } + else { + ok = false; /* if a vertex has 3+ edge users then cancel - this is only simple cases */ + } + + if (ok == false) { + break; + } + } + + if (ok == true && v_free && v_a && v_b) { + BMEdge *e; + + e = BM_edge_create(bm, v_free, v_a, NULL, BM_CREATE_NO_DOUBLE); + BMO_edge_flag_enable(bm, e, ELE_NEW); + + e = BM_edge_create(bm, v_free, v_b, NULL, BM_CREATE_NO_DOUBLE); + BMO_edge_flag_enable(bm, e, ELE_NEW); + tote += 2; + } + } + /* --- end special case support, continue as normal --- */ + + /* -------------------------------------------------------------------- */ + /* EdgeNet Create */ + if (tote != 0) { + /* call edgenet prepare op so additional face creation cases work */ + + BMOperator op_sub; + BMO_op_initf(bm, &op_sub, op->flag, "edgenet_prepare edges=%fe", ELE_NEW); + BMO_op_exec(bm, &op_sub); + BMO_slot_buffer_flag_enable(bm, op_sub.slots_out, "edges.out", BM_EDGE, ELE_NEW); + BMO_op_finish(bm, &op_sub); + + BMO_op_initf(bm, + &op_sub, + op->flag, + "edgenet_fill edges=%fe mat_nr=%i use_smooth=%b sides=%i", + ELE_NEW, + mat_nr, + use_smooth, + 10000); + + BMO_op_exec(bm, &op_sub); + + /* return if edge net create did something */ + if (BMO_slot_buffer_count(op_sub.slots_out, "faces.out")) { + BMO_slot_copy(&op_sub, slots_out, "faces.out", op, slots_out, "faces.out"); + BMO_op_finish(bm, &op_sub); + return; + } + + BMO_op_finish(bm, &op_sub); + } + + /* -------------------------------------------------------------------- */ + /* Dissolve Face */ + if (totf != 0) { /* should be (totf > 1)... see below */ + /* note: allow this to run on single faces so running on a single face + * won't go on to create a face, treating them as random */ + BMOperator op_sub; + BMO_op_initf(bm, &op_sub, op->flag, "dissolve_faces faces=%ff", ELE_NEW); + BMO_op_exec(bm, &op_sub); + + /* if we dissolved anything, then return */ + if (BMO_slot_buffer_count(op_sub.slots_out, "region.out")) { + BMO_slot_copy(&op_sub, slots_out, "region.out", op, slots_out, "faces.out"); + BMO_op_finish(bm, &op_sub); + return; + } + + BMO_op_finish(bm, &op_sub); + } + + /* -------------------------------------------------------------------- */ + /* Fill EdgeLoop's - fills isolated loops, different from edgenet */ + if (tote > 2) { + BMOperator op_sub; + /* note: in most cases 'edgenet_fill' will handle this case since in common cases + * users fill in empty spaces, however its possible to have an edge selection around + * existing geometry that makes 'edgenet_fill' fail. */ + BMO_op_initf(bm, &op_sub, op->flag, "edgeloop_fill edges=%fe", ELE_NEW); + BMO_op_exec(bm, &op_sub); + + /* return if edge loop fill did something */ + if (BMO_slot_buffer_count(op_sub.slots_out, "faces.out")) { + BMO_slot_copy(&op_sub, slots_out, "faces.out", op, slots_out, "faces.out"); + BMO_op_finish(bm, &op_sub); + return; + } + + BMO_op_finish(bm, &op_sub); + } + + /* -------------------------------------------------------------------- */ + /* Continue with ad-hoc fill methods since operators fail, + * edge, vcloud... may add more */ + + if (0) { /* nice feature but perhaps it should be a different tool? */ + + /* tricky feature for making a line/edge from selection history... + * + * Rather then do nothing, when 5+ verts are selected, check if they are in our history, + * when this is so, we can make edges from them, but _not_ a face, + * if it is the intention to make a face the user can just hit F again since there will be edges next + * time around. + * + * if all history verts have ELE_NEW flagged and the total number of history verts == totv, + * then we know the history contains all verts here and we can continue... + */ + + BMEditSelection *ese; + int tot_ese_v = 0; + + for (ese = bm->selected.first; ese; ese = ese->next) { + if (ese->htype == BM_VERT) { + if (BMO_vert_flag_test(bm, (BMVert *)ese->ele, ELE_NEW)) { + tot_ese_v++; + } + else { + /* unflagged vert means we are not in sync */ + tot_ese_v = -1; + break; + } + } + } + + if (tot_ese_v == totv) { + BMVert *v_prev = NULL; + /* yes, all select-history verts are accounted for, now make edges */ + + for (ese = bm->selected.first; ese; ese = ese->next) { + if (ese->htype == BM_VERT) { + BMVert *v = (BMVert *)ese->ele; + if (v_prev) { + BMEdge *e = BM_edge_create(bm, v, v_prev, NULL, BM_CREATE_NO_DOUBLE); + BMO_edge_flag_enable(bm, e, ELE_OUT); + } + v_prev = v; + } + } + } + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, ELE_OUT); + /* done creating edges */ + + return; + } + + /* -------------------------------------------------------------------- */ + /* Fill Vertex Cloud + * + * last resort when all else fails. + */ + if (totv > 2) { + /* TODO, some of these vertes may be connected by edges, + * this connectivity could be used rather than treating + * them as a bunch of isolated verts. */ + + BMVert **vert_arr = MEM_mallocN(sizeof(BMVert *) * totv, __func__); + BMFace *f; + + totv = BMO_iter_as_array(op->slots_in, "geom", BM_VERT, (void **)vert_arr, totv); + + BM_verts_sort_radial_plane(vert_arr, totv); + + /* create edges and find the winding (if faces are attached to any existing edges) */ + f = BM_face_create_ngon_verts(bm, vert_arr, totv, NULL, BM_CREATE_NO_DOUBLE, true, true); + + if (f) { + BMO_face_flag_enable(bm, f, ELE_OUT); + f->mat_nr = mat_nr; + if (use_smooth) { + BM_elem_flag_enable(f, BM_ELEM_SMOOTH); + } + BM_face_copy_shared(bm, f, NULL, NULL); + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, ELE_OUT); + } + + MEM_freeN(vert_arr); + } } diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c index d04fe2b7146..9cea982f6bd 100644 --- a/source/blender/bmesh/operators/bmo_dissolve.c +++ b/source/blender/bmesh/operators/bmo_dissolve.c @@ -31,603 +31,604 @@ #include "intern/bmesh_operators_private.h" - /* ***_ISGC: mark for garbage-collection */ -#define FACE_MARK 1 -#define FACE_ORIG 2 -#define FACE_NEW 4 -#define FACE_TAG 8 +#define FACE_MARK 1 +#define FACE_ORIG 2 +#define FACE_NEW 4 +#define FACE_TAG 8 -#define EDGE_MARK 1 -#define EDGE_TAG 2 -#define EDGE_ISGC 8 +#define EDGE_MARK 1 +#define EDGE_TAG 2 +#define EDGE_ISGC 8 -#define VERT_MARK 1 +#define VERT_MARK 1 #define VERT_MARK_PAIR 4 -#define VERT_TAG 2 -#define VERT_ISGC 8 +#define VERT_TAG 2 +#define VERT_ISGC 8 #define VERT_MARK_TEAR 16 - - -static bool UNUSED_FUNCTION(check_hole_in_region) (BMesh *bm, BMFace *f) +static bool UNUSED_FUNCTION(check_hole_in_region)(BMesh *bm, BMFace *f) { - BMWalker regwalker; - BMIter liter2; - BMLoop *l2, *l3; - BMFace *f2; - - /* checks if there are any unmarked boundary edges in the face regio */ - - BMW_init(®walker, bm, BMW_ISLAND, - BMW_MASK_NOP, BMW_MASK_NOP, FACE_MARK, - BMW_FLAG_NOP, - BMW_NIL_LAY); - - for (f2 = BMW_begin(®walker, f); f2; f2 = BMW_step(®walker)) { - BM_ITER_ELEM (l2, &liter2, f2, BM_LOOPS_OF_FACE) { - l3 = l2->radial_next; - if (BMO_face_flag_test(bm, l3->f, FACE_MARK) != - BMO_face_flag_test(bm, l2->f, FACE_MARK)) - { - if (!BMO_edge_flag_test(bm, l2->e, EDGE_MARK)) { - return false; - } - } - } - } - BMW_end(®walker); - - return true; + BMWalker regwalker; + BMIter liter2; + BMLoop *l2, *l3; + BMFace *f2; + + /* checks if there are any unmarked boundary edges in the face regio */ + + BMW_init(®walker, + bm, + BMW_ISLAND, + BMW_MASK_NOP, + BMW_MASK_NOP, + FACE_MARK, + BMW_FLAG_NOP, + BMW_NIL_LAY); + + for (f2 = BMW_begin(®walker, f); f2; f2 = BMW_step(®walker)) { + BM_ITER_ELEM (l2, &liter2, f2, BM_LOOPS_OF_FACE) { + l3 = l2->radial_next; + if (BMO_face_flag_test(bm, l3->f, FACE_MARK) != BMO_face_flag_test(bm, l2->f, FACE_MARK)) { + if (!BMO_edge_flag_test(bm, l2->e, EDGE_MARK)) { + return false; + } + } + } + } + BMW_end(®walker); + + return true; } static void bm_face_split(BMesh *bm, const short oflag, bool use_edge_delete) { - BLI_Stack *edge_delete_verts; - BMIter iter; - BMVert *v; - - if (use_edge_delete) { - edge_delete_verts = BLI_stack_new(sizeof(BMVert *), __func__); - } - - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (BMO_vert_flag_test(bm, v, oflag)) { - if (BM_vert_is_edge_pair(v) == false) { - BMIter liter; - BMLoop *l; - BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { - if (l->f->len > 3) { - if (BMO_vert_flag_test(bm, l->next->v, oflag) == 0 && - BMO_vert_flag_test(bm, l->prev->v, oflag) == 0) - { - BM_face_split(bm, l->f, l->next, l->prev, NULL, NULL, true); - } - } - } - - if (use_edge_delete) { - BLI_stack_push(edge_delete_verts, &v); - } - } - } - } - - if (use_edge_delete) { - while (!BLI_stack_is_empty(edge_delete_verts)) { - /* remove surrounding edges & faces */ - BLI_stack_pop(edge_delete_verts, &v); - while (v->e) { - BM_edge_kill(bm, v->e); - } - } - BLI_stack_free(edge_delete_verts); - } + BLI_Stack *edge_delete_verts; + BMIter iter; + BMVert *v; + + if (use_edge_delete) { + edge_delete_verts = BLI_stack_new(sizeof(BMVert *), __func__); + } + + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (BMO_vert_flag_test(bm, v, oflag)) { + if (BM_vert_is_edge_pair(v) == false) { + BMIter liter; + BMLoop *l; + BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { + if (l->f->len > 3) { + if (BMO_vert_flag_test(bm, l->next->v, oflag) == 0 && + BMO_vert_flag_test(bm, l->prev->v, oflag) == 0) { + BM_face_split(bm, l->f, l->next, l->prev, NULL, NULL, true); + } + } + } + + if (use_edge_delete) { + BLI_stack_push(edge_delete_verts, &v); + } + } + } + } + + if (use_edge_delete) { + while (!BLI_stack_is_empty(edge_delete_verts)) { + /* remove surrounding edges & faces */ + BLI_stack_pop(edge_delete_verts, &v); + while (v->e) { + BM_edge_kill(bm, v->e); + } + } + BLI_stack_free(edge_delete_verts); + } } void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op) { - BMOIter oiter; - BMFace *f; - BMFace ***regions = NULL; - BMFace **faces = NULL; - BLI_array_declare(regions); - BLI_array_declare(faces); - BMFace *act_face = bm->act_face; - BMWalker regwalker; - int i; - - const bool use_verts = BMO_slot_bool_get(op->slots_in, "use_verts"); - - if (use_verts) { - /* tag verts that start out with only 2 edges, - * don't remove these later */ - BMIter viter; - BMVert *v; - - BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { - BMO_vert_flag_set(bm, v, VERT_MARK, !BM_vert_is_edge_pair(v)); - } - } - - BMO_slot_buffer_flag_enable(bm, op->slots_in, "faces", BM_FACE, FACE_MARK | FACE_TAG); - - /* collect region */ - BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) { - BMFace *f_iter; - if (!BMO_face_flag_test(bm, f, FACE_TAG)) { - continue; - } - - BLI_array_clear(faces); - faces = NULL; /* forces different allocatio */ - - BMW_init(®walker, bm, BMW_ISLAND_MANIFOLD, - BMW_MASK_NOP, BMW_MASK_NOP, FACE_MARK, - BMW_FLAG_NOP, /* no need to check BMW_FLAG_TEST_HIDDEN, faces are already marked by the bmo */ - BMW_NIL_LAY); - - for (f_iter = BMW_begin(®walker, f); f_iter; f_iter = BMW_step(®walker)) { - BLI_array_append(faces, f_iter); - } - BMW_end(®walker); - - for (i = 0; i < BLI_array_len(faces); i++) { - f_iter = faces[i]; - BMO_face_flag_disable(bm, f_iter, FACE_TAG); - BMO_face_flag_enable(bm, f_iter, FACE_ORIG); - } - - if (BMO_error_occurred(bm)) { - BMO_error_clear(bm); - BMO_error_raise(bm, op, BMERR_DISSOLVEFACES_FAILED, NULL); - goto cleanup; - } - - BLI_array_append(faces, NULL); - BLI_array_append(regions, faces); - } - - /* track how many faces we should end up with */ - int totface_target = bm->totface; - - for (i = 0; i < BLI_array_len(regions); i++) { - BMFace *f_new; - int tot = 0; - - faces = regions[i]; - if (!faces[0]) { - BMO_error_raise(bm, op, BMERR_DISSOLVEFACES_FAILED, - "Could not find boundary of dissolve region"); - goto cleanup; - } - - while (faces[tot]) { - tot++; - } - - f_new = BM_faces_join(bm, faces, tot, true); - - if (f_new) { - /* maintain active face */ - if (act_face && bm->act_face == NULL) { - bm->act_face = f_new; - } - totface_target -= tot - 1; - } - else { - BMO_error_raise(bm, op, BMERR_DISSOLVEFACES_FAILED, - "Could not create merged face"); - goto cleanup; - } - - /* if making the new face failed (e.g. overlapping test) - * unmark the original faces for deletion */ - BMO_face_flag_disable(bm, f_new, FACE_ORIG); - BMO_face_flag_enable(bm, f_new, FACE_NEW); - } - - /* Typically no faces need to be deleted */ - if (totface_target != bm->totface) { - BMO_op_callf(bm, op->flag, "delete geom=%ff context=%i", FACE_ORIG, DEL_FACES); - } - - if (use_verts) { - BMIter viter; - BMVert *v, *v_next; - - BM_ITER_MESH_MUTABLE (v, v_next, &viter, bm, BM_VERTS_OF_MESH) { - if (BMO_vert_flag_test(bm, v, VERT_MARK)) { - if (BM_vert_is_edge_pair(v)) { - BM_vert_collapse_edge(bm, v->e, v, true, true); - } - } - } - } - - if (BMO_error_occurred(bm)) { - goto cleanup; - } - - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "region.out", BM_FACE, FACE_NEW); + BMOIter oiter; + BMFace *f; + BMFace ***regions = NULL; + BMFace **faces = NULL; + BLI_array_declare(regions); + BLI_array_declare(faces); + BMFace *act_face = bm->act_face; + BMWalker regwalker; + int i; + + const bool use_verts = BMO_slot_bool_get(op->slots_in, "use_verts"); + + if (use_verts) { + /* tag verts that start out with only 2 edges, + * don't remove these later */ + BMIter viter; + BMVert *v; + + BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { + BMO_vert_flag_set(bm, v, VERT_MARK, !BM_vert_is_edge_pair(v)); + } + } + + BMO_slot_buffer_flag_enable(bm, op->slots_in, "faces", BM_FACE, FACE_MARK | FACE_TAG); + + /* collect region */ + BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) { + BMFace *f_iter; + if (!BMO_face_flag_test(bm, f, FACE_TAG)) { + continue; + } + + BLI_array_clear(faces); + faces = NULL; /* forces different allocatio */ + + BMW_init( + ®walker, + bm, + BMW_ISLAND_MANIFOLD, + BMW_MASK_NOP, + BMW_MASK_NOP, + FACE_MARK, + BMW_FLAG_NOP, /* no need to check BMW_FLAG_TEST_HIDDEN, faces are already marked by the bmo */ + BMW_NIL_LAY); + + for (f_iter = BMW_begin(®walker, f); f_iter; f_iter = BMW_step(®walker)) { + BLI_array_append(faces, f_iter); + } + BMW_end(®walker); + + for (i = 0; i < BLI_array_len(faces); i++) { + f_iter = faces[i]; + BMO_face_flag_disable(bm, f_iter, FACE_TAG); + BMO_face_flag_enable(bm, f_iter, FACE_ORIG); + } + + if (BMO_error_occurred(bm)) { + BMO_error_clear(bm); + BMO_error_raise(bm, op, BMERR_DISSOLVEFACES_FAILED, NULL); + goto cleanup; + } + + BLI_array_append(faces, NULL); + BLI_array_append(regions, faces); + } + + /* track how many faces we should end up with */ + int totface_target = bm->totface; + + for (i = 0; i < BLI_array_len(regions); i++) { + BMFace *f_new; + int tot = 0; + + faces = regions[i]; + if (!faces[0]) { + BMO_error_raise( + bm, op, BMERR_DISSOLVEFACES_FAILED, "Could not find boundary of dissolve region"); + goto cleanup; + } + + while (faces[tot]) { + tot++; + } + + f_new = BM_faces_join(bm, faces, tot, true); + + if (f_new) { + /* maintain active face */ + if (act_face && bm->act_face == NULL) { + bm->act_face = f_new; + } + totface_target -= tot - 1; + } + else { + BMO_error_raise(bm, op, BMERR_DISSOLVEFACES_FAILED, "Could not create merged face"); + goto cleanup; + } + + /* if making the new face failed (e.g. overlapping test) + * unmark the original faces for deletion */ + BMO_face_flag_disable(bm, f_new, FACE_ORIG); + BMO_face_flag_enable(bm, f_new, FACE_NEW); + } + + /* Typically no faces need to be deleted */ + if (totface_target != bm->totface) { + BMO_op_callf(bm, op->flag, "delete geom=%ff context=%i", FACE_ORIG, DEL_FACES); + } + + if (use_verts) { + BMIter viter; + BMVert *v, *v_next; + + BM_ITER_MESH_MUTABLE (v, v_next, &viter, bm, BM_VERTS_OF_MESH) { + if (BMO_vert_flag_test(bm, v, VERT_MARK)) { + if (BM_vert_is_edge_pair(v)) { + BM_vert_collapse_edge(bm, v->e, v, true, true); + } + } + } + } + + if (BMO_error_occurred(bm)) { + goto cleanup; + } + + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "region.out", BM_FACE, FACE_NEW); cleanup: - /* free/cleanup */ - for (i = 0; i < BLI_array_len(regions); i++) { - if (regions[i]) { - MEM_freeN(regions[i]); - } - } - - BLI_array_free(regions); + /* free/cleanup */ + for (i = 0; i < BLI_array_len(regions); i++) { + if (regions[i]) { + MEM_freeN(regions[i]); + } + } + + BLI_array_free(regions); } void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op) { - /* BMOperator fop; */ - BMFace *act_face = bm->act_face; - BMOIter eiter; - BMIter iter; - BMEdge *e, *e_next; - BMVert *v, *v_next; - - const bool use_verts = BMO_slot_bool_get(op->slots_in, "use_verts"); - const bool use_face_split = BMO_slot_bool_get(op->slots_in, "use_face_split"); - - if (use_face_split) { - BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, EDGE_TAG); - - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - BMIter itersub; - int untag_count = 0; - BM_ITER_ELEM (e, &itersub, v, BM_EDGES_OF_VERT) { - if (!BMO_edge_flag_test(bm, e, EDGE_TAG)) { - untag_count++; - } - } - - /* check that we have 2 edges remaining after dissolve */ - if (untag_count <= 2) { - BMO_vert_flag_enable(bm, v, VERT_TAG); - } - } - - bm_face_split(bm, VERT_TAG, false); - } - - if (use_verts) { - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - BMO_vert_flag_set(bm, v, VERT_MARK, !BM_vert_is_edge_pair(v)); - } - } - - /* tag all verts/edges connected to faces */ - BMO_ITER (e, &eiter, op->slots_in, "edges", BM_EDGE) { - BMFace *f_pair[2]; - if (BM_edge_face_pair(e, &f_pair[0], &f_pair[1])) { - uint j; - for (j = 0; j < 2; j++) { - BMLoop *l_first, *l_iter; - l_iter = l_first = BM_FACE_FIRST_LOOP(f_pair[j]); - do { - BMO_vert_flag_enable(bm, l_iter->v, VERT_ISGC); - BMO_edge_flag_enable(bm, l_iter->e, EDGE_ISGC); - } while ((l_iter = l_iter->next) != l_first); - } - } - } - - BMO_ITER (e, &eiter, op->slots_in, "edges", BM_EDGE) { - BMLoop *l_a, *l_b; - if (BM_edge_loop_pair(e, &l_a, &l_b)) { - BMFace *f_new; - - /* join faces */ - f_new = BM_faces_join_pair(bm, l_a, l_b, false); - - if (f_new) { - /* maintain active face */ - if (act_face && bm->act_face == NULL) { - bm->act_face = f_new; - } - } - } - } - - /* Cleanup geometry (#BM_faces_join_pair, but it removes geometry we're looping on) - * so do this in a separate pass instead. */ - BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) { - if ((e->l == NULL) && BMO_edge_flag_test(bm, e, EDGE_ISGC)) { - BM_edge_kill(bm, e); - } - } - BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { - if ((v->e == NULL) && BMO_vert_flag_test(bm, v, VERT_ISGC)) { - BM_vert_kill(bm, v); - } - } - /* done with cleanup */ - - - if (use_verts) { - BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { - if (BMO_vert_flag_test(bm, v, VERT_MARK)) { - if (BM_vert_is_edge_pair(v)) { - BM_vert_collapse_edge(bm, v->e, v, true, true); - } - } - } - } + /* BMOperator fop; */ + BMFace *act_face = bm->act_face; + BMOIter eiter; + BMIter iter; + BMEdge *e, *e_next; + BMVert *v, *v_next; + + const bool use_verts = BMO_slot_bool_get(op->slots_in, "use_verts"); + const bool use_face_split = BMO_slot_bool_get(op->slots_in, "use_face_split"); + + if (use_face_split) { + BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, EDGE_TAG); + + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + BMIter itersub; + int untag_count = 0; + BM_ITER_ELEM (e, &itersub, v, BM_EDGES_OF_VERT) { + if (!BMO_edge_flag_test(bm, e, EDGE_TAG)) { + untag_count++; + } + } + + /* check that we have 2 edges remaining after dissolve */ + if (untag_count <= 2) { + BMO_vert_flag_enable(bm, v, VERT_TAG); + } + } + + bm_face_split(bm, VERT_TAG, false); + } + + if (use_verts) { + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + BMO_vert_flag_set(bm, v, VERT_MARK, !BM_vert_is_edge_pair(v)); + } + } + + /* tag all verts/edges connected to faces */ + BMO_ITER (e, &eiter, op->slots_in, "edges", BM_EDGE) { + BMFace *f_pair[2]; + if (BM_edge_face_pair(e, &f_pair[0], &f_pair[1])) { + uint j; + for (j = 0; j < 2; j++) { + BMLoop *l_first, *l_iter; + l_iter = l_first = BM_FACE_FIRST_LOOP(f_pair[j]); + do { + BMO_vert_flag_enable(bm, l_iter->v, VERT_ISGC); + BMO_edge_flag_enable(bm, l_iter->e, EDGE_ISGC); + } while ((l_iter = l_iter->next) != l_first); + } + } + } + + BMO_ITER (e, &eiter, op->slots_in, "edges", BM_EDGE) { + BMLoop *l_a, *l_b; + if (BM_edge_loop_pair(e, &l_a, &l_b)) { + BMFace *f_new; + + /* join faces */ + f_new = BM_faces_join_pair(bm, l_a, l_b, false); + + if (f_new) { + /* maintain active face */ + if (act_face && bm->act_face == NULL) { + bm->act_face = f_new; + } + } + } + } + + /* Cleanup geometry (#BM_faces_join_pair, but it removes geometry we're looping on) + * so do this in a separate pass instead. */ + BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) { + if ((e->l == NULL) && BMO_edge_flag_test(bm, e, EDGE_ISGC)) { + BM_edge_kill(bm, e); + } + } + BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { + if ((v->e == NULL) && BMO_vert_flag_test(bm, v, VERT_ISGC)) { + BM_vert_kill(bm, v); + } + } + /* done with cleanup */ + + if (use_verts) { + BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { + if (BMO_vert_flag_test(bm, v, VERT_MARK)) { + if (BM_vert_is_edge_pair(v)) { + BM_vert_collapse_edge(bm, v->e, v, true, true); + } + } + } + } } void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op) { - BMOIter oiter; - BMIter iter; - BMVert *v, *v_next; - BMEdge *e, *e_next; - BMFace *act_face = bm->act_face; - - const bool use_face_split = BMO_slot_bool_get(op->slots_in, "use_face_split"); - const bool use_boundary_tear = BMO_slot_bool_get(op->slots_in, "use_boundary_tear"); - - BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) { - BMO_vert_flag_enable(bm, v, VERT_MARK | VERT_ISGC); - } - - if (use_face_split) { - bm_face_split(bm, VERT_MARK, false); - } - - if (use_boundary_tear) { - BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) { - if (!BM_vert_is_edge_pair(v)) { - BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { - if (BM_edge_is_boundary(e)) { - BMO_vert_flag_enable(bm, v, VERT_MARK_TEAR); - break; - } - } - } - } - - bm_face_split(bm, VERT_MARK_TEAR, true); - } - - BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) { - BMIter itersub; - BMLoop *l_first; - BMEdge *e_first = NULL; - BM_ITER_ELEM (l_first, &itersub, v, BM_LOOPS_OF_VERT) { - BMLoop *l_iter; - l_iter = l_first; - do { - BMO_vert_flag_enable(bm, l_iter->v, VERT_ISGC); - BMO_edge_flag_enable(bm, l_iter->e, EDGE_ISGC); - } while ((l_iter = l_iter->next) != l_first); - - e_first = l_first->e; - } - - /* important e_first won't be deleted */ - if (e_first) { - e = e_first; - do { - e_next = BM_DISK_EDGE_NEXT(e, v); - if (BM_edge_is_wire(e)) { - BM_edge_kill(bm, e); - } - } while ((e = e_next) != e_first); - } - } - - BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) { - /* tag here so we avoid feedback loop (checking topology as we edit) */ - if (BM_vert_is_edge_pair(v)) { - BMO_vert_flag_enable(bm, v, VERT_MARK_PAIR); - } - } - - BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) { - BMIter itersub; - - if (!BMO_vert_flag_test(bm, v, VERT_MARK_PAIR)) { - BM_ITER_ELEM (e, &itersub, v, BM_EDGES_OF_VERT) { - BMLoop *l_a, *l_b; - if (BM_edge_loop_pair(e, &l_a, &l_b)) { - BMFace *f_new; - - /* join faces */ - f_new = BM_faces_join_pair(bm, l_a, l_b, false); - - /* maintain active face */ - if (act_face && bm->act_face == NULL) { - bm->act_face = f_new; - } - } - } - } - } - - /* Cleanup geometry (#BM_faces_join_pair, but it removes geometry we're looping on) - * so do this in a separate pass instead. */ - BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) { - if ((e->l == NULL) && BMO_edge_flag_test(bm, e, EDGE_ISGC)) { - BM_edge_kill(bm, e); - } - } - - /* final cleanup */ - BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) { - if (BM_vert_is_edge_pair(v)) { - BM_vert_collapse_edge(bm, v->e, v, false, true); - } - } - - BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { - if ((v->e == NULL) && BMO_vert_flag_test(bm, v, VERT_ISGC)) { - BM_vert_kill(bm, v); - } - } - /* done with cleanup */ + BMOIter oiter; + BMIter iter; + BMVert *v, *v_next; + BMEdge *e, *e_next; + BMFace *act_face = bm->act_face; + + const bool use_face_split = BMO_slot_bool_get(op->slots_in, "use_face_split"); + const bool use_boundary_tear = BMO_slot_bool_get(op->slots_in, "use_boundary_tear"); + + BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) { + BMO_vert_flag_enable(bm, v, VERT_MARK | VERT_ISGC); + } + + if (use_face_split) { + bm_face_split(bm, VERT_MARK, false); + } + + if (use_boundary_tear) { + BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) { + if (!BM_vert_is_edge_pair(v)) { + BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { + if (BM_edge_is_boundary(e)) { + BMO_vert_flag_enable(bm, v, VERT_MARK_TEAR); + break; + } + } + } + } + + bm_face_split(bm, VERT_MARK_TEAR, true); + } + + BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) { + BMIter itersub; + BMLoop *l_first; + BMEdge *e_first = NULL; + BM_ITER_ELEM (l_first, &itersub, v, BM_LOOPS_OF_VERT) { + BMLoop *l_iter; + l_iter = l_first; + do { + BMO_vert_flag_enable(bm, l_iter->v, VERT_ISGC); + BMO_edge_flag_enable(bm, l_iter->e, EDGE_ISGC); + } while ((l_iter = l_iter->next) != l_first); + + e_first = l_first->e; + } + + /* important e_first won't be deleted */ + if (e_first) { + e = e_first; + do { + e_next = BM_DISK_EDGE_NEXT(e, v); + if (BM_edge_is_wire(e)) { + BM_edge_kill(bm, e); + } + } while ((e = e_next) != e_first); + } + } + + BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) { + /* tag here so we avoid feedback loop (checking topology as we edit) */ + if (BM_vert_is_edge_pair(v)) { + BMO_vert_flag_enable(bm, v, VERT_MARK_PAIR); + } + } + + BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) { + BMIter itersub; + + if (!BMO_vert_flag_test(bm, v, VERT_MARK_PAIR)) { + BM_ITER_ELEM (e, &itersub, v, BM_EDGES_OF_VERT) { + BMLoop *l_a, *l_b; + if (BM_edge_loop_pair(e, &l_a, &l_b)) { + BMFace *f_new; + + /* join faces */ + f_new = BM_faces_join_pair(bm, l_a, l_b, false); + + /* maintain active face */ + if (act_face && bm->act_face == NULL) { + bm->act_face = f_new; + } + } + } + } + } + + /* Cleanup geometry (#BM_faces_join_pair, but it removes geometry we're looping on) + * so do this in a separate pass instead. */ + BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) { + if ((e->l == NULL) && BMO_edge_flag_test(bm, e, EDGE_ISGC)) { + BM_edge_kill(bm, e); + } + } + + /* final cleanup */ + BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) { + if (BM_vert_is_edge_pair(v)) { + BM_vert_collapse_edge(bm, v->e, v, false, true); + } + } + + BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { + if ((v->e == NULL) && BMO_vert_flag_test(bm, v, VERT_ISGC)) { + BM_vert_kill(bm, v); + } + } + /* done with cleanup */ } /* Limited Dissolve */ void bmo_dissolve_limit_exec(BMesh *bm, BMOperator *op) { - BMOpSlot *einput = BMO_slot_get(op->slots_in, "edges"); - BMOpSlot *vinput = BMO_slot_get(op->slots_in, "verts"); - const float angle_max = M_PI_2; - const float angle_limit = min_ff(angle_max, BMO_slot_float_get(op->slots_in, "angle_limit")); - const bool do_dissolve_boundaries = BMO_slot_bool_get(op->slots_in, "use_dissolve_boundaries"); - const BMO_Delimit delimit = BMO_slot_int_get(op->slots_in, "delimit"); - - BM_mesh_decimate_dissolve_ex(bm, angle_limit, do_dissolve_boundaries, delimit, - (BMVert **)BMO_SLOT_AS_BUFFER(vinput), vinput->len, - (BMEdge **)BMO_SLOT_AS_BUFFER(einput), einput->len, - FACE_NEW); - - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "region.out", BM_FACE, FACE_NEW); + BMOpSlot *einput = BMO_slot_get(op->slots_in, "edges"); + BMOpSlot *vinput = BMO_slot_get(op->slots_in, "verts"); + const float angle_max = M_PI_2; + const float angle_limit = min_ff(angle_max, BMO_slot_float_get(op->slots_in, "angle_limit")); + const bool do_dissolve_boundaries = BMO_slot_bool_get(op->slots_in, "use_dissolve_boundaries"); + const BMO_Delimit delimit = BMO_slot_int_get(op->slots_in, "delimit"); + + BM_mesh_decimate_dissolve_ex(bm, + angle_limit, + do_dissolve_boundaries, + delimit, + (BMVert **)BMO_SLOT_AS_BUFFER(vinput), + vinput->len, + (BMEdge **)BMO_SLOT_AS_BUFFER(einput), + einput->len, + FACE_NEW); + + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "region.out", BM_FACE, FACE_NEW); } - #define EDGE_MARK 1 #define EDGE_COLLAPSE 2 static void bm_mesh_edge_collapse_flagged(BMesh *bm, const int flag, const short oflag) { - BMO_op_callf(bm, flag, "collapse edges=%fe uvs=%b", oflag, true); + BMO_op_callf(bm, flag, "collapse edges=%fe uvs=%b", oflag, true); } void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op) { - const float dist = BMO_slot_float_get(op->slots_in, "dist"); - const float dist_sq = dist * dist; - - bool found; - BMIter eiter; - BMEdge *e; - - - BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, EDGE_MARK); - - /* collapse zero length edges, this accounts for zero area faces too */ - found = false; - BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { - if (BMO_edge_flag_test(bm, e, EDGE_MARK)) { - if (BM_edge_calc_length_squared(e) < dist_sq) { - BMO_edge_flag_enable(bm, e, EDGE_COLLAPSE); - found = true; - } - } - - /* clear all loop tags (checked later) */ - if (e->l) { - BMLoop *l_iter, *l_first; - l_iter = l_first = e->l; - do { - BM_elem_flag_disable(l_iter, BM_ELEM_TAG); - } while ((l_iter = l_iter->radial_next) != l_first); - } - } - - if (found) { - bm_mesh_edge_collapse_flagged(bm, op->flag, EDGE_COLLAPSE); - } - - - /* clip degenerate ears from the face */ - found = false; - BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { - if (e->l && BMO_edge_flag_test(bm, e, EDGE_MARK)) { - BMLoop *l_iter, *l_first; - l_iter = l_first = e->l; - do { - if ( - /* check the loop hasn't already been tested (and flag not to test again) */ - !BM_elem_flag_test(l_iter, BM_ELEM_TAG) && - ((void)BM_elem_flag_enable(l_iter, BM_ELEM_TAG), - - /* check we're marked to tested (radial edge already tested) */ - BMO_edge_flag_test(bm, l_iter->prev->e, EDGE_MARK) && - - /* check edges are not already going to be collapsed */ - !BMO_edge_flag_test(bm, l_iter->e, EDGE_COLLAPSE) && - !BMO_edge_flag_test(bm, l_iter->prev->e, EDGE_COLLAPSE))) - { - /* test if the faces loop (ear) is degenerate */ - float dir_prev[3], len_prev; - float dir_next[3], len_next; - - - sub_v3_v3v3(dir_prev, l_iter->prev->v->co, l_iter->v->co); - sub_v3_v3v3(dir_next, l_iter->next->v->co, l_iter->v->co); - - len_prev = normalize_v3(dir_prev); - len_next = normalize_v3(dir_next); - - if ((len_v3v3(dir_prev, dir_next) * min_ff(len_prev, len_next)) <= dist) { - bool reset = false; - - if (fabsf(len_prev - len_next) <= dist) { - /* both edges the same length */ - if (l_iter->f->len == 3) { - /* ideally this would have been discovered with short edge test above */ - BMO_edge_flag_enable(bm, l_iter->next->e, EDGE_COLLAPSE); - found = true; - } - else { - /* add a joining edge and tag for removal */ - BMLoop *l_split; - if (BM_face_split(bm, l_iter->f, l_iter->prev, l_iter->next, &l_split, NULL, true)) { - BMO_edge_flag_enable(bm, l_split->e, EDGE_COLLAPSE); - found = true; - reset = true; - } - } - } - else if (len_prev < len_next) { - /* split 'l_iter->e', then join the vert with next */ - BMVert *v_new; - BMEdge *e_new; - BMLoop *l_split; - v_new = BM_edge_split(bm, l_iter->e, l_iter->v, &e_new, len_prev / len_next); - BLI_assert(v_new == l_iter->next->v); - (void)v_new; - if (BM_face_split(bm, l_iter->f, l_iter->prev, l_iter->next, &l_split, NULL, true)) { - BMO_edge_flag_enable(bm, l_split->e, EDGE_COLLAPSE); - found = true; - } - reset = true; - } - else if (len_next < len_prev) { - /* split 'l_iter->prev->e', then join the vert with next */ - BMVert *v_new; - BMEdge *e_new; - BMLoop *l_split; - v_new = BM_edge_split(bm, l_iter->prev->e, l_iter->v, &e_new, len_next / len_prev); - BLI_assert(v_new == l_iter->prev->v); - (void)v_new; - if (BM_face_split(bm, l_iter->f, l_iter->prev, l_iter->next, &l_split, NULL, true)) { - BMO_edge_flag_enable(bm, l_split->e, EDGE_COLLAPSE); - found = true; - } - reset = true; - } - - if (reset) { - /* we can't easily track where we are on the radial edge, reset! */ - l_first = l_iter; - } - } - } - } while ((l_iter = l_iter->radial_next) != l_first); - } - } - - if (found) { - bm_mesh_edge_collapse_flagged(bm, op->flag, EDGE_COLLAPSE); - } - + const float dist = BMO_slot_float_get(op->slots_in, "dist"); + const float dist_sq = dist * dist; + + bool found; + BMIter eiter; + BMEdge *e; + + BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, EDGE_MARK); + + /* collapse zero length edges, this accounts for zero area faces too */ + found = false; + BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { + if (BMO_edge_flag_test(bm, e, EDGE_MARK)) { + if (BM_edge_calc_length_squared(e) < dist_sq) { + BMO_edge_flag_enable(bm, e, EDGE_COLLAPSE); + found = true; + } + } + + /* clear all loop tags (checked later) */ + if (e->l) { + BMLoop *l_iter, *l_first; + l_iter = l_first = e->l; + do { + BM_elem_flag_disable(l_iter, BM_ELEM_TAG); + } while ((l_iter = l_iter->radial_next) != l_first); + } + } + + if (found) { + bm_mesh_edge_collapse_flagged(bm, op->flag, EDGE_COLLAPSE); + } + + /* clip degenerate ears from the face */ + found = false; + BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { + if (e->l && BMO_edge_flag_test(bm, e, EDGE_MARK)) { + BMLoop *l_iter, *l_first; + l_iter = l_first = e->l; + do { + if ( + /* check the loop hasn't already been tested (and flag not to test again) */ + !BM_elem_flag_test(l_iter, BM_ELEM_TAG) && + ((void)BM_elem_flag_enable(l_iter, BM_ELEM_TAG), + + /* check we're marked to tested (radial edge already tested) */ + BMO_edge_flag_test(bm, l_iter->prev->e, EDGE_MARK) && + + /* check edges are not already going to be collapsed */ + !BMO_edge_flag_test(bm, l_iter->e, EDGE_COLLAPSE) && + !BMO_edge_flag_test(bm, l_iter->prev->e, EDGE_COLLAPSE))) { + /* test if the faces loop (ear) is degenerate */ + float dir_prev[3], len_prev; + float dir_next[3], len_next; + + sub_v3_v3v3(dir_prev, l_iter->prev->v->co, l_iter->v->co); + sub_v3_v3v3(dir_next, l_iter->next->v->co, l_iter->v->co); + + len_prev = normalize_v3(dir_prev); + len_next = normalize_v3(dir_next); + + if ((len_v3v3(dir_prev, dir_next) * min_ff(len_prev, len_next)) <= dist) { + bool reset = false; + + if (fabsf(len_prev - len_next) <= dist) { + /* both edges the same length */ + if (l_iter->f->len == 3) { + /* ideally this would have been discovered with short edge test above */ + BMO_edge_flag_enable(bm, l_iter->next->e, EDGE_COLLAPSE); + found = true; + } + else { + /* add a joining edge and tag for removal */ + BMLoop *l_split; + if (BM_face_split( + bm, l_iter->f, l_iter->prev, l_iter->next, &l_split, NULL, true)) { + BMO_edge_flag_enable(bm, l_split->e, EDGE_COLLAPSE); + found = true; + reset = true; + } + } + } + else if (len_prev < len_next) { + /* split 'l_iter->e', then join the vert with next */ + BMVert *v_new; + BMEdge *e_new; + BMLoop *l_split; + v_new = BM_edge_split(bm, l_iter->e, l_iter->v, &e_new, len_prev / len_next); + BLI_assert(v_new == l_iter->next->v); + (void)v_new; + if (BM_face_split(bm, l_iter->f, l_iter->prev, l_iter->next, &l_split, NULL, true)) { + BMO_edge_flag_enable(bm, l_split->e, EDGE_COLLAPSE); + found = true; + } + reset = true; + } + else if (len_next < len_prev) { + /* split 'l_iter->prev->e', then join the vert with next */ + BMVert *v_new; + BMEdge *e_new; + BMLoop *l_split; + v_new = BM_edge_split(bm, l_iter->prev->e, l_iter->v, &e_new, len_next / len_prev); + BLI_assert(v_new == l_iter->prev->v); + (void)v_new; + if (BM_face_split(bm, l_iter->f, l_iter->prev, l_iter->next, &l_split, NULL, true)) { + BMO_edge_flag_enable(bm, l_split->e, EDGE_COLLAPSE); + found = true; + } + reset = true; + } + + if (reset) { + /* we can't easily track where we are on the radial edge, reset! */ + l_first = l_iter; + } + } + } + } while ((l_iter = l_iter->radial_next) != l_first); + } + } + + if (found) { + bm_mesh_edge_collapse_flagged(bm, op->flag, EDGE_COLLAPSE); + } } diff --git a/source/blender/bmesh/operators/bmo_dupe.c b/source/blender/bmesh/operators/bmo_dupe.c index 5c7c78eb654..6dd361d62b3 100644 --- a/source/blender/bmesh/operators/bmo_dupe.c +++ b/source/blender/bmesh/operators/bmo_dupe.c @@ -30,9 +30,9 @@ #include "intern/bmesh_operators_private.h" /* own include */ /* local flag define */ -#define DUPE_INPUT 1 /* input from operator */ -#define DUPE_NEW 2 -#define DUPE_DONE 4 +#define DUPE_INPUT 1 /* input from operator */ +#define DUPE_NEW 2 +#define DUPE_DONE 4 // #define DUPE_MAPPED 8 // UNUSED /** @@ -40,28 +40,30 @@ * * Copy an existing vertex from one bmesh to another. */ -static BMVert *bmo_vert_copy( - BMOperator *op, - BMOpSlot *slot_vertmap_out, - BMesh *bm_dst, BMesh *bm_src, BMVert *v_src, GHash *vhash) +static BMVert *bmo_vert_copy(BMOperator *op, + BMOpSlot *slot_vertmap_out, + BMesh *bm_dst, + BMesh *bm_src, + BMVert *v_src, + GHash *vhash) { - BMVert *v_dst; + BMVert *v_dst; - /* Create a new vertex */ - v_dst = BM_vert_create(bm_dst, v_src->co, NULL, BM_CREATE_SKIP_CD); - BMO_slot_map_elem_insert(op, slot_vertmap_out, v_src, v_dst); - BMO_slot_map_elem_insert(op, slot_vertmap_out, v_dst, v_src); + /* Create a new vertex */ + v_dst = BM_vert_create(bm_dst, v_src->co, NULL, BM_CREATE_SKIP_CD); + BMO_slot_map_elem_insert(op, slot_vertmap_out, v_src, v_dst); + BMO_slot_map_elem_insert(op, slot_vertmap_out, v_dst, v_src); - /* Insert new vertex into the vert hash */ - BLI_ghash_insert(vhash, v_src, v_dst); + /* Insert new vertex into the vert hash */ + BLI_ghash_insert(vhash, v_src, v_dst); - /* Copy attributes */ - BM_elem_attrs_copy(bm_src, bm_dst, v_src, v_dst); + /* Copy attributes */ + BM_elem_attrs_copy(bm_src, bm_dst, v_src, v_dst); - /* Mark the vert for output */ - BMO_vert_flag_enable(bm_dst, v_dst, DUPE_NEW); + /* Mark the vert for output */ + BMO_vert_flag_enable(bm_dst, v_dst, DUPE_NEW); - return v_dst; + return v_dst; } /** @@ -69,68 +71,69 @@ static BMVert *bmo_vert_copy( * * Copy an existing edge from one bmesh to another. */ -static BMEdge *bmo_edge_copy( - BMOperator *op, - BMOpSlot *slot_edgemap_out, - BMOpSlot *slot_boundarymap_out, - BMesh *bm_dst, BMesh *bm_src, - BMEdge *e_src, - GHash *vhash, GHash *ehash, - const bool use_edge_flip_from_face) +static BMEdge *bmo_edge_copy(BMOperator *op, + BMOpSlot *slot_edgemap_out, + BMOpSlot *slot_boundarymap_out, + BMesh *bm_dst, + BMesh *bm_src, + BMEdge *e_src, + GHash *vhash, + GHash *ehash, + const bool use_edge_flip_from_face) { - BMEdge *e_dst; - BMVert *e_dst_v1, *e_dst_v2; - uint rlen; - - /* see if any of the neighboring faces are - * not being duplicated. in that case, - * add it to the new/old map. */ - /* lookup edge */ - rlen = 0; - if (e_src->l) { - BMLoop *l_iter_src, *l_first_src; - l_iter_src = l_first_src = e_src->l; - do { - if (BMO_face_flag_test(bm_src, l_iter_src->f, DUPE_INPUT)) { - rlen++; - } - } while ((l_iter_src = l_iter_src->radial_next) != l_first_src); - } - - /* Lookup v1 and v2 */ - e_dst_v1 = BLI_ghash_lookup(vhash, e_src->v1); - e_dst_v2 = BLI_ghash_lookup(vhash, e_src->v2); - - /* Create a new edge */ - e_dst = BM_edge_create(bm_dst, e_dst_v1, e_dst_v2, NULL, BM_CREATE_SKIP_CD); - BMO_slot_map_elem_insert(op, slot_edgemap_out, e_src, e_dst); - BMO_slot_map_elem_insert(op, slot_edgemap_out, e_dst, e_src); - - /* add to new/old edge map if necassary */ - if (rlen < 2) { - /* not sure what non-manifold cases of greater than three - * radial should do. */ - BMO_slot_map_elem_insert(op, slot_boundarymap_out, e_src, e_dst); - } - - /* Insert new edge into the edge hash */ - BLI_ghash_insert(ehash, e_src, e_dst); - - /* Copy attributes */ - BM_elem_attrs_copy(bm_src, bm_dst, e_src, e_dst); - - /* Mark the edge for output */ - BMO_edge_flag_enable(bm_dst, e_dst, DUPE_NEW); - - if (use_edge_flip_from_face) { - /* Take winding from previous face (if we had one), - * otherwise extruding a duplicated edges gives bad normals, see: T62487. */ - if (BM_edge_is_boundary(e_src) && (e_src->l->v == e_src->v1)) { - BM_edge_verts_swap(e_dst); - } - } - - return e_dst; + BMEdge *e_dst; + BMVert *e_dst_v1, *e_dst_v2; + uint rlen; + + /* see if any of the neighboring faces are + * not being duplicated. in that case, + * add it to the new/old map. */ + /* lookup edge */ + rlen = 0; + if (e_src->l) { + BMLoop *l_iter_src, *l_first_src; + l_iter_src = l_first_src = e_src->l; + do { + if (BMO_face_flag_test(bm_src, l_iter_src->f, DUPE_INPUT)) { + rlen++; + } + } while ((l_iter_src = l_iter_src->radial_next) != l_first_src); + } + + /* Lookup v1 and v2 */ + e_dst_v1 = BLI_ghash_lookup(vhash, e_src->v1); + e_dst_v2 = BLI_ghash_lookup(vhash, e_src->v2); + + /* Create a new edge */ + e_dst = BM_edge_create(bm_dst, e_dst_v1, e_dst_v2, NULL, BM_CREATE_SKIP_CD); + BMO_slot_map_elem_insert(op, slot_edgemap_out, e_src, e_dst); + BMO_slot_map_elem_insert(op, slot_edgemap_out, e_dst, e_src); + + /* add to new/old edge map if necassary */ + if (rlen < 2) { + /* not sure what non-manifold cases of greater than three + * radial should do. */ + BMO_slot_map_elem_insert(op, slot_boundarymap_out, e_src, e_dst); + } + + /* Insert new edge into the edge hash */ + BLI_ghash_insert(ehash, e_src, e_dst); + + /* Copy attributes */ + BM_elem_attrs_copy(bm_src, bm_dst, e_src, e_dst); + + /* Mark the edge for output */ + BMO_edge_flag_enable(bm_dst, e_dst, DUPE_NEW); + + if (use_edge_flip_from_face) { + /* Take winding from previous face (if we had one), + * otherwise extruding a duplicated edges gives bad normals, see: T62487. */ + if (BM_edge_is_boundary(e_src) && (e_src->l->v == e_src->v1)) { + BM_edge_verts_swap(e_dst); + } + } + + return e_dst; } /** @@ -138,51 +141,50 @@ static BMEdge *bmo_edge_copy( * * Copy an existing face from one bmesh to another. */ -static BMFace *bmo_face_copy( - BMOperator *op, - BMOpSlot *slot_facemap_out, - BMesh *bm_dst, BMesh *bm_src, - BMFace *f_src, - GHash *vhash, GHash *ehash) +static BMFace *bmo_face_copy(BMOperator *op, + BMOpSlot *slot_facemap_out, + BMesh *bm_dst, + BMesh *bm_src, + BMFace *f_src, + GHash *vhash, + GHash *ehash) { - BMFace *f_dst; - BMVert **vtar = BLI_array_alloca(vtar, f_src->len); - BMEdge **edar = BLI_array_alloca(edar, f_src->len); - BMLoop *l_iter_src, *l_iter_dst, *l_first_src; - int i; - - l_first_src = BM_FACE_FIRST_LOOP(f_src); - - /* lookup edge */ - l_iter_src = l_first_src; - i = 0; - do { - vtar[i] = BLI_ghash_lookup(vhash, l_iter_src->v); - edar[i] = BLI_ghash_lookup(ehash, l_iter_src->e); - i++; - } while ((l_iter_src = l_iter_src->next) != l_first_src); - - /* create new face */ - f_dst = BM_face_create(bm_dst, vtar, edar, f_src->len, NULL, BM_CREATE_SKIP_CD); - BMO_slot_map_elem_insert(op, slot_facemap_out, f_src, f_dst); - BMO_slot_map_elem_insert(op, slot_facemap_out, f_dst, f_src); - - /* Copy attributes */ - BM_elem_attrs_copy(bm_src, bm_dst, f_src, f_dst); - - /* copy per-loop custom data */ - l_iter_src = l_first_src; - l_iter_dst = BM_FACE_FIRST_LOOP(f_dst); - do { - BM_elem_attrs_copy(bm_src, bm_dst, l_iter_src, l_iter_dst); - } while ((void) - (l_iter_dst = l_iter_dst->next), - (l_iter_src = l_iter_src->next) != l_first_src); - - /* Mark the face for output */ - BMO_face_flag_enable(bm_dst, f_dst, DUPE_NEW); - - return f_dst; + BMFace *f_dst; + BMVert **vtar = BLI_array_alloca(vtar, f_src->len); + BMEdge **edar = BLI_array_alloca(edar, f_src->len); + BMLoop *l_iter_src, *l_iter_dst, *l_first_src; + int i; + + l_first_src = BM_FACE_FIRST_LOOP(f_src); + + /* lookup edge */ + l_iter_src = l_first_src; + i = 0; + do { + vtar[i] = BLI_ghash_lookup(vhash, l_iter_src->v); + edar[i] = BLI_ghash_lookup(ehash, l_iter_src->e); + i++; + } while ((l_iter_src = l_iter_src->next) != l_first_src); + + /* create new face */ + f_dst = BM_face_create(bm_dst, vtar, edar, f_src->len, NULL, BM_CREATE_SKIP_CD); + BMO_slot_map_elem_insert(op, slot_facemap_out, f_src, f_dst); + BMO_slot_map_elem_insert(op, slot_facemap_out, f_dst, f_src); + + /* Copy attributes */ + BM_elem_attrs_copy(bm_src, bm_dst, f_src, f_dst); + + /* copy per-loop custom data */ + l_iter_src = l_first_src; + l_iter_dst = BM_FACE_FIRST_LOOP(f_dst); + do { + BM_elem_attrs_copy(bm_src, bm_dst, l_iter_src, l_iter_dst); + } while ((void)(l_iter_dst = l_iter_dst->next), (l_iter_src = l_iter_src->next) != l_first_src); + + /* Mark the face for output */ + BMO_face_flag_enable(bm_dst, f_dst, DUPE_NEW); + + return f_dst; } /** @@ -192,120 +194,128 @@ static BMFace *bmo_face_copy( */ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src) { - const bool use_select_history = BMO_slot_bool_get(op->slots_in, "use_select_history"); - const bool use_edge_flip_from_face = BMO_slot_bool_get(op->slots_in, "use_edge_flip_from_face"); - - BMVert *v = NULL, *v2; - BMEdge *e = NULL; - BMFace *f = NULL; - - BMIter viter, eiter, fiter; - GHash *vhash, *ehash; - - BMOpSlot *slot_boundary_map_out = BMO_slot_get(op->slots_out, "boundary_map.out"); - BMOpSlot *slot_isovert_map_out = BMO_slot_get(op->slots_out, "isovert_map.out"); - - BMOpSlot *slot_vert_map_out = BMO_slot_get(op->slots_out, "vert_map.out"); - BMOpSlot *slot_edge_map_out = BMO_slot_get(op->slots_out, "edge_map.out"); - BMOpSlot *slot_face_map_out = BMO_slot_get(op->slots_out, "face_map.out"); - - /* initialize pointer hashes */ - vhash = BLI_ghash_ptr_new("bmesh dupeops v"); - ehash = BLI_ghash_ptr_new("bmesh dupeops e"); - - /* duplicate flagged vertices */ - BM_ITER_MESH (v, &viter, bm_src, BM_VERTS_OF_MESH) { - if (BMO_vert_flag_test(bm_src, v, DUPE_INPUT) && - BMO_vert_flag_test(bm_src, v, DUPE_DONE) == false) - { - BMIter iter; - bool isolated = true; - - v2 = bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, v, vhash); - - BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) { - if (BMO_face_flag_test(bm_src, f, DUPE_INPUT)) { - isolated = false; - break; - } - } - - if (isolated) { - BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { - if (BMO_edge_flag_test(bm_src, e, DUPE_INPUT)) { - isolated = false; - break; - } - } - } - - if (isolated) { - BMO_slot_map_elem_insert(op, slot_isovert_map_out, v, v2); - } - - BMO_vert_flag_enable(bm_src, v, DUPE_DONE); - } - } - - /* now we dupe all the edges */ - BM_ITER_MESH (e, &eiter, bm_src, BM_EDGES_OF_MESH) { - if (BMO_edge_flag_test(bm_src, e, DUPE_INPUT) && - BMO_edge_flag_test(bm_src, e, DUPE_DONE) == false) - { - /* make sure that verts are copied */ - if (!BMO_vert_flag_test(bm_src, e->v1, DUPE_DONE)) { - bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, e->v1, vhash); - BMO_vert_flag_enable(bm_src, e->v1, DUPE_DONE); - } - if (!BMO_vert_flag_test(bm_src, e->v2, DUPE_DONE)) { - bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, e->v2, vhash); - BMO_vert_flag_enable(bm_src, e->v2, DUPE_DONE); - } - /* now copy the actual edge */ - bmo_edge_copy(op, slot_edge_map_out, slot_boundary_map_out, - bm_dst, bm_src, e, vhash, ehash, use_edge_flip_from_face); - BMO_edge_flag_enable(bm_src, e, DUPE_DONE); - } - } - - /* first we dupe all flagged faces and their elements from source */ - BM_ITER_MESH (f, &fiter, bm_src, BM_FACES_OF_MESH) { - if (BMO_face_flag_test(bm_src, f, DUPE_INPUT)) { - /* vertex pass */ - BM_ITER_ELEM (v, &viter, f, BM_VERTS_OF_FACE) { - if (!BMO_vert_flag_test(bm_src, v, DUPE_DONE)) { - bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, v, vhash); - BMO_vert_flag_enable(bm_src, v, DUPE_DONE); - } - } - - /* edge pass */ - BM_ITER_ELEM (e, &eiter, f, BM_EDGES_OF_FACE) { - if (!BMO_edge_flag_test(bm_src, e, DUPE_DONE)) { - bmo_edge_copy(op, slot_edge_map_out, slot_boundary_map_out, - bm_dst, bm_src, e, vhash, ehash, use_edge_flip_from_face); - BMO_edge_flag_enable(bm_src, e, DUPE_DONE); - } - } - - bmo_face_copy(op, slot_face_map_out, bm_dst, bm_src, f, vhash, ehash); - BMO_face_flag_enable(bm_src, f, DUPE_DONE); - } - } - - /* free pointer hashes */ - BLI_ghash_free(vhash, NULL, NULL); - BLI_ghash_free(ehash, NULL, NULL); - - if (use_select_history) { - BLI_assert(bm_src == bm_dst); - BMO_mesh_selected_remap( - bm_dst, - slot_vert_map_out, - slot_edge_map_out, - slot_face_map_out, - false); - } + const bool use_select_history = BMO_slot_bool_get(op->slots_in, "use_select_history"); + const bool use_edge_flip_from_face = BMO_slot_bool_get(op->slots_in, "use_edge_flip_from_face"); + + BMVert *v = NULL, *v2; + BMEdge *e = NULL; + BMFace *f = NULL; + + BMIter viter, eiter, fiter; + GHash *vhash, *ehash; + + BMOpSlot *slot_boundary_map_out = BMO_slot_get(op->slots_out, "boundary_map.out"); + BMOpSlot *slot_isovert_map_out = BMO_slot_get(op->slots_out, "isovert_map.out"); + + BMOpSlot *slot_vert_map_out = BMO_slot_get(op->slots_out, "vert_map.out"); + BMOpSlot *slot_edge_map_out = BMO_slot_get(op->slots_out, "edge_map.out"); + BMOpSlot *slot_face_map_out = BMO_slot_get(op->slots_out, "face_map.out"); + + /* initialize pointer hashes */ + vhash = BLI_ghash_ptr_new("bmesh dupeops v"); + ehash = BLI_ghash_ptr_new("bmesh dupeops e"); + + /* duplicate flagged vertices */ + BM_ITER_MESH (v, &viter, bm_src, BM_VERTS_OF_MESH) { + if (BMO_vert_flag_test(bm_src, v, DUPE_INPUT) && + BMO_vert_flag_test(bm_src, v, DUPE_DONE) == false) { + BMIter iter; + bool isolated = true; + + v2 = bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, v, vhash); + + BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) { + if (BMO_face_flag_test(bm_src, f, DUPE_INPUT)) { + isolated = false; + break; + } + } + + if (isolated) { + BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { + if (BMO_edge_flag_test(bm_src, e, DUPE_INPUT)) { + isolated = false; + break; + } + } + } + + if (isolated) { + BMO_slot_map_elem_insert(op, slot_isovert_map_out, v, v2); + } + + BMO_vert_flag_enable(bm_src, v, DUPE_DONE); + } + } + + /* now we dupe all the edges */ + BM_ITER_MESH (e, &eiter, bm_src, BM_EDGES_OF_MESH) { + if (BMO_edge_flag_test(bm_src, e, DUPE_INPUT) && + BMO_edge_flag_test(bm_src, e, DUPE_DONE) == false) { + /* make sure that verts are copied */ + if (!BMO_vert_flag_test(bm_src, e->v1, DUPE_DONE)) { + bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, e->v1, vhash); + BMO_vert_flag_enable(bm_src, e->v1, DUPE_DONE); + } + if (!BMO_vert_flag_test(bm_src, e->v2, DUPE_DONE)) { + bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, e->v2, vhash); + BMO_vert_flag_enable(bm_src, e->v2, DUPE_DONE); + } + /* now copy the actual edge */ + bmo_edge_copy(op, + slot_edge_map_out, + slot_boundary_map_out, + bm_dst, + bm_src, + e, + vhash, + ehash, + use_edge_flip_from_face); + BMO_edge_flag_enable(bm_src, e, DUPE_DONE); + } + } + + /* first we dupe all flagged faces and their elements from source */ + BM_ITER_MESH (f, &fiter, bm_src, BM_FACES_OF_MESH) { + if (BMO_face_flag_test(bm_src, f, DUPE_INPUT)) { + /* vertex pass */ + BM_ITER_ELEM (v, &viter, f, BM_VERTS_OF_FACE) { + if (!BMO_vert_flag_test(bm_src, v, DUPE_DONE)) { + bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, v, vhash); + BMO_vert_flag_enable(bm_src, v, DUPE_DONE); + } + } + + /* edge pass */ + BM_ITER_ELEM (e, &eiter, f, BM_EDGES_OF_FACE) { + if (!BMO_edge_flag_test(bm_src, e, DUPE_DONE)) { + bmo_edge_copy(op, + slot_edge_map_out, + slot_boundary_map_out, + bm_dst, + bm_src, + e, + vhash, + ehash, + use_edge_flip_from_face); + BMO_edge_flag_enable(bm_src, e, DUPE_DONE); + } + } + + bmo_face_copy(op, slot_face_map_out, bm_dst, bm_src, f, vhash, ehash); + BMO_face_flag_enable(bm_src, f, DUPE_DONE); + } + } + + /* free pointer hashes */ + BLI_ghash_free(vhash, NULL, NULL); + BLI_ghash_free(ehash, NULL, NULL); + + if (use_select_history) { + BLI_assert(bm_src == bm_dst); + BMO_mesh_selected_remap( + bm_dst, slot_vert_map_out, slot_edge_map_out, slot_face_map_out, false); + } } /** @@ -330,26 +340,26 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src) */ void bmo_duplicate_exec(BMesh *bm, BMOperator *op) { - BMOperator *dupeop = op; - BMesh *bm_dst = BMO_slot_ptr_get(op->slots_in, "dest"); + BMOperator *dupeop = op; + BMesh *bm_dst = BMO_slot_ptr_get(op->slots_in, "dest"); - if (!bm_dst) { - bm_dst = bm; - } + if (!bm_dst) { + bm_dst = bm; + } - /* flag input */ - BMO_slot_buffer_flag_enable(bm, dupeop->slots_in, "geom", BM_ALL_NOLOOP, DUPE_INPUT); + /* flag input */ + BMO_slot_buffer_flag_enable(bm, dupeop->slots_in, "geom", BM_ALL_NOLOOP, DUPE_INPUT); - /* use the internal copy function */ - bmo_mesh_copy(dupeop, bm_dst, bm); + /* use the internal copy function */ + bmo_mesh_copy(dupeop, bm_dst, bm); - /* Output */ - /* First copy the input buffers to output buffers - original data */ - BMO_slot_copy(dupeop, slots_in, "geom", - dupeop, slots_out, "geom_orig.out"); + /* Output */ + /* First copy the input buffers to output buffers - original data */ + BMO_slot_copy(dupeop, slots_in, "geom", dupeop, slots_out, "geom_orig.out"); - /* Now alloc the new output buffers */ - BMO_slot_buffer_from_enabled_flag(bm, dupeop, dupeop->slots_out, "geom.out", BM_ALL_NOLOOP, DUPE_NEW); + /* Now alloc the new output buffers */ + BMO_slot_buffer_from_enabled_flag( + bm, dupeop, dupeop->slots_out, "geom.out", BM_ALL_NOLOOP, DUPE_NEW); } #if 0 /* UNUSED */ @@ -359,13 +369,13 @@ void bmo_duplicate_exec(BMesh *bm, BMOperator *op) * original to new elements) you should run the dupe op manually */ void BMO_dupe_from_flag(BMesh *bm, int htype, const char hflag) { - BMOperator dupeop; + BMOperator dupeop; - BMO_op_init(bm, &dupeop, "duplicate"); - BMO_slot_buffer_from_enabled_hflag(bm, &dupeop, "geom", htype, hflag); + BMO_op_init(bm, &dupeop, "duplicate"); + BMO_slot_buffer_from_enabled_hflag(bm, &dupeop, "geom", htype, hflag); - BMO_op_exec(bm, &dupeop); - BMO_op_finish(bm, &dupeop); + BMO_op_exec(bm, &dupeop); + BMO_op_finish(bm, &dupeop); } #endif @@ -393,77 +403,74 @@ void bmo_split_exec(BMesh *bm, BMOperator *op) { #define SPLIT_INPUT 1 - BMOperator *splitop = op; - BMOperator dupeop; - const bool use_only_faces = BMO_slot_bool_get(op->slots_in, "use_only_faces"); - - /* initialize our sub-operator */ - BMO_op_init(bm, &dupeop, op->flag, "duplicate"); - - BMO_slot_copy(splitop, slots_in, "geom", - &dupeop, slots_in, "geom"); - BMO_op_exec(bm, &dupeop); - - BMO_slot_buffer_flag_enable(bm, splitop->slots_in, "geom", BM_ALL_NOLOOP, SPLIT_INPUT); - - if (use_only_faces) { - BMVert *v; - BMEdge *e; - BMFace *f; - BMIter iter, iter2; - - /* make sure to remove edges and verts we don't need */ - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - bool found = false; - BM_ITER_ELEM (f, &iter2, e, BM_FACES_OF_EDGE) { - if (!BMO_face_flag_test(bm, f, SPLIT_INPUT)) { - found = true; - break; - } - } - if (found == false) { - BMO_edge_flag_enable(bm, e, SPLIT_INPUT); - } - } - - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - bool found = false; - BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) { - if (!BMO_edge_flag_test(bm, e, SPLIT_INPUT)) { - found = true; - break; - } - } - if (found == false) { - BMO_vert_flag_enable(bm, v, SPLIT_INPUT); - } - } - } - - /* connect outputs of dupe to delete, exluding keep geometry */ - BMO_mesh_delete_oflag_context(bm, SPLIT_INPUT, DEL_FACES); - - /* now we make our outputs by copying the dupe output */ - BMO_slot_copy(&dupeop, slots_out, "geom.out", - splitop, slots_out, "geom.out"); - - /* cleanup */ - BMO_op_finish(bm, &dupeop); + BMOperator *splitop = op; + BMOperator dupeop; + const bool use_only_faces = BMO_slot_bool_get(op->slots_in, "use_only_faces"); + + /* initialize our sub-operator */ + BMO_op_init(bm, &dupeop, op->flag, "duplicate"); + + BMO_slot_copy(splitop, slots_in, "geom", &dupeop, slots_in, "geom"); + BMO_op_exec(bm, &dupeop); + + BMO_slot_buffer_flag_enable(bm, splitop->slots_in, "geom", BM_ALL_NOLOOP, SPLIT_INPUT); + + if (use_only_faces) { + BMVert *v; + BMEdge *e; + BMFace *f; + BMIter iter, iter2; + + /* make sure to remove edges and verts we don't need */ + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + bool found = false; + BM_ITER_ELEM (f, &iter2, e, BM_FACES_OF_EDGE) { + if (!BMO_face_flag_test(bm, f, SPLIT_INPUT)) { + found = true; + break; + } + } + if (found == false) { + BMO_edge_flag_enable(bm, e, SPLIT_INPUT); + } + } + + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + bool found = false; + BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) { + if (!BMO_edge_flag_test(bm, e, SPLIT_INPUT)) { + found = true; + break; + } + } + if (found == false) { + BMO_vert_flag_enable(bm, v, SPLIT_INPUT); + } + } + } + + /* connect outputs of dupe to delete, exluding keep geometry */ + BMO_mesh_delete_oflag_context(bm, SPLIT_INPUT, DEL_FACES); + + /* now we make our outputs by copying the dupe output */ + BMO_slot_copy(&dupeop, slots_out, "geom.out", splitop, slots_out, "geom.out"); + + /* cleanup */ + BMO_op_finish(bm, &dupeop); #undef SPLIT_INPUT } - void bmo_delete_exec(BMesh *bm, BMOperator *op) { #define DEL_INPUT 1 - BMOperator *delop = op; + BMOperator *delop = op; - /* Mark Buffer */ - BMO_slot_buffer_flag_enable(bm, delop->slots_in, "geom", BM_ALL_NOLOOP, DEL_INPUT); + /* Mark Buffer */ + BMO_slot_buffer_flag_enable(bm, delop->slots_in, "geom", BM_ALL_NOLOOP, DEL_INPUT); - BMO_mesh_delete_oflag_context(bm, DEL_INPUT, BMO_slot_int_get(op->slots_in, "context")); + BMO_mesh_delete_oflag_context(bm, DEL_INPUT, BMO_slot_int_get(op->slots_in, "context")); #undef DEL_INPUT } @@ -476,128 +483,147 @@ void bmo_delete_exec(BMesh *bm, BMOperator *op) */ void bmo_spin_exec(BMesh *bm, BMOperator *op) { - BMOperator dupop, extop; - float cent[3], dvec[3]; - float axis[3]; - float rmat[3][3]; - float phi; - int steps, do_dupli, a; - bool use_dvec; - - BMO_slot_vec_get(op->slots_in, "cent", cent); - BMO_slot_vec_get(op->slots_in, "axis", axis); - normalize_v3(axis); - BMO_slot_vec_get(op->slots_in, "dvec", dvec); - use_dvec = !is_zero_v3(dvec); - steps = BMO_slot_int_get(op->slots_in, "steps"); - phi = BMO_slot_float_get(op->slots_in, "angle") / steps; - do_dupli = BMO_slot_bool_get(op->slots_in, "use_duplicate"); - const bool use_normal_flip = BMO_slot_bool_get(op->slots_in, "use_normal_flip"); - /* Caller needs to perform other sanity checks (such as the spin being 360d). */ - const bool use_merge = BMO_slot_bool_get(op->slots_in, "use_merge") && steps >= 3; - - axis_angle_normalized_to_mat3(rmat, axis, phi); - - BMVert **vtable = NULL; - if (use_merge) { - vtable = MEM_mallocN(sizeof(BMVert *) * bm->totvert, __func__); - int i = 0; - BMIter iter; - BMVert *v; - BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { - vtable[i] = v; - /* Evil! store original index in normal, - * this is duplicated into every other vertex. - * So we can read the original from the final. - * - * The normals must be recalculated anyway. */ - *((int *)&v->no[0]) = i; - } - } - - BMO_slot_copy(op, slots_in, "geom", - op, slots_out, "geom_last.out"); - for (a = 0; a < steps; a++) { - if (do_dupli) { - BMO_op_initf(bm, &dupop, op->flag, "duplicate geom=%S", op, "geom_last.out"); - BMO_op_exec(bm, &dupop); - BMO_op_callf(bm, op->flag, - "rotate cent=%v matrix=%m3 space=%s verts=%S", - cent, rmat, op, "space", &dupop, "geom.out"); - BMO_slot_copy(&dupop, slots_out, "geom.out", - op, slots_out, "geom_last.out"); - BMO_op_finish(bm, &dupop); - } - else { - BMO_op_initf(bm, &extop, op->flag, - "extrude_face_region geom=%S use_normal_flip=%b use_normal_from_adjacent=%b", - op, "geom_last.out", use_normal_flip && (a == 0), (a != 0)); - BMO_op_exec(bm, &extop); - if ((use_merge && (a == steps - 1)) == false) { - BMO_op_callf(bm, op->flag, - "rotate cent=%v matrix=%m3 space=%s verts=%S", - cent, rmat, op, "space", &extop, "geom.out"); - BMO_slot_copy(&extop, slots_out, "geom.out", - op, slots_out, "geom_last.out"); - } - else { - /* Merge first/last vertices and edges (maintaining 'geom.out' state). */ - BMOpSlot *slot_geom_out = BMO_slot_get(extop.slots_out, "geom.out"); - BMElem **elem_array = (BMElem **)slot_geom_out->data.buf; - int elem_array_len = slot_geom_out->len; - for (int i = 0; i < elem_array_len; ) { - if (elem_array[i]->head.htype == BM_VERT) { - BMVert *v_src = (BMVert *)elem_array[i]; - BMVert *v_dst = vtable[*((const int *)&v_src->no[0])]; - BM_vert_splice(bm, v_dst, v_src); - elem_array_len--; - elem_array[i] = elem_array[elem_array_len]; - } - else { - i++; - } - } - for (int i = 0; i < elem_array_len; ) { - if (elem_array[i]->head.htype == BM_EDGE) { - BMEdge *e_src = (BMEdge *)elem_array[i]; - BMEdge *e_dst = BM_edge_find_double(e_src); - if (e_dst != NULL) { - BM_edge_splice(bm, e_dst, e_src); - elem_array_len--; - elem_array[i] = elem_array[elem_array_len]; - continue; - } - } - i++; - } - /* Full copies of faces may cause overlap. */ - for (int i = 0; i < elem_array_len; ) { - if (elem_array[i]->head.htype == BM_FACE) { - BMFace *f_src = (BMFace *)elem_array[i]; - BMFace *f_dst = BM_face_find_double(f_src); - if (f_dst != NULL) { - BM_face_kill(bm, f_src); - elem_array_len--; - elem_array[i] = elem_array[elem_array_len]; - continue; - } - } - i++; - } - slot_geom_out->len = elem_array_len; - } - BMO_op_finish(bm, &extop); - } - - if (use_dvec) { - mul_m3_v3(rmat, dvec); - BMO_op_callf(bm, op->flag, - "translate vec=%v space=%s verts=%S", - dvec, op, "space", op, "geom_last.out"); - } - } - - if (vtable) { - MEM_freeN(vtable); - } + BMOperator dupop, extop; + float cent[3], dvec[3]; + float axis[3]; + float rmat[3][3]; + float phi; + int steps, do_dupli, a; + bool use_dvec; + + BMO_slot_vec_get(op->slots_in, "cent", cent); + BMO_slot_vec_get(op->slots_in, "axis", axis); + normalize_v3(axis); + BMO_slot_vec_get(op->slots_in, "dvec", dvec); + use_dvec = !is_zero_v3(dvec); + steps = BMO_slot_int_get(op->slots_in, "steps"); + phi = BMO_slot_float_get(op->slots_in, "angle") / steps; + do_dupli = BMO_slot_bool_get(op->slots_in, "use_duplicate"); + const bool use_normal_flip = BMO_slot_bool_get(op->slots_in, "use_normal_flip"); + /* Caller needs to perform other sanity checks (such as the spin being 360d). */ + const bool use_merge = BMO_slot_bool_get(op->slots_in, "use_merge") && steps >= 3; + + axis_angle_normalized_to_mat3(rmat, axis, phi); + + BMVert **vtable = NULL; + if (use_merge) { + vtable = MEM_mallocN(sizeof(BMVert *) * bm->totvert, __func__); + int i = 0; + BMIter iter; + BMVert *v; + BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { + vtable[i] = v; + /* Evil! store original index in normal, + * this is duplicated into every other vertex. + * So we can read the original from the final. + * + * The normals must be recalculated anyway. */ + *((int *)&v->no[0]) = i; + } + } + + BMO_slot_copy(op, slots_in, "geom", op, slots_out, "geom_last.out"); + for (a = 0; a < steps; a++) { + if (do_dupli) { + BMO_op_initf(bm, &dupop, op->flag, "duplicate geom=%S", op, "geom_last.out"); + BMO_op_exec(bm, &dupop); + BMO_op_callf(bm, + op->flag, + "rotate cent=%v matrix=%m3 space=%s verts=%S", + cent, + rmat, + op, + "space", + &dupop, + "geom.out"); + BMO_slot_copy(&dupop, slots_out, "geom.out", op, slots_out, "geom_last.out"); + BMO_op_finish(bm, &dupop); + } + else { + BMO_op_initf(bm, + &extop, + op->flag, + "extrude_face_region geom=%S use_normal_flip=%b use_normal_from_adjacent=%b", + op, + "geom_last.out", + use_normal_flip && (a == 0), + (a != 0)); + BMO_op_exec(bm, &extop); + if ((use_merge && (a == steps - 1)) == false) { + BMO_op_callf(bm, + op->flag, + "rotate cent=%v matrix=%m3 space=%s verts=%S", + cent, + rmat, + op, + "space", + &extop, + "geom.out"); + BMO_slot_copy(&extop, slots_out, "geom.out", op, slots_out, "geom_last.out"); + } + else { + /* Merge first/last vertices and edges (maintaining 'geom.out' state). */ + BMOpSlot *slot_geom_out = BMO_slot_get(extop.slots_out, "geom.out"); + BMElem **elem_array = (BMElem **)slot_geom_out->data.buf; + int elem_array_len = slot_geom_out->len; + for (int i = 0; i < elem_array_len;) { + if (elem_array[i]->head.htype == BM_VERT) { + BMVert *v_src = (BMVert *)elem_array[i]; + BMVert *v_dst = vtable[*((const int *)&v_src->no[0])]; + BM_vert_splice(bm, v_dst, v_src); + elem_array_len--; + elem_array[i] = elem_array[elem_array_len]; + } + else { + i++; + } + } + for (int i = 0; i < elem_array_len;) { + if (elem_array[i]->head.htype == BM_EDGE) { + BMEdge *e_src = (BMEdge *)elem_array[i]; + BMEdge *e_dst = BM_edge_find_double(e_src); + if (e_dst != NULL) { + BM_edge_splice(bm, e_dst, e_src); + elem_array_len--; + elem_array[i] = elem_array[elem_array_len]; + continue; + } + } + i++; + } + /* Full copies of faces may cause overlap. */ + for (int i = 0; i < elem_array_len;) { + if (elem_array[i]->head.htype == BM_FACE) { + BMFace *f_src = (BMFace *)elem_array[i]; + BMFace *f_dst = BM_face_find_double(f_src); + if (f_dst != NULL) { + BM_face_kill(bm, f_src); + elem_array_len--; + elem_array[i] = elem_array[elem_array_len]; + continue; + } + } + i++; + } + slot_geom_out->len = elem_array_len; + } + BMO_op_finish(bm, &extop); + } + + if (use_dvec) { + mul_m3_v3(rmat, dvec); + BMO_op_callf(bm, + op->flag, + "translate vec=%v space=%s verts=%S", + dvec, + op, + "space", + op, + "geom_last.out"); + } + } + + if (vtable) { + MEM_freeN(vtable); + } } diff --git a/source/blender/bmesh/operators/bmo_edgenet.c b/source/blender/bmesh/operators/bmo_edgenet.c index 4334c7bcdcc..7ab8406a3ec 100644 --- a/source/blender/bmesh/operators/bmo_edgenet.c +++ b/source/blender/bmesh/operators/bmo_edgenet.c @@ -30,247 +30,245 @@ #include "intern/bmesh_operators_private.h" /* own include */ -#define EDGE_MARK 1 -#define EDGE_VIS 2 +#define EDGE_MARK 1 +#define EDGE_VIS 2 -#define ELE_NEW 1 +#define ELE_NEW 1 void bmo_edgenet_fill_exec(BMesh *bm, BMOperator *op) { - BMOperator op_attr; - BMOIter siter; - BMFace *f; - const short mat_nr = BMO_slot_int_get(op->slots_in, "mat_nr"); - const bool use_smooth = BMO_slot_bool_get(op->slots_in, "use_smooth"); -// const int sides = BMO_slot_int_get(op->slots_in, "sides"); - - if (!bm->totvert || !bm->totedge) { - return; - } - - BM_mesh_elem_hflag_disable_all(bm, BM_EDGE, BM_ELEM_TAG, false); - BMO_slot_buffer_hflag_enable(bm, op->slots_in, "edges", BM_EDGE, BM_ELEM_TAG, false); - - BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); - BM_mesh_edgenet(bm, true, true); // TODO, sides - - BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG); - - BMO_ITER (f, &siter, op->slots_out, "faces.out", BM_FACE) { - f->mat_nr = mat_nr; - if (use_smooth) { - BM_elem_flag_enable(f, BM_ELEM_SMOOTH); - } - /* normals are zero'd */ - BM_face_normal_update(f); - } - - /* --- Attribute Fill --- */ - /* may as well since we have the faces already in a buffer */ - BMO_op_initf(bm, &op_attr, op->flag, - "face_attribute_fill faces=%S use_normals=%b use_data=%b", - op, "faces.out", true, true); - - BMO_op_exec(bm, &op_attr); - - /* check if some faces couldn't be touched */ - if (BMO_slot_buffer_count(op_attr.slots_out, "faces_fail.out")) { - BMO_op_callf(bm, op->flag, "recalc_face_normals faces=%S", &op_attr, "faces_fail.out"); - } - BMO_op_finish(bm, &op_attr); - + BMOperator op_attr; + BMOIter siter; + BMFace *f; + const short mat_nr = BMO_slot_int_get(op->slots_in, "mat_nr"); + const bool use_smooth = BMO_slot_bool_get(op->slots_in, "use_smooth"); + // const int sides = BMO_slot_int_get(op->slots_in, "sides"); + + if (!bm->totvert || !bm->totedge) { + return; + } + + BM_mesh_elem_hflag_disable_all(bm, BM_EDGE, BM_ELEM_TAG, false); + BMO_slot_buffer_hflag_enable(bm, op->slots_in, "edges", BM_EDGE, BM_ELEM_TAG, false); + + BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); + BM_mesh_edgenet(bm, true, true); // TODO, sides + + BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG); + + BMO_ITER (f, &siter, op->slots_out, "faces.out", BM_FACE) { + f->mat_nr = mat_nr; + if (use_smooth) { + BM_elem_flag_enable(f, BM_ELEM_SMOOTH); + } + /* normals are zero'd */ + BM_face_normal_update(f); + } + + /* --- Attribute Fill --- */ + /* may as well since we have the faces already in a buffer */ + BMO_op_initf(bm, + &op_attr, + op->flag, + "face_attribute_fill faces=%S use_normals=%b use_data=%b", + op, + "faces.out", + true, + true); + + BMO_op_exec(bm, &op_attr); + + /* check if some faces couldn't be touched */ + if (BMO_slot_buffer_count(op_attr.slots_out, "faces_fail.out")) { + BMO_op_callf(bm, op->flag, "recalc_face_normals faces=%S", &op_attr, "faces_fail.out"); + } + BMO_op_finish(bm, &op_attr); } static BMEdge *edge_next(BMesh *bm, BMEdge *e) { - BMIter iter; - BMEdge *e2; - int i; - - for (i = 0; i < 2; i++) { - BM_ITER_ELEM (e2, &iter, i ? e->v2 : e->v1, BM_EDGES_OF_VERT) { - if ((BMO_edge_flag_test(bm, e2, EDGE_MARK)) && - (BMO_edge_flag_test(bm, e2, EDGE_VIS) == false) && - (e2 != e)) - { - return e2; - } - } - } - - return NULL; + BMIter iter; + BMEdge *e2; + int i; + + for (i = 0; i < 2; i++) { + BM_ITER_ELEM (e2, &iter, i ? e->v2 : e->v1, BM_EDGES_OF_VERT) { + if ((BMO_edge_flag_test(bm, e2, EDGE_MARK)) && + (BMO_edge_flag_test(bm, e2, EDGE_VIS) == false) && (e2 != e)) { + return e2; + } + } + } + + return NULL; } void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op) { - BMOIter siter; - BMEdge *e; - BMEdge **edges1 = NULL, **edges2 = NULL, **edges; - BLI_array_declare(edges1); - BLI_array_declare(edges2); - BLI_array_declare(edges); - bool ok = true; - int i, count; - - BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, EDGE_MARK); - - /* validate that each edge has at most one other tagged edge in the - * disk cycle around each of it's vertices */ - BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { - for (i = 0; i < 2; i++) { - count = BMO_iter_elem_count_flag(bm, BM_EDGES_OF_VERT, (i ? e->v2 : e->v1), EDGE_MARK, true); - if (count > 2) { - ok = 0; - break; - } - } - - if (!ok) { - break; - } - } - - /* we don't have valid edge layouts, retur */ - if (!ok) { - return; - } - - /* find connected loops within the input edge */ - count = 0; - while (1) { - BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { - if (!BMO_edge_flag_test(bm, e, EDGE_VIS)) { - if (BMO_iter_elem_count_flag(bm, BM_EDGES_OF_VERT, e->v1, EDGE_MARK, true) == 1 || - BMO_iter_elem_count_flag(bm, BM_EDGES_OF_VERT, e->v2, EDGE_MARK, true) == 1) - { - break; - } - } - } - - if (!e) { - break; - } - - if (!count) { - edges = edges1; - } - else if (count == 1) { - edges = edges2; - } - else { - break; - } - - i = 0; - while (e) { - BMO_edge_flag_enable(bm, e, EDGE_VIS); - BLI_array_grow_one(edges); - edges[i] = e; - - e = edge_next(bm, e); - i++; - } - - if (!count) { - edges1 = edges; - BLI_array_len_set(edges1, BLI_array_len(edges)); - } - else { - edges2 = edges; - BLI_array_len_set(edges2, BLI_array_len(edges)); - } - - BLI_array_clear(edges); - count++; - } - - if (edges1 && BLI_array_len(edges1) > 2 && - BM_edge_share_vert_check(edges1[0], edges1[BLI_array_len(edges1) - 1])) - { - if (edges2 && BLI_array_len(edges2) > 2 && - BM_edge_share_vert_check(edges2[0], edges2[BLI_array_len(edges2) - 1])) - { - BLI_array_free(edges1); - BLI_array_free(edges2); - return; - } - else { - edges1 = edges2; - edges2 = NULL; - } - } - - if (edges2 && BLI_array_len(edges2) > 2 && - BM_edge_share_vert_check(edges2[0], edges2[BLI_array_len(edges2) - 1])) - { - edges2 = NULL; - } - - /* two unconnected loops, connect the */ - if (edges1 && edges2) { - BMVert *v1, *v2, *v3, *v4; - float dvec1[3]; - float dvec2[3]; - - if (BLI_array_len(edges1) == 1) { - v1 = edges1[0]->v1; - v2 = edges1[0]->v2; - } - else { - v1 = BM_vert_in_edge(edges1[1], edges1[0]->v1) ? edges1[0]->v2 : edges1[0]->v1; - i = BLI_array_len(edges1) - 1; - v2 = BM_vert_in_edge(edges1[i - 1], edges1[i]->v1) ? edges1[i]->v2 : edges1[i]->v1; - } - - if (BLI_array_len(edges2) == 1) { - v3 = edges2[0]->v1; - v4 = edges2[0]->v2; - } - else { - v3 = BM_vert_in_edge(edges2[1], edges2[0]->v1) ? edges2[0]->v2 : edges2[0]->v1; - i = BLI_array_len(edges2) - 1; - v4 = BM_vert_in_edge(edges2[i - 1], edges2[i]->v1) ? edges2[i]->v2 : edges2[i]->v1; - } - - /* if there is ever bow-tie quads between two edges the problem is here! [#30367] */ + BMOIter siter; + BMEdge *e; + BMEdge **edges1 = NULL, **edges2 = NULL, **edges; + BLI_array_declare(edges1); + BLI_array_declare(edges2); + BLI_array_declare(edges); + bool ok = true; + int i, count; + + BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, EDGE_MARK); + + /* validate that each edge has at most one other tagged edge in the + * disk cycle around each of it's vertices */ + BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { + for (i = 0; i < 2; i++) { + count = BMO_iter_elem_count_flag(bm, BM_EDGES_OF_VERT, (i ? e->v2 : e->v1), EDGE_MARK, true); + if (count > 2) { + ok = 0; + break; + } + } + + if (!ok) { + break; + } + } + + /* we don't have valid edge layouts, retur */ + if (!ok) { + return; + } + + /* find connected loops within the input edge */ + count = 0; + while (1) { + BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { + if (!BMO_edge_flag_test(bm, e, EDGE_VIS)) { + if (BMO_iter_elem_count_flag(bm, BM_EDGES_OF_VERT, e->v1, EDGE_MARK, true) == 1 || + BMO_iter_elem_count_flag(bm, BM_EDGES_OF_VERT, e->v2, EDGE_MARK, true) == 1) { + break; + } + } + } + + if (!e) { + break; + } + + if (!count) { + edges = edges1; + } + else if (count == 1) { + edges = edges2; + } + else { + break; + } + + i = 0; + while (e) { + BMO_edge_flag_enable(bm, e, EDGE_VIS); + BLI_array_grow_one(edges); + edges[i] = e; + + e = edge_next(bm, e); + i++; + } + + if (!count) { + edges1 = edges; + BLI_array_len_set(edges1, BLI_array_len(edges)); + } + else { + edges2 = edges; + BLI_array_len_set(edges2, BLI_array_len(edges)); + } + + BLI_array_clear(edges); + count++; + } + + if (edges1 && BLI_array_len(edges1) > 2 && + BM_edge_share_vert_check(edges1[0], edges1[BLI_array_len(edges1) - 1])) { + if (edges2 && BLI_array_len(edges2) > 2 && + BM_edge_share_vert_check(edges2[0], edges2[BLI_array_len(edges2) - 1])) { + BLI_array_free(edges1); + BLI_array_free(edges2); + return; + } + else { + edges1 = edges2; + edges2 = NULL; + } + } + + if (edges2 && BLI_array_len(edges2) > 2 && + BM_edge_share_vert_check(edges2[0], edges2[BLI_array_len(edges2) - 1])) { + edges2 = NULL; + } + + /* two unconnected loops, connect the */ + if (edges1 && edges2) { + BMVert *v1, *v2, *v3, *v4; + float dvec1[3]; + float dvec2[3]; + + if (BLI_array_len(edges1) == 1) { + v1 = edges1[0]->v1; + v2 = edges1[0]->v2; + } + else { + v1 = BM_vert_in_edge(edges1[1], edges1[0]->v1) ? edges1[0]->v2 : edges1[0]->v1; + i = BLI_array_len(edges1) - 1; + v2 = BM_vert_in_edge(edges1[i - 1], edges1[i]->v1) ? edges1[i]->v2 : edges1[i]->v1; + } + + if (BLI_array_len(edges2) == 1) { + v3 = edges2[0]->v1; + v4 = edges2[0]->v2; + } + else { + v3 = BM_vert_in_edge(edges2[1], edges2[0]->v1) ? edges2[0]->v2 : edges2[0]->v1; + i = BLI_array_len(edges2) - 1; + v4 = BM_vert_in_edge(edges2[i - 1], edges2[i]->v1) ? edges2[i]->v2 : edges2[i]->v1; + } + + /* if there is ever bow-tie quads between two edges the problem is here! [#30367] */ #if 0 - normal_tri_v3(dvec1, v1->co, v2->co, v4->co); - normal_tri_v3(dvec2, v1->co, v4->co, v3->co); + normal_tri_v3(dvec1, v1->co, v2->co, v4->co); + normal_tri_v3(dvec2, v1->co, v4->co, v3->co); #else - { - /* save some CPU cycles and skip the sqrt and 1 subtraction */ - float a1[3], a2[3], a3[3]; - sub_v3_v3v3(a1, v1->co, v2->co); - sub_v3_v3v3(a2, v1->co, v4->co); - sub_v3_v3v3(a3, v1->co, v3->co); - cross_v3_v3v3(dvec1, a1, a2); - cross_v3_v3v3(dvec2, a2, a3); - } + { + /* save some CPU cycles and skip the sqrt and 1 subtraction */ + float a1[3], a2[3], a3[3]; + sub_v3_v3v3(a1, v1->co, v2->co); + sub_v3_v3v3(a2, v1->co, v4->co); + sub_v3_v3v3(a3, v1->co, v3->co); + cross_v3_v3v3(dvec1, a1, a2); + cross_v3_v3v3(dvec2, a2, a3); + } #endif - if (dot_v3v3(dvec1, dvec2) < 0.0f) { - SWAP(BMVert *, v3, v4); - } - - e = BM_edge_create(bm, v1, v3, NULL, BM_CREATE_NO_DOUBLE); - BMO_edge_flag_enable(bm, e, ELE_NEW); - e = BM_edge_create(bm, v2, v4, NULL, BM_CREATE_NO_DOUBLE); - BMO_edge_flag_enable(bm, e, ELE_NEW); - } - else if (edges1) { - BMVert *v1, *v2; - - if (BLI_array_len(edges1) > 1) { - v1 = BM_vert_in_edge(edges1[1], edges1[0]->v1) ? edges1[0]->v2 : edges1[0]->v1; - i = BLI_array_len(edges1) - 1; - v2 = BM_vert_in_edge(edges1[i - 1], edges1[i]->v1) ? edges1[i]->v2 : edges1[i]->v1; - e = BM_edge_create(bm, v1, v2, NULL, BM_CREATE_NO_DOUBLE); - BMO_edge_flag_enable(bm, e, ELE_NEW); - } - } - - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, ELE_NEW); - - BLI_array_free(edges1); - BLI_array_free(edges2); + if (dot_v3v3(dvec1, dvec2) < 0.0f) { + SWAP(BMVert *, v3, v4); + } + + e = BM_edge_create(bm, v1, v3, NULL, BM_CREATE_NO_DOUBLE); + BMO_edge_flag_enable(bm, e, ELE_NEW); + e = BM_edge_create(bm, v2, v4, NULL, BM_CREATE_NO_DOUBLE); + BMO_edge_flag_enable(bm, e, ELE_NEW); + } + else if (edges1) { + BMVert *v1, *v2; + + if (BLI_array_len(edges1) > 1) { + v1 = BM_vert_in_edge(edges1[1], edges1[0]->v1) ? edges1[0]->v2 : edges1[0]->v1; + i = BLI_array_len(edges1) - 1; + v2 = BM_vert_in_edge(edges1[i - 1], edges1[i]->v1) ? edges1[i]->v2 : edges1[i]->v1; + e = BM_edge_create(bm, v1, v2, NULL, BM_CREATE_NO_DOUBLE); + BMO_edge_flag_enable(bm, e, ELE_NEW); + } + } + + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, ELE_NEW); + + BLI_array_free(edges1); + BLI_array_free(edges2); } diff --git a/source/blender/bmesh/operators/bmo_extrude.c b/source/blender/bmesh/operators/bmo_extrude.c index eaf059c7e03..cec7a920abb 100644 --- a/source/blender/bmesh/operators/bmo_extrude.c +++ b/source/blender/bmesh/operators/bmo_extrude.c @@ -36,9 +36,9 @@ #define USE_EDGE_REGION_FLAGS enum { - EXT_INPUT = 1, - EXT_KEEP = 2, - EXT_DEL = 4, + EXT_INPUT = 1, + EXT_KEEP = 2, + EXT_DEL = 4, }; #define VERT_MARK 1 @@ -49,80 +49,78 @@ enum { void bmo_extrude_discrete_faces_exec(BMesh *bm, BMOperator *op) { - const bool use_select_history = BMO_slot_bool_get(op->slots_in, "use_select_history"); - GHash *select_history_map = NULL; - - BMOIter siter; - BMFace *f_org; - - if (use_select_history) { - select_history_map = BM_select_history_map_create(bm); - } - - BMO_ITER (f_org, &siter, op->slots_in, "faces", BM_FACE) { - BMFace *f_new; - BMLoop *l_org, *l_org_first; - BMLoop *l_new; - - BMO_face_flag_enable(bm, f_org, EXT_DEL); - - f_new = BM_face_copy(bm, bm, f_org, true, true); - BMO_face_flag_enable(bm, f_new, EXT_KEEP); - - if (select_history_map) { - BMEditSelection *ese; - ese = BLI_ghash_lookup(select_history_map, f_org); - if (ese) { - ese->ele = (BMElem *)f_new; - } - } - - l_org = l_org_first = BM_FACE_FIRST_LOOP(f_org); - l_new = BM_FACE_FIRST_LOOP(f_new); - - do { - BMFace *f_side; - BMLoop *l_side_iter; - - BM_elem_attrs_copy(bm, bm, l_org, l_new); - - f_side = BM_face_create_quad_tri(bm, - l_org->next->v, l_new->next->v, l_new->v, l_org->v, - f_org, BM_CREATE_NOP); - - l_side_iter = BM_FACE_FIRST_LOOP(f_side); - - BM_elem_attrs_copy(bm, bm, l_org->next, l_side_iter); l_side_iter = l_side_iter->next; - BM_elem_attrs_copy(bm, bm, l_org->next, l_side_iter); l_side_iter = l_side_iter->next; - BM_elem_attrs_copy(bm, bm, l_org, l_side_iter); l_side_iter = l_side_iter->next; - BM_elem_attrs_copy(bm, bm, l_org, l_side_iter); - - if (select_history_map) { - BMEditSelection *ese; - - ese = BLI_ghash_lookup(select_history_map, l_org->v); - if (ese) { - ese->ele = (BMElem *)l_new->v; - } - ese = BLI_ghash_lookup(select_history_map, l_org->e); - if (ese) { - ese->ele = (BMElem *)l_new->e; - } - } - - } while (((void) - (l_new = l_new->next), - (l_org = l_org->next)) != l_org_first); - } - - if (select_history_map) { - BLI_ghash_free(select_history_map, NULL, NULL); - } - - BMO_op_callf(bm, op->flag, - "delete geom=%ff context=%i", - EXT_DEL, DEL_ONLYFACES); - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, EXT_KEEP); + const bool use_select_history = BMO_slot_bool_get(op->slots_in, "use_select_history"); + GHash *select_history_map = NULL; + + BMOIter siter; + BMFace *f_org; + + if (use_select_history) { + select_history_map = BM_select_history_map_create(bm); + } + + BMO_ITER (f_org, &siter, op->slots_in, "faces", BM_FACE) { + BMFace *f_new; + BMLoop *l_org, *l_org_first; + BMLoop *l_new; + + BMO_face_flag_enable(bm, f_org, EXT_DEL); + + f_new = BM_face_copy(bm, bm, f_org, true, true); + BMO_face_flag_enable(bm, f_new, EXT_KEEP); + + if (select_history_map) { + BMEditSelection *ese; + ese = BLI_ghash_lookup(select_history_map, f_org); + if (ese) { + ese->ele = (BMElem *)f_new; + } + } + + l_org = l_org_first = BM_FACE_FIRST_LOOP(f_org); + l_new = BM_FACE_FIRST_LOOP(f_new); + + do { + BMFace *f_side; + BMLoop *l_side_iter; + + BM_elem_attrs_copy(bm, bm, l_org, l_new); + + f_side = BM_face_create_quad_tri( + bm, l_org->next->v, l_new->next->v, l_new->v, l_org->v, f_org, BM_CREATE_NOP); + + l_side_iter = BM_FACE_FIRST_LOOP(f_side); + + BM_elem_attrs_copy(bm, bm, l_org->next, l_side_iter); + l_side_iter = l_side_iter->next; + BM_elem_attrs_copy(bm, bm, l_org->next, l_side_iter); + l_side_iter = l_side_iter->next; + BM_elem_attrs_copy(bm, bm, l_org, l_side_iter); + l_side_iter = l_side_iter->next; + BM_elem_attrs_copy(bm, bm, l_org, l_side_iter); + + if (select_history_map) { + BMEditSelection *ese; + + ese = BLI_ghash_lookup(select_history_map, l_org->v); + if (ese) { + ese->ele = (BMElem *)l_new->v; + } + ese = BLI_ghash_lookup(select_history_map, l_org->e); + if (ese) { + ese->ele = (BMElem *)l_new->e; + } + } + + } while (((void)(l_new = l_new->next), (l_org = l_org->next)) != l_org_first); + } + + if (select_history_map) { + BLI_ghash_free(select_history_map, NULL, NULL); + } + + BMO_op_callf(bm, op->flag, "delete geom=%ff context=%i", EXT_DEL, DEL_ONLYFACES); + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, EXT_KEEP); } /** @@ -137,156 +135,157 @@ void bmo_extrude_discrete_faces_exec(BMesh *bm, BMOperator *op) */ static void bm_extrude_copy_face_loop_attributes(BMesh *bm, BMFace *f) { - /* edge we are extruded from */ - BMLoop *l_first_0 = BM_FACE_FIRST_LOOP(f); - BMLoop *l_first_1 = l_first_0->next; - BMLoop *l_first_2 = l_first_1->next; - BMLoop *l_first_3 = l_first_2->next; + /* edge we are extruded from */ + BMLoop *l_first_0 = BM_FACE_FIRST_LOOP(f); + BMLoop *l_first_1 = l_first_0->next; + BMLoop *l_first_2 = l_first_1->next; + BMLoop *l_first_3 = l_first_2->next; - BMLoop *l_other_0; - BMLoop *l_other_1; + BMLoop *l_other_0; + BMLoop *l_other_1; - if (UNLIKELY(l_first_0 == l_first_0->radial_next)) { - return; - } + if (UNLIKELY(l_first_0 == l_first_0->radial_next)) { + return; + } - l_other_0 = BM_edge_other_loop(l_first_0->e, l_first_0); - l_other_1 = BM_edge_other_loop(l_first_0->e, l_first_1); + l_other_0 = BM_edge_other_loop(l_first_0->e, l_first_0); + l_other_1 = BM_edge_other_loop(l_first_0->e, l_first_1); - /* copy data */ - BM_elem_attrs_copy(bm, bm, l_other_0->f, f); - BM_elem_flag_disable(f, BM_ELEM_HIDDEN); /* possibly we copy from a hidden face */ + /* copy data */ + BM_elem_attrs_copy(bm, bm, l_other_0->f, f); + BM_elem_flag_disable(f, BM_ELEM_HIDDEN); /* possibly we copy from a hidden face */ - BM_elem_attrs_copy(bm, bm, l_other_0, l_first_0); - BM_elem_attrs_copy(bm, bm, l_other_0, l_first_3); + BM_elem_attrs_copy(bm, bm, l_other_0, l_first_0); + BM_elem_attrs_copy(bm, bm, l_other_0, l_first_3); - BM_elem_attrs_copy(bm, bm, l_other_1, l_first_1); - BM_elem_attrs_copy(bm, bm, l_other_1, l_first_2); + BM_elem_attrs_copy(bm, bm, l_other_1, l_first_1); + BM_elem_attrs_copy(bm, bm, l_other_1, l_first_2); } /* Disable the skin root flag on the input vert, assumes that the vert * data includes an CD_MVERT_SKIN layer */ static void bm_extrude_disable_skin_root(BMesh *bm, BMVert *v) { - MVertSkin *vs; + MVertSkin *vs; - vs = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_MVERT_SKIN); - vs->flag &= ~MVERT_SKIN_ROOT; + vs = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_MVERT_SKIN); + vs->flag &= ~MVERT_SKIN_ROOT; } void bmo_extrude_edge_only_exec(BMesh *bm, BMOperator *op) { - BMOIter siter; - BMOperator dupeop; - BMFace *f; - BMEdge *e, *e_new; - const bool use_normal_flip = BMO_slot_bool_get(op->slots_in, "use_normal_flip"); - - BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { - BMO_edge_flag_enable(bm, e, EXT_INPUT); - BMO_vert_flag_enable(bm, e->v1, EXT_INPUT); - BMO_vert_flag_enable(bm, e->v2, EXT_INPUT); - } - - BMO_op_initf( - bm, &dupeop, op->flag, - "duplicate geom=%fve use_select_history=%b", - EXT_INPUT, BMO_slot_bool_get(op->slots_in, "use_select_history")); - - BMO_op_exec(bm, &dupeop); - - /* disable root flag on all new skin nodes */ - if (CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN)) { - BMVert *v; - BMO_ITER (v, &siter, dupeop.slots_out, "geom.out", BM_VERT) { - bm_extrude_disable_skin_root(bm, v); - } - } - - for (e = BMO_iter_new(&siter, dupeop.slots_out, "boundary_map.out", 0); e; e = BMO_iter_step(&siter)) { - BMVert *f_verts[4]; - e_new = BMO_iter_map_value_ptr(&siter); - - - const bool edge_normal_flip = !(e->l && e->v1 != e->l->v); - if (edge_normal_flip == use_normal_flip) { - f_verts[0] = e->v1; - f_verts[1] = e->v2; - f_verts[2] = e_new->v2; - f_verts[3] = e_new->v1; - } - else { - f_verts[0] = e->v2; - f_verts[1] = e->v1; - f_verts[2] = e_new->v1; - f_verts[3] = e_new->v2; - } - /* not sure what to do about example face, pass NULL for now */ - f = BM_face_create_verts(bm, f_verts, 4, NULL, BM_CREATE_NOP, true); - bm_extrude_copy_face_loop_attributes(bm, f); - - if (BMO_edge_flag_test(bm, e, EXT_INPUT)) { - e = e_new; - } - - BMO_face_flag_enable(bm, f, EXT_KEEP); - BMO_edge_flag_enable(bm, e, EXT_KEEP); - BMO_vert_flag_enable(bm, e->v1, EXT_KEEP); - BMO_vert_flag_enable(bm, e->v2, EXT_KEEP); - - } - - BMO_op_finish(bm, &dupeop); - - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, EXT_KEEP); + BMOIter siter; + BMOperator dupeop; + BMFace *f; + BMEdge *e, *e_new; + const bool use_normal_flip = BMO_slot_bool_get(op->slots_in, "use_normal_flip"); + + BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { + BMO_edge_flag_enable(bm, e, EXT_INPUT); + BMO_vert_flag_enable(bm, e->v1, EXT_INPUT); + BMO_vert_flag_enable(bm, e->v2, EXT_INPUT); + } + + BMO_op_initf(bm, + &dupeop, + op->flag, + "duplicate geom=%fve use_select_history=%b", + EXT_INPUT, + BMO_slot_bool_get(op->slots_in, "use_select_history")); + + BMO_op_exec(bm, &dupeop); + + /* disable root flag on all new skin nodes */ + if (CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN)) { + BMVert *v; + BMO_ITER (v, &siter, dupeop.slots_out, "geom.out", BM_VERT) { + bm_extrude_disable_skin_root(bm, v); + } + } + + for (e = BMO_iter_new(&siter, dupeop.slots_out, "boundary_map.out", 0); e; + e = BMO_iter_step(&siter)) { + BMVert *f_verts[4]; + e_new = BMO_iter_map_value_ptr(&siter); + + const bool edge_normal_flip = !(e->l && e->v1 != e->l->v); + if (edge_normal_flip == use_normal_flip) { + f_verts[0] = e->v1; + f_verts[1] = e->v2; + f_verts[2] = e_new->v2; + f_verts[3] = e_new->v1; + } + else { + f_verts[0] = e->v2; + f_verts[1] = e->v1; + f_verts[2] = e_new->v1; + f_verts[3] = e_new->v2; + } + /* not sure what to do about example face, pass NULL for now */ + f = BM_face_create_verts(bm, f_verts, 4, NULL, BM_CREATE_NOP, true); + bm_extrude_copy_face_loop_attributes(bm, f); + + if (BMO_edge_flag_test(bm, e, EXT_INPUT)) { + e = e_new; + } + + BMO_face_flag_enable(bm, f, EXT_KEEP); + BMO_edge_flag_enable(bm, e, EXT_KEEP); + BMO_vert_flag_enable(bm, e->v1, EXT_KEEP); + BMO_vert_flag_enable(bm, e->v2, EXT_KEEP); + } + + BMO_op_finish(bm, &dupeop); + + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, EXT_KEEP); } void bmo_extrude_vert_indiv_exec(BMesh *bm, BMOperator *op) { - const bool use_select_history = BMO_slot_bool_get(op->slots_in, "use_select_history"); - BMOIter siter; - BMVert *v, *dupev; - BMEdge *e; - const bool has_vskin = CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN); - GHash *select_history_map = NULL; - - if (use_select_history) { - select_history_map = BM_select_history_map_create(bm); - } - - for (v = BMO_iter_new(&siter, op->slots_in, "verts", BM_VERT); v; v = BMO_iter_step(&siter)) { - dupev = BM_vert_create(bm, v->co, v, BM_CREATE_NOP); - BMO_vert_flag_enable(bm, dupev, EXT_KEEP); - - if (has_vskin) { - bm_extrude_disable_skin_root(bm, v); - } - - if (select_history_map) { - BMEditSelection *ese; - ese = BLI_ghash_lookup(select_history_map, v); - if (ese) { - ese->ele = (BMElem *)dupev; - } - } - - /* not essential, but ensures face normals from extruded edges are contiguous */ - if (BM_vert_is_wire_endpoint(v)) { - if (v->e->v1 == v) { - SWAP(BMVert *, v, dupev); - } - } - - e = BM_edge_create(bm, v, dupev, NULL, BM_CREATE_NOP); - BMO_edge_flag_enable(bm, e, EXT_KEEP); - } - - if (select_history_map) { - BLI_ghash_free(select_history_map, NULL, NULL); - } - - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, EXT_KEEP); - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EXT_KEEP); + const bool use_select_history = BMO_slot_bool_get(op->slots_in, "use_select_history"); + BMOIter siter; + BMVert *v, *dupev; + BMEdge *e; + const bool has_vskin = CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN); + GHash *select_history_map = NULL; + + if (use_select_history) { + select_history_map = BM_select_history_map_create(bm); + } + + for (v = BMO_iter_new(&siter, op->slots_in, "verts", BM_VERT); v; v = BMO_iter_step(&siter)) { + dupev = BM_vert_create(bm, v->co, v, BM_CREATE_NOP); + BMO_vert_flag_enable(bm, dupev, EXT_KEEP); + + if (has_vskin) { + bm_extrude_disable_skin_root(bm, v); + } + + if (select_history_map) { + BMEditSelection *ese; + ese = BLI_ghash_lookup(select_history_map, v); + if (ese) { + ese->ele = (BMElem *)dupev; + } + } + + /* not essential, but ensures face normals from extruded edges are contiguous */ + if (BM_vert_is_wire_endpoint(v)) { + if (v->e->v1 == v) { + SWAP(BMVert *, v, dupev); + } + } + + e = BM_edge_create(bm, v, dupev, NULL, BM_CREATE_NOP); + BMO_edge_flag_enable(bm, e, EXT_KEEP); + } + + if (select_history_map) { + BLI_ghash_free(select_history_map, NULL, NULL); + } + + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, EXT_KEEP); + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EXT_KEEP); } #ifdef USE_EDGE_REGION_FLAGS @@ -296,280 +295,275 @@ void bmo_extrude_vert_indiv_exec(BMesh *bm, BMOperator *op) */ static bool bm_extrude_region_edge_flag(const BMVert *v, char r_e_hflag[2]) { - BMEdge *e_iter; - const char hflag_enable = BM_ELEM_SEAM; - const char hflag_disable = BM_ELEM_SMOOTH; - bool ok = false; - - r_e_hflag[0] = 0x0; - r_e_hflag[1] = 0xff; - - /* clear flags on both disks */ - e_iter = v->e; - do { - if (e_iter->l && !BM_edge_is_boundary(e_iter)) { - r_e_hflag[0] |= e_iter->head.hflag; - r_e_hflag[1] &= e_iter->head.hflag; - ok = true; - } - } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != v->e); - - if (ok) { - r_e_hflag[0] &= hflag_enable; - r_e_hflag[1] = hflag_disable & ~r_e_hflag[1]; - } - return ok; + BMEdge *e_iter; + const char hflag_enable = BM_ELEM_SEAM; + const char hflag_disable = BM_ELEM_SMOOTH; + bool ok = false; + + r_e_hflag[0] = 0x0; + r_e_hflag[1] = 0xff; + + /* clear flags on both disks */ + e_iter = v->e; + do { + if (e_iter->l && !BM_edge_is_boundary(e_iter)) { + r_e_hflag[0] |= e_iter->head.hflag; + r_e_hflag[1] &= e_iter->head.hflag; + ok = true; + } + } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != v->e); + + if (ok) { + r_e_hflag[0] &= hflag_enable; + r_e_hflag[1] = hflag_disable & ~r_e_hflag[1]; + } + return ok; } -#endif /* USE_EDGE_REGION_FLAGS */ +#endif /* USE_EDGE_REGION_FLAGS */ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op) { - BMOperator dupeop, delop; - BMOIter siter; - BMIter iter, fiter, viter; - BMEdge *e, *e_new; - BMVert *v; - BMFace *f; - bool found, delorig = false; - BMOpSlot *slot_facemap_out; - BMOpSlot *slot_edges_exclude; - const bool use_normal_flip = BMO_slot_bool_get(op->slots_in, "use_normal_flip"); - const bool use_normal_from_adjacent = BMO_slot_bool_get(op->slots_in, "use_normal_from_adjacent"); - - /* initialize our sub-operators */ - BMO_op_initf( - bm, &dupeop, op->flag, - "duplicate use_select_history=%b", - BMO_slot_bool_get(op->slots_in, "use_select_history")); - - BMO_slot_buffer_flag_enable(bm, op->slots_in, "geom", BM_EDGE | BM_FACE, EXT_INPUT); - - /* if one flagged face is bordered by an un-flagged face, then we delete - * original geometry unless caller explicitly asked to keep it. */ - if (!BMO_slot_bool_get(op->slots_in, "use_keep_orig")) { - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - - int edge_face_tot; - - if (!BMO_edge_flag_test(bm, e, EXT_INPUT)) { - continue; - } - - found = false; /* found a face that isn't input? */ - edge_face_tot = 0; /* edge/face count */ - - BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { - if (!BMO_face_flag_test(bm, f, EXT_INPUT)) { - found = true; - delorig = true; - break; - } - - edge_face_tot++; - } - - if ((edge_face_tot > 1) && (found == false)) { - /* edge has a face user, that face isn't extrude input */ - BMO_edge_flag_enable(bm, e, EXT_DEL); - } - } - } - - /* calculate verts to delete */ - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (v->e) { /* only deal with verts attached to geometry [#33651] */ - found = false; - - BM_ITER_ELEM (e, &viter, v, BM_EDGES_OF_VERT) { - if (!BMO_edge_flag_test(bm, e, EXT_INPUT) || - !BMO_edge_flag_test(bm, e, EXT_DEL)) - { - found = true; - break; - } - } - - /* avoid an extra loop */ - if (found == true) { - BM_ITER_ELEM (f, &viter, v, BM_FACES_OF_VERT) { - if (!BMO_face_flag_test(bm, f, EXT_INPUT)) { - found = true; - break; - } - } - } - - if (found == false) { - BMO_vert_flag_enable(bm, v, EXT_DEL); - } - } - } - - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (BMO_face_flag_test(bm, f, EXT_INPUT)) { - BMO_face_flag_enable(bm, f, EXT_DEL); - } - } - - if (delorig == true) { - BMO_op_initf(bm, &delop, op->flag, - "delete geom=%fvef context=%i", - EXT_DEL, DEL_ONLYTAGGED); - } - - BMO_slot_copy(op, slots_in, "geom", - &dupeop, slots_in, "geom"); - BMO_op_exec(bm, &dupeop); - - /* disable root flag on all new skin nodes */ - if (CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN)) { - BMO_ITER (v, &siter, dupeop.slots_out, "geom.out", BM_VERT) { - bm_extrude_disable_skin_root(bm, v); - } - } - - slot_facemap_out = BMO_slot_get(dupeop.slots_out, "face_map.out"); - if (bm->act_face && BMO_face_flag_test(bm, bm->act_face, EXT_INPUT)) { - bm->act_face = BMO_slot_map_elem_get(slot_facemap_out, bm->act_face); - } - - if (delorig) { - BMO_op_exec(bm, &delop); - } - - /* if not delorig, reverse loops of original face */ - if (!delorig) { - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (BMO_face_flag_test(bm, f, EXT_INPUT)) { - BM_face_normal_flip(bm, f); - } - } - } - - BMO_slot_copy(&dupeop, slots_out, "geom.out", - op, slots_out, "geom.out"); - - slot_edges_exclude = BMO_slot_get(op->slots_in, "edges_exclude"); - for (e = BMO_iter_new(&siter, dupeop.slots_out, "boundary_map.out", 0); e; e = BMO_iter_step(&siter)) { - BMVert *f_verts[4]; + BMOperator dupeop, delop; + BMOIter siter; + BMIter iter, fiter, viter; + BMEdge *e, *e_new; + BMVert *v; + BMFace *f; + bool found, delorig = false; + BMOpSlot *slot_facemap_out; + BMOpSlot *slot_edges_exclude; + const bool use_normal_flip = BMO_slot_bool_get(op->slots_in, "use_normal_flip"); + const bool use_normal_from_adjacent = BMO_slot_bool_get(op->slots_in, + "use_normal_from_adjacent"); + + /* initialize our sub-operators */ + BMO_op_initf(bm, + &dupeop, + op->flag, + "duplicate use_select_history=%b", + BMO_slot_bool_get(op->slots_in, "use_select_history")); + + BMO_slot_buffer_flag_enable(bm, op->slots_in, "geom", BM_EDGE | BM_FACE, EXT_INPUT); + + /* if one flagged face is bordered by an un-flagged face, then we delete + * original geometry unless caller explicitly asked to keep it. */ + if (!BMO_slot_bool_get(op->slots_in, "use_keep_orig")) { + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + + int edge_face_tot; + + if (!BMO_edge_flag_test(bm, e, EXT_INPUT)) { + continue; + } + + found = false; /* found a face that isn't input? */ + edge_face_tot = 0; /* edge/face count */ + + BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { + if (!BMO_face_flag_test(bm, f, EXT_INPUT)) { + found = true; + delorig = true; + break; + } + + edge_face_tot++; + } + + if ((edge_face_tot > 1) && (found == false)) { + /* edge has a face user, that face isn't extrude input */ + BMO_edge_flag_enable(bm, e, EXT_DEL); + } + } + } + + /* calculate verts to delete */ + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (v->e) { /* only deal with verts attached to geometry [#33651] */ + found = false; + + BM_ITER_ELEM (e, &viter, v, BM_EDGES_OF_VERT) { + if (!BMO_edge_flag_test(bm, e, EXT_INPUT) || !BMO_edge_flag_test(bm, e, EXT_DEL)) { + found = true; + break; + } + } + + /* avoid an extra loop */ + if (found == true) { + BM_ITER_ELEM (f, &viter, v, BM_FACES_OF_VERT) { + if (!BMO_face_flag_test(bm, f, EXT_INPUT)) { + found = true; + break; + } + } + } + + if (found == false) { + BMO_vert_flag_enable(bm, v, EXT_DEL); + } + } + } + + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (BMO_face_flag_test(bm, f, EXT_INPUT)) { + BMO_face_flag_enable(bm, f, EXT_DEL); + } + } + + if (delorig == true) { + BMO_op_initf(bm, &delop, op->flag, "delete geom=%fvef context=%i", EXT_DEL, DEL_ONLYTAGGED); + } + + BMO_slot_copy(op, slots_in, "geom", &dupeop, slots_in, "geom"); + BMO_op_exec(bm, &dupeop); + + /* disable root flag on all new skin nodes */ + if (CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN)) { + BMO_ITER (v, &siter, dupeop.slots_out, "geom.out", BM_VERT) { + bm_extrude_disable_skin_root(bm, v); + } + } + + slot_facemap_out = BMO_slot_get(dupeop.slots_out, "face_map.out"); + if (bm->act_face && BMO_face_flag_test(bm, bm->act_face, EXT_INPUT)) { + bm->act_face = BMO_slot_map_elem_get(slot_facemap_out, bm->act_face); + } + + if (delorig) { + BMO_op_exec(bm, &delop); + } + + /* if not delorig, reverse loops of original face */ + if (!delorig) { + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (BMO_face_flag_test(bm, f, EXT_INPUT)) { + BM_face_normal_flip(bm, f); + } + } + } + + BMO_slot_copy(&dupeop, slots_out, "geom.out", op, slots_out, "geom.out"); + + slot_edges_exclude = BMO_slot_get(op->slots_in, "edges_exclude"); + for (e = BMO_iter_new(&siter, dupeop.slots_out, "boundary_map.out", 0); e; + e = BMO_iter_step(&siter)) { + BMVert *f_verts[4]; #ifdef USE_EDGE_REGION_FLAGS - BMEdge *f_edges[4]; + BMEdge *f_edges[4]; #endif - /* this should always be wire, so this is mainly a speedup to avoid map lookup */ - if (BM_edge_is_wire(e) && BMO_slot_map_contains(slot_edges_exclude, e)) { - BMVert *v1 = e->v1, *v2 = e->v2; - - /* The original edge was excluded, - * this would result in a standalone wire edge - see [#30399] */ - BM_edge_kill(bm, e); - - /* kill standalone vertices from this edge - see [#32341] */ - if (!v1->e) { - BM_vert_kill(bm, v1); - } - if (!v2->e) { - BM_vert_kill(bm, v2); - } - - continue; - } - - /* skip creating face for excluded edges see [#35503] */ - if (BMO_slot_map_contains(slot_edges_exclude, e)) { - /* simply skip creating the face */ - continue; - } - - e_new = BMO_iter_map_value_ptr(&siter); - - if (!e_new) { - continue; - } - - bool edge_normal_flip; - if (use_normal_from_adjacent == false) { - /* Orient loop to give same normal as a loop of 'e_new' - * if it exists (will be one of the faces from the region), - * else same normal as a loop of e, if it exists. */ - edge_normal_flip = !( - e_new->l ? - (e_new->l->v == e_new->v1) : - (!e->l || !(e->l->v == e->v1))); - } - else { - /* Special case, needed for repetitive extrusions - * that use the normals from the previously created faces. */ - edge_normal_flip = !(e->l && e->v1 != e->l->v); - } - - if (edge_normal_flip == use_normal_flip) { - f_verts[0] = e->v1; - f_verts[1] = e->v2; - f_verts[2] = e_new->v2; - f_verts[3] = e_new->v1; - } - else { - f_verts[0] = e->v2; - f_verts[1] = e->v1; - f_verts[2] = e_new->v1; - f_verts[3] = e_new->v2; - } + /* this should always be wire, so this is mainly a speedup to avoid map lookup */ + if (BM_edge_is_wire(e) && BMO_slot_map_contains(slot_edges_exclude, e)) { + BMVert *v1 = e->v1, *v2 = e->v2; + + /* The original edge was excluded, + * this would result in a standalone wire edge - see [#30399] */ + BM_edge_kill(bm, e); + + /* kill standalone vertices from this edge - see [#32341] */ + if (!v1->e) { + BM_vert_kill(bm, v1); + } + if (!v2->e) { + BM_vert_kill(bm, v2); + } + + continue; + } + + /* skip creating face for excluded edges see [#35503] */ + if (BMO_slot_map_contains(slot_edges_exclude, e)) { + /* simply skip creating the face */ + continue; + } + + e_new = BMO_iter_map_value_ptr(&siter); + + if (!e_new) { + continue; + } + + bool edge_normal_flip; + if (use_normal_from_adjacent == false) { + /* Orient loop to give same normal as a loop of 'e_new' + * if it exists (will be one of the faces from the region), + * else same normal as a loop of e, if it exists. */ + edge_normal_flip = !(e_new->l ? (e_new->l->v == e_new->v1) : (!e->l || !(e->l->v == e->v1))); + } + else { + /* Special case, needed for repetitive extrusions + * that use the normals from the previously created faces. */ + edge_normal_flip = !(e->l && e->v1 != e->l->v); + } + + if (edge_normal_flip == use_normal_flip) { + f_verts[0] = e->v1; + f_verts[1] = e->v2; + f_verts[2] = e_new->v2; + f_verts[3] = e_new->v1; + } + else { + f_verts[0] = e->v2; + f_verts[1] = e->v1; + f_verts[2] = e_new->v1; + f_verts[3] = e_new->v2; + } #ifdef USE_EDGE_REGION_FLAGS - /* handle new edges */ - f_edges[0] = e; - f_edges[2] = e_new; - - f_edges[1] = BM_edge_exists(f_verts[1], f_verts[2]); - if (f_edges[1] == NULL) { - char e_hflag[2]; - bool e_hflag_ok = bm_extrude_region_edge_flag(f_verts[2], e_hflag); - f_edges[1] = BM_edge_create(bm, f_verts[1], f_verts[2], NULL, BM_CREATE_NOP); - if (e_hflag_ok) { - BM_elem_flag_enable(f_edges[1], e_hflag[0]); - BM_elem_flag_disable(f_edges[1], e_hflag[1]); - } - } - - f_edges[3] = BM_edge_exists(f_verts[3], f_verts[0]); - if (f_edges[3] == NULL) { - char e_hflag[2]; - bool e_hflag_ok = bm_extrude_region_edge_flag(f_verts[3], e_hflag); - f_edges[3] = BM_edge_create(bm, f_verts[3], f_verts[0], NULL, BM_CREATE_NOP); - if (e_hflag_ok) { - BM_elem_flag_enable(f_edges[3], e_hflag[0]); - BM_elem_flag_disable(f_edges[3], e_hflag[1]); - } - } - - f = BM_face_create(bm, f_verts, f_edges, 4, NULL, BM_CREATE_NOP); + /* handle new edges */ + f_edges[0] = e; + f_edges[2] = e_new; + + f_edges[1] = BM_edge_exists(f_verts[1], f_verts[2]); + if (f_edges[1] == NULL) { + char e_hflag[2]; + bool e_hflag_ok = bm_extrude_region_edge_flag(f_verts[2], e_hflag); + f_edges[1] = BM_edge_create(bm, f_verts[1], f_verts[2], NULL, BM_CREATE_NOP); + if (e_hflag_ok) { + BM_elem_flag_enable(f_edges[1], e_hflag[0]); + BM_elem_flag_disable(f_edges[1], e_hflag[1]); + } + } + + f_edges[3] = BM_edge_exists(f_verts[3], f_verts[0]); + if (f_edges[3] == NULL) { + char e_hflag[2]; + bool e_hflag_ok = bm_extrude_region_edge_flag(f_verts[3], e_hflag); + f_edges[3] = BM_edge_create(bm, f_verts[3], f_verts[0], NULL, BM_CREATE_NOP); + if (e_hflag_ok) { + BM_elem_flag_enable(f_edges[3], e_hflag[0]); + BM_elem_flag_disable(f_edges[3], e_hflag[1]); + } + } + + f = BM_face_create(bm, f_verts, f_edges, 4, NULL, BM_CREATE_NOP); #else - f = BM_face_create_verts(bm, f_verts, 4, NULL, BM_CREATE_NOP, true); + f = BM_face_create_verts(bm, f_verts, 4, NULL, BM_CREATE_NOP, true); #endif - bm_extrude_copy_face_loop_attributes(bm, f); - } - - /* link isolated vert */ - for (v = BMO_iter_new(&siter, dupeop.slots_out, "isovert_map.out", 0); v; v = BMO_iter_step(&siter)) { - BMVert *v2 = BMO_iter_map_value_ptr(&siter); - - /* not essential, but ensures face normals from extruded edges are contiguous */ - if (BM_vert_is_wire_endpoint(v)) { - if (v->e->v1 == v) { - SWAP(BMVert *, v, v2); - } - } - - BM_edge_create(bm, v, v2, NULL, BM_CREATE_NO_DOUBLE); - } - - /* cleanup */ - if (delorig) { - BMO_op_finish(bm, &delop); - } - BMO_op_finish(bm, &dupeop); + bm_extrude_copy_face_loop_attributes(bm, f); + } + + /* link isolated vert */ + for (v = BMO_iter_new(&siter, dupeop.slots_out, "isovert_map.out", 0); v; + v = BMO_iter_step(&siter)) { + BMVert *v2 = BMO_iter_map_value_ptr(&siter); + + /* not essential, but ensures face normals from extruded edges are contiguous */ + if (BM_vert_is_wire_endpoint(v)) { + if (v->e->v1 == v) { + SWAP(BMVert *, v, v2); + } + } + + BM_edge_create(bm, v, v2, NULL, BM_CREATE_NO_DOUBLE); + } + + /* cleanup */ + if (delorig) { + BMO_op_finish(bm, &delop); + } + BMO_op_finish(bm, &dupeop); } /* @@ -580,231 +574,229 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op) */ static void calc_solidify_normals(BMesh *bm) { - BMIter viter, eiter, fiter; - BMVert *v; - BMEdge *e; - BMFace *f, *f1, *f2; - float edge_normal[3]; - int i; - - /* can't use BM_edge_face_count because we need to count only marked faces */ - int *edge_face_count = MEM_callocN(sizeof(int) * bm->totedge, __func__); - - BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { - BM_elem_flag_enable(v, BM_ELEM_TAG); - } - - BM_mesh_elem_index_ensure(bm, BM_EDGE); - - BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { - if (!BMO_face_flag_test(bm, f, FACE_MARK)) { - continue; - } - - BM_ITER_ELEM (e, &eiter, f, BM_EDGES_OF_FACE) { - - /* And mark all edges and vertices on the - * marked faces */ - BMO_edge_flag_enable(bm, e, EDGE_MARK); - BMO_vert_flag_enable(bm, e->v1, VERT_MARK); - BMO_vert_flag_enable(bm, e->v2, VERT_MARK); - edge_face_count[BM_elem_index_get(e)]++; - } - } - - BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { - if (!BMO_edge_flag_test(bm, e, EDGE_MARK)) { - continue; - } - - i = edge_face_count[BM_elem_index_get(e)]++; - - if (i == 0 || i > 2) { - /* Edge & vertices are non-manifold even when considering - * only marked faces */ - BMO_edge_flag_enable(bm, e, EDGE_NONMAN); - BMO_vert_flag_enable(bm, e->v1, VERT_NONMAN); - BMO_vert_flag_enable(bm, e->v2, VERT_NONMAN); - } - } - MEM_freeN(edge_face_count); - edge_face_count = NULL; /* don't re-use */ - - BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { - if (!BM_vert_is_manifold(v)) { - BMO_vert_flag_enable(bm, v, VERT_NONMAN); - continue; - } - - if (BMO_vert_flag_test(bm, v, VERT_MARK)) { - zero_v3(v->no); - } - } - - BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { - - /* If the edge is not part of a the solidify region - * its normal should not be considered */ - if (!BMO_edge_flag_test(bm, e, EDGE_MARK)) { - continue; - } - - /* If the edge joins more than two marked faces high - * quality normal computation won't work */ - if (BMO_edge_flag_test(bm, e, EDGE_NONMAN)) { - continue; - } - - f1 = f2 = NULL; - - BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { - if (BMO_face_flag_test(bm, f, FACE_MARK)) { - if (f1 == NULL) { - f1 = f; - } - else { - BLI_assert(f2 == NULL); - f2 = f; - } - } - } - - BLI_assert(f1 != NULL); - - if (f2 != NULL) { - const float angle = angle_normalized_v3v3(f1->no, f2->no); - - if (angle > 0.0f) { - /* two faces using this edge, calculate the edge normal - * using the angle between the faces as a weighting */ - add_v3_v3v3(edge_normal, f1->no, f2->no); - normalize_v3_length(edge_normal, angle); - } - else { - /* can't do anything useful here! - * Set the face index for a vert in case it gets a zero normal */ - BM_elem_flag_disable(e->v1, BM_ELEM_TAG); - BM_elem_flag_disable(e->v2, BM_ELEM_TAG); - continue; - } - } - else { - /* only one face attached to that edge */ - /* an edge without another attached- the weight on this is undefined, - * M_PI_2 is 90d in radians and that seems good enough */ - copy_v3_v3(edge_normal, f1->no); - mul_v3_fl(edge_normal, M_PI_2); - } - - add_v3_v3(e->v1->no, edge_normal); - add_v3_v3(e->v2->no, edge_normal); - } - - /* normalize accumulated vertex normal */ - BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { - if (!BMO_vert_flag_test(bm, v, VERT_MARK)) { - continue; - } - - if (BMO_vert_flag_test(bm, v, VERT_NONMAN)) { - /* use standard normals for vertices connected to non-manifold edges */ - BM_vert_normal_update(v); - } - else if (normalize_v3(v->no) == 0.0f && !BM_elem_flag_test(v, BM_ELEM_TAG)) { - /* exceptional case, totally flat. use the normal - * of any marked face around the vertex */ - BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) { - if (BMO_face_flag_test(bm, f, FACE_MARK)) { - break; - } - } - copy_v3_v3(v->no, f->no); - } - } + BMIter viter, eiter, fiter; + BMVert *v; + BMEdge *e; + BMFace *f, *f1, *f2; + float edge_normal[3]; + int i; + + /* can't use BM_edge_face_count because we need to count only marked faces */ + int *edge_face_count = MEM_callocN(sizeof(int) * bm->totedge, __func__); + + BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { + BM_elem_flag_enable(v, BM_ELEM_TAG); + } + + BM_mesh_elem_index_ensure(bm, BM_EDGE); + + BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { + if (!BMO_face_flag_test(bm, f, FACE_MARK)) { + continue; + } + + BM_ITER_ELEM (e, &eiter, f, BM_EDGES_OF_FACE) { + + /* And mark all edges and vertices on the + * marked faces */ + BMO_edge_flag_enable(bm, e, EDGE_MARK); + BMO_vert_flag_enable(bm, e->v1, VERT_MARK); + BMO_vert_flag_enable(bm, e->v2, VERT_MARK); + edge_face_count[BM_elem_index_get(e)]++; + } + } + + BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { + if (!BMO_edge_flag_test(bm, e, EDGE_MARK)) { + continue; + } + + i = edge_face_count[BM_elem_index_get(e)]++; + + if (i == 0 || i > 2) { + /* Edge & vertices are non-manifold even when considering + * only marked faces */ + BMO_edge_flag_enable(bm, e, EDGE_NONMAN); + BMO_vert_flag_enable(bm, e->v1, VERT_NONMAN); + BMO_vert_flag_enable(bm, e->v2, VERT_NONMAN); + } + } + MEM_freeN(edge_face_count); + edge_face_count = NULL; /* don't re-use */ + + BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { + if (!BM_vert_is_manifold(v)) { + BMO_vert_flag_enable(bm, v, VERT_NONMAN); + continue; + } + + if (BMO_vert_flag_test(bm, v, VERT_MARK)) { + zero_v3(v->no); + } + } + + BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { + + /* If the edge is not part of a the solidify region + * its normal should not be considered */ + if (!BMO_edge_flag_test(bm, e, EDGE_MARK)) { + continue; + } + + /* If the edge joins more than two marked faces high + * quality normal computation won't work */ + if (BMO_edge_flag_test(bm, e, EDGE_NONMAN)) { + continue; + } + + f1 = f2 = NULL; + + BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { + if (BMO_face_flag_test(bm, f, FACE_MARK)) { + if (f1 == NULL) { + f1 = f; + } + else { + BLI_assert(f2 == NULL); + f2 = f; + } + } + } + + BLI_assert(f1 != NULL); + + if (f2 != NULL) { + const float angle = angle_normalized_v3v3(f1->no, f2->no); + + if (angle > 0.0f) { + /* two faces using this edge, calculate the edge normal + * using the angle between the faces as a weighting */ + add_v3_v3v3(edge_normal, f1->no, f2->no); + normalize_v3_length(edge_normal, angle); + } + else { + /* can't do anything useful here! + * Set the face index for a vert in case it gets a zero normal */ + BM_elem_flag_disable(e->v1, BM_ELEM_TAG); + BM_elem_flag_disable(e->v2, BM_ELEM_TAG); + continue; + } + } + else { + /* only one face attached to that edge */ + /* an edge without another attached- the weight on this is undefined, + * M_PI_2 is 90d in radians and that seems good enough */ + copy_v3_v3(edge_normal, f1->no); + mul_v3_fl(edge_normal, M_PI_2); + } + + add_v3_v3(e->v1->no, edge_normal); + add_v3_v3(e->v2->no, edge_normal); + } + + /* normalize accumulated vertex normal */ + BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { + if (!BMO_vert_flag_test(bm, v, VERT_MARK)) { + continue; + } + + if (BMO_vert_flag_test(bm, v, VERT_NONMAN)) { + /* use standard normals for vertices connected to non-manifold edges */ + BM_vert_normal_update(v); + } + else if (normalize_v3(v->no) == 0.0f && !BM_elem_flag_test(v, BM_ELEM_TAG)) { + /* exceptional case, totally flat. use the normal + * of any marked face around the vertex */ + BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) { + if (BMO_face_flag_test(bm, f, FACE_MARK)) { + break; + } + } + copy_v3_v3(v->no, f->no); + } + } } static void solidify_add_thickness(BMesh *bm, const float dist) { - BMFace *f; - BMVert *v; - BMLoop *l; - BMIter iter, loopIter; - float *vert_angles = MEM_callocN(sizeof(float) * bm->totvert * 2, "solidify"); /* 2 in 1 */ - float *vert_accum = vert_angles + bm->totvert; - int i, index; - - BLI_buffer_declare_static(float, face_angles_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); - BLI_buffer_declare_static(float *, verts_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); - - BM_mesh_elem_index_ensure(bm, BM_VERT); - - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (BMO_face_flag_test(bm, f, FACE_MARK)) { - - /* array for passing verts to angle_poly_v3 */ - float *face_angles = BLI_buffer_reinit_data(&face_angles_buf, float, f->len); - /* array for receiving angles from angle_poly_v3 */ - float **verts = BLI_buffer_reinit_data(&verts_buf, float *, f->len); - - BM_ITER_ELEM_INDEX (l, &loopIter, f, BM_LOOPS_OF_FACE, i) { - verts[i] = l->v->co; - } - - angle_poly_v3(face_angles, (const float **)verts, f->len); - - i = 0; - BM_ITER_ELEM (l, &loopIter, f, BM_LOOPS_OF_FACE) { - v = l->v; - index = BM_elem_index_get(v); - vert_accum[index] += face_angles[i]; - vert_angles[index] += shell_v3v3_normalized_to_dist(v->no, f->no) * face_angles[i]; - i++; - } - } - } - - BLI_buffer_free(&face_angles_buf); - BLI_buffer_free(&verts_buf); - - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - index = BM_elem_index_get(v); - if (vert_accum[index]) { /* zero if unselected */ - madd_v3_v3fl(v->co, v->no, dist * (vert_angles[index] / vert_accum[index])); - } - } - - MEM_freeN(vert_angles); + BMFace *f; + BMVert *v; + BMLoop *l; + BMIter iter, loopIter; + float *vert_angles = MEM_callocN(sizeof(float) * bm->totvert * 2, "solidify"); /* 2 in 1 */ + float *vert_accum = vert_angles + bm->totvert; + int i, index; + + BLI_buffer_declare_static(float, face_angles_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); + BLI_buffer_declare_static(float *, verts_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); + + BM_mesh_elem_index_ensure(bm, BM_VERT); + + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (BMO_face_flag_test(bm, f, FACE_MARK)) { + + /* array for passing verts to angle_poly_v3 */ + float *face_angles = BLI_buffer_reinit_data(&face_angles_buf, float, f->len); + /* array for receiving angles from angle_poly_v3 */ + float **verts = BLI_buffer_reinit_data(&verts_buf, float *, f->len); + + BM_ITER_ELEM_INDEX(l, &loopIter, f, BM_LOOPS_OF_FACE, i) + { + verts[i] = l->v->co; + } + + angle_poly_v3(face_angles, (const float **)verts, f->len); + + i = 0; + BM_ITER_ELEM (l, &loopIter, f, BM_LOOPS_OF_FACE) { + v = l->v; + index = BM_elem_index_get(v); + vert_accum[index] += face_angles[i]; + vert_angles[index] += shell_v3v3_normalized_to_dist(v->no, f->no) * face_angles[i]; + i++; + } + } + } + + BLI_buffer_free(&face_angles_buf); + BLI_buffer_free(&verts_buf); + + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + index = BM_elem_index_get(v); + if (vert_accum[index]) { /* zero if unselected */ + madd_v3_v3fl(v->co, v->no, dist * (vert_angles[index] / vert_accum[index])); + } + } + + MEM_freeN(vert_angles); } void bmo_solidify_face_region_exec(BMesh *bm, BMOperator *op) { - BMOperator extrudeop; - BMOperator reverseop; - float thickness; - - thickness = BMO_slot_float_get(op->slots_in, "thickness"); - - /* Flip original faces (so the shell is extruded inward) */ - BMO_op_init(bm, &reverseop, op->flag, "reverse_faces"); - BMO_slot_bool_set(reverseop.slots_in, "flip_multires", true); - BMO_slot_copy(op, slots_in, "geom", - &reverseop, slots_in, "faces"); - BMO_op_exec(bm, &reverseop); - BMO_op_finish(bm, &reverseop); - - /* Extrude the region */ - BMO_op_initf(bm, &extrudeop, op->flag, "extrude_face_region use_keep_orig=%b", true); - BMO_slot_copy(op, slots_in, "geom", - &extrudeop, slots_in, "geom"); - BMO_op_exec(bm, &extrudeop); - - /* Push the verts of the extruded faces inward to create thickness */ - BMO_slot_buffer_flag_enable(bm, extrudeop.slots_out, "geom.out", BM_FACE, FACE_MARK); - calc_solidify_normals(bm); - solidify_add_thickness(bm, thickness); - - BMO_slot_copy(&extrudeop, slots_out, "geom.out", - op, slots_out, "geom.out"); - - BMO_op_finish(bm, &extrudeop); + BMOperator extrudeop; + BMOperator reverseop; + float thickness; + + thickness = BMO_slot_float_get(op->slots_in, "thickness"); + + /* Flip original faces (so the shell is extruded inward) */ + BMO_op_init(bm, &reverseop, op->flag, "reverse_faces"); + BMO_slot_bool_set(reverseop.slots_in, "flip_multires", true); + BMO_slot_copy(op, slots_in, "geom", &reverseop, slots_in, "faces"); + BMO_op_exec(bm, &reverseop); + BMO_op_finish(bm, &reverseop); + + /* Extrude the region */ + BMO_op_initf(bm, &extrudeop, op->flag, "extrude_face_region use_keep_orig=%b", true); + BMO_slot_copy(op, slots_in, "geom", &extrudeop, slots_in, "geom"); + BMO_op_exec(bm, &extrudeop); + + /* Push the verts of the extruded faces inward to create thickness */ + BMO_slot_buffer_flag_enable(bm, extrudeop.slots_out, "geom.out", BM_FACE, FACE_MARK); + calc_solidify_normals(bm); + solidify_add_thickness(bm, thickness); + + BMO_slot_copy(&extrudeop, slots_out, "geom.out", op, slots_out, "geom.out"); + + BMO_op_finish(bm, &extrudeop); } diff --git a/source/blender/bmesh/operators/bmo_fill_attribute.c b/source/blender/bmesh/operators/bmo_fill_attribute.c index b724f6202bd..1e226beffc7 100644 --- a/source/blender/bmesh/operators/bmo_fill_attribute.c +++ b/source/blender/bmesh/operators/bmo_fill_attribute.c @@ -32,15 +32,15 @@ */ static bool bm_loop_is_all_radial_tag(BMLoop *l) { - BMLoop *l_iter; - l_iter = l->radial_next; - do { - if (BM_elem_flag_test(l_iter->f, BM_ELEM_TAG) == 0) { - return false; - } - } while ((l_iter = l_iter->radial_next) != l); - - return true; + BMLoop *l_iter; + l_iter = l->radial_next; + do { + if (BM_elem_flag_test(l_iter->f, BM_ELEM_TAG) == 0) { + return false; + } + } while ((l_iter = l_iter->radial_next) != l); + + return true; } /** @@ -48,122 +48,121 @@ static bool bm_loop_is_all_radial_tag(BMLoop *l) */ static bool bm_loop_is_face_untag(const BMLoop *l, void *UNUSED(user_data)) { - return (BM_elem_flag_test(l->f, BM_ELEM_TAG) == 0); + return (BM_elem_flag_test(l->f, BM_ELEM_TAG) == 0); } /** * Copy all attributes from adjacent untagged faces. */ -static void bm_face_copy_shared_all( - BMesh *bm, BMLoop *l, - const bool use_normals, const bool use_data) +static void bm_face_copy_shared_all(BMesh *bm, + BMLoop *l, + const bool use_normals, + const bool use_data) { - BMLoop *l_other = l->radial_next; - BMFace *f = l->f, *f_other; - while (BM_elem_flag_test(l_other->f, BM_ELEM_TAG)) { - l_other = l_other->radial_next; - } - f_other = l_other->f; - - if (use_data) { - /* copy face-attrs */ - BM_elem_attrs_copy(bm, bm, f_other, f); - - /* copy loop-attrs */ - BM_face_copy_shared(bm, f, bm_loop_is_face_untag, NULL); - } - - if (use_normals) { - /* copy winding (flipping) */ - if (l->v == l_other->v) { - BM_face_normal_flip(bm, f); - } - } + BMLoop *l_other = l->radial_next; + BMFace *f = l->f, *f_other; + while (BM_elem_flag_test(l_other->f, BM_ELEM_TAG)) { + l_other = l_other->radial_next; + } + f_other = l_other->f; + + if (use_data) { + /* copy face-attrs */ + BM_elem_attrs_copy(bm, bm, f_other, f); + + /* copy loop-attrs */ + BM_face_copy_shared(bm, f, bm_loop_is_face_untag, NULL); + } + + if (use_normals) { + /* copy winding (flipping) */ + if (l->v == l_other->v) { + BM_face_normal_flip(bm, f); + } + } } /** * Flood fill attributes. */ -static uint bmesh_face_attribute_fill( - BMesh *bm, - const bool use_normals, const bool use_data) +static uint bmesh_face_attribute_fill(BMesh *bm, const bool use_normals, const bool use_data) { - BLI_LINKSTACK_DECLARE(loop_queue_prev, BMLoop *); - BLI_LINKSTACK_DECLARE(loop_queue_next, BMLoop *); - - BMFace *f; - BMIter iter; - BMLoop *l; - - uint face_tot = 0; - - - BLI_LINKSTACK_INIT(loop_queue_prev); - BLI_LINKSTACK_INIT(loop_queue_next); - - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(f, BM_ELEM_TAG)) { - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - if (bm_loop_is_all_radial_tag(l_iter) == false) { - BLI_LINKSTACK_PUSH(loop_queue_prev, l_iter); - } - } while ((l_iter = l_iter->next) != l_first); - } - } - - while (BLI_LINKSTACK_SIZE(loop_queue_prev)) { - while ((l = BLI_LINKSTACK_POP(loop_queue_prev))) { - /* check we're still un-assigned */ - if (BM_elem_flag_test(l->f, BM_ELEM_TAG)) { - BMLoop *l_iter; - - BM_elem_flag_disable(l->f, BM_ELEM_TAG); - - l_iter = l->next; - do { - BMLoop *l_radial_iter = l_iter->radial_next; - if (l_radial_iter != l_iter) { - do { - if (BM_elem_flag_test(l_radial_iter->f, BM_ELEM_TAG)) { - BLI_LINKSTACK_PUSH(loop_queue_next, l_radial_iter); - } - } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter); - } - } while ((l_iter = l_iter->next) != l); - - /* do last because of face flipping */ - bm_face_copy_shared_all(bm, l, - use_normals, use_data); - face_tot += 1; - } - } - - BLI_LINKSTACK_SWAP(loop_queue_prev, loop_queue_next); - } - - BLI_LINKSTACK_FREE(loop_queue_prev); - BLI_LINKSTACK_FREE(loop_queue_next); - - return face_tot; + BLI_LINKSTACK_DECLARE(loop_queue_prev, BMLoop *); + BLI_LINKSTACK_DECLARE(loop_queue_next, BMLoop *); + + BMFace *f; + BMIter iter; + BMLoop *l; + + uint face_tot = 0; + + BLI_LINKSTACK_INIT(loop_queue_prev); + BLI_LINKSTACK_INIT(loop_queue_next); + + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_TAG)) { + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (bm_loop_is_all_radial_tag(l_iter) == false) { + BLI_LINKSTACK_PUSH(loop_queue_prev, l_iter); + } + } while ((l_iter = l_iter->next) != l_first); + } + } + + while (BLI_LINKSTACK_SIZE(loop_queue_prev)) { + while ((l = BLI_LINKSTACK_POP(loop_queue_prev))) { + /* check we're still un-assigned */ + if (BM_elem_flag_test(l->f, BM_ELEM_TAG)) { + BMLoop *l_iter; + + BM_elem_flag_disable(l->f, BM_ELEM_TAG); + + l_iter = l->next; + do { + BMLoop *l_radial_iter = l_iter->radial_next; + if (l_radial_iter != l_iter) { + do { + if (BM_elem_flag_test(l_radial_iter->f, BM_ELEM_TAG)) { + BLI_LINKSTACK_PUSH(loop_queue_next, l_radial_iter); + } + } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter); + } + } while ((l_iter = l_iter->next) != l); + + /* do last because of face flipping */ + bm_face_copy_shared_all(bm, l, use_normals, use_data); + face_tot += 1; + } + } + + BLI_LINKSTACK_SWAP(loop_queue_prev, loop_queue_next); + } + + BLI_LINKSTACK_FREE(loop_queue_prev); + BLI_LINKSTACK_FREE(loop_queue_next); + + return face_tot; } -void bmo_face_attribute_fill_exec(BMesh *bm, BMOperator *op) +void bmo_face_attribute_fill_exec(BMesh *bm, BMOperator *op) { - const bool use_normals = BMO_slot_bool_get(op->slots_in, "use_normals"); - const bool use_data = BMO_slot_bool_get(op->slots_in, "use_data"); + const bool use_normals = BMO_slot_bool_get(op->slots_in, "use_normals"); + const bool use_data = BMO_slot_bool_get(op->slots_in, "use_data"); - int face_tot; + int face_tot; - BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); - BMO_slot_buffer_hflag_enable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false); /* do inline */ + BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); + BMO_slot_buffer_hflag_enable( + bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false); /* do inline */ - /* now we can copy adjacent data */ - face_tot = bmesh_face_attribute_fill(bm, use_normals, use_data); + /* now we can copy adjacent data */ + face_tot = bmesh_face_attribute_fill(bm, use_normals, use_data); - if (face_tot != BMO_slot_buffer_count(op->slots_in, "faces")) { - /* any remaining tags will be skipped */ - BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces_fail.out", BM_FACE, BM_ELEM_TAG); - } + if (face_tot != BMO_slot_buffer_count(op->slots_in, "faces")) { + /* any remaining tags will be skipped */ + BMO_slot_buffer_from_enabled_hflag( + bm, op, op->slots_out, "faces_fail.out", BM_FACE, BM_ELEM_TAG); + } } diff --git a/source/blender/bmesh/operators/bmo_fill_edgeloop.c b/source/blender/bmesh/operators/bmo_fill_edgeloop.c index e82072de90f..16f9922b21d 100644 --- a/source/blender/bmesh/operators/bmo_fill_edgeloop.c +++ b/source/blender/bmesh/operators/bmo_fill_edgeloop.c @@ -28,125 +28,125 @@ #include "intern/bmesh_operators_private.h" /* own include */ -#define VERT_USED 1 -#define EDGE_MARK 2 -#define ELE_OUT 4 +#define VERT_USED 1 +#define EDGE_MARK 2 +#define ELE_OUT 4 void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op) { - /* first collect an array of unique from the edges */ - const int tote = BMO_slot_buffer_count(op->slots_in, "edges"); - const int totv = tote; /* these should be the same */ - BMVert **verts = MEM_mallocN(sizeof(*verts) * totv, __func__); - - BMVert *v; - BMEdge *e; - int i; - bool ok = true; - - BMOIter oiter; - - const short mat_nr = BMO_slot_int_get(op->slots_in, "mat_nr"); - const bool use_smooth = BMO_slot_bool_get(op->slots_in, "use_smooth"); - - /* 'VERT_USED' will be disabled, so enable and fill the array */ - i = 0; - BMO_ITER (e, &oiter, op->slots_in, "edges", BM_EDGE) { - BMIter viter; - BMO_edge_flag_enable(bm, e, EDGE_MARK); - BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) { - if (BMO_vert_flag_test(bm, v, VERT_USED) == false) { - if (i == tote) { - goto cleanup; - } - - BMO_vert_flag_enable(bm, v, VERT_USED); - verts[i++] = v; - } - } - } - - /* we have a different number of verts to edges */ - if (i != tote) { - goto cleanup; - } - - /* loop over connected flagged edges and fill in faces, this is made slightly more - * complicated because there may be multiple disconnected loops to fill. */ - - /* sanity check - that each vertex has 2 edge users */ - for (i = 0; i < totv; i++) { - v = verts[i]; - /* count how many flagged edges this vertex uses */ - if (BMO_iter_elem_count_flag(bm, BM_EDGES_OF_VERT, v, EDGE_MARK, true) != 2) { - ok = false; - break; - } - } - - if (ok) { - /* note: in the case of multiple loops, this over-allocs (which is fine) */ - BMVert **f_verts = MEM_mallocN(sizeof(*verts) * totv, __func__); - BMIter eiter; - - /* build array of connected verts and edges */ - BMEdge *e_prev = NULL; - BMEdge *e_next = NULL; - int totv_used = 0; - - while (totv_used < totv) { - for (i = 0; i < totv; i++) { - v = verts[i]; - if (BMO_vert_flag_test(bm, v, VERT_USED)) { - break; - } - } - - /* this should never fail, as long as (totv_used < totv) - * we should have marked verts available */ - BLI_assert(BMO_vert_flag_test(bm, v, VERT_USED)); - - /* watch it, 'i' is used for final face length */ - i = 0; - do { - /* we know that there are 2 edges per vertex so no need to check */ - BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (BMO_edge_flag_test(bm, e, EDGE_MARK)) { - if (e != e_prev) { - e_next = e; - break; - } - } - } - - /* fill in the array */ - f_verts[i] = v; - BMO_vert_flag_disable(bm, v, VERT_USED); - totv_used++; - - /* step over the edges */ - v = BM_edge_other_vert(e_next, v); - e_prev = e_next; - i++; - } while ((v != f_verts[0])); - - if (!BM_face_exists(f_verts, i)) { - BMFace *f; - - /* don't use calc_edges option because we already have the edges */ - f = BM_face_create_ngon_verts(bm, f_verts, i, NULL, BM_CREATE_NOP, true, false); - BMO_face_flag_enable(bm, f, ELE_OUT); - f->mat_nr = mat_nr; - if (use_smooth) { - BM_elem_flag_enable(f, BM_ELEM_SMOOTH); - } - } - } - MEM_freeN(f_verts); - - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, ELE_OUT); - } + /* first collect an array of unique from the edges */ + const int tote = BMO_slot_buffer_count(op->slots_in, "edges"); + const int totv = tote; /* these should be the same */ + BMVert **verts = MEM_mallocN(sizeof(*verts) * totv, __func__); + + BMVert *v; + BMEdge *e; + int i; + bool ok = true; + + BMOIter oiter; + + const short mat_nr = BMO_slot_int_get(op->slots_in, "mat_nr"); + const bool use_smooth = BMO_slot_bool_get(op->slots_in, "use_smooth"); + + /* 'VERT_USED' will be disabled, so enable and fill the array */ + i = 0; + BMO_ITER (e, &oiter, op->slots_in, "edges", BM_EDGE) { + BMIter viter; + BMO_edge_flag_enable(bm, e, EDGE_MARK); + BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) { + if (BMO_vert_flag_test(bm, v, VERT_USED) == false) { + if (i == tote) { + goto cleanup; + } + + BMO_vert_flag_enable(bm, v, VERT_USED); + verts[i++] = v; + } + } + } + + /* we have a different number of verts to edges */ + if (i != tote) { + goto cleanup; + } + + /* loop over connected flagged edges and fill in faces, this is made slightly more + * complicated because there may be multiple disconnected loops to fill. */ + + /* sanity check - that each vertex has 2 edge users */ + for (i = 0; i < totv; i++) { + v = verts[i]; + /* count how many flagged edges this vertex uses */ + if (BMO_iter_elem_count_flag(bm, BM_EDGES_OF_VERT, v, EDGE_MARK, true) != 2) { + ok = false; + break; + } + } + + if (ok) { + /* note: in the case of multiple loops, this over-allocs (which is fine) */ + BMVert **f_verts = MEM_mallocN(sizeof(*verts) * totv, __func__); + BMIter eiter; + + /* build array of connected verts and edges */ + BMEdge *e_prev = NULL; + BMEdge *e_next = NULL; + int totv_used = 0; + + while (totv_used < totv) { + for (i = 0; i < totv; i++) { + v = verts[i]; + if (BMO_vert_flag_test(bm, v, VERT_USED)) { + break; + } + } + + /* this should never fail, as long as (totv_used < totv) + * we should have marked verts available */ + BLI_assert(BMO_vert_flag_test(bm, v, VERT_USED)); + + /* watch it, 'i' is used for final face length */ + i = 0; + do { + /* we know that there are 2 edges per vertex so no need to check */ + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + if (BMO_edge_flag_test(bm, e, EDGE_MARK)) { + if (e != e_prev) { + e_next = e; + break; + } + } + } + + /* fill in the array */ + f_verts[i] = v; + BMO_vert_flag_disable(bm, v, VERT_USED); + totv_used++; + + /* step over the edges */ + v = BM_edge_other_vert(e_next, v); + e_prev = e_next; + i++; + } while ((v != f_verts[0])); + + if (!BM_face_exists(f_verts, i)) { + BMFace *f; + + /* don't use calc_edges option because we already have the edges */ + f = BM_face_create_ngon_verts(bm, f_verts, i, NULL, BM_CREATE_NOP, true, false); + BMO_face_flag_enable(bm, f, ELE_OUT); + f->mat_nr = mat_nr; + if (use_smooth) { + BM_elem_flag_enable(f, BM_ELEM_SMOOTH); + } + } + } + MEM_freeN(f_verts); + + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, ELE_OUT); + } cleanup: - MEM_freeN(verts); + MEM_freeN(verts); } diff --git a/source/blender/bmesh/operators/bmo_fill_grid.c b/source/blender/bmesh/operators/bmo_fill_grid.c index 09c174586f8..b71bd482e3b 100644 --- a/source/blender/bmesh/operators/bmo_fill_grid.c +++ b/source/blender/bmesh/operators/bmo_fill_grid.c @@ -33,8 +33,8 @@ #include "BLI_strict_flags.h" -#define EDGE_MARK 4 -#define FACE_OUT 16 +#define EDGE_MARK 4 +#define FACE_OUT 16 #define BARYCENTRIC_INTERP @@ -42,65 +42,59 @@ /** * 2 edge vectors to normal. */ -static void quad_edges_to_normal( - float no[3], - const float co_a1[3], const float co_a2[3], - const float co_b1[3], const float co_b2[3]) +static void quad_edges_to_normal(float no[3], + const float co_a1[3], + const float co_a2[3], + const float co_b1[3], + const float co_b2[3]) { - float diff_a[3]; - float diff_b[3]; - - sub_v3_v3v3(diff_a, co_a2, co_a1); - sub_v3_v3v3(diff_b, co_b2, co_b1); - normalize_v3(diff_a); - normalize_v3(diff_b); - add_v3_v3v3(no, diff_a, diff_b); - normalize_v3(no); + float diff_a[3]; + float diff_b[3]; + + sub_v3_v3v3(diff_a, co_a2, co_a1); + sub_v3_v3v3(diff_b, co_b2, co_b1); + normalize_v3(diff_a); + normalize_v3(diff_b); + add_v3_v3v3(no, diff_a, diff_b); + normalize_v3(no); } -static void quad_verts_to_barycentric_tri( - float tri[3][3], - const float co_a[3], - const float co_b[3], +static void quad_verts_to_barycentric_tri(float tri[3][3], + const float co_a[3], + const float co_b[3], - const float co_a_next[3], - const float co_b_next[3], + const float co_a_next[3], + const float co_b_next[3], - const float co_a_prev[3], - const float co_b_prev[3], - const bool is_flip - ) + const float co_a_prev[3], + const float co_b_prev[3], + const bool is_flip) { - float no[3]; - - copy_v3_v3(tri[0], co_a); - copy_v3_v3(tri[1], co_b); - - quad_edges_to_normal(no, - co_a, co_a_next, - co_b, co_b_next); - - if (co_a_prev) { - float no_t[3]; - quad_edges_to_normal(no_t, - co_a_prev, co_a, - co_b_prev, co_b); - add_v3_v3(no, no_t); - normalize_v3(no); - } - - if (is_flip) { - negate_v3(no); - } - mul_v3_fl(no, len_v3v3(tri[0], tri[1])); - - mid_v3_v3v3(tri[2], tri[0], tri[1]); - add_v3_v3(tri[2], no); + float no[3]; + + copy_v3_v3(tri[0], co_a); + copy_v3_v3(tri[1], co_b); + + quad_edges_to_normal(no, co_a, co_a_next, co_b, co_b_next); + + if (co_a_prev) { + float no_t[3]; + quad_edges_to_normal(no_t, co_a_prev, co_a, co_b_prev, co_b); + add_v3_v3(no, no_t); + normalize_v3(no); + } + + if (is_flip) { + negate_v3(no); + } + mul_v3_fl(no, len_v3v3(tri[0], tri[1])); + + mid_v3_v3v3(tri[2], tri[0], tri[1]); + add_v3_v3(tri[2], no); } #endif - /* -------------------------------------------------------------------- */ /* Handle Loop Pairs */ @@ -110,25 +104,23 @@ static void quad_verts_to_barycentric_tri( /** * Assign a loop pair from 2 verts (which _must_ share an edge) */ -static void bm_loop_pair_from_verts( - BMVert *v_a, BMVert *v_b, - BMLoop *l_pair[2]) +static void bm_loop_pair_from_verts(BMVert *v_a, BMVert *v_b, BMLoop *l_pair[2]) { - BMEdge *e = BM_edge_exists(v_a, v_b); - if (e->l) { - if (e->l->v == v_a) { - l_pair[0] = e->l; - l_pair[1] = e->l->next; - } - else { - l_pair[0] = e->l->next; - l_pair[1] = e->l; - } - } - else { - l_pair[0] = NULL; - l_pair[1] = NULL; - } + BMEdge *e = BM_edge_exists(v_a, v_b); + if (e->l) { + if (e->l->v == v_a) { + l_pair[0] = e->l; + l_pair[1] = e->l->next; + } + else { + l_pair[0] = e->l->next; + l_pair[1] = e->l; + } + } + else { + l_pair[0] = NULL; + l_pair[1] = NULL; + } } /** @@ -138,15 +130,15 @@ static void bm_loop_pair_from_verts( */ static void bm_loop_pair_test_copy(BMLoop *l_pair_a[2], BMLoop *l_pair_b[2]) { - /* if the first one is set, we know the second is too */ - if (l_pair_a[0] && l_pair_b[0] == NULL) { - l_pair_b[0] = l_pair_a[1]; - l_pair_b[1] = l_pair_a[0]; - } - else if (l_pair_b[0] && l_pair_a[0] == NULL) { - l_pair_a[0] = l_pair_b[1]; - l_pair_a[1] = l_pair_b[0]; - } + /* if the first one is set, we know the second is too */ + if (l_pair_a[0] && l_pair_b[0] == NULL) { + l_pair_b[0] = l_pair_a[1]; + l_pair_b[1] = l_pair_a[0]; + } + else if (l_pair_b[0] && l_pair_a[0] == NULL) { + l_pair_a[0] = l_pair_b[1]; + l_pair_a[1] = l_pair_b[0]; + } } /** @@ -154,576 +146,584 @@ static void bm_loop_pair_test_copy(BMLoop *l_pair_a[2], BMLoop *l_pair_b[2]) * * \note These weights will be calculated multiple times per vertex. */ -static void bm_loop_interp_from_grid_boundary_4(BMesh *bm, BMLoop *l, BMLoop *l_bound[4], const float w[4]) +static void bm_loop_interp_from_grid_boundary_4(BMesh *bm, + BMLoop *l, + BMLoop *l_bound[4], + const float w[4]) { - const void *l_cdata[4] = { - l_bound[0]->head.data, - l_bound[1]->head.data, - l_bound[2]->head.data, - l_bound[3]->head.data}; + const void *l_cdata[4] = { + l_bound[0]->head.data, l_bound[1]->head.data, l_bound[2]->head.data, l_bound[3]->head.data}; - CustomData_bmesh_interp(&bm->ldata, l_cdata, w, NULL, 4, l->head.data); + CustomData_bmesh_interp(&bm->ldata, l_cdata, w, NULL, 4, l->head.data); } -static void bm_loop_interp_from_grid_boundary_2(BMesh *bm, BMLoop *l, BMLoop *l_bound[2], const float t) +static void bm_loop_interp_from_grid_boundary_2(BMesh *bm, + BMLoop *l, + BMLoop *l_bound[2], + const float t) { - const void *l_cdata[2] = { - l_bound[0]->head.data, - l_bound[1]->head.data}; + const void *l_cdata[2] = {l_bound[0]->head.data, l_bound[1]->head.data}; - const float w[2] = {1.0f - t, t}; + const float w[2] = {1.0f - t, t}; - CustomData_bmesh_interp(&bm->ldata, l_cdata, w, NULL, 2, l->head.data); + CustomData_bmesh_interp(&bm->ldata, l_cdata, w, NULL, 2, l->head.data); } /** \} */ - /** * Avoids calling #barycentric_weights_v2_quad often by caching weights into an array. */ -static void barycentric_weights_v2_grid_cache( - const uint xtot, const uint ytot, - float (*weight_table)[4]) +static void barycentric_weights_v2_grid_cache(const uint xtot, + const uint ytot, + float (*weight_table)[4]) { - float x_step = 1.0f / (float)(xtot - 1); - float y_step = 1.0f / (float)(ytot - 1); - uint i = 0; - float xy_fl[2]; - - uint x, y; - for (y = 0; y < ytot; y++) { - xy_fl[1] = y_step * (float)y; - for (x = 0; x < xtot; x++) { - xy_fl[0] = x_step * (float)x; - { - const float cos[4][2] = { - {xy_fl[0], 0.0f}, - {0.0f, xy_fl[1]}, - {xy_fl[0], 1.0f}, - {1.0f, xy_fl[1]}}; - barycentric_weights_v2_quad(UNPACK4(cos), xy_fl, weight_table[i++]); - } - } - } + float x_step = 1.0f / (float)(xtot - 1); + float y_step = 1.0f / (float)(ytot - 1); + uint i = 0; + float xy_fl[2]; + + uint x, y; + for (y = 0; y < ytot; y++) { + xy_fl[1] = y_step * (float)y; + for (x = 0; x < xtot; x++) { + xy_fl[0] = x_step * (float)x; + { + const float cos[4][2] = { + {xy_fl[0], 0.0f}, {0.0f, xy_fl[1]}, {xy_fl[0], 1.0f}, {1.0f, xy_fl[1]}}; + barycentric_weights_v2_quad(UNPACK4(cos), xy_fl, weight_table[i++]); + } + } + } } - /** * This may be useful outside the bmesh operator. * * \param v_grid: 2d array of verts, all boundary verts must be set, we fill in the middle. */ -static void bm_grid_fill_array( - BMesh *bm, BMVert **v_grid, const uint xtot, unsigned const int ytot, - const short mat_nr, const bool use_smooth, - const bool use_flip, const bool use_interp_simple) +static void bm_grid_fill_array(BMesh *bm, + BMVert **v_grid, + const uint xtot, + unsigned const int ytot, + const short mat_nr, + const bool use_smooth, + const bool use_flip, + const bool use_interp_simple) { - const bool use_vert_interp = CustomData_has_interp(&bm->vdata); - const bool use_loop_interp = CustomData_has_interp(&bm->ldata); - uint x, y; + const bool use_vert_interp = CustomData_has_interp(&bm->vdata); + const bool use_loop_interp = CustomData_has_interp(&bm->ldata); + uint x, y; - /* for use_loop_interp */ - BMLoop *((*larr_x_a)[2]), *((*larr_x_b)[2]), *((*larr_y_a)[2]), *((*larr_y_b)[2]); + /* for use_loop_interp */ + BMLoop *((*larr_x_a)[2]), *((*larr_x_b)[2]), *((*larr_y_a)[2]), *((*larr_y_b)[2]); - float (*weight_table)[4]; + float(*weight_table)[4]; -#define XY(_x, _y) ((_x) + ((_y) * (xtot))) +#define XY(_x, _y) ((_x) + ((_y) * (xtot))) #ifdef BARYCENTRIC_INTERP - float tri_a[3][3]; - float tri_b[3][3]; - float tri_t[3][3]; /* temp */ - - quad_verts_to_barycentric_tri( - tri_a, - v_grid[XY(0, 0)]->co, - v_grid[XY(xtot - 1, 0)]->co, - v_grid[XY(0, 1)]->co, - v_grid[XY(xtot - 1, 1)]->co, - NULL, NULL, - false); - - quad_verts_to_barycentric_tri( - tri_b, - v_grid[XY(0, (ytot - 1))]->co, - v_grid[XY(xtot - 1, (ytot - 1))]->co, - v_grid[XY(0, (ytot - 2))]->co, - v_grid[XY(xtot - 1, (ytot - 2))]->co, - NULL, NULL, - true); + float tri_a[3][3]; + float tri_b[3][3]; + float tri_t[3][3]; /* temp */ + + quad_verts_to_barycentric_tri(tri_a, + v_grid[XY(0, 0)]->co, + v_grid[XY(xtot - 1, 0)]->co, + v_grid[XY(0, 1)]->co, + v_grid[XY(xtot - 1, 1)]->co, + NULL, + NULL, + false); + + quad_verts_to_barycentric_tri(tri_b, + v_grid[XY(0, (ytot - 1))]->co, + v_grid[XY(xtot - 1, (ytot - 1))]->co, + v_grid[XY(0, (ytot - 2))]->co, + v_grid[XY(xtot - 1, (ytot - 2))]->co, + NULL, + NULL, + true); #endif - if (use_interp_simple || use_vert_interp || use_loop_interp) { - weight_table = MEM_mallocN(sizeof(*weight_table) * (size_t)(xtot * ytot), __func__); - barycentric_weights_v2_grid_cache(xtot, ytot, weight_table); - } - else { - weight_table = NULL; - } - - - /* Store loops */ - if (use_loop_interp) { - /* x2 because each edge connects 2 loops */ - larr_x_a = MEM_mallocN(sizeof(*larr_x_a) * (xtot - 1), __func__); - larr_x_b = MEM_mallocN(sizeof(*larr_x_b) * (xtot - 1), __func__); - - larr_y_a = MEM_mallocN(sizeof(*larr_y_a) * (ytot - 1), __func__); - larr_y_b = MEM_mallocN(sizeof(*larr_y_b) * (ytot - 1), __func__); - - /* fill in the loops */ - for (x = 0; x < xtot - 1; x++) { - bm_loop_pair_from_verts(v_grid[XY(x, 0)], v_grid[XY(x + 1, 0)], larr_x_a[x]); - bm_loop_pair_from_verts(v_grid[XY(x, ytot - 1)], v_grid[XY(x + 1, ytot - 1)], larr_x_b[x]); - bm_loop_pair_test_copy(larr_x_a[x], larr_x_b[x]); - } - - for (y = 0; y < ytot - 1; y++) { - bm_loop_pair_from_verts(v_grid[XY(0, y)], v_grid[XY(0, y + 1)], larr_y_a[y]); - bm_loop_pair_from_verts(v_grid[XY(xtot - 1, y)], v_grid[XY(xtot - 1, y + 1)], larr_y_b[y]); - bm_loop_pair_test_copy(larr_y_a[y], larr_y_b[y]); - } - } - - - /* Build Verts */ - for (y = 1; y < ytot - 1; y++) { + if (use_interp_simple || use_vert_interp || use_loop_interp) { + weight_table = MEM_mallocN(sizeof(*weight_table) * (size_t)(xtot * ytot), __func__); + barycentric_weights_v2_grid_cache(xtot, ytot, weight_table); + } + else { + weight_table = NULL; + } + + /* Store loops */ + if (use_loop_interp) { + /* x2 because each edge connects 2 loops */ + larr_x_a = MEM_mallocN(sizeof(*larr_x_a) * (xtot - 1), __func__); + larr_x_b = MEM_mallocN(sizeof(*larr_x_b) * (xtot - 1), __func__); + + larr_y_a = MEM_mallocN(sizeof(*larr_y_a) * (ytot - 1), __func__); + larr_y_b = MEM_mallocN(sizeof(*larr_y_b) * (ytot - 1), __func__); + + /* fill in the loops */ + for (x = 0; x < xtot - 1; x++) { + bm_loop_pair_from_verts(v_grid[XY(x, 0)], v_grid[XY(x + 1, 0)], larr_x_a[x]); + bm_loop_pair_from_verts(v_grid[XY(x, ytot - 1)], v_grid[XY(x + 1, ytot - 1)], larr_x_b[x]); + bm_loop_pair_test_copy(larr_x_a[x], larr_x_b[x]); + } + + for (y = 0; y < ytot - 1; y++) { + bm_loop_pair_from_verts(v_grid[XY(0, y)], v_grid[XY(0, y + 1)], larr_y_a[y]); + bm_loop_pair_from_verts(v_grid[XY(xtot - 1, y)], v_grid[XY(xtot - 1, y + 1)], larr_y_b[y]); + bm_loop_pair_test_copy(larr_y_a[y], larr_y_b[y]); + } + } + + /* Build Verts */ + for (y = 1; y < ytot - 1; y++) { #ifdef BARYCENTRIC_INTERP - quad_verts_to_barycentric_tri( - tri_t, - v_grid[XY(0, y + 0)]->co, - v_grid[XY(xtot - 1, y + 0)]->co, - v_grid[XY(0, y + 1)]->co, - v_grid[XY(xtot - 1, y + 1)]->co, - v_grid[XY(0, y - 1)]->co, - v_grid[XY(xtot - 1, y - 1)]->co, - false); + quad_verts_to_barycentric_tri(tri_t, + v_grid[XY(0, y + 0)]->co, + v_grid[XY(xtot - 1, y + 0)]->co, + v_grid[XY(0, y + 1)]->co, + v_grid[XY(xtot - 1, y + 1)]->co, + v_grid[XY(0, y - 1)]->co, + v_grid[XY(xtot - 1, y - 1)]->co, + false); #endif - for (x = 1; x < xtot - 1; x++) { - float co[3]; - BMVert *v; - /* we may want to allow sparse filled arrays, but for now, ensure its empty */ - BLI_assert(v_grid[(y * xtot) + x] == NULL); + for (x = 1; x < xtot - 1; x++) { + float co[3]; + BMVert *v; + /* we may want to allow sparse filled arrays, but for now, ensure its empty */ + BLI_assert(v_grid[(y * xtot) + x] == NULL); - /* place the vertex */ + /* place the vertex */ #ifdef BARYCENTRIC_INTERP - if (use_interp_simple == false) { - float co_a[3], co_b[3]; - - transform_point_by_tri_v3( - co_a, - v_grid[x]->co, - tri_t[0], tri_t[1], tri_t[2], - tri_a[0], tri_a[1], tri_a[2]); - transform_point_by_tri_v3( - co_b, - v_grid[(xtot * ytot) + (x - xtot)]->co, - tri_t[0], tri_t[1], tri_t[2], - tri_b[0], tri_b[1], tri_b[2]); - - interp_v3_v3v3(co, co_a, co_b, (float)y / ((float)ytot - 1)); - } - else + if (use_interp_simple == false) { + float co_a[3], co_b[3]; + + transform_point_by_tri_v3( + co_a, v_grid[x]->co, tri_t[0], tri_t[1], tri_t[2], tri_a[0], tri_a[1], tri_a[2]); + transform_point_by_tri_v3(co_b, + v_grid[(xtot * ytot) + (x - xtot)]->co, + tri_t[0], + tri_t[1], + tri_t[2], + tri_b[0], + tri_b[1], + tri_b[2]); + + interp_v3_v3v3(co, co_a, co_b, (float)y / ((float)ytot - 1)); + } + else #endif - { - const float *w = weight_table[XY(x, y)]; - - zero_v3(co); - madd_v3_v3fl(co, v_grid[XY(x, 0)]->co, w[0]); - madd_v3_v3fl(co, v_grid[XY(0, y)]->co, w[1]); - madd_v3_v3fl(co, v_grid[XY(x, ytot - 1)]->co, w[2]); - madd_v3_v3fl(co, v_grid[XY(xtot - 1, y)]->co, w[3]); - } - - v = BM_vert_create(bm, co, NULL, BM_CREATE_NOP); - v_grid[(y * xtot) + x] = v; - - /* interpolate only along one axis, this could be changed - * but from user pov gives predictable results since these are selected loop */ - if (use_vert_interp) { - const float *w = weight_table[XY(x, y)]; - - const void *v_cdata[4] = { - v_grid[XY(x, 0)]->head.data, - v_grid[XY(0, y)]->head.data, - v_grid[XY(x, ytot - 1)]->head.data, - v_grid[XY(xtot - 1, y)]->head.data, - }; - - CustomData_bmesh_interp(&bm->vdata, v_cdata, w, NULL, 4, v->head.data); - } - - } - } - - /* Build Faces */ - for (x = 0; x < xtot - 1; x++) { - for (y = 0; y < ytot - 1; y++) { - BMFace *f; - - if (use_flip) { - f = BM_face_create_quad_tri( - bm, - v_grid[XY(x, y + 0)], /* BL */ - v_grid[XY(x, y + 1)], /* TL */ - v_grid[XY(x + 1, y + 1)], /* TR */ - v_grid[XY(x + 1, y + 0)], /* BR */ - NULL, - BM_CREATE_NOP); - } - else { - f = BM_face_create_quad_tri( - bm, - v_grid[XY(x + 1, y + 0)], /* BR */ - v_grid[XY(x + 1, y + 1)], /* TR */ - v_grid[XY(x, y + 1)], /* TL */ - v_grid[XY(x, y + 0)], /* BL */ - NULL, - BM_CREATE_NOP); - } - - - if (use_loop_interp && (larr_x_a[x][0] || larr_y_a[y][0])) { - /* bottom/left/top/right */ - BMLoop *l_quad[4]; - BMLoop *l_bound[4]; - BMLoop *l_tmp; - uint x_side, y_side, i; - char interp_from; - - - if (larr_x_a[x][0] && larr_y_a[y][0]) { - interp_from = 'B'; /* B == both */ - l_tmp = larr_x_a[x][0]; - } - else if (larr_x_a[x][0]) { - interp_from = 'X'; - l_tmp = larr_x_a[x][0]; - } - else { - interp_from = 'Y'; - l_tmp = larr_y_a[y][0]; - } - - BM_elem_attrs_copy(bm, bm, l_tmp->f, f); - - - BM_face_as_array_loop_quad(f, l_quad); - - l_tmp = BM_FACE_FIRST_LOOP(f); - - if (use_flip) { - l_quad[0] = l_tmp; l_tmp = l_tmp->next; - l_quad[1] = l_tmp; l_tmp = l_tmp->next; - l_quad[3] = l_tmp; l_tmp = l_tmp->next; - l_quad[2] = l_tmp; - } - else { - l_quad[2] = l_tmp; l_tmp = l_tmp->next; - l_quad[3] = l_tmp; l_tmp = l_tmp->next; - l_quad[1] = l_tmp; l_tmp = l_tmp->next; - l_quad[0] = l_tmp; - } - - i = 0; - - for (x_side = 0; x_side < 2; x_side++) { - for (y_side = 0; y_side < 2; y_side++) { - if (interp_from == 'B') { - const float *w = weight_table[XY(x + x_side, y + y_side)]; - l_bound[0] = larr_x_a[x][x_side]; /* B */ - l_bound[1] = larr_y_a[y][y_side]; /* L */ - l_bound[2] = larr_x_b[x][x_side]; /* T */ - l_bound[3] = larr_y_b[y][y_side]; /* R */ - - bm_loop_interp_from_grid_boundary_4(bm, l_quad[i++], l_bound, w); - } - else if (interp_from == 'X') { - const float t = (float)(y + y_side) / (float)(ytot - 1); - l_bound[0] = larr_x_a[x][x_side]; /* B */ - l_bound[1] = larr_x_b[x][x_side]; /* T */ - - bm_loop_interp_from_grid_boundary_2(bm, l_quad[i++], l_bound, t); - } - else if (interp_from == 'Y') { - const float t = (float)(x + x_side) / (float)(xtot - 1); - l_bound[0] = larr_y_a[y][y_side]; /* L */ - l_bound[1] = larr_y_b[y][y_side]; /* R */ - - bm_loop_interp_from_grid_boundary_2(bm, l_quad[i++], l_bound, t); - } - else { - BLI_assert(0); - } - } - } - } - /* end interp */ - - - BMO_face_flag_enable(bm, f, FACE_OUT); - f->mat_nr = mat_nr; - if (use_smooth) { - BM_elem_flag_enable(f, BM_ELEM_SMOOTH); - } - } - } - - if (use_loop_interp) { - MEM_freeN(larr_x_a); - MEM_freeN(larr_y_a); - MEM_freeN(larr_x_b); - MEM_freeN(larr_y_b); - } - - if (weight_table) { - MEM_freeN(weight_table); - } + { + const float *w = weight_table[XY(x, y)]; + + zero_v3(co); + madd_v3_v3fl(co, v_grid[XY(x, 0)]->co, w[0]); + madd_v3_v3fl(co, v_grid[XY(0, y)]->co, w[1]); + madd_v3_v3fl(co, v_grid[XY(x, ytot - 1)]->co, w[2]); + madd_v3_v3fl(co, v_grid[XY(xtot - 1, y)]->co, w[3]); + } + + v = BM_vert_create(bm, co, NULL, BM_CREATE_NOP); + v_grid[(y * xtot) + x] = v; + + /* interpolate only along one axis, this could be changed + * but from user pov gives predictable results since these are selected loop */ + if (use_vert_interp) { + const float *w = weight_table[XY(x, y)]; + + const void *v_cdata[4] = { + v_grid[XY(x, 0)]->head.data, + v_grid[XY(0, y)]->head.data, + v_grid[XY(x, ytot - 1)]->head.data, + v_grid[XY(xtot - 1, y)]->head.data, + }; + + CustomData_bmesh_interp(&bm->vdata, v_cdata, w, NULL, 4, v->head.data); + } + } + } + + /* Build Faces */ + for (x = 0; x < xtot - 1; x++) { + for (y = 0; y < ytot - 1; y++) { + BMFace *f; + + if (use_flip) { + f = BM_face_create_quad_tri(bm, + v_grid[XY(x, y + 0)], /* BL */ + v_grid[XY(x, y + 1)], /* TL */ + v_grid[XY(x + 1, y + 1)], /* TR */ + v_grid[XY(x + 1, y + 0)], /* BR */ + NULL, + BM_CREATE_NOP); + } + else { + f = BM_face_create_quad_tri(bm, + v_grid[XY(x + 1, y + 0)], /* BR */ + v_grid[XY(x + 1, y + 1)], /* TR */ + v_grid[XY(x, y + 1)], /* TL */ + v_grid[XY(x, y + 0)], /* BL */ + NULL, + BM_CREATE_NOP); + } + + if (use_loop_interp && (larr_x_a[x][0] || larr_y_a[y][0])) { + /* bottom/left/top/right */ + BMLoop *l_quad[4]; + BMLoop *l_bound[4]; + BMLoop *l_tmp; + uint x_side, y_side, i; + char interp_from; + + if (larr_x_a[x][0] && larr_y_a[y][0]) { + interp_from = 'B'; /* B == both */ + l_tmp = larr_x_a[x][0]; + } + else if (larr_x_a[x][0]) { + interp_from = 'X'; + l_tmp = larr_x_a[x][0]; + } + else { + interp_from = 'Y'; + l_tmp = larr_y_a[y][0]; + } + + BM_elem_attrs_copy(bm, bm, l_tmp->f, f); + + BM_face_as_array_loop_quad(f, l_quad); + + l_tmp = BM_FACE_FIRST_LOOP(f); + + if (use_flip) { + l_quad[0] = l_tmp; + l_tmp = l_tmp->next; + l_quad[1] = l_tmp; + l_tmp = l_tmp->next; + l_quad[3] = l_tmp; + l_tmp = l_tmp->next; + l_quad[2] = l_tmp; + } + else { + l_quad[2] = l_tmp; + l_tmp = l_tmp->next; + l_quad[3] = l_tmp; + l_tmp = l_tmp->next; + l_quad[1] = l_tmp; + l_tmp = l_tmp->next; + l_quad[0] = l_tmp; + } + + i = 0; + + for (x_side = 0; x_side < 2; x_side++) { + for (y_side = 0; y_side < 2; y_side++) { + if (interp_from == 'B') { + const float *w = weight_table[XY(x + x_side, y + y_side)]; + l_bound[0] = larr_x_a[x][x_side]; /* B */ + l_bound[1] = larr_y_a[y][y_side]; /* L */ + l_bound[2] = larr_x_b[x][x_side]; /* T */ + l_bound[3] = larr_y_b[y][y_side]; /* R */ + + bm_loop_interp_from_grid_boundary_4(bm, l_quad[i++], l_bound, w); + } + else if (interp_from == 'X') { + const float t = (float)(y + y_side) / (float)(ytot - 1); + l_bound[0] = larr_x_a[x][x_side]; /* B */ + l_bound[1] = larr_x_b[x][x_side]; /* T */ + + bm_loop_interp_from_grid_boundary_2(bm, l_quad[i++], l_bound, t); + } + else if (interp_from == 'Y') { + const float t = (float)(x + x_side) / (float)(xtot - 1); + l_bound[0] = larr_y_a[y][y_side]; /* L */ + l_bound[1] = larr_y_b[y][y_side]; /* R */ + + bm_loop_interp_from_grid_boundary_2(bm, l_quad[i++], l_bound, t); + } + else { + BLI_assert(0); + } + } + } + } + /* end interp */ + + BMO_face_flag_enable(bm, f, FACE_OUT); + f->mat_nr = mat_nr; + if (use_smooth) { + BM_elem_flag_enable(f, BM_ELEM_SMOOTH); + } + } + } + + if (use_loop_interp) { + MEM_freeN(larr_x_a); + MEM_freeN(larr_y_a); + MEM_freeN(larr_x_b); + MEM_freeN(larr_y_b); + } + + if (weight_table) { + MEM_freeN(weight_table); + } #undef XY } -static void bm_grid_fill( - BMesh *bm, - struct BMEdgeLoopStore *estore_a, struct BMEdgeLoopStore *estore_b, - struct BMEdgeLoopStore *estore_rail_a, struct BMEdgeLoopStore *estore_rail_b, - const short mat_nr, const bool use_smooth, const bool use_interp_simple) +static void bm_grid_fill(BMesh *bm, + struct BMEdgeLoopStore *estore_a, + struct BMEdgeLoopStore *estore_b, + struct BMEdgeLoopStore *estore_rail_a, + struct BMEdgeLoopStore *estore_rail_b, + const short mat_nr, + const bool use_smooth, + const bool use_interp_simple) { #define USE_FLIP_DETECT - const uint xtot = (uint)BM_edgeloop_length_get(estore_a); - const uint ytot = (uint)BM_edgeloop_length_get(estore_rail_a); - //BMVert *v; - uint i; + const uint xtot = (uint)BM_edgeloop_length_get(estore_a); + const uint ytot = (uint)BM_edgeloop_length_get(estore_rail_a); + //BMVert *v; + uint i; #ifdef DEBUG - uint x, y; + uint x, y; #endif - LinkData *el; - bool use_flip = false; - - ListBase *lb_a = BM_edgeloop_verts_get(estore_a); - ListBase *lb_b = BM_edgeloop_verts_get(estore_b); - - ListBase *lb_rail_a = BM_edgeloop_verts_get(estore_rail_a); - ListBase *lb_rail_b = BM_edgeloop_verts_get(estore_rail_b); - - BMVert **v_grid = MEM_callocN(sizeof(BMVert *) * (size_t)(xtot * ytot), __func__); - /** - * <pre> - * estore_b - * +------------------+ - * ^ | | - * end | | | - * | | | - * | |estore_rail_a |estore_rail_b - * | | | - * start | | | - * |estore_a | - * +------------------+ - * ---> - * start -> end - * </pre> - */ - - BLI_assert(((LinkData *)lb_a->first)->data == ((LinkData *)lb_rail_a->first)->data); /* BL */ - BLI_assert(((LinkData *)lb_b->first)->data == ((LinkData *)lb_rail_a->last)->data); /* TL */ - BLI_assert(((LinkData *)lb_b->last)->data == ((LinkData *)lb_rail_b->last)->data); /* TR */ - BLI_assert(((LinkData *)lb_a->last)->data == ((LinkData *)lb_rail_b->first)->data); /* BR */ - - for (el = lb_a->first, i = 0; el; el = el->next, i++) { v_grid[i] = el->data; } - for (el = lb_b->first, i = 0; el; el = el->next, i++) { v_grid[(ytot * xtot) + (i - xtot)] = el->data; } - for (el = lb_rail_a->first, i = 0; el; el = el->next, i++) { v_grid[xtot * i] = el->data; } - for (el = lb_rail_b->first, i = 0; el; el = el->next, i++) { v_grid[(xtot * i) + (xtot - 1)] = el->data; } + LinkData *el; + bool use_flip = false; + + ListBase *lb_a = BM_edgeloop_verts_get(estore_a); + ListBase *lb_b = BM_edgeloop_verts_get(estore_b); + + ListBase *lb_rail_a = BM_edgeloop_verts_get(estore_rail_a); + ListBase *lb_rail_b = BM_edgeloop_verts_get(estore_rail_b); + + BMVert **v_grid = MEM_callocN(sizeof(BMVert *) * (size_t)(xtot * ytot), __func__); + /** + * <pre> + * estore_b + * +------------------+ + * ^ | | + * end | | | + * | | | + * | |estore_rail_a |estore_rail_b + * | | | + * start | | | + * |estore_a | + * +------------------+ + * ---> + * start -> end + * </pre> + */ + + BLI_assert(((LinkData *)lb_a->first)->data == ((LinkData *)lb_rail_a->first)->data); /* BL */ + BLI_assert(((LinkData *)lb_b->first)->data == ((LinkData *)lb_rail_a->last)->data); /* TL */ + BLI_assert(((LinkData *)lb_b->last)->data == ((LinkData *)lb_rail_b->last)->data); /* TR */ + BLI_assert(((LinkData *)lb_a->last)->data == ((LinkData *)lb_rail_b->first)->data); /* BR */ + + for (el = lb_a->first, i = 0; el; el = el->next, i++) { + v_grid[i] = el->data; + } + for (el = lb_b->first, i = 0; el; el = el->next, i++) { + v_grid[(ytot * xtot) + (i - xtot)] = el->data; + } + for (el = lb_rail_a->first, i = 0; el; el = el->next, i++) { + v_grid[xtot * i] = el->data; + } + for (el = lb_rail_b->first, i = 0; el; el = el->next, i++) { + v_grid[(xtot * i) + (xtot - 1)] = el->data; + } #ifdef DEBUG - for (x = 1; x < xtot - 1; x++) { for (y = 1; y < ytot - 1; y++) { BLI_assert(v_grid[(y * xtot) + x] == NULL); }} + for (x = 1; x < xtot - 1; x++) { + for (y = 1; y < ytot - 1; y++) { + BLI_assert(v_grid[(y * xtot) + x] == NULL); + } + } #endif #ifdef USE_FLIP_DETECT - { - ListBase *lb_iter[4] = {lb_a, lb_b, lb_rail_a, lb_rail_b}; - const int lb_iter_dir[4] = {-1, 1, 1, -1}; - int winding_votes = 0; - - for (i = 0; i < 4; i++) { - LinkData *el_next; - for (el = lb_iter[i]->first; el && (el_next = el->next); el = el->next) { - BMEdge *e = BM_edge_exists(el->data, el_next->data); - if (BM_edge_is_boundary(e)) { - winding_votes += (e->l->v == el->data) ? lb_iter_dir[i] : -lb_iter_dir[i]; - } - } - } - use_flip = (winding_votes < 0); - } + { + ListBase *lb_iter[4] = {lb_a, lb_b, lb_rail_a, lb_rail_b}; + const int lb_iter_dir[4] = {-1, 1, 1, -1}; + int winding_votes = 0; + + for (i = 0; i < 4; i++) { + LinkData *el_next; + for (el = lb_iter[i]->first; el && (el_next = el->next); el = el->next) { + BMEdge *e = BM_edge_exists(el->data, el_next->data); + if (BM_edge_is_boundary(e)) { + winding_votes += (e->l->v == el->data) ? lb_iter_dir[i] : -lb_iter_dir[i]; + } + } + } + use_flip = (winding_votes < 0); + } #endif - - bm_grid_fill_array(bm, v_grid, xtot, ytot, mat_nr, use_smooth, use_flip, use_interp_simple); - MEM_freeN(v_grid); + bm_grid_fill_array(bm, v_grid, xtot, ytot, mat_nr, use_smooth, use_flip, use_interp_simple); + MEM_freeN(v_grid); #undef USE_FLIP_DETECT } static void bm_edgeloop_flag_set(struct BMEdgeLoopStore *estore, char hflag, bool set) { - /* only handle closed loops in this case */ - LinkData *link = BM_edgeloop_verts_get(estore)->first; - link = link->next; - while (link) { - BMEdge *e = BM_edge_exists(link->data, link->prev->data); - if (e) { - BM_elem_flag_set(e, hflag, set); - } - link = link->next; - } + /* only handle closed loops in this case */ + LinkData *link = BM_edgeloop_verts_get(estore)->first; + link = link->next; + while (link) { + BMEdge *e = BM_edge_exists(link->data, link->prev->data); + if (e) { + BM_elem_flag_set(e, hflag, set); + } + link = link->next; + } } static bool bm_edge_test_cb(BMEdge *e, void *bm_v) { - return BMO_edge_flag_test_bool((BMesh *)bm_v, e, EDGE_MARK); + return BMO_edge_flag_test_bool((BMesh *)bm_v, e, EDGE_MARK); } static bool bm_edge_test_rail_cb(BMEdge *e, void *UNUSED(bm_v)) { - /* normally operators dont check for hidden state - * but alternative would be to pass slot of rail edges */ - if (BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { - return false; - } - return BM_edge_is_wire(e) || BM_edge_is_boundary(e); + /* normally operators dont check for hidden state + * but alternative would be to pass slot of rail edges */ + if (BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { + return false; + } + return BM_edge_is_wire(e) || BM_edge_is_boundary(e); } void bmo_grid_fill_exec(BMesh *bm, BMOperator *op) { - ListBase eloops = {NULL, NULL}; - ListBase eloops_rail = {NULL, NULL}; - struct BMEdgeLoopStore *estore_a, *estore_b; - struct BMEdgeLoopStore *estore_rail_a, *estore_rail_b; - BMVert *v_a_first, *v_a_last; - BMVert *v_b_first, *v_b_last; - const short mat_nr = (short)BMO_slot_int_get(op->slots_in, "mat_nr"); - const bool use_smooth = BMO_slot_bool_get(op->slots_in, "use_smooth"); - const bool use_interp_simple = BMO_slot_bool_get(op->slots_in, "use_interp_simple"); - GSet *split_edges = NULL; - - int count; - bool changed = false; - BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, EDGE_MARK); - - count = BM_mesh_edgeloops_find(bm, &eloops, bm_edge_test_cb, (void *)bm); - - if (count != 2) { - BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, - "Select two edge loops"); - goto cleanup; - } - - estore_a = eloops.first; - estore_b = eloops.last; - - v_a_first = ((LinkData *)BM_edgeloop_verts_get(estore_a)->first)->data; - v_a_last = ((LinkData *)BM_edgeloop_verts_get(estore_a)->last)->data; - v_b_first = ((LinkData *)BM_edgeloop_verts_get(estore_b)->first)->data; - v_b_last = ((LinkData *)BM_edgeloop_verts_get(estore_b)->last)->data; - - if (BM_edgeloop_is_closed(estore_a) || BM_edgeloop_is_closed(estore_b)) { - BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, - "Closed loops unsupported"); - goto cleanup; - } - - /* ok. all error checking done, now we can find the rail edges */ - - - /* cheat here, temp hide all edges so they won't be included in rails - * this puts the mesh in an invalid state for a short time. */ - bm_edgeloop_flag_set(estore_a, BM_ELEM_HIDDEN, true); - bm_edgeloop_flag_set(estore_b, BM_ELEM_HIDDEN, true); - - if ((BM_mesh_edgeloops_find_path(bm, &eloops_rail, bm_edge_test_rail_cb, bm, v_a_first, v_b_first)) && - (BM_mesh_edgeloops_find_path(bm, &eloops_rail, bm_edge_test_rail_cb, bm, v_a_last, v_b_last))) - { - estore_rail_a = eloops_rail.first; - estore_rail_b = eloops_rail.last; - } - else { - BM_mesh_edgeloops_free(&eloops_rail); - - if ((BM_mesh_edgeloops_find_path(bm, &eloops_rail, bm_edge_test_rail_cb, bm, v_a_first, v_b_last)) && - (BM_mesh_edgeloops_find_path(bm, &eloops_rail, bm_edge_test_rail_cb, bm, v_a_last, v_b_first))) - { - estore_rail_a = eloops_rail.first; - estore_rail_b = eloops_rail.last; - BM_edgeloop_flip(bm, estore_b); - } - else { - BM_mesh_edgeloops_free(&eloops_rail); - } - } - - bm_edgeloop_flag_set(estore_a, BM_ELEM_HIDDEN, false); - bm_edgeloop_flag_set(estore_b, BM_ELEM_HIDDEN, false); - - - if (BLI_listbase_is_empty(&eloops_rail)) { - BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, - "Loops are not connected by wire/boundary edges"); - goto cleanup; - } - - BLI_assert(estore_a != estore_b); - BLI_assert(v_a_last != v_b_last); - - if (BM_edgeloop_overlap_check(estore_rail_a, estore_rail_b)) { - BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, - "Connecting edge loops overlap"); - goto cleanup; - } - - /* add vertices if needed */ - { - struct BMEdgeLoopStore *estore_pairs[2][2] = {{estore_a, estore_b}, {estore_rail_a, estore_rail_b}}; - int i; - - for (i = 0; i < 2; i++) { - const int len_a = BM_edgeloop_length_get(estore_pairs[i][0]); - const int len_b = BM_edgeloop_length_get(estore_pairs[i][1]); - if (len_a != len_b) { - if (split_edges == NULL) { - split_edges = BLI_gset_ptr_new(__func__); - } - - if (len_a < len_b) { - BM_edgeloop_expand(bm, estore_pairs[i][0], len_b, true, split_edges); - } - else { - BM_edgeloop_expand(bm, estore_pairs[i][1], len_a, true, split_edges); - } - } - } - } - - /* finally we have all edge loops needed */ - bm_grid_fill(bm, estore_a, estore_b, estore_rail_a, estore_rail_b, - mat_nr, use_smooth, use_interp_simple); - - changed = true; - - if (split_edges) { - GSetIterator gs_iter; - GSET_ITER (gs_iter, split_edges) { - BMEdge *e = BLI_gsetIterator_getKey(&gs_iter); - BM_edge_collapse(bm, e, e->v2, true, true); - } - BLI_gset_free(split_edges, NULL); - } + ListBase eloops = {NULL, NULL}; + ListBase eloops_rail = {NULL, NULL}; + struct BMEdgeLoopStore *estore_a, *estore_b; + struct BMEdgeLoopStore *estore_rail_a, *estore_rail_b; + BMVert *v_a_first, *v_a_last; + BMVert *v_b_first, *v_b_last; + const short mat_nr = (short)BMO_slot_int_get(op->slots_in, "mat_nr"); + const bool use_smooth = BMO_slot_bool_get(op->slots_in, "use_smooth"); + const bool use_interp_simple = BMO_slot_bool_get(op->slots_in, "use_interp_simple"); + GSet *split_edges = NULL; + + int count; + bool changed = false; + BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, EDGE_MARK); + + count = BM_mesh_edgeloops_find(bm, &eloops, bm_edge_test_cb, (void *)bm); + + if (count != 2) { + BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, "Select two edge loops"); + goto cleanup; + } + + estore_a = eloops.first; + estore_b = eloops.last; + + v_a_first = ((LinkData *)BM_edgeloop_verts_get(estore_a)->first)->data; + v_a_last = ((LinkData *)BM_edgeloop_verts_get(estore_a)->last)->data; + v_b_first = ((LinkData *)BM_edgeloop_verts_get(estore_b)->first)->data; + v_b_last = ((LinkData *)BM_edgeloop_verts_get(estore_b)->last)->data; + + if (BM_edgeloop_is_closed(estore_a) || BM_edgeloop_is_closed(estore_b)) { + BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, "Closed loops unsupported"); + goto cleanup; + } + + /* ok. all error checking done, now we can find the rail edges */ + + /* cheat here, temp hide all edges so they won't be included in rails + * this puts the mesh in an invalid state for a short time. */ + bm_edgeloop_flag_set(estore_a, BM_ELEM_HIDDEN, true); + bm_edgeloop_flag_set(estore_b, BM_ELEM_HIDDEN, true); + + if ((BM_mesh_edgeloops_find_path( + bm, &eloops_rail, bm_edge_test_rail_cb, bm, v_a_first, v_b_first)) && + (BM_mesh_edgeloops_find_path( + bm, &eloops_rail, bm_edge_test_rail_cb, bm, v_a_last, v_b_last))) { + estore_rail_a = eloops_rail.first; + estore_rail_b = eloops_rail.last; + } + else { + BM_mesh_edgeloops_free(&eloops_rail); + + if ((BM_mesh_edgeloops_find_path( + bm, &eloops_rail, bm_edge_test_rail_cb, bm, v_a_first, v_b_last)) && + (BM_mesh_edgeloops_find_path( + bm, &eloops_rail, bm_edge_test_rail_cb, bm, v_a_last, v_b_first))) { + estore_rail_a = eloops_rail.first; + estore_rail_b = eloops_rail.last; + BM_edgeloop_flip(bm, estore_b); + } + else { + BM_mesh_edgeloops_free(&eloops_rail); + } + } + + bm_edgeloop_flag_set(estore_a, BM_ELEM_HIDDEN, false); + bm_edgeloop_flag_set(estore_b, BM_ELEM_HIDDEN, false); + + if (BLI_listbase_is_empty(&eloops_rail)) { + BMO_error_raise( + bm, op, BMERR_INVALID_SELECTION, "Loops are not connected by wire/boundary edges"); + goto cleanup; + } + + BLI_assert(estore_a != estore_b); + BLI_assert(v_a_last != v_b_last); + + if (BM_edgeloop_overlap_check(estore_rail_a, estore_rail_b)) { + BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, "Connecting edge loops overlap"); + goto cleanup; + } + + /* add vertices if needed */ + { + struct BMEdgeLoopStore *estore_pairs[2][2] = {{estore_a, estore_b}, + {estore_rail_a, estore_rail_b}}; + int i; + + for (i = 0; i < 2; i++) { + const int len_a = BM_edgeloop_length_get(estore_pairs[i][0]); + const int len_b = BM_edgeloop_length_get(estore_pairs[i][1]); + if (len_a != len_b) { + if (split_edges == NULL) { + split_edges = BLI_gset_ptr_new(__func__); + } + + if (len_a < len_b) { + BM_edgeloop_expand(bm, estore_pairs[i][0], len_b, true, split_edges); + } + else { + BM_edgeloop_expand(bm, estore_pairs[i][1], len_a, true, split_edges); + } + } + } + } + + /* finally we have all edge loops needed */ + bm_grid_fill( + bm, estore_a, estore_b, estore_rail_a, estore_rail_b, mat_nr, use_smooth, use_interp_simple); + + changed = true; + + if (split_edges) { + GSetIterator gs_iter; + GSET_ITER (gs_iter, split_edges) { + BMEdge *e = BLI_gsetIterator_getKey(&gs_iter); + BM_edge_collapse(bm, e, e->v2, true, true); + } + BLI_gset_free(split_edges, NULL); + } cleanup: - BM_mesh_edgeloops_free(&eloops); - BM_mesh_edgeloops_free(&eloops_rail); + BM_mesh_edgeloops_free(&eloops); + BM_mesh_edgeloops_free(&eloops_rail); - if (changed) { - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, FACE_OUT); - } + if (changed) { + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, FACE_OUT); + } } diff --git a/source/blender/bmesh/operators/bmo_fill_holes.c b/source/blender/bmesh/operators/bmo_fill_holes.c index bf3c4cb1fc7..5801db582e1 100644 --- a/source/blender/bmesh/operators/bmo_fill_holes.c +++ b/source/blender/bmesh/operators/bmo_fill_holes.c @@ -29,49 +29,52 @@ void bmo_holes_fill_exec(BMesh *bm, BMOperator *op) { - BMOperator op_attr; - const uint sides = BMO_slot_int_get(op->slots_in, "sides"); - - - BM_mesh_elem_hflag_disable_all(bm, BM_EDGE | BM_FACE, BM_ELEM_TAG, false); - BMO_slot_buffer_hflag_enable(bm, op->slots_in, "edges", BM_EDGE, BM_ELEM_TAG, false); - - BM_mesh_edgenet(bm, true, true); // TODO, sides - - - /* bad - remove faces after as a workaround */ - if (sides != 0) { - BMOIter siter; - BMFace *f; - - BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG); - BMO_ITER (f, &siter, op->slots_out, "faces.out", BM_FACE) { - if (f->len > sides) { - BM_face_kill(bm, f); - } - } - } - - BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG); - - /* --- Attribute Fill --- */ - /* may as well since we have the faces already in a buffer */ - BMO_op_initf(bm, &op_attr, op->flag, - "face_attribute_fill faces=%S use_normals=%b use_data=%b", - op, "faces.out", true, true); - - BMO_op_exec(bm, &op_attr); - - /* check if some faces couldn't be touched */ - if (BMO_slot_buffer_count(op_attr.slots_out, "faces_fail.out")) { - BMOIter siter; - BMFace *f; - - BMO_ITER (f, &siter, op_attr.slots_out, "faces_fail.out", BM_FACE) { - BM_face_normal_update(f); /* normals are zero'd */ - } - - BMO_op_callf(bm, op->flag, "recalc_face_normals faces=%S", &op_attr, "faces_fail.out"); - } - BMO_op_finish(bm, &op_attr); + BMOperator op_attr; + const uint sides = BMO_slot_int_get(op->slots_in, "sides"); + + BM_mesh_elem_hflag_disable_all(bm, BM_EDGE | BM_FACE, BM_ELEM_TAG, false); + BMO_slot_buffer_hflag_enable(bm, op->slots_in, "edges", BM_EDGE, BM_ELEM_TAG, false); + + BM_mesh_edgenet(bm, true, true); // TODO, sides + + /* bad - remove faces after as a workaround */ + if (sides != 0) { + BMOIter siter; + BMFace *f; + + BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG); + BMO_ITER (f, &siter, op->slots_out, "faces.out", BM_FACE) { + if (f->len > sides) { + BM_face_kill(bm, f); + } + } + } + + BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG); + + /* --- Attribute Fill --- */ + /* may as well since we have the faces already in a buffer */ + BMO_op_initf(bm, + &op_attr, + op->flag, + "face_attribute_fill faces=%S use_normals=%b use_data=%b", + op, + "faces.out", + true, + true); + + BMO_op_exec(bm, &op_attr); + + /* check if some faces couldn't be touched */ + if (BMO_slot_buffer_count(op_attr.slots_out, "faces_fail.out")) { + BMOIter siter; + BMFace *f; + + BMO_ITER (f, &siter, op_attr.slots_out, "faces_fail.out", BM_FACE) { + BM_face_normal_update(f); /* normals are zero'd */ + } + + BMO_op_callf(bm, op->flag, "recalc_face_normals faces=%S", &op_attr, "faces_fail.out"); + } + BMO_op_finish(bm, &op_attr); } diff --git a/source/blender/bmesh/operators/bmo_hull.c b/source/blender/bmesh/operators/bmo_hull.c index 664c4b3f615..46b31ce40d3 100644 --- a/source/blender/bmesh/operators/bmo_hull.c +++ b/source/blender/bmesh/operators/bmo_hull.c @@ -22,629 +22,597 @@ #ifdef WITH_BULLET -#include "MEM_guardedalloc.h" +# include "MEM_guardedalloc.h" -#include "BLI_array.h" -#include "BLI_listbase.h" -#include "BLI_math.h" +# include "BLI_array.h" +# include "BLI_listbase.h" +# include "BLI_math.h" -#include "Bullet-C-Api.h" +# include "Bullet-C-Api.h" /* XXX: using 128 for totelem and pchunk of mempool, no idea what good * values would be though */ -#include "bmesh.h" +# include "bmesh.h" -#include "intern/bmesh_operators_private.h" /* own include */ +# include "intern/bmesh_operators_private.h" /* own include */ /* Internal operator flags */ typedef enum { - HULL_FLAG_INPUT = (1 << 0), + HULL_FLAG_INPUT = (1 << 0), - HULL_FLAG_INTERIOR_ELE = (1 << 1), - HULL_FLAG_OUTPUT_GEOM = (1 << 2), + HULL_FLAG_INTERIOR_ELE = (1 << 1), + HULL_FLAG_OUTPUT_GEOM = (1 << 2), - HULL_FLAG_DEL = (1 << 3), - HULL_FLAG_HOLE = (1 << 4), + HULL_FLAG_DEL = (1 << 3), + HULL_FLAG_HOLE = (1 << 4), } HullFlags; /* Store hull triangles separate from BMesh faces until the end; this * way we don't have to worry about cleaning up extraneous edges or * incorrectly deleting existing geometry. */ typedef struct HullTriangle { - BMVert *v[3]; - float no[3]; - int skip; + BMVert *v[3]; + float no[3]; + int skip; } HullTriangle; - - /*************************** Hull Triangles ***************************/ static void hull_add_triangle( - BMesh *bm, GSet *hull_triangles, BLI_mempool *pool, - BMVert *v1, BMVert *v2, BMVert *v3) + BMesh *bm, GSet *hull_triangles, BLI_mempool *pool, BMVert *v1, BMVert *v2, BMVert *v3) { - HullTriangle *t; - int i; + HullTriangle *t; + int i; - t = BLI_mempool_calloc(pool); - t->v[0] = v1; - t->v[1] = v2; - t->v[2] = v3; + t = BLI_mempool_calloc(pool); + t->v[0] = v1; + t->v[1] = v2; + t->v[2] = v3; - /* Mark triangles vertices as not interior */ - for (i = 0; i < 3; i++) { - BMO_vert_flag_disable(bm, t->v[i], HULL_FLAG_INTERIOR_ELE); - } + /* Mark triangles vertices as not interior */ + for (i = 0; i < 3; i++) { + BMO_vert_flag_disable(bm, t->v[i], HULL_FLAG_INTERIOR_ELE); + } - BLI_gset_insert(hull_triangles, t); - normal_tri_v3(t->no, v1->co, v2->co, v3->co); + BLI_gset_insert(hull_triangles, t); + normal_tri_v3(t->no, v1->co, v2->co, v3->co); } static BMFace *hull_find_example_face(BMesh *bm, BMEdge *e) { - BMIter iter; - BMFace *f; - - BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) { - if (BMO_face_flag_test(bm, f, HULL_FLAG_INPUT) || - BMO_face_flag_test(bm, f, HULL_FLAG_OUTPUT_GEOM) == false) - { - return f; - } - } - - return NULL; + BMIter iter; + BMFace *f; + + BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) { + if (BMO_face_flag_test(bm, f, HULL_FLAG_INPUT) || + BMO_face_flag_test(bm, f, HULL_FLAG_OUTPUT_GEOM) == false) { + return f; + } + } + + return NULL; } static void hull_output_triangles(BMesh *bm, GSet *hull_triangles) { - GSetIterator iter; - - GSET_ITER (iter, hull_triangles) { - HullTriangle *t = BLI_gsetIterator_getKey(&iter); - int i; - - if (!t->skip) { - BMEdge *edges[3] = { - BM_edge_create(bm, t->v[0], t->v[1], NULL, BM_CREATE_NO_DOUBLE), - BM_edge_create(bm, t->v[1], t->v[2], NULL, BM_CREATE_NO_DOUBLE), - BM_edge_create(bm, t->v[2], t->v[0], NULL, BM_CREATE_NO_DOUBLE) - }; - BMFace *f, *example = NULL; - - f = BM_face_exists(t->v, 3); - if (f != NULL) { - /* If the operator is run with "use_existing_faces" - * disabled, but an output face in the hull is the - * same as a face in the existing mesh, it should not - * be marked as unused or interior. */ - BMO_face_flag_enable(bm, f, HULL_FLAG_OUTPUT_GEOM); - BMO_face_flag_disable(bm, f, HULL_FLAG_HOLE); - BMO_face_flag_disable(bm, f, HULL_FLAG_INTERIOR_ELE); - } - else { - /* Look for an adjacent face that existed before the hull */ - for (i = 0; i < 3; i++) { - if (!example) { - example = hull_find_example_face(bm, edges[i]); - } - } - - /* Create new hull face */ - f = BM_face_create_verts(bm, t->v, 3, example, BM_CREATE_NO_DOUBLE, true); - BM_face_copy_shared(bm, f, NULL, NULL); - } - /* Mark face for 'geom.out' slot and select */ - BMO_face_flag_enable(bm, f, HULL_FLAG_OUTPUT_GEOM); - BM_face_select_set(bm, f, true); - - /* Mark edges for 'geom.out' slot */ - for (i = 0; i < 3; i++) { - BMO_edge_flag_enable(bm, edges[i], HULL_FLAG_OUTPUT_GEOM); - } - } - else { - /* Mark input edges for 'geom.out' slot */ - for (i = 0; i < 3; i++) { - const int next = (i == 2 ? 0 : i + 1); - BMEdge *e = BM_edge_exists(t->v[i], t->v[next]); - if (e && - BMO_edge_flag_test(bm, e, HULL_FLAG_INPUT) && - !BMO_edge_flag_test(bm, e, HULL_FLAG_HOLE)) - { - BMO_edge_flag_enable(bm, e, HULL_FLAG_OUTPUT_GEOM); - } - } - } - - /* Mark verts for 'geom.out' slot */ - for (i = 0; i < 3; i++) { - BMO_vert_flag_enable(bm, t->v[i], HULL_FLAG_OUTPUT_GEOM); - } - } + GSetIterator iter; + + GSET_ITER (iter, hull_triangles) { + HullTriangle *t = BLI_gsetIterator_getKey(&iter); + int i; + + if (!t->skip) { + BMEdge *edges[3] = {BM_edge_create(bm, t->v[0], t->v[1], NULL, BM_CREATE_NO_DOUBLE), + BM_edge_create(bm, t->v[1], t->v[2], NULL, BM_CREATE_NO_DOUBLE), + BM_edge_create(bm, t->v[2], t->v[0], NULL, BM_CREATE_NO_DOUBLE)}; + BMFace *f, *example = NULL; + + f = BM_face_exists(t->v, 3); + if (f != NULL) { + /* If the operator is run with "use_existing_faces" + * disabled, but an output face in the hull is the + * same as a face in the existing mesh, it should not + * be marked as unused or interior. */ + BMO_face_flag_enable(bm, f, HULL_FLAG_OUTPUT_GEOM); + BMO_face_flag_disable(bm, f, HULL_FLAG_HOLE); + BMO_face_flag_disable(bm, f, HULL_FLAG_INTERIOR_ELE); + } + else { + /* Look for an adjacent face that existed before the hull */ + for (i = 0; i < 3; i++) { + if (!example) { + example = hull_find_example_face(bm, edges[i]); + } + } + + /* Create new hull face */ + f = BM_face_create_verts(bm, t->v, 3, example, BM_CREATE_NO_DOUBLE, true); + BM_face_copy_shared(bm, f, NULL, NULL); + } + /* Mark face for 'geom.out' slot and select */ + BMO_face_flag_enable(bm, f, HULL_FLAG_OUTPUT_GEOM); + BM_face_select_set(bm, f, true); + + /* Mark edges for 'geom.out' slot */ + for (i = 0; i < 3; i++) { + BMO_edge_flag_enable(bm, edges[i], HULL_FLAG_OUTPUT_GEOM); + } + } + else { + /* Mark input edges for 'geom.out' slot */ + for (i = 0; i < 3; i++) { + const int next = (i == 2 ? 0 : i + 1); + BMEdge *e = BM_edge_exists(t->v[i], t->v[next]); + if (e && BMO_edge_flag_test(bm, e, HULL_FLAG_INPUT) && + !BMO_edge_flag_test(bm, e, HULL_FLAG_HOLE)) { + BMO_edge_flag_enable(bm, e, HULL_FLAG_OUTPUT_GEOM); + } + } + } + + /* Mark verts for 'geom.out' slot */ + for (i = 0; i < 3; i++) { + BMO_vert_flag_enable(bm, t->v[i], HULL_FLAG_OUTPUT_GEOM); + } + } } - - /***************************** Final Edges ****************************/ typedef struct { - GHash *edges; - BLI_mempool *base_pool, *link_pool; + GHash *edges; + BLI_mempool *base_pool, *link_pool; } HullFinalEdges; static LinkData *final_edges_find_link(ListBase *adj, BMVert *v) { - LinkData *link; + LinkData *link; - for (link = adj->first; link; link = link->next) { - if (link->data == v) { - return link; - } - } + for (link = adj->first; link; link = link->next) { + if (link->data == v) { + return link; + } + } - return NULL; + return NULL; } -static int hull_final_edges_lookup( - HullFinalEdges *final_edges, - BMVert *v1, BMVert *v2) +static int hull_final_edges_lookup(HullFinalEdges *final_edges, BMVert *v1, BMVert *v2) { - ListBase *adj; + ListBase *adj; - /* Use lower vertex pointer for hash key */ - if (v1 > v2) { - SWAP(BMVert *, v1, v2); - } + /* Use lower vertex pointer for hash key */ + if (v1 > v2) { + SWAP(BMVert *, v1, v2); + } - adj = BLI_ghash_lookup(final_edges->edges, v1); - if (!adj) { - return false; - } + adj = BLI_ghash_lookup(final_edges->edges, v1); + if (!adj) { + return false; + } - return !!final_edges_find_link(adj, v2); + return !!final_edges_find_link(adj, v2); } /* Used for checking whether a pre-existing edge lies on the hull */ static HullFinalEdges *hull_final_edges(GSet *hull_triangles) { - HullFinalEdges *final_edges; - GSetIterator iter; - - final_edges = MEM_callocN(sizeof(HullFinalEdges), "HullFinalEdges"); - final_edges->edges = BLI_ghash_ptr_new("final edges ghash"); - final_edges->base_pool = BLI_mempool_create(sizeof(ListBase), 0, 128, BLI_MEMPOOL_NOP); - final_edges->link_pool = BLI_mempool_create(sizeof(LinkData), 0, 128, BLI_MEMPOOL_NOP); - - GSET_ITER (iter, hull_triangles) { - HullTriangle *t = BLI_gsetIterator_getKey(&iter); - LinkData *link; - int i; - - for (i = 0; i < 3; i++) { - BMVert *v1 = t->v[i]; - BMVert *v2 = t->v[(i + 1) % 3]; - ListBase *adj; - - /* Use lower vertex pointer for hash key */ - if (v1 > v2) { - SWAP(BMVert *, v1, v2); - } - - adj = BLI_ghash_lookup(final_edges->edges, v1); - if (!adj) { - adj = BLI_mempool_calloc(final_edges->base_pool); - BLI_ghash_insert(final_edges->edges, v1, adj); - } - - if (!final_edges_find_link(adj, v2)) { - link = BLI_mempool_calloc(final_edges->link_pool); - link->data = v2; - BLI_addtail(adj, link); - } - } - } - - return final_edges; + HullFinalEdges *final_edges; + GSetIterator iter; + + final_edges = MEM_callocN(sizeof(HullFinalEdges), "HullFinalEdges"); + final_edges->edges = BLI_ghash_ptr_new("final edges ghash"); + final_edges->base_pool = BLI_mempool_create(sizeof(ListBase), 0, 128, BLI_MEMPOOL_NOP); + final_edges->link_pool = BLI_mempool_create(sizeof(LinkData), 0, 128, BLI_MEMPOOL_NOP); + + GSET_ITER (iter, hull_triangles) { + HullTriangle *t = BLI_gsetIterator_getKey(&iter); + LinkData *link; + int i; + + for (i = 0; i < 3; i++) { + BMVert *v1 = t->v[i]; + BMVert *v2 = t->v[(i + 1) % 3]; + ListBase *adj; + + /* Use lower vertex pointer for hash key */ + if (v1 > v2) { + SWAP(BMVert *, v1, v2); + } + + adj = BLI_ghash_lookup(final_edges->edges, v1); + if (!adj) { + adj = BLI_mempool_calloc(final_edges->base_pool); + BLI_ghash_insert(final_edges->edges, v1, adj); + } + + if (!final_edges_find_link(adj, v2)) { + link = BLI_mempool_calloc(final_edges->link_pool); + link->data = v2; + BLI_addtail(adj, link); + } + } + } + + return final_edges; } static void hull_final_edges_free(HullFinalEdges *final_edges) { - BLI_ghash_free(final_edges->edges, NULL, NULL); - BLI_mempool_destroy(final_edges->base_pool); - BLI_mempool_destroy(final_edges->link_pool); - MEM_freeN(final_edges); + BLI_ghash_free(final_edges->edges, NULL, NULL); + BLI_mempool_destroy(final_edges->base_pool); + BLI_mempool_destroy(final_edges->link_pool); + MEM_freeN(final_edges); } - - /**************************** Final Output ****************************/ -static void hull_remove_overlapping( - BMesh *bm, GSet *hull_triangles, - HullFinalEdges *final_edges) +static void hull_remove_overlapping(BMesh *bm, GSet *hull_triangles, HullFinalEdges *final_edges) { - GSetIterator hull_iter; - - GSET_ITER (hull_iter, hull_triangles) { - HullTriangle *t = BLI_gsetIterator_getKey(&hull_iter); - BMIter bm_iter1, bm_iter2; - BMFace *f; - bool f_on_hull; - - BM_ITER_ELEM (f, &bm_iter1, t->v[0], BM_FACES_OF_VERT) { - BMEdge *e; - - /* Check that all the face's edges are on the hull, - * otherwise can't reuse it */ - f_on_hull = true; - BM_ITER_ELEM (e, &bm_iter2, f, BM_EDGES_OF_FACE) { - if (!hull_final_edges_lookup(final_edges, e->v1, e->v2)) { - f_on_hull = false; - break; - } - } - - /* Note: can't change ghash while iterating, so mark - * with 'skip' flag rather than deleting triangles */ - if (BM_vert_in_face(t->v[1], f) && - BM_vert_in_face(t->v[2], f) && f_on_hull) - { - t->skip = true; - BMO_face_flag_disable(bm, f, HULL_FLAG_INTERIOR_ELE); - BMO_face_flag_enable(bm, f, HULL_FLAG_HOLE); - } - } - } + GSetIterator hull_iter; + + GSET_ITER (hull_iter, hull_triangles) { + HullTriangle *t = BLI_gsetIterator_getKey(&hull_iter); + BMIter bm_iter1, bm_iter2; + BMFace *f; + bool f_on_hull; + + BM_ITER_ELEM (f, &bm_iter1, t->v[0], BM_FACES_OF_VERT) { + BMEdge *e; + + /* Check that all the face's edges are on the hull, + * otherwise can't reuse it */ + f_on_hull = true; + BM_ITER_ELEM (e, &bm_iter2, f, BM_EDGES_OF_FACE) { + if (!hull_final_edges_lookup(final_edges, e->v1, e->v2)) { + f_on_hull = false; + break; + } + } + + /* Note: can't change ghash while iterating, so mark + * with 'skip' flag rather than deleting triangles */ + if (BM_vert_in_face(t->v[1], f) && BM_vert_in_face(t->v[2], f) && f_on_hull) { + t->skip = true; + BMO_face_flag_disable(bm, f, HULL_FLAG_INTERIOR_ELE); + BMO_face_flag_enable(bm, f, HULL_FLAG_HOLE); + } + } + } } -static void hull_mark_interior_elements( - BMesh *bm, BMOperator *op, - HullFinalEdges *final_edges) +static void hull_mark_interior_elements(BMesh *bm, BMOperator *op, HullFinalEdges *final_edges) { - BMEdge *e; - BMFace *f; - BMOIter oiter; - - /* Check for interior edges too */ - BMO_ITER (e, &oiter, op->slots_in, "input", BM_EDGE) { - if (!hull_final_edges_lookup(final_edges, e->v1, e->v2)) { - BMO_edge_flag_enable(bm, e, HULL_FLAG_INTERIOR_ELE); - } - } - - /* Mark all input faces as interior, some may be unmarked in - * hull_remove_overlapping() */ - BMO_ITER (f, &oiter, op->slots_in, "input", BM_FACE) { - BMO_face_flag_enable(bm, f, HULL_FLAG_INTERIOR_ELE); - } + BMEdge *e; + BMFace *f; + BMOIter oiter; + + /* Check for interior edges too */ + BMO_ITER (e, &oiter, op->slots_in, "input", BM_EDGE) { + if (!hull_final_edges_lookup(final_edges, e->v1, e->v2)) { + BMO_edge_flag_enable(bm, e, HULL_FLAG_INTERIOR_ELE); + } + } + + /* Mark all input faces as interior, some may be unmarked in + * hull_remove_overlapping() */ + BMO_ITER (f, &oiter, op->slots_in, "input", BM_FACE) { + BMO_face_flag_enable(bm, f, HULL_FLAG_INTERIOR_ELE); + } } static void hull_tag_unused(BMesh *bm, BMOperator *op) { - BMIter iter; - BMOIter oiter; - BMVert *v; - BMEdge *e; - BMFace *f; - - /* Mark vertices, edges, and faces that are already marked - * interior (i.e. were already part of the input, but not part of - * the hull), but that aren't also used by elements outside the - * input set */ - BMO_ITER (v, &oiter, op->slots_in, "input", BM_VERT) { - if (BMO_vert_flag_test(bm, v, HULL_FLAG_INTERIOR_ELE)) { - bool del = true; - - BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { - if (!BMO_edge_flag_test(bm, e, HULL_FLAG_INPUT)) { - del = false; - break; - } - } - - BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) { - if (!BMO_face_flag_test(bm, f, HULL_FLAG_INPUT)) { - del = false; - break; - } - } - - if (del) { - BMO_vert_flag_enable(bm, v, HULL_FLAG_DEL); - } - } - } - - BMO_ITER (e, &oiter, op->slots_in, "input", BM_EDGE) { - if (BMO_edge_flag_test(bm, e, HULL_FLAG_INTERIOR_ELE)) { - bool del = true; - - BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) { - if (!BMO_face_flag_test(bm, f, HULL_FLAG_INPUT)) { - del = false; - break; - } - } - - if (del) { - BMO_edge_flag_enable(bm, e, HULL_FLAG_DEL); - } - } - } - - BMO_ITER (f, &oiter, op->slots_in, "input", BM_FACE) { - if (BMO_face_flag_test(bm, f, HULL_FLAG_INTERIOR_ELE)) { - BMO_face_flag_enable(bm, f, HULL_FLAG_DEL); - } - } + BMIter iter; + BMOIter oiter; + BMVert *v; + BMEdge *e; + BMFace *f; + + /* Mark vertices, edges, and faces that are already marked + * interior (i.e. were already part of the input, but not part of + * the hull), but that aren't also used by elements outside the + * input set */ + BMO_ITER (v, &oiter, op->slots_in, "input", BM_VERT) { + if (BMO_vert_flag_test(bm, v, HULL_FLAG_INTERIOR_ELE)) { + bool del = true; + + BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { + if (!BMO_edge_flag_test(bm, e, HULL_FLAG_INPUT)) { + del = false; + break; + } + } + + BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) { + if (!BMO_face_flag_test(bm, f, HULL_FLAG_INPUT)) { + del = false; + break; + } + } + + if (del) { + BMO_vert_flag_enable(bm, v, HULL_FLAG_DEL); + } + } + } + + BMO_ITER (e, &oiter, op->slots_in, "input", BM_EDGE) { + if (BMO_edge_flag_test(bm, e, HULL_FLAG_INTERIOR_ELE)) { + bool del = true; + + BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) { + if (!BMO_face_flag_test(bm, f, HULL_FLAG_INPUT)) { + del = false; + break; + } + } + + if (del) { + BMO_edge_flag_enable(bm, e, HULL_FLAG_DEL); + } + } + } + + BMO_ITER (f, &oiter, op->slots_in, "input", BM_FACE) { + if (BMO_face_flag_test(bm, f, HULL_FLAG_INTERIOR_ELE)) { + BMO_face_flag_enable(bm, f, HULL_FLAG_DEL); + } + } } static void hull_tag_holes(BMesh *bm, BMOperator *op) { - BMIter iter; - BMOIter oiter; - BMFace *f; - BMEdge *e; - - /* Unmark any hole faces if they are isolated or part of a - * border */ - BMO_ITER (f, &oiter, op->slots_in, "input", BM_FACE) { - if (BMO_face_flag_test(bm, f, HULL_FLAG_HOLE)) { - BM_ITER_ELEM (e, &iter, f, BM_EDGES_OF_FACE) { - if (BM_edge_is_boundary(e)) { - BMO_face_flag_disable(bm, f, HULL_FLAG_HOLE); - break; - } - } - } - } - - /* Mark edges too if all adjacent faces are holes and the edge is - * not already isolated */ - BMO_ITER (e, &oiter, op->slots_in, "input", BM_EDGE) { - bool hole = true; - bool any_faces = false; - - BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) { - any_faces = true; - if (!BMO_face_flag_test(bm, f, HULL_FLAG_HOLE)) { - hole = false; - break; - } - } - - if (hole && any_faces) { - BMO_edge_flag_enable(bm, e, HULL_FLAG_HOLE); - } - } + BMIter iter; + BMOIter oiter; + BMFace *f; + BMEdge *e; + + /* Unmark any hole faces if they are isolated or part of a + * border */ + BMO_ITER (f, &oiter, op->slots_in, "input", BM_FACE) { + if (BMO_face_flag_test(bm, f, HULL_FLAG_HOLE)) { + BM_ITER_ELEM (e, &iter, f, BM_EDGES_OF_FACE) { + if (BM_edge_is_boundary(e)) { + BMO_face_flag_disable(bm, f, HULL_FLAG_HOLE); + break; + } + } + } + } + + /* Mark edges too if all adjacent faces are holes and the edge is + * not already isolated */ + BMO_ITER (e, &oiter, op->slots_in, "input", BM_EDGE) { + bool hole = true; + bool any_faces = false; + + BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) { + any_faces = true; + if (!BMO_face_flag_test(bm, f, HULL_FLAG_HOLE)) { + hole = false; + break; + } + } + + if (hole && any_faces) { + BMO_edge_flag_enable(bm, e, HULL_FLAG_HOLE); + } + } } static int hull_input_vert_count(BMOperator *op) { - BMOIter oiter; - BMVert *v; - int count = 0; + BMOIter oiter; + BMVert *v; + int count = 0; - BMO_ITER (v, &oiter, op->slots_in, "input", BM_VERT) { - count++; - } + BMO_ITER (v, &oiter, op->slots_in, "input", BM_VERT) { + count++; + } - return count; + return count; } -static BMVert **hull_input_verts_copy( - BMOperator *op, - const int num_input_verts) +static BMVert **hull_input_verts_copy(BMOperator *op, const int num_input_verts) { - BMOIter oiter; - BMVert *v; - BMVert **input_verts = MEM_callocN(sizeof(*input_verts) * - num_input_verts, AT); - int i = 0; + BMOIter oiter; + BMVert *v; + BMVert **input_verts = MEM_callocN(sizeof(*input_verts) * num_input_verts, AT); + int i = 0; - BMO_ITER (v, &oiter, op->slots_in, "input", BM_VERT) { - input_verts[i++] = v; - } + BMO_ITER (v, &oiter, op->slots_in, "input", BM_VERT) { + input_verts[i++] = v; + } - return input_verts; + return input_verts; } -static float (*hull_verts_for_bullet( - BMVert **input_verts, - const int num_input_verts))[3] +static float (*hull_verts_for_bullet(BMVert **input_verts, const int num_input_verts))[3] { - float (*coords)[3] = MEM_callocN(sizeof(*coords) * num_input_verts, __func__); - int i; + float(*coords)[3] = MEM_callocN(sizeof(*coords) * num_input_verts, __func__); + int i; - for (i = 0; i < num_input_verts; i++) { - copy_v3_v3(coords[i], input_verts[i]->co); - } + for (i = 0; i < num_input_verts; i++) { + copy_v3_v3(coords[i], input_verts[i]->co); + } - return coords; + return coords; } -static BMVert **hull_verts_from_bullet( - plConvexHull hull, - BMVert **input_verts, - const int num_input_verts) +static BMVert **hull_verts_from_bullet(plConvexHull hull, + BMVert **input_verts, + const int num_input_verts) { - const int num_verts = plConvexHullNumVertices(hull); - BMVert **hull_verts = MEM_mallocN(sizeof(*hull_verts) * - num_verts, AT); - int i; - - for (i = 0; i < num_verts; i++) { - float co[3]; - int original_index; - plConvexHullGetVertex(hull, i, co, &original_index); - - if (original_index >= 0 && original_index < num_input_verts) { - hull_verts[i] = input_verts[original_index]; - } - else { - BLI_assert(!"Unexpected new vertex in hull output"); - } - } - - return hull_verts; + const int num_verts = plConvexHullNumVertices(hull); + BMVert **hull_verts = MEM_mallocN(sizeof(*hull_verts) * num_verts, AT); + int i; + + for (i = 0; i < num_verts; i++) { + float co[3]; + int original_index; + plConvexHullGetVertex(hull, i, co, &original_index); + + if (original_index >= 0 && original_index < num_input_verts) { + hull_verts[i] = input_verts[original_index]; + } + else { + BLI_assert(!"Unexpected new vertex in hull output"); + } + } + + return hull_verts; } -static void hull_from_bullet( - BMesh *bm, BMOperator *op, - GSet *hull_triangles, - BLI_mempool *pool) +static void hull_from_bullet(BMesh *bm, BMOperator *op, GSet *hull_triangles, BLI_mempool *pool) { - int *fvi = NULL; - BLI_array_declare(fvi); + int *fvi = NULL; + BLI_array_declare(fvi); - BMVert **input_verts; - float (*coords)[3]; - BMVert **hull_verts; + BMVert **input_verts; + float(*coords)[3]; + BMVert **hull_verts; - plConvexHull hull; - int i, count = 0; + plConvexHull hull; + int i, count = 0; - const int num_input_verts = hull_input_vert_count(op); + const int num_input_verts = hull_input_vert_count(op); - input_verts = hull_input_verts_copy(op, num_input_verts); - coords = hull_verts_for_bullet(input_verts, num_input_verts); + input_verts = hull_input_verts_copy(op, num_input_verts); + coords = hull_verts_for_bullet(input_verts, num_input_verts); - hull = plConvexHullCompute(coords, num_input_verts); - hull_verts = hull_verts_from_bullet(hull, input_verts, num_input_verts); + hull = plConvexHullCompute(coords, num_input_verts); + hull_verts = hull_verts_from_bullet(hull, input_verts, num_input_verts); - count = plConvexHullNumFaces(hull); - for (i = 0; i < count; i++) { - const int len = plConvexHullGetFaceSize(hull, i); + count = plConvexHullNumFaces(hull); + for (i = 0; i < count; i++) { + const int len = plConvexHullGetFaceSize(hull, i); - if (len > 2) { - BMVert *fv[3]; - int j; + if (len > 2) { + BMVert *fv[3]; + int j; - /* Get face vertex indices */ - BLI_array_clear(fvi); - BLI_array_grow_items(fvi, len); - plConvexHullGetFaceVertices(hull, i, fvi); + /* Get face vertex indices */ + BLI_array_clear(fvi); + BLI_array_grow_items(fvi, len); + plConvexHullGetFaceVertices(hull, i, fvi); - /* Note: here we throw away any NGons from Bullet and turn - * them into triangle fans. Would be nice to use these - * directly, but will have to wait until HullTriangle goes - * away (TODO) */ - fv[0] = hull_verts[fvi[0]]; - for (j = 2; j < len; j++) { - fv[1] = hull_verts[fvi[j - 1]]; - fv[2] = hull_verts[fvi[j]]; + /* Note: here we throw away any NGons from Bullet and turn + * them into triangle fans. Would be nice to use these + * directly, but will have to wait until HullTriangle goes + * away (TODO) */ + fv[0] = hull_verts[fvi[0]]; + for (j = 2; j < len; j++) { + fv[1] = hull_verts[fvi[j - 1]]; + fv[2] = hull_verts[fvi[j]]; - hull_add_triangle(bm, hull_triangles, pool, - fv[0], fv[1], fv[2]); - } - } - } + hull_add_triangle(bm, hull_triangles, pool, fv[0], fv[1], fv[2]); + } + } + } - BLI_array_free(fvi); + BLI_array_free(fvi); - plConvexHullDelete(hull); + plConvexHullDelete(hull); - MEM_freeN(hull_verts); - MEM_freeN(coords); - MEM_freeN(input_verts); + MEM_freeN(hull_verts); + MEM_freeN(coords); + MEM_freeN(input_verts); } /* Check that there are at least three vertices in the input */ static bool hull_num_input_verts_is_ok(BMOperator *op) { - BMOIter oiter; - BMVert *v; - int partial_num_verts = 0; - - BMO_ITER (v, &oiter, op->slots_in, "input", BM_VERT) { - partial_num_verts++; - if (partial_num_verts >= 3) { - break; - } - } - - return (partial_num_verts >= 3); + BMOIter oiter; + BMVert *v; + int partial_num_verts = 0; + + BMO_ITER (v, &oiter, op->slots_in, "input", BM_VERT) { + partial_num_verts++; + if (partial_num_verts >= 3) { + break; + } + } + + return (partial_num_verts >= 3); } void bmo_convex_hull_exec(BMesh *bm, BMOperator *op) { - HullFinalEdges *final_edges; - BLI_mempool *hull_pool; - BMElemF *ele; - BMOIter oiter; - GSet *hull_triangles; - - /* Verify that at least three verts in the input */ - if (!hull_num_input_verts_is_ok(op)) { - BMO_error_raise(bm, op, BMERR_CONVEX_HULL_FAILED, - "Requires at least three vertices"); - return; - } - - /* Tag input elements */ - BMO_ITER (ele, &oiter, op->slots_in, "input", BM_ALL) { - - /* Mark all vertices as interior to begin with */ - if (ele->head.htype == BM_VERT) { - BMO_vert_flag_enable(bm, (BMVert *)ele, HULL_FLAG_INPUT | HULL_FLAG_INTERIOR_ELE); - } - else if (ele->head.htype == BM_EDGE) { - BMO_edge_flag_enable(bm, (BMEdge *)ele, HULL_FLAG_INPUT); - } - else { - BMO_face_flag_enable(bm, (BMFace *)ele, HULL_FLAG_INPUT); - } - } - - hull_pool = BLI_mempool_create(sizeof(HullTriangle), 0, 128, BLI_MEMPOOL_NOP); - hull_triangles = BLI_gset_ptr_new("hull_triangles"); - - hull_from_bullet(bm, op, hull_triangles, hull_pool); - - final_edges = hull_final_edges(hull_triangles); - - hull_mark_interior_elements(bm, op, final_edges); - - /* Remove hull triangles covered by an existing face */ - if (BMO_slot_bool_get(op->slots_in, "use_existing_faces")) { - hull_remove_overlapping(bm, hull_triangles, final_edges); - - hull_tag_holes(bm, op); - } - - /* Done with edges */ - hull_final_edges_free(final_edges); - - /* Convert hull triangles to BMesh faces */ - hull_output_triangles(bm, hull_triangles); - BLI_mempool_destroy(hull_pool); - - BLI_gset_free(hull_triangles, NULL); - - hull_tag_unused(bm, op); - - /* Output slot of input elements that ended up inside the hull - * rather than part of it */ - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom_interior.out", - BM_ALL_NOLOOP, HULL_FLAG_INTERIOR_ELE); - - /* Output slot of input elements that ended up inside the hull and - * are are unused by other geometry. */ - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom_unused.out", - BM_ALL_NOLOOP, HULL_FLAG_DEL); - - /* Output slot of faces and edges that were in the input and on - * the hull (useful for cases like bridging where you want to - * delete some input geometry) */ - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom_holes.out", - BM_ALL_NOLOOP, HULL_FLAG_HOLE); - - /* Output slot of all hull vertices, faces, and edges */ - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", - BM_ALL_NOLOOP, HULL_FLAG_OUTPUT_GEOM); + HullFinalEdges *final_edges; + BLI_mempool *hull_pool; + BMElemF *ele; + BMOIter oiter; + GSet *hull_triangles; + + /* Verify that at least three verts in the input */ + if (!hull_num_input_verts_is_ok(op)) { + BMO_error_raise(bm, op, BMERR_CONVEX_HULL_FAILED, "Requires at least three vertices"); + return; + } + + /* Tag input elements */ + BMO_ITER (ele, &oiter, op->slots_in, "input", BM_ALL) { + + /* Mark all vertices as interior to begin with */ + if (ele->head.htype == BM_VERT) { + BMO_vert_flag_enable(bm, (BMVert *)ele, HULL_FLAG_INPUT | HULL_FLAG_INTERIOR_ELE); + } + else if (ele->head.htype == BM_EDGE) { + BMO_edge_flag_enable(bm, (BMEdge *)ele, HULL_FLAG_INPUT); + } + else { + BMO_face_flag_enable(bm, (BMFace *)ele, HULL_FLAG_INPUT); + } + } + + hull_pool = BLI_mempool_create(sizeof(HullTriangle), 0, 128, BLI_MEMPOOL_NOP); + hull_triangles = BLI_gset_ptr_new("hull_triangles"); + + hull_from_bullet(bm, op, hull_triangles, hull_pool); + + final_edges = hull_final_edges(hull_triangles); + + hull_mark_interior_elements(bm, op, final_edges); + + /* Remove hull triangles covered by an existing face */ + if (BMO_slot_bool_get(op->slots_in, "use_existing_faces")) { + hull_remove_overlapping(bm, hull_triangles, final_edges); + + hull_tag_holes(bm, op); + } + + /* Done with edges */ + hull_final_edges_free(final_edges); + + /* Convert hull triangles to BMesh faces */ + hull_output_triangles(bm, hull_triangles); + BLI_mempool_destroy(hull_pool); + + BLI_gset_free(hull_triangles, NULL); + + hull_tag_unused(bm, op); + + /* Output slot of input elements that ended up inside the hull + * rather than part of it */ + BMO_slot_buffer_from_enabled_flag( + bm, op, op->slots_out, "geom_interior.out", BM_ALL_NOLOOP, HULL_FLAG_INTERIOR_ELE); + + /* Output slot of input elements that ended up inside the hull and + * are are unused by other geometry. */ + BMO_slot_buffer_from_enabled_flag( + bm, op, op->slots_out, "geom_unused.out", BM_ALL_NOLOOP, HULL_FLAG_DEL); + + /* Output slot of faces and edges that were in the input and on + * the hull (useful for cases like bridging where you want to + * delete some input geometry) */ + BMO_slot_buffer_from_enabled_flag( + bm, op, op->slots_out, "geom_holes.out", BM_ALL_NOLOOP, HULL_FLAG_HOLE); + + /* Output slot of all hull vertices, faces, and edges */ + BMO_slot_buffer_from_enabled_flag( + bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, HULL_FLAG_OUTPUT_GEOM); } -#endif /* WITH_BULLET */ +#endif /* WITH_BULLET */ diff --git a/source/blender/bmesh/operators/bmo_inset.c b/source/blender/bmesh/operators/bmo_inset.c index 3534d798b02..724b974c50f 100644 --- a/source/blender/bmesh/operators/bmo_inset.c +++ b/source/blender/bmesh/operators/bmo_inset.c @@ -35,8 +35,7 @@ /* Merge loop-data that diverges, see: T41445 */ #define USE_LOOP_CUSTOMDATA_MERGE -#define ELE_NEW 1 - +#define ELE_NEW 1 /* -------------------------------------------------------------------- */ /* Generic Interp Face (use for both types of inset) */ @@ -50,56 +49,59 @@ /* just enough of a face to store interpolation data we can use once the inset is done */ typedef struct InterpFace { - BMFace *f; - void **blocks_l; - void **blocks_v; - float (*cos_2d)[2]; - float axis_mat[3][3]; + BMFace *f; + void **blocks_l; + void **blocks_v; + float (*cos_2d)[2]; + float axis_mat[3][3]; } InterpFace; /* basically a clone of #BM_vert_interp_from_face */ static void bm_interp_face_store(InterpFace *iface, BMesh *bm, BMFace *f, MemArena *interp_arena) { - BMLoop *l_iter, *l_first; - void **blocks_l = iface->blocks_l = BLI_memarena_alloc(interp_arena, sizeof(*iface->blocks_l) * f->len); - void **blocks_v = iface->blocks_v = BLI_memarena_alloc(interp_arena, sizeof(*iface->blocks_v) * f->len); - float (*cos_2d)[2] = iface->cos_2d = BLI_memarena_alloc(interp_arena, sizeof(*iface->cos_2d) * f->len); - void *axis_mat = iface->axis_mat; - int i; - - BLI_assert(BM_face_is_normal_valid(f)); - - axis_dominant_v3_to_m3(axis_mat, f->no); - - iface->f = f; - - i = 0; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - mul_v2_m3v3(cos_2d[i], axis_mat, l_iter->v->co); - blocks_l[i] = NULL; - CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, l_iter->head.data, &blocks_l[i]); - /* if we were not modifying the loops later we would do... */ - // blocks[i] = l_iter->head.data; - - blocks_v[i] = NULL; - CustomData_bmesh_copy_data(&bm->vdata, &bm->vdata, l_iter->v->head.data, &blocks_v[i]); - - /* use later for index lookups */ - BM_elem_index_set(l_iter, i); /* set_dirty */ - } while ((void)i++, (l_iter = l_iter->next) != l_first); - bm->elem_index_dirty |= BM_LOOP; + BMLoop *l_iter, *l_first; + void **blocks_l = iface->blocks_l = BLI_memarena_alloc(interp_arena, + sizeof(*iface->blocks_l) * f->len); + void **blocks_v = iface->blocks_v = BLI_memarena_alloc(interp_arena, + sizeof(*iface->blocks_v) * f->len); + float(*cos_2d)[2] = iface->cos_2d = BLI_memarena_alloc(interp_arena, + sizeof(*iface->cos_2d) * f->len); + void *axis_mat = iface->axis_mat; + int i; + + BLI_assert(BM_face_is_normal_valid(f)); + + axis_dominant_v3_to_m3(axis_mat, f->no); + + iface->f = f; + + i = 0; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + mul_v2_m3v3(cos_2d[i], axis_mat, l_iter->v->co); + blocks_l[i] = NULL; + CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, l_iter->head.data, &blocks_l[i]); + /* if we were not modifying the loops later we would do... */ + // blocks[i] = l_iter->head.data; + + blocks_v[i] = NULL; + CustomData_bmesh_copy_data(&bm->vdata, &bm->vdata, l_iter->v->head.data, &blocks_v[i]); + + /* use later for index lookups */ + BM_elem_index_set(l_iter, i); /* set_dirty */ + } while ((void)i++, (l_iter = l_iter->next) != l_first); + bm->elem_index_dirty |= BM_LOOP; } static void bm_interp_face_free(InterpFace *iface, BMesh *bm) { - void **blocks_l = iface->blocks_l; - void **blocks_v = iface->blocks_v; - int i; - - for (i = 0; i < iface->f->len; i++) { - CustomData_bmesh_free_block(&bm->ldata, &blocks_l[i]); - CustomData_bmesh_free_block(&bm->vdata, &blocks_v[i]); - } + void **blocks_l = iface->blocks_l; + void **blocks_v = iface->blocks_v; + int i; + + for (i = 0; i < iface->f->len; i++) { + CustomData_bmesh_free_block(&bm->ldata, &blocks_l[i]); + CustomData_bmesh_free_block(&bm->vdata, &blocks_v[i]); + } } #ifdef USE_LOOP_CUSTOMDATA_MERGE @@ -107,300 +109,294 @@ static void bm_interp_face_free(InterpFace *iface, BMesh *bm) * This function merges loop customdata (UV's) * where interpolating the values across the face causes values to diverge. */ -static void bm_loop_customdata_merge( - BMesh *bm, - BMEdge *e_connect, - BMLoop *l_a_outer, BMLoop *l_b_outer, - BMLoop *l_a_inner, BMLoop *l_b_inner) +static void bm_loop_customdata_merge(BMesh *bm, + BMEdge *e_connect, + BMLoop *l_a_outer, + BMLoop *l_b_outer, + BMLoop *l_a_inner, + BMLoop *l_b_inner) { - /** - * Check for diverged values at the vert shared by - * \a l_a_inner & \a l_b_inner. - * - * <pre> - * -----------------------+ - * l_a_outer--> /|<--l_b_outer - * / | - * (face a) / | - * / <--e_connect - * / | - * e_a l_a_inner--> / <--l_b_inner - * -----------------+ | - * /| | - * l_a/b_inner_inset| (face b) - * / | | - * / |e_b | - * (inset face(s)) | | - * / | | - * </pre> - */ - - const bool is_flip = (l_a_inner->next == l_a_outer); - BMLoop *l_a_inner_inset, *l_b_inner_inset; - BMEdge *e_a, *e_b; - int layer_n; - - /* paranoid sanity checks */ - BLI_assert(l_a_outer->v == l_b_outer->v); - BLI_assert(l_a_inner->v == l_b_inner->v); - - BLI_assert(l_b_inner->f != l_a_inner->f); - - BLI_assert(l_a_outer->f == l_a_inner->f); - BLI_assert(l_b_outer->f == l_b_inner->f); - - (void) e_connect; - BLI_assert(BM_edge_in_face(e_connect, l_a_inner->f)); - BLI_assert(BM_edge_in_face(e_connect, l_b_inner->f)); - - if (is_flip) { - e_a = l_a_inner->prev->e; - e_b = l_b_inner->e; - } - else { - e_a = l_a_inner->e; - e_b = l_b_inner->prev->e; - } - - l_a_inner_inset = BM_edge_other_loop(e_a, l_a_inner); - l_b_inner_inset = BM_edge_other_loop(e_b, l_b_inner); - BLI_assert(l_a_inner_inset->v == l_b_inner_inset->v); - - /* check if there is no chance of diversion */ - if (l_a_inner_inset->f == l_b_inner_inset->f) { - return; - } - - for (layer_n = 0; layer_n < bm->ldata.totlayer; layer_n++) { - const int type = bm->ldata.layers[layer_n].type; - const int offset = bm->ldata.layers[layer_n].offset; - if (!CustomData_layer_has_math(&bm->ldata, layer_n)) { - continue; - } - - /* check we begin with merged data */ - if ((CustomData_data_equals( - type, - BM_ELEM_CD_GET_VOID_P(l_a_outer, offset), - BM_ELEM_CD_GET_VOID_P(l_b_outer, offset)) == true) - - /* epsilon for comparing UV's is too big, gives noticable problems */ -#if 0 - && - /* check if the data ends up diverged */ - (CustomData_data_equals( - type, - BM_ELEM_CD_GET_VOID_P(l_a_inner, offset), - BM_ELEM_CD_GET_VOID_P(l_b_inner, offset)) == false) -#endif - ) - { - /* no need to allocate a temp block: - * a = (a + b); - * a *= 0.5f; - * b = a; - */ - const void *data_src; - - CustomData_data_mix_value( - type, - BM_ELEM_CD_GET_VOID_P(l_a_inner_inset, offset), - BM_ELEM_CD_GET_VOID_P(l_b_inner_inset, offset), - CDT_MIX_MIX, 0.5f); - CustomData_data_copy_value( - type, - BM_ELEM_CD_GET_VOID_P(l_a_inner_inset, offset), - BM_ELEM_CD_GET_VOID_P(l_b_inner_inset, offset)); - - /* use this as a reference (could be 'l_b_inner_inset' too) */ - data_src = BM_ELEM_CD_GET_VOID_P(l_a_inner_inset, offset); - - /* check if the 2 faces share an edge */ - if (is_flip ? - (l_b_inner_inset->e == l_a_inner_inset->prev->e) : - (l_a_inner_inset->e == l_b_inner_inset->prev->e)) - { - /* simple case, we have all loops already */ - } - else { - /* compare with (l_a_inner / l_b_inner) and assign the blended value if they match */ - BMIter iter; - BMLoop *l_iter; - const void *data_cmp_a = BM_ELEM_CD_GET_VOID_P(l_b_inner, offset); - const void *data_cmp_b = BM_ELEM_CD_GET_VOID_P(l_a_inner, offset); - BM_ITER_ELEM (l_iter, &iter, l_a_inner_inset->v, BM_LOOPS_OF_VERT) { - if (BM_elem_flag_test(l_iter->f, BM_ELEM_TAG)) { - if (!ELEM(l_iter, l_a_inner, l_b_inner, l_a_inner_inset, l_b_inner_inset)) { - void *data_dst = BM_ELEM_CD_GET_VOID_P(l_iter, offset); - - if (CustomData_data_equals(type, data_dst, data_cmp_a) || - CustomData_data_equals(type, data_dst, data_cmp_b)) - { - CustomData_data_copy_value(type, data_src, data_dst); - } - } - } - } - } - - CustomData_data_copy_value(type, data_src, BM_ELEM_CD_GET_VOID_P(l_b_inner, offset)); - CustomData_data_copy_value(type, data_src, BM_ELEM_CD_GET_VOID_P(l_a_inner, offset)); - } - } + /** + * Check for diverged values at the vert shared by + * \a l_a_inner & \a l_b_inner. + * + * <pre> + * -----------------------+ + * l_a_outer--> /|<--l_b_outer + * / | + * (face a) / | + * / <--e_connect + * / | + * e_a l_a_inner--> / <--l_b_inner + * -----------------+ | + * /| | + * l_a/b_inner_inset| (face b) + * / | | + * / |e_b | + * (inset face(s)) | | + * / | | + * </pre> + */ + + const bool is_flip = (l_a_inner->next == l_a_outer); + BMLoop *l_a_inner_inset, *l_b_inner_inset; + BMEdge *e_a, *e_b; + int layer_n; + + /* paranoid sanity checks */ + BLI_assert(l_a_outer->v == l_b_outer->v); + BLI_assert(l_a_inner->v == l_b_inner->v); + + BLI_assert(l_b_inner->f != l_a_inner->f); + + BLI_assert(l_a_outer->f == l_a_inner->f); + BLI_assert(l_b_outer->f == l_b_inner->f); + + (void)e_connect; + BLI_assert(BM_edge_in_face(e_connect, l_a_inner->f)); + BLI_assert(BM_edge_in_face(e_connect, l_b_inner->f)); + + if (is_flip) { + e_a = l_a_inner->prev->e; + e_b = l_b_inner->e; + } + else { + e_a = l_a_inner->e; + e_b = l_b_inner->prev->e; + } + + l_a_inner_inset = BM_edge_other_loop(e_a, l_a_inner); + l_b_inner_inset = BM_edge_other_loop(e_b, l_b_inner); + BLI_assert(l_a_inner_inset->v == l_b_inner_inset->v); + + /* check if there is no chance of diversion */ + if (l_a_inner_inset->f == l_b_inner_inset->f) { + return; + } + + for (layer_n = 0; layer_n < bm->ldata.totlayer; layer_n++) { + const int type = bm->ldata.layers[layer_n].type; + const int offset = bm->ldata.layers[layer_n].offset; + if (!CustomData_layer_has_math(&bm->ldata, layer_n)) { + continue; + } + + /* check we begin with merged data */ + if ((CustomData_data_equals(type, + BM_ELEM_CD_GET_VOID_P(l_a_outer, offset), + BM_ELEM_CD_GET_VOID_P(l_b_outer, offset)) == true) + + /* epsilon for comparing UV's is too big, gives noticable problems */ +# if 0 + && + /* check if the data ends up diverged */ + (CustomData_data_equals( + type, + BM_ELEM_CD_GET_VOID_P(l_a_inner, offset), + BM_ELEM_CD_GET_VOID_P(l_b_inner, offset)) == false) +# endif + ) { + /* no need to allocate a temp block: + * a = (a + b); + * a *= 0.5f; + * b = a; + */ + const void *data_src; + + CustomData_data_mix_value(type, + BM_ELEM_CD_GET_VOID_P(l_a_inner_inset, offset), + BM_ELEM_CD_GET_VOID_P(l_b_inner_inset, offset), + CDT_MIX_MIX, + 0.5f); + CustomData_data_copy_value(type, + BM_ELEM_CD_GET_VOID_P(l_a_inner_inset, offset), + BM_ELEM_CD_GET_VOID_P(l_b_inner_inset, offset)); + + /* use this as a reference (could be 'l_b_inner_inset' too) */ + data_src = BM_ELEM_CD_GET_VOID_P(l_a_inner_inset, offset); + + /* check if the 2 faces share an edge */ + if (is_flip ? (l_b_inner_inset->e == l_a_inner_inset->prev->e) : + (l_a_inner_inset->e == l_b_inner_inset->prev->e)) { + /* simple case, we have all loops already */ + } + else { + /* compare with (l_a_inner / l_b_inner) and assign the blended value if they match */ + BMIter iter; + BMLoop *l_iter; + const void *data_cmp_a = BM_ELEM_CD_GET_VOID_P(l_b_inner, offset); + const void *data_cmp_b = BM_ELEM_CD_GET_VOID_P(l_a_inner, offset); + BM_ITER_ELEM (l_iter, &iter, l_a_inner_inset->v, BM_LOOPS_OF_VERT) { + if (BM_elem_flag_test(l_iter->f, BM_ELEM_TAG)) { + if (!ELEM(l_iter, l_a_inner, l_b_inner, l_a_inner_inset, l_b_inner_inset)) { + void *data_dst = BM_ELEM_CD_GET_VOID_P(l_iter, offset); + + if (CustomData_data_equals(type, data_dst, data_cmp_a) || + CustomData_data_equals(type, data_dst, data_cmp_b)) { + CustomData_data_copy_value(type, data_src, data_dst); + } + } + } + } + } + + CustomData_data_copy_value(type, data_src, BM_ELEM_CD_GET_VOID_P(l_b_inner, offset)); + CustomData_data_copy_value(type, data_src, BM_ELEM_CD_GET_VOID_P(l_a_inner, offset)); + } + } } -#endif /* USE_LOOP_CUSTOMDATA_MERGE */ - +#endif /* USE_LOOP_CUSTOMDATA_MERGE */ /* -------------------------------------------------------------------- */ /* Inset Individual */ -static void bmo_face_inset_individual( - BMesh *bm, BMFace *f, MemArena *interp_arena, - const float thickness, const float depth, - const bool use_even_offset, const bool use_relative_offset, const bool use_interpolate) +static void bmo_face_inset_individual(BMesh *bm, + BMFace *f, + MemArena *interp_arena, + const float thickness, + const float depth, + const bool use_even_offset, + const bool use_relative_offset, + const bool use_interpolate) { - InterpFace *iface = NULL; - - /* stores verts split away from the face (aligned with face verts) */ - BMVert **verts = BLI_array_alloca(verts, f->len); - /* store edge normals (aligned with face-loop-edges) */ - float (*edge_nors)[3] = BLI_array_alloca(edge_nors, f->len); - float (*coords)[3] = BLI_array_alloca(coords, f->len); - - BMLoop *l_iter, *l_first; - BMLoop *l_other; - uint i; - float e_length_prev; - - l_first = BM_FACE_FIRST_LOOP(f); - - /* split off all loops */ - l_iter = l_first; - i = 0; - do { - BMVert *v_other = l_iter->v; - BMVert *v_sep = BM_face_loop_separate(bm, l_iter); - if (v_sep == v_other) { - v_other = BM_vert_create(bm, l_iter->v->co, l_iter->v, BM_CREATE_NOP); - } - verts[i] = v_other; - - /* unrelated to splitting, but calc here */ - BM_edge_calc_face_tangent(l_iter->e, l_iter, edge_nors[i]); - } while ((void)i++, ((l_iter = l_iter->next) != l_first)); - - - /* build rim faces */ - l_iter = l_first; - i = 0; - do { - BMFace *f_new_outer; - BMVert *v_other = verts[i]; - BMVert *v_other_next = verts[(i + 1) % f->len]; - - BMEdge *e_other = BM_edge_create(bm, v_other, v_other_next, l_iter->e, BM_CREATE_NO_DOUBLE); - (void)e_other; - - f_new_outer = BM_face_create_quad_tri(bm, - v_other, - v_other_next, - l_iter->next->v, - l_iter->v, - f, BM_CREATE_NOP); - BMO_face_flag_enable(bm, f_new_outer, ELE_NEW); - - /* copy loop data */ - l_other = l_iter->radial_next; - BM_elem_attrs_copy(bm, bm, l_iter->next, l_other->prev); - BM_elem_attrs_copy(bm, bm, l_iter, l_other->next->next); - - if (use_interpolate == false) { - BM_elem_attrs_copy(bm, bm, l_iter->next, l_other); - BM_elem_attrs_copy(bm, bm, l_iter, l_other->next); - } - } while ((void)i++, ((l_iter = l_iter->next) != l_first)); - - /* hold interpolation values */ - if (use_interpolate) { - iface = BLI_memarena_alloc(interp_arena, sizeof(*iface)); - bm_interp_face_store(iface, bm, f, interp_arena); - } - - /* Calculate translation vector for new */ - l_iter = l_first; - i = 0; - - if (depth != 0.0f) { - e_length_prev = BM_edge_calc_length(l_iter->prev->e); - } - - do { - const float *eno_prev = edge_nors[(i ? i : f->len) - 1]; - const float *eno_next = edge_nors[i]; - float tvec[3]; - float v_new_co[3]; - - add_v3_v3v3(tvec, eno_prev, eno_next); - normalize_v3(tvec); - - copy_v3_v3(v_new_co, l_iter->v->co); - - if (use_even_offset) { - mul_v3_fl(tvec, shell_v3v3_mid_normalized_to_dist(eno_prev, eno_next)); - } - - /* Modify vertices and their normals */ - if (use_relative_offset) { - mul_v3_fl(tvec, (BM_edge_calc_length(l_iter->e) + BM_edge_calc_length(l_iter->prev->e)) / 2.0f); - } - - madd_v3_v3fl(v_new_co, tvec, thickness); - - /* Set normal, add depth and write new vertex position*/ - copy_v3_v3(l_iter->v->no, f->no); - - if (depth != 0.0f) { - const float e_length = BM_edge_calc_length(l_iter->e); - const float fac = depth * (use_relative_offset ? ((e_length_prev + e_length) * 0.5f) : 1.0f); - e_length_prev = e_length; - - madd_v3_v3fl(v_new_co, f->no, fac); - } - - - - copy_v3_v3(coords[i], v_new_co); - } while ((void)i++, ((l_iter = l_iter->next) != l_first)); - - /* update the coords */ - l_iter = l_first; - i = 0; - do { - copy_v3_v3(l_iter->v->co, coords[i]); - } while ((void)i++, ((l_iter = l_iter->next) != l_first)); - - - if (use_interpolate) { - BM_face_interp_from_face_ex( - bm, iface->f, iface->f, true, - (const void **)iface->blocks_l, (const void **)iface->blocks_v, - iface->cos_2d, iface->axis_mat); - - /* build rim faces */ - l_iter = l_first; - do { - /* copy loop data */ - l_other = l_iter->radial_next; - - BM_elem_attrs_copy(bm, bm, l_iter->next, l_other); - BM_elem_attrs_copy(bm, bm, l_iter, l_other->next); - } while ((l_iter = l_iter->next) != l_first); - - bm_interp_face_free(iface, bm); - } + InterpFace *iface = NULL; + + /* stores verts split away from the face (aligned with face verts) */ + BMVert **verts = BLI_array_alloca(verts, f->len); + /* store edge normals (aligned with face-loop-edges) */ + float(*edge_nors)[3] = BLI_array_alloca(edge_nors, f->len); + float(*coords)[3] = BLI_array_alloca(coords, f->len); + + BMLoop *l_iter, *l_first; + BMLoop *l_other; + uint i; + float e_length_prev; + + l_first = BM_FACE_FIRST_LOOP(f); + + /* split off all loops */ + l_iter = l_first; + i = 0; + do { + BMVert *v_other = l_iter->v; + BMVert *v_sep = BM_face_loop_separate(bm, l_iter); + if (v_sep == v_other) { + v_other = BM_vert_create(bm, l_iter->v->co, l_iter->v, BM_CREATE_NOP); + } + verts[i] = v_other; + + /* unrelated to splitting, but calc here */ + BM_edge_calc_face_tangent(l_iter->e, l_iter, edge_nors[i]); + } while ((void)i++, ((l_iter = l_iter->next) != l_first)); + + /* build rim faces */ + l_iter = l_first; + i = 0; + do { + BMFace *f_new_outer; + BMVert *v_other = verts[i]; + BMVert *v_other_next = verts[(i + 1) % f->len]; + + BMEdge *e_other = BM_edge_create(bm, v_other, v_other_next, l_iter->e, BM_CREATE_NO_DOUBLE); + (void)e_other; + + f_new_outer = BM_face_create_quad_tri( + bm, v_other, v_other_next, l_iter->next->v, l_iter->v, f, BM_CREATE_NOP); + BMO_face_flag_enable(bm, f_new_outer, ELE_NEW); + + /* copy loop data */ + l_other = l_iter->radial_next; + BM_elem_attrs_copy(bm, bm, l_iter->next, l_other->prev); + BM_elem_attrs_copy(bm, bm, l_iter, l_other->next->next); + + if (use_interpolate == false) { + BM_elem_attrs_copy(bm, bm, l_iter->next, l_other); + BM_elem_attrs_copy(bm, bm, l_iter, l_other->next); + } + } while ((void)i++, ((l_iter = l_iter->next) != l_first)); + + /* hold interpolation values */ + if (use_interpolate) { + iface = BLI_memarena_alloc(interp_arena, sizeof(*iface)); + bm_interp_face_store(iface, bm, f, interp_arena); + } + + /* Calculate translation vector for new */ + l_iter = l_first; + i = 0; + + if (depth != 0.0f) { + e_length_prev = BM_edge_calc_length(l_iter->prev->e); + } + + do { + const float *eno_prev = edge_nors[(i ? i : f->len) - 1]; + const float *eno_next = edge_nors[i]; + float tvec[3]; + float v_new_co[3]; + + add_v3_v3v3(tvec, eno_prev, eno_next); + normalize_v3(tvec); + + copy_v3_v3(v_new_co, l_iter->v->co); + + if (use_even_offset) { + mul_v3_fl(tvec, shell_v3v3_mid_normalized_to_dist(eno_prev, eno_next)); + } + + /* Modify vertices and their normals */ + if (use_relative_offset) { + mul_v3_fl(tvec, + (BM_edge_calc_length(l_iter->e) + BM_edge_calc_length(l_iter->prev->e)) / 2.0f); + } + + madd_v3_v3fl(v_new_co, tvec, thickness); + + /* Set normal, add depth and write new vertex position*/ + copy_v3_v3(l_iter->v->no, f->no); + + if (depth != 0.0f) { + const float e_length = BM_edge_calc_length(l_iter->e); + const float fac = depth * (use_relative_offset ? ((e_length_prev + e_length) * 0.5f) : 1.0f); + e_length_prev = e_length; + + madd_v3_v3fl(v_new_co, f->no, fac); + } + + copy_v3_v3(coords[i], v_new_co); + } while ((void)i++, ((l_iter = l_iter->next) != l_first)); + + /* update the coords */ + l_iter = l_first; + i = 0; + do { + copy_v3_v3(l_iter->v->co, coords[i]); + } while ((void)i++, ((l_iter = l_iter->next) != l_first)); + + if (use_interpolate) { + BM_face_interp_from_face_ex(bm, + iface->f, + iface->f, + true, + (const void **)iface->blocks_l, + (const void **)iface->blocks_v, + iface->cos_2d, + iface->axis_mat); + + /* build rim faces */ + l_iter = l_first; + do { + /* copy loop data */ + l_other = l_iter->radial_next; + + BM_elem_attrs_copy(bm, bm, l_iter->next, l_other); + BM_elem_attrs_copy(bm, bm, l_iter, l_other->next); + } while ((l_iter = l_iter->next) != l_first); + + bm_interp_face_free(iface, bm); + } } - /** * Individual Face Inset. * Find all tagged faces (f), duplicate edges around faces, inset verts of @@ -409,56 +405,58 @@ static void bmo_face_inset_individual( */ void bmo_inset_individual_exec(BMesh *bm, BMOperator *op) { - BMFace *f; - - BMOIter oiter; - MemArena *interp_arena = NULL; - - const float thickness = BMO_slot_float_get(op->slots_in, "thickness"); - const float depth = BMO_slot_float_get(op->slots_in, "depth"); - const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset"); - const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset"); - const bool use_interpolate = BMO_slot_bool_get(op->slots_in, "use_interpolate"); - - /* Only tag faces in slot */ - BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); - - BMO_slot_buffer_hflag_enable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false); - - if (use_interpolate) { - interp_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); - } - - BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) { - bmo_face_inset_individual( - bm, f, interp_arena, - thickness, depth, - use_even_offset, use_relative_offset, use_interpolate); - - if (use_interpolate) { - BLI_memarena_clear(interp_arena); - } - } - - /* we could flag new edges/verts too, is it useful? */ - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, ELE_NEW); - - if (use_interpolate) { - BLI_memarena_free(interp_arena); - } + BMFace *f; + + BMOIter oiter; + MemArena *interp_arena = NULL; + + const float thickness = BMO_slot_float_get(op->slots_in, "thickness"); + const float depth = BMO_slot_float_get(op->slots_in, "depth"); + const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset"); + const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset"); + const bool use_interpolate = BMO_slot_bool_get(op->slots_in, "use_interpolate"); + + /* Only tag faces in slot */ + BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); + + BMO_slot_buffer_hflag_enable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false); + + if (use_interpolate) { + interp_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + } + + BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) { + bmo_face_inset_individual(bm, + f, + interp_arena, + thickness, + depth, + use_even_offset, + use_relative_offset, + use_interpolate); + + if (use_interpolate) { + BLI_memarena_clear(interp_arena); + } + } + + /* we could flag new edges/verts too, is it useful? */ + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, ELE_NEW); + + if (use_interpolate) { + BLI_memarena_free(interp_arena); + } } - - /* -------------------------------------------------------------------- */ /* Inset Region */ typedef struct SplitEdgeInfo { - float no[3]; - float length; - BMEdge *e_old; - BMEdge *e_new; - BMLoop *l; + float no[3]; + float length; + BMEdge *e_old; + BMEdge *e_new; + BMLoop *l; } SplitEdgeInfo; /** @@ -471,53 +469,52 @@ typedef struct SplitEdgeInfo { */ static BMLoop *bm_edge_is_mixed_face_tag(BMLoop *l) { - if (LIKELY(l != NULL)) { - int tot_tag = 0; - int tot_untag = 0; - BMLoop *l_iter; - BMLoop *l_tag = NULL; - l_iter = l; - do { - if (BM_elem_flag_test(l_iter->f, BM_ELEM_TAG)) { - /* more than one tagged face - bail out early! */ - if (tot_tag == 1) { - return NULL; - } - l_tag = l_iter; - tot_tag++; - } - else { - tot_untag++; - } - - } while ((l_iter = l_iter->radial_next) != l); - - return ((tot_tag == 1) && (tot_untag >= 1)) ? l_tag : NULL; - } - else { - return NULL; - } + if (LIKELY(l != NULL)) { + int tot_tag = 0; + int tot_untag = 0; + BMLoop *l_iter; + BMLoop *l_tag = NULL; + l_iter = l; + do { + if (BM_elem_flag_test(l_iter->f, BM_ELEM_TAG)) { + /* more than one tagged face - bail out early! */ + if (tot_tag == 1) { + return NULL; + } + l_tag = l_iter; + tot_tag++; + } + else { + tot_untag++; + } + + } while ((l_iter = l_iter->radial_next) != l); + + return ((tot_tag == 1) && (tot_untag >= 1)) ? l_tag : NULL; + } + else { + return NULL; + } } static float bm_edge_info_average_length(BMVert *v, SplitEdgeInfo *edge_info) { - BMIter iter; - BMEdge *e; - - float len = 0.0f; - int tot = 0; - - - BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { - const int i = BM_elem_index_get(e); - if (i != -1) { - len += edge_info[i].length; - tot++; - } - } - - BLI_assert(tot != 0); - return len / (float)tot; + BMIter iter; + BMEdge *e; + + float len = 0.0f; + int tot = 0; + + BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { + const int i = BM_elem_index_get(e); + if (i != -1) { + len += edge_info[i].length; + tot++; + } + } + + BLI_assert(tot != 0); + return len / (float)tot; } /** @@ -532,683 +529,697 @@ static float bm_edge_info_average_length(BMVert *v, SplitEdgeInfo *edge_info) void bmo_inset_region_exec(BMesh *bm, BMOperator *op) { - const bool use_outset = BMO_slot_bool_get(op->slots_in, "use_outset"); - const bool use_boundary = BMO_slot_bool_get(op->slots_in, "use_boundary") && (use_outset == false); - const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset"); - const bool use_even_boundary = use_even_offset; /* could make own option */ - const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset"); - const bool use_edge_rail = BMO_slot_bool_get(op->slots_in, "use_edge_rail"); - const bool use_interpolate = BMO_slot_bool_get(op->slots_in, "use_interpolate"); - const float thickness = BMO_slot_float_get(op->slots_in, "thickness"); - const float depth = BMO_slot_float_get(op->slots_in, "depth"); + const bool use_outset = BMO_slot_bool_get(op->slots_in, "use_outset"); + const bool use_boundary = BMO_slot_bool_get(op->slots_in, "use_boundary") && + (use_outset == false); + const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset"); + const bool use_even_boundary = use_even_offset; /* could make own option */ + const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset"); + const bool use_edge_rail = BMO_slot_bool_get(op->slots_in, "use_edge_rail"); + const bool use_interpolate = BMO_slot_bool_get(op->slots_in, "use_interpolate"); + const float thickness = BMO_slot_float_get(op->slots_in, "thickness"); + const float depth = BMO_slot_float_get(op->slots_in, "depth"); #ifdef USE_LOOP_CUSTOMDATA_MERGE - const bool has_math_ldata = (use_interpolate && CustomData_has_math(&bm->ldata)); + const bool has_math_ldata = (use_interpolate && CustomData_has_math(&bm->ldata)); #endif - int edge_info_len = 0; - - BMIter iter; - SplitEdgeInfo *edge_info; - SplitEdgeInfo *es; - - /* Interpolation Vars */ - /* an array alligned with faces but only fill items which are used. */ - InterpFace **iface_array = NULL; - int iface_array_len; - MemArena *interp_arena = NULL; - - /* BMVert original location storage */ - const bool use_vert_coords_orig = use_edge_rail; - MemArena *vert_coords_orig = NULL; - GHash *vert_coords = NULL; - - BMVert *v; - BMEdge *e; - BMFace *f; - int i, k; - - if (use_interpolate) { - interp_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); - /* warning, we could be more clever here and not over alloc */ - iface_array = MEM_callocN(sizeof(*iface_array) * bm->totface, __func__); - iface_array_len = bm->totface; - } - - if (use_outset == false) { - BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); - BMO_slot_buffer_hflag_enable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false); - } - else { - BM_mesh_elem_hflag_enable_all(bm, BM_FACE, BM_ELEM_TAG, false); - BMO_slot_buffer_hflag_disable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false); - BMO_slot_buffer_hflag_disable(bm, op->slots_in, "faces_exclude", BM_FACE, BM_ELEM_TAG, false); - } - - /* first count all inset edges we will split */ - /* fill in array and initialize tagging */ - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - if ( - /* tag if boundary is enabled */ - (use_boundary && BM_edge_is_boundary(e) && BM_elem_flag_test(e->l->f, BM_ELEM_TAG)) || - - /* tag if edge is an interior edge inbetween a tagged and untagged face */ - (bm_edge_is_mixed_face_tag(e->l))) - { - /* tag */ - BM_elem_flag_enable(e->v1, BM_ELEM_TAG); - BM_elem_flag_enable(e->v2, BM_ELEM_TAG); - BM_elem_flag_enable(e, BM_ELEM_TAG); - - BM_elem_index_set(e, edge_info_len); /* set_dirty! */ - edge_info_len++; - } - else { - BM_elem_flag_disable(e->v1, BM_ELEM_TAG); - BM_elem_flag_disable(e->v2, BM_ELEM_TAG); - BM_elem_flag_disable(e, BM_ELEM_TAG); - - BM_elem_index_set(e, -1); /* set_dirty! */ - } - } - bm->elem_index_dirty |= BM_EDGE; - - edge_info = MEM_mallocN(edge_info_len * sizeof(SplitEdgeInfo), __func__); - - /* fill in array and initialize tagging */ - es = edge_info; - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - i = BM_elem_index_get(e); - if (i != -1) { - /* calc edge-split info */ - es->length = BM_edge_calc_length(e); - es->e_old = e; - es++; - /* initialize no and e_new after */ - } - } - - - if (use_vert_coords_orig) { - vert_coords_orig = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); - vert_coords = BLI_ghash_ptr_new(__func__); - } - - /* util macros */ -#define VERT_ORIG_STORE(_v) { \ - float *_co = BLI_memarena_alloc(vert_coords_orig, sizeof(float[3])); \ - copy_v3_v3(_co, (_v)->co); \ - BLI_ghash_insert(vert_coords, _v, _co); \ - } (void)0 -#define VERT_ORIG_GET(_v) \ - (const float *)BLI_ghash_lookup_default(vert_coords, (_v), (_v)->co) - /* memory for the coords isn't given back to the arena, - * acceptable in this case since it runs a fixed number of times. */ -#define VERT_ORIG_REMOVE(_v) \ - BLI_ghash_remove(vert_coords, (_v), NULL, NULL) - - - for (i = 0, es = edge_info; i < edge_info_len; i++, es++) { - if ((es->l = bm_edge_is_mixed_face_tag(es->e_old->l))) { - /* do nothing */ - } - else { - es->l = es->e_old->l; /* must be a boundary */ - } - - /* run the separate arg */ - if (!BM_edge_is_boundary(es->e_old)) { - bmesh_kernel_edge_separate(bm, es->e_old, es->l, false); - } - - /* calc edge-split info */ - es->e_new = es->l->e; - BM_edge_calc_face_tangent(es->e_new, es->l, es->no); - - if (es->e_new == es->e_old) { /* happens on boundary edges */ - /* take care here, we're creating this double edge which _must_ have its verts replaced later on */ - es->e_old = BM_edge_create(bm, es->e_new->v1, es->e_new->v2, es->e_new, BM_CREATE_NOP); - } - - /* store index back to original in 'edge_info' */ - BM_elem_index_set(es->e_new, i); - BM_elem_flag_enable(es->e_new, BM_ELEM_TAG); - - /* important to tag again here */ - BM_elem_flag_enable(es->e_new->v1, BM_ELEM_TAG); - BM_elem_flag_enable(es->e_new->v2, BM_ELEM_TAG); - - - /* initialize interpolation vars */ - /* this could go in its own loop, - * only use the 'es->l->f' so we don't store loops for faces which have no mixed selection - * - * note: faces on the other side of the inset will be interpolated too since this is hard to - * detect, just allow it even though it will cause some redundant interpolation */ - if (use_interpolate) { - BMIter viter; - BM_ITER_ELEM (v, &viter, es->l->e, BM_VERTS_OF_EDGE) { - BMIter fiter; - BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) { - const int j = BM_elem_index_get(f); - if (iface_array[j] == NULL) { - InterpFace *iface = BLI_memarena_alloc(interp_arena, sizeof(*iface)); - bm_interp_face_store(iface, bm, f, interp_arena); - iface_array[j] = iface; - } - } - } - } - /* done interpolation */ - } - - /* show edge normals for debugging */ + int edge_info_len = 0; + + BMIter iter; + SplitEdgeInfo *edge_info; + SplitEdgeInfo *es; + + /* Interpolation Vars */ + /* an array alligned with faces but only fill items which are used. */ + InterpFace **iface_array = NULL; + int iface_array_len; + MemArena *interp_arena = NULL; + + /* BMVert original location storage */ + const bool use_vert_coords_orig = use_edge_rail; + MemArena *vert_coords_orig = NULL; + GHash *vert_coords = NULL; + + BMVert *v; + BMEdge *e; + BMFace *f; + int i, k; + + if (use_interpolate) { + interp_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + /* warning, we could be more clever here and not over alloc */ + iface_array = MEM_callocN(sizeof(*iface_array) * bm->totface, __func__); + iface_array_len = bm->totface; + } + + if (use_outset == false) { + BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); + BMO_slot_buffer_hflag_enable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false); + } + else { + BM_mesh_elem_hflag_enable_all(bm, BM_FACE, BM_ELEM_TAG, false); + BMO_slot_buffer_hflag_disable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false); + BMO_slot_buffer_hflag_disable(bm, op->slots_in, "faces_exclude", BM_FACE, BM_ELEM_TAG, false); + } + + /* first count all inset edges we will split */ + /* fill in array and initialize tagging */ + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if ( + /* tag if boundary is enabled */ + (use_boundary && BM_edge_is_boundary(e) && BM_elem_flag_test(e->l->f, BM_ELEM_TAG)) || + + /* tag if edge is an interior edge inbetween a tagged and untagged face */ + (bm_edge_is_mixed_face_tag(e->l))) { + /* tag */ + BM_elem_flag_enable(e->v1, BM_ELEM_TAG); + BM_elem_flag_enable(e->v2, BM_ELEM_TAG); + BM_elem_flag_enable(e, BM_ELEM_TAG); + + BM_elem_index_set(e, edge_info_len); /* set_dirty! */ + edge_info_len++; + } + else { + BM_elem_flag_disable(e->v1, BM_ELEM_TAG); + BM_elem_flag_disable(e->v2, BM_ELEM_TAG); + BM_elem_flag_disable(e, BM_ELEM_TAG); + + BM_elem_index_set(e, -1); /* set_dirty! */ + } + } + bm->elem_index_dirty |= BM_EDGE; + + edge_info = MEM_mallocN(edge_info_len * sizeof(SplitEdgeInfo), __func__); + + /* fill in array and initialize tagging */ + es = edge_info; + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + i = BM_elem_index_get(e); + if (i != -1) { + /* calc edge-split info */ + es->length = BM_edge_calc_length(e); + es->e_old = e; + es++; + /* initialize no and e_new after */ + } + } + + if (use_vert_coords_orig) { + vert_coords_orig = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + vert_coords = BLI_ghash_ptr_new(__func__); + } + + /* util macros */ +#define VERT_ORIG_STORE(_v) \ + { \ + float *_co = BLI_memarena_alloc(vert_coords_orig, sizeof(float[3])); \ + copy_v3_v3(_co, (_v)->co); \ + BLI_ghash_insert(vert_coords, _v, _co); \ + } \ + (void)0 +#define VERT_ORIG_GET(_v) (const float *)BLI_ghash_lookup_default(vert_coords, (_v), (_v)->co) + /* memory for the coords isn't given back to the arena, + * acceptable in this case since it runs a fixed number of times. */ +#define VERT_ORIG_REMOVE(_v) BLI_ghash_remove(vert_coords, (_v), NULL, NULL) + + for (i = 0, es = edge_info; i < edge_info_len; i++, es++) { + if ((es->l = bm_edge_is_mixed_face_tag(es->e_old->l))) { + /* do nothing */ + } + else { + es->l = es->e_old->l; /* must be a boundary */ + } + + /* run the separate arg */ + if (!BM_edge_is_boundary(es->e_old)) { + bmesh_kernel_edge_separate(bm, es->e_old, es->l, false); + } + + /* calc edge-split info */ + es->e_new = es->l->e; + BM_edge_calc_face_tangent(es->e_new, es->l, es->no); + + if (es->e_new == es->e_old) { /* happens on boundary edges */ + /* take care here, we're creating this double edge which _must_ have its verts replaced later on */ + es->e_old = BM_edge_create(bm, es->e_new->v1, es->e_new->v2, es->e_new, BM_CREATE_NOP); + } + + /* store index back to original in 'edge_info' */ + BM_elem_index_set(es->e_new, i); + BM_elem_flag_enable(es->e_new, BM_ELEM_TAG); + + /* important to tag again here */ + BM_elem_flag_enable(es->e_new->v1, BM_ELEM_TAG); + BM_elem_flag_enable(es->e_new->v2, BM_ELEM_TAG); + + /* initialize interpolation vars */ + /* this could go in its own loop, + * only use the 'es->l->f' so we don't store loops for faces which have no mixed selection + * + * note: faces on the other side of the inset will be interpolated too since this is hard to + * detect, just allow it even though it will cause some redundant interpolation */ + if (use_interpolate) { + BMIter viter; + BM_ITER_ELEM (v, &viter, es->l->e, BM_VERTS_OF_EDGE) { + BMIter fiter; + BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) { + const int j = BM_elem_index_get(f); + if (iface_array[j] == NULL) { + InterpFace *iface = BLI_memarena_alloc(interp_arena, sizeof(*iface)); + bm_interp_face_store(iface, bm, f, interp_arena); + iface_array[j] = iface; + } + } + } + } + /* done interpolation */ + } + + /* show edge normals for debugging */ #if 0 - for (i = 0, es = edge_info; i < edge_info_len; i++, es++) { - float tvec[3]; - BMVert *v1, *v2; + for (i = 0, es = edge_info; i < edge_info_len; i++, es++) { + float tvec[3]; + BMVert *v1, *v2; - mid_v3_v3v3(tvec, es->e_new->v1->co, es->e_new->v2->co); + mid_v3_v3v3(tvec, es->e_new->v1->co, es->e_new->v2->co); - v1 = BM_vert_create(bm, tvec, NULL, BM_CREATE_NOP); - v2 = BM_vert_create(bm, tvec, NULL, BM_CREATE_NOP); - madd_v3_v3fl(v2->co, es->no, 0.1f); - BM_edge_create(bm, v1, v2, NULL, 0); - } + v1 = BM_vert_create(bm, tvec, NULL, BM_CREATE_NOP); + v2 = BM_vert_create(bm, tvec, NULL, BM_CREATE_NOP); + madd_v3_v3fl(v2->co, es->no, 0.1f); + BM_edge_create(bm, v1, v2, NULL, 0); + } #endif - /* execute the split and position verts, it would be most obvious to loop over verts - * here but don't do this since we will be splitting them off (iterating stuff you modify is bad juju) - * instead loop over edges then their verts */ - for (i = 0, es = edge_info; i < edge_info_len; i++, es++) { - for (int j = 0; j < 2; j++) { - v = (j == 0) ? es->e_new->v1 : es->e_new->v2; - - /* end confusing part - just pretend this is a typical loop on verts */ - - /* only split of tagged verts - used by separated edges */ - - /* comment the first part because we know this verts in a tagged face */ - if (/* v->e && */BM_elem_flag_test(v, BM_ELEM_TAG)) { - BMVert **vout; - int r_vout_len; - BMVert *v_glue = NULL; - - /* disable touching twice, this _will_ happen if the flags not disabled */ - BM_elem_flag_disable(v, BM_ELEM_TAG); - - bmesh_kernel_vert_separate(bm, v, &vout, &r_vout_len, false); - v = NULL; /* don't use again */ - - /* in some cases the edge doesn't split off */ - if (r_vout_len == 1) { - if (use_vert_coords_orig) { - VERT_ORIG_STORE(vout[0]); - } - MEM_freeN(vout); - continue; - } - - for (k = 0; k < r_vout_len; k++) { - BMVert *v_split = vout[k]; /* only to avoid vout[k] all over */ - - /* need to check if this vertex is from a */ - int vert_edge_tag_tot = 0; - int vecpair[2]; - - if (use_vert_coords_orig) { - VERT_ORIG_STORE(v_split); - } - - /* find adjacent */ - BM_ITER_ELEM (e, &iter, v_split, BM_EDGES_OF_VERT) { - if (BM_elem_flag_test(e, BM_ELEM_TAG) && - e->l && BM_elem_flag_test(e->l->f, BM_ELEM_TAG)) - { - if (vert_edge_tag_tot < 2) { - vecpair[vert_edge_tag_tot] = BM_elem_index_get(e); - BLI_assert(vecpair[vert_edge_tag_tot] != -1); - } - - vert_edge_tag_tot++; - } - } - - if (vert_edge_tag_tot != 0) { - float tvec[3]; - - if (vert_edge_tag_tot >= 2) { /* 2 edge users - common case */ - /* now there are 2 cases to check for, - * - * if both edges use the same face OR both faces have the same normal, - * ...then we can calculate an edge that fits nicely between the 2 edge normals. - * - * Otherwise use the shared edge OR the corner defined by these 2 face normals, - * when both edges faces are adjacent this works best but even when this vertex - * fans out faces it should work ok. - */ - - SplitEdgeInfo *e_info_a = &edge_info[vecpair[0]]; - SplitEdgeInfo *e_info_b = &edge_info[vecpair[1]]; - - BMFace *f_a = e_info_a->l->f; - BMFace *f_b = e_info_b->l->f; - - /* set to true when we're not in-between (e_info_a->no, e_info_b->no) exactly - * in this case use a check the angle of the tvec when calculating shell thickness */ - bool is_mid = true; - - /* we use this as either the normal OR to find the right direction for the - * cross product between both face normals */ - add_v3_v3v3(tvec, e_info_a->no, e_info_b->no); - - if (use_edge_rail == false) { - /* pass */ - } - else if (f_a != f_b) { - /* these lookups are very quick */ - BMLoop *l_other_a = BM_loop_other_vert_loop(e_info_a->l, v_split); - BMLoop *l_other_b = BM_loop_other_vert_loop(e_info_b->l, v_split); - - if (l_other_a->v == l_other_b->v) { - /* both edges faces are adjacent, but we don't need to know the shared edge - * having both verts is enough. */ - const float *co_other; - - /* note that we can't use 'l_other_a->v' directly since it - * may be inset and give a feedback loop. */ - if (use_vert_coords_orig) { - co_other = VERT_ORIG_GET(l_other_a->v); - } - else { - co_other = l_other_a->v->co; - } - - sub_v3_v3v3(tvec, co_other, v_split->co); - is_mid = false; - } - - /* distable gives odd results at times, see [#39288] */ + /* execute the split and position verts, it would be most obvious to loop over verts + * here but don't do this since we will be splitting them off (iterating stuff you modify is bad juju) + * instead loop over edges then their verts */ + for (i = 0, es = edge_info; i < edge_info_len; i++, es++) { + for (int j = 0; j < 2; j++) { + v = (j == 0) ? es->e_new->v1 : es->e_new->v2; + + /* end confusing part - just pretend this is a typical loop on verts */ + + /* only split of tagged verts - used by separated edges */ + + /* comment the first part because we know this verts in a tagged face */ + if (/* v->e && */ BM_elem_flag_test(v, BM_ELEM_TAG)) { + BMVert **vout; + int r_vout_len; + BMVert *v_glue = NULL; + + /* disable touching twice, this _will_ happen if the flags not disabled */ + BM_elem_flag_disable(v, BM_ELEM_TAG); + + bmesh_kernel_vert_separate(bm, v, &vout, &r_vout_len, false); + v = NULL; /* don't use again */ + + /* in some cases the edge doesn't split off */ + if (r_vout_len == 1) { + if (use_vert_coords_orig) { + VERT_ORIG_STORE(vout[0]); + } + MEM_freeN(vout); + continue; + } + + for (k = 0; k < r_vout_len; k++) { + BMVert *v_split = vout[k]; /* only to avoid vout[k] all over */ + + /* need to check if this vertex is from a */ + int vert_edge_tag_tot = 0; + int vecpair[2]; + + if (use_vert_coords_orig) { + VERT_ORIG_STORE(v_split); + } + + /* find adjacent */ + BM_ITER_ELEM (e, &iter, v_split, BM_EDGES_OF_VERT) { + if (BM_elem_flag_test(e, BM_ELEM_TAG) && e->l && + BM_elem_flag_test(e->l->f, BM_ELEM_TAG)) { + if (vert_edge_tag_tot < 2) { + vecpair[vert_edge_tag_tot] = BM_elem_index_get(e); + BLI_assert(vecpair[vert_edge_tag_tot] != -1); + } + + vert_edge_tag_tot++; + } + } + + if (vert_edge_tag_tot != 0) { + float tvec[3]; + + if (vert_edge_tag_tot >= 2) { /* 2 edge users - common case */ + /* now there are 2 cases to check for, + * + * if both edges use the same face OR both faces have the same normal, + * ...then we can calculate an edge that fits nicely between the 2 edge normals. + * + * Otherwise use the shared edge OR the corner defined by these 2 face normals, + * when both edges faces are adjacent this works best but even when this vertex + * fans out faces it should work ok. + */ + + SplitEdgeInfo *e_info_a = &edge_info[vecpair[0]]; + SplitEdgeInfo *e_info_b = &edge_info[vecpair[1]]; + + BMFace *f_a = e_info_a->l->f; + BMFace *f_b = e_info_b->l->f; + + /* set to true when we're not in-between (e_info_a->no, e_info_b->no) exactly + * in this case use a check the angle of the tvec when calculating shell thickness */ + bool is_mid = true; + + /* we use this as either the normal OR to find the right direction for the + * cross product between both face normals */ + add_v3_v3v3(tvec, e_info_a->no, e_info_b->no); + + if (use_edge_rail == false) { + /* pass */ + } + else if (f_a != f_b) { + /* these lookups are very quick */ + BMLoop *l_other_a = BM_loop_other_vert_loop(e_info_a->l, v_split); + BMLoop *l_other_b = BM_loop_other_vert_loop(e_info_b->l, v_split); + + if (l_other_a->v == l_other_b->v) { + /* both edges faces are adjacent, but we don't need to know the shared edge + * having both verts is enough. */ + const float *co_other; + + /* note that we can't use 'l_other_a->v' directly since it + * may be inset and give a feedback loop. */ + if (use_vert_coords_orig) { + co_other = VERT_ORIG_GET(l_other_a->v); + } + else { + co_other = l_other_a->v->co; + } + + sub_v3_v3v3(tvec, co_other, v_split->co); + is_mid = false; + } + + /* distable gives odd results at times, see [#39288] */ #if 0 - else if (compare_v3v3(f_a->no, f_b->no, 0.001f) == false) { - /* epsilon increased to fix [#32329] */ - - /* faces don't touch, - * just get cross product of their normals, its *good enough* - */ - float tno[3]; - cross_v3_v3v3(tno, f_a->no, f_b->no); - if (dot_v3v3(tvec, tno) < 0.0f) { - negate_v3(tno); - } - copy_v3_v3(tvec, tno); - is_mid = false; - } + else if (compare_v3v3(f_a->no, f_b->no, 0.001f) == false) { + /* epsilon increased to fix [#32329] */ + + /* faces don't touch, + * just get cross product of their normals, its *good enough* + */ + float tno[3]; + cross_v3_v3v3(tno, f_a->no, f_b->no); + if (dot_v3v3(tvec, tno) < 0.0f) { + negate_v3(tno); + } + copy_v3_v3(tvec, tno); + is_mid = false; + } #endif - } - normalize_v3(tvec); - - /* scale by edge angle */ - if (use_even_offset) { - if (is_mid) { - mul_v3_fl(tvec, shell_v3v3_mid_normalized_to_dist(e_info_a->no, - e_info_b->no)); - } - else { - /* use the largest angle */ - mul_v3_fl(tvec, - shell_v3v3_normalized_to_dist(tvec, - len_squared_v3v3(tvec, e_info_a->no) > - len_squared_v3v3(tvec, e_info_b->no) ? - e_info_a->no : e_info_b->no)); - } - } - - /* scale relative to edge lengths */ - if (use_relative_offset) { - mul_v3_fl(tvec, (edge_info[vecpair[0]].length + edge_info[vecpair[1]].length) / 2.0f); - } - } - else if (vert_edge_tag_tot == 1) { /* 1 edge user - boundary vert, not so common */ - const float *e_no_a = edge_info[vecpair[0]].no; - - if (use_even_boundary) { - - /* This case where only one edge attached to v_split - * is used - ei - the face to inset is on a boundary. - * - * We want the inset to align flush with the - * boundary edge, not the normal of the interior - * <--- edge which would give an unsightly bump. - * --+-------------------------+---------------+-- - * |^v_other ^e_other /^v_split | - * | / | - * | / | - * | / <- tag split edge | - * | / | - * | / | - * | / | - * --+-----------------+-----------------------+-- - * | | - * | | - * - * note, the fact we are doing location comparisons on verts that are moved about - * doesn't matter because the direction will remain the same in this case. - */ - - BMEdge *e_other; - BMVert *v_other; - /* loop will always be either next of prev */ - BMLoop *l = v_split->e->l; - if (l->prev->v == v_split) { - l = l->prev; - } - else if (l->next->v == v_split) { - l = l->next; - } - else if (l->v == v_split) { - /* pass */ - } - else { - /* should never happen */ - BLI_assert(0); - } - - /* find the edge which is _not_ being split here */ - if (!BM_elem_flag_test(l->e, BM_ELEM_TAG)) { - e_other = l->e; - } - else if (!BM_elem_flag_test(l->prev->e, BM_ELEM_TAG)) { - e_other = l->prev->e; - } - else { - BLI_assert(0); - e_other = NULL; - } - - v_other = BM_edge_other_vert(e_other, v_split); - sub_v3_v3v3(tvec, v_other->co, v_split->co); - normalize_v3(tvec); - - if (use_even_offset) { - mul_v3_fl(tvec, shell_v3v3_normalized_to_dist(e_no_a, tvec)); - } - } - else { - copy_v3_v3(tvec, e_no_a); - } - - /* use_even_offset - doesn't apply here */ - - /* scale relative to edge length */ - if (use_relative_offset) { - mul_v3_fl(tvec, edge_info[vecpair[0]].length); - } - } - else { - /* should never happen */ - BLI_assert(0); - zero_v3(tvec); - } - - /* apply the offset */ - madd_v3_v3fl(v_split->co, tvec, thickness); - } - - /* this saves expensive/slow glue check for common cases */ - if (r_vout_len > 2) { - bool ok = true; - /* last step, NULL this vertex if has a tagged face */ - BM_ITER_ELEM (f, &iter, v_split, BM_FACES_OF_VERT) { - if (BM_elem_flag_test(f, BM_ELEM_TAG)) { - ok = false; - break; - } - } - - if (ok) { - if (v_glue == NULL) { - v_glue = v_split; - } - else { - if (BM_vert_splice(bm, v_glue, v_split)) { - if (use_vert_coords_orig) { - VERT_ORIG_REMOVE(v_split); - } - } - } - } - } - /* end glue */ - - } - MEM_freeN(vout); - } - } - } - - if (use_vert_coords_orig) { - BLI_memarena_free(vert_coords_orig); - BLI_ghash_free(vert_coords, NULL, NULL); - } - - if (use_interpolate) { - for (i = 0; i < iface_array_len; i++) { - if (iface_array[i]) { - InterpFace *iface = iface_array[i]; - BM_face_interp_from_face_ex( - bm, iface->f, iface->f, true, - (const void **)iface->blocks_l, (const void **)iface->blocks_v, - iface->cos_2d, iface->axis_mat); - } - } - } - - /* create faces */ - for (i = 0, es = edge_info; i < edge_info_len; i++, es++) { - BMVert *varr[4] = {NULL}; - int j; - /* get the verts in the correct order */ - BM_edge_ordered_verts_ex(es->e_new, &varr[1], &varr[0], es->l); + } + normalize_v3(tvec); + + /* scale by edge angle */ + if (use_even_offset) { + if (is_mid) { + mul_v3_fl(tvec, shell_v3v3_mid_normalized_to_dist(e_info_a->no, e_info_b->no)); + } + else { + /* use the largest angle */ + mul_v3_fl( + tvec, + shell_v3v3_normalized_to_dist(tvec, + len_squared_v3v3(tvec, e_info_a->no) > + len_squared_v3v3(tvec, e_info_b->no) ? + e_info_a->no : + e_info_b->no)); + } + } + + /* scale relative to edge lengths */ + if (use_relative_offset) { + mul_v3_fl(tvec, + (edge_info[vecpair[0]].length + edge_info[vecpair[1]].length) / 2.0f); + } + } + else if (vert_edge_tag_tot == 1) { /* 1 edge user - boundary vert, not so common */ + const float *e_no_a = edge_info[vecpair[0]].no; + + if (use_even_boundary) { + + /* This case where only one edge attached to v_split + * is used - ei - the face to inset is on a boundary. + * + * We want the inset to align flush with the + * boundary edge, not the normal of the interior + * <--- edge which would give an unsightly bump. + * --+-------------------------+---------------+-- + * |^v_other ^e_other /^v_split | + * | / | + * | / | + * | / <- tag split edge | + * | / | + * | / | + * | / | + * --+-----------------+-----------------------+-- + * | | + * | | + * + * note, the fact we are doing location comparisons on verts that are moved about + * doesn't matter because the direction will remain the same in this case. + */ + + BMEdge *e_other; + BMVert *v_other; + /* loop will always be either next of prev */ + BMLoop *l = v_split->e->l; + if (l->prev->v == v_split) { + l = l->prev; + } + else if (l->next->v == v_split) { + l = l->next; + } + else if (l->v == v_split) { + /* pass */ + } + else { + /* should never happen */ + BLI_assert(0); + } + + /* find the edge which is _not_ being split here */ + if (!BM_elem_flag_test(l->e, BM_ELEM_TAG)) { + e_other = l->e; + } + else if (!BM_elem_flag_test(l->prev->e, BM_ELEM_TAG)) { + e_other = l->prev->e; + } + else { + BLI_assert(0); + e_other = NULL; + } + + v_other = BM_edge_other_vert(e_other, v_split); + sub_v3_v3v3(tvec, v_other->co, v_split->co); + normalize_v3(tvec); + + if (use_even_offset) { + mul_v3_fl(tvec, shell_v3v3_normalized_to_dist(e_no_a, tvec)); + } + } + else { + copy_v3_v3(tvec, e_no_a); + } + + /* use_even_offset - doesn't apply here */ + + /* scale relative to edge length */ + if (use_relative_offset) { + mul_v3_fl(tvec, edge_info[vecpair[0]].length); + } + } + else { + /* should never happen */ + BLI_assert(0); + zero_v3(tvec); + } + + /* apply the offset */ + madd_v3_v3fl(v_split->co, tvec, thickness); + } + + /* this saves expensive/slow glue check for common cases */ + if (r_vout_len > 2) { + bool ok = true; + /* last step, NULL this vertex if has a tagged face */ + BM_ITER_ELEM (f, &iter, v_split, BM_FACES_OF_VERT) { + if (BM_elem_flag_test(f, BM_ELEM_TAG)) { + ok = false; + break; + } + } + + if (ok) { + if (v_glue == NULL) { + v_glue = v_split; + } + else { + if (BM_vert_splice(bm, v_glue, v_split)) { + if (use_vert_coords_orig) { + VERT_ORIG_REMOVE(v_split); + } + } + } + } + } + /* end glue */ + } + MEM_freeN(vout); + } + } + } + + if (use_vert_coords_orig) { + BLI_memarena_free(vert_coords_orig); + BLI_ghash_free(vert_coords, NULL, NULL); + } + + if (use_interpolate) { + for (i = 0; i < iface_array_len; i++) { + if (iface_array[i]) { + InterpFace *iface = iface_array[i]; + BM_face_interp_from_face_ex(bm, + iface->f, + iface->f, + true, + (const void **)iface->blocks_l, + (const void **)iface->blocks_v, + iface->cos_2d, + iface->axis_mat); + } + } + } + + /* create faces */ + for (i = 0, es = edge_info; i < edge_info_len; i++, es++) { + BMVert *varr[4] = {NULL}; + int j; + /* get the verts in the correct order */ + BM_edge_ordered_verts_ex(es->e_new, &varr[1], &varr[0], es->l); #if 0 - if (varr[0] == es->e_new->v1) { - varr[2] = es->e_old->v2; - varr[3] = es->e_old->v1; - } - else { - varr[2] = es->e_old->v1; - varr[3] = es->e_old->v2; - } - j = 4; + if (varr[0] == es->e_new->v1) { + varr[2] = es->e_old->v2; + varr[3] = es->e_old->v1; + } + else { + varr[2] = es->e_old->v1; + varr[3] = es->e_old->v2; + } + j = 4; #else - /* slightly trickier check - since we can't assume the verts are split */ - j = 2; /* 2 edges are set */ - if (varr[0] == es->e_new->v1) { - if (es->e_old->v2 != es->e_new->v2) { varr[j++] = es->e_old->v2; } - if (es->e_old->v1 != es->e_new->v1) { varr[j++] = es->e_old->v1; } - } - else { - if (es->e_old->v1 != es->e_new->v1) { varr[j++] = es->e_old->v1; } - if (es->e_old->v2 != es->e_new->v2) { varr[j++] = es->e_old->v2; } - } - - if (j == 2) { - /* can't make face! */ - continue; - } + /* slightly trickier check - since we can't assume the verts are split */ + j = 2; /* 2 edges are set */ + if (varr[0] == es->e_new->v1) { + if (es->e_old->v2 != es->e_new->v2) { + varr[j++] = es->e_old->v2; + } + if (es->e_old->v1 != es->e_new->v1) { + varr[j++] = es->e_old->v1; + } + } + else { + if (es->e_old->v1 != es->e_new->v1) { + varr[j++] = es->e_old->v1; + } + if (es->e_old->v2 != es->e_new->v2) { + varr[j++] = es->e_old->v2; + } + } + + if (j == 2) { + /* can't make face! */ + continue; + } #endif - /* no need to check doubles, we KNOW there won't be any */ - /* yes - reverse face is correct in this case */ - f = BM_face_create_verts(bm, varr, j, es->l->f, BM_CREATE_NOP, true); - BMO_face_flag_enable(bm, f, ELE_NEW); - - /* copy for loop data, otherwise UV's and vcols are no good. - * tiny speedup here we could be more clever and copy from known adjacent data - * also - we could attempt to interpolate the loop data, this would be much slower but more useful too */ + /* no need to check doubles, we KNOW there won't be any */ + /* yes - reverse face is correct in this case */ + f = BM_face_create_verts(bm, varr, j, es->l->f, BM_CREATE_NOP, true); + BMO_face_flag_enable(bm, f, ELE_NEW); + + /* copy for loop data, otherwise UV's and vcols are no good. + * tiny speedup here we could be more clever and copy from known adjacent data + * also - we could attempt to interpolate the loop data, this would be much slower but more useful too */ #if 0 - /* don't use this because face boundaries have no adjacent loops and won't be filled in. - * instead copy from the opposite side with the code below */ - BM_face_copy_shared(bm, f, NULL, NULL); + /* don't use this because face boundaries have no adjacent loops and won't be filled in. + * instead copy from the opposite side with the code below */ + BM_face_copy_shared(bm, f, NULL, NULL); #else - { - /* 2 inner loops on the edge between the new face and the original */ - BMLoop *l_a; - BMLoop *l_b; - BMLoop *l_a_other; - BMLoop *l_b_other; - - l_a = BM_FACE_FIRST_LOOP(f); - l_b = l_a->next; - - /* we know this side has a radial_next because of the order of created verts in the quad */ - l_a_other = BM_edge_other_loop(l_a->e, l_a); - l_b_other = BM_edge_other_loop(l_a->e, l_b); - BM_elem_attrs_copy(bm, bm, l_a_other, l_a); - BM_elem_attrs_copy(bm, bm, l_b_other, l_b); - - BLI_assert(l_a->f != l_a_other->f); - BLI_assert(l_b->f != l_b_other->f); - - /* step around to the opposite side of the quad - warning, this may have no other edges! */ - l_a = l_a->next->next; - l_b = l_a->next; - - /** - * Loops vars from newly created face (face_a/b) - * <pre> - * l_a->e & l_b->prev->e - * +------------------------------------+ - * |\ l_a l_b /| - * | \ l_a->prev->e l_b->e / | - * | \ l_a->prev l_b->next / | - * | +----------------------------+ | - * | |l_a_other ^ l_b_other| | - * | | l_b->next->e &... | | - * | | l_a->prev->prev->e | | - * | | (inset face) | | - * | +----------------------------+ | - * | / \ | - * | / \ | - * |/ \| - * +------------------------------------+ - * </pre> - */ - - /* swap a<->b intentionally */ - if (use_interpolate) { - InterpFace *iface = iface_array[BM_elem_index_get(es->l->f)]; - const int i_a = BM_elem_index_get(l_a_other); - const int i_b = BM_elem_index_get(l_b_other); - CustomData_bmesh_free_block_data(&bm->ldata, l_b->head.data); - CustomData_bmesh_free_block_data(&bm->ldata, l_a->head.data); - CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, iface->blocks_l[i_a], &l_b->head.data); - CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, iface->blocks_l[i_b], &l_a->head.data); - -#ifdef USE_LOOP_CUSTOMDATA_MERGE - if (has_math_ldata) { - BMEdge *e_connect; - - /* connecting edge 'a' */ - e_connect = l_a->prev->e; - if (BM_edge_is_manifold(e_connect)) { - bm_loop_customdata_merge( - bm, e_connect, - l_a, BM_edge_other_loop(e_connect, l_a), - l_a->prev, BM_edge_other_loop(e_connect, l_a->prev)); - } - - /* connecting edge 'b' */ - e_connect = l_b->e; - if (BM_edge_is_manifold(e_connect)) { - /* swap arg order to maintain winding */ - bm_loop_customdata_merge( - bm, e_connect, - l_b, BM_edge_other_loop(e_connect, l_b), - l_b->next, BM_edge_other_loop(e_connect, l_b->next)); - } - } -#endif /* USE_LOOP_CUSTOMDATA_MERGE */ - } - else { - BM_elem_attrs_copy(bm, bm, l_a_other, l_b); - BM_elem_attrs_copy(bm, bm, l_b_other, l_a); - } - } - } + { + /* 2 inner loops on the edge between the new face and the original */ + BMLoop *l_a; + BMLoop *l_b; + BMLoop *l_a_other; + BMLoop *l_b_other; + + l_a = BM_FACE_FIRST_LOOP(f); + l_b = l_a->next; + + /* we know this side has a radial_next because of the order of created verts in the quad */ + l_a_other = BM_edge_other_loop(l_a->e, l_a); + l_b_other = BM_edge_other_loop(l_a->e, l_b); + BM_elem_attrs_copy(bm, bm, l_a_other, l_a); + BM_elem_attrs_copy(bm, bm, l_b_other, l_b); + + BLI_assert(l_a->f != l_a_other->f); + BLI_assert(l_b->f != l_b_other->f); + + /* step around to the opposite side of the quad - warning, this may have no other edges! */ + l_a = l_a->next->next; + l_b = l_a->next; + + /** + * Loops vars from newly created face (face_a/b) + * <pre> + * l_a->e & l_b->prev->e + * +------------------------------------+ + * |\ l_a l_b /| + * | \ l_a->prev->e l_b->e / | + * | \ l_a->prev l_b->next / | + * | +----------------------------+ | + * | |l_a_other ^ l_b_other| | + * | | l_b->next->e &... | | + * | | l_a->prev->prev->e | | + * | | (inset face) | | + * | +----------------------------+ | + * | / \ | + * | / \ | + * |/ \| + * +------------------------------------+ + * </pre> + */ + + /* swap a<->b intentionally */ + if (use_interpolate) { + InterpFace *iface = iface_array[BM_elem_index_get(es->l->f)]; + const int i_a = BM_elem_index_get(l_a_other); + const int i_b = BM_elem_index_get(l_b_other); + CustomData_bmesh_free_block_data(&bm->ldata, l_b->head.data); + CustomData_bmesh_free_block_data(&bm->ldata, l_a->head.data); + CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, iface->blocks_l[i_a], &l_b->head.data); + CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, iface->blocks_l[i_b], &l_a->head.data); + +# ifdef USE_LOOP_CUSTOMDATA_MERGE + if (has_math_ldata) { + BMEdge *e_connect; + + /* connecting edge 'a' */ + e_connect = l_a->prev->e; + if (BM_edge_is_manifold(e_connect)) { + bm_loop_customdata_merge(bm, + e_connect, + l_a, + BM_edge_other_loop(e_connect, l_a), + l_a->prev, + BM_edge_other_loop(e_connect, l_a->prev)); + } + + /* connecting edge 'b' */ + e_connect = l_b->e; + if (BM_edge_is_manifold(e_connect)) { + /* swap arg order to maintain winding */ + bm_loop_customdata_merge(bm, + e_connect, + l_b, + BM_edge_other_loop(e_connect, l_b), + l_b->next, + BM_edge_other_loop(e_connect, l_b->next)); + } + } +# endif /* USE_LOOP_CUSTOMDATA_MERGE */ + } + else { + BM_elem_attrs_copy(bm, bm, l_a_other, l_b); + BM_elem_attrs_copy(bm, bm, l_b_other, l_a); + } + } + } #endif - if (use_interpolate) { - for (i = 0; i < iface_array_len; i++) { - if (iface_array[i]) { - bm_interp_face_free(iface_array[i], bm); - } - } - - BLI_memarena_free(interp_arena); - MEM_freeN(iface_array); - } - - /* we could flag new edges/verts too, is it useful? */ - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, ELE_NEW); - - /* cheap feature to add depth to the inset */ - if (depth != 0.0f) { - float (*varr_co)[3]; - BMOIter oiter; - - /* we need to re-calculate tagged normals, but for this purpose we can copy tagged verts from the - * faces they inset from, */ - for (i = 0, es = edge_info; i < edge_info_len; i++, es++) { - zero_v3(es->e_new->v1->no); - zero_v3(es->e_new->v2->no); - } - for (i = 0, es = edge_info; i < edge_info_len; i++, es++) { - const float *no = es->l->f->no; - add_v3_v3(es->e_new->v1->no, no); - add_v3_v3(es->e_new->v2->no, no); - } - for (i = 0, es = edge_info; i < edge_info_len; i++, es++) { - /* annoying, avoid normalizing twice */ - if (len_squared_v3(es->e_new->v1->no) != 1.0f) { - normalize_v3(es->e_new->v1->no); - } - if (len_squared_v3(es->e_new->v2->no) != 1.0f) { - normalize_v3(es->e_new->v2->no); - } - } - /* done correcting edge verts normals */ - - /* untag verts */ - BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false); - - /* tag face verts */ - BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) { - BM_ITER_ELEM (v, &iter, f, BM_VERTS_OF_FACE) { - BM_elem_flag_enable(v, BM_ELEM_TAG); - } - } - - /* do in 2 passes so moving the verts doesn't feed back into face angle checks - * which BM_vert_calc_shell_factor uses. */ - - /* over allocate */ - varr_co = MEM_callocN(sizeof(*varr_co) * bm->totvert, __func__); - - BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { - if (BM_elem_flag_test(v, BM_ELEM_TAG)) { - const float fac = (depth * - (use_relative_offset ? bm_edge_info_average_length(v, edge_info) : 1.0f) * - (use_even_boundary ? BM_vert_calc_shell_factor(v) : 1.0f)); - madd_v3_v3v3fl(varr_co[i], v->co, v->no, fac); - } - } - - BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { - if (BM_elem_flag_test(v, BM_ELEM_TAG)) { - copy_v3_v3(v->co, varr_co[i]); - } - } - MEM_freeN(varr_co); - } - - MEM_freeN(edge_info); -} + if (use_interpolate) { + for (i = 0; i < iface_array_len; i++) { + if (iface_array[i]) { + bm_interp_face_free(iface_array[i], bm); + } + } + + BLI_memarena_free(interp_arena); + MEM_freeN(iface_array); + } + + /* we could flag new edges/verts too, is it useful? */ + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, ELE_NEW); + + /* cheap feature to add depth to the inset */ + if (depth != 0.0f) { + float(*varr_co)[3]; + BMOIter oiter; + + /* we need to re-calculate tagged normals, but for this purpose we can copy tagged verts from the + * faces they inset from, */ + for (i = 0, es = edge_info; i < edge_info_len; i++, es++) { + zero_v3(es->e_new->v1->no); + zero_v3(es->e_new->v2->no); + } + for (i = 0, es = edge_info; i < edge_info_len; i++, es++) { + const float *no = es->l->f->no; + add_v3_v3(es->e_new->v1->no, no); + add_v3_v3(es->e_new->v2->no, no); + } + for (i = 0, es = edge_info; i < edge_info_len; i++, es++) { + /* annoying, avoid normalizing twice */ + if (len_squared_v3(es->e_new->v1->no) != 1.0f) { + normalize_v3(es->e_new->v1->no); + } + if (len_squared_v3(es->e_new->v2->no) != 1.0f) { + normalize_v3(es->e_new->v2->no); + } + } + /* done correcting edge verts normals */ + + /* untag verts */ + BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false); + + /* tag face verts */ + BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) { + BM_ITER_ELEM (v, &iter, f, BM_VERTS_OF_FACE) { + BM_elem_flag_enable(v, BM_ELEM_TAG); + } + } + + /* do in 2 passes so moving the verts doesn't feed back into face angle checks + * which BM_vert_calc_shell_factor uses. */ + + /* over allocate */ + varr_co = MEM_callocN(sizeof(*varr_co) * bm->totvert, __func__); + + BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { + if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + const float fac = (depth * + (use_relative_offset ? bm_edge_info_average_length(v, edge_info) : + 1.0f) * + (use_even_boundary ? BM_vert_calc_shell_factor(v) : 1.0f)); + madd_v3_v3v3fl(varr_co[i], v->co, v->no, fac); + } + } + + BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { + if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + copy_v3_v3(v->co, varr_co[i]); + } + } + MEM_freeN(varr_co); + } + + MEM_freeN(edge_info); + } diff --git a/source/blender/bmesh/operators/bmo_join_triangles.c b/source/blender/bmesh/operators/bmo_join_triangles.c index 19d01cb2e08..9734dab7ca4 100644 --- a/source/blender/bmesh/operators/bmo_join_triangles.c +++ b/source/blender/bmesh/operators/bmo_join_triangles.c @@ -37,342 +37,333 @@ #include "intern/bmesh_operators_private.h" /* own include */ /* assumes edges are validated before reaching this poin */ -static float quad_calc_error( - const float v1[3], const float v2[3], - const float v3[3], const float v4[3]) +static float quad_calc_error(const float v1[3], + const float v2[3], + const float v3[3], + const float v4[3]) { - /* gives a 'weight' to a pair of triangles that join an edge to decide how good a join they would make */ - /* Note: this is more complicated than it needs to be and should be cleaned up.. */ - float error = 0.0f; + /* gives a 'weight' to a pair of triangles that join an edge to decide how good a join they would make */ + /* Note: this is more complicated than it needs to be and should be cleaned up.. */ + float error = 0.0f; - /* Normal difference */ - { - float n1[3], n2[3]; - float angle_a, angle_b; - float diff; + /* Normal difference */ + { + float n1[3], n2[3]; + float angle_a, angle_b; + float diff; - normal_tri_v3(n1, v1, v2, v3); - normal_tri_v3(n2, v1, v3, v4); - angle_a = (compare_v3v3(n1, n2, FLT_EPSILON)) ? 0.0f : angle_normalized_v3v3(n1, n2); + normal_tri_v3(n1, v1, v2, v3); + normal_tri_v3(n2, v1, v3, v4); + angle_a = (compare_v3v3(n1, n2, FLT_EPSILON)) ? 0.0f : angle_normalized_v3v3(n1, n2); - normal_tri_v3(n1, v2, v3, v4); - normal_tri_v3(n2, v4, v1, v2); - angle_b = (compare_v3v3(n1, n2, FLT_EPSILON)) ? 0.0f : angle_normalized_v3v3(n1, n2); + normal_tri_v3(n1, v2, v3, v4); + normal_tri_v3(n2, v4, v1, v2); + angle_b = (compare_v3v3(n1, n2, FLT_EPSILON)) ? 0.0f : angle_normalized_v3v3(n1, n2); - diff = (angle_a + angle_b) / (float)(M_PI * 2); + diff = (angle_a + angle_b) / (float)(M_PI * 2); - error += diff; - } + error += diff; + } - /* Colinearity */ - { - float edge_vecs[4][3]; - float diff; + /* Colinearity */ + { + float edge_vecs[4][3]; + float diff; - sub_v3_v3v3(edge_vecs[0], v1, v2); - sub_v3_v3v3(edge_vecs[1], v2, v3); - sub_v3_v3v3(edge_vecs[2], v3, v4); - sub_v3_v3v3(edge_vecs[3], v4, v1); + sub_v3_v3v3(edge_vecs[0], v1, v2); + sub_v3_v3v3(edge_vecs[1], v2, v3); + sub_v3_v3v3(edge_vecs[2], v3, v4); + sub_v3_v3v3(edge_vecs[3], v4, v1); - normalize_v3(edge_vecs[0]); - normalize_v3(edge_vecs[1]); - normalize_v3(edge_vecs[2]); - normalize_v3(edge_vecs[3]); + normalize_v3(edge_vecs[0]); + normalize_v3(edge_vecs[1]); + normalize_v3(edge_vecs[2]); + normalize_v3(edge_vecs[3]); - /* a completely skinny face is 'pi' after halving */ - diff = (fabsf(angle_normalized_v3v3(edge_vecs[0], edge_vecs[1]) - (float)M_PI_2) + - fabsf(angle_normalized_v3v3(edge_vecs[1], edge_vecs[2]) - (float)M_PI_2) + - fabsf(angle_normalized_v3v3(edge_vecs[2], edge_vecs[3]) - (float)M_PI_2) + - fabsf(angle_normalized_v3v3(edge_vecs[3], edge_vecs[0]) - (float)M_PI_2)) / (float)(M_PI * 2); + /* a completely skinny face is 'pi' after halving */ + diff = (fabsf(angle_normalized_v3v3(edge_vecs[0], edge_vecs[1]) - (float)M_PI_2) + + fabsf(angle_normalized_v3v3(edge_vecs[1], edge_vecs[2]) - (float)M_PI_2) + + fabsf(angle_normalized_v3v3(edge_vecs[2], edge_vecs[3]) - (float)M_PI_2) + + fabsf(angle_normalized_v3v3(edge_vecs[3], edge_vecs[0]) - (float)M_PI_2)) / + (float)(M_PI * 2); - error += diff; - } + error += diff; + } - /* Concavity */ - { - float area_min, area_max, area_a, area_b; - float diff; + /* Concavity */ + { + float area_min, area_max, area_a, area_b; + float diff; - area_a = area_tri_v3(v1, v2, v3) + area_tri_v3(v1, v3, v4); - area_b = area_tri_v3(v2, v3, v4) + area_tri_v3(v4, v1, v2); + area_a = area_tri_v3(v1, v2, v3) + area_tri_v3(v1, v3, v4); + area_b = area_tri_v3(v2, v3, v4) + area_tri_v3(v4, v1, v2); - area_min = min_ff(area_a, area_b); - area_max = max_ff(area_a, area_b); + area_min = min_ff(area_a, area_b); + area_max = max_ff(area_a, area_b); - diff = area_max ? (1.0f - (area_min / area_max)) : 1.0f; + diff = area_max ? (1.0f - (area_min / area_max)) : 1.0f; - error += diff; - } + error += diff; + } - return error; + return error; } static void bm_edge_to_quad_verts(const BMEdge *e, const BMVert *r_v_quad[4]) { - BLI_assert(e->l->f->len == 3 && e->l->radial_next->f->len == 3); - BLI_assert(BM_edge_is_manifold(e)); - r_v_quad[0] = e->l->v; - r_v_quad[1] = e->l->prev->v; - r_v_quad[2] = e->l->next->v; - r_v_quad[3] = e->l->radial_next->prev->v; + BLI_assert(e->l->f->len == 3 && e->l->radial_next->f->len == 3); + BLI_assert(BM_edge_is_manifold(e)); + r_v_quad[0] = e->l->v; + r_v_quad[1] = e->l->prev->v; + r_v_quad[2] = e->l->next->v; + r_v_quad[3] = e->l->radial_next->prev->v; } /* cache customdata delimiters */ struct DelimitData_CD { - int cd_type; - int cd_size; - int cd_offset; - int cd_offset_end; + int cd_type; + int cd_size; + int cd_offset; + int cd_offset_end; }; struct DelimitData { - uint do_seam : 1; - uint do_sharp : 1; - uint do_mat : 1; - uint do_angle_face : 1; - uint do_angle_shape : 1; + uint do_seam : 1; + uint do_sharp : 1; + uint do_mat : 1; + uint do_angle_face : 1; + uint do_angle_shape : 1; - float angle_face; - float angle_face__cos; + float angle_face; + float angle_face__cos; - float angle_shape; + float angle_shape; - struct DelimitData_CD cdata[4]; - int cdata_len; + struct DelimitData_CD cdata[4]; + int cdata_len; }; -static bool bm_edge_is_contiguous_loop_cd_all( - const BMEdge *e, const struct DelimitData_CD *delimit_data) +static bool bm_edge_is_contiguous_loop_cd_all(const BMEdge *e, + const struct DelimitData_CD *delimit_data) { - int cd_offset; - for (cd_offset = delimit_data->cd_offset; - cd_offset < delimit_data->cd_offset_end; - cd_offset += delimit_data->cd_size) - { - if (BM_edge_is_contiguous_loop_cd(e, delimit_data->cd_type, cd_offset) == false) { - return false; - } - } - - return true; + int cd_offset; + for (cd_offset = delimit_data->cd_offset; cd_offset < delimit_data->cd_offset_end; + cd_offset += delimit_data->cd_size) { + if (BM_edge_is_contiguous_loop_cd(e, delimit_data->cd_type, cd_offset) == false) { + return false; + } + } + + return true; } -static bool bm_edge_delimit_cdata( - CustomData *ldata, CustomDataType type, - struct DelimitData_CD *r_delim_cd) +static bool bm_edge_delimit_cdata(CustomData *ldata, + CustomDataType type, + struct DelimitData_CD *r_delim_cd) { - const int layer_len = CustomData_number_of_layers(ldata, type); - r_delim_cd->cd_type = type; - r_delim_cd->cd_size = CustomData_sizeof(r_delim_cd->cd_type); - r_delim_cd->cd_offset = CustomData_get_n_offset(ldata, type, 0); - r_delim_cd->cd_offset_end = r_delim_cd->cd_size * layer_len; - return (r_delim_cd->cd_offset != -1); + const int layer_len = CustomData_number_of_layers(ldata, type); + r_delim_cd->cd_type = type; + r_delim_cd->cd_size = CustomData_sizeof(r_delim_cd->cd_type); + r_delim_cd->cd_offset = CustomData_get_n_offset(ldata, type, 0); + r_delim_cd->cd_offset_end = r_delim_cd->cd_size * layer_len; + return (r_delim_cd->cd_offset != -1); } -static float bm_edge_is_delimit( - const BMEdge *e, - const struct DelimitData *delimit_data) +static float bm_edge_is_delimit(const BMEdge *e, const struct DelimitData *delimit_data) { - BMFace *f_a = e->l->f, *f_b = e->l->radial_next->f; + BMFace *f_a = e->l->f, *f_b = e->l->radial_next->f; #if 0 - const bool is_contig = BM_edge_is_contiguous(e); - float angle; + const bool is_contig = BM_edge_is_contiguous(e); + float angle; #endif - if ((delimit_data->do_seam) && - (BM_elem_flag_test(e, BM_ELEM_SEAM))) - { - goto fail; - } - - if ((delimit_data->do_sharp) && - (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == 0)) - { - goto fail; - } - - if ((delimit_data->do_mat) && - (f_a->mat_nr != f_b->mat_nr)) - { - goto fail; - } - - if (delimit_data->do_angle_face) { - if (dot_v3v3(f_a->no, f_b->no) < delimit_data->angle_face__cos) { - goto fail; - } - } - - if (delimit_data->do_angle_shape) { - const BMVert *verts[4]; - bm_edge_to_quad_verts(e, verts); - - /* if we're checking the shape at all, a flipped face is out of the question */ - if (is_quad_flip_v3(verts[0]->co, verts[1]->co, verts[2]->co, verts[3]->co)) { - goto fail; - } - else { - float edge_vecs[4][3]; - - sub_v3_v3v3(edge_vecs[0], verts[0]->co, verts[1]->co); - sub_v3_v3v3(edge_vecs[1], verts[1]->co, verts[2]->co); - sub_v3_v3v3(edge_vecs[2], verts[2]->co, verts[3]->co); - sub_v3_v3v3(edge_vecs[3], verts[3]->co, verts[0]->co); - - normalize_v3(edge_vecs[0]); - normalize_v3(edge_vecs[1]); - normalize_v3(edge_vecs[2]); - normalize_v3(edge_vecs[3]); - - if ((fabsf(angle_normalized_v3v3(edge_vecs[0], edge_vecs[1]) - (float)M_PI_2) > delimit_data->angle_shape) || - (fabsf(angle_normalized_v3v3(edge_vecs[1], edge_vecs[2]) - (float)M_PI_2) > delimit_data->angle_shape) || - (fabsf(angle_normalized_v3v3(edge_vecs[2], edge_vecs[3]) - (float)M_PI_2) > delimit_data->angle_shape) || - (fabsf(angle_normalized_v3v3(edge_vecs[3], edge_vecs[0]) - (float)M_PI_2) > delimit_data->angle_shape)) - { - goto fail; - } - } - } - - if (delimit_data->cdata_len) { - int i; - for (i = 0; i < delimit_data->cdata_len; i++) { - if (!bm_edge_is_contiguous_loop_cd_all(e, &delimit_data->cdata[i])) { - goto fail; - } - } - } - - return false; + if ((delimit_data->do_seam) && (BM_elem_flag_test(e, BM_ELEM_SEAM))) { + goto fail; + } + + if ((delimit_data->do_sharp) && (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == 0)) { + goto fail; + } + + if ((delimit_data->do_mat) && (f_a->mat_nr != f_b->mat_nr)) { + goto fail; + } + + if (delimit_data->do_angle_face) { + if (dot_v3v3(f_a->no, f_b->no) < delimit_data->angle_face__cos) { + goto fail; + } + } + + if (delimit_data->do_angle_shape) { + const BMVert *verts[4]; + bm_edge_to_quad_verts(e, verts); + + /* if we're checking the shape at all, a flipped face is out of the question */ + if (is_quad_flip_v3(verts[0]->co, verts[1]->co, verts[2]->co, verts[3]->co)) { + goto fail; + } + else { + float edge_vecs[4][3]; + + sub_v3_v3v3(edge_vecs[0], verts[0]->co, verts[1]->co); + sub_v3_v3v3(edge_vecs[1], verts[1]->co, verts[2]->co); + sub_v3_v3v3(edge_vecs[2], verts[2]->co, verts[3]->co); + sub_v3_v3v3(edge_vecs[3], verts[3]->co, verts[0]->co); + + normalize_v3(edge_vecs[0]); + normalize_v3(edge_vecs[1]); + normalize_v3(edge_vecs[2]); + normalize_v3(edge_vecs[3]); + + if ((fabsf(angle_normalized_v3v3(edge_vecs[0], edge_vecs[1]) - (float)M_PI_2) > + delimit_data->angle_shape) || + (fabsf(angle_normalized_v3v3(edge_vecs[1], edge_vecs[2]) - (float)M_PI_2) > + delimit_data->angle_shape) || + (fabsf(angle_normalized_v3v3(edge_vecs[2], edge_vecs[3]) - (float)M_PI_2) > + delimit_data->angle_shape) || + (fabsf(angle_normalized_v3v3(edge_vecs[3], edge_vecs[0]) - (float)M_PI_2) > + delimit_data->angle_shape)) { + goto fail; + } + } + } + + if (delimit_data->cdata_len) { + int i; + for (i = 0; i < delimit_data->cdata_len; i++) { + if (!bm_edge_is_contiguous_loop_cd_all(e, &delimit_data->cdata[i])) { + goto fail; + } + } + } + + return false; fail: - return true; + return true; } - -#define EDGE_MARK (1 << 0) +#define EDGE_MARK (1 << 0) #define FACE_OUT (1 << 0) -#define FACE_INPUT (1 << 2) +#define FACE_INPUT (1 << 2) void bmo_join_triangles_exec(BMesh *bm, BMOperator *op) { - float angle_face, angle_shape; - - BMIter iter; - BMOIter siter; - BMFace *f; - BMEdge *e; - /* data: edge-to-join, sort_value: error weight */ - struct SortPtrByFloat *jedges; - unsigned i, totedge; - uint totedge_tag = 0; - - struct DelimitData delimit_data = {0}; - - delimit_data.do_seam = BMO_slot_bool_get(op->slots_in, "cmp_seam"); - delimit_data.do_sharp = BMO_slot_bool_get(op->slots_in, "cmp_sharp"); - delimit_data.do_mat = BMO_slot_bool_get(op->slots_in, "cmp_materials"); - - angle_face = BMO_slot_float_get(op->slots_in, "angle_face_threshold"); - if (angle_face < DEG2RADF(180.0f)) { - delimit_data.angle_face = angle_face; - delimit_data.angle_face__cos = cosf(angle_face); - delimit_data.do_angle_face = true; - } - else { - delimit_data.do_angle_face = false; - } - - angle_shape = BMO_slot_float_get(op->slots_in, "angle_shape_threshold"); - if (angle_shape < DEG2RADF(180.0f)) { - delimit_data.angle_shape = angle_shape; - delimit_data.do_angle_shape = true; - } - else { - delimit_data.do_angle_shape = false; - } - - if (BMO_slot_bool_get(op->slots_in, "cmp_uvs") && - bm_edge_delimit_cdata(&bm->ldata, CD_MLOOPUV, &delimit_data.cdata[delimit_data.cdata_len])) - { - delimit_data.cdata_len += 1; - } - - delimit_data.cdata[delimit_data.cdata_len].cd_offset = -1; - if (BMO_slot_bool_get(op->slots_in, "cmp_vcols") && - bm_edge_delimit_cdata(&bm->ldata, CD_MLOOPCOL, &delimit_data.cdata[delimit_data.cdata_len])) - { - delimit_data.cdata_len += 1; - } - - /* flag all edges of all input face */ - BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) { - if (f->len == 3) { - BMO_face_flag_enable(bm, f, FACE_INPUT); - } - } - - /* flag edges surrounded by 2 flagged triangles */ - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - BMFace *f_a, *f_b; - if (BM_edge_face_pair(e, &f_a, &f_b) && - (BMO_face_flag_test(bm, f_a, FACE_INPUT) && - BMO_face_flag_test(bm, f_b, FACE_INPUT))) - { - if (!bm_edge_is_delimit(e, &delimit_data)) { - BMO_edge_flag_enable(bm, e, EDGE_MARK); - totedge_tag++; - } - } - } - - if (totedge_tag == 0) { - return; - } - - /* over alloc, some of the edges will be delimited */ - jedges = MEM_mallocN(sizeof(*jedges) * totedge_tag, __func__); - - i = 0; - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - const BMVert *verts[4]; - float error; - - if (!BMO_edge_flag_test(bm, e, EDGE_MARK)) { - continue; - } - - bm_edge_to_quad_verts(e, verts); - - error = quad_calc_error(verts[0]->co, verts[1]->co, verts[2]->co, verts[3]->co); - - jedges[i].data = e; - jedges[i].sort_value = error; - i++; - } - - totedge = i; - qsort(jedges, totedge, sizeof(*jedges), BLI_sortutil_cmp_float); - - for (i = 0; i < totedge; i++) { - BMLoop *l_a, *l_b; - - e = jedges[i].data; - l_a = e->l; - l_b = e->l->radial_next; - - /* check if another edge already claimed this face */ - if ((l_a->f->len == 3) && (l_b->f->len == 3)) { - BMFace *f_new; - f_new = BM_faces_join_pair(bm, l_a, l_b, true); - if (f_new) { - BMO_face_flag_enable(bm, f_new, FACE_OUT); - } - } - } - - MEM_freeN(jedges); - - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, FACE_OUT); + float angle_face, angle_shape; + + BMIter iter; + BMOIter siter; + BMFace *f; + BMEdge *e; + /* data: edge-to-join, sort_value: error weight */ + struct SortPtrByFloat *jedges; + unsigned i, totedge; + uint totedge_tag = 0; + + struct DelimitData delimit_data = {0}; + + delimit_data.do_seam = BMO_slot_bool_get(op->slots_in, "cmp_seam"); + delimit_data.do_sharp = BMO_slot_bool_get(op->slots_in, "cmp_sharp"); + delimit_data.do_mat = BMO_slot_bool_get(op->slots_in, "cmp_materials"); + + angle_face = BMO_slot_float_get(op->slots_in, "angle_face_threshold"); + if (angle_face < DEG2RADF(180.0f)) { + delimit_data.angle_face = angle_face; + delimit_data.angle_face__cos = cosf(angle_face); + delimit_data.do_angle_face = true; + } + else { + delimit_data.do_angle_face = false; + } + + angle_shape = BMO_slot_float_get(op->slots_in, "angle_shape_threshold"); + if (angle_shape < DEG2RADF(180.0f)) { + delimit_data.angle_shape = angle_shape; + delimit_data.do_angle_shape = true; + } + else { + delimit_data.do_angle_shape = false; + } + + if (BMO_slot_bool_get(op->slots_in, "cmp_uvs") && + bm_edge_delimit_cdata(&bm->ldata, CD_MLOOPUV, &delimit_data.cdata[delimit_data.cdata_len])) { + delimit_data.cdata_len += 1; + } + + delimit_data.cdata[delimit_data.cdata_len].cd_offset = -1; + if (BMO_slot_bool_get(op->slots_in, "cmp_vcols") && + bm_edge_delimit_cdata( + &bm->ldata, CD_MLOOPCOL, &delimit_data.cdata[delimit_data.cdata_len])) { + delimit_data.cdata_len += 1; + } + + /* flag all edges of all input face */ + BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) { + if (f->len == 3) { + BMO_face_flag_enable(bm, f, FACE_INPUT); + } + } + + /* flag edges surrounded by 2 flagged triangles */ + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + BMFace *f_a, *f_b; + if (BM_edge_face_pair(e, &f_a, &f_b) && + (BMO_face_flag_test(bm, f_a, FACE_INPUT) && BMO_face_flag_test(bm, f_b, FACE_INPUT))) { + if (!bm_edge_is_delimit(e, &delimit_data)) { + BMO_edge_flag_enable(bm, e, EDGE_MARK); + totedge_tag++; + } + } + } + + if (totedge_tag == 0) { + return; + } + + /* over alloc, some of the edges will be delimited */ + jedges = MEM_mallocN(sizeof(*jedges) * totedge_tag, __func__); + + i = 0; + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + const BMVert *verts[4]; + float error; + + if (!BMO_edge_flag_test(bm, e, EDGE_MARK)) { + continue; + } + + bm_edge_to_quad_verts(e, verts); + + error = quad_calc_error(verts[0]->co, verts[1]->co, verts[2]->co, verts[3]->co); + + jedges[i].data = e; + jedges[i].sort_value = error; + i++; + } + + totedge = i; + qsort(jedges, totedge, sizeof(*jedges), BLI_sortutil_cmp_float); + + for (i = 0; i < totedge; i++) { + BMLoop *l_a, *l_b; + + e = jedges[i].data; + l_a = e->l; + l_b = e->l->radial_next; + + /* check if another edge already claimed this face */ + if ((l_a->f->len == 3) && (l_b->f->len == 3)) { + BMFace *f_new; + f_new = BM_faces_join_pair(bm, l_a, l_b, true); + if (f_new) { + BMO_face_flag_enable(bm, f_new, FACE_OUT); + } + } + } + + MEM_freeN(jedges); + + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, FACE_OUT); } diff --git a/source/blender/bmesh/operators/bmo_mesh_conv.c b/source/blender/bmesh/operators/bmo_mesh_conv.c index 5db189a6748..2c76074ad79 100644 --- a/source/blender/bmesh/operators/bmo_mesh_conv.c +++ b/source/blender/bmesh/operators/bmo_mesh_conv.c @@ -22,7 +22,6 @@ * into a Bmesh, and back again. */ - #include "DNA_mesh_types.h" #include "DNA_object_types.h" #include "DNA_key_types.h" @@ -36,39 +35,40 @@ void bmo_mesh_to_bmesh_exec(BMesh *bm, BMOperator *op) { - Object *ob = BMO_slot_ptr_get(op->slots_in, "object"); - Mesh *me = BMO_slot_ptr_get(op->slots_in, "mesh"); - bool set_key = BMO_slot_bool_get(op->slots_in, "use_shapekey"); + Object *ob = BMO_slot_ptr_get(op->slots_in, "object"); + Mesh *me = BMO_slot_ptr_get(op->slots_in, "mesh"); + bool set_key = BMO_slot_bool_get(op->slots_in, "use_shapekey"); - BM_mesh_bm_from_me( - bm, me, (&(struct BMeshFromMeshParams){ - .use_shapekey = set_key, .active_shapekey = ob->shapenr, - })); + BM_mesh_bm_from_me(bm, + me, + (&(struct BMeshFromMeshParams){ + .use_shapekey = set_key, + .active_shapekey = ob->shapenr, + })); - if (me->key && ob->shapenr > me->key->totkey) { - ob->shapenr = me->key->totkey - 1; - } + if (me->key && ob->shapenr > me->key->totkey) { + ob->shapenr = me->key->totkey - 1; + } } void bmo_object_load_bmesh_exec(BMesh *bm, BMOperator *op) { - Object *ob = BMO_slot_ptr_get(op->slots_in, "object"); - /* Scene *scene = BMO_slot_ptr_get(op, "scene"); */ - Mesh *me = ob->data; + Object *ob = BMO_slot_ptr_get(op->slots_in, "object"); + /* Scene *scene = BMO_slot_ptr_get(op, "scene"); */ + Mesh *me = ob->data; - BMO_op_callf(bm, op->flag, - "bmesh_to_mesh mesh=%p object=%p", - me, ob); + BMO_op_callf(bm, op->flag, "bmesh_to_mesh mesh=%p object=%p", me, ob); } void bmo_bmesh_to_mesh_exec(BMesh *bm, BMOperator *op) { - Mesh *me = BMO_slot_ptr_get(op->slots_in, "mesh"); - /* Object *ob = BMO_slot_ptr_get(op, "object"); */ + Mesh *me = BMO_slot_ptr_get(op->slots_in, "mesh"); + /* Object *ob = BMO_slot_ptr_get(op, "object"); */ - BM_mesh_bm_to_me( - G.main, bm, me, - (&(struct BMeshToMeshParams){ - .calc_object_remap = true, - })); + BM_mesh_bm_to_me(G.main, + bm, + me, + (&(struct BMeshToMeshParams){ + .calc_object_remap = true, + })); } diff --git a/source/blender/bmesh/operators/bmo_mirror.c b/source/blender/bmesh/operators/bmo_mirror.c index 2ef96d1df03..36297b3f816 100644 --- a/source/blender/bmesh/operators/bmo_mirror.c +++ b/source/blender/bmesh/operators/bmo_mirror.c @@ -31,87 +31,87 @@ #include "bmesh.h" #include "intern/bmesh_operators_private.h" /* own include */ -#define ELE_NEW 1 +#define ELE_NEW 1 void bmo_mirror_exec(BMesh *bm, BMOperator *op) { - BMOperator dupeop, weldop; - BMOIter siter; - BMIter iter; - BMVert *v, **vmap; - int vmap_size = 0; - float mtx[4][4]; - float imtx[4][4]; - float scale[3] = {1.0f, 1.0f, 1.0f}; - float dist = BMO_slot_float_get(op->slots_in, "merge_dist"); - int i, ototvert; - int axis = BMO_slot_int_get(op->slots_in, "axis"); - bool mirror_u = BMO_slot_bool_get(op->slots_in, "mirror_u"); - bool mirror_v = BMO_slot_bool_get(op->slots_in, "mirror_v"); - BMOpSlot *slot_targetmap; - - ototvert = bm->totvert; - - BMO_slot_mat4_get(op->slots_in, "matrix", mtx); - invert_m4_m4(imtx, mtx); - - BMO_op_initf(bm, &dupeop, op->flag, "duplicate geom=%s", op, "geom"); - BMO_op_exec(bm, &dupeop); - - BMO_slot_buffer_flag_enable(bm, dupeop.slots_out, "geom.out", BM_ALL_NOLOOP, ELE_NEW); - - /* create old -> new mappin */ - vmap = BMO_iter_as_arrayN(dupeop.slots_out, "geom.out", BM_VERT, &vmap_size, NULL, 0); - - /* feed old data to transform bmo */ - scale[axis] = -1.0f; - BMO_op_callf(bm, op->flag, "transform verts=%fv matrix=%m4", ELE_NEW, mtx); - BMO_op_callf(bm, op->flag, "scale verts=%fv vec=%v", ELE_NEW, scale); - BMO_op_callf(bm, op->flag, "transform verts=%fv matrix=%m4", ELE_NEW, imtx); - - BMO_op_init(bm, &weldop, op->flag, "weld_verts"); - - slot_targetmap = BMO_slot_get(weldop.slots_in, "targetmap"); - - v = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL); - for (i = 0; i < ototvert; i++) { - if (fabsf(v->co[axis]) <= dist) { - BLI_assert(vmap_size >= i); - BMO_slot_map_elem_insert(&weldop, slot_targetmap, vmap[i], v); - } - v = BM_iter_step(&iter); - } - - if (mirror_u || mirror_v) { - BMFace *f; - BMLoop *l; - MLoopUV *luv; - const int totlayer = CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV); - BMIter liter; - - BMO_ITER (f, &siter, dupeop.slots_out, "geom.out", BM_FACE) { - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - for (i = 0; i < totlayer; i++) { - luv = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPUV, i); - if (mirror_u) { - luv->uv[0] = 1.0f - luv->uv[0]; - } - if (mirror_v) { - luv->uv[1] = 1.0f - luv->uv[1]; - } - } - } - } - } - - BMO_op_exec(bm, &weldop); - - BMO_op_finish(bm, &weldop); - BMO_op_finish(bm, &dupeop); - - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, ELE_NEW); - - if (vmap) { - MEM_freeN(vmap); - } + BMOperator dupeop, weldop; + BMOIter siter; + BMIter iter; + BMVert *v, **vmap; + int vmap_size = 0; + float mtx[4][4]; + float imtx[4][4]; + float scale[3] = {1.0f, 1.0f, 1.0f}; + float dist = BMO_slot_float_get(op->slots_in, "merge_dist"); + int i, ototvert; + int axis = BMO_slot_int_get(op->slots_in, "axis"); + bool mirror_u = BMO_slot_bool_get(op->slots_in, "mirror_u"); + bool mirror_v = BMO_slot_bool_get(op->slots_in, "mirror_v"); + BMOpSlot *slot_targetmap; + + ototvert = bm->totvert; + + BMO_slot_mat4_get(op->slots_in, "matrix", mtx); + invert_m4_m4(imtx, mtx); + + BMO_op_initf(bm, &dupeop, op->flag, "duplicate geom=%s", op, "geom"); + BMO_op_exec(bm, &dupeop); + + BMO_slot_buffer_flag_enable(bm, dupeop.slots_out, "geom.out", BM_ALL_NOLOOP, ELE_NEW); + + /* create old -> new mappin */ + vmap = BMO_iter_as_arrayN(dupeop.slots_out, "geom.out", BM_VERT, &vmap_size, NULL, 0); + + /* feed old data to transform bmo */ + scale[axis] = -1.0f; + BMO_op_callf(bm, op->flag, "transform verts=%fv matrix=%m4", ELE_NEW, mtx); + BMO_op_callf(bm, op->flag, "scale verts=%fv vec=%v", ELE_NEW, scale); + BMO_op_callf(bm, op->flag, "transform verts=%fv matrix=%m4", ELE_NEW, imtx); + + BMO_op_init(bm, &weldop, op->flag, "weld_verts"); + + slot_targetmap = BMO_slot_get(weldop.slots_in, "targetmap"); + + v = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL); + for (i = 0; i < ototvert; i++) { + if (fabsf(v->co[axis]) <= dist) { + BLI_assert(vmap_size >= i); + BMO_slot_map_elem_insert(&weldop, slot_targetmap, vmap[i], v); + } + v = BM_iter_step(&iter); + } + + if (mirror_u || mirror_v) { + BMFace *f; + BMLoop *l; + MLoopUV *luv; + const int totlayer = CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV); + BMIter liter; + + BMO_ITER (f, &siter, dupeop.slots_out, "geom.out", BM_FACE) { + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + for (i = 0; i < totlayer; i++) { + luv = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPUV, i); + if (mirror_u) { + luv->uv[0] = 1.0f - luv->uv[0]; + } + if (mirror_v) { + luv->uv[1] = 1.0f - luv->uv[1]; + } + } + } + } + } + + BMO_op_exec(bm, &weldop); + + BMO_op_finish(bm, &weldop); + BMO_op_finish(bm, &dupeop); + + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, ELE_NEW); + + if (vmap) { + MEM_freeN(vmap); + } } diff --git a/source/blender/bmesh/operators/bmo_normals.c b/source/blender/bmesh/operators/bmo_normals.c index f91f15ee881..ee55165244b 100644 --- a/source/blender/bmesh/operators/bmo_normals.c +++ b/source/blender/bmesh/operators/bmo_normals.c @@ -31,13 +31,13 @@ /********* righthand faces implementation ****** */ -#define FACE_FLAG (1 << 0) -#define FACE_FLIP (1 << 1) -#define FACE_TEMP (1 << 2) +#define FACE_FLAG (1 << 0) +#define FACE_FLIP (1 << 1) +#define FACE_TEMP (1 << 2) static bool bmo_recalc_normal_loop_filter_cb(const BMLoop *l, void *UNUSED(user_data)) { - return BM_edge_is_manifold(l->e); + return BM_edge_is_manifold(l->e); } /** @@ -69,116 +69,116 @@ static bool bmo_recalc_normal_loop_filter_cb(const BMLoop *l, void *UNUSED(user_ /** * \return a face index in \a faces and set \a r_is_flip if the face is flipped away from the center. */ -static int recalc_face_normals_find_index(BMesh *bm, BMFace **faces, const int faces_len, bool *r_is_flip) +static int recalc_face_normals_find_index(BMesh *bm, + BMFace **faces, + const int faces_len, + bool *r_is_flip) { - const float eps = FLT_EPSILON; - float cent_area_accum = 0.0f; - float cent[3]; - const float cent_fac = 1.0f / (float)faces_len; - - bool is_flip = false; - int f_start_index; - int i; - - /* Search for the best loop. Members are compared in-order defined here. */ - struct { - /* Squared distance from the center to the loops vertex 'l->v'. - * The normalized direction between the center and this vertex is also used for the dot-products below. */ - float dist_sq; - /* Signed dot product using the normalized edge vector, - * (best of 'l->prev->v' or 'l->next->v'). */ - float edge_dot; - /* Unsigned dot product using the loop-normal - * (sign is used to check if we need to flip) */ - float loop_dot; - } best, test; - - UNUSED_VARS_NDEBUG(bm); - - zero_v3(cent); - - /* first calculate the center */ - for (i = 0; i < faces_len; i++) { - float f_cent[3]; - const float f_area = BM_face_calc_area(faces[i]); - BM_face_calc_center_median_weighted(faces[i], f_cent); - madd_v3_v3fl(cent, f_cent, cent_fac * f_area); - cent_area_accum += f_area; - - BLI_assert(BMO_face_flag_test(bm, faces[i], FACE_TEMP) == 0); - BLI_assert(BM_face_is_normal_valid(faces[i])); - } - - if (cent_area_accum != 0.0f) { - mul_v3_fl(cent, 1.0f / cent_area_accum); - } - - /* Distances must start above zero, - * or we can't do meaningful calculations based on the direction to the center */ - best.dist_sq = eps; - best.edge_dot = best.loop_dot = -FLT_MAX; - - /* used in degenerate cases only */ - f_start_index = 0; - - /** - * Find the outer-most vertex, comparing distance to the center, - * then the outer-most loop attached to that vertex. - * - * Important this is correctly detected, - * where casting a ray from the center wont hit any loops past this one. - * Otherwise the result may be incorrect. - */ - for (i = 0; i < faces_len; i++) { - BMLoop *l_iter, *l_first; - - l_iter = l_first = BM_FACE_FIRST_LOOP(faces[i]); - do { - bool is_best_dist_sq; - float dir[3]; - sub_v3_v3v3(dir, l_iter->v->co, cent); - test.dist_sq = len_squared_v3(dir); - is_best_dist_sq = (test.dist_sq > best.dist_sq); - if (is_best_dist_sq || (test.dist_sq == best.dist_sq)) { - float edge_dir_pair[2][3]; - mul_v3_fl(dir, 1.0f / sqrtf(test.dist_sq)); - - sub_v3_v3v3(edge_dir_pair[0], l_iter->next->v->co, l_iter->v->co); - sub_v3_v3v3(edge_dir_pair[1], l_iter->prev->v->co, l_iter->v->co); - - if ((normalize_v3(edge_dir_pair[0]) > eps) && - (normalize_v3(edge_dir_pair[1]) > eps)) - { - bool is_best_edge_dot; - test.edge_dot = max_ff(dot_v3v3(dir, edge_dir_pair[0]), - dot_v3v3(dir, edge_dir_pair[1])); - is_best_edge_dot = (test.edge_dot > best.edge_dot); - if (is_best_dist_sq || is_best_edge_dot || (test.edge_dot == best.edge_dot)) { - float loop_dir[3]; - cross_v3_v3v3(loop_dir, edge_dir_pair[0], edge_dir_pair[1]); - if (normalize_v3(loop_dir) > eps) { - float loop_dir_dot; - /* Highly unlikely the furthest loop is also the concave part of an ngon, - * but it can be contrived with _very_ non-planar faces - so better check. */ - if (UNLIKELY(dot_v3v3(loop_dir, l_iter->f->no) < 0.0f)) { - negate_v3(loop_dir); - } - loop_dir_dot = dot_v3v3(dir, loop_dir); - test.loop_dot = fabsf(loop_dir_dot); - if (is_best_dist_sq || is_best_edge_dot || (test.loop_dot > best.loop_dot)) { - best = test; - f_start_index = i; - is_flip = (loop_dir_dot < 0.0f); - } - } - } - } - } - } while ((l_iter = l_iter->next) != l_first); - } - - *r_is_flip = is_flip; - return f_start_index; + const float eps = FLT_EPSILON; + float cent_area_accum = 0.0f; + float cent[3]; + const float cent_fac = 1.0f / (float)faces_len; + + bool is_flip = false; + int f_start_index; + int i; + + /* Search for the best loop. Members are compared in-order defined here. */ + struct { + /* Squared distance from the center to the loops vertex 'l->v'. + * The normalized direction between the center and this vertex is also used for the dot-products below. */ + float dist_sq; + /* Signed dot product using the normalized edge vector, + * (best of 'l->prev->v' or 'l->next->v'). */ + float edge_dot; + /* Unsigned dot product using the loop-normal + * (sign is used to check if we need to flip) */ + float loop_dot; + } best, test; + + UNUSED_VARS_NDEBUG(bm); + + zero_v3(cent); + + /* first calculate the center */ + for (i = 0; i < faces_len; i++) { + float f_cent[3]; + const float f_area = BM_face_calc_area(faces[i]); + BM_face_calc_center_median_weighted(faces[i], f_cent); + madd_v3_v3fl(cent, f_cent, cent_fac * f_area); + cent_area_accum += f_area; + + BLI_assert(BMO_face_flag_test(bm, faces[i], FACE_TEMP) == 0); + BLI_assert(BM_face_is_normal_valid(faces[i])); + } + + if (cent_area_accum != 0.0f) { + mul_v3_fl(cent, 1.0f / cent_area_accum); + } + + /* Distances must start above zero, + * or we can't do meaningful calculations based on the direction to the center */ + best.dist_sq = eps; + best.edge_dot = best.loop_dot = -FLT_MAX; + + /* used in degenerate cases only */ + f_start_index = 0; + + /** + * Find the outer-most vertex, comparing distance to the center, + * then the outer-most loop attached to that vertex. + * + * Important this is correctly detected, + * where casting a ray from the center wont hit any loops past this one. + * Otherwise the result may be incorrect. + */ + for (i = 0; i < faces_len; i++) { + BMLoop *l_iter, *l_first; + + l_iter = l_first = BM_FACE_FIRST_LOOP(faces[i]); + do { + bool is_best_dist_sq; + float dir[3]; + sub_v3_v3v3(dir, l_iter->v->co, cent); + test.dist_sq = len_squared_v3(dir); + is_best_dist_sq = (test.dist_sq > best.dist_sq); + if (is_best_dist_sq || (test.dist_sq == best.dist_sq)) { + float edge_dir_pair[2][3]; + mul_v3_fl(dir, 1.0f / sqrtf(test.dist_sq)); + + sub_v3_v3v3(edge_dir_pair[0], l_iter->next->v->co, l_iter->v->co); + sub_v3_v3v3(edge_dir_pair[1], l_iter->prev->v->co, l_iter->v->co); + + if ((normalize_v3(edge_dir_pair[0]) > eps) && (normalize_v3(edge_dir_pair[1]) > eps)) { + bool is_best_edge_dot; + test.edge_dot = max_ff(dot_v3v3(dir, edge_dir_pair[0]), dot_v3v3(dir, edge_dir_pair[1])); + is_best_edge_dot = (test.edge_dot > best.edge_dot); + if (is_best_dist_sq || is_best_edge_dot || (test.edge_dot == best.edge_dot)) { + float loop_dir[3]; + cross_v3_v3v3(loop_dir, edge_dir_pair[0], edge_dir_pair[1]); + if (normalize_v3(loop_dir) > eps) { + float loop_dir_dot; + /* Highly unlikely the furthest loop is also the concave part of an ngon, + * but it can be contrived with _very_ non-planar faces - so better check. */ + if (UNLIKELY(dot_v3v3(loop_dir, l_iter->f->no) < 0.0f)) { + negate_v3(loop_dir); + } + loop_dir_dot = dot_v3v3(dir, loop_dir); + test.loop_dot = fabsf(loop_dir_dot); + if (is_best_dist_sq || is_best_edge_dot || (test.loop_dot > best.loop_dot)) { + best = test; + f_start_index = i; + is_flip = (loop_dir_dot < 0.0f); + } + } + } + } + } + } while ((l_iter = l_iter->next) != l_first); + } + + *r_is_flip = is_flip; + return f_start_index; } /** @@ -190,58 +190,61 @@ static int recalc_face_normals_find_index(BMesh *bm, BMFace **faces, const int f * \param faces_len: Length of \a faces * \param oflag: Flag to check before doing the actual face flipping. */ -static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int faces_len, const short oflag) +static void bmo_recalc_face_normals_array(BMesh *bm, + BMFace **faces, + const int faces_len, + const short oflag) { - int i, f_start_index; - const short oflag_flip = oflag | FACE_FLIP; - bool is_flip; - - BMFace *f; - - BLI_LINKSTACK_DECLARE(fstack, BMFace *); - - f_start_index = recalc_face_normals_find_index(bm, faces, faces_len, &is_flip); - - if (is_flip) { - BMO_face_flag_enable(bm, faces[f_start_index], FACE_FLIP); - } - - /* now that we've found our starting face, make all connected faces - * have the same winding. this is done recursively, using a manual - * stack (if we use simple function recursion, we'd end up overloading - * the stack on large meshes). */ - BLI_LINKSTACK_INIT(fstack); - - BLI_LINKSTACK_PUSH(fstack, faces[f_start_index]); - BMO_face_flag_enable(bm, faces[f_start_index], FACE_TEMP); - - while ((f = BLI_LINKSTACK_POP(fstack))) { - const bool flip_state = BMO_face_flag_test_bool(bm, f, FACE_FLIP); - BMLoop *l_iter, *l_first; - - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - BMLoop *l_other = l_iter->radial_next; - - if ((l_other != l_iter) && bmo_recalc_normal_loop_filter_cb(l_iter, NULL)) { - if (!BMO_face_flag_test(bm, l_other->f, FACE_TEMP)) { - BMO_face_flag_enable(bm, l_other->f, FACE_TEMP); - BMO_face_flag_set(bm, l_other->f, FACE_FLIP, (l_other->v == l_iter->v) != flip_state); - BLI_LINKSTACK_PUSH(fstack, l_other->f); - } - } - } while ((l_iter = l_iter->next) != l_first); - } - - BLI_LINKSTACK_FREE(fstack); - - /* apply flipping to oflag'd faces */ - for (i = 0; i < faces_len; i++) { - if (BMO_face_flag_test(bm, faces[i], oflag_flip) == oflag_flip) { - BM_face_normal_flip(bm, faces[i]); - } - BMO_face_flag_disable(bm, faces[i], FACE_TEMP); - } + int i, f_start_index; + const short oflag_flip = oflag | FACE_FLIP; + bool is_flip; + + BMFace *f; + + BLI_LINKSTACK_DECLARE(fstack, BMFace *); + + f_start_index = recalc_face_normals_find_index(bm, faces, faces_len, &is_flip); + + if (is_flip) { + BMO_face_flag_enable(bm, faces[f_start_index], FACE_FLIP); + } + + /* now that we've found our starting face, make all connected faces + * have the same winding. this is done recursively, using a manual + * stack (if we use simple function recursion, we'd end up overloading + * the stack on large meshes). */ + BLI_LINKSTACK_INIT(fstack); + + BLI_LINKSTACK_PUSH(fstack, faces[f_start_index]); + BMO_face_flag_enable(bm, faces[f_start_index], FACE_TEMP); + + while ((f = BLI_LINKSTACK_POP(fstack))) { + const bool flip_state = BMO_face_flag_test_bool(bm, f, FACE_FLIP); + BMLoop *l_iter, *l_first; + + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BMLoop *l_other = l_iter->radial_next; + + if ((l_other != l_iter) && bmo_recalc_normal_loop_filter_cb(l_iter, NULL)) { + if (!BMO_face_flag_test(bm, l_other->f, FACE_TEMP)) { + BMO_face_flag_enable(bm, l_other->f, FACE_TEMP); + BMO_face_flag_set(bm, l_other->f, FACE_FLIP, (l_other->v == l_iter->v) != flip_state); + BLI_LINKSTACK_PUSH(fstack, l_other->f); + } + } + } while ((l_iter = l_iter->next) != l_first); + } + + BLI_LINKSTACK_FREE(fstack); + + /* apply flipping to oflag'd faces */ + for (i = 0; i < faces_len; i++) { + if (BMO_face_flag_test(bm, faces[i], oflag_flip) == oflag_flip) { + BM_face_normal_flip(bm, faces[i]); + } + BMO_face_flag_disable(bm, faces[i], FACE_TEMP); + } } /* @@ -254,41 +257,39 @@ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int f void bmo_recalc_face_normals_exec(BMesh *bm, BMOperator *op) { - int *groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totface, __func__); - BMFace **faces_grp = MEM_mallocN(sizeof(*faces_grp) * bm->totface, __func__); + int *groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totface, __func__); + BMFace **faces_grp = MEM_mallocN(sizeof(*faces_grp) * bm->totface, __func__); - int (*group_index)[2]; - const int group_tot = BM_mesh_calc_face_groups( - bm, groups_array, &group_index, - bmo_recalc_normal_loop_filter_cb, NULL, - 0, BM_EDGE); - int i; + int(*group_index)[2]; + const int group_tot = BM_mesh_calc_face_groups( + bm, groups_array, &group_index, bmo_recalc_normal_loop_filter_cb, NULL, 0, BM_EDGE); + int i; - BMO_slot_buffer_flag_enable(bm, op->slots_in, "faces", BM_FACE, FACE_FLAG); + BMO_slot_buffer_flag_enable(bm, op->slots_in, "faces", BM_FACE, FACE_FLAG); - BM_mesh_elem_table_ensure(bm, BM_FACE); + BM_mesh_elem_table_ensure(bm, BM_FACE); - for (i = 0; i < group_tot; i++) { - const int fg_sta = group_index[i][0]; - const int fg_len = group_index[i][1]; - int j; - bool is_calc = false; + for (i = 0; i < group_tot; i++) { + const int fg_sta = group_index[i][0]; + const int fg_len = group_index[i][1]; + int j; + bool is_calc = false; - for (j = 0; j < fg_len; j++) { - faces_grp[j] = BM_face_at_index(bm, groups_array[fg_sta + j]); + for (j = 0; j < fg_len; j++) { + faces_grp[j] = BM_face_at_index(bm, groups_array[fg_sta + j]); - if (is_calc == false) { - is_calc = BMO_face_flag_test_bool(bm, faces_grp[j], FACE_FLAG); - } - } + if (is_calc == false) { + is_calc = BMO_face_flag_test_bool(bm, faces_grp[j], FACE_FLAG); + } + } - if (is_calc) { - bmo_recalc_face_normals_array(bm, faces_grp, fg_len, FACE_FLAG); - } - } + if (is_calc) { + bmo_recalc_face_normals_array(bm, faces_grp, fg_len, FACE_FLAG); + } + } - MEM_freeN(faces_grp); + MEM_freeN(faces_grp); - MEM_freeN(groups_array); - MEM_freeN(group_index); + MEM_freeN(groups_array); + MEM_freeN(group_index); } diff --git a/source/blender/bmesh/operators/bmo_offset_edgeloops.c b/source/blender/bmesh/operators/bmo_offset_edgeloops.c index 9bf48eaeb96..37b2133e0e4 100644 --- a/source/blender/bmesh/operators/bmo_offset_edgeloops.c +++ b/source/blender/bmesh/operators/bmo_offset_edgeloops.c @@ -37,249 +37,239 @@ #define USE_CAP_OPTION -#define ELE_NEW (1 << 0) +#define ELE_NEW (1 << 0) #ifdef USE_CAP_OPTION -#define ELE_VERT_ENDPOINT (1 << 1) +# define ELE_VERT_ENDPOINT (1 << 1) #endif /* set for debugging */ #define OFFSET 0.0f -static BMFace *bm_face_split_walk_back( - BMesh *bm, BMLoop *l_src, - BMLoop **r_l) +static BMFace *bm_face_split_walk_back(BMesh *bm, BMLoop *l_src, BMLoop **r_l) { - float (*cos)[3]; - BMLoop *l_dst; - BMFace *f; - int num, i; + float(*cos)[3]; + BMLoop *l_dst; + BMFace *f; + int num, i; - for (l_dst = l_src->prev, num = 0; BM_elem_index_get(l_dst->prev->v) != -1; l_dst = l_dst->prev, num++) { - /* pass */ - } + for (l_dst = l_src->prev, num = 0; BM_elem_index_get(l_dst->prev->v) != -1; + l_dst = l_dst->prev, num++) { + /* pass */ + } - BLI_assert(num != 0); + BLI_assert(num != 0); - cos = BLI_array_alloca( - cos, num); + cos = BLI_array_alloca(cos, num); - for (l_dst = l_src->prev, i = 0; BM_elem_index_get(l_dst->prev->v) != -1; l_dst = l_dst->prev, i++) { - copy_v3_v3(cos[num - (i + 1)], l_dst->v->co); - } + for (l_dst = l_src->prev, i = 0; BM_elem_index_get(l_dst->prev->v) != -1; + l_dst = l_dst->prev, i++) { + copy_v3_v3(cos[num - (i + 1)], l_dst->v->co); + } - f = BM_face_split_n( bm, l_src->f, l_dst->prev, l_src->next, cos, num, r_l, NULL); + f = BM_face_split_n(bm, l_src->f, l_dst->prev, l_src->next, cos, num, r_l, NULL); - return f; + return f; } void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op) { - const int edges_num = BMO_slot_buffer_count(op->slots_in, "edges"); - BMVert **verts; - STACK_DECLARE(verts); - int i; + const int edges_num = BMO_slot_buffer_count(op->slots_in, "edges"); + BMVert **verts; + STACK_DECLARE(verts); + int i; #ifdef USE_CAP_OPTION - bool use_cap_endpoint = BMO_slot_bool_get(op->slots_in, "use_cap_endpoint"); - int v_edges_max = 0; + bool use_cap_endpoint = BMO_slot_bool_get(op->slots_in, "use_cap_endpoint"); + int v_edges_max = 0; #endif - BMOIter oiter; - - /* only so we can detect new verts (index == -1) */ - BM_mesh_elem_index_ensure(bm, BM_VERT); - - BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); - - /* over alloc */ - verts = MEM_mallocN(sizeof(*verts) * (edges_num * 2), __func__); - - STACK_INIT(verts, (edges_num * 2)); - - { - BMEdge *e; - BMO_ITER (e, &oiter, op->slots_in, "edges", BM_EDGE) { - int j; - - BM_elem_flag_enable(e, BM_ELEM_TAG); - - for (j = 0; j < 2; j++) { - BMVert *v_edge = *(&(e->v1) + j); - if (!BM_elem_flag_test(v_edge, BM_ELEM_TAG)) { - BM_elem_flag_enable(v_edge, BM_ELEM_TAG); - STACK_PUSH(verts, v_edge); - } - } - } - } - - - /* -------------------------------------------------------------------- */ - /* Remove verts only used by tagged edges */ - - for (i = 0; i < STACK_SIZE(verts); i++) { - BMIter iter; - int flag = 0; - BMEdge *e; - - BM_ITER_ELEM (e, &iter, verts[i], BM_EDGES_OF_VERT) { - flag |= BM_elem_flag_test(e, BM_ELEM_TAG) ? 1 : 2; - if (flag == (1 | 2)) { - break; - } - } - - /* only boundary verts are interesting */ - if (flag != (1 | 2)) { - STACK_REMOVE(verts, i); - } - } - - /* possible but unlikely we have no mixed vertices */ - if (UNLIKELY(STACK_SIZE(verts) == 0)) { - MEM_freeN(verts); - return; - } - - /* main loop */ - for (i = 0; i < STACK_SIZE(verts); i++) { - int v_edges_num = 0; - int v_edges_num_untag = 0; - BMVert *v = verts[i]; - BMIter iter; - BMEdge *e; - - BM_ITER_ELEM (e, &iter, verts[i], BM_EDGES_OF_VERT) { - if (!BM_elem_flag_test(e, BM_ELEM_TAG)) { - BMVert *v_other; - BMIter liter; - BMLoop *l; - - BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) { - BM_elem_flag_enable(l->f, BM_ELEM_TAG); - } - - v_other = BM_edge_other_vert(e, v); - BM_edge_split(bm, e, v_other, NULL, 1.0f - OFFSET); - } - else { - v_edges_num_untag += 1; - } - - v_edges_num += 1; - } + BMOIter oiter; + + /* only so we can detect new verts (index == -1) */ + BM_mesh_elem_index_ensure(bm, BM_VERT); + + BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); + + /* over alloc */ + verts = MEM_mallocN(sizeof(*verts) * (edges_num * 2), __func__); + + STACK_INIT(verts, (edges_num * 2)); + + { + BMEdge *e; + BMO_ITER (e, &oiter, op->slots_in, "edges", BM_EDGE) { + int j; + + BM_elem_flag_enable(e, BM_ELEM_TAG); + + for (j = 0; j < 2; j++) { + BMVert *v_edge = *(&(e->v1) + j); + if (!BM_elem_flag_test(v_edge, BM_ELEM_TAG)) { + BM_elem_flag_enable(v_edge, BM_ELEM_TAG); + STACK_PUSH(verts, v_edge); + } + } + } + } + + /* -------------------------------------------------------------------- */ + /* Remove verts only used by tagged edges */ + + for (i = 0; i < STACK_SIZE(verts); i++) { + BMIter iter; + int flag = 0; + BMEdge *e; + + BM_ITER_ELEM (e, &iter, verts[i], BM_EDGES_OF_VERT) { + flag |= BM_elem_flag_test(e, BM_ELEM_TAG) ? 1 : 2; + if (flag == (1 | 2)) { + break; + } + } + + /* only boundary verts are interesting */ + if (flag != (1 | 2)) { + STACK_REMOVE(verts, i); + } + } + + /* possible but unlikely we have no mixed vertices */ + if (UNLIKELY(STACK_SIZE(verts) == 0)) { + MEM_freeN(verts); + return; + } + + /* main loop */ + for (i = 0; i < STACK_SIZE(verts); i++) { + int v_edges_num = 0; + int v_edges_num_untag = 0; + BMVert *v = verts[i]; + BMIter iter; + BMEdge *e; + + BM_ITER_ELEM (e, &iter, verts[i], BM_EDGES_OF_VERT) { + if (!BM_elem_flag_test(e, BM_ELEM_TAG)) { + BMVert *v_other; + BMIter liter; + BMLoop *l; + + BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) { + BM_elem_flag_enable(l->f, BM_ELEM_TAG); + } + + v_other = BM_edge_other_vert(e, v); + BM_edge_split(bm, e, v_other, NULL, 1.0f - OFFSET); + } + else { + v_edges_num_untag += 1; + } + + v_edges_num += 1; + } #ifdef USE_CAP_OPTION - if (v_edges_num_untag == 1) { - BMO_vert_flag_enable(bm, v, ELE_VERT_ENDPOINT); - } + if (v_edges_num_untag == 1) { + BMO_vert_flag_enable(bm, v, ELE_VERT_ENDPOINT); + } - CLAMP_MIN(v_edges_max, v_edges_num); + CLAMP_MIN(v_edges_max, v_edges_num); #endif + } - } + for (i = 0; i < STACK_SIZE(verts); i++) { + BMVert *v = verts[i]; + BMIter liter; + BMLoop *l; - - for (i = 0; i < STACK_SIZE(verts); i++) { - BMVert *v = verts[i]; - BMIter liter; - BMLoop *l; - - BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { - if (BM_elem_flag_test(l->f, BM_ELEM_TAG) && - (l->f->len != 3)) - { - BMFace *f_cmp = l->f; - if ((BM_elem_index_get(l->next->v) == -1) && - (BM_elem_index_get(l->prev->v) == -1)) - { + BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { + if (BM_elem_flag_test(l->f, BM_ELEM_TAG) && (l->f->len != 3)) { + BMFace *f_cmp = l->f; + if ((BM_elem_index_get(l->next->v) == -1) && (BM_elem_index_get(l->prev->v) == -1)) { #ifdef USE_CAP_OPTION - if (use_cap_endpoint || (BMO_vert_flag_test(bm, v, ELE_VERT_ENDPOINT) == 0)) + if (use_cap_endpoint || (BMO_vert_flag_test(bm, v, ELE_VERT_ENDPOINT) == 0)) #endif - { - BMLoop *l_new; - BM_face_split(bm, l->f, l->prev, l->next, &l_new, NULL, true); - BLI_assert(f_cmp == l->f); - BLI_assert(f_cmp != l_new->f); - UNUSED_VARS_NDEBUG(f_cmp); - BMO_edge_flag_enable(bm, l_new->e, ELE_NEW); - } - } - else if (l->f->len > 4) { - if (BM_elem_flag_test(l->e, BM_ELEM_TAG) != - BM_elem_flag_test(l->prev->e, BM_ELEM_TAG)) - { - if (BM_elem_index_get(l->next->v) == -1) { - if (BM_elem_index_get(l->prev->prev->v) == -1) { - BMLoop *l_new; - BM_face_split(bm, l->f, l->prev->prev, l->next, &l_new, NULL, true); - BLI_assert(f_cmp == l->f); - BLI_assert(f_cmp != l_new->f); - BMO_edge_flag_enable(bm, l_new->e, ELE_NEW); - BM_elem_flag_disable(l->f, BM_ELEM_TAG); - } - else { - /* walk backwards */ - BMLoop *l_new; - bm_face_split_walk_back(bm, l, &l_new); - do { - BMO_edge_flag_enable(bm, l_new->e, ELE_NEW); - l_new = l_new->next; - } while (BM_vert_is_edge_pair(l_new->v)); - BM_elem_flag_disable(l->f, BM_ELEM_TAG); - } - } - - /* Note: instead of duplicate code in alternate direction, - * we can be sure to hit the other vertex, so the code above runs. */ + { + BMLoop *l_new; + BM_face_split(bm, l->f, l->prev, l->next, &l_new, NULL, true); + BLI_assert(f_cmp == l->f); + BLI_assert(f_cmp != l_new->f); + UNUSED_VARS_NDEBUG(f_cmp); + BMO_edge_flag_enable(bm, l_new->e, ELE_NEW); + } + } + else if (l->f->len > 4) { + if (BM_elem_flag_test(l->e, BM_ELEM_TAG) != BM_elem_flag_test(l->prev->e, BM_ELEM_TAG)) { + if (BM_elem_index_get(l->next->v) == -1) { + if (BM_elem_index_get(l->prev->prev->v) == -1) { + BMLoop *l_new; + BM_face_split(bm, l->f, l->prev->prev, l->next, &l_new, NULL, true); + BLI_assert(f_cmp == l->f); + BLI_assert(f_cmp != l_new->f); + BMO_edge_flag_enable(bm, l_new->e, ELE_NEW); + BM_elem_flag_disable(l->f, BM_ELEM_TAG); + } + else { + /* walk backwards */ + BMLoop *l_new; + bm_face_split_walk_back(bm, l, &l_new); + do { + BMO_edge_flag_enable(bm, l_new->e, ELE_NEW); + l_new = l_new->next; + } while (BM_vert_is_edge_pair(l_new->v)); + BM_elem_flag_disable(l->f, BM_ELEM_TAG); + } + } + + /* Note: instead of duplicate code in alternate direction, + * we can be sure to hit the other vertex, so the code above runs. */ #if 0 - else if (BM_elem_index_get(l->prev->v) == -1) { - if (BM_elem_index_get(l->next->next->v) == -1) { - /* pass */ - } - } + else if (BM_elem_index_get(l->prev->v) == -1) { + if (BM_elem_index_get(l->next->next->v) == -1) { + /* pass */ + } + } #endif - } - } - } - } - } + } + } + } + } + } #ifdef USE_CAP_OPTION - if (use_cap_endpoint == false) { - BMVert **varr = BLI_array_alloca(varr, v_edges_max); - STACK_DECLARE(varr); - BMVert *v; - - for (i = 0; i < STACK_SIZE(verts); i++) { - BMIter iter; - BMEdge *e; - - v = verts[i]; - - STACK_INIT(varr, v_edges_max); - - BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { - BMVert *v_other; - v_other = BM_edge_other_vert(e, v); - if (BM_elem_index_get(v_other) == -1) { - if (BM_vert_is_edge_pair(v_other)) { - /* defer bmesh_kernel_join_edge_kill_vert to avoid looping over data we're removing */ - v_other->e = e; - STACK_PUSH(varr, v_other); - } - } - } - - while ((v = STACK_POP(varr))) { - bmesh_kernel_join_edge_kill_vert(bm, v->e, v, true, false, false); - } - } - } + if (use_cap_endpoint == false) { + BMVert **varr = BLI_array_alloca(varr, v_edges_max); + STACK_DECLARE(varr); + BMVert *v; + + for (i = 0; i < STACK_SIZE(verts); i++) { + BMIter iter; + BMEdge *e; + + v = verts[i]; + + STACK_INIT(varr, v_edges_max); + + BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { + BMVert *v_other; + v_other = BM_edge_other_vert(e, v); + if (BM_elem_index_get(v_other) == -1) { + if (BM_vert_is_edge_pair(v_other)) { + /* defer bmesh_kernel_join_edge_kill_vert to avoid looping over data we're removing */ + v_other->e = e; + STACK_PUSH(varr, v_other); + } + } + } + + while ((v = STACK_POP(varr))) { + bmesh_kernel_join_edge_kill_vert(bm, v->e, v, true, false, false); + } + } + } #endif - MEM_freeN(verts); + MEM_freeN(verts); - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, ELE_NEW); + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, ELE_NEW); } diff --git a/source/blender/bmesh/operators/bmo_planar_faces.c b/source/blender/bmesh/operators/bmo_planar_faces.c index f5a0e6aec74..ca336175f19 100644 --- a/source/blender/bmesh/operators/bmo_planar_faces.c +++ b/source/blender/bmesh/operators/bmo_planar_faces.c @@ -33,122 +33,124 @@ #define ELE_FACE_ADJUST (1 << 1) struct VertAccum { - float co[3]; - int co_tot; + float co[3]; + int co_tot; }; void bmo_planar_faces_exec(BMesh *bm, BMOperator *op) { - const float fac = BMO_slot_float_get(op->slots_in, "factor"); - const int iterations = BMO_slot_int_get(op->slots_in, "iterations"); - const int faces_num = BMO_slot_buffer_count(op->slots_in, "faces"); + const float fac = BMO_slot_float_get(op->slots_in, "factor"); + const int iterations = BMO_slot_int_get(op->slots_in, "iterations"); + const int faces_num = BMO_slot_buffer_count(op->slots_in, "faces"); - const float eps = 0.00001f; - const float eps_sq = SQUARE(eps); + const float eps = 0.00001f; + const float eps_sq = SQUARE(eps); - BMOIter oiter; - BMFace *f; - BLI_mempool *vert_accum_pool; - GHash *vaccum_map; - float (*faces_center)[3]; - int i, iter_step, shared_vert_num; + BMOIter oiter; + BMFace *f; + BLI_mempool *vert_accum_pool; + GHash *vaccum_map; + float(*faces_center)[3]; + int i, iter_step, shared_vert_num; - faces_center = MEM_mallocN(sizeof(*faces_center) * faces_num, __func__); + faces_center = MEM_mallocN(sizeof(*faces_center) * faces_num, __func__); - shared_vert_num = 0; - BMO_ITER_INDEX (f, &oiter, op->slots_in, "faces", BM_FACE, i) { - BMLoop *l_iter, *l_first; + shared_vert_num = 0; + BMO_ITER_INDEX(f, &oiter, op->slots_in, "faces", BM_FACE, i) + { + BMLoop *l_iter, *l_first; - if (f->len == 3) { - continue; - } + if (f->len == 3) { + continue; + } - BM_face_calc_center_median_weighted(f, faces_center[i]); + BM_face_calc_center_median_weighted(f, faces_center[i]); - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - if (!BMO_vert_flag_test(bm, l_iter->v, ELE_VERT_ADJUST)) { - BMO_vert_flag_enable(bm, l_iter->v, ELE_VERT_ADJUST); - shared_vert_num += 1; - } - } while ((l_iter = l_iter->next) != l_first); + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (!BMO_vert_flag_test(bm, l_iter->v, ELE_VERT_ADJUST)) { + BMO_vert_flag_enable(bm, l_iter->v, ELE_VERT_ADJUST); + shared_vert_num += 1; + } + } while ((l_iter = l_iter->next) != l_first); - BMO_face_flag_enable(bm, f, ELE_FACE_ADJUST); - } + BMO_face_flag_enable(bm, f, ELE_FACE_ADJUST); + } - vert_accum_pool = BLI_mempool_create(sizeof(struct VertAccum), 0, 512, BLI_MEMPOOL_NOP); - vaccum_map = BLI_ghash_ptr_new_ex(__func__, shared_vert_num); + vert_accum_pool = BLI_mempool_create(sizeof(struct VertAccum), 0, 512, BLI_MEMPOOL_NOP); + vaccum_map = BLI_ghash_ptr_new_ex(__func__, shared_vert_num); - for (iter_step = 0; iter_step < iterations; iter_step++) { - GHashIterator gh_iter; - bool changed = false; + for (iter_step = 0; iter_step < iterations; iter_step++) { + GHashIterator gh_iter; + bool changed = false; - BMO_ITER_INDEX (f, &oiter, op->slots_in, "faces", BM_FACE, i) { - BMLoop *l_iter, *l_first; - float plane[4]; + BMO_ITER_INDEX(f, &oiter, op->slots_in, "faces", BM_FACE, i) + { + BMLoop *l_iter, *l_first; + float plane[4]; - if (!BMO_face_flag_test(bm, f, ELE_FACE_ADJUST)) { - continue; - } - BMO_face_flag_disable(bm, f, ELE_FACE_ADJUST); + if (!BMO_face_flag_test(bm, f, ELE_FACE_ADJUST)) { + continue; + } + BMO_face_flag_disable(bm, f, ELE_FACE_ADJUST); - BLI_assert(f->len != 3); + BLI_assert(f->len != 3); - /* keep original face data (else we 'move' the face) */ + /* keep original face data (else we 'move' the face) */ #if 0 - BM_face_normal_update(f); - BM_face_calc_center_median_weighted(f, f_center); + BM_face_normal_update(f); + BM_face_calc_center_median_weighted(f, f_center); #endif - plane_from_point_normal_v3(plane, faces_center[i], f->no); - - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - struct VertAccum *va; - void **va_p; - float co[3]; - - if (!BLI_ghash_ensure_p(vaccum_map, l_iter->v, &va_p)) { - *va_p = BLI_mempool_calloc(vert_accum_pool); - } - va = *va_p; - - closest_to_plane_normalized_v3(co, plane, l_iter->v->co); - va->co_tot += 1; - - interp_v3_v3v3(va->co, va->co, co, 1.0f / (float)va->co_tot); - } while ((l_iter = l_iter->next) != l_first); - } - - GHASH_ITER (gh_iter, vaccum_map) { - BMVert *v = BLI_ghashIterator_getKey(&gh_iter); - struct VertAccum *va = BLI_ghashIterator_getValue(&gh_iter); - BMIter iter; - - if (len_squared_v3v3(v->co, va->co) > eps_sq) { - BMO_vert_flag_enable(bm, v, ELE_VERT_ADJUST); - interp_v3_v3v3(v->co, v->co, va->co, fac); - changed = true; - } - - /* tag for re-calculation */ - BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) { - if (f->len != 3) { - BMO_face_flag_enable(bm, f, ELE_FACE_ADJUST); - } - } - } - - /* if nothing changed, break out early */ - if (changed == false) { - break; - } - - BLI_ghash_clear(vaccum_map, NULL, NULL); - BLI_mempool_clear(vert_accum_pool); - } - - MEM_freeN(faces_center); - BLI_ghash_free(vaccum_map, NULL, NULL); - BLI_mempool_destroy(vert_accum_pool); + plane_from_point_normal_v3(plane, faces_center[i], f->no); + + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + struct VertAccum *va; + void **va_p; + float co[3]; + + if (!BLI_ghash_ensure_p(vaccum_map, l_iter->v, &va_p)) { + *va_p = BLI_mempool_calloc(vert_accum_pool); + } + va = *va_p; + + closest_to_plane_normalized_v3(co, plane, l_iter->v->co); + va->co_tot += 1; + + interp_v3_v3v3(va->co, va->co, co, 1.0f / (float)va->co_tot); + } while ((l_iter = l_iter->next) != l_first); + } + + GHASH_ITER (gh_iter, vaccum_map) { + BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + struct VertAccum *va = BLI_ghashIterator_getValue(&gh_iter); + BMIter iter; + + if (len_squared_v3v3(v->co, va->co) > eps_sq) { + BMO_vert_flag_enable(bm, v, ELE_VERT_ADJUST); + interp_v3_v3v3(v->co, v->co, va->co, fac); + changed = true; + } + + /* tag for re-calculation */ + BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) { + if (f->len != 3) { + BMO_face_flag_enable(bm, f, ELE_FACE_ADJUST); + } + } + } + + /* if nothing changed, break out early */ + if (changed == false) { + break; + } + + BLI_ghash_clear(vaccum_map, NULL, NULL); + BLI_mempool_clear(vert_accum_pool); + } + + MEM_freeN(faces_center); + BLI_ghash_free(vaccum_map, NULL, NULL); + BLI_mempool_destroy(vert_accum_pool); } diff --git a/source/blender/bmesh/operators/bmo_poke.c b/source/blender/bmesh/operators/bmo_poke.c index 2d2a13f3207..f57a2285e4a 100644 --- a/source/blender/bmesh/operators/bmo_poke.c +++ b/source/blender/bmesh/operators/bmo_poke.c @@ -41,113 +41,114 @@ */ void bmo_poke_exec(BMesh *bm, BMOperator *op) { - const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS); - BMOIter oiter; - BMFace *f; - - const float offset = BMO_slot_float_get(op->slots_in, "offset"); - const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset"); - const int center_mode = BMO_slot_int_get(op->slots_in, "center_mode"); - void (*bm_face_calc_center_fn)(const BMFace *f, float r_cent[3]); - - switch (center_mode) { - case BMOP_POKE_MEDIAN_WEIGHTED: - bm_face_calc_center_fn = BM_face_calc_center_median_weighted; - break; - case BMOP_POKE_BOUNDS: - bm_face_calc_center_fn = BM_face_calc_center_bounds; - break; - case BMOP_POKE_MEDIAN: - bm_face_calc_center_fn = BM_face_calc_center_median; - break; - default: - BLI_assert(0); - return; - } - - BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) { - BMFace *f_new; - float f_center[3], f_center_mean[3]; - BMVert *v_center = NULL; - BMLoop *l_iter, *l_first; - /* only interpolate the central loop from the face once, - * then copy to all others in the fan */ - BMLoop *l_center_example; - - /* 1.0 or the average length from the center to the face verts */ - float offset_fac; - - int i; - - bm_face_calc_center_fn(f, f_center); - v_center = BM_vert_create(bm, f_center, NULL, BM_CREATE_NOP); - BMO_vert_flag_enable(bm, v_center, ELE_NEW); - - if (cd_loop_mdisp_offset != -1) { - if (center_mode == BMOP_POKE_MEDIAN) { - copy_v3_v3(f_center_mean, f_center); - } - else { - BM_face_calc_center_median(f, f_center_mean); - } - } - - /* handled by BM_loop_interp_from_face */ - // BM_vert_interp_from_face(bm, v_center, f); - - if (use_relative_offset) { - offset_fac = 0.0f; - } - else { - offset_fac = 1.0f; - } - - i = 0; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - BMLoop *l_new; - - f_new = BM_face_create_quad_tri(bm, l_iter->v, l_iter->next->v, v_center, NULL, f, BM_CREATE_NOP); - l_new = BM_FACE_FIRST_LOOP(f_new); - - if (i == 0) { - l_center_example = l_new->prev; - BM_loop_interp_from_face(bm, l_center_example, f, true, false); - } - else { - BM_elem_attrs_copy(bm, bm, l_center_example, l_new->prev); - } - - /* Copy Loop Data */ - BM_elem_attrs_copy(bm, bm, l_iter, l_new); - BM_elem_attrs_copy(bm, bm, l_iter->next, l_new->next); - - BMO_face_flag_enable(bm, f_new, ELE_NEW); - - if (cd_loop_mdisp_offset != -1) { - float f_new_center[3]; - BM_face_calc_center_median(f_new, f_new_center); - BM_face_interp_multires_ex(bm, f_new, f, f_new_center, f_center, cd_loop_mdisp_offset); - } - - if (use_relative_offset) { - offset_fac += len_v3v3(f_center, l_iter->v->co); - } - - } while ((void)i++, (l_iter = l_iter->next) != l_first); - - if (use_relative_offset) { - offset_fac /= (float)f->len; - } - /* else remain at 1.0 */ - - copy_v3_v3(v_center->no, f->no); - madd_v3_v3fl(v_center->co, v_center->no, offset * offset_fac); - - /* Kill Face */ - BM_face_kill(bm, f); - } - - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, ELE_NEW); - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, ELE_NEW); + const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS); + BMOIter oiter; + BMFace *f; + + const float offset = BMO_slot_float_get(op->slots_in, "offset"); + const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset"); + const int center_mode = BMO_slot_int_get(op->slots_in, "center_mode"); + void (*bm_face_calc_center_fn)(const BMFace *f, float r_cent[3]); + + switch (center_mode) { + case BMOP_POKE_MEDIAN_WEIGHTED: + bm_face_calc_center_fn = BM_face_calc_center_median_weighted; + break; + case BMOP_POKE_BOUNDS: + bm_face_calc_center_fn = BM_face_calc_center_bounds; + break; + case BMOP_POKE_MEDIAN: + bm_face_calc_center_fn = BM_face_calc_center_median; + break; + default: + BLI_assert(0); + return; + } + + BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) { + BMFace *f_new; + float f_center[3], f_center_mean[3]; + BMVert *v_center = NULL; + BMLoop *l_iter, *l_first; + /* only interpolate the central loop from the face once, + * then copy to all others in the fan */ + BMLoop *l_center_example; + + /* 1.0 or the average length from the center to the face verts */ + float offset_fac; + + int i; + + bm_face_calc_center_fn(f, f_center); + v_center = BM_vert_create(bm, f_center, NULL, BM_CREATE_NOP); + BMO_vert_flag_enable(bm, v_center, ELE_NEW); + + if (cd_loop_mdisp_offset != -1) { + if (center_mode == BMOP_POKE_MEDIAN) { + copy_v3_v3(f_center_mean, f_center); + } + else { + BM_face_calc_center_median(f, f_center_mean); + } + } + + /* handled by BM_loop_interp_from_face */ + // BM_vert_interp_from_face(bm, v_center, f); + + if (use_relative_offset) { + offset_fac = 0.0f; + } + else { + offset_fac = 1.0f; + } + + i = 0; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BMLoop *l_new; + + f_new = BM_face_create_quad_tri( + bm, l_iter->v, l_iter->next->v, v_center, NULL, f, BM_CREATE_NOP); + l_new = BM_FACE_FIRST_LOOP(f_new); + + if (i == 0) { + l_center_example = l_new->prev; + BM_loop_interp_from_face(bm, l_center_example, f, true, false); + } + else { + BM_elem_attrs_copy(bm, bm, l_center_example, l_new->prev); + } + + /* Copy Loop Data */ + BM_elem_attrs_copy(bm, bm, l_iter, l_new); + BM_elem_attrs_copy(bm, bm, l_iter->next, l_new->next); + + BMO_face_flag_enable(bm, f_new, ELE_NEW); + + if (cd_loop_mdisp_offset != -1) { + float f_new_center[3]; + BM_face_calc_center_median(f_new, f_new_center); + BM_face_interp_multires_ex(bm, f_new, f, f_new_center, f_center, cd_loop_mdisp_offset); + } + + if (use_relative_offset) { + offset_fac += len_v3v3(f_center, l_iter->v->co); + } + + } while ((void)i++, (l_iter = l_iter->next) != l_first); + + if (use_relative_offset) { + offset_fac /= (float)f->len; + } + /* else remain at 1.0 */ + + copy_v3_v3(v_center->no, f->no); + madd_v3_v3fl(v_center->co, v_center->no, offset * offset_fac); + + /* Kill Face */ + BM_face_kill(bm, f); + } + + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, ELE_NEW); + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, ELE_NEW); } diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c index ae9adfbcbba..bea7c56b1d4 100644 --- a/source/blender/bmesh/operators/bmo_primitive.c +++ b/source/blender/bmesh/operators/bmo_primitive.c @@ -31,787 +31,760 @@ #include "bmesh.h" #include "intern/bmesh_operators_private.h" - /* ************************ primitives ******************* */ static const float icovert[12][3] = { - {0.0f, 0.0f, -200.0f}, - {144.72f, -105.144f, -89.443f}, - {-55.277f, -170.128, -89.443f}, - {-178.885f, 0.0f, -89.443f}, - {-55.277f, 170.128f, -89.443f}, - {144.72f, 105.144f, -89.443f}, - {55.277f, -170.128f, 89.443f}, - {-144.72f, -105.144f, 89.443f}, - {-144.72f, 105.144f, 89.443f}, - {55.277f, 170.128f, 89.443f}, - {178.885f, 0.0f, 89.443f}, - {0.0f, 0.0f, 200.0f}, + {0.0f, 0.0f, -200.0f}, + {144.72f, -105.144f, -89.443f}, + {-55.277f, -170.128, -89.443f}, + {-178.885f, 0.0f, -89.443f}, + {-55.277f, 170.128f, -89.443f}, + {144.72f, 105.144f, -89.443f}, + {55.277f, -170.128f, 89.443f}, + {-144.72f, -105.144f, 89.443f}, + {-144.72f, 105.144f, 89.443f}, + {55.277f, 170.128f, 89.443f}, + {178.885f, 0.0f, 89.443f}, + {0.0f, 0.0f, 200.0f}, }; static const short icoface[20][3] = { - {0, 1, 2}, - {1, 0, 5}, - {0, 2, 3}, - {0, 3, 4}, - {0, 4, 5}, - {1, 5, 10}, - {2, 1, 6}, - {3, 2, 7}, - {4, 3, 8}, - {5, 4, 9}, - {1, 10, 6}, - {2, 6, 7}, - {3, 7, 8}, - {4, 8, 9}, - {5, 9, 10}, - {6, 10, 11}, - {7, 6, 11}, - {8, 7, 11}, - {9, 8, 11}, - {10, 9, 11}, + {0, 1, 2}, {1, 0, 5}, {0, 2, 3}, {0, 3, 4}, {0, 4, 5}, {1, 5, 10}, {2, 1, 6}, + {3, 2, 7}, {4, 3, 8}, {5, 4, 9}, {1, 10, 6}, {2, 6, 7}, {3, 7, 8}, {4, 8, 9}, + {5, 9, 10}, {6, 10, 11}, {7, 6, 11}, {8, 7, 11}, {9, 8, 11}, {10, 9, 11}, }; -static const float icouvs[60][2] = -{ - {0.818181f, 0.000000f}, {0.727272f, 0.157461f}, {0.909090f, 0.157461f}, - {0.727272f, 0.157461f}, {0.636363f, 0.000000f}, {0.545454f, 0.157461f}, - {0.090909f, 0.000000f}, {0.000000f, 0.157461f}, {0.181818f, 0.157461f}, - {0.272727f, 0.000000f}, {0.181818f, 0.157461f}, {0.363636f, 0.157461f}, - {0.454545f, 0.000000f}, {0.363636f, 0.157461f}, {0.545454f, 0.157461f}, - {0.727272f, 0.157461f}, {0.545454f, 0.157461f}, {0.636363f, 0.314921f}, - {0.909090f, 0.157461f}, {0.727272f, 0.157461f}, {0.818181f, 0.314921f}, - {0.181818f, 0.157461f}, {0.000000f, 0.157461f}, {0.090909f, 0.314921f}, - {0.363636f, 0.157461f}, {0.181818f, 0.157461f}, {0.272727f, 0.314921f}, - {0.545454f, 0.157461f}, {0.363636f, 0.157461f}, {0.454545f, 0.314921f}, - {0.727272f, 0.157461f}, {0.636363f, 0.314921f}, {0.818181f, 0.314921f}, - {0.909090f, 0.157461f}, {0.818181f, 0.314921f}, {1.000000f, 0.314921f}, - {0.181818f, 0.157461f}, {0.090909f, 0.314921f}, {0.272727f, 0.314921f}, - {0.363636f, 0.157461f}, {0.272727f, 0.314921f}, {0.454545f, 0.314921f}, - {0.545454f, 0.157461f}, {0.454545f, 0.314921f}, {0.636363f, 0.314921f}, - {0.818181f, 0.314921f}, {0.636363f, 0.314921f}, {0.727272f, 0.472382f}, - {1.000000f, 0.314921f}, {0.818181f, 0.314921f}, {0.909090f, 0.472382f}, - {0.272727f, 0.314921f}, {0.090909f, 0.314921f}, {0.181818f, 0.472382f}, - {0.454545f, 0.314921f}, {0.272727f, 0.314921f}, {0.363636f, 0.472382f}, - {0.636363f, 0.314921f}, {0.454545f, 0.314921f}, {0.545454f, 0.472382f}, +static const float icouvs[60][2] = { + {0.818181f, 0.000000f}, {0.727272f, 0.157461f}, {0.909090f, 0.157461f}, {0.727272f, 0.157461f}, + {0.636363f, 0.000000f}, {0.545454f, 0.157461f}, {0.090909f, 0.000000f}, {0.000000f, 0.157461f}, + {0.181818f, 0.157461f}, {0.272727f, 0.000000f}, {0.181818f, 0.157461f}, {0.363636f, 0.157461f}, + {0.454545f, 0.000000f}, {0.363636f, 0.157461f}, {0.545454f, 0.157461f}, {0.727272f, 0.157461f}, + {0.545454f, 0.157461f}, {0.636363f, 0.314921f}, {0.909090f, 0.157461f}, {0.727272f, 0.157461f}, + {0.818181f, 0.314921f}, {0.181818f, 0.157461f}, {0.000000f, 0.157461f}, {0.090909f, 0.314921f}, + {0.363636f, 0.157461f}, {0.181818f, 0.157461f}, {0.272727f, 0.314921f}, {0.545454f, 0.157461f}, + {0.363636f, 0.157461f}, {0.454545f, 0.314921f}, {0.727272f, 0.157461f}, {0.636363f, 0.314921f}, + {0.818181f, 0.314921f}, {0.909090f, 0.157461f}, {0.818181f, 0.314921f}, {1.000000f, 0.314921f}, + {0.181818f, 0.157461f}, {0.090909f, 0.314921f}, {0.272727f, 0.314921f}, {0.363636f, 0.157461f}, + {0.272727f, 0.314921f}, {0.454545f, 0.314921f}, {0.545454f, 0.157461f}, {0.454545f, 0.314921f}, + {0.636363f, 0.314921f}, {0.818181f, 0.314921f}, {0.636363f, 0.314921f}, {0.727272f, 0.472382f}, + {1.000000f, 0.314921f}, {0.818181f, 0.314921f}, {0.909090f, 0.472382f}, {0.272727f, 0.314921f}, + {0.090909f, 0.314921f}, {0.181818f, 0.472382f}, {0.454545f, 0.314921f}, {0.272727f, 0.314921f}, + {0.363636f, 0.472382f}, {0.636363f, 0.314921f}, {0.454545f, 0.314921f}, {0.545454f, 0.472382f}, }; - static const int monkeyo = 4; static const int monkeynv = 271; static const int monkeynf = 250; static const signed char monkeyv[271][3] = { - {-71, 21, 98}, {-63, 12, 88}, {-57, 7, 74}, {-82, -3, 79}, {-82, 4, 92}, - {-82, 17, 100}, {-92, 21, 102}, {-101, 12, 95}, {-107, 7, 83}, - {-117, 31, 84}, {-109, 31, 95}, {-96, 31, 102}, {-92, 42, 102}, - {-101, 50, 95}, {-107, 56, 83}, {-82, 66, 79}, {-82, 58, 92}, - {-82, 46, 100}, {-71, 42, 98}, {-63, 50, 88}, {-57, 56, 74}, - {-47, 31, 72}, {-55, 31, 86}, {-67, 31, 97}, {-66, 31, 99}, - {-70, 43, 100}, {-82, 48, 103}, {-93, 43, 105}, {-98, 31, 105}, - {-93, 20, 105}, {-82, 31, 106}, {-82, 15, 103}, {-70, 20, 100}, - {-127, 55, 95}, {-127, 45, 105}, {-127, -87, 94}, {-127, -41, 100}, - {-127, -24, 102}, {-127, -99, 92}, {-127, 52, 77}, {-127, 73, 73}, - {-127, 115, -70}, {-127, 72, -109}, {-127, 9, -106}, {-127, -49, -45}, - {-101, -24, 72}, {-87, -56, 73}, {-82, -89, 73}, {-80, -114, 68}, - {-85, -121, 67}, {-104, -124, 71}, {-127, -126, 74}, {-71, -18, 68}, - {-46, -5, 69}, {-21, 19, 57}, {-17, 55, 76}, {-36, 62, 80}, - {-64, 77, 88}, {-86, 97, 94}, {-107, 92, 97}, {-119, 63, 96}, - {-106, 53, 99}, {-111, 39, 98}, {-101, 12, 95}, {-79, 2, 90}, - {-64, 8, 86}, {-47, 24, 83}, {-45, 38, 83}, {-50, 48, 85}, - {-72, 56, 92}, {-95, 60, 97}, {-127, -98, 94}, {-113, -92, 94}, - {-112, -107, 91}, {-119, -113, 89}, {-127, -114, 88}, {-127, -25, 96}, - {-127, -18, 95}, {-114, -19, 95}, {-111, -29, 96}, {-116, -37, 95}, - {-76, -6, 86}, {-48, 7, 80}, {-34, 26, 77}, {-32, 48, 84}, - {-39, 53, 93}, {-71, 70, 102}, {-87, 82, 107}, {-101, 79, 109}, - {-114, 55, 108}, {-111, -13, 104}, {-100, -57, 91}, {-95, -90, 88}, - {-93, -105, 85}, {-97, -117, 81}, {-106, -119, 81}, {-127, -121, 82}, - {-127, 6, 93}, {-127, 27, 98}, {-85, 61, 95}, {-106, 18, 96}, - {-110, 27, 97}, {-112, -88, 94}, {-117, -57, 96}, {-127, -57, 96}, - {-127, -42, 95}, {-115, -35, 100}, {-110, -29, 102}, {-113, -17, 100}, - {-122, -16, 100}, {-127, -26, 106}, {-121, -19, 104}, {-115, -20, 104}, - {-113, -29, 106}, {-117, -32, 103}, {-127, -37, 103}, {-94, -40, 71}, - {-106, -31, 91}, {-104, -40, 91}, {-97, -32, 71}, {-127, -112, 88}, - {-121, -111, 88}, {-115, -105, 91}, {-115, -95, 93}, {-127, -100, 84}, - {-115, -96, 85}, {-115, -104, 82}, {-121, -109, 81}, {-127, -110, 81}, - {-105, 28, 100}, {-103, 20, 99}, {-84, 55, 97}, {-92, 54, 99}, - {-73, 51, 99}, {-55, 45, 89}, {-52, 37, 88}, {-53, 25, 87}, - {-66, 13, 92}, {-79, 8, 95}, {-98, 14, 100}, {-104, 38, 100}, - {-100, 48, 100}, {-97, 46, 97}, {-102, 38, 97}, {-96, 16, 97}, - {-79, 11, 93}, {-68, 15, 90}, {-57, 27, 86}, {-56, 36, 86}, - {-59, 43, 87}, {-74, 50, 96}, {-91, 51, 98}, {-84, 52, 96}, - {-101, 22, 96}, {-102, 29, 96}, {-113, 59, 78}, {-102, 85, 79}, - {-84, 88, 76}, {-65, 71, 71}, {-40, 58, 63}, {-25, 52, 59}, - {-28, 21, 48}, {-50, 0, 53}, {-71, -12, 60}, {-127, 115, 37}, - {-127, 126, -10}, {-127, -25, -86}, {-127, -59, 24}, {-127, -125, 59}, - {-127, -103, 44}, {-127, -73, 41}, {-127, -62, 36}, {-18, 30, 7}, - {-17, 41, -6}, {-28, 34, -56}, {-68, 56, -90}, {-33, -6, 9}, - {-51, -16, -21}, {-45, -1, -55}, {-84, 7, -85}, {-97, -45, 52}, - {-104, -53, 33}, {-90, -91, 49}, {-95, -64, 50}, {-85, -117, 51}, - {-109, -97, 47}, {-111, -69, 46}, {-106, -121, 56}, {-99, -36, 55}, - {-100, -29, 60}, {-101, -22, 64}, {-100, -50, 21}, {-89, -40, -34}, - {-83, -19, -69}, {-69, 111, -49}, {-69, 119, -9}, {-69, 109, 30}, - {-68, 67, 55}, {-34, 52, 43}, {-46, 58, 36}, {-45, 90, 7}, - {-25, 72, 16}, {-25, 79, -15}, {-45, 96, -25}, {-45, 87, -57}, - {-25, 69, -46}, {-48, 42, -75}, {-65, 3, -70}, {-22, 42, -26}, - {-75, -22, 19}, {-72, -25, -27}, {-13, 52, -30}, {-28, -18, -16}, - {6, -13, -42}, {37, 7, -55}, {46, 41, -54}, {31, 65, -54}, - {4, 61, -40}, {3, 53, -37}, {25, 56, -50}, {35, 37, -52}, - {28, 10, -52}, {5, -5, -39}, {-21, -9, -17}, {-9, 46, -28}, - {-6, 39, -37}, {-14, -3, -27}, {6, 0, -47}, {25, 12, -57}, - {31, 32, -57}, {23, 46, -56}, {4, 44, -46}, {-19, 37, -27}, - {-20, 22, -35}, {-30, 12, -35}, {-22, 11, -35}, {-19, 2, -35}, - {-23, -2, -35}, {-34, 0, -9}, {-35, -3, -22}, {-35, 5, -24}, - {-25, 26, -27}, {-13, 31, -34}, {-13, 30, -41}, {-23, -2, -41}, - {-18, 2, -41}, {-21, 10, -41}, {-29, 12, -41}, {-19, 22, -41}, - {6, 42, -53}, {25, 44, -62}, {34, 31, -63}, {28, 11, -62}, - {7, 0, -54}, {-14, -2, -34}, {-5, 37, -44}, {-13, 14, -42}, - {-7, 8, -43}, {1, 16, -47}, {-4, 22, -45}, {3, 30, -48}, - {8, 24, -49}, {15, 27, -50}, {12, 35, -50}, {4, 56, -62}, - {33, 60, -70}, {48, 38, -64}, {41, 7, -68}, {6, -11, -63}, - {-26, -16, -42}, {-17, 49, -49}, + {-71, 21, 98}, {-63, 12, 88}, {-57, 7, 74}, {-82, -3, 79}, {-82, 4, 92}, + {-82, 17, 100}, {-92, 21, 102}, {-101, 12, 95}, {-107, 7, 83}, {-117, 31, 84}, + {-109, 31, 95}, {-96, 31, 102}, {-92, 42, 102}, {-101, 50, 95}, {-107, 56, 83}, + {-82, 66, 79}, {-82, 58, 92}, {-82, 46, 100}, {-71, 42, 98}, {-63, 50, 88}, + {-57, 56, 74}, {-47, 31, 72}, {-55, 31, 86}, {-67, 31, 97}, {-66, 31, 99}, + {-70, 43, 100}, {-82, 48, 103}, {-93, 43, 105}, {-98, 31, 105}, {-93, 20, 105}, + {-82, 31, 106}, {-82, 15, 103}, {-70, 20, 100}, {-127, 55, 95}, {-127, 45, 105}, + {-127, -87, 94}, {-127, -41, 100}, {-127, -24, 102}, {-127, -99, 92}, {-127, 52, 77}, + {-127, 73, 73}, {-127, 115, -70}, {-127, 72, -109}, {-127, 9, -106}, {-127, -49, -45}, + {-101, -24, 72}, {-87, -56, 73}, {-82, -89, 73}, {-80, -114, 68}, {-85, -121, 67}, + {-104, -124, 71}, {-127, -126, 74}, {-71, -18, 68}, {-46, -5, 69}, {-21, 19, 57}, + {-17, 55, 76}, {-36, 62, 80}, {-64, 77, 88}, {-86, 97, 94}, {-107, 92, 97}, + {-119, 63, 96}, {-106, 53, 99}, {-111, 39, 98}, {-101, 12, 95}, {-79, 2, 90}, + {-64, 8, 86}, {-47, 24, 83}, {-45, 38, 83}, {-50, 48, 85}, {-72, 56, 92}, + {-95, 60, 97}, {-127, -98, 94}, {-113, -92, 94}, {-112, -107, 91}, {-119, -113, 89}, + {-127, -114, 88}, {-127, -25, 96}, {-127, -18, 95}, {-114, -19, 95}, {-111, -29, 96}, + {-116, -37, 95}, {-76, -6, 86}, {-48, 7, 80}, {-34, 26, 77}, {-32, 48, 84}, + {-39, 53, 93}, {-71, 70, 102}, {-87, 82, 107}, {-101, 79, 109}, {-114, 55, 108}, + {-111, -13, 104}, {-100, -57, 91}, {-95, -90, 88}, {-93, -105, 85}, {-97, -117, 81}, + {-106, -119, 81}, {-127, -121, 82}, {-127, 6, 93}, {-127, 27, 98}, {-85, 61, 95}, + {-106, 18, 96}, {-110, 27, 97}, {-112, -88, 94}, {-117, -57, 96}, {-127, -57, 96}, + {-127, -42, 95}, {-115, -35, 100}, {-110, -29, 102}, {-113, -17, 100}, {-122, -16, 100}, + {-127, -26, 106}, {-121, -19, 104}, {-115, -20, 104}, {-113, -29, 106}, {-117, -32, 103}, + {-127, -37, 103}, {-94, -40, 71}, {-106, -31, 91}, {-104, -40, 91}, {-97, -32, 71}, + {-127, -112, 88}, {-121, -111, 88}, {-115, -105, 91}, {-115, -95, 93}, {-127, -100, 84}, + {-115, -96, 85}, {-115, -104, 82}, {-121, -109, 81}, {-127, -110, 81}, {-105, 28, 100}, + {-103, 20, 99}, {-84, 55, 97}, {-92, 54, 99}, {-73, 51, 99}, {-55, 45, 89}, + {-52, 37, 88}, {-53, 25, 87}, {-66, 13, 92}, {-79, 8, 95}, {-98, 14, 100}, + {-104, 38, 100}, {-100, 48, 100}, {-97, 46, 97}, {-102, 38, 97}, {-96, 16, 97}, + {-79, 11, 93}, {-68, 15, 90}, {-57, 27, 86}, {-56, 36, 86}, {-59, 43, 87}, + {-74, 50, 96}, {-91, 51, 98}, {-84, 52, 96}, {-101, 22, 96}, {-102, 29, 96}, + {-113, 59, 78}, {-102, 85, 79}, {-84, 88, 76}, {-65, 71, 71}, {-40, 58, 63}, + {-25, 52, 59}, {-28, 21, 48}, {-50, 0, 53}, {-71, -12, 60}, {-127, 115, 37}, + {-127, 126, -10}, {-127, -25, -86}, {-127, -59, 24}, {-127, -125, 59}, {-127, -103, 44}, + {-127, -73, 41}, {-127, -62, 36}, {-18, 30, 7}, {-17, 41, -6}, {-28, 34, -56}, + {-68, 56, -90}, {-33, -6, 9}, {-51, -16, -21}, {-45, -1, -55}, {-84, 7, -85}, + {-97, -45, 52}, {-104, -53, 33}, {-90, -91, 49}, {-95, -64, 50}, {-85, -117, 51}, + {-109, -97, 47}, {-111, -69, 46}, {-106, -121, 56}, {-99, -36, 55}, {-100, -29, 60}, + {-101, -22, 64}, {-100, -50, 21}, {-89, -40, -34}, {-83, -19, -69}, {-69, 111, -49}, + {-69, 119, -9}, {-69, 109, 30}, {-68, 67, 55}, {-34, 52, 43}, {-46, 58, 36}, + {-45, 90, 7}, {-25, 72, 16}, {-25, 79, -15}, {-45, 96, -25}, {-45, 87, -57}, + {-25, 69, -46}, {-48, 42, -75}, {-65, 3, -70}, {-22, 42, -26}, {-75, -22, 19}, + {-72, -25, -27}, {-13, 52, -30}, {-28, -18, -16}, {6, -13, -42}, {37, 7, -55}, + {46, 41, -54}, {31, 65, -54}, {4, 61, -40}, {3, 53, -37}, {25, 56, -50}, + {35, 37, -52}, {28, 10, -52}, {5, -5, -39}, {-21, -9, -17}, {-9, 46, -28}, + {-6, 39, -37}, {-14, -3, -27}, {6, 0, -47}, {25, 12, -57}, {31, 32, -57}, + {23, 46, -56}, {4, 44, -46}, {-19, 37, -27}, {-20, 22, -35}, {-30, 12, -35}, + {-22, 11, -35}, {-19, 2, -35}, {-23, -2, -35}, {-34, 0, -9}, {-35, -3, -22}, + {-35, 5, -24}, {-25, 26, -27}, {-13, 31, -34}, {-13, 30, -41}, {-23, -2, -41}, + {-18, 2, -41}, {-21, 10, -41}, {-29, 12, -41}, {-19, 22, -41}, {6, 42, -53}, + {25, 44, -62}, {34, 31, -63}, {28, 11, -62}, {7, 0, -54}, {-14, -2, -34}, + {-5, 37, -44}, {-13, 14, -42}, {-7, 8, -43}, {1, 16, -47}, {-4, 22, -45}, + {3, 30, -48}, {8, 24, -49}, {15, 27, -50}, {12, 35, -50}, {4, 56, -62}, + {33, 60, -70}, {48, 38, -64}, {41, 7, -68}, {6, -11, -63}, {-26, -16, -42}, + {-17, 49, -49}, }; static signed char monkeyf[250][4] = { - {27, 4, 5, 26}, {25, 4, 5, 24}, {3, 6, 5, 4}, {1, 6, 5, 2}, {5, 6, 7, 4}, - {3, 6, 7, 2}, {5, 8, 7, 6}, {3, 8, 7, 4}, {7, 8, 9, 6}, - {5, 8, 9, 4}, {7, 10, 9, 8}, {5, 10, 9, 6}, {9, 10, 11, 8}, - {7, 10, 11, 6}, {9, 12, 11, 10}, {7, 12, 11, 8}, {11, 6, 13, 12}, - {5, 4, 13, 12}, {3, -2, 13, 12}, {-3, -4, 13, 12}, {-5, -10, 13, 12}, - {-11, -12, 14, 12}, {-13, -18, 14, 13}, {-19, 4, 5, 13}, {10, 12, 4, 4}, - {10, 11, 9, 9}, {8, 7, 9, 9}, {7, 5, 6, 6}, {6, 3, 4, 4}, - {5, 1, 2, 2}, {4, -1, 0, 0}, {3, -3, -2, -2}, {22, 67, 68, 23}, - {20, 65, 66, 21}, {18, 63, 64, 19}, {16, 61, 62, 17}, {14, 59, 60, 15}, - {12, 19, 48, 57}, {18, 19, 48, 47}, {18, 19, 48, 47}, {18, 19, 48, 47}, - {18, 19, 48, 47}, {18, 19, 48, 47}, {18, 19, 48, 47}, {18, 19, 48, 47}, - {18, 19, 48, 47}, {18, -9, -8, 47}, {18, 27, 45, 46}, {26, 55, 43, 44}, - {24, 41, 42, 54}, {22, 39, 40, 23}, {20, 37, 38, 21}, {18, 35, 36, 19}, - {16, 33, 34, 17}, {14, 31, 32, 15}, {12, 39, 30, 13}, {11, 48, 45, 38}, - {8, 36, -19, 9}, {8, -20, 44, 47}, {42, 45, 46, 43}, {18, 19, 40, 39}, - {16, 17, 38, 37}, {14, 15, 36, 35}, {32, 44, 43, 33}, {12, 33, 32, 42}, - {19, 44, 43, 42}, {40, 41, 42, -27}, {8, 9, 39, -28}, {15, 43, 42, 16}, - {13, 43, 42, 14}, {11, 43, 42, 12}, {9, -30, 42, 10}, {37, 12, 38, -32}, - {-33, 37, 45, 46}, {-33, 40, 41, 39}, {38, 40, 41, 37}, {36, 40, 41, 35}, - {34, 40, 41, 33}, {36, 39, 38, 37}, {35, 40, 39, 38}, {1, 2, 14, 21}, - {1, 2, 40, 13}, {1, 2, 40, 39}, {1, 24, 12, 39}, {-34, 36, 38, 11}, - {35, 38, 36, 37}, {-37, 8, 35, 37}, {-11, -12, -45, 40}, {-11, -12, 39, 38}, - {-11, -12, 37, 36}, {-11, -12, 35, 34}, {33, 34, 40, 41}, {33, 34, 38, 39}, - {33, 34, 36, 37}, {33, -52, 34, 35}, {33, 37, 36, 34}, {33, 35, 34, 34}, - {8, 7, 37, 36}, {-32, 7, 35, 46}, {-34, -33, 45, 46}, {4, -33, 43, 34}, - {-34, -33, 41, 42}, {-34, -33, 39, 40}, {-34, -33, 37, 38}, {-34, -33, 35, 36}, - {-34, -33, 33, 34}, {-34, -33, 31, 32}, {-34, -4, 28, 30}, {-5, -34, 28, 27}, - {-35, -44, 36, 27}, {26, 35, 36, 45}, {24, 25, 44, 45}, {25, 23, 44, 42}, - {25, 24, 41, 40}, {25, 24, 39, 38}, {25, 24, 37, 36}, {25, 24, 35, 34}, - {25, 24, 33, 32}, {25, 24, 31, 30}, {15, 24, 29, 38}, {25, 24, 27, 26}, - {23, 12, 37, 26}, {11, 12, 35, 36}, {-86, -59, 36, -80}, {-60, -61, 36, 35}, - {-62, -63, 36, 35}, {-64, -65, 36, 35}, {-66, -67, 36, 35}, {-68, -69, 36, 35}, - {-70, -71, 36, 35}, {-72, -73, 36, 35}, {-74, -75, 36, 35}, {42, 43, 53, 58}, - {40, 41, 57, 56}, {38, 39, 55, 57}, {-81, -80, 37, 56}, {-83, -82, 55, 52}, - {-85, -84, 51, 49}, {-87, -86, 48, 49}, {47, 50, 51, 48}, {46, 48, 51, 49}, - {43, 46, 49, 44}, {-92, -91, 45, 42}, {-23, 49, 50, -20}, {-94, 40, 48, -24}, - {-96, -22, 48, 49}, {-97, 48, 21, -90}, {-100, 36, 50, 23}, {22, 49, 48, -100}, - {-101, 47, 46, 22}, {21, 45, 35, 25}, {33, 34, 44, 41}, {13, 14, 28, 24}, - {-107, 26, 30, -106}, {14, 46, 45, 15}, {14, 44, 43, -110}, {-111, 42, 23, -110}, - {6, 7, 45, 46}, {45, 44, 47, 46}, {45, 46, 47, 48}, {47, 46, 49, 48}, - {17, 49, 47, 48}, {17, 36, 46, 48}, {35, 36, 44, 45}, {35, 36, 40, 43}, - {35, 36, 38, 39}, {-4, -3, 37, 35}, {-123, 34, 33, 1}, {-9, -8, -7, -6}, - {-10, -7, 32, -125}, {-127, -11, -126, -126}, {-7, -6, 5, 31}, {4, 5, 33, 30}, - {4, 39, 33, 32}, {4, 35, 32, 38}, {20, 21, 39, 38}, {4, 37, 38, 5}, - {-11, -10, 36, 3}, {-11, 15, 14, 35}, {13, 16, 34, 34}, {-13, 14, 13, 13}, - {-3, 1, 30, 29}, {-3, 28, 29, 1}, {-2, 31, 28, -1}, {12, 13, 27, 30}, - {-2, 26, 12, 12}, {35, 29, 42, 36}, {34, 35, 36, 33}, {32, 35, 36, 31}, - {30, 35, 36, 29}, {28, 35, 36, 27}, {26, 35, 36, 25}, {34, 39, 38, 35}, - {32, 39, 38, 33}, {30, 39, 38, 31}, {28, 39, 38, 29}, {26, 39, 38, 27}, - {25, 31, 32, 38}, {-18, -17, 45, 44}, {-18, 17, 28, 44}, {-24, -20, 42, -23}, - {11, 35, 27, 14}, {25, 28, 39, 41}, {37, 41, 40, 38}, {34, 40, 36, 35}, - {32, 40, 39, 33}, {30, 39, 31, 40}, {21, 29, 39, 22}, {-31, 37, 28, 4}, - {-32, 33, 35, 36}, {32, 33, 34, 34}, {18, 35, 36, 48}, {34, 25, 40, 35}, - {24, 25, 38, 39}, {24, 25, 36, 37}, {24, 25, 34, 35}, {24, 25, 32, 33}, - {24, 13, 41, 31}, {17, 11, 41, 35}, {15, 16, 34, 35}, {13, 14, 34, 35}, - {11, 12, 34, 35}, {9, 10, 34, 35}, {7, 8, 34, 35}, {26, 25, 37, 36}, - {35, 36, 37, 38}, {37, 36, 39, 38}, {37, 38, 39, 40}, {25, 31, 36, 39}, - {18, 34, 35, 30}, {17, 22, 30, 33}, {19, 29, 21, 20}, {16, 26, 29, 17}, - {24, 29, 28, 25}, {22, 31, 28, 23}, {20, 31, 30, 21}, {18, 31, 30, 19}, - {16, 30, 17, 17}, {-21, -22, 35, 34}, {-21, -22, 33, 32}, {-21, -22, 31, 30}, - {-21, -22, 29, 28}, {-21, -22, 27, 26}, {-28, -22, 25, 31}, {24, 28, 29, 30}, - {23, 24, 26, 27}, {23, 24, 25, 25}, {-69, -35, -32, 27}, {-70, 26, 25, -66}, - {-68, -67, 24, -33}, + {27, 4, 5, 26}, {25, 4, 5, 24}, {3, 6, 5, 4}, + {1, 6, 5, 2}, {5, 6, 7, 4}, {3, 6, 7, 2}, + {5, 8, 7, 6}, {3, 8, 7, 4}, {7, 8, 9, 6}, + {5, 8, 9, 4}, {7, 10, 9, 8}, {5, 10, 9, 6}, + {9, 10, 11, 8}, {7, 10, 11, 6}, {9, 12, 11, 10}, + {7, 12, 11, 8}, {11, 6, 13, 12}, {5, 4, 13, 12}, + {3, -2, 13, 12}, {-3, -4, 13, 12}, {-5, -10, 13, 12}, + {-11, -12, 14, 12}, {-13, -18, 14, 13}, {-19, 4, 5, 13}, + {10, 12, 4, 4}, {10, 11, 9, 9}, {8, 7, 9, 9}, + {7, 5, 6, 6}, {6, 3, 4, 4}, {5, 1, 2, 2}, + {4, -1, 0, 0}, {3, -3, -2, -2}, {22, 67, 68, 23}, + {20, 65, 66, 21}, {18, 63, 64, 19}, {16, 61, 62, 17}, + {14, 59, 60, 15}, {12, 19, 48, 57}, {18, 19, 48, 47}, + {18, 19, 48, 47}, {18, 19, 48, 47}, {18, 19, 48, 47}, + {18, 19, 48, 47}, {18, 19, 48, 47}, {18, 19, 48, 47}, + {18, 19, 48, 47}, {18, -9, -8, 47}, {18, 27, 45, 46}, + {26, 55, 43, 44}, {24, 41, 42, 54}, {22, 39, 40, 23}, + {20, 37, 38, 21}, {18, 35, 36, 19}, {16, 33, 34, 17}, + {14, 31, 32, 15}, {12, 39, 30, 13}, {11, 48, 45, 38}, + {8, 36, -19, 9}, {8, -20, 44, 47}, {42, 45, 46, 43}, + {18, 19, 40, 39}, {16, 17, 38, 37}, {14, 15, 36, 35}, + {32, 44, 43, 33}, {12, 33, 32, 42}, {19, 44, 43, 42}, + {40, 41, 42, -27}, {8, 9, 39, -28}, {15, 43, 42, 16}, + {13, 43, 42, 14}, {11, 43, 42, 12}, {9, -30, 42, 10}, + {37, 12, 38, -32}, {-33, 37, 45, 46}, {-33, 40, 41, 39}, + {38, 40, 41, 37}, {36, 40, 41, 35}, {34, 40, 41, 33}, + {36, 39, 38, 37}, {35, 40, 39, 38}, {1, 2, 14, 21}, + {1, 2, 40, 13}, {1, 2, 40, 39}, {1, 24, 12, 39}, + {-34, 36, 38, 11}, {35, 38, 36, 37}, {-37, 8, 35, 37}, + {-11, -12, -45, 40}, {-11, -12, 39, 38}, {-11, -12, 37, 36}, + {-11, -12, 35, 34}, {33, 34, 40, 41}, {33, 34, 38, 39}, + {33, 34, 36, 37}, {33, -52, 34, 35}, {33, 37, 36, 34}, + {33, 35, 34, 34}, {8, 7, 37, 36}, {-32, 7, 35, 46}, + {-34, -33, 45, 46}, {4, -33, 43, 34}, {-34, -33, 41, 42}, + {-34, -33, 39, 40}, {-34, -33, 37, 38}, {-34, -33, 35, 36}, + {-34, -33, 33, 34}, {-34, -33, 31, 32}, {-34, -4, 28, 30}, + {-5, -34, 28, 27}, {-35, -44, 36, 27}, {26, 35, 36, 45}, + {24, 25, 44, 45}, {25, 23, 44, 42}, {25, 24, 41, 40}, + {25, 24, 39, 38}, {25, 24, 37, 36}, {25, 24, 35, 34}, + {25, 24, 33, 32}, {25, 24, 31, 30}, {15, 24, 29, 38}, + {25, 24, 27, 26}, {23, 12, 37, 26}, {11, 12, 35, 36}, + {-86, -59, 36, -80}, {-60, -61, 36, 35}, {-62, -63, 36, 35}, + {-64, -65, 36, 35}, {-66, -67, 36, 35}, {-68, -69, 36, 35}, + {-70, -71, 36, 35}, {-72, -73, 36, 35}, {-74, -75, 36, 35}, + {42, 43, 53, 58}, {40, 41, 57, 56}, {38, 39, 55, 57}, + {-81, -80, 37, 56}, {-83, -82, 55, 52}, {-85, -84, 51, 49}, + {-87, -86, 48, 49}, {47, 50, 51, 48}, {46, 48, 51, 49}, + {43, 46, 49, 44}, {-92, -91, 45, 42}, {-23, 49, 50, -20}, + {-94, 40, 48, -24}, {-96, -22, 48, 49}, {-97, 48, 21, -90}, + {-100, 36, 50, 23}, {22, 49, 48, -100}, {-101, 47, 46, 22}, + {21, 45, 35, 25}, {33, 34, 44, 41}, {13, 14, 28, 24}, + {-107, 26, 30, -106}, {14, 46, 45, 15}, {14, 44, 43, -110}, + {-111, 42, 23, -110}, {6, 7, 45, 46}, {45, 44, 47, 46}, + {45, 46, 47, 48}, {47, 46, 49, 48}, {17, 49, 47, 48}, + {17, 36, 46, 48}, {35, 36, 44, 45}, {35, 36, 40, 43}, + {35, 36, 38, 39}, {-4, -3, 37, 35}, {-123, 34, 33, 1}, + {-9, -8, -7, -6}, {-10, -7, 32, -125}, {-127, -11, -126, -126}, + {-7, -6, 5, 31}, {4, 5, 33, 30}, {4, 39, 33, 32}, + {4, 35, 32, 38}, {20, 21, 39, 38}, {4, 37, 38, 5}, + {-11, -10, 36, 3}, {-11, 15, 14, 35}, {13, 16, 34, 34}, + {-13, 14, 13, 13}, {-3, 1, 30, 29}, {-3, 28, 29, 1}, + {-2, 31, 28, -1}, {12, 13, 27, 30}, {-2, 26, 12, 12}, + {35, 29, 42, 36}, {34, 35, 36, 33}, {32, 35, 36, 31}, + {30, 35, 36, 29}, {28, 35, 36, 27}, {26, 35, 36, 25}, + {34, 39, 38, 35}, {32, 39, 38, 33}, {30, 39, 38, 31}, + {28, 39, 38, 29}, {26, 39, 38, 27}, {25, 31, 32, 38}, + {-18, -17, 45, 44}, {-18, 17, 28, 44}, {-24, -20, 42, -23}, + {11, 35, 27, 14}, {25, 28, 39, 41}, {37, 41, 40, 38}, + {34, 40, 36, 35}, {32, 40, 39, 33}, {30, 39, 31, 40}, + {21, 29, 39, 22}, {-31, 37, 28, 4}, {-32, 33, 35, 36}, + {32, 33, 34, 34}, {18, 35, 36, 48}, {34, 25, 40, 35}, + {24, 25, 38, 39}, {24, 25, 36, 37}, {24, 25, 34, 35}, + {24, 25, 32, 33}, {24, 13, 41, 31}, {17, 11, 41, 35}, + {15, 16, 34, 35}, {13, 14, 34, 35}, {11, 12, 34, 35}, + {9, 10, 34, 35}, {7, 8, 34, 35}, {26, 25, 37, 36}, + {35, 36, 37, 38}, {37, 36, 39, 38}, {37, 38, 39, 40}, + {25, 31, 36, 39}, {18, 34, 35, 30}, {17, 22, 30, 33}, + {19, 29, 21, 20}, {16, 26, 29, 17}, {24, 29, 28, 25}, + {22, 31, 28, 23}, {20, 31, 30, 21}, {18, 31, 30, 19}, + {16, 30, 17, 17}, {-21, -22, 35, 34}, {-21, -22, 33, 32}, + {-21, -22, 31, 30}, {-21, -22, 29, 28}, {-21, -22, 27, 26}, + {-28, -22, 25, 31}, {24, 28, 29, 30}, {23, 24, 26, 27}, + {23, 24, 25, 25}, {-69, -35, -32, 27}, {-70, 26, 25, -66}, + {-68, -67, 24, -33}, }; -static const float monkeyuvs[] = -{ - 0.890955f, 0.590063f, 0.870622f, 0.589649f, 0.860081f, 0.560115f, 0.904571f, 0.559404f, - 0.856226f, 0.850547f, 0.868067f, 0.821510f, 0.888398f, 0.821999f, 0.900640f, 0.853232f, - 0.904571f, 0.559404f, 0.860081f, 0.560115f, 0.853018f, 0.521562f, 0.920166f, 0.524546f, - 0.847458f, 0.888748f, 0.856226f, 0.850547f, 0.900640f, 0.853232f, 0.914672f, 0.888748f, - 0.860081f, 0.560115f, 0.828900f, 0.590771f, 0.798481f, 0.569535f, 0.853018f, 0.521562f, - 0.795104f, 0.838402f, 0.826436f, 0.818537f, 0.856226f, 0.850547f, 0.847458f, 0.888748f, - 0.870622f, 0.589649f, 0.854402f, 0.604754f, 0.828900f, 0.590771f, 0.860081f, 0.560115f, - 0.826436f, 0.818537f, 0.852534f, 0.805700f, 0.868067f, 0.821510f, 0.856226f, 0.850547f, - 0.854402f, 0.604754f, 0.854107f, 0.625459f, 0.828171f, 0.633354f, 0.828900f, 0.590771f, - 0.827598f, 0.775964f, 0.853157f, 0.785002f, 0.852534f, 0.805700f, 0.826436f, 0.818537f, - 0.828900f, 0.590771f, 0.828171f, 0.633354f, 0.791018f, 0.645443f, 0.798481f, 0.569535f, - 0.791018f, 0.762238f, 0.827598f, 0.775964f, 0.826436f, 0.818537f, 0.795104f, 0.838402f, - 0.828171f, 0.633354f, 0.855181f, 0.668527f, 0.842358f, 0.702491f, 0.791018f, 0.645443f, - 0.844839f, 0.707525f, 0.856142f, 0.742025f, 0.827598f, 0.775964f, 0.791018f, 0.762238f, - 0.854107f, 0.625459f, 0.867508f, 0.642291f, 0.855181f, 0.668527f, 0.828171f, 0.633354f, - 0.856142f, 0.742025f, 0.867293f, 0.768782f, 0.853157f, 0.785002f, 0.827598f, 0.775964f, - 0.867508f, 0.642291f, 0.890474f, 0.641909f, 0.900375f, 0.666964f, 0.855181f, 0.668527f, - 0.901223f, 0.745592f, 0.890219f, 0.770183f, 0.867293f, 0.768782f, 0.856142f, 0.742025f, - 0.855181f, 0.668527f, 0.900375f, 0.666964f, 0.918898f, 0.699697f, 0.842358f, 0.702491f, - 0.921180f, 0.713713f, 0.901223f, 0.745592f, 0.856142f, 0.742025f, 0.844839f, 0.707525f, - 0.900375f, 0.666964f, 0.931889f, 0.636832f, 0.968392f, 0.645333f, 0.918898f, 0.699697f, - 0.968213f, 0.770220f, 0.931368f, 0.777093f, 0.901223f, 0.745592f, 0.921180f, 0.713713f, - 0.890474f, 0.641909f, 0.905882f, 0.627902f, 0.931889f, 0.636832f, 0.900375f, 0.666964f, - 0.931368f, 0.777093f, 0.904990f, 0.784860f, 0.890219f, 0.770183f, 0.901223f, 0.745592f, - 0.905882f, 0.627902f, 0.906232f, 0.605742f, 0.933717f, 0.593037f, 0.931889f, 0.636832f, - 0.931250f, 0.820926f, 0.904357f, 0.807013f, 0.904990f, 0.784860f, 0.931368f, 0.777093f, - 0.931889f, 0.636832f, 0.933717f, 0.593037f, 0.968392f, 0.573812f, 0.968392f, 0.645333f, - 0.965038f, 0.841671f, 0.931250f, 0.820926f, 0.931368f, 0.777093f, 0.968213f, 0.770220f, - 0.933717f, 0.593037f, 0.904571f, 0.559404f, 0.920166f, 0.524546f, 0.968392f, 0.573812f, - 0.914672f, 0.888748f, 0.900640f, 0.853232f, 0.931250f, 0.820926f, 0.965038f, 0.841671f, - 0.906232f, 0.605742f, 0.890955f, 0.590063f, 0.904571f, 0.559404f, 0.933717f, 0.593037f, - 0.900640f, 0.853232f, 0.888398f, 0.821999f, 0.904357f, 0.807013f, 0.931250f, 0.820926f, - 0.890955f, 0.590063f, 0.906232f, 0.605742f, 0.902359f, 0.607909f, 0.889591f, 0.593275f, - 0.900583f, 0.804677f, 0.904357f, 0.807013f, 0.888398f, 0.821999f, 0.887178f, 0.818729f, - 0.906232f, 0.605742f, 0.905882f, 0.627902f, 0.899781f, 0.626257f, 0.902359f, 0.607909f, - 0.898822f, 0.786233f, 0.904990f, 0.784860f, 0.904357f, 0.807013f, 0.900583f, 0.804677f, - 0.905882f, 0.627902f, 0.890474f, 0.641909f, 0.887842f, 0.636527f, 0.899781f, 0.626257f, - 0.887351f, 0.775442f, 0.890219f, 0.770183f, 0.904990f, 0.784860f, 0.898822f, 0.786233f, - 0.890474f, 0.641909f, 0.867508f, 0.642291f, 0.870908f, 0.635245f, 0.887842f, 0.636527f, - 0.870376f, 0.775972f, 0.867293f, 0.768782f, 0.890219f, 0.770183f, 0.887351f, 0.775442f, - 0.867508f, 0.642291f, 0.854107f, 0.625459f, 0.859881f, 0.623942f, 0.870908f, 0.635245f, - 0.858859f, 0.786774f, 0.853157f, 0.785002f, 0.867293f, 0.768782f, 0.870376f, 0.775972f, - 0.854107f, 0.625459f, 0.854402f, 0.604754f, 0.859664f, 0.608186f, 0.859881f, 0.623942f, - 0.857942f, 0.802505f, 0.852534f, 0.805700f, 0.853157f, 0.785002f, 0.858859f, 0.786774f, - 0.854402f, 0.604754f, 0.870622f, 0.589649f, 0.871664f, 0.593961f, 0.859664f, 0.608186f, - 0.869299f, 0.817249f, 0.868067f, 0.821510f, 0.852534f, 0.805700f, 0.857942f, 0.802505f, - 0.870622f, 0.589649f, 0.890955f, 0.590063f, 0.889591f, 0.593275f, 0.871664f, 0.593961f, - 0.887178f, 0.818729f, 0.888398f, 0.821999f, 0.868067f, 0.821510f, 0.869299f, 0.817249f, - 0.879400f, 0.616512f, 0.871664f, 0.593961f, 0.889591f, 0.593275f, - 0.887178f, 0.818729f, 0.869299f, 0.817249f, 0.878029f, 0.795063f, - 0.859664f, 0.608186f, 0.871664f, 0.593961f, 0.879400f, 0.616512f, - 0.878029f, 0.795063f, 0.869299f, 0.817249f, 0.857942f, 0.802505f, - 0.879400f, 0.616512f, 0.859881f, 0.623942f, 0.859664f, 0.608186f, - 0.857942f, 0.802505f, 0.858859f, 0.786774f, 0.878029f, 0.795063f, - 0.879400f, 0.616512f, 0.870908f, 0.635245f, 0.859881f, 0.623942f, - 0.858859f, 0.786774f, 0.870376f, 0.775972f, 0.878029f, 0.795063f, - 0.879400f, 0.616512f, 0.887842f, 0.636527f, 0.870908f, 0.635245f, - 0.870376f, 0.775972f, 0.887351f, 0.775442f, 0.878029f, 0.795063f, - 0.879400f, 0.616512f, 0.899781f, 0.626257f, 0.887842f, 0.636527f, - 0.887351f, 0.775442f, 0.898822f, 0.786233f, 0.878029f, 0.795063f, - 0.879400f, 0.616512f, 0.902359f, 0.607909f, 0.899781f, 0.626257f, - 0.898822f, 0.786233f, 0.900583f, 0.804677f, 0.878029f, 0.795063f, - 0.879400f, 0.616512f, 0.889591f, 0.593275f, 0.902359f, 0.607909f, - 0.900583f, 0.804677f, 0.887178f, 0.818729f, 0.878029f, 0.795063f, - 0.540260f, 0.053805f, 0.536419f, 0.062072f, 0.518925f, 0.059681f, 0.518916f, 0.050294f, - 0.518925f, 0.059681f, 0.501452f, 0.062043f, 0.497626f, 0.053770f, 0.518916f, 0.050294f, - 0.551930f, 0.058338f, 0.542788f, 0.064089f, 0.536419f, 0.062072f, 0.540260f, 0.053805f, - 0.501452f, 0.062043f, 0.495083f, 0.064047f, 0.485955f, 0.058273f, 0.497626f, 0.053770f, - 0.555073f, 0.061900f, 0.546290f, 0.072669f, 0.542788f, 0.064089f, 0.551930f, 0.058338f, - 0.495083f, 0.064047f, 0.491565f, 0.072625f, 0.482805f, 0.061829f, 0.485955f, 0.058273f, - 0.563812f, 0.076586f, 0.548333f, 0.084893f, 0.546290f, 0.072669f, 0.555073f, 0.061900f, - 0.491565f, 0.072625f, 0.489507f, 0.084858f, 0.474014f, 0.076511f, 0.482805f, 0.061829f, - 0.583135f, 0.108495f, 0.555621f, 0.121749f, 0.548333f, 0.084893f, 0.563812f, 0.076586f, - 0.489507f, 0.084858f, 0.482177f, 0.121781f, 0.454527f, 0.108481f, 0.474014f, 0.076511f, - 0.605512f, 0.165134f, 0.647395f, 0.200502f, 0.621513f, 0.227818f, 0.553118f, 0.209599f, - 0.416514f, 0.229490f, 0.389677f, 0.201890f, 0.432024f, 0.165644f, 0.485339f, 0.210053f, - 0.647395f, 0.200502f, 0.676379f, 0.233241f, 0.664761f, 0.253225f, 0.621513f, 0.227818f, - 0.372747f, 0.256357f, 0.360308f, 0.235899f, 0.389677f, 0.201890f, 0.416514f, 0.229490f, - 0.676379f, 0.233241f, 0.715342f, 0.265392f, 0.683908f, 0.279995f, 0.664761f, 0.253225f, - 0.353696f, 0.284606f, 0.320452f, 0.270303f, 0.360308f, 0.235899f, 0.372747f, 0.256357f, - 0.715342f, 0.265392f, 0.707254f, 0.310054f, 0.687515f, 0.311539f, 0.683908f, 0.279995f, - 0.351187f, 0.317440f, 0.330721f, 0.316853f, 0.320452f, 0.270303f, 0.353696f, 0.284606f, - 0.707254f, 0.310054f, 0.697446f, 0.332673f, 0.676824f, 0.323937f, 0.687515f, 0.311539f, - 0.362723f, 0.329722f, 0.341964f, 0.339667f, 0.330721f, 0.316853f, 0.351187f, 0.317440f, - 0.697446f, 0.332673f, 0.662817f, 0.372521f, 0.639050f, 0.357330f, 0.676824f, 0.323937f, - 0.402772f, 0.362131f, 0.379297f, 0.378686f, 0.341964f, 0.339667f, 0.362723f, 0.329722f, - 0.662817f, 0.372521f, 0.626842f, 0.395792f, 0.618316f, 0.375151f, 0.639050f, 0.357330f, - 0.424583f, 0.379267f, 0.416915f, 0.400552f, 0.379297f, 0.378686f, 0.402772f, 0.362131f, - 0.626842f, 0.395792f, 0.604826f, 0.397804f, 0.600808f, 0.377857f, 0.618316f, 0.375151f, - 0.442396f, 0.381222f, 0.439252f, 0.401540f, 0.416915f, 0.400552f, 0.424583f, 0.379267f, - 0.604826f, 0.397804f, 0.553095f, 0.390512f, 0.559674f, 0.357011f, 0.600808f, 0.377857f, - 0.482938f, 0.358497f, 0.490934f, 0.391862f, 0.439252f, 0.401540f, 0.442396f, 0.381222f, - 0.553095f, 0.390512f, 0.521923f, 0.386009f, 0.521086f, 0.343868f, 0.559674f, 0.357011f, - 0.521086f, 0.343868f, 0.521923f, 0.386009f, 0.490934f, 0.391862f, 0.482938f, 0.358497f, - 0.577279f, 0.340156f, 0.599845f, 0.344815f, 0.600808f, 0.377857f, 0.559674f, 0.357011f, - 0.442396f, 0.381222f, 0.441977f, 0.347815f, 0.464579f, 0.342230f, 0.482938f, 0.358497f, - 0.599845f, 0.344815f, 0.615546f, 0.342005f, 0.618316f, 0.375151f, 0.600808f, 0.377857f, - 0.424583f, 0.379267f, 0.425972f, 0.345582f, 0.441977f, 0.347815f, 0.442396f, 0.381222f, - 0.634472f, 0.332311f, 0.639050f, 0.357330f, 0.618316f, 0.375151f, 0.615546f, 0.342005f, - 0.424583f, 0.379267f, 0.402772f, 0.362131f, 0.406362f, 0.336480f, 0.425972f, 0.345582f, - 0.662406f, 0.312804f, 0.676824f, 0.323937f, 0.639050f, 0.357330f, 0.634472f, 0.332311f, - 0.402772f, 0.362131f, 0.362723f, 0.329722f, 0.377061f, 0.317685f, 0.406362f, 0.336480f, - 0.668440f, 0.297958f, 0.687515f, 0.311539f, 0.676824f, 0.323937f, 0.662406f, 0.312804f, - 0.362723f, 0.329722f, 0.351187f, 0.317440f, 0.370304f, 0.302644f, 0.377061f, 0.317685f, - 0.664101f, 0.277872f, 0.683908f, 0.279995f, 0.687515f, 0.311539f, 0.668440f, 0.297958f, - 0.351187f, 0.317440f, 0.353696f, 0.284606f, 0.374100f, 0.281778f, 0.370304f, 0.302644f, - 0.639236f, 0.253047f, 0.664761f, 0.253225f, 0.683908f, 0.279995f, 0.664101f, 0.277872f, - 0.353696f, 0.284606f, 0.372747f, 0.256357f, 0.398938f, 0.255633f, 0.374100f, 0.281778f, - 0.613992f, 0.242662f, 0.621513f, 0.227818f, 0.664761f, 0.253225f, 0.639236f, 0.253047f, - 0.372747f, 0.256357f, 0.416514f, 0.229490f, 0.424464f, 0.244473f, 0.398938f, 0.255633f, - 0.572941f, 0.258564f, 0.553118f, 0.209599f, 0.621513f, 0.227818f, 0.613992f, 0.242662f, - 0.416514f, 0.229490f, 0.485339f, 0.210053f, 0.466409f, 0.259709f, 0.424464f, 0.244473f, - 0.572941f, 0.258564f, 0.563905f, 0.272007f, 0.519760f, 0.248864f, 0.553118f, 0.209599f, - 0.519760f, 0.248864f, 0.475886f, 0.273078f, 0.466409f, 0.259709f, 0.485339f, 0.210053f, - 0.577279f, 0.340156f, 0.559674f, 0.357011f, 0.521086f, 0.343868f, 0.558527f, 0.316594f, - 0.521086f, 0.343868f, 0.482938f, 0.358497f, 0.464579f, 0.342230f, 0.482619f, 0.317843f, - 0.558527f, 0.316594f, 0.521086f, 0.343868f, 0.520277f, 0.294764f, 0.556923f, 0.291214f, - 0.520277f, 0.294764f, 0.521086f, 0.343868f, 0.482619f, 0.317843f, 0.483433f, 0.292249f, - 0.519760f, 0.248864f, 0.563905f, 0.272007f, 0.556923f, 0.291214f, 0.520277f, 0.294764f, - 0.483433f, 0.292249f, 0.475886f, 0.273078f, 0.519760f, 0.248864f, 0.520277f, 0.294764f, - 0.525483f, 0.068967f, 0.518928f, 0.067899f, 0.518925f, 0.059681f, 0.536419f, 0.062072f, - 0.518925f, 0.059681f, 0.518928f, 0.067899f, 0.512375f, 0.068956f, 0.501452f, 0.062043f, - 0.531231f, 0.073829f, 0.525483f, 0.068967f, 0.536419f, 0.062072f, 0.542788f, 0.064089f, - 0.501452f, 0.062043f, 0.512375f, 0.068956f, 0.506626f, 0.073811f, 0.495083f, 0.064047f, - 0.531019f, 0.087431f, 0.531231f, 0.073829f, 0.542788f, 0.064089f, 0.546290f, 0.072669f, - 0.495083f, 0.064047f, 0.506626f, 0.073811f, 0.506827f, 0.087416f, 0.491565f, 0.072625f, - 0.555621f, 0.121749f, 0.532042f, 0.127713f, 0.532669f, 0.090920f, 0.548333f, 0.084893f, - 0.505177f, 0.090908f, 0.505828f, 0.127728f, 0.482177f, 0.121781f, 0.489507f, 0.084858f, - 0.531019f, 0.087431f, 0.546290f, 0.072669f, 0.548333f, 0.084893f, 0.532669f, 0.090920f, - 0.489507f, 0.084858f, 0.491565f, 0.072625f, 0.506827f, 0.087416f, 0.505177f, 0.090908f, - 0.538112f, 0.158382f, 0.518981f, 0.151749f, 0.518941f, 0.128358f, 0.532042f, 0.127713f, - 0.518941f, 0.128358f, 0.518981f, 0.151749f, 0.499851f, 0.158434f, 0.505828f, 0.127728f, - 0.532669f, 0.090920f, 0.532042f, 0.127713f, 0.518941f, 0.128358f, 0.518925f, 0.093952f, - 0.518941f, 0.128358f, 0.505828f, 0.127728f, 0.505177f, 0.090908f, 0.518925f, 0.093952f, - 0.518927f, 0.085180f, 0.531019f, 0.087431f, 0.532669f, 0.090920f, 0.518925f, 0.093952f, - 0.505177f, 0.090908f, 0.506827f, 0.087416f, 0.518927f, 0.085180f, 0.518925f, 0.093952f, - 0.548362f, 0.173560f, 0.537959f, 0.175966f, 0.535214f, 0.166808f, 0.538112f, 0.158382f, - 0.502799f, 0.166857f, 0.500100f, 0.176033f, 0.489683f, 0.173693f, 0.499851f, 0.158434f, - 0.544281f, 0.193366f, 0.537248f, 0.187577f, 0.537959f, 0.175966f, 0.548362f, 0.173560f, - 0.500100f, 0.176033f, 0.500890f, 0.187571f, 0.493996f, 0.193428f, 0.489683f, 0.173693f, - 0.519841f, 0.200843f, 0.528757f, 0.191785f, 0.537248f, 0.187577f, 0.544281f, 0.193366f, - 0.500890f, 0.187571f, 0.509219f, 0.191626f, 0.519841f, 0.200843f, 0.493996f, 0.193428f, - 0.517577f, 0.190607f, 0.519132f, 0.185382f, 0.528757f, 0.191785f, 0.519841f, 0.200843f, - 0.509219f, 0.191626f, 0.519132f, 0.185382f, 0.517577f, 0.190607f, 0.519841f, 0.200843f, - 0.518981f, 0.151749f, 0.538112f, 0.158382f, 0.535214f, 0.166808f, 0.518998f, 0.159028f, - 0.502799f, 0.166857f, 0.499851f, 0.158434f, 0.518981f, 0.151749f, 0.518998f, 0.159028f, - 0.518998f, 0.159028f, 0.535214f, 0.166808f, 0.531131f, 0.171631f, 0.519016f, 0.165599f, - 0.506910f, 0.171667f, 0.502799f, 0.166857f, 0.518998f, 0.159028f, 0.519016f, 0.165599f, - 0.519132f, 0.185382f, 0.519099f, 0.179457f, 0.528222f, 0.186316f, 0.528757f, 0.191785f, - 0.509787f, 0.186260f, 0.519099f, 0.179457f, 0.519132f, 0.185382f, 0.509219f, 0.191626f, - 0.528757f, 0.191785f, 0.528222f, 0.186316f, 0.533528f, 0.184215f, 0.537248f, 0.187577f, - 0.504547f, 0.184206f, 0.509787f, 0.186260f, 0.509219f, 0.191626f, 0.500890f, 0.187571f, - 0.537248f, 0.187577f, 0.533528f, 0.184215f, 0.533449f, 0.176739f, 0.537959f, 0.175966f, - 0.504604f, 0.176791f, 0.504547f, 0.184206f, 0.500890f, 0.187571f, 0.500100f, 0.176033f, - 0.537959f, 0.175966f, 0.533449f, 0.176739f, 0.531131f, 0.171631f, 0.535214f, 0.166808f, - 0.506910f, 0.171667f, 0.504604f, 0.176791f, 0.500100f, 0.176033f, 0.502799f, 0.166857f, - 0.519099f, 0.179457f, 0.533449f, 0.176739f, 0.533528f, 0.184215f, 0.528222f, 0.186316f, - 0.504547f, 0.184206f, 0.504604f, 0.176791f, 0.519099f, 0.179457f, 0.509787f, 0.186260f, - 0.519099f, 0.179457f, 0.519016f, 0.165599f, 0.531131f, 0.171631f, 0.533449f, 0.176739f, - 0.506910f, 0.171667f, 0.519016f, 0.165599f, 0.519099f, 0.179457f, 0.504604f, 0.176791f, - 0.519841f, 0.200843f, 0.544281f, 0.193366f, 0.553118f, 0.209599f, 0.519760f, 0.248864f, - 0.485339f, 0.210053f, 0.493996f, 0.193428f, 0.519841f, 0.200843f, 0.519760f, 0.248864f, - 0.544281f, 0.193366f, 0.548362f, 0.173560f, 0.561572f, 0.167779f, 0.553118f, 0.209599f, - 0.476363f, 0.167996f, 0.489683f, 0.173693f, 0.493996f, 0.193428f, 0.485339f, 0.210053f, - 0.548362f, 0.173560f, 0.538112f, 0.158382f, 0.559475f, 0.149319f, 0.561572f, 0.167779f, - 0.478371f, 0.149447f, 0.499851f, 0.158434f, 0.489683f, 0.173693f, 0.476363f, 0.167996f, - 0.538112f, 0.158382f, 0.532042f, 0.127713f, 0.555621f, 0.121749f, 0.559475f, 0.149319f, - 0.482177f, 0.121781f, 0.505828f, 0.127728f, 0.499851f, 0.158434f, 0.478371f, 0.149447f, - 0.583135f, 0.108495f, 0.596138f, 0.133426f, 0.559475f, 0.149319f, 0.555621f, 0.121749f, - 0.478371f, 0.149447f, 0.441395f, 0.133592f, 0.454527f, 0.108481f, 0.482177f, 0.121781f, - 0.596138f, 0.133426f, 0.601169f, 0.147885f, 0.561572f, 0.167779f, 0.559475f, 0.149319f, - 0.476363f, 0.167996f, 0.436337f, 0.148194f, 0.441395f, 0.133592f, 0.478371f, 0.149447f, - 0.605512f, 0.165134f, 0.553118f, 0.209599f, 0.561572f, 0.167779f, 0.601169f, 0.147885f, - 0.476363f, 0.167996f, 0.485339f, 0.210053f, 0.432024f, 0.165644f, 0.436337f, 0.148194f, - 0.531019f, 0.087431f, 0.518927f, 0.085180f, 0.518925f, 0.083865f, 0.528933f, 0.084957f, - 0.518925f, 0.083865f, 0.518927f, 0.085180f, 0.506827f, 0.087416f, 0.508915f, 0.084945f, - 0.531231f, 0.073829f, 0.531019f, 0.087431f, 0.528933f, 0.084957f, 0.529036f, 0.075429f, - 0.508915f, 0.084945f, 0.506827f, 0.087416f, 0.506626f, 0.073811f, 0.508820f, 0.075415f, - 0.525483f, 0.068967f, 0.531231f, 0.073829f, 0.529036f, 0.075429f, 0.523751f, 0.070508f, - 0.508820f, 0.075415f, 0.506626f, 0.073811f, 0.512375f, 0.068956f, 0.514106f, 0.070501f, - 0.518928f, 0.067899f, 0.525483f, 0.068967f, 0.523751f, 0.070508f, 0.518929f, 0.069468f, - 0.514106f, 0.070501f, 0.512375f, 0.068956f, 0.518928f, 0.067899f, 0.518929f, 0.069468f, - 0.518929f, 0.069468f, 0.523751f, 0.070508f, 0.521560f, 0.074970f, 0.518928f, 0.074259f, - 0.516297f, 0.074966f, 0.514106f, 0.070501f, 0.518929f, 0.069468f, 0.518928f, 0.074259f, - 0.523751f, 0.070508f, 0.529036f, 0.075429f, 0.524236f, 0.076691f, 0.521560f, 0.074970f, - 0.513619f, 0.076684f, 0.508820f, 0.075415f, 0.514106f, 0.070501f, 0.516297f, 0.074966f, - 0.529036f, 0.075429f, 0.528933f, 0.084957f, 0.524601f, 0.079886f, 0.524236f, 0.076691f, - 0.513252f, 0.079879f, 0.508915f, 0.084945f, 0.508820f, 0.075415f, 0.513619f, 0.076684f, - 0.528933f, 0.084957f, 0.518925f, 0.083865f, 0.518926f, 0.079331f, 0.524601f, 0.079886f, - 0.518926f, 0.079331f, 0.518925f, 0.083865f, 0.508915f, 0.084945f, 0.513252f, 0.079879f, - 0.518926f, 0.079331f, 0.518928f, 0.074259f, 0.521560f, 0.074970f, 0.524601f, 0.079886f, - 0.516297f, 0.074966f, 0.518928f, 0.074259f, 0.518926f, 0.079331f, 0.513252f, 0.079879f, - 0.524601f, 0.079886f, 0.521560f, 0.074970f, 0.524236f, 0.076691f, - 0.513619f, 0.076684f, 0.516297f, 0.074966f, 0.513252f, 0.079879f, - 0.556923f, 0.291214f, 0.563905f, 0.272007f, 0.571787f, 0.277295f, 0.568351f, 0.292904f, - 0.468070f, 0.278617f, 0.475886f, 0.273078f, 0.483433f, 0.292249f, 0.471978f, 0.294282f, - 0.558527f, 0.316594f, 0.556923f, 0.291214f, 0.568351f, 0.292904f, 0.573085f, 0.311386f, - 0.471978f, 0.294282f, 0.483433f, 0.292249f, 0.482619f, 0.317843f, 0.467790f, 0.313081f, - 0.577279f, 0.340156f, 0.558527f, 0.316594f, 0.573085f, 0.311386f, 0.584855f, 0.327708f, - 0.467790f, 0.313081f, 0.482619f, 0.317843f, 0.464579f, 0.342230f, 0.456477f, 0.329961f, - 0.563905f, 0.272007f, 0.572941f, 0.258564f, 0.580734f, 0.266620f, 0.571787f, 0.277295f, - 0.458737f, 0.268049f, 0.466409f, 0.259709f, 0.475886f, 0.273078f, 0.468070f, 0.278617f, - 0.572941f, 0.258564f, 0.613992f, 0.242662f, 0.611720f, 0.255725f, 0.580734f, 0.266620f, - 0.427062f, 0.257728f, 0.424464f, 0.244473f, 0.466409f, 0.259709f, 0.458737f, 0.268049f, - 0.613992f, 0.242662f, 0.639236f, 0.253047f, 0.632494f, 0.262853f, 0.611720f, 0.255725f, - 0.406068f, 0.265508f, 0.398938f, 0.255633f, 0.424464f, 0.244473f, 0.427062f, 0.257728f, - 0.639236f, 0.253047f, 0.664101f, 0.277872f, 0.653658f, 0.279971f, 0.632494f, 0.262853f, - 0.384904f, 0.283634f, 0.374100f, 0.281778f, 0.398938f, 0.255633f, 0.406068f, 0.265508f, - 0.664101f, 0.277872f, 0.668440f, 0.297958f, 0.656064f, 0.297636f, 0.653658f, 0.279971f, - 0.383015f, 0.301864f, 0.370304f, 0.302644f, 0.374100f, 0.281778f, 0.384904f, 0.283634f, - 0.668440f, 0.297958f, 0.662406f, 0.312804f, 0.652752f, 0.310186f, 0.656064f, 0.297636f, - 0.386858f, 0.314615f, 0.377061f, 0.317685f, 0.370304f, 0.302644f, 0.383015f, 0.301864f, - 0.662406f, 0.312804f, 0.634472f, 0.332311f, 0.629040f, 0.323864f, 0.652752f, 0.310186f, - 0.411556f, 0.327673f, 0.406362f, 0.336480f, 0.377061f, 0.317685f, 0.386858f, 0.314615f, - 0.634472f, 0.332311f, 0.615546f, 0.342005f, 0.614408f, 0.331972f, 0.629040f, 0.323864f, - 0.426727f, 0.335361f, 0.425972f, 0.345582f, 0.406362f, 0.336480f, 0.411556f, 0.327673f, - 0.615546f, 0.342005f, 0.599845f, 0.344815f, 0.601033f, 0.333624f, 0.614408f, 0.331972f, - 0.440344f, 0.336537f, 0.441977f, 0.347815f, 0.425972f, 0.345582f, 0.426727f, 0.335361f, - 0.599845f, 0.344815f, 0.577279f, 0.340156f, 0.584855f, 0.327708f, 0.601033f, 0.333624f, - 0.456477f, 0.329961f, 0.464579f, 0.342230f, 0.441977f, 0.347815f, 0.440344f, 0.336537f, - 0.601033f, 0.333624f, 0.584855f, 0.327708f, 0.590644f, 0.321516f, 0.601799f, 0.328453f, - 0.450408f, 0.323919f, 0.456477f, 0.329961f, 0.440344f, 0.336537f, 0.439372f, 0.331331f, - 0.614408f, 0.331972f, 0.601033f, 0.333624f, 0.601799f, 0.328453f, 0.613335f, 0.327083f, - 0.439372f, 0.331331f, 0.440344f, 0.336537f, 0.426727f, 0.335361f, 0.427623f, 0.330358f, - 0.629040f, 0.323864f, 0.614408f, 0.331972f, 0.613335f, 0.327083f, 0.626851f, 0.320513f, - 0.427623f, 0.330358f, 0.426727f, 0.335361f, 0.411556f, 0.327673f, 0.413648f, 0.324175f, - 0.652752f, 0.310186f, 0.629040f, 0.323864f, 0.626851f, 0.320513f, 0.646248f, 0.306421f, - 0.413648f, 0.324175f, 0.411556f, 0.327673f, 0.386858f, 0.314615f, 0.393381f, 0.310510f, - 0.656064f, 0.297636f, 0.652752f, 0.310186f, 0.646248f, 0.306421f, 0.649541f, 0.296225f, - 0.393381f, 0.310510f, 0.386858f, 0.314615f, 0.383015f, 0.301864f, 0.389662f, 0.300183f, - 0.653658f, 0.279971f, 0.656064f, 0.297636f, 0.649541f, 0.296225f, 0.647785f, 0.283486f, - 0.389662f, 0.300183f, 0.383015f, 0.301864f, 0.384904f, 0.283634f, 0.391040f, 0.287071f, - 0.632494f, 0.262853f, 0.653658f, 0.279971f, 0.647785f, 0.283486f, 0.629829f, 0.267263f, - 0.391040f, 0.287071f, 0.384904f, 0.283634f, 0.406068f, 0.265508f, 0.408893f, 0.269959f, - 0.611720f, 0.255725f, 0.632494f, 0.262853f, 0.629829f, 0.267263f, 0.612641f, 0.261560f, - 0.408893f, 0.269959f, 0.406068f, 0.265508f, 0.427062f, 0.257728f, 0.426254f, 0.263693f, - 0.580734f, 0.266620f, 0.611720f, 0.255725f, 0.612641f, 0.261560f, 0.585166f, 0.270991f, - 0.426254f, 0.263693f, 0.427062f, 0.257728f, 0.458737f, 0.268049f, 0.454369f, 0.272583f, - 0.571787f, 0.277295f, 0.580734f, 0.266620f, 0.585166f, 0.270991f, 0.578124f, 0.281900f, - 0.454369f, 0.272583f, 0.458737f, 0.268049f, 0.468070f, 0.278617f, 0.461798f, 0.283441f, - 0.584855f, 0.327708f, 0.573085f, 0.311386f, 0.579548f, 0.309340f, 0.590644f, 0.321516f, - 0.461204f, 0.311233f, 0.467790f, 0.313081f, 0.456477f, 0.329961f, 0.450408f, 0.323919f, - 0.573085f, 0.311386f, 0.568351f, 0.292904f, 0.577524f, 0.293776f, 0.579548f, 0.309340f, - 0.462754f, 0.295432f, 0.471978f, 0.294282f, 0.467790f, 0.313081f, 0.461204f, 0.311233f, - 0.568351f, 0.292904f, 0.571787f, 0.277295f, 0.578124f, 0.281900f, 0.577524f, 0.293776f, - 0.461798f, 0.283441f, 0.468070f, 0.278617f, 0.471978f, 0.294282f, 0.462754f, 0.295432f, - 0.521923f, 0.386009f, 0.553095f, 0.390512f, 0.553209f, 0.433063f, 0.523031f, 0.433628f, - 0.492809f, 0.434538f, 0.490934f, 0.391862f, 0.521923f, 0.386009f, 0.523031f, 0.433628f, - 0.553095f, 0.390512f, 0.604826f, 0.397804f, 0.609819f, 0.431516f, 0.553209f, 0.433063f, - 0.435860f, 0.435740f, 0.439252f, 0.401540f, 0.490934f, 0.391862f, 0.492809f, 0.434538f, - 0.604826f, 0.397804f, 0.626842f, 0.395792f, 0.648174f, 0.419316f, 0.609819f, 0.431516f, - 0.396518f, 0.425416f, 0.416915f, 0.400552f, 0.439252f, 0.401540f, 0.435860f, 0.435740f, - 0.626842f, 0.395792f, 0.662817f, 0.372521f, 0.692106f, 0.388274f, 0.648174f, 0.419316f, - 0.350292f, 0.396229f, 0.379297f, 0.378686f, 0.416915f, 0.400552f, 0.396518f, 0.425416f, - 0.662817f, 0.372521f, 0.697446f, 0.332673f, 0.726332f, 0.341754f, 0.692106f, 0.388274f, - 0.312756f, 0.350588f, 0.341964f, 0.339667f, 0.379297f, 0.378686f, 0.350292f, 0.396229f, - 0.697446f, 0.332673f, 0.707254f, 0.310054f, 0.735879f, 0.312112f, 0.726332f, 0.341754f, - 0.301067f, 0.320593f, 0.330721f, 0.316853f, 0.341964f, 0.339667f, 0.312756f, 0.350588f, - 0.707254f, 0.310054f, 0.715342f, 0.265392f, 0.729900f, 0.256393f, 0.735879f, 0.312112f, - 0.304876f, 0.261087f, 0.320452f, 0.270303f, 0.330721f, 0.316853f, 0.301067f, 0.320593f, - 0.715342f, 0.265392f, 0.676379f, 0.233241f, 0.698172f, 0.216906f, 0.729900f, 0.256393f, - 0.337414f, 0.219179f, 0.360308f, 0.235899f, 0.320452f, 0.270303f, 0.304876f, 0.261087f, - 0.676379f, 0.233241f, 0.647395f, 0.200502f, 0.663103f, 0.190671f, 0.698172f, 0.216906f, - 0.373474f, 0.191872f, 0.389677f, 0.201890f, 0.360308f, 0.235899f, 0.337414f, 0.219179f, - 0.626908f, 0.015608f, 0.649444f, 0.022378f, 0.660451f, 0.076084f, 0.621440f, 0.048089f, - 0.376796f, 0.075296f, 0.388827f, 0.021586f, 0.411318f, 0.015131f, 0.416419f, 0.047631f, - 0.567460f, 0.000144f, 0.626908f, 0.015608f, 0.621440f, 0.048089f, 0.577206f, 0.032801f, - 0.416419f, 0.047631f, 0.411318f, 0.015131f, 0.470636f, 0.000144f, 0.460782f, 0.032656f, - 0.518922f, 0.024886f, 0.567460f, 0.000144f, 0.577206f, 0.032801f, 0.547413f, 0.041724f, - 0.460782f, 0.032656f, 0.470636f, 0.000144f, 0.518922f, 0.024886f, 0.490511f, 0.041669f, - 0.540260f, 0.053805f, 0.518916f, 0.050294f, 0.518922f, 0.024886f, 0.547413f, 0.041724f, - 0.518922f, 0.024886f, 0.518916f, 0.050294f, 0.497626f, 0.053770f, 0.490511f, 0.041669f, - 0.551930f, 0.058338f, 0.540260f, 0.053805f, 0.547413f, 0.041724f, 0.558059f, 0.053871f, - 0.490511f, 0.041669f, 0.497626f, 0.053770f, 0.485955f, 0.058273f, 0.479842f, 0.053785f, - 0.555073f, 0.061900f, 0.551930f, 0.058338f, 0.558059f, 0.053871f, 0.576951f, 0.057998f, - 0.479842f, 0.053785f, 0.485955f, 0.058273f, 0.482805f, 0.061829f, 0.460920f, 0.057845f, - 0.563812f, 0.076586f, 0.555073f, 0.061900f, 0.576951f, 0.057998f, 0.611687f, 0.078268f, - 0.460920f, 0.057845f, 0.482805f, 0.061829f, 0.474014f, 0.076511f, 0.425932f, 0.077985f, - 0.576951f, 0.057998f, 0.577206f, 0.032801f, 0.621440f, 0.048089f, 0.611687f, 0.078268f, - 0.416419f, 0.047631f, 0.460782f, 0.032656f, 0.460920f, 0.057845f, 0.425932f, 0.077985f, - 0.576951f, 0.057998f, 0.558059f, 0.053871f, 0.547413f, 0.041724f, 0.577206f, 0.032801f, - 0.490511f, 0.041669f, 0.479842f, 0.053785f, 0.460920f, 0.057845f, 0.460782f, 0.032656f, - 0.626663f, 0.111357f, 0.611687f, 0.078268f, 0.621440f, 0.048089f, 0.660451f, 0.076084f, - 0.416419f, 0.047631f, 0.425932f, 0.077985f, 0.410618f, 0.111244f, 0.376796f, 0.075296f, - 0.583135f, 0.108495f, 0.563812f, 0.076586f, 0.611687f, 0.078268f, 0.626663f, 0.111357f, - 0.425932f, 0.077985f, 0.474014f, 0.076511f, 0.454527f, 0.108481f, 0.410618f, 0.111244f, - 0.596138f, 0.133426f, 0.629482f, 0.130456f, 0.623495f, 0.146796f, 0.601169f, 0.147885f, - 0.413741f, 0.147158f, 0.407648f, 0.130594f, 0.441395f, 0.133592f, 0.436337f, 0.148194f, - 0.583135f, 0.108495f, 0.626663f, 0.111357f, 0.629482f, 0.130456f, 0.596138f, 0.133426f, - 0.407648f, 0.130594f, 0.410618f, 0.111244f, 0.454527f, 0.108481f, 0.441395f, 0.133592f, - 0.605512f, 0.165134f, 0.601169f, 0.147885f, 0.623495f, 0.146796f, 0.619303f, 0.159841f, - 0.413741f, 0.147158f, 0.436337f, 0.148194f, 0.432024f, 0.165644f, 0.418035f, 0.160361f, - 0.605512f, 0.165134f, 0.619303f, 0.159841f, 0.663103f, 0.190671f, 0.647395f, 0.200502f, - 0.373474f, 0.191872f, 0.418035f, 0.160361f, 0.432024f, 0.165644f, 0.389677f, 0.201890f, - 0.945900f, 0.079569f, 0.886245f, 0.121777f, 0.849114f, 0.099732f, 0.891780f, 0.036916f, - 0.183115f, 0.092127f, 0.141314f, 0.112482f, 0.078961f, 0.060719f, 0.142277f, 0.021467f, - 0.891780f, 0.036916f, 0.849114f, 0.099732f, 0.788458f, 0.080826f, 0.805584f, 0.010786f, - 0.246353f, 0.076510f, 0.183115f, 0.092127f, 0.142277f, 0.021467f, 0.232648f, 0.003484f, - 0.805584f, 0.010786f, 0.788458f, 0.080826f, 0.687018f, 0.077204f, 0.672384f, 0.022201f, - 0.349875f, 0.075955f, 0.246353f, 0.076510f, 0.232648f, 0.003484f, 0.365979f, 0.020991f, - 0.672384f, 0.022201f, 0.687018f, 0.077204f, 0.660451f, 0.076084f, 0.649444f, 0.022378f, - 0.376796f, 0.075296f, 0.349875f, 0.075955f, 0.365979f, 0.020991f, 0.388827f, 0.021586f, - 0.626663f, 0.111357f, 0.660451f, 0.076084f, 0.687018f, 0.077204f, 0.629482f, 0.130456f, - 0.349875f, 0.075955f, 0.376796f, 0.075296f, 0.410618f, 0.111244f, 0.407648f, 0.130594f, - 0.729900f, 0.256393f, 0.698172f, 0.216906f, 0.760215f, 0.193244f, 0.789046f, 0.233323f, - 0.271553f, 0.193871f, 0.337414f, 0.219179f, 0.304876f, 0.261087f, 0.241255f, 0.236977f, - 0.994525f, 0.167705f, 0.909112f, 0.183261f, 0.886245f, 0.121777f, 0.945900f, 0.079569f, - 0.141314f, 0.112482f, 0.107928f, 0.179083f, 0.011829f, 0.155367f, 0.078961f, 0.060719f, - 0.911671f, 0.402429f, 0.862868f, 0.338556f, 0.894128f, 0.301884f, 0.962901f, 0.344752f, - 0.123776f, 0.315519f, 0.160557f, 0.356821f, 0.106400f, 0.432652f, 0.043968f, 0.367038f, - 0.962901f, 0.344752f, 0.894128f, 0.301884f, 0.915360f, 0.259804f, 0.999856f, 0.254640f, - 0.098965f, 0.266968f, 0.123776f, 0.315519f, 0.043968f, 0.367038f, 0.000144f, 0.259113f, - 0.999856f, 0.254640f, 0.915360f, 0.259804f, 0.909112f, 0.183261f, 0.994525f, 0.167705f, - 0.107928f, 0.179083f, 0.098965f, 0.266968f, 0.000144f, 0.259113f, 0.011829f, 0.155367f, - 0.749542f, 0.334683f, 0.735879f, 0.312112f, 0.766337f, 0.300809f, 0.789162f, 0.313727f, - 0.267408f, 0.310142f, 0.301067f, 0.320593f, 0.288183f, 0.346496f, 0.242992f, 0.325552f, - 0.789162f, 0.313727f, 0.766337f, 0.300809f, 0.815314f, 0.276388f, 0.846174f, 0.293397f, - 0.213065f, 0.285164f, 0.267408f, 0.310142f, 0.242992f, 0.325552f, 0.178537f, 0.304983f, - 0.846174f, 0.293397f, 0.815314f, 0.276388f, 0.845007f, 0.256352f, 0.873517f, 0.265922f, - 0.179662f, 0.263312f, 0.213065f, 0.285164f, 0.178537f, 0.304983f, 0.147089f, 0.274284f, - 0.873517f, 0.265922f, 0.845007f, 0.256352f, 0.859075f, 0.228168f, 0.886999f, 0.233769f, - 0.162803f, 0.231720f, 0.179662f, 0.263312f, 0.147089f, 0.274284f, 0.131514f, 0.237587f, - 0.842355f, 0.195160f, 0.875030f, 0.184705f, 0.886999f, 0.233769f, 0.859075f, 0.228168f, - 0.131514f, 0.237587f, 0.145224f, 0.182749f, 0.176788f, 0.196179f, 0.162803f, 0.231720f, - 0.909112f, 0.183261f, 0.915360f, 0.259804f, 0.886999f, 0.233769f, 0.875030f, 0.184705f, - 0.131514f, 0.237587f, 0.098965f, 0.266968f, 0.107928f, 0.179083f, 0.145224f, 0.182749f, - 0.915360f, 0.259804f, 0.894128f, 0.301884f, 0.873517f, 0.265922f, 0.886999f, 0.233769f, - 0.147089f, 0.274284f, 0.123776f, 0.315519f, 0.098965f, 0.266968f, 0.131514f, 0.237587f, - 0.894128f, 0.301884f, 0.862868f, 0.338556f, 0.846174f, 0.293397f, 0.873517f, 0.265922f, - 0.178537f, 0.304983f, 0.160557f, 0.356821f, 0.123776f, 0.315519f, 0.147089f, 0.274284f, - 0.862868f, 0.338556f, 0.794286f, 0.364062f, 0.789162f, 0.313727f, 0.846174f, 0.293397f, - 0.242992f, 0.325552f, 0.239776f, 0.382592f, 0.160557f, 0.356821f, 0.178537f, 0.304983f, - 0.770185f, 0.379538f, 0.749542f, 0.334683f, 0.789162f, 0.313727f, 0.794286f, 0.364062f, - 0.242992f, 0.325552f, 0.288183f, 0.346496f, 0.268122f, 0.398737f, 0.239776f, 0.382592f, - 0.845499f, 0.449967f, 0.794286f, 0.364062f, 0.862868f, 0.338556f, 0.911671f, 0.402429f, - 0.160557f, 0.356821f, 0.239776f, 0.382592f, 0.185281f, 0.484099f, 0.106400f, 0.432652f, - 0.815858f, 0.445381f, 0.770572f, 0.444261f, 0.755700f, 0.418603f, 0.770185f, 0.379538f, - 0.287033f, 0.442912f, 0.271364f, 0.473316f, 0.219260f, 0.477186f, 0.268122f, 0.398737f, - 0.815858f, 0.445381f, 0.770185f, 0.379538f, 0.794286f, 0.364062f, 0.845499f, 0.449967f, - 0.239776f, 0.382592f, 0.268122f, 0.398737f, 0.219260f, 0.477186f, 0.185281f, 0.484099f, - 0.819845f, 0.468071f, 0.815858f, 0.445381f, 0.845499f, 0.449967f, - 0.185281f, 0.484099f, 0.219260f, 0.477186f, 0.215894f, 0.503605f, - 0.735879f, 0.312112f, 0.729900f, 0.256393f, 0.789046f, 0.233323f, 0.766337f, 0.300809f, - 0.241255f, 0.236977f, 0.304876f, 0.261087f, 0.301067f, 0.320593f, 0.267408f, 0.310142f, - 0.789046f, 0.233323f, 0.809631f, 0.233887f, 0.815314f, 0.276388f, 0.766337f, 0.300809f, - 0.213065f, 0.285164f, 0.219168f, 0.237388f, 0.241255f, 0.236977f, 0.267408f, 0.310142f, - 0.809631f, 0.233887f, 0.829287f, 0.219562f, 0.845007f, 0.256352f, 0.815314f, 0.276388f, - 0.179662f, 0.263312f, 0.199067f, 0.222464f, 0.219168f, 0.237388f, 0.213065f, 0.285164f, - 0.842355f, 0.195160f, 0.859075f, 0.228168f, 0.845007f, 0.256352f, 0.829287f, 0.219562f, - 0.179662f, 0.263312f, 0.162803f, 0.231720f, 0.176788f, 0.196179f, 0.199067f, 0.222464f, - 0.687018f, 0.077204f, 0.788458f, 0.080826f, 0.786480f, 0.117591f, 0.715482f, 0.139727f, - 0.246666f, 0.114850f, 0.246353f, 0.076510f, 0.349875f, 0.075955f, 0.319538f, 0.139409f, - 0.760215f, 0.193244f, 0.715482f, 0.139727f, 0.786480f, 0.117591f, 0.785486f, 0.152330f, - 0.246666f, 0.114850f, 0.319538f, 0.139409f, 0.271553f, 0.193871f, 0.245969f, 0.151002f, - 0.698172f, 0.216906f, 0.663103f, 0.190671f, 0.715482f, 0.139727f, 0.760215f, 0.193244f, - 0.319538f, 0.139409f, 0.373474f, 0.191872f, 0.337414f, 0.219179f, 0.271553f, 0.193871f, - 0.663103f, 0.190671f, 0.623495f, 0.146796f, 0.629482f, 0.130456f, 0.715482f, 0.139727f, - 0.407648f, 0.130594f, 0.413741f, 0.147158f, 0.373474f, 0.191872f, 0.319538f, 0.139409f, - 0.629482f, 0.130456f, 0.687018f, 0.077204f, 0.715482f, 0.139727f, - 0.319538f, 0.139409f, 0.349875f, 0.075955f, 0.407648f, 0.130594f, - 0.663103f, 0.190671f, 0.619303f, 0.159841f, 0.623495f, 0.146796f, - 0.413741f, 0.147158f, 0.418035f, 0.160361f, 0.373474f, 0.191872f, - 0.842355f, 0.195160f, 0.837382f, 0.156361f, 0.858171f, 0.137775f, 0.875030f, 0.184705f, - 0.171653f, 0.132294f, 0.196622f, 0.155241f, 0.176788f, 0.196179f, 0.145224f, 0.182749f, - 0.909112f, 0.183261f, 0.875030f, 0.184705f, 0.858171f, 0.137775f, 0.886245f, 0.121777f, - 0.171653f, 0.132294f, 0.145224f, 0.182749f, 0.107928f, 0.179083f, 0.141314f, 0.112482f, - 0.785486f, 0.152330f, 0.786480f, 0.117591f, 0.858171f, 0.137775f, 0.837382f, 0.156361f, - 0.171653f, 0.132294f, 0.246666f, 0.114850f, 0.245969f, 0.151002f, 0.196622f, 0.155241f, - 0.788458f, 0.080826f, 0.849114f, 0.099732f, 0.858171f, 0.137775f, 0.786480f, 0.117591f, - 0.171653f, 0.132294f, 0.183115f, 0.092127f, 0.246353f, 0.076510f, 0.246666f, 0.114850f, - 0.886245f, 0.121777f, 0.858171f, 0.137775f, 0.849114f, 0.099732f, - 0.183115f, 0.092127f, 0.171653f, 0.132294f, 0.141314f, 0.112482f, - 0.506166f, 0.904851f, 0.432388f, 0.894943f, 0.438797f, 0.870229f, 0.491058f, 0.881714f, - 0.315867f, 0.868209f, 0.321637f, 0.893225f, 0.247207f, 0.901159f, 0.263032f, 0.878321f, - 0.506166f, 0.904851f, 0.491058f, 0.881714f, 0.572792f, 0.860484f, 0.604825f, 0.879946f, - 0.181486f, 0.854693f, 0.263032f, 0.878321f, 0.247207f, 0.901159f, 0.148729f, 0.873349f, - 0.604825f, 0.879946f, 0.572792f, 0.860484f, 0.586396f, 0.793977f, 0.619962f, 0.791615f, - 0.169745f, 0.787474f, 0.181486f, 0.854693f, 0.148729f, 0.873349f, 0.136063f, 0.784093f, - 0.619962f, 0.791615f, 0.586396f, 0.793977f, 0.549027f, 0.746412f, 0.563786f, 0.739211f, - 0.208656f, 0.740879f, 0.169745f, 0.787474f, 0.136063f, 0.784093f, 0.194086f, 0.733241f, - 0.563786f, 0.739211f, 0.549027f, 0.746412f, 0.500314f, 0.711729f, 0.508270f, 0.697693f, - 0.258399f, 0.707497f, 0.208656f, 0.740879f, 0.194086f, 0.733241f, 0.250811f, 0.693249f, - 0.508270f, 0.697693f, 0.500314f, 0.711729f, 0.438641f, 0.680683f, 0.434803f, 0.658882f, - 0.320962f, 0.677959f, 0.258399f, 0.707497f, 0.250811f, 0.693249f, 0.325318f, 0.656224f, - 0.500314f, 0.711729f, 0.505666f, 0.730944f, 0.452955f, 0.700023f, 0.438641f, 0.680683f, - 0.306136f, 0.696976f, 0.252524f, 0.726592f, 0.258399f, 0.707497f, 0.320962f, 0.677959f, - 0.549027f, 0.746412f, 0.542850f, 0.755753f, 0.505666f, 0.730944f, 0.500314f, 0.711729f, - 0.252524f, 0.726592f, 0.214575f, 0.750414f, 0.208656f, 0.740879f, 0.258399f, 0.707497f, - 0.586396f, 0.793977f, 0.568148f, 0.787367f, 0.542850f, 0.755753f, 0.549027f, 0.746412f, - 0.214575f, 0.750414f, 0.188269f, 0.781375f, 0.169745f, 0.787474f, 0.208656f, 0.740879f, - 0.572792f, 0.860484f, 0.555495f, 0.826352f, 0.568148f, 0.787367f, 0.586396f, 0.793977f, - 0.188269f, 0.781375f, 0.199850f, 0.820889f, 0.181486f, 0.854693f, 0.169745f, 0.787474f, - 0.491058f, 0.881714f, 0.501231f, 0.844356f, 0.555495f, 0.826352f, 0.572792f, 0.860484f, - 0.199850f, 0.820889f, 0.253846f, 0.840502f, 0.263032f, 0.878321f, 0.181486f, 0.854693f, - 0.491058f, 0.881714f, 0.438797f, 0.870229f, 0.457832f, 0.840040f, 0.501231f, 0.844356f, - 0.297562f, 0.837358f, 0.315867f, 0.868209f, 0.263032f, 0.878321f, 0.253846f, 0.840502f, - 0.760215f, 0.193244f, 0.785486f, 0.152330f, 0.796021f, 0.176969f, 0.783193f, 0.187449f, - 0.233625f, 0.175620f, 0.245969f, 0.151002f, 0.271553f, 0.193871f, 0.246955f, 0.187075f, - 0.391039f, 0.611891f, 0.434803f, 0.658882f, 0.438641f, 0.680683f, 0.394766f, 0.686125f, - 0.320962f, 0.677959f, 0.325318f, 0.656224f, 0.369913f, 0.610196f, 0.364838f, 0.684445f, - 0.789046f, 0.233323f, 0.760215f, 0.193244f, 0.783193f, 0.187449f, 0.809631f, 0.233887f, - 0.246955f, 0.187075f, 0.271553f, 0.193871f, 0.241255f, 0.236977f, 0.219168f, 0.237388f, - 0.391747f, 0.862097f, 0.401605f, 0.841460f, 0.438797f, 0.870229f, 0.432388f, 0.894943f, - 0.315867f, 0.868209f, 0.354026f, 0.840297f, 0.363377f, 0.861308f, 0.321637f, 0.893225f, - 0.438641f, 0.680683f, 0.452955f, 0.700023f, 0.435018f, 0.718280f, 0.394766f, 0.686125f, - 0.323658f, 0.715731f, 0.306136f, 0.696976f, 0.320962f, 0.677959f, 0.364838f, 0.684445f, - 0.433669f, 0.729661f, 0.384658f, 0.710299f, 0.394766f, 0.686125f, 0.435018f, 0.718280f, - 0.364838f, 0.684445f, 0.374400f, 0.708969f, 0.324726f, 0.727177f, 0.323658f, 0.715731f, - 0.410995f, 0.747662f, 0.384658f, 0.710299f, 0.433669f, 0.729661f, 0.427812f, 0.742828f, - 0.324726f, 0.727177f, 0.374400f, 0.708969f, 0.347028f, 0.745816f, 0.330270f, 0.740536f, - 0.418086f, 0.784946f, 0.384657f, 0.795423f, 0.384658f, 0.710299f, 0.410995f, 0.747662f, - 0.374400f, 0.708969f, 0.372270f, 0.794472f, 0.338952f, 0.783073f, 0.347028f, 0.745816f, - 0.401605f, 0.841460f, 0.384657f, 0.795423f, 0.418086f, 0.784946f, 0.431333f, 0.817535f, - 0.338952f, 0.783073f, 0.372270f, 0.794472f, 0.354026f, 0.840297f, 0.324790f, 0.815460f, - 0.438797f, 0.870229f, 0.401605f, 0.841460f, 0.431333f, 0.817535f, 0.457832f, 0.840040f, - 0.324790f, 0.815460f, 0.354026f, 0.840297f, 0.315867f, 0.868209f, 0.297562f, 0.837358f, - 0.809631f, 0.233887f, 0.816266f, 0.203086f, 0.825107f, 0.209762f, 0.829287f, 0.219562f, - 0.199767f, 0.214827f, 0.209828f, 0.206161f, 0.219168f, 0.237388f, 0.199067f, 0.222464f, - 0.809631f, 0.233887f, 0.783193f, 0.187449f, 0.802192f, 0.184609f, 0.816266f, 0.203086f, - 0.226485f, 0.183086f, 0.246955f, 0.187075f, 0.219168f, 0.237388f, 0.209828f, 0.206161f, - 0.783193f, 0.187449f, 0.796021f, 0.176969f, 0.802192f, 0.184609f, - 0.226485f, 0.183086f, 0.233625f, 0.175620f, 0.246955f, 0.187075f, - 0.457832f, 0.840040f, 0.431333f, 0.817535f, 0.448505f, 0.804621f, 0.473386f, 0.824700f, - 0.307886f, 0.802031f, 0.324790f, 0.815460f, 0.297562f, 0.837358f, 0.282357f, 0.821525f, - 0.431333f, 0.817535f, 0.418086f, 0.784946f, 0.435868f, 0.779569f, 0.448505f, 0.804621f, - 0.321237f, 0.777208f, 0.338952f, 0.783073f, 0.324790f, 0.815460f, 0.307886f, 0.802031f, - 0.418086f, 0.784946f, 0.410995f, 0.747662f, 0.423718f, 0.754191f, 0.435868f, 0.779569f, - 0.334089f, 0.752045f, 0.347028f, 0.745816f, 0.338952f, 0.783073f, 0.321237f, 0.777208f, - 0.410995f, 0.747662f, 0.427812f, 0.742828f, 0.437950f, 0.749777f, 0.423718f, 0.754191f, - 0.319919f, 0.747250f, 0.330270f, 0.740536f, 0.347028f, 0.745816f, 0.334089f, 0.752045f, - 0.427812f, 0.742828f, 0.433669f, 0.729661f, 0.445392f, 0.731997f, 0.437950f, 0.749777f, - 0.312907f, 0.729222f, 0.324726f, 0.727177f, 0.330270f, 0.740536f, 0.319919f, 0.747250f, - 0.433669f, 0.729661f, 0.435018f, 0.718280f, 0.440995f, 0.724383f, 0.445392f, 0.731997f, - 0.317510f, 0.721697f, 0.323658f, 0.715731f, 0.324726f, 0.727177f, 0.312907f, 0.729222f, - 0.435018f, 0.718280f, 0.452955f, 0.700023f, 0.455277f, 0.713731f, 0.440995f, 0.724383f, - 0.303460f, 0.710657f, 0.306136f, 0.696976f, 0.323658f, 0.715731f, 0.317510f, 0.721697f, - 0.501231f, 0.844356f, 0.457832f, 0.840040f, 0.473386f, 0.824700f, 0.512485f, 0.828811f, - 0.282357f, 0.821525f, 0.297562f, 0.837358f, 0.253846f, 0.840502f, 0.242975f, 0.824574f, - 0.555495f, 0.826352f, 0.501231f, 0.844356f, 0.512485f, 0.828811f, 0.550942f, 0.811814f, - 0.242975f, 0.824574f, 0.253846f, 0.840502f, 0.199850f, 0.820889f, 0.204839f, 0.806417f, - 0.568148f, 0.787367f, 0.555495f, 0.826352f, 0.550942f, 0.811814f, 0.552139f, 0.787682f, - 0.204839f, 0.806417f, 0.199850f, 0.820889f, 0.188269f, 0.781375f, 0.204331f, 0.782156f, - 0.542850f, 0.755753f, 0.568148f, 0.787367f, 0.552139f, 0.787682f, 0.539407f, 0.764539f, - 0.204331f, 0.782156f, 0.188269f, 0.781375f, 0.214575f, 0.750414f, 0.217774f, 0.759319f, - 0.505666f, 0.730944f, 0.542850f, 0.755753f, 0.539407f, 0.764539f, 0.508439f, 0.743135f, - 0.217774f, 0.759319f, 0.214575f, 0.750414f, 0.252524f, 0.726592f, 0.249419f, 0.738732f, - 0.452955f, 0.700023f, 0.505666f, 0.730944f, 0.508439f, 0.743135f, 0.455277f, 0.713731f, - 0.249419f, 0.738732f, 0.252524f, 0.726592f, 0.306136f, 0.696976f, 0.303460f, 0.710657f, - 0.437950f, 0.749777f, 0.445392f, 0.731997f, 0.470841f, 0.748408f, 0.454776f, 0.761665f, - 0.286960f, 0.745020f, 0.312907f, 0.729222f, 0.319919f, 0.747250f, 0.302729f, 0.758742f, - 0.454776f, 0.761665f, 0.470841f, 0.748408f, 0.488870f, 0.770464f, 0.475403f, 0.783904f, - 0.268291f, 0.766661f, 0.286960f, 0.745020f, 0.302729f, 0.758742f, 0.281439f, 0.780511f, - 0.475403f, 0.783904f, 0.488870f, 0.770464f, 0.503673f, 0.787562f, 0.494476f, 0.802470f, - 0.252972f, 0.783410f, 0.268291f, 0.766661f, 0.281439f, 0.780511f, 0.261790f, 0.798626f, - 0.494476f, 0.802470f, 0.503673f, 0.787562f, 0.518562f, 0.791602f, 0.516802f, 0.807339f, - 0.237920f, 0.787045f, 0.252972f, 0.783410f, 0.261790f, 0.798626f, 0.239243f, 0.802891f, - 0.512485f, 0.828811f, 0.473386f, 0.824700f, 0.494476f, 0.802470f, 0.516802f, 0.807339f, - 0.261790f, 0.798626f, 0.282357f, 0.821525f, 0.242975f, 0.824574f, 0.239243f, 0.802891f, - 0.448505f, 0.804621f, 0.475403f, 0.783904f, 0.494476f, 0.802470f, 0.473386f, 0.824700f, - 0.261790f, 0.798626f, 0.281439f, 0.780511f, 0.307886f, 0.802031f, 0.282357f, 0.821525f, - 0.448505f, 0.804621f, 0.435868f, 0.779569f, 0.454776f, 0.761665f, 0.475403f, 0.783904f, - 0.302729f, 0.758742f, 0.321237f, 0.777208f, 0.307886f, 0.802031f, 0.281439f, 0.780511f, - 0.437950f, 0.749777f, 0.454776f, 0.761665f, 0.435868f, 0.779569f, 0.423718f, 0.754191f, - 0.321237f, 0.777208f, 0.302729f, 0.758742f, 0.319919f, 0.747250f, 0.334089f, 0.752045f, - 0.440995f, 0.724383f, 0.455277f, 0.713731f, 0.470841f, 0.748408f, 0.445392f, 0.731997f, - 0.286960f, 0.745020f, 0.303460f, 0.710657f, 0.317510f, 0.721697f, 0.312907f, 0.729222f, - 0.508439f, 0.743135f, 0.488870f, 0.770464f, 0.470841f, 0.748408f, 0.455277f, 0.713731f, - 0.286960f, 0.745020f, 0.268291f, 0.766661f, 0.249419f, 0.738732f, 0.303460f, 0.710657f, - 0.539407f, 0.764539f, 0.503673f, 0.787562f, 0.488870f, 0.770464f, 0.508439f, 0.743135f, - 0.268291f, 0.766661f, 0.252972f, 0.783410f, 0.217774f, 0.759319f, 0.249419f, 0.738732f, - 0.552139f, 0.787682f, 0.518562f, 0.791602f, 0.503673f, 0.787562f, 0.539407f, 0.764539f, - 0.252972f, 0.783410f, 0.237920f, 0.787045f, 0.204331f, 0.782156f, 0.217774f, 0.759319f, - 0.550942f, 0.811814f, 0.516802f, 0.807339f, 0.518562f, 0.791602f, 0.552139f, 0.787682f, - 0.237920f, 0.787045f, 0.239243f, 0.802891f, 0.204839f, 0.806417f, 0.204331f, 0.782156f, - 0.512485f, 0.828811f, 0.516802f, 0.807339f, 0.550942f, 0.811814f, - 0.204839f, 0.806417f, 0.239243f, 0.802891f, 0.242975f, 0.824574f, - 0.508270f, 0.697693f, 0.434803f, 0.658882f, 0.484068f, 0.628776f, 0.543385f, 0.683538f, - 0.276936f, 0.625067f, 0.325318f, 0.656224f, 0.250811f, 0.693249f, 0.216123f, 0.678120f, - 0.563786f, 0.739211f, 0.508270f, 0.697693f, 0.543385f, 0.683538f, 0.581052f, 0.726933f, - 0.216123f, 0.678120f, 0.250811f, 0.693249f, 0.194086f, 0.733241f, 0.177176f, 0.720426f, - 0.619962f, 0.791615f, 0.563786f, 0.739211f, 0.581052f, 0.726933f, 0.616701f, 0.759965f, - 0.177176f, 0.720426f, 0.194086f, 0.733241f, 0.136063f, 0.784093f, 0.140379f, 0.752377f, - 0.707492f, 0.759884f, 0.619962f, 0.791615f, 0.616701f, 0.759965f, 0.660647f, 0.741167f, - 0.140379f, 0.752377f, 0.136063f, 0.784093f, 0.049526f, 0.748824f, 0.097038f, 0.732052f, - 0.745511f, 0.652100f, 0.707492f, 0.759884f, 0.660647f, 0.741167f, 0.677256f, 0.670436f, - 0.097038f, 0.732052f, 0.049526f, 0.748824f, 0.019409f, 0.639749f, 0.083564f, 0.662038f, - 0.740843f, 0.572428f, 0.745511f, 0.652100f, 0.677256f, 0.670436f, 0.671403f, 0.592656f, - 0.083564f, 0.662038f, 0.019409f, 0.639749f, 0.033664f, 0.564403f, 0.092820f, 0.589862f, - 0.677256f, 0.670436f, 0.543385f, 0.683538f, 0.484068f, 0.628776f, 0.671403f, 0.592656f, - 0.276936f, 0.625067f, 0.216123f, 0.678120f, 0.083564f, 0.662038f, 0.092820f, 0.589862f, - 0.677256f, 0.670436f, 0.660647f, 0.741167f, 0.581052f, 0.726933f, 0.543385f, 0.683538f, - 0.177176f, 0.720426f, 0.097038f, 0.732052f, 0.083564f, 0.662038f, 0.216123f, 0.678120f, - 0.660647f, 0.741167f, 0.616701f, 0.759965f, 0.581052f, 0.726933f, - 0.177176f, 0.720426f, 0.140379f, 0.752377f, 0.097038f, 0.732052f, - 0.842355f, 0.195160f, 0.829287f, 0.219562f, 0.834578f, 0.206879f, 0.834705f, 0.206959f, - 0.033664f, 0.564403f, 0.051216f, 0.522659f, 0.145041f, 0.562595f, 0.092820f, 0.589862f, - 0.620420f, 0.565675f, 0.671403f, 0.592656f, 0.484068f, 0.628776f, 0.498072f, 0.552315f, - 0.276936f, 0.625067f, 0.092820f, 0.589862f, 0.145041f, 0.562595f, 0.264218f, 0.550140f, - 0.391039f, 0.611891f, 0.498072f, 0.552315f, 0.484068f, 0.628776f, 0.434803f, 0.658882f, - 0.276936f, 0.625067f, 0.264218f, 0.550140f, 0.369913f, 0.610196f, 0.325318f, 0.656224f, +static const float monkeyuvs[] = { + 0.890955f, 0.590063f, 0.870622f, 0.589649f, 0.860081f, 0.560115f, 0.904571f, 0.559404f, + 0.856226f, 0.850547f, 0.868067f, 0.821510f, 0.888398f, 0.821999f, 0.900640f, 0.853232f, + 0.904571f, 0.559404f, 0.860081f, 0.560115f, 0.853018f, 0.521562f, 0.920166f, 0.524546f, + 0.847458f, 0.888748f, 0.856226f, 0.850547f, 0.900640f, 0.853232f, 0.914672f, 0.888748f, + 0.860081f, 0.560115f, 0.828900f, 0.590771f, 0.798481f, 0.569535f, 0.853018f, 0.521562f, + 0.795104f, 0.838402f, 0.826436f, 0.818537f, 0.856226f, 0.850547f, 0.847458f, 0.888748f, + 0.870622f, 0.589649f, 0.854402f, 0.604754f, 0.828900f, 0.590771f, 0.860081f, 0.560115f, + 0.826436f, 0.818537f, 0.852534f, 0.805700f, 0.868067f, 0.821510f, 0.856226f, 0.850547f, + 0.854402f, 0.604754f, 0.854107f, 0.625459f, 0.828171f, 0.633354f, 0.828900f, 0.590771f, + 0.827598f, 0.775964f, 0.853157f, 0.785002f, 0.852534f, 0.805700f, 0.826436f, 0.818537f, + 0.828900f, 0.590771f, 0.828171f, 0.633354f, 0.791018f, 0.645443f, 0.798481f, 0.569535f, + 0.791018f, 0.762238f, 0.827598f, 0.775964f, 0.826436f, 0.818537f, 0.795104f, 0.838402f, + 0.828171f, 0.633354f, 0.855181f, 0.668527f, 0.842358f, 0.702491f, 0.791018f, 0.645443f, + 0.844839f, 0.707525f, 0.856142f, 0.742025f, 0.827598f, 0.775964f, 0.791018f, 0.762238f, + 0.854107f, 0.625459f, 0.867508f, 0.642291f, 0.855181f, 0.668527f, 0.828171f, 0.633354f, + 0.856142f, 0.742025f, 0.867293f, 0.768782f, 0.853157f, 0.785002f, 0.827598f, 0.775964f, + 0.867508f, 0.642291f, 0.890474f, 0.641909f, 0.900375f, 0.666964f, 0.855181f, 0.668527f, + 0.901223f, 0.745592f, 0.890219f, 0.770183f, 0.867293f, 0.768782f, 0.856142f, 0.742025f, + 0.855181f, 0.668527f, 0.900375f, 0.666964f, 0.918898f, 0.699697f, 0.842358f, 0.702491f, + 0.921180f, 0.713713f, 0.901223f, 0.745592f, 0.856142f, 0.742025f, 0.844839f, 0.707525f, + 0.900375f, 0.666964f, 0.931889f, 0.636832f, 0.968392f, 0.645333f, 0.918898f, 0.699697f, + 0.968213f, 0.770220f, 0.931368f, 0.777093f, 0.901223f, 0.745592f, 0.921180f, 0.713713f, + 0.890474f, 0.641909f, 0.905882f, 0.627902f, 0.931889f, 0.636832f, 0.900375f, 0.666964f, + 0.931368f, 0.777093f, 0.904990f, 0.784860f, 0.890219f, 0.770183f, 0.901223f, 0.745592f, + 0.905882f, 0.627902f, 0.906232f, 0.605742f, 0.933717f, 0.593037f, 0.931889f, 0.636832f, + 0.931250f, 0.820926f, 0.904357f, 0.807013f, 0.904990f, 0.784860f, 0.931368f, 0.777093f, + 0.931889f, 0.636832f, 0.933717f, 0.593037f, 0.968392f, 0.573812f, 0.968392f, 0.645333f, + 0.965038f, 0.841671f, 0.931250f, 0.820926f, 0.931368f, 0.777093f, 0.968213f, 0.770220f, + 0.933717f, 0.593037f, 0.904571f, 0.559404f, 0.920166f, 0.524546f, 0.968392f, 0.573812f, + 0.914672f, 0.888748f, 0.900640f, 0.853232f, 0.931250f, 0.820926f, 0.965038f, 0.841671f, + 0.906232f, 0.605742f, 0.890955f, 0.590063f, 0.904571f, 0.559404f, 0.933717f, 0.593037f, + 0.900640f, 0.853232f, 0.888398f, 0.821999f, 0.904357f, 0.807013f, 0.931250f, 0.820926f, + 0.890955f, 0.590063f, 0.906232f, 0.605742f, 0.902359f, 0.607909f, 0.889591f, 0.593275f, + 0.900583f, 0.804677f, 0.904357f, 0.807013f, 0.888398f, 0.821999f, 0.887178f, 0.818729f, + 0.906232f, 0.605742f, 0.905882f, 0.627902f, 0.899781f, 0.626257f, 0.902359f, 0.607909f, + 0.898822f, 0.786233f, 0.904990f, 0.784860f, 0.904357f, 0.807013f, 0.900583f, 0.804677f, + 0.905882f, 0.627902f, 0.890474f, 0.641909f, 0.887842f, 0.636527f, 0.899781f, 0.626257f, + 0.887351f, 0.775442f, 0.890219f, 0.770183f, 0.904990f, 0.784860f, 0.898822f, 0.786233f, + 0.890474f, 0.641909f, 0.867508f, 0.642291f, 0.870908f, 0.635245f, 0.887842f, 0.636527f, + 0.870376f, 0.775972f, 0.867293f, 0.768782f, 0.890219f, 0.770183f, 0.887351f, 0.775442f, + 0.867508f, 0.642291f, 0.854107f, 0.625459f, 0.859881f, 0.623942f, 0.870908f, 0.635245f, + 0.858859f, 0.786774f, 0.853157f, 0.785002f, 0.867293f, 0.768782f, 0.870376f, 0.775972f, + 0.854107f, 0.625459f, 0.854402f, 0.604754f, 0.859664f, 0.608186f, 0.859881f, 0.623942f, + 0.857942f, 0.802505f, 0.852534f, 0.805700f, 0.853157f, 0.785002f, 0.858859f, 0.786774f, + 0.854402f, 0.604754f, 0.870622f, 0.589649f, 0.871664f, 0.593961f, 0.859664f, 0.608186f, + 0.869299f, 0.817249f, 0.868067f, 0.821510f, 0.852534f, 0.805700f, 0.857942f, 0.802505f, + 0.870622f, 0.589649f, 0.890955f, 0.590063f, 0.889591f, 0.593275f, 0.871664f, 0.593961f, + 0.887178f, 0.818729f, 0.888398f, 0.821999f, 0.868067f, 0.821510f, 0.869299f, 0.817249f, + 0.879400f, 0.616512f, 0.871664f, 0.593961f, 0.889591f, 0.593275f, 0.887178f, 0.818729f, + 0.869299f, 0.817249f, 0.878029f, 0.795063f, 0.859664f, 0.608186f, 0.871664f, 0.593961f, + 0.879400f, 0.616512f, 0.878029f, 0.795063f, 0.869299f, 0.817249f, 0.857942f, 0.802505f, + 0.879400f, 0.616512f, 0.859881f, 0.623942f, 0.859664f, 0.608186f, 0.857942f, 0.802505f, + 0.858859f, 0.786774f, 0.878029f, 0.795063f, 0.879400f, 0.616512f, 0.870908f, 0.635245f, + 0.859881f, 0.623942f, 0.858859f, 0.786774f, 0.870376f, 0.775972f, 0.878029f, 0.795063f, + 0.879400f, 0.616512f, 0.887842f, 0.636527f, 0.870908f, 0.635245f, 0.870376f, 0.775972f, + 0.887351f, 0.775442f, 0.878029f, 0.795063f, 0.879400f, 0.616512f, 0.899781f, 0.626257f, + 0.887842f, 0.636527f, 0.887351f, 0.775442f, 0.898822f, 0.786233f, 0.878029f, 0.795063f, + 0.879400f, 0.616512f, 0.902359f, 0.607909f, 0.899781f, 0.626257f, 0.898822f, 0.786233f, + 0.900583f, 0.804677f, 0.878029f, 0.795063f, 0.879400f, 0.616512f, 0.889591f, 0.593275f, + 0.902359f, 0.607909f, 0.900583f, 0.804677f, 0.887178f, 0.818729f, 0.878029f, 0.795063f, + 0.540260f, 0.053805f, 0.536419f, 0.062072f, 0.518925f, 0.059681f, 0.518916f, 0.050294f, + 0.518925f, 0.059681f, 0.501452f, 0.062043f, 0.497626f, 0.053770f, 0.518916f, 0.050294f, + 0.551930f, 0.058338f, 0.542788f, 0.064089f, 0.536419f, 0.062072f, 0.540260f, 0.053805f, + 0.501452f, 0.062043f, 0.495083f, 0.064047f, 0.485955f, 0.058273f, 0.497626f, 0.053770f, + 0.555073f, 0.061900f, 0.546290f, 0.072669f, 0.542788f, 0.064089f, 0.551930f, 0.058338f, + 0.495083f, 0.064047f, 0.491565f, 0.072625f, 0.482805f, 0.061829f, 0.485955f, 0.058273f, + 0.563812f, 0.076586f, 0.548333f, 0.084893f, 0.546290f, 0.072669f, 0.555073f, 0.061900f, + 0.491565f, 0.072625f, 0.489507f, 0.084858f, 0.474014f, 0.076511f, 0.482805f, 0.061829f, + 0.583135f, 0.108495f, 0.555621f, 0.121749f, 0.548333f, 0.084893f, 0.563812f, 0.076586f, + 0.489507f, 0.084858f, 0.482177f, 0.121781f, 0.454527f, 0.108481f, 0.474014f, 0.076511f, + 0.605512f, 0.165134f, 0.647395f, 0.200502f, 0.621513f, 0.227818f, 0.553118f, 0.209599f, + 0.416514f, 0.229490f, 0.389677f, 0.201890f, 0.432024f, 0.165644f, 0.485339f, 0.210053f, + 0.647395f, 0.200502f, 0.676379f, 0.233241f, 0.664761f, 0.253225f, 0.621513f, 0.227818f, + 0.372747f, 0.256357f, 0.360308f, 0.235899f, 0.389677f, 0.201890f, 0.416514f, 0.229490f, + 0.676379f, 0.233241f, 0.715342f, 0.265392f, 0.683908f, 0.279995f, 0.664761f, 0.253225f, + 0.353696f, 0.284606f, 0.320452f, 0.270303f, 0.360308f, 0.235899f, 0.372747f, 0.256357f, + 0.715342f, 0.265392f, 0.707254f, 0.310054f, 0.687515f, 0.311539f, 0.683908f, 0.279995f, + 0.351187f, 0.317440f, 0.330721f, 0.316853f, 0.320452f, 0.270303f, 0.353696f, 0.284606f, + 0.707254f, 0.310054f, 0.697446f, 0.332673f, 0.676824f, 0.323937f, 0.687515f, 0.311539f, + 0.362723f, 0.329722f, 0.341964f, 0.339667f, 0.330721f, 0.316853f, 0.351187f, 0.317440f, + 0.697446f, 0.332673f, 0.662817f, 0.372521f, 0.639050f, 0.357330f, 0.676824f, 0.323937f, + 0.402772f, 0.362131f, 0.379297f, 0.378686f, 0.341964f, 0.339667f, 0.362723f, 0.329722f, + 0.662817f, 0.372521f, 0.626842f, 0.395792f, 0.618316f, 0.375151f, 0.639050f, 0.357330f, + 0.424583f, 0.379267f, 0.416915f, 0.400552f, 0.379297f, 0.378686f, 0.402772f, 0.362131f, + 0.626842f, 0.395792f, 0.604826f, 0.397804f, 0.600808f, 0.377857f, 0.618316f, 0.375151f, + 0.442396f, 0.381222f, 0.439252f, 0.401540f, 0.416915f, 0.400552f, 0.424583f, 0.379267f, + 0.604826f, 0.397804f, 0.553095f, 0.390512f, 0.559674f, 0.357011f, 0.600808f, 0.377857f, + 0.482938f, 0.358497f, 0.490934f, 0.391862f, 0.439252f, 0.401540f, 0.442396f, 0.381222f, + 0.553095f, 0.390512f, 0.521923f, 0.386009f, 0.521086f, 0.343868f, 0.559674f, 0.357011f, + 0.521086f, 0.343868f, 0.521923f, 0.386009f, 0.490934f, 0.391862f, 0.482938f, 0.358497f, + 0.577279f, 0.340156f, 0.599845f, 0.344815f, 0.600808f, 0.377857f, 0.559674f, 0.357011f, + 0.442396f, 0.381222f, 0.441977f, 0.347815f, 0.464579f, 0.342230f, 0.482938f, 0.358497f, + 0.599845f, 0.344815f, 0.615546f, 0.342005f, 0.618316f, 0.375151f, 0.600808f, 0.377857f, + 0.424583f, 0.379267f, 0.425972f, 0.345582f, 0.441977f, 0.347815f, 0.442396f, 0.381222f, + 0.634472f, 0.332311f, 0.639050f, 0.357330f, 0.618316f, 0.375151f, 0.615546f, 0.342005f, + 0.424583f, 0.379267f, 0.402772f, 0.362131f, 0.406362f, 0.336480f, 0.425972f, 0.345582f, + 0.662406f, 0.312804f, 0.676824f, 0.323937f, 0.639050f, 0.357330f, 0.634472f, 0.332311f, + 0.402772f, 0.362131f, 0.362723f, 0.329722f, 0.377061f, 0.317685f, 0.406362f, 0.336480f, + 0.668440f, 0.297958f, 0.687515f, 0.311539f, 0.676824f, 0.323937f, 0.662406f, 0.312804f, + 0.362723f, 0.329722f, 0.351187f, 0.317440f, 0.370304f, 0.302644f, 0.377061f, 0.317685f, + 0.664101f, 0.277872f, 0.683908f, 0.279995f, 0.687515f, 0.311539f, 0.668440f, 0.297958f, + 0.351187f, 0.317440f, 0.353696f, 0.284606f, 0.374100f, 0.281778f, 0.370304f, 0.302644f, + 0.639236f, 0.253047f, 0.664761f, 0.253225f, 0.683908f, 0.279995f, 0.664101f, 0.277872f, + 0.353696f, 0.284606f, 0.372747f, 0.256357f, 0.398938f, 0.255633f, 0.374100f, 0.281778f, + 0.613992f, 0.242662f, 0.621513f, 0.227818f, 0.664761f, 0.253225f, 0.639236f, 0.253047f, + 0.372747f, 0.256357f, 0.416514f, 0.229490f, 0.424464f, 0.244473f, 0.398938f, 0.255633f, + 0.572941f, 0.258564f, 0.553118f, 0.209599f, 0.621513f, 0.227818f, 0.613992f, 0.242662f, + 0.416514f, 0.229490f, 0.485339f, 0.210053f, 0.466409f, 0.259709f, 0.424464f, 0.244473f, + 0.572941f, 0.258564f, 0.563905f, 0.272007f, 0.519760f, 0.248864f, 0.553118f, 0.209599f, + 0.519760f, 0.248864f, 0.475886f, 0.273078f, 0.466409f, 0.259709f, 0.485339f, 0.210053f, + 0.577279f, 0.340156f, 0.559674f, 0.357011f, 0.521086f, 0.343868f, 0.558527f, 0.316594f, + 0.521086f, 0.343868f, 0.482938f, 0.358497f, 0.464579f, 0.342230f, 0.482619f, 0.317843f, + 0.558527f, 0.316594f, 0.521086f, 0.343868f, 0.520277f, 0.294764f, 0.556923f, 0.291214f, + 0.520277f, 0.294764f, 0.521086f, 0.343868f, 0.482619f, 0.317843f, 0.483433f, 0.292249f, + 0.519760f, 0.248864f, 0.563905f, 0.272007f, 0.556923f, 0.291214f, 0.520277f, 0.294764f, + 0.483433f, 0.292249f, 0.475886f, 0.273078f, 0.519760f, 0.248864f, 0.520277f, 0.294764f, + 0.525483f, 0.068967f, 0.518928f, 0.067899f, 0.518925f, 0.059681f, 0.536419f, 0.062072f, + 0.518925f, 0.059681f, 0.518928f, 0.067899f, 0.512375f, 0.068956f, 0.501452f, 0.062043f, + 0.531231f, 0.073829f, 0.525483f, 0.068967f, 0.536419f, 0.062072f, 0.542788f, 0.064089f, + 0.501452f, 0.062043f, 0.512375f, 0.068956f, 0.506626f, 0.073811f, 0.495083f, 0.064047f, + 0.531019f, 0.087431f, 0.531231f, 0.073829f, 0.542788f, 0.064089f, 0.546290f, 0.072669f, + 0.495083f, 0.064047f, 0.506626f, 0.073811f, 0.506827f, 0.087416f, 0.491565f, 0.072625f, + 0.555621f, 0.121749f, 0.532042f, 0.127713f, 0.532669f, 0.090920f, 0.548333f, 0.084893f, + 0.505177f, 0.090908f, 0.505828f, 0.127728f, 0.482177f, 0.121781f, 0.489507f, 0.084858f, + 0.531019f, 0.087431f, 0.546290f, 0.072669f, 0.548333f, 0.084893f, 0.532669f, 0.090920f, + 0.489507f, 0.084858f, 0.491565f, 0.072625f, 0.506827f, 0.087416f, 0.505177f, 0.090908f, + 0.538112f, 0.158382f, 0.518981f, 0.151749f, 0.518941f, 0.128358f, 0.532042f, 0.127713f, + 0.518941f, 0.128358f, 0.518981f, 0.151749f, 0.499851f, 0.158434f, 0.505828f, 0.127728f, + 0.532669f, 0.090920f, 0.532042f, 0.127713f, 0.518941f, 0.128358f, 0.518925f, 0.093952f, + 0.518941f, 0.128358f, 0.505828f, 0.127728f, 0.505177f, 0.090908f, 0.518925f, 0.093952f, + 0.518927f, 0.085180f, 0.531019f, 0.087431f, 0.532669f, 0.090920f, 0.518925f, 0.093952f, + 0.505177f, 0.090908f, 0.506827f, 0.087416f, 0.518927f, 0.085180f, 0.518925f, 0.093952f, + 0.548362f, 0.173560f, 0.537959f, 0.175966f, 0.535214f, 0.166808f, 0.538112f, 0.158382f, + 0.502799f, 0.166857f, 0.500100f, 0.176033f, 0.489683f, 0.173693f, 0.499851f, 0.158434f, + 0.544281f, 0.193366f, 0.537248f, 0.187577f, 0.537959f, 0.175966f, 0.548362f, 0.173560f, + 0.500100f, 0.176033f, 0.500890f, 0.187571f, 0.493996f, 0.193428f, 0.489683f, 0.173693f, + 0.519841f, 0.200843f, 0.528757f, 0.191785f, 0.537248f, 0.187577f, 0.544281f, 0.193366f, + 0.500890f, 0.187571f, 0.509219f, 0.191626f, 0.519841f, 0.200843f, 0.493996f, 0.193428f, + 0.517577f, 0.190607f, 0.519132f, 0.185382f, 0.528757f, 0.191785f, 0.519841f, 0.200843f, + 0.509219f, 0.191626f, 0.519132f, 0.185382f, 0.517577f, 0.190607f, 0.519841f, 0.200843f, + 0.518981f, 0.151749f, 0.538112f, 0.158382f, 0.535214f, 0.166808f, 0.518998f, 0.159028f, + 0.502799f, 0.166857f, 0.499851f, 0.158434f, 0.518981f, 0.151749f, 0.518998f, 0.159028f, + 0.518998f, 0.159028f, 0.535214f, 0.166808f, 0.531131f, 0.171631f, 0.519016f, 0.165599f, + 0.506910f, 0.171667f, 0.502799f, 0.166857f, 0.518998f, 0.159028f, 0.519016f, 0.165599f, + 0.519132f, 0.185382f, 0.519099f, 0.179457f, 0.528222f, 0.186316f, 0.528757f, 0.191785f, + 0.509787f, 0.186260f, 0.519099f, 0.179457f, 0.519132f, 0.185382f, 0.509219f, 0.191626f, + 0.528757f, 0.191785f, 0.528222f, 0.186316f, 0.533528f, 0.184215f, 0.537248f, 0.187577f, + 0.504547f, 0.184206f, 0.509787f, 0.186260f, 0.509219f, 0.191626f, 0.500890f, 0.187571f, + 0.537248f, 0.187577f, 0.533528f, 0.184215f, 0.533449f, 0.176739f, 0.537959f, 0.175966f, + 0.504604f, 0.176791f, 0.504547f, 0.184206f, 0.500890f, 0.187571f, 0.500100f, 0.176033f, + 0.537959f, 0.175966f, 0.533449f, 0.176739f, 0.531131f, 0.171631f, 0.535214f, 0.166808f, + 0.506910f, 0.171667f, 0.504604f, 0.176791f, 0.500100f, 0.176033f, 0.502799f, 0.166857f, + 0.519099f, 0.179457f, 0.533449f, 0.176739f, 0.533528f, 0.184215f, 0.528222f, 0.186316f, + 0.504547f, 0.184206f, 0.504604f, 0.176791f, 0.519099f, 0.179457f, 0.509787f, 0.186260f, + 0.519099f, 0.179457f, 0.519016f, 0.165599f, 0.531131f, 0.171631f, 0.533449f, 0.176739f, + 0.506910f, 0.171667f, 0.519016f, 0.165599f, 0.519099f, 0.179457f, 0.504604f, 0.176791f, + 0.519841f, 0.200843f, 0.544281f, 0.193366f, 0.553118f, 0.209599f, 0.519760f, 0.248864f, + 0.485339f, 0.210053f, 0.493996f, 0.193428f, 0.519841f, 0.200843f, 0.519760f, 0.248864f, + 0.544281f, 0.193366f, 0.548362f, 0.173560f, 0.561572f, 0.167779f, 0.553118f, 0.209599f, + 0.476363f, 0.167996f, 0.489683f, 0.173693f, 0.493996f, 0.193428f, 0.485339f, 0.210053f, + 0.548362f, 0.173560f, 0.538112f, 0.158382f, 0.559475f, 0.149319f, 0.561572f, 0.167779f, + 0.478371f, 0.149447f, 0.499851f, 0.158434f, 0.489683f, 0.173693f, 0.476363f, 0.167996f, + 0.538112f, 0.158382f, 0.532042f, 0.127713f, 0.555621f, 0.121749f, 0.559475f, 0.149319f, + 0.482177f, 0.121781f, 0.505828f, 0.127728f, 0.499851f, 0.158434f, 0.478371f, 0.149447f, + 0.583135f, 0.108495f, 0.596138f, 0.133426f, 0.559475f, 0.149319f, 0.555621f, 0.121749f, + 0.478371f, 0.149447f, 0.441395f, 0.133592f, 0.454527f, 0.108481f, 0.482177f, 0.121781f, + 0.596138f, 0.133426f, 0.601169f, 0.147885f, 0.561572f, 0.167779f, 0.559475f, 0.149319f, + 0.476363f, 0.167996f, 0.436337f, 0.148194f, 0.441395f, 0.133592f, 0.478371f, 0.149447f, + 0.605512f, 0.165134f, 0.553118f, 0.209599f, 0.561572f, 0.167779f, 0.601169f, 0.147885f, + 0.476363f, 0.167996f, 0.485339f, 0.210053f, 0.432024f, 0.165644f, 0.436337f, 0.148194f, + 0.531019f, 0.087431f, 0.518927f, 0.085180f, 0.518925f, 0.083865f, 0.528933f, 0.084957f, + 0.518925f, 0.083865f, 0.518927f, 0.085180f, 0.506827f, 0.087416f, 0.508915f, 0.084945f, + 0.531231f, 0.073829f, 0.531019f, 0.087431f, 0.528933f, 0.084957f, 0.529036f, 0.075429f, + 0.508915f, 0.084945f, 0.506827f, 0.087416f, 0.506626f, 0.073811f, 0.508820f, 0.075415f, + 0.525483f, 0.068967f, 0.531231f, 0.073829f, 0.529036f, 0.075429f, 0.523751f, 0.070508f, + 0.508820f, 0.075415f, 0.506626f, 0.073811f, 0.512375f, 0.068956f, 0.514106f, 0.070501f, + 0.518928f, 0.067899f, 0.525483f, 0.068967f, 0.523751f, 0.070508f, 0.518929f, 0.069468f, + 0.514106f, 0.070501f, 0.512375f, 0.068956f, 0.518928f, 0.067899f, 0.518929f, 0.069468f, + 0.518929f, 0.069468f, 0.523751f, 0.070508f, 0.521560f, 0.074970f, 0.518928f, 0.074259f, + 0.516297f, 0.074966f, 0.514106f, 0.070501f, 0.518929f, 0.069468f, 0.518928f, 0.074259f, + 0.523751f, 0.070508f, 0.529036f, 0.075429f, 0.524236f, 0.076691f, 0.521560f, 0.074970f, + 0.513619f, 0.076684f, 0.508820f, 0.075415f, 0.514106f, 0.070501f, 0.516297f, 0.074966f, + 0.529036f, 0.075429f, 0.528933f, 0.084957f, 0.524601f, 0.079886f, 0.524236f, 0.076691f, + 0.513252f, 0.079879f, 0.508915f, 0.084945f, 0.508820f, 0.075415f, 0.513619f, 0.076684f, + 0.528933f, 0.084957f, 0.518925f, 0.083865f, 0.518926f, 0.079331f, 0.524601f, 0.079886f, + 0.518926f, 0.079331f, 0.518925f, 0.083865f, 0.508915f, 0.084945f, 0.513252f, 0.079879f, + 0.518926f, 0.079331f, 0.518928f, 0.074259f, 0.521560f, 0.074970f, 0.524601f, 0.079886f, + 0.516297f, 0.074966f, 0.518928f, 0.074259f, 0.518926f, 0.079331f, 0.513252f, 0.079879f, + 0.524601f, 0.079886f, 0.521560f, 0.074970f, 0.524236f, 0.076691f, 0.513619f, 0.076684f, + 0.516297f, 0.074966f, 0.513252f, 0.079879f, 0.556923f, 0.291214f, 0.563905f, 0.272007f, + 0.571787f, 0.277295f, 0.568351f, 0.292904f, 0.468070f, 0.278617f, 0.475886f, 0.273078f, + 0.483433f, 0.292249f, 0.471978f, 0.294282f, 0.558527f, 0.316594f, 0.556923f, 0.291214f, + 0.568351f, 0.292904f, 0.573085f, 0.311386f, 0.471978f, 0.294282f, 0.483433f, 0.292249f, + 0.482619f, 0.317843f, 0.467790f, 0.313081f, 0.577279f, 0.340156f, 0.558527f, 0.316594f, + 0.573085f, 0.311386f, 0.584855f, 0.327708f, 0.467790f, 0.313081f, 0.482619f, 0.317843f, + 0.464579f, 0.342230f, 0.456477f, 0.329961f, 0.563905f, 0.272007f, 0.572941f, 0.258564f, + 0.580734f, 0.266620f, 0.571787f, 0.277295f, 0.458737f, 0.268049f, 0.466409f, 0.259709f, + 0.475886f, 0.273078f, 0.468070f, 0.278617f, 0.572941f, 0.258564f, 0.613992f, 0.242662f, + 0.611720f, 0.255725f, 0.580734f, 0.266620f, 0.427062f, 0.257728f, 0.424464f, 0.244473f, + 0.466409f, 0.259709f, 0.458737f, 0.268049f, 0.613992f, 0.242662f, 0.639236f, 0.253047f, + 0.632494f, 0.262853f, 0.611720f, 0.255725f, 0.406068f, 0.265508f, 0.398938f, 0.255633f, + 0.424464f, 0.244473f, 0.427062f, 0.257728f, 0.639236f, 0.253047f, 0.664101f, 0.277872f, + 0.653658f, 0.279971f, 0.632494f, 0.262853f, 0.384904f, 0.283634f, 0.374100f, 0.281778f, + 0.398938f, 0.255633f, 0.406068f, 0.265508f, 0.664101f, 0.277872f, 0.668440f, 0.297958f, + 0.656064f, 0.297636f, 0.653658f, 0.279971f, 0.383015f, 0.301864f, 0.370304f, 0.302644f, + 0.374100f, 0.281778f, 0.384904f, 0.283634f, 0.668440f, 0.297958f, 0.662406f, 0.312804f, + 0.652752f, 0.310186f, 0.656064f, 0.297636f, 0.386858f, 0.314615f, 0.377061f, 0.317685f, + 0.370304f, 0.302644f, 0.383015f, 0.301864f, 0.662406f, 0.312804f, 0.634472f, 0.332311f, + 0.629040f, 0.323864f, 0.652752f, 0.310186f, 0.411556f, 0.327673f, 0.406362f, 0.336480f, + 0.377061f, 0.317685f, 0.386858f, 0.314615f, 0.634472f, 0.332311f, 0.615546f, 0.342005f, + 0.614408f, 0.331972f, 0.629040f, 0.323864f, 0.426727f, 0.335361f, 0.425972f, 0.345582f, + 0.406362f, 0.336480f, 0.411556f, 0.327673f, 0.615546f, 0.342005f, 0.599845f, 0.344815f, + 0.601033f, 0.333624f, 0.614408f, 0.331972f, 0.440344f, 0.336537f, 0.441977f, 0.347815f, + 0.425972f, 0.345582f, 0.426727f, 0.335361f, 0.599845f, 0.344815f, 0.577279f, 0.340156f, + 0.584855f, 0.327708f, 0.601033f, 0.333624f, 0.456477f, 0.329961f, 0.464579f, 0.342230f, + 0.441977f, 0.347815f, 0.440344f, 0.336537f, 0.601033f, 0.333624f, 0.584855f, 0.327708f, + 0.590644f, 0.321516f, 0.601799f, 0.328453f, 0.450408f, 0.323919f, 0.456477f, 0.329961f, + 0.440344f, 0.336537f, 0.439372f, 0.331331f, 0.614408f, 0.331972f, 0.601033f, 0.333624f, + 0.601799f, 0.328453f, 0.613335f, 0.327083f, 0.439372f, 0.331331f, 0.440344f, 0.336537f, + 0.426727f, 0.335361f, 0.427623f, 0.330358f, 0.629040f, 0.323864f, 0.614408f, 0.331972f, + 0.613335f, 0.327083f, 0.626851f, 0.320513f, 0.427623f, 0.330358f, 0.426727f, 0.335361f, + 0.411556f, 0.327673f, 0.413648f, 0.324175f, 0.652752f, 0.310186f, 0.629040f, 0.323864f, + 0.626851f, 0.320513f, 0.646248f, 0.306421f, 0.413648f, 0.324175f, 0.411556f, 0.327673f, + 0.386858f, 0.314615f, 0.393381f, 0.310510f, 0.656064f, 0.297636f, 0.652752f, 0.310186f, + 0.646248f, 0.306421f, 0.649541f, 0.296225f, 0.393381f, 0.310510f, 0.386858f, 0.314615f, + 0.383015f, 0.301864f, 0.389662f, 0.300183f, 0.653658f, 0.279971f, 0.656064f, 0.297636f, + 0.649541f, 0.296225f, 0.647785f, 0.283486f, 0.389662f, 0.300183f, 0.383015f, 0.301864f, + 0.384904f, 0.283634f, 0.391040f, 0.287071f, 0.632494f, 0.262853f, 0.653658f, 0.279971f, + 0.647785f, 0.283486f, 0.629829f, 0.267263f, 0.391040f, 0.287071f, 0.384904f, 0.283634f, + 0.406068f, 0.265508f, 0.408893f, 0.269959f, 0.611720f, 0.255725f, 0.632494f, 0.262853f, + 0.629829f, 0.267263f, 0.612641f, 0.261560f, 0.408893f, 0.269959f, 0.406068f, 0.265508f, + 0.427062f, 0.257728f, 0.426254f, 0.263693f, 0.580734f, 0.266620f, 0.611720f, 0.255725f, + 0.612641f, 0.261560f, 0.585166f, 0.270991f, 0.426254f, 0.263693f, 0.427062f, 0.257728f, + 0.458737f, 0.268049f, 0.454369f, 0.272583f, 0.571787f, 0.277295f, 0.580734f, 0.266620f, + 0.585166f, 0.270991f, 0.578124f, 0.281900f, 0.454369f, 0.272583f, 0.458737f, 0.268049f, + 0.468070f, 0.278617f, 0.461798f, 0.283441f, 0.584855f, 0.327708f, 0.573085f, 0.311386f, + 0.579548f, 0.309340f, 0.590644f, 0.321516f, 0.461204f, 0.311233f, 0.467790f, 0.313081f, + 0.456477f, 0.329961f, 0.450408f, 0.323919f, 0.573085f, 0.311386f, 0.568351f, 0.292904f, + 0.577524f, 0.293776f, 0.579548f, 0.309340f, 0.462754f, 0.295432f, 0.471978f, 0.294282f, + 0.467790f, 0.313081f, 0.461204f, 0.311233f, 0.568351f, 0.292904f, 0.571787f, 0.277295f, + 0.578124f, 0.281900f, 0.577524f, 0.293776f, 0.461798f, 0.283441f, 0.468070f, 0.278617f, + 0.471978f, 0.294282f, 0.462754f, 0.295432f, 0.521923f, 0.386009f, 0.553095f, 0.390512f, + 0.553209f, 0.433063f, 0.523031f, 0.433628f, 0.492809f, 0.434538f, 0.490934f, 0.391862f, + 0.521923f, 0.386009f, 0.523031f, 0.433628f, 0.553095f, 0.390512f, 0.604826f, 0.397804f, + 0.609819f, 0.431516f, 0.553209f, 0.433063f, 0.435860f, 0.435740f, 0.439252f, 0.401540f, + 0.490934f, 0.391862f, 0.492809f, 0.434538f, 0.604826f, 0.397804f, 0.626842f, 0.395792f, + 0.648174f, 0.419316f, 0.609819f, 0.431516f, 0.396518f, 0.425416f, 0.416915f, 0.400552f, + 0.439252f, 0.401540f, 0.435860f, 0.435740f, 0.626842f, 0.395792f, 0.662817f, 0.372521f, + 0.692106f, 0.388274f, 0.648174f, 0.419316f, 0.350292f, 0.396229f, 0.379297f, 0.378686f, + 0.416915f, 0.400552f, 0.396518f, 0.425416f, 0.662817f, 0.372521f, 0.697446f, 0.332673f, + 0.726332f, 0.341754f, 0.692106f, 0.388274f, 0.312756f, 0.350588f, 0.341964f, 0.339667f, + 0.379297f, 0.378686f, 0.350292f, 0.396229f, 0.697446f, 0.332673f, 0.707254f, 0.310054f, + 0.735879f, 0.312112f, 0.726332f, 0.341754f, 0.301067f, 0.320593f, 0.330721f, 0.316853f, + 0.341964f, 0.339667f, 0.312756f, 0.350588f, 0.707254f, 0.310054f, 0.715342f, 0.265392f, + 0.729900f, 0.256393f, 0.735879f, 0.312112f, 0.304876f, 0.261087f, 0.320452f, 0.270303f, + 0.330721f, 0.316853f, 0.301067f, 0.320593f, 0.715342f, 0.265392f, 0.676379f, 0.233241f, + 0.698172f, 0.216906f, 0.729900f, 0.256393f, 0.337414f, 0.219179f, 0.360308f, 0.235899f, + 0.320452f, 0.270303f, 0.304876f, 0.261087f, 0.676379f, 0.233241f, 0.647395f, 0.200502f, + 0.663103f, 0.190671f, 0.698172f, 0.216906f, 0.373474f, 0.191872f, 0.389677f, 0.201890f, + 0.360308f, 0.235899f, 0.337414f, 0.219179f, 0.626908f, 0.015608f, 0.649444f, 0.022378f, + 0.660451f, 0.076084f, 0.621440f, 0.048089f, 0.376796f, 0.075296f, 0.388827f, 0.021586f, + 0.411318f, 0.015131f, 0.416419f, 0.047631f, 0.567460f, 0.000144f, 0.626908f, 0.015608f, + 0.621440f, 0.048089f, 0.577206f, 0.032801f, 0.416419f, 0.047631f, 0.411318f, 0.015131f, + 0.470636f, 0.000144f, 0.460782f, 0.032656f, 0.518922f, 0.024886f, 0.567460f, 0.000144f, + 0.577206f, 0.032801f, 0.547413f, 0.041724f, 0.460782f, 0.032656f, 0.470636f, 0.000144f, + 0.518922f, 0.024886f, 0.490511f, 0.041669f, 0.540260f, 0.053805f, 0.518916f, 0.050294f, + 0.518922f, 0.024886f, 0.547413f, 0.041724f, 0.518922f, 0.024886f, 0.518916f, 0.050294f, + 0.497626f, 0.053770f, 0.490511f, 0.041669f, 0.551930f, 0.058338f, 0.540260f, 0.053805f, + 0.547413f, 0.041724f, 0.558059f, 0.053871f, 0.490511f, 0.041669f, 0.497626f, 0.053770f, + 0.485955f, 0.058273f, 0.479842f, 0.053785f, 0.555073f, 0.061900f, 0.551930f, 0.058338f, + 0.558059f, 0.053871f, 0.576951f, 0.057998f, 0.479842f, 0.053785f, 0.485955f, 0.058273f, + 0.482805f, 0.061829f, 0.460920f, 0.057845f, 0.563812f, 0.076586f, 0.555073f, 0.061900f, + 0.576951f, 0.057998f, 0.611687f, 0.078268f, 0.460920f, 0.057845f, 0.482805f, 0.061829f, + 0.474014f, 0.076511f, 0.425932f, 0.077985f, 0.576951f, 0.057998f, 0.577206f, 0.032801f, + 0.621440f, 0.048089f, 0.611687f, 0.078268f, 0.416419f, 0.047631f, 0.460782f, 0.032656f, + 0.460920f, 0.057845f, 0.425932f, 0.077985f, 0.576951f, 0.057998f, 0.558059f, 0.053871f, + 0.547413f, 0.041724f, 0.577206f, 0.032801f, 0.490511f, 0.041669f, 0.479842f, 0.053785f, + 0.460920f, 0.057845f, 0.460782f, 0.032656f, 0.626663f, 0.111357f, 0.611687f, 0.078268f, + 0.621440f, 0.048089f, 0.660451f, 0.076084f, 0.416419f, 0.047631f, 0.425932f, 0.077985f, + 0.410618f, 0.111244f, 0.376796f, 0.075296f, 0.583135f, 0.108495f, 0.563812f, 0.076586f, + 0.611687f, 0.078268f, 0.626663f, 0.111357f, 0.425932f, 0.077985f, 0.474014f, 0.076511f, + 0.454527f, 0.108481f, 0.410618f, 0.111244f, 0.596138f, 0.133426f, 0.629482f, 0.130456f, + 0.623495f, 0.146796f, 0.601169f, 0.147885f, 0.413741f, 0.147158f, 0.407648f, 0.130594f, + 0.441395f, 0.133592f, 0.436337f, 0.148194f, 0.583135f, 0.108495f, 0.626663f, 0.111357f, + 0.629482f, 0.130456f, 0.596138f, 0.133426f, 0.407648f, 0.130594f, 0.410618f, 0.111244f, + 0.454527f, 0.108481f, 0.441395f, 0.133592f, 0.605512f, 0.165134f, 0.601169f, 0.147885f, + 0.623495f, 0.146796f, 0.619303f, 0.159841f, 0.413741f, 0.147158f, 0.436337f, 0.148194f, + 0.432024f, 0.165644f, 0.418035f, 0.160361f, 0.605512f, 0.165134f, 0.619303f, 0.159841f, + 0.663103f, 0.190671f, 0.647395f, 0.200502f, 0.373474f, 0.191872f, 0.418035f, 0.160361f, + 0.432024f, 0.165644f, 0.389677f, 0.201890f, 0.945900f, 0.079569f, 0.886245f, 0.121777f, + 0.849114f, 0.099732f, 0.891780f, 0.036916f, 0.183115f, 0.092127f, 0.141314f, 0.112482f, + 0.078961f, 0.060719f, 0.142277f, 0.021467f, 0.891780f, 0.036916f, 0.849114f, 0.099732f, + 0.788458f, 0.080826f, 0.805584f, 0.010786f, 0.246353f, 0.076510f, 0.183115f, 0.092127f, + 0.142277f, 0.021467f, 0.232648f, 0.003484f, 0.805584f, 0.010786f, 0.788458f, 0.080826f, + 0.687018f, 0.077204f, 0.672384f, 0.022201f, 0.349875f, 0.075955f, 0.246353f, 0.076510f, + 0.232648f, 0.003484f, 0.365979f, 0.020991f, 0.672384f, 0.022201f, 0.687018f, 0.077204f, + 0.660451f, 0.076084f, 0.649444f, 0.022378f, 0.376796f, 0.075296f, 0.349875f, 0.075955f, + 0.365979f, 0.020991f, 0.388827f, 0.021586f, 0.626663f, 0.111357f, 0.660451f, 0.076084f, + 0.687018f, 0.077204f, 0.629482f, 0.130456f, 0.349875f, 0.075955f, 0.376796f, 0.075296f, + 0.410618f, 0.111244f, 0.407648f, 0.130594f, 0.729900f, 0.256393f, 0.698172f, 0.216906f, + 0.760215f, 0.193244f, 0.789046f, 0.233323f, 0.271553f, 0.193871f, 0.337414f, 0.219179f, + 0.304876f, 0.261087f, 0.241255f, 0.236977f, 0.994525f, 0.167705f, 0.909112f, 0.183261f, + 0.886245f, 0.121777f, 0.945900f, 0.079569f, 0.141314f, 0.112482f, 0.107928f, 0.179083f, + 0.011829f, 0.155367f, 0.078961f, 0.060719f, 0.911671f, 0.402429f, 0.862868f, 0.338556f, + 0.894128f, 0.301884f, 0.962901f, 0.344752f, 0.123776f, 0.315519f, 0.160557f, 0.356821f, + 0.106400f, 0.432652f, 0.043968f, 0.367038f, 0.962901f, 0.344752f, 0.894128f, 0.301884f, + 0.915360f, 0.259804f, 0.999856f, 0.254640f, 0.098965f, 0.266968f, 0.123776f, 0.315519f, + 0.043968f, 0.367038f, 0.000144f, 0.259113f, 0.999856f, 0.254640f, 0.915360f, 0.259804f, + 0.909112f, 0.183261f, 0.994525f, 0.167705f, 0.107928f, 0.179083f, 0.098965f, 0.266968f, + 0.000144f, 0.259113f, 0.011829f, 0.155367f, 0.749542f, 0.334683f, 0.735879f, 0.312112f, + 0.766337f, 0.300809f, 0.789162f, 0.313727f, 0.267408f, 0.310142f, 0.301067f, 0.320593f, + 0.288183f, 0.346496f, 0.242992f, 0.325552f, 0.789162f, 0.313727f, 0.766337f, 0.300809f, + 0.815314f, 0.276388f, 0.846174f, 0.293397f, 0.213065f, 0.285164f, 0.267408f, 0.310142f, + 0.242992f, 0.325552f, 0.178537f, 0.304983f, 0.846174f, 0.293397f, 0.815314f, 0.276388f, + 0.845007f, 0.256352f, 0.873517f, 0.265922f, 0.179662f, 0.263312f, 0.213065f, 0.285164f, + 0.178537f, 0.304983f, 0.147089f, 0.274284f, 0.873517f, 0.265922f, 0.845007f, 0.256352f, + 0.859075f, 0.228168f, 0.886999f, 0.233769f, 0.162803f, 0.231720f, 0.179662f, 0.263312f, + 0.147089f, 0.274284f, 0.131514f, 0.237587f, 0.842355f, 0.195160f, 0.875030f, 0.184705f, + 0.886999f, 0.233769f, 0.859075f, 0.228168f, 0.131514f, 0.237587f, 0.145224f, 0.182749f, + 0.176788f, 0.196179f, 0.162803f, 0.231720f, 0.909112f, 0.183261f, 0.915360f, 0.259804f, + 0.886999f, 0.233769f, 0.875030f, 0.184705f, 0.131514f, 0.237587f, 0.098965f, 0.266968f, + 0.107928f, 0.179083f, 0.145224f, 0.182749f, 0.915360f, 0.259804f, 0.894128f, 0.301884f, + 0.873517f, 0.265922f, 0.886999f, 0.233769f, 0.147089f, 0.274284f, 0.123776f, 0.315519f, + 0.098965f, 0.266968f, 0.131514f, 0.237587f, 0.894128f, 0.301884f, 0.862868f, 0.338556f, + 0.846174f, 0.293397f, 0.873517f, 0.265922f, 0.178537f, 0.304983f, 0.160557f, 0.356821f, + 0.123776f, 0.315519f, 0.147089f, 0.274284f, 0.862868f, 0.338556f, 0.794286f, 0.364062f, + 0.789162f, 0.313727f, 0.846174f, 0.293397f, 0.242992f, 0.325552f, 0.239776f, 0.382592f, + 0.160557f, 0.356821f, 0.178537f, 0.304983f, 0.770185f, 0.379538f, 0.749542f, 0.334683f, + 0.789162f, 0.313727f, 0.794286f, 0.364062f, 0.242992f, 0.325552f, 0.288183f, 0.346496f, + 0.268122f, 0.398737f, 0.239776f, 0.382592f, 0.845499f, 0.449967f, 0.794286f, 0.364062f, + 0.862868f, 0.338556f, 0.911671f, 0.402429f, 0.160557f, 0.356821f, 0.239776f, 0.382592f, + 0.185281f, 0.484099f, 0.106400f, 0.432652f, 0.815858f, 0.445381f, 0.770572f, 0.444261f, + 0.755700f, 0.418603f, 0.770185f, 0.379538f, 0.287033f, 0.442912f, 0.271364f, 0.473316f, + 0.219260f, 0.477186f, 0.268122f, 0.398737f, 0.815858f, 0.445381f, 0.770185f, 0.379538f, + 0.794286f, 0.364062f, 0.845499f, 0.449967f, 0.239776f, 0.382592f, 0.268122f, 0.398737f, + 0.219260f, 0.477186f, 0.185281f, 0.484099f, 0.819845f, 0.468071f, 0.815858f, 0.445381f, + 0.845499f, 0.449967f, 0.185281f, 0.484099f, 0.219260f, 0.477186f, 0.215894f, 0.503605f, + 0.735879f, 0.312112f, 0.729900f, 0.256393f, 0.789046f, 0.233323f, 0.766337f, 0.300809f, + 0.241255f, 0.236977f, 0.304876f, 0.261087f, 0.301067f, 0.320593f, 0.267408f, 0.310142f, + 0.789046f, 0.233323f, 0.809631f, 0.233887f, 0.815314f, 0.276388f, 0.766337f, 0.300809f, + 0.213065f, 0.285164f, 0.219168f, 0.237388f, 0.241255f, 0.236977f, 0.267408f, 0.310142f, + 0.809631f, 0.233887f, 0.829287f, 0.219562f, 0.845007f, 0.256352f, 0.815314f, 0.276388f, + 0.179662f, 0.263312f, 0.199067f, 0.222464f, 0.219168f, 0.237388f, 0.213065f, 0.285164f, + 0.842355f, 0.195160f, 0.859075f, 0.228168f, 0.845007f, 0.256352f, 0.829287f, 0.219562f, + 0.179662f, 0.263312f, 0.162803f, 0.231720f, 0.176788f, 0.196179f, 0.199067f, 0.222464f, + 0.687018f, 0.077204f, 0.788458f, 0.080826f, 0.786480f, 0.117591f, 0.715482f, 0.139727f, + 0.246666f, 0.114850f, 0.246353f, 0.076510f, 0.349875f, 0.075955f, 0.319538f, 0.139409f, + 0.760215f, 0.193244f, 0.715482f, 0.139727f, 0.786480f, 0.117591f, 0.785486f, 0.152330f, + 0.246666f, 0.114850f, 0.319538f, 0.139409f, 0.271553f, 0.193871f, 0.245969f, 0.151002f, + 0.698172f, 0.216906f, 0.663103f, 0.190671f, 0.715482f, 0.139727f, 0.760215f, 0.193244f, + 0.319538f, 0.139409f, 0.373474f, 0.191872f, 0.337414f, 0.219179f, 0.271553f, 0.193871f, + 0.663103f, 0.190671f, 0.623495f, 0.146796f, 0.629482f, 0.130456f, 0.715482f, 0.139727f, + 0.407648f, 0.130594f, 0.413741f, 0.147158f, 0.373474f, 0.191872f, 0.319538f, 0.139409f, + 0.629482f, 0.130456f, 0.687018f, 0.077204f, 0.715482f, 0.139727f, 0.319538f, 0.139409f, + 0.349875f, 0.075955f, 0.407648f, 0.130594f, 0.663103f, 0.190671f, 0.619303f, 0.159841f, + 0.623495f, 0.146796f, 0.413741f, 0.147158f, 0.418035f, 0.160361f, 0.373474f, 0.191872f, + 0.842355f, 0.195160f, 0.837382f, 0.156361f, 0.858171f, 0.137775f, 0.875030f, 0.184705f, + 0.171653f, 0.132294f, 0.196622f, 0.155241f, 0.176788f, 0.196179f, 0.145224f, 0.182749f, + 0.909112f, 0.183261f, 0.875030f, 0.184705f, 0.858171f, 0.137775f, 0.886245f, 0.121777f, + 0.171653f, 0.132294f, 0.145224f, 0.182749f, 0.107928f, 0.179083f, 0.141314f, 0.112482f, + 0.785486f, 0.152330f, 0.786480f, 0.117591f, 0.858171f, 0.137775f, 0.837382f, 0.156361f, + 0.171653f, 0.132294f, 0.246666f, 0.114850f, 0.245969f, 0.151002f, 0.196622f, 0.155241f, + 0.788458f, 0.080826f, 0.849114f, 0.099732f, 0.858171f, 0.137775f, 0.786480f, 0.117591f, + 0.171653f, 0.132294f, 0.183115f, 0.092127f, 0.246353f, 0.076510f, 0.246666f, 0.114850f, + 0.886245f, 0.121777f, 0.858171f, 0.137775f, 0.849114f, 0.099732f, 0.183115f, 0.092127f, + 0.171653f, 0.132294f, 0.141314f, 0.112482f, 0.506166f, 0.904851f, 0.432388f, 0.894943f, + 0.438797f, 0.870229f, 0.491058f, 0.881714f, 0.315867f, 0.868209f, 0.321637f, 0.893225f, + 0.247207f, 0.901159f, 0.263032f, 0.878321f, 0.506166f, 0.904851f, 0.491058f, 0.881714f, + 0.572792f, 0.860484f, 0.604825f, 0.879946f, 0.181486f, 0.854693f, 0.263032f, 0.878321f, + 0.247207f, 0.901159f, 0.148729f, 0.873349f, 0.604825f, 0.879946f, 0.572792f, 0.860484f, + 0.586396f, 0.793977f, 0.619962f, 0.791615f, 0.169745f, 0.787474f, 0.181486f, 0.854693f, + 0.148729f, 0.873349f, 0.136063f, 0.784093f, 0.619962f, 0.791615f, 0.586396f, 0.793977f, + 0.549027f, 0.746412f, 0.563786f, 0.739211f, 0.208656f, 0.740879f, 0.169745f, 0.787474f, + 0.136063f, 0.784093f, 0.194086f, 0.733241f, 0.563786f, 0.739211f, 0.549027f, 0.746412f, + 0.500314f, 0.711729f, 0.508270f, 0.697693f, 0.258399f, 0.707497f, 0.208656f, 0.740879f, + 0.194086f, 0.733241f, 0.250811f, 0.693249f, 0.508270f, 0.697693f, 0.500314f, 0.711729f, + 0.438641f, 0.680683f, 0.434803f, 0.658882f, 0.320962f, 0.677959f, 0.258399f, 0.707497f, + 0.250811f, 0.693249f, 0.325318f, 0.656224f, 0.500314f, 0.711729f, 0.505666f, 0.730944f, + 0.452955f, 0.700023f, 0.438641f, 0.680683f, 0.306136f, 0.696976f, 0.252524f, 0.726592f, + 0.258399f, 0.707497f, 0.320962f, 0.677959f, 0.549027f, 0.746412f, 0.542850f, 0.755753f, + 0.505666f, 0.730944f, 0.500314f, 0.711729f, 0.252524f, 0.726592f, 0.214575f, 0.750414f, + 0.208656f, 0.740879f, 0.258399f, 0.707497f, 0.586396f, 0.793977f, 0.568148f, 0.787367f, + 0.542850f, 0.755753f, 0.549027f, 0.746412f, 0.214575f, 0.750414f, 0.188269f, 0.781375f, + 0.169745f, 0.787474f, 0.208656f, 0.740879f, 0.572792f, 0.860484f, 0.555495f, 0.826352f, + 0.568148f, 0.787367f, 0.586396f, 0.793977f, 0.188269f, 0.781375f, 0.199850f, 0.820889f, + 0.181486f, 0.854693f, 0.169745f, 0.787474f, 0.491058f, 0.881714f, 0.501231f, 0.844356f, + 0.555495f, 0.826352f, 0.572792f, 0.860484f, 0.199850f, 0.820889f, 0.253846f, 0.840502f, + 0.263032f, 0.878321f, 0.181486f, 0.854693f, 0.491058f, 0.881714f, 0.438797f, 0.870229f, + 0.457832f, 0.840040f, 0.501231f, 0.844356f, 0.297562f, 0.837358f, 0.315867f, 0.868209f, + 0.263032f, 0.878321f, 0.253846f, 0.840502f, 0.760215f, 0.193244f, 0.785486f, 0.152330f, + 0.796021f, 0.176969f, 0.783193f, 0.187449f, 0.233625f, 0.175620f, 0.245969f, 0.151002f, + 0.271553f, 0.193871f, 0.246955f, 0.187075f, 0.391039f, 0.611891f, 0.434803f, 0.658882f, + 0.438641f, 0.680683f, 0.394766f, 0.686125f, 0.320962f, 0.677959f, 0.325318f, 0.656224f, + 0.369913f, 0.610196f, 0.364838f, 0.684445f, 0.789046f, 0.233323f, 0.760215f, 0.193244f, + 0.783193f, 0.187449f, 0.809631f, 0.233887f, 0.246955f, 0.187075f, 0.271553f, 0.193871f, + 0.241255f, 0.236977f, 0.219168f, 0.237388f, 0.391747f, 0.862097f, 0.401605f, 0.841460f, + 0.438797f, 0.870229f, 0.432388f, 0.894943f, 0.315867f, 0.868209f, 0.354026f, 0.840297f, + 0.363377f, 0.861308f, 0.321637f, 0.893225f, 0.438641f, 0.680683f, 0.452955f, 0.700023f, + 0.435018f, 0.718280f, 0.394766f, 0.686125f, 0.323658f, 0.715731f, 0.306136f, 0.696976f, + 0.320962f, 0.677959f, 0.364838f, 0.684445f, 0.433669f, 0.729661f, 0.384658f, 0.710299f, + 0.394766f, 0.686125f, 0.435018f, 0.718280f, 0.364838f, 0.684445f, 0.374400f, 0.708969f, + 0.324726f, 0.727177f, 0.323658f, 0.715731f, 0.410995f, 0.747662f, 0.384658f, 0.710299f, + 0.433669f, 0.729661f, 0.427812f, 0.742828f, 0.324726f, 0.727177f, 0.374400f, 0.708969f, + 0.347028f, 0.745816f, 0.330270f, 0.740536f, 0.418086f, 0.784946f, 0.384657f, 0.795423f, + 0.384658f, 0.710299f, 0.410995f, 0.747662f, 0.374400f, 0.708969f, 0.372270f, 0.794472f, + 0.338952f, 0.783073f, 0.347028f, 0.745816f, 0.401605f, 0.841460f, 0.384657f, 0.795423f, + 0.418086f, 0.784946f, 0.431333f, 0.817535f, 0.338952f, 0.783073f, 0.372270f, 0.794472f, + 0.354026f, 0.840297f, 0.324790f, 0.815460f, 0.438797f, 0.870229f, 0.401605f, 0.841460f, + 0.431333f, 0.817535f, 0.457832f, 0.840040f, 0.324790f, 0.815460f, 0.354026f, 0.840297f, + 0.315867f, 0.868209f, 0.297562f, 0.837358f, 0.809631f, 0.233887f, 0.816266f, 0.203086f, + 0.825107f, 0.209762f, 0.829287f, 0.219562f, 0.199767f, 0.214827f, 0.209828f, 0.206161f, + 0.219168f, 0.237388f, 0.199067f, 0.222464f, 0.809631f, 0.233887f, 0.783193f, 0.187449f, + 0.802192f, 0.184609f, 0.816266f, 0.203086f, 0.226485f, 0.183086f, 0.246955f, 0.187075f, + 0.219168f, 0.237388f, 0.209828f, 0.206161f, 0.783193f, 0.187449f, 0.796021f, 0.176969f, + 0.802192f, 0.184609f, 0.226485f, 0.183086f, 0.233625f, 0.175620f, 0.246955f, 0.187075f, + 0.457832f, 0.840040f, 0.431333f, 0.817535f, 0.448505f, 0.804621f, 0.473386f, 0.824700f, + 0.307886f, 0.802031f, 0.324790f, 0.815460f, 0.297562f, 0.837358f, 0.282357f, 0.821525f, + 0.431333f, 0.817535f, 0.418086f, 0.784946f, 0.435868f, 0.779569f, 0.448505f, 0.804621f, + 0.321237f, 0.777208f, 0.338952f, 0.783073f, 0.324790f, 0.815460f, 0.307886f, 0.802031f, + 0.418086f, 0.784946f, 0.410995f, 0.747662f, 0.423718f, 0.754191f, 0.435868f, 0.779569f, + 0.334089f, 0.752045f, 0.347028f, 0.745816f, 0.338952f, 0.783073f, 0.321237f, 0.777208f, + 0.410995f, 0.747662f, 0.427812f, 0.742828f, 0.437950f, 0.749777f, 0.423718f, 0.754191f, + 0.319919f, 0.747250f, 0.330270f, 0.740536f, 0.347028f, 0.745816f, 0.334089f, 0.752045f, + 0.427812f, 0.742828f, 0.433669f, 0.729661f, 0.445392f, 0.731997f, 0.437950f, 0.749777f, + 0.312907f, 0.729222f, 0.324726f, 0.727177f, 0.330270f, 0.740536f, 0.319919f, 0.747250f, + 0.433669f, 0.729661f, 0.435018f, 0.718280f, 0.440995f, 0.724383f, 0.445392f, 0.731997f, + 0.317510f, 0.721697f, 0.323658f, 0.715731f, 0.324726f, 0.727177f, 0.312907f, 0.729222f, + 0.435018f, 0.718280f, 0.452955f, 0.700023f, 0.455277f, 0.713731f, 0.440995f, 0.724383f, + 0.303460f, 0.710657f, 0.306136f, 0.696976f, 0.323658f, 0.715731f, 0.317510f, 0.721697f, + 0.501231f, 0.844356f, 0.457832f, 0.840040f, 0.473386f, 0.824700f, 0.512485f, 0.828811f, + 0.282357f, 0.821525f, 0.297562f, 0.837358f, 0.253846f, 0.840502f, 0.242975f, 0.824574f, + 0.555495f, 0.826352f, 0.501231f, 0.844356f, 0.512485f, 0.828811f, 0.550942f, 0.811814f, + 0.242975f, 0.824574f, 0.253846f, 0.840502f, 0.199850f, 0.820889f, 0.204839f, 0.806417f, + 0.568148f, 0.787367f, 0.555495f, 0.826352f, 0.550942f, 0.811814f, 0.552139f, 0.787682f, + 0.204839f, 0.806417f, 0.199850f, 0.820889f, 0.188269f, 0.781375f, 0.204331f, 0.782156f, + 0.542850f, 0.755753f, 0.568148f, 0.787367f, 0.552139f, 0.787682f, 0.539407f, 0.764539f, + 0.204331f, 0.782156f, 0.188269f, 0.781375f, 0.214575f, 0.750414f, 0.217774f, 0.759319f, + 0.505666f, 0.730944f, 0.542850f, 0.755753f, 0.539407f, 0.764539f, 0.508439f, 0.743135f, + 0.217774f, 0.759319f, 0.214575f, 0.750414f, 0.252524f, 0.726592f, 0.249419f, 0.738732f, + 0.452955f, 0.700023f, 0.505666f, 0.730944f, 0.508439f, 0.743135f, 0.455277f, 0.713731f, + 0.249419f, 0.738732f, 0.252524f, 0.726592f, 0.306136f, 0.696976f, 0.303460f, 0.710657f, + 0.437950f, 0.749777f, 0.445392f, 0.731997f, 0.470841f, 0.748408f, 0.454776f, 0.761665f, + 0.286960f, 0.745020f, 0.312907f, 0.729222f, 0.319919f, 0.747250f, 0.302729f, 0.758742f, + 0.454776f, 0.761665f, 0.470841f, 0.748408f, 0.488870f, 0.770464f, 0.475403f, 0.783904f, + 0.268291f, 0.766661f, 0.286960f, 0.745020f, 0.302729f, 0.758742f, 0.281439f, 0.780511f, + 0.475403f, 0.783904f, 0.488870f, 0.770464f, 0.503673f, 0.787562f, 0.494476f, 0.802470f, + 0.252972f, 0.783410f, 0.268291f, 0.766661f, 0.281439f, 0.780511f, 0.261790f, 0.798626f, + 0.494476f, 0.802470f, 0.503673f, 0.787562f, 0.518562f, 0.791602f, 0.516802f, 0.807339f, + 0.237920f, 0.787045f, 0.252972f, 0.783410f, 0.261790f, 0.798626f, 0.239243f, 0.802891f, + 0.512485f, 0.828811f, 0.473386f, 0.824700f, 0.494476f, 0.802470f, 0.516802f, 0.807339f, + 0.261790f, 0.798626f, 0.282357f, 0.821525f, 0.242975f, 0.824574f, 0.239243f, 0.802891f, + 0.448505f, 0.804621f, 0.475403f, 0.783904f, 0.494476f, 0.802470f, 0.473386f, 0.824700f, + 0.261790f, 0.798626f, 0.281439f, 0.780511f, 0.307886f, 0.802031f, 0.282357f, 0.821525f, + 0.448505f, 0.804621f, 0.435868f, 0.779569f, 0.454776f, 0.761665f, 0.475403f, 0.783904f, + 0.302729f, 0.758742f, 0.321237f, 0.777208f, 0.307886f, 0.802031f, 0.281439f, 0.780511f, + 0.437950f, 0.749777f, 0.454776f, 0.761665f, 0.435868f, 0.779569f, 0.423718f, 0.754191f, + 0.321237f, 0.777208f, 0.302729f, 0.758742f, 0.319919f, 0.747250f, 0.334089f, 0.752045f, + 0.440995f, 0.724383f, 0.455277f, 0.713731f, 0.470841f, 0.748408f, 0.445392f, 0.731997f, + 0.286960f, 0.745020f, 0.303460f, 0.710657f, 0.317510f, 0.721697f, 0.312907f, 0.729222f, + 0.508439f, 0.743135f, 0.488870f, 0.770464f, 0.470841f, 0.748408f, 0.455277f, 0.713731f, + 0.286960f, 0.745020f, 0.268291f, 0.766661f, 0.249419f, 0.738732f, 0.303460f, 0.710657f, + 0.539407f, 0.764539f, 0.503673f, 0.787562f, 0.488870f, 0.770464f, 0.508439f, 0.743135f, + 0.268291f, 0.766661f, 0.252972f, 0.783410f, 0.217774f, 0.759319f, 0.249419f, 0.738732f, + 0.552139f, 0.787682f, 0.518562f, 0.791602f, 0.503673f, 0.787562f, 0.539407f, 0.764539f, + 0.252972f, 0.783410f, 0.237920f, 0.787045f, 0.204331f, 0.782156f, 0.217774f, 0.759319f, + 0.550942f, 0.811814f, 0.516802f, 0.807339f, 0.518562f, 0.791602f, 0.552139f, 0.787682f, + 0.237920f, 0.787045f, 0.239243f, 0.802891f, 0.204839f, 0.806417f, 0.204331f, 0.782156f, + 0.512485f, 0.828811f, 0.516802f, 0.807339f, 0.550942f, 0.811814f, 0.204839f, 0.806417f, + 0.239243f, 0.802891f, 0.242975f, 0.824574f, 0.508270f, 0.697693f, 0.434803f, 0.658882f, + 0.484068f, 0.628776f, 0.543385f, 0.683538f, 0.276936f, 0.625067f, 0.325318f, 0.656224f, + 0.250811f, 0.693249f, 0.216123f, 0.678120f, 0.563786f, 0.739211f, 0.508270f, 0.697693f, + 0.543385f, 0.683538f, 0.581052f, 0.726933f, 0.216123f, 0.678120f, 0.250811f, 0.693249f, + 0.194086f, 0.733241f, 0.177176f, 0.720426f, 0.619962f, 0.791615f, 0.563786f, 0.739211f, + 0.581052f, 0.726933f, 0.616701f, 0.759965f, 0.177176f, 0.720426f, 0.194086f, 0.733241f, + 0.136063f, 0.784093f, 0.140379f, 0.752377f, 0.707492f, 0.759884f, 0.619962f, 0.791615f, + 0.616701f, 0.759965f, 0.660647f, 0.741167f, 0.140379f, 0.752377f, 0.136063f, 0.784093f, + 0.049526f, 0.748824f, 0.097038f, 0.732052f, 0.745511f, 0.652100f, 0.707492f, 0.759884f, + 0.660647f, 0.741167f, 0.677256f, 0.670436f, 0.097038f, 0.732052f, 0.049526f, 0.748824f, + 0.019409f, 0.639749f, 0.083564f, 0.662038f, 0.740843f, 0.572428f, 0.745511f, 0.652100f, + 0.677256f, 0.670436f, 0.671403f, 0.592656f, 0.083564f, 0.662038f, 0.019409f, 0.639749f, + 0.033664f, 0.564403f, 0.092820f, 0.589862f, 0.677256f, 0.670436f, 0.543385f, 0.683538f, + 0.484068f, 0.628776f, 0.671403f, 0.592656f, 0.276936f, 0.625067f, 0.216123f, 0.678120f, + 0.083564f, 0.662038f, 0.092820f, 0.589862f, 0.677256f, 0.670436f, 0.660647f, 0.741167f, + 0.581052f, 0.726933f, 0.543385f, 0.683538f, 0.177176f, 0.720426f, 0.097038f, 0.732052f, + 0.083564f, 0.662038f, 0.216123f, 0.678120f, 0.660647f, 0.741167f, 0.616701f, 0.759965f, + 0.581052f, 0.726933f, 0.177176f, 0.720426f, 0.140379f, 0.752377f, 0.097038f, 0.732052f, + 0.842355f, 0.195160f, 0.829287f, 0.219562f, 0.834578f, 0.206879f, 0.834705f, 0.206959f, + 0.033664f, 0.564403f, 0.051216f, 0.522659f, 0.145041f, 0.562595f, 0.092820f, 0.589862f, + 0.620420f, 0.565675f, 0.671403f, 0.592656f, 0.484068f, 0.628776f, 0.498072f, 0.552315f, + 0.276936f, 0.625067f, 0.092820f, 0.589862f, 0.145041f, 0.562595f, 0.264218f, 0.550140f, + 0.391039f, 0.611891f, 0.498072f, 0.552315f, 0.484068f, 0.628776f, 0.434803f, 0.658882f, + 0.276936f, 0.625067f, 0.264218f, 0.550140f, 0.369913f, 0.610196f, 0.325318f, 0.656224f, }; -#define VERT_MARK 1 +#define VERT_MARK 1 -#define EDGE_ORIG 1 -#define EDGE_MARK 2 +#define EDGE_ORIG 1 +#define EDGE_MARK 2 -#define FACE_MARK 1 -#define FACE_NEW 2 +#define FACE_MARK 1 +#define FACE_NEW 2 void bmo_create_grid_exec(BMesh *bm, BMOperator *op) { - BMOpSlot *slot_verts_out = BMO_slot_get(op->slots_out, "verts.out"); - - const float dia = BMO_slot_float_get(op->slots_in, "size"); - const uint xtot = max_ii(2, BMO_slot_int_get(op->slots_in, "x_segments")); - const uint ytot = max_ii(2, BMO_slot_int_get(op->slots_in, "y_segments")); - const float xtot_inv2 = 2.0f / (xtot - 1); - const float ytot_inv2 = 2.0f / (ytot - 1); + BMOpSlot *slot_verts_out = BMO_slot_get(op->slots_out, "verts.out"); - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs"); + const float dia = BMO_slot_float_get(op->slots_in, "size"); + const uint xtot = max_ii(2, BMO_slot_int_get(op->slots_in, "x_segments")); + const uint ytot = max_ii(2, BMO_slot_int_get(op->slots_in, "y_segments")); + const float xtot_inv2 = 2.0f / (xtot - 1); + const float ytot_inv2 = 2.0f / (ytot - 1); - BMVert **varr; - BMVert *vquad[4]; + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs"); - float mat[4][4]; - float vec[3], tvec[3]; + BMVert **varr; + BMVert *vquad[4]; - uint x, y, i; + float mat[4][4]; + float vec[3], tvec[3]; + uint x, y, i; - BMO_slot_mat4_get(op->slots_in, "matrix", mat); + BMO_slot_mat4_get(op->slots_in, "matrix", mat); - BMO_slot_buffer_alloc(op, op->slots_out, "verts.out", xtot * ytot); - varr = (BMVert **)slot_verts_out->data.buf; + BMO_slot_buffer_alloc(op, op->slots_out, "verts.out", xtot * ytot); + varr = (BMVert **)slot_verts_out->data.buf; - i = 0; - vec[2] = 0.0f; - for (y = 0; y < ytot; y++) { - vec[1] = ((y * ytot_inv2) - 1.0f) * dia; - for (x = 0; x < xtot; x++) { - vec[0] = ((x * xtot_inv2) - 1.0f) * dia; - mul_v3_m4v3(tvec, mat, vec); - varr[i] = BM_vert_create(bm, tvec, NULL, BM_CREATE_NOP); - BMO_vert_flag_enable(bm, varr[i], VERT_MARK); - i++; - } - } + i = 0; + vec[2] = 0.0f; + for (y = 0; y < ytot; y++) { + vec[1] = ((y * ytot_inv2) - 1.0f) * dia; + for (x = 0; x < xtot; x++) { + vec[0] = ((x * xtot_inv2) - 1.0f) * dia; + mul_v3_m4v3(tvec, mat, vec); + varr[i] = BM_vert_create(bm, tvec, NULL, BM_CREATE_NOP); + BMO_vert_flag_enable(bm, varr[i], VERT_MARK); + i++; + } + } -#define XY(_x, _y) ((_x) + ((_y) * (xtot))) +#define XY(_x, _y) ((_x) + ((_y) * (xtot))) - for (y = 1; y < ytot; y++) { - for (x = 1; x < xtot; x++) { - BMFace *f; + for (y = 1; y < ytot; y++) { + for (x = 1; x < xtot; x++) { + BMFace *f; - vquad[0] = varr[XY(x - 1, y - 1)]; - vquad[1] = varr[XY(x, y - 1)]; - vquad[2] = varr[XY(x, y)]; - vquad[3] = varr[XY(x - 1, y)]; + vquad[0] = varr[XY(x - 1, y - 1)]; + vquad[1] = varr[XY(x, y - 1)]; + vquad[2] = varr[XY(x, y)]; + vquad[3] = varr[XY(x - 1, y)]; - f = BM_face_create_verts(bm, vquad, 4, NULL, BM_CREATE_NOP, true); - if (calc_uvs) { - BMO_face_flag_enable(bm, f, FACE_MARK); - } - } - } + f = BM_face_create_verts(bm, vquad, 4, NULL, BM_CREATE_NOP, true); + if (calc_uvs) { + BMO_face_flag_enable(bm, f, FACE_MARK); + } + } + } #undef XY - if (calc_uvs) { - BM_mesh_calc_uvs_grid(bm, xtot, ytot, FACE_MARK, cd_loop_uv_offset); - } + if (calc_uvs) { + BM_mesh_calc_uvs_grid(bm, xtot, ytot, FACE_MARK, cd_loop_uv_offset); + } } /** @@ -822,334 +795,343 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op) * \param y_segments: The y-resolution of the grid * \param oflag: The flag to check faces with. */ -void BM_mesh_calc_uvs_grid( - BMesh *bm, const uint x_segments, const uint y_segments, - const short oflag, const int cd_loop_uv_offset) +void BM_mesh_calc_uvs_grid(BMesh *bm, + const uint x_segments, + const uint y_segments, + const short oflag, + const int cd_loop_uv_offset) { - BMFace *f; - BMLoop *l; - BMIter iter, liter; - - const float dx = 1.0f / (float)(x_segments - 1); - const float dy = 1.0f / (float)(y_segments - 1); - float x = 0.0f; - float y = dy; - - int loop_index; - - BLI_assert(cd_loop_uv_offset != -1); - - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (!BMO_face_flag_test(bm, f, oflag)) { - continue; - } - - BM_ITER_ELEM_INDEX (l, &liter, f, BM_LOOPS_OF_FACE, loop_index) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - - switch (loop_index) { - case 0: - y -= dy; - break; - case 1: - x += dx; - break; - case 2: - y += dy; - break; - case 3: - x -= dx; - break; - default: - break; - } - - luv->uv[0] = x; - luv->uv[1] = y; - } - - x += dx; - if (x >= 1.0f) { - x = 0.0f; - y += dy; - } - } + BMFace *f; + BMLoop *l; + BMIter iter, liter; + + const float dx = 1.0f / (float)(x_segments - 1); + const float dy = 1.0f / (float)(y_segments - 1); + float x = 0.0f; + float y = dy; + + int loop_index; + + BLI_assert(cd_loop_uv_offset != -1); + + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (!BMO_face_flag_test(bm, f, oflag)) { + continue; + } + + BM_ITER_ELEM_INDEX(l, &liter, f, BM_LOOPS_OF_FACE, loop_index) + { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + switch (loop_index) { + case 0: + y -= dy; + break; + case 1: + x += dx; + break; + case 2: + y += dy; + break; + case 3: + x -= dx; + break; + default: + break; + } + + luv->uv[0] = x; + luv->uv[1] = y; + } + + x += dx; + if (x >= 1.0f) { + x = 0.0f; + y += dy; + } + } } void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op) { - const float dia = BMO_slot_float_get(op->slots_in, "diameter"); - const int seg = BMO_slot_int_get(op->slots_in, "u_segments"); - const int tot = BMO_slot_int_get(op->slots_in, "v_segments"); - - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs"); - - BMOperator bmop, prevop; - BMVert *eve, *preveve; - BMEdge *e; - BMIter iter; - const float axis[3] = {0, 0, 1}; - float vec[3], mat[4][4], cmat[3][3]; - float phi, phid; - int a; - - BMO_slot_mat4_get(op->slots_in, "matrix", mat); - - phid = 2.0f * (float)M_PI / tot; - /* phi = 0.25f * (float)M_PI; */ /* UNUSED */ - - /* one segment first */ - phi = 0; - phid /= 2; - for (a = 0; a <= tot; a++) { - /* Going in this direction, then edge extruding, makes normals face outward */ - vec[0] = 0.0; - vec[1] = dia * sinf(phi); - vec[2] = dia * cosf(phi); - eve = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - BMO_vert_flag_enable(bm, eve, VERT_MARK); - - if (a != 0) { - e = BM_edge_create(bm, preveve, eve, NULL, BM_CREATE_NOP); - BMO_edge_flag_enable(bm, e, EDGE_ORIG); - } - - phi += phid; - preveve = eve; - } - - /* extrude and rotate; negative phi to make normals face outward */ - axis_angle_to_mat3(cmat, axis, -(M_PI * 2) / seg); - - for (a = 0; a < seg; a++) { - if (a) { - BMO_op_initf(bm, &bmop, op->flag, "extrude_edge_only edges=%S", &prevop, "geom.out"); - BMO_op_exec(bm, &bmop); - BMO_op_finish(bm, &prevop); - } - else { - BMO_op_initf(bm, &bmop, op->flag, "extrude_edge_only edges=%fe", EDGE_ORIG); - BMO_op_exec(bm, &bmop); - } - - BMO_slot_buffer_flag_enable(bm, bmop.slots_out, "geom.out", BM_VERT, VERT_MARK); - BMO_op_callf(bm, op->flag, "rotate cent=%v matrix=%m3 verts=%S", vec, cmat, &bmop, "geom.out"); - - prevop = bmop; - } - - if (a) { - BMO_op_finish(bm, &bmop); - } - - { - float len, len2, vec2[3]; - - len = 2 *dia * sinf(phid / 2.0f); - - /* length of one segment in shortest parallen */ - vec[0] = dia * sinf(phid); - vec[1] = 0.0f; - vec[2] = dia * cosf(phid); - - mul_v3_m3v3(vec2, cmat, vec); - len2 = len_v3v3(vec, vec2); - - /* use shortest segment length divided by 3 as merge threshold */ - BMO_op_callf(bm, op->flag, "remove_doubles verts=%fv dist=%f", VERT_MARK, min_ff(len, len2) / 3.0f); - } - - if (calc_uvs) { - BMFace *f; - BMLoop *l; - BMIter fiter, liter; - - /* We cannot tag faces for UVs computing above, so we have to do it now, based on all its vertices - * being tagged. */ - BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { - bool valid = true; - - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - if (!BMO_vert_flag_test(bm, l->v, VERT_MARK)) { - valid = false; - break; - } - } - - if (valid) { - BMO_face_flag_enable(bm, f, FACE_MARK); - } - } - - BM_mesh_calc_uvs_sphere(bm, FACE_MARK, cd_loop_uv_offset); - } - - /* and now do imat */ - BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { - if (BMO_vert_flag_test(bm, eve, VERT_MARK)) { - mul_m4_v3(mat, eve->co); - } - } - - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); + const float dia = BMO_slot_float_get(op->slots_in, "diameter"); + const int seg = BMO_slot_int_get(op->slots_in, "u_segments"); + const int tot = BMO_slot_int_get(op->slots_in, "v_segments"); + + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs"); + + BMOperator bmop, prevop; + BMVert *eve, *preveve; + BMEdge *e; + BMIter iter; + const float axis[3] = {0, 0, 1}; + float vec[3], mat[4][4], cmat[3][3]; + float phi, phid; + int a; + + BMO_slot_mat4_get(op->slots_in, "matrix", mat); + + phid = 2.0f * (float)M_PI / tot; + /* phi = 0.25f * (float)M_PI; */ /* UNUSED */ + + /* one segment first */ + phi = 0; + phid /= 2; + for (a = 0; a <= tot; a++) { + /* Going in this direction, then edge extruding, makes normals face outward */ + vec[0] = 0.0; + vec[1] = dia * sinf(phi); + vec[2] = dia * cosf(phi); + eve = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); + BMO_vert_flag_enable(bm, eve, VERT_MARK); + + if (a != 0) { + e = BM_edge_create(bm, preveve, eve, NULL, BM_CREATE_NOP); + BMO_edge_flag_enable(bm, e, EDGE_ORIG); + } + + phi += phid; + preveve = eve; + } + + /* extrude and rotate; negative phi to make normals face outward */ + axis_angle_to_mat3(cmat, axis, -(M_PI * 2) / seg); + + for (a = 0; a < seg; a++) { + if (a) { + BMO_op_initf(bm, &bmop, op->flag, "extrude_edge_only edges=%S", &prevop, "geom.out"); + BMO_op_exec(bm, &bmop); + BMO_op_finish(bm, &prevop); + } + else { + BMO_op_initf(bm, &bmop, op->flag, "extrude_edge_only edges=%fe", EDGE_ORIG); + BMO_op_exec(bm, &bmop); + } + + BMO_slot_buffer_flag_enable(bm, bmop.slots_out, "geom.out", BM_VERT, VERT_MARK); + BMO_op_callf(bm, op->flag, "rotate cent=%v matrix=%m3 verts=%S", vec, cmat, &bmop, "geom.out"); + + prevop = bmop; + } + + if (a) { + BMO_op_finish(bm, &bmop); + } + + { + float len, len2, vec2[3]; + + len = 2 * dia * sinf(phid / 2.0f); + + /* length of one segment in shortest parallen */ + vec[0] = dia * sinf(phid); + vec[1] = 0.0f; + vec[2] = dia * cosf(phid); + + mul_v3_m3v3(vec2, cmat, vec); + len2 = len_v3v3(vec, vec2); + + /* use shortest segment length divided by 3 as merge threshold */ + BMO_op_callf( + bm, op->flag, "remove_doubles verts=%fv dist=%f", VERT_MARK, min_ff(len, len2) / 3.0f); + } + + if (calc_uvs) { + BMFace *f; + BMLoop *l; + BMIter fiter, liter; + + /* We cannot tag faces for UVs computing above, so we have to do it now, based on all its vertices + * being tagged. */ + BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { + bool valid = true; + + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + if (!BMO_vert_flag_test(bm, l->v, VERT_MARK)) { + valid = false; + break; + } + } + + if (valid) { + BMO_face_flag_enable(bm, f, FACE_MARK); + } + } + + BM_mesh_calc_uvs_sphere(bm, FACE_MARK, cd_loop_uv_offset); + } + + /* and now do imat */ + BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { + if (BMO_vert_flag_test(bm, eve, VERT_MARK)) { + mul_m4_v3(mat, eve->co); + } + } + + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); } void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op) { - const float dia = BMO_slot_float_get(op->slots_in, "diameter"); - const float dia_div = dia / 200.0f; - const int subdiv = BMO_slot_int_get(op->slots_in, "subdivisions"); - - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs"); - - BMVert *eva[12]; - BMVert *v; - BMIter liter; - BMIter viter; - BMLoop *l; - float vec[3], mat[4][4] /* , phi, phid */; - int a; - - BMO_slot_mat4_get(op->slots_in, "matrix", mat); - - /* phid = 2.0f * (float)M_PI / subdiv; */ /* UNUSED */ - /* phi = 0.25f * (float)M_PI; */ /* UNUSED */ - - - for (a = 0; a < 12; a++) { - vec[0] = dia_div * icovert[a][0]; - vec[1] = dia_div * icovert[a][1]; - vec[2] = dia_div * icovert[a][2]; - eva[a] = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - - BMO_vert_flag_enable(bm, eva[a], VERT_MARK); - } - - int uvi = 0; - for (a = 0; a < 20; a++) { - BMFace *f; - BMVert *v1, *v2, *v3; - - v1 = eva[icoface[a][0]]; - v2 = eva[icoface[a][1]]; - v3 = eva[icoface[a][2]]; - - f = BM_face_create_quad_tri(bm, v1, v2, v3, NULL, NULL, BM_CREATE_NOP); - - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - BMO_edge_flag_enable(bm, l->e, EDGE_MARK); - } - - /* Set the UVs here, the iteration order of the faces is not guaranteed, - * so it's best to set the UVs right after the face is created. */ - if (calc_uvs) { - int loop_index; - BM_ITER_ELEM_INDEX (l, &liter, f, BM_LOOPS_OF_FACE, loop_index) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv->uv[0] = icouvs[uvi][0]; - luv->uv[1] = icouvs[uvi][1]; - uvi++; - } - } - } - - if (subdiv > 1) { - BMOperator bmop; - - BMO_op_initf(bm, &bmop, op->flag, - "subdivide_edges edges=%fe " - "smooth=%f " - "cuts=%i " - "use_grid_fill=%b use_sphere=%b", - EDGE_MARK, dia, (1 << (subdiv - 1)) - 1, - true, true); - - BMO_op_exec(bm, &bmop); - BMO_slot_buffer_flag_enable(bm, bmop.slots_out, "geom.out", BM_VERT, VERT_MARK); - BMO_slot_buffer_flag_enable(bm, bmop.slots_out, "geom.out", BM_EDGE, EDGE_MARK); - BMO_op_finish(bm, &bmop); - } - - - - /* must transform after because of sphere subdivision */ - BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { - if (BMO_vert_flag_test(bm, v, VERT_MARK)) { - mul_m4_v3(mat, v->co); - } - } - - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); + const float dia = BMO_slot_float_get(op->slots_in, "diameter"); + const float dia_div = dia / 200.0f; + const int subdiv = BMO_slot_int_get(op->slots_in, "subdivisions"); + + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs"); + + BMVert *eva[12]; + BMVert *v; + BMIter liter; + BMIter viter; + BMLoop *l; + float vec[3], mat[4][4] /* , phi, phid */; + int a; + + BMO_slot_mat4_get(op->slots_in, "matrix", mat); + + /* phid = 2.0f * (float)M_PI / subdiv; */ /* UNUSED */ + /* phi = 0.25f * (float)M_PI; */ /* UNUSED */ + + for (a = 0; a < 12; a++) { + vec[0] = dia_div * icovert[a][0]; + vec[1] = dia_div * icovert[a][1]; + vec[2] = dia_div * icovert[a][2]; + eva[a] = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); + + BMO_vert_flag_enable(bm, eva[a], VERT_MARK); + } + + int uvi = 0; + for (a = 0; a < 20; a++) { + BMFace *f; + BMVert *v1, *v2, *v3; + + v1 = eva[icoface[a][0]]; + v2 = eva[icoface[a][1]]; + v3 = eva[icoface[a][2]]; + + f = BM_face_create_quad_tri(bm, v1, v2, v3, NULL, NULL, BM_CREATE_NOP); + + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + BMO_edge_flag_enable(bm, l->e, EDGE_MARK); + } + + /* Set the UVs here, the iteration order of the faces is not guaranteed, + * so it's best to set the UVs right after the face is created. */ + if (calc_uvs) { + int loop_index; + BM_ITER_ELEM_INDEX(l, &liter, f, BM_LOOPS_OF_FACE, loop_index) + { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv->uv[0] = icouvs[uvi][0]; + luv->uv[1] = icouvs[uvi][1]; + uvi++; + } + } + } + + if (subdiv > 1) { + BMOperator bmop; + + BMO_op_initf(bm, + &bmop, + op->flag, + "subdivide_edges edges=%fe " + "smooth=%f " + "cuts=%i " + "use_grid_fill=%b use_sphere=%b", + EDGE_MARK, + dia, + (1 << (subdiv - 1)) - 1, + true, + true); + + BMO_op_exec(bm, &bmop); + BMO_slot_buffer_flag_enable(bm, bmop.slots_out, "geom.out", BM_VERT, VERT_MARK); + BMO_slot_buffer_flag_enable(bm, bmop.slots_out, "geom.out", BM_EDGE, EDGE_MARK); + BMO_op_finish(bm, &bmop); + } + + /* must transform after because of sphere subdivision */ + BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { + if (BMO_vert_flag_test(bm, v, VERT_MARK)) { + mul_m4_v3(mat, v->co); + } + } + + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); } static void bm_mesh_calc_uvs_sphere_face(BMFace *f, const int cd_loop_uv_offset) { - float *uvs[4]; - BMLoop *l; - BMIter iter; - float dx; - int loop_index, loop_index_max_x; - - BLI_assert(f->len <= 4); - - /* If face has 3 vertices, it's a polar face, in which case we need to - * compute a nearby to determine its latitude. */ - float avgx = 0.0f, avgy = 0.0f; - BM_ITER_ELEM_INDEX (l, &iter, f, BM_LOOPS_OF_FACE, loop_index) { - if (f->len == 3) { - avgx += l->v->co[0]; - avgy += l->v->co[1]; - } - } - avgx /= 3.0f; - avgy /= 3.0f; - - BM_ITER_ELEM_INDEX (l, &iter, f, BM_LOOPS_OF_FACE, loop_index) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - float x = l->v->co[0]; - float y = l->v->co[1]; - float z = l->v->co[2]; - float len = len_v3(l->v->co); - - /* Use neigboring point to compute angle for poles. */ - float theta; - if (f->len == 3 && fabsf(x) < 0.0001f && fabsf(y) < 0.0001f) { - theta = atan2f(avgy, avgx); - } - else { - theta = atan2f(y, x); - } - - /* Shift borderline coordinates to the left. */ - if (fabsf(theta - (float)M_PI) < 0.0001f) { - theta = -M_PI; - } - - float phi = saacos(z / len); - luv->uv[0] = 0.5f + theta / ((float)M_PI * 2); - luv->uv[1] = 1.0f - phi / (float)M_PI; - - uvs[loop_index] = luv->uv; - } - - /* Fix awkwardly-wrapping UVs */ - loop_index_max_x = 0; - for (loop_index = 1; loop_index < f->len; loop_index++) { - if (uvs[loop_index][0] > uvs[loop_index_max_x][0]) { - loop_index_max_x = loop_index; - } - } - - for (loop_index = 0; loop_index < f->len; loop_index++) { - if (loop_index != loop_index_max_x) { - dx = uvs[loop_index_max_x][0] - uvs[loop_index][0]; - if (dx > 0.5f) { - uvs[loop_index][0] += 1.0f; - } - } - } + float *uvs[4]; + BMLoop *l; + BMIter iter; + float dx; + int loop_index, loop_index_max_x; + + BLI_assert(f->len <= 4); + + /* If face has 3 vertices, it's a polar face, in which case we need to + * compute a nearby to determine its latitude. */ + float avgx = 0.0f, avgy = 0.0f; + BM_ITER_ELEM_INDEX(l, &iter, f, BM_LOOPS_OF_FACE, loop_index) + { + if (f->len == 3) { + avgx += l->v->co[0]; + avgy += l->v->co[1]; + } + } + avgx /= 3.0f; + avgy /= 3.0f; + + BM_ITER_ELEM_INDEX(l, &iter, f, BM_LOOPS_OF_FACE, loop_index) + { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + float x = l->v->co[0]; + float y = l->v->co[1]; + float z = l->v->co[2]; + float len = len_v3(l->v->co); + + /* Use neigboring point to compute angle for poles. */ + float theta; + if (f->len == 3 && fabsf(x) < 0.0001f && fabsf(y) < 0.0001f) { + theta = atan2f(avgy, avgx); + } + else { + theta = atan2f(y, x); + } + + /* Shift borderline coordinates to the left. */ + if (fabsf(theta - (float)M_PI) < 0.0001f) { + theta = -M_PI; + } + + float phi = saacos(z / len); + luv->uv[0] = 0.5f + theta / ((float)M_PI * 2); + luv->uv[1] = 1.0f - phi / (float)M_PI; + + uvs[loop_index] = luv->uv; + } + + /* Fix awkwardly-wrapping UVs */ + loop_index_max_x = 0; + for (loop_index = 1; loop_index < f->len; loop_index++) { + if (uvs[loop_index][0] > uvs[loop_index_max_x][0]) { + loop_index_max_x = loop_index; + } + } + + for (loop_index = 0; loop_index < f->len; loop_index++) { + if (loop_index != loop_index_max_x) { + dx = uvs[loop_index_max_x][0] - uvs[loop_index][0]; + if (dx > 0.5f) { + uvs[loop_index][0] += 1.0f; + } + } + } } /** @@ -1158,211 +1140,213 @@ static void bm_mesh_calc_uvs_sphere_face(BMFace *f, const int cd_loop_uv_offset) * \param bm: The BMesh to operate on * \param oflag: The flag to check faces with. */ -void BM_mesh_calc_uvs_sphere( - BMesh *bm, - const short oflag, const int cd_loop_uv_offset) +void BM_mesh_calc_uvs_sphere(BMesh *bm, const short oflag, const int cd_loop_uv_offset) { - BMFace *f; - BMIter iter; - - BLI_assert(cd_loop_uv_offset != -1); /* caller is responsible for giving us UVs */ - - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (!BMO_face_flag_test(bm, f, oflag)) { - continue; - } - - bm_mesh_calc_uvs_sphere_face(f, cd_loop_uv_offset); - } - - BMIter iter2; - BMLoop *l; - int loop_index; - float minx = 1.0f; - - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (!BMO_face_flag_test(bm, f, oflag)) { - continue; - } - BM_ITER_ELEM_INDEX (l, &iter2, f, BM_LOOPS_OF_FACE, loop_index) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (luv->uv[0] < minx) { - minx = luv->uv[0]; - } - } - } - - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (!BMO_face_flag_test(bm, f, oflag)) { - continue; - } - BM_ITER_ELEM_INDEX (l, &iter2, f, BM_LOOPS_OF_FACE, loop_index) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv->uv[0] -= minx; - } - } + BMFace *f; + BMIter iter; + + BLI_assert(cd_loop_uv_offset != -1); /* caller is responsible for giving us UVs */ + + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (!BMO_face_flag_test(bm, f, oflag)) { + continue; + } + + bm_mesh_calc_uvs_sphere_face(f, cd_loop_uv_offset); + } + + BMIter iter2; + BMLoop *l; + int loop_index; + float minx = 1.0f; + + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (!BMO_face_flag_test(bm, f, oflag)) { + continue; + } + BM_ITER_ELEM_INDEX(l, &iter2, f, BM_LOOPS_OF_FACE, loop_index) + { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (luv->uv[0] < minx) { + minx = luv->uv[0]; + } + } + } + + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (!BMO_face_flag_test(bm, f, oflag)) { + continue; + } + BM_ITER_ELEM_INDEX(l, &iter2, f, BM_LOOPS_OF_FACE, loop_index) + { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv->uv[0] -= minx; + } + } } void bmo_create_monkey_exec(BMesh *bm, BMOperator *op) { - BMVert **tv = MEM_mallocN(sizeof(*tv) * monkeynv * 2, "tv"); - float mat[4][4]; - int i; - - BMO_slot_mat4_get(op->slots_in, "matrix", mat); - - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs"); - - for (i = 0; i < monkeynv; i++) { - float v[3]; - - /* rotate to face in the -Y axis */ - v[0] = (monkeyv[i][0] + 127) / 128.0; - v[2] = monkeyv[i][1] / 128.0; - v[1] = monkeyv[i][2] / -128.0; - - tv[i] = BM_vert_create(bm, v, NULL, BM_CREATE_NOP); - BMO_vert_flag_enable(bm, tv[i], VERT_MARK); - - if (fabsf(v[0] = -v[0]) < 0.001f) { - tv[monkeynv + i] = tv[i]; - } - else { - BMVert *eve = BM_vert_create(bm, v, NULL, BM_CREATE_NOP); - mul_m4_v3(mat, eve->co); - tv[monkeynv + i] = eve; - } - - BMO_vert_flag_enable(bm, tv[monkeynv + i], VERT_MARK); - - mul_m4_v3(mat, tv[i]->co); - } - - int uvi = 0; - for (i = 0; i < monkeynf; i++) { - BMFace *f_new_a = BM_face_create_quad_tri(bm, - tv[monkeyf[i][0] + i - monkeyo], - tv[monkeyf[i][1] + i - monkeyo], - tv[monkeyf[i][2] + i - monkeyo], - (monkeyf[i][3] != monkeyf[i][2]) ? tv[monkeyf[i][3] + i - monkeyo] : NULL, - NULL, BM_CREATE_NOP); - - BMFace *f_new_b = BM_face_create_quad_tri(bm, - tv[monkeynv + monkeyf[i][2] + i - monkeyo], - tv[monkeynv + monkeyf[i][1] + i - monkeyo], - tv[monkeynv + monkeyf[i][0] + i - monkeyo], - (monkeyf[i][3] != monkeyf[i][2]) ? tv[monkeynv + monkeyf[i][3] + i - monkeyo] : NULL, - NULL, BM_CREATE_NOP); - - /* Set the UVs here, the iteration order of the faces is not guaranteed, - * so it's best to set the UVs right after the face is created. */ - if (calc_uvs) { - BMLoop *l; - BMIter liter; - BM_ITER_ELEM (l, &liter, f_new_a, BM_LOOPS_OF_FACE) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv->uv[0] = monkeyuvs[uvi * 2 + 0]; - luv->uv[1] = monkeyuvs[uvi * 2 + 1]; - uvi++; - } - BM_ITER_ELEM (l, &liter, f_new_b, BM_LOOPS_OF_FACE) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv->uv[0] = monkeyuvs[uvi * 2 + 0]; - luv->uv[1] = monkeyuvs[uvi * 2 + 1]; - uvi++; - } - - } - } - - MEM_freeN(tv); - - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); + BMVert **tv = MEM_mallocN(sizeof(*tv) * monkeynv * 2, "tv"); + float mat[4][4]; + int i; + + BMO_slot_mat4_get(op->slots_in, "matrix", mat); + + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs"); + + for (i = 0; i < monkeynv; i++) { + float v[3]; + + /* rotate to face in the -Y axis */ + v[0] = (monkeyv[i][0] + 127) / 128.0; + v[2] = monkeyv[i][1] / 128.0; + v[1] = monkeyv[i][2] / -128.0; + + tv[i] = BM_vert_create(bm, v, NULL, BM_CREATE_NOP); + BMO_vert_flag_enable(bm, tv[i], VERT_MARK); + + if (fabsf(v[0] = -v[0]) < 0.001f) { + tv[monkeynv + i] = tv[i]; + } + else { + BMVert *eve = BM_vert_create(bm, v, NULL, BM_CREATE_NOP); + mul_m4_v3(mat, eve->co); + tv[monkeynv + i] = eve; + } + + BMO_vert_flag_enable(bm, tv[monkeynv + i], VERT_MARK); + + mul_m4_v3(mat, tv[i]->co); + } + + int uvi = 0; + for (i = 0; i < monkeynf; i++) { + BMFace *f_new_a = BM_face_create_quad_tri( + bm, + tv[monkeyf[i][0] + i - monkeyo], + tv[monkeyf[i][1] + i - monkeyo], + tv[monkeyf[i][2] + i - monkeyo], + (monkeyf[i][3] != monkeyf[i][2]) ? tv[monkeyf[i][3] + i - monkeyo] : NULL, + NULL, + BM_CREATE_NOP); + + BMFace *f_new_b = BM_face_create_quad_tri( + bm, + tv[monkeynv + monkeyf[i][2] + i - monkeyo], + tv[monkeynv + monkeyf[i][1] + i - monkeyo], + tv[monkeynv + monkeyf[i][0] + i - monkeyo], + (monkeyf[i][3] != monkeyf[i][2]) ? tv[monkeynv + monkeyf[i][3] + i - monkeyo] : NULL, + NULL, + BM_CREATE_NOP); + + /* Set the UVs here, the iteration order of the faces is not guaranteed, + * so it's best to set the UVs right after the face is created. */ + if (calc_uvs) { + BMLoop *l; + BMIter liter; + BM_ITER_ELEM (l, &liter, f_new_a, BM_LOOPS_OF_FACE) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv->uv[0] = monkeyuvs[uvi * 2 + 0]; + luv->uv[1] = monkeyuvs[uvi * 2 + 1]; + uvi++; + } + BM_ITER_ELEM (l, &liter, f_new_b, BM_LOOPS_OF_FACE) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv->uv[0] = monkeyuvs[uvi * 2 + 0]; + luv->uv[1] = monkeyuvs[uvi * 2 + 1]; + uvi++; + } + } + } + + MEM_freeN(tv); + + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); } - void bmo_create_circle_exec(BMesh *bm, BMOperator *op) { - const float radius = BMO_slot_float_get(op->slots_in, "radius"); - const int segs = BMO_slot_int_get(op->slots_in, "segments"); - const bool cap_ends = BMO_slot_bool_get(op->slots_in, "cap_ends"); - const bool cap_tris = BMO_slot_bool_get(op->slots_in, "cap_tris"); + const float radius = BMO_slot_float_get(op->slots_in, "radius"); + const int segs = BMO_slot_int_get(op->slots_in, "segments"); + const bool cap_ends = BMO_slot_bool_get(op->slots_in, "cap_ends"); + const bool cap_tris = BMO_slot_bool_get(op->slots_in, "cap_tris"); - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs"); + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs"); - BMVert *v1, *lastv1 = NULL, *cent1, *firstv1 = NULL; - float vec[3], mat[4][4], phi, phid; - int a; + BMVert *v1, *lastv1 = NULL, *cent1, *firstv1 = NULL; + float vec[3], mat[4][4], phi, phid; + int a; - if (!segs) { - return; - } + if (!segs) { + return; + } - BMO_slot_mat4_get(op->slots_in, "matrix", mat); + BMO_slot_mat4_get(op->slots_in, "matrix", mat); - phid = 2.0f * (float)M_PI / segs; - phi = 0; + phid = 2.0f * (float)M_PI / segs; + phi = 0; - if (cap_ends) { - zero_v3(vec); - mul_m4_v3(mat, vec); + if (cap_ends) { + zero_v3(vec); + mul_m4_v3(mat, vec); - cent1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - BMO_vert_flag_enable(bm, cent1, VERT_MARK); - } + cent1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); + BMO_vert_flag_enable(bm, cent1, VERT_MARK); + } - for (a = 0; a < segs; a++, phi += phid) { - /* Going this way ends up with normal(s) upward */ - vec[0] = -radius * sinf(phi); - vec[1] = radius * cosf(phi); - vec[2] = 0.0f; - mul_m4_v3(mat, vec); - v1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); + for (a = 0; a < segs; a++, phi += phid) { + /* Going this way ends up with normal(s) upward */ + vec[0] = -radius * sinf(phi); + vec[1] = radius * cosf(phi); + vec[2] = 0.0f; + mul_m4_v3(mat, vec); + v1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - BMO_vert_flag_enable(bm, v1, VERT_MARK); + BMO_vert_flag_enable(bm, v1, VERT_MARK); - if (lastv1) { - BM_edge_create(bm, v1, lastv1, NULL, BM_CREATE_NOP); - } + if (lastv1) { + BM_edge_create(bm, v1, lastv1, NULL, BM_CREATE_NOP); + } - if (a && cap_ends) { - BMFace *f; + if (a && cap_ends) { + BMFace *f; - f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, BM_CREATE_NOP); - BMO_face_flag_enable(bm, f, FACE_NEW); - } + f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, BM_CREATE_NOP); + BMO_face_flag_enable(bm, f, FACE_NEW); + } - if (!firstv1) { - firstv1 = v1; - } + if (!firstv1) { + firstv1 = v1; + } - lastv1 = v1; - } + lastv1 = v1; + } - if (!a) { - return; - } + if (!a) { + return; + } - BM_edge_create(bm, firstv1, lastv1, NULL, 0); + BM_edge_create(bm, firstv1, lastv1, NULL, 0); - if (cap_ends) { - BMFace *f; + if (cap_ends) { + BMFace *f; - f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, BM_CREATE_NOP); - BMO_face_flag_enable(bm, f, FACE_NEW); + f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, BM_CREATE_NOP); + BMO_face_flag_enable(bm, f, FACE_NEW); - if (calc_uvs) { - BM_mesh_calc_uvs_circle(bm, mat, radius, FACE_NEW, cd_loop_uv_offset); - } - } + if (calc_uvs) { + BM_mesh_calc_uvs_circle(bm, mat, radius, FACE_NEW, cd_loop_uv_offset); + } + } - if (!cap_tris) { - BMO_op_callf(bm, op->flag, "dissolve_faces faces=%ff", FACE_NEW); - } + if (!cap_tris) { + BMO_op_callf(bm, op->flag, "dissolve_faces faces=%ff", FACE_NEW); + } - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); } /** @@ -1374,163 +1358,162 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op) * \param oflag: The flag to check faces with. */ void BM_mesh_calc_uvs_circle( - BMesh *bm, float mat[4][4], const float radius, - const short oflag, const int cd_loop_uv_offset) + BMesh *bm, float mat[4][4], const float radius, const short oflag, const int cd_loop_uv_offset) { - BMFace *f; - BMLoop *l; - BMIter fiter, liter; + BMFace *f; + BMLoop *l; + BMIter fiter, liter; - const float uv_scale = 0.5f / radius; - const float uv_center = 0.5f; + const float uv_scale = 0.5f / radius; + const float uv_center = 0.5f; - float inv_mat[4][4]; + float inv_mat[4][4]; - BLI_assert(cd_loop_uv_offset != -1); /* caller must ensure we have UVs already */ + BLI_assert(cd_loop_uv_offset != -1); /* caller must ensure we have UVs already */ - invert_m4_m4(inv_mat, mat); + invert_m4_m4(inv_mat, mat); - BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { - if (!BMO_face_flag_test(bm, f, oflag)) { - continue; - } + BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { + if (!BMO_face_flag_test(bm, f, oflag)) { + continue; + } - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - float uv_vco[3]; - copy_v3_v3(uv_vco, l->v->co); - /* transform back into the unit circle flat on the Z-axis */ - mul_m4_v3(inv_mat, uv_vco); + float uv_vco[3]; + copy_v3_v3(uv_vco, l->v->co); + /* transform back into the unit circle flat on the Z-axis */ + mul_m4_v3(inv_mat, uv_vco); - /* then just take those coords for UVs */ - luv->uv[0] = uv_center + uv_scale * uv_vco[0]; - luv->uv[1] = uv_center + uv_scale * uv_vco[1]; - } - } + /* then just take those coords for UVs */ + luv->uv[0] = uv_center + uv_scale * uv_vco[0]; + luv->uv[1] = uv_center + uv_scale * uv_vco[1]; + } + } } void bmo_create_cone_exec(BMesh *bm, BMOperator *op) { - BMVert *v1, *v2, *lastv1 = NULL, *lastv2 = NULL, *cent1, *cent2, *firstv1, *firstv2; - BMFace *f; - float vec[3], mat[4][4], phi, phid; - float dia1 = BMO_slot_float_get(op->slots_in, "diameter1"); - float dia2 = BMO_slot_float_get(op->slots_in, "diameter2"); - float depth = BMO_slot_float_get(op->slots_in, "depth"); - int segs = BMO_slot_int_get(op->slots_in, "segments"); - const bool cap_ends = BMO_slot_bool_get(op->slots_in, "cap_ends"); - const bool cap_tris = BMO_slot_bool_get(op->slots_in, "cap_tris"); - - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs"); - int a; - - if (!segs) { - return; - } - - BMO_slot_mat4_get(op->slots_in, "matrix", mat); - - phid = 2.0f * (float)M_PI / segs; - phi = 0; - - depth *= 0.5f; - if (cap_ends) { - vec[0] = vec[1] = 0.0f; - vec[2] = -depth; - mul_m4_v3(mat, vec); - - cent1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - - vec[0] = vec[1] = 0.0f; - vec[2] = depth; - mul_m4_v3(mat, vec); - - cent2 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - - BMO_vert_flag_enable(bm, cent1, VERT_MARK); - BMO_vert_flag_enable(bm, cent2, VERT_MARK); - } - - for (a = 0; a < segs; a++, phi += phid) { - vec[0] = dia1 * sinf(phi); - vec[1] = dia1 * cosf(phi); - vec[2] = -depth; - mul_m4_v3(mat, vec); - v1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - - vec[0] = dia2 * sinf(phi); - vec[1] = dia2 * cosf(phi); - vec[2] = depth; - mul_m4_v3(mat, vec); - v2 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - - BMO_vert_flag_enable(bm, v1, VERT_MARK); - BMO_vert_flag_enable(bm, v2, VERT_MARK); - - if (a) { - if (cap_ends) { - f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, BM_CREATE_NOP); - if (calc_uvs) { - BMO_face_flag_enable(bm, f, FACE_MARK); - } - BMO_face_flag_enable(bm, f, FACE_NEW); - - f = BM_face_create_quad_tri(bm, cent2, v2, lastv2, NULL, NULL, BM_CREATE_NOP); - if (calc_uvs) { - BMO_face_flag_enable(bm, f, FACE_MARK); - } - BMO_face_flag_enable(bm, f, FACE_NEW); - } - - f = BM_face_create_quad_tri(bm, lastv1, lastv2, v2, v1, NULL, BM_CREATE_NOP); - if (calc_uvs) { - BMO_face_flag_enable(bm, f, FACE_MARK); - } - } - else { - firstv1 = v1; - firstv2 = v2; - } - - lastv1 = v1; - lastv2 = v2; - } - - if (!a) { - return; - } - - if (cap_ends) { - f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, BM_CREATE_NOP); - if (calc_uvs) { - BMO_face_flag_enable(bm, f, FACE_MARK); - } - BMO_face_flag_enable(bm, f, FACE_NEW); - - f = BM_face_create_quad_tri(bm, cent2, firstv2, v2, NULL, NULL, BM_CREATE_NOP); - if (calc_uvs) { - BMO_face_flag_enable(bm, f, FACE_MARK); - } - BMO_face_flag_enable(bm, f, FACE_NEW); - } - - f = BM_face_create_quad_tri(bm, v1, v2, firstv2, firstv1, NULL, BM_CREATE_NOP); - if (calc_uvs) { - BMO_face_flag_enable(bm, f, FACE_MARK); - } - - if (calc_uvs) { - BM_mesh_calc_uvs_cone(bm, mat, dia2, dia1, segs, cap_ends, FACE_MARK, cd_loop_uv_offset); - } - - if (!cap_tris) { - BMO_op_callf(bm, op->flag, "dissolve_faces faces=%ff", FACE_NEW); - } - - BMO_op_callf(bm, op->flag, "remove_doubles verts=%fv dist=%f", VERT_MARK, 0.000001); - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); + BMVert *v1, *v2, *lastv1 = NULL, *lastv2 = NULL, *cent1, *cent2, *firstv1, *firstv2; + BMFace *f; + float vec[3], mat[4][4], phi, phid; + float dia1 = BMO_slot_float_get(op->slots_in, "diameter1"); + float dia2 = BMO_slot_float_get(op->slots_in, "diameter2"); + float depth = BMO_slot_float_get(op->slots_in, "depth"); + int segs = BMO_slot_int_get(op->slots_in, "segments"); + const bool cap_ends = BMO_slot_bool_get(op->slots_in, "cap_ends"); + const bool cap_tris = BMO_slot_bool_get(op->slots_in, "cap_tris"); + + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs"); + int a; + + if (!segs) { + return; + } + + BMO_slot_mat4_get(op->slots_in, "matrix", mat); + + phid = 2.0f * (float)M_PI / segs; + phi = 0; + + depth *= 0.5f; + if (cap_ends) { + vec[0] = vec[1] = 0.0f; + vec[2] = -depth; + mul_m4_v3(mat, vec); + + cent1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); + + vec[0] = vec[1] = 0.0f; + vec[2] = depth; + mul_m4_v3(mat, vec); + + cent2 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); + + BMO_vert_flag_enable(bm, cent1, VERT_MARK); + BMO_vert_flag_enable(bm, cent2, VERT_MARK); + } + + for (a = 0; a < segs; a++, phi += phid) { + vec[0] = dia1 * sinf(phi); + vec[1] = dia1 * cosf(phi); + vec[2] = -depth; + mul_m4_v3(mat, vec); + v1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); + + vec[0] = dia2 * sinf(phi); + vec[1] = dia2 * cosf(phi); + vec[2] = depth; + mul_m4_v3(mat, vec); + v2 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); + + BMO_vert_flag_enable(bm, v1, VERT_MARK); + BMO_vert_flag_enable(bm, v2, VERT_MARK); + + if (a) { + if (cap_ends) { + f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, BM_CREATE_NOP); + if (calc_uvs) { + BMO_face_flag_enable(bm, f, FACE_MARK); + } + BMO_face_flag_enable(bm, f, FACE_NEW); + + f = BM_face_create_quad_tri(bm, cent2, v2, lastv2, NULL, NULL, BM_CREATE_NOP); + if (calc_uvs) { + BMO_face_flag_enable(bm, f, FACE_MARK); + } + BMO_face_flag_enable(bm, f, FACE_NEW); + } + + f = BM_face_create_quad_tri(bm, lastv1, lastv2, v2, v1, NULL, BM_CREATE_NOP); + if (calc_uvs) { + BMO_face_flag_enable(bm, f, FACE_MARK); + } + } + else { + firstv1 = v1; + firstv2 = v2; + } + + lastv1 = v1; + lastv2 = v2; + } + + if (!a) { + return; + } + + if (cap_ends) { + f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, BM_CREATE_NOP); + if (calc_uvs) { + BMO_face_flag_enable(bm, f, FACE_MARK); + } + BMO_face_flag_enable(bm, f, FACE_NEW); + + f = BM_face_create_quad_tri(bm, cent2, firstv2, v2, NULL, NULL, BM_CREATE_NOP); + if (calc_uvs) { + BMO_face_flag_enable(bm, f, FACE_MARK); + } + BMO_face_flag_enable(bm, f, FACE_NEW); + } + + f = BM_face_create_quad_tri(bm, v1, v2, firstv2, firstv1, NULL, BM_CREATE_NOP); + if (calc_uvs) { + BMO_face_flag_enable(bm, f, FACE_MARK); + } + + if (calc_uvs) { + BM_mesh_calc_uvs_cone(bm, mat, dia2, dia1, segs, cap_ends, FACE_MARK, cd_loop_uv_offset); + } + + if (!cap_tris) { + BMO_op_callf(bm, op->flag, "dissolve_faces faces=%ff", FACE_NEW); + } + + BMO_op_callf(bm, op->flag, "remove_doubles verts=%fv dist=%f", VERT_MARK, 0.000001); + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); } /** @@ -1544,159 +1527,167 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) * \param cap_ends: Whether the ends of the cone/cylinder are filled or not. * \param oflag: The flag to check faces with. */ -void BM_mesh_calc_uvs_cone( - BMesh *bm, float mat[4][4], - const float radius_top, const float radius_bottom, const int segments, const bool cap_ends, - const short oflag, const int cd_loop_uv_offset) +void BM_mesh_calc_uvs_cone(BMesh *bm, + float mat[4][4], + const float radius_top, + const float radius_bottom, + const int segments, + const bool cap_ends, + const short oflag, + const int cd_loop_uv_offset) { - BMFace *f; - BMLoop *l; - BMIter fiter, liter; - - const float uv_width = 1.0f / (float)segments; - const float uv_height = cap_ends ? 0.5f : 1.0f; - - /* Note that all this allows us to handle all cases (real cone, truncated cone, with or without ends capped) - * with a single common code. */ - const float uv_center_y = cap_ends ? 0.25f : 0.5f; - const float uv_center_x_top = cap_ends ? 0.25f : 0.5f; - const float uv_center_x_bottom = cap_ends ? 0.75f : 0.5f; - const float uv_radius = cap_ends ? 0.24f : 0.5f; - - /* Using the opposite's end uv_scale as fallback allows us to handle 'real cone' case. */ - const float uv_scale_top = (radius_top != 0.0f) ? (uv_radius / radius_top) : - ((radius_bottom != 0.0f) ? (uv_radius / radius_bottom) : uv_radius); - const float uv_scale_bottom = (radius_bottom != 0.0f) ? (uv_radius / radius_bottom) : - uv_scale_top; - - float local_up[3] = {0.0f, 0.0f, 1.0f}; - - float x, y; - float inv_mat[4][4]; - int loop_index; - - mul_mat3_m4_v3(mat, local_up); /* transform the upvector like we did the cone itself, without location. */ - normalize_v3(local_up); /* remove global scaling... */ - - invert_m4_m4(inv_mat, mat); - - BLI_assert(cd_loop_uv_offset != -1); /* caller is responsible for ensuring the mesh has UVs */ - - x = 1.0f; - y = 1.0f - uv_height; - - BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { - if (!BMO_face_flag_test(bm, f, oflag)) { - continue; - } - - if (f->len == 4 && radius_top && radius_bottom) { - /* side face - so unwrap it in a rectangle */ - BM_ITER_ELEM_INDEX (l, &liter, f, BM_LOOPS_OF_FACE, loop_index) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - - switch (loop_index) { - case 0: - /* Continue in the last position */ - break; - case 1: - y += uv_height; - break; - case 2: - x -= uv_width; - break; - case 3: - y -= uv_height; - break; - default: - break; - } - - luv->uv[0] = x; - luv->uv[1] = y; - } - } - else { - /* top or bottom face - so unwrap it by transforming back to a circle and using the X/Y coords */ - BM_face_normal_update(f); - - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - float uv_vco[3]; - - mul_v3_m4v3(uv_vco, inv_mat, l->v->co); - - if (dot_v3v3(f->no, local_up) > 0.0f) { /* if this is a top face of the cone */ - luv->uv[0] = uv_center_x_top + uv_vco[0] * uv_scale_top; - luv->uv[1] = uv_center_y + uv_vco[1] * uv_scale_top; - } - else { - luv->uv[0] = uv_center_x_bottom + uv_vco[0] * uv_scale_bottom; - luv->uv[1] = uv_center_y + uv_vco[1] * uv_scale_bottom; - } - } - } - } + BMFace *f; + BMLoop *l; + BMIter fiter, liter; + + const float uv_width = 1.0f / (float)segments; + const float uv_height = cap_ends ? 0.5f : 1.0f; + + /* Note that all this allows us to handle all cases (real cone, truncated cone, with or without ends capped) + * with a single common code. */ + const float uv_center_y = cap_ends ? 0.25f : 0.5f; + const float uv_center_x_top = cap_ends ? 0.25f : 0.5f; + const float uv_center_x_bottom = cap_ends ? 0.75f : 0.5f; + const float uv_radius = cap_ends ? 0.24f : 0.5f; + + /* Using the opposite's end uv_scale as fallback allows us to handle 'real cone' case. */ + const float uv_scale_top = (radius_top != 0.0f) ? + (uv_radius / radius_top) : + ((radius_bottom != 0.0f) ? (uv_radius / radius_bottom) : + uv_radius); + const float uv_scale_bottom = (radius_bottom != 0.0f) ? (uv_radius / radius_bottom) : + uv_scale_top; + + float local_up[3] = {0.0f, 0.0f, 1.0f}; + + float x, y; + float inv_mat[4][4]; + int loop_index; + + mul_mat3_m4_v3( + mat, local_up); /* transform the upvector like we did the cone itself, without location. */ + normalize_v3(local_up); /* remove global scaling... */ + + invert_m4_m4(inv_mat, mat); + + BLI_assert(cd_loop_uv_offset != -1); /* caller is responsible for ensuring the mesh has UVs */ + + x = 1.0f; + y = 1.0f - uv_height; + + BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { + if (!BMO_face_flag_test(bm, f, oflag)) { + continue; + } + + if (f->len == 4 && radius_top && radius_bottom) { + /* side face - so unwrap it in a rectangle */ + BM_ITER_ELEM_INDEX(l, &liter, f, BM_LOOPS_OF_FACE, loop_index) + { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + switch (loop_index) { + case 0: + /* Continue in the last position */ + break; + case 1: + y += uv_height; + break; + case 2: + x -= uv_width; + break; + case 3: + y -= uv_height; + break; + default: + break; + } + + luv->uv[0] = x; + luv->uv[1] = y; + } + } + else { + /* top or bottom face - so unwrap it by transforming back to a circle and using the X/Y coords */ + BM_face_normal_update(f); + + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + float uv_vco[3]; + + mul_v3_m4v3(uv_vco, inv_mat, l->v->co); + + if (dot_v3v3(f->no, local_up) > 0.0f) { /* if this is a top face of the cone */ + luv->uv[0] = uv_center_x_top + uv_vco[0] * uv_scale_top; + luv->uv[1] = uv_center_y + uv_vco[1] * uv_scale_top; + } + else { + luv->uv[0] = uv_center_x_bottom + uv_vco[0] * uv_scale_bottom; + luv->uv[1] = uv_center_y + uv_vco[1] * uv_scale_bottom; + } + } + } + } } void bmo_create_cube_exec(BMesh *bm, BMOperator *op) { - BMVert *verts[8]; - float mat[4][4]; - float off = BMO_slot_float_get(op->slots_in, "size") / 2.0f; - - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs"); - - /* rotation order set to match 'BM_mesh_calc_uvs_cube' */ - const char faces[6][4] = { - {0, 1, 3, 2}, - {2, 3, 7, 6}, - {6, 7, 5, 4}, - {4, 5, 1, 0}, - {2, 6, 4, 0}, - {7, 3, 1, 5}, - }; - - BMO_slot_mat4_get(op->slots_in, "matrix", mat); - - if (!off) { - off = 0.5f; - } - int i = 0; - - for (int x = -1; x < 2; x += 2) { - for (int y = -1; y < 2; y += 2) { - for (int z = -1; z < 2; z += 2) { - float vec[3] = {(float)x * off, (float)y * off, (float)z * off}; - mul_m4_v3(mat, vec); - verts[i] = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - BMO_vert_flag_enable(bm, verts[i], VERT_MARK); - i++; - } - } - } - - for (i = 0; i < ARRAY_SIZE(faces); i++) { - BMFace *f; - BMVert *quad[4] = { - verts[faces[i][0]], - verts[faces[i][1]], - verts[faces[i][2]], - verts[faces[i][3]], - }; - - f = BM_face_create_verts(bm, quad, 4, NULL, BM_CREATE_NOP, true); - if (calc_uvs) { - BMO_face_flag_enable(bm, f, FACE_MARK); - } - } - - if (calc_uvs) { - BM_mesh_calc_uvs_cube(bm, FACE_MARK); - } - - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); + BMVert *verts[8]; + float mat[4][4]; + float off = BMO_slot_float_get(op->slots_in, "size") / 2.0f; + + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs"); + + /* rotation order set to match 'BM_mesh_calc_uvs_cube' */ + const char faces[6][4] = { + {0, 1, 3, 2}, + {2, 3, 7, 6}, + {6, 7, 5, 4}, + {4, 5, 1, 0}, + {2, 6, 4, 0}, + {7, 3, 1, 5}, + }; + + BMO_slot_mat4_get(op->slots_in, "matrix", mat); + + if (!off) { + off = 0.5f; + } + int i = 0; + + for (int x = -1; x < 2; x += 2) { + for (int y = -1; y < 2; y += 2) { + for (int z = -1; z < 2; z += 2) { + float vec[3] = {(float)x * off, (float)y * off, (float)z * off}; + mul_m4_v3(mat, vec); + verts[i] = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); + BMO_vert_flag_enable(bm, verts[i], VERT_MARK); + i++; + } + } + } + + for (i = 0; i < ARRAY_SIZE(faces); i++) { + BMFace *f; + BMVert *quad[4] = { + verts[faces[i][0]], + verts[faces[i][1]], + verts[faces[i][2]], + verts[faces[i][3]], + }; + + f = BM_face_create_verts(bm, quad, 4, NULL, BM_CREATE_NOP, true); + if (calc_uvs) { + BMO_face_flag_enable(bm, f, FACE_MARK); + } + } + + if (calc_uvs) { + BM_mesh_calc_uvs_cube(bm, FACE_MARK); + } + + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); } /** @@ -1710,59 +1701,60 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op) */ void BM_mesh_calc_uvs_cube(BMesh *bm, const short oflag) { - BMFace *f; - BMLoop *l; - BMIter fiter, liter; - const float width = 0.25f; - - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - - float x = 0.375f; - float y = 0.0f; - - int loop_index; - - BLI_assert(cd_loop_uv_offset != -1); /* the caller can ensure that we have UVs */ - - BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { - if (!BMO_face_flag_test(bm, f, oflag)) { - continue; - } - - BM_ITER_ELEM_INDEX (l, &liter, f, BM_LOOPS_OF_FACE, loop_index) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - - luv->uv[0] = x; - luv->uv[1] = y; - - switch (loop_index) { - case 0: - x += width; - break; - case 1: - y += width; - break; - case 2: - x -= width; - break; - case 3: - y -= width; - break; - default: - break; - } - } - - if (y >= 0.75f && x > 0.125f) { - x = 0.125f; - y = 0.5f; - } - else if (x <= 0.125f) { - x = 0.625f; - y = 0.5f; - } - else { - y += 0.25f; - } - } + BMFace *f; + BMLoop *l; + BMIter fiter, liter; + const float width = 0.25f; + + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + + float x = 0.375f; + float y = 0.0f; + + int loop_index; + + BLI_assert(cd_loop_uv_offset != -1); /* the caller can ensure that we have UVs */ + + BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { + if (!BMO_face_flag_test(bm, f, oflag)) { + continue; + } + + BM_ITER_ELEM_INDEX(l, &liter, f, BM_LOOPS_OF_FACE, loop_index) + { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + luv->uv[0] = x; + luv->uv[1] = y; + + switch (loop_index) { + case 0: + x += width; + break; + case 1: + y += width; + break; + case 2: + x -= width; + break; + case 3: + y -= width; + break; + default: + break; + } + } + + if (y >= 0.75f && x > 0.125f) { + x = 0.125f; + y = 0.5f; + } + else if (x <= 0.125f) { + x = 0.625f; + y = 0.5f; + } + else { + y += 0.25f; + } + } } diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c index e59bad0d682..144d944e939 100644 --- a/source/blender/bmesh/operators/bmo_removedoubles.c +++ b/source/blender/bmesh/operators/bmo_removedoubles.c @@ -36,149 +36,150 @@ static void remdoubles_splitface(BMFace *f, BMesh *bm, BMOperator *op, BMOpSlot *slot_targetmap) { - BMIter liter; - BMLoop *l, *l_tar, *l_double; - bool split = false; - - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - BMVert *v_tar = BMO_slot_map_elem_get(slot_targetmap, l->v); - /* ok: if v_tar is NULL (e.g. not in the map) then it's - * a target vert, otherwise it's a double */ - if (v_tar) { - l_tar = BM_face_vert_share_loop(f, v_tar); - - if (l_tar && (l_tar != l) && !BM_loop_is_adjacent(l_tar, l)) { - l_double = l; - split = true; - break; - } - } - } - - if (split) { - BMLoop *l_new; - BMFace *f_new; - - f_new = BM_face_split(bm, f, l_double, l_tar, &l_new, NULL, false); - - remdoubles_splitface(f, bm, op, slot_targetmap); - remdoubles_splitface(f_new, bm, op, slot_targetmap); - } + BMIter liter; + BMLoop *l, *l_tar, *l_double; + bool split = false; + + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + BMVert *v_tar = BMO_slot_map_elem_get(slot_targetmap, l->v); + /* ok: if v_tar is NULL (e.g. not in the map) then it's + * a target vert, otherwise it's a double */ + if (v_tar) { + l_tar = BM_face_vert_share_loop(f, v_tar); + + if (l_tar && (l_tar != l) && !BM_loop_is_adjacent(l_tar, l)) { + l_double = l; + split = true; + break; + } + } + } + + if (split) { + BMLoop *l_new; + BMFace *f_new; + + f_new = BM_face_split(bm, f, l_double, l_tar, &l_new, NULL, false); + + remdoubles_splitface(f, bm, op, slot_targetmap); + remdoubles_splitface(f_new, bm, op, slot_targetmap); + } } -#define ELE_DEL 1 -#define EDGE_COL 2 -#define VERT_IN_FACE 4 +#define ELE_DEL 1 +#define EDGE_COL 2 +#define VERT_IN_FACE 4 /** * helper function for bmo_weld_verts_exec so we can use stack memory */ -static BMFace *remdoubles_createface(BMesh *bm, BMFace *f, BMOpSlot *slot_targetmap, bool *r_created) +static BMFace *remdoubles_createface(BMesh *bm, + BMFace *f, + BMOpSlot *slot_targetmap, + bool *r_created) { - BMEdge *e_new; + BMEdge *e_new; - BMEdge **edges = BLI_array_alloca(edges, f->len); /* new ordered edges */ - BMVert **verts = BLI_array_alloca(verts, f->len); /* new ordered verts */ - BMLoop **loops = BLI_array_alloca(loops, f->len); /* original ordered loops to copy attrs into the new face */ + BMEdge **edges = BLI_array_alloca(edges, f->len); /* new ordered edges */ + BMVert **verts = BLI_array_alloca(verts, f->len); /* new ordered verts */ + BMLoop **loops = BLI_array_alloca( + loops, f->len); /* original ordered loops to copy attrs into the new face */ - STACK_DECLARE(edges); - STACK_DECLARE(loops); - STACK_DECLARE(verts); + STACK_DECLARE(edges); + STACK_DECLARE(loops); + STACK_DECLARE(verts); - STACK_INIT(edges, f->len); - STACK_INIT(loops, f->len); - STACK_INIT(verts, f->len); + STACK_INIT(edges, f->len); + STACK_INIT(loops, f->len); + STACK_INIT(verts, f->len); - *r_created = false; + *r_created = false; - { + { #define LOOP_MAP_VERT_INIT(l_init, v_map, is_del) \ - v_map = l_init->v; \ - is_del = BMO_vert_flag_test_bool(bm, v_map, ELE_DEL); \ - if (is_del) { \ - v_map = BMO_slot_map_elem_get(slot_targetmap, v_map); \ - } ((void)0) - - - BMLoop *l_first, *l_curr, *l_next; - BMVert *v_curr; - bool is_del_v_curr; - - l_curr = l_first = BM_FACE_FIRST_LOOP(f); - LOOP_MAP_VERT_INIT(l_curr, v_curr, is_del_v_curr); - - do { - BMVert *v_next; - bool is_del_v_next; - - l_next = l_curr->next; - LOOP_MAP_VERT_INIT(l_next, v_next, is_del_v_next); - - /* only search for a new edge if one of the verts is mapped */ - if ((is_del_v_curr || is_del_v_next) == 0) { - e_new = l_curr->e; - } - else if (v_curr == v_next) { - e_new = NULL; /* skip */ - } - else { - e_new = BM_edge_exists(v_curr, v_next); - BLI_assert(e_new); /* never fails */ - } - - if (e_new) { - if (UNLIKELY(BMO_vert_flag_test(bm, v_curr, VERT_IN_FACE))) { - /* we can't make the face, bail out */ - STACK_CLEAR(edges); - goto finally; - } - BMO_vert_flag_enable(bm, v_curr, VERT_IN_FACE); - - STACK_PUSH(edges, e_new); - STACK_PUSH(loops, l_curr); - STACK_PUSH(verts, v_curr); - } - - v_curr = v_next; - is_del_v_curr = is_del_v_next; - } while ((l_curr = l_next) != l_first); + v_map = l_init->v; \ + is_del = BMO_vert_flag_test_bool(bm, v_map, ELE_DEL); \ + if (is_del) { \ + v_map = BMO_slot_map_elem_get(slot_targetmap, v_map); \ + } \ + ((void)0) + + BMLoop *l_first, *l_curr, *l_next; + BMVert *v_curr; + bool is_del_v_curr; + + l_curr = l_first = BM_FACE_FIRST_LOOP(f); + LOOP_MAP_VERT_INIT(l_curr, v_curr, is_del_v_curr); + + do { + BMVert *v_next; + bool is_del_v_next; + + l_next = l_curr->next; + LOOP_MAP_VERT_INIT(l_next, v_next, is_del_v_next); + + /* only search for a new edge if one of the verts is mapped */ + if ((is_del_v_curr || is_del_v_next) == 0) { + e_new = l_curr->e; + } + else if (v_curr == v_next) { + e_new = NULL; /* skip */ + } + else { + e_new = BM_edge_exists(v_curr, v_next); + BLI_assert(e_new); /* never fails */ + } + + if (e_new) { + if (UNLIKELY(BMO_vert_flag_test(bm, v_curr, VERT_IN_FACE))) { + /* we can't make the face, bail out */ + STACK_CLEAR(edges); + goto finally; + } + BMO_vert_flag_enable(bm, v_curr, VERT_IN_FACE); + + STACK_PUSH(edges, e_new); + STACK_PUSH(loops, l_curr); + STACK_PUSH(verts, v_curr); + } + + v_curr = v_next; + is_del_v_curr = is_del_v_next; + } while ((l_curr = l_next) != l_first); #undef LOOP_MAP_VERT_INIT + } - } - -finally: - { - uint i; - for (i = 0; i < STACK_SIZE(verts); i++) { - BMO_vert_flag_disable(bm, verts[i], VERT_IN_FACE); - } - } - - if (STACK_SIZE(edges) >= 3) { - BMFace *f_new = BM_face_exists(verts, STACK_SIZE(verts)); - if (f_new) { - return f_new; - } - f_new = BM_face_create(bm, verts, edges, STACK_SIZE(edges), f, BM_CREATE_NOP); - BLI_assert(f_new != f); - - if (f_new) { - uint i = 0; - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f_new); - do { - BM_elem_attrs_copy(bm, bm, loops[i], l_iter); - } while ((void)i++, (l_iter = l_iter->next) != l_first); - - *r_created = true; - return f_new; - } - } - - return NULL; +finally : { + uint i; + for (i = 0; i < STACK_SIZE(verts); i++) { + BMO_vert_flag_disable(bm, verts[i], VERT_IN_FACE); + } } + if (STACK_SIZE(edges) >= 3) { + BMFace *f_new = BM_face_exists(verts, STACK_SIZE(verts)); + if (f_new) { + return f_new; + } + f_new = BM_face_create(bm, verts, edges, STACK_SIZE(edges), f, BM_CREATE_NOP); + BLI_assert(f_new != f); + + if (f_new) { + uint i = 0; + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f_new); + do { + BM_elem_attrs_copy(bm, bm, loops[i], l_iter); + } while ((void)i++, (l_iter = l_iter->next) != l_first); + + *r_created = true; + return f_new; + } + } + + return NULL; +} /** * \note with 'targetmap', multiple 'keys' are currently supported, though no callers should be using. @@ -186,547 +187,550 @@ finally: */ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op) { - BMIter iter, liter; - BMVert *v; - BMEdge *e; - BMLoop *l; - BMFace *f; - BMOpSlot *slot_targetmap = BMO_slot_get(op->slots_in, "targetmap"); - - /* Maintain selection history. */ - const bool has_selected = !BLI_listbase_is_empty(&bm->selected); - const bool use_targetmap_all = has_selected; - GHash *targetmap_all = NULL; - if (use_targetmap_all) { - /* Map deleted to keep elem. */ - targetmap_all = BLI_ghash_ptr_new(__func__); - } - - /* mark merge verts for deletion */ - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - BMVert *v_dst = BMO_slot_map_elem_get(slot_targetmap, v); - if (v_dst != NULL) { - BMO_vert_flag_enable(bm, v, ELE_DEL); - - /* merge the vertex flags, else we get randomly selected/unselected verts */ - BM_elem_flag_merge_ex(v, v_dst, BM_ELEM_HIDDEN); - - if (use_targetmap_all) { - BLI_assert(v != v_dst); - BLI_ghash_insert(targetmap_all, v, v_dst); - } - } - } - - /* check if any faces are getting their own corners merged - * together, split face if so */ - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - remdoubles_splitface(f, bm, op, slot_targetmap); - } - - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - BMVert *v1, *v2; - const bool is_del_v1 = BMO_vert_flag_test_bool(bm, (v1 = e->v1), ELE_DEL); - const bool is_del_v2 = BMO_vert_flag_test_bool(bm, (v2 = e->v2), ELE_DEL); - - if (is_del_v1 || is_del_v2) { - if (is_del_v1) { - v1 = BMO_slot_map_elem_get(slot_targetmap, v1); - } - if (is_del_v2) { - v2 = BMO_slot_map_elem_get(slot_targetmap, v2); - } - - if (v1 == v2) { - BMO_edge_flag_enable(bm, e, EDGE_COL); - } - else { - /* always merge flags, even for edges we already created */ - BMEdge *e_new = BM_edge_exists(v1, v2); - if (e_new == NULL) { - e_new = BM_edge_create(bm, v1, v2, e, BM_CREATE_NOP); - } - BM_elem_flag_merge_ex(e_new, e, BM_ELEM_HIDDEN); - if (use_targetmap_all) { - BLI_assert(e != e_new); - BLI_ghash_insert(targetmap_all, e, e_new); - } - } - - BMO_edge_flag_enable(bm, e, ELE_DEL); - } - } - - /* faces get "modified" by creating new faces here, then at the - * end the old faces are deleted */ - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - bool vert_delete = false; - int edge_collapse = 0; - - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - if (BMO_vert_flag_test(bm, l->v, ELE_DEL)) { - vert_delete = true; - } - if (BMO_edge_flag_test(bm, l->e, EDGE_COL)) { - edge_collapse++; - } - } - - if (vert_delete) { - bool use_in_place = false; - BMFace *f_new = NULL; - BMO_face_flag_enable(bm, f, ELE_DEL); - - if (f->len - edge_collapse >= 3) { - bool created; - f_new = remdoubles_createface(bm, f, slot_targetmap, &created); - /* do this so we don't need to return a list of created faces */ - if (f_new) { - if (created) { - bmesh_face_swap_data(f_new, f); - - if (bm->use_toolflags) { - SWAP(BMFlagLayer *, ((BMFace_OFlag *)f)->oflags, ((BMFace_OFlag *)f_new)->oflags); - } - - BMO_face_flag_disable(bm, f, ELE_DEL); - BM_face_kill(bm, f_new); - use_in_place = true; - } - else { - BM_elem_flag_merge_ex(f_new, f, BM_ELEM_HIDDEN); - } - } - } - - if ((use_in_place == false) && (f_new != NULL)) { - BLI_assert(f != f_new); - if (use_targetmap_all) { - BLI_ghash_insert(targetmap_all, f, f_new); - } - if (bm->act_face && (f == bm->act_face)) { - bm->act_face = f_new; - } - } - } - } - - if (has_selected) { - BM_select_history_merge_from_targetmap(bm, targetmap_all, targetmap_all, targetmap_all, true); - } - - if (use_targetmap_all) { - BLI_ghash_free(targetmap_all, NULL, NULL); - } - - BMO_mesh_delete_oflag_context(bm, ELE_DEL, DEL_ONLYTAGGED); + BMIter iter, liter; + BMVert *v; + BMEdge *e; + BMLoop *l; + BMFace *f; + BMOpSlot *slot_targetmap = BMO_slot_get(op->slots_in, "targetmap"); + + /* Maintain selection history. */ + const bool has_selected = !BLI_listbase_is_empty(&bm->selected); + const bool use_targetmap_all = has_selected; + GHash *targetmap_all = NULL; + if (use_targetmap_all) { + /* Map deleted to keep elem. */ + targetmap_all = BLI_ghash_ptr_new(__func__); + } + + /* mark merge verts for deletion */ + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + BMVert *v_dst = BMO_slot_map_elem_get(slot_targetmap, v); + if (v_dst != NULL) { + BMO_vert_flag_enable(bm, v, ELE_DEL); + + /* merge the vertex flags, else we get randomly selected/unselected verts */ + BM_elem_flag_merge_ex(v, v_dst, BM_ELEM_HIDDEN); + + if (use_targetmap_all) { + BLI_assert(v != v_dst); + BLI_ghash_insert(targetmap_all, v, v_dst); + } + } + } + + /* check if any faces are getting their own corners merged + * together, split face if so */ + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + remdoubles_splitface(f, bm, op, slot_targetmap); + } + + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + BMVert *v1, *v2; + const bool is_del_v1 = BMO_vert_flag_test_bool(bm, (v1 = e->v1), ELE_DEL); + const bool is_del_v2 = BMO_vert_flag_test_bool(bm, (v2 = e->v2), ELE_DEL); + + if (is_del_v1 || is_del_v2) { + if (is_del_v1) { + v1 = BMO_slot_map_elem_get(slot_targetmap, v1); + } + if (is_del_v2) { + v2 = BMO_slot_map_elem_get(slot_targetmap, v2); + } + + if (v1 == v2) { + BMO_edge_flag_enable(bm, e, EDGE_COL); + } + else { + /* always merge flags, even for edges we already created */ + BMEdge *e_new = BM_edge_exists(v1, v2); + if (e_new == NULL) { + e_new = BM_edge_create(bm, v1, v2, e, BM_CREATE_NOP); + } + BM_elem_flag_merge_ex(e_new, e, BM_ELEM_HIDDEN); + if (use_targetmap_all) { + BLI_assert(e != e_new); + BLI_ghash_insert(targetmap_all, e, e_new); + } + } + + BMO_edge_flag_enable(bm, e, ELE_DEL); + } + } + + /* faces get "modified" by creating new faces here, then at the + * end the old faces are deleted */ + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + bool vert_delete = false; + int edge_collapse = 0; + + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + if (BMO_vert_flag_test(bm, l->v, ELE_DEL)) { + vert_delete = true; + } + if (BMO_edge_flag_test(bm, l->e, EDGE_COL)) { + edge_collapse++; + } + } + + if (vert_delete) { + bool use_in_place = false; + BMFace *f_new = NULL; + BMO_face_flag_enable(bm, f, ELE_DEL); + + if (f->len - edge_collapse >= 3) { + bool created; + f_new = remdoubles_createface(bm, f, slot_targetmap, &created); + /* do this so we don't need to return a list of created faces */ + if (f_new) { + if (created) { + bmesh_face_swap_data(f_new, f); + + if (bm->use_toolflags) { + SWAP(BMFlagLayer *, ((BMFace_OFlag *)f)->oflags, ((BMFace_OFlag *)f_new)->oflags); + } + + BMO_face_flag_disable(bm, f, ELE_DEL); + BM_face_kill(bm, f_new); + use_in_place = true; + } + else { + BM_elem_flag_merge_ex(f_new, f, BM_ELEM_HIDDEN); + } + } + } + + if ((use_in_place == false) && (f_new != NULL)) { + BLI_assert(f != f_new); + if (use_targetmap_all) { + BLI_ghash_insert(targetmap_all, f, f_new); + } + if (bm->act_face && (f == bm->act_face)) { + bm->act_face = f_new; + } + } + } + } + + if (has_selected) { + BM_select_history_merge_from_targetmap(bm, targetmap_all, targetmap_all, targetmap_all, true); + } + + if (use_targetmap_all) { + BLI_ghash_free(targetmap_all, NULL, NULL); + } + + BMO_mesh_delete_oflag_context(bm, ELE_DEL, DEL_ONLYTAGGED); } -#define VERT_KEEP 8 -#define VERT_IN 32 +#define VERT_KEEP 8 +#define VERT_IN 32 -#define EDGE_MARK 1 +#define EDGE_MARK 1 void bmo_pointmerge_facedata_exec(BMesh *bm, BMOperator *op) { - BMOIter siter; - BMIter iter; - BMVert *v, *vert_snap; - BMLoop *l, *l_first = NULL; - float fac; - int i, tot; - - vert_snap = BMO_slot_buffer_get_single(BMO_slot_get(op->slots_in, "vert_snap")); - tot = BM_vert_face_count(vert_snap); - - if (!tot) { - return; - } - - fac = 1.0f / tot; - BM_ITER_ELEM (l, &iter, vert_snap, BM_LOOPS_OF_VERT) { - if (l_first == NULL) { - l_first = l; - } - - for (i = 0; i < bm->ldata.totlayer; i++) { - if (CustomData_layer_has_math(&bm->ldata, i)) { - const int type = bm->ldata.layers[i].type; - const int offset = bm->ldata.layers[i].offset; - void *e1, *e2; - - e1 = BM_ELEM_CD_GET_VOID_P(l_first, offset); - e2 = BM_ELEM_CD_GET_VOID_P(l, offset); - - CustomData_data_multiply(type, e2, fac); - - if (l != l_first) { - CustomData_data_add(type, e1, e2); - } - } - } - } - - BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) { - BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) { - if (l == l_first) { - continue; - } - - CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, l_first->head.data, &l->head.data); - } - } + BMOIter siter; + BMIter iter; + BMVert *v, *vert_snap; + BMLoop *l, *l_first = NULL; + float fac; + int i, tot; + + vert_snap = BMO_slot_buffer_get_single(BMO_slot_get(op->slots_in, "vert_snap")); + tot = BM_vert_face_count(vert_snap); + + if (!tot) { + return; + } + + fac = 1.0f / tot; + BM_ITER_ELEM (l, &iter, vert_snap, BM_LOOPS_OF_VERT) { + if (l_first == NULL) { + l_first = l; + } + + for (i = 0; i < bm->ldata.totlayer; i++) { + if (CustomData_layer_has_math(&bm->ldata, i)) { + const int type = bm->ldata.layers[i].type; + const int offset = bm->ldata.layers[i].offset; + void *e1, *e2; + + e1 = BM_ELEM_CD_GET_VOID_P(l_first, offset); + e2 = BM_ELEM_CD_GET_VOID_P(l, offset); + + CustomData_data_multiply(type, e2, fac); + + if (l != l_first) { + CustomData_data_add(type, e1, e2); + } + } + } + } + + BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) { + BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) { + if (l == l_first) { + continue; + } + + CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, l_first->head.data, &l->head.data); + } + } } void bmo_average_vert_facedata_exec(BMesh *bm, BMOperator *op) { - BMOIter siter; - BMIter iter; - BMVert *v; - BMLoop *l /* , *firstl = NULL */; - CDBlockBytes min, max; - int i; - - for (i = 0; i < bm->ldata.totlayer; i++) { - const int type = bm->ldata.layers[i].type; - const int offset = bm->ldata.layers[i].offset; - - if (!CustomData_layer_has_math(&bm->ldata, i)) { - continue; - } - - CustomData_data_initminmax(type, &min, &max); - - BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) { - BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) { - void *block = BM_ELEM_CD_GET_VOID_P(l, offset); - CustomData_data_dominmax(type, block, &min, &max); - } - } - - CustomData_data_multiply(type, &min, 0.5f); - CustomData_data_multiply(type, &max, 0.5f); - CustomData_data_add(type, &min, &max); - - BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) { - BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) { - void *block = BM_ELEM_CD_GET_VOID_P(l, offset); - CustomData_data_copy_value(type, &min, block); - } - } - } + BMOIter siter; + BMIter iter; + BMVert *v; + BMLoop *l /* , *firstl = NULL */; + CDBlockBytes min, max; + int i; + + for (i = 0; i < bm->ldata.totlayer; i++) { + const int type = bm->ldata.layers[i].type; + const int offset = bm->ldata.layers[i].offset; + + if (!CustomData_layer_has_math(&bm->ldata, i)) { + continue; + } + + CustomData_data_initminmax(type, &min, &max); + + BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) { + BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) { + void *block = BM_ELEM_CD_GET_VOID_P(l, offset); + CustomData_data_dominmax(type, block, &min, &max); + } + } + + CustomData_data_multiply(type, &min, 0.5f); + CustomData_data_multiply(type, &max, 0.5f); + CustomData_data_add(type, &min, &max); + + BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) { + BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) { + void *block = BM_ELEM_CD_GET_VOID_P(l, offset); + CustomData_data_copy_value(type, &min, block); + } + } + } } void bmo_pointmerge_exec(BMesh *bm, BMOperator *op) { - BMOperator weldop; - BMOIter siter; - BMVert *v, *vert_snap = NULL; - float vec[3]; - BMOpSlot *slot_targetmap; - - BMO_slot_vec_get(op->slots_in, "merge_co", vec); - - //BMO_op_callf(bm, op->flag, "collapse_uvs edges=%s", op, "edges"); - BMO_op_init(bm, &weldop, op->flag, "weld_verts"); - - slot_targetmap = BMO_slot_get(weldop.slots_in, "targetmap"); - - BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) { - if (!vert_snap) { - vert_snap = v; - copy_v3_v3(vert_snap->co, vec); - } - else { - BMO_slot_map_elem_insert(&weldop, slot_targetmap, v, vert_snap); - } - } - - BMO_op_exec(bm, &weldop); - BMO_op_finish(bm, &weldop); + BMOperator weldop; + BMOIter siter; + BMVert *v, *vert_snap = NULL; + float vec[3]; + BMOpSlot *slot_targetmap; + + BMO_slot_vec_get(op->slots_in, "merge_co", vec); + + //BMO_op_callf(bm, op->flag, "collapse_uvs edges=%s", op, "edges"); + BMO_op_init(bm, &weldop, op->flag, "weld_verts"); + + slot_targetmap = BMO_slot_get(weldop.slots_in, "targetmap"); + + BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) { + if (!vert_snap) { + vert_snap = v; + copy_v3_v3(vert_snap->co, vec); + } + else { + BMO_slot_map_elem_insert(&weldop, slot_targetmap, v, vert_snap); + } + } + + BMO_op_exec(bm, &weldop); + BMO_op_finish(bm, &weldop); } void bmo_collapse_exec(BMesh *bm, BMOperator *op) { - BMOperator weldop; - BMWalker walker; - BMIter iter; - BMEdge *e; - BLI_Stack *edge_stack; - BMOpSlot *slot_targetmap; + BMOperator weldop; + BMWalker walker; + BMIter iter; + BMEdge *e; + BLI_Stack *edge_stack; + BMOpSlot *slot_targetmap; - if (BMO_slot_bool_get(op->slots_in, "uvs")) { - BMO_op_callf(bm, op->flag, "collapse_uvs edges=%s", op, "edges"); - } + if (BMO_slot_bool_get(op->slots_in, "uvs")) { + BMO_op_callf(bm, op->flag, "collapse_uvs edges=%s", op, "edges"); + } - BMO_op_init(bm, &weldop, op->flag, "weld_verts"); - slot_targetmap = BMO_slot_get(weldop.slots_in, "targetmap"); + BMO_op_init(bm, &weldop, op->flag, "weld_verts"); + slot_targetmap = BMO_slot_get(weldop.slots_in, "targetmap"); - BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, EDGE_MARK); + BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, EDGE_MARK); - BMW_init(&walker, bm, BMW_VERT_SHELL, - BMW_MASK_NOP, EDGE_MARK, BMW_MASK_NOP, - BMW_FLAG_NOP, /* no need to use BMW_FLAG_TEST_HIDDEN, already marked data */ - BMW_NIL_LAY); + BMW_init(&walker, + bm, + BMW_VERT_SHELL, + BMW_MASK_NOP, + EDGE_MARK, + BMW_MASK_NOP, + BMW_FLAG_NOP, /* no need to use BMW_FLAG_TEST_HIDDEN, already marked data */ + BMW_NIL_LAY); - edge_stack = BLI_stack_new(sizeof(BMEdge *), __func__); + edge_stack = BLI_stack_new(sizeof(BMEdge *), __func__); - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - float center[3]; - int count = 0; - BMVert *v_tar; + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + float center[3]; + int count = 0; + BMVert *v_tar; - zero_v3(center); + zero_v3(center); - if (!BMO_edge_flag_test(bm, e, EDGE_MARK)) { - continue; - } + if (!BMO_edge_flag_test(bm, e, EDGE_MARK)) { + continue; + } - BLI_assert(BLI_stack_is_empty(edge_stack)); + BLI_assert(BLI_stack_is_empty(edge_stack)); - for (e = BMW_begin(&walker, e->v1); e; e = BMW_step(&walker)) { - BLI_stack_push(edge_stack, &e); + for (e = BMW_begin(&walker, e->v1); e; e = BMW_step(&walker)) { + BLI_stack_push(edge_stack, &e); - add_v3_v3(center, e->v1->co); - add_v3_v3(center, e->v2->co); + add_v3_v3(center, e->v1->co); + add_v3_v3(center, e->v2->co); - count += 2; + count += 2; - /* prevent adding to slot_targetmap multiple times */ - BM_elem_flag_disable(e->v1, BM_ELEM_TAG); - BM_elem_flag_disable(e->v2, BM_ELEM_TAG); - } + /* prevent adding to slot_targetmap multiple times */ + BM_elem_flag_disable(e->v1, BM_ELEM_TAG); + BM_elem_flag_disable(e->v2, BM_ELEM_TAG); + } - if (!BLI_stack_is_empty(edge_stack)) { - mul_v3_fl(center, 1.0f / count); + if (!BLI_stack_is_empty(edge_stack)) { + mul_v3_fl(center, 1.0f / count); - /* snap edges to a point. for initial testing purposes anyway */ - e = *(BMEdge **)BLI_stack_peek(edge_stack); - v_tar = e->v1; + /* snap edges to a point. for initial testing purposes anyway */ + e = *(BMEdge **)BLI_stack_peek(edge_stack); + v_tar = e->v1; - while (!BLI_stack_is_empty(edge_stack)) { - uint j; - BLI_stack_pop(edge_stack, &e); + while (!BLI_stack_is_empty(edge_stack)) { + uint j; + BLI_stack_pop(edge_stack, &e); - for (j = 0; j < 2; j++) { - BMVert *v_src = *((&e->v1) + j); + for (j = 0; j < 2; j++) { + BMVert *v_src = *((&e->v1) + j); - copy_v3_v3(v_src->co, center); - if ((v_src != v_tar) && !BM_elem_flag_test(v_src, BM_ELEM_TAG)) { - BM_elem_flag_enable(v_src, BM_ELEM_TAG); - BMO_slot_map_elem_insert(&weldop, slot_targetmap, v_src, v_tar); - } - } - } - } - } + copy_v3_v3(v_src->co, center); + if ((v_src != v_tar) && !BM_elem_flag_test(v_src, BM_ELEM_TAG)) { + BM_elem_flag_enable(v_src, BM_ELEM_TAG); + BMO_slot_map_elem_insert(&weldop, slot_targetmap, v_src, v_tar); + } + } + } + } + } - BLI_stack_free(edge_stack); + BLI_stack_free(edge_stack); - BMO_op_exec(bm, &weldop); - BMO_op_finish(bm, &weldop); + BMO_op_exec(bm, &weldop); + BMO_op_finish(bm, &weldop); - BMW_end(&walker); + BMW_end(&walker); } /* uv collapse function */ static void bmo_collapsecon_do_layer(BMesh *bm, const int layer, const short oflag) { - const int type = bm->ldata.layers[layer].type; - const int offset = bm->ldata.layers[layer].offset; - BMIter iter, liter; - BMFace *f; - BMLoop *l, *l2; - BMWalker walker; - BLI_Stack *block_stack; - CDBlockBytes min, max; - - BMW_init(&walker, bm, BMW_LOOPDATA_ISLAND, - BMW_MASK_NOP, oflag, BMW_MASK_NOP, - BMW_FLAG_NOP, /* no need to use BMW_FLAG_TEST_HIDDEN, already marked data */ - layer); - - block_stack = BLI_stack_new(sizeof(void *), __func__); - - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - if (BMO_edge_flag_test(bm, l->e, oflag)) { - /* walk */ - BLI_assert(BLI_stack_is_empty(block_stack)); - - CustomData_data_initminmax(type, &min, &max); - for (l2 = BMW_begin(&walker, l); l2; l2 = BMW_step(&walker)) { - void *block = BM_ELEM_CD_GET_VOID_P(l2, offset); - CustomData_data_dominmax(type, block, &min, &max); - BLI_stack_push(block_stack, &block); - } - - if (!BLI_stack_is_empty(block_stack)) { - CustomData_data_multiply(type, &min, 0.5f); - CustomData_data_multiply(type, &max, 0.5f); - CustomData_data_add(type, &min, &max); - - /* snap CD (uv, vcol) points to their centroid */ - while (!BLI_stack_is_empty(block_stack)) { - void *block; - BLI_stack_pop(block_stack, &block); - CustomData_data_copy_value(type, &min, block); - } - } - } - } - } - - BLI_stack_free(block_stack); - - BMW_end(&walker); + const int type = bm->ldata.layers[layer].type; + const int offset = bm->ldata.layers[layer].offset; + BMIter iter, liter; + BMFace *f; + BMLoop *l, *l2; + BMWalker walker; + BLI_Stack *block_stack; + CDBlockBytes min, max; + + BMW_init(&walker, + bm, + BMW_LOOPDATA_ISLAND, + BMW_MASK_NOP, + oflag, + BMW_MASK_NOP, + BMW_FLAG_NOP, /* no need to use BMW_FLAG_TEST_HIDDEN, already marked data */ + layer); + + block_stack = BLI_stack_new(sizeof(void *), __func__); + + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + if (BMO_edge_flag_test(bm, l->e, oflag)) { + /* walk */ + BLI_assert(BLI_stack_is_empty(block_stack)); + + CustomData_data_initminmax(type, &min, &max); + for (l2 = BMW_begin(&walker, l); l2; l2 = BMW_step(&walker)) { + void *block = BM_ELEM_CD_GET_VOID_P(l2, offset); + CustomData_data_dominmax(type, block, &min, &max); + BLI_stack_push(block_stack, &block); + } + + if (!BLI_stack_is_empty(block_stack)) { + CustomData_data_multiply(type, &min, 0.5f); + CustomData_data_multiply(type, &max, 0.5f); + CustomData_data_add(type, &min, &max); + + /* snap CD (uv, vcol) points to their centroid */ + while (!BLI_stack_is_empty(block_stack)) { + void *block; + BLI_stack_pop(block_stack, &block); + CustomData_data_copy_value(type, &min, block); + } + } + } + } + } + + BLI_stack_free(block_stack); + + BMW_end(&walker); } void bmo_collapse_uvs_exec(BMesh *bm, BMOperator *op) { - const short oflag = EDGE_MARK; - int i; + const short oflag = EDGE_MARK; + int i; - /* check flags dont change once set */ + /* check flags dont change once set */ #ifndef NDEBUG - int tot_test; + int tot_test; #endif - if (!CustomData_has_math(&bm->ldata)) { - return; - } + if (!CustomData_has_math(&bm->ldata)) { + return; + } - BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, oflag); + BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, oflag); #ifndef NDEBUG - tot_test = BM_iter_mesh_count_flag(BM_EDGES_OF_MESH, bm, oflag, true); + tot_test = BM_iter_mesh_count_flag(BM_EDGES_OF_MESH, bm, oflag, true); #endif - for (i = 0; i < bm->ldata.totlayer; i++) { - if (CustomData_layer_has_math(&bm->ldata, i)) { - bmo_collapsecon_do_layer(bm, i, oflag); - } - } + for (i = 0; i < bm->ldata.totlayer; i++) { + if (CustomData_layer_has_math(&bm->ldata, i)) { + bmo_collapsecon_do_layer(bm, i, oflag); + } + } #ifndef NDEBUG - BLI_assert(tot_test == BM_iter_mesh_count_flag(BM_EDGES_OF_MESH, bm, EDGE_MARK, true)); + BLI_assert(tot_test == BM_iter_mesh_count_flag(BM_EDGES_OF_MESH, bm, EDGE_MARK, true)); #endif - } -static void bmesh_find_doubles_common( - BMesh *bm, BMOperator *op, - BMOperator *optarget, BMOpSlot *optarget_slot) +static void bmesh_find_doubles_common(BMesh *bm, + BMOperator *op, + BMOperator *optarget, + BMOpSlot *optarget_slot) { - const BMOpSlot *slot_verts = BMO_slot_get(op->slots_in, "verts"); - BMVert * const *verts = (BMVert **)slot_verts->data.buf; - const int verts_len = slot_verts->len; - - bool has_keep_vert = false; - bool found_duplicates = false; - - const float dist = BMO_slot_float_get(op->slots_in, "dist"); - - /* Test whether keep_verts arg exists and is non-empty */ - if (BMO_slot_exists(op->slots_in, "keep_verts")) { - BMOIter oiter; - has_keep_vert = BMO_iter_new(&oiter, op->slots_in, "keep_verts", BM_VERT) != NULL; - } - - /* Flag keep_verts */ - if (has_keep_vert) { - BMO_slot_buffer_flag_enable(bm, op->slots_in, "keep_verts", BM_VERT, VERT_KEEP); - } - - int *duplicates = MEM_mallocN(sizeof(int) * verts_len, __func__); - { - KDTree_3d *tree = BLI_kdtree_3d_new(verts_len); - for (int i = 0; i < verts_len; i++) { - BLI_kdtree_3d_insert(tree, i, verts[i]->co); - if (has_keep_vert && BMO_vert_flag_test(bm, verts[i], VERT_KEEP)) { - duplicates[i] = i; - } - else { - duplicates[i] = -1; - } - } - - BLI_kdtree_3d_balance(tree); - found_duplicates = BLI_kdtree_3d_calc_duplicates_fast(tree, dist, false, duplicates) != 0; - BLI_kdtree_3d_free(tree); - } - - if (found_duplicates) { - for (int i = 0; i < verts_len; i++) { - BMVert *v_check = verts[i]; - if (duplicates[i] == -1) { - /* nop (others can use as target) */ - } - else if (duplicates[i] == i) { - /* keep (others can use as target) */ - } - else { - BMVert *v_other = verts[duplicates[i]]; - BLI_assert(ELEM(duplicates[duplicates[i]], -1, duplicates[i])); - BMO_slot_map_elem_insert(optarget, optarget_slot, v_check, v_other); - } - } - } - - MEM_freeN(duplicates); + const BMOpSlot *slot_verts = BMO_slot_get(op->slots_in, "verts"); + BMVert *const *verts = (BMVert **)slot_verts->data.buf; + const int verts_len = slot_verts->len; + + bool has_keep_vert = false; + bool found_duplicates = false; + + const float dist = BMO_slot_float_get(op->slots_in, "dist"); + + /* Test whether keep_verts arg exists and is non-empty */ + if (BMO_slot_exists(op->slots_in, "keep_verts")) { + BMOIter oiter; + has_keep_vert = BMO_iter_new(&oiter, op->slots_in, "keep_verts", BM_VERT) != NULL; + } + + /* Flag keep_verts */ + if (has_keep_vert) { + BMO_slot_buffer_flag_enable(bm, op->slots_in, "keep_verts", BM_VERT, VERT_KEEP); + } + + int *duplicates = MEM_mallocN(sizeof(int) * verts_len, __func__); + { + KDTree_3d *tree = BLI_kdtree_3d_new(verts_len); + for (int i = 0; i < verts_len; i++) { + BLI_kdtree_3d_insert(tree, i, verts[i]->co); + if (has_keep_vert && BMO_vert_flag_test(bm, verts[i], VERT_KEEP)) { + duplicates[i] = i; + } + else { + duplicates[i] = -1; + } + } + + BLI_kdtree_3d_balance(tree); + found_duplicates = BLI_kdtree_3d_calc_duplicates_fast(tree, dist, false, duplicates) != 0; + BLI_kdtree_3d_free(tree); + } + + if (found_duplicates) { + for (int i = 0; i < verts_len; i++) { + BMVert *v_check = verts[i]; + if (duplicates[i] == -1) { + /* nop (others can use as target) */ + } + else if (duplicates[i] == i) { + /* keep (others can use as target) */ + } + else { + BMVert *v_other = verts[duplicates[i]]; + BLI_assert(ELEM(duplicates[duplicates[i]], -1, duplicates[i])); + BMO_slot_map_elem_insert(optarget, optarget_slot, v_check, v_other); + } + } + } + + MEM_freeN(duplicates); } void bmo_remove_doubles_exec(BMesh *bm, BMOperator *op) { - BMOperator weldop; - BMOpSlot *slot_targetmap; - - BMO_op_init(bm, &weldop, op->flag, "weld_verts"); - slot_targetmap = BMO_slot_get(weldop.slots_in, "targetmap"); - bmesh_find_doubles_common(bm, op, - &weldop, slot_targetmap); - BMO_op_exec(bm, &weldop); - BMO_op_finish(bm, &weldop); + BMOperator weldop; + BMOpSlot *slot_targetmap; + + BMO_op_init(bm, &weldop, op->flag, "weld_verts"); + slot_targetmap = BMO_slot_get(weldop.slots_in, "targetmap"); + bmesh_find_doubles_common(bm, op, &weldop, slot_targetmap); + BMO_op_exec(bm, &weldop); + BMO_op_finish(bm, &weldop); } - void bmo_find_doubles_exec(BMesh *bm, BMOperator *op) { - BMOpSlot *slot_targetmap_out; - slot_targetmap_out = BMO_slot_get(op->slots_out, "targetmap.out"); - bmesh_find_doubles_common(bm, op, - op, slot_targetmap_out); + BMOpSlot *slot_targetmap_out; + slot_targetmap_out = BMO_slot_get(op->slots_out, "targetmap.out"); + bmesh_find_doubles_common(bm, op, op, slot_targetmap_out); } void bmo_automerge_exec(BMesh *bm, BMOperator *op) { - BMOperator findop, weldop; - BMIter viter; - BMVert *v; - - /* The "verts" input sent to this op is the set of verts that - * can be merged away into any other verts. Mark all other verts - * as VERT_KEEP. */ - BMO_slot_buffer_flag_enable(bm, op->slots_in, "verts", BM_VERT, VERT_IN); - BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { - if (!BMO_vert_flag_test(bm, v, VERT_IN)) { - BMO_vert_flag_enable(bm, v, VERT_KEEP); - } - } - - /* Search for doubles among all vertices, but only merge non-VERT_KEEP - * vertices into VERT_KEEP vertices. */ - BMO_op_initf(bm, &findop, op->flag, "find_doubles verts=%av keep_verts=%fv", VERT_KEEP); - BMO_slot_copy(op, slots_in, "dist", - &findop, slots_in, "dist"); - BMO_op_exec(bm, &findop); - - /* weld the vertices */ - BMO_op_init(bm, &weldop, op->flag, "weld_verts"); - BMO_slot_copy(&findop, slots_out, "targetmap.out", - &weldop, slots_in, "targetmap"); - BMO_op_exec(bm, &weldop); - - BMO_op_finish(bm, &findop); - BMO_op_finish(bm, &weldop); + BMOperator findop, weldop; + BMIter viter; + BMVert *v; + + /* The "verts" input sent to this op is the set of verts that + * can be merged away into any other verts. Mark all other verts + * as VERT_KEEP. */ + BMO_slot_buffer_flag_enable(bm, op->slots_in, "verts", BM_VERT, VERT_IN); + BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { + if (!BMO_vert_flag_test(bm, v, VERT_IN)) { + BMO_vert_flag_enable(bm, v, VERT_KEEP); + } + } + + /* Search for doubles among all vertices, but only merge non-VERT_KEEP + * vertices into VERT_KEEP vertices. */ + BMO_op_initf(bm, &findop, op->flag, "find_doubles verts=%av keep_verts=%fv", VERT_KEEP); + BMO_slot_copy(op, slots_in, "dist", &findop, slots_in, "dist"); + BMO_op_exec(bm, &findop); + + /* weld the vertices */ + BMO_op_init(bm, &weldop, op->flag, "weld_verts"); + BMO_slot_copy(&findop, slots_out, "targetmap.out", &weldop, slots_in, "targetmap"); + BMO_op_exec(bm, &weldop); + + BMO_op_finish(bm, &findop); + BMO_op_finish(bm, &weldop); } diff --git a/source/blender/bmesh/operators/bmo_rotate_edges.c b/source/blender/bmesh/operators/bmo_rotate_edges.c index bfc7ba75763..e017806df0d 100644 --- a/source/blender/bmesh/operators/bmo_rotate_edges.c +++ b/source/blender/bmesh/operators/bmo_rotate_edges.c @@ -29,33 +29,33 @@ #include "intern/bmesh_operators_private.h" /* own include */ -#define EDGE_OUT 1 +#define EDGE_OUT 1 #define FACE_MARK 1 /** * Rotate edges where every edge has it's own faces (we can rotate in any order). */ -static void bm_rotate_edges_simple( - BMesh *bm, BMOperator *op, - const short check_flag, const bool use_ccw) +static void bm_rotate_edges_simple(BMesh *bm, + BMOperator *op, + const short check_flag, + const bool use_ccw) { - BMOIter siter; - BMEdge *e; - - BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { - /** - * this ends up being called twice, could add option to not to call check in - * #BM_edge_rotate to get some extra speed */ - if (BM_edge_rotate_check(e)) { - BMEdge *e_rotate = BM_edge_rotate(bm, e, use_ccw, check_flag); - if (e_rotate != NULL) { - BMO_edge_flag_enable(bm, e_rotate, EDGE_OUT); - } - } - } + BMOIter siter; + BMEdge *e; + + BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { + /** + * this ends up being called twice, could add option to not to call check in + * #BM_edge_rotate to get some extra speed */ + if (BM_edge_rotate_check(e)) { + BMEdge *e_rotate = BM_edge_rotate(bm, e, use_ccw, check_flag); + if (e_rotate != NULL) { + BMO_edge_flag_enable(bm, e_rotate, EDGE_OUT); + } + } + } } - /** * Edge length is just a way of ordering that's independent of order in the edges argument, * we could use some other method since ideally all edges will be rotated, @@ -63,7 +63,7 @@ static void bm_rotate_edges_simple( */ static float bm_edge_calc_rotate_cost(const BMEdge *e) { - return -BM_edge_calc_length_squared(e); + return -BM_edge_calc_length_squared(e); } /** @@ -71,25 +71,25 @@ static float bm_edge_calc_rotate_cost(const BMEdge *e) */ static float bm_edge_rotate_is_boundary(const BMEdge *e) { - /* Number of adjacent shared faces. */ - int count = 0; - BMLoop *l_radial_iter = e->l; - do { - /* Skip this edge. */ - BMLoop *l_iter = l_radial_iter->next; - do { - BMEdge *e_iter = l_iter->e; - const int e_iter_index = BM_elem_index_get(e_iter); - if ((e_iter_index != -1)) { - if (count == 1) { - return false; - } - count += 1; - break; - } - } while ((l_iter = l_iter->next) != l_radial_iter); - } while ((l_radial_iter = l_radial_iter->radial_next) != e->l); - return true; + /* Number of adjacent shared faces. */ + int count = 0; + BMLoop *l_radial_iter = e->l; + do { + /* Skip this edge. */ + BMLoop *l_iter = l_radial_iter->next; + do { + BMEdge *e_iter = l_iter->e; + const int e_iter_index = BM_elem_index_get(e_iter); + if ((e_iter_index != -1)) { + if (count == 1) { + return false; + } + count += 1; + break; + } + } while ((l_iter = l_iter->next) != l_radial_iter); + } while ((l_radial_iter = l_radial_iter->radial_next) != e->l); + return true; } /** @@ -97,172 +97,171 @@ static float bm_edge_rotate_is_boundary(const BMEdge *e) * edges which could not rotate need to be re-considered after neighbors are rotated. */ static void bm_rotate_edges_shared( - BMesh *bm, BMOperator *op, - short check_flag, const bool use_ccw, const int edges_len) + BMesh *bm, BMOperator *op, short check_flag, const bool use_ccw, const int edges_len) { - Heap *heap = BLI_heap_new_ex(edges_len); - HeapNode **eheap_table = MEM_mallocN(sizeof(*eheap_table) * edges_len, __func__); - int edges_len_rotate = 0; - - { - BMIter iter; - BMEdge *e; - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - BM_elem_index_set(e, -1); /* set_dirty! */ - } - bm->elem_index_dirty |= BM_EDGE; - } - - { - BMOIter siter; - BMEdge *e; - uint i; - BMO_ITER_INDEX (e, &siter, op->slots_in, "edges", BM_EDGE, i) { - BM_elem_index_set(e, BM_edge_is_manifold(e) ? i : -1); /* set_dirty! */ - eheap_table[i] = NULL; - } - } - - /* First operate on boundary edges, this is often all that's needed, - * regions that have no boundaries are handles after. */ - enum { - PASS_TYPE_BOUNDARY = 0, - PASS_TYPE_ALL = 1, - PASS_TYPE_DONE = 2, - }; - uint pass_type = PASS_TYPE_BOUNDARY; - - - while ((pass_type != PASS_TYPE_DONE) && (edges_len_rotate != edges_len)) { - BLI_assert(BLI_heap_is_empty(heap)); - { - BMOIter siter; - BMEdge *e; - uint i; - BMO_ITER_INDEX (e, &siter, op->slots_in, "edges", BM_EDGE, i) { - BLI_assert(eheap_table[i] == NULL); - - bool ok = (BM_elem_index_get(e) != -1) && BM_edge_rotate_check(e); - - if (ok) { - if (pass_type == PASS_TYPE_BOUNDARY) { - ok = bm_edge_rotate_is_boundary(e); - } - } - - if (ok) { - float cost = bm_edge_calc_rotate_cost(e); - if (pass_type == PASS_TYPE_BOUNDARY) { - /* Trick to ensure once started, non boundaries are handled before other boundary edges. - * This means the first longest boundary defines the starting point which is rotated - * until all its connected edges are exhausted and the next boundary is popped off the heap. - * - * Without this we may rotate from different starting points and meet in the middle - * with obviously uneven topology. - * - * Move from negative to positive value, inverting so large values are still handled first. - */ - cost = cost != 0.0f ? -1.0f / cost : FLT_MAX; - } - eheap_table[i] = BLI_heap_insert(heap, cost, e); - } - } - } - - if (BLI_heap_is_empty(heap)) { - pass_type += 1; - continue; - } - - const int edges_len_rotate_prev = edges_len_rotate; - while (!BLI_heap_is_empty(heap)) { - BMEdge *e_best = BLI_heap_pop_min(heap); - eheap_table[BM_elem_index_get(e_best)] = NULL; - - /* No problem if this fails, re-evaluate if faces connected to this edge are touched. */ - if (BM_edge_rotate_check(e_best)) { - BMEdge *e_rotate = BM_edge_rotate(bm, e_best, use_ccw, check_flag); - if (e_rotate != NULL) { - BMO_edge_flag_enable(bm, e_rotate, EDGE_OUT); - - /* invalidate so we don't try touch this again. */ - BM_elem_index_set(e_rotate, -1); /* set_dirty! */ - - edges_len_rotate += 1; - - /* Note: we could validate all edges which have not been rotated - * (not just previously degenerate edges). - * However there is no real need - they can be left until they're popped off the queue. */ - - /* We don't know the exact topology after rotating the edge, - * so loop over all faces attached to the new edge, typically this will only be two faces. */ - BMLoop *l_radial_iter = e_rotate->l; - do { - /* Skip this edge. */ - BMLoop *l_iter = l_radial_iter->next; - do { - BMEdge *e_iter = l_iter->e; - const int e_iter_index = BM_elem_index_get(e_iter); - if ((e_iter_index != -1) && (eheap_table[e_iter_index] == NULL)) { - if (BM_edge_rotate_check(e_iter)) { - /* Previously degenerate, now valid. */ - float cost = bm_edge_calc_rotate_cost(e_iter); - eheap_table[e_iter_index] = BLI_heap_insert(heap, cost, e_iter); - } - } - } while ((l_iter = l_iter->next) != l_radial_iter); - } while ((l_radial_iter = l_radial_iter->radial_next) != e_rotate->l); - } - } - } - - /* If no actions were taken, move onto the next pass. */ - if (edges_len_rotate == edges_len_rotate_prev) { - pass_type += 1; - continue; - } - } - - BLI_heap_free(heap, NULL); - MEM_freeN(eheap_table); + Heap *heap = BLI_heap_new_ex(edges_len); + HeapNode **eheap_table = MEM_mallocN(sizeof(*eheap_table) * edges_len, __func__); + int edges_len_rotate = 0; + + { + BMIter iter; + BMEdge *e; + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + BM_elem_index_set(e, -1); /* set_dirty! */ + } + bm->elem_index_dirty |= BM_EDGE; + } + + { + BMOIter siter; + BMEdge *e; + uint i; + BMO_ITER_INDEX(e, &siter, op->slots_in, "edges", BM_EDGE, i) + { + BM_elem_index_set(e, BM_edge_is_manifold(e) ? i : -1); /* set_dirty! */ + eheap_table[i] = NULL; + } + } + + /* First operate on boundary edges, this is often all that's needed, + * regions that have no boundaries are handles after. */ + enum { + PASS_TYPE_BOUNDARY = 0, + PASS_TYPE_ALL = 1, + PASS_TYPE_DONE = 2, + }; + uint pass_type = PASS_TYPE_BOUNDARY; + + while ((pass_type != PASS_TYPE_DONE) && (edges_len_rotate != edges_len)) { + BLI_assert(BLI_heap_is_empty(heap)); + { + BMOIter siter; + BMEdge *e; + uint i; + BMO_ITER_INDEX(e, &siter, op->slots_in, "edges", BM_EDGE, i) + { + BLI_assert(eheap_table[i] == NULL); + + bool ok = (BM_elem_index_get(e) != -1) && BM_edge_rotate_check(e); + + if (ok) { + if (pass_type == PASS_TYPE_BOUNDARY) { + ok = bm_edge_rotate_is_boundary(e); + } + } + + if (ok) { + float cost = bm_edge_calc_rotate_cost(e); + if (pass_type == PASS_TYPE_BOUNDARY) { + /* Trick to ensure once started, non boundaries are handled before other boundary edges. + * This means the first longest boundary defines the starting point which is rotated + * until all its connected edges are exhausted and the next boundary is popped off the heap. + * + * Without this we may rotate from different starting points and meet in the middle + * with obviously uneven topology. + * + * Move from negative to positive value, inverting so large values are still handled first. + */ + cost = cost != 0.0f ? -1.0f / cost : FLT_MAX; + } + eheap_table[i] = BLI_heap_insert(heap, cost, e); + } + } + } + + if (BLI_heap_is_empty(heap)) { + pass_type += 1; + continue; + } + + const int edges_len_rotate_prev = edges_len_rotate; + while (!BLI_heap_is_empty(heap)) { + BMEdge *e_best = BLI_heap_pop_min(heap); + eheap_table[BM_elem_index_get(e_best)] = NULL; + + /* No problem if this fails, re-evaluate if faces connected to this edge are touched. */ + if (BM_edge_rotate_check(e_best)) { + BMEdge *e_rotate = BM_edge_rotate(bm, e_best, use_ccw, check_flag); + if (e_rotate != NULL) { + BMO_edge_flag_enable(bm, e_rotate, EDGE_OUT); + + /* invalidate so we don't try touch this again. */ + BM_elem_index_set(e_rotate, -1); /* set_dirty! */ + + edges_len_rotate += 1; + + /* Note: we could validate all edges which have not been rotated + * (not just previously degenerate edges). + * However there is no real need - they can be left until they're popped off the queue. */ + + /* We don't know the exact topology after rotating the edge, + * so loop over all faces attached to the new edge, typically this will only be two faces. */ + BMLoop *l_radial_iter = e_rotate->l; + do { + /* Skip this edge. */ + BMLoop *l_iter = l_radial_iter->next; + do { + BMEdge *e_iter = l_iter->e; + const int e_iter_index = BM_elem_index_get(e_iter); + if ((e_iter_index != -1) && (eheap_table[e_iter_index] == NULL)) { + if (BM_edge_rotate_check(e_iter)) { + /* Previously degenerate, now valid. */ + float cost = bm_edge_calc_rotate_cost(e_iter); + eheap_table[e_iter_index] = BLI_heap_insert(heap, cost, e_iter); + } + } + } while ((l_iter = l_iter->next) != l_radial_iter); + } while ((l_radial_iter = l_radial_iter->radial_next) != e_rotate->l); + } + } + } + + /* If no actions were taken, move onto the next pass. */ + if (edges_len_rotate == edges_len_rotate_prev) { + pass_type += 1; + continue; + } + } + + BLI_heap_free(heap, NULL); + MEM_freeN(eheap_table); } void bmo_rotate_edges_exec(BMesh *bm, BMOperator *op) { - BMOIter siter; - BMEdge *e; - const int edges_len = BMO_slot_buffer_count(op->slots_in, "edges"); - const bool use_ccw = BMO_slot_bool_get(op->slots_in, "use_ccw"); - const bool is_single = (edges_len == 1); - short check_flag = is_single ? - BM_EDGEROT_CHECK_EXISTS : - BM_EDGEROT_CHECK_EXISTS | BM_EDGEROT_CHECK_DEGENERATE; - - bool is_simple = true; - if (is_single == false) { - BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { - BMFace *f_pair[2]; - if (BM_edge_face_pair(e, &f_pair[0], &f_pair[1])) { - for (uint i = 0; i < ARRAY_SIZE(f_pair); i += 1) { - if (BMO_face_flag_test(bm, f_pair[i], FACE_MARK)) { - is_simple = false; - break; - } - BMO_face_flag_enable(bm, f_pair[i], FACE_MARK); - } - if (is_simple == false) { - break; - } - } - } - } - - if (is_simple) { - bm_rotate_edges_simple(bm, op, check_flag, use_ccw); - } - else { - bm_rotate_edges_shared(bm, op, check_flag, use_ccw, edges_len); - } - - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EDGE_OUT); + BMOIter siter; + BMEdge *e; + const int edges_len = BMO_slot_buffer_count(op->slots_in, "edges"); + const bool use_ccw = BMO_slot_bool_get(op->slots_in, "use_ccw"); + const bool is_single = (edges_len == 1); + short check_flag = is_single ? BM_EDGEROT_CHECK_EXISTS : + BM_EDGEROT_CHECK_EXISTS | BM_EDGEROT_CHECK_DEGENERATE; + + bool is_simple = true; + if (is_single == false) { + BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { + BMFace *f_pair[2]; + if (BM_edge_face_pair(e, &f_pair[0], &f_pair[1])) { + for (uint i = 0; i < ARRAY_SIZE(f_pair); i += 1) { + if (BMO_face_flag_test(bm, f_pair[i], FACE_MARK)) { + is_simple = false; + break; + } + BMO_face_flag_enable(bm, f_pair[i], FACE_MARK); + } + if (is_simple == false) { + break; + } + } + } + } + + if (is_simple) { + bm_rotate_edges_simple(bm, op, check_flag, use_ccw); + } + else { + bm_rotate_edges_shared(bm, op, check_flag, use_ccw, edges_len); + } + + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EDGE_OUT); } diff --git a/source/blender/bmesh/operators/bmo_smooth_laplacian.c b/source/blender/bmesh/operators/bmo_smooth_laplacian.c index bf376a757ef..85f62241782 100644 --- a/source/blender/bmesh/operators/bmo_smooth_laplacian.c +++ b/source/blender/bmesh/operators/bmo_smooth_laplacian.c @@ -26,7 +26,6 @@ #include "eigen_capi.h" - #include "bmesh.h" #include "intern/bmesh_operators_private.h" /* own include */ @@ -37,23 +36,23 @@ #define SMOOTH_LAPLACIAN_MIN_EDGE_PERCENTAGE 0.15f struct BLaplacianSystem { - float *eweights; /* Length weights per Edge */ - float (*fweights)[3]; /* Cotangent weights per face */ - float *ring_areas; /* Total area per ring*/ - float *vlengths; /* Total sum of lengths(edges) per vertice*/ - float *vweights; /* Total sum of weights per vertice*/ - int numEdges; /* Number of edges*/ - int numFaces; /* Number of faces*/ - int numVerts; /* Number of verts*/ - short *zerola; /* Is zero area or length*/ - - /* Pointers to data*/ - BMesh *bm; - BMOperator *op; - LinearSolver *context; - - /*Data*/ - float min_area; + float *eweights; /* Length weights per Edge */ + float (*fweights)[3]; /* Cotangent weights per face */ + float *ring_areas; /* Total area per ring*/ + float *vlengths; /* Total sum of lengths(edges) per vertice*/ + float *vweights; /* Total sum of weights per vertice*/ + int numEdges; /* Number of edges*/ + int numFaces; /* Number of faces*/ + int numVerts; /* Number of verts*/ + short *zerola; /* Is zero area or length*/ + + /* Pointers to data*/ + BMesh *bm; + BMOperator *op; + LinearSolver *context; + + /*Data*/ + float min_area; }; typedef struct BLaplacianSystem LaplacianSystem; @@ -64,87 +63,89 @@ static void delete_laplacian_system(LaplacianSystem *sys); static void delete_void_pointer(void *data); static void fill_laplacian_matrix(LaplacianSystem *sys); static void memset_laplacian_system(LaplacianSystem *sys, int val); -static void validate_solution(LaplacianSystem *sys, int usex, int usey, int usez, int preserve_volume); -static void volume_preservation(BMOperator *op, float vini, float vend, int usex, int usey, int usez); +static void validate_solution( + LaplacianSystem *sys, int usex, int usey, int usez, int preserve_volume); +static void volume_preservation( + BMOperator *op, float vini, float vend, int usex, int usey, int usez); static void delete_void_pointer(void *data) { - if (data) { - MEM_freeN(data); - } + if (data) { + MEM_freeN(data); + } } static void delete_laplacian_system(LaplacianSystem *sys) { - delete_void_pointer(sys->eweights); - delete_void_pointer(sys->fweights); - delete_void_pointer(sys->ring_areas); - delete_void_pointer(sys->vlengths); - delete_void_pointer(sys->vweights); - delete_void_pointer(sys->zerola); - if (sys->context) { - EIG_linear_solver_delete(sys->context); - } - sys->bm = NULL; - sys->op = NULL; - MEM_freeN(sys); + delete_void_pointer(sys->eweights); + delete_void_pointer(sys->fweights); + delete_void_pointer(sys->ring_areas); + delete_void_pointer(sys->vlengths); + delete_void_pointer(sys->vweights); + delete_void_pointer(sys->zerola); + if (sys->context) { + EIG_linear_solver_delete(sys->context); + } + sys->bm = NULL; + sys->op = NULL; + MEM_freeN(sys); } static void memset_laplacian_system(LaplacianSystem *sys, int val) { - memset(sys->eweights, val, sizeof(float) * sys->numEdges); - memset(sys->fweights, val, sizeof(float) * sys->numFaces * 3); - memset(sys->ring_areas, val, sizeof(float) * sys->numVerts); - memset(sys->vlengths, val, sizeof(float) * sys->numVerts); - memset(sys->vweights, val, sizeof(float) * sys->numVerts); - memset(sys->zerola, val, sizeof(short) * sys->numVerts); + memset(sys->eweights, val, sizeof(float) * sys->numEdges); + memset(sys->fweights, val, sizeof(float) * sys->numFaces * 3); + memset(sys->ring_areas, val, sizeof(float) * sys->numVerts); + memset(sys->vlengths, val, sizeof(float) * sys->numVerts); + memset(sys->vweights, val, sizeof(float) * sys->numVerts); + memset(sys->zerola, val, sizeof(short) * sys->numVerts); } static LaplacianSystem *init_laplacian_system(int a_numEdges, int a_numFaces, int a_numVerts) { - LaplacianSystem *sys; - sys = MEM_callocN(sizeof(LaplacianSystem), "ModLaplSmoothSystem"); - sys->numEdges = a_numEdges; - sys->numFaces = a_numFaces; - sys->numVerts = a_numVerts; - - sys->eweights = MEM_callocN(sizeof(float) * sys->numEdges, "ModLaplSmoothEWeight"); - if (!sys->eweights) { - delete_laplacian_system(sys); - return NULL; - } - - sys->fweights = MEM_callocN(sizeof(float) * 3 * sys->numFaces, "ModLaplSmoothFWeight"); - if (!sys->fweights) { - delete_laplacian_system(sys); - return NULL; - } - - sys->ring_areas = MEM_callocN(sizeof(float) * sys->numVerts, "ModLaplSmoothRingAreas"); - if (!sys->ring_areas) { - delete_laplacian_system(sys); - return NULL; - } - - sys->vlengths = MEM_callocN(sizeof(float) * sys->numVerts, "ModLaplSmoothVlengths"); - if (!sys->vlengths) { - delete_laplacian_system(sys); - return NULL; - } - - sys->vweights = MEM_callocN(sizeof(float) * sys->numVerts, "ModLaplSmoothVweights"); - if (!sys->vweights) { - delete_laplacian_system(sys); - return NULL; - } - - sys->zerola = MEM_callocN(sizeof(short) * sys->numVerts, "ModLaplSmoothZeloa"); - if (!sys->zerola) { - delete_laplacian_system(sys); - return NULL; - } - - return sys; + LaplacianSystem *sys; + sys = MEM_callocN(sizeof(LaplacianSystem), "ModLaplSmoothSystem"); + sys->numEdges = a_numEdges; + sys->numFaces = a_numFaces; + sys->numVerts = a_numVerts; + + sys->eweights = MEM_callocN(sizeof(float) * sys->numEdges, "ModLaplSmoothEWeight"); + if (!sys->eweights) { + delete_laplacian_system(sys); + return NULL; + } + + sys->fweights = MEM_callocN(sizeof(float) * 3 * sys->numFaces, "ModLaplSmoothFWeight"); + if (!sys->fweights) { + delete_laplacian_system(sys); + return NULL; + } + + sys->ring_areas = MEM_callocN(sizeof(float) * sys->numVerts, "ModLaplSmoothRingAreas"); + if (!sys->ring_areas) { + delete_laplacian_system(sys); + return NULL; + } + + sys->vlengths = MEM_callocN(sizeof(float) * sys->numVerts, "ModLaplSmoothVlengths"); + if (!sys->vlengths) { + delete_laplacian_system(sys); + return NULL; + } + + sys->vweights = MEM_callocN(sizeof(float) * sys->numVerts, "ModLaplSmoothVweights"); + if (!sys->vweights) { + delete_laplacian_system(sys); + return NULL; + } + + sys->zerola = MEM_callocN(sizeof(short) * sys->numVerts, "ModLaplSmoothZeloa"); + if (!sys->zerola) { + delete_laplacian_system(sys); + return NULL; + } + + return sys; } /** @@ -165,387 +166,398 @@ static LaplacianSystem *init_laplacian_system(int a_numEdges, int a_numFaces, in static void init_laplacian_matrix(LaplacianSystem *sys) { - float areaf; - float *v1, *v2, *v3, *v4; - float w1, w2, w3, w4; - int i, j; - bool has_4_vert; - uint idv1, idv2, idv3, idv4, idv[4]; - BMEdge *e; - BMFace *f; - BMIter eiter; - BMIter fiter; - BMIter vi; - BMVert *vn; - BMVert *vf[4]; - - BM_ITER_MESH_INDEX (e, &eiter, sys->bm, BM_EDGES_OF_MESH, j) { - if (!BM_elem_flag_test(e, BM_ELEM_SELECT) && BM_edge_is_boundary(e)) { - v1 = e->v1->co; - v2 = e->v2->co; - idv1 = BM_elem_index_get(e->v1); - idv2 = BM_elem_index_get(e->v2); - - w1 = len_v3v3(v1, v2); - if (w1 > sys->min_area) { - w1 = 1.0f / w1; - i = BM_elem_index_get(e); - sys->eweights[i] = w1; - sys->vlengths[idv1] += w1; - sys->vlengths[idv2] += w1; - } - else { - sys->zerola[idv1] = 1; - sys->zerola[idv2] = 1; - } - } - } - - BM_ITER_MESH (f, &fiter, sys->bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - - BM_ITER_ELEM_INDEX (vn, &vi, f, BM_VERTS_OF_FACE, i) { - vf[i] = vn; - } - has_4_vert = (i == 4) ? 1 : 0; - idv1 = BM_elem_index_get(vf[0]); - idv2 = BM_elem_index_get(vf[1]); - idv3 = BM_elem_index_get(vf[2]); - idv4 = has_4_vert ? BM_elem_index_get(vf[3]) : 0; - - v1 = vf[0]->co; - v2 = vf[1]->co; - v3 = vf[2]->co; - v4 = has_4_vert ? vf[3]->co : NULL; - - if (has_4_vert) { - areaf = area_quad_v3(v1, v2, v3, v4); - } - else { - areaf = area_tri_v3(v1, v2, v3); - } - - if (fabsf(areaf) < sys->min_area) { - sys->zerola[idv1] = 1; - sys->zerola[idv2] = 1; - sys->zerola[idv3] = 1; - if (has_4_vert) { - sys->zerola[idv4] = 1; - } - } - - sys->ring_areas[idv1] += areaf; - sys->ring_areas[idv2] += areaf; - sys->ring_areas[idv3] += areaf; - if (has_4_vert) { - sys->ring_areas[idv4] += areaf; - } - - if (has_4_vert) { - - idv[0] = idv1; - idv[1] = idv2; - idv[2] = idv3; - idv[3] = idv4; - - for (j = 0; j < 4; j++) { - idv1 = idv[j]; - idv2 = idv[(j + 1) % 4]; - idv3 = idv[(j + 2) % 4]; - idv4 = idv[(j + 3) % 4]; - - v1 = vf[j]->co; - v2 = vf[(j + 1) % 4]->co; - v3 = vf[(j + 2) % 4]->co; - v4 = vf[(j + 3) % 4]->co; - - w2 = cotangent_tri_weight_v3(v4, v1, v2) + cotangent_tri_weight_v3(v3, v1, v2); - w3 = cotangent_tri_weight_v3(v2, v3, v1) + cotangent_tri_weight_v3(v4, v1, v3); - w4 = cotangent_tri_weight_v3(v2, v4, v1) + cotangent_tri_weight_v3(v3, v4, v1); - - sys->vweights[idv1] += (w2 + w3 + w4) / 4.0f; - } - } - else { - i = BM_elem_index_get(f); - - w1 = cotangent_tri_weight_v3(v1, v2, v3); - w2 = cotangent_tri_weight_v3(v2, v3, v1); - w3 = cotangent_tri_weight_v3(v3, v1, v2); - - sys->fweights[i][0] += w1; - sys->fweights[i][1] += w2; - sys->fweights[i][2] += w3; - - sys->vweights[idv1] += w2 + w3; - sys->vweights[idv2] += w1 + w3; - sys->vweights[idv3] += w1 + w2; - } - } - } + float areaf; + float *v1, *v2, *v3, *v4; + float w1, w2, w3, w4; + int i, j; + bool has_4_vert; + uint idv1, idv2, idv3, idv4, idv[4]; + BMEdge *e; + BMFace *f; + BMIter eiter; + BMIter fiter; + BMIter vi; + BMVert *vn; + BMVert *vf[4]; + + BM_ITER_MESH_INDEX (e, &eiter, sys->bm, BM_EDGES_OF_MESH, j) { + if (!BM_elem_flag_test(e, BM_ELEM_SELECT) && BM_edge_is_boundary(e)) { + v1 = e->v1->co; + v2 = e->v2->co; + idv1 = BM_elem_index_get(e->v1); + idv2 = BM_elem_index_get(e->v2); + + w1 = len_v3v3(v1, v2); + if (w1 > sys->min_area) { + w1 = 1.0f / w1; + i = BM_elem_index_get(e); + sys->eweights[i] = w1; + sys->vlengths[idv1] += w1; + sys->vlengths[idv2] += w1; + } + else { + sys->zerola[idv1] = 1; + sys->zerola[idv2] = 1; + } + } + } + + BM_ITER_MESH (f, &fiter, sys->bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + + BM_ITER_ELEM_INDEX(vn, &vi, f, BM_VERTS_OF_FACE, i) + { + vf[i] = vn; + } + has_4_vert = (i == 4) ? 1 : 0; + idv1 = BM_elem_index_get(vf[0]); + idv2 = BM_elem_index_get(vf[1]); + idv3 = BM_elem_index_get(vf[2]); + idv4 = has_4_vert ? BM_elem_index_get(vf[3]) : 0; + + v1 = vf[0]->co; + v2 = vf[1]->co; + v3 = vf[2]->co; + v4 = has_4_vert ? vf[3]->co : NULL; + + if (has_4_vert) { + areaf = area_quad_v3(v1, v2, v3, v4); + } + else { + areaf = area_tri_v3(v1, v2, v3); + } + + if (fabsf(areaf) < sys->min_area) { + sys->zerola[idv1] = 1; + sys->zerola[idv2] = 1; + sys->zerola[idv3] = 1; + if (has_4_vert) { + sys->zerola[idv4] = 1; + } + } + + sys->ring_areas[idv1] += areaf; + sys->ring_areas[idv2] += areaf; + sys->ring_areas[idv3] += areaf; + if (has_4_vert) { + sys->ring_areas[idv4] += areaf; + } + + if (has_4_vert) { + + idv[0] = idv1; + idv[1] = idv2; + idv[2] = idv3; + idv[3] = idv4; + + for (j = 0; j < 4; j++) { + idv1 = idv[j]; + idv2 = idv[(j + 1) % 4]; + idv3 = idv[(j + 2) % 4]; + idv4 = idv[(j + 3) % 4]; + + v1 = vf[j]->co; + v2 = vf[(j + 1) % 4]->co; + v3 = vf[(j + 2) % 4]->co; + v4 = vf[(j + 3) % 4]->co; + + w2 = cotangent_tri_weight_v3(v4, v1, v2) + cotangent_tri_weight_v3(v3, v1, v2); + w3 = cotangent_tri_weight_v3(v2, v3, v1) + cotangent_tri_weight_v3(v4, v1, v3); + w4 = cotangent_tri_weight_v3(v2, v4, v1) + cotangent_tri_weight_v3(v3, v4, v1); + + sys->vweights[idv1] += (w2 + w3 + w4) / 4.0f; + } + } + else { + i = BM_elem_index_get(f); + + w1 = cotangent_tri_weight_v3(v1, v2, v3); + w2 = cotangent_tri_weight_v3(v2, v3, v1); + w3 = cotangent_tri_weight_v3(v3, v1, v2); + + sys->fweights[i][0] += w1; + sys->fweights[i][1] += w2; + sys->fweights[i][2] += w3; + + sys->vweights[idv1] += w2 + w3; + sys->vweights[idv2] += w1 + w3; + sys->vweights[idv3] += w1 + w2; + } + } + } } static void fill_laplacian_matrix(LaplacianSystem *sys) { - float *v1, *v2, *v3, *v4; - float w2, w3, w4; - int i, j; - bool has_4_vert; - uint idv1, idv2, idv3, idv4, idv[4]; - - BMEdge *e; - BMFace *f; - BMIter eiter; - BMIter fiter; - BMIter vi; - BMVert *vn; - BMVert *vf[4]; - - BM_ITER_MESH (f, &fiter, sys->bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - BM_ITER_ELEM_INDEX (vn, &vi, f, BM_VERTS_OF_FACE, i) { - vf[i] = vn; - } - has_4_vert = (i == 4) ? 1 : 0; - if (has_4_vert) { - idv[0] = BM_elem_index_get(vf[0]); - idv[1] = BM_elem_index_get(vf[1]); - idv[2] = BM_elem_index_get(vf[2]); - idv[3] = BM_elem_index_get(vf[3]); - for (j = 0; j < 4; j++) { - idv1 = idv[j]; - idv2 = idv[(j + 1) % 4]; - idv3 = idv[(j + 2) % 4]; - idv4 = idv[(j + 3) % 4]; - - v1 = vf[j]->co; - v2 = vf[(j + 1) % 4]->co; - v3 = vf[(j + 2) % 4]->co; - v4 = vf[(j + 3) % 4]->co; - - w2 = cotangent_tri_weight_v3(v4, v1, v2) + cotangent_tri_weight_v3(v3, v1, v2); - w3 = cotangent_tri_weight_v3(v2, v3, v1) + cotangent_tri_weight_v3(v4, v1, v3); - w4 = cotangent_tri_weight_v3(v2, v4, v1) + cotangent_tri_weight_v3(v3, v4, v1); - - w2 = w2 / 4.0f; - w3 = w3 / 4.0f; - w4 = w4 / 4.0f; - - if (!vert_is_boundary(vf[j]) && sys->zerola[idv1] == 0) { - EIG_linear_solver_matrix_add(sys->context, idv1, idv2, w2 * sys->vweights[idv1]); - EIG_linear_solver_matrix_add(sys->context, idv1, idv3, w3 * sys->vweights[idv1]); - EIG_linear_solver_matrix_add(sys->context, idv1, idv4, w4 * sys->vweights[idv1]); - } - } - } - else { - idv1 = BM_elem_index_get(vf[0]); - idv2 = BM_elem_index_get(vf[1]); - idv3 = BM_elem_index_get(vf[2]); - /* Is ring if number of faces == number of edges around vertice*/ - i = BM_elem_index_get(f); - if (!vert_is_boundary(vf[0]) && sys->zerola[idv1] == 0) { - EIG_linear_solver_matrix_add(sys->context, idv1, idv2, sys->fweights[i][2] * sys->vweights[idv1]); - EIG_linear_solver_matrix_add(sys->context, idv1, idv3, sys->fweights[i][1] * sys->vweights[idv1]); - } - if (!vert_is_boundary(vf[1]) && sys->zerola[idv2] == 0) { - EIG_linear_solver_matrix_add(sys->context, idv2, idv1, sys->fweights[i][2] * sys->vweights[idv2]); - EIG_linear_solver_matrix_add(sys->context, idv2, idv3, sys->fweights[i][0] * sys->vweights[idv2]); - } - if (!vert_is_boundary(vf[2]) && sys->zerola[idv3] == 0) { - EIG_linear_solver_matrix_add(sys->context, idv3, idv1, sys->fweights[i][1] * sys->vweights[idv3]); - EIG_linear_solver_matrix_add(sys->context, idv3, idv2, sys->fweights[i][0] * sys->vweights[idv3]); - } - } - } - } - BM_ITER_MESH (e, &eiter, sys->bm, BM_EDGES_OF_MESH) { - if (!BM_elem_flag_test(e, BM_ELEM_SELECT) && BM_edge_is_boundary(e)) { - v1 = e->v1->co; - v2 = e->v2->co; - idv1 = BM_elem_index_get(e->v1); - idv2 = BM_elem_index_get(e->v2); - if (sys->zerola[idv1] == 0 && sys->zerola[idv2] == 0) { - i = BM_elem_index_get(e); - EIG_linear_solver_matrix_add(sys->context, idv1, idv2, sys->eweights[i] * sys->vlengths[idv1]); - EIG_linear_solver_matrix_add(sys->context, idv2, idv1, sys->eweights[i] * sys->vlengths[idv2]); - } - } - } + float *v1, *v2, *v3, *v4; + float w2, w3, w4; + int i, j; + bool has_4_vert; + uint idv1, idv2, idv3, idv4, idv[4]; + + BMEdge *e; + BMFace *f; + BMIter eiter; + BMIter fiter; + BMIter vi; + BMVert *vn; + BMVert *vf[4]; + + BM_ITER_MESH (f, &fiter, sys->bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + BM_ITER_ELEM_INDEX(vn, &vi, f, BM_VERTS_OF_FACE, i) + { + vf[i] = vn; + } + has_4_vert = (i == 4) ? 1 : 0; + if (has_4_vert) { + idv[0] = BM_elem_index_get(vf[0]); + idv[1] = BM_elem_index_get(vf[1]); + idv[2] = BM_elem_index_get(vf[2]); + idv[3] = BM_elem_index_get(vf[3]); + for (j = 0; j < 4; j++) { + idv1 = idv[j]; + idv2 = idv[(j + 1) % 4]; + idv3 = idv[(j + 2) % 4]; + idv4 = idv[(j + 3) % 4]; + + v1 = vf[j]->co; + v2 = vf[(j + 1) % 4]->co; + v3 = vf[(j + 2) % 4]->co; + v4 = vf[(j + 3) % 4]->co; + + w2 = cotangent_tri_weight_v3(v4, v1, v2) + cotangent_tri_weight_v3(v3, v1, v2); + w3 = cotangent_tri_weight_v3(v2, v3, v1) + cotangent_tri_weight_v3(v4, v1, v3); + w4 = cotangent_tri_weight_v3(v2, v4, v1) + cotangent_tri_weight_v3(v3, v4, v1); + + w2 = w2 / 4.0f; + w3 = w3 / 4.0f; + w4 = w4 / 4.0f; + + if (!vert_is_boundary(vf[j]) && sys->zerola[idv1] == 0) { + EIG_linear_solver_matrix_add(sys->context, idv1, idv2, w2 * sys->vweights[idv1]); + EIG_linear_solver_matrix_add(sys->context, idv1, idv3, w3 * sys->vweights[idv1]); + EIG_linear_solver_matrix_add(sys->context, idv1, idv4, w4 * sys->vweights[idv1]); + } + } + } + else { + idv1 = BM_elem_index_get(vf[0]); + idv2 = BM_elem_index_get(vf[1]); + idv3 = BM_elem_index_get(vf[2]); + /* Is ring if number of faces == number of edges around vertice*/ + i = BM_elem_index_get(f); + if (!vert_is_boundary(vf[0]) && sys->zerola[idv1] == 0) { + EIG_linear_solver_matrix_add( + sys->context, idv1, idv2, sys->fweights[i][2] * sys->vweights[idv1]); + EIG_linear_solver_matrix_add( + sys->context, idv1, idv3, sys->fweights[i][1] * sys->vweights[idv1]); + } + if (!vert_is_boundary(vf[1]) && sys->zerola[idv2] == 0) { + EIG_linear_solver_matrix_add( + sys->context, idv2, idv1, sys->fweights[i][2] * sys->vweights[idv2]); + EIG_linear_solver_matrix_add( + sys->context, idv2, idv3, sys->fweights[i][0] * sys->vweights[idv2]); + } + if (!vert_is_boundary(vf[2]) && sys->zerola[idv3] == 0) { + EIG_linear_solver_matrix_add( + sys->context, idv3, idv1, sys->fweights[i][1] * sys->vweights[idv3]); + EIG_linear_solver_matrix_add( + sys->context, idv3, idv2, sys->fweights[i][0] * sys->vweights[idv3]); + } + } + } + } + BM_ITER_MESH (e, &eiter, sys->bm, BM_EDGES_OF_MESH) { + if (!BM_elem_flag_test(e, BM_ELEM_SELECT) && BM_edge_is_boundary(e)) { + v1 = e->v1->co; + v2 = e->v2->co; + idv1 = BM_elem_index_get(e->v1); + idv2 = BM_elem_index_get(e->v2); + if (sys->zerola[idv1] == 0 && sys->zerola[idv2] == 0) { + i = BM_elem_index_get(e); + EIG_linear_solver_matrix_add( + sys->context, idv1, idv2, sys->eweights[i] * sys->vlengths[idv1]); + EIG_linear_solver_matrix_add( + sys->context, idv2, idv1, sys->eweights[i] * sys->vlengths[idv2]); + } + } + } } static bool vert_is_boundary(BMVert *v) { - BMEdge *ed; - BMFace *f; - BMIter ei; - BMIter fi; - BM_ITER_ELEM (ed, &ei, v, BM_EDGES_OF_VERT) { - if (BM_edge_is_boundary(ed)) { - return 1; - } - } - BM_ITER_ELEM (f, &fi, v, BM_FACES_OF_VERT) { - if (!BM_elem_flag_test(f, BM_ELEM_SELECT)) { - return 1; - } - } - return 0; + BMEdge *ed; + BMFace *f; + BMIter ei; + BMIter fi; + BM_ITER_ELEM (ed, &ei, v, BM_EDGES_OF_VERT) { + if (BM_edge_is_boundary(ed)) { + return 1; + } + } + BM_ITER_ELEM (f, &fi, v, BM_FACES_OF_VERT) { + if (!BM_elem_flag_test(f, BM_ELEM_SELECT)) { + return 1; + } + } + return 0; } -static void volume_preservation(BMOperator *op, float vini, float vend, int usex, int usey, int usez) +static void volume_preservation( + BMOperator *op, float vini, float vend, int usex, int usey, int usez) { - float beta; - BMOIter siter; - BMVert *v; - - if (vend != 0.0f) { - beta = pow(vini / vend, 1.0f / 3.0f); - BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) { - if (usex) { - v->co[0] *= beta; - } - if (usey) { - v->co[1] *= beta; - } - if (usez) { - v->co[2] *= beta; - } - - } - } + float beta; + BMOIter siter; + BMVert *v; + + if (vend != 0.0f) { + beta = pow(vini / vend, 1.0f / 3.0f); + BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) { + if (usex) { + v->co[0] *= beta; + } + if (usey) { + v->co[1] *= beta; + } + if (usez) { + v->co[2] *= beta; + } + } + } } -static void validate_solution(LaplacianSystem *sys, int usex, int usey, int usez, int preserve_volume) +static void validate_solution( + LaplacianSystem *sys, int usex, int usey, int usez, int preserve_volume) { - int m_vertex_id; - float leni, lene; - float vini, vend; - float *vi1, *vi2, ve1[3], ve2[3]; - uint idv1, idv2; - BMOIter siter; - BMVert *v; - BMEdge *e; - BMIter eiter; - - BM_ITER_MESH (e, &eiter, sys->bm, BM_EDGES_OF_MESH) { - idv1 = BM_elem_index_get(e->v1); - idv2 = BM_elem_index_get(e->v2); - vi1 = e->v1->co; - vi2 = e->v2->co; - ve1[0] = EIG_linear_solver_variable_get(sys->context, 0, idv1); - ve1[1] = EIG_linear_solver_variable_get(sys->context, 1, idv1); - ve1[2] = EIG_linear_solver_variable_get(sys->context, 2, idv1); - ve2[0] = EIG_linear_solver_variable_get(sys->context, 0, idv2); - ve2[1] = EIG_linear_solver_variable_get(sys->context, 1, idv2); - ve2[2] = EIG_linear_solver_variable_get(sys->context, 2, idv2); - leni = len_v3v3(vi1, vi2); - lene = len_v3v3(ve1, ve2); - if (lene > leni * SMOOTH_LAPLACIAN_MAX_EDGE_PERCENTAGE || lene < leni * SMOOTH_LAPLACIAN_MIN_EDGE_PERCENTAGE) { - sys->zerola[idv1] = 1; - sys->zerola[idv2] = 1; - } - } - - if (preserve_volume) { - vini = BM_mesh_calc_volume(sys->bm, false); - } - BMO_ITER (v, &siter, sys->op->slots_in, "verts", BM_VERT) { - m_vertex_id = BM_elem_index_get(v); - if (sys->zerola[m_vertex_id] == 0) { - if (usex) { - v->co[0] = EIG_linear_solver_variable_get(sys->context, 0, m_vertex_id); - } - if (usey) { - v->co[1] = EIG_linear_solver_variable_get(sys->context, 1, m_vertex_id); - } - if (usez) { - v->co[2] = EIG_linear_solver_variable_get(sys->context, 2, m_vertex_id); - } - } - } - if (preserve_volume) { - vend = BM_mesh_calc_volume(sys->bm, false); - volume_preservation(sys->op, vini, vend, usex, usey, usez); - } - + int m_vertex_id; + float leni, lene; + float vini, vend; + float *vi1, *vi2, ve1[3], ve2[3]; + uint idv1, idv2; + BMOIter siter; + BMVert *v; + BMEdge *e; + BMIter eiter; + + BM_ITER_MESH (e, &eiter, sys->bm, BM_EDGES_OF_MESH) { + idv1 = BM_elem_index_get(e->v1); + idv2 = BM_elem_index_get(e->v2); + vi1 = e->v1->co; + vi2 = e->v2->co; + ve1[0] = EIG_linear_solver_variable_get(sys->context, 0, idv1); + ve1[1] = EIG_linear_solver_variable_get(sys->context, 1, idv1); + ve1[2] = EIG_linear_solver_variable_get(sys->context, 2, idv1); + ve2[0] = EIG_linear_solver_variable_get(sys->context, 0, idv2); + ve2[1] = EIG_linear_solver_variable_get(sys->context, 1, idv2); + ve2[2] = EIG_linear_solver_variable_get(sys->context, 2, idv2); + leni = len_v3v3(vi1, vi2); + lene = len_v3v3(ve1, ve2); + if (lene > leni * SMOOTH_LAPLACIAN_MAX_EDGE_PERCENTAGE || + lene < leni * SMOOTH_LAPLACIAN_MIN_EDGE_PERCENTAGE) { + sys->zerola[idv1] = 1; + sys->zerola[idv2] = 1; + } + } + + if (preserve_volume) { + vini = BM_mesh_calc_volume(sys->bm, false); + } + BMO_ITER (v, &siter, sys->op->slots_in, "verts", BM_VERT) { + m_vertex_id = BM_elem_index_get(v); + if (sys->zerola[m_vertex_id] == 0) { + if (usex) { + v->co[0] = EIG_linear_solver_variable_get(sys->context, 0, m_vertex_id); + } + if (usey) { + v->co[1] = EIG_linear_solver_variable_get(sys->context, 1, m_vertex_id); + } + if (usez) { + v->co[2] = EIG_linear_solver_variable_get(sys->context, 2, m_vertex_id); + } + } + } + if (preserve_volume) { + vend = BM_mesh_calc_volume(sys->bm, false); + volume_preservation(sys->op, vini, vend, usex, usey, usez); + } } void bmo_smooth_laplacian_vert_exec(BMesh *bm, BMOperator *op) { - int i; - int m_vertex_id; - bool usex, usey, usez, preserve_volume; - float lambda_factor, lambda_border; - float w; - BMOIter siter; - BMVert *v; - LaplacianSystem *sys; - - if (bm->totface == 0) { - return; - } - sys = init_laplacian_system(bm->totedge, bm->totface, bm->totvert); - if (!sys) { - return; - } - sys->bm = bm; - sys->op = op; - - memset_laplacian_system(sys, 0); - - BM_mesh_elem_index_ensure(bm, BM_VERT); - lambda_factor = BMO_slot_float_get(op->slots_in, "lambda_factor"); - lambda_border = BMO_slot_float_get(op->slots_in, "lambda_border"); - sys->min_area = 0.00001f; - usex = BMO_slot_bool_get(op->slots_in, "use_x"); - usey = BMO_slot_bool_get(op->slots_in, "use_y"); - usez = BMO_slot_bool_get(op->slots_in, "use_z"); - preserve_volume = BMO_slot_bool_get(op->slots_in, "preserve_volume"); - - - sys->context = EIG_linear_least_squares_solver_new(bm->totvert, bm->totvert, 3); - - for (i = 0; i < bm->totvert; i++) { - EIG_linear_solver_variable_lock(sys->context, i); - } - BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) { - m_vertex_id = BM_elem_index_get(v); - EIG_linear_solver_variable_unlock(sys->context, m_vertex_id); - EIG_linear_solver_variable_set(sys->context, 0, m_vertex_id, v->co[0]); - EIG_linear_solver_variable_set(sys->context, 1, m_vertex_id, v->co[1]); - EIG_linear_solver_variable_set(sys->context, 2, m_vertex_id, v->co[2]); - } - - init_laplacian_matrix(sys); - BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) { - m_vertex_id = BM_elem_index_get(v); - EIG_linear_solver_right_hand_side_add(sys->context, 0, m_vertex_id, v->co[0]); - EIG_linear_solver_right_hand_side_add(sys->context, 1, m_vertex_id, v->co[1]); - EIG_linear_solver_right_hand_side_add(sys->context, 2, m_vertex_id, v->co[2]); - i = m_vertex_id; - if (sys->zerola[i] == 0) { - w = sys->vweights[i] * sys->ring_areas[i]; - sys->vweights[i] = (w == 0.0f) ? 0.0f : -lambda_factor / (4.0f * w); - w = sys->vlengths[i]; - sys->vlengths[i] = (w == 0.0f) ? 0.0f : -lambda_border * 2.0f / w; - - if (!vert_is_boundary(v)) { - EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + lambda_factor / (4.0f * sys->ring_areas[i])); - } - else { - EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + lambda_border * 2.0f); - } - } - else { - EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f); - } - } - fill_laplacian_matrix(sys); - - if (EIG_linear_solver_solve(sys->context) ) { - validate_solution(sys, usex, usey, usez, preserve_volume); - } - - delete_laplacian_system(sys); + int i; + int m_vertex_id; + bool usex, usey, usez, preserve_volume; + float lambda_factor, lambda_border; + float w; + BMOIter siter; + BMVert *v; + LaplacianSystem *sys; + + if (bm->totface == 0) { + return; + } + sys = init_laplacian_system(bm->totedge, bm->totface, bm->totvert); + if (!sys) { + return; + } + sys->bm = bm; + sys->op = op; + + memset_laplacian_system(sys, 0); + + BM_mesh_elem_index_ensure(bm, BM_VERT); + lambda_factor = BMO_slot_float_get(op->slots_in, "lambda_factor"); + lambda_border = BMO_slot_float_get(op->slots_in, "lambda_border"); + sys->min_area = 0.00001f; + usex = BMO_slot_bool_get(op->slots_in, "use_x"); + usey = BMO_slot_bool_get(op->slots_in, "use_y"); + usez = BMO_slot_bool_get(op->slots_in, "use_z"); + preserve_volume = BMO_slot_bool_get(op->slots_in, "preserve_volume"); + + sys->context = EIG_linear_least_squares_solver_new(bm->totvert, bm->totvert, 3); + + for (i = 0; i < bm->totvert; i++) { + EIG_linear_solver_variable_lock(sys->context, i); + } + BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) { + m_vertex_id = BM_elem_index_get(v); + EIG_linear_solver_variable_unlock(sys->context, m_vertex_id); + EIG_linear_solver_variable_set(sys->context, 0, m_vertex_id, v->co[0]); + EIG_linear_solver_variable_set(sys->context, 1, m_vertex_id, v->co[1]); + EIG_linear_solver_variable_set(sys->context, 2, m_vertex_id, v->co[2]); + } + + init_laplacian_matrix(sys); + BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) { + m_vertex_id = BM_elem_index_get(v); + EIG_linear_solver_right_hand_side_add(sys->context, 0, m_vertex_id, v->co[0]); + EIG_linear_solver_right_hand_side_add(sys->context, 1, m_vertex_id, v->co[1]); + EIG_linear_solver_right_hand_side_add(sys->context, 2, m_vertex_id, v->co[2]); + i = m_vertex_id; + if (sys->zerola[i] == 0) { + w = sys->vweights[i] * sys->ring_areas[i]; + sys->vweights[i] = (w == 0.0f) ? 0.0f : -lambda_factor / (4.0f * w); + w = sys->vlengths[i]; + sys->vlengths[i] = (w == 0.0f) ? 0.0f : -lambda_border * 2.0f / w; + + if (!vert_is_boundary(v)) { + EIG_linear_solver_matrix_add( + sys->context, i, i, 1.0f + lambda_factor / (4.0f * sys->ring_areas[i])); + } + else { + EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + lambda_border * 2.0f); + } + } + else { + EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f); + } + } + fill_laplacian_matrix(sys); + + if (EIG_linear_solver_solve(sys->context)) { + validate_solution(sys, usex, usey, usez, preserve_volume); + } + + delete_laplacian_system(sys); } diff --git a/source/blender/bmesh/operators/bmo_split_edges.c b/source/blender/bmesh/operators/bmo_split_edges.c index e0728c6539b..d030a6e11b0 100644 --- a/source/blender/bmesh/operators/bmo_split_edges.c +++ b/source/blender/bmesh/operators/bmo_split_edges.c @@ -27,22 +27,21 @@ #include "intern/bmesh_operators_private.h" /* own include */ - /* keep this operator fast, its used in a modifier */ void bmo_split_edges_exec(BMesh *bm, BMOperator *op) { - const bool use_verts = BMO_slot_bool_get(op->slots_in, "use_verts"); + const bool use_verts = BMO_slot_bool_get(op->slots_in, "use_verts"); - BM_mesh_elem_hflag_disable_all(bm, BM_EDGE, BM_ELEM_TAG, false); - BMO_slot_buffer_hflag_enable(bm, op->slots_in, "edges", BM_EDGE, BM_ELEM_TAG, false); + BM_mesh_elem_hflag_disable_all(bm, BM_EDGE, BM_ELEM_TAG, false); + BMO_slot_buffer_hflag_enable(bm, op->slots_in, "edges", BM_EDGE, BM_ELEM_TAG, false); - if (use_verts) { - /* this slows down the operation but its ok because the modifier doesn't use */ - BMO_slot_buffer_hflag_enable(bm, op->slots_in, "verts", BM_VERT, BM_ELEM_TAG, false); - } + if (use_verts) { + /* this slows down the operation but its ok because the modifier doesn't use */ + BMO_slot_buffer_hflag_enable(bm, op->slots_in, "verts", BM_VERT, BM_ELEM_TAG, false); + } - /* this is where everything happens */ - BM_mesh_edgesplit(bm, use_verts, true, false); + /* this is where everything happens */ + BM_mesh_edgesplit(bm, use_verts, true, false); - BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "edges.out", BM_EDGE, BM_ELEM_TAG); + BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "edges.out", BM_EDGE, BM_ELEM_TAG); } diff --git a/source/blender/bmesh/operators/bmo_subdivide.c b/source/blender/bmesh/operators/bmo_subdivide.c index 6b7f81aabb6..869c61832f9 100644 --- a/source/blender/bmesh/operators/bmo_subdivide.c +++ b/source/blender/bmesh/operators/bmo_subdivide.c @@ -30,53 +30,53 @@ #include "BKE_customdata.h" - #include "bmesh.h" #include "intern/bmesh_private.h" #include "intern/bmesh_operators_private.h" typedef struct SubDParams { - int numcuts; - float smooth; - int smooth_falloff; - float fractal; - float along_normal; - //int beauty; - bool use_smooth; - bool use_smooth_even; - bool use_sphere; - bool use_fractal; - int seed; - BMOperator *op; - BMOpSlot *slot_edge_percents; /* BMO_slot_get(params->op->slots_in, "edge_percents"); */ - BMOpSlot *slot_custom_patterns; /* BMO_slot_get(params->op->slots_in, "custom_patterns"); */ - float fractal_ofs[3]; - - /* rumtime storage for shape key */ - struct { - int cd_vert_shape_offset; - int cd_vert_shape_offset_tmp; - int totlayer; - - /* shapekey holding displaced vertex coordinates for current geometry */ - int tmpkey; - } shape_info; + int numcuts; + float smooth; + int smooth_falloff; + float fractal; + float along_normal; + //int beauty; + bool use_smooth; + bool use_smooth_even; + bool use_sphere; + bool use_fractal; + int seed; + BMOperator *op; + BMOpSlot *slot_edge_percents; /* BMO_slot_get(params->op->slots_in, "edge_percents"); */ + BMOpSlot *slot_custom_patterns; /* BMO_slot_get(params->op->slots_in, "custom_patterns"); */ + float fractal_ofs[3]; + + /* rumtime storage for shape key */ + struct { + int cd_vert_shape_offset; + int cd_vert_shape_offset_tmp; + int totlayer; + + /* shapekey holding displaced vertex coordinates for current geometry */ + int tmpkey; + } shape_info; } SubDParams; static void bmo_subd_init_shape_info(BMesh *bm, SubDParams *params) { - const int skey = CustomData_number_of_layers(&bm->vdata, CD_SHAPEKEY) - 1; - params->shape_info.tmpkey = skey; - params->shape_info.cd_vert_shape_offset = CustomData_get_offset(&bm->vdata, CD_SHAPEKEY); - params->shape_info.cd_vert_shape_offset_tmp = CustomData_get_n_offset(&bm->vdata, CD_SHAPEKEY, skey); - params->shape_info.totlayer = CustomData_number_of_layers(&bm->vdata, CD_SHAPEKEY); - + const int skey = CustomData_number_of_layers(&bm->vdata, CD_SHAPEKEY) - 1; + params->shape_info.tmpkey = skey; + params->shape_info.cd_vert_shape_offset = CustomData_get_offset(&bm->vdata, CD_SHAPEKEY); + params->shape_info.cd_vert_shape_offset_tmp = CustomData_get_n_offset( + &bm->vdata, CD_SHAPEKEY, skey); + params->shape_info.totlayer = CustomData_number_of_layers(&bm->vdata, CD_SHAPEKEY); } -typedef void (*subd_pattern_fill_fp)( - BMesh *bm, BMFace *face, BMVert **verts, - const SubDParams *params); +typedef void (*subd_pattern_fill_fp)(BMesh *bm, + BMFace *face, + BMVert **verts, + const SubDParams *params); /* * note: this is a pattern-based edge subdivider. @@ -84,11 +84,11 @@ typedef void (*subd_pattern_fill_fp)( * then executes functions to cut them. */ typedef struct SubDPattern { - int seledges[20]; /* selected edges mask, for splitting */ + int seledges[20]; /* selected edges mask, for splitting */ - /* verts starts at the first new vert cut, not the first vert in the face */ - subd_pattern_fill_fp connectexec; - int len; /* total number of verts, before any subdivision */ + /* verts starts at the first new vert cut, not the first vert in the face */ + subd_pattern_fill_fp connectexec; + int len; /* total number of verts, before any subdivision */ } SubDPattern; /* generic subdivision rules: @@ -101,15 +101,15 @@ typedef struct SubDPattern { */ /* flags for all elements share a common bitfield space */ -#define SUBD_SPLIT 1 +#define SUBD_SPLIT 1 -#define EDGE_PERCENT 2 +#define EDGE_PERCENT 2 /* I don't think new faces are flagged, currently, but * better safe than sorry. */ -#define FACE_CUSTOMFILL 4 -#define ELE_INNER 8 -#define ELE_SPLIT 16 +#define FACE_CUSTOMFILL 4 +#define ELE_INNER 8 +#define ELE_SPLIT 16 /* see bug [#32665], 0.00005 means a we get face splits at a little under 1.0 degrees */ #define FLT_FACE_SPLIT_EPSILON 0.00005f @@ -131,335 +131,342 @@ typedef struct SubDPattern { * edge subdivision */ static BMEdge *connect_smallest_face(BMesh *bm, BMVert *v_a, BMVert *v_b, BMFace **r_f_new) { - BMLoop *l_a, *l_b; - BMFace *f; - - /* this isn't the best thing in the world. it doesn't handle cases where there's - * multiple faces yet. that might require a convexity test to figure out which - * face is "best" and who knows what for non-manifold conditions. - * - * note: we allow adjacent here, since theres no chance this happens. - */ - f = BM_vert_pair_share_face_by_len(v_a, v_b, &l_a, &l_b, true); + BMLoop *l_a, *l_b; + BMFace *f; + /* this isn't the best thing in the world. it doesn't handle cases where there's + * multiple faces yet. that might require a convexity test to figure out which + * face is "best" and who knows what for non-manifold conditions. + * + * note: we allow adjacent here, since theres no chance this happens. + */ + f = BM_vert_pair_share_face_by_len(v_a, v_b, &l_a, &l_b, true); - if (f) { - BMFace *f_new; - BMLoop *l_new; + if (f) { + BMFace *f_new; + BMLoop *l_new; - BLI_assert(!BM_loop_is_adjacent(l_a, l_b)); + BLI_assert(!BM_loop_is_adjacent(l_a, l_b)); - f_new = BM_face_split(bm, f, l_a, l_b, &l_new, NULL, false); + f_new = BM_face_split(bm, f, l_a, l_b, &l_new, NULL, false); - if (r_f_new) { - *r_f_new = f_new; - } - return l_new ? l_new->e : NULL; - } + if (r_f_new) { + *r_f_new = f_new; + } + return l_new ? l_new->e : NULL; + } - return NULL; + return NULL; } /** * Specialized slerp that uses a sphere defined by each points normal. */ static void interp_slerp_co_no_v3( - const float co_a[3], const float no_a[3], - const float co_b[3], const float no_b[3], - const float no_dir[3], /* caller already knows, avoid normalize */ - float fac, - float r_co[3]) + const float co_a[3], + const float no_a[3], + const float co_b[3], + const float no_b[3], + const float no_dir[3], /* caller already knows, avoid normalize */ + float fac, + float r_co[3]) { - /* center of the sphere defined by both normals */ - float center[3]; + /* center of the sphere defined by both normals */ + float center[3]; - BLI_assert(len_squared_v3v3(no_a, no_b) != 0); + BLI_assert(len_squared_v3v3(no_a, no_b) != 0); - /* calculate sphere 'center' */ - { - /* use point on plane to */ - float no_mid[3], no_ortho[3]; - /* pass this as an arg instead */ + /* calculate sphere 'center' */ + { + /* use point on plane to */ + float no_mid[3], no_ortho[3]; + /* pass this as an arg instead */ #if 0 - float no_dir[3]; + float no_dir[3]; #endif - add_v3_v3v3(no_mid, no_a, no_b); - normalize_v3(no_mid); + add_v3_v3v3(no_mid, no_a, no_b); + normalize_v3(no_mid); #if 0 - sub_v3_v3v3(no_dir, co_a, co_b); - normalize_v3(no_dir); + sub_v3_v3v3(no_dir, co_a, co_b); + normalize_v3(no_dir); #endif - /* axis of slerp */ - bool center_ok = false; - cross_v3_v3v3(no_ortho, no_mid, no_dir); - if (normalize_v3(no_ortho) != 0.0f) { - float plane_a[4], plane_b[4], plane_c[4]; - float v_a_no_ortho[3], v_b_no_ortho[3]; - - /* create planes */ - cross_v3_v3v3(v_a_no_ortho, no_ortho, no_a); - cross_v3_v3v3(v_b_no_ortho, no_ortho, no_b); - project_v3_plane(v_a_no_ortho, no_ortho, v_a_no_ortho); - project_v3_plane(v_b_no_ortho, no_ortho, v_b_no_ortho); - - plane_from_point_normal_v3(plane_a, co_a, v_a_no_ortho); - plane_from_point_normal_v3(plane_b, co_b, v_b_no_ortho); - plane_from_point_normal_v3(plane_c, co_b, no_ortho); - - /* find the sphere center from 3 planes */ - if (isect_plane_plane_plane_v3(plane_a, plane_b, plane_c, center)) { - center_ok = true; - } - } - if (center_ok == false) { - mid_v3_v3v3(center, co_a, co_b); - } - } - - /* calculate the final output 'r_co' */ - { - float ofs_a[3], ofs_b[3], ofs_slerp[3]; - float dist_a, dist_b; - - sub_v3_v3v3(ofs_a, co_a, center); - sub_v3_v3v3(ofs_b, co_b, center); - - dist_a = normalize_v3(ofs_a); - dist_b = normalize_v3(ofs_b); - - if (interp_v3_v3v3_slerp(ofs_slerp, ofs_a, ofs_b, fac)) { - madd_v3_v3v3fl(r_co, center, ofs_slerp, interpf(dist_b, dist_a, fac)); - } - else { - interp_v3_v3v3(r_co, co_a, co_b, fac); - } - } + /* axis of slerp */ + bool center_ok = false; + cross_v3_v3v3(no_ortho, no_mid, no_dir); + if (normalize_v3(no_ortho) != 0.0f) { + float plane_a[4], plane_b[4], plane_c[4]; + float v_a_no_ortho[3], v_b_no_ortho[3]; + + /* create planes */ + cross_v3_v3v3(v_a_no_ortho, no_ortho, no_a); + cross_v3_v3v3(v_b_no_ortho, no_ortho, no_b); + project_v3_plane(v_a_no_ortho, no_ortho, v_a_no_ortho); + project_v3_plane(v_b_no_ortho, no_ortho, v_b_no_ortho); + + plane_from_point_normal_v3(plane_a, co_a, v_a_no_ortho); + plane_from_point_normal_v3(plane_b, co_b, v_b_no_ortho); + plane_from_point_normal_v3(plane_c, co_b, no_ortho); + + /* find the sphere center from 3 planes */ + if (isect_plane_plane_plane_v3(plane_a, plane_b, plane_c, center)) { + center_ok = true; + } + } + if (center_ok == false) { + mid_v3_v3v3(center, co_a, co_b); + } + } + + /* calculate the final output 'r_co' */ + { + float ofs_a[3], ofs_b[3], ofs_slerp[3]; + float dist_a, dist_b; + + sub_v3_v3v3(ofs_a, co_a, center); + sub_v3_v3v3(ofs_b, co_b, center); + + dist_a = normalize_v3(ofs_a); + dist_b = normalize_v3(ofs_b); + + if (interp_v3_v3v3_slerp(ofs_slerp, ofs_a, ofs_b, fac)) { + madd_v3_v3v3fl(r_co, center, ofs_slerp, interpf(dist_b, dist_a, fac)); + } + else { + interp_v3_v3v3(r_co, co_a, co_b, fac); + } + } } /* calculates offset for co, based on fractal, sphere or smooth settings */ -static void alter_co( - BMVert *v, BMEdge *UNUSED(e_orig), - const SubDParams *params, const float perc, - const BMVert *v_a, const BMVert *v_b) +static void alter_co(BMVert *v, + BMEdge *UNUSED(e_orig), + const SubDParams *params, + const float perc, + const BMVert *v_a, + const BMVert *v_b) { - float *co = BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset_tmp); - int i; + float *co = BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset_tmp); + int i; - copy_v3_v3(co, v->co); + copy_v3_v3(co, v->co); - if (UNLIKELY(params->use_sphere)) { /* subdivide sphere */ - normalize_v3_length(co, params->smooth); - } - else if (params->use_smooth) { - /* calculating twice and blending gives smoother results, - * removing visible seams. */ + if (UNLIKELY(params->use_sphere)) { /* subdivide sphere */ + normalize_v3_length(co, params->smooth); + } + else if (params->use_smooth) { + /* calculating twice and blending gives smoother results, + * removing visible seams. */ #define USE_SPHERE_DUAL_BLEND - const float eps_unit_vec = 1e-5f; - float smooth; - float no_dir[3]; + const float eps_unit_vec = 1e-5f; + float smooth; + float no_dir[3]; #ifdef USE_SPHERE_DUAL_BLEND - float no_reflect[3], co_a[3], co_b[3]; + float no_reflect[3], co_a[3], co_b[3]; #endif - sub_v3_v3v3(no_dir, v_a->co, v_b->co); - normalize_v3(no_dir); + sub_v3_v3v3(no_dir, v_a->co, v_b->co); + normalize_v3(no_dir); #ifndef USE_SPHERE_DUAL_BLEND - if (len_squared_v3v3(v_a->no, v_b->no) < eps_unit_vec) { - interp_v3_v3v3(co, v_a->co, v_b->co, perc); - } - else { - interp_slerp_co_no_v3(v_a->co, v_a->no, v_b->co, v_b->no, no_dir, perc, co); - } + if (len_squared_v3v3(v_a->no, v_b->no) < eps_unit_vec) { + interp_v3_v3v3(co, v_a->co, v_b->co, perc); + } + else { + interp_slerp_co_no_v3(v_a->co, v_a->no, v_b->co, v_b->no, no_dir, perc, co); + } #else - /* sphere-a */ - reflect_v3_v3v3(no_reflect, v_a->no, no_dir); - if (len_squared_v3v3(v_a->no, no_reflect) < eps_unit_vec) { - interp_v3_v3v3(co_a, v_a->co, v_b->co, perc); - } - else { - interp_slerp_co_no_v3(v_a->co, v_a->no, v_b->co, no_reflect, no_dir, perc, co_a); - } - - /* sphere-b */ - reflect_v3_v3v3(no_reflect, v_b->no, no_dir); - if (len_squared_v3v3(v_b->no, no_reflect) < eps_unit_vec) { - interp_v3_v3v3(co_b, v_a->co, v_b->co, perc); - } - else { - interp_slerp_co_no_v3(v_a->co, no_reflect, v_b->co, v_b->no, no_dir, perc, co_b); - } - - /* blend both spheres */ - interp_v3_v3v3(co, co_a, co_b, perc); -#endif /* USE_SPHERE_DUAL_BLEND */ - - /* apply falloff */ - if (params->smooth_falloff == SUBD_FALLOFF_LIN) { - smooth = 1.0f; - } - else { - smooth = fabsf(1.0f - 2.0f * fabsf(0.5f - perc)); - smooth = 1.0f + bmesh_subd_falloff_calc(params->smooth_falloff, smooth); - } - - if (params->use_smooth_even) { - smooth *= shell_v3v3_mid_normalized_to_dist(v_a->no, v_b->no); - } - - smooth *= params->smooth; - if (smooth != 1.0f) { - float co_flat[3]; - interp_v3_v3v3(co_flat, v_a->co, v_b->co, perc); - interp_v3_v3v3(co, co_flat, co, smooth); - } + /* sphere-a */ + reflect_v3_v3v3(no_reflect, v_a->no, no_dir); + if (len_squared_v3v3(v_a->no, no_reflect) < eps_unit_vec) { + interp_v3_v3v3(co_a, v_a->co, v_b->co, perc); + } + else { + interp_slerp_co_no_v3(v_a->co, v_a->no, v_b->co, no_reflect, no_dir, perc, co_a); + } + + /* sphere-b */ + reflect_v3_v3v3(no_reflect, v_b->no, no_dir); + if (len_squared_v3v3(v_b->no, no_reflect) < eps_unit_vec) { + interp_v3_v3v3(co_b, v_a->co, v_b->co, perc); + } + else { + interp_slerp_co_no_v3(v_a->co, no_reflect, v_b->co, v_b->no, no_dir, perc, co_b); + } + + /* blend both spheres */ + interp_v3_v3v3(co, co_a, co_b, perc); +#endif /* USE_SPHERE_DUAL_BLEND */ + + /* apply falloff */ + if (params->smooth_falloff == SUBD_FALLOFF_LIN) { + smooth = 1.0f; + } + else { + smooth = fabsf(1.0f - 2.0f * fabsf(0.5f - perc)); + smooth = 1.0f + bmesh_subd_falloff_calc(params->smooth_falloff, smooth); + } + + if (params->use_smooth_even) { + smooth *= shell_v3v3_mid_normalized_to_dist(v_a->no, v_b->no); + } + + smooth *= params->smooth; + if (smooth != 1.0f) { + float co_flat[3]; + interp_v3_v3v3(co_flat, v_a->co, v_b->co, perc); + interp_v3_v3v3(co, co_flat, co, smooth); + } #undef USE_SPHERE_DUAL_BLEND - } - - if (params->use_fractal) { - float normal[3], co2[3], base1[3], base2[3], tvec[3]; - const float len = len_v3v3(v_a->co, v_b->co); - float fac; - - fac = params->fractal * len; - - mid_v3_v3v3(normal, v_a->no, v_b->no); - ortho_basis_v3v3_v3(base1, base2, normal); - - add_v3_v3v3(co2, v->co, params->fractal_ofs); - mul_v3_fl(co2, 10.0f); - - tvec[0] = fac * (BLI_gTurbulence(1.0, co2[0], co2[1], co2[2], 15, 0, 2) - 0.5f); - tvec[1] = fac * (BLI_gTurbulence(1.0, co2[1], co2[0], co2[2], 15, 0, 2) - 0.5f); - tvec[2] = fac * (BLI_gTurbulence(1.0, co2[1], co2[2], co2[0], 15, 0, 2) - 0.5f); - - /* add displacement */ - madd_v3_v3fl(co, normal, tvec[0]); - madd_v3_v3fl(co, base1, tvec[1] * (1.0f - params->along_normal)); - madd_v3_v3fl(co, base2, tvec[2] * (1.0f - params->along_normal)); - } - - /* apply the new difference to the rest of the shape keys, - * note that this doesn't take rotations into account, we _could_ support - * this by getting the normals and coords for each shape key and - * re-calculate the smooth value for each but this is quite involved. - * for now its ok to simply apply the difference IMHO - campbell */ - - if (params->shape_info.totlayer > 1) { - float tvec[3]; - - sub_v3_v3v3(tvec, v->co, co); - - /* skip the last layer since its the temp */ - i = params->shape_info.totlayer - 1; - co = BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset); - while (i--) { - BLI_assert(co != BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset_tmp)); - sub_v3_v3(co += 3, tvec); - } - } + } + + if (params->use_fractal) { + float normal[3], co2[3], base1[3], base2[3], tvec[3]; + const float len = len_v3v3(v_a->co, v_b->co); + float fac; + + fac = params->fractal * len; + + mid_v3_v3v3(normal, v_a->no, v_b->no); + ortho_basis_v3v3_v3(base1, base2, normal); + + add_v3_v3v3(co2, v->co, params->fractal_ofs); + mul_v3_fl(co2, 10.0f); + + tvec[0] = fac * (BLI_gTurbulence(1.0, co2[0], co2[1], co2[2], 15, 0, 2) - 0.5f); + tvec[1] = fac * (BLI_gTurbulence(1.0, co2[1], co2[0], co2[2], 15, 0, 2) - 0.5f); + tvec[2] = fac * (BLI_gTurbulence(1.0, co2[1], co2[2], co2[0], 15, 0, 2) - 0.5f); + + /* add displacement */ + madd_v3_v3fl(co, normal, tvec[0]); + madd_v3_v3fl(co, base1, tvec[1] * (1.0f - params->along_normal)); + madd_v3_v3fl(co, base2, tvec[2] * (1.0f - params->along_normal)); + } + + /* apply the new difference to the rest of the shape keys, + * note that this doesn't take rotations into account, we _could_ support + * this by getting the normals and coords for each shape key and + * re-calculate the smooth value for each but this is quite involved. + * for now its ok to simply apply the difference IMHO - campbell */ + + if (params->shape_info.totlayer > 1) { + float tvec[3]; + + sub_v3_v3v3(tvec, v->co, co); + + /* skip the last layer since its the temp */ + i = params->shape_info.totlayer - 1; + co = BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset); + while (i--) { + BLI_assert(co != BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset_tmp)); + sub_v3_v3(co += 3, tvec); + } + } } /* assumes in the edge is the correct interpolated vertices already */ /* percent defines the interpolation, rad and flag are for special options */ /* results in new vertex with correct coordinate, vertex normal and weight group info */ -static BMVert *bm_subdivide_edge_addvert( - BMesh *bm, BMEdge *edge, BMEdge *e_orig, - const SubDParams *params, - const float factor_edge_split, const float factor_subd, - BMVert *v_a, BMVert *v_b, - BMEdge **r_edge) +static BMVert *bm_subdivide_edge_addvert(BMesh *bm, + BMEdge *edge, + BMEdge *e_orig, + const SubDParams *params, + const float factor_edge_split, + const float factor_subd, + BMVert *v_a, + BMVert *v_b, + BMEdge **r_edge) { - BMVert *v_new; - - v_new = BM_edge_split(bm, edge, edge->v1, r_edge, factor_edge_split); - - BMO_vert_flag_enable(bm, v_new, ELE_INNER); - - /* offset for smooth or sphere or fractal */ - alter_co(v_new, e_orig, params, factor_subd, v_a, v_b); - -#if 0 //BMESH_TODO - /* clip if needed by mirror modifier */ - if (edge->v1->f2) { - if (edge->v1->f2 & edge->v2->f2 & 1) { - co[0] = 0.0f; - } - if (edge->v1->f2 & edge->v2->f2 & 2) { - co[1] = 0.0f; - } - if (edge->v1->f2 & edge->v2->f2 & 4) { - co[2] = 0.0f; - } - } + BMVert *v_new; + + v_new = BM_edge_split(bm, edge, edge->v1, r_edge, factor_edge_split); + + BMO_vert_flag_enable(bm, v_new, ELE_INNER); + + /* offset for smooth or sphere or fractal */ + alter_co(v_new, e_orig, params, factor_subd, v_a, v_b); + +#if 0 //BMESH_TODO + /* clip if needed by mirror modifier */ + if (edge->v1->f2) { + if (edge->v1->f2 & edge->v2->f2 & 1) { + co[0] = 0.0f; + } + if (edge->v1->f2 & edge->v2->f2 & 2) { + co[1] = 0.0f; + } + if (edge->v1->f2 & edge->v2->f2 & 4) { + co[2] = 0.0f; + } + } #endif - interp_v3_v3v3(v_new->no, v_a->no, v_b->no, factor_subd); - normalize_v3(v_new->no); + interp_v3_v3v3(v_new->no, v_a->no, v_b->no, factor_subd); + normalize_v3(v_new->no); - return v_new; + return v_new; } -static BMVert *subdivide_edge_num( - BMesh *bm, BMEdge *edge, BMEdge *e_orig, - int curpoint, int totpoint, const SubDParams *params, - BMVert *v_a, BMVert *v_b, - BMEdge **r_edge) +static BMVert *subdivide_edge_num(BMesh *bm, + BMEdge *edge, + BMEdge *e_orig, + int curpoint, + int totpoint, + const SubDParams *params, + BMVert *v_a, + BMVert *v_b, + BMEdge **r_edge) { - BMVert *v_new; - float factor_edge_split, factor_subd; - - if (BMO_edge_flag_test(bm, edge, EDGE_PERCENT) && totpoint == 1) { - factor_edge_split = BMO_slot_map_float_get(params->slot_edge_percents, edge); - factor_subd = 0.0f; - } - else { - factor_edge_split = 1.0f / (float)(totpoint + 1 - curpoint); - factor_subd = (float)(curpoint + 1) / (float)(totpoint + 1); - } - - v_new = bm_subdivide_edge_addvert( - bm, edge, e_orig, params, - factor_edge_split, factor_subd, - v_a, v_b, r_edge); - return v_new; + BMVert *v_new; + float factor_edge_split, factor_subd; + + if (BMO_edge_flag_test(bm, edge, EDGE_PERCENT) && totpoint == 1) { + factor_edge_split = BMO_slot_map_float_get(params->slot_edge_percents, edge); + factor_subd = 0.0f; + } + else { + factor_edge_split = 1.0f / (float)(totpoint + 1 - curpoint); + factor_subd = (float)(curpoint + 1) / (float)(totpoint + 1); + } + + v_new = bm_subdivide_edge_addvert( + bm, edge, e_orig, params, factor_edge_split, factor_subd, v_a, v_b, r_edge); + return v_new; } static void bm_subdivide_multicut( - BMesh *bm, BMEdge *edge, const SubDParams *params, - BMVert *v_a, BMVert *v_b) + BMesh *bm, BMEdge *edge, const SubDParams *params, BMVert *v_a, BMVert *v_b) { - BMEdge *eed = edge, *e_new, e_tmp = *edge; - BMVert *v, v1_tmp = *edge->v1, v2_tmp = *edge->v2, *v1 = edge->v1, *v2 = edge->v2; - int i, numcuts = params->numcuts; - - e_tmp.v1 = &v1_tmp; - e_tmp.v2 = &v2_tmp; - - for (i = 0; i < numcuts; i++) { - v = subdivide_edge_num(bm, eed, &e_tmp, i, params->numcuts, params, v_a, v_b, &e_new); - - BMO_vert_flag_enable(bm, v, SUBD_SPLIT | ELE_SPLIT); - BMO_edge_flag_enable(bm, eed, SUBD_SPLIT | ELE_SPLIT); - BMO_edge_flag_enable(bm, e_new, SUBD_SPLIT | ELE_SPLIT); - - BM_CHECK_ELEMENT(v); - if (v->e) { - BM_CHECK_ELEMENT(v->e); - } - if (v->e && v->e->l) { - BM_CHECK_ELEMENT(v->e->l->f); - } - } - - alter_co(v1, &e_tmp, params, 0, &v1_tmp, &v2_tmp); - alter_co(v2, &e_tmp, params, 1.0, &v1_tmp, &v2_tmp); + BMEdge *eed = edge, *e_new, e_tmp = *edge; + BMVert *v, v1_tmp = *edge->v1, v2_tmp = *edge->v2, *v1 = edge->v1, *v2 = edge->v2; + int i, numcuts = params->numcuts; + + e_tmp.v1 = &v1_tmp; + e_tmp.v2 = &v2_tmp; + + for (i = 0; i < numcuts; i++) { + v = subdivide_edge_num(bm, eed, &e_tmp, i, params->numcuts, params, v_a, v_b, &e_new); + + BMO_vert_flag_enable(bm, v, SUBD_SPLIT | ELE_SPLIT); + BMO_edge_flag_enable(bm, eed, SUBD_SPLIT | ELE_SPLIT); + BMO_edge_flag_enable(bm, e_new, SUBD_SPLIT | ELE_SPLIT); + + BM_CHECK_ELEMENT(v); + if (v->e) { + BM_CHECK_ELEMENT(v->e); + } + if (v->e && v->e->l) { + BM_CHECK_ELEMENT(v->e->l->f); + } + } + + alter_co(v1, &e_tmp, params, 0, &v1_tmp, &v2_tmp); + alter_co(v2, &e_tmp, params, 1.0, &v1_tmp, &v2_tmp); } /* note: the patterns are rotated as necessary to @@ -476,42 +483,42 @@ static void bm_subdivide_multicut( * v4---v0---v1 * </pre> */ -static void quad_1edge_split(BMesh *bm, BMFace *UNUSED(face), - BMVert **verts, const SubDParams *params) +static void quad_1edge_split(BMesh *bm, + BMFace *UNUSED(face), + BMVert **verts, + const SubDParams *params) { - BMFace *f_new; - int i, add, numcuts = params->numcuts; - - /* if it's odd, the middle face is a quad, otherwise it's a triangle */ - if ((numcuts % 2) == 0) { - add = 2; - for (i = 0; i < numcuts; i++) { - if (i == numcuts / 2) { - add -= 1; - } - connect_smallest_face(bm, verts[i], verts[numcuts + add], &f_new); - } - } - else { - add = 2; - for (i = 0; i < numcuts; i++) { - connect_smallest_face(bm, verts[i], verts[numcuts + add], &f_new); - if (i == numcuts / 2) { - add -= 1; - connect_smallest_face(bm, verts[i], verts[numcuts + add], &f_new); - } - } - - } + BMFace *f_new; + int i, add, numcuts = params->numcuts; + + /* if it's odd, the middle face is a quad, otherwise it's a triangle */ + if ((numcuts % 2) == 0) { + add = 2; + for (i = 0; i < numcuts; i++) { + if (i == numcuts / 2) { + add -= 1; + } + connect_smallest_face(bm, verts[i], verts[numcuts + add], &f_new); + } + } + else { + add = 2; + for (i = 0; i < numcuts; i++) { + connect_smallest_face(bm, verts[i], verts[numcuts + add], &f_new); + if (i == numcuts / 2) { + add -= 1; + connect_smallest_face(bm, verts[i], verts[numcuts + add], &f_new); + } + } + } } static const SubDPattern quad_1edge = { - {1, 0, 0, 0}, - quad_1edge_split, - 4, + {1, 0, 0, 0}, + quad_1edge_split, + 4, }; - /** * <pre> * v6--------v5 @@ -522,22 +529,24 @@ static const SubDPattern quad_1edge = { * v7-v0--v1-v2 * </pre> */ -static void quad_2edge_split_path(BMesh *bm, BMFace *UNUSED(face), BMVert **verts, +static void quad_2edge_split_path(BMesh *bm, + BMFace *UNUSED(face), + BMVert **verts, const SubDParams *params) { - BMFace *f_new; - int i, numcuts = params->numcuts; + BMFace *f_new; + int i, numcuts = params->numcuts; - for (i = 0; i < numcuts; i++) { - connect_smallest_face(bm, verts[i], verts[numcuts + (numcuts - i)], &f_new); - } - connect_smallest_face(bm, verts[numcuts * 2 + 3], verts[numcuts * 2 + 1], &f_new); + for (i = 0; i < numcuts; i++) { + connect_smallest_face(bm, verts[i], verts[numcuts + (numcuts - i)], &f_new); + } + connect_smallest_face(bm, verts[numcuts * 2 + 3], verts[numcuts * 2 + 1], &f_new); } static const SubDPattern quad_2edge_path = { - {1, 1, 0, 0}, - quad_2edge_split_path, - 4, + {1, 1, 0, 0}, + quad_2edge_split_path, + 4, }; /** @@ -550,36 +559,38 @@ static const SubDPattern quad_2edge_path = { * v7-v0--v1-v2 * </pre> */ -static void quad_2edge_split_innervert(BMesh *bm, BMFace *UNUSED(face), BMVert **verts, +static void quad_2edge_split_innervert(BMesh *bm, + BMFace *UNUSED(face), + BMVert **verts, const SubDParams *params) { - BMFace *f_new; - BMVert *v, *v_last; - BMEdge *e, *e_new, e_tmp; - int i, numcuts = params->numcuts; + BMFace *f_new; + BMVert *v, *v_last; + BMEdge *e, *e_new, e_tmp; + int i, numcuts = params->numcuts; - v_last = verts[numcuts]; + v_last = verts[numcuts]; - for (i = numcuts - 1; i >= 0; i--) { - e = connect_smallest_face(bm, verts[i], verts[numcuts + (numcuts - i)], &f_new); + for (i = numcuts - 1; i >= 0; i--) { + e = connect_smallest_face(bm, verts[i], verts[numcuts + (numcuts - i)], &f_new); - e_tmp = *e; - v = bm_subdivide_edge_addvert(bm, e, &e_tmp, params, 0.5f, 0.5f, e->v1, e->v2, &e_new); + e_tmp = *e; + v = bm_subdivide_edge_addvert(bm, e, &e_tmp, params, 0.5f, 0.5f, e->v1, e->v2, &e_new); - if (i != numcuts - 1) { - connect_smallest_face(bm, v_last, v, &f_new); - } + if (i != numcuts - 1) { + connect_smallest_face(bm, v_last, v, &f_new); + } - v_last = v; - } + v_last = v; + } - connect_smallest_face(bm, v_last, verts[numcuts * 2 + 2], &f_new); + connect_smallest_face(bm, v_last, verts[numcuts * 2 + 2], &f_new); } static const SubDPattern quad_2edge_innervert = { - {1, 1, 0, 0}, - quad_2edge_split_innervert, - 4, + {1, 1, 0, 0}, + quad_2edge_split_innervert, + 4, }; /** @@ -592,25 +603,27 @@ static const SubDPattern quad_2edge_innervert = { * v7-v0--v1-v2 * </pre> */ -static void quad_2edge_split_fan(BMesh *bm, BMFace *UNUSED(face), BMVert **verts, +static void quad_2edge_split_fan(BMesh *bm, + BMFace *UNUSED(face), + BMVert **verts, const SubDParams *params) { - BMFace *f_new; - /* BMVert *v; */ /* UNUSED */ - /* BMVert *v_last = verts[2]; */ /* UNUSED */ - /* BMEdge *e, *e_new; */ /* UNUSED */ - int i, numcuts = params->numcuts; - - for (i = 0; i < numcuts; i++) { - connect_smallest_face(bm, verts[i], verts[numcuts * 2 + 2], &f_new); - connect_smallest_face(bm, verts[numcuts + (numcuts - i)], verts[numcuts * 2 + 2], &f_new); - } + BMFace *f_new; + /* BMVert *v; */ /* UNUSED */ + /* BMVert *v_last = verts[2]; */ /* UNUSED */ + /* BMEdge *e, *e_new; */ /* UNUSED */ + int i, numcuts = params->numcuts; + + for (i = 0; i < numcuts; i++) { + connect_smallest_face(bm, verts[i], verts[numcuts * 2 + 2], &f_new); + connect_smallest_face(bm, verts[numcuts + (numcuts - i)], verts[numcuts * 2 + 2], &f_new); + } } static const SubDPattern quad_2edge_fan = { - {1, 1, 0, 0}, - quad_2edge_split_fan, - 4, + {1, 1, 0, 0}, + quad_2edge_split_fan, + 4, }; /** @@ -625,31 +638,33 @@ static const SubDPattern quad_2edge_fan = { * v9-v0--v1-v2 * </pre> */ -static void quad_3edge_split(BMesh *bm, BMFace *UNUSED(face), BMVert **verts, +static void quad_3edge_split(BMesh *bm, + BMFace *UNUSED(face), + BMVert **verts, const SubDParams *params) { - BMFace *f_new; - int i, add = 0, numcuts = params->numcuts; - - for (i = 0; i < numcuts; i++) { - if (i == numcuts / 2) { - if (numcuts % 2 != 0) { - connect_smallest_face(bm, verts[numcuts - i - 1 + add], verts[i + numcuts + 1], &f_new); - } - add = numcuts * 2 + 2; - } - connect_smallest_face(bm, verts[numcuts - i - 1 + add], verts[i + numcuts + 1], &f_new); - } - - for (i = 0; i < numcuts / 2 + 1; i++) { - connect_smallest_face(bm, verts[i], verts[(numcuts - i) + numcuts * 2 + 1], &f_new); - } + BMFace *f_new; + int i, add = 0, numcuts = params->numcuts; + + for (i = 0; i < numcuts; i++) { + if (i == numcuts / 2) { + if (numcuts % 2 != 0) { + connect_smallest_face(bm, verts[numcuts - i - 1 + add], verts[i + numcuts + 1], &f_new); + } + add = numcuts * 2 + 2; + } + connect_smallest_face(bm, verts[numcuts - i - 1 + add], verts[i + numcuts + 1], &f_new); + } + + for (i = 0; i < numcuts / 2 + 1; i++) { + connect_smallest_face(bm, verts[i], verts[(numcuts - i) + numcuts * 2 + 1], &f_new); + } } static const SubDPattern quad_3edge = { - {1, 1, 1, 0}, - quad_3edge_split, - 4, + {1, 1, 1, 0}, + quad_3edge_split, + 4, }; /** @@ -664,74 +679,75 @@ static const SubDPattern quad_3edge = { * it goes from bottom up * </pre> */ -static void quad_4edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts, +static void quad_4edge_subdivide(BMesh *bm, + BMFace *UNUSED(face), + BMVert **verts, const SubDParams *params) { - BMFace *f_new; - BMVert *v, *v1, *v2; - BMEdge *e, *e_new, e_tmp; - BMVert **lines; - int numcuts = params->numcuts; - int i, j, a, b, s = numcuts + 2 /* , totv = numcuts * 4 + 4 */; - - lines = MEM_callocN(sizeof(BMVert *) * (numcuts + 2) * (numcuts + 2), "q_4edge_split"); - /* build a 2-dimensional array of verts, - * containing every vert (and all new ones) - * in the face */ - - /* first line */ - for (i = 0; i < numcuts + 2; i++) { - lines[i] = verts[numcuts * 3 + 2 + (numcuts - i + 1)]; - } - - /* last line */ - for (i = 0; i < numcuts + 2; i++) { - lines[(s - 1) * s + i] = verts[numcuts + i]; - } - - /* first and last members of middle lines */ - for (i = 0; i < numcuts; i++) { - a = i; - b = numcuts + 1 + numcuts + 1 + (numcuts - i - 1); - - e = connect_smallest_face(bm, verts[a], verts[b], &f_new); - if (!e) { - continue; - } - - BMO_edge_flag_enable(bm, e, ELE_INNER); - BMO_face_flag_enable(bm, f_new, ELE_INNER); - - - v1 = lines[(i + 1) * s] = verts[a]; - v2 = lines[(i + 1) * s + s - 1] = verts[b]; - - e_tmp = *e; - for (a = 0; a < numcuts; a++) { - v = subdivide_edge_num(bm, e, &e_tmp, a, numcuts, params, v1, v2, &e_new); - - BMESH_ASSERT(v != NULL); - - BMO_edge_flag_enable(bm, e_new, ELE_INNER); - lines[(i + 1) * s + a + 1] = v; - } - } - - for (i = 1; i < numcuts + 2; i++) { - for (j = 1; j <= numcuts; j++) { - a = i * s + j; - b = (i - 1) * s + j; - e = connect_smallest_face(bm, lines[a], lines[b], &f_new); - if (!e) { - continue; - } - - BMO_edge_flag_enable(bm, e, ELE_INNER); - BMO_face_flag_enable(bm, f_new, ELE_INNER); - } - } - - MEM_freeN(lines); + BMFace *f_new; + BMVert *v, *v1, *v2; + BMEdge *e, *e_new, e_tmp; + BMVert **lines; + int numcuts = params->numcuts; + int i, j, a, b, s = numcuts + 2 /* , totv = numcuts * 4 + 4 */; + + lines = MEM_callocN(sizeof(BMVert *) * (numcuts + 2) * (numcuts + 2), "q_4edge_split"); + /* build a 2-dimensional array of verts, + * containing every vert (and all new ones) + * in the face */ + + /* first line */ + for (i = 0; i < numcuts + 2; i++) { + lines[i] = verts[numcuts * 3 + 2 + (numcuts - i + 1)]; + } + + /* last line */ + for (i = 0; i < numcuts + 2; i++) { + lines[(s - 1) * s + i] = verts[numcuts + i]; + } + + /* first and last members of middle lines */ + for (i = 0; i < numcuts; i++) { + a = i; + b = numcuts + 1 + numcuts + 1 + (numcuts - i - 1); + + e = connect_smallest_face(bm, verts[a], verts[b], &f_new); + if (!e) { + continue; + } + + BMO_edge_flag_enable(bm, e, ELE_INNER); + BMO_face_flag_enable(bm, f_new, ELE_INNER); + + v1 = lines[(i + 1) * s] = verts[a]; + v2 = lines[(i + 1) * s + s - 1] = verts[b]; + + e_tmp = *e; + for (a = 0; a < numcuts; a++) { + v = subdivide_edge_num(bm, e, &e_tmp, a, numcuts, params, v1, v2, &e_new); + + BMESH_ASSERT(v != NULL); + + BMO_edge_flag_enable(bm, e_new, ELE_INNER); + lines[(i + 1) * s + a + 1] = v; + } + } + + for (i = 1; i < numcuts + 2; i++) { + for (j = 1; j <= numcuts; j++) { + a = i * s + j; + b = (i - 1) * s + j; + e = connect_smallest_face(bm, lines[a], lines[b], &f_new); + if (!e) { + continue; + } + + BMO_edge_flag_enable(bm, e, ELE_INNER); + BMO_face_flag_enable(bm, f_new, ELE_INNER); + } + } + + MEM_freeN(lines); } /** @@ -746,21 +762,23 @@ static void quad_4edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts * s s * </pre> */ -static void tri_1edge_split(BMesh *bm, BMFace *UNUSED(face), BMVert **verts, +static void tri_1edge_split(BMesh *bm, + BMFace *UNUSED(face), + BMVert **verts, const SubDParams *params) { - BMFace *f_new; - int i, numcuts = params->numcuts; + BMFace *f_new; + int i, numcuts = params->numcuts; - for (i = 0; i < numcuts; i++) { - connect_smallest_face(bm, verts[i], verts[numcuts + 1], &f_new); - } + for (i = 0; i < numcuts; i++) { + connect_smallest_face(bm, verts[i], verts[numcuts + 1], &f_new); + } } static const SubDPattern tri_1edge = { - {1, 0, 0}, - tri_1edge_split, - 3, + {1, 0, 0}, + tri_1edge_split, + 3, }; /** @@ -775,615 +793,636 @@ static const SubDPattern tri_1edge = { * s s * </pre> */ -static void tri_3edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts, +static void tri_3edge_subdivide(BMesh *bm, + BMFace *UNUSED(face), + BMVert **verts, const SubDParams *params) { - BMFace *f_new; - BMEdge *e, *e_new, e_tmp; - BMVert ***lines, *v, v1_tmp, v2_tmp; - void *stackarr[1]; - int i, j, a, b, numcuts = params->numcuts; - - /* number of verts in each lin */ - lines = MEM_callocN(sizeof(void *) * (numcuts + 2), "triangle vert table"); - - lines[0] = (BMVert **) stackarr; - lines[0][0] = verts[numcuts * 2 + 1]; - - lines[numcuts + 1] = MEM_callocN(sizeof(void *) * (numcuts + 2), "triangle vert table 2"); - for (i = 0; i < numcuts; i++) { - lines[numcuts + 1][i + 1] = verts[i]; - } - lines[numcuts + 1][0] = verts[numcuts * 3 + 2]; - lines[numcuts + 1][numcuts + 1] = verts[numcuts]; - - for (i = 0; i < numcuts; i++) { - lines[i + 1] = MEM_callocN(sizeof(void *) * (2 + i), "triangle vert table row"); - a = numcuts * 2 + 2 + i; - b = numcuts + numcuts - i; - e = connect_smallest_face(bm, verts[a], verts[b], &f_new); - if (!e) { - goto cleanup; - } - - BMO_edge_flag_enable(bm, e, ELE_INNER); - BMO_face_flag_enable(bm, f_new, ELE_INNER); - - lines[i + 1][0] = verts[a]; - lines[i + 1][i + 1] = verts[b]; - - e_tmp = *e; - v1_tmp = *verts[a]; - v2_tmp = *verts[b]; - e_tmp.v1 = &v1_tmp; - e_tmp.v2 = &v2_tmp; - for (j = 0; j < i; j++) { - v = subdivide_edge_num(bm, e, &e_tmp, j, i, params, verts[a], verts[b], &e_new); - lines[i + 1][j + 1] = v; - - BMO_edge_flag_enable(bm, e_new, ELE_INNER); - } - } - - /** - * <pre> - * v5 - * / \ - * s v6/---\ v4 s - * / \ / \ - * sv7/---v---\ v3 s - * / \/ \/ \ - * v8--v0--v1--v2 - * s s - * </pre> - */ - for (i = 1; i <= numcuts; i++) { - for (j = 0; j < i; j++) { - e = connect_smallest_face(bm, lines[i][j], lines[i + 1][j + 1], &f_new); - - BMO_edge_flag_enable(bm, e, ELE_INNER); - BMO_face_flag_enable(bm, f_new, ELE_INNER); - - e = connect_smallest_face(bm, lines[i][j + 1], lines[i + 1][j + 1], &f_new); - - BMO_edge_flag_enable(bm, e, ELE_INNER); - BMO_face_flag_enable(bm, f_new, ELE_INNER); - } - } + BMFace *f_new; + BMEdge *e, *e_new, e_tmp; + BMVert ***lines, *v, v1_tmp, v2_tmp; + void *stackarr[1]; + int i, j, a, b, numcuts = params->numcuts; + + /* number of verts in each lin */ + lines = MEM_callocN(sizeof(void *) * (numcuts + 2), "triangle vert table"); + + lines[0] = (BMVert **)stackarr; + lines[0][0] = verts[numcuts * 2 + 1]; + + lines[numcuts + 1] = MEM_callocN(sizeof(void *) * (numcuts + 2), "triangle vert table 2"); + for (i = 0; i < numcuts; i++) { + lines[numcuts + 1][i + 1] = verts[i]; + } + lines[numcuts + 1][0] = verts[numcuts * 3 + 2]; + lines[numcuts + 1][numcuts + 1] = verts[numcuts]; + + for (i = 0; i < numcuts; i++) { + lines[i + 1] = MEM_callocN(sizeof(void *) * (2 + i), "triangle vert table row"); + a = numcuts * 2 + 2 + i; + b = numcuts + numcuts - i; + e = connect_smallest_face(bm, verts[a], verts[b], &f_new); + if (!e) { + goto cleanup; + } + + BMO_edge_flag_enable(bm, e, ELE_INNER); + BMO_face_flag_enable(bm, f_new, ELE_INNER); + + lines[i + 1][0] = verts[a]; + lines[i + 1][i + 1] = verts[b]; + + e_tmp = *e; + v1_tmp = *verts[a]; + v2_tmp = *verts[b]; + e_tmp.v1 = &v1_tmp; + e_tmp.v2 = &v2_tmp; + for (j = 0; j < i; j++) { + v = subdivide_edge_num(bm, e, &e_tmp, j, i, params, verts[a], verts[b], &e_new); + lines[i + 1][j + 1] = v; + + BMO_edge_flag_enable(bm, e_new, ELE_INNER); + } + } + + /** + * <pre> + * v5 + * / \ + * s v6/---\ v4 s + * / \ / \ + * sv7/---v---\ v3 s + * / \/ \/ \ + * v8--v0--v1--v2 + * s s + * </pre> + */ + for (i = 1; i <= numcuts; i++) { + for (j = 0; j < i; j++) { + e = connect_smallest_face(bm, lines[i][j], lines[i + 1][j + 1], &f_new); + + BMO_edge_flag_enable(bm, e, ELE_INNER); + BMO_face_flag_enable(bm, f_new, ELE_INNER); + + e = connect_smallest_face(bm, lines[i][j + 1], lines[i + 1][j + 1], &f_new); + + BMO_edge_flag_enable(bm, e, ELE_INNER); + BMO_face_flag_enable(bm, f_new, ELE_INNER); + } + } cleanup: - for (i = 1; i < numcuts + 2; i++) { - if (lines[i]) { - MEM_freeN(lines[i]); - } - } + for (i = 1; i < numcuts + 2; i++) { + if (lines[i]) { + MEM_freeN(lines[i]); + } + } - MEM_freeN(lines); + MEM_freeN(lines); } static const SubDPattern tri_3edge = { - {1, 1, 1}, - tri_3edge_subdivide, - 3, + {1, 1, 1}, + tri_3edge_subdivide, + 3, }; - static const SubDPattern quad_4edge = { - {1, 1, 1, 1}, - quad_4edge_subdivide, - 4, + {1, 1, 1, 1}, + quad_4edge_subdivide, + 4, }; static const SubDPattern *patterns[] = { - NULL, /* quad single edge pattern is inserted here */ - NULL, /* quad corner vert pattern is inserted here */ - NULL, /* tri single edge pattern is inserted here */ - NULL, - &quad_3edge, - NULL, + NULL, /* quad single edge pattern is inserted here */ + NULL, /* quad corner vert pattern is inserted here */ + NULL, /* tri single edge pattern is inserted here */ + NULL, + &quad_3edge, + NULL, }; -#define PATTERNS_TOT ARRAY_SIZE(patterns) +#define PATTERNS_TOT ARRAY_SIZE(patterns) typedef struct SubDFaceData { - BMVert *start; - const SubDPattern *pat; - int totedgesel; /* only used if pat was NULL, e.g. no pattern was found */ - BMFace *face; + BMVert *start; + const SubDPattern *pat; + int totedgesel; /* only used if pat was NULL, e.g. no pattern was found */ + BMFace *face; } SubDFaceData; void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op) { - BMOpSlot *einput; - const SubDPattern *pat; - SubDParams params; - BLI_Stack *facedata; - BMIter viter, fiter, liter; - BMVert *v, **verts = NULL; - BMEdge *edge; - BMEdge **edges = NULL; - BLI_array_declare(edges); - BMLoop *(*loops_split)[2] = NULL; - BLI_array_declare(loops_split); - BMLoop **loops = NULL; - BLI_array_declare(loops); - BMLoop *l_new, *l; - BMFace *face; - BLI_array_declare(verts); - float smooth, fractal, along_normal; - bool use_sphere, use_single_edge, use_grid_fill, use_only_quads; - int cornertype, seed, i, j, a, b, numcuts, totesel, smooth_falloff; - - BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, SUBD_SPLIT); - - numcuts = BMO_slot_int_get(op->slots_in, "cuts"); - seed = BMO_slot_int_get(op->slots_in, "seed"); - smooth = BMO_slot_float_get(op->slots_in, "smooth"); - smooth_falloff = BMO_slot_int_get(op->slots_in, "smooth_falloff"); - fractal = BMO_slot_float_get(op->slots_in, "fractal"); - along_normal = BMO_slot_float_get(op->slots_in, "along_normal"); - cornertype = BMO_slot_int_get(op->slots_in, "quad_corner_type"); - - use_single_edge = BMO_slot_bool_get(op->slots_in, "use_single_edge"); - use_grid_fill = BMO_slot_bool_get(op->slots_in, "use_grid_fill"); - use_only_quads = BMO_slot_bool_get(op->slots_in, "use_only_quads"); - use_sphere = BMO_slot_bool_get(op->slots_in, "use_sphere"); - - patterns[1] = NULL; - /* straight cut is patterns[1] == NULL */ - switch (cornertype) { - case SUBD_CORNER_PATH: - patterns[1] = &quad_2edge_path; - break; - case SUBD_CORNER_INNERVERT: - patterns[1] = &quad_2edge_innervert; - break; - case SUBD_CORNER_FAN: - patterns[1] = &quad_2edge_fan; - break; - } - - if (use_single_edge) { - patterns[0] = &quad_1edge; - patterns[2] = &tri_1edge; - } - else { - patterns[0] = NULL; - patterns[2] = NULL; - } - - if (use_grid_fill) { - patterns[3] = &quad_4edge; - patterns[5] = &tri_3edge; - } - else { - patterns[3] = NULL; - patterns[5] = NULL; - } - - /* add a temporary shapekey layer to store displacements on current geometry */ - BM_data_layer_add(bm, &bm->vdata, CD_SHAPEKEY); - - bmo_subd_init_shape_info(bm, ¶ms); - - BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { - float *co = BM_ELEM_CD_GET_VOID_P(v, params.shape_info.cd_vert_shape_offset_tmp); - copy_v3_v3(co, v->co); - } - - /* first go through and tag edges */ - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_in, "edges", BM_EDGE, SUBD_SPLIT); - - params.numcuts = numcuts; - params.op = op; - params.slot_edge_percents = BMO_slot_get(op->slots_in, "edge_percents"); - params.slot_custom_patterns = BMO_slot_get(op->slots_in, "custom_patterns"); - params.smooth = smooth; - params.smooth_falloff = smooth_falloff; - params.seed = seed; - params.fractal = fractal; - params.along_normal = along_normal; - params.use_smooth = (smooth != 0.0f); - params.use_smooth_even = BMO_slot_bool_get(op->slots_in, "use_smooth_even"); - params.use_fractal = (fractal != 0.0f); - params.use_sphere = use_sphere; - - if (params.use_fractal) { - RNG *rng = BLI_rng_new_srandom(seed); - - params.fractal_ofs[0] = BLI_rng_get_float(rng) * 200.0f; - params.fractal_ofs[1] = BLI_rng_get_float(rng) * 200.0f; - params.fractal_ofs[2] = BLI_rng_get_float(rng) * 200.0f; - - BLI_rng_free(rng); - } - - BMO_slot_map_to_flag(bm, op->slots_in, "custom_patterns", - BM_FACE, FACE_CUSTOMFILL); - - BMO_slot_map_to_flag(bm, op->slots_in, "edge_percents", - BM_EDGE, EDGE_PERCENT); - - - facedata = BLI_stack_new(sizeof(SubDFaceData), __func__); - - BM_ITER_MESH (face, &fiter, bm, BM_FACES_OF_MESH) { - BMEdge *e1 = NULL, *e2 = NULL; - float vec1[3], vec2[3]; - bool matched = false; - - /* skip non-quads if requested */ - if (use_only_quads && face->len != 4) { - continue; - } - - /* figure out which pattern to use */ - - BLI_array_clear(edges); - BLI_array_clear(verts); - - BLI_array_grow_items(edges, face->len); - BLI_array_grow_items(verts, face->len); - - totesel = 0; - BM_ITER_ELEM_INDEX (l_new, &liter, face, BM_LOOPS_OF_FACE, i) { - edges[i] = l_new->e; - verts[i] = l_new->v; - - if (BMO_edge_flag_test(bm, edges[i], SUBD_SPLIT)) { - if (!e1) { e1 = edges[i]; } - else { e2 = edges[i]; } - - totesel++; - } - } - - /* make sure the two edges have a valid angle to each other */ - if (totesel == 2 && BM_edge_share_vert_check(e1, e2)) { - sub_v3_v3v3(vec1, e1->v2->co, e1->v1->co); - sub_v3_v3v3(vec2, e2->v2->co, e2->v1->co); - normalize_v3(vec1); - normalize_v3(vec2); - - if (fabsf(dot_v3v3(vec1, vec2)) > 1.0f - FLT_FACE_SPLIT_EPSILON) { - totesel = 0; - } - } - - if (BMO_face_flag_test(bm, face, FACE_CUSTOMFILL)) { - pat = *BMO_slot_map_data_get(params.slot_custom_patterns, face); - for (i = 0; i < pat->len; i++) { - matched = 1; - for (j = 0; j < pat->len; j++) { - a = (j + i) % pat->len; - if ((!!BMO_edge_flag_test(bm, edges[a], SUBD_SPLIT)) != (!!pat->seledges[j])) { - matched = 0; - break; - } - } - if (matched) { - SubDFaceData *fd; - - fd = BLI_stack_push_r(facedata); - fd->pat = pat; - fd->start = verts[i]; - fd->face = face; - fd->totedgesel = totesel; - BMO_face_flag_enable(bm, face, SUBD_SPLIT); - break; - } - } - - /* obvously don't test for other patterns matching */ - continue; - } - - for (i = 0; i < PATTERNS_TOT; i++) { - pat = patterns[i]; - if (!pat) { - continue; - } - - if (pat->len == face->len) { - for (a = 0; a < pat->len; a++) { - matched = 1; - for (b = 0; b < pat->len; b++) { - j = (b + a) % pat->len; - if ((!!BMO_edge_flag_test(bm, edges[j], SUBD_SPLIT)) != (!!pat->seledges[b])) { - matched = 0; - break; - } - } - if (matched) { - break; - } - } - if (matched) { - SubDFaceData *fd; - - BMO_face_flag_enable(bm, face, SUBD_SPLIT); - - fd = BLI_stack_push_r(facedata); - fd->pat = pat; - fd->start = verts[a]; - fd->face = face; - fd->totedgesel = totesel; - break; - } - } - - } - - if (!matched && totesel) { - SubDFaceData *fd; - - BMO_face_flag_enable(bm, face, SUBD_SPLIT); - - /* must initialize all members here */ - fd = BLI_stack_push_r(facedata); - fd->start = NULL; - fd->pat = NULL; - fd->totedgesel = totesel; - fd->face = face; - } - } - - einput = BMO_slot_get(op->slots_in, "edges"); - - /* go through and split edges */ - for (i = 0; i < einput->len; i++) { - edge = einput->data.buf[i]; - bm_subdivide_multicut(bm, edge, ¶ms, edge->v1, edge->v2); - } - - /* copy original-geometry displacements to current coordinates */ - BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { - const float *co = BM_ELEM_CD_GET_VOID_P(v, params.shape_info.cd_vert_shape_offset_tmp); - copy_v3_v3(v->co, co); - } - - for (; !BLI_stack_is_empty(facedata); BLI_stack_discard(facedata)) { - SubDFaceData *fd = BLI_stack_peek(facedata); - - face = fd->face; - - /* figure out which pattern to use */ - BLI_array_clear(verts); - - pat = fd->pat; - - if (!pat && fd->totedgesel == 2) { - int vlen; - - /* ok, no pattern. we still may be able to do something */ - BLI_array_clear(loops); - BLI_array_clear(loops_split); - - /* for case of two edges, connecting them shouldn't be too hard */ - BLI_array_grow_items(loops, face->len); - BM_ITER_ELEM_INDEX (l, &liter, face, BM_LOOPS_OF_FACE, a) { - loops[a] = l; - } - - vlen = BLI_array_len(loops); - - /* find the boundary of one of the split edges */ - for (a = 1; a < vlen; a++) { - if (!BMO_vert_flag_test(bm, loops[a - 1]->v, ELE_INNER) && - BMO_vert_flag_test(bm, loops[a]->v, ELE_INNER)) - { - break; - } - } - - if (BMO_vert_flag_test(bm, loops[(a + numcuts + 1) % vlen]->v, ELE_INNER)) { - b = (a + numcuts + 1) % vlen; - } - else { - /* find the boundary of the other edge. */ - for (j = 0; j < vlen; j++) { - b = (j + a + numcuts + 1) % vlen; - if (!BMO_vert_flag_test(bm, loops[b == 0 ? vlen - 1 : b - 1]->v, ELE_INNER) && - BMO_vert_flag_test(bm, loops[b]->v, ELE_INNER)) - { - break; - } - } - } - - b += numcuts - 1; - - BLI_array_grow_items(loops_split, numcuts); - for (j = 0; j < numcuts; j++) { - bool ok = true; - - /* Check for special case: [#32500] - * This edge pair could be used by more than one face, - * in this case it used to (2.63), split both faces along the same verts - * while it could be calculated which face should do the split, - * it's ambiguous, so in this case we're better off to skip them as exceptional cases - * and not try to be clever guessing which face to cut up. - * - * To avoid this case we need to check: - * Do the verts of each share a face besides the one we are subdividing, - * (but not connect to make an edge of that face). - */ - { - BMLoop *other_loop; - BMIter other_fiter; - BM_ITER_ELEM (other_loop, &other_fiter, loops[a]->v, BM_LOOPS_OF_VERT) { - if (other_loop->f != face) { - if (BM_vert_in_face(loops[b]->v, other_loop->f)) { - /* we assume that these verts are not making an edge in the face */ - BLI_assert(other_loop->prev->v != loops[a]->v); - BLI_assert(other_loop->next->v != loops[a]->v); - - ok = false; - break; - } - } - } - } - - - if (ok == true) { - loops_split[j][0] = loops[a]; - loops_split[j][1] = loops[b]; - } - else { - loops_split[j][0] = NULL; - loops_split[j][1] = NULL; - } - - b = (b - 1) % vlen; - a = (a + 1) % vlen; - } - - /* Since these are newly created vertices, we don't need to worry about them being legal, - * ... though there are some cases we _should_ check for - * - concave corner of an ngon. - * - 2 edges being used in 2+ ngons. - */ -// BM_face_splits_check_legal(bm, face, loops_split, BLI_array_len(loops_split)); - - for (j = 0; j < BLI_array_len(loops_split); j++) { - if (loops_split[j][0]) { - BMFace *f_new; - BLI_assert(BM_edge_exists(loops_split[j][0]->v, loops_split[j][1]->v) == NULL); - f_new = BM_face_split(bm, face, loops_split[j][0], loops_split[j][1], &l_new, NULL, false); - if (f_new) { - BMO_edge_flag_enable(bm, l_new->e, ELE_INNER); - } - } - } - - continue; - } - else if (!pat) { - continue; - } - - a = 0; - BM_ITER_ELEM_INDEX (l_new, &liter, face, BM_LOOPS_OF_FACE, j) { - if (l_new->v == fd->start) { - a = j + 1; - break; - } - } - - BLI_array_grow_items(verts, face->len); - - BM_ITER_ELEM_INDEX (l_new, &liter, face, BM_LOOPS_OF_FACE, j) { - b = (j - a + face->len) % face->len; - verts[b] = l_new->v; - } - - BM_CHECK_ELEMENT(face); - pat->connectexec(bm, face, verts, ¶ms); - } - - /* copy original-geometry displacements to current coordinates */ - BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { - const float *co = BM_ELEM_CD_GET_VOID_P(v, params.shape_info.cd_vert_shape_offset_tmp); - copy_v3_v3(v->co, co); - } - - BM_data_layer_free_n(bm, &bm->vdata, CD_SHAPEKEY, params.shape_info.tmpkey); - - BLI_stack_free(facedata); - if (edges) { - BLI_array_free(edges); - } - if (verts) { - BLI_array_free(verts); - } - BLI_array_free(loops_split); - BLI_array_free(loops); - - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom_inner.out", BM_ALL_NOLOOP, ELE_INNER); - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom_split.out", BM_ALL_NOLOOP, ELE_SPLIT); - - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, ELE_INNER | ELE_SPLIT | SUBD_SPLIT); + BMOpSlot *einput; + const SubDPattern *pat; + SubDParams params; + BLI_Stack *facedata; + BMIter viter, fiter, liter; + BMVert *v, **verts = NULL; + BMEdge *edge; + BMEdge **edges = NULL; + BLI_array_declare(edges); + BMLoop *(*loops_split)[2] = NULL; + BLI_array_declare(loops_split); + BMLoop **loops = NULL; + BLI_array_declare(loops); + BMLoop *l_new, *l; + BMFace *face; + BLI_array_declare(verts); + float smooth, fractal, along_normal; + bool use_sphere, use_single_edge, use_grid_fill, use_only_quads; + int cornertype, seed, i, j, a, b, numcuts, totesel, smooth_falloff; + + BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, SUBD_SPLIT); + + numcuts = BMO_slot_int_get(op->slots_in, "cuts"); + seed = BMO_slot_int_get(op->slots_in, "seed"); + smooth = BMO_slot_float_get(op->slots_in, "smooth"); + smooth_falloff = BMO_slot_int_get(op->slots_in, "smooth_falloff"); + fractal = BMO_slot_float_get(op->slots_in, "fractal"); + along_normal = BMO_slot_float_get(op->slots_in, "along_normal"); + cornertype = BMO_slot_int_get(op->slots_in, "quad_corner_type"); + + use_single_edge = BMO_slot_bool_get(op->slots_in, "use_single_edge"); + use_grid_fill = BMO_slot_bool_get(op->slots_in, "use_grid_fill"); + use_only_quads = BMO_slot_bool_get(op->slots_in, "use_only_quads"); + use_sphere = BMO_slot_bool_get(op->slots_in, "use_sphere"); + + patterns[1] = NULL; + /* straight cut is patterns[1] == NULL */ + switch (cornertype) { + case SUBD_CORNER_PATH: + patterns[1] = &quad_2edge_path; + break; + case SUBD_CORNER_INNERVERT: + patterns[1] = &quad_2edge_innervert; + break; + case SUBD_CORNER_FAN: + patterns[1] = &quad_2edge_fan; + break; + } + + if (use_single_edge) { + patterns[0] = &quad_1edge; + patterns[2] = &tri_1edge; + } + else { + patterns[0] = NULL; + patterns[2] = NULL; + } + + if (use_grid_fill) { + patterns[3] = &quad_4edge; + patterns[5] = &tri_3edge; + } + else { + patterns[3] = NULL; + patterns[5] = NULL; + } + + /* add a temporary shapekey layer to store displacements on current geometry */ + BM_data_layer_add(bm, &bm->vdata, CD_SHAPEKEY); + + bmo_subd_init_shape_info(bm, ¶ms); + + BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { + float *co = BM_ELEM_CD_GET_VOID_P(v, params.shape_info.cd_vert_shape_offset_tmp); + copy_v3_v3(co, v->co); + } + + /* first go through and tag edges */ + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_in, "edges", BM_EDGE, SUBD_SPLIT); + + params.numcuts = numcuts; + params.op = op; + params.slot_edge_percents = BMO_slot_get(op->slots_in, "edge_percents"); + params.slot_custom_patterns = BMO_slot_get(op->slots_in, "custom_patterns"); + params.smooth = smooth; + params.smooth_falloff = smooth_falloff; + params.seed = seed; + params.fractal = fractal; + params.along_normal = along_normal; + params.use_smooth = (smooth != 0.0f); + params.use_smooth_even = BMO_slot_bool_get(op->slots_in, "use_smooth_even"); + params.use_fractal = (fractal != 0.0f); + params.use_sphere = use_sphere; + + if (params.use_fractal) { + RNG *rng = BLI_rng_new_srandom(seed); + + params.fractal_ofs[0] = BLI_rng_get_float(rng) * 200.0f; + params.fractal_ofs[1] = BLI_rng_get_float(rng) * 200.0f; + params.fractal_ofs[2] = BLI_rng_get_float(rng) * 200.0f; + + BLI_rng_free(rng); + } + + BMO_slot_map_to_flag(bm, op->slots_in, "custom_patterns", BM_FACE, FACE_CUSTOMFILL); + + BMO_slot_map_to_flag(bm, op->slots_in, "edge_percents", BM_EDGE, EDGE_PERCENT); + + facedata = BLI_stack_new(sizeof(SubDFaceData), __func__); + + BM_ITER_MESH (face, &fiter, bm, BM_FACES_OF_MESH) { + BMEdge *e1 = NULL, *e2 = NULL; + float vec1[3], vec2[3]; + bool matched = false; + + /* skip non-quads if requested */ + if (use_only_quads && face->len != 4) { + continue; + } + + /* figure out which pattern to use */ + + BLI_array_clear(edges); + BLI_array_clear(verts); + + BLI_array_grow_items(edges, face->len); + BLI_array_grow_items(verts, face->len); + + totesel = 0; + BM_ITER_ELEM_INDEX(l_new, &liter, face, BM_LOOPS_OF_FACE, i) + { + edges[i] = l_new->e; + verts[i] = l_new->v; + + if (BMO_edge_flag_test(bm, edges[i], SUBD_SPLIT)) { + if (!e1) { + e1 = edges[i]; + } + else { + e2 = edges[i]; + } + + totesel++; + } + } + + /* make sure the two edges have a valid angle to each other */ + if (totesel == 2 && BM_edge_share_vert_check(e1, e2)) { + sub_v3_v3v3(vec1, e1->v2->co, e1->v1->co); + sub_v3_v3v3(vec2, e2->v2->co, e2->v1->co); + normalize_v3(vec1); + normalize_v3(vec2); + + if (fabsf(dot_v3v3(vec1, vec2)) > 1.0f - FLT_FACE_SPLIT_EPSILON) { + totesel = 0; + } + } + + if (BMO_face_flag_test(bm, face, FACE_CUSTOMFILL)) { + pat = *BMO_slot_map_data_get(params.slot_custom_patterns, face); + for (i = 0; i < pat->len; i++) { + matched = 1; + for (j = 0; j < pat->len; j++) { + a = (j + i) % pat->len; + if ((!!BMO_edge_flag_test(bm, edges[a], SUBD_SPLIT)) != (!!pat->seledges[j])) { + matched = 0; + break; + } + } + if (matched) { + SubDFaceData *fd; + + fd = BLI_stack_push_r(facedata); + fd->pat = pat; + fd->start = verts[i]; + fd->face = face; + fd->totedgesel = totesel; + BMO_face_flag_enable(bm, face, SUBD_SPLIT); + break; + } + } + + /* obvously don't test for other patterns matching */ + continue; + } + + for (i = 0; i < PATTERNS_TOT; i++) { + pat = patterns[i]; + if (!pat) { + continue; + } + + if (pat->len == face->len) { + for (a = 0; a < pat->len; a++) { + matched = 1; + for (b = 0; b < pat->len; b++) { + j = (b + a) % pat->len; + if ((!!BMO_edge_flag_test(bm, edges[j], SUBD_SPLIT)) != (!!pat->seledges[b])) { + matched = 0; + break; + } + } + if (matched) { + break; + } + } + if (matched) { + SubDFaceData *fd; + + BMO_face_flag_enable(bm, face, SUBD_SPLIT); + + fd = BLI_stack_push_r(facedata); + fd->pat = pat; + fd->start = verts[a]; + fd->face = face; + fd->totedgesel = totesel; + break; + } + } + } + + if (!matched && totesel) { + SubDFaceData *fd; + + BMO_face_flag_enable(bm, face, SUBD_SPLIT); + + /* must initialize all members here */ + fd = BLI_stack_push_r(facedata); + fd->start = NULL; + fd->pat = NULL; + fd->totedgesel = totesel; + fd->face = face; + } + } + + einput = BMO_slot_get(op->slots_in, "edges"); + + /* go through and split edges */ + for (i = 0; i < einput->len; i++) { + edge = einput->data.buf[i]; + bm_subdivide_multicut(bm, edge, ¶ms, edge->v1, edge->v2); + } + + /* copy original-geometry displacements to current coordinates */ + BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { + const float *co = BM_ELEM_CD_GET_VOID_P(v, params.shape_info.cd_vert_shape_offset_tmp); + copy_v3_v3(v->co, co); + } + + for (; !BLI_stack_is_empty(facedata); BLI_stack_discard(facedata)) { + SubDFaceData *fd = BLI_stack_peek(facedata); + + face = fd->face; + + /* figure out which pattern to use */ + BLI_array_clear(verts); + + pat = fd->pat; + + if (!pat && fd->totedgesel == 2) { + int vlen; + + /* ok, no pattern. we still may be able to do something */ + BLI_array_clear(loops); + BLI_array_clear(loops_split); + + /* for case of two edges, connecting them shouldn't be too hard */ + BLI_array_grow_items(loops, face->len); + BM_ITER_ELEM_INDEX(l, &liter, face, BM_LOOPS_OF_FACE, a) + { + loops[a] = l; + } + + vlen = BLI_array_len(loops); + + /* find the boundary of one of the split edges */ + for (a = 1; a < vlen; a++) { + if (!BMO_vert_flag_test(bm, loops[a - 1]->v, ELE_INNER) && + BMO_vert_flag_test(bm, loops[a]->v, ELE_INNER)) { + break; + } + } + + if (BMO_vert_flag_test(bm, loops[(a + numcuts + 1) % vlen]->v, ELE_INNER)) { + b = (a + numcuts + 1) % vlen; + } + else { + /* find the boundary of the other edge. */ + for (j = 0; j < vlen; j++) { + b = (j + a + numcuts + 1) % vlen; + if (!BMO_vert_flag_test(bm, loops[b == 0 ? vlen - 1 : b - 1]->v, ELE_INNER) && + BMO_vert_flag_test(bm, loops[b]->v, ELE_INNER)) { + break; + } + } + } + + b += numcuts - 1; + + BLI_array_grow_items(loops_split, numcuts); + for (j = 0; j < numcuts; j++) { + bool ok = true; + + /* Check for special case: [#32500] + * This edge pair could be used by more than one face, + * in this case it used to (2.63), split both faces along the same verts + * while it could be calculated which face should do the split, + * it's ambiguous, so in this case we're better off to skip them as exceptional cases + * and not try to be clever guessing which face to cut up. + * + * To avoid this case we need to check: + * Do the verts of each share a face besides the one we are subdividing, + * (but not connect to make an edge of that face). + */ + { + BMLoop *other_loop; + BMIter other_fiter; + BM_ITER_ELEM (other_loop, &other_fiter, loops[a]->v, BM_LOOPS_OF_VERT) { + if (other_loop->f != face) { + if (BM_vert_in_face(loops[b]->v, other_loop->f)) { + /* we assume that these verts are not making an edge in the face */ + BLI_assert(other_loop->prev->v != loops[a]->v); + BLI_assert(other_loop->next->v != loops[a]->v); + + ok = false; + break; + } + } + } + } + + if (ok == true) { + loops_split[j][0] = loops[a]; + loops_split[j][1] = loops[b]; + } + else { + loops_split[j][0] = NULL; + loops_split[j][1] = NULL; + } + + b = (b - 1) % vlen; + a = (a + 1) % vlen; + } + + /* Since these are newly created vertices, we don't need to worry about them being legal, + * ... though there are some cases we _should_ check for + * - concave corner of an ngon. + * - 2 edges being used in 2+ ngons. + */ + // BM_face_splits_check_legal(bm, face, loops_split, BLI_array_len(loops_split)); + + for (j = 0; j < BLI_array_len(loops_split); j++) { + if (loops_split[j][0]) { + BMFace *f_new; + BLI_assert(BM_edge_exists(loops_split[j][0]->v, loops_split[j][1]->v) == NULL); + f_new = BM_face_split( + bm, face, loops_split[j][0], loops_split[j][1], &l_new, NULL, false); + if (f_new) { + BMO_edge_flag_enable(bm, l_new->e, ELE_INNER); + } + } + } + + continue; + } + else if (!pat) { + continue; + } + + a = 0; + BM_ITER_ELEM_INDEX(l_new, &liter, face, BM_LOOPS_OF_FACE, j) + { + if (l_new->v == fd->start) { + a = j + 1; + break; + } + } + + BLI_array_grow_items(verts, face->len); + + BM_ITER_ELEM_INDEX(l_new, &liter, face, BM_LOOPS_OF_FACE, j) + { + b = (j - a + face->len) % face->len; + verts[b] = l_new->v; + } + + BM_CHECK_ELEMENT(face); + pat->connectexec(bm, face, verts, ¶ms); + } + + /* copy original-geometry displacements to current coordinates */ + BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { + const float *co = BM_ELEM_CD_GET_VOID_P(v, params.shape_info.cd_vert_shape_offset_tmp); + copy_v3_v3(v->co, co); + } + + BM_data_layer_free_n(bm, &bm->vdata, CD_SHAPEKEY, params.shape_info.tmpkey); + + BLI_stack_free(facedata); + if (edges) { + BLI_array_free(edges); + } + if (verts) { + BLI_array_free(verts); + } + BLI_array_free(loops_split); + BLI_array_free(loops); + + BMO_slot_buffer_from_enabled_flag( + bm, op, op->slots_out, "geom_inner.out", BM_ALL_NOLOOP, ELE_INNER); + BMO_slot_buffer_from_enabled_flag( + bm, op, op->slots_out, "geom_split.out", BM_ALL_NOLOOP, ELE_SPLIT); + + BMO_slot_buffer_from_enabled_flag( + bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, ELE_INNER | ELE_SPLIT | SUBD_SPLIT); } /* editmesh-emulating function */ -void BM_mesh_esubdivide( - BMesh *bm, const char edge_hflag, - const float smooth, const short smooth_falloff, const bool use_smooth_even, - const float fractal, const float along_normal, - const int numcuts, - const int seltype, const int cornertype, - const short use_single_edge, const short use_grid_fill, - const short use_only_quads, - const int seed) +void BM_mesh_esubdivide(BMesh *bm, + const char edge_hflag, + const float smooth, + const short smooth_falloff, + const bool use_smooth_even, + const float fractal, + const float along_normal, + const int numcuts, + const int seltype, + const int cornertype, + const short use_single_edge, + const short use_grid_fill, + const short use_only_quads, + const int seed) { - BMOperator op; - - /* use_sphere isnt exposed here since its only used for new primitives */ - BMO_op_initf(bm, &op, BMO_FLAG_DEFAULTS, - "subdivide_edges edges=%he " - "smooth=%f smooth_falloff=%i use_smooth_even=%b " - "fractal=%f along_normal=%f " - "cuts=%i " - "quad_corner_type=%i " - "use_single_edge=%b use_grid_fill=%b " - "use_only_quads=%b " - "seed=%i", - edge_hflag, - smooth, smooth_falloff, use_smooth_even, - fractal, along_normal, - numcuts, - cornertype, - use_single_edge, use_grid_fill, - use_only_quads, - seed); - - BMO_op_exec(bm, &op); - - switch (seltype) { - case SUBDIV_SELECT_NONE: - break; - case SUBDIV_SELECT_ORIG: - /* set the newly created data to be selected */ - BMO_slot_buffer_hflag_enable(bm, op.slots_out, "geom_inner.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true); - BM_mesh_select_flush(bm); - break; - case SUBDIV_SELECT_INNER: - BMO_slot_buffer_hflag_enable(bm, op.slots_out, "geom_inner.out", BM_EDGE | BM_VERT, BM_ELEM_SELECT, true); - break; - case SUBDIV_SELECT_LOOPCUT: - /* deselect input */ - BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); - BMO_slot_buffer_hflag_enable(bm, op.slots_out, "geom_inner.out", BM_EDGE, BM_ELEM_SELECT, true); - break; - } - - BMO_op_finish(bm, &op); + BMOperator op; + + /* use_sphere isnt exposed here since its only used for new primitives */ + BMO_op_initf(bm, + &op, + BMO_FLAG_DEFAULTS, + "subdivide_edges edges=%he " + "smooth=%f smooth_falloff=%i use_smooth_even=%b " + "fractal=%f along_normal=%f " + "cuts=%i " + "quad_corner_type=%i " + "use_single_edge=%b use_grid_fill=%b " + "use_only_quads=%b " + "seed=%i", + edge_hflag, + smooth, + smooth_falloff, + use_smooth_even, + fractal, + along_normal, + numcuts, + cornertype, + use_single_edge, + use_grid_fill, + use_only_quads, + seed); + + BMO_op_exec(bm, &op); + + switch (seltype) { + case SUBDIV_SELECT_NONE: + break; + case SUBDIV_SELECT_ORIG: + /* set the newly created data to be selected */ + BMO_slot_buffer_hflag_enable( + bm, op.slots_out, "geom_inner.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true); + BM_mesh_select_flush(bm); + break; + case SUBDIV_SELECT_INNER: + BMO_slot_buffer_hflag_enable( + bm, op.slots_out, "geom_inner.out", BM_EDGE | BM_VERT, BM_ELEM_SELECT, true); + break; + case SUBDIV_SELECT_LOOPCUT: + /* deselect input */ + BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); + BMO_slot_buffer_hflag_enable( + bm, op.slots_out, "geom_inner.out", BM_EDGE, BM_ELEM_SELECT, true); + break; + } + + BMO_op_finish(bm, &op); } void bmo_bisect_edges_exec(BMesh *bm, BMOperator *op) { - BMOIter siter; - BMEdge *e; - SubDParams params = {0}; + BMOIter siter; + BMEdge *e; + SubDParams params = {0}; - params.numcuts = BMO_slot_int_get(op->slots_in, "cuts"); - params.op = op; - params.slot_edge_percents = BMO_slot_get(op->slots_in, "edge_percents"); + params.numcuts = BMO_slot_int_get(op->slots_in, "cuts"); + params.op = op; + params.slot_edge_percents = BMO_slot_get(op->slots_in, "edge_percents"); - BM_data_layer_add(bm, &bm->vdata, CD_SHAPEKEY); + BM_data_layer_add(bm, &bm->vdata, CD_SHAPEKEY); - bmo_subd_init_shape_info(bm, ¶ms); + bmo_subd_init_shape_info(bm, ¶ms); - /* tag edges in map */ - BMO_slot_map_to_flag(bm, op->slots_in, "edge_percents", BM_EDGE, EDGE_PERCENT); + /* tag edges in map */ + BMO_slot_map_to_flag(bm, op->slots_in, "edge_percents", BM_EDGE, EDGE_PERCENT); - /* go through and split edges */ - BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { - bm_subdivide_multicut(bm, e, ¶ms, e->v1, e->v2); - } + /* go through and split edges */ + BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { + bm_subdivide_multicut(bm, e, ¶ms, e->v1, e->v2); + } - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom_split.out", BM_ALL_NOLOOP, ELE_SPLIT); + BMO_slot_buffer_from_enabled_flag( + bm, op, op->slots_out, "geom_split.out", BM_ALL_NOLOOP, ELE_SPLIT); - BM_data_layer_free_n(bm, &bm->vdata, CD_SHAPEKEY, params.shape_info.tmpkey); + BM_data_layer_free_n(bm, &bm->vdata, CD_SHAPEKEY, params.shape_info.tmpkey); } 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); + } } diff --git a/source/blender/bmesh/operators/bmo_symmetrize.c b/source/blender/bmesh/operators/bmo_symmetrize.c index 0df3759ae8b..31c61f28ea9 100644 --- a/source/blender/bmesh/operators/bmo_symmetrize.c +++ b/source/blender/bmesh/operators/bmo_symmetrize.c @@ -30,74 +30,77 @@ void bmo_symmetrize_exec(BMesh *bm, BMOperator *op) { - const float dist = BMO_slot_float_get(op->slots_in, "dist"); - const int direction = BMO_slot_int_get(op->slots_in, "direction"); - const int axis = direction % 3; + const float dist = BMO_slot_float_get(op->slots_in, "dist"); + const int direction = BMO_slot_int_get(op->slots_in, "direction"); + const int axis = direction % 3; - BMOperator op_bisect; - BMOperator op_dupe; - BMOperator op_weld; + BMOperator op_bisect; + BMOperator op_dupe; + BMOperator op_weld; - BMOpSlot *slot_vertmap; - BMOpSlot *slot_targetmap; + BMOpSlot *slot_vertmap; + BMOpSlot *slot_targetmap; - float plane_no[3]; - float scale[3]; + float plane_no[3]; + float scale[3]; - BMOIter siter; - BMVert *v; + BMOIter siter; + BMVert *v; - copy_v3_fl(plane_no, 0.0f); - copy_v3_fl(scale, 1.0f); + copy_v3_fl(plane_no, 0.0f); + copy_v3_fl(scale, 1.0f); - plane_no[axis] = direction > 2 ? -1.0f : 1.0f; - scale[axis] *= -1.0f; + plane_no[axis] = direction > 2 ? -1.0f : 1.0f; + scale[axis] *= -1.0f; - /* Cut in half */ - BMO_op_initf(bm, &op_bisect, op->flag, - "bisect_plane geom=%s plane_no=%v dist=%f clear_outer=%b use_snap_center=%b", - op, "input", plane_no, dist, true, true); + /* Cut in half */ + BMO_op_initf(bm, + &op_bisect, + op->flag, + "bisect_plane geom=%s plane_no=%v dist=%f clear_outer=%b use_snap_center=%b", + op, + "input", + plane_no, + dist, + true, + true); - BMO_op_exec(bm, &op_bisect); + BMO_op_exec(bm, &op_bisect); - /* Duplicate */ - BMO_op_initf(bm, &op_dupe, op->flag, - "duplicate geom=%S", - &op_bisect, "geom.out"); + /* Duplicate */ + BMO_op_initf(bm, &op_dupe, op->flag, "duplicate geom=%S", &op_bisect, "geom.out"); - BMO_op_exec(bm, &op_dupe); + BMO_op_exec(bm, &op_dupe); - /* Flag for output (some will be merged) */ - BMO_slot_buffer_flag_enable(bm, op_bisect.slots_out, "geom.out", BM_ALL_NOLOOP, ELE_OUT); - BMO_slot_buffer_flag_enable(bm, op_dupe.slots_out, "geom.out", BM_ALL_NOLOOP, ELE_OUT); + /* Flag for output (some will be merged) */ + BMO_slot_buffer_flag_enable(bm, op_bisect.slots_out, "geom.out", BM_ALL_NOLOOP, ELE_OUT); + BMO_slot_buffer_flag_enable(bm, op_dupe.slots_out, "geom.out", BM_ALL_NOLOOP, ELE_OUT); + BMO_op_callf(bm, op->flag, "scale verts=%S vec=%v", &op_dupe, "geom.out", scale); - BMO_op_callf(bm, op->flag, "scale verts=%S vec=%v", &op_dupe, "geom.out", scale); + /* important 'flip_multires' is disabled, + * otherwise multi-res data will be reversed, see: T47788 */ + BMO_op_callf(bm, op->flag, "reverse_faces faces=%S", &op_dupe, "geom.out"); - /* important 'flip_multires' is disabled, - * otherwise multi-res data will be reversed, see: T47788 */ - BMO_op_callf(bm, op->flag, "reverse_faces faces=%S", &op_dupe, "geom.out"); + /* Weld verts */ + BMO_op_init(bm, &op_weld, op->flag, "weld_verts"); + slot_vertmap = BMO_slot_get(op_dupe.slots_out, "vert_map.out"); + slot_targetmap = BMO_slot_get(op_weld.slots_in, "targetmap"); - /* Weld verts */ - BMO_op_init(bm, &op_weld, op->flag, "weld_verts"); + BMO_ITER (v, &siter, op_bisect.slots_out, "geom_cut.out", BM_VERT) { + BMVert *v_dupe = BMO_slot_map_elem_get(slot_vertmap, v); + BMO_slot_map_elem_insert(&op_weld, slot_targetmap, v_dupe, v); + } - slot_vertmap = BMO_slot_get(op_dupe.slots_out, "vert_map.out"); - slot_targetmap = BMO_slot_get(op_weld.slots_in, "targetmap"); + BMO_op_exec(bm, &op_weld); - BMO_ITER (v, &siter, op_bisect.slots_out, "geom_cut.out", BM_VERT) { - BMVert *v_dupe = BMO_slot_map_elem_get(slot_vertmap, v); - BMO_slot_map_elem_insert(&op_weld, slot_targetmap, v_dupe, v); - } + /* Cleanup */ + BMO_op_finish(bm, &op_weld); - BMO_op_exec(bm, &op_weld); + BMO_op_finish(bm, &op_dupe); + BMO_op_finish(bm, &op_bisect); - /* Cleanup */ - BMO_op_finish(bm, &op_weld); - - BMO_op_finish(bm, &op_dupe); - BMO_op_finish(bm, &op_bisect); - - /* Create output */ - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, ELE_OUT); + /* Create output */ + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, ELE_OUT); } diff --git a/source/blender/bmesh/operators/bmo_triangulate.c b/source/blender/bmesh/operators/bmo_triangulate.c index 35f5c40a213..f2a4f85acf9 100644 --- a/source/blender/bmesh/operators/bmo_triangulate.c +++ b/source/blender/bmesh/operators/bmo_triangulate.c @@ -32,240 +32,241 @@ #include "bmesh_tools.h" #include "intern/bmesh_operators_private.h" - -#define ELE_NEW 1 -#define EDGE_MARK 4 +#define ELE_NEW 1 +#define EDGE_MARK 4 void bmo_triangulate_exec(BMesh *bm, BMOperator *op) { - const int quad_method = BMO_slot_int_get(op->slots_in, "quad_method"); - const int ngon_method = BMO_slot_int_get(op->slots_in, "ngon_method"); - - BMOpSlot *slot_facemap_out = BMO_slot_get(op->slots_out, "face_map.out"); - BMOpSlot *slot_facemap_double_out = BMO_slot_get(op->slots_out, "face_map_double.out"); + const int quad_method = BMO_slot_int_get(op->slots_in, "quad_method"); + const int ngon_method = BMO_slot_int_get(op->slots_in, "ngon_method"); - BM_mesh_elem_hflag_disable_all(bm, BM_FACE | BM_EDGE, BM_ELEM_TAG, false); - BMO_slot_buffer_hflag_enable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false); + BMOpSlot *slot_facemap_out = BMO_slot_get(op->slots_out, "face_map.out"); + BMOpSlot *slot_facemap_double_out = BMO_slot_get(op->slots_out, "face_map_double.out"); - BM_mesh_triangulate(bm, quad_method, ngon_method, 4, true, op, slot_facemap_out, slot_facemap_double_out); + BM_mesh_elem_hflag_disable_all(bm, BM_FACE | BM_EDGE, BM_ELEM_TAG, false); + BMO_slot_buffer_hflag_enable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false); - BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "edges.out", BM_EDGE, BM_ELEM_TAG); - BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG); + BM_mesh_triangulate( + bm, quad_method, ngon_method, 4, true, op, slot_facemap_out, slot_facemap_double_out); + BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "edges.out", BM_EDGE, BM_ELEM_TAG); + BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG); } struct SortNormal { - float value; /* keep first */ - float no[3]; + float value; /* keep first */ + float no[3]; }; void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op) { - const bool use_beauty = BMO_slot_bool_get(op->slots_in, "use_beauty"); - const bool use_dissolve = BMO_slot_bool_get(op->slots_in, "use_dissolve"); - BMOIter siter; - BMEdge *e; - ScanFillContext sf_ctx; - /* ScanFillEdge *sf_edge; */ /* UNUSED */ - ScanFillFace *sf_tri; - GHash *sf_vert_map; - float normal[3]; - const int scanfill_flag = BLI_SCANFILL_CALC_HOLES | BLI_SCANFILL_CALC_POLYS | BLI_SCANFILL_CALC_LOOSE; - uint nors_tot; - bool calc_winding = false; - - sf_vert_map = BLI_ghash_ptr_new_ex(__func__, BMO_slot_buffer_count(op->slots_in, "edges")); - - BMO_slot_vec_get(op->slots_in, "normal", normal); - - BLI_scanfill_begin(&sf_ctx); - - BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { - ScanFillVert *sf_verts[2]; - BMVert **e_verts = &e->v1; - uint i; - - BMO_edge_flag_enable(bm, e, EDGE_MARK); - - calc_winding = (calc_winding || BM_edge_is_boundary(e)); - - for (i = 0; i < 2; i++) { - if ((sf_verts[i] = BLI_ghash_lookup(sf_vert_map, e_verts[i])) == NULL) { - sf_verts[i] = BLI_scanfill_vert_add(&sf_ctx, e_verts[i]->co); - sf_verts[i]->tmp.p = e_verts[i]; - BLI_ghash_insert(sf_vert_map, e_verts[i], sf_verts[i]); - } - } - - /* sf_edge = */ BLI_scanfill_edge_add(&sf_ctx, UNPACK2(sf_verts)); - /* sf_edge->tmp.p = e; */ /* UNUSED */ - } - nors_tot = BLI_ghash_len(sf_vert_map); - BLI_ghash_free(sf_vert_map, NULL, NULL); - - - if (is_zero_v3(normal)) { - /* calculate the normal from the cross product of vert-edge pairs. - * Since we don't know winding, just accumulate */ - ScanFillVert *sf_vert; - struct SortNormal *nors; - uint i; - bool is_degenerate = true; - - nors = MEM_mallocN(sizeof(*nors) * nors_tot, __func__); - - for (sf_vert = sf_ctx.fillvertbase.first, i = 0; sf_vert; sf_vert = sf_vert->next, i++) { - BMVert *v = sf_vert->tmp.p; - BMIter eiter; - BMEdge *e_pair[2]; - uint e_index = 0; - - nors[i].value = -1.0f; - - /* only use if 'is_degenerate' stays true */ - add_v3_v3(normal, v->no); - - BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (BMO_edge_flag_test(bm, e, EDGE_MARK)) { - if (e_index == 2) { - e_index = 0; - break; - } - e_pair[e_index++] = e; - } - } - - if (e_index == 2) { - float dir_a[3], dir_b[3]; - - is_degenerate = false; - - sub_v3_v3v3(dir_a, v->co, BM_edge_other_vert(e_pair[0], v)->co); - sub_v3_v3v3(dir_b, v->co, BM_edge_other_vert(e_pair[1], v)->co); - - cross_v3_v3v3(nors[i].no, dir_a, dir_b); - nors[i].value = len_squared_v3(nors[i].no); - - /* only to get deterministic behavior (for initial normal) */ - if (len_squared_v3(dir_a) > len_squared_v3(dir_b)) { - negate_v3(nors[i].no); - } - } - } - - if (UNLIKELY(is_degenerate)) { - /* no vertices have 2 edges? - * in this case fall back to the average vertex normals */ - } - else { - qsort(nors, nors_tot, sizeof(*nors), BLI_sortutil_cmp_float_reverse); - - copy_v3_v3(normal, nors[0].no); - for (i = 0; i < nors_tot; i++) { - if (UNLIKELY(nors[i].value == -1.0f)) { - break; - } - if (dot_v3v3(normal, nors[i].no) < 0.0f) { - negate_v3(nors[i].no); - } - add_v3_v3(normal, nors[i].no); - } - normalize_v3(normal); - } - - MEM_freeN(nors); - } - else { - calc_winding = false; - } - - /* in this case we almost certainly have degenerate geometry, - * better set a fallback value as a last resort */ - if (UNLIKELY(normalize_v3(normal) == 0.0f)) { - normal[2] = 1.0f; - } - - BLI_scanfill_calc_ex(&sf_ctx, scanfill_flag, normal); - - - /* if we have existing faces, base winding on those */ - if (calc_winding) { - int winding_votes = 0; - for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) { - BMVert *v_tri[3] = {sf_tri->v1->tmp.p, sf_tri->v2->tmp.p, sf_tri->v3->tmp.p}; - uint i, i_prev; - - for (i = 0, i_prev = 2; i < 3; i_prev = i++) { - e = BM_edge_exists(v_tri[i], v_tri[i_prev]); - if (e && BM_edge_is_boundary(e) && BMO_edge_flag_test(bm, e, EDGE_MARK)) { - winding_votes += (e->l->v == v_tri[i]) ? 1 : -1; - } - } - } - - if (winding_votes < 0) { - for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) { - SWAP(struct ScanFillVert *, sf_tri->v2, sf_tri->v3); - } - } - } - - - for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) { - BMFace *f; - BMLoop *l; - BMIter liter; - - f = BM_face_create_quad_tri(bm, - sf_tri->v1->tmp.p, sf_tri->v2->tmp.p, sf_tri->v3->tmp.p, NULL, - NULL, BM_CREATE_NO_DOUBLE); - - BMO_face_flag_enable(bm, f, ELE_NEW); - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - if (!BMO_edge_flag_test(bm, l->e, EDGE_MARK)) { - BMO_edge_flag_enable(bm, l->e, ELE_NEW); - } - } - } - - BLI_scanfill_end(&sf_ctx); - - if (use_beauty) { - BMOperator bmop; - - BMO_op_initf(bm, &bmop, op->flag, "beautify_fill faces=%ff edges=%Fe", ELE_NEW, EDGE_MARK); - BMO_op_exec(bm, &bmop); - BMO_slot_buffer_flag_enable(bm, bmop.slots_out, "geom.out", BM_FACE | BM_EDGE, ELE_NEW); - BMO_op_finish(bm, &bmop); - } - - if (use_dissolve) { - BMEdge *e_next; - BMIter iter; - - BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) { - if (BMO_edge_flag_test(bm, e, ELE_NEW)) { - /* in rare cases the edges face will have already been removed from the edge */ - if (LIKELY(BM_edge_is_manifold(e))) { - BMFace *f_new = BM_faces_join_pair(bm, e->l, e->l->radial_next, false); - if (f_new) { - BMO_face_flag_enable(bm, f_new, ELE_NEW); - BM_edge_kill(bm, e); - } - else { - BMO_error_clear(bm); - } - } - else if (e->l == NULL) { - BM_edge_kill(bm, e); - } - else { - /* Edges with 1 or 3+ faces attached, - * most likely caused by a degenerate mesh. */ - } - } - } - } - - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_EDGE | BM_FACE, ELE_NEW); + const bool use_beauty = BMO_slot_bool_get(op->slots_in, "use_beauty"); + const bool use_dissolve = BMO_slot_bool_get(op->slots_in, "use_dissolve"); + BMOIter siter; + BMEdge *e; + ScanFillContext sf_ctx; + /* ScanFillEdge *sf_edge; */ /* UNUSED */ + ScanFillFace *sf_tri; + GHash *sf_vert_map; + float normal[3]; + const int scanfill_flag = BLI_SCANFILL_CALC_HOLES | BLI_SCANFILL_CALC_POLYS | + BLI_SCANFILL_CALC_LOOSE; + uint nors_tot; + bool calc_winding = false; + + sf_vert_map = BLI_ghash_ptr_new_ex(__func__, BMO_slot_buffer_count(op->slots_in, "edges")); + + BMO_slot_vec_get(op->slots_in, "normal", normal); + + BLI_scanfill_begin(&sf_ctx); + + BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { + ScanFillVert *sf_verts[2]; + BMVert **e_verts = &e->v1; + uint i; + + BMO_edge_flag_enable(bm, e, EDGE_MARK); + + calc_winding = (calc_winding || BM_edge_is_boundary(e)); + + for (i = 0; i < 2; i++) { + if ((sf_verts[i] = BLI_ghash_lookup(sf_vert_map, e_verts[i])) == NULL) { + sf_verts[i] = BLI_scanfill_vert_add(&sf_ctx, e_verts[i]->co); + sf_verts[i]->tmp.p = e_verts[i]; + BLI_ghash_insert(sf_vert_map, e_verts[i], sf_verts[i]); + } + } + + /* sf_edge = */ BLI_scanfill_edge_add(&sf_ctx, UNPACK2(sf_verts)); + /* sf_edge->tmp.p = e; */ /* UNUSED */ + } + nors_tot = BLI_ghash_len(sf_vert_map); + BLI_ghash_free(sf_vert_map, NULL, NULL); + + if (is_zero_v3(normal)) { + /* calculate the normal from the cross product of vert-edge pairs. + * Since we don't know winding, just accumulate */ + ScanFillVert *sf_vert; + struct SortNormal *nors; + uint i; + bool is_degenerate = true; + + nors = MEM_mallocN(sizeof(*nors) * nors_tot, __func__); + + for (sf_vert = sf_ctx.fillvertbase.first, i = 0; sf_vert; sf_vert = sf_vert->next, i++) { + BMVert *v = sf_vert->tmp.p; + BMIter eiter; + BMEdge *e_pair[2]; + uint e_index = 0; + + nors[i].value = -1.0f; + + /* only use if 'is_degenerate' stays true */ + add_v3_v3(normal, v->no); + + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + if (BMO_edge_flag_test(bm, e, EDGE_MARK)) { + if (e_index == 2) { + e_index = 0; + break; + } + e_pair[e_index++] = e; + } + } + + if (e_index == 2) { + float dir_a[3], dir_b[3]; + + is_degenerate = false; + + sub_v3_v3v3(dir_a, v->co, BM_edge_other_vert(e_pair[0], v)->co); + sub_v3_v3v3(dir_b, v->co, BM_edge_other_vert(e_pair[1], v)->co); + + cross_v3_v3v3(nors[i].no, dir_a, dir_b); + nors[i].value = len_squared_v3(nors[i].no); + + /* only to get deterministic behavior (for initial normal) */ + if (len_squared_v3(dir_a) > len_squared_v3(dir_b)) { + negate_v3(nors[i].no); + } + } + } + + if (UNLIKELY(is_degenerate)) { + /* no vertices have 2 edges? + * in this case fall back to the average vertex normals */ + } + else { + qsort(nors, nors_tot, sizeof(*nors), BLI_sortutil_cmp_float_reverse); + + copy_v3_v3(normal, nors[0].no); + for (i = 0; i < nors_tot; i++) { + if (UNLIKELY(nors[i].value == -1.0f)) { + break; + } + if (dot_v3v3(normal, nors[i].no) < 0.0f) { + negate_v3(nors[i].no); + } + add_v3_v3(normal, nors[i].no); + } + normalize_v3(normal); + } + + MEM_freeN(nors); + } + else { + calc_winding = false; + } + + /* in this case we almost certainly have degenerate geometry, + * better set a fallback value as a last resort */ + if (UNLIKELY(normalize_v3(normal) == 0.0f)) { + normal[2] = 1.0f; + } + + BLI_scanfill_calc_ex(&sf_ctx, scanfill_flag, normal); + + /* if we have existing faces, base winding on those */ + if (calc_winding) { + int winding_votes = 0; + for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) { + BMVert *v_tri[3] = {sf_tri->v1->tmp.p, sf_tri->v2->tmp.p, sf_tri->v3->tmp.p}; + uint i, i_prev; + + for (i = 0, i_prev = 2; i < 3; i_prev = i++) { + e = BM_edge_exists(v_tri[i], v_tri[i_prev]); + if (e && BM_edge_is_boundary(e) && BMO_edge_flag_test(bm, e, EDGE_MARK)) { + winding_votes += (e->l->v == v_tri[i]) ? 1 : -1; + } + } + } + + if (winding_votes < 0) { + for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) { + SWAP(struct ScanFillVert *, sf_tri->v2, sf_tri->v3); + } + } + } + + for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) { + BMFace *f; + BMLoop *l; + BMIter liter; + + f = BM_face_create_quad_tri(bm, + sf_tri->v1->tmp.p, + sf_tri->v2->tmp.p, + sf_tri->v3->tmp.p, + NULL, + NULL, + BM_CREATE_NO_DOUBLE); + + BMO_face_flag_enable(bm, f, ELE_NEW); + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + if (!BMO_edge_flag_test(bm, l->e, EDGE_MARK)) { + BMO_edge_flag_enable(bm, l->e, ELE_NEW); + } + } + } + + BLI_scanfill_end(&sf_ctx); + + if (use_beauty) { + BMOperator bmop; + + BMO_op_initf(bm, &bmop, op->flag, "beautify_fill faces=%ff edges=%Fe", ELE_NEW, EDGE_MARK); + BMO_op_exec(bm, &bmop); + BMO_slot_buffer_flag_enable(bm, bmop.slots_out, "geom.out", BM_FACE | BM_EDGE, ELE_NEW); + BMO_op_finish(bm, &bmop); + } + + if (use_dissolve) { + BMEdge *e_next; + BMIter iter; + + BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) { + if (BMO_edge_flag_test(bm, e, ELE_NEW)) { + /* in rare cases the edges face will have already been removed from the edge */ + if (LIKELY(BM_edge_is_manifold(e))) { + BMFace *f_new = BM_faces_join_pair(bm, e->l, e->l->radial_next, false); + if (f_new) { + BMO_face_flag_enable(bm, f_new, ELE_NEW); + BM_edge_kill(bm, e); + } + else { + BMO_error_clear(bm); + } + } + else if (e->l == NULL) { + BM_edge_kill(bm, e); + } + else { + /* Edges with 1 or 3+ faces attached, + * most likely caused by a degenerate mesh. */ + } + } + } + } + + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_EDGE | BM_FACE, ELE_NEW); } diff --git a/source/blender/bmesh/operators/bmo_unsubdivide.c b/source/blender/bmesh/operators/bmo_unsubdivide.c index cd95cda3088..c5de6df34a7 100644 --- a/source/blender/bmesh/operators/bmo_unsubdivide.c +++ b/source/blender/bmesh/operators/bmo_unsubdivide.c @@ -34,24 +34,24 @@ */ void bmo_unsubdivide_exec(BMesh *bm, BMOperator *op) { - BMVert *v; - BMIter iter; - - const int iterations = max_ii(1, BMO_slot_int_get(op->slots_in, "iterations")); - - BMOpSlot *vinput = BMO_slot_get(op->slots_in, "verts"); - BMVert **vinput_arr = (BMVert **)vinput->data.buf; - int v_index; - - /* tag verts */ - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - BM_elem_flag_disable(v, BM_ELEM_TAG); - } - for (v_index = 0; v_index < vinput->len; v_index++) { - v = vinput_arr[v_index]; - BM_elem_flag_enable(v, BM_ELEM_TAG); - } - - /* do all the real work here */ - BM_mesh_decimate_unsubdivide_ex(bm, iterations, true); + BMVert *v; + BMIter iter; + + const int iterations = max_ii(1, BMO_slot_int_get(op->slots_in, "iterations")); + + BMOpSlot *vinput = BMO_slot_get(op->slots_in, "verts"); + BMVert **vinput_arr = (BMVert **)vinput->data.buf; + int v_index; + + /* tag verts */ + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + BM_elem_flag_disable(v, BM_ELEM_TAG); + } + for (v_index = 0; v_index < vinput->len; v_index++) { + v = vinput_arr[v_index]; + BM_elem_flag_enable(v, BM_ELEM_TAG); + } + + /* do all the real work here */ + BM_mesh_decimate_unsubdivide_ex(bm, iterations, true); } diff --git a/source/blender/bmesh/operators/bmo_utils.c b/source/blender/bmesh/operators/bmo_utils.c index 2439b5fe2b2..6495f2b0afe 100644 --- a/source/blender/bmesh/operators/bmo_utils.c +++ b/source/blender/bmesh/operators/bmo_utils.c @@ -38,396 +38,391 @@ void bmo_create_vert_exec(BMesh *bm, BMOperator *op) { - float vec[3]; + float vec[3]; - BMO_slot_vec_get(op->slots_in, "co", vec); + BMO_slot_vec_get(op->slots_in, "co", vec); - BMO_vert_flag_enable(bm, BM_vert_create(bm, vec, NULL, BM_CREATE_NOP), ELE_NEW); - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "vert.out", BM_VERT, ELE_NEW); + BMO_vert_flag_enable(bm, BM_vert_create(bm, vec, NULL, BM_CREATE_NOP), ELE_NEW); + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "vert.out", BM_VERT, ELE_NEW); } void bmo_transform_exec(BMesh *UNUSED(bm), BMOperator *op) { - BMOIter iter; - BMVert *v; - float mat[4][4], mat_space[4][4], imat_space[4][4]; + BMOIter iter; + BMVert *v; + float mat[4][4], mat_space[4][4], imat_space[4][4]; - BMO_slot_mat4_get(op->slots_in, "matrix", mat); - BMO_slot_mat4_get(op->slots_in, "space", mat_space); + BMO_slot_mat4_get(op->slots_in, "matrix", mat); + BMO_slot_mat4_get(op->slots_in, "space", mat_space); - if (!is_zero_m4(mat_space)) { - invert_m4_m4(imat_space, mat_space); - mul_m4_series(mat, imat_space, mat, mat_space); - } + if (!is_zero_m4(mat_space)) { + invert_m4_m4(imat_space, mat_space); + mul_m4_series(mat, imat_space, mat, mat_space); + } - BMO_ITER (v, &iter, op->slots_in, "verts", BM_VERT) { - mul_m4_v3(mat, v->co); - } + BMO_ITER (v, &iter, op->slots_in, "verts", BM_VERT) { + mul_m4_v3(mat, v->co); + } } void bmo_translate_exec(BMesh *bm, BMOperator *op) { - float mat[4][4], vec[3]; + float mat[4][4], vec[3]; - BMO_slot_vec_get(op->slots_in, "vec", vec); + BMO_slot_vec_get(op->slots_in, "vec", vec); - unit_m4(mat); - copy_v3_v3(mat[3], vec); + unit_m4(mat); + copy_v3_v3(mat[3], vec); - BMO_op_callf(bm, op->flag, "transform matrix=%m4 space=%s verts=%s", mat, op, "space", op, "verts"); + BMO_op_callf( + bm, op->flag, "transform matrix=%m4 space=%s verts=%s", mat, op, "space", op, "verts"); } void bmo_scale_exec(BMesh *bm, BMOperator *op) { - float mat[3][3], vec[3]; + float mat[3][3], vec[3]; - BMO_slot_vec_get(op->slots_in, "vec", vec); + BMO_slot_vec_get(op->slots_in, "vec", vec); - unit_m3(mat); - mat[0][0] = vec[0]; - mat[1][1] = vec[1]; - mat[2][2] = vec[2]; + unit_m3(mat); + mat[0][0] = vec[0]; + mat[1][1] = vec[1]; + mat[2][2] = vec[2]; - BMO_op_callf(bm, op->flag, "transform matrix=%m3 space=%s verts=%s", mat, op, "space", op, "verts"); + BMO_op_callf( + bm, op->flag, "transform matrix=%m3 space=%s verts=%s", mat, op, "space", op, "verts"); } void bmo_rotate_exec(BMesh *bm, BMOperator *op) { - float center[3]; - float mat[4][4]; + float center[3]; + float mat[4][4]; - BMO_slot_vec_get(op->slots_in, "cent", center); - BMO_slot_mat4_get(op->slots_in, "matrix", mat); - transform_pivot_set_m4(mat, center); + BMO_slot_vec_get(op->slots_in, "cent", center); + BMO_slot_mat4_get(op->slots_in, "matrix", mat); + transform_pivot_set_m4(mat, center); - BMO_op_callf(bm, op->flag, "transform matrix=%m4 space=%s verts=%s", mat, op, "space", op, "verts"); + BMO_op_callf( + bm, op->flag, "transform matrix=%m4 space=%s verts=%s", mat, op, "space", op, "verts"); } void bmo_reverse_faces_exec(BMesh *bm, BMOperator *op) { - const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS); - const bool use_loop_mdisp_flip = BMO_slot_bool_get(op->slots_in, "flip_multires"); - BMOIter siter; - BMFace *f; - - BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) { - BM_face_normal_flip_ex(bm, f, cd_loop_mdisp_offset, use_loop_mdisp_flip); - } + const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS); + const bool use_loop_mdisp_flip = BMO_slot_bool_get(op->slots_in, "flip_multires"); + BMOIter siter; + BMFace *f; + + BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) { + BM_face_normal_flip_ex(bm, f, cd_loop_mdisp_offset, use_loop_mdisp_flip); + } } - -#define SEL_FLAG 1 -#define SEL_ORIG 2 +#define SEL_FLAG 1 +#define SEL_ORIG 2 static void bmo_face_flag_set_flush(BMesh *bm, BMFace *f, const short oflag, const bool value) { - BMLoop *l_iter; - BMLoop *l_first; - - BMO_face_flag_set(bm, f, oflag, value); - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - BMO_edge_flag_set(bm, l_iter->e, oflag, value); - BMO_vert_flag_set(bm, l_iter->v, oflag, value); - } while ((l_iter = l_iter->next) != l_first); + BMLoop *l_iter; + BMLoop *l_first; + + BMO_face_flag_set(bm, f, oflag, value); + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BMO_edge_flag_set(bm, l_iter->e, oflag, value); + BMO_vert_flag_set(bm, l_iter->v, oflag, value); + } while ((l_iter = l_iter->next) != l_first); } - -static void bmo_region_extend_expand( - BMesh *bm, BMOperator *op, - const bool use_faces, const bool use_faces_step) +static void bmo_region_extend_expand(BMesh *bm, + BMOperator *op, + const bool use_faces, + const bool use_faces_step) { - BMOIter siter; - - if (!use_faces) { - BMVert *v; - - BMO_ITER (v, &siter, op->slots_in, "geom", BM_VERT) { - bool found = false; - - { - BMIter eiter; - BMEdge *e; - - BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (!BMO_edge_flag_test(bm, e, SEL_ORIG) && - !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) - { - found = true; - break; - } - } - } - - if (found) { - if (!use_faces_step) { - BMIter eiter; - BMEdge *e; - - BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (!BMO_edge_flag_test(bm, e, SEL_FLAG) && - !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) - { - BMO_edge_flag_enable(bm, e, SEL_FLAG); - BMO_vert_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG); - } - } - } - else { - BMIter fiter; - BMFace *f; - - BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) { - if (!BMO_face_flag_test(bm, f, SEL_FLAG) && - !BM_elem_flag_test(f, BM_ELEM_HIDDEN)) - { - bmo_face_flag_set_flush(bm, f, SEL_FLAG, true); - } - } - - /* handle wire edges (when stepping over faces) */ - { - BMIter eiter; - BMEdge *e; - BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (BM_edge_is_wire(e)) { - if (!BMO_edge_flag_test(bm, e, SEL_FLAG) && - !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) - { - BMO_edge_flag_enable(bm, e, SEL_FLAG); - BMO_vert_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG); - } - } - } - } - } - } - } - } - else { - BMFace *f; - - BMO_ITER (f, &siter, op->slots_in, "geom", BM_FACE) { - BMIter liter; - BMLoop *l; - - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - if (!use_faces_step) { - BMIter fiter; - BMFace *f_other; - - BM_ITER_ELEM (f_other, &fiter, l->e, BM_FACES_OF_EDGE) { - if (!BMO_face_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG) && - !BM_elem_flag_test(f_other, BM_ELEM_HIDDEN)) - { - BMO_face_flag_enable(bm, f_other, SEL_FLAG); - } - } - } - else { - BMIter fiter; - BMFace *f_other; - - BM_ITER_ELEM (f_other, &fiter, l->v, BM_FACES_OF_VERT) { - if (!BMO_face_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG) && - !BM_elem_flag_test(f_other, BM_ELEM_HIDDEN)) - { - BMO_face_flag_enable(bm, f_other, SEL_FLAG); - } - } - } - } - } - } + BMOIter siter; + + if (!use_faces) { + BMVert *v; + + BMO_ITER (v, &siter, op->slots_in, "geom", BM_VERT) { + bool found = false; + + { + BMIter eiter; + BMEdge *e; + + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + if (!BMO_edge_flag_test(bm, e, SEL_ORIG) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { + found = true; + break; + } + } + } + + if (found) { + if (!use_faces_step) { + BMIter eiter; + BMEdge *e; + + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + if (!BMO_edge_flag_test(bm, e, SEL_FLAG) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { + BMO_edge_flag_enable(bm, e, SEL_FLAG); + BMO_vert_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG); + } + } + } + else { + BMIter fiter; + BMFace *f; + + BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) { + if (!BMO_face_flag_test(bm, f, SEL_FLAG) && !BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + bmo_face_flag_set_flush(bm, f, SEL_FLAG, true); + } + } + + /* handle wire edges (when stepping over faces) */ + { + BMIter eiter; + BMEdge *e; + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + if (BM_edge_is_wire(e)) { + if (!BMO_edge_flag_test(bm, e, SEL_FLAG) && + !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { + BMO_edge_flag_enable(bm, e, SEL_FLAG); + BMO_vert_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG); + } + } + } + } + } + } + } + } + else { + BMFace *f; + + BMO_ITER (f, &siter, op->slots_in, "geom", BM_FACE) { + BMIter liter; + BMLoop *l; + + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + if (!use_faces_step) { + BMIter fiter; + BMFace *f_other; + + BM_ITER_ELEM (f_other, &fiter, l->e, BM_FACES_OF_EDGE) { + if (!BMO_face_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG) && + !BM_elem_flag_test(f_other, BM_ELEM_HIDDEN)) { + BMO_face_flag_enable(bm, f_other, SEL_FLAG); + } + } + } + else { + BMIter fiter; + BMFace *f_other; + + BM_ITER_ELEM (f_other, &fiter, l->v, BM_FACES_OF_VERT) { + if (!BMO_face_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG) && + !BM_elem_flag_test(f_other, BM_ELEM_HIDDEN)) { + BMO_face_flag_enable(bm, f_other, SEL_FLAG); + } + } + } + } + } + } } -static void bmo_region_extend_contract( - BMesh *bm, BMOperator *op, - const bool use_faces, const bool use_faces_step) +static void bmo_region_extend_contract(BMesh *bm, + BMOperator *op, + const bool use_faces, + const bool use_faces_step) { - BMOIter siter; - - if (!use_faces) { - BMVert *v; - - BMO_ITER (v, &siter, op->slots_in, "geom", BM_VERT) { - bool found = false; - - if (!use_faces_step) { - BMIter eiter; - BMEdge *e; - - BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (!BMO_edge_flag_test(bm, e, SEL_ORIG)) { - found = true; - break; - } - } - } - else { - BMIter fiter; - BMFace *f; - - BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) { - if (!BMO_face_flag_test(bm, f, SEL_ORIG)) { - found = true; - break; - } - } - - /* handle wire edges (when stepping over faces) */ - if (!found) { - BMIter eiter; - BMEdge *e; - - BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (BM_edge_is_wire(e)) { - if (!BMO_edge_flag_test(bm, e, SEL_ORIG)) { - found = true; - break; - } - } - } - } - } - - if (found) { - BMIter eiter; - BMEdge *e; - - BMO_vert_flag_enable(bm, v, SEL_FLAG); - - BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - BMO_edge_flag_enable(bm, e, SEL_FLAG); - } - } - } - } - else { - BMFace *f; - - BMO_ITER (f, &siter, op->slots_in, "geom", BM_FACE) { - BMIter liter; - BMLoop *l; - - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - - if (!use_faces_step) { - BMIter fiter; - BMFace *f_other; - - BM_ITER_ELEM (f_other, &fiter, l->e, BM_FACES_OF_EDGE) { - if (!BMO_face_flag_test(bm, f_other, SEL_ORIG)) { - BMO_face_flag_enable(bm, f, SEL_FLAG); - break; - } - } - } - else { - BMIter fiter; - BMFace *f_other; - - BM_ITER_ELEM (f_other, &fiter, l->v, BM_FACES_OF_VERT) { - if (!BMO_face_flag_test(bm, f_other, SEL_ORIG)) { - BMO_face_flag_enable(bm, f, SEL_FLAG); - break; - } - } - } - } - } - } + BMOIter siter; + + if (!use_faces) { + BMVert *v; + + BMO_ITER (v, &siter, op->slots_in, "geom", BM_VERT) { + bool found = false; + + if (!use_faces_step) { + BMIter eiter; + BMEdge *e; + + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + if (!BMO_edge_flag_test(bm, e, SEL_ORIG)) { + found = true; + break; + } + } + } + else { + BMIter fiter; + BMFace *f; + + BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) { + if (!BMO_face_flag_test(bm, f, SEL_ORIG)) { + found = true; + break; + } + } + + /* handle wire edges (when stepping over faces) */ + if (!found) { + BMIter eiter; + BMEdge *e; + + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + if (BM_edge_is_wire(e)) { + if (!BMO_edge_flag_test(bm, e, SEL_ORIG)) { + found = true; + break; + } + } + } + } + } + + if (found) { + BMIter eiter; + BMEdge *e; + + BMO_vert_flag_enable(bm, v, SEL_FLAG); + + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + BMO_edge_flag_enable(bm, e, SEL_FLAG); + } + } + } + } + else { + BMFace *f; + + BMO_ITER (f, &siter, op->slots_in, "geom", BM_FACE) { + BMIter liter; + BMLoop *l; + + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + + if (!use_faces_step) { + BMIter fiter; + BMFace *f_other; + + BM_ITER_ELEM (f_other, &fiter, l->e, BM_FACES_OF_EDGE) { + if (!BMO_face_flag_test(bm, f_other, SEL_ORIG)) { + BMO_face_flag_enable(bm, f, SEL_FLAG); + break; + } + } + } + else { + BMIter fiter; + BMFace *f_other; + + BM_ITER_ELEM (f_other, &fiter, l->v, BM_FACES_OF_VERT) { + if (!BMO_face_flag_test(bm, f_other, SEL_ORIG)) { + BMO_face_flag_enable(bm, f, SEL_FLAG); + break; + } + } + } + } + } + } } void bmo_region_extend_exec(BMesh *bm, BMOperator *op) { - const bool use_faces = BMO_slot_bool_get(op->slots_in, "use_faces"); - const bool use_face_step = BMO_slot_bool_get(op->slots_in, "use_face_step"); - const bool constrict = BMO_slot_bool_get(op->slots_in, "use_contract"); + const bool use_faces = BMO_slot_bool_get(op->slots_in, "use_faces"); + const bool use_face_step = BMO_slot_bool_get(op->slots_in, "use_face_step"); + const bool constrict = BMO_slot_bool_get(op->slots_in, "use_contract"); - BMO_slot_buffer_flag_enable(bm, op->slots_in, "geom", BM_ALL_NOLOOP, SEL_ORIG); + BMO_slot_buffer_flag_enable(bm, op->slots_in, "geom", BM_ALL_NOLOOP, SEL_ORIG); - if (constrict) { - bmo_region_extend_contract(bm, op, use_faces, use_face_step); - } - else { - bmo_region_extend_expand(bm, op, use_faces, use_face_step); - } + if (constrict) { + bmo_region_extend_contract(bm, op, use_faces, use_face_step); + } + else { + bmo_region_extend_expand(bm, op, use_faces, use_face_step); + } - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, SEL_FLAG); + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, SEL_FLAG); } void bmo_smooth_vert_exec(BMesh *UNUSED(bm), BMOperator *op) { - BMOIter siter; - BMIter iter; - BMVert *v; - BMEdge *e; - float (*cos)[3] = MEM_mallocN(sizeof(*cos) * BMO_slot_buffer_count(op->slots_in, "verts"), __func__); - float *co, *co2, clip_dist = BMO_slot_float_get(op->slots_in, "clip_dist"); - const float fac = BMO_slot_float_get(op->slots_in, "factor"); - int i, j, clipx, clipy, clipz; - int xaxis, yaxis, zaxis; - - clipx = BMO_slot_bool_get(op->slots_in, "mirror_clip_x"); - clipy = BMO_slot_bool_get(op->slots_in, "mirror_clip_y"); - clipz = BMO_slot_bool_get(op->slots_in, "mirror_clip_z"); - - xaxis = BMO_slot_bool_get(op->slots_in, "use_axis_x"); - yaxis = BMO_slot_bool_get(op->slots_in, "use_axis_y"); - zaxis = BMO_slot_bool_get(op->slots_in, "use_axis_z"); - - i = 0; - BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) { - - co = cos[i]; - zero_v3(co); - - j = 0; - BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { - co2 = BM_edge_other_vert(e, v)->co; - add_v3_v3v3(co, co, co2); - j += 1; - } - - if (!j) { - copy_v3_v3(co, v->co); - i++; - continue; - } - - mul_v3_fl(co, 1.0f / (float)j); - interp_v3_v3v3(co, v->co, co, fac); - - if (clipx && fabsf(v->co[0]) <= clip_dist) { - co[0] = 0.0f; - } - if (clipy && fabsf(v->co[1]) <= clip_dist) { - co[1] = 0.0f; - } - if (clipz && fabsf(v->co[2]) <= clip_dist) { - co[2] = 0.0f; - } - - i++; - } - - i = 0; - BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) { - if (xaxis) { - v->co[0] = cos[i][0]; - } - if (yaxis) { - v->co[1] = cos[i][1]; - } - if (zaxis) { - v->co[2] = cos[i][2]; - } - - i++; - } - - MEM_freeN(cos); + BMOIter siter; + BMIter iter; + BMVert *v; + BMEdge *e; + float(*cos)[3] = MEM_mallocN(sizeof(*cos) * BMO_slot_buffer_count(op->slots_in, "verts"), + __func__); + float *co, *co2, clip_dist = BMO_slot_float_get(op->slots_in, "clip_dist"); + const float fac = BMO_slot_float_get(op->slots_in, "factor"); + int i, j, clipx, clipy, clipz; + int xaxis, yaxis, zaxis; + + clipx = BMO_slot_bool_get(op->slots_in, "mirror_clip_x"); + clipy = BMO_slot_bool_get(op->slots_in, "mirror_clip_y"); + clipz = BMO_slot_bool_get(op->slots_in, "mirror_clip_z"); + + xaxis = BMO_slot_bool_get(op->slots_in, "use_axis_x"); + yaxis = BMO_slot_bool_get(op->slots_in, "use_axis_y"); + zaxis = BMO_slot_bool_get(op->slots_in, "use_axis_z"); + + i = 0; + BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) { + + co = cos[i]; + zero_v3(co); + + j = 0; + BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { + co2 = BM_edge_other_vert(e, v)->co; + add_v3_v3v3(co, co, co2); + j += 1; + } + + if (!j) { + copy_v3_v3(co, v->co); + i++; + continue; + } + + mul_v3_fl(co, 1.0f / (float)j); + interp_v3_v3v3(co, v->co, co, fac); + + if (clipx && fabsf(v->co[0]) <= clip_dist) { + co[0] = 0.0f; + } + if (clipy && fabsf(v->co[1]) <= clip_dist) { + co[1] = 0.0f; + } + if (clipz && fabsf(v->co[2]) <= clip_dist) { + co[2] = 0.0f; + } + + i++; + } + + i = 0; + BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) { + if (xaxis) { + v->co[0] = cos[i][0]; + } + if (yaxis) { + v->co[1] = cos[i][1]; + } + if (zaxis) { + v->co[2] = cos[i][2]; + } + + i++; + } + + MEM_freeN(cos); } /**************************************************************************** * @@ -436,64 +431,64 @@ void bmo_smooth_vert_exec(BMesh *UNUSED(bm), BMOperator *op) void bmo_rotate_uvs_exec(BMesh *bm, BMOperator *op) { - BMOIter fs_iter; /* selected faces iterator */ - BMFace *fs; /* current face */ - BMIter l_iter; /* iteration loop */ - - const bool use_ccw = BMO_slot_bool_get(op->slots_in, "use_ccw"); - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - - if (cd_loop_uv_offset != -1) { - BMO_ITER (fs, &fs_iter, op->slots_in, "faces", BM_FACE) { - if (use_ccw == false) { /* same loops direction */ - BMLoop *lf; /* current face loops */ - MLoopUV *f_luv; /* first face loop uv */ - float p_uv[2]; /* previous uvs */ - float t_uv[2]; /* tmp uvs */ - - int n = 0; - BM_ITER_ELEM (lf, &l_iter, fs, BM_LOOPS_OF_FACE) { - /* current loop uv is the previous loop uv */ - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(lf, cd_loop_uv_offset); - if (n == 0) { - f_luv = luv; - copy_v2_v2(p_uv, luv->uv); - } - else { - copy_v2_v2(t_uv, luv->uv); - copy_v2_v2(luv->uv, p_uv); - copy_v2_v2(p_uv, t_uv); - } - n++; - } - - copy_v2_v2(f_luv->uv, p_uv); - } - else { /* counter loop direction */ - BMLoop *lf; /* current face loops */ - MLoopUV *p_luv; /* previous loop uv */ - MLoopUV *luv; - float t_uv[2]; /* current uvs */ - - int n = 0; - BM_ITER_ELEM (lf, &l_iter, fs, BM_LOOPS_OF_FACE) { - /* previous loop uv is the current loop uv */ - luv = BM_ELEM_CD_GET_VOID_P(lf, cd_loop_uv_offset); - if (n == 0) { - p_luv = luv; - copy_v2_v2(t_uv, luv->uv); - } - else { - copy_v2_v2(p_luv->uv, luv->uv); - p_luv = luv; - } - n++; - } - - copy_v2_v2(luv->uv, t_uv); - } - } - } + BMOIter fs_iter; /* selected faces iterator */ + BMFace *fs; /* current face */ + BMIter l_iter; /* iteration loop */ + + const bool use_ccw = BMO_slot_bool_get(op->slots_in, "use_ccw"); + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + + if (cd_loop_uv_offset != -1) { + BMO_ITER (fs, &fs_iter, op->slots_in, "faces", BM_FACE) { + if (use_ccw == false) { /* same loops direction */ + BMLoop *lf; /* current face loops */ + MLoopUV *f_luv; /* first face loop uv */ + float p_uv[2]; /* previous uvs */ + float t_uv[2]; /* tmp uvs */ + + int n = 0; + BM_ITER_ELEM (lf, &l_iter, fs, BM_LOOPS_OF_FACE) { + /* current loop uv is the previous loop uv */ + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(lf, cd_loop_uv_offset); + if (n == 0) { + f_luv = luv; + copy_v2_v2(p_uv, luv->uv); + } + else { + copy_v2_v2(t_uv, luv->uv); + copy_v2_v2(luv->uv, p_uv); + copy_v2_v2(p_uv, t_uv); + } + n++; + } + + copy_v2_v2(f_luv->uv, p_uv); + } + else { /* counter loop direction */ + BMLoop *lf; /* current face loops */ + MLoopUV *p_luv; /* previous loop uv */ + MLoopUV *luv; + float t_uv[2]; /* current uvs */ + + int n = 0; + BM_ITER_ELEM (lf, &l_iter, fs, BM_LOOPS_OF_FACE) { + /* previous loop uv is the current loop uv */ + luv = BM_ELEM_CD_GET_VOID_P(lf, cd_loop_uv_offset); + if (n == 0) { + p_luv = luv; + copy_v2_v2(t_uv, luv->uv); + } + else { + copy_v2_v2(p_luv->uv, luv->uv); + p_luv = luv; + } + n++; + } + + copy_v2_v2(luv->uv, t_uv); + } + } + } } /**************************************************************************** * @@ -502,35 +497,37 @@ void bmo_rotate_uvs_exec(BMesh *bm, BMOperator *op) static void bm_face_reverse_uvs(BMFace *f, const int cd_loop_uv_offset) { - BMIter iter; - BMLoop *l; - int i; - - float (*uvs)[2] = BLI_array_alloca(uvs, f->len); - - BM_ITER_ELEM_INDEX (l, &iter, f, BM_LOOPS_OF_FACE, i) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - copy_v2_v2(uvs[i], luv->uv); - } - - /* now that we have the uvs in the array, reverse! */ - BM_ITER_ELEM_INDEX (l, &iter, f, BM_LOOPS_OF_FACE, i) { - /* current loop uv is the previous loop uv */ - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - copy_v2_v2(luv->uv, uvs[(f->len - i - 1)]); - } + BMIter iter; + BMLoop *l; + int i; + + float(*uvs)[2] = BLI_array_alloca(uvs, f->len); + + BM_ITER_ELEM_INDEX(l, &iter, f, BM_LOOPS_OF_FACE, i) + { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + copy_v2_v2(uvs[i], luv->uv); + } + + /* now that we have the uvs in the array, reverse! */ + BM_ITER_ELEM_INDEX(l, &iter, f, BM_LOOPS_OF_FACE, i) + { + /* current loop uv is the previous loop uv */ + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + copy_v2_v2(luv->uv, uvs[(f->len - i - 1)]); + } } void bmo_reverse_uvs_exec(BMesh *bm, BMOperator *op) { - BMOIter iter; - BMFace *f; - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - - if (cd_loop_uv_offset != -1) { - BMO_ITER (f, &iter, op->slots_in, "faces", BM_FACE) { - bm_face_reverse_uvs(f, cd_loop_uv_offset); - } - } + BMOIter iter; + BMFace *f; + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + + if (cd_loop_uv_offset != -1) { + BMO_ITER (f, &iter, op->slots_in, "faces", BM_FACE) { + bm_face_reverse_uvs(f, cd_loop_uv_offset); + } + } } /**************************************************************************** * @@ -539,64 +536,64 @@ void bmo_reverse_uvs_exec(BMesh *bm, BMOperator *op) void bmo_rotate_colors_exec(BMesh *bm, BMOperator *op) { - BMOIter fs_iter; /* selected faces iterator */ - BMFace *fs; /* current face */ - BMIter l_iter; /* iteration loop */ - - const bool use_ccw = BMO_slot_bool_get(op->slots_in, "use_ccw"); - const int cd_loop_color_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL); - - if (cd_loop_color_offset != -1) { - BMO_ITER (fs, &fs_iter, op->slots_in, "faces", BM_FACE) { - if (use_ccw == false) { /* same loops direction */ - BMLoop *lf; /* current face loops */ - MLoopCol *f_lcol; /* first face loop color */ - MLoopCol p_col; /* previous color */ - MLoopCol t_col; /* tmp color */ - - int n = 0; - BM_ITER_ELEM (lf, &l_iter, fs, BM_LOOPS_OF_FACE) { - /* current loop color is the previous loop color */ - MLoopCol *lcol = BM_ELEM_CD_GET_VOID_P(lf, cd_loop_color_offset); - if (n == 0) { - f_lcol = lcol; - p_col = *lcol; - } - else { - t_col = *lcol; - *lcol = p_col; - p_col = t_col; - } - n++; - } - - *f_lcol = p_col; - } - else { /* counter loop direction */ - BMLoop *lf; /* current face loops */ - MLoopCol *p_lcol; /* previous loop color */ - MLoopCol *lcol; - MLoopCol t_col; /* current color */ - - int n = 0; - BM_ITER_ELEM (lf, &l_iter, fs, BM_LOOPS_OF_FACE) { - /* previous loop color is the current loop color */ - lcol = BM_ELEM_CD_GET_VOID_P(lf, cd_loop_color_offset); - if (n == 0) { - p_lcol = lcol; - t_col = *lcol; - } - else { - *p_lcol = *lcol; - p_lcol = lcol; - } - n++; - } - - *lcol = t_col; - } - } - } + BMOIter fs_iter; /* selected faces iterator */ + BMFace *fs; /* current face */ + BMIter l_iter; /* iteration loop */ + + const bool use_ccw = BMO_slot_bool_get(op->slots_in, "use_ccw"); + const int cd_loop_color_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL); + + if (cd_loop_color_offset != -1) { + BMO_ITER (fs, &fs_iter, op->slots_in, "faces", BM_FACE) { + if (use_ccw == false) { /* same loops direction */ + BMLoop *lf; /* current face loops */ + MLoopCol *f_lcol; /* first face loop color */ + MLoopCol p_col; /* previous color */ + MLoopCol t_col; /* tmp color */ + + int n = 0; + BM_ITER_ELEM (lf, &l_iter, fs, BM_LOOPS_OF_FACE) { + /* current loop color is the previous loop color */ + MLoopCol *lcol = BM_ELEM_CD_GET_VOID_P(lf, cd_loop_color_offset); + if (n == 0) { + f_lcol = lcol; + p_col = *lcol; + } + else { + t_col = *lcol; + *lcol = p_col; + p_col = t_col; + } + n++; + } + + *f_lcol = p_col; + } + else { /* counter loop direction */ + BMLoop *lf; /* current face loops */ + MLoopCol *p_lcol; /* previous loop color */ + MLoopCol *lcol; + MLoopCol t_col; /* current color */ + + int n = 0; + BM_ITER_ELEM (lf, &l_iter, fs, BM_LOOPS_OF_FACE) { + /* previous loop color is the current loop color */ + lcol = BM_ELEM_CD_GET_VOID_P(lf, cd_loop_color_offset); + if (n == 0) { + p_lcol = lcol; + t_col = *lcol; + } + else { + *p_lcol = *lcol; + p_lcol = lcol; + } + n++; + } + + *lcol = t_col; + } + } + } } /*************************************************************************** * @@ -604,33 +601,35 @@ void bmo_rotate_colors_exec(BMesh *bm, BMOperator *op) *************************************************************************** */ static void bm_face_reverse_colors(BMFace *f, const int cd_loop_color_offset) { - BMIter iter; - BMLoop *l; - int i; - - MLoopCol *cols = BLI_array_alloca(cols, f->len); - - BM_ITER_ELEM_INDEX (l, &iter, f, BM_LOOPS_OF_FACE, i) { - MLoopCol *lcol = BM_ELEM_CD_GET_VOID_P(l, cd_loop_color_offset); - cols[i] = *lcol; - } - - /* now that we have the uvs in the array, reverse! */ - BM_ITER_ELEM_INDEX (l, &iter, f, BM_LOOPS_OF_FACE, i) { - /* current loop uv is the previous loop color */ - MLoopCol *lcol = BM_ELEM_CD_GET_VOID_P(l, cd_loop_color_offset); - *lcol = cols[(f->len - i - 1)]; - } + BMIter iter; + BMLoop *l; + int i; + + MLoopCol *cols = BLI_array_alloca(cols, f->len); + + BM_ITER_ELEM_INDEX(l, &iter, f, BM_LOOPS_OF_FACE, i) + { + MLoopCol *lcol = BM_ELEM_CD_GET_VOID_P(l, cd_loop_color_offset); + cols[i] = *lcol; + } + + /* now that we have the uvs in the array, reverse! */ + BM_ITER_ELEM_INDEX(l, &iter, f, BM_LOOPS_OF_FACE, i) + { + /* current loop uv is the previous loop color */ + MLoopCol *lcol = BM_ELEM_CD_GET_VOID_P(l, cd_loop_color_offset); + *lcol = cols[(f->len - i - 1)]; + } } void bmo_reverse_colors_exec(BMesh *bm, BMOperator *op) { - BMOIter iter; - BMFace *f; - const int cd_loop_color_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL); - - if (cd_loop_color_offset != -1) { - BMO_ITER (f, &iter, op->slots_in, "faces", BM_FACE) { - bm_face_reverse_colors(f, cd_loop_color_offset); - } - } + BMOIter iter; + BMFace *f; + const int cd_loop_color_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL); + + if (cd_loop_color_offset != -1) { + BMO_ITER (f, &iter, op->slots_in, "faces", BM_FACE) { + bm_face_reverse_colors(f, cd_loop_color_offset); + } + } } diff --git a/source/blender/bmesh/operators/bmo_wireframe.c b/source/blender/bmesh/operators/bmo_wireframe.c index dcce9dbfb01..dc8a8d03eef 100644 --- a/source/blender/bmesh/operators/bmo_wireframe.c +++ b/source/blender/bmesh/operators/bmo_wireframe.c @@ -31,32 +31,36 @@ #include "intern/bmesh_operators_private.h" /* own include */ - void bmo_wireframe_exec(BMesh *bm, BMOperator *op) { - const float offset = BMO_slot_float_get(op->slots_in, "thickness"); - const float offset_fac = BMO_slot_float_get(op->slots_in, "offset"); - const bool use_replace = BMO_slot_bool_get(op->slots_in, "use_replace"); - const bool use_boundary = BMO_slot_bool_get(op->slots_in, "use_boundary"); - const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset"); - const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset"); - const bool use_crease = BMO_slot_bool_get(op->slots_in, "use_crease"); - const float crease_weight = BMO_slot_float_get(op->slots_in, "crease_weight"); - - BM_mesh_elem_hflag_disable_all(bm, BM_EDGE | BM_FACE, BM_ELEM_TAG, false); - BMO_slot_buffer_hflag_enable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false); - - BM_mesh_wireframe( - bm, - offset, offset_fac, 0.0f, - use_replace, - use_boundary, - use_even_offset, use_relative_offset, - use_crease, crease_weight, - /* dummy vgroup */ - -1, false, - 0, MAXMAT, - true); - - BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG); + const float offset = BMO_slot_float_get(op->slots_in, "thickness"); + const float offset_fac = BMO_slot_float_get(op->slots_in, "offset"); + const bool use_replace = BMO_slot_bool_get(op->slots_in, "use_replace"); + const bool use_boundary = BMO_slot_bool_get(op->slots_in, "use_boundary"); + const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset"); + const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset"); + const bool use_crease = BMO_slot_bool_get(op->slots_in, "use_crease"); + const float crease_weight = BMO_slot_float_get(op->slots_in, "crease_weight"); + + BM_mesh_elem_hflag_disable_all(bm, BM_EDGE | BM_FACE, BM_ELEM_TAG, false); + BMO_slot_buffer_hflag_enable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false); + + BM_mesh_wireframe(bm, + offset, + offset_fac, + 0.0f, + use_replace, + use_boundary, + use_even_offset, + use_relative_offset, + use_crease, + crease_weight, + /* dummy vgroup */ + -1, + false, + 0, + MAXMAT, + true); + + BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG); } |