Sculpt-dev: fixed edge collapse

* Code needs more cleanup
* Added even more debugging tools
  to bmesh_log.c.
This commit is contained in:
Joseph Eagar 2022-02-23 20:56:32 -08:00
parent 1591c9a978
commit c9c9b80593
7 changed files with 1025 additions and 207 deletions

View File

@ -216,7 +216,7 @@ GHOST_Wintab::GHOST_Wintab(unique_hmodule handle,
m_context{std::move(hctx)},
m_tabletCoord{tablet},
m_systemCoord{system},
m_pkts{queueSize}
m_pkts{(size_t)queueSize}
{
m_fpInfo(WTI_INTERFACE, IFC_NDEVICES, &m_numDevices);
updateCursorInfo();

View File

@ -32,10 +32,19 @@
#include "bmesh.h"
#include "bmesh_log.h"
#include "pbvh_intern.h"
#include <stdio.h>
//#define DYNTOPO_VALIDATE_LOG
#ifdef DYNTOPO_VALIDATE_LOG
# define VALIDATE_LOG(log) BM_log_validate_cur(log)
#else
# define VALIDATE_LOG(log)
#endif
//#define DYNTOPO_REPORT
//#define WITH_ADAPTIVE_CURVATURE
//#define DYNTOPO_NO_THREADING
@ -295,7 +304,7 @@ static void fix_mesh(PBVH *pbvh, BMesh *bm)
printf("done fixing mesh.\n");
}
#define CHECKMESH
//#define CHECKMESH
//#define TEST_INVALID_NORMALS
#ifndef CHECKMESH
@ -1276,7 +1285,7 @@ static void pbvh_bmesh_face_remove(
PBVHNode *f_node = pbvh_bmesh_node_from_face(pbvh, f);
if (!f_node || !(f_node->flag & PBVH_Leaf)) {
printf("%s: pbvh corruption\n", __func__);
printf("pbvh corruption\n");
fflush(stdout);
return;
}
@ -2182,7 +2191,6 @@ static bool check_face_is_tri(PBVH *pbvh, BMFace *f)
static bool destroy_nonmanifold_fins(PBVH *pbvh, BMEdge *e_root)
{
return false; // XXXX
bm_logstack_push();
static int max_faces = 64;
@ -3025,6 +3033,7 @@ static bool bm_edge_collapse_is_degenerate_topology(BMEdge *e_first)
typedef struct TraceData {
PBVH *pbvh;
SmallHash visit;
BMEdge *e;
} TraceData;
ATTR_NO_OPT void col_on_vert_kill(BMesh *bm, BMVert *v, void *userdata)
@ -3033,13 +3042,14 @@ ATTR_NO_OPT void col_on_vert_kill(BMesh *bm, BMVert *v, void *userdata)
PBVH *pbvh = data->pbvh;
if (BM_ELEM_CD_GET_INT(v, pbvh->cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
printf("vert pbvh remove!\n");
// printf("vert pbvh remove!\n");
pbvh_bmesh_vert_remove(pbvh, v);
}
if (!BLI_smallhash_haskey(&data->visit, (uintptr_t)v)) {
printf("vert kill!\n");
// printf("vert kill!\n");
BM_log_vert_topo_pre(pbvh->bm_log, v);
BLI_smallhash_insert(&data->visit, (uintptr_t)v, NULL);
}
}
@ -3049,8 +3059,9 @@ ATTR_NO_OPT void col_on_edge_kill(BMesh *bm, BMEdge *e, void *userdata)
PBVH *pbvh = data->pbvh;
if (!BLI_smallhash_haskey(&data->visit, (uintptr_t)e)) {
printf("edge kill!\n");
// printf("edge kill!\n");
BM_log_edge_topo_pre(pbvh->bm_log, e);
BLI_smallhash_insert(&data->visit, (uintptr_t)e, NULL);
}
}
@ -3064,26 +3075,62 @@ ATTR_NO_OPT void col_on_face_kill(BMesh *bm, BMFace *f, void *userdata)
}
if (!BLI_smallhash_haskey(&data->visit, (uintptr_t)f)) {
printf("face kill!\n");
BM_log_face_topo_pre(pbvh->bm_log, f);
BLI_smallhash_insert(&data->visit, (uintptr_t)f, NULL);
}
}
ATTR_NO_OPT static void vert_ring_do(BMVert *v,
void (*callback)(BMElem *elem, void *userdata),
void *userdata,
int tag)
ATTR_NO_OPT void col_on_vert_add(BMesh *bm, BMVert *v, void *userdata)
{
if (!v->e) {
v->head.hflag &= ~tag;
callback((BMElem *)v, userdata);
TraceData *data = (TraceData *)userdata;
PBVH *pbvh = data->pbvh;
MSculptVert *mv = BM_ELEM_CD_GET_VOID_P(v, data->pbvh->cd_sculpt_vert);
mv->flag |= SCULPTVERT_NEED_VALENCE | SCULPTVERT_NEED_BOUNDARY | SCULPTVERT_NEED_DISK_SORT;
BM_log_vert_topo_post(pbvh->bm_log, v);
}
ATTR_NO_OPT void col_on_edge_add(BMesh *bm, BMEdge *e, void *userdata)
{
TraceData *data = (TraceData *)userdata;
PBVH *pbvh = data->pbvh;
BM_log_edge_topo_post(pbvh->bm_log, e);
}
ATTR_NO_OPT void col_on_face_add(BMesh *bm, BMFace *f, void *userdata)
{
TraceData *data = (TraceData *)userdata;
PBVH *pbvh = data->pbvh;
if (bm_elem_is_free((BMElem *)f, BM_FACE)) {
printf("%s: error, f was freed!\n", __func__);
return;
}
if (BM_ELEM_CD_GET_INT(f, pbvh->cd_face_node_offset) != DYNTOPO_NODE_NONE) {
pbvh_bmesh_face_remove(pbvh, f, false, false, false);
}
BM_log_face_topo_post(pbvh->bm_log, f);
BKE_pbvh_bmesh_add_face(pbvh, f, false, false);
}
/* Faces *outside* the ring region are tagged with facetag, used to detect
* border edges.
*/
static void vert_ring_do_tag(BMVert *v, int tag, int facetag, int depth)
{
BMEdge *e = v->e;
do {
BMVert *v2 = BM_edge_other_vert(e, v);
if (depth > 0) {
vert_ring_do_tag(v2, tag, facetag, depth - 1);
}
e->head.hflag |= tag;
v2->head.hflag |= tag;
@ -3093,20 +3140,73 @@ ATTR_NO_OPT static void vert_ring_do(BMVert *v,
BMLoop *l = e->l;
do {
BMLoop *l2 = l;
l->f->head.hflag |= tag;
BMLoop *l2 = l;
do {
l2->v->head.hflag |= tag;
l2->e->head.hflag |= tag;
l2->f->head.hflag |= tag;
/*set up face tags for faces outside this region*/
BMLoop *l3 = l2->radial_next;
do {
l3->f->head.hflag |= facetag;
} while ((l3 = l3->radial_next) != l2);
} while ((l2 = l2->next) != l);
} while ((l = l->radial_next) != e->l);
} while ((e = BM_DISK_EDGE_NEXT(e, v)) != v->e);
}
static void vert_ring_untag_inner_faces(BMVert *v, int tag, int facetag, int depth)
{
if (!v->e) {
return;
}
BMEdge *e = v->e;
/* untag faces inside this region with facetag */
do {
BMLoop *l = e->l;
if (depth > 0) {
BMVert *v2 = BM_edge_other_vert(e, v);
vert_ring_untag_inner_faces(v2, tag, facetag, depth - 1);
}
if (!l) {
continue;
}
do {
l->f->head.hflag &= ~facetag;
} while ((l = l->radial_next) != e->l);
} while ((e = BM_DISK_EDGE_NEXT(e, v)) != v->e);
}
void vert_ring_do_apply(BMVert *v,
void (*callback)(BMElem *elem, void *userdata),
void *userdata,
int tag,
int facetag,
int depth)
{
BMEdge *e = v->e;
callback((BMElem *)v, userdata);
v->head.hflag &= ~tag;
e = v->e;
do {
BMVert *v2 = BM_edge_other_vert(e, v);
if (depth > 0) {
vert_ring_do_apply(v2, callback, userdata, tag, facetag, depth - 1);
}
if (v2->head.hflag & tag) {
v2->head.hflag &= ~tag;
callback((BMElem *)v2, userdata);
@ -3129,10 +3229,12 @@ ATTR_NO_OPT static void vert_ring_do(BMVert *v,
l2->v->head.hflag &= ~tag;
callback((BMElem *)l2->v, userdata);
}
if (l2->e->head.hflag & tag) {
l2->e->head.hflag &= ~tag;
callback((BMElem *)l2->e, userdata);
}
if (l2->f->head.hflag & tag) {
l2->f->head.hflag &= ~tag;
callback((BMElem *)l2->f, userdata);
@ -3142,11 +3244,45 @@ ATTR_NO_OPT static void vert_ring_do(BMVert *v,
} while ((e = BM_DISK_EDGE_NEXT(e, v)) != v->e);
}
const int COLLAPSE_TAG = BM_ELEM_INTERNAL_TAG;
const int COLLAPSE_FACE_TAG = BM_ELEM_TAG_ALT;
ATTR_NO_OPT static void vert_ring_do(BMVert *v,
void (*callback)(BMElem *elem, void *userdata),
void *userdata,
int tag,
int facetag,
int depth)
{
if (!v->e) {
v->head.hflag &= ~tag;
callback((BMElem *)v, userdata);
return;
}
vert_ring_do_tag(v, tag, facetag, depth);
vert_ring_untag_inner_faces(v, tag, facetag, depth);
vert_ring_do_apply(v, callback, userdata, tag, facetag, depth);
}
ATTR_NO_OPT static void edge_ring_do(BMEdge *e,
void (*callback)(BMElem *elem, void *userdata),
void *userdata,
int tag)
int tag,
int facetag,
int depth)
{
vert_ring_do_tag(e->v1, tag, facetag, depth);
vert_ring_do_tag(e->v2, tag, facetag, depth);
vert_ring_untag_inner_faces(e->v1, tag, facetag, depth);
vert_ring_untag_inner_faces(e->v2, tag, facetag, depth);
vert_ring_do_apply(e->v1, callback, userdata, tag, facetag, depth);
vert_ring_do_apply(e->v2, callback, userdata, tag, facetag, depth);
return;
for (int i = 0; i < 2; i++) {
BMVert *v2 = i ? e->v2 : e->v1;
BMEdge *e2 = v2->e;
@ -3217,6 +3353,27 @@ ATTR_NO_OPT static void edge_ring_do(BMEdge *e,
}
}
ATTR_NO_OPT static void collapse_ring_callback_pre2(BMElem *elem, void *userdata)
{
TraceData *data = (TraceData *)userdata;
PBVH *pbvh = data->pbvh;
if (elem->head.htype != BM_FACE) {
return;
}
BMFace *f = (BMFace *)elem;
if (BM_ELEM_CD_GET_INT(f, pbvh->cd_face_node_offset) != DYNTOPO_NODE_NONE) {
pbvh_bmesh_face_remove(pbvh, f, false, false, false);
}
void **item;
if (!BLI_smallhash_ensure_p(&data->visit, (uintptr_t)f, &item)) {
*item = NULL;
BM_log_face_topo_pre(pbvh->bm_log, f);
}
}
ATTR_NO_OPT static void collapse_ring_callback_pre(BMElem *elem, void *userdata)
{
bm_logstack_push();
@ -3239,8 +3396,28 @@ ATTR_NO_OPT static void collapse_ring_callback_pre(BMElem *elem, void *userdata)
}
case BM_EDGE: {
BMEdge *e = (BMEdge *)elem;
if (e == data->e || !e->l) {
return;
}
BMLoop *l = e->l;
do {
if (l->f->head.hflag & COLLAPSE_FACE_TAG) {
/* do not log boundary edges */
// return;
}
void **item;
if (!BLI_smallhash_ensure_p(&data->visit, (uintptr_t)l->f, &item)) {
*item = NULL;
BM_log_face_topo_pre(pbvh->bm_log, l->f);
}
} while ((l = l->radial_next) != e->l);
BLI_smallhash_reinsert(&data->visit, (uintptr_t)e, NULL);
BM_log_edge_topo_pre(pbvh->bm_log, e);
break;
}
case BM_LOOP: // shouldn't happen
@ -3251,14 +3428,12 @@ ATTR_NO_OPT static void collapse_ring_callback_pre(BMElem *elem, void *userdata)
if (BM_ELEM_CD_GET_INT(f, pbvh->cd_face_node_offset) != DYNTOPO_NODE_NONE) {
pbvh_bmesh_face_remove(pbvh, f, false, false, false);
// BM_log_face_removed(pbvh->bm_log, f);
BM_log_face_topo_pre(pbvh->bm_log, f);
}
else {
//printf("%s: error, face not in pbvh\n", __func__);
// printf("%s: error, face not in pbvh\n", __func__);
}
//BM_log_face_removed(pbvh->bm_log, f);
BM_log_face_topo_pre(pbvh->bm_log, f);
break;
}
}
@ -3284,8 +3459,9 @@ ATTR_NO_OPT static void collapse_ring_callback_post(BMElem *elem, void *userdata
break;
}
case BM_EDGE: {
BMEdge *e = (BMEdge *)elem;
BM_log_edge_topo_post(pbvh->bm_log, e);
// BMEdge *e = (BMEdge *)elem;
// now logged elsewhere
// BM_log_edge_topo_post(pbvh->bm_log, e);
break;
}
case BM_LOOP: // shouldn't happen
@ -3298,8 +3474,9 @@ ATTR_NO_OPT static void collapse_ring_callback_post(BMElem *elem, void *userdata
}
BKE_pbvh_bmesh_add_face(pbvh, f, false, false);
//BM_log_face_added(pbvh->bm_log, f);
BM_log_face_topo_post(pbvh->bm_log, f);
// now logged elsewhere
// BM_log_face_topo_post(pbvh->bm_log, f);
break;
}
@ -3318,18 +3495,6 @@ ATTR_NO_OPT static BMVert *pbvh_bmesh_collapse_edge(PBVH *pbvh,
{
bm_logstack_push();
TraceData tdata;
BLI_smallhash_init(&tdata.visit);
tdata.pbvh = pbvh;
BMTracer tracer;
BM_empty_tracer(&tracer, &tdata);
tracer.on_vert_kill = col_on_vert_kill;
tracer.on_edge_kill = col_on_edge_kill;
tracer.on_face_kill = col_on_face_kill;
BMVert *v_del, *v_conn;
if (pbvh->dyntopo_stop) {
@ -3340,8 +3505,21 @@ ATTR_NO_OPT static BMVert *pbvh_bmesh_collapse_edge(PBVH *pbvh,
pbvh_check_vert_boundary(pbvh, v1);
pbvh_check_vert_boundary(pbvh, v2);
// const int mupdateflag = SCULPTVERT_NEED_VALENCE | SCULPTVERT_NEED_BOUNDARY |
// SCULPTVERT_NEED_DISK_SORT;
TraceData tdata;
BLI_smallhash_init(&tdata.visit);
tdata.pbvh = pbvh;
tdata.e = e;
BMTracer tracer;
BM_empty_tracer(&tracer, &tdata);
tracer.on_vert_kill = col_on_vert_kill;
tracer.on_edge_kill = col_on_edge_kill;
tracer.on_face_kill = col_on_face_kill;
const int mupdateflag = SCULPTVERT_NEED_VALENCE | SCULPTVERT_NEED_BOUNDARY |
SCULPTVERT_NEED_DISK_SORT;
// updateflag |= SCULPTVERT_NEED_TRIANGULATE; // to check for non-manifold flaps
validate_edge(pbvh, pbvh->bm, e, true, true);
@ -3349,9 +3527,6 @@ ATTR_NO_OPT static BMVert *pbvh_bmesh_collapse_edge(PBVH *pbvh,
check_vert_fan_are_tris(pbvh, e->v1);
check_vert_fan_are_tris(pbvh, e->v2);
const int tag = BM_ELEM_TAG_ALT;
//edge_ring_do(e, collapse_ring_callback_pre, &tdata, tag);
MSculptVert *mv1 = BKE_PBVH_SCULPTVERT(pbvh->cd_sculpt_vert, v1);
MSculptVert *mv2 = BKE_PBVH_SCULPTVERT(pbvh->cd_sculpt_vert, v2);
@ -3370,8 +3545,6 @@ ATTR_NO_OPT static BMVert *pbvh_bmesh_collapse_edge(PBVH *pbvh,
if ((mv1->flag & SCULPTVERT_ALL_CORNER) ||
(mv1->flag & SCULPTVERT_ALL_BOUNDARY) != (mv2->flag & SCULPTVERT_ALL_BOUNDARY)) {
BLI_smallhash_release(&tdata.visit);
bm_logstack_pop();
return NULL;
}
@ -3393,12 +3566,10 @@ ATTR_NO_OPT static BMVert *pbvh_bmesh_collapse_edge(PBVH *pbvh,
/*have to check edge flags directly, vertex flag test above isn't specific enough and
can sometimes let bad edges through*/
if ((mv1->flag & SCULPTVERT_SHARP_BOUNDARY) && (e->head.hflag & BM_ELEM_SMOOTH)) {
BLI_smallhash_release(&tdata.visit);
bm_logstack_pop();
return NULL;
}
if ((mv1->flag & SCULPTVERT_SEAM_BOUNDARY) && !(e->head.hflag & BM_ELEM_SEAM)) {
BLI_smallhash_release(&tdata.visit);
bm_logstack_pop();
return NULL;
}
@ -3520,12 +3691,37 @@ ATTR_NO_OPT static BMVert *pbvh_bmesh_collapse_edge(PBVH *pbvh,
validate_vert_faces(pbvh, pbvh->bm, v_conn, false, true);
BLI_smallhash_reinsert(&tdata.visit, (uintptr_t)v_del, NULL);
BMEdge *e2;
const int tag = COLLAPSE_TAG;
const int facetag = COLLAPSE_FACE_TAG;
const int log_rings = 1;
edge_ring_do(e, collapse_ring_callback_pre2, &tdata, tag, facetag, log_rings - 1);
// edge_ring_do(e, collapse_ring_callback_pre, &tdata, tag, facetag, log_rings - 1);
pbvh_bmesh_vert_remove(pbvh, v_del);
BM_log_edge_topo_pre(pbvh->bm_log, e);
BLI_smallhash_reinsert(&tdata.visit, (uintptr_t)e, NULL);
BM_log_vert_removed(pbvh->bm_log, v_del, pbvh->cd_vert_mask_offset);
BLI_smallhash_reinsert(&tdata.visit, (uintptr_t)v_del, NULL);
if (deleted_verts) {
BLI_ghash_insert(deleted_verts, (void *)v_del, NULL);
}
pbvh_bmesh_check_nodes(pbvh);
validate_vert_faces(pbvh, pbvh->bm, v_conn, false, true);
#if 1
tracer.on_vert_create = col_on_vert_add;
tracer.on_edge_create = col_on_edge_add;
tracer.on_face_create = col_on_face_add;
#endif
if (!snap) {
float co[3];
@ -3548,42 +3744,11 @@ ATTR_NO_OPT static BMVert *pbvh_bmesh_collapse_edge(PBVH *pbvh,
if (!v_conn->e) {
printf("%s: pbvh error, v_conn->e was null\n", __func__);
BLI_smallhash_release(&tdata.visit);
return v_conn;
}
validate_vert_faces(pbvh, pbvh->bm, v_conn, false, true);
BMEdge *e2 = v_conn->e, *e2next;
do {
e2next = BM_DISK_EDGE_NEXT(e2, v_conn);
if (!e2->l) {
/* wire edge, should have been added to log already */
BM_edge_kill(pbvh->bm, e2);
}
} while (e2next && (e2 = e2next) != v_conn->e);
if (!v_conn->e) {
if (BM_ELEM_CD_GET_INT(v_conn, pbvh->cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
pbvh_bmesh_vert_remove(pbvh, v_conn);
}
BM_log_vert_removed(pbvh->bm_log, v_conn, -1);
BM_vert_kill(pbvh->bm, v_conn);
}
else {
pbvh_bmesh_check_nodes(pbvh);
//vert_ring_do(v_conn, collapse_ring_callback_post, &tdata, tag);
pbvh_bmesh_check_nodes(pbvh);
}
#if 1
const int mupdateflag = SCULPTVERT_NEED_BOUNDARY | SCULPTVERT_NEED_DISK_SORT |
SCULPTVERT_NEED_VALENCE;
validate_vert_faces(pbvh, pbvh->bm, v_conn, false, true);
e2 = v_conn->e;
do {
BMLoop *l = e2->l;
@ -3605,15 +3770,13 @@ ATTR_NO_OPT static BMVert *pbvh_bmesh_collapse_edge(PBVH *pbvh,
if (!v_conn) {
bm_logstack_pop();
BLI_smallhash_release(&tdata.visit);
return NULL;
}
MSculptVert *mv_conn = BKE_PBVH_SCULPTVERT(pbvh->cd_sculpt_vert, v_conn);
MV_ADD_FLAG(mv_conn, mupdateflag);
bool wasbad = false;
#if 1
e2 = v_conn->e;
BMEdge *enext;
do {
@ -3622,63 +3785,47 @@ ATTR_NO_OPT static BMVert *pbvh_bmesh_collapse_edge(PBVH *pbvh,
}
enext = BM_DISK_EDGE_NEXT(e2, v_conn);
BMLoop *l = e2->l;
BMVert *v2 = BM_edge_other_vert(e2, v_conn);
MSculptVert *mv2 = BKE_PBVH_SCULPTVERT(pbvh->cd_sculpt_vert, v2);
MV_ADD_FLAG(mv2, mupdateflag);
// kill wire edge
if (!l) {
// edge should have been marked as removed earlier in the function
BM_log_edge_removed(pbvh->bm_log, e2);
if (!e2->l) {
BM_log_edge_topo_pre(pbvh->bm_log, e2);
BM_edge_kill(pbvh->bm, e2);
continue;
}
if (e2->head.hflag & tag) {
e2->head.hflag &= ~tag;
BM_log_edge_topo_post(pbvh->bm_log, e2);
}
BMLoop *lnext;
do {
lnext = l->radial_next;
bool fbad = false;
# if 0
do {
if (l2->v == l2->next->v) {
int ni = BM_ELEM_CD_GET_INT(l2->f, pbvh->cd_face_node_offset);
if (ni >= 0 && ni < pbvh->totnode && (pbvh->nodes[ni].flag & PBVH_Leaf)) {
BLI_table_gset_remove(pbvh->nodes[ni].bm_faces, l2->f, NULL);
}
printf("duplicate verts in face!! %s\n", __func__);
wasbad = true;
BM_face_kill(pbvh->bm, l2->f);
fbad = true;
lnext = e2->l ? e2->l->radial_next : NULL;
break;
}
} while ((l2 = l2->next) != l->f->l_first);
# endif
if (!fbad && BM_ELEM_CD_GET_INT(l->f, pbvh->cd_face_node_offset) == DYNTOPO_NODE_NONE) {
BKE_pbvh_bmesh_add_face(pbvh, l->f, false, false);
BM_log_face_topo_post(pbvh->bm_log, l->f);
}
if (!lnext) {
break;
}
} while ((l = lnext) != e2->l);
} while (v_conn->e && (e2 = enext) != v_conn->e);
// BM_vert_splice(pbvh->bm, v_del, v_conn);
#endif
// vert_ring_do(v_conn, collapse_ring_callback_post, &tdata, tag, facetag, log_rings - 1);
{
BMElem *elem = NULL;
SmallHashIter siter;
void **val = BLI_smallhash_iternew_p(&tdata.visit, &siter, (uintptr_t *)&elem);
for (; val; val = BLI_smallhash_iternext_p(&siter, (uintptr_t *)&elem)) {
if (bm_elem_is_free(elem, BM_EDGE) && bm_elem_is_free(elem, BM_VERT) &&
bm_elem_is_free(elem, BM_FACE)) {
continue;
}
switch (elem->head.htype) {
case BM_VERT:
if (!BM_log_has_vert_post(pbvh->bm_log, (BMVert *)elem)) {
BM_log_vert_added(pbvh->bm_log, (BMVert *)elem, -1);
}
break;
case BM_EDGE:
if (!BM_log_has_edge_post(pbvh->bm_log, (BMEdge *)elem)) {
BM_log_edge_added(pbvh->bm_log, (BMEdge *)elem);
}
break;
case BM_FACE:
if (!BM_log_has_face_post(pbvh->bm_log, (BMFace *)elem)) {
BM_log_face_added(pbvh->bm_log, (BMFace *)elem);
}
break;
}
}
}
MSculptVert *mv3 = BKE_PBVH_SCULPTVERT(pbvh->cd_sculpt_vert, v_conn);
MV_ADD_FLAG(mv3, mupdateflag);
@ -3693,22 +3840,14 @@ ATTR_NO_OPT static BMVert *pbvh_bmesh_collapse_edge(PBVH *pbvh,
BM_vert_kill(pbvh->bm, v_conn);
bm_logstack_pop();
BLI_smallhash_release(&tdata.visit);
return NULL;
}
if (BM_ELEM_CD_GET_INT(v_conn, pbvh->cd_vert_node_offset) == DYNTOPO_NODE_NONE) {
//printf("%s: error: failed to remove vert from pbvh?\n", __func__);
printf("%s: error: failed to remove vert from pbvh?\n", __func__);
}
if (wasbad) {
fix_mesh(pbvh, pbvh->bm);
bm_logstack_pop();
BLI_smallhash_release(&tdata.visit);
return NULL;
}
# if 0
#if 0
e = v_conn->e;
if (e) {
@ -3720,15 +3859,17 @@ ATTR_NO_OPT static BMVert *pbvh_bmesh_collapse_edge(PBVH *pbvh,
} while ((e = enext) != v_conn->e);
}
# endif
#endif
if (v_conn) {
check_for_fins(pbvh, v_conn);
}
validate_vert_faces(pbvh, pbvh->bm, v_conn, false, true);
#endif
bm_logstack_pop();
PBVH_CHECK_NAN(v_conn->co);
BLI_smallhash_release(&tdata.visit);
return v_conn;
}
@ -3746,8 +3887,6 @@ cleanup_valence_3_4(EdgeQueueContext *ectx,
const bool use_frontface,
const bool use_projected)
{
return false; //XXXX
bool modified = false;
bm_logstack_push();
@ -4372,22 +4511,21 @@ ATTR_NO_OPT bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
// ratio = 1.0f;
#endif
BM_log_entry_add_ex(pbvh->bm, pbvh->bm_log, true);
int steps[2] = {0, 0};
if ((mode & PBVH_Subdivide) && (mode & PBVH_Collapse)) {
steps[0] = 32;
steps[1] = 32;
steps[0] = 1024;
steps[1] = 128;
}
else if (mode & PBVH_Subdivide) {
steps[0] = 512;
steps[0] = 2048;
}
else if (mode & PBVH_Collapse) {
steps[0] = 512;
steps[0] = 2048;
}
BMEdge **edges = MEM_malloc_arrayN(steps[0], sizeof(void *), __func__);
int edges_size = steps[0];
BMEdge **edges = MEM_malloc_arrayN(edges_size, sizeof(void *), __func__);
int etot = 0;
PBVHTopologyUpdateMode ops[2];
@ -4409,7 +4547,10 @@ ATTR_NO_OPT bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
float limit_len_cold = pbvh->bm_min_edge_len * pbvh->bm_min_edge_len;
// limit_len_cold = limit_len_cold * limit_len_cold;
printf(" minmax queue size: %d\n", BLI_mm_heap_len(eq_ctx.heap_mm));
// printf(" minmax queue size: %d\n", BLI_mm_heap_len(eq_ctx.heap_mm));
SmallHash subd_edges;
BLI_smallhash_init(&subd_edges);
while (totop > 0 && !BLI_mm_heap_is_empty(eq_ctx.heap_mm) && i < max_steps) {
BMEdge *e = NULL;
@ -4417,7 +4558,9 @@ ATTR_NO_OPT bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
if (count >= steps[curop]) {
if (ops[curop] == PBVH_Subdivide) {
modified = true;
BLI_smallhash_clear(&subd_edges, 0);
pbvh_split_edges(&eq_ctx, pbvh, pbvh->bm, edges, etot, false);
VALIDATE_LOG(pbvh->bm_log);
etot = 0;
}
@ -4442,7 +4585,27 @@ ATTR_NO_OPT bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
break;
}
edges[etot++] = e;
/* add complete triangles */
BMLoop *l = e->l;
if (l) {
do {
BMLoop *l2 = l;
do {
if (etot >= edges_size) {
break;
}
void **val = NULL;
if (!BLI_smallhash_ensure_p(&subd_edges, (uintptr_t)l->e, &val)) {
*val = NULL;
edges[etot++] = e;
}
} while ((l2 = l2->next) != l);
} while ((l = l->radial_next) != e->l);
}
//edges[etot++] = e;
break;
}
case PBVH_Collapse: {
@ -4463,21 +4626,34 @@ ATTR_NO_OPT bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
modified = true;
pbvh_bmesh_collapse_edge(pbvh, e, e->v1, e->v2, NULL, NULL, &eq_ctx);
VALIDATE_LOG(pbvh->bm_log);
break;
}
default:
break;
}
count++;
i++;
}
if (etot > 0) {
modified = true;
BLI_smallhash_clear(&subd_edges, 0);
pbvh_split_edges(&eq_ctx, pbvh, pbvh->bm, edges, etot, false);
VALIDATE_LOG(pbvh->bm_log);
etot = 0;
}
MEM_SAFE_FREE(edges);
BLI_smallhash_release(&subd_edges);
if (mode & PBVH_Cleanup) {
modified |= do_cleanup_3_4(
&eq_ctx, pbvh, center, view_normal, radius, use_frontface, use_projected);
VALIDATE_LOG(pbvh->bm_log);
}
if (modified) {
@ -4735,11 +4911,6 @@ ATTR_NO_OPT static void pbvh_split_edges(EdgeQueueContext *eq_ctx,
// BM_log_entry_add_ex(pbvh->bm, pbvh->bm_log, true);
#if 0
bm_logstack_pop();
return; // XXX
#endif
for (int i = 0; i < totedge; i++) {
BMEdge *e = edges[i];
BMLoop *l = e->l;

View File

@ -4566,13 +4566,10 @@ void BKE_pbvh_get_vert_face_areas(PBVH *pbvh, SculptVertRef vertex, float *r_are
SubdivCCGCoord *coord2 = neighbors.coords + i;
int vertex_index2 = coord2->y * key->grid_size + coord2->x;
int index2 = coord2->grid_index * key->grid_area + vertex_index2;
float *co2 = CCG_elem_co(
key, CCG_elem_offset(key, pbvh->grids[coord2->grid_index], vertex_index2));
float w = len_v3v3(co1, co2);
// w = sqrtf(w);
// w *= w;
r_areas[i] = w;
totw += w;

View File

@ -601,7 +601,7 @@ typedef enum {
IS_FACE_WRONG_LENGTH = (1 << 26),
} BMeshInternalError;
#if 1 //#ifndef NDEBUG
#ifndef NDEBUG
int bmesh_elem_check(void *element, const char htype)
{
@ -2367,6 +2367,18 @@ ATTR_NO_OPT static char *bm_save_local_obj_text(
str = obj_append_line(line, str, buf, &size, &stri);
}
/* save wire edges */
for (int i = 0; i < BLI_array_len(es); i++) {
BMEdge *e = es[i];
if (e->l) {
continue;
}
sprintf(line, "l %d %d\n", e->v1->head.index, e->v2->head.index);
str = obj_append_line(line, str, buf, &size, &stri);
}
for (int i = 0; i < BLI_array_len(fs); i++) {
BMFace *f = fs[i];
BMLoop *l = f->l_first;
@ -2423,7 +2435,7 @@ static void trigger_jvke_error(int err, char *obj_text)
char *_last_local_obj = NULL;
#define JVKE_DEBUG
//#define JVKE_DEBUG
#ifdef JVKE_DEBUG
# define JVKE_CHECK_ELEMENT(elem) \
@ -2437,6 +2449,99 @@ char *_last_local_obj = NULL;
# define JVKE_CHECK_ELEMENT(elem)
#endif
ATTR_NO_OPT static bool cleanup_vert(BMesh *bm, BMVert *v, const BMTracer *tracer)
{
BMEdge *e = v->e;
if (!e->l || e->l->f == e->l->radial_next->f) {
return false;
}
BMFace *f_example = NULL;
do {
if (tracer) {
tracer->on_edge_kill(bm, e, tracer->userdata);
}
BMLoop *l = e->l;
if (!l) {
continue;
}
f_example = l->f;
BMLoop *lnext;
do {
if (tracer) {
tracer->on_face_kill(bm, l->f, tracer->userdata);
}
} while ((l = l->radial_next) != e->l);
} while ((e = BM_DISK_EDGE_NEXT(e, v)) != v->e);
if (tracer) {
tracer->on_vert_kill(bm, v, tracer->userdata);
}
BMVert *v1 = BM_edge_other_vert(v->e, v);
BMVert *v2 = BM_edge_other_vert(BM_DISK_EDGE_NEXT(v->e, v), v);
BMVert *v3 = BM_edge_other_vert(BM_DISK_EDGE_NEXT(BM_DISK_EDGE_NEXT(v->e, v), v), v);
BMFace *f = BM_face_create_quad_tri(bm, v1, v2, v3, NULL, f_example, BM_CREATE_NOP);
BMLoop *l = f->l_first;
//ensure correct winding
do {
if (l->radial_next != l && l->radial_next->v == l->v) {
BM_face_normal_flip(bm, f);
break;
}
} while ((l = l->next) != f->l_first);
BM_vert_kill(bm, v);
if (tracer) {
tracer->on_face_create(bm, f, tracer->userdata);
}
return true;
}
ATTR_NO_OPT static void bmesh_kernel_check_val3_vert(BMesh *bm, BMEdge *e, const BMTracer *tracer)
{
if (!e->l) {
return;
}
bool stop;
do {
stop = true;
BMLoop *l = e->l;
if (!l) {
break;
}
do {
BMLoop *l2 = l->prev;
if (l2 == l2->radial_next) {
continue;
}
if (BM_vert_edge_count(l2->v) == 3) {
if (cleanup_vert(bm, l2->v, tracer)) {
stop = false;
break;
}
}
} while ((l = l->radial_next) != e->l);
} while (!stop);
}
ATTR_NO_OPT BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
BMEdge *e,
BMVert *v_kill,
@ -2449,24 +2554,30 @@ ATTR_NO_OPT BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
#ifdef JVKE_DEBUG
char buf[LOCAL_OBJ_SIZE];
bool have_boundary = false;
if (_last_local_obj) {
free(_last_local_obj);
}
char *saved_obj = bm_save_local_obj_text(bm, 2, buf, "e", e);
_last_local_obj = strdup(saved_obj);
bm_local_obj_free(saved_obj, buf);
#endif
bmesh_kernel_check_val3_vert(bm, e, tracer);
BMFace **fs = NULL;
BMEdge **deles = NULL;
BLI_array_staticdeclare(fs, 32);
BLI_array_staticdeclare(deles, 32);
BMEdge **es = NULL;
BLI_array_staticdeclare(es, 32);
BMVert *v_del = BM_edge_other_vert(e, v_conn);
const int tag = _FLAG_WALK_ALT; // using bmhead.api_flag here
const int dup_tag = _FLAG_OVERLAP;
const int final_tag = _FLAG_JF;
JVKE_CHECK_ELEMENT(v_conn);
JVKE_CHECK_ELEMENT(v_del);
@ -2476,6 +2587,22 @@ ATTR_NO_OPT BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
BMVert *v = i ? v_del : v_conn;
BMEdge *e2 = v->e;
do {
/* build list of edges if needed for tracing */
if (tracer) {
bool ok = true;
for (int j = 0; j < BLI_array_len(es); j++) {
if (es[j] == e2) {
ok = false;
break;
}
}
if (ok) {
BLI_array_append(es, e2);
}
}
if (!e2->l) {
continue;
}
@ -2484,6 +2611,12 @@ ATTR_NO_OPT BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
do {
BM_ELEM_API_FLAG_DISABLE(l->f, tag);
#ifdef JVKE_DEBUG
if (l->radial_next == l) {
have_boundary = true;
}
#endif
BM_ELEM_API_FLAG_DISABLE(l->f, dup_tag);
BM_ELEM_API_FLAG_DISABLE(l->e, dup_tag);
BM_ELEM_API_FLAG_DISABLE(l->v, dup_tag);
@ -2522,6 +2655,18 @@ ATTR_NO_OPT BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
} while ((e2 = BM_DISK_EDGE_NEXT(e2, v)) != v->e);
}
if (tracer) {
for (int i = 0; i < BLI_array_len(fs); i++) {
tracer->on_face_kill(bm, fs[i], tracer->userdata);
}
}
if (tracer) {
for (int i = 0; i < BLI_array_len(es); i++) {
tracer->on_edge_kill(bm, es[i], tracer->userdata);
}
}
/* unlink loops */
for (int i = 0; i < BLI_array_len(fs); i++) {
BMFace *f = fs[i];
@ -2616,9 +2761,9 @@ ATTR_NO_OPT BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
e2->l = NULL;
if (tracer) {
tracer->on_edge_kill(bm, deles[i], tracer->userdata);
}
// if (tracer) {
// tracer->on_edge_kill(bm, deles[i], tracer->userdata);
//}
BM_edge_kill(bm, deles[i]);
}
@ -2651,9 +2796,9 @@ ATTR_NO_OPT BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
} while (lnext && (l = lnext) != f->l_first);
if (f->len <= 2) {
if (tracer) {
tracer->on_face_kill(bm, f, tracer->userdata);
}
// if (tracer) {
// tracer->on_face_kill(bm, f, tracer->userdata);
//}
/* kill face */
while (f->l_first) {
@ -2685,6 +2830,8 @@ ATTR_NO_OPT BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
continue;
}
BM_ELEM_API_FLAG_ENABLE(f, final_tag);
BMLoop *l = f->l_first;
do {
l->e = BM_edge_exists(l->v, l->next->v);
@ -2714,6 +2861,16 @@ ATTR_NO_OPT BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
JVKE_CHECK_ELEMENT(e1);
BMLoop *l = e1->l;
if (!l) {
continue;
}
/* boundary? */
if (l == l->radial_next && !have_boundary) {
trigger_jvke_error(IS_LOOP_WRONG_RADIAL_LENGTH, saved_obj);
}
if (!l) {
continue;
}
@ -2825,6 +2982,46 @@ ATTR_NO_OPT BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
BM_vert_kill(bm, v_del);
}
if (tracer && v_conn->e) {
e = v_conn->e;
do {
tracer->on_edge_create(bm, e, tracer->userdata);
BMLoop *l = e->l;
if (!l) {
continue;
}
do {
if (BM_ELEM_API_FLAG_TEST(l->f, final_tag)) {
BM_ELEM_API_FLAG_DISABLE(l->f, final_tag);
tracer->on_face_create(bm, l->f, tracer->userdata);
}
} while ((l = l->radial_next) != e->l);
} while ((e = BM_DISK_EDGE_NEXT(e, v_conn)) != v_conn->e);
}
#ifdef JVKE_DEBUG
if (v_conn && v_conn->e) {
BMEdge *e = v_conn->e;
do {
BMLoop *l = e->l;
if (!l) {
continue;
}
/* boundary? */
if (l == l->radial_next && !have_boundary) {
trigger_jvke_error(IS_LOOP_WRONG_RADIAL_LENGTH, saved_obj);
}
} while ((e = BM_DISK_EDGE_NEXT(e, v_conn)) != v_conn->e);
}
bm_local_obj_free(saved_obj, buf);
#endif
BLI_array_free(deles);
BLI_array_free(fs);

View File

@ -51,12 +51,20 @@
#include "BKE_customdata.h"
#include "BKE_mesh.h"
#include "BLI_strict_flags.h"
//#include "BLI_strict_flags.h"
#include "bmesh.h"
#include "bmesh_log.h"
#include "bmesh_private.h"
#include "range_tree.h"
//#define BM_VALIDATE_LOG
#ifdef BM_VALIDATE_LOG
# define VALIDATE_LOG(bm, emtry) BM_log_validate(bm, entry, false)
#else
# define VALIDATE_LOG(bm, entry)
#endif
#define CUSTOMDATA
void CustomData_bmesh_asan_unpoison(const CustomData *data, void *block);
@ -515,7 +523,7 @@ BLI_INLINE int get_face_id(BMesh *bm, BMFace *f)
#if 0
int id = BM_ELEM_GET_ID(bm, f);
int id2 = 0;
BMLoop *l = f->l_first;
BMLoop* l = f->l_first;
do {
id2 ^= BM_ELEM_GET_ID(bm, l->v);
@ -628,6 +636,16 @@ static uint bm_log_vert_id_get(BMLog *log, BMVert *v)
return (uint)BM_ELEM_GET_ID(log->bm, v);
}
/*Get a vertex from its unique ID */
ATTR_NO_OPT static BMElem *bm_log_elem_from_id(BMLog *log, uint id)
{
if (log->bm->idmap.map && id >= ((unsigned int)log->bm->idmap.map_size)) {
return NULL;
}
return (BMElem *)BM_ELEM_FROM_ID(log->bm, id);
}
/* Get a vertex from its unique ID */
ATTR_NO_OPT static BMVert *bm_log_vert_from_id(BMLog *log, uint id)
{
@ -1403,8 +1421,8 @@ static void bm_log_faces_restore(
#if 0
for (size_t j = 0; j < lf->len; j++) {
BMVert *v1 = bm_log_vert_from_id(log, lf->v_ids[j]);
BMVert *v2 = bm_log_vert_from_id(log, lf->v_ids[(j + 1) % lf->len]);
BMVert* v1 = bm_log_vert_from_id(log, lf->v_ids[j]);
BMVert* v2 = bm_log_vert_from_id(log, lf->v_ids[(j + 1) % lf->len]);
if (!v1 || !v2) {
continue;
@ -1894,7 +1912,7 @@ BMLog *BM_log_unfreeze(BMesh *bm, BMLogEntry *entry)
}
#if 0
BMLogEntry *frozen = entry->log->frozen_full_mesh;
BMLogEntry* frozen = entry->log->frozen_full_mesh;
if (!frozen && entry->type == LOG_ENTRY_FULL_MESH) {
frozen = entry;
}
@ -2018,45 +2036,45 @@ void BM_log_print_entry(BMLog *log, BMLogEntry *entry)
void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
{
#if 0 // TODO: make sure no edge cases relying on this function still exist
uint *varr;
uint *farr;
uint* varr;
uint* farr;
GHash *id_to_idx;
GHash* id_to_idx;
BMIter bm_iter;
BMVert *v;
BMFace *f;
BMVert* v;
BMFace* f;
uint i;
/* Put all vertex IDs into an array */
varr = MEM_mallocN(sizeof(int) * (size_t)bm->totvert, __func__);
BM_ITER_MESH_INDEX (v, &bm_iter, bm, BM_VERTS_OF_MESH, i) {
BM_ITER_MESH_INDEX(v, &bm_iter, bm, BM_VERTS_OF_MESH, i) {
varr[i] = bm_log_vert_id_get(log, v);
}
/* Put all face IDs into an array */
farr = MEM_mallocN(sizeof(int) * (size_t)bm->totface, __func__);
BM_ITER_MESH_INDEX (f, &bm_iter, bm, BM_FACES_OF_MESH, i) {
BM_ITER_MESH_INDEX(f, &bm_iter, bm, BM_FACES_OF_MESH, i) {
farr[i] = bm_log_face_id_get(log, f);
}
/* Create BMVert index remap array */
id_to_idx = bm_log_compress_ids_to_indices(varr, (uint)bm->totvert);
BM_ITER_MESH_INDEX (v, &bm_iter, bm, BM_VERTS_OF_MESH, i) {
BM_ITER_MESH_INDEX(v, &bm_iter, bm, BM_VERTS_OF_MESH, i) {
const uint id = bm_log_vert_id_get(log, v);
const void *key = POINTER_FROM_UINT(id);
const void *val = log_ghash_lookup(log, id_to_idx, key);
const void* key = POINTER_FROM_UINT(id);
const void* val = log_ghash_lookup(log, id_to_idx, key);
varr[i] = POINTER_AS_UINT(val);
}
BLI_ghash_free(id_to_idx, NULL, NULL);
/* Create BMFace index remap array */
id_to_idx = bm_log_compress_ids_to_indices(farr, (uint)bm->totface);
BM_ITER_MESH_INDEX (f, &bm_iter, bm, BM_FACES_OF_MESH, i) {
BM_ITER_MESH_INDEX(f, &bm_iter, bm, BM_FACES_OF_MESH, i) {
const uint id = bm_log_face_id_get(log, f);
const void *key = POINTER_FROM_UINT(id);
const void *val = log_ghash_lookup(log, id_to_idx, key);
const void* key = POINTER_FROM_UINT(id);
const void* val = log_ghash_lookup(log, id_to_idx, key);
farr[i] = POINTER_AS_UINT(val);
}
BLI_ghash_free(id_to_idx, NULL, NULL);
@ -2134,7 +2152,7 @@ BMLogEntry *bm_log_entry_add_ex(
/* Delete any entries after the current one */
entry = log->current_entry;
if (entry) {
BMLogEntry *next;
BMLogEntry* next;
for (entry = entry->next; entry; entry = next) {
next = entry->next;
bm_log_entry_free(entry);
@ -3056,6 +3074,7 @@ void _BM_log_face_topo_pre(BMLog *log, BMFace *f BMLOG_DEBUG_ARGS)
*val = (void *)lf;
}
VALIDATE_LOG(log->bm, log->current_entry);
bm_logstack_pop();
}
@ -3095,6 +3114,7 @@ void _BM_log_face_topo_post(BMLog *log, BMFace *f, const char *func, int line)
}
}
VALIDATE_LOG(log->bm, log->current_entry);
bm_logstack_pop();
}
@ -3140,6 +3160,7 @@ void _BM_log_edge_topo_pre(BMLog *log, BMEdge *e, const char *func, int line)
*val = (void *)le;
}
VALIDATE_LOG(log->bm, log->current_entry);
bm_logstack_pop();
}
@ -3178,6 +3199,7 @@ void _BM_log_edge_topo_post(BMLog *log, BMEdge *e, const char *func, int line)
*val = (void *)le;
}
VALIDATE_LOG(log->bm, log->current_entry);
bm_logstack_pop();
}
@ -3216,6 +3238,7 @@ void _BM_log_vert_topo_pre(BMLog *log, BMVert *v, const char *func, int line)
*val = (void *)lv;
}
VALIDATE_LOG(log->bm, log->current_entry);
bm_logstack_pop();
}
@ -3259,6 +3282,8 @@ void _BM_log_vert_topo_post(BMLog *log, BMVert *v, const char *func, int line)
}
}
VALIDATE_LOG(log->bm, log->current_entry);
bm_logstack_pop();
}
/* Log a vertex as removed from the BMesh
@ -3322,12 +3347,12 @@ BMVert *BM_log_edge_split_do(BMLog *log, BMEdge *e, BMVert *v, BMEdge **newe, fl
return newv;
#if 0
BMEdge *tmp = NULL;
BMEdge* tmp = NULL;
if (!newe) {
newe = &tmp;
}
BMesh *bm = log->bm;
BMesh* bm = log->bm;
int eid0 = BM_ELEM_GET_ID(bm, e);
@ -3335,12 +3360,12 @@ BMVert *BM_log_edge_split_do(BMLog *log, BMEdge *e, BMVert *v, BMEdge **newe, fl
bm_log_message(" esplit: remove edge %d", eid0);
BM_log_edge_removed(log, e);
BMVert *v1 = e->v1, *v2 = e->v2;
BMVert* v1 = e->v1, * v2 = e->v2;
uint id1 = (uint)BM_ELEM_GET_ID(bm, v1);
uint id2 = (uint)BM_ELEM_GET_ID(bm, v2);
bm_log_message(" esplit: split edge %d (v1=%d v2=%d)", eid0, id1, id2);
BMVert *newv = BM_edge_split(log->bm, e, v, newe, t);
BMVert* newv = BM_edge_split(log->bm, e, v, newe, t);
uint id3 = (uint)BM_ELEM_GET_ID(bm, newv);
uint nid = (uint)BM_ELEM_GET_ID(bm, (*newe));
@ -3348,11 +3373,11 @@ BMVert *BM_log_edge_split_do(BMLog *log, BMEdge *e, BMVert *v, BMEdge **newe, fl
// get a new id
# ifndef WITH_BM_ID_FREELIST
uint id = range_tree_uint_take_any(log->bm->idmap.idtree);
bm_free_id(log->bm, (BMElem *)e);
bm_assign_id(log->bm, (BMElem *)e, id, true);
bm_free_id(log->bm, (BMElem*)e);
bm_assign_id(log->bm, (BMElem*)e, id, true);
# else
bm_free_id(log->bm, (BMElem *)e);
bm_alloc_id(log->bm, (BMElem *)e);
bm_free_id(log->bm, (BMElem*)e);
bm_alloc_id(log->bm, (BMElem*)e);
uint id = BM_ELEM_GET_ID(bm, e);
# endif
@ -3534,10 +3559,10 @@ BMLogEntry *BM_log_current_entry(BMLog *log)
/* Print the list of entries, marking the current one
*
* Keep around for debugging */
void bm_log_print(const BMLog *log, const char *description)
void bm_log_print(const BMLog* log, const char* description)
{
const BMLogEntry *entry;
const char *current = " <-- current";
const BMLogEntry* entry;
const char* current = " <-- current";
int i;
fprintf(DEBUG_FILE, "%s:\n", description);
@ -3599,3 +3624,420 @@ int BM_log_entry_size(BMLogEntry *entry)
return ret;
}
BMesh *BM_mesh_copy_ex(BMesh *bm_old, struct BMeshCreateParams *params);
int type_idx_map[] = {
0, // 0
0, // 1 BM_VERT
1, // 2 BM_EDGE
0, // 3
2, // 4 BM_LOOP
0, // 5
0, // 6
0, // 7
3, // 8 BM_FACE
};
ATTR_NO_OPT static GHash *bm_clone_ghash(BMLogEntry *entry, GHash *ghash, int type)
{
GHash *ghash2 = BLI_ghash_new(logkey_hash, logkey_cmp, __func__);
GHashIterator gh_iter;
GHASH_ITER (gh_iter, ghash) {
void *key = BLI_ghashIterator_getKey(&gh_iter);
void *newval = NULL;
switch (type) {
case BM_VERT: {
BMLogVert *lv = BLI_ghashIterator_getValue(&gh_iter);
BMLogVert *lv2 = BLI_mempool_alloc(entry->pool_verts);
*lv2 = *lv;
if (lv2->customdata) {
void *cdata = BLI_mempool_alloc(entry->vdata.pool);
memcpy(cdata, lv->customdata, entry->vdata.totsize);
lv2->customdata = cdata;
}
newval = (void *)lv2;
break;
}
case BM_EDGE: {
BMLogEdge *le = BLI_ghashIterator_getValue(&gh_iter);
BMLogEdge *le2 = BLI_mempool_alloc(entry->pool_edges);
*le2 = *le;
if (le2->customdata) {
void *cdata = BLI_mempool_alloc(entry->edata.pool);
memcpy(cdata, le->customdata, entry->edata.totsize);
le2->customdata = cdata;
}
newval = (void *)le2;
break;
}
case BM_FACE: {
BMLogFace *lf = BLI_ghashIterator_getValue(&gh_iter);
BMLogFace *lf2 = BLI_mempool_alloc(entry->pool_faces);
*lf2 = *lf;
if (lf2->customdata_f) {
void *cdata = BLI_mempool_alloc(entry->pdata.pool);
memcpy(cdata, lf->customdata_f, entry->pdata.totsize);
lf2->customdata_f = cdata;
}
for (int i = 0; i < lf->len; i++) {
if (lf->customdata[i]) {
lf2->customdata[i] = BLI_mempool_alloc(entry->ldata.pool);
memcpy(lf2->customdata[i], lf->customdata[i], entry->ldata.totsize);
}
}
newval = (void *)lf2;
break;
}
}
BLI_ghash_insert(ghash2, key, newval);
}
return ghash2;
}
ATTR_NO_OPT static BMLogEntry *bm_log_entry_clone_intern(BMLogEntry *entry, BMLog *newlog)
{
BMLogEntry *newentry = MEM_callocN(sizeof(*entry), "BMLogEntry cloned");
*newentry = *entry;
newentry->combined_next = newentry->combined_prev = newentry->next = newentry->prev = NULL;
if (entry->type == LOG_ENTRY_PARTIAL) {
newentry->pool_verts = BLI_mempool_create(sizeof(BMLogVert), 0, 64, BLI_MEMPOOL_NOP);
newentry->pool_edges = BLI_mempool_create(sizeof(BMLogEdge), 0, 64, BLI_MEMPOOL_NOP);
newentry->pool_faces = BLI_mempool_create(sizeof(BMLogFace), 0, 64, BLI_MEMPOOL_NOP);
CustomData *cdata = &newentry->vdata;
for (int i = 0; i < 4; i++) {
cdata->pool = NULL;
CustomData_bmesh_init_pool(cdata, 0, 1 << i);
}
entry->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "bmlog arena");
newentry->modified_verts = bm_clone_ghash(newentry, entry->modified_verts, BM_VERT);
newentry->topo_modified_verts_pre = bm_clone_ghash(
newentry, entry->topo_modified_verts_pre, BM_VERT);
newentry->topo_modified_verts_post = bm_clone_ghash(
newentry, entry->topo_modified_verts_post, BM_VERT);
newentry->modified_edges = bm_clone_ghash(newentry, entry->modified_edges, BM_EDGE);
newentry->topo_modified_edges_pre = bm_clone_ghash(
newentry, entry->topo_modified_edges_pre, BM_EDGE);
newentry->topo_modified_edges_post = bm_clone_ghash(
newentry, entry->topo_modified_edges_post, BM_EDGE);
newentry->modified_faces = bm_clone_ghash(newentry, entry->modified_faces, BM_FACE);
newentry->topo_modified_faces_pre = bm_clone_ghash(
newentry, entry->topo_modified_faces_pre, BM_FACE);
newentry->topo_modified_faces_post = bm_clone_ghash(
newentry, entry->topo_modified_faces_post, BM_FACE);
newentry->log = newlog;
}
return newentry;
}
ATTR_NO_OPT static BMLogEntry *bm_log_entry_clone(BMLogEntry *entry, BMLog *newlog)
{
BMLogEntry *cur = entry;
BMLogEntry *ret = NULL;
BMLogEntry *last = NULL;
while (cur) {
BMLogEntry *cpy = bm_log_entry_clone_intern(cur, newlog);
if (!ret) {
ret = cpy;
}
if (last) {
last->combined_prev = cpy;
cpy->combined_next = last;
}
last = cpy;
cur = cur->combined_prev;
}
return ret;
}
#include <stdarg.h>
ATTR_NO_OPT static void debuglog(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
static const char *elem_type_to_str(int type)
{
switch (type) {
case BM_VERT:
return "vertex";
case BM_EDGE:
return "edge";
case BM_LOOP:
return "loop";
case BM_FACE:
return "face";
default:
return "(error)";
}
}
static bool check_log_elem(BMesh *bm, BMLog *newlog, int id, int type, bool expected)
{
/* id should be in mesh and of right type */
BMElem *elem = bm_log_elem_from_id(newlog, id);
if (!!elem != expected) {
debuglog("Missing %s %d\n", elem_type_to_str(type), id);
return false;
}
else if (elem && (elem->head.htype == type) != expected) {
debuglog("Expected %s at id %d; got %s instead\n",
elem_type_to_str(type),
id,
elem_type_to_str(elem->head.htype));
return false;
}
return true;
}
static bool bm_check_ghash_set(
GHash *ghashes[4], BMesh *bm, BMLog *newlog, BMLogEntry *entry, bool shouldExist)
{
bool ok = true;
for (int i = 0; i < 4; i++) {
if (!ghashes[i]) {
continue;
}
int type = 1 << i;
GHashIterator gh_iter;
GHASH_ITER (gh_iter, ghashes[i]) {
void *key = BLI_ghashIterator_getKey(&gh_iter);
uint id = POINTER_AS_UINT(key);
if (!check_log_elem(bm, newlog, id, type, shouldExist)) {
ok = false;
continue;
}
if (type == BM_EDGE) {
BMLogEdge *le = (BMLogEdge *)BLI_ghashIterator_getValue(&gh_iter);
ok = ok && check_log_elem(bm, newlog, le->v1, BM_VERT, shouldExist);
}
else if (type == BM_FACE) {
BMLogFace *lf = (BMLogFace *)BLI_ghashIterator_getValue(&gh_iter);
for (int i = 0; i < lf->len; i++) {
ok = ok && check_log_elem(bm, newlog, lf->v_ids[i], BM_VERT, shouldExist);
}
}
}
}
return ok;
}
ATTR_NO_OPT static bool bm_log_validate_intern(
BMesh *bm, BMLog *newlog, BMLogEntry *srcEntry, bool is_applied, bool do_apply)
{
bool precopy = do_apply;
if (srcEntry->type != LOG_ENTRY_PARTIAL) {
printf("%s: not a partial log entry!\n", __func__);
return true;
}
BMLogEntry *entry = precopy ? bm_log_entry_clone(srcEntry, newlog) : srcEntry;
bool ok = true;
GHash *ghashes1[] = {entry->topo_modified_verts_pre,
entry->topo_modified_edges_pre,
NULL,
entry->topo_modified_faces_pre};
GHash *ghashes2[] = {entry->topo_modified_verts_post,
entry->topo_modified_edges_post,
NULL,
entry->topo_modified_faces_post};
if (!is_applied) {
ok = ok && bm_check_ghash_set(ghashes2, bm, newlog, entry, true);
}
else {
ok = ok && bm_check_ghash_set(ghashes1, bm, newlog, entry, true);
}
int iters[4] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, -1, BM_FACES_OF_MESH};
for (int i = 0; i < 4; i++) {
// int type = 1 << i;
BMIter iter;
BMElem *elem;
if (i == 2) { // skip loops
continue;
}
BM_ITER_MESH (elem, &iter, bm, iters[i]) {
uint id = BM_ELEM_GET_ID(bm, elem);
void *key = POINTER_FROM_UINT(id);
bool exist1 = BLI_ghash_haskey(ghashes1[i], POINTER_FROM_UINT(id));
bool exist2 = BLI_ghash_haskey(ghashes2[i], POINTER_FROM_UINT(id));
for (int j = 0; j < 4; j++) {
if (j != i && ghashes1[j] && BLI_ghash_haskey(ghashes1[j], key) && exist1) {
int type1 = 1 << i;
int type2 = 1 << j;
debuglog("pre: id %d used by multiple element types: %s and %s\n",
elem_type_to_str(type1),
elem_type_to_str(type2));
}
if (j != i && ghashes2[j] && BLI_ghash_haskey(ghashes2[j], key) && exist2) {
int type1 = 1 << i;
int type2 = 1 << j;
debuglog("post: id %d used by multiple element types: %s and %s\n",
elem_type_to_str(type1),
elem_type_to_str(type2));
}
}
if (is_applied) {
}
else {
/*element should exist in post but not in pre, or in neither*/
if (exist1 && !exist2) {
debuglog("element %u:%s should not exist\n", id, elem_type_to_str(1 << i));
// debuglog("%s %u existes in both pre and post log sets!\n", elem_type_to_str(type),
// id); ok = false;
}
}
}
}
if (do_apply) {
if (!is_applied) {
bm_log_undo_intern(bm, newlog, entry, NULL, "_dyntopo_node_id");
}
else {
bm_log_redo_intern(bm, newlog, entry, NULL, "_dyntopo_node_id");
}
}
if (precopy) {
bm_log_entry_free_direct(entry);
MEM_freeN(entry);
}
return ok;
}
ATTR_NO_OPT bool BM_log_validate_cur(BMLog *log)
{
return BM_log_validate(log->bm, log->current_entry, false);
}
ATTR_NO_OPT bool BM_log_validate(BMesh *inbm, BMLogEntry *entry, bool is_applied)
{
return bm_log_validate_intern(inbm, entry->log, entry, is_applied, false);
BMLogEntry *cur;
bool ret = true;
BMLog newlog = {0};
struct BMeshCreateParams params = {.create_unique_ids = true,
.id_elem_mask = BM_VERT | BM_EDGE | BM_FACE,
.no_reuse_ids = false,
.temporary_ids = false,
.copy_all_layers = true,
.id_map = true};
BMesh *bm = BM_mesh_copy_ex(inbm, &params);
newlog.bm = bm;
newlog.has_edges = true;
newlog.refcount = 1;
newlog.cd_sculpt_vert = entry->log->cd_sculpt_vert;
if (!is_applied) {
cur = entry;
while (cur) {
ret &= bm_log_validate_intern(bm, &newlog, cur, is_applied, true);
cur = cur->combined_prev;
}
}
else {
cur = entry;
while (cur->combined_prev) {
cur = cur->combined_prev;
}
while (cur) {
ret &= bm_log_validate_intern(bm, &newlog, cur, is_applied, true);
cur = cur->combined_next;
}
}
BM_mesh_free(bm);
return ret;
}
bool BM_log_has_vert_pre(BMLog *log, BMVert *v)
{
return BLI_ghash_haskey(log->current_entry->topo_modified_verts_pre,
POINTER_FROM_UINT(BM_ELEM_GET_ID(log->bm, v)));
}
bool BM_log_has_edge_pre(BMLog *log, BMEdge *e)
{
return BLI_ghash_haskey(log->current_entry->topo_modified_edges_pre,
POINTER_FROM_UINT(BM_ELEM_GET_ID(log->bm, e)));
}
bool BM_log_has_face_pre(BMLog *log, BMFace *f)
{
return BLI_ghash_haskey(log->current_entry->topo_modified_faces_pre,
POINTER_FROM_UINT(BM_ELEM_GET_ID(log->bm, f)));
}
bool BM_log_has_vert_post(BMLog *log, BMVert *v)
{
return BLI_ghash_haskey(log->current_entry->topo_modified_verts_post, POINTER_FROM_UINT(BM_ELEM_GET_ID(log->bm, v)));
}
bool BM_log_has_edge_post(BMLog *log, BMEdge *e)
{
return BLI_ghash_haskey(log->current_entry->topo_modified_edges_post,
POINTER_FROM_UINT(BM_ELEM_GET_ID(log->bm, e)));
}
bool BM_log_has_face_post(BMLog *log, BMFace *f)
{
return BLI_ghash_haskey(log->current_entry->topo_modified_faces_post,
POINTER_FROM_UINT(BM_ELEM_GET_ID(log->bm, f)));
}

View File

@ -275,6 +275,14 @@ bool BM_log_has_vert(BMLog *log, BMVert *v);
bool BM_log_has_edge(BMLog *log, BMEdge *e);
bool BM_log_has_face(BMLog *log, BMFace *f);
bool BM_log_has_vert_post(BMLog *log, BMVert *v);
bool BM_log_has_edge_post(BMLog *log, BMEdge *e);
bool BM_log_has_face_post(BMLog *log, BMFace *f);
bool BM_log_has_vert_pre(BMLog *log, BMVert *v);
bool BM_log_has_edge_pre(BMLog *log, BMEdge *e);
bool BM_log_has_face_pre(BMLog *log, BMFace *f);
/*Log an edge before changing its topological connections*/
void _BM_log_edge_topo_pre(BMLog *log, BMEdge *e, const char *func, int line);
#define BM_log_edge_topo_pre(log, e) _BM_log_edge_topo_pre(log, e, __func__, __LINE__)
@ -296,3 +304,6 @@ void _BM_log_vert_topo_pre(BMLog *log, BMVert *v, const char *func, int line);
void _BM_log_vert_topo_post(BMLog *log, BMVert *v, const char *func, int line);
#define BM_log_vert_topo_post(log, v) _BM_log_vert_topo_post(log, v, __func__, __LINE__)
bool BM_log_validate(BMesh *inbm, BMLogEntry *entry, bool is_applied);
bool BM_log_validate_cur(BMLog *log);

View File

@ -33,7 +33,7 @@ extern "C" {
/* returns positive nonzero on error */
#if 1//def NDEBUG
#ifdef NDEBUG
/* No error checking for release,
* it can take most of the CPU time when running some tools. */
# define BM_CHECK_ELEMENT(el) (void)(el)