diff options
m--------- | release/scripts/addons | 0 | ||||
m--------- | release/scripts/addons_contrib | 0 | ||||
-rw-r--r-- | release/scripts/startup/bl_ui/properties_data_modifier.py | 5 | ||||
-rw-r--r-- | source/blender/bmesh/intern/bmesh_opdefines.c | 12 | ||||
-rw-r--r-- | source/blender/bmesh/intern/bmesh_operator_api.h | 2 | ||||
-rw-r--r-- | source/blender/bmesh/intern/bmesh_operators.h | 7 | ||||
-rw-r--r-- | source/blender/bmesh/operators/bmo_bevel.c | 10 | ||||
-rw-r--r-- | source/blender/bmesh/tools/bmesh_bevel.c | 410 | ||||
-rw-r--r-- | source/blender/bmesh/tools/bmesh_bevel.h | 3 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_bevel.c | 34 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_modifier_types.h | 11 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_modifier.c | 28 | ||||
-rw-r--r-- | source/blender/modifiers/intern/MOD_bevel.c | 9 |
13 files changed, 465 insertions, 66 deletions
diff --git a/release/scripts/addons b/release/scripts/addons -Subproject 5f7fba0565a7c9ae93eae31a08fc9bbbd16d333 +Subproject ba97e19e5b3df449784a4cc4ed89ce7b511ec3e diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib -Subproject fecc0db5600405a0c14c70120ae279222861ef8 +Subproject 272b1a4ef07717beb3d0bfcb7380c2164fd008a diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index a6bab561e29..23bba83271b 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -166,6 +166,11 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): layout.label(text="Set Face Strength Mode") layout.row().prop(md, "face_strength_mode", expand=True) + layout.label(text="Miter Patterns") + layout.row().prop(md, "miter_outer") + layout.row().prop(md, "miter_inner") + layout.row().prop(md, "spread") + def BOOLEAN(self, layout, ob, md): split = layout.split() diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index db4985c62f6..dd913d95778 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -1743,6 +1743,13 @@ static BMO_FlagSet bmo_enum_bevel_face_strength_type[] = { {0, NULL}, }; +static BMO_FlagSet bmo_enum_bevel_miter_type[] = { + {BEVEL_MITER_SHARP, "SHARP"}, + {BEVEL_MITER_PATCH, "PATCH"}, + {BEVEL_MITER_ARC, "ARC"}, + {0, NULL}, +}; + /* * Bevel. * @@ -1765,6 +1772,11 @@ static BMOpDefine bmo_bevel_def = { {"harden_normals", BMO_OP_SLOT_BOOL}, /* harden normals */ {"face_strength_mode", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_bevel_face_strength_type}, /* whether to set face strength, and which faces to set if so */ + {"miter_outer", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, + bmo_enum_bevel_miter_type}, /* outer miter kind */ + {"miter_inner", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, + bmo_enum_bevel_miter_type}, /* outer miter kind */ + {"spread", BMO_OP_SLOT_FLT}, /* amount to offset beveled edge */ {"smoothresh", BMO_OP_SLOT_FLT}, /* for passing mesh's smoothresh, used in hardening */ {{'\0'}}, }, diff --git a/source/blender/bmesh/intern/bmesh_operator_api.h b/source/blender/bmesh/intern/bmesh_operator_api.h index fd01bec9531..e609500ddc3 100644 --- a/source/blender/bmesh/intern/bmesh_operator_api.h +++ b/source/blender/bmesh/intern/bmesh_operator_api.h @@ -246,7 +246,7 @@ typedef struct BMOpSlot { ((slot >= (op)->slots_out) && (slot < &(op)->slots_out[BMO_OP_MAX_SLOTS]))) /* way more than probably needed, compiler complains if limit hit */ -#define BMO_OP_MAX_SLOTS 16 +#define BMO_OP_MAX_SLOTS 20 /* BMOpDefine->type_flag */ typedef enum { diff --git a/source/blender/bmesh/intern/bmesh_operators.h b/source/blender/bmesh/intern/bmesh_operators.h index 365b5eb4681..dd9c57d6b6d 100644 --- a/source/blender/bmesh/intern/bmesh_operators.h +++ b/source/blender/bmesh/intern/bmesh_operators.h @@ -125,6 +125,13 @@ enum { BEVEL_FACE_STRENGTH_ALL, }; +/* Bevel miter slot values */ +enum { + BEVEL_MITER_SHARP, + BEVEL_MITER_PATCH, + BEVEL_MITER_ARC, +}; + extern const BMOpDefine *bmo_opdefines[]; extern const int bmo_opdefines_total; diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 3277824b890..853d11aade6 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -43,10 +43,13 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) 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 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) { @@ -73,7 +76,8 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) 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, smoothresh); + 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); diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 452dfa22993..043a40a9568 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -154,6 +154,8 @@ typedef struct BoundVert { Profile profile; /* edge profile between this and next BoundVert */ bool any_seam; /* are any of the edges attached here seams? */ bool visited; /* used during delta adjust pass */ + bool is_arc_start; /* this boundvert begins an arc profile */ + bool is_patch_start; /* this boundvert begins a patch profile */ int seam_len; /* length of seam starting from current boundvert to next boundvert with ccw ordering */ int sharp_len; /* Same as seam_len but defines length of sharp edges */ // int _pad; @@ -222,6 +224,9 @@ typedef struct BevelParams { int vertex_group; /* vertex group index, maybe set if vertex_only */ int mat_nr; /* if >= 0, material number for bevel; else material comes from adjacent faces */ int face_strength_mode; /* setting face strength if > 0 */ + int miter_outer; /* what kind of miter pattern to use on reflex angles */ + int miter_inner; /* what kind of miter pattern to use on non-reflex angles */ + float spread; /* amount to spread when doing inside miter */ float smoothresh; /* mesh's smoothresh, used if hardening */ } BevelParams; @@ -306,6 +311,9 @@ static BoundVert *add_new_bound_vert(MemArena *mem_arena, VMesh *vm, const float ans->adjchain = NULL; ans->sinratio = 1.0f; ans->visited = false; + ans->any_seam = false; + ans->is_arc_start = false; + ans->is_patch_start = false; vm->count++; return ans; } @@ -450,7 +458,7 @@ static BMFace *boundvert_rep_face(BoundVert *v, BMFace **r_fother) if (v->efirst->fprev != frep) frep2 = v->efirst->fprev; } - else { + else if (v->efirst) { frep = v->efirst->fprev; if (frep) { if (v->elast->fnext != frep) @@ -469,6 +477,18 @@ static BMFace *boundvert_rep_face(BoundVert *v, BMFace **r_fother) frep = v->elast->fprev; } } + else if (v->prev->elast) { + frep = v->prev->elast->fnext; + if (v->next->efirst) { + if (frep) + frep2 = v->next->efirst->fprev; + else + frep = v->next->efirst->fprev; + } + } + else { + frep = NULL; + } if (r_fother) *r_fother = frep2; return frep; @@ -737,6 +757,33 @@ static bool is_outside_edge(EdgeHalf *e, const float co[3], BMVert **ret_closer_ } } +/* Return -1, 0, or 1 as angle from e1 to e2 is <. =, or > 180 degrees */ +static int edges_angle_kind(EdgeHalf *e1, EdgeHalf *e2, BMVert *v) +{ + BMVert *v1, *v2; + float dir1[3], dir2[3], cross[3], *no, dot; + + v1 = BM_edge_other_vert(e1->e, v); + v2 = BM_edge_other_vert(e2->e, v); + sub_v3_v3v3(dir1, v->co, v1->co); + sub_v3_v3v3(dir2, v->co, v2->co); + /* angles are in [0,pi]. need to compare cross product with normal to see if they are reflex */ + cross_v3_v3v3(cross, dir1, dir2); + if (e1->fnext) + no = e1->fnext->no; + else if (e2->fprev) + no = e2->fprev->no; + else + no = v->no; + dot = dot_v3v3(cross, no); + if (fabsf(dot) < BEVEL_EPSILON_BIG) + return 0; + else if (dot < 0.0f) + return 1; + else + return -1; +} + /* co should be approximately on the plane between e1 and e2, which share common vert v * and common face f (which cannot be NULL). * Is it between those edges, sweeping CCW? */ @@ -1181,6 +1228,16 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv) } copy_v3_v3(pro->plane_co, co1); } + else if (bndv->is_arc_start) { + /* assume pro->midco was alredy set */ + copy_v3_v3(pro->coa, co1); + copy_v3_v3(pro->cob, co2); + pro->super_r = PRO_CIRCLE_R; + zero_v3(pro->plane_co); + zero_v3(pro->plane_no); + zero_v3(pro->proj_dir); + do_linear_interp = false; + } if (do_linear_interp) { pro->super_r = PRO_LINE_R; copy_v3_v3(pro->coa, co1); @@ -2129,6 +2186,87 @@ static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf } } +/* Helper for build_boundary to handle special miters */ +static void adjust_miter_coords(BevelParams *bp, BevVert *bv, EdgeHalf *emiter) +{ + float co1[3], co2[3], co3[3], edge_dir[3], line_p[3]; + BoundVert *v1, *v2, *v3, *v1prev, *v3next; + BMVert *vother; + EdgeHalf *emiter_other; + int miter_outer = bp->miter_outer; + + v1 = emiter->rightv; + if (miter_outer == BEVEL_MITER_PATCH) { + v2 = v1->next; + v3 = v2->next; + } + else { + BLI_assert(miter_outer == BEVEL_MITER_ARC); + v2 = NULL; + v3 = v1->next; + } + v1prev = v1->prev; + v3next = v3->next; + copy_v3_v3(co2, v1->nv.co); + if (v1->is_arc_start) + copy_v3_v3(v1->profile.midco, co2); + + /* co1 is intersection of line through co2 in dir of emiter->e + * and plane with normal the dir of emiter->e and through v1prev */ + vother = BM_edge_other_vert(emiter->e, bv->v); + sub_v3_v3v3(edge_dir, bv->v->co, vother->co); + normalize_v3(edge_dir); + float d = bp->offset / (bp->seg / 2.0f); /* a fallback amount to move */ + madd_v3_v3v3fl(line_p, co2, edge_dir, d); + if (!isect_line_plane_v3(co1, co2, line_p, v1prev->nv.co, edge_dir)) { + copy_v3_v3(co1, line_p); + } + adjust_bound_vert(v1, co1); + + /* co3 is similar, but plane is through v3next and line is other side of miter edge */ + emiter_other = v3->efirst; + vother = BM_edge_other_vert(emiter_other->e, bv->v); + sub_v3_v3v3(edge_dir, bv->v->co, vother->co); + normalize_v3(edge_dir); + madd_v3_v3v3fl(line_p, co2, edge_dir, d); + if (!isect_line_plane_v3(co3, co2, line_p, v3next->nv.co, edge_dir)) { + copy_v3_v3(co1, line_p); + } + adjust_bound_vert(v3, co3); +} + +static void adjust_miter_inner_coords(BevelParams *bp, BevVert *bv, EdgeHalf *emiter) +{ + BoundVert *v, *vstart, *v3; + EdgeHalf *e; + BMVert *vother; + float edge_dir[3], co[3]; + + v = vstart = bv->vmesh->boundstart; + do { + if (v->is_arc_start) { + v3 = v->next; + e = v->efirst; + if (e != emiter) { + copy_v3_v3(co, v->nv.co); + vother = BM_edge_other_vert(e->e, bv->v); + sub_v3_v3v3(edge_dir, vother->co, bv->v->co); + normalize_v3(edge_dir); + madd_v3_v3v3fl(v->nv.co, co, edge_dir, bp->spread); + e = v3->elast; + vother = BM_edge_other_vert(e->e, bv->v); + sub_v3_v3v3(edge_dir, vother->co, bv->v->co); + normalize_v3(edge_dir); + madd_v3_v3v3fl(v3->nv.co, co, edge_dir, bp->spread); + } + v = v3->next; + } + else { + v = v->next; + } + } while (v != vstart); +} + /* Make a circular list of BoundVerts for bv, each of which has the coordinates * of a vertex on the boundary of the beveled vertex bv->v. * This may adjust some EdgeHalf widths, and there might have to be @@ -2144,11 +2282,12 @@ static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) { MemArena *mem_arena = bp->mem_arena; - EdgeHalf *efirst, *e, *e2, *e3, *enip, *eip, *eon; - BoundVert *v; + EdgeHalf *efirst, *e, *e2, *e3, *enip, *eip, *eon, *emiter; + BoundVert *v, *v1, *v2, *v3; VMesh *vm; float co[3], r; - int nip, nnip; + int nip, nnip, miter_outer, miter_inner; + int ang_kind; /* Current bevel does nothing if only one edge into a vertex */ if (bv->edgecount <= 1) @@ -2171,6 +2310,13 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) return; } + /* Special miters outside only for 3 or more beveled edges */ + miter_outer = (bv->selcount >= 3) ? bp->miter_outer : BEVEL_MITER_SHARP; + miter_inner = bp->miter_inner; + + /* keep track of the first beveled edge of an outside miter (there can be at most 1 per bv */ + emiter = NULL; + /* Here: there is more than one beveled edge. * We make BoundVerts to connect the sides of the beveled edges. * Non-beveled edges in between will just join to the appropriate juncture point. */ @@ -2231,13 +2377,92 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) for (e3 = e->next; e3 != e2; e3 = e3->next) { e3->leftv = e3->rightv = v; } + ang_kind = edges_angle_kind(e, e2, bv->v); + if ((miter_outer != BEVEL_MITER_SHARP && !emiter && ang_kind == 1) || + (miter_inner != BEVEL_MITER_SHARP && ang_kind == -1)) + { + if (ang_kind == 1) + emiter = e; /* a reflex angle, i.e., the (only) outer miter, if any */ + /* make one or two more boundverts; for now all will have same co */ + v1 = v; + v1->ebev = NULL; + if (ang_kind == 1 && miter_outer == BEVEL_MITER_PATCH) { + v1->is_patch_start = true; + v2 = add_new_bound_vert(mem_arena, vm, co); + v2->eon = v1->eon; + v2->sinratio = v1->sinratio; + v2->ebev = NULL; + v1->eon = NULL; + v1->sinratio = 1.0f; + v1->elast = e; + if (e->next == e2) { + v2->efirst = NULL; + v2->elast = NULL; + } + else { + v2->efirst = e->next; + for (e3 = e->next; e3 != e2; e3 = e3->next) { + e3->leftv = e3->rightv = v2; + v2->elast = e3; + } + } + } + else { + v1->is_arc_start = true; + copy_v3_v3(v1->profile.midco, co); + v2 = NULL; + if (e->next == e2) { + v1->elast = v1->efirst; + } + else { + for (e3 = e->next; e3 != e2; e3 = e3->next) { + v1->elast = e3; + } + } + } + v3 = add_new_bound_vert(mem_arena, vm, co); + v3->ebev = e2; + v3->efirst = e2; + v3->elast = e2; + v3->eon = NULL; + e2->leftv = v3; + } } else { - adjust_bound_vert(e->rightv, co); + ang_kind = edges_angle_kind(e, e2, bv->v); + if ((miter_outer != BEVEL_MITER_SHARP && !emiter && ang_kind == 1) || + (miter_inner != BEVEL_MITER_SHARP && ang_kind == -1)) + { + if (ang_kind == 1) + emiter = e; + v1 = e->rightv; + if (ang_kind == 1 && miter_outer == BEVEL_MITER_PATCH) { + v2 = v1->next; + v3 = v2->next; + } + else { + v2 = NULL; + v3 = v1->next; + } + adjust_bound_vert(v1, co); + if (v2) + adjust_bound_vert(v2, co); + adjust_bound_vert(v3, co); + } + else { + adjust_bound_vert(e->rightv, co); + } } e = e2; } while (e != efirst); + if (miter_inner != BEVEL_MITER_SHARP) { + adjust_miter_inner_coords(bp, bv, emiter); + } + if (emiter) { + adjust_miter_coords(bp, bv, emiter); + } + calculate_vm_profiles(bp, bv, vm); if (construct) { @@ -3304,6 +3529,8 @@ static int tri_corner_test(BevelParams *bp, BevVert *bv) if (bp->vertex_only) return -1; + if (bv->vmesh->count != 3) + return 0; totang = 0.0f; for (i = 0; i < bv->edgecount; i++) { e = &bv->edges[i]; @@ -3658,10 +3885,11 @@ static void closer_v3_v3v3v3(float r[3], float a[3], float b[3], float v[3]) * We have to move the boundary edges too -- the usual method is to make one profile plane between * successive BoundVerts, but for the effect we want here, there will be two planes, one on each side * of the original edge. + * At the moment, this is not called for odd number of segments, though code does something if it is. */ static VMesh *square_out_adj_vmesh(BevelParams *bp, BevVert *bv) { - int n, ns, ns2, odd, i, j, k, ikind, im1, clstride; + int n, ns, ns2, odd, i, j, k, ikind, im1, clstride, iprev, akind; float bndco[3], dir1[3], dir2[3], co1[3], co2[3], meet1[3], meet2[3], v1co[3], v2co[3]; float *on_edge_cur, *on_edge_prev, *p; float ns2inv, finalfrac, ang; @@ -3669,6 +3897,7 @@ static VMesh *square_out_adj_vmesh(BevelParams *bp, BevVert *bv) EdgeHalf *e1, *e2; VMesh *vm; float *centerline; + bool *cset, v1set, v2set; n = bv->vmesh->count; ns = bv->vmesh->seg; @@ -3678,52 +3907,118 @@ static VMesh *square_out_adj_vmesh(BevelParams *bp, BevVert *bv) vm = new_adj_vmesh(bp->mem_arena, n, ns, bv->vmesh->boundstart); clstride = 3 * (ns2 + 1); centerline = MEM_mallocN(clstride * n * sizeof(float), "bevel"); + cset = MEM_callocN(n * sizeof(bool), "bevel"); /* find on_edge, place on bndv[i]'s elast where offset line would meet, - * averaging with position where next sector's offset line would meet */ + * taking min-distance-to bv->v with position where next sector's offset line would meet */ bndv = vm->boundstart; for (i = 0; i < n; i++) { copy_v3_v3(bndco, bndv->nv.co); e1 = bndv->efirst; e2 = bndv->elast; - sub_v3_v3v3(dir1, e1->e->v1->co, e1->e->v2->co); - sub_v3_v3v3(dir2, e2->e->v1->co, e2->e->v2->co); - add_v3_v3v3(co1, bndco, dir1); - add_v3_v3v3(co2, bndco, dir2); - /* intersect e1 with line through bndv parallel to e2 to get v1co */ - ikind = isect_line_line_v3(e1->e->v1->co, e1->e->v2->co, bndco, co2, meet1, meet2); - - if (ikind == 0) { - /* Placeholder: this should get eliminated by min dist test with adjacent edge */ - mid_v3_v3v3(v1co, e1->e->v1->co, e1->e->v2->co); - } - else { - /* if the lines are skew (ikind == 2), want meet1 which is on e1 */ - copy_v3_v3(v1co, meet1); - } - /* intersect e2 with line through bndv parallel to e1 to get v2co */ - ikind = isect_line_line_v3(e2->e->v1->co, e2->e->v2->co, bndco, co1, meet1, meet2); - if (ikind == 0) { - mid_v3_v3v3(v2co, e2->e->v1->co, e2->e->v2->co); - } - else { - copy_v3_v3(v2co, meet1); - } + akind = 0; + if (e1 && e2) + akind = edges_angle_kind(e1, e2, bv->v); + if (bndv->is_patch_start) { + mid_v3_v3v3(centerline + clstride * i, bndv->nv.co, bndv->next->nv.co); + cset[i] = true; + bndv = bndv->next; + i++; + mid_v3_v3v3(centerline + clstride * i, bndv->nv.co, bndv->next->nv.co); + cset[i] = true; + bndv = bndv->next; + i++; + /* leave cset[i] where it was - probably false, unless i == n - 1 */ + } + else if (bndv->is_arc_start) { + e1 = bndv->efirst; + e2 = bndv->next->efirst; + copy_v3_v3(centerline + clstride * i, bndv->profile.midco); + bndv = bndv->next; + cset[i] = true; + i++; + /* leave cset[i] where it was - probably false, unless i == n - 1 */ + } + else if (akind < 0) { + sub_v3_v3v3(dir1, e1->e->v1->co, e1->e->v2->co); + sub_v3_v3v3(dir2, e2->e->v1->co, e2->e->v2->co); + add_v3_v3v3(co1, bndco, dir1); + add_v3_v3v3(co2, bndco, dir2); + /* intersect e1 with line through bndv parallel to e2 to get v1co */ + ikind = isect_line_line_v3(e1->e->v1->co, e1->e->v2->co, bndco, co2, meet1, meet2); + if (ikind == 0) { + v1set = false; + } + else { + /* if the lines are skew (ikind == 2), want meet1 which is on e1 */ + copy_v3_v3(v1co, meet1); + v1set = true; + } + /* intersect e2 with line through bndv parallel to e1 to get v2co */ + ikind = isect_line_line_v3(e2->e->v1->co, e2->e->v2->co, bndco, co1, meet1, meet2); + if (ikind == 0) { + v2set = false; + } + else { + v2set = true; + copy_v3_v3(v2co, meet1); + } - /* want on_edge[i] to be min dist to bv->v of v2co and the v1co of next iteration */ - on_edge_cur = centerline + clstride * i; - on_edge_prev = centerline + clstride * ((i == 0) ? n - 1 : i - 1); - if (i == 0) { - copy_v3_v3(on_edge_cur, v2co); - copy_v3_v3(on_edge_prev, v1co); - } - else if (i == n - 1) { - closer_v3_v3v3v3(on_edge_cur, on_edge_cur, v2co, bv->v->co); - closer_v3_v3v3v3(on_edge_prev, on_edge_prev, v1co, bv->v->co); + /* want on_edge[i] to be min dist to bv->v of v2co and the v1co of next iteration */ + on_edge_cur = centerline + clstride * i; + iprev = (i == 0) ? n - 1 : i - 1; + on_edge_prev = centerline + clstride * iprev; + if (v2set) { + if (cset[i]) { + closer_v3_v3v3v3(on_edge_cur, on_edge_cur, v2co, bv->v->co); + } + else { + copy_v3_v3(on_edge_cur, v2co); + cset[i] = true; + } + } + if (v1set) { + if (cset[iprev]) { + closer_v3_v3v3v3(on_edge_prev, on_edge_prev, v1co, bv->v->co); + } + else { + copy_v3_v3(on_edge_prev, v1co); + cset[iprev] = true; + } + } } - else { - copy_v3_v3(on_edge_cur, v2co); - closer_v3_v3v3v3(on_edge_prev, on_edge_prev, v1co, bv->v->co); + bndv = bndv->next; + } + /* Maybe not everything was set by the previous loop */ + bndv = vm->boundstart; + for (i = 0; i < n; i++) { + if (!cset[i]) { + on_edge_cur = centerline + clstride * i; + e1 = bndv->next->efirst; + copy_v3_v3(co1, bndv->nv.co); + copy_v3_v3(co2, bndv->next->nv.co); + if (e1) { + if (bndv->prev->is_arc_start && bndv->next->is_arc_start) { + ikind = isect_line_line_v3(e1->e->v1->co, e1->e->v2->co, co1, co2, meet1, meet2); + if (ikind != 0) { + copy_v3_v3(on_edge_cur, meet1); + cset[i] = true; + } + } + else { + if (bndv->prev->is_arc_start) { + closest_to_line_segment_v3(on_edge_cur, co1, e1->e->v1->co, e1->e->v2->co); + } + else { + closest_to_line_segment_v3(on_edge_cur, co2, e1->e->v1->co, e1->e->v2->co); + } + cset[i] = true; + } + } + if (!cset[i]) { + mid_v3_v3v3(on_edge_cur, co1, co2); + cset[i] = true; + } } bndv = bndv->next; } @@ -3806,6 +4101,7 @@ static VMesh *square_out_adj_vmesh(BevelParams *bp, BevVert *bv) vmesh_copy_equiv_verts(vm); MEM_freeN(centerline); + MEM_freeN(cset); return vm; } @@ -3889,8 +4185,7 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv) e = v->efirst; else e = v->ebev; - BLI_assert(e != NULL); - bme = e->e; + bme = e ? e->e : NULL; /* For odd ns, make polys with lower left corner at (i,j,k) for * j in [0, ns2-1], k in [0, ns2]. And then the center ngon. * For even ns, @@ -3930,7 +4225,7 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv) else { /* edge bevel */ if (odd) { if (k == ns2) { - if (e->is_seam) { + if (e && e->is_seam) { r_f = bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f, NULL, bme, bme, NULL, mat_nr); } @@ -3944,7 +4239,9 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv) } else { bme1 = k == ns2 - 1 ? bme : NULL; - bme3 = j == ns2 - 1 ? v->prev->ebev->e : NULL; + bme3 = NULL; + if (j == ns2 - 1 && v->prev->ebev) + bme3 = v->prev->ebev->e; bme2 = bme1 != NULL ? bme1 : bme3; r_f = bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f, NULL, bme1, bme2, bme3, mat_nr); @@ -5714,12 +6011,14 @@ static void bevel_limit_offset(BevelParams *bp) * \warning all tagged edges _must_ be manifold. */ void BM_mesh_bevel( - BMesh *bm, const float offset, const int offset_type, - const float segments, const float profile, - const bool vertex_only, const bool use_weights, const bool limit_offset, - const struct MDeformVert *dvert, const int vertex_group, const int mat, - const bool loop_slide, const bool mark_seam, const bool mark_sharp, - const bool harden_normals, const int face_strength_mode, const float smoothresh) + BMesh *bm, const float offset, const int offset_type, + const float segments, const float profile, + const bool vertex_only, const bool use_weights, const bool limit_offset, + const struct MDeformVert *dvert, const int vertex_group, const int mat, + const bool loop_slide, const bool mark_seam, const bool mark_sharp, + const bool harden_normals, const int face_strength_mode, + const int miter_outer, const int miter_inner, const float spread, + const float smoothresh) { BMIter iter, liter; BMVert *v, *v_next; @@ -5738,7 +6037,7 @@ void BM_mesh_bevel( bp.use_weights = use_weights; bp.loop_slide = loop_slide; bp.limit_offset = limit_offset; - bp.offset_adjust = true; + bp.offset_adjust = false; // DEBUG true; bp.dvert = dvert; bp.vertex_group = vertex_group; bp.mat_nr = mat; @@ -5746,6 +6045,9 @@ void BM_mesh_bevel( bp.mark_sharp = mark_sharp; bp.harden_normals = harden_normals; bp.face_strength_mode = face_strength_mode; + bp.miter_outer = miter_outer; + bp.miter_inner = miter_inner; + bp.spread = spread; bp.smoothresh = smoothresh; bp.face_hash = NULL; diff --git a/source/blender/bmesh/tools/bmesh_bevel.h b/source/blender/bmesh/tools/bmesh_bevel.h index 36a80ee5e25..ff0d1f04af5 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.h +++ b/source/blender/bmesh/tools/bmesh_bevel.h @@ -34,6 +34,7 @@ void BM_mesh_bevel( const float profile, const bool vertex_only, const bool use_weights, const bool limit_offset, const struct MDeformVert *dvert, const int vertex_group, const int mat, const bool loop_slide, const bool mark_seam, const bool mark_sharp, - const bool harden_normals, const int face_strength_mode, const float smoothresh); + const bool harden_normals, const int face_strength_mode, const int miter_outer, + const int miter_inner, const float spread, const float smoothresh); #endif /* __BMESH_BEVEL_H__ */ diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index f2ac54bf0f4..4e796b9492a 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -156,7 +156,8 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal) { uint ob_store_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &ob_store_len); + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &ob_store_len); opdata->ob_store = MEM_malloc_arrayN(ob_store_len, sizeof(*opdata->ob_store), __func__); for (uint ob_index = 0; ob_index < ob_store_len; ob_index++) { Object *obedit = objects[ob_index]; @@ -234,7 +235,9 @@ static bool edbm_bevel_calc(wmOperator *op) const bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp"); const bool harden_normals = RNA_boolean_get(op->ptr, "harden_normals"); const int face_strength_mode = RNA_enum_get(op->ptr, "face_strength_mode"); - + const int miter_outer = RNA_enum_get(op->ptr, "miter_outer"); + const int miter_inner = RNA_enum_get(op->ptr, "miter_inner"); + const float spread = RNA_float_get(op->ptr, "spread"); for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { em = opdata->ob_store[ob_index].em; @@ -259,10 +262,11 @@ static bool edbm_bevel_calc(wmOperator *op) em, &bmop, op, "bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f " "clamp_overlap=%b material=%i loop_slide=%b mark_seam=%b mark_sharp=%b " - "harden_normals=%b face_strength_mode=%i smoothresh=%f", + "harden_normals=%b face_strength_mode=%i " + "miter_outer=%i miter_inner=%i spread=%f smoothresh=%f", BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile, clamp_overlap, material, loop_slide, mark_seam, mark_sharp, harden_normals, face_strength_mode, - me->smoothresh); + miter_outer, miter_inner, spread, me->smoothresh); BMO_op_exec(em->bm, &bmop); @@ -691,6 +695,19 @@ void MESH_OT_bevel(wmOperatorType *ot) {0, NULL, 0, NULL, NULL}, }; + static const EnumPropertyItem miter_outer_items[] = { + {BEVEL_MITER_SHARP, "SHARP", 0, "Sharp", "Outside of miter is sharp"}, + {BEVEL_MITER_PATCH, "PATCH", 0, "Patch", "Outside of miter is squared-off patch"}, + {BEVEL_MITER_ARC, "ARC", 0, "Arc", "Outside of miter is arc"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem miter_inner_items[] = { + {BEVEL_MITER_SHARP, "SHARP", 0, "Sharp", "Inside of miter is sharp"}, + {BEVEL_MITER_ARC, "ARC", 0, "Arc", "Inside of miter is arc"}, + {0, NULL, 0, NULL, NULL}, + }; + /* identifiers */ ot->name = "Bevel"; ot->description = "Edge Bevel"; @@ -720,9 +737,16 @@ void MESH_OT_bevel(wmOperatorType *ot) RNA_def_boolean(ot->srna, "mark_sharp", false, "Mark Sharp", "Mark beveled edges as sharp"); RNA_def_int(ot->srna, "material", -1, -1, INT_MAX, "Material", "Material for bevel faces (-1 means use adjacent faces)", -1, 100); - RNA_def_boolean(ot->srna, "harden_normals", false, "Harden Normals", "Match normals of new faces to adjacent faces"); + RNA_def_boolean(ot->srna, "harden_normals", false, "Harden Normals", + "Match normals of new faces to adjacent faces"); RNA_def_enum(ot->srna, "face_strength_mode", face_strength_mode_items, BEVEL_FACE_STRENGTH_NONE, "Face Strength Mode", "Whether to set face strength, and which faces to set face strength on"); + RNA_def_enum(ot->srna, "miter_outer", miter_outer_items, BEVEL_MITER_SHARP, + "Outer Miter", "Pattern to use for outside of miters"); + RNA_def_enum(ot->srna, "miter_inner", miter_inner_items, BEVEL_MITER_SHARP, + "Inner Miter", "Pattern to use for inside of miters"); + RNA_def_float(ot->srna, "spread", 0.1f, 0.0f, 1e6f, "Spread", + "Amount to spread arcs for arc inner miters", 0.0f, 100.0f); prop = RNA_def_boolean(ot->srna, "release_confirm", 0, "Confirm on Release", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 101d655ded5..9a06af14b9d 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -384,12 +384,16 @@ typedef struct BevelModifierData { short mat; short edge_flags; short face_str_mode; + /* patterns to use for mitering non-reflex and reflex miter edges */ + short miter_inner; + short miter_outer; short pad2; /** Controls profile shape (0->1, .5 is round). */ float profile; /** if the MOD_BEVEL_ANGLE is set, * this will be how "sharp" an edge must be before it gets beveled */ float bevel_angle; + float spread; /** if the MOD_BEVEL_VWEIGHT option is set, * this will be the name of the vert group, MAX_VGROUP_NAME */ char defgrp_name[64]; @@ -439,6 +443,13 @@ enum { MOD_BEVEL_FACE_STRENGTH_ALL, }; +/* BevelModifier->miter_inner and ->miter_outer */ +enum { + MOD_BEVEL_MITER_SHARP, + MOD_BEVEL_MITER_PATCH, + MOD_BEVEL_MITER_ARC, +}; + typedef struct SmokeModifierData { ModifierData modifier; diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 2ef4773de20..97785c55ef1 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -3057,6 +3057,13 @@ static void rna_def_modifier_bevel(BlenderRNA *brna) { 0, NULL, 0, NULL, NULL }, }; + static EnumPropertyItem prop_miter_items[] = { + { MOD_BEVEL_MITER_SHARP, "MITER_SHARP", 0, "Sharp", "Default sharp miter" }, + { MOD_BEVEL_MITER_PATCH, "MITER_PATCH", 0, "Patch", "Miter with extra corner" }, + { MOD_BEVEL_MITER_ARC, "MITER_ARC", 0, "Arc", "Miter with curved arc" }, + { 0, NULL, 0, NULL, NULL }, + }; + srna = RNA_def_struct(brna, "BevelModifier", "Modifier"); RNA_def_struct_ui_text(srna, "Bevel Modifier", "Bevel modifier to make edges and vertices more rounded"); RNA_def_struct_sdna(srna, "BevelModifierData"); @@ -3154,7 +3161,7 @@ static void rna_def_modifier_bevel(BlenderRNA *brna) prop = RNA_def_property(srna, "harden_normals", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_BEVEL_HARDEN_NORMALS); RNA_def_property_ui_text(prop, "Harden Normals", - "Match normals of new faces to adjacent faces"); + "Match normals of new faces to adjacent faces"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "face_strength_mode", PROP_ENUM, PROP_NONE); @@ -3162,6 +3169,25 @@ static void rna_def_modifier_bevel(BlenderRNA *brna) RNA_def_property_enum_items(prop, prop_harden_normals_items); RNA_def_property_ui_text(prop, "Set Face Strength", "Whether to set face strength, and which faces to set it on"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "miter_outer", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "miter_outer"); + RNA_def_property_enum_items(prop, prop_miter_items); + RNA_def_property_ui_text(prop, "Outer Miter", "Pattern to use for outside of miters"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "miter_inner", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "miter_inner"); + RNA_def_property_enum_items(prop, prop_miter_items); + RNA_def_property_ui_text(prop, "Inner Miter", "Pattern to use for inside of miters"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "spread", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_float_sdna(prop, NULL, "value"); + RNA_def_property_range(prop, 0, FLT_MAX); + RNA_def_property_ui_range(prop, 0.0f, 100.0f, 0.1, 4); + RNA_def_property_ui_text(prop, "Spread", "Spread distance for inner miter arcs"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); } static void rna_def_modifier_shrinkwrap(BlenderRNA *brna) diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index 05015492158..568cdcf6707 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -67,6 +67,9 @@ static void initData(ModifierData *md) bmd->e_flags = 0; bmd->edge_flags = 0; bmd->face_str_mode = MOD_BEVEL_FACE_STRENGTH_NONE; + bmd->miter_inner = MOD_BEVEL_MITER_SHARP; + bmd->miter_outer = MOD_BEVEL_MITER_SHARP; + bmd->spread = 0.1f; bmd->mat = -1; bmd->profile = 0.5f; bmd->bevel_angle = DEG2RADF(30.0f); @@ -119,6 +122,9 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes const bool mark_sharp = (bmd->edge_flags & MOD_BEVEL_MARK_SHARP); bool harden_normals = (bmd->flags & MOD_BEVEL_HARDEN_NORMALS); const int face_strength_mode = bmd->face_str_mode; + const int miter_outer = bmd->miter_outer; + const int miter_inner = bmd->miter_inner; + const float spread = bmd->spread; bm = BKE_mesh_to_bmesh_ex( mesh, @@ -196,7 +202,8 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes BM_mesh_bevel(bm, value, offset_type, bmd->res, bmd->profile, vertex_only, bmd->lim_flags & MOD_BEVEL_WEIGHT, do_clamp, dvert, vgroup, mat, loop_slide, mark_seam, mark_sharp, - harden_normals, face_strength_mode, mesh->smoothresh); + harden_normals, face_strength_mode, + miter_outer, miter_inner, spread, mesh->smoothresh); result = BKE_mesh_from_bmesh_for_eval_nomain(bm, 0); |