Sculpt: fix collapse for non-manifold edges

* BM_edge_collapse now has an option to use
  a new collapse implementation that can
  handle non-manifold geometry properly.
* The aforementioned implementation is a replacement
  for bmesh_kernel_join_vert_kill_edge.  Note that
  the old code still exists as
  bmesh_kernel_join_vert_kill_edge_fast and is used
  by default.
This commit is contained in:
Joseph Eagar 2021-10-12 00:34:17 -07:00
parent e2755640c1
commit 73eb2b426a
14 changed files with 326 additions and 204 deletions

View File

@ -1450,12 +1450,12 @@ void BKE_brush_commandset_inherit_all_mappings(BrushChannelSet *chset)
}
}
ATTR_NO_OPT static void commandlist_add_dyntopo(BrushChannelSet *chset,
BrushCommandList *cl,
Brush *brush,
int tool,
bool hard_edge_mode,
float radius_base)
static void commandlist_add_dyntopo(BrushChannelSet *chset,
BrushCommandList *cl,
Brush *brush,
int tool,
bool hard_edge_mode,
float radius_base)
{
if (!BKE_brush_channelset_get_int(chset, "dyntopo_disabled", NULL)) {

View File

@ -670,8 +670,6 @@ BLI_INLINE void surface_smooth_v_safe(PBVH *pbvh, BMVert *v, float fac)
atomic_cas_float(&mv1->origco[1], y, ny);
atomic_cas_float(&mv1->origco[2], z, nz);
volatile int stroke_id = mv1->stroke_id;
// atomic_cas_int32(&mv1->stroke_id, stroke_id, pbvh->stroke_id);
}
@ -1265,9 +1263,9 @@ void BKE_pbvh_bmesh_remove_face(PBVH *pbvh, BMFace *f, bool log_face)
pbvh_bmesh_face_remove(pbvh, f, log_face, true, true);
}
void BKE_pbvh_bmesh_remove_edge(PBVH *pbvh, BMEdge *e, bool log_vert)
void BKE_pbvh_bmesh_remove_edge(PBVH *pbvh, BMEdge *e, bool log_edge)
{
if (log_vert) {
if (log_edge) {
BM_log_edge_removed(pbvh->bm_log, e);
}
}
@ -1423,7 +1421,7 @@ static void edge_queue_insert_val34_vert(EdgeQueueContext *eq_ctx, BMVert *v)
eq_ctx->val34_verts[eq_ctx->val34_verts_tot - 1] = v;
}
ATTR_NO_OPT static float maskcb_get(EdgeQueueContext *eq_ctx, BMEdge *e)
static float maskcb_get(EdgeQueueContext *eq_ctx, BMEdge *e)
{
float ret = 0.0f;
@ -1443,7 +1441,7 @@ ATTR_NO_OPT static float maskcb_get(EdgeQueueContext *eq_ctx, BMEdge *e)
return ret;
}
ATTR_NO_OPT static float calc_weighted_edge_split(EdgeQueueContext *eq_ctx, BMVert *v1, BMVert *v2)
static float calc_weighted_edge_split(EdgeQueueContext *eq_ctx, BMVert *v1, BMVert *v2)
{
#ifdef FANCY_EDGE_WEIGHTS
float l = len_squared_v3v3(v1->co, v2->co);
@ -2099,7 +2097,7 @@ BLI_INLINE int dyntopo_thread_rand(int seed)
// glibc
const uint32_t multiplier = 1103515245;
const uint32_t addend = 12345;
const uint32_t mask = (1 << 31) - 1;
const uint32_t mask = (1 << 30) - 1;
return (seed * multiplier + addend) & mask;
}
@ -2119,7 +2117,6 @@ static void long_edge_queue_task_cb(void *__restrict userdata,
BMFace *f, **faces = NULL;
BLI_array_declare(faces);
const int cd_sculpt_vert = tdata->pbvh->cd_sculpt_vert;
bool do_smooth = eq_ctx->surface_smooth_fac > 0.0f;
BKE_pbvh_bmesh_check_tris(tdata->pbvh, node);
@ -2334,8 +2331,6 @@ static void short_edge_queue_task_cb_local(void *__restrict userdata,
static bool check_face_is_tri(PBVH *pbvh, BMFace *f)
{
bool origlen = f->len;
if (f->len == 3) {
return true;
}
@ -2456,6 +2451,8 @@ static bool check_face_is_tri(PBVH *pbvh, BMFace *f)
static bool destroy_nonmanifold_fins(PBVH *pbvh, BMEdge *e_root)
{
// return false;
static int max_faces = 64;
BMFace **stack = NULL;
BLI_array_staticdeclare(stack, 32);
@ -2639,6 +2636,10 @@ static bool check_for_fins(PBVH *pbvh, BMVert *v)
}
do {
if (!e) {
printf("%s: e was NULL\n", __func__);
break;
}
if (e->l) {
BMLoop *l = e->l->f->l_first;
@ -3046,10 +3047,6 @@ static void edge_queue_create_local(EdgeQueueContext *eq_ctx,
pbvh->bm->elem_index_dirty |= BM_EDGE;
float sign = is_collapse ? 1.0f : -1.0f;
const float detail_range = pbvh->bm_min_edge_len == 0.0f ?
0.0f :
pbvh->bm_max_edge_len / pbvh->bm_min_edge_len;
for (int i = 0; i < BLI_array_len(edges); i++) {
BMEdge *e = edges[i];
MSculptVert *mv1, *mv2;
@ -3279,7 +3276,8 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
MV_ADD_FLAG(mv1, SCULPTVERT_NEED_VALENCE | SCULPTVERT_NEED_BOUNDARY | SCULPTVERT_NEED_DISK_SORT);
MV_ADD_FLAG(mv2, SCULPTVERT_NEED_VALENCE | SCULPTVERT_NEED_BOUNDARY | SCULPTVERT_NEED_DISK_SORT);
bool boundary = (mv1->flag & SCULPTVERT_ALL_BOUNDARY) && (mv2->flag & SCULPTVERT_ALL_BOUNDARY);
// bool boundary = (mv1->flag & SCULPTVERT_ALL_BOUNDARY) && (mv2->flag &
// SCULPTVERT_ALL_BOUNDARY);
/* Get all faces adjacent to the edge */
pbvh_bmesh_edge_loops(edge_loops, e);
@ -3738,10 +3736,6 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
return;
}
if (bm_edge_collapse_is_degenerate_topology(e)) {
// return;
}
pbvh_check_vert_boundary(pbvh, v1);
pbvh_check_vert_boundary(pbvh, v2);
@ -3800,127 +3794,9 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
bool snap = !(mv2->flag & SCULPTVERT_ALL_CORNER);
#if 0
// don't allow non-manifold case of
// there being 3-valence verts
// in neighborhood around edge
bool bad = false;
for (int i = 0; i < 2; i++) {
BMVert *v = i ? v_conn : v_del;
BMEdge *e2 = v->e;
do {
BMVert *v2 = v == e2->v1 ? e2->v2 : e2->v1;
int val = BM_vert_edge_count(v);
if (val < 4) {
bad = true;
break;
}
} while ((e2 = BM_DISK_EDGE_NEXT(e2, v)) != v->e);
if (bad) {
break;
}
}
if (bad) {
return; // bad edge
}
#endif
#if 0
// remove all faces from pbvh
for (int i = 0; i < 2; i++) {
BMVert *v = i ? v_conn : v_del;
BMEdge *e = v->e;
do {
BMLoop *l = e->l;
if (!l) {
continue;
}
do {
if (BM_ELEM_CD_GET_INT(l->f, pbvh->cd_face_node_offset) != DYNTOPO_NODE_NONE) {
pbvh_bmesh_face_remove(pbvh, l->f, true, false, false);
}
} while ((l = l->radial_next) != e->l);
} while ((e = BM_DISK_EDGE_NEXT(e, v)) != v->e);
}
// repeatedly dissolve 3-valence verts
while (1) {
bool bad = false;
for (int i = 0; i < 2; i++) {
BMVert *v = i ? v_conn : v_del;
BMEdge *e2 = v->e;
if (!e2) {
continue;
}
BMEdge *enext;
do {
BMVert *v2 = BM_edge_other_vert(e2, v);
enext = BM_DISK_EDGE_NEXT(e2, v);
if (v2 == v_conn || v2 == v_del) {
continue;
}
if (BM_vert_edge_count(v2) < 4) {
BMEdge *e3 = v2->e;
do {
BMLoop *l = e3->l;
if (e3 == e) {
e = NULL;
}
if (!l) {
continue;
}
do {
if (BM_ELEM_CD_GET_INT(l->f, pbvh->cd_face_node_offset) != DYNTOPO_NODE_NONE) {
pbvh_bmesh_face_remove(pbvh, l->f, true, false, false);
}
} while ((l = l->radial_next) != e3->l);
BM_log_edge_removed(pbvh->bm_log, e3);
} while ((e3 = BM_DISK_EDGE_NEXT(e3, v2)) != v2->e);
pbvh_bmesh_vert_remove(pbvh, v2);
BM_log_vert_removed(pbvh->bm_log, v2, pbvh->cd_vert_mask_offset);
BLI_ghash_insert(deleted_verts, v, NULL);
BM_vert_dissolve(pbvh->bm, v);
bad = true;
break;
}
} while ((e2 = enext) != v->e);
}
if (!bad) {
break;
}
}
if (!e || bm_elem_is_free((BMElem *)v_conn, BM_VERT) ||
bm_elem_is_free((BMElem *)v_del, BM_VERT)) {
return;
}
#endif
BMLoop *l;
// snap customdata
/* snap customdata */
if (snap) {
int ni_conn = BM_ELEM_CD_GET_INT(v_conn, pbvh->cd_vert_node_offset);
@ -3933,9 +3809,6 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
// deal with UVs
if (e->l) {
const int lflag = BM_ELEM_TAG_ALT;
int totl = 0;
BMLoop *l = e->l;
for (int step = 0; step < 2; step++) {
@ -3954,7 +3827,6 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
}
do {
bool ok = true;
BMLoop *l3 = l2->v != v ? l2->next : l2;
/* store visit bits for each uv layer in l3->head.index */
@ -3963,8 +3835,6 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
} while ((e2 = BM_DISK_EDGE_NEXT(e2, v)) != v->e);
}
float(*uv)[2] = alloca(sizeof(float) * 4 * totuv);
do {
const void *ls2[2] = {l->head.data, l->next->head.data};
float ws2[2] = {0.5f, 0.5f};
@ -4127,7 +3997,10 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
float co[3];
copy_v3_v3(co, v_conn->co);
BM_edge_collapse(pbvh->bm, e, v_del, true, true, true);
// full non-manifold collapse
BM_edge_collapse(pbvh->bm, e, v_del, true, true, true, true);
// non_manifold_collapse(pbvh->bm, e, v_conn);
copy_v3_v3(v_conn->co, co);
}
else {
@ -4136,7 +4009,9 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
add_v3_v3v3(co, v_del->co, v_conn->co);
mul_v3_fl(co, 0.5f);
BM_edge_collapse(pbvh->bm, e, v_del, true, true, true);
// full non-manifold collapse
BM_edge_collapse(pbvh->bm, e, v_del, true, true, true, true);
// non_manifold_collapse(pbvh->bm, e, v_conn);
copy_v3_v3(v_conn->co, co);
}
@ -4344,12 +4219,8 @@ static void pbvh_bmesh_collapse_edge1(PBVH *pbvh,
while ((l_adj = e->l)) {
BMFace *f_adj = l_adj->f;
int eflag = 0;
BMLoop *l = f_adj->l_first;
do {
BMEdge *e2 = l->e;
MSculptVert *mv_l = BKE_PBVH_SCULPTVERT(pbvh->cd_sculpt_vert, l->v);
MV_ADD_FLAG(mv_l, mupdateflag);
@ -4417,7 +4288,9 @@ static void pbvh_bmesh_collapse_edge1(PBVH *pbvh,
BLI_array_append(ws, w);
}
// snap customdata
/* snap customdata
TODO: use bm_edge_collapse_loop_customdata
*/
if (totl > 0) {
CustomData_bmesh_interp(
&pbvh->bm->ldata, (const void **)blocks, ws, NULL, totl, ls[0]->head.data);
@ -4471,7 +4344,7 @@ static void pbvh_bmesh_collapse_edge1(PBVH *pbvh,
BLI_buffer_append(deleted_faces, BMFace *, f);
}
else {
printf("tried to add same face to deleted list twice. %x %d\n", f, f->len);
printf("tried to add same face to deleted list twice. %p %d\n", f, f->len);
continue;
}
@ -4610,7 +4483,9 @@ static void pbvh_bmesh_collapse_edge1(PBVH *pbvh,
/* Delete the tagged faces */
for (int i = 0; i < (int)deleted_faces->count; i++) {
v_conn ? validate_vert_faces(pbvh, pbvh->bm, v_conn, false, false) : NULL;
if (v_conn) {
validate_vert_faces(pbvh, pbvh->bm, v_conn, false, false);
}
BMFace *f_del = BLI_buffer_at(deleted_faces, BMFace *, i);
@ -4645,9 +4520,16 @@ static void pbvh_bmesh_collapse_edge1(PBVH *pbvh,
/* Remove the face */
pbvh_bmesh_face_remove(pbvh, f_del, true, true, true);
v_conn ? validate_vert_faces(pbvh, pbvh->bm, v_conn, false, false) : NULL;
if (v_conn) {
validate_vert_faces(pbvh, pbvh->bm, v_conn, false, false);
}
BM_face_kill(pbvh->bm, f_del);
v_conn ? validate_vert_faces(pbvh, pbvh->bm, v_conn, false, false) : NULL;
if (v_conn) {
validate_vert_faces(pbvh, pbvh->bm, v_conn, false, false);
}
/* Check if any of the face's edges are now unused by any
* face, if so delete them */
@ -4792,7 +4674,6 @@ static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx,
return false;
}
const float min_len_squared = pbvh->bm_min_edge_len * pbvh->bm_min_edge_len;
bool any_collapsed = false;
/* deleted verts point to vertices they were merged into, or NULL when removed. */
GHash *deleted_verts = BLI_ghash_ptr_new("deleted_verts");
@ -5391,12 +5272,12 @@ static void on_vert_swap(BMVert *v1, BMVert *v2, void *userdata)
int updateflag = PBVH_UpdateOtherVerts;
if (node1 && node1->bm_unique_verts) {
node1->flag |= PBVH_UpdateOtherVerts;
node1->flag |= updateflag;
pbvh_node_tribuf_swap_verts(pbvh, node1, node2, v1, v2);
}
if (node2 && node2->bm_unique_verts && node2 != node1) {
node2->flag |= PBVH_UpdateOtherVerts;
node2->flag |= updateflag;
pbvh_node_tribuf_swap_verts(pbvh, node2, node1, v2, v1);
}
@ -5597,8 +5478,6 @@ typedef struct EdgeQueueContext {
.local_mode = false,
.surface_smooth_fac = safe_smooth};
int tempflag = 1 << 15;
#if 1
// if no collapse, run cleanup here to avoid degenerate geometry

View File

@ -619,7 +619,7 @@ struct Mesh *BKE_mesh_remesh_voxel_fix_poles(const Mesh *mesh)
if (BM_elem_flag_test(ed, BM_ELEM_TAG)) {
float co[3];
mid_v3_v3v3(co, ed->v1->co, ed->v2->co);
BMVert *vc = BM_edge_collapse(bm, ed, ed->v1, true, true, false);
BMVert *vc = BM_edge_collapse(bm, ed, ed->v1, true, true, false, false);
copy_v3_v3(vc->co, co);
}
}

View File

@ -1493,13 +1493,13 @@ static int color_boundary_key(float col[4])
}
#endif
ATTR_NO_OPT void bke_pbvh_update_vert_boundary(int cd_sculpt_vert,
int cd_faceset_offset,
int cd_vert_node_offset,
int cd_face_node_offset,
int cd_vcol,
BMVert *v,
int bound_symmetry)
void bke_pbvh_update_vert_boundary(int cd_sculpt_vert,
int cd_faceset_offset,
int cd_vert_node_offset,
int cd_face_node_offset,
int cd_vcol,
BMVert *v,
int bound_symmetry)
{
MSculptVert *mv = BKE_PBVH_SCULPTVERT(cd_sculpt_vert, v);

View File

@ -2133,6 +2133,23 @@ BMEdge *bmesh_kernel_join_edge_kill_vert(BMesh *bm,
return NULL;
}
static void check_vert_faces(BMVert *v_target)
{
BMEdge *e = v_target->e;
if (e) {
do {
BM_CHECK_ELEMENT(e);
if (e->l) {
BMLoop *l = e->l;
do {
BM_CHECK_ELEMENT(l->f);
} while ((l = l->radial_next) != e->l);
}
} while ((e = BM_DISK_EDGE_NEXT(e, v_target)) != v_target->e);
}
}
/**
* \brief Join Vert Kill Edge (JVKE)
*
@ -2151,13 +2168,227 @@ BMEdge *bmesh_kernel_join_edge_kill_vert(BMesh *bm,
* +-+-+-+ +-+-+-+
* </pre>
*/
BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
const bool do_del,
const bool check_edge_exists,
const bool kill_degenerate_faces,
const bool combine_flags)
BMVert *bmesh_kernel_join_vert_kill_edge(
BMesh *bm, BMEdge *e, BMVert *v_kill, const bool do_del, const bool combine_flags)
{
BMVert *v_conn = BM_edge_other_vert(e, v_kill);
BMFace **fs = NULL;
BMEdge **deles = NULL;
BLI_array_staticdeclare(fs, 32);
BLI_array_staticdeclare(deles, 32);
BMVert *v_del = BM_edge_other_vert(e, v_conn);
const int tag = _FLAG_WALK_ALT; // using bmhead.api_flag here
/* first clear tags */
for (int i = 0; i < 2; i++) {
BMVert *v = i ? v_del : v_conn;
BMEdge *e2 = v->e;
do {
if (!e2->l) {
continue;
}
BMLoop *l = e2->l;
do {
BM_ELEM_API_FLAG_DISABLE(l->f, tag);
} while ((l = l->radial_next) != e2->l);
} while ((e2 = BM_DISK_EDGE_NEXT(e2, v)) != v->e);
}
/* now build face list */
for (int i = 0; i < 2; i++) {
BMVert *v = i ? v_del : v_conn;
BMEdge *e2 = v->e;
if (!e2 || !e2->l) {
continue;
}
do {
BMLoop *l = e2->l;
do {
if (!BM_ELEM_API_FLAG_TEST(l->f, tag)) {
BM_ELEM_API_FLAG_ENABLE(l->f, tag);
BMLoop *l2 = l;
do {
BM_ELEM_API_FLAG_DISABLE(l2->e, tag);
} while ((l2 = l2->next) != l);
BLI_array_append(fs, l->f);
}
} while ((l = l->radial_next) != e2->l);
} while ((e2 = BM_DISK_EDGE_NEXT(e2, v)) != v->e);
}
/* unlink loops */
for (int i = 0; i < BLI_array_len(fs); i++) {
BMFace *f = fs[i];
BMLoop *l = f->l_first;
do {
BMEdge *e2 = l->e;
l->radial_next->radial_prev = l->radial_prev;
l->radial_prev->radial_next = l->radial_next;
if (l == e2->l) {
e2->l = l->radial_next;
}
if (l == e2->l) {
e2->l = NULL;
}
} while ((l = l->next) != f->l_first);
}
/* swap verts */
for (int i = 0; i < BLI_array_len(fs); i++) {
BMFace *f = fs[i];
BMLoop *l = f->l_first, *lnext = NULL;
do {
lnext = l->next;
if (l->v == v_del) {
l->v = v_conn;
}
BM_ELEM_API_FLAG_DISABLE(l->v, tag);
for (int step = 0; step < 2; step++) {
BMVert *v_edge = step ? l->e->v2 : l->e->v1;
BMVert *v_other = BM_edge_other_vert(l->e, v_edge);
if (v_edge != v_del) {
continue;
}
if (v_other == v_conn) {
/* flag for later selection */
if (!BM_ELEM_API_FLAG_TEST(l->e, tag)) {
BLI_array_append(deles, l->e);
}
BM_ELEM_API_FLAG_ENABLE(l->e, tag);
}
else {
BMEdge *e3;
if ((e3 = BM_edge_exists(v_conn, v_other))) {
if (combine_flags) {
e3->head.hflag |= l->e->head.hflag;
}
/* flag for later deletion */
if (!BM_ELEM_API_FLAG_TEST(l->e, tag)) {
BLI_array_append(deles, l->e);
}
BM_ELEM_API_FLAG_ENABLE(l->e, tag);
l->e = e3;
}
else {
bmesh_disk_vert_replace(l->e, v_conn, v_del);
}
}
}
} while ((l = lnext) != f->l_first);
}
for (int i = 0; i < BLI_array_len(deles); i++) {
deles[i]->l = NULL;
BM_edge_kill(bm, deles[i]);
}
for (int i = 0; i < BLI_array_len(fs); i++) {
BMFace *f = fs[i];
BMLoop *l, *lnext;
/* validate */
l = f->l_first;
do {
lnext = l->next;
if (l->v == l->next->v) {
l->prev->next = l->next;
l->next->prev = l->prev;
if (l == l->f->l_first) {
l->f->l_first = l->next;
}
l->f->len--;
bm_kill_only_loop(bm, l);
}
} while ((l = lnext) != f->l_first);
if (f->len <= 2) {
/* kill face */
while (f->l_first) {
BMLoop *l = f->l_first;
l->prev->next = l->next;
f->l_first = l->next;
bm_kill_only_loop(bm, l);
if (f->l_first == l) {
f->l_first = NULL;
}
}
bm_kill_only_face(bm, f);
fs[i] = NULL;
}
}
bm->elem_index_dirty |= BM_VERT | BM_EDGE | BM_FACE;
bm->elem_table_dirty |= BM_VERT | BM_EDGE | BM_FACE;
/* relink */
for (int i = 0; i < BLI_array_len(fs); i++) {
BMFace *f = fs[i];
if (!f) {
continue;
}
BMLoop *l = f->l_first;
do {
l->e = BM_edge_exists(l->v, l->next->v);
if (!l->e) {
printf("warning: missing edge! %p %p\n", l->v, l->next->v);
l->e = BM_edge_create(bm, l->v, l->next->v, NULL, BM_CREATE_NOP);
}
bmesh_radial_loop_append(l->e, l);
} while ((l = l->next) != f->l_first);
}
// printf("v_del: %p, v_conn: %p\n", v_del->e, v_conn->e);
if (do_del) {
BM_vert_kill(bm, v_del);
}
BLI_array_free(deles);
BLI_array_free(fs);
return v_conn;
}
/*original version of bmesh_kernel_join_vert_kill_edge*/
BMVert *bmesh_kernel_join_vert_kill_edge_fast(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
const bool do_del,
const bool check_edge_exists,
const bool kill_degenerate_faces,
const bool combine_flags)
{
BLI_SMALLSTACK_DECLARE(faces_degenerate, BMFace *);
BMVert *v_target = BM_edge_other_vert(e_kill, v_kill);
@ -2186,6 +2417,7 @@ BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
BLI_SMALLSTACK_PUSH(faces_degenerate, l_kill->f);
}
}
l_kill_next = l_kill->radial_next;
bm_kill_only_loop(bm, l_kill);
@ -2203,7 +2435,7 @@ BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
/* inline BM_vert_splice(bm, v_target, v_kill); */
BMEdge *e;
while ((e = v_kill->e)) {
BMEdge *e_target;
BMEdge *e_target = NULL;
if (check_edge_exists) {
e_target = BM_edge_exists(v_target, BM_edge_other_vert(e, v_kill));
@ -2232,6 +2464,8 @@ BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
bm_kill_only_vert(bm, v_kill);
}
BM_CHECK_ELEMENT(v_target);
return v_target;
}

View File

@ -122,13 +122,15 @@ BMEdge *bmesh_kernel_join_edge_kill_vert(BMesh *bm,
const bool check_edge_exists,
const bool kill_degenerate_faces,
const bool kill_duplicate_faces);
BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
const bool do_del,
const bool check_edge_exists,
const bool kill_degenerate_faces,
const bool combine_flags);
BMVert *bmesh_kernel_join_vert_kill_edge(
BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool do_del, const bool combine_flags);
BMVert *bmesh_kernel_join_vert_kill_edge_fast(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
const bool do_del,
const bool check_edge_exists,
const bool kill_degenerate_faces,
const bool combine_flags);
BMFace *bmesh_kernel_join_face_kill_edge(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e);
BMVert *bmesh_kernel_unglue_region_make_vert(BMesh *bm, BMLoop *l_sep);

View File

@ -568,10 +568,16 @@ BMVert *BM_edge_collapse(BMesh *bm,
BMVert *v_kill,
const bool do_del,
const bool kill_degenerate_faces,
const bool combine_flags)
const bool combine_flags,
const bool full_non_manifold_collapse)
{
return bmesh_kernel_join_vert_kill_edge(
bm, e_kill, v_kill, do_del, true, kill_degenerate_faces, combine_flags);
if (full_non_manifold_collapse) {
return bmesh_kernel_join_vert_kill_edge(bm, e_kill, v_kill, do_del, combine_flags);
}
else {
return bmesh_kernel_join_vert_kill_edge_fast(
bm, e_kill, v_kill, do_del, true, kill_degenerate_faces, combine_flags);
}
}
/**

View File

@ -65,7 +65,8 @@ BMVert *BM_edge_collapse(BMesh *bm,
BMVert *v_kill,
const bool do_del,
const bool kill_degenerate_faces,
const bool combine_flags);
const bool combine_flags,
const bool full_non_manifold_collapse);
BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac);

View File

@ -55,7 +55,7 @@ int bmesh_disk_count(const BMVert *v);
void bm_rebuild_idmap(BMesh *bm);
void bm_alloc_toolflags_cdlayers(BMesh *bm, bool set_elems);
/**
/**
* Internal BMHeader.api_flag
* \note Ensure different parts of the API do not conflict
* on using these internal flags!

View File

@ -624,7 +624,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
if ((e_other == e) || (BM_DISK_EDGE_NEXT(e_other, v) == e)) {
/* Loose edge or BMVert is edge pair. */
BM_edge_collapse(
bm, BMO_elem_flag_test(bm, e, EXT_TAG) ? e : e_other, v, true, true, false);
bm, BMO_elem_flag_test(bm, e, EXT_TAG) ? e : e_other, v, true, true, false, false);
}
else {
BLI_assert(!BM_vert_is_edge_pair(v));

View File

@ -720,7 +720,7 @@ void bmo_grid_fill_exec(BMesh *bm, BMOperator *op)
GSetIterator gs_iter;
GSET_ITER (gs_iter, split_edges) {
BMEdge *e = BLI_gsetIterator_getKey(&gs_iter);
BM_edge_collapse(bm, e, e->v2, true, true, false);
BM_edge_collapse(bm, e, e->v2, true, true, false, false);
}
BLI_gset_free(split_edges, NULL);
}

View File

@ -1507,7 +1507,7 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
for (int i = 0; i < side_faces_len; i++) {
f = side_faces[i];
BMLoop *l = BM_FACE_FIRST_LOOP(f);
BM_edge_collapse(bm, l->prev->e, l->prev->v, true, true, false);
BM_edge_collapse(bm, l->prev->e, l->prev->v, true, true, false, false);
}
}
@ -1519,7 +1519,7 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
for (int i = 0; i < side_faces_len; i++) {
f = side_faces[i];
BMLoop *l = BM_FACE_FIRST_LOOP(f);
BM_edge_collapse(bm, l->next->e, l->next->v, true, true, false);
BM_edge_collapse(bm, l->next->e, l->next->v, true, true, false, false);
}
}

View File

@ -221,7 +221,7 @@ static int edbm_polybuild_delete_at_cursor_invoke(bContext *C,
if (ele_act->head.htype == BM_VERT) {
BMVert *v_act = (BMVert *)ele_act;
if (BM_vert_is_edge_pair(v_act) && !BM_vert_is_wire(v_act)) {
BM_edge_collapse(bm, v_act->e, v_act, true, true, false);
BM_edge_collapse(bm, v_act->e, v_act, true, true, false, false);
changed = true;
}
else {
@ -570,7 +570,7 @@ static int edbm_polybuild_dissolve_at_cursor_invoke(bContext *C,
else if (ele_act->head.htype == BM_VERT) {
BMVert *v_act = (BMVert *)ele_act;
if (BM_vert_is_edge_pair(v_act)) {
BM_edge_collapse(bm, v_act->e, v_act, true, true, false);
BM_edge_collapse(bm, v_act->e, v_act, true, true, false, false);
}
else {
/* too involved to do inline */

View File

@ -74,10 +74,10 @@
#include <math.h>
#include <stdlib.h>
ATTR_NO_OPT void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
float result[3],
SculptVertRef vertex,
SculptSmoothArgs *args)
void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
float result[3],
SculptVertRef vertex,
SculptSmoothArgs *args)
{
float avg[3] = {0.0f, 0.0f, 0.0f};