Sculpt dyntopo: Added a function to add multiple customdata

layers to a bmesh at once.  Helpful since bmesh customdata
layers are allocated in single blocks, thus adding
layers individually can lead to lots of memory
copying.
This commit is contained in:
Joseph Eagar 2021-06-26 19:12:07 -07:00
parent dba4f30328
commit 27986e9b56
3 changed files with 115 additions and 17 deletions

View File

@ -1336,6 +1336,102 @@ static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data)
}
}
ATTR_NO_OPT void BM_data_layers_ensure(BMesh *bm,
CustomData *data,
BMCustomLayerReq *layers,
int totlayer)
{
bool modified = false;
CustomData old = *data;
CustomData temp;
CustomDataMask mask = 0;
if (old.layers) {
old.layers = MEM_dupallocN(old.layers);
}
memset(&temp, 0, sizeof(temp));
CustomData_reset(&temp);
for (int i = 0; i < totlayer; i++) {
BMCustomLayerReq *req = layers + i;
int idx;
mask |= 1ULL << (CustomDataMask)req->type;
if (req->name) {
idx = CustomData_get_named_layer_index(data, req->type, req->name);
}
else {
idx = CustomData_get_layer_index(data, req->type);
}
if (idx < 0) {
modified = true;
if (req->name) {
CustomData_add_layer_named(&temp, req->type, CD_ASSIGN, NULL, 0, req->name);
}
else {
CustomData_add_layer(&temp, req->type, CD_ASSIGN, NULL, 0);
}
}
}
int htype;
if (data == &bm->vdata) {
htype = BM_VERT;
}
else if (data == &bm->edata) {
htype = BM_EDGE;
}
else if (data == &bm->ldata) {
htype = BM_LOOP;
}
else if (data == &bm->pdata) {
htype = BM_FACE;
}
else {
printf("error in %s!\n", __func__);
CustomData_free(&temp, 0);
return;
}
if (modified) {
CustomData_merge(&temp, data, mask, CD_ASSIGN, 0);
}
for (int i = 0; i < totlayer; i++) {
BMCustomLayerReq *req = layers + i;
int idx;
mask |= 1 << req->type;
if (req->name) {
idx = CustomData_get_named_layer_index(data, req->type, req->name);
}
else {
idx = CustomData_get_layer_index(data, req->type);
}
data->layers[idx].flag |= req->flag;
}
if (modified) {
/* the pool is now owned by olddata and must not be shared */
data->pool = NULL;
update_data_blocks(bm, &old, data);
bm_update_idmap_cdlayers(bm);
}
if (old.layers) {
MEM_freeN(old.layers);
}
CustomData_free(&temp, 0);
}
void BM_data_layer_add(BMesh *bm, CustomData *data, int type)
{
CustomData olddata;

View File

@ -24,6 +24,12 @@
struct LinkNode;
struct MemArena;
typedef struct BMCustomLayerReq {
int type;
char *name; // can be NULL
int flag;
} BMCustomLayerReq;
void BM_face_multires_stitch(BMesh *bm, BMFace *f);
void BM_loop_interp_multires_ex(BMesh *bm,
BMLoop *l_dst,
@ -53,6 +59,9 @@ void BM_data_interp_face_vert_edge(BMesh *bm,
BMVert *v,
BMEdge *e,
const float fac);
void BM_data_layers_ensure(BMesh *bm, CustomData *data, BMCustomLayerReq *layers, int totlayer);
void BM_data_layer_add(BMesh *bm, CustomData *data, int type);
void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const char *name);
void BM_data_layer_free(BMesh *bm, CustomData *data, int type);

View File

@ -296,18 +296,11 @@ void SCULPT_dyntopo_node_layers_add(SculptSession *ss)
int cd_origco_index, cd_origno_index, cd_origvcol_index = -1;
bool have_vcol = CustomData_has_layer(&ss->bm->vdata, CD_PROP_COLOR);
if (!CustomData_has_layer(&ss->bm->vdata, CD_DYNTOPO_VERT)) {
BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_DYNTOPO_VERT);
BMCustomLayerReq vlayers[] = {{CD_PAINT_MASK, NULL, 0},
{CD_DYNTOPO_VERT, NULL, CD_FLAG_TEMPORARY},
{CD_PROP_INT32, dyntopop_node_idx_layer_id, CD_FLAG_TEMPORARY}};
int cd_dyn_vert = CustomData_get_layer_index(&ss->bm->vdata, CD_DYNTOPO_VERT);
ss->bm->vdata.layers[cd_dyn_vert].flag |= CD_FLAG_TEMPORARY;
}
cd_node_layer_index = CustomData_get_named_layer_index(
&ss->bm->vdata, CD_PROP_INT32, dyntopop_node_idx_layer_id);
if (cd_node_layer_index == -1) {
BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_INT32, dyntopop_node_idx_layer_id);
}
BM_data_layers_ensure(ss->bm, &ss->bm->vdata, vlayers, 3);
cd_face_node_layer_index = CustomData_get_named_layer_index(
&ss->bm->pdata, CD_PROP_INT32, dyntopop_node_idx_layer_id);
@ -513,8 +506,6 @@ void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene
#endif
SCULPT_dynamic_topology_triangulate(ss, ss->bm);
BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
SCULPT_dyntopo_node_layers_add(ss);
SCULPT_dyntopo_save_origverts(ss);
@ -527,10 +518,12 @@ void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene
// convert layer brush data
if (ss->persistent_base) {
SCULPT_dyntopo_ensure_templayer(ss, CD_PROP_FLOAT3, SCULPT_LAYER_PERS_CO);
SCULPT_dyntopo_ensure_templayer(ss, CD_PROP_FLOAT3, SCULPT_LAYER_PERS_NO);
SCULPT_dyntopo_ensure_templayer(ss, CD_PROP_FLOAT, SCULPT_LAYER_PERS_DISP);
SCULPT_dyntopo_ensure_templayer(ss, CD_PROP_FLOAT, SCULPT_LAYER_DISP);
BMCustomLayerReq layers[] = {{CD_PROP_FLOAT3, SCULPT_LAYER_PERS_CO, CD_FLAG_TEMPORARY},
{CD_PROP_FLOAT3, SCULPT_LAYER_PERS_NO, CD_FLAG_TEMPORARY},
{CD_PROP_FLOAT, SCULPT_LAYER_PERS_DISP, CD_FLAG_TEMPORARY},
{CD_PROP_FLOAT, SCULPT_LAYER_DISP, CD_FLAG_TEMPORARY}};
BM_data_layers_ensure(ss->bm, &ss->bm->vdata, layers, 4);
cd_pers_co = SCULPT_dyntopo_get_templayer(ss, CD_PROP_FLOAT3, SCULPT_LAYER_PERS_CO);
cd_pers_no = SCULPT_dyntopo_get_templayer(ss, CD_PROP_FLOAT3, SCULPT_LAYER_PERS_NO);