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:
parent
e2755640c1
commit
73eb2b426a
|
@ -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)) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
Loading…
Reference in New Issue