From b747759698fa8b7f6bed746a9f30419840973c3b Mon Sep 17 00:00:00 2001 From: Howard Trickey Date: Mon, 12 Nov 2012 02:52:24 +0000 Subject: Bevel: several bug fixes. --- source/blender/bmesh/operators/bmo_bevel.c | 63 ++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 17 deletions(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 7df5aa8fe9c..0b7f2b8292a 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -384,10 +384,9 @@ static void offset_in_two_planes(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, madd_v3_v3fl(off2a, norm_perp2, e2->offset); add_v3_v3v3(off2b, off2a, dir2); - /* intersect the lines; by construction they should be on the same plane and not parallel */ if (!isect_line_line_v3(off1a, off1b, off2a, off2b, meetco, isect2)) { - BLI_assert(!"offset_meet failure"); - copy_v3_v3(meetco, off1a); /* just to do something */ + /* lines are parallel; off1a is a good meet point */ + copy_v3_v3(meetco, off1a); } } @@ -537,10 +536,10 @@ static void get_point_on_round_edge(EdgeHalf *e, int i, get_point_on_round_profile(point, e->offset, i, n, vaadj, vmid, vbadj); - add_v3_v3v3(p2, profileco, dir); + add_v3_v3v3(p2, point, dir); cross_v3_v3v3(pn, vva, vvb); if (!isect_line_plane_v3(profileco, point, p2, vmid, pn, 0)) { - BLI_assert(!"bevel: unexpected non-intersection"); + /* TODO: track down why this sometimes fails */ copy_v3_v3(profileco, point); } } @@ -669,7 +668,7 @@ static void build_boundary(BevVert *bv) BLI_assert(vm->count >= 2); if (vm->count == 2 && bv->edgecount == 3) vm->mesh_kind = M_NONE; - else if (efirst->seg == 1 || bv->selcount < 3) + else if (efirst->seg == 1 || bv->selcount == 1) vm->mesh_kind = M_POLY; else vm->mesh_kind = M_ADJ; @@ -694,8 +693,9 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv) ns = vm->seg; ns2 = ns / 2; BLI_assert(n > 2 && ns > 1); - - /* Make initial rings, going between points on neighbors */ + /* Make initial rings, going between points on neighbors. + * After this loop, will have coords for all (i, r, k) where + * BoundVert for i has a bevel, 0 <= r <= ns2, 0 <= k <= ns */ for (ring = 1; ring <= ns2; ring++) { v = vm->boundstart; do { @@ -736,7 +736,12 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv) } while (v != vm->boundstart); } - /* Now make sure cross points of rings share coordinates and vertices */ + /* Now make sure cross points of rings share coordinates and vertices. + * After this loop, will have BMVerts for all (i, r, k) where + * i is for a BoundVert that is beveled and has either a predecessor or + * successor BoundVert beveled too, and + * for odd ns: 0 <= r <= ns2, 0 <= k <= ns + * for even ns: 0 <= r < ns2, 0 <= k <= ns except k=ns2 */ v = vm->boundstart; do { i = v->index; @@ -781,7 +786,10 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv) } while (v != vm->boundstart); if (ns % 2 == 0) { - /* do special case center lines */ + /* Do special case center lines. + * This loop makes verts for (i, ns2, k) for 1 <= k <= ns-1, k!=ns2 + * and for (i, r, ns2) for 1 <= r <= ns2-1, + * whenever i is in a sequence of at least two beveled verts */ v = vm->boundstart; do { i = v->index; @@ -807,12 +815,16 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv) copy_v3_v3(nv->co, co); create_mesh_bmvert(bm, vm, i, k, ns2, bv->v); copy_mesh_vert(vm, vprev->index, ns2, ns - k, i, k, ns2); + + create_mesh_bmvert(bm, vm, i, ns2, ns - k, bv->v); } else if (vnext->ebev) { mid_v3_v3v3(co, nv->co, nvnext->co); copy_v3_v3(nv->co, co); create_mesh_bmvert(bm, vm, i, k, ns2, bv->v); copy_mesh_vert(vm, vnext->index, ns2, k, i, k, ns2); + + create_mesh_bmvert(bm, vm, i, ns2, k, bv->v); } } } @@ -871,11 +883,16 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv) i = v->prev->index; f = boundvert_rep_face(v->prev); for (k = ns2 + (ns % 2); k < ns; k++) { - bmv1 = mesh_vert(vm, i, ring + 1, k)->v; - bmv2 = mesh_vert(vm, i, ring, k)->v; - bmv3 = mesh_vert(vm, i, ring, k + 1)->v; - BLI_assert(bmv1 && bmv2 && bmv3); - bev_create_quad_tri(bm, bmv1, bmv2, bmv3, NULL, f); + bmv1 = mesh_vert(vm, i, ring, k)->v; + bmv2 = mesh_vert(vm, i, ring, k + 1)->v; + bmv3 = mesh_vert(vm, i, ring + 1, k + 1)->v; + bmv4 = mesh_vert(vm, i, ring + 1, k)->v; + BLI_assert(bmv1 && bmv2 && bmv3 && bmv4); + if (bmv2 == bmv3) { + bmv3 = bmv4; + bmv4 = NULL; + } + bev_create_quad_tri(bm, bmv1, bmv2, bmv3, bmv4, f); } } v = v->next; @@ -915,21 +932,30 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv) if (!v->prev->ebev) { for (k = 0; k < ns2; k++) { bmv1 = mesh_vert(vm, i, ns2, k)->v; + if (!bmv1) + bmv1 = mesh_vert(vm, i, 0, k)->v; if (!(j > 0 && bmv1 == vv[j - 1])) { + BLI_assert(bmv1 != NULL); BLI_array_append(vv, bmv1); j++; } } } bmv1 = mesh_vert(vm, i, ns2, ns2)->v; + if (!bmv1) + bmv1 = mesh_vert(vm, i, 0, ns2)->v; if (!(j > 0 && bmv1 == vv[j - 1])) { + BLI_assert(bmv1 != NULL); BLI_array_append(vv, bmv1); j++; } if (!v->next->ebev) { for (k = ns - ns2; k < ns; k++) { bmv1 = mesh_vert(vm, i, ns2, k)->v; + if (!bmv1) + bmv1 = mesh_vert(vm, i, 0, k)->v; if (!(j > 0 && bmv1 == vv[j - 1])) { + BLI_assert(bmv1 != NULL); BLI_array_append(vv, bmv1); j++; } @@ -937,6 +963,7 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv) } } else { + BLI_assert(mesh_vert(vm, i, 0, 0)->v != NULL); BLI_array_append(vv, mesh_vert(vm, i, 0, 0)->v); j++; } @@ -1032,9 +1059,11 @@ static void build_vmesh(BMesh *bm, BevVert *bv) } while (v != vm->boundstart); if (weld) { + vm->mesh_kind = M_NONE; for (k = 1; k < ns; k++) { - mid_v3_v3v3(co, mesh_vert(vm, weld1->index, 0, k)->co, - mesh_vert(vm, weld2->index, 0, ns - k)->co); + va = mesh_vert(vm, weld1->index, 0, k)->co; + vb = mesh_vert(vm, weld2->index, 0, ns - k)->co; + mid_v3_v3v3(co,va, vb); copy_v3_v3(mesh_vert(vm, weld1->index, 0, k)->co, co); create_mesh_bmvert(bm, vm, weld1->index, 0, k, bv->v); } -- cgit v1.2.3 From 744378483cd5a3e43931740315515ffb02c185b0 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 12 Nov 2012 03:41:25 +0000 Subject: style cleanup --- source/blender/bmesh/operators/bmo_bevel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 0b7f2b8292a..cbaf0cf40d3 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -1063,7 +1063,7 @@ static void build_vmesh(BMesh *bm, BevVert *bv) for (k = 1; k < ns; k++) { va = mesh_vert(vm, weld1->index, 0, k)->co; vb = mesh_vert(vm, weld2->index, 0, ns - k)->co; - mid_v3_v3v3(co,va, vb); + mid_v3_v3v3(co, va, vb); copy_v3_v3(mesh_vert(vm, weld1->index, 0, k)->co, co); create_mesh_bmvert(bm, vm, weld1->index, 0, k, bv->v); } -- cgit v1.2.3 From 97b7154142edd2ab72cb2637bb4caa66536039b2 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 12 Nov 2012 04:50:45 +0000 Subject: replace BM_edge_face_count with BM_edge_is_manifold/BM_edge_is_wire/BM_edge_is_boundary --- source/blender/bmesh/operators/bmo_bevel.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index cbaf0cf40d3..2c9f3a1cc6e 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -1097,7 +1097,7 @@ static void bevel_vert_construct(BMesh *bm, BevelParams *bp, BMOperator *op, BMV * Only bevel selected edges that have exactly two incident faces. */ BMO_ITER (bme, &siter, bm, op, "geom", BM_EDGE) { if ((bme->v1 == v) || (BM_edge_other_vert(bme, bme->v1) == v)) { - if (BM_edge_face_count(bme) == 2) { + if (BM_edge_is_manifold(bme)) { BMO_elem_flag_enable(bm, bme, EDGE_SELECTED); nsel++; } @@ -1295,7 +1295,7 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme) BMFace *f1, *f2, *f; int k, nseg, i1, i2; - if (BM_edge_face_count(bme) != 2) + if (!BM_edge_is_manifold(bme)) return; bv1 = find_bevvert(bp, bme->v1); @@ -1592,7 +1592,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) BMO_elem_flag_disable(bm, e->v2, BEVEL_DEL); } #if 0 - if (BM_edge_face_count(e) == 0) { + if (BM_edge_is_wire(e)) { BMVert *verts[2] = {e->v1, e->v2}; BMEdge *edges[2] = {e, BM_edge_create(bm, e->v1, e->v2, e, 0)}; -- cgit v1.2.3 From 428e5b7a99eeae77caccbabbf32a7e596d0907d7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 12 Nov 2012 05:29:54 +0000 Subject: bmesh bevel todo: don't loop through all faces to find faces connected to a vertex. --- source/blender/bmesh/operators/bmo_bevel.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 2c9f3a1cc6e..7fededd0635 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -1265,19 +1265,17 @@ static void rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f) /* All polygons touching v need rebuilding because beveling v has made new vertices */ static void bevel_rebuild_existing_polygons(BMesh *bm, BevelParams *bp, BMVert *v) { - BMFace *f; - BMIter iter; + int faces_len, f_index; + BMFace **faces = BM_iter_as_arrayN(bm, BM_FACES_OF_VERT, v, &faces_len); + + if (LIKELY(faces != NULL)) { + for (f_index = 0; f_index < faces_len; f_index++) { + BMFace *f = faces[f_index]; + rebuild_polygon(bm, bp, f); + BM_face_kill(bm, f); + } - /* TODO: don't iterate through all faces, but just local geometry around v */ - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - BMLoop *l = f->l_first; - do { - if (l->v == v) { - rebuild_polygon(bm, bp, f); - BM_face_kill(bm, f); - } - l = l->next; - } while (l != f->l_first); + MEM_freeN(faces); } } -- cgit v1.2.3 From 0bfc92ff8e16c76b8a01ace39f3e98b2beeda795 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 12 Nov 2012 05:53:43 +0000 Subject: BM_iter_as_arrayN() can now take an optional existing array argument, useful to avoid many small malloc's by passing a fixes size stack variable instead. Will give some speedup to edge-split modifier and bevel. --- source/blender/bmesh/operators/bmo_bevel.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 7fededd0635..e18920fc98e 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -1265,8 +1265,10 @@ static void rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f) /* All polygons touching v need rebuilding because beveling v has made new vertices */ static void bevel_rebuild_existing_polygons(BMesh *bm, BevelParams *bp, BMVert *v) { + void *faces_stack[BM_DEFAULT_ITER_STACK_SIZE]; int faces_len, f_index; - BMFace **faces = BM_iter_as_arrayN(bm, BM_FACES_OF_VERT, v, &faces_len); + BMFace **faces = BM_iter_as_arrayN(bm, BM_FACES_OF_VERT, v, &faces_len, + faces_stack, BM_DEFAULT_ITER_STACK_SIZE); if (LIKELY(faces != NULL)) { for (f_index = 0; f_index < faces_len; f_index++) { @@ -1275,7 +1277,9 @@ static void bevel_rebuild_existing_polygons(BMesh *bm, BevelParams *bp, BMVert * BM_face_kill(bm, f); } - MEM_freeN(faces); + if (faces != (BMFace **)faces_stack) { + MEM_freeN(faces); + } } } -- cgit v1.2.3 From cf6994b9104669b0057e5519636b8819b936b5b7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 12 Nov 2012 07:33:01 +0000 Subject: code cleanup: spelling, also initialize bmesh-bevel settings struct to zero to avoid possible uninitialized memory later. --- source/blender/bmesh/operators/bmo_bevel.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index e18920fc98e..0b95cc03d1e 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -1094,9 +1094,13 @@ static void bevel_vert_construct(BMesh *bm, BevelParams *bp, BMOperator *op, BMV int nsel = 0; /* Gather input selected edges. - * Only bevel selected edges that have exactly two incident faces. */ + * Only bevel selected edges that have exactly two incident faces. + * + * TODO, optimization - we could tag edges in 'geom' + * and then just iterate edges-of-vert, checking tags. + */ BMO_ITER (bme, &siter, bm, op, "geom", BM_EDGE) { - if ((bme->v1 == v) || (BM_edge_other_vert(bme, bme->v1) == v)) { + if (BM_vert_in_edge(bme, v)) { if (BM_edge_is_manifold(bme)) { BMO_elem_flag_enable(bm, bme, EDGE_SELECTED); nsel++; @@ -1310,12 +1314,12 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme) BLI_assert(e1 && e2); - /* v4 v3 - * \ / - * e->v1 - e->v2 - * / \ - * v1 v2 */ - + /* v4 v3 + * \ / + * e->v1 - e->v2 + * / \ + * v1 v2 + */ nseg = e1->seg; BLI_assert(nseg > 0 && nseg == e2->seg); @@ -1380,15 +1384,13 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) BMOIter siter; BMVert *v; BMEdge *e; - BevelParams bp; + BevelParams bp = {{NULL}}; bp.offset = BMO_slot_float_get(op, "offset"); bp.op = op; bp.seg = BMO_slot_int_get(op, "segments"); if (bp.offset > 0) { - bp.vertList.first = bp.vertList.last = NULL; - /* The analysis of the input vertices and execution additional constructions */ BMO_ITER (v, &siter, bm, op, "geom", BM_VERT) { bevel_vert_construct(bm, &bp, op, v); -- cgit v1.2.3 From 08ec3ab64e95e0d4a8cf9401a11ae3c5f97ef981 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 12 Nov 2012 11:59:28 +0000 Subject: bevel fan fill edges meeting non selected geometry rather then making ngons which often dont triangulate nicely to follow rounded corners: http://www.graphicall.org/ftp/ideasman42/bevel_fan_fill.png --- source/blender/bmesh/operators/bmo_bevel.c | 58 +++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 4 deletions(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 0b95cc03d1e..ae8012d7849 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -84,6 +84,7 @@ typedef struct VMesh { M_POLY, /* a simple polygon */ M_ADJ, /* "adjacent edges" mesh pattern */ M_CROSS, /* "cross edges" mesh pattern */ + M_FAN, /* a simple polygon - fan filled */ } mesh_kind; int count; /* number of vertices in the boundary */ int seg; /* common # of segments for segmented edges */ @@ -669,7 +670,7 @@ static void build_boundary(BevVert *bv) if (vm->count == 2 && bv->edgecount == 3) vm->mesh_kind = M_NONE; else if (efirst->seg == 1 || bv->selcount == 1) - vm->mesh_kind = M_POLY; + vm->mesh_kind = M_FAN; /* was M_POLY */ else vm->mesh_kind = M_ADJ; /* TODO: if vm->count == 4 and bv->selcount == 4, use M_CROSS pattern */ @@ -977,8 +978,9 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv) } } -static void bevel_build_poly(BMesh *bm, BevVert *bv) +static BMFace *bevel_build_poly_ex(BMesh *bm, BevVert *bv) { + BMFace *f; int n, k; VMesh *vm = bv->vmesh; BoundVert *v; @@ -999,11 +1001,57 @@ static void bevel_build_poly(BMesh *bm, BevVert *bv) } v = v->next; } while (v != vm->boundstart); - if (n > 2) - bev_create_ngon(bm, vv, n, boundvert_rep_face(v)); + if (n > 2) { + f = bev_create_ngon(bm, vv, n, boundvert_rep_face(v)); + } + else { + f = NULL; + } BLI_array_free(vv); + return f; +} + +static void bevel_build_poly(BMesh *bm, BevVert *bv) +{ + bevel_build_poly_ex(bm, bv); } +static void bevel_build_fan(BMesh *bm, BevVert *bv) +{ + BMFace *f; + BLI_assert(next_bev(bv, NULL)->seg == 1 || bv->selcount == 1); + + f = bevel_build_poly_ex(bm, bv); + + if (f) { + /* we have a polygon which we know starts at the previous vertex, make it into a fan */ + BMLoop *l_fan = BM_FACE_FIRST_LOOP(f)->prev; + BMVert *v_fan = l_fan->v; + + while (f->len > 3) { + BMLoop *l_new; + BMFace *f_new; + BLI_assert(v_fan == l_fan->v); + f_new = BM_face_split(bm, f, l_fan->v, l_fan->next->next->v, &l_new, NULL, FALSE); + + if (f_new->len > f->len) { + f = f_new; + if (l_new->v == v_fan) { l_fan = l_new; } + else if (l_new->next->v == v_fan) { l_fan = l_new->next; } + else if (l_new->prev->v == v_fan) { l_fan = l_new->prev; } + else { BLI_assert(0); } + } + else { + if (l_fan->v == v_fan) { l_fan = l_fan; } + else if (l_fan->next->v == v_fan) { l_fan = l_fan->next; } + else if (l_fan->prev->v == v_fan) { l_fan = l_fan->prev; } + else { BLI_assert(0); } + } + } + } +} + + /* Given that the boundary is built, now make the actual BMVerts * for the boundary and the interior of the vertex mesh. */ static void build_vmesh(BMesh *bm, BevVert *bv) @@ -1075,6 +1123,8 @@ static void build_vmesh(BMesh *bm, BevVert *bv) bevel_build_rings(bm, bv); else if (vm->mesh_kind == M_POLY) bevel_build_poly(bm, bv); + else if (vm->mesh_kind == M_FAN) + bevel_build_fan(bm, bv); } /* -- cgit v1.2.3 From fbdae9ca0aacd3c93e38d36fb39bb09ce7461f4b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 12 Nov 2012 12:16:21 +0000 Subject: change bevel do/while loops to step the pointer in the while check, no functional changes. --- source/blender/bmesh/operators/bmo_bevel.c | 57 +++++++++++------------------- 1 file changed, 21 insertions(+), 36 deletions(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index ae8012d7849..a270496a936 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -188,10 +188,10 @@ static EdgeHalf *next_bev(BevVert *bv, EdgeHalf *from_e) from_e = &bv->edges[bv->edgecount - 1]; e = from_e; do { - if (e->isbev) + if (e->isbev) { return e; - e = e->next; - } while (e != from_e); + } + } while ((e = e->next) != from_e); return NULL; } @@ -440,8 +440,7 @@ static void project_to_edge(BMEdge *e, float co_a[3], float co_b[3], float projc { float otherco[3]; - if (!isect_line_line_v3(e->v1->co, e->v2->co, co_a, co_b, - projco, otherco)) { + if (!isect_line_line_v3(e->v1->co, e->v2->co, co_a, co_b, projco, otherco)) { BLI_assert(!"project meet failure"); copy_v3_v3(projco, e->v1->co); } @@ -639,10 +638,9 @@ static void build_boundary(BevVert *bv) /* e is not beveled */ if (e->next->isbev) { /* next iteration will place e between beveled previous and next edges */ - e = e->next; - continue; + /* do nothing... */ } - if (e->prev->isbev) { + else if (e->prev->isbev) { /* on-edge meet between e->prev and e */ offset_meet(e->prev, e, bv->v, e->fprev, TRUE, co); v = add_new_bound_vert(vm, co); @@ -663,8 +661,7 @@ static void build_boundary(BevVert *bv) e->leftv = v; } } - e = e->next; - } while (e != efirst); + } while ((e = e->next) != efirst); BLI_assert(vm->count >= 2); if (vm->count == 2 && bv->edgecount == 3) @@ -733,8 +730,7 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv) copy_v3_v3(mesh_vert(vm, i, ring, k)->co, co); } } - v = v->next; - } while (v != vm->boundstart); + } while ((v = v->next) != vm->boundstart); } /* Now make sure cross points of rings share coordinates and vertices. @@ -783,8 +779,7 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv) } } } - v = v->next; - } while (v != vm->boundstart); + } while ((v = v->next) != vm->boundstart); if (ns % 2 == 0) { /* Do special case center lines. @@ -829,8 +824,7 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv) } } } - v = v->next; - } while (v != vm->boundstart); + } while ((v = v->next) != vm->boundstart); /* center point need to be average of all centers of rings */ /* TODO: this is wrong if not all verts have ebev: could have @@ -845,8 +839,7 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv) add_v3_v3(midco, nv->co); nn++; } - v = v->next; - } while (v != vm->boundstart); + } while ((v = v->next) != vm->boundstart); mul_v3_fl(midco, 1.0f / nn); bmv = BM_vert_create(bm, midco, NULL); v = vm->boundstart; @@ -857,8 +850,7 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv) copy_v3_v3(nv->co, midco); nv->v = bmv; } - v = v->next; - } while (v != vm->boundstart); + } while ((v = v->next) != vm->boundstart); } /* Make the ring quads */ @@ -896,8 +888,7 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv) bev_create_quad_tri(bm, bmv1, bmv2, bmv3, bmv4, f); } } - v = v->next; - } while (v != vm->boundstart); + } while ((v = v->next) != vm->boundstart); } /* Make center ngon if odd number of segments and fully beveled */ @@ -910,8 +901,7 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv) i = v->index; BLI_assert(v->ebev); BLI_array_append(vv, mesh_vert(vm, i, ns2, ns2)->v); - v = v->next; - } while (v != vm->boundstart); + } while ((v = v->next) != vm->boundstart); f = boundvert_rep_face(vm->boundstart); bev_create_ngon(bm, vv, BLI_array_count(vv), f); @@ -968,8 +958,7 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv) BLI_array_append(vv, mesh_vert(vm, i, 0, 0)->v); j++; } - v = v->next; - } while (v != vm->boundstart); + } while ((v = v->next) != vm->boundstart); if (vv[0] == vv[j - 1]) j--; bev_create_ngon(bm, vv, j, f); @@ -999,8 +988,7 @@ static BMFace *bevel_build_poly_ex(BMesh *bm, BevVert *bv) n++; } } - v = v->next; - } while (v != vm->boundstart); + } while ((v = v->next) != vm->boundstart); if (n > 2) { f = bev_create_ngon(bm, vv, n, boundvert_rep_face(v)); } @@ -1036,13 +1024,13 @@ static void bevel_build_fan(BMesh *bm, BevVert *bv) if (f_new->len > f->len) { f = f_new; - if (l_new->v == v_fan) { l_fan = l_new; } + if (l_new->v == v_fan) { l_fan = l_new; } else if (l_new->next->v == v_fan) { l_fan = l_new->next; } else if (l_new->prev->v == v_fan) { l_fan = l_new->prev; } else { BLI_assert(0); } } else { - if (l_fan->v == v_fan) { l_fan = l_fan; } + if (l_fan->v == v_fan) { l_fan = l_fan; } else if (l_fan->next->v == v_fan) { l_fan = l_fan->next; } else if (l_fan->prev->v == v_fan) { l_fan = l_fan->prev; } else { BLI_assert(0); } @@ -1084,8 +1072,7 @@ static void build_vmesh(BMesh *bm, BevVert *bv) else weld2 = v; } - v = v->next; - } while (v != vm->boundstart); + } while ((v = v->next) != vm->boundstart); /* copy other ends to (i, 0, ns) for all i, and fill in profiles for beveled edges */ v = vm->boundstart; @@ -1103,8 +1090,7 @@ static void build_vmesh(BMesh *bm, BevVert *bv) create_mesh_bmvert(bm, vm, i, 0, k, bv->v); } } - v = v->next; - } while (v != vm->boundstart); + } while ((v = v->next) != vm->boundstart); if (weld) { vm->mesh_kind = M_NONE; @@ -1419,8 +1405,7 @@ static void free_bevel_params(BevelParams *bp) do { vnext = v->next; MEM_freeN(v); - v = vnext; - } while (v != vm->boundstart); + } while ((v = vnext) != vm->boundstart); } if (vm->mesh) MEM_freeN(vm->mesh); -- cgit v1.2.3 From 0364a83771aedc5b2911a74cc5f2ae23d07996c5 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 12 Nov 2012 12:30:58 +0000 Subject: fan filling didnt always work well, now only apply this when its going to work properly. --- source/blender/bmesh/operators/bmo_bevel.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index a270496a936..fcf3816ff9d 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -664,12 +664,20 @@ static void build_boundary(BevVert *bv) } while ((e = e->next) != efirst); BLI_assert(vm->count >= 2); - if (vm->count == 2 && bv->edgecount == 3) + if (vm->count == 2 && bv->edgecount == 3) { vm->mesh_kind = M_NONE; - else if (efirst->seg == 1 || bv->selcount == 1) - vm->mesh_kind = M_FAN; /* was M_POLY */ - else + } + else if (efirst->seg == 1 || bv->selcount == 1) { + if (vm->count == 3 && bv->selcount == 1) { + vm->mesh_kind = M_FAN; + } + else { + vm->mesh_kind = M_POLY; + } + } + else { vm->mesh_kind = M_ADJ; + } /* TODO: if vm->count == 4 and bv->selcount == 4, use M_CROSS pattern */ } -- cgit v1.2.3 From 66aa7e9192921207445ae6ab5807b15ccd8e8b3b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 12 Nov 2012 16:08:02 +0000 Subject: add simple quad-strip filling to bevel, use to bevel edges when 2 bevel-edges share a vertex. this gives more useful topology, eg: http://www.graphicall.org/ftp/ideasman42/bevel_strip_fill.png --- source/blender/bmesh/operators/bmo_bevel.c | 55 ++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 6 deletions(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index fcf3816ff9d..db5b769d078 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -84,7 +84,8 @@ typedef struct VMesh { M_POLY, /* a simple polygon */ M_ADJ, /* "adjacent edges" mesh pattern */ M_CROSS, /* "cross edges" mesh pattern */ - M_FAN, /* a simple polygon - fan filled */ + M_TRI_FAN, /* a simple polygon - fan filled */ + M_QUAD_STRIP, /* a simple polygon - cut into paralelle strips */ } mesh_kind; int count; /* number of vertices in the boundary */ int seg; /* common # of segments for segmented edges */ @@ -669,14 +670,19 @@ static void build_boundary(BevVert *bv) } else if (efirst->seg == 1 || bv->selcount == 1) { if (vm->count == 3 && bv->selcount == 1) { - vm->mesh_kind = M_FAN; + vm->mesh_kind = M_TRI_FAN; } else { vm->mesh_kind = M_POLY; } } else { - vm->mesh_kind = M_ADJ; + if (bv->selcount == 2) { + vm->mesh_kind = M_QUAD_STRIP; + } + else { + vm->mesh_kind = M_ADJ; + } } /* TODO: if vm->count == 4 and bv->selcount == 4, use M_CROSS pattern */ } @@ -1012,7 +1018,7 @@ static void bevel_build_poly(BMesh *bm, BevVert *bv) bevel_build_poly_ex(bm, bv); } -static void bevel_build_fan(BMesh *bm, BevVert *bv) +static void bevel_build_trifan(BMesh *bm, BevVert *bv) { BMFace *f; BLI_assert(next_bev(bv, NULL)->seg == 1 || bv->selcount == 1); @@ -1047,6 +1053,41 @@ static void bevel_build_fan(BMesh *bm, BevVert *bv) } } +static void bevel_build_quadstrip(BMesh *bm, BevVert *bv) +{ + BMFace *f; + BLI_assert(bv->selcount == 2); + + f = bevel_build_poly_ex(bm, bv); + + if (f) { + /* we have a polygon which we know starts at this vertex, make it into strips */ + BMVert *v_first = bv->vmesh->boundstart->efirst->next->next->leftv->nv.v; /* magic? */ + //BMLoop *l_start = BM_FACE_FIRST_LOOP(f); + BMLoop *l_start = BM_face_vert_share_loop(f, v_first); + BMLoop *l_a = l_start->prev, *l_a_step; + BMLoop *l_b = l_start->next, *l_b_step; + + while (f->len > 4) { + // BMLoop *l_new; + BMFace *f_new; + BLI_assert(l_a->f == f); + BLI_assert(l_b->f == f); + + l_a_step = l_a->prev; + l_b_step = l_b->next; + + f_new = BM_face_split(bm, f, l_a->v, l_b->v, NULL, NULL, FALSE); + + if (f_new->len > f->len) { + f = f_new; + } + + l_a = l_a_step; + l_b = l_b_step; + } + } +} /* Given that the boundary is built, now make the actual BMVerts * for the boundary and the interior of the vertex mesh. */ @@ -1117,8 +1158,10 @@ static void build_vmesh(BMesh *bm, BevVert *bv) bevel_build_rings(bm, bv); else if (vm->mesh_kind == M_POLY) bevel_build_poly(bm, bv); - else if (vm->mesh_kind == M_FAN) - bevel_build_fan(bm, bv); + else if (vm->mesh_kind == M_TRI_FAN) + bevel_build_trifan(bm, bv); + else if (vm->mesh_kind == M_QUAD_STRIP) + bevel_build_quadstrip(bm, bv); } /* -- cgit v1.2.3 From 7c3db355b1e0496e9e75e8d6fd575dae17729e83 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 14 Nov 2012 09:45:15 +0000 Subject: remove ifdef'd bevel code, current bevel works better then the previous code. reduce strlen check in texttool_suggest_add() use 'del list[:]' rather then 'list[:] = []' in python scripts which clear lists. --- source/blender/bmesh/operators/bmo_bevel.c | 857 ----------------------------- 1 file changed, 857 deletions(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index db5b769d078..37489510976 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -37,9 +37,6 @@ #include "intern/bmesh_operators_private.h" /* own include */ -#define NEW_BEVEL 1 - -#ifdef NEW_BEVEL #define BEVEL_FLAG 1 #define EDGE_SELECTED 2 @@ -1496,858 +1493,4 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) } free_bevel_params(&bp); } - -} - -#else -#define BEVEL_FLAG 1 -#define BEVEL_DEL 2 -#define FACE_NEW 4 -#define EDGE_OLD 8 -#define FACE_OLD 16 -#define VERT_OLD 32 -#define FACE_SPAN 64 -#define FACE_HOLE 128 - -typedef struct LoopTag { - BMVert *newv; -} LoopTag; - -typedef struct EdgeTag { - BMVert *newv1, *newv2; -} EdgeTag; - -static void calc_corner_co(BMLoop *l, const float fac, float r_co[3], - const short do_dist, const short do_even) -{ - float no[3], l_vec_prev[3], l_vec_next[3], l_co_prev[3], l_co[3], l_co_next[3], co_ofs[3]; - int is_concave; - - /* first get the prev/next verts */ - if (l->f->len > 2) { - copy_v3_v3(l_co_prev, l->prev->v->co); - copy_v3_v3(l_co, l->v->co); - copy_v3_v3(l_co_next, l->next->v->co); - - /* calculate normal */ - sub_v3_v3v3(l_vec_prev, l_co_prev, l_co); - sub_v3_v3v3(l_vec_next, l_co_next, l_co); - - cross_v3_v3v3(no, l_vec_prev, l_vec_next); - is_concave = dot_v3v3(no, l->f->no) > 0.0f; - } - else { - BMIter iter; - BMLoop *l2; - float up[3] = {0.0f, 0.0f, 1.0f}; - - copy_v3_v3(l_co_prev, l->prev->v->co); - copy_v3_v3(l_co, l->v->co); - - BM_ITER_ELEM (l2, &iter, l->v, BM_LOOPS_OF_VERT) { - if (l2->f != l->f) { - copy_v3_v3(l_co_next, BM_edge_other_vert(l2->e, l2->next->v)->co); - break; - } - } - - sub_v3_v3v3(l_vec_prev, l_co_prev, l_co); - sub_v3_v3v3(l_vec_next, l_co_next, l_co); - - cross_v3_v3v3(no, l_vec_prev, l_vec_next); - if (dot_v3v3(no, no) == 0.0f) { - no[0] = no[1] = 0.0f; no[2] = -1.0f; - } - - is_concave = dot_v3v3(no, up) < 0.0f; - } - - - /* now calculate the new location */ - if (do_dist) { /* treat 'fac' as distance */ - - normalize_v3(l_vec_prev); - normalize_v3(l_vec_next); - - add_v3_v3v3(co_ofs, l_vec_prev, l_vec_next); - if (UNLIKELY(normalize_v3(co_ofs) == 0.0f)) { /* edges form a straight line */ - cross_v3_v3v3(co_ofs, l_vec_prev, l->f->no); - } - - if (do_even) { - negate_v3(l_vec_next); - mul_v3_fl(co_ofs, fac * shell_angle_to_dist(0.5f * angle_normalized_v3v3(l_vec_prev, l_vec_next))); - /* negate_v3(l_vec_next); */ /* no need unless we use again */ - } - else { - mul_v3_fl(co_ofs, fac); - } - } - else { /* treat as 'fac' as a factor (0 - 1) */ - - /* not strictly necessary, balance vectors - * so the longer edge doesn't skew the result, - * gives nicer, move even output. - * - * Use the minimum rather then the middle value so skinny faces don't flip along the short axis */ - float min_fac = min_ff(normalize_v3(l_vec_prev), normalize_v3(l_vec_next)); - float angle; - - if (do_even) { - negate_v3(l_vec_next); - angle = angle_normalized_v3v3(l_vec_prev, l_vec_next); - negate_v3(l_vec_next); /* no need unless we use again */ - } - else { - angle = 0.0f; - } - - mul_v3_fl(l_vec_prev, min_fac); - mul_v3_fl(l_vec_next, min_fac); - - add_v3_v3v3(co_ofs, l_vec_prev, l_vec_next); - - if (UNLIKELY(is_zero_v3(co_ofs))) { - cross_v3_v3v3(co_ofs, l_vec_prev, l->f->no); - normalize_v3(co_ofs); - mul_v3_fl(co_ofs, min_fac); - } - - /* done */ - if (do_even) { - mul_v3_fl(co_ofs, (fac * 0.5f) * shell_angle_to_dist(0.5f * angle)); - } - else { - mul_v3_fl(co_ofs, fac * 0.5f); - } - } - - /* apply delta vec */ - if (is_concave) - negate_v3(co_ofs); - - add_v3_v3v3(r_co, co_ofs, l->v->co); -} - - -#define ETAG_SET(e, v, nv) ( \ - (v) == (e)->v1 ? \ - (etags[BM_elem_index_get((e))].newv1 = (nv)) : \ - (etags[BM_elem_index_get((e))].newv2 = (nv)) \ - ) - -#define ETAG_GET(e, v) ( \ - (v) == (e)->v1 ? \ - (etags[BM_elem_index_get((e))].newv1) : \ - (etags[BM_elem_index_get((e))].newv2) \ - ) - -void bmo_bevel_exec(BMesh *bm, BMOperator *op) -{ - BMOIter siter; - BMIter iter; - BMEdge *e; - BMVert *v; - BMFace **faces = NULL, *f; - LoopTag *tags = NULL, *tag; - EdgeTag *etags = NULL; - BMVert **verts = NULL; - BMEdge **edges = NULL; - BLI_array_declare(faces); - BLI_array_declare(tags); - BLI_array_declare(etags); - BLI_array_declare(verts); - BLI_array_declare(edges); - SmallHash hash; - float fac = BMO_slot_float_get(op, "percent"); - const short do_even = BMO_slot_bool_get(op, "use_even"); - const short do_dist = BMO_slot_bool_get(op, "use_dist"); - int i, li, has_elens, HasMDisps = CustomData_has_layer(&bm->ldata, CD_MDISPS); - - has_elens = CustomData_has_layer(&bm->edata, CD_PROP_FLT) && BMO_slot_bool_get(op, "use_lengths"); - if (has_elens) { - li = BMO_slot_int_get(op, "lengthlayer"); - } - - BLI_smallhash_init(&hash); - - BMO_ITER (e, &siter, bm, op, "geom", BM_EDGE) { - BMO_elem_flag_enable(bm, e, BEVEL_FLAG | BEVEL_DEL); - BMO_elem_flag_enable(bm, e->v1, BEVEL_FLAG | BEVEL_DEL); - BMO_elem_flag_enable(bm, e->v2, BEVEL_FLAG | BEVEL_DEL); - - if (BM_edge_face_count(e) < 2) { - BMO_elem_flag_disable(bm, e, BEVEL_DEL); - BMO_elem_flag_disable(bm, e->v1, BEVEL_DEL); - BMO_elem_flag_disable(bm, e->v2, BEVEL_DEL); - } -#if 0 - if (BM_edge_is_wire(e)) { - BMVert *verts[2] = {e->v1, e->v2}; - BMEdge *edges[2] = {e, BM_edge_create(bm, e->v1, e->v2, e, 0)}; - - BMO_elem_flag_enable(bm, edges[1], BEVEL_FLAG); - BM_face_create(bm, verts, edges, 2, FALSE); - } -#endif - } - - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - BMO_elem_flag_enable(bm, v, VERT_OLD); - } - -#if 0 - /* a bit of cleaner code that, alas, doens't work. */ - /* build edge tag */ - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - if (BMO_elem_flag_test(bm, e->v1, BEVEL_FLAG) || BMO_elem_flag_test(bm, e->v2, BEVEL_FLAG)) { - BMIter liter; - BMLoop *l; - - if (!BMO_elem_flag_test(bm, e, EDGE_OLD)) { - BM_elem_index_set(e, BLI_array_count(etags)); /* set_dirty! */ - BLI_array_grow_one(etags); - - BMO_elem_flag_enable(bm, e, EDGE_OLD); - } - - BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) { - BMLoop *l2; - BMIter liter2; - - if (BMO_elem_flag_test(bm, l->f, BEVEL_FLAG)) - continue; - - BM_ITER_ELEM (l2, &liter2, l->f, BM_LOOPS_OF_FACE) { - BM_elem_index_set(l2, BLI_array_count(tags)); /* set_loop */ - BLI_array_grow_one(tags); - - if (!BMO_elem_flag_test(bm, l2->e, EDGE_OLD)) { - BM_elem_index_set(l2->e, BLI_array_count(etags)); /* set_dirty! */ - BLI_array_grow_one(etags); - - BMO_elem_flag_enable(bm, l2->e, EDGE_OLD); - } - } - - BMO_elem_flag_enable(bm, l->f, BEVEL_FLAG); - BLI_array_append(faces, l->f); - } - } - else { - BM_elem_index_set(e, -1); /* set_dirty! */ - } - } -#endif - - /* create and assign looptag structure */ - BMO_ITER (e, &siter, bm, op, "geom", BM_EDGE) { - BMLoop *l; - BMIter liter; - - BMO_elem_flag_enable(bm, e->v1, BEVEL_FLAG | BEVEL_DEL); - BMO_elem_flag_enable(bm, e->v2, BEVEL_FLAG | BEVEL_DEL); - - if (BM_edge_face_count(e) < 2) { - BMO_elem_flag_disable(bm, e, BEVEL_DEL); - BMO_elem_flag_disable(bm, e->v1, BEVEL_DEL); - BMO_elem_flag_disable(bm, e->v2, BEVEL_DEL); - } - - if (!BLI_smallhash_haskey(&hash, (intptr_t)e)) { - BLI_array_grow_one(etags); - BM_elem_index_set(e, BLI_array_count(etags) - 1); /* set_dirty! */ - BLI_smallhash_insert(&hash, (intptr_t)e, NULL); - BMO_elem_flag_enable(bm, e, EDGE_OLD); - } - - /* find all faces surrounding e->v1 and, e->v2 */ - for (i = 0; i < 2; i++) { - BM_ITER_ELEM (l, &liter, i ? e->v2 : e->v1, BM_LOOPS_OF_VERT) { - BMLoop *l2; - BMIter liter2; - - /* see if we've already processed this loop's fac */ - if (BLI_smallhash_haskey(&hash, (intptr_t)l->f)) - continue; - - /* create tags for all loops in l-> */ - BM_ITER_ELEM (l2, &liter2, l->f, BM_LOOPS_OF_FACE) { - BLI_array_grow_one(tags); - BM_elem_index_set(l2, BLI_array_count(tags) - 1); /* set_loop */ - - if (!BLI_smallhash_haskey(&hash, (intptr_t)l2->e)) { - BLI_array_grow_one(etags); - BM_elem_index_set(l2->e, BLI_array_count(etags) - 1); /* set_dirty! */ - BLI_smallhash_insert(&hash, (intptr_t)l2->e, NULL); - BMO_elem_flag_enable(bm, l2->e, EDGE_OLD); - } - } - - BLI_smallhash_insert(&hash, (intptr_t)l->f, NULL); - BMO_elem_flag_enable(bm, l->f, BEVEL_FLAG); - BLI_array_append(faces, l->f); - } - } - } - - bm->elem_index_dirty |= BM_EDGE; - - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - BMIter eiter; - - if (!BMO_elem_flag_test(bm, v, BEVEL_FLAG)) - continue; - - BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (!BMO_elem_flag_test(bm, e, BEVEL_FLAG) && !ETAG_GET(e, v)) { - BMVert *v2; - float co[3]; - - v2 = BM_edge_other_vert(e, v); - sub_v3_v3v3(co, v2->co, v->co); - if (has_elens) { - float elen = *(float *)CustomData_bmesh_get_n(&bm->edata, e->head.data, CD_PROP_FLT, li); - - normalize_v3(co); - mul_v3_fl(co, elen); - } - - mul_v3_fl(co, fac); - add_v3_v3(co, v->co); - - v2 = BM_vert_create(bm, co, v); - ETAG_SET(e, v, v2); - } - } - } - - for (i = 0; i < BLI_array_count(faces); i++) { - BMLoop *l; - BMIter liter; - - BMO_elem_flag_enable(bm, faces[i], FACE_OLD); - - BM_ITER_ELEM (l, &liter, faces[i], BM_LOOPS_OF_FACE) { - float co[3]; - - if (BMO_elem_flag_test(bm, l->e, BEVEL_FLAG)) { - if (BMO_elem_flag_test(bm, l->prev->e, BEVEL_FLAG)) { - tag = tags + BM_elem_index_get(l); - calc_corner_co(l, fac, co, do_dist, do_even); - tag->newv = BM_vert_create(bm, co, l->v); - } - else { - tag = tags + BM_elem_index_get(l); - tag->newv = ETAG_GET(l->prev->e, l->v); - - if (!tag->newv) { - sub_v3_v3v3(co, l->prev->v->co, l->v->co); - if (has_elens) { - float elen = *(float *)CustomData_bmesh_get_n(&bm->edata, l->prev->e->head.data, - CD_PROP_FLT, li); - - normalize_v3(co); - mul_v3_fl(co, elen); - } - - mul_v3_fl(co, fac); - add_v3_v3(co, l->v->co); - - tag->newv = BM_vert_create(bm, co, l->v); - - ETAG_SET(l->prev->e, l->v, tag->newv); - } - } - } - else if (BMO_elem_flag_test(bm, l->v, BEVEL_FLAG)) { - tag = tags + BM_elem_index_get(l); - tag->newv = ETAG_GET(l->e, l->v); - - if (!tag->newv) { - sub_v3_v3v3(co, l->next->v->co, l->v->co); - if (has_elens) { - float elen = *(float *)CustomData_bmesh_get_n(&bm->edata, l->e->head.data, CD_PROP_FLT, li); - - normalize_v3(co); - mul_v3_fl(co, elen); - } - - mul_v3_fl(co, fac); - add_v3_v3(co, l->v->co); - - tag = tags + BM_elem_index_get(l); - tag->newv = BM_vert_create(bm, co, l->v); - - ETAG_SET(l->e, l->v, tag->newv); - } - } - else { - tag = tags + BM_elem_index_get(l); - tag->newv = l->v; - BMO_elem_flag_disable(bm, l->v, BEVEL_DEL); - } - } - } - - /* create new faces inset from original face */ - for (i = 0; i < BLI_array_count(faces); i++) { - BMLoop *l; - BMIter liter; - BMFace *f; - BMVert *lastv = NULL, *firstv = NULL; - - BMO_elem_flag_enable(bm, faces[i], BEVEL_DEL); - - BLI_array_empty(verts); - BLI_array_empty(edges); - - BM_ITER_ELEM (l, &liter, faces[i], BM_LOOPS_OF_FACE) { - BMVert *v2; - - tag = tags + BM_elem_index_get(l); - BLI_array_append(verts, tag->newv); - - if (!firstv) - firstv = tag->newv; - - if (lastv) { - e = BM_edge_create(bm, lastv, tag->newv, l->e, TRUE); - BM_elem_attrs_copy(bm, bm, l->prev->e, e); - BLI_array_append(edges, e); - } - lastv = tag->newv; - - v2 = ETAG_GET(l->e, l->next->v); - - tag = &tags[BM_elem_index_get(l->next)]; - if (!BMO_elem_flag_test(bm, l->e, BEVEL_FLAG) && v2 && v2 != tag->newv) { - BLI_array_append(verts, v2); - - e = BM_edge_create(bm, lastv, v2, l->e, TRUE); - BM_elem_attrs_copy(bm, bm, l->e, e); - - BLI_array_append(edges, e); - lastv = v2; - } - } - - e = BM_edge_create(bm, firstv, lastv, BM_FACE_FIRST_LOOP(faces[i])->e, TRUE); - if (BM_FACE_FIRST_LOOP(faces[i])->prev->e != e) { - BM_elem_attrs_copy(bm, bm, BM_FACE_FIRST_LOOP(faces[i])->prev->e, e); - } - BLI_array_append(edges, e); - - f = BM_face_create_ngon(bm, verts[0], verts[1], edges, BLI_array_count(edges), FALSE); - if (UNLIKELY(f == NULL)) { - printf("%s: could not make face!\n", __func__); - continue; - } - - BMO_elem_flag_enable(bm, f, FACE_NEW); - } - - for (i = 0; i < BLI_array_count(faces); i++) { - BMLoop *l; - BMIter liter; - int j; - - /* create quad spans between split edge */ - BM_ITER_ELEM (l, &liter, faces[i], BM_LOOPS_OF_FACE) { - BMVert *v1 = NULL, *v2 = NULL, *v3 = NULL, *v4 = NULL; - - if (!BMO_elem_flag_test(bm, l->e, BEVEL_FLAG)) - continue; - - v1 = tags[BM_elem_index_get(l)].newv; - v2 = tags[BM_elem_index_get(l->next)].newv; - if (l->radial_next != l) { - v3 = tags[BM_elem_index_get(l->radial_next)].newv; - if (l->radial_next->next->v == l->next->v) { - v4 = v3; - v3 = tags[BM_elem_index_get(l->radial_next->next)].newv; - } - else { - v4 = tags[BM_elem_index_get(l->radial_next->next)].newv; - } - } - else { - /* the loop is on a boundar */ - v3 = l->next->v; - v4 = l->v; - - for (j = 0; j < 2; j++) { - BMIter eiter; - BMVert *v = j ? v4 : v3; - - BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (!BM_vert_in_edge(e, v3) || !BM_vert_in_edge(e, v4)) - continue; - - if (!BMO_elem_flag_test(bm, e, BEVEL_FLAG) && BMO_elem_flag_test(bm, e, EDGE_OLD)) { - BMVert *vv; - - vv = ETAG_GET(e, v); - if (!vv || BMO_elem_flag_test(bm, vv, BEVEL_FLAG)) - continue; - - if (j) { - v1 = vv; - } - else { - v2 = vv; - } - break; - } - } - } - - BMO_elem_flag_disable(bm, v3, BEVEL_DEL); - BMO_elem_flag_disable(bm, v4, BEVEL_DEL); - } - - if (v1 != v2 && v2 != v3 && v3 != v4) { - BMIter liter2; - BMLoop *l2, *l3; - BMEdge *e1, *e2; - float d1, d2, *d3; - - f = BM_face_create_quad_tri(bm, v4, v3, v2, v1, l->f, TRUE); - - e1 = BM_edge_exists(v4, v3); - e2 = BM_edge_exists(v2, v1); - BM_elem_attrs_copy(bm, bm, l->e, e1); - BM_elem_attrs_copy(bm, bm, l->e, e2); - - /* set edge lengths of cross edges as the average of the cross edges they're based o */ - if (has_elens) { - /* angle happens not to be used. why? - not sure it just isn't - campbell. - * leave this in in case we need to use it later */ -#if 0 - float ang; -#endif - e1 = BM_edge_exists(v1, v4); - e2 = BM_edge_exists(v2, v3); - - if (l->radial_next->v == l->v) { - l2 = l->radial_next->prev; - l3 = l->radial_next->next; - } - else { - l2 = l->radial_next->next; - l3 = l->radial_next->prev; - } - - d3 = CustomData_bmesh_get_n(&bm->edata, e1->head.data, CD_PROP_FLT, li); - d1 = *(float *)CustomData_bmesh_get_n(&bm->edata, l->prev->e->head.data, CD_PROP_FLT, li); - d2 = *(float *)CustomData_bmesh_get_n(&bm->edata, l2->e->head.data, CD_PROP_FLT, li); -#if 0 - ang = angle_v3v3v3(l->prev->v->co, l->v->co, BM_edge_other_vert(l2->e, l->v)->co); -#endif - *d3 = (d1 + d2) * 0.5f; - - d3 = CustomData_bmesh_get_n(&bm->edata, e2->head.data, CD_PROP_FLT, li); - d1 = *(float *)CustomData_bmesh_get_n(&bm->edata, l->next->e->head.data, CD_PROP_FLT, li); - d2 = *(float *)CustomData_bmesh_get_n(&bm->edata, l3->e->head.data, CD_PROP_FLT, li); -#if 0 - ang = angle_v3v3v3(BM_edge_other_vert(l->next->e, l->next->v)->co, l->next->v->co, - BM_edge_other_vert(l3->e, l->next->v)->co); -#endif - *d3 = (d1 + d2) * 0.5f; - } - - if (UNLIKELY(f == NULL)) { - fprintf(stderr, "%s: face index out of range! (bmesh internal error)\n", __func__); - continue; - } - - BMO_elem_flag_enable(bm, f, FACE_NEW | FACE_SPAN); - - /* un-tag edges in f for deletio */ - BM_ITER_ELEM (l2, &liter2, f, BM_LOOPS_OF_FACE) { - BMO_elem_flag_disable(bm, l2->e, BEVEL_DEL); - } - } - else { - f = NULL; - } - } - } - - /* fill in holes at vertices */ - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - BMIter eiter; - BMVert *vv, *vstart = NULL, *lastv = NULL; - SmallHash tmphash; - int rad, insorig = 0, err = 0; - - BLI_smallhash_init(&tmphash); - - if (!BMO_elem_flag_test(bm, v, BEVEL_FLAG)) - continue; - - BLI_array_empty(verts); - BLI_array_empty(edges); - - BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - BMIter liter; - BMVert *v1 = NULL, *v2 = NULL; - BMLoop *l; - - if (BM_edge_face_count(e) < 2) - insorig = 1; - - if (BM_elem_index_get(e) == -1) - continue; - - rad = 0; - BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) { - if (!BMO_elem_flag_test(bm, l->f, FACE_OLD)) - continue; - - rad++; - - tag = tags + BM_elem_index_get((l->v == v) ? l : l->next); - - if (!v1) - v1 = tag->newv; - else if (!v2) - v2 = tag->newv; - } - - if (rad < 2) - insorig = 1; - - if (!v1) - v1 = ETAG_GET(e, v); - if (!v2 || v1 == v2) - v2 = ETAG_GET(e, v); - - if (v1) { - if (!BLI_smallhash_haskey(&tmphash, (intptr_t)v1)) { - BLI_array_append(verts, v1); - BLI_smallhash_insert(&tmphash, (intptr_t)v1, NULL); - } - - if (v2 && v1 != v2 && !BLI_smallhash_haskey(&tmphash, (intptr_t)v2)) { - BLI_array_append(verts, v2); - BLI_smallhash_insert(&tmphash, (intptr_t)v2, NULL); - } - } - } - - if (!BLI_array_count(verts)) - continue; - - if (insorig) { - BLI_array_append(verts, v); - BLI_smallhash_insert(&tmphash, (intptr_t)v, NULL); - } - - /* find edges that exist between vertices in verts. this is basically - * a topological walk of the edges connecting them */ - vstart = vstart ? vstart : verts[0]; - vv = vstart; - do { - BM_ITER_ELEM (e, &eiter, vv, BM_EDGES_OF_VERT) { - BMVert *vv2 = BM_edge_other_vert(e, vv); - - if (vv2 != lastv && BLI_smallhash_haskey(&tmphash, (intptr_t)vv2)) { - /* if we've go over the same vert twice, break out of outer loop */ - if (BLI_smallhash_lookup(&tmphash, (intptr_t)vv2) != NULL) { - e = NULL; - err = 1; - break; - } - - /* use self pointer as ta */ - BLI_smallhash_remove(&tmphash, (intptr_t)vv2); - BLI_smallhash_insert(&tmphash, (intptr_t)vv2, vv2); - - lastv = vv; - BLI_array_append(edges, e); - vv = vv2; - break; - } - } - - if (e == NULL) { - break; - } - } while (vv != vstart); - - if (err) { - continue; - } - - /* there may not be a complete loop of edges, so start again and make - * final edge afterwards. in this case, the previous loop worked to - * find one of the two edges at the extremes. */ - if (vv != vstart) { - /* undo previous taggin */ - for (i = 0; i < BLI_array_count(verts); i++) { - BLI_smallhash_remove(&tmphash, (intptr_t)verts[i]); - BLI_smallhash_insert(&tmphash, (intptr_t)verts[i], NULL); - } - - vstart = vv; - lastv = NULL; - BLI_array_empty(edges); - do { - BM_ITER_ELEM (e, &eiter, vv, BM_EDGES_OF_VERT) { - BMVert *vv2 = BM_edge_other_vert(e, vv); - - if (vv2 != lastv && BLI_smallhash_haskey(&tmphash, (intptr_t)vv2)) { - /* if we've go over the same vert twice, break out of outer loo */ - if (BLI_smallhash_lookup(&tmphash, (intptr_t)vv2) != NULL) { - e = NULL; - err = 1; - break; - } - - /* use self pointer as ta */ - BLI_smallhash_remove(&tmphash, (intptr_t)vv2); - BLI_smallhash_insert(&tmphash, (intptr_t)vv2, vv2); - - lastv = vv; - BLI_array_append(edges, e); - vv = vv2; - break; - } - } - if (e == NULL) - break; - } while (vv != vstart); - - if (!err) { - e = BM_edge_create(bm, vv, vstart, NULL, TRUE); - BLI_array_append(edges, e); - } - } - - if (err) - continue; - - if (BLI_array_count(edges) >= 3) { - BMFace *f; - - if (BM_face_exists(bm, verts, BLI_array_count(verts), &f)) - continue; - - f = BM_face_create_ngon(bm, lastv, vstart, edges, BLI_array_count(edges), FALSE); - if (UNLIKELY(f == NULL)) { - fprintf(stderr, "%s: in bevel vert fill! (bmesh internal error)\n", __func__); - } - else { - BMO_elem_flag_enable(bm, f, FACE_NEW | FACE_HOLE); - } - } - BLI_smallhash_release(&tmphash); - } - - /* copy over customdat */ - for (i = 0; i < BLI_array_count(faces); i++) { - BMLoop *l; - BMIter liter; - BMFace *f = faces[i]; - - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - BMLoop *l2; - BMIter liter2; - - tag = tags + BM_elem_index_get(l); - if (!tag->newv) - continue; - - BM_ITER_ELEM (l2, &liter2, tag->newv, BM_LOOPS_OF_VERT) { - if (!BMO_elem_flag_test(bm, l2->f, FACE_NEW) || (l2->v != tag->newv && l2->v != l->v)) - continue; - - if (tag->newv != l->v || HasMDisps) { - BM_elem_attrs_copy(bm, bm, l->f, l2->f); - BM_loop_interp_from_face(bm, l2, l->f, TRUE, TRUE); - } - else { - BM_elem_attrs_copy(bm, bm, l->f, l2->f); - BM_elem_attrs_copy(bm, bm, l, l2); - } - - if (HasMDisps) { - BMLoop *l3; - BMIter liter3; - - BM_ITER_ELEM (l3, &liter3, l2->f, BM_LOOPS_OF_FACE) { - BM_loop_interp_multires(bm, l3, l->f); - } - } - } - } - } - - /* handle vertices along boundary edge */ - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (BMO_elem_flag_test(bm, v, VERT_OLD) && - BMO_elem_flag_test(bm, v, BEVEL_FLAG) && - !BMO_elem_flag_test(bm, v, BEVEL_DEL)) - { - BMLoop *l; - BMLoop *lorig = NULL; - BMIter liter; - - BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { - // BMIter liter2; - // BMLoop *l2 = l->v == v ? l : l->next, *l3; - - if (BMO_elem_flag_test(bm, l->f, FACE_OLD)) { - lorig = l; - break; - } - } - - if (!lorig) - continue; - - BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { - BMLoop *l2 = l->v == v ? l : l->next; - - BM_elem_attrs_copy(bm, bm, lorig->f, l2->f); - BM_elem_attrs_copy(bm, bm, lorig, l2); - } - } - } -#if 0 - /* clean up any remaining 2-edged face */ - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (f->len == 2) { - BMFace *faces[2] = {f, BM_FACE_FIRST_LOOP(f)->radial_next->f}; - - if (faces[0] == faces[1]) - BM_face_kill(bm, f); - else - BM_faces_join(bm, faces, 2); - } - } -#endif - - BMO_op_callf(bm, op->flag, "delete geom=%fv context=%i", BEVEL_DEL, DEL_VERTS); - - /* clean up any edges that might not get properly delete */ - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - if (BMO_elem_flag_test(bm, e, EDGE_OLD) && !e->l) - BMO_elem_flag_enable(bm, e, BEVEL_DEL); - } - - BMO_op_callf(bm, op->flag, "delete geom=%fe context=%i", BEVEL_DEL, DEL_EDGES); - BMO_op_callf(bm, op->flag, "delete geom=%ff context=%i", BEVEL_DEL, DEL_FACES); - - BLI_smallhash_release(&hash); - BLI_array_free(tags); - BLI_array_free(etags); - BLI_array_free(verts); - BLI_array_free(edges); - BLI_array_free(faces); - - BMO_slot_buffer_from_enabled_flag(bm, op, "face_spans", BM_FACE, FACE_SPAN); - BMO_slot_buffer_from_enabled_flag(bm, op, "face_holes", BM_FACE, FACE_HOLE); } -#endif /* NEW_BEVEL */ -- cgit v1.2.3 From 0163ae1701bb1725225d3efdb49e54e179209bc7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 14 Nov 2012 10:08:39 +0000 Subject: speedup bevel by tagging verts and edges to bevel, this avoids a loop over all bevel edges for each bevel vert (can use edges-of-vert instead) --- source/blender/bmesh/operators/bmo_bevel.c | 52 ++++++++++++++++++------------ 1 file changed, 32 insertions(+), 20 deletions(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 37489510976..3437873b953 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -107,8 +107,6 @@ typedef struct BevelParams { ListBase vertList; /* list of BevVert for each vertex involved in bevel */ float offset; /* blender units to offset each side of a beveled edge */ int seg; /* number of segments in beveled edge profile */ - - BMOperator *op; } BevelParams; /* Make a new BoundVert of the given kind, insert it at the end of the circular linked @@ -1164,10 +1162,8 @@ static void build_vmesh(BMesh *bm, BevVert *bv) /* * Construction around the vertex */ -static void bevel_vert_construct(BMesh *bm, BevelParams *bp, BMOperator *op, BMVert *v) +static void bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) { - - BMOIter siter; BMEdge *bme; BevVert *bv; BMEdge *bme2, *unflagged_bme; @@ -1179,12 +1175,10 @@ static void bevel_vert_construct(BMesh *bm, BevelParams *bp, BMOperator *op, BMV /* Gather input selected edges. * Only bevel selected edges that have exactly two incident faces. - * - * TODO, optimization - we could tag edges in 'geom' - * and then just iterate edges-of-vert, checking tags. */ - BMO_ITER (bme, &siter, bm, op, "geom", BM_EDGE) { - if (BM_vert_in_edge(bme, v)) { + + BM_ITER_ELEM (bme, &iter, v, BM_EDGES_OF_VERT) { + if (BM_elem_flag_test(bme, BM_ELEM_TAG)) { if (BM_edge_is_manifold(bme)) { BMO_elem_flag_enable(bm, bme, EDGE_SELECTED); nsel++; @@ -1464,33 +1458,51 @@ static void free_bevel_params(BevelParams *bp) void bmo_bevel_exec(BMesh *bm, BMOperator *op) { + BMIter iter; BMOIter siter; BMVert *v; BMEdge *e; BevelParams bp = {{NULL}}; bp.offset = BMO_slot_float_get(op, "offset"); - bp.op = op; bp.seg = BMO_slot_int_get(op, "segments"); if (bp.offset > 0) { + /* first flush 'geom' into flags, this makes it possible to check connected data */ + BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE, BM_ELEM_TAG, FALSE); + + BMO_ITER (v, &siter, bm, op, "geom", BM_VERT | BM_EDGE) { + BM_elem_flag_enable(v, BM_ELEM_TAG); + } + /* The analysis of the input vertices and execution additional constructions */ - BMO_ITER (v, &siter, bm, op, "geom", BM_VERT) { - bevel_vert_construct(bm, &bp, op, v); + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + bevel_vert_construct(bm, &bp, v); + } } + /* Build polygons for edges */ - BMO_ITER (e, &siter, bm, op, "geom", BM_EDGE) { - bevel_build_edge_polygons(bm, &bp, e); + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + bevel_build_edge_polygons(bm, &bp, e); + } } - BMO_ITER (v, &siter, bm, op, "geom", BM_VERT) { - bevel_rebuild_existing_polygons(bm, &bp, v); + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + bevel_rebuild_existing_polygons(bm, &bp, v); + } } - BMO_ITER (v, &siter, bm, op, "geom", BM_VERT) { - if (find_bevvert(&bp, v)) - BM_vert_kill(bm, v); + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + if (find_bevvert(&bp, v)) { + BM_vert_kill(bm, v); + } + } } + free_bevel_params(&bp); } } -- cgit v1.2.3 From 7295d98e0707db3eeb09123a272fbed3849db70a Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 14 Nov 2012 10:23:38 +0000 Subject: use ghash for bevel verts, saves list lookups when getting a BMVert's BevVert --- source/blender/bmesh/operators/bmo_bevel.c | 33 +++++++++++++++++------------- 1 file changed, 19 insertions(+), 14 deletions(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 3437873b953..ed4d19b845a 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -92,7 +92,6 @@ typedef struct VMesh { /* Data for a vertex involved in a bevel */ typedef struct BevVert { - struct BevVert *next, *prev; BMVert *v; /* original mesh vertex */ int edgecount; /* total number of edges around the vertex */ int selcount; /* number of selected edges around the vertex */ @@ -104,7 +103,10 @@ typedef struct BevVert { * Bevel parameters and state */ typedef struct BevelParams { - ListBase vertList; /* list of BevVert for each vertex involved in bevel */ + /* hash of BevVert for each vertex involved in bevel + * GHash: (key=(BMVert *), value=(BevVert *)) */ + GHash *vert_hash; + float offset; /* blender units to offset each side of a beveled edge */ int seg; /* number of segments in beveled edge profile */ } BevelParams; @@ -194,13 +196,7 @@ static EdgeHalf *next_bev(BevVert *bv, EdgeHalf *from_e) /* find the BevVert corresponding to BMVert bmv */ static BevVert *find_bevvert(BevelParams *bp, BMVert *bmv) { - BevVert *bv; - - for (bv = bp->vertList.first; bv; bv = bv->next) { - if (bv->v == bmv) - return bv; - } - return NULL; + return BLI_ghash_lookup(bp->vert_hash, bmv); } /* Return a good respresentative face (for materials, etc.) for faces @@ -1197,7 +1193,7 @@ static void bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) bv->edges = (EdgeHalf *)MEM_callocN(ntot * sizeof(EdgeHalf), "EdgeHalf"); bv->vmesh = (VMesh *)MEM_callocN(sizeof(VMesh), "VMesh"); bv->vmesh->seg = bp->seg; - BLI_addtail(&bp->vertList, bv); + BLI_ghash_insert(bp->vert_hash, v, bv); /* add edges to bv->edges in order that keeps adjacent edges sharing * a face, if possible */ @@ -1435,11 +1431,17 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme) static void free_bevel_params(BevelParams *bp) { - BevVert *bv; VMesh *vm; BoundVert *v, *vnext; - for (bv = bp->vertList.first; bv; bv = bv->next) { + + GHashIterator ghi; + + /* look on deform bones first */ + BLI_ghashIterator_init(&ghi, bp->vert_hash); + + for (; !BLI_ghashIterator_isDone(&ghi); BLI_ghashIterator_step(&ghi)) { + BevVert *bv = (BevVert *)BLI_ghashIterator_getValue(&ghi); MEM_freeN(bv->edges); vm = bv->vmesh; v = vm->boundstart; @@ -1452,8 +1454,9 @@ static void free_bevel_params(BevelParams *bp) if (vm->mesh) MEM_freeN(vm->mesh); MEM_freeN(vm); + MEM_freeN(bv); } - BLI_freelistN(&bp->vertList); + BLI_ghash_free(bp->vert_hash, NULL, NULL); } void bmo_bevel_exec(BMesh *bm, BMOperator *op) @@ -1462,12 +1465,14 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) BMOIter siter; BMVert *v; BMEdge *e; - BevelParams bp = {{NULL}}; + BevelParams bp = {NULL}; bp.offset = BMO_slot_float_get(op, "offset"); bp.seg = BMO_slot_int_get(op, "segments"); if (bp.offset > 0) { + bp.vert_hash = BLI_ghash_ptr_new(__func__); + /* first flush 'geom' into flags, this makes it possible to check connected data */ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE, BM_ELEM_TAG, FALSE); -- cgit v1.2.3 From a286afe75ddaed8003afb695d14483a05733c4a0 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 14 Nov 2012 11:06:58 +0000 Subject: use memarena for bevel allocs --- source/blender/bmesh/operators/bmo_bevel.c | 83 +++++++++++------------------- 1 file changed, 29 insertions(+), 54 deletions(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index ed4d19b845a..f812b6c5320 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -26,10 +26,9 @@ #include "MEM_guardedalloc.h" -#include "BLI_listbase.h" #include "BLI_array.h" #include "BLI_math.h" -#include "BLI_smallhash.h" +#include "BLI_memarena.h" #include "BKE_customdata.h" @@ -44,8 +43,8 @@ /* Constructed vertex, sometimes later instantiated as BMVert */ typedef struct NewVert { - float co[3]; BMVert *v; + float co[3]; } NewVert; struct BoundVert; @@ -105,7 +104,8 @@ typedef struct BevVert { typedef struct BevelParams { /* hash of BevVert for each vertex involved in bevel * GHash: (key=(BMVert *), value=(BevVert *)) */ - GHash *vert_hash; + GHash *vert_hash; + MemArena *mem_arena; /* use for all allocs while bevel runs, if we need to free we can switch to mempool */ float offset; /* blender units to offset each side of a beveled edge */ int seg; /* number of segments in beveled edge profile */ @@ -113,9 +113,10 @@ typedef struct BevelParams { /* Make a new BoundVert of the given kind, insert it at the end of the circular linked * list with entry point bv->boundstart, and return it. */ -static BoundVert *add_new_bound_vert(VMesh *vm, float co[3]) +static BoundVert *add_new_bound_vert(MemArena *mem_arena, VMesh *vm, float co[3]) { - BoundVert *ans = (BoundVert *) MEM_callocN(sizeof(BoundVert), "BoundVert"); + BoundVert *ans = (BoundVert *)BLI_memarena_alloc(mem_arena, sizeof(BoundVert)); + copy_v3_v3(ans->nv.co, co); if (!vm->boundstart) { ans->index = 0; @@ -552,7 +553,7 @@ static void mid_v3_v3v3v3(float v[3], const float v1[3], const float v2[3], cons * of a vertex on the the boundary of the beveled vertex bv->v. * Also decide on the mesh pattern that will be used inside the boundary. * Doesn't make the actual BMVerts */ -static void build_boundary(BevVert *bv) +static void build_boundary(MemArena *mem_arena, BevVert *bv) { EdgeHalf *efirst, *e; BoundVert *v; @@ -569,17 +570,17 @@ static void build_boundary(BevVert *bv) /* special case: beveled edge meets non-beveled one at valence 2 vert */ no = e->fprev ? e->fprev->no : (e->fnext ? e->fnext->no : NULL); offset_in_plane(e, no, TRUE, co); - v = add_new_bound_vert(vm, co); + v = add_new_bound_vert(mem_arena, vm, co); v->efirst = v->elast = v->ebev = e; e->leftv = v; no = e->fnext ? e->fnext->no : (e->fprev ? e->fprev->no : NULL); offset_in_plane(e, no, FALSE, co); - v = add_new_bound_vert(vm, co); + v = add_new_bound_vert(mem_arena, vm, co); v->efirst = v->elast = e; e->rightv = v; /* make artifical extra point along unbeveled edge, and form triangle */ slide_dist(e->next, bv->v, e->offset, co); - v = add_new_bound_vert(vm, co); + v = add_new_bound_vert(mem_arena, vm, co); v->efirst = v->elast = e->next; vm->mesh_kind = M_POLY; return; @@ -593,7 +594,7 @@ static void build_boundary(BevVert *bv) if (e->prev->isbev) { BLI_assert(e->prev != e); /* see: wire edge special case */ offset_meet(e->prev, e, bv->v, e->fprev, TRUE, co); - v = add_new_bound_vert(vm, co); + v = add_new_bound_vert(mem_arena, vm, co); v->efirst = e->prev; v->elast = v->ebev = e; e->leftv = v; @@ -607,7 +608,7 @@ static void build_boundary(BevVert *bv) /* TODO: fix case when one or both faces in following are NULL */ offset_in_two_planes(e->prev->prev, e, bv->v, e->prev->prev->fnext, e->fprev, co); - v = add_new_bound_vert(vm, co); + v = add_new_bound_vert(mem_arena, vm, co); v->efirst = e->prev->prev; v->elast = v->ebev = e; e->leftv = v; @@ -617,7 +618,7 @@ static void build_boundary(BevVert *bv) else { /* neither e->prev nor e->prev->prev are beveled: make on-edge on e->prev */ offset_meet(e->prev, e, bv->v, e->fprev, TRUE, co); - v = add_new_bound_vert(vm, co); + v = add_new_bound_vert(mem_arena, vm, co); v->efirst = e->prev; v->elast = v->ebev = e; e->leftv = v; @@ -635,7 +636,7 @@ static void build_boundary(BevVert *bv) else if (e->prev->isbev) { /* on-edge meet between e->prev and e */ offset_meet(e->prev, e, bv->v, e->fprev, TRUE, co); - v = add_new_bound_vert(vm, co); + v = add_new_bound_vert(mem_arena, vm, co); v->efirst = e->prev; v->elast = e; e->leftv = v; @@ -648,7 +649,7 @@ static void build_boundary(BevVert *bv) * Could slide to make an even bevel plane but for now will * just use last distance a meet point moved from bv->v. */ slide_dist(e, bv->v, lastd, co); - v = add_new_bound_vert(vm, co); + v = add_new_bound_vert(mem_arena, vm, co); v->efirst = v->elast = e; e->leftv = v; } @@ -1082,7 +1083,7 @@ static void bevel_build_quadstrip(BMesh *bm, BevVert *bv) /* Given that the boundary is built, now make the actual BMVerts * for the boundary and the interior of the vertex mesh. */ -static void build_vmesh(BMesh *bm, BevVert *bv) +static void build_vmesh(MemArena *mem_arena, BMesh *bm, BevVert *bv) { VMesh *vm = bv->vmesh; BoundVert *v, *weld1, *weld2; @@ -1093,7 +1094,7 @@ static void build_vmesh(BMesh *bm, BevVert *bv) ns = vm->seg; ns2 = ns / 2; - vm->mesh = (NewVert *)MEM_callocN(n * (ns2 + 1) * (ns + 1) * sizeof(NewVert), "NewVert"); + vm->mesh = (NewVert *)BLI_memarena_alloc(mem_arena, n * (ns2 + 1) * (ns + 1) * sizeof(NewVert)); /* special case: two beveled ends welded together */ weld = (bv->selcount == 2) && (vm->count == 2); @@ -1186,12 +1187,12 @@ static void bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) return; ntot = BM_vert_edge_count(v); - bv = (BevVert *)MEM_callocN(sizeof(BevVert), "BevVert"); + bv = (BevVert *)BLI_memarena_alloc(bp->mem_arena, (sizeof(BevVert))); bv->v = v; bv->edgecount = ntot; bv->selcount = nsel; - bv->edges = (EdgeHalf *)MEM_callocN(ntot * sizeof(EdgeHalf), "EdgeHalf"); - bv->vmesh = (VMesh *)MEM_callocN(sizeof(VMesh), "VMesh"); + bv->edges = (EdgeHalf *)BLI_memarena_alloc(bp->mem_arena, ntot * sizeof(EdgeHalf)); + bv->vmesh = (VMesh *)BLI_memarena_alloc(bp->mem_arena, sizeof(VMesh)); bv->vmesh->seg = bp->seg; BLI_ghash_insert(bp->vert_hash, v, bv); @@ -1285,8 +1286,8 @@ static void bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) e->prev = &bv->edges[(i + ntot - 1) % ntot]; } - build_boundary(bv); - build_vmesh(bm, bv); + build_boundary(bp->mem_arena, bv); + build_vmesh(bp->mem_arena, bm, bv); } /* Face f has at least one beveled vertex. Rebuild f */ @@ -1428,37 +1429,6 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme) } } - -static void free_bevel_params(BevelParams *bp) -{ - VMesh *vm; - BoundVert *v, *vnext; - - - GHashIterator ghi; - - /* look on deform bones first */ - BLI_ghashIterator_init(&ghi, bp->vert_hash); - - for (; !BLI_ghashIterator_isDone(&ghi); BLI_ghashIterator_step(&ghi)) { - BevVert *bv = (BevVert *)BLI_ghashIterator_getValue(&ghi); - MEM_freeN(bv->edges); - vm = bv->vmesh; - v = vm->boundstart; - if (v) { - do { - vnext = v->next; - MEM_freeN(v); - } while ((v = vnext) != vm->boundstart); - } - if (vm->mesh) - MEM_freeN(vm->mesh); - MEM_freeN(vm); - MEM_freeN(bv); - } - BLI_ghash_free(bp->vert_hash, NULL, NULL); -} - void bmo_bevel_exec(BMesh *bm, BMOperator *op) { BMIter iter; @@ -1471,7 +1441,10 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) bp.seg = BMO_slot_int_get(op, "segments"); if (bp.offset > 0) { + /* primary alloc */ bp.vert_hash = BLI_ghash_ptr_new(__func__); + bp.mem_arena = BLI_memarena_new((1 << 16), __func__); + BLI_memarena_use_calloc(bp.mem_arena); /* first flush 'geom' into flags, this makes it possible to check connected data */ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE, BM_ELEM_TAG, FALSE); @@ -1508,6 +1481,8 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) } } - free_bevel_params(&bp); + /* primary free */ + BLI_ghash_free(bp.vert_hash, NULL, NULL); + BLI_memarena_free(bp.mem_arena); } } -- cgit v1.2.3 From cd8584aad56eb7fcc94dc4ebfbcde034aebbe3cd Mon Sep 17 00:00:00 2001 From: Howard Trickey Date: Thu, 15 Nov 2012 02:05:32 +0000 Subject: Fix 'polygon eating' problem in bevel (bug #33141) which was due to almost-parallel lines. --- source/blender/bmesh/operators/bmo_bevel.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index f812b6c5320..281ff44e358 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -110,6 +110,7 @@ typedef struct BevelParams { float offset; /* blender units to offset each side of a beveled edge */ int seg; /* number of segments in beveled edge profile */ } BevelParams; +#include "bevdebug.c" /* Make a new BoundVert of the given kind, insert it at the end of the circular linked * list with entry point bv->boundstart, and return it. */ @@ -378,9 +379,12 @@ static void offset_in_two_planes(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, madd_v3_v3fl(off2a, norm_perp2, e2->offset); add_v3_v3v3(off2b, off2a, dir2); - if (!isect_line_line_v3(off1a, off1b, off2a, off2b, meetco, isect2)) { + if (fabs(angle_v3v3(dir1, dir2)) < BEVEL_EPSILON) { /* lines are parallel; off1a is a good meet point */ copy_v3_v3(meetco, off1a); + } else if (!isect_line_line_v3(off1a, off1b, off2a, off2b, meetco, isect2)) { + /* another test says they are parallel */ + copy_v3_v3(meetco, off1a); } } -- cgit v1.2.3 From 283ee53085b1e215cbd0d8af91b0000660406bfe Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 15 Nov 2012 02:11:40 +0000 Subject: fix for deleting lines hanging the text editor when no markers are used, presence of markers still hangs. also compiler warnings and some style edits. --- source/blender/bmesh/operators/bmo_bevel.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 281ff44e358..2209c60b280 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -110,7 +110,8 @@ typedef struct BevelParams { float offset; /* blender units to offset each side of a beveled edge */ int seg; /* number of segments in beveled edge profile */ } BevelParams; -#include "bevdebug.c" + +//#include "bevdebug.c" /* Make a new BoundVert of the given kind, insert it at the end of the circular linked * list with entry point bv->boundstart, and return it. */ -- cgit v1.2.3 From 987f6a7d4f8637441cadf1bfe162070b965dbf96 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 15 Nov 2012 13:24:14 +0000 Subject: code cleanup: move local math functions into math_geom.c, math_vector.c, no functional changes. --- source/blender/bmesh/operators/bmo_bevel.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 2209c60b280..4b1ea5298a3 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -115,7 +115,7 @@ typedef struct BevelParams { /* Make a new BoundVert of the given kind, insert it at the end of the circular linked * list with entry point bv->boundstart, and return it. */ -static BoundVert *add_new_bound_vert(MemArena *mem_arena, VMesh *vm, float co[3]) +static BoundVert *add_new_bound_vert(MemArena *mem_arena, VMesh *vm, const float co[3]) { BoundVert *ans = (BoundVert *)BLI_memarena_alloc(mem_arena, sizeof(BoundVert)); @@ -383,7 +383,8 @@ static void offset_in_two_planes(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, if (fabs(angle_v3v3(dir1, dir2)) < BEVEL_EPSILON) { /* lines are parallel; off1a is a good meet point */ copy_v3_v3(meetco, off1a); - } else if (!isect_line_line_v3(off1a, off1b, off2a, off2b, meetco, isect2)) { + } + else if (!isect_line_line_v3(off1a, off1b, off2a, off2b, meetco, isect2)) { /* another test says they are parallel */ copy_v3_v3(meetco, off1a); } @@ -392,7 +393,7 @@ static void offset_in_two_planes(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, /* Offset by e->offset in plane with normal plane_no, on left if left==TRUE, * else on right. If no is NULL, choose an arbitrary plane different * from eh's direction. */ -static void offset_in_plane(EdgeHalf *e, float plane_no[3], int left, float r[3]) +static void offset_in_plane(EdgeHalf *e, const float plane_no[3], int left, float r[3]) { float dir[3], no[3]; BMVert *v; @@ -434,7 +435,7 @@ static void slide_dist(EdgeHalf *e, BMVert *v, float d, float slideco[3]) } /* Calculate the point on e where line (co_a, co_b) comes closest to and return it in projco */ -static void project_to_edge(BMEdge *e, float co_a[3], float co_b[3], float projco[3]) +static void project_to_edge(BMEdge *e, const float co_a[3], const float co_b[3], float projco[3]) { float otherco[3]; @@ -471,7 +472,7 @@ static int bev_ccw_test(BMEdge *a, BMEdge *b, BMFace *f) * of that segment in r. */ static void get_point_on_round_profile(float r[3], float offset, int i, int count, - float va[3], float v[3], float vb[3]) + const float va[3], const float v[3], const float vb[3]) { float vva[3], vvb[3], angle, center[3], rv[3], axis[3], co[3]; @@ -514,7 +515,8 @@ static void get_point_on_round_profile(float r[3], float offset, int i, int coun * If va, vmid, and vb are all on the same plane, just interpolate between va and vb. */ static void get_point_on_round_edge(EdgeHalf *e, int i, - float va[3], float vmid[3], float vb[3], float profileco[3]) + const float va[3], const float vmid[3], const float vb[3], + float profileco[3]) { float vva[3], vvb[3], point[3], dir[3], vaadj[3], vbadj[3], p2[3], pn[3]; int n = e->seg; @@ -547,13 +549,6 @@ static void get_point_on_round_edge(EdgeHalf *e, int i, } } -static void mid_v3_v3v3v3(float v[3], const float v1[3], const float v2[3], const float v3[3]) -{ - v[0] = (v1[0] + v2[0] + v3[0]) / 3.0f; - v[1] = (v1[1] + v2[1] + v3[1]) / 3.0f; - v[2] = (v1[2] + v2[2] + v3[2]) / 3.0f; -} - /* Make a circular list of BoundVerts for bv, each of which has the coordinates * of a vertex on the the boundary of the beveled vertex bv->v. * Also decide on the mesh pattern that will be used inside the boundary. -- cgit v1.2.3 From 8270592fa4f82b9ea51f95b13a00b3bac6660a2d Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 15 Nov 2012 22:32:29 +0000 Subject: code cleanup: some renaming to avoid confusion. --- source/blender/bmesh/operators/bmo_bevel.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 4b1ea5298a3..89f2c448f24 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -471,7 +471,7 @@ static int bev_ccw_test(BMEdge *a, BMEdge *b, BMFace *f) * angle va - center -vb, and put the endpoint * of that segment in r. */ -static void get_point_on_round_profile(float r[3], float offset, int i, int count, +static void get_point_on_round_profile(float r_co[3], float offset, int k, int count, const float va[3], const float v[3], const float vb[3]) { float vva[3], vvb[3], angle, center[3], rv[3], axis[3], co[3]; @@ -498,14 +498,14 @@ static void get_point_on_round_profile(float r[3], float offset, int i, int coun sub_v3_v3v3(vvb, vb, center); angle = angle_v3v3(vva, vvb); - rotate_v3_v3v3fl(co, rv, axis, angle * (float)(i) / (float)(count)); + rotate_v3_v3v3fl(co, rv, axis, angle * (float)k / (float)count); add_v3_v3(co, center); - copy_v3_v3(r, co); + copy_v3_v3(r_co, co); } /* - * Find the point (i/n) of the way around the round profile for e, + * Find the point (/n) of the way around the round profile for e, * where start point is va, midarc point is vmid, and end point is vb. * Return the answer in profileco. * Method: @@ -514,9 +514,9 @@ static void get_point_on_round_profile(float r[3], float offset, int i, int coun * back onto original va - vmid - vb plane. * If va, vmid, and vb are all on the same plane, just interpolate between va and vb. */ -static void get_point_on_round_edge(EdgeHalf *e, int i, +static void get_point_on_round_edge(EdgeHalf *e, int k, const float va[3], const float vmid[3], const float vb[3], - float profileco[3]) + float r_co[3]) { float vva[3], vvb[3], point[3], dir[3], vaadj[3], vbadj[3], p2[3], pn[3]; int n = e->seg; @@ -534,18 +534,18 @@ static void get_point_on_round_edge(EdgeHalf *e, int i, copy_v3_v3(vbadj, vb); madd_v3_v3fl(vbadj, dir, -len_v3(vvb) * cosf(angle_v3v3(vvb, dir))); - get_point_on_round_profile(point, e->offset, i, n, vaadj, vmid, vbadj); + get_point_on_round_profile(point, e->offset, k, n, vaadj, vmid, vbadj); add_v3_v3v3(p2, point, dir); cross_v3_v3v3(pn, vva, vvb); - if (!isect_line_plane_v3(profileco, point, p2, vmid, pn, 0)) { + if (!isect_line_plane_v3(r_co, point, p2, vmid, pn, 0)) { /* TODO: track down why this sometimes fails */ - copy_v3_v3(profileco, point); + copy_v3_v3(r_co, point); } } else { /* planar case */ - interp_v3_v3v3(profileco, va, vb, (float) i / (float) n); + interp_v3_v3v3(r_co, va, vb, (float)k / (float)n); } } -- cgit v1.2.3 From b3f6c1213697b152c14837f280b469af9c499651 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 15 Nov 2012 23:21:21 +0000 Subject: bevel: wip ifdef'd code to test an alternative method of placing corner vertices. --- source/blender/bmesh/operators/bmo_bevel.c | 131 ++++++++++++++++++++++++++++- 1 file changed, 129 insertions(+), 2 deletions(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 89f2c448f24..93e69909ff9 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -36,6 +36,9 @@ #include "intern/bmesh_operators_private.h" /* own include */ +/* experemental - Campbell */ +// #define USE_ALTERNATE_ADJ + #define BEVEL_FLAG 1 #define EDGE_SELECTED 2 @@ -434,6 +437,7 @@ static void slide_dist(EdgeHalf *e, BMVert *v, float d, float slideco[3]) madd_v3_v3fl(slideco, dir, -d); } +#ifndef USE_ALTERNATE_ADJ /* Calculate the point on e where line (co_a, co_b) comes closest to and return it in projco */ static void project_to_edge(BMEdge *e, const float co_a[3], const float co_b[3], float projco[3]) { @@ -444,7 +448,7 @@ static void project_to_edge(BMEdge *e, const float co_a[3], const float co_b[3], copy_v3_v3(projco, e->v1->co); } } - +#endif /* return 1 if a and b are in CCW order on the normal side of f, * and -1 if they are reversed, and 0 if there is no shared face f */ @@ -461,6 +465,68 @@ static int bev_ccw_test(BMEdge *a, BMEdge *b, BMFace *f) return lb->next == la ? 1 : -1; } +#ifdef USE_ALTERNATE_ADJ + +static void vmesh_cent(VMesh *vm, float r_cent[3]) +{ + BoundVert *v; + int tot = 0; + zero_v3(r_cent); + + v = vm->boundstart; + do { + add_v3_v3(r_cent, v->nv.co); + tot++; + } while ((v = v->next) != vm->boundstart); + mul_v3_fl(r_cent, 1.0f / (float)tot); +} + +/** + * + * This example shows a tri fan of quads, + * but could be an NGon fan of quads too. + *
+ *      The whole triangle   X
+ *      represents the      / \
+ *      new bevel face.    /   \
+ *                        /     \
+ *       Split into      /       \
+ *       a quad fan.    /         \
+ *                     /           \
+ *                    /             \
+ *                   /               \
+ *          co_prev +-.             .-+
+ *                 /   `-._     _.-'   \
+ *                / co_cent`-+-'        \
+ *               /           |           \
+ * Quad of      /            |            \
+ * interest -- / ---> X      |             \
+ *            /              |              \
+ *           /               |               \
+ *          /         co_next|                \
+ * co_orig +-----------------+-----------------+
+ *
+ *         For each quad, calcualte UV's based on the following:
+ *           U = k    / (vm->seg * 2)
+ *           V = ring / (vm->seg * 2)
+ *           quad = (co_orig, co_prev, co_cent, co_next)
+ *           ... note that co_cent is the same for all quads in the fan.
+ * 
+ * + */ + +static void get_point_on_round_edge(EdgeHalf *e, int ring, int k, + float quad[4][3], + float r_co[3]) +{ + const float n = e->seg; + const float uv[2] = {(ring / n) * 2.0f, (k / n) * 2.0f}; + + interp_bilinear_quad_v3(quad, uv[0], uv[1], r_co); +} + +#else /* USE_ALTERNATE_ADJ */ + /* * calculation of points on the round profile * r - result, coordinate of point on round profile @@ -549,6 +615,8 @@ static void get_point_on_round_edge(EdgeHalf *e, int k, } } +#endif /* !USE_ALTERNATE_ADJ */ + /* Make a circular list of BoundVerts for bv, each of which has the coordinates * of a vertex on the the boundary of the beveled vertex bv->v. * Also decide on the mesh pattern that will be used inside the boundary. @@ -693,6 +761,13 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv) BMFace *f; float co[3], coa[3], cob[3], midco[3]; +#ifdef USE_ALTERNATE_ADJ + /* ordered as follows (orig, prev, center, next)*/ + float quad[4][3]; + /* the rest are initialized inline, this remains the same for all */ + vmesh_cent(vm, quad[2]); +#endif + n = vm->count; ns = vm->seg; ns2 = ns / 2; @@ -702,6 +777,7 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv) * BoundVert for i has a bevel, 0 <= r <= ns2, 0 <= k <= ns */ for (ring = 1; ring <= ns2; ring++) { v = vm->boundstart; + do { i = v->index; if (v->ebev) { @@ -728,6 +804,19 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv) copy_v3_v3(nv->co, cob); nv->v = nvnext->v; +#ifdef USE_ALTERNATE_ADJ + copy_v3_v3(quad[0], v->nv.co); + mid_v3_v3v3(quad[1], v->nv.co, v->prev->nv.co); + /* quad[2] is set */ + mid_v3_v3v3(quad[3], v->nv.co, v->next->nv.co); +#endif + +#ifdef USE_ALTERNATE_ADJ + for (k = 1; k < ns; k++) { + get_point_on_round_edge(v->ebev, ring, k, quad, co); + copy_v3_v3(mesh_vert(vm, i, ring, k)->co, co); + } +#else /* TODO: better calculation of new midarc point? */ project_to_edge(v->ebev->e, coa, cob, midco); @@ -735,6 +824,7 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv) get_point_on_round_edge(v->ebev, k, coa, midco, cob, co); copy_v3_v3(mesh_vert(vm, i, ring, k)->co, co); } +#endif } } while ((v = v->next) != vm->boundstart); } @@ -759,7 +849,9 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv) nv = mesh_vert(vm, i, ring, k); nvprev = mesh_vert(vm, vprev->index, k, ns - ring); mid_v3_v3v3(co, nv->co, nvprev->co); +#ifndef USE_ALTERNATE_ADJ copy_v3_v3(nv->co, co); +#endif BLI_assert(nv->v == NULL && nvprev->v == NULL); create_mesh_bmvert(bm, vm, i, ring, k, bv->v); copy_mesh_vert(vm, vprev->index, k, ns - ring, i, ring, k); @@ -806,7 +898,9 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv) nvnext = mesh_vert(vm, vnext->index, ns2, k); if (vprev->ebev && vnext->ebev) { mid_v3_v3v3v3(co, nvprev->co, nv->co, nvnext->co); +#ifndef USE_ALTERNATE_ADJ copy_v3_v3(nv->co, co); +#endif create_mesh_bmvert(bm, vm, i, k, ns2, bv->v); copy_mesh_vert(vm, vprev->index, ns2, ns - k, i, k, ns2); copy_mesh_vert(vm, vnext->index, ns2, k, i, k, ns2); @@ -814,7 +908,9 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv) } else if (vprev->ebev) { mid_v3_v3v3(co, nvprev->co, nv->co); +#ifndef USE_ALTERNATE_ADJ copy_v3_v3(nv->co, co); +#endif create_mesh_bmvert(bm, vm, i, k, ns2, bv->v); copy_mesh_vert(vm, vprev->index, ns2, ns - k, i, k, ns2); @@ -822,7 +918,9 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv) } else if (vnext->ebev) { mid_v3_v3v3(co, nv->co, nvnext->co); +#ifndef USE_ALTERNATE_ADJ copy_v3_v3(nv->co, co); +#endif create_mesh_bmvert(bm, vm, i, k, ns2, bv->v); copy_mesh_vert(vm, vnext->index, ns2, k, i, k, ns2); @@ -1088,7 +1186,19 @@ static void build_vmesh(MemArena *mem_arena, BMesh *bm, BevVert *bv) VMesh *vm = bv->vmesh; BoundVert *v, *weld1, *weld2; int n, ns, ns2, i, k, weld; - float *va, *vb, co[3], midco[3]; + float *va, *vb, co[3]; + +#ifdef USE_ALTERNATE_ADJ + /* ordered as follows (orig, prev, center, next)*/ + float quad[4][3]; +#else + float midco[3]; +#endif + +#ifdef USE_ALTERNATE_ADJ + /* the rest are initialized inline, this remains the same for all */ + vmesh_cent(vm, quad[2]); +#endif n = vm->count; ns = vm->seg; @@ -1118,9 +1228,25 @@ static void build_vmesh(MemArena *mem_arena, BMesh *bm, BevVert *bv) /* copy other ends to (i, 0, ns) for all i, and fill in profiles for beveled edges */ v = vm->boundstart; do { + +#ifdef USE_ALTERNATE_ADJ + copy_v3_v3(quad[0], v->nv.co); + mid_v3_v3v3(quad[1], v->nv.co, v->prev->nv.co); + /* quad[2] is set */ + mid_v3_v3v3(quad[3], v->nv.co, v->next->nv.co); +#endif + i = v->index; copy_mesh_vert(vm, i, 0, ns, v->next->index, 0, 0); if (v->ebev) { +#ifdef USE_ALTERNATE_ADJ + for (k = 1; k < ns; k++) { + get_point_on_round_edge(v->ebev, 0, k, quad, co); + copy_v3_v3(mesh_vert(vm, i, 0, k)->co, co); + if (!weld) + create_mesh_bmvert(bm, vm, i, 0, k, bv->v); + } +#else va = mesh_vert(vm, i, 0, 0)->co; vb = mesh_vert(vm, i, 0, ns)->co; project_to_edge(v->ebev->e, va, vb, midco); @@ -1130,6 +1256,7 @@ static void build_vmesh(MemArena *mem_arena, BMesh *bm, BevVert *bv) if (!weld) create_mesh_bmvert(bm, vm, i, 0, k, bv->v); } +#endif } } while ((v = v->next) != vm->boundstart); -- cgit v1.2.3 From f5b356bf188528fd618cacaa22f6c72b3a625e09 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 16 Nov 2012 08:12:06 +0000 Subject: wip - alternate bevel curve calculation (still disabled) now USE_ALTERNATE_ADJ works, giving more stable corners that don't flicker and glitch out as the offset changes. The shape is not a circle though and doesnt look quite as nice as the existing method. --- source/blender/bmesh/operators/bmo_bevel.c | 128 +++++++++++++++++++++++------ 1 file changed, 103 insertions(+), 25 deletions(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 93e69909ff9..28e28b67399 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -437,7 +437,6 @@ static void slide_dist(EdgeHalf *e, BMVert *v, float d, float slideco[3]) madd_v3_v3fl(slideco, dir, -d); } -#ifndef USE_ALTERNATE_ADJ /* Calculate the point on e where line (co_a, co_b) comes closest to and return it in projco */ static void project_to_edge(BMEdge *e, const float co_a[3], const float co_b[3], float projco[3]) { @@ -448,7 +447,6 @@ static void project_to_edge(BMEdge *e, const float co_a[3], const float co_b[3], copy_v3_v3(projco, e->v1->co); } } -#endif /* return 1 if a and b are in CCW order on the normal side of f, * and -1 if they are reversed, and 0 if there is no shared face f */ @@ -515,13 +513,26 @@ static void vmesh_cent(VMesh *vm, float r_cent[3]) * */ -static void get_point_on_round_edge(EdgeHalf *e, int ring, int k, +static void get_point_uv(float uv[2], + /* all these args are int's originally + * but pass as floats to the function */ + const float seg, const float ring, const float k) +{ + uv[0] = (ring / seg) * 2.0f; + uv[1] = (k / seg) * 2.0f; +} + +/* TODO: make this a lot smarter!, + * this is the main reason USE_ALTERNATE_ADJ isn't so good right now :S */ +static float get_point_uv_factor(const float uv[2]) +{ + return sinf(1.0f - max_ff(uv[0], uv[1]) / 2.0f); +} + +static void get_point_on_round_edge(const float uv[2], float quad[4][3], float r_co[3]) { - const float n = e->seg; - const float uv[2] = {(ring / n) * 2.0f, (k / n) * 2.0f}; - interp_bilinear_quad_v3(quad, uv[0], uv[1], r_co); } @@ -763,9 +774,15 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv) #ifdef USE_ALTERNATE_ADJ /* ordered as follows (orig, prev, center, next)*/ - float quad[4][3]; + float quad_plane[4][3]; + float quad_orig[4][3]; +#endif + + +#ifdef USE_ALTERNATE_ADJ /* the rest are initialized inline, this remains the same for all */ - vmesh_cent(vm, quad[2]); + vmesh_cent(vm, quad_plane[2]); + copy_v3_v3(quad_orig[2], bv->v->co); #endif n = vm->count; @@ -805,15 +822,33 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv) nv->v = nvnext->v; #ifdef USE_ALTERNATE_ADJ - copy_v3_v3(quad[0], v->nv.co); - mid_v3_v3v3(quad[1], v->nv.co, v->prev->nv.co); + /* plane */ + copy_v3_v3(quad_plane[0], v->nv.co); + mid_v3_v3v3(quad_plane[1], v->nv.co, v->prev->nv.co); /* quad[2] is set */ - mid_v3_v3v3(quad[3], v->nv.co, v->next->nv.co); + mid_v3_v3v3(quad_plane[3], v->nv.co, v->next->nv.co); + + /* orig */ + copy_v3_v3(quad_orig[0], v->nv.co); /* only shared location between 2 quads */ + project_to_edge(v->ebev->prev->e, v->nv.co, v->prev->nv.co, quad_orig[1]); + project_to_edge(v->ebev->e, v->nv.co, v->next->nv.co, quad_orig[3]); + + //bl_debug_draw_quad_add(UNPACK4(quad_plane)); + //bl_debug_draw_quad_add(UNPACK4(quad_orig)); #endif #ifdef USE_ALTERNATE_ADJ for (k = 1; k < ns; k++) { - get_point_on_round_edge(v->ebev, ring, k, quad, co); + float uv[2]; + float fac; + float co_plane[3]; + float co_orig[3]; + + get_point_uv(uv, v->ebev->seg, ring, k); + get_point_on_round_edge(uv, quad_plane, co_plane); + get_point_on_round_edge(uv, quad_orig, co_orig); + fac = get_point_uv_factor(uv); + interp_v3_v3v3(co, co_plane, co_orig, fac); copy_v3_v3(mesh_vert(vm, i, ring, k)->co, co); } #else @@ -1190,14 +1225,20 @@ static void build_vmesh(MemArena *mem_arena, BMesh *bm, BevVert *bv) #ifdef USE_ALTERNATE_ADJ /* ordered as follows (orig, prev, center, next)*/ - float quad[4][3]; + float quad_plane[4][3]; + float quad_orig_a[4][3]; + float quad_orig_b[4][3]; + const int is_odd = (vm->seg % 2); #else float midco[3]; #endif #ifdef USE_ALTERNATE_ADJ /* the rest are initialized inline, this remains the same for all */ - vmesh_cent(vm, quad[2]); + /* NOTE; in this usage we only interpolate on the 'V' so cent and next points are unused (2,3)*/ + vmesh_cent(vm, quad_plane[2]); + copy_v3_v3(quad_orig_a[2], bv->v->co); + copy_v3_v3(quad_orig_b[2], bv->v->co); #endif n = vm->count; @@ -1228,25 +1269,62 @@ static void build_vmesh(MemArena *mem_arena, BMesh *bm, BevVert *bv) /* copy other ends to (i, 0, ns) for all i, and fill in profiles for beveled edges */ v = vm->boundstart; do { - -#ifdef USE_ALTERNATE_ADJ - copy_v3_v3(quad[0], v->nv.co); - mid_v3_v3v3(quad[1], v->nv.co, v->prev->nv.co); - /* quad[2] is set */ - mid_v3_v3v3(quad[3], v->nv.co, v->next->nv.co); -#endif - i = v->index; copy_mesh_vert(vm, i, 0, ns, v->next->index, 0, 0); if (v->ebev) { + +#ifdef USE_ALTERNATE_ADJ + copy_v3_v3(quad_plane[0], v->nv.co); + mid_v3_v3v3(quad_plane[1], v->nv.co, v->prev->nv.co); + /* quad[2] is set */ + mid_v3_v3v3(quad_plane[3], v->nv.co, v->next->nv.co); + + /* orig 'A' */ + copy_v3_v3(quad_orig_a[0], v->nv.co); /* only shared location between 2 quads */ + project_to_edge(v->ebev->prev->e, v->nv.co, v->prev->nv.co, quad_orig_a[1]); + project_to_edge(v->ebev->e, v->nv.co, v->next->nv.co, quad_orig_a[3]); + + /* orig 'B' */ + copy_v3_v3(quad_orig_b[3], v->next->nv.co); /* only shared location between 2 quads */ + project_to_edge(v->ebev->prev->e, v->nv.co, v->prev->nv.co, quad_orig_b[1]); + project_to_edge(v->ebev->e, v->nv.co, v->next->nv.co, quad_orig_b[0]); + + //bl_debug_draw_quad_add(UNPACK4(quad_plane)); + //bl_debug_draw_quad_add(UNPACK4(quad_orig_a)); + //bl_debug_draw_quad_add(UNPACK4(quad_orig_b)); +#endif /* USE_ALTERNATE_ADJ */ + #ifdef USE_ALTERNATE_ADJ for (k = 1; k < ns; k++) { - get_point_on_round_edge(v->ebev, 0, k, quad, co); + float uv[2]; + float fac; + float co_plane[3]; + float co_orig[3]; + + /* quad_plane */ + get_point_uv(uv, v->ebev->seg, 0, k); + get_point_on_round_edge(uv, quad_plane, co_plane); + + /* quad_orig */ + /* each half has different UV's */ + if (k <= ns2) { + get_point_uv(uv, v->ebev->seg, 0, k); + get_point_on_round_edge(uv, quad_orig_a, co_orig); + } + else { + get_point_uv(uv, v->ebev->seg, 0, (k - ns2) - (is_odd ? 0.5f : 0.0f)); + get_point_on_round_edge(uv, quad_orig_b, co_orig); + uv[1] = 1.0f - uv[1]; /* so we can get the factor */ + } + fac = get_point_uv_factor(uv); + + /* done. interp */ + interp_v3_v3v3(co, co_plane, co_orig, fac); copy_v3_v3(mesh_vert(vm, i, 0, k)->co, co); if (!weld) create_mesh_bmvert(bm, vm, i, 0, k, bv->v); } -#else +#else /* USE_ALTERNATE_ADJ */ va = mesh_vert(vm, i, 0, 0)->co; vb = mesh_vert(vm, i, 0, ns)->co; project_to_edge(v->ebev->e, va, vb, midco); @@ -1256,7 +1334,7 @@ static void build_vmesh(MemArena *mem_arena, BMesh *bm, BevVert *bv) if (!weld) create_mesh_bmvert(bm, vm, i, 0, k, bv->v); } -#endif +#endif /* !USE_ALTERNATE_ADJ */ } } while ((v = v->next) != vm->boundstart); -- cgit v1.2.3 From 3edbd1d0e2b8b09af60cec4e058b795fc0c2a1f7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 16 Nov 2012 10:15:25 +0000 Subject: bevel: save some memory by aligning struct members. --- source/blender/bmesh/operators/bmo_bevel.c | 33 ++++++++++++++++++------------ 1 file changed, 20 insertions(+), 13 deletions(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 28e28b67399..47295a44a84 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -37,17 +37,21 @@ #include "intern/bmesh_operators_private.h" /* own include */ /* experemental - Campbell */ -// #define USE_ALTERNATE_ADJ +//#define USE_ALTERNATE_ADJ #define BEVEL_FLAG 1 #define EDGE_SELECTED 2 #define BEVEL_EPSILON 1e-6 +/* for testing */ +// #pragma GCC diagnostic error "-Wpadded" + /* Constructed vertex, sometimes later instantiated as BMVert */ typedef struct NewVert { BMVert *v; float co[3]; + int _pad; } NewVert; struct BoundVert; @@ -56,28 +60,34 @@ struct BoundVert; typedef struct EdgeHalf { struct EdgeHalf *next, *prev; /* in CCW order */ BMEdge *e; /* original mesh edge */ - int isbev; /* is this edge beveled? */ - int isrev; /* is e->v2 the vertex at this end? */ - int seg; /* how many segments for the bevel */ - float offset; /* offset for this edge */ BMFace *fprev; /* face between this edge and previous, if any */ BMFace *fnext; /* face between this edge and next, if any */ struct BoundVert *leftv; /* left boundary vert (looking along edge to end) */ struct BoundVert *rightv; /* right boundary vert, if beveled */ + short isbev; /* is this edge beveled? */ + short isrev; /* is e->v2 the vertex at this end? */ + int seg; /* how many segments for the bevel */ + float offset; /* offset for this edge */ +// int _pad; } EdgeHalf; /* An element in a cyclic boundary of a Vertex Mesh (VMesh) */ typedef struct BoundVert { struct BoundVert *next, *prev; /* in CCW order */ - int index; /* used for vmesh indexing */ NewVert nv; EdgeHalf *efirst; /* first of edges attached here: in CCW order */ EdgeHalf *elast; EdgeHalf *ebev; /* beveled edge whose left side is attached here, if any */ + int index; /* used for vmesh indexing */ +// int _pad; } BoundVert; /* Mesh structure replacing a vertex */ typedef struct VMesh { + NewVert *mesh; /* allocated array - size and structure depends on kind */ + BoundVert *boundstart; /* start of boundary double-linked list */ + int count; /* number of vertices in the boundary */ + int seg; /* common # of segments for segmented edges */ enum { M_NONE, /* no polygon mesh needed */ M_POLY, /* a simple polygon */ @@ -86,10 +96,7 @@ typedef struct VMesh { M_TRI_FAN, /* a simple polygon - fan filled */ M_QUAD_STRIP, /* a simple polygon - cut into paralelle strips */ } mesh_kind; - int count; /* number of vertices in the boundary */ - int seg; /* common # of segments for segmented edges */ - BoundVert *boundstart; /* start of boundary double-linked list */ - NewVert *mesh; /* allocated array - size and structure depends on kind */ +// int _pad; } VMesh; /* Data for a vertex involved in a bevel */ @@ -101,9 +108,7 @@ typedef struct BevVert { VMesh *vmesh; /* mesh structure for replacing vertex */ } BevVert; -/* - * Bevel parameters and state - */ +/* Bevel parameters and state */ typedef struct BevelParams { /* hash of BevVert for each vertex involved in bevel * GHash: (key=(BMVert *), value=(BevVert *)) */ @@ -114,6 +119,8 @@ typedef struct BevelParams { int seg; /* number of segments in beveled edge profile */ } BevelParams; +// #pragma GCC diagnostic ignored "-Wpadded" + //#include "bevdebug.c" /* Make a new BoundVert of the given kind, insert it at the end of the circular linked -- cgit v1.2.3 From 6b0c200403fe37478a169add18efd706db46960f Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 16 Nov 2012 12:25:15 +0000 Subject: code cleanup: remove unneeded normalize (face normal), and unneeded call to len_v3v3 --- source/blender/bmesh/operators/bmo_bevel.c | 39 +++++++++++++++--------------- 1 file changed, 19 insertions(+), 20 deletions(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 47295a44a84..656fef28393 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -37,7 +37,7 @@ #include "intern/bmesh_operators_private.h" /* own include */ /* experemental - Campbell */ -//#define USE_ALTERNATE_ADJ +// #define USE_ALTERNATE_ADJ #define BEVEL_FLAG 1 #define EDGE_SELECTED 2 @@ -64,8 +64,8 @@ typedef struct EdgeHalf { BMFace *fnext; /* face between this edge and next, if any */ struct BoundVert *leftv; /* left boundary vert (looking along edge to end) */ struct BoundVert *rightv; /* right boundary vert, if beveled */ - short isbev; /* is this edge beveled? */ - short isrev; /* is e->v2 the vertex at this end? */ + short is_bev; /* is this edge beveled? */ + short is_rev; /* is e->v2 the vertex at this end? */ int seg; /* how many segments for the bevel */ float offset; /* offset for this edge */ // int _pad; @@ -199,7 +199,7 @@ static EdgeHalf *next_bev(BevVert *bv, EdgeHalf *from_e) from_e = &bv->edges[bv->edgecount - 1]; e = from_e; do { - if (e->isbev) { + if (e->is_bev) { return e; } } while ((e = e->next) != from_e); @@ -338,7 +338,6 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, /* get vectors perp to each edge, perp to norm_v, and pointing into face */ if (f) { copy_v3_v3(norm_v, f->no); - normalize_v3(norm_v); } cross_v3_v3v3(norm_perp1, dir1, norm_v); cross_v3_v3v3(norm_perp2, dir2, norm_v); @@ -408,7 +407,7 @@ static void offset_in_plane(EdgeHalf *e, const float plane_no[3], int left, floa float dir[3], no[3]; BMVert *v; - v = e->isrev ? e->e->v1 : e->e->v2; + v = e->is_rev ? e->e->v1 : e->e->v2; sub_v3_v3v3(dir, BM_edge_other_vert(e->e, v)->co, v->co); normalize_v3(dir); @@ -436,8 +435,7 @@ static void slide_dist(EdgeHalf *e, BMVert *v, float d, float slideco[3]) float dir[3], len; sub_v3_v3v3(dir, v->co, BM_edge_other_vert(e->e, v)->co); - len = len_v3(dir); - normalize_v3(dir); + len = normalize_v3(dir); if (d > len) d = len - (float)(50 * BEVEL_EPSILON); copy_v3_v3(slideco, v->co); @@ -607,7 +605,7 @@ static void get_point_on_round_edge(EdgeHalf *e, int k, sub_v3_v3v3(vva, va, vmid); sub_v3_v3v3(vvb, vb, vmid); - if (e->isrev) + if (e->is_rev) sub_v3_v3v3(dir, e->e->v1->co, e->e->v2->co); else sub_v3_v3v3(dir, e->e->v2->co, e->e->v1->co); @@ -644,7 +642,8 @@ static void build_boundary(MemArena *mem_arena, BevVert *bv) EdgeHalf *efirst, *e; BoundVert *v; VMesh *vm; - float co[3], *no; + float co[3]; + const float *no; float lastd; e = efirst = next_bev(bv, NULL); @@ -675,9 +674,9 @@ static void build_boundary(MemArena *mem_arena, BevVert *bv) lastd = e->offset; vm->boundstart = NULL; do { - if (e->isbev) { + if (e->is_bev) { /* handle only left side of beveled edge e here: next iteration should do right side */ - if (e->prev->isbev) { + if (e->prev->is_bev) { BLI_assert(e->prev != e); /* see: wire edge special case */ offset_meet(e->prev, e, bv->v, e->fprev, TRUE, co); v = add_new_bound_vert(mem_arena, vm, co); @@ -688,7 +687,7 @@ static void build_boundary(MemArena *mem_arena, BevVert *bv) } else { /* e->prev is not beveled */ - if (e->prev->prev->isbev) { + if (e->prev->prev->is_bev) { BLI_assert(e->prev->prev != e); /* see: edgecount 2, selcount 1 case */ /* find meet point between e->prev->prev and e and attach e->prev there */ /* TODO: fix case when one or both faces in following are NULL */ @@ -715,11 +714,11 @@ static void build_boundary(MemArena *mem_arena, BevVert *bv) } else { /* e is not beveled */ - if (e->next->isbev) { + if (e->next->is_bev) { /* next iteration will place e between beveled previous and next edges */ /* do nothing... */ } - else if (e->prev->isbev) { + else if (e->prev->is_bev) { /* on-edge meet between e->prev and e */ offset_meet(e->prev, e, bv->v, e->fprev, TRUE, co); v = add_new_bound_vert(mem_arena, vm, co); @@ -1447,15 +1446,15 @@ static void bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) bme = e->e; BMO_elem_flag_enable(bm, bme, BEVEL_FLAG); if (BMO_elem_flag_test(bm, bme, EDGE_SELECTED)) { - e->isbev = 1; + e->is_bev = TRUE; e->seg = bp->seg; } else { - e->isbev = 0; + e->is_bev = FALSE; e->seg = 0; } - e->isrev = (bme->v2 == v); - e->offset = e->isbev ? bp->offset : 0.0f; + e->is_rev = (bme->v2 == v); + e->offset = e->is_bev ? bp->offset : 0.0f; } /* find wrap-around shared face */ BM_ITER_ELEM (f, &iter2, bme, BM_FACES_OF_EDGE) { @@ -1524,7 +1523,7 @@ static void rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f) eprev = find_edge_half(bv, lprev->e); BLI_assert(e != NULL && eprev != NULL); vstart = eprev->leftv; - if (e->isbev) + if (e->is_bev) vend = e->rightv; else vend = e->leftv; -- cgit v1.2.3 From b7dbf83d19a9e2f6e1109948f7fa81b338f3a7b3 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 16 Nov 2012 12:33:24 +0000 Subject: more minor improvements to bevel use of math functions --- source/blender/bmesh/operators/bmo_bevel.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 656fef28393..076ff0b75cb 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -389,7 +389,7 @@ static void offset_in_two_planes(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, madd_v3_v3fl(off2a, norm_perp2, e2->offset); add_v3_v3v3(off2b, off2a, dir2); - if (fabs(angle_v3v3(dir1, dir2)) < BEVEL_EPSILON) { + if (angle_v3v3(dir1, dir2) < (float)BEVEL_EPSILON) { /* lines are parallel; off1a is a good meet point */ copy_v3_v3(meetco, off1a); } @@ -437,7 +437,7 @@ static void slide_dist(EdgeHalf *e, BMVert *v, float d, float slideco[3]) sub_v3_v3v3(dir, v->co, BM_edge_other_vert(e->e, v)->co); len = normalize_v3(dir); if (d > len) - d = len - (float)(50 * BEVEL_EPSILON); + d = len - (float)(50.0 * BEVEL_EPSILON); copy_v3_v3(slideco, v->co); madd_v3_v3fl(slideco, dir, -d); } @@ -562,7 +562,7 @@ static void get_point_on_round_profile(float r_co[3], float offset, int k, int c sub_v3_v3v3(vvb, vb, v); normalize_v3(vva); normalize_v3(vvb); - angle = angle_v3v3(vva, vvb); + angle = angle_normalized_v3v3(vva, vvb); add_v3_v3v3(center, vva, vvb); normalize_v3(center); -- cgit v1.2.3 From 8928344bf7cb1319aa6ab1b0089fad474e796ce6 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 16 Nov 2012 13:41:21 +0000 Subject: fix for own bug in quad-stip fill method, quad strips were skewed. --- source/blender/bmesh/operators/bmo_bevel.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 076ff0b75cb..d8a3e3fbb3e 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -1193,7 +1193,10 @@ static void bevel_build_quadstrip(BMesh *bm, BevVert *bv) if (f) { /* we have a polygon which we know starts at this vertex, make it into strips */ - BMVert *v_first = bv->vmesh->boundstart->efirst->next->next->leftv->nv.v; /* magic? */ + EdgeHalf *efirst = bv->vmesh->boundstart->efirst; + BMVert *v_first = efirst->is_bev ? + efirst->next->leftv->nv.v : + efirst->next->next->leftv->nv.v; /* magic? */ //BMLoop *l_start = BM_FACE_FIRST_LOOP(f); BMLoop *l_start = BM_face_vert_share_loop(f, v_first); BMLoop *l_a = l_start->prev, *l_a_step; -- cgit v1.2.3 From dc06523622e90ce236bf7bf32bebb45968bc51ae Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 16 Nov 2012 14:28:37 +0000 Subject: rework the bevel quad strip logic to work with ngons correctly, previously it only worked properly with triangles. --- source/blender/bmesh/operators/bmo_bevel.c | 57 ++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 18 deletions(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index d8a3e3fbb3e..1b1fc53011f 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -1193,32 +1193,53 @@ static void bevel_build_quadstrip(BMesh *bm, BevVert *bv) if (f) { /* we have a polygon which we know starts at this vertex, make it into strips */ - EdgeHalf *efirst = bv->vmesh->boundstart->efirst; - BMVert *v_first = efirst->is_bev ? - efirst->next->leftv->nv.v : - efirst->next->next->leftv->nv.v; /* magic? */ - //BMLoop *l_start = BM_FACE_FIRST_LOOP(f); - BMLoop *l_start = BM_face_vert_share_loop(f, v_first); - BMLoop *l_a = l_start->prev, *l_a_step; - BMLoop *l_b = l_start->next, *l_b_step; + EdgeHalf *eh_first, *eh_iter; + EdgeHalf *eh_a = NULL, *eh_b = NULL; + BMVert *v_a_first, *v_b_first; + + BMLoop *l_a; + BMLoop *l_b; + + /* find both edges */ + eh_iter = eh_first = bv->vmesh->boundstart->efirst; + do { + if (eh_iter->seg) { + if (eh_a == NULL) { + eh_a = eh_iter; + } + else if (eh_b == NULL) { + eh_b = eh_iter; + break; + } + } + } while ((eh_iter = eh_iter->next) != NULL); + + v_a_first = eh_a->rightv->nv.v; + v_b_first = eh_b->leftv->nv.v; + + l_a = BM_face_vert_share_loop(f, v_a_first); + l_b = BM_face_vert_share_loop(f, v_b_first); + if (l_a == l_b) { + /* step once around if we hit the same loop */ + l_a = l_a->prev; + l_b = l_b->next; + } while (f->len > 4) { - // BMLoop *l_new; - BMFace *f_new; + BMLoop *l_new; BLI_assert(l_a->f == f); BLI_assert(l_b->f == f); - l_a_step = l_a->prev; - l_b_step = l_b->next; + BM_face_split(bm, f, l_a->v, l_b->v, &l_new, NULL, FALSE); - f_new = BM_face_split(bm, f, l_a->v, l_b->v, NULL, NULL, FALSE); - - if (f_new->len > f->len) { - f = f_new; + if (l_new->f->len < l_new->radial_next->f->len) { + l_new = l_new->radial_next; } + f = l_new->f; - l_a = l_a_step; - l_b = l_b_step; + /* walk around the new face to get the next verts to split */ + l_a = l_new->prev; + l_b = l_new->next->next; } } } -- cgit v1.2.3 From 6de13de7ab6a8b625dedd8a46de2d6181328f7cf Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 16 Nov 2012 21:05:27 +0000 Subject: more straightforward way to implement quad-strip face filling suggested by Howard Trickey, also some other changes - no need to check the new loops face is larger and no longer split up the ngon more times then there are subdivisions in the face strip (now ngons will remain on both sides). --- source/blender/bmesh/operators/bmo_bevel.c | 40 +++++++++++------------------- 1 file changed, 15 insertions(+), 25 deletions(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 1b1fc53011f..c76693d5347 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -1193,48 +1193,38 @@ static void bevel_build_quadstrip(BMesh *bm, BevVert *bv) if (f) { /* we have a polygon which we know starts at this vertex, make it into strips */ - EdgeHalf *eh_first, *eh_iter; - EdgeHalf *eh_a = NULL, *eh_b = NULL; - BMVert *v_a_first, *v_b_first; + EdgeHalf *eh_a = bv->vmesh->boundstart->elast; + EdgeHalf *eh_b = next_bev(bv, eh_a->next); /* since (selcount == 2) we know this is valid */ + BMLoop *l_a = BM_face_vert_share_loop(f, eh_a->rightv->nv.v); + BMLoop *l_b = BM_face_vert_share_loop(f, eh_b->leftv->nv.v); + int seg_count = bv->vmesh->seg; /* ensure we don't walk past the segments */ - BMLoop *l_a; - BMLoop *l_b; - - /* find both edges */ - eh_iter = eh_first = bv->vmesh->boundstart->efirst; - do { - if (eh_iter->seg) { - if (eh_a == NULL) { - eh_a = eh_iter; - } - else if (eh_b == NULL) { - eh_b = eh_iter; - break; - } - } - } while ((eh_iter = eh_iter->next) != NULL); - - v_a_first = eh_a->rightv->nv.v; - v_b_first = eh_b->leftv->nv.v; - - l_a = BM_face_vert_share_loop(f, v_a_first); - l_b = BM_face_vert_share_loop(f, v_b_first); if (l_a == l_b) { /* step once around if we hit the same loop */ l_a = l_a->prev; l_b = l_b->next; + seg_count--; } + BLI_assert(l_a != l_b); + while (f->len > 4) { BMLoop *l_new; BLI_assert(l_a->f == f); BLI_assert(l_b->f == f); BM_face_split(bm, f, l_a->v, l_b->v, &l_new, NULL, FALSE); + if (seg_count-- == 0) { + break; + } + /* turns out we don't need this, + * because of how BM_face_split works we always get the loop of the larger face */ +#if 0 if (l_new->f->len < l_new->radial_next->f->len) { l_new = l_new->radial_next; } +#endif f = l_new->f; /* walk around the new face to get the next verts to split */ -- cgit v1.2.3 From c3c14f862b552a1536c5f4deae7e68c14f1d6e92 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 16 Nov 2012 21:25:11 +0000 Subject: use quad-strip for filling even when no segments are being added, this gives quad-loops along the bevel whereas before it made ngons. --- source/blender/bmesh/operators/bmo_bevel.c | 39 ++++++++++++++++++------------ 1 file changed, 23 insertions(+), 16 deletions(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index c76693d5347..3854bca5d44 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -92,7 +92,7 @@ typedef struct VMesh { M_NONE, /* no polygon mesh needed */ M_POLY, /* a simple polygon */ M_ADJ, /* "adjacent edges" mesh pattern */ - M_CROSS, /* "cross edges" mesh pattern */ +// M_CROSS, /* "cross edges" mesh pattern */ M_TRI_FAN, /* a simple polygon - fan filled */ M_QUAD_STRIP, /* a simple polygon - cut into paralelle strips */ } mesh_kind; @@ -745,6 +745,9 @@ static void build_boundary(MemArena *mem_arena, BevVert *bv) if (vm->count == 2 && bv->edgecount == 3) { vm->mesh_kind = M_NONE; } + else if (bv->selcount == 2) { + vm->mesh_kind = M_QUAD_STRIP; + } else if (efirst->seg == 1 || bv->selcount == 1) { if (vm->count == 3 && bv->selcount == 1) { vm->mesh_kind = M_TRI_FAN; @@ -754,12 +757,7 @@ static void build_boundary(MemArena *mem_arena, BevVert *bv) } } else { - if (bv->selcount == 2) { - vm->mesh_kind = M_QUAD_STRIP; - } - else { - vm->mesh_kind = M_ADJ; - } + vm->mesh_kind = M_ADJ; } /* TODO: if vm->count == 4 and bv->selcount == 4, use M_CROSS pattern */ } @@ -1219,7 +1217,7 @@ static void bevel_build_quadstrip(BMesh *bm, BevVert *bv) } /* turns out we don't need this, - * because of how BM_face_split works we always get the loop of the larger face */ + * because of how BM_face_split works we always get the loop of the next face */ #if 0 if (l_new->f->len < l_new->radial_next->f->len) { l_new = l_new->radial_next; @@ -1371,14 +1369,23 @@ static void build_vmesh(MemArena *mem_arena, BMesh *bm, BevVert *bv) copy_mesh_vert(vm, weld2->index, 0, ns - k, weld1->index, 0, k); } - if (vm->mesh_kind == M_ADJ) - bevel_build_rings(bm, bv); - else if (vm->mesh_kind == M_POLY) - bevel_build_poly(bm, bv); - else if (vm->mesh_kind == M_TRI_FAN) - bevel_build_trifan(bm, bv); - else if (vm->mesh_kind == M_QUAD_STRIP) - bevel_build_quadstrip(bm, bv); + switch (vm->mesh_kind) { + case M_NONE: + /* do nothing */ + break; + case M_POLY: + bevel_build_poly(bm, bv); + break; + case M_ADJ: + bevel_build_rings(bm, bv); + break; + case M_TRI_FAN: + bevel_build_trifan(bm, bv); + break; + case M_QUAD_STRIP: + bevel_build_quadstrip(bm, bv); + break; + } } /* -- cgit v1.2.3 From 9a74fb5b05476eacdaf1a2d8c8f027c8aae34805 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 18 Nov 2012 08:20:02 +0000 Subject: moving bevel to tools dir as-is to keep svn history (breaks build, will fix next). --- source/blender/bmesh/operators/bmo_bevel.c | 1720 ---------------------------- 1 file changed, 1720 deletions(-) delete mode 100644 source/blender/bmesh/operators/bmo_bevel.c (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c deleted file mode 100644 index 3854bca5d44..00000000000 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ /dev/null @@ -1,1720 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Contributor(s): Joseph Eagar, Aleksandr Mokhov, Howard Trickey - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/bmesh/operators/bmo_bevel.c - * \ingroup bmesh - */ - -#include "MEM_guardedalloc.h" - -#include "BLI_array.h" -#include "BLI_math.h" -#include "BLI_memarena.h" - -#include "BKE_customdata.h" - -#include "bmesh.h" - -#include "intern/bmesh_operators_private.h" /* own include */ - -/* experemental - Campbell */ -// #define USE_ALTERNATE_ADJ - -#define BEVEL_FLAG 1 -#define EDGE_SELECTED 2 - -#define BEVEL_EPSILON 1e-6 - -/* for testing */ -// #pragma GCC diagnostic error "-Wpadded" - -/* Constructed vertex, sometimes later instantiated as BMVert */ -typedef struct NewVert { - BMVert *v; - float co[3]; - int _pad; -} NewVert; - -struct BoundVert; - -/* Data for one end of an edge involved in a bevel */ -typedef struct EdgeHalf { - struct EdgeHalf *next, *prev; /* in CCW order */ - BMEdge *e; /* original mesh edge */ - BMFace *fprev; /* face between this edge and previous, if any */ - BMFace *fnext; /* face between this edge and next, if any */ - struct BoundVert *leftv; /* left boundary vert (looking along edge to end) */ - struct BoundVert *rightv; /* right boundary vert, if beveled */ - short is_bev; /* is this edge beveled? */ - short is_rev; /* is e->v2 the vertex at this end? */ - int seg; /* how many segments for the bevel */ - float offset; /* offset for this edge */ -// int _pad; -} EdgeHalf; - -/* An element in a cyclic boundary of a Vertex Mesh (VMesh) */ -typedef struct BoundVert { - struct BoundVert *next, *prev; /* in CCW order */ - NewVert nv; - EdgeHalf *efirst; /* first of edges attached here: in CCW order */ - EdgeHalf *elast; - EdgeHalf *ebev; /* beveled edge whose left side is attached here, if any */ - int index; /* used for vmesh indexing */ -// int _pad; -} BoundVert; - -/* Mesh structure replacing a vertex */ -typedef struct VMesh { - NewVert *mesh; /* allocated array - size and structure depends on kind */ - BoundVert *boundstart; /* start of boundary double-linked list */ - int count; /* number of vertices in the boundary */ - int seg; /* common # of segments for segmented edges */ - enum { - M_NONE, /* no polygon mesh needed */ - M_POLY, /* a simple polygon */ - M_ADJ, /* "adjacent edges" mesh pattern */ -// M_CROSS, /* "cross edges" mesh pattern */ - M_TRI_FAN, /* a simple polygon - fan filled */ - M_QUAD_STRIP, /* a simple polygon - cut into paralelle strips */ - } mesh_kind; -// int _pad; -} VMesh; - -/* Data for a vertex involved in a bevel */ -typedef struct BevVert { - BMVert *v; /* original mesh vertex */ - int edgecount; /* total number of edges around the vertex */ - int selcount; /* number of selected edges around the vertex */ - EdgeHalf *edges; /* array of size edgecount; CCW order from vertex normal side */ - VMesh *vmesh; /* mesh structure for replacing vertex */ -} BevVert; - -/* Bevel parameters and state */ -typedef struct BevelParams { - /* hash of BevVert for each vertex involved in bevel - * GHash: (key=(BMVert *), value=(BevVert *)) */ - GHash *vert_hash; - MemArena *mem_arena; /* use for all allocs while bevel runs, if we need to free we can switch to mempool */ - - float offset; /* blender units to offset each side of a beveled edge */ - int seg; /* number of segments in beveled edge profile */ -} BevelParams; - -// #pragma GCC diagnostic ignored "-Wpadded" - -//#include "bevdebug.c" - -/* Make a new BoundVert of the given kind, insert it at the end of the circular linked - * list with entry point bv->boundstart, and return it. */ -static BoundVert *add_new_bound_vert(MemArena *mem_arena, VMesh *vm, const float co[3]) -{ - BoundVert *ans = (BoundVert *)BLI_memarena_alloc(mem_arena, sizeof(BoundVert)); - - copy_v3_v3(ans->nv.co, co); - if (!vm->boundstart) { - ans->index = 0; - vm->boundstart = ans; - ans->next = ans->prev = ans; - } - else { - BoundVert *tail = vm->boundstart->prev; - ans->index = tail->index + 1; - ans->prev = tail; - ans->next = vm->boundstart; - tail->next = ans; - vm->boundstart->prev = ans; - } - vm->count++; - return ans; -} - -/* Mesh verts are indexed (i, j, k) where - * i = boundvert index (0 <= i < nv) - * j = ring index (0 <= j <= ns2) - * k = segment index (0 <= k <= ns) - * Not all of these are used, and some will share BMVerts */ -static NewVert *mesh_vert(VMesh *vm, int i, int j, int k) -{ - int nj = (vm->seg / 2) + 1; - int nk = vm->seg + 1; - - return &vm->mesh[i * nk * nj + j * nk + k]; -} - -static void create_mesh_bmvert(BMesh *bm, VMesh *vm, int i, int j, int k, BMVert *eg) -{ - NewVert *nv = mesh_vert(vm, i, j, k); - nv->v = BM_vert_create(bm, nv->co, eg); -} - -static void copy_mesh_vert(VMesh *vm, int ito, int jto, int kto, - int ifrom, int jfrom, int kfrom) -{ - NewVert *nvto, *nvfrom; - - nvto = mesh_vert(vm, ito, jto, kto); - nvfrom = mesh_vert(vm, ifrom, jfrom, kfrom); - nvto->v = nvfrom->v; - copy_v3_v3(nvto->co, nvfrom->co); -} - -/* find the EdgeHalf in bv's array that has edge bme */ -static EdgeHalf *find_edge_half(BevVert *bv, BMEdge *bme) -{ - int i; - - for (i = 0; i < bv->edgecount; i++) { - if (bv->edges[i].e == bme) - return &bv->edges[i]; - } - return NULL; -} - -/* Return the next EdgeHalf after from_e that is beveled. - * If from_e is NULL, find the first beveled edge. */ -static EdgeHalf *next_bev(BevVert *bv, EdgeHalf *from_e) -{ - EdgeHalf *e; - - if (from_e == NULL) - from_e = &bv->edges[bv->edgecount - 1]; - e = from_e; - do { - if (e->is_bev) { - return e; - } - } while ((e = e->next) != from_e); - return NULL; -} - -/* find the BevVert corresponding to BMVert bmv */ -static BevVert *find_bevvert(BevelParams *bp, BMVert *bmv) -{ - return BLI_ghash_lookup(bp->vert_hash, bmv); -} - -/* Return a good respresentative face (for materials, etc.) for faces - * created around/near BoundVert v */ -static BMFace *boundvert_rep_face(BoundVert *v) -{ - BMFace *fans = NULL; - BMFace *firstf = NULL; - BMEdge *e1, *e2; - BMFace *f1, *f2; - BMIter iter1, iter2; - - BLI_assert(v->efirst != NULL && v->elast != NULL); - e1 = v->efirst->e; - e2 = v->elast->e; - BM_ITER_ELEM (f1, &iter1, e1, BM_FACES_OF_EDGE) { - if (!firstf) - firstf = f1; - BM_ITER_ELEM (f2, &iter2, e2, BM_FACES_OF_EDGE) { - if (f1 == f2) { - fans = f1; - break; - } - } - } - if (!fans) - fans = firstf; - - return fans; -} - -/* Make ngon from verts alone. - * Make sure to properly copy face attributes and do custom data interpolation from - * example face, facerep. */ -static BMFace *bev_create_ngon(BMesh *bm, BMVert **vert_arr, int totv, BMFace *facerep) -{ - BMIter iter; - BMLoop *l; - BMFace *f; - - if (totv == 3) { - f = BM_face_create_quad_tri(bm, - vert_arr[0], vert_arr[1], vert_arr[2], NULL, facerep, 0); - } - else if (totv == 4) { - f = BM_face_create_quad_tri(bm, - vert_arr[0], vert_arr[1], vert_arr[2], vert_arr[3], facerep, 0); - } - else { - int i; - BMEdge *e; - BMEdge **ee = NULL; - BLI_array_staticdeclare(ee, 30); - - for (i = 0; i < totv; i++) { - e = BM_edge_create(bm, vert_arr[i], vert_arr[(i + 1) % totv], NULL, TRUE); - BLI_array_append(ee, e); - } - f = BM_face_create_ngon(bm, vert_arr[0], vert_arr[1], ee, totv, FALSE); - BLI_array_free(ee); - } - if (facerep && f) { - int has_mdisps = CustomData_has_layer(&bm->ldata, CD_MDISPS); - BM_elem_attrs_copy(bm, bm, facerep, f); - BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) { - BM_loop_interp_from_face(bm, l, facerep, TRUE, TRUE); - if (has_mdisps) - BM_loop_interp_multires(bm, l, facerep); - } - } - return f; -} - -static BMFace *bev_create_quad_tri(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4, - BMFace *facerep) -{ - BMVert *varr[4]; - - varr[0] = v1; - varr[1] = v2; - varr[2] = v3; - varr[3] = v4; - return bev_create_ngon(bm, varr, v4 ? 4 : 3, facerep); -} - -/* - * Calculate the meeting point between the offset edges for e1 and e2, putting answer in meetco. - * e1 and e2 share vertex v and face f (may be NULL) and viewed from the normal side of - * the bevel vertex, e1 precedes e2 in CCW order. - * If on_right is true, offset edge is on right of both edges, where e1 enters v and - * e2 leave it. If on_right is false, then the offset edge is on the left. - * When offsets are equal, the new point is on the edge bisector, with length offset/sin(angle/2), - * but if the offsets are not equal (allowing for this, as bevel modifier has edge weights that may - * lead to different offsets) then meeting point can be found be intersecting offset lines. - */ -static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, - int on_right, float meetco[3]) -{ - float dir1[3], dir2[3], norm_v[3], norm_perp1[3], norm_perp2[3], - off1a[3], off1b[3], off2a[3], off2b[3], isect2[3]; - - /* get direction vectors for two offset lines */ - sub_v3_v3v3(dir1, v->co, BM_edge_other_vert(e1->e, v)->co); - sub_v3_v3v3(dir2, BM_edge_other_vert(e2->e, v)->co, v->co); - - /* get normal to plane where meet point should be */ - cross_v3_v3v3(norm_v, dir2, dir1); - normalize_v3(norm_v); - if (!on_right) - negate_v3(norm_v); - if (is_zero_v3(norm_v)) { - /* special case: e1 and e2 are parallel; put offset point perp to both, from v. - * need to find a suitable plane. - * if offsets are different, we're out of luck: just use e1->offset */ - if (f) - copy_v3_v3(norm_v, f->no); - else - copy_v3_v3(norm_v, v->no); - cross_v3_v3v3(norm_perp1, dir1, norm_v); - normalize_v3(norm_perp1); - copy_v3_v3(off1a, v->co); - madd_v3_v3fl(off1a, norm_perp1, e1->offset); - copy_v3_v3(meetco, off1a); - } - else { - /* get vectors perp to each edge, perp to norm_v, and pointing into face */ - if (f) { - copy_v3_v3(norm_v, f->no); - } - cross_v3_v3v3(norm_perp1, dir1, norm_v); - cross_v3_v3v3(norm_perp2, dir2, norm_v); - normalize_v3(norm_perp1); - normalize_v3(norm_perp2); - - /* get points that are offset distances from each line, then another point on each line */ - copy_v3_v3(off1a, v->co); - madd_v3_v3fl(off1a, norm_perp1, e1->offset); - add_v3_v3v3(off1b, off1a, dir1); - copy_v3_v3(off2a, v->co); - madd_v3_v3fl(off2a, norm_perp2, e2->offset); - add_v3_v3v3(off2b, off2a, dir2); - - /* intersect the lines; by construction they should be on the same plane and not parallel */ - if (!isect_line_line_v3(off1a, off1b, off2a, off2b, meetco, isect2)) { - BLI_assert(!"offset_meet failure"); - copy_v3_v3(meetco, off1a); /* just to do something */ - } - } -} - -/* Like offset_meet, but here f1 and f2 must not be NULL and give the - * planes in which to run the offset lines. They may not meet exactly, - * but the line intersection routine will find the closest approach point. */ -static void offset_in_two_planes(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, - BMFace *f1, BMFace *f2, float meetco[3]) -{ - float dir1[3], dir2[3], norm_perp1[3], norm_perp2[3], - off1a[3], off1b[3], off2a[3], off2b[3], isect2[3]; - - BLI_assert(f1 != NULL && f2 != NULL); - - /* get direction vectors for two offset lines */ - sub_v3_v3v3(dir1, v->co, BM_edge_other_vert(e1->e, v)->co); - sub_v3_v3v3(dir2, BM_edge_other_vert(e2->e, v)->co, v->co); - - /* get directions into offset planes */ - cross_v3_v3v3(norm_perp1, dir1, f1->no); - normalize_v3(norm_perp1); - cross_v3_v3v3(norm_perp2, dir2, f2->no); - normalize_v3(norm_perp2); - - /* get points that are offset distances from each line, then another point on each line */ - copy_v3_v3(off1a, v->co); - madd_v3_v3fl(off1a, norm_perp1, e1->offset); - add_v3_v3v3(off1b, off1a, dir1); - copy_v3_v3(off2a, v->co); - madd_v3_v3fl(off2a, norm_perp2, e2->offset); - add_v3_v3v3(off2b, off2a, dir2); - - if (angle_v3v3(dir1, dir2) < (float)BEVEL_EPSILON) { - /* lines are parallel; off1a is a good meet point */ - copy_v3_v3(meetco, off1a); - } - else if (!isect_line_line_v3(off1a, off1b, off2a, off2b, meetco, isect2)) { - /* another test says they are parallel */ - copy_v3_v3(meetco, off1a); - } -} - -/* Offset by e->offset in plane with normal plane_no, on left if left==TRUE, - * else on right. If no is NULL, choose an arbitrary plane different - * from eh's direction. */ -static void offset_in_plane(EdgeHalf *e, const float plane_no[3], int left, float r[3]) -{ - float dir[3], no[3]; - BMVert *v; - - v = e->is_rev ? e->e->v1 : e->e->v2; - - sub_v3_v3v3(dir, BM_edge_other_vert(e->e, v)->co, v->co); - normalize_v3(dir); - if (plane_no) { - copy_v3_v3(no, plane_no); - } - else { - zero_v3(no); - if (fabs(dir[0]) < fabs(dir[1])) - no[0] = 1.0f; - else - no[1] = 1.0f; - } - if (left) - cross_v3_v3v3(r, no, dir); - else - cross_v3_v3v3(r, dir, no); - normalize_v3(r); - mul_v3_fl(r, e->offset); -} - -/* Calculate coordinates of a point a distance d from v on e->e and return it in slideco */ -static void slide_dist(EdgeHalf *e, BMVert *v, float d, float slideco[3]) -{ - float dir[3], len; - - sub_v3_v3v3(dir, v->co, BM_edge_other_vert(e->e, v)->co); - len = normalize_v3(dir); - if (d > len) - d = len - (float)(50.0 * BEVEL_EPSILON); - copy_v3_v3(slideco, v->co); - madd_v3_v3fl(slideco, dir, -d); -} - -/* Calculate the point on e where line (co_a, co_b) comes closest to and return it in projco */ -static void project_to_edge(BMEdge *e, const float co_a[3], const float co_b[3], float projco[3]) -{ - float otherco[3]; - - if (!isect_line_line_v3(e->v1->co, e->v2->co, co_a, co_b, projco, otherco)) { - BLI_assert(!"project meet failure"); - copy_v3_v3(projco, e->v1->co); - } -} - -/* return 1 if a and b are in CCW order on the normal side of f, - * and -1 if they are reversed, and 0 if there is no shared face f */ -static int bev_ccw_test(BMEdge *a, BMEdge *b, BMFace *f) -{ - BMLoop *la, *lb; - - if (!f) - return 0; - la = BM_face_edge_share_loop(f, a); - lb = BM_face_edge_share_loop(f, b); - if (!la || !lb) - return 0; - return lb->next == la ? 1 : -1; -} - -#ifdef USE_ALTERNATE_ADJ - -static void vmesh_cent(VMesh *vm, float r_cent[3]) -{ - BoundVert *v; - int tot = 0; - zero_v3(r_cent); - - v = vm->boundstart; - do { - add_v3_v3(r_cent, v->nv.co); - tot++; - } while ((v = v->next) != vm->boundstart); - mul_v3_fl(r_cent, 1.0f / (float)tot); -} - -/** - * - * This example shows a tri fan of quads, - * but could be an NGon fan of quads too. - *
- *      The whole triangle   X
- *      represents the      / \
- *      new bevel face.    /   \
- *                        /     \
- *       Split into      /       \
- *       a quad fan.    /         \
- *                     /           \
- *                    /             \
- *                   /               \
- *          co_prev +-.             .-+
- *                 /   `-._     _.-'   \
- *                / co_cent`-+-'        \
- *               /           |           \
- * Quad of      /            |            \
- * interest -- / ---> X      |             \
- *            /              |              \
- *           /               |               \
- *          /         co_next|                \
- * co_orig +-----------------+-----------------+
- *
- *         For each quad, calcualte UV's based on the following:
- *           U = k    / (vm->seg * 2)
- *           V = ring / (vm->seg * 2)
- *           quad = (co_orig, co_prev, co_cent, co_next)
- *           ... note that co_cent is the same for all quads in the fan.
- * 
- * - */ - -static void get_point_uv(float uv[2], - /* all these args are int's originally - * but pass as floats to the function */ - const float seg, const float ring, const float k) -{ - uv[0] = (ring / seg) * 2.0f; - uv[1] = (k / seg) * 2.0f; -} - -/* TODO: make this a lot smarter!, - * this is the main reason USE_ALTERNATE_ADJ isn't so good right now :S */ -static float get_point_uv_factor(const float uv[2]) -{ - return sinf(1.0f - max_ff(uv[0], uv[1]) / 2.0f); -} - -static void get_point_on_round_edge(const float uv[2], - float quad[4][3], - float r_co[3]) -{ - interp_bilinear_quad_v3(quad, uv[0], uv[1], r_co); -} - -#else /* USE_ALTERNATE_ADJ */ - -/* - * calculation of points on the round profile - * r - result, coordinate of point on round profile - * method: - * Inscribe a circle in angle va - v -vb - * such that it touches the arms at offset from v. - * Rotate the center-va segment by (i/n) of the - * angle va - center -vb, and put the endpoint - * of that segment in r. - */ -static void get_point_on_round_profile(float r_co[3], float offset, int k, int count, - const float va[3], const float v[3], const float vb[3]) -{ - float vva[3], vvb[3], angle, center[3], rv[3], axis[3], co[3]; - - sub_v3_v3v3(vva, va, v); - sub_v3_v3v3(vvb, vb, v); - normalize_v3(vva); - normalize_v3(vvb); - angle = angle_normalized_v3v3(vva, vvb); - - add_v3_v3v3(center, vva, vvb); - normalize_v3(center); - mul_v3_fl(center, offset * (1.0f / cosf(0.5f * angle))); - add_v3_v3(center, v); /* coordinates of the center of the inscribed circle */ - - - sub_v3_v3v3(rv, va, center); /* radius vector */ - - - sub_v3_v3v3(co, v, center); - cross_v3_v3v3(axis, rv, co); /* calculate axis */ - - sub_v3_v3v3(vva, va, center); - sub_v3_v3v3(vvb, vb, center); - angle = angle_v3v3(vva, vvb); - - rotate_v3_v3v3fl(co, rv, axis, angle * (float)k / (float)count); - - add_v3_v3(co, center); - copy_v3_v3(r_co, co); -} - -/* - * Find the point (/n) of the way around the round profile for e, - * where start point is va, midarc point is vmid, and end point is vb. - * Return the answer in profileco. - * Method: - * Adjust va and vb (along edge direction) so that they are perpendicular - * to edge at v, then use get_point_on_round_profile, then project - * back onto original va - vmid - vb plane. - * If va, vmid, and vb are all on the same plane, just interpolate between va and vb. - */ -static void get_point_on_round_edge(EdgeHalf *e, int k, - const float va[3], const float vmid[3], const float vb[3], - float r_co[3]) -{ - float vva[3], vvb[3], point[3], dir[3], vaadj[3], vbadj[3], p2[3], pn[3]; - int n = e->seg; - - sub_v3_v3v3(vva, va, vmid); - sub_v3_v3v3(vvb, vb, vmid); - if (e->is_rev) - sub_v3_v3v3(dir, e->e->v1->co, e->e->v2->co); - else - sub_v3_v3v3(dir, e->e->v2->co, e->e->v1->co); - normalize_v3(dir); - if (fabsf(angle_v3v3(vva, vvb) - (float)M_PI) > (float)BEVEL_EPSILON) { - copy_v3_v3(vaadj, va); - madd_v3_v3fl(vaadj, dir, -len_v3(vva) * cosf(angle_v3v3(vva, dir))); - copy_v3_v3(vbadj, vb); - madd_v3_v3fl(vbadj, dir, -len_v3(vvb) * cosf(angle_v3v3(vvb, dir))); - - get_point_on_round_profile(point, e->offset, k, n, vaadj, vmid, vbadj); - - add_v3_v3v3(p2, point, dir); - cross_v3_v3v3(pn, vva, vvb); - if (!isect_line_plane_v3(r_co, point, p2, vmid, pn, 0)) { - /* TODO: track down why this sometimes fails */ - copy_v3_v3(r_co, point); - } - } - else { - /* planar case */ - interp_v3_v3v3(r_co, va, vb, (float)k / (float)n); - } -} - -#endif /* !USE_ALTERNATE_ADJ */ - -/* Make a circular list of BoundVerts for bv, each of which has the coordinates - * of a vertex on the the boundary of the beveled vertex bv->v. - * Also decide on the mesh pattern that will be used inside the boundary. - * Doesn't make the actual BMVerts */ -static void build_boundary(MemArena *mem_arena, BevVert *bv) -{ - EdgeHalf *efirst, *e; - BoundVert *v; - VMesh *vm; - float co[3]; - const float *no; - float lastd; - - e = efirst = next_bev(bv, NULL); - vm = bv->vmesh; - - BLI_assert(bv->edgecount >= 2); /* since bevel edges incident to 2 faces */ - - if (bv->edgecount == 2 && bv->selcount == 1) { - /* special case: beveled edge meets non-beveled one at valence 2 vert */ - no = e->fprev ? e->fprev->no : (e->fnext ? e->fnext->no : NULL); - offset_in_plane(e, no, TRUE, co); - v = add_new_bound_vert(mem_arena, vm, co); - v->efirst = v->elast = v->ebev = e; - e->leftv = v; - no = e->fnext ? e->fnext->no : (e->fprev ? e->fprev->no : NULL); - offset_in_plane(e, no, FALSE, co); - v = add_new_bound_vert(mem_arena, vm, co); - v->efirst = v->elast = e; - e->rightv = v; - /* make artifical extra point along unbeveled edge, and form triangle */ - slide_dist(e->next, bv->v, e->offset, co); - v = add_new_bound_vert(mem_arena, vm, co); - v->efirst = v->elast = e->next; - vm->mesh_kind = M_POLY; - return; - } - - lastd = e->offset; - vm->boundstart = NULL; - do { - if (e->is_bev) { - /* handle only left side of beveled edge e here: next iteration should do right side */ - if (e->prev->is_bev) { - BLI_assert(e->prev != e); /* see: wire edge special case */ - offset_meet(e->prev, e, bv->v, e->fprev, TRUE, co); - v = add_new_bound_vert(mem_arena, vm, co); - v->efirst = e->prev; - v->elast = v->ebev = e; - e->leftv = v; - e->prev->rightv = v; - } - else { - /* e->prev is not beveled */ - if (e->prev->prev->is_bev) { - BLI_assert(e->prev->prev != e); /* see: edgecount 2, selcount 1 case */ - /* find meet point between e->prev->prev and e and attach e->prev there */ - /* TODO: fix case when one or both faces in following are NULL */ - offset_in_two_planes(e->prev->prev, e, bv->v, - e->prev->prev->fnext, e->fprev, co); - v = add_new_bound_vert(mem_arena, vm, co); - v->efirst = e->prev->prev; - v->elast = v->ebev = e; - e->leftv = v; - e->prev->leftv = v; - e->prev->prev->rightv = v; - } - else { - /* neither e->prev nor e->prev->prev are beveled: make on-edge on e->prev */ - offset_meet(e->prev, e, bv->v, e->fprev, TRUE, co); - v = add_new_bound_vert(mem_arena, vm, co); - v->efirst = e->prev; - v->elast = v->ebev = e; - e->leftv = v; - e->prev->leftv = v; - } - } - lastd = len_v3v3(bv->v->co, v->nv.co); - } - else { - /* e is not beveled */ - if (e->next->is_bev) { - /* next iteration will place e between beveled previous and next edges */ - /* do nothing... */ - } - else if (e->prev->is_bev) { - /* on-edge meet between e->prev and e */ - offset_meet(e->prev, e, bv->v, e->fprev, TRUE, co); - v = add_new_bound_vert(mem_arena, vm, co); - v->efirst = e->prev; - v->elast = e; - e->leftv = v; - e->prev->rightv = v; - } - else { - /* None of e->prev, e, e->next are beveled. - * could either leave alone or add slide points to make - * one polygon around bv->v. For now, we choose latter. - * Could slide to make an even bevel plane but for now will - * just use last distance a meet point moved from bv->v. */ - slide_dist(e, bv->v, lastd, co); - v = add_new_bound_vert(mem_arena, vm, co); - v->efirst = v->elast = e; - e->leftv = v; - } - } - } while ((e = e->next) != efirst); - - BLI_assert(vm->count >= 2); - if (vm->count == 2 && bv->edgecount == 3) { - vm->mesh_kind = M_NONE; - } - else if (bv->selcount == 2) { - vm->mesh_kind = M_QUAD_STRIP; - } - else if (efirst->seg == 1 || bv->selcount == 1) { - if (vm->count == 3 && bv->selcount == 1) { - vm->mesh_kind = M_TRI_FAN; - } - else { - vm->mesh_kind = M_POLY; - } - } - else { - vm->mesh_kind = M_ADJ; - } - /* TODO: if vm->count == 4 and bv->selcount == 4, use M_CROSS pattern */ -} - -/* - * Given that the boundary is built and the boundary BMVerts have been made, - * calculate the positions of the interior mesh points for the M_ADJ pattern, - * then make the BMVerts and the new faces. */ -static void bevel_build_rings(BMesh *bm, BevVert *bv) -{ - int k, ring, i, n, ns, ns2, nn; - VMesh *vm = bv->vmesh; - BoundVert *v, *vprev, *vnext; - NewVert *nv, *nvprev, *nvnext; - BMVert *bmv, *bmv1, *bmv2, *bmv3, *bmv4; - BMFace *f; - float co[3], coa[3], cob[3], midco[3]; - -#ifdef USE_ALTERNATE_ADJ - /* ordered as follows (orig, prev, center, next)*/ - float quad_plane[4][3]; - float quad_orig[4][3]; -#endif - - -#ifdef USE_ALTERNATE_ADJ - /* the rest are initialized inline, this remains the same for all */ - vmesh_cent(vm, quad_plane[2]); - copy_v3_v3(quad_orig[2], bv->v->co); -#endif - - n = vm->count; - ns = vm->seg; - ns2 = ns / 2; - BLI_assert(n > 2 && ns > 1); - /* Make initial rings, going between points on neighbors. - * After this loop, will have coords for all (i, r, k) where - * BoundVert for i has a bevel, 0 <= r <= ns2, 0 <= k <= ns */ - for (ring = 1; ring <= ns2; ring++) { - v = vm->boundstart; - - do { - i = v->index; - if (v->ebev) { - /* get points coords of points a and b, on outer rings - * of prev and next edges, k away from this edge */ - vprev = v->prev; - vnext = v->next; - - if (vprev->ebev) - nvprev = mesh_vert(vm, vprev->index, 0, ns - ring); - else - nvprev = mesh_vert(vm, vprev->index, 0, ns); - copy_v3_v3(coa, nvprev->co); - nv = mesh_vert(vm, i, ring, 0); - copy_v3_v3(nv->co, coa); - nv->v = nvprev->v; - - if (vnext->ebev) - nvnext = mesh_vert(vm, vnext->index, 0, ring); - else - nvnext = mesh_vert(vm, vnext->index, 0, 0); - copy_v3_v3(cob, nvnext->co); - nv = mesh_vert(vm, i, ring, ns); - copy_v3_v3(nv->co, cob); - nv->v = nvnext->v; - -#ifdef USE_ALTERNATE_ADJ - /* plane */ - copy_v3_v3(quad_plane[0], v->nv.co); - mid_v3_v3v3(quad_plane[1], v->nv.co, v->prev->nv.co); - /* quad[2] is set */ - mid_v3_v3v3(quad_plane[3], v->nv.co, v->next->nv.co); - - /* orig */ - copy_v3_v3(quad_orig[0], v->nv.co); /* only shared location between 2 quads */ - project_to_edge(v->ebev->prev->e, v->nv.co, v->prev->nv.co, quad_orig[1]); - project_to_edge(v->ebev->e, v->nv.co, v->next->nv.co, quad_orig[3]); - - //bl_debug_draw_quad_add(UNPACK4(quad_plane)); - //bl_debug_draw_quad_add(UNPACK4(quad_orig)); -#endif - -#ifdef USE_ALTERNATE_ADJ - for (k = 1; k < ns; k++) { - float uv[2]; - float fac; - float co_plane[3]; - float co_orig[3]; - - get_point_uv(uv, v->ebev->seg, ring, k); - get_point_on_round_edge(uv, quad_plane, co_plane); - get_point_on_round_edge(uv, quad_orig, co_orig); - fac = get_point_uv_factor(uv); - interp_v3_v3v3(co, co_plane, co_orig, fac); - copy_v3_v3(mesh_vert(vm, i, ring, k)->co, co); - } -#else - /* TODO: better calculation of new midarc point? */ - project_to_edge(v->ebev->e, coa, cob, midco); - - for (k = 1; k < ns; k++) { - get_point_on_round_edge(v->ebev, k, coa, midco, cob, co); - copy_v3_v3(mesh_vert(vm, i, ring, k)->co, co); - } -#endif - } - } while ((v = v->next) != vm->boundstart); - } - - /* Now make sure cross points of rings share coordinates and vertices. - * After this loop, will have BMVerts for all (i, r, k) where - * i is for a BoundVert that is beveled and has either a predecessor or - * successor BoundVert beveled too, and - * for odd ns: 0 <= r <= ns2, 0 <= k <= ns - * for even ns: 0 <= r < ns2, 0 <= k <= ns except k=ns2 */ - v = vm->boundstart; - do { - i = v->index; - if (v->ebev) { - vprev = v->prev; - vnext = v->next; - if (vprev->ebev) { - for (ring = 1; ring <= ns2; ring++) { - for (k = 1; k <= ns2; k++) { - if (ns % 2 == 0 && (k == ns2 || ring == ns2)) - continue; /* center line is special case: do after the rest are done */ - nv = mesh_vert(vm, i, ring, k); - nvprev = mesh_vert(vm, vprev->index, k, ns - ring); - mid_v3_v3v3(co, nv->co, nvprev->co); -#ifndef USE_ALTERNATE_ADJ - copy_v3_v3(nv->co, co); -#endif - BLI_assert(nv->v == NULL && nvprev->v == NULL); - create_mesh_bmvert(bm, vm, i, ring, k, bv->v); - copy_mesh_vert(vm, vprev->index, k, ns - ring, i, ring, k); - } - } - if (!vprev->prev->ebev) { - for (ring = 1; ring <= ns2; ring++) { - for (k = 1; k <= ns2; k++) { - if (ns % 2 == 0 && (k == ns2 || ring == ns2)) - continue; - create_mesh_bmvert(bm, vm, vprev->index, ring, k, bv->v); - } - } - } - if (!vnext->ebev) { - for (ring = 1; ring <= ns2; ring++) { - for (k = ns - ns2; k < ns; k++) { - if (ns % 2 == 0 && (k == ns2 || ring == ns2)) - continue; - create_mesh_bmvert(bm, vm, i, ring, k, bv->v); - } - } - } - } - } - } while ((v = v->next) != vm->boundstart); - - if (ns % 2 == 0) { - /* Do special case center lines. - * This loop makes verts for (i, ns2, k) for 1 <= k <= ns-1, k!=ns2 - * and for (i, r, ns2) for 1 <= r <= ns2-1, - * whenever i is in a sequence of at least two beveled verts */ - v = vm->boundstart; - do { - i = v->index; - if (v->ebev) { - vprev = v->prev; - vnext = v->next; - for (k = 1; k < ns2; k++) { - nv = mesh_vert(vm, i, k, ns2); - if (vprev->ebev) - nvprev = mesh_vert(vm, vprev->index, ns2, ns - k); - if (vnext->ebev) - nvnext = mesh_vert(vm, vnext->index, ns2, k); - if (vprev->ebev && vnext->ebev) { - mid_v3_v3v3v3(co, nvprev->co, nv->co, nvnext->co); -#ifndef USE_ALTERNATE_ADJ - copy_v3_v3(nv->co, co); -#endif - create_mesh_bmvert(bm, vm, i, k, ns2, bv->v); - copy_mesh_vert(vm, vprev->index, ns2, ns - k, i, k, ns2); - copy_mesh_vert(vm, vnext->index, ns2, k, i, k, ns2); - - } - else if (vprev->ebev) { - mid_v3_v3v3(co, nvprev->co, nv->co); -#ifndef USE_ALTERNATE_ADJ - copy_v3_v3(nv->co, co); -#endif - create_mesh_bmvert(bm, vm, i, k, ns2, bv->v); - copy_mesh_vert(vm, vprev->index, ns2, ns - k, i, k, ns2); - - create_mesh_bmvert(bm, vm, i, ns2, ns - k, bv->v); - } - else if (vnext->ebev) { - mid_v3_v3v3(co, nv->co, nvnext->co); -#ifndef USE_ALTERNATE_ADJ - copy_v3_v3(nv->co, co); -#endif - create_mesh_bmvert(bm, vm, i, k, ns2, bv->v); - copy_mesh_vert(vm, vnext->index, ns2, k, i, k, ns2); - - create_mesh_bmvert(bm, vm, i, ns2, k, bv->v); - } - } - } - } while ((v = v->next) != vm->boundstart); - - /* center point need to be average of all centers of rings */ - /* TODO: this is wrong if not all verts have ebev: could have - * several disconnected sections of mesh. */ - zero_v3(midco); - nn = 0; - v = vm->boundstart; - do { - i = v->index; - if (v->ebev) { - nv = mesh_vert(vm, i, ns2, ns2); - add_v3_v3(midco, nv->co); - nn++; - } - } while ((v = v->next) != vm->boundstart); - mul_v3_fl(midco, 1.0f / nn); - bmv = BM_vert_create(bm, midco, NULL); - v = vm->boundstart; - do { - i = v->index; - if (v->ebev) { - nv = mesh_vert(vm, i, ns2, ns2); - copy_v3_v3(nv->co, midco); - nv->v = bmv; - } - } while ((v = v->next) != vm->boundstart); - } - - /* Make the ring quads */ - for (ring = 0; ring < ns2; ring++) { - v = vm->boundstart; - do { - i = v->index; - f = boundvert_rep_face(v); - if (v->ebev && (v->prev->ebev || v->next->ebev)) { - for (k = 0; k < ns2 + (ns % 2); k++) { - bmv1 = mesh_vert(vm, i, ring, k)->v; - bmv2 = mesh_vert(vm, i, ring, k + 1)->v; - bmv3 = mesh_vert(vm, i, ring + 1, k + 1)->v; - bmv4 = mesh_vert(vm, i, ring + 1, k)->v; - BLI_assert(bmv1 && bmv2 && bmv3 && bmv4); - if (bmv3 == bmv4 || bmv1 == bmv4) - bmv4 = NULL; - bev_create_quad_tri(bm, bmv1, bmv2, bmv3, bmv4, f); - } - } - else if (v->prev->ebev && v->prev->prev->ebev) { - /* finish off a sequence of beveled edges */ - i = v->prev->index; - f = boundvert_rep_face(v->prev); - for (k = ns2 + (ns % 2); k < ns; k++) { - bmv1 = mesh_vert(vm, i, ring, k)->v; - bmv2 = mesh_vert(vm, i, ring, k + 1)->v; - bmv3 = mesh_vert(vm, i, ring + 1, k + 1)->v; - bmv4 = mesh_vert(vm, i, ring + 1, k)->v; - BLI_assert(bmv1 && bmv2 && bmv3 && bmv4); - if (bmv2 == bmv3) { - bmv3 = bmv4; - bmv4 = NULL; - } - bev_create_quad_tri(bm, bmv1, bmv2, bmv3, bmv4, f); - } - } - } while ((v = v->next) != vm->boundstart); - } - - /* Make center ngon if odd number of segments and fully beveled */ - if (ns % 2 == 1 && vm->count == bv->selcount) { - BMVert **vv = NULL; - BLI_array_declare(vv); - - v = vm->boundstart; - do { - i = v->index; - BLI_assert(v->ebev); - BLI_array_append(vv, mesh_vert(vm, i, ns2, ns2)->v); - } while ((v = v->next) != vm->boundstart); - f = boundvert_rep_face(vm->boundstart); - bev_create_ngon(bm, vv, BLI_array_count(vv), f); - - BLI_array_free(vv); - } - - /* Make 'rest-of-vmesh' polygon if not fully beveled */ - if (vm->count > bv->selcount) { - int j; - BMVert **vv = NULL; - BLI_array_declare(vv); - - v = vm->boundstart; - f = boundvert_rep_face(v); - j = 0; - do { - i = v->index; - if (v->ebev) { - if (!v->prev->ebev) { - for (k = 0; k < ns2; k++) { - bmv1 = mesh_vert(vm, i, ns2, k)->v; - if (!bmv1) - bmv1 = mesh_vert(vm, i, 0, k)->v; - if (!(j > 0 && bmv1 == vv[j - 1])) { - BLI_assert(bmv1 != NULL); - BLI_array_append(vv, bmv1); - j++; - } - } - } - bmv1 = mesh_vert(vm, i, ns2, ns2)->v; - if (!bmv1) - bmv1 = mesh_vert(vm, i, 0, ns2)->v; - if (!(j > 0 && bmv1 == vv[j - 1])) { - BLI_assert(bmv1 != NULL); - BLI_array_append(vv, bmv1); - j++; - } - if (!v->next->ebev) { - for (k = ns - ns2; k < ns; k++) { - bmv1 = mesh_vert(vm, i, ns2, k)->v; - if (!bmv1) - bmv1 = mesh_vert(vm, i, 0, k)->v; - if (!(j > 0 && bmv1 == vv[j - 1])) { - BLI_assert(bmv1 != NULL); - BLI_array_append(vv, bmv1); - j++; - } - } - } - } - else { - BLI_assert(mesh_vert(vm, i, 0, 0)->v != NULL); - BLI_array_append(vv, mesh_vert(vm, i, 0, 0)->v); - j++; - } - } while ((v = v->next) != vm->boundstart); - if (vv[0] == vv[j - 1]) - j--; - bev_create_ngon(bm, vv, j, f); - - BLI_array_free(vv); - } -} - -static BMFace *bevel_build_poly_ex(BMesh *bm, BevVert *bv) -{ - BMFace *f; - int n, k; - VMesh *vm = bv->vmesh; - BoundVert *v; - BMVert **vv = NULL; - BLI_array_declare(vv); - - v = vm->boundstart; - n = 0; - do { - /* accumulate vertices for vertex ngon */ - BLI_array_append(vv, v->nv.v); - n++; - if (v->ebev && v->ebev->seg > 1) { - for (k = 1; k < v->ebev->seg; k++) { - BLI_array_append(vv, mesh_vert(vm, v->index, 0, k)->v); - n++; - } - } - } while ((v = v->next) != vm->boundstart); - if (n > 2) { - f = bev_create_ngon(bm, vv, n, boundvert_rep_face(v)); - } - else { - f = NULL; - } - BLI_array_free(vv); - return f; -} - -static void bevel_build_poly(BMesh *bm, BevVert *bv) -{ - bevel_build_poly_ex(bm, bv); -} - -static void bevel_build_trifan(BMesh *bm, BevVert *bv) -{ - BMFace *f; - BLI_assert(next_bev(bv, NULL)->seg == 1 || bv->selcount == 1); - - f = bevel_build_poly_ex(bm, bv); - - if (f) { - /* we have a polygon which we know starts at the previous vertex, make it into a fan */ - BMLoop *l_fan = BM_FACE_FIRST_LOOP(f)->prev; - BMVert *v_fan = l_fan->v; - - while (f->len > 3) { - BMLoop *l_new; - BMFace *f_new; - BLI_assert(v_fan == l_fan->v); - f_new = BM_face_split(bm, f, l_fan->v, l_fan->next->next->v, &l_new, NULL, FALSE); - - if (f_new->len > f->len) { - f = f_new; - if (l_new->v == v_fan) { l_fan = l_new; } - else if (l_new->next->v == v_fan) { l_fan = l_new->next; } - else if (l_new->prev->v == v_fan) { l_fan = l_new->prev; } - else { BLI_assert(0); } - } - else { - if (l_fan->v == v_fan) { l_fan = l_fan; } - else if (l_fan->next->v == v_fan) { l_fan = l_fan->next; } - else if (l_fan->prev->v == v_fan) { l_fan = l_fan->prev; } - else { BLI_assert(0); } - } - } - } -} - -static void bevel_build_quadstrip(BMesh *bm, BevVert *bv) -{ - BMFace *f; - BLI_assert(bv->selcount == 2); - - f = bevel_build_poly_ex(bm, bv); - - if (f) { - /* we have a polygon which we know starts at this vertex, make it into strips */ - EdgeHalf *eh_a = bv->vmesh->boundstart->elast; - EdgeHalf *eh_b = next_bev(bv, eh_a->next); /* since (selcount == 2) we know this is valid */ - BMLoop *l_a = BM_face_vert_share_loop(f, eh_a->rightv->nv.v); - BMLoop *l_b = BM_face_vert_share_loop(f, eh_b->leftv->nv.v); - int seg_count = bv->vmesh->seg; /* ensure we don't walk past the segments */ - - if (l_a == l_b) { - /* step once around if we hit the same loop */ - l_a = l_a->prev; - l_b = l_b->next; - seg_count--; - } - - BLI_assert(l_a != l_b); - - while (f->len > 4) { - BMLoop *l_new; - BLI_assert(l_a->f == f); - BLI_assert(l_b->f == f); - - BM_face_split(bm, f, l_a->v, l_b->v, &l_new, NULL, FALSE); - if (seg_count-- == 0) { - break; - } - - /* turns out we don't need this, - * because of how BM_face_split works we always get the loop of the next face */ -#if 0 - if (l_new->f->len < l_new->radial_next->f->len) { - l_new = l_new->radial_next; - } -#endif - f = l_new->f; - - /* walk around the new face to get the next verts to split */ - l_a = l_new->prev; - l_b = l_new->next->next; - } - } -} - -/* Given that the boundary is built, now make the actual BMVerts - * for the boundary and the interior of the vertex mesh. */ -static void build_vmesh(MemArena *mem_arena, BMesh *bm, BevVert *bv) -{ - VMesh *vm = bv->vmesh; - BoundVert *v, *weld1, *weld2; - int n, ns, ns2, i, k, weld; - float *va, *vb, co[3]; - -#ifdef USE_ALTERNATE_ADJ - /* ordered as follows (orig, prev, center, next)*/ - float quad_plane[4][3]; - float quad_orig_a[4][3]; - float quad_orig_b[4][3]; - const int is_odd = (vm->seg % 2); -#else - float midco[3]; -#endif - -#ifdef USE_ALTERNATE_ADJ - /* the rest are initialized inline, this remains the same for all */ - /* NOTE; in this usage we only interpolate on the 'V' so cent and next points are unused (2,3)*/ - vmesh_cent(vm, quad_plane[2]); - copy_v3_v3(quad_orig_a[2], bv->v->co); - copy_v3_v3(quad_orig_b[2], bv->v->co); -#endif - - n = vm->count; - ns = vm->seg; - ns2 = ns / 2; - - vm->mesh = (NewVert *)BLI_memarena_alloc(mem_arena, n * (ns2 + 1) * (ns + 1) * sizeof(NewVert)); - - /* special case: two beveled ends welded together */ - weld = (bv->selcount == 2) && (vm->count == 2); - weld1 = weld2 = NULL; /* will hold two BoundVerts involved in weld */ - - /* make (i, 0, 0) mesh verts for all i */ - v = vm->boundstart; - do { - i = v->index; - copy_v3_v3(mesh_vert(vm, i, 0, 0)->co, v->nv.co); - create_mesh_bmvert(bm, vm, i, 0, 0, bv->v); - v->nv.v = mesh_vert(vm, i, 0, 0)->v; - if (weld && v->ebev) { - if (!weld1) - weld1 = v; - else - weld2 = v; - } - } while ((v = v->next) != vm->boundstart); - - /* copy other ends to (i, 0, ns) for all i, and fill in profiles for beveled edges */ - v = vm->boundstart; - do { - i = v->index; - copy_mesh_vert(vm, i, 0, ns, v->next->index, 0, 0); - if (v->ebev) { - -#ifdef USE_ALTERNATE_ADJ - copy_v3_v3(quad_plane[0], v->nv.co); - mid_v3_v3v3(quad_plane[1], v->nv.co, v->prev->nv.co); - /* quad[2] is set */ - mid_v3_v3v3(quad_plane[3], v->nv.co, v->next->nv.co); - - /* orig 'A' */ - copy_v3_v3(quad_orig_a[0], v->nv.co); /* only shared location between 2 quads */ - project_to_edge(v->ebev->prev->e, v->nv.co, v->prev->nv.co, quad_orig_a[1]); - project_to_edge(v->ebev->e, v->nv.co, v->next->nv.co, quad_orig_a[3]); - - /* orig 'B' */ - copy_v3_v3(quad_orig_b[3], v->next->nv.co); /* only shared location between 2 quads */ - project_to_edge(v->ebev->prev->e, v->nv.co, v->prev->nv.co, quad_orig_b[1]); - project_to_edge(v->ebev->e, v->nv.co, v->next->nv.co, quad_orig_b[0]); - - //bl_debug_draw_quad_add(UNPACK4(quad_plane)); - //bl_debug_draw_quad_add(UNPACK4(quad_orig_a)); - //bl_debug_draw_quad_add(UNPACK4(quad_orig_b)); -#endif /* USE_ALTERNATE_ADJ */ - -#ifdef USE_ALTERNATE_ADJ - for (k = 1; k < ns; k++) { - float uv[2]; - float fac; - float co_plane[3]; - float co_orig[3]; - - /* quad_plane */ - get_point_uv(uv, v->ebev->seg, 0, k); - get_point_on_round_edge(uv, quad_plane, co_plane); - - /* quad_orig */ - /* each half has different UV's */ - if (k <= ns2) { - get_point_uv(uv, v->ebev->seg, 0, k); - get_point_on_round_edge(uv, quad_orig_a, co_orig); - } - else { - get_point_uv(uv, v->ebev->seg, 0, (k - ns2) - (is_odd ? 0.5f : 0.0f)); - get_point_on_round_edge(uv, quad_orig_b, co_orig); - uv[1] = 1.0f - uv[1]; /* so we can get the factor */ - } - fac = get_point_uv_factor(uv); - - /* done. interp */ - interp_v3_v3v3(co, co_plane, co_orig, fac); - copy_v3_v3(mesh_vert(vm, i, 0, k)->co, co); - if (!weld) - create_mesh_bmvert(bm, vm, i, 0, k, bv->v); - } -#else /* USE_ALTERNATE_ADJ */ - va = mesh_vert(vm, i, 0, 0)->co; - vb = mesh_vert(vm, i, 0, ns)->co; - project_to_edge(v->ebev->e, va, vb, midco); - for (k = 1; k < ns; k++) { - get_point_on_round_edge(v->ebev, k, va, midco, vb, co); - copy_v3_v3(mesh_vert(vm, i, 0, k)->co, co); - if (!weld) - create_mesh_bmvert(bm, vm, i, 0, k, bv->v); - } -#endif /* !USE_ALTERNATE_ADJ */ - } - } while ((v = v->next) != vm->boundstart); - - if (weld) { - vm->mesh_kind = M_NONE; - for (k = 1; k < ns; k++) { - va = mesh_vert(vm, weld1->index, 0, k)->co; - vb = mesh_vert(vm, weld2->index, 0, ns - k)->co; - mid_v3_v3v3(co, va, vb); - copy_v3_v3(mesh_vert(vm, weld1->index, 0, k)->co, co); - create_mesh_bmvert(bm, vm, weld1->index, 0, k, bv->v); - } - for (k = 1; k < ns; k++) - copy_mesh_vert(vm, weld2->index, 0, ns - k, weld1->index, 0, k); - } - - switch (vm->mesh_kind) { - case M_NONE: - /* do nothing */ - break; - case M_POLY: - bevel_build_poly(bm, bv); - break; - case M_ADJ: - bevel_build_rings(bm, bv); - break; - case M_TRI_FAN: - bevel_build_trifan(bm, bv); - break; - case M_QUAD_STRIP: - bevel_build_quadstrip(bm, bv); - break; - } -} - -/* - * Construction around the vertex - */ -static void bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) -{ - BMEdge *bme; - BevVert *bv; - BMEdge *bme2, *unflagged_bme; - BMFace *f; - BMIter iter, iter2; - EdgeHalf *e; - int i, ntot, found_shared_face, ccw_test_sum; - int nsel = 0; - - /* Gather input selected edges. - * Only bevel selected edges that have exactly two incident faces. - */ - - BM_ITER_ELEM (bme, &iter, v, BM_EDGES_OF_VERT) { - if (BM_elem_flag_test(bme, BM_ELEM_TAG)) { - if (BM_edge_is_manifold(bme)) { - BMO_elem_flag_enable(bm, bme, EDGE_SELECTED); - nsel++; - } - } - } - - if (nsel == 0) - return; - - ntot = BM_vert_edge_count(v); - bv = (BevVert *)BLI_memarena_alloc(bp->mem_arena, (sizeof(BevVert))); - bv->v = v; - bv->edgecount = ntot; - bv->selcount = nsel; - bv->edges = (EdgeHalf *)BLI_memarena_alloc(bp->mem_arena, ntot * sizeof(EdgeHalf)); - bv->vmesh = (VMesh *)BLI_memarena_alloc(bp->mem_arena, sizeof(VMesh)); - bv->vmesh->seg = bp->seg; - BLI_ghash_insert(bp->vert_hash, v, bv); - - /* add edges to bv->edges in order that keeps adjacent edges sharing - * a face, if possible */ - i = 0; - bme = v->e; - BMO_elem_flag_enable(bm, bme, BEVEL_FLAG); - e = &bv->edges[0]; - e->e = bme; - for (i = 0; i < ntot; i++) { - if (i > 0) { - /* find an unflagged edge bme2 that shares a face f with previous bme */ - found_shared_face = 0; - unflagged_bme = NULL; - BM_ITER_ELEM (bme2, &iter, v, BM_EDGES_OF_VERT) { - if (BMO_elem_flag_test(bm, bme2, BEVEL_FLAG)) - continue; - if (!unflagged_bme) - unflagged_bme = bme2; - BM_ITER_ELEM (f, &iter2, bme2, BM_FACES_OF_EDGE) { - if (BM_face_edge_share_loop(f, bme)) { - found_shared_face = 1; - break; - } - } - if (found_shared_face) - break; - } - e = &bv->edges[i]; - if (found_shared_face) { - e->e = bme2; - e->fprev = f; - bv->edges[i - 1].fnext = f; - } - else { - e->e = unflagged_bme; - } - } - bme = e->e; - BMO_elem_flag_enable(bm, bme, BEVEL_FLAG); - if (BMO_elem_flag_test(bm, bme, EDGE_SELECTED)) { - e->is_bev = TRUE; - e->seg = bp->seg; - } - else { - e->is_bev = FALSE; - e->seg = 0; - } - e->is_rev = (bme->v2 == v); - e->offset = e->is_bev ? bp->offset : 0.0f; - } - /* find wrap-around shared face */ - BM_ITER_ELEM (f, &iter2, bme, BM_FACES_OF_EDGE) { - if (BM_face_edge_share_loop(f, bv->edges[0].e)) { - if (bv->edges[0].fnext == f) - continue; /* if two shared faces, want the other one now */ - bv->edges[ntot - 1].fnext = f; - bv->edges[0].fprev = f; - break; - } - } - - /* remove BEVEL_FLAG now that we are finished with it*/ - for (i = 0; i < ntot; i++) - BMO_elem_flag_disable(bm, bv->edges[i].e, BEVEL_FLAG); - - /* if edge array doesn't go CCW around vertex from average normal side, - * reverse the array, being careful to reverse face pointers too */ - if (ntot > 1) { - ccw_test_sum = 0; - for (i = 0; i < ntot; i++) - ccw_test_sum += bev_ccw_test(bv->edges[i].e, bv->edges[(i + 1) % ntot].e, - bv->edges[i].fnext); - if (ccw_test_sum < 0) { - for (i = 0; i <= (ntot / 2) - 1; i++) { - SWAP(EdgeHalf, bv->edges[i], bv->edges[ntot - i - 1]); - SWAP(BMFace *, bv->edges[i].fprev, bv->edges[i].fnext); - SWAP(BMFace *, bv->edges[ntot - i - 1].fprev, bv->edges[ntot - i - 1].fnext); - } - if (ntot % 2 == 1) { - i = ntot / 2; - SWAP(BMFace *, bv->edges[i].fprev, bv->edges[i].fnext); - } - } - } - - for (i = 0; i < ntot; i++) { - e = &bv->edges[i]; - e->next = &bv->edges[(i + 1) % ntot]; - e->prev = &bv->edges[(i + ntot - 1) % ntot]; - } - - build_boundary(bp->mem_arena, bv); - build_vmesh(bp->mem_arena, bm, bv); -} - -/* Face f has at least one beveled vertex. Rebuild f */ -static void rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f) -{ - BMIter liter; - BMLoop *l, *lprev; - BevVert *bv; - BoundVert *v, *vstart, *vend; - EdgeHalf *e, *eprev; - VMesh *vm; - int i, k; - BMVert *bmv; - BMVert **vv = NULL; - BLI_array_declare(vv); - - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - bv = find_bevvert(bp, l->v); - if (bv) { - lprev = l->prev; - e = find_edge_half(bv, l->e); - eprev = find_edge_half(bv, lprev->e); - BLI_assert(e != NULL && eprev != NULL); - vstart = eprev->leftv; - if (e->is_bev) - vend = e->rightv; - else - vend = e->leftv; - v = vstart; - vm = bv->vmesh; - BLI_array_append(vv, v->nv.v); - while (v != vend) { - if (vm->mesh_kind == M_NONE && v->ebev && v->ebev->seg > 1 && v->ebev != e && v->ebev != eprev) { - /* case of 3rd face opposite a beveled edge, with no vmesh */ - i = v->index; - e = v->ebev; - for (k = 1; k < e->seg; k++) { - bmv = mesh_vert(vm, i, 0, k)->v; - BLI_array_append(vv, bmv); - } - } - v = v->prev; - BLI_array_append(vv, v->nv.v); - } - } - else { - BLI_array_append(vv, l->v); - } - } - bev_create_ngon(bm, vv, BLI_array_count(vv), f); - BLI_array_free(vv); -} - -/* All polygons touching v need rebuilding because beveling v has made new vertices */ -static void bevel_rebuild_existing_polygons(BMesh *bm, BevelParams *bp, BMVert *v) -{ - void *faces_stack[BM_DEFAULT_ITER_STACK_SIZE]; - int faces_len, f_index; - BMFace **faces = BM_iter_as_arrayN(bm, BM_FACES_OF_VERT, v, &faces_len, - faces_stack, BM_DEFAULT_ITER_STACK_SIZE); - - if (LIKELY(faces != NULL)) { - for (f_index = 0; f_index < faces_len; f_index++) { - BMFace *f = faces[f_index]; - rebuild_polygon(bm, bp, f); - BM_face_kill(bm, f); - } - - if (faces != (BMFace **)faces_stack) { - MEM_freeN(faces); - } - } -} - - - -/* - * Build the polygons along the selected Edge - */ -static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme) -{ - BevVert *bv1, *bv2; - BMVert *bmv1, *bmv2, *bmv3, *bmv4, *bmv1i, *bmv2i, *bmv3i, *bmv4i; - VMesh *vm1, *vm2; - EdgeHalf *e1, *e2; - BMFace *f1, *f2, *f; - int k, nseg, i1, i2; - - if (!BM_edge_is_manifold(bme)) - return; - - bv1 = find_bevvert(bp, bme->v1); - bv2 = find_bevvert(bp, bme->v2); - - BLI_assert(bv1 && bv2); - - e1 = find_edge_half(bv1, bme); - e2 = find_edge_half(bv2, bme); - - BLI_assert(e1 && e2); - - /* v4 v3 - * \ / - * e->v1 - e->v2 - * / \ - * v1 v2 - */ - nseg = e1->seg; - BLI_assert(nseg > 0 && nseg == e2->seg); - - bmv1 = e1->leftv->nv.v; - bmv4 = e1->rightv->nv.v; - bmv2 = e2->rightv->nv.v; - bmv3 = e2->leftv->nv.v; - - BLI_assert(bmv1 && bmv2 && bmv3 && bmv4); - - f1 = boundvert_rep_face(e1->leftv); - f2 = boundvert_rep_face(e1->rightv); - - if (nseg == 1) { - bev_create_quad_tri(bm, bmv1, bmv2, bmv3, bmv4, f1); - } - else { - i1 = e1->leftv->index; - i2 = e2->leftv->index; - vm1 = bv1->vmesh; - vm2 = bv2->vmesh; - bmv1i = bmv1; - bmv2i = bmv2; - for (k = 1; k <= nseg; k++) { - bmv4i = mesh_vert(vm1, i1, 0, k)->v; - bmv3i = mesh_vert(vm2, i2, 0, nseg - k)->v; - f = (k <= nseg / 2 + (nseg % 2)) ? f1 : f2; - bev_create_quad_tri(bm, bmv1i, bmv2i, bmv3i, bmv4i, f); - bmv1i = bmv4i; - bmv2i = bmv3i; - } - } -} - -void bmo_bevel_exec(BMesh *bm, BMOperator *op) -{ - BMIter iter; - BMOIter siter; - BMVert *v; - BMEdge *e; - BevelParams bp = {NULL}; - - bp.offset = BMO_slot_float_get(op, "offset"); - bp.seg = BMO_slot_int_get(op, "segments"); - - if (bp.offset > 0) { - /* primary alloc */ - bp.vert_hash = BLI_ghash_ptr_new(__func__); - bp.mem_arena = BLI_memarena_new((1 << 16), __func__); - BLI_memarena_use_calloc(bp.mem_arena); - - /* first flush 'geom' into flags, this makes it possible to check connected data */ - BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE, BM_ELEM_TAG, FALSE); - - BMO_ITER (v, &siter, bm, op, "geom", BM_VERT | BM_EDGE) { - BM_elem_flag_enable(v, BM_ELEM_TAG); - } - - /* The analysis of the input vertices and execution additional constructions */ - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_TAG)) { - bevel_vert_construct(bm, &bp, v); - } - } - - /* Build polygons for edges */ - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_TAG)) { - bevel_build_edge_polygons(bm, &bp, e); - } - } - - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_TAG)) { - bevel_rebuild_existing_polygons(bm, &bp, v); - } - } - - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_TAG)) { - if (find_bevvert(&bp, v)) { - BM_vert_kill(bm, v); - } - } - } - - /* primary free */ - BLI_ghash_free(bp.vert_hash, NULL, NULL); - BLI_memarena_free(bp.mem_arena); - } -} -- cgit v1.2.3 From 4401ac8c9e312a81bf1a750f0a7068e24174a7fd Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 18 Nov 2012 08:35:27 +0000 Subject: finish moving bevel code out of the operator dir (it works again) --- source/blender/bmesh/operators/bmo_bevel.c | 51 ++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 source/blender/bmesh/operators/bmo_bevel.c (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c new file mode 100644 index 00000000000..9de15fb9c9c --- /dev/null +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -0,0 +1,51 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/bmesh/operators/bmesh_bevel.c + * \ingroup bmesh + */ + +#include "BLI_utildefines.h" + +#include "bmesh.h" + +#include "intern/bmesh_operators_private.h" /* own include */ + +void bmo_bevel_exec(BMesh *bm, BMOperator *op) +{ + BMOIter siter; + BMVert *v; + + const float offset = BMO_slot_float_get(op, "offset"); + const int seg = BMO_slot_int_get(op, "segments"); + + if (offset > 0) { + /* first flush 'geom' into flags, this makes it possible to check connected data */ + BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE, BM_ELEM_TAG, FALSE); + + BMO_ITER (v, &siter, bm, op, "geom", BM_VERT | BM_EDGE) { + BM_elem_flag_enable(v, BM_ELEM_TAG); + } + + BM_mesh_bevel(bm, offset, seg); + } +} -- cgit v1.2.3 From fd9dac77d1d6de6ae6eea3ccc19099decfae665f Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 18 Nov 2012 09:33:11 +0000 Subject: bevel now only takes manifold edges (so it doesnt need to check for them) --- source/blender/bmesh/operators/bmo_bevel.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 9de15fb9c9c..049b923315b 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -32,20 +32,27 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) { - BMOIter siter; - BMVert *v; - const float offset = BMO_slot_float_get(op, "offset"); const int seg = BMO_slot_int_get(op, "segments"); if (offset > 0) { + BMOIter siter; + BMEdge *e; + BMVert *v; + /* first flush 'geom' into flags, this makes it possible to check connected data */ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE, BM_ELEM_TAG, FALSE); - BMO_ITER (v, &siter, bm, op, "geom", BM_VERT | BM_EDGE) { + BMO_ITER (v, &siter, bm, op, "geom", BM_VERT) { BM_elem_flag_enable(v, BM_ELEM_TAG); } + BMO_ITER (e, &siter, bm, op, "geom", BM_EDGE) { + if (BM_edge_is_manifold(e)) { + BM_elem_flag_enable(e, BM_ELEM_TAG); + } + } + BM_mesh_bevel(bm, offset, seg); } } -- cgit v1.2.3 From cdc4037f0dbdc73016420504a3c6c0f6de78d3a3 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 19 Nov 2012 00:54:55 +0000 Subject: bmesh: BM_verts_in_face was using bmesh operator flag which is no longer ensured to be available, use internal apiflag instead, Thanks to Nicholas Bishop for spotting. also quiet some warnings. --- source/blender/bmesh/operators/bmo_bevel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 049b923315b..1e95191bc73 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -20,7 +20,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/bmesh/operators/bmesh_bevel.c +/** \file blender/bmesh/operators/bmo_bevel.c * \ingroup bmesh */ -- cgit v1.2.3 From 185cf6095e50eb4b3c27ad07dc31367da9d486f0 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 19 Nov 2012 02:26:59 +0000 Subject: improvements to bevel - the resulting selection is now correct internal details - bev_rebuild_polygon() now only rebuilds polygons that are attached to a bevel vertex (was rebuilding ALL). ... need to take care we don't leave faces pointing to removed geometry, so far this works fine. - bev_rebuild_polygon() uses stack memory for <32 size ngons to reduce allocs. - skip hash lookup when removing bevel verts (use tag instead). --- source/blender/bmesh/operators/bmo_bevel.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 1e95191bc73..a8c859b2ebf 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -40,8 +40,9 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) BMEdge *e; BMVert *v; - /* first flush 'geom' into flags, this makes it possible to check connected data */ - BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE, BM_ELEM_TAG, FALSE); + /* first flush 'geom' into flags, this makes it possible to check connected data, + * BM_FACE is cleared so we can put newly created faces into a bmesh slot. */ + BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, FALSE); BMO_ITER (v, &siter, bm, op, "geom", BM_VERT) { BM_elem_flag_enable(v, BM_ELEM_TAG); @@ -54,5 +55,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) } BM_mesh_bevel(bm, offset, seg); + + BMO_slot_buffer_from_enabled_hflag(bm, op, "faceout", BM_FACE, BM_ELEM_TAG); } } -- cgit v1.2.3 From 48639af5f89e08e81cd68fce0a7138007d4ebe1d Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 19 Nov 2012 14:58:31 +0000 Subject: use input and output slots for bmesh operators, needed for the python api to get return values. --- source/blender/bmesh/operators/bmo_bevel.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index a8c859b2ebf..f36856cece4 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -32,8 +32,8 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) { - const float offset = BMO_slot_float_get(op, "offset"); - const int seg = BMO_slot_int_get(op, "segments"); + const float offset = BMO_slot_float_get(op->slots_in, "offset"); + const int seg = BMO_slot_int_get(op->slots_in, "segments"); if (offset > 0) { BMOIter siter; @@ -44,11 +44,11 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) * BM_FACE is cleared so we can put newly created faces into a bmesh slot. */ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, FALSE); - BMO_ITER (v, &siter, bm, op, "geom", BM_VERT) { + BMO_ITER (v, &siter, op->slots_in, "geom", BM_VERT) { BM_elem_flag_enable(v, BM_ELEM_TAG); } - BMO_ITER (e, &siter, bm, op, "geom", BM_EDGE) { + BMO_ITER (e, &siter, op->slots_in, "geom", BM_EDGE) { if (BM_edge_is_manifold(e)) { BM_elem_flag_enable(e, BM_ELEM_TAG); } @@ -56,6 +56,6 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) BM_mesh_bevel(bm, offset, seg); - BMO_slot_buffer_from_enabled_hflag(bm, op, "faceout", BM_FACE, BM_ELEM_TAG); + BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faceout", BM_FACE, BM_ELEM_TAG); } } -- cgit v1.2.3 From dbdc76c9d01d9f84cf315555ddabd5cba43932d3 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 20 Nov 2012 05:50:19 +0000 Subject: code cleanup: make bmesh operator names more consistant since python has access to these as input arguments and return values. all output values currently have ".out" suffix, this may go in the future, but for now it makes it clear in C code what are inputs and outputs. --- source/blender/bmesh/operators/bmo_bevel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender/bmesh/operators/bmo_bevel.c') diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index f36856cece4..126d0f46119 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -56,6 +56,6 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) BM_mesh_bevel(bm, offset, seg); - BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faceout", BM_FACE, BM_ELEM_TAG); + BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG); } } -- cgit v1.2.3