* BM_mesh_remap can now reorder loops

* Wrote yet another BKE_pbvh_reorder_bmesh function
This commit is contained in:
Joseph Eagar 2021-08-18 21:43:59 -07:00
parent 106f542ac4
commit de1f2c41fa
6 changed files with 496 additions and 8 deletions

View File

@ -48,8 +48,10 @@ Topology rake:
#include "BLI_math.h"
#include "BLI_memarena.h"
#include "BLI_rand.h"
#include "BLI_sort_utils.h"
#include "BLI_task.h"
#include "BLI_utildefines.h"
#include "PIL_time.h"
#include "atomic_ops.h"
@ -1339,6 +1341,87 @@ void BKE_pbvh_recalc_bmesh_boundary(PBVH *pbvh)
}
}
void BKE_pbvh_update_all_boundary_bmesh(PBVH *pbvh)
{
// update boundary flags in a hopefully faster manner then v->e iteration
// XXX or not, it's slower
BMIter iter;
BMEdge *e;
BMVert *v;
const int cd_fset = CustomData_get_offset(&pbvh->bm->pdata, CD_SCULPT_FACE_SETS);
BM_ITER_MESH (v, &iter, pbvh->bm, BM_VERTS_OF_MESH) {
MDynTopoVert *mv = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v);
mv->flag &= ~(DYNVERT_BOUNDARY | DYNVERT_FSET_BOUNDARY | DYNVERT_NEED_BOUNDARY |
DYNVERT_VERT_FSET_HIDDEN);
if (cd_fset >= 0 && v->e && v->e->l) {
mv->flag |= DYNVERT_VERT_FSET_HIDDEN;
}
}
BM_ITER_MESH (e, &iter, pbvh->bm, BM_EDGES_OF_MESH) {
if (!e->l || e->l == e->l->radial_next) {
MDynTopoVert *mv1 = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, e->v1);
MDynTopoVert *mv2 = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, e->v2);
mv1->flag |= DYNVERT_BOUNDARY;
mv2->flag |= DYNVERT_BOUNDARY;
}
if (!e->l) {
continue;
}
if (cd_fset < 0) {
MDynTopoVert *mv1 = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, e->v1);
MDynTopoVert *mv2 = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, e->v2);
BMLoop *l = e->l;
do {
if (l->f->len > 3) {
mv1->flag |= DYNVERT_NEED_TRIANGULATE;
mv2->flag |= DYNVERT_NEED_TRIANGULATE;
break;
}
l = l->radial_next;
} while (l != e->l);
continue;
}
MDynTopoVert *mv1 = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, e->v1);
MDynTopoVert *mv2 = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, e->v2);
BMLoop *l = e->l;
int lastfset = BM_ELEM_CD_GET_INT(l->f, cd_fset);
do {
int fset = BM_ELEM_CD_GET_INT(l->f, cd_fset);
if (l->f->len > 3) {
mv1->flag |= DYNVERT_NEED_TRIANGULATE;
mv2->flag |= DYNVERT_NEED_TRIANGULATE;
}
if (fset > 0) {
MDynTopoVert *mv = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, l->v);
mv->flag &= ~DYNVERT_VERT_FSET_HIDDEN;
}
if (lastfset != fset) {
mv1->flag |= DYNVERT_FSET_BOUNDARY;
mv2->flag |= DYNVERT_FSET_BOUNDARY;
}
lastfset = fset;
l = l->radial_next;
} while (l != e->l);
}
}
/* Build a PBVH from a BMesh */
void BKE_pbvh_build_bmesh(PBVH *pbvh,
BMesh *bm,
@ -1373,6 +1456,8 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh,
BMIter iter;
BMVert *v;
// BKE_pbvh_update_all_boundary_bmesh(pbvh);
int cd_vcol_offset = CustomData_get_offset(&bm->vdata, CD_PROP_COLOR);
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
@ -2558,6 +2643,316 @@ static void scan_edge_split(BMesh *bm, BMEdge **edges, int totedge)
BLI_array_free(fmap);
}
#define MAX_RE_CHILD 3
typedef struct ReVertNode {
int totvert, totchild;
struct ReVertNode *parent;
struct ReVertNode *children[MAX_RE_CHILD];
BMVert *verts[];
} ReVertNode;
ATTR_NO_OPT BMesh *BKE_pbvh_reorder_bmesh(PBVH *pbvh)
{
/*try to compute size of verts per node*/
int vsize = sizeof(BMVert);
vsize += pbvh->bm->vdata.totsize;
// perhaps aim for l2 cache?
const int limit = 1024;
int leaf_limit = MAX2(limit / vsize, 4);
const int cd_vcol = CustomData_get_offset(&pbvh->bm->vdata, CD_PROP_COLOR);
BLI_mempool *pool = BLI_mempool_create(sizeof(ReVertNode) + sizeof(void *) * vsize, 0, 8192, 0);
ReVertNode **vnodemap = MEM_calloc_arrayN(pbvh->bm->totvert, sizeof(void *), "vnodemap");
printf("leaf_limit: %d\n", leaf_limit);
BMIter iter;
BMVert *v;
const char flag = BM_ELEM_TAG_ALT;
int i = 0;
BM_ITER_MESH (v, &iter, pbvh->bm, BM_VERTS_OF_MESH) {
BM_elem_flag_disable(v, flag);
v->head.index = i++;
}
BMVert **stack = NULL;
BLI_array_declare(stack);
BM_ITER_MESH (v, &iter, pbvh->bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(v, flag)) {
continue;
}
ReVertNode *node = BLI_mempool_calloc(pool);
BLI_array_clear(stack);
BLI_array_append(stack, v);
BM_elem_flag_enable(v, flag);
vnodemap[v->head.index] = node;
node->verts[node->totvert++] = v;
while (BLI_array_len(stack) > 0) {
BMVert *v2 = BLI_array_pop(stack);
BMEdge *e;
if (node->totvert >= leaf_limit) {
break;
}
if (!v2->e) {
continue;
}
int len = node->totvert;
e = v2->e;
do {
BMVert *v3 = BM_edge_other_vert(e, v2);
if (!BM_elem_flag_test(v3, flag) && len < leaf_limit) {
BM_elem_flag_enable(v3, flag);
vnodemap[v3->head.index] = node;
node->verts[node->totvert++] = v3;
len++;
BLI_array_append(stack, v3);
}
e = e->v1 == v2 ? e->v1_disk_link.next : e->v2_disk_link.next;
} while (e != v2->e);
}
}
const int steps = 4;
ReVertNode **roots = NULL;
BLI_array_declare(roots);
for (int step = 0; step < steps; step++) {
const bool last_step = step == steps - 1;
BM_ITER_MESH_INDEX (v, &iter, pbvh->bm, BM_VERTS_OF_MESH, i) {
BMEdge *e = v->e;
if (!e) {
continue;
}
ReVertNode *node = vnodemap[v->head.index];
if (node->parent) {
continue;
}
ReVertNode *other_node = NULL;
ReVertNode *parent = BLI_mempool_calloc(pool);
parent->children[0] = node;
parent->totchild = 1;
do {
BMVert *v2 = BM_edge_other_vert(e, v);
ReVertNode *node2 = vnodemap[v2->head.index];
bool ok = node != node2 && !node2->parent;
for (int j = 0; j < parent->totchild; j++) {
if (parent->children[j] == node2) {
ok = false;
break;
}
}
if (ok) {
parent->children[parent->totchild++] = node2;
break;
}
e = e->v1 == v ? e->v1_disk_link.next : e->v2_disk_link.next;
} while (e != v->e);
if (parent->totchild == 1) {
BLI_mempool_free(pool, parent);
continue;
}
if (last_step) {
BLI_array_append(roots, parent);
}
for (int j = 0; j < parent->totchild; j++) {
parent->children[j]->parent = parent;
}
}
BM_ITER_MESH_INDEX (v, &iter, pbvh->bm, BM_VERTS_OF_MESH, i) {
while (vnodemap[i]->parent) {
vnodemap[i] = vnodemap[i]->parent;
}
}
}
BLI_mempool_iter loopiter;
BLI_mempool_iternew(pbvh->bm->lpool, &loopiter);
BMLoop *l = BLI_mempool_iterstep(&loopiter);
BMEdge *e;
BMFace *f;
for (i = 0; l; l = BLI_mempool_iterstep(&loopiter), i++) {
l->head.hflag &= ~flag;
}
BM_ITER_MESH (e, &iter, pbvh->bm, BM_EDGES_OF_MESH) {
e->head.hflag &= ~flag;
}
BM_ITER_MESH (f, &iter, pbvh->bm, BM_FACES_OF_MESH) {
f->head.hflag &= ~flag;
}
int totroot = BLI_array_len(roots);
ReVertNode **nstack = NULL;
BLI_array_declare(nstack);
int vorder = 0, eorder = 0, lorder = 0, forder = 0;
for (i = 0; i < totroot; i++) {
BLI_array_clear(nstack);
ReVertNode *node = roots[i];
BLI_array_append(nstack, node);
while (BLI_array_len(nstack) > 0) {
ReVertNode *node2 = BLI_array_pop(nstack);
if (node2->totchild == 0) {
for (int j = 0; j < node2->totvert; j++) {
v = node2->verts[j];
#if 0
if (cd_vcol >= 0) {
MPropCol *col = BM_ELEM_CD_GET_VOID_P(node2->verts[j], cd_vcol);
float r = 0.0f, g = 0.0f, b = 0.0f;
unsigned int p = (unsigned int)node2->parent;
p = p % 65535;
unsigned int p2 = (unsigned int)node2->parent;
p2 = p2 % 65535;
r = ((float)vorder) * 0.01;
g = ((float)p2) / 65535.0f;
b = ((float)p) / 65535.0f;
r = cosf(r * 17.2343) * 0.5 + 0.5;
g = cosf(g * 11.2343) * 0.5 + 0.5;
b = cosf(b * 19.2343) * 0.5 + 0.5;
col->color[0] = r;
col->color[1] = g;
col->color[2] = b;
col->color[3] = 1.0f;
}
#endif
v->head.index = vorder++;
BMEdge *e = v->e;
if (!e) {
continue;
}
do {
if (!(e->head.hflag & flag)) {
e->head.hflag |= flag;
e->head.index = eorder++;
}
if (e->l) {
BMLoop *l = e->l;
do {
if (!(l->head.hflag & flag)) {
l->head.hflag |= flag;
l->head.index = lorder++;
}
if (!(l->f->head.hflag & flag)) {
l->f->head.hflag |= flag;
l->f->head.index = forder++;
}
l = l->radial_next;
} while (l != e->l);
}
e = e->v1 == v ? e->v1_disk_link.next : e->v2_disk_link.next;
} while (e != v->e);
}
}
else {
for (int j = 0; j < node2->totchild; j++) {
BLI_array_append(nstack, node2->children[j]);
}
}
}
}
uint *vidx, *eidx, *lidx, *fidx;
vidx = MEM_malloc_arrayN(pbvh->bm->totvert, sizeof(*vidx), "vorder");
eidx = MEM_malloc_arrayN(pbvh->bm->totedge, sizeof(*eidx), "eorder");
lidx = MEM_malloc_arrayN(pbvh->bm->totloop, sizeof(*lidx), "lorder");
fidx = MEM_malloc_arrayN(pbvh->bm->totface, sizeof(*fidx), "forder");
printf("v %d %d\n", vorder, pbvh->bm->totvert);
printf("e %d %d\n", eorder, pbvh->bm->totedge);
printf("l %d %d\n", lorder, pbvh->bm->totloop);
printf("f %d %d\n", forder, pbvh->bm->totface);
BM_ITER_MESH_INDEX (v, &iter, pbvh->bm, BM_VERTS_OF_MESH, i) {
vidx[i] = (uint)v->head.index;
}
BM_ITER_MESH_INDEX (e, &iter, pbvh->bm, BM_EDGES_OF_MESH, i) {
eidx[i] = (uint)e->head.index;
}
BM_ITER_MESH_INDEX (f, &iter, pbvh->bm, BM_FACES_OF_MESH, i) {
fidx[i] = (uint)f->head.index;
}
BLI_mempool_iternew(pbvh->bm->lpool, &loopiter);
l = BLI_mempool_iterstep(&loopiter);
for (i = 0; l; l = BLI_mempool_iterstep(&loopiter), i++) {
// handle orphaned loops
if (!(l->head.hflag & flag)) {
printf("warning in %s: orphaned loop!\n", __func__);
l->head.index = lorder++;
}
lidx[i] = (uint)l->head.index;
}
BM_mesh_remap(pbvh->bm, vidx, eidx, fidx, lidx);
printf("roots: %d\n", BLI_array_len(roots));
MEM_SAFE_FREE(vidx);
MEM_SAFE_FREE(eidx);
MEM_SAFE_FREE(lidx);
MEM_SAFE_FREE(fidx);
MEM_SAFE_FREE(nstack);
MEM_SAFE_FREE(roots);
BLI_mempool_destroy(pool);
MEM_SAFE_FREE(stack);
MEM_SAFE_FREE(vnodemap);
return pbvh->bm;
}
BMesh *BKE_pbvh_reorder_bmesh2(PBVH *pbvh)
{
if (BKE_pbvh_type(pbvh) != PBVH_BMESH || pbvh->totnode == 0) {
@ -2826,7 +3221,7 @@ static int sort_edges(const void *va, const void *vb)
return (ni1 + ni2) - (ni3 + ni4);
}
BMesh *BKE_pbvh_reorder_bmesh(PBVH *pbvh)
BMesh *BKE_pbvh_reorder_bmesh1(PBVH *pbvh)
{
BMesh *bm = pbvh->bm;
@ -2920,7 +3315,7 @@ BMesh *BKE_pbvh_reorder_bmesh(PBVH *pbvh)
faces[i].elem->head.index = faces[i].index;
}
BM_mesh_remap(bm, vs, es, fs);
BM_mesh_remap(bm, vs, es, fs, NULL);
// create new mappings
BMVert **mapvs = MEM_malloc_arrayN(bm->totvert, sizeof(BMVert *), __func__);

View File

@ -1200,7 +1200,7 @@ void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
}
BLI_ghash_free(id_to_idx, NULL, NULL);
BM_mesh_remap(bm, varr, NULL, farr);
BM_mesh_remap(bm, varr, NULL, farr, NULL);
MEM_freeN(varr);
MEM_freeN(farr);

View File

@ -72,7 +72,7 @@ static void bm_mempool_init_ex(const BMAllocTemplate *allocsize,
}
if (r_lpool) {
*r_lpool = BLI_mempool_create(
loop_size, allocsize->totloop, bm_mesh_chunksize_default.totloop, BLI_MEMPOOL_NOP);
loop_size, allocsize->totloop, bm_mesh_chunksize_default.totloop, BLI_MEMPOOL_ALLOW_ITER);
}
if (r_fpool) {
*r_fpool = BLI_mempool_create(
@ -875,7 +875,11 @@ int BM_mesh_elem_count(BMesh *bm, const char htype)
* \warning Be careful if you keep pointers to affected BM elements,
* or arrays, when using this func!
*/
void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const uint *face_idx)
void BM_mesh_remap(BMesh *bm,
const uint *vert_idx,
const uint *edge_idx,
const uint *face_idx,
const uint *loop_idx)
{
/* Mapping old to new pointers. */
GHash *vptr_map = NULL, *eptr_map = NULL, *fptr_map = NULL;
@ -944,6 +948,70 @@ void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const
}
}
GHash *lptr_map = NULL;
/* Remap Loops */
if (loop_idx) {
BMLoop **ltable = MEM_malloc_arrayN(bm->totloop, sizeof(*ltable), "ltable");
BMLoop *ed;
BLI_mempool_iter liter;
BLI_mempool_iternew(bm->lpool, &liter);
BMLoop *l = (BMLoop *)BLI_mempool_iterstep(&liter);
int i = 0;
for (; l; l = (BMLoop *)BLI_mempool_iterstep(&liter), i++) {
l->head.index = i;
ltable[i] = l;
}
BMLoop **loops_pool, *loops_copy, **edl;
int totloop = bm->totloop;
const uint *new_idx;
/* Special case: Python uses custom data layers to hold PyObject references.
* These have to be kept in place, else the PyObjects we point to, won't point back to us. */
const int cd_loop_pyptr = CustomData_get_offset(&bm->ldata, CD_BM_ELEM_PYPTR);
/* Init the old-to-new vert pointers mapping */
lptr_map = BLI_ghash_ptr_new_ex("BM_mesh_remap loop pointers mapping", bm->totloop);
/* Make a copy of all vertices. */
loops_pool = ltable;
loops_copy = MEM_mallocN(sizeof(BMLoop) * totloop, "BM_mesh_remap loops copy");
void **pyptrs = (cd_loop_pyptr != -1) ? MEM_mallocN(sizeof(void *) * totloop, __func__) : NULL;
for (i = totloop, ed = loops_copy + totloop - 1, edl = loops_pool + totloop - 1; i--;
ed--, edl--) {
*ed = **edl;
if (cd_loop_pyptr != -1) {
void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)ed), cd_loop_pyptr);
pyptrs[i] = *pyptr;
}
}
/* Copy back verts to their new place, and update old2new pointers mapping. */
new_idx = loop_idx + totloop - 1;
ed = loops_copy + totloop - 1;
edl = loops_pool + totloop - 1; /* old, org pointer */
for (i = totloop; i--; new_idx--, ed--, edl--) {
BMLoop *new_edl = loops_pool[*new_idx];
*new_edl = *ed;
BLI_ghash_insert(lptr_map, *edl, new_edl);
#if 0
printf(
"mapping loop from %d to %d (%p/%p to %p)\n", i, *new_idx, *edl, loops_pool[i], new_edl);
#endif
if (cd_loop_pyptr != -1) {
void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)new_edl), cd_loop_pyptr);
*pyptr = pyptrs[*new_idx];
}
}
MEM_SAFE_FREE(ltable);
MEM_SAFE_FREE(loops_copy);
MEM_SAFE_FREE(pyptrs);
}
/* Remap Edges */
if (edge_idx) {
BMEdge **edges_pool, *edges_copy, **edp;
@ -976,6 +1044,11 @@ void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const
for (i = totedge; i--; new_idx--, ed--, edp--) {
BMEdge *new_edp = edges_pool[*new_idx];
*new_edp = *ed;
if (new_edp->l && lptr_map) {
new_edp->l = BLI_ghash_lookup(lptr_map, (BMLoop *)new_edp->l);
}
BLI_ghash_insert(eptr_map, *edp, new_edp);
#if 0
printf(
@ -1028,6 +1101,22 @@ void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const
BMFace *new_fap = faces_pool[*new_idx];
*new_fap = *fa;
BLI_ghash_insert(fptr_map, *fap, new_fap);
if (lptr_map) {
new_fap->l_first = BLI_ghash_lookup(lptr_map, (void *)new_fap->l_first);
BMLoop *l = new_fap->l_first;
do {
l->next = BLI_ghash_lookup(lptr_map, (void *)l->next);
l->prev = BLI_ghash_lookup(lptr_map, (void *)l->prev);
l->radial_next = BLI_ghash_lookup(lptr_map, (void *)l->radial_next);
l->radial_prev = BLI_ghash_lookup(lptr_map, (void *)l->radial_prev);
l = l->next;
} while (l != new_fap->l_first);
}
if (cd_poly_pyptr != -1) {
void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)new_fap), cd_poly_pyptr);
*pyptr = pyptrs[*new_idx];

View File

@ -99,7 +99,11 @@ BMFace *BM_face_at_index_find_or_table(BMesh *bm, const int index);
int BM_mesh_elem_count(BMesh *bm, const char htype);
void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const uint *face_idx);
void BM_mesh_remap(BMesh *bm,
const uint *vert_idx,
const uint *edge_idx,
const uint *face_idx,
const uint *loop_idx);
void BM_mesh_rebuild(BMesh *bm,
const struct BMeshCreateParams *params,

View File

@ -7105,7 +7105,7 @@ static void sort_bmelem_flag(bContext *C,
}
}
BM_mesh_remap(em->bm, map[0], map[1], map[2]);
BM_mesh_remap(em->bm, map[0], map[1], map[2], NULL);
DEG_id_tag_update(ob->data, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);

View File

@ -2764,7 +2764,7 @@ static PyObject *bpy_bmelemseq_sort(BPy_BMElemSeq *self, PyObject *args, PyObjec
return NULL;
}
BM_mesh_remap(bm, vert_idx, edge_idx, face_idx);
BM_mesh_remap(bm, vert_idx, edge_idx, face_idx, NULL);
PyMem_FREE(elem_map_idx);
PyMem_FREE(elem_idx);