diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:17:24 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:21:24 +0300 |
commit | e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch) | |
tree | 8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/bmesh/operators/bmo_subdivide.c | |
parent | b3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff) |
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211.
For details on usage and instructions for migrating branches
without conflicts, see:
https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/bmesh/operators/bmo_subdivide.c')
-rw-r--r-- | source/blender/bmesh/operators/bmo_subdivide.c | 2159 |
1 files changed, 1099 insertions, 1060 deletions
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); } |