Sculpt-dev: fixed edge collapse
* Code needs more cleanup * Added even more debugging tools to bmesh_log.c.
This commit is contained in:
parent
1591c9a978
commit
c9c9b80593
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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, ¶ms);
|
||||
|
||||
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)));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue