This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/bmesh/operators/bmo_bevel.c
Campbell Barton 90d215535e add option so operators can be called with a flag, currently the only flag is to respect hidden geometry.
this is useful for bmesh tools that operate in object mode or for modifiers which would previously use hidden faces in some cases.
2012-07-21 00:58:02 +00:00

889 lines
23 KiB
C

/*
* ***** 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.
*
* ***** 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_smallhash.h"
#include "BKE_customdata.h"
#include "bmesh.h"
#include "intern/bmesh_operators_private.h" /* own include */
#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 = minf(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_face_count(e) == 0) {
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 (!f) {
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 (!f) {
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 (!f) {
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);
}