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:
authorHoward Trickey <howard.trickey@gmail.com>2019-01-18 20:54:10 +0300
committerHoward Trickey <howard.trickey@gmail.com>2019-01-18 20:54:10 +0300
commitb640fd829e3a228561e4d9dba9c830ae22d3ebc7 (patch)
tree431a203d22e26bb816ccc6e3990c54fc41bd3bbd /source/blender
parentc9938ebb0064675a17c92e8112fc4d416bba5f7c (diff)
Add miter pattern options.
Will document the new options in release notes, then in manual. Still a bit of work to do on the bulging shape that appears on cube corners if using arc inner miters, but will do that later. Also need to do something smarter in clamp overlap.
Diffstat (limited to 'source/blender')
-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
10 files changed, 460 insertions, 66 deletions
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);