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:
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c597
1 files changed, 436 insertions, 161 deletions
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index be5521d45ab..ea2cc1c24d6 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -675,7 +675,7 @@ static BMFace *bev_create_ngon(BMesh *bm,
const int totv,
BMFace **face_arr,
BMFace *facerep,
- BMEdge **edge_arr,
+ BMEdge **snap_edge_arr,
int mat_nr,
bool do_interp)
{
@@ -699,8 +699,8 @@ static BMFace *bev_create_ngon(BMesh *bm,
}
if (interp_f) {
BMEdge *bme = NULL;
- if (edge_arr) {
- bme = edge_arr[i];
+ if (snap_edge_arr) {
+ bme = snap_edge_arr[i];
}
float save_co[3];
if (bme) {
@@ -734,44 +734,6 @@ static BMFace *bev_create_ngon(BMesh *bm,
return f;
}
-static BMFace *bev_create_quad(BMesh *bm,
- BMVert *v1,
- BMVert *v2,
- BMVert *v3,
- BMVert *v4,
- BMFace *f1,
- BMFace *f2,
- BMFace *f3,
- BMFace *f4,
- int mat_nr)
-{
- BMVert *varr[4] = {v1, v2, v3, v4};
- BMFace *farr[4] = {f1, f2, f3, f4};
- return bev_create_ngon(bm, varr, 4, farr, f1, NULL, mat_nr, true);
-}
-
-static BMFace *bev_create_quad_ex(BMesh *bm,
- BMVert *v1,
- BMVert *v2,
- BMVert *v3,
- BMVert *v4,
- BMFace *f1,
- BMFace *f2,
- BMFace *f3,
- BMFace *f4,
- BMEdge *e1,
- BMEdge *e2,
- BMEdge *e3,
- BMEdge *e4,
- BMFace *frep,
- int mat_nr)
-{
- BMVert *varr[4] = {v1, v2, v3, v4};
- BMFace *farr[4] = {f1, f2, f3, f4};
- BMEdge *earr[4] = {e1, e2, e3, e4};
- return bev_create_ngon(bm, varr, 4, farr, frep, earr, mat_nr, true);
-}
-
/* Is Loop layer layer_index contiguous across shared vertex of l1 and l2? */
static bool contig_ldata_across_loops(BMesh *bm, BMLoop *l1, BMLoop *l2, int layer_index)
{
@@ -828,6 +790,25 @@ static bool contig_ldata_across_edge(BMesh *bm, BMEdge *e, BMFace *f1, BMFace *f
return true;
}
+/**
+ * In array face_component of total totface elements, swap values c1 and c2
+ * whereever they occur.
+ */
+static void swap_face_components(int *face_component, int totface, int c1, int c2)
+{
+ if (c1 == c2) {
+ return; /* Nothing to do. */
+ }
+ for (int f = 0; f < totface; f++) {
+ if (face_component[f] == c1) {
+ face_component[f] = c2;
+ }
+ else if (face_component[f] == c2) {
+ face_component[f] = c1;
+ }
+ }
+}
+
/*
* Set up the fields of bp->math_layer_info.
* We always set has_math_layers to the correct value.
@@ -836,6 +817,7 @@ static bool contig_ldata_across_edge(BMesh *bm, BMEdge *e, BMFace *f1, BMFace *f
*/
static void math_layer_info_init(BevelParams *bp, BMesh *bm)
{
+ int f;
bp->math_layer_info.has_math_layers = false;
bp->math_layer_info.face_component = NULL;
for (int i = 0; i < bm->ldata.totlayer; i++) {
@@ -860,12 +842,12 @@ static void math_layer_info_init(BevelParams *bp, BMesh *bm)
bool *in_stack = MEM_malloc_arrayN(totface, sizeof(bool), __func__);
/* Set all component ids by DFS from faces with unassigned components. */
- for (int f = 0; f < totface; f++) {
+ for (f = 0; f < totface; f++) {
face_component[f] = -1;
in_stack[f] = false;
}
int current_component = -1;
- for (int f = 0; f < totface; f++) {
+ for (f = 0; f < totface; f++) {
if (face_component[f] == -1 && !in_stack[f]) {
int stack_top = 0;
current_component++;
@@ -910,6 +892,44 @@ static void math_layer_info_init(BevelParams *bp, BMesh *bm)
}
MEM_freeN(stack);
MEM_freeN(in_stack);
+ /* We can usually get more pleasing result if components 0 and 1
+ * are the topmost and bottommost (in z-coordinate) componenets,
+ * so adjust component indices to make that so.
+ */
+ if (current_component <= 0) {
+ return; /* Only one component, so no need to do this. */
+ }
+ BMFace *top_face = NULL;
+ float top_face_z = -1e30f;
+ int top_face_component = -1;
+ BMFace *bot_face = NULL;
+ float bot_face_z = 1e30f;
+ int bot_face_component = -1;
+ for (f = 0; f < totface; f++) {
+ float cent[3];
+ BMFace *bmf = BM_face_at_index(bm, f);
+ BM_face_calc_center_bounds(bmf, cent);
+ float fz = cent[2];
+ if (fz > top_face_z) {
+ top_face_z = fz;
+ top_face = bmf;
+ top_face_component = face_component[f];
+ }
+ if (fz < bot_face_z) {
+ bot_face_z = fz;
+ bot_face = bmf;
+ bot_face_component = face_component[f];
+ }
+ }
+ BLI_assert(top_face != NULL && bot_face != NULL);
+ swap_face_components(face_component, totface, face_component[0], top_face_component);
+ if (bot_face_component != top_face_component) {
+ if (bot_face_component == 0) {
+ /* It was swapped with old top_face_component. */
+ bot_face_component = top_face_component;
+ }
+ swap_face_components(face_component, totface, face_component[1], bot_face_component);
+ }
}
/**
@@ -3843,8 +3863,8 @@ static VMesh *new_adj_vmesh(MemArena *mem_arena, int count, int seg, BoundVert *
* where ns2 = floor(nseg / 2).
* But these overlap data from previous and next i: there are some forced equivalences.
* Let's call these indices the canonical ones: we will just calculate data for these
- * 0 <= j <= ns2, 0 <= k < ns2 (for odd ns2)
- * 0 <= j < ns2, 0 <= k <= ns2 (for even ns2)
+ * 0 <= j <= ns2, 0 <= k <= ns2 (for odd ns)
+ * 0 <= j < ns2, 0 <= k <= ns2 (for even ns)
* also (j=ns2, k=ns2) at i=0 (for even ns2)
* This function returns the canonical one for any i, j, k in [0,n],[0,ns],[0,ns].
*/
@@ -4118,7 +4138,7 @@ static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm_in)
for (int i = 0; i < n_boundary; i++) {
float co1[3], co2[3], acc[3];
EdgeHalf *e = bndv->elast;
- /* Generate tangents. This is hacked together and would ideally be done elsewhere and then only
+ /* Generate tangents. This is hacked together and would ideally be done elsewere and then only
* used here. */
float tangent[3], tangent2[3], normal[3];
bool convex = true;
@@ -4185,7 +4205,7 @@ static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm_in)
sub_v3_v3v3(co1, mesh_vert(vm_in, i, 0, 0)->co, mesh_vert(vm_in, i, 0, 1)->co);
sub_v3_v3v3(co2, mesh_vert(vm_in, i, 0, 1)->co, mesh_vert(vm_in, i, 0, 2)->co);
cross_v3_v3v3(tangent, co1, co2);
- /** The following constant is chosen to best match the old results. */
+ /** The following constant is choosen to best match the old results. */
normalize_v3_length(tangent, 1.5f / ns_out);
}
/** Copy corner vertex. */
@@ -4799,46 +4819,85 @@ static BMEdge *find_closer_edge(float *co, BMEdge *e1, BMEdge *e2)
return e2;
}
-/* Snap co to the closest edge of face f. Return the edge in *r_snap_e,
- * the coordinates of snap point in r_ snap_co,
- * and the distance squared to the snap point as function return */
-static float snap_face_dist_squared(float *co, BMFace *f, BMEdge **r_snap_e, float *r_snap_co)
+/**
+ * Find which BoundVerts of \a bv are internal to face \a f.
+ * That is, when both the face and the point are projected to 2d,
+ * the point is on the boundary of or inside the projected face.
+ * There can only be up to three of then, since, including miters,
+ * that is the maximum number of BoundVerts that can be between two edges.
+ * Return the number of face-internal vertices found.
+ */
+static int find_face_internal_boundverts(const BevVert *bv,
+ const BMFace *f,
+ BoundVert *(r_internal[3]))
{
- BMEdge *beste = NULL;
- float beste_d2 = 1e20f;
- BMIter iter;
- BMEdge *e;
- BM_ITER_ELEM (e, &iter, f, BM_EDGES_OF_FACE) {
- float closest[3];
- closest_to_line_segment_v3(closest, co, e->v1->co, e->v2->co);
- float d2 = len_squared_v3v3(closest, co);
- if (d2 < beste_d2) {
- beste_d2 = d2;
- beste = e;
- copy_v3_v3(r_snap_co, closest);
+ if (f == NULL) {
+ return 0;
+ }
+ int n_internal = 0;
+ VMesh *vm = bv->vmesh;
+ BLI_assert(vm != NULL);
+ BoundVert *v = vm->boundstart;
+ do {
+ /* Possible speedup: do the matrix projection done by the following
+ * once, outside the loop, or even better, cache it if ever done
+ * in the course of Bevel. */
+ if (BM_face_point_inside_test(f, v->nv.co)) {
+ r_internal[n_internal++] = v;
+ if (n_internal == 3) {
+ break;
+ }
}
+ } while ((v = v->next) != vm->boundstart);
+ for (int i = n_internal; i < 3; i++) {
+ r_internal[i] = NULL;
}
- *r_snap_e = beste;
- return beste_d2;
+ return n_internal;
}
-/* What would be the area of the polygon around bv if interpolated in face frep?
+/**
+ * Find where the coordinates of the BndVerts in \a bv should snap to in face \a f.
+ * Face \a f should contain vertex `bv->v`.
+ * Project the snapped verts to 2d, then return the area of the resulting polygon.
+ * Usually one BndVert is inside the face, sometimes up to 3 (if there are miters),
+ * so don't snap those to an edge; all the rest snap to one of the edges of \a bmf
+ * incident on `bv->v`.
*/
-static float interp_poly_area(BevVert *bv, BMFace *frep)
+static float projected_boundary_area(BevVert *bv, BMFace *f)
{
+ BMEdge *e1, *e2;
VMesh *vm = bv->vmesh;
-
+ float(*proj_co)[2] = BLI_array_alloca(proj_co, vm->count);
+ float axis_mat[3][3];
+ axis_dominant_v3_to_m3(axis_mat, f->no);
+ get_incident_edges(f, bv->v, &e1, &e2);
+ BLI_assert(e1 != NULL && e2 != NULL);
BLI_assert(vm != NULL);
- float(*uv_co)[3] = BLI_array_alloca(uv_co, vm->count);
BoundVert *v = vm->boundstart;
- int n = 0;
+ int i = 0;
+ BoundVert *unsnapped[3];
+ find_face_internal_boundverts(bv, f, unsnapped);
do {
- BLI_assert(n < vm->count);
- BMEdge *snape;
- snap_face_dist_squared(v->nv.v->co, frep, &snape, uv_co[n]);
- n++;
+ float *co = v->nv.v->co;
+ if (v == unsnapped[0] || v == unsnapped[1] || v == unsnapped[2]) {
+ mul_v2_m3v3(proj_co[i], axis_mat, co);
+ }
+ else {
+ float snap1[3], snap2[3];
+ closest_to_line_segment_v3(snap1, co, e1->v1->co, e1->v2->co);
+ closest_to_line_segment_v3(snap2, co, e2->v1->co, e2->v2->co);
+ float d1_sq = len_squared_v3v3(snap1, co);
+ float d2_sq = len_squared_v3v3(snap2, co);
+ if (d1_sq <= d2_sq) {
+ mul_v2_m3v3(proj_co[i], axis_mat, snap1);
+ }
+ else {
+ mul_v2_m3v3(proj_co[i], axis_mat, snap2);
+ }
+ }
+ ++i;
} while ((v = v->next) != vm->boundstart);
- float area = fabsf(area_poly_v3(uv_co, n));
+ float area = area_poly_v2(proj_co, vm->count);
return area;
}
@@ -4851,7 +4910,9 @@ static float interp_poly_area(BevVert *bv, BMFace *frep)
*/
static bool is_bad_uv_poly(BevVert *bv, BMFace *frep)
{
- float area = interp_poly_area(bv, frep);
+ VMesh *vm = bv->vmesh;
+ BLI_assert(vm != NULL);
+ float area = projected_boundary_area(bv, frep);
return area < BEVEL_EPSILON_BIG;
}
@@ -4876,6 +4937,8 @@ static BMFace *frep_for_center_poly(BevelParams *bp, BevVert *bv)
bool consider_all_faces = bv->selcount == 1;
/* Make an array that can hold maximum possible number of choices. */
BMFace **fchoices = BLI_array_alloca(fchoices, bv->edgecount);
+ /* For each choice, need to remember the unsnapped BoundVerts. */
+
for (int i = 0; i < bv->edgecount; i++) {
if (!bv->edges[i].is_bev && !consider_all_faces) {
continue;
@@ -4924,9 +4987,11 @@ static void build_center_ngon(BevelParams *bp, BMesh *bm, BevVert *bv, int mat_n
int ns2 = vm->seg / 2;
BMFace *frep;
BMEdge *frep_e1, *frep_e2;
+ BoundVert *frep_unsnapped[3];
if (bv->any_seam) {
frep = frep_for_center_poly(bp, bv);
get_incident_edges(frep, bv->v, &frep_e1, &frep_e2);
+ find_face_internal_boundverts(bv, frep, frep_unsnapped);
}
else {
frep = NULL;
@@ -4938,8 +5003,13 @@ static void build_center_ngon(BevelParams *bp, BMesh *bm, BevVert *bv, int mat_n
BLI_array_append(vv, mesh_vert(vm, i, ns2, ns2)->v);
if (frep) {
BLI_array_append(vf, frep);
- BMEdge *frep_e = find_closer_edge(mesh_vert(vm, i, ns2, ns2)->v->co, frep_e1, frep_e2);
- BLI_array_append(ve, v == vm->boundstart ? NULL : frep_e);
+ if (v == frep_unsnapped[0] || v == frep_unsnapped[1] || v == frep_unsnapped[2]) {
+ BLI_array_append(ve, NULL);
+ }
+ else {
+ BMEdge *frep_e = find_closer_edge(mesh_vert(vm, i, ns2, ns2)->v->co, frep_e1, frep_e2);
+ BLI_array_append(ve, frep_e);
+ }
}
else {
BLI_array_append(vf, boundvert_rep_face(v, NULL));
@@ -5242,6 +5312,109 @@ static VMesh *square_out_adj_vmesh(BevelParams *bp, BevVert *bv)
return vm;
}
+static BMEdge *snap_edge_for_center_vmesh_vert(int i,
+ int n_bndv,
+ BMEdge *eprev,
+ BMEdge *enext,
+ BMFace **bndv_rep_faces,
+ BMFace *center_frep,
+ const bool *frep_beats_next)
+{
+ int previ = (i + n_bndv - 1) % n_bndv;
+ int nexti = (i + 1) % n_bndv;
+
+ if (frep_beats_next[previ] && bndv_rep_faces[previ] == center_frep) {
+ return eprev;
+ }
+ else if (!frep_beats_next[i] && bndv_rep_faces[nexti] == center_frep) {
+ return enext;
+ }
+ /* If n_bndv > 3 then we won't snap in the boundvert regions
+ * that are not directly adjacent to the center-winning boundvert.
+ * This is probably wrong, maybe getting UV positions outside the
+ * original area, but the alternative may be even worse. */
+ return NULL;
+}
+
+/**
+ * Fill the r_snap_edges array with the edges to snap to (or NUL, if no snapping)
+ * for the adj mesh face with lower left corner at (i, ring j, segment k).
+ * The indices of the four corners are (i,j,k), (i,j,k+1), (i,j+1,k+1), (i,j+1,k).
+ * The answer will be one of NULL (don't snap), eprev (the edge between
+ * boundvert i and boundvert i-1), or enext (the edge between boundvert i
+ * and boundvert i+1).
+ * When n is odd, the center column (seg ns2) is ambiguous as to whether it
+ * interpolates in the current boundvert's frep [= interpolation face] or the next one's.
+ * Similarly, when n is odd, the center row (ring ns2) is ambiguous as to
+ * whether it interpolates in the current boundvert's frep or the previous one's.
+ * Parameter frep_beats_next should have an array of size n_bndv of bools
+ * that say whether the tie should be broken in favor of the next boundvert's
+ * frep (if true) or the current one's.
+ * For vertices in the center polygon (when ns is odd), the snapping edge depends
+ * on where the boundvert is in relation to the boundvert that has the center face's frep,
+ * so the arguments bndv_rep_faces is an array of size n_bndv give the freps for each i,
+ * and center_frep is the frep for the center.
+ *
+ * Note: this function is for edge bevels only, at the moment.
+ */
+static void snap_edges_for_vmesh_vert(int i,
+ int j,
+ int k,
+ int ns,
+ int ns2,
+ int n_bndv,
+ BMEdge *eprev,
+ BMEdge *enext,
+ BMEdge *enextnext,
+ BMFace **bndv_rep_faces,
+ BMFace *center_frep,
+ const bool *frep_beats_next,
+ BMEdge *r_snap_edges[4])
+{
+ BLI_assert(0 <= i && i < n_bndv && 0 <= j && j < ns2 && 0 <= k && k <= ns2);
+ for (int corner = 0; corner < 4; corner++) {
+ r_snap_edges[corner] = NULL;
+ if (ns % 2 == 0) {
+ continue;
+ }
+ int previ = (i + n_bndv - 1) % n_bndv;
+ /* Make jj and kk be the j and k indices for this corner. */
+ int jj = corner < 2 ? j : j + 1;
+ int kk = (corner == 0 || corner == 3) ? k : k + 1;
+ if (jj < ns2 && kk < ns2) {
+ ; /* No snap. */
+ }
+ else if (jj < ns2 && kk == ns2) {
+ /* On the left side of the center strip quads, but not on center poly. */
+ if (!frep_beats_next[i]) {
+ r_snap_edges[corner] = enext;
+ }
+ }
+ else if (jj < ns2 && kk == ns2 + 1) {
+ /* On the right side of the center strip quads, but not on center poly. */
+ if (frep_beats_next[i]) {
+ r_snap_edges[corner] = enext;
+ }
+ }
+ else if (jj == ns2 && kk < ns2) {
+ /* On the top of the top strip quads, but not on center poly. */
+ if (frep_beats_next[previ]) {
+ r_snap_edges[corner] = eprev;
+ }
+ }
+ else if (jj == ns2 && kk == ns2) {
+ /* Center poly vert for boundvert i. */
+ r_snap_edges[corner] = snap_edge_for_center_vmesh_vert(
+ i, n_bndv, eprev, enext, bndv_rep_faces, center_frep, frep_beats_next);
+ }
+ else if (jj == ns2 && kk == ns2 + 1) {
+ /* Center poly vert for boundvert i+1. */
+ r_snap_edges[corner] = snap_edge_for_center_vmesh_vert(
+ i + 1, n_bndv, enext, enextnext, bndv_rep_faces, center_frep, frep_beats_next);
+ }
+ }
+}
+
/**
* Given that the boundary is built and the boundary #BMVert's have been made,
* calculate the positions of the interior mesh points for the M_ADJ pattern,
@@ -5295,17 +5468,62 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv, BoundVert
}
}
vmesh_copy_equiv_verts(vm);
- /* Make the polygons. */
+
+ /* Find and store the interpolation face for each BoundVert. */
+ BMFace **bndv_rep_faces = BLI_array_alloca(bndv_rep_faces, n_bndv);
BoundVert *bndv = vm->boundstart;
do {
int i = bndv->index;
- BMFace *f = boundvert_rep_face(bndv, NULL);
- BMFace *f2 = boundvert_rep_face(bndv->next, NULL);
- BMFace *fchoices[2] = {f, f2};
- BMFace *fc = odd ? choose_rep_face(bp, fchoices, 2) : NULL;
+ bndv_rep_faces[i] = boundvert_rep_face(bndv, NULL);
+ } while ((bndv = bndv->next) != vm->boundstart);
- EdgeHalf *e = (bp->affect_type == BEVEL_AFFECT_VERTICES) ? bndv->efirst : bndv->ebev;
+ /* If odd number of segments, need data to break interpolation ties. */
+ BMVert **center_verts = NULL;
+ BMEdge **center_edge_snaps = NULL;
+ BMFace **center_face_interps = NULL;
+ bool *frep_beats_next = NULL;
+ BMFace *center_frep = NULL;
+ if (odd && bp->affect_type == BEVEL_AFFECT_EDGES) {
+ center_verts = BLI_array_alloca(center_verts, n_bndv);
+ center_edge_snaps = BLI_array_alloca(center_edge_snaps, n_bndv);
+ center_face_interps = BLI_array_alloca(center_face_interps, n_bndv);
+ frep_beats_next = BLI_array_alloca(frep_beats_next, n_bndv);
+ center_frep = frep_for_center_poly(bp, bv);
+ for (int i = 0; i < n_bndv; i++) {
+ center_edge_snaps[i] = NULL;
+ /* frep_beats_next[i] == true if frep for i is chosen over that for i + 1. */
+ int inext = (i + 1) % n_bndv;
+ BMFace *fchoices[2] = {bndv_rep_faces[i], bndv_rep_faces[inext]};
+ BMFace *fwinner = choose_rep_face(bp, fchoices, 2);
+ frep_beats_next[i] = fwinner == bndv_rep_faces[i];
+ }
+ }
+ /* Make the polygons. */
+ bndv = vm->boundstart;
+ do {
+ int i = bndv->index;
+ int inext = bndv->next->index;
+ BMFace *f = bndv_rep_faces[i];
+ BMFace *f2 = bndv_rep_faces[inext];
+ BMFace *fc = NULL;
+ if (odd && bp->affect_type == BEVEL_AFFECT_EDGES) {
+ fc = frep_beats_next[i] ? f : f2;
+ }
+
+ EdgeHalf *e, *eprev, *enext;
+ if (bp->affect_type == BEVEL_AFFECT_VERTICES) {
+ e = bndv->efirst;
+ eprev = bndv->prev->efirst;
+ enext = bndv->next->efirst;
+ }
+ else {
+ e = bndv->ebev;
+ eprev = bndv->prev->ebev;
+ enext = bndv->next->ebev;
+ }
BMEdge *bme = e ? e->e : NULL;
+ BMEdge *bmeprev = eprev ? eprev->e : NULL;
+ BMEdge *bmenext = enext ? enext->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,
@@ -5315,77 +5533,84 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv, BoundVert
*/
for (int j = 0; j < ns2; j++) {
for (int k = 0; k < ns2 + odd; k++) {
+ /* We will create a quad with these four corners. */
BMVert *bmv1 = mesh_vert(vm, i, j, k)->v;
BMVert *bmv2 = mesh_vert(vm, i, j, k + 1)->v;
BMVert *bmv3 = mesh_vert(vm, i, j + 1, k + 1)->v;
BMVert *bmv4 = mesh_vert(vm, i, j + 1, k)->v;
+ BMVert *bmvs[4] = {bmv1, bmv2, bmv3, bmv4};
BLI_assert(bmv1 && bmv2 && bmv3 && bmv4);
- BMFace *r_f;
+ /* For each created quad, the UVs etc. will be interpolated
+ * in potentially a different face for each corner and may need
+ * to snap to a particular edge before intorpolating.
+ * The fr and se arrays will be filled with the interpolation faces
+ * and snapping edges for the for corners in the order given
+ * in the bmvs array.
+ */
+ BMFace *fr[4];
+ BMEdge *se[4] = {NULL, NULL, NULL, NULL};
if (bp->affect_type == BEVEL_AFFECT_VERTICES) {
+ fr[0] = fr[1] = fr[2] = fr[3] = f2;
if (j < k) {
if (k == ns2 && j == ns2 - 1) {
- r_f = bev_create_quad_ex(bm,
- bmv1,
- bmv2,
- bmv3,
- bmv4,
- f2,
- f2,
- f2,
- f2,
- NULL,
- NULL,
- bndv->next->efirst->e,
- bme,
- f2,
- mat_nr);
- }
- else {
- r_f = bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2, mat_nr);
+ se[2] = bndv->next->efirst->e;
+ se[3] = bme;
}
}
- else if (j > k) {
- r_f = bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2, mat_nr);
- }
- else { /* j == k */
+ else if (j == k) {
/* Only one edge attached to v, since vertex only. */
- if (e->is_seam) {
- r_f = bev_create_quad_ex(
- bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2, bme, NULL, bme, NULL, f2, mat_nr);
- }
- else {
- r_f = bev_create_quad_ex(
- bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f, bme, NULL, bme, NULL, f2, mat_nr);
+ se[0] = se[2] = bme;
+ if (!e->is_seam) {
+ fr[3] = f;
}
}
}
else { /* Edge bevel. */
+ fr[0] = fr[1] = fr[2] = fr[3] = f;
if (odd) {
+ BMEdge *b1 = (eprev && eprev->is_seam) ? bmeprev : NULL;
+ BMEdge *b2 = (e && e->is_seam) ? bme : NULL;
+ BMEdge *b3 = (enext && enext->is_seam) ? bmenext : NULL;
+ snap_edges_for_vmesh_vert(i,
+ j,
+ k,
+ ns,
+ ns2,
+ n_bndv,
+ b1,
+ b2,
+ b3,
+ bndv_rep_faces,
+ center_frep,
+ frep_beats_next,
+ se);
if (k == ns2) {
- if (e && e->is_seam) {
- r_f = bev_create_quad_ex(
- bm, bmv1, bmv2, bmv3, bmv4, fc, fc, fc, fc, NULL, bme, bme, NULL, fc, mat_nr);
+ if (!e || e->is_seam) {
+ fr[0] = fr[1] = fr[2] = fr[3] = fc;
}
else {
- r_f = bev_create_quad_ex(
- bm, bmv1, bmv2, bmv3, bmv4, f, f2, f2, f, NULL, bme, bme, NULL, fc, mat_nr);
+ fr[0] = fr[3] = f;
+ fr[1] = fr[2] = f2;
+ }
+ if (j == ns2 - 1) {
+ /* Use the 4th vertex of these faces as the ones used for the center polygon. */
+ center_verts[i] = bmvs[3];
+ center_edge_snaps[i] = se[3];
+ center_face_interps[i] = bv->any_seam ? center_frep : f;
}
- }
- else {
- r_f = bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f, mat_nr);
}
}
- else {
- BMEdge *bme1 = k == ns2 - 1 ? bme : NULL;
- BMEdge *bme3 = NULL;
+ else { /* Edge bevel, Even number of segments. */
+ if (k == ns2 - 1) {
+ se[1] = bme;
+ }
if (j == ns2 - 1 && bndv->prev->ebev) {
- bme3 = bndv->prev->ebev->e;
+ se[3] = bmeprev;
}
- BMEdge *bme2 = bme1 != NULL ? bme1 : bme3;
- r_f = bev_create_quad_ex(
- bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f, NULL, bme1, bme2, bme3, f, mat_nr);
+ se[2] = se[1] != NULL ? se[1] : se[3];
}
}
+ BMFace *r_f = bev_create_ngon(bm, bmvs, 4, fr, NULL, se, mat_nr, true);
record_face_kind(bp, r_f, F_VERT);
}
}
@@ -5413,7 +5638,18 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv, BoundVert
/* Center ngon. */
if (odd) {
- build_center_ngon(bp, bm, bv, mat_nr);
+ if (bp->affect_type == BEVEL_AFFECT_EDGES) {
+ BMFace *frep = NULL;
+ if (bv->any_seam) {
+ frep = frep_for_center_poly(bp, bv);
+ }
+ BMFace *cen_f = bev_create_ngon(
+ bm, center_verts, n_bndv, center_face_interps, frep, center_edge_snaps, mat_nr, true);
+ record_face_kind(bp, cen_f, F_VERT);
+ }
+ else {
+ build_center_ngon(bp, bm, bv, mat_nr);
+ }
}
}
@@ -5421,11 +5657,11 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv, BoundVert
* Builds the vertex mesh when the vertex mesh type is set to "cut off" with a face closing
* off each incoming edge's profile.
*
- * TODO(Hans): Make cutoff VMesh work with outer miter != sharp. This should be possible but there
- * are two problems currently:
+ * TODO(Hans): Make cutoff VMesh work with outer miter != sharp. This should be possible but
+ * there are two problems currently:
* - Miter profiles don't have plane_no filled, so down direction is incorrect.
- * - Indexing profile points of miters with (i, 0, k) seems to return zero except for the first
- * and last profile point.
+ * - Indexing profile points of miters with (i, 0, k) seems to return zero except for the
+ * first and last profile point.
* TODO(Hans): Use repface / edge arrays for UV interpolation properly.
*/
static void bevel_build_cutoff(BevelParams *bp, BMesh *bm, BevVert *bv)
@@ -5449,7 +5685,8 @@ static void bevel_build_cutoff(BevelParams *bp, BMesh *bm, BevVert *bv)
negate_v3(down_direction);
}
- /* Move down from the boundvert by average profile height from the two adjacent profiles. */
+ /* Move down from the boundvert by average profile height from the two adjacent profiles.
+ */
float length = (bndv->profile.height / sqrtf(2.0f) +
bndv->prev->profile.height / sqrtf(2.0f)) /
2;
@@ -5502,8 +5739,8 @@ static void bevel_build_cutoff(BevelParams *bp, BMesh *bm, BevVert *bv)
}
/* Build the profile cutoff faces. */
- /* Extra one or two for corner vertices and one for last point along profile, or the size of the
- * center face array if it's bigger. */
+ /* Extra one or two for corner vertices and one for last point along profile, or the size of
+ * the center face array if it's bigger. */
#ifdef DEBUG_CUSTOM_PROFILE_CUTOFF
printf("Building profile cutoff faces.\n");
#endif
@@ -5591,9 +5828,11 @@ static BMFace *bevel_build_poly(BevelParams *bp, BMesh *bm, BevVert *bv)
BMFace *repface;
BMEdge *repface_e1, *repface_e2;
+ BoundVert *unsnapped[3];
if (bv->any_seam) {
repface = frep_for_center_poly(bp, bv);
get_incident_edges(repface, bv->v, &repface_e1, &repface_e2);
+ find_face_internal_boundverts(bv, repface, unsnapped);
}
else {
repface = NULL;
@@ -5607,8 +5846,13 @@ static BMFace *bevel_build_poly(BevelParams *bp, BMesh *bm, BevVert *bv)
BLI_array_append(bmverts, bndv->nv.v);
if (repface) {
BLI_array_append(bmfaces, repface);
- BMEdge *frep_e = find_closer_edge(bndv->nv.v->co, repface_e1, repface_e2);
- BLI_array_append(bmedges, n > 0 ? frep_e : NULL);
+ if (bndv == unsnapped[0] || bndv == unsnapped[1] || bndv == unsnapped[2]) {
+ BLI_array_append(bmedges, NULL);
+ }
+ else {
+ BMEdge *frep_e = find_closer_edge(bndv->nv.v->co, repface_e1, repface_e2);
+ BLI_array_append(bmedges, frep_e);
+ }
}
else {
BLI_array_append(bmfaces, boundvert_rep_face(bndv, NULL));
@@ -5858,7 +6102,8 @@ static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv)
}
}
- /* Make sure the pipe case ADJ mesh is used for both the "Grid Fill" (ADJ) and cutoff options. */
+ /* Make sure the pipe case ADJ mesh is used for both the "Grid Fill" (ADJ) and cutoff
+ * options. */
BoundVert *vpipe = NULL;
if (ELEM(vm->count, 3, 4) && bp->seg > 1) {
/* Result is passed to bevel_build_rings to avoid overhead. */
@@ -5979,8 +6224,8 @@ static int bevel_edge_order_extend(BMesh *bm, BevVert *bv, int i)
* Assume the first edge is already in bv->edges[0].e and it is tagged. */
#ifdef FASTER_FASTORDER
/* The alternative older code is O(n^2) where n = # of edges incident to bv->v.
- * This implementation is O(n * m) where m = average number of faces attached to an edge incident
- * to bv->v, which is almost certainly a small constant except in very strange cases.
+ * This implementation is O(n * m) where m = average number of faces attached to an edge
+ * incident to bv->v, which is almost certainly a small constant except in very strange cases.
* But this code produces different choices of ordering than the legacy system,
* leading to differences in vertex orders etc. in user models,
* so for now will continue to use the legacy code. */
@@ -6070,8 +6315,8 @@ static bool fast_bevel_edge_order(BevVert *bv)
#endif
/* Fill in bv->edges with a good ordering of non-wire edges around bv->v.
- * Use only edges where BM_BEVEL_EDGE_TAG is disabled so far (if edge beveling, others are wire).
- * first_bme is a good edge to start with. */
+ * Use only edges where BM_BEVEL_EDGE_TAG is disabled so far (if edge beveling, others are
+ * wire). first_bme is a good edge to start with. */
static void find_bevel_edge_order(BMesh *bm, BevVert *bv, BMEdge *first_bme)
{
int ntot = bv->edgecount;
@@ -6359,10 +6604,10 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
sub_v3_v3v3(edge_dir, bv->v->co, v2->co);
float z = fabsf(2.0f * sinf(angle_v3v3(vert_axis, edge_dir)));
if (z < BEVEL_EPSILON) {
- e->offset_l_spec = 0.01f * bv->offset; /* Undefined behavior, so tiny bevel. */
+ e->offset_l_spec = 0.01f * bp->offset; /* Undefined behavior, so tiny bevel. */
}
else {
- e->offset_l_spec = bv->offset / z;
+ e->offset_l_spec = bp->offset / z;
}
break;
}
@@ -6371,10 +6616,10 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
sub_v3_v3v3(edge_dir, bv->v->co, v2->co);
float z = fabsf(cosf(angle_v3v3(vert_axis, edge_dir)));
if (z < BEVEL_EPSILON) {
- e->offset_l_spec = 0.01f * bv->offset; /* Undefined behavior, so tiny bevel. */
+ e->offset_l_spec = 0.01f * bp->offset; /* Undefined behavior, so tiny bevel. */
}
else {
- e->offset_l_spec = bv->offset / z;
+ e->offset_l_spec = bp->offset / z;
}
break;
}
@@ -6494,7 +6739,8 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f)
BLI_array_append(ee, bme);
}
while (v != vend) {
- /* Check for special case: multi-segment 3rd face opposite a beveled edge with no vmesh. */
+ /* Check for special case: multi-segment 3rd face opposite a beveled edge with no
+ * vmesh. */
bool corner3special = (vm->mesh_kind == M_NONE && v->ebev != e && v->ebev != eprev);
if (go_ccw) {
int i = v->index;
@@ -6829,13 +7075,20 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme)
int odd = nseg % 2;
int mid = nseg / 2;
BMEdge *center_bme = NULL;
+ BMFace *fchoices[2] = {f1, f2};
+ BMFace *f_choice = NULL;
+ int center_adj_k = -1;
+ if (odd & e1->is_seam) {
+ f_choice = choose_rep_face(bp, fchoices, 2);
+ if (nseg > 1) {
+ center_adj_k = f_choice == f1 ? mid + 2 : mid;
+ }
+ }
for (int k = 1; k <= nseg; k++) {
verts[3] = mesh_vert(vm1, i1, 0, k)->v;
verts[2] = mesh_vert(vm2, i2, 0, nseg - k)->v;
BMFace *r_f;
if (odd && k == mid + 1) {
- BMFace *fchoices[2] = {f1, f2};
- BMFace *f_choice = choose_rep_face(bp, fchoices, 2);
if (e1->is_seam) {
/* Straddles a seam: choose to interpolate in f_choice and snap the loops whose verts
* are in the non-chosen face to bme for interpolation purposes.
@@ -6856,6 +7109,25 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme)
r_f = bev_create_ngon(bm, verts, 4, faces, f_choice, NULL, mat_nr, true);
}
}
+ else if (odd && k == center_adj_k && e1->is_seam) {
+ /* The strip adjacent to the center one, in another UV island.
+ * Snap the edge near the seam to bme to match what happens in
+ * the bevel rings.
+ */
+ BMEdge *edges[4];
+ BMFace *f_interp;
+ if (k == mid) {
+ edges[0] = edges[1] = NULL;
+ edges[2] = edges[3] = bme;
+ f_interp = f1;
+ }
+ else {
+ edges[0] = edges[1] = bme;
+ edges[2] = edges[3] = NULL;
+ f_interp = f2;
+ }
+ r_f = bev_create_ngon(bm, verts, 4, NULL, f_interp, edges, mat_nr, true);
+ }
else if (!odd && k == mid) {
/* Left poly that touches an even center line on right. */
BMEdge *edges[4] = {NULL, NULL, bme, bme};
@@ -6929,7 +7201,8 @@ static double find_superellipse_chord_endpoint(double x0, double dtarget, float
const double tol = 1e-13; /* accumulates for many segments so use low value. */
const int maxiter = 10;
- /* For gradient between -1 and 1, xnew can only be in [x0 + sqrt(2)/2*dtarget, x0 + dtarget]. */
+ /* For gradient between -1 and 1, xnew can only be in [x0 + sqrt(2)/2*dtarget, x0 + dtarget].
+ */
double xmin = x0 + M_SQRT2 / 2.0 * dtarget;
if (xmin > 1.0) {
xmin = 1.0;
@@ -7222,8 +7495,8 @@ static float find_profile_fullness(BevelParams *bp)
* The superellipse used for multi-segment profiles does not have a closed-form way
* to generate evenly spaced points along an arc. We use an expensive search procedure
* to find the parameter values that lead to bp->seg even chords.
- * We also want spacing for a number of segments that is a power of 2 >= bp->seg (but at least 4).
- * Use doubles because otherwise we cannot come close to float precision for final results.
+ * We also want spacing for a number of segments that is a power of 2 >= bp->seg (but at least
+ * 4). Use doubles because otherwise we cannot come close to float precision for final results.
*
* \param pro_spacing: The struct to fill. Changes depending on whether there needs
* to be a separate miter profile.
@@ -7426,9 +7699,9 @@ static float geometry_collide_offset(BevelParams *bp, EdgeHalf *eb)
}
/**
- * We have an edge A between vertices a and b, where EdgeHalf ea is the half of A that starts at a.
- * For vertex-only bevels, the new vertices slide from a at a rate ka*t and from b at a rate kb*t.
- * We want to calculate the t at which the two meet.
+ * We have an edge A between vertices a and b, where EdgeHalf ea is the half of A that starts
+ * at a. For vertex-only bevels, the new vertices slide from a at a rate ka*t and from b at a
+ * rate kb*t. We want to calculate the t at which the two meet.
*/
static float vertex_collide_offset(BevelParams *bp, EdgeHalf *ea)
{
@@ -7448,9 +7721,10 @@ static float vertex_collide_offset(BevelParams *bp, EdgeHalf *ea)
}
/**
- * Calculate an offset that is the lesser of the current bp.offset and the maximum possible offset
- * before geometry collisions happen. If the offset changes as a result of this, adjust the current
- * edge offset specs to reflect this clamping, and store the new offset in bp.offset.
+ * Calculate an offset that is the lesser of the current bp.offset and the maximum possible
+ * offset before geometry collisions happen. If the offset changes as a result of this, adjust
+ * the current edge offset specs to reflect this clamping, and store the new offset in
+ * bp.offset.
*/
static void bevel_limit_offset(BevelParams *bp, BMesh *bm)
{
@@ -7577,7 +7851,8 @@ void BM_mesh_bevel(BMesh *bm,
double start_time = PIL_check_seconds_timer();
#endif
- /* Disable the miters with the cutoff vertex mesh method, the combination isn't useful anyway. */
+ /* Disable the miters with the cutoff vertex mesh method, the combination isn't useful
+ * anyway. */
if (bp.vmesh_method == BEVEL_VMESH_CUTOFF) {
bp.miter_outer = BEVEL_MITER_SHARP;
bp.miter_inner = BEVEL_MITER_SHARP;