Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
m---------release/scripts/addons0
m---------release/scripts/addons_contrib0
-rw-r--r--release/scripts/startup/bl_ui/properties_data_modifier.py5
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c12
-rw-r--r--source/blender/bmesh/intern/bmesh_operator_api.h2
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.h7
-rw-r--r--source/blender/bmesh/operators/bmo_bevel.c10
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c410
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.h3
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c34
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h11
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c28
-rw-r--r--source/blender/modifiers/intern/MOD_bevel.c9
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);