Sculpt-dev: fix bmesh python bug

Save and restore python pointers when
adding or removing customdata layers, this is needed
since tool flags are a customdata layer in sculpt-dev.
Reallocating tool flags shouldn't clear python pointers.
This commit is contained in:
Joseph Eagar 2022-06-13 20:13:02 -07:00
parent d54416506a
commit 1cd88104f0
3 changed files with 151 additions and 0 deletions

View File

@ -13,6 +13,7 @@ set(INC
../../../intern/eigen
../../../intern/guardedalloc
../../../extern/rangetree
../python/bmesh
)
set(INC_SYS

View File

@ -1238,6 +1238,9 @@ void BM_vert_interp_from_face(BMesh *bm, BMVert *v_dst, const BMFace *f_src)
CustomData_bmesh_interp(&bm->vdata, blocks, w, NULL, f_src->len, v_dst->head.data);
}
void BPy_bm_new_customdata_layout(BMesh *bm, CustomData *cdata, void *state, char htype);
void *BPy_bm_new_customdata_layout_pre(BMesh *bm, CustomData *cdata, char htype);
static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data)
{
BMIter iter;
@ -1259,6 +1262,7 @@ static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data)
BMVert *eve;
CustomData_bmesh_init_pool_ex(data, bm->totvert, BM_VERT, __func__);
void *state = BPy_bm_new_customdata_layout_pre(bm, olddata, BM_VERT);
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
block = NULL;
@ -1267,11 +1271,15 @@ static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data)
CustomData_bmesh_free_block(olddata, &eve->head.data);
eve->head.data = block;
}
BPy_bm_new_customdata_layout(bm, &bm->vdata, state, BM_VERT);
MEM_SAFE_FREE(state);
}
else if (data == &bm->edata) {
BMEdge *eed;
CustomData_bmesh_init_pool_ex(data, bm->totedge, BM_EDGE, __func__);
void *state = BPy_bm_new_customdata_layout_pre(bm, olddata, BM_EDGE);
BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
block = NULL;
@ -1280,6 +1288,9 @@ static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data)
CustomData_bmesh_free_block(olddata, &eed->head.data);
eed->head.data = block;
}
BPy_bm_new_customdata_layout(bm, &bm->edata, state, BM_EDGE);
MEM_SAFE_FREE(state);
}
else if (data == &bm->ldata) {
BMIter liter;
@ -1287,6 +1298,8 @@ static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data)
BMLoop *l;
CustomData_bmesh_init_pool_ex(data, bm->totloop, BM_LOOP, __func__);
void *state = BPy_bm_new_customdata_layout_pre(bm, olddata, BM_LOOP);
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
block = NULL;
@ -1296,11 +1309,15 @@ static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data)
l->head.data = block;
}
}
BPy_bm_new_customdata_layout(bm, &bm->ldata, state, BM_LOOP);
MEM_SAFE_FREE(state);
}
else if (data == &bm->pdata) {
BMFace *efa;
CustomData_bmesh_init_pool_ex(data, bm->totface, BM_FACE, __func__);
void *state = BPy_bm_new_customdata_layout_pre(bm, olddata, BM_FACE);
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
block = NULL;
@ -1309,6 +1326,9 @@ static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data)
CustomData_bmesh_free_block(olddata, &efa->head.data);
efa->head.data = block;
}
BPy_bm_new_customdata_layout(bm, &bm->pdata, state, BM_FACE);
MEM_SAFE_FREE(state);
}
else {
/* should never reach this! */

View File

@ -5,6 +5,8 @@
* \ingroup pybmesh
*/
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "BLI_sort.h"
@ -4047,6 +4049,134 @@ int bpy_bm_generic_valid_check_source(BMesh *bm_source,
return ret;
}
void *BPy_bm_new_customdata_layout_pre(BMesh *bm, CustomData *cdata, char htype)
{
if (!CustomData_has_layer(cdata, CD_BM_ELEM_PYPTR)) {
return NULL;
}
BLI_mempool *pool = NULL;
int num = 0;
switch (htype) {
case BM_VERT:
pool = bm->vpool;
num = bm->totvert;
break;
case BM_EDGE:
pool = bm->epool;
num = bm->totedge;
break;
case BM_LOOP:
pool = bm->fpool;
num = bm->totloop;
break;
case BM_FACE:
pool = bm->fpool;
num = bm->totface;
break;
}
void **ptrs = MEM_malloc_arrayN(num, sizeof(void *), __func__);
int cd_py = CustomData_get_offset(cdata, CD_BM_ELEM_PYPTR);
BMElem *elem;
BLI_mempool_iter iter;
int i = 0;
if (htype != BM_LOOP) {
BLI_mempool_iternew(pool, &iter);
while ((elem = BLI_mempool_iterstep(&iter))) {
ptrs[i++] = *((void **)BM_ELEM_CD_GET_VOID_P(elem, cd_py));
}
}
else {
BMFace *f;
BLI_mempool_iternew(pool, &iter);
while ((f = BLI_mempool_iterstep(&iter))) {
BMLoop *l = f->l_first;
do {
ptrs[i++] = *((void **)BM_ELEM_CD_GET_VOID_P(l, cd_py));
} while ((l = l->next) != f->l_first);
}
}
return ptrs;
}
ATTR_NO_OPT void BPy_bm_new_customdata_layout(BMesh *bm, CustomData *cdata, void *state, char htype)
{
/*
* Un-invalidate python pointers, which got invalidated when the customdata layout
* changed.
*/
if (!state || !CustomData_has_layer(cdata, CD_BM_ELEM_PYPTR)) {
return;
}
BLI_mempool *pool = NULL;
void **ptrs = (void **)state;
switch (htype) {
case BM_VERT:
pool = bm->vpool;
break;
case BM_EDGE:
pool = bm->epool;
break;
case BM_LOOP:
pool = bm->fpool;
break;
case BM_FACE:
pool = bm->fpool;
break;
}
int cd_py = CustomData_get_offset(cdata, CD_BM_ELEM_PYPTR);
BMElem *elem;
BLI_mempool_iter iter;
int i = 0;
if (htype != BM_LOOP) {
BLI_mempool_iternew(pool, &iter);
while ((elem = BLI_mempool_iterstep(&iter))) {
void **ptr = BM_ELEM_CD_GET_VOID_P(elem, cd_py);
*ptr = ptrs[i++];
BPy_BMGeneric *bpy_ptr = (BPy_BMGeneric *)*ptr;
if (bpy_ptr) {
bpy_ptr->bm = bm;
}
}
}
else {
BMFace *f;
BLI_mempool_iternew(pool, &iter);
while ((f = BLI_mempool_iterstep(&iter))) {
BMLoop *l = f->l_first;
do {
void **ptr = BM_ELEM_CD_GET_VOID_P(l, cd_py);
*ptr = ptrs[i++];
BPy_BMGeneric *bpy_ptr = (BPy_BMGeneric *)*ptr;
if (bpy_ptr) {
bpy_ptr->bm = bm;
}
} while ((l = l->next) != f->l_first);
}
}
}
void bpy_bm_generic_invalidate(BPy_BMGeneric *self)
{
self->bm = NULL;