sculpt-dev: part one of new id system for dyntopo

This commit is contained in:
Joseph Eagar 2022-11-22 12:39:49 -08:00
parent 8a4d2eb670
commit e19d6d2f18
5 changed files with 437 additions and 6 deletions

View File

@ -220,6 +220,7 @@ struct LayerTypeInfo {
/** a function to determine max allowed number of layers,
* should be null or return -1 if no limit */
int (*layers_max)();
bool use_default_data;
};
/** \} */
@ -1848,7 +1849,21 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
nullptr,
nullptr,
layerInterp_propInt,
nullptr},
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
true},
/* 12: CD_PROP_STRING */
{sizeof(MStringProperty),
"MStringProperty",
@ -2624,6 +2639,10 @@ bool CustomData_merge(const CustomData *source,
}
if (newlayer) {
if (layer->default_data) {
newlayer->default_data = MEM_dupallocN(layer->default_data);
}
newlayer->uid = layer->uid;
newlayer->active = lastactive;
@ -2759,6 +2778,10 @@ static void customData_free_layer__internal(CustomDataLayer *layer, const int to
if (layer->data) {
MEM_freeN(layer->data);
}
if (layer->default_data) {
MEM_freeN(layer->default_data);
}
}
}
@ -4295,7 +4318,7 @@ static void CustomData_bmesh_alloc_block(CustomData *data, void **block)
ptr += cd_tflags;
MToolFlags *flags = (MToolFlags *)ptr;
flags->flag = NULL;
flags->flag = nullptr;
}
}
else {
@ -4345,7 +4368,12 @@ static void CustomData_bmesh_set_default_n(CustomData *data, void **block, const
typeInfo->set_default_value(POINTER_OFFSET(*block, offset), 1);
}
else {
memset(POINTER_OFFSET(*block, offset), 0, typeInfo->size);
if (typeInfo->use_default_data && data->layers[n].default_data) {
memcpy(POINTER_OFFSET(*block, offset), data->layers[n].default_data, typeInfo->size);
}
else {
memset(POINTER_OFFSET(*block, offset), 0, typeInfo->size);
}
}
}
@ -4850,9 +4878,16 @@ void CustomData_bmesh_interp(CustomData *data,
1);
}
else {
memcpy(POINTER_OFFSET(dst_block, layer->offset),
POINTER_OFFSET(src_blocks[0], layer->offset),
typeInfo->size);
if (layer->default_data && typeInfo->use_default_data) {
memcpy(POINTER_OFFSET(dst_block, layer->offset),
layer->default_data,
typeInfo->size);
}
else {
memcpy(POINTER_OFFSET(dst_block, layer->offset),
POINTER_OFFSET(src_blocks[0], layer->offset),
typeInfo->size);
}
}
}
@ -5846,6 +5881,12 @@ void CustomData_blend_write(BlendWriter *writer,
writer, CustomDataLayer, data->totlayer, data->layers, layers_to_write.data());
for (const CustomDataLayer &layer : layers_to_write) {
const LayerTypeInfo *typeInfo = layerType_getInfo(layer.type);
if (typeInfo->use_default_data && layer.default_data) {
BLO_write_struct_by_name(writer, typeInfo->structname, layer.default_data);
}
switch (layer.type) {
case CD_MDEFORMVERT:
BKE_defvert_blend_write(writer, count, static_cast<const MDeformVert *>(layer.data));
@ -5956,6 +5997,14 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, const int
int i = 0;
while (i < data->totlayer) {
CustomDataLayer *layer = &data->layers[i];
const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
if (layer->default_data && typeInfo->use_default_data) {
BLO_read_data_address(reader, &layer->default_data);
}
else {
layer->default_data = nullptr;
}
if (layer->flag & CD_FLAG_EXTERNAL) {
layer->flag &= ~CD_FLAG_IN_MEMORY;

View File

@ -73,6 +73,8 @@ set(SRC
intern/bmesh_delete.h
intern/bmesh_edgeloop.c
intern/bmesh_edgeloop.h
intern/bmesh_idmap.cc
intern/bmesh_idmap.h
intern/bmesh_inline.h
intern/bmesh_interp.c
intern/bmesh_interp.h

View File

@ -0,0 +1,315 @@
#include "MEM_guardedalloc.h"
#include "BLI_assert.h"
#include "BLI_index_range.hh"
#include "BLI_map.hh"
#include "BLI_set.hh"
#include "BLI_vector.hh"
#include "BKE_customdata.h"
#include "DNA_customdata_types.h"
#include "DNA_meshdata_types.h"
#include "bmesh_idmap.h"
#include <cstdio>
using namespace blender;
#define FREELIST_HASHMAP_THRESHOLD_HIGH 1024
#define FREELIST_HASHMAP_THRESHOLD_LOW 700
BMIdMap *BM_idmap_new(BMesh *bm, int elem_mask)
{
BMIdMap *idmap = MEM_new<BMIdMap>("BMIdMap");
for (int i = 0; i < ARRAY_SIZE(idmap->cd_id_off); i++) {
idmap->cd_id_off[i] = -1;
}
idmap->flag = elem_mask;
idmap->bm = bm;
BM_idmap_check_attributes(idmap);
return idmap;
}
static void idmap_grow_map(BMIdMap *idmap, int newid)
{
if (idmap->map_size > newid) {
return;
}
int newsize = (newid + 1);
newsize += newsize >> 1;
if (idmap->map) {
idmap->map = (BMElem **)MEM_recallocN((void *)idmap->map, sizeof(void *) * newsize);
}
else {
idmap->map = (BMElem **)MEM_calloc_arrayN(newsize, sizeof(void *), "bm idmap");
}
idmap->map_size = newsize;
}
void BM_idmap_check_ids(BMIdMap *idmap)
{
BMIter iter;
BMVert *v;
BMEdge *e;
BMFace *f;
idmap->freelist.clear();
if (idmap->free_idx_map) {
MEM_delete<BMIdMap::FreeIdxMap>(idmap->free_idx_map);
idmap->free_idx_map = nullptr;
}
Set<int> used;
int max_id = 0;
if (idmap->flag & BM_VERT) {
BM_ITER_MESH (v, &iter, idmap->bm, BM_VERTS_OF_MESH) {
int id = BM_ELEM_CD_GET_INT(v, idmap->cd_id_off[BM_VERT]);
max_id = max_ff(max_id, id);
}
}
if (idmap->flag & BM_EDGE) {
BM_ITER_MESH (e, &iter, idmap->bm, BM_EDGES_OF_MESH) {
int id = BM_ELEM_CD_GET_INT(e, idmap->cd_id_off[BM_EDGE]);
max_id = max_ff(max_id, id);
}
}
if (idmap->flag & (BM_FACE | BM_LOOP)) {
BM_ITER_MESH (f, &iter, idmap->bm, BM_FACES_OF_MESH) {
if (idmap->flag & BM_FACE) {
int id = BM_ELEM_CD_GET_INT(f, idmap->cd_id_off[BM_FACE]);
max_id = max_ff(max_id, id);
}
if (idmap->flag & BM_LOOP) {
BMLoop *l = f->l_first;
do {
int id = BM_ELEM_CD_GET_INT(l, idmap->cd_id_off[BM_LOOP]);
max_id = max_ff(max_id, id);
} while ((l = l->next) != f->l_first);
}
}
}
if (idmap->map_size >= max_id) {
memset((void *)idmap->map, 0, sizeof(void *) * idmap->map_size);
}
else {
MEM_SAFE_FREE(idmap->map);
idmap->map_size = max_id;
idmap->map = (BMElem **)MEM_calloc_arrayN(max_id, sizeof(BMElem *), "bm idmap->map");
}
auto check_elem = [&](auto *elem) {
int id = BM_ELEM_CD_GET_INT(elem, idmap->cd_id_off[(int)elem->head.htype]);
if (id < 0 || used.contains(id)) {
id = max_id++;
}
idmap_grow_map(idmap, id);
idmap->map[id] = reinterpret_cast<BMElem *>(elem);
used.add(id);
};
idmap->maxid = max_id;
if (idmap->flag & BM_VERT) {
BM_ITER_MESH (v, &iter, idmap->bm, BM_VERTS_OF_MESH) {
check_elem(v);
}
}
if (idmap->flag & BM_EDGE) {
BM_ITER_MESH (e, &iter, idmap->bm, BM_EDGES_OF_MESH) {
check_elem(e);
}
}
if (idmap->flag & (BM_FACE | BM_LOOP)) {
BM_ITER_MESH (f, &iter, idmap->bm, BM_FACES_OF_MESH) {
check_elem(f);
if (idmap->flag & BM_LOOP) {
BMLoop *l = f->l_first;
do {
check_elem(l);
} while ((l = l->next) != f->l_first);
}
}
}
if (idmap->flag & BM_VERT) {
BM_ITER_MESH (v, &iter, idmap->bm, BM_VERTS_OF_MESH) {
check_elem(v);
}
}
}
void BM_idmap_check_attributes(BMIdMap *idmap)
{
auto check_attr = [&](int type) {
if (!(idmap->flag & type)) {
return;
}
CustomData *cdata;
const char *name;
switch (type) {
case BM_VERT:
name = ".sculpt.vertex.id";
cdata = &idmap->bm->vdata;
break;
case BM_EDGE:
name = ".sculpt.edge.id";
cdata = &idmap->bm->edata;
break;
case BM_LOOP:
name = ".sculpt.loop.id";
cdata = &idmap->bm->ldata;
break;
case BM_FACE:
name = ".sculpt.face.id";
cdata = &idmap->bm->pdata;
break;
default:
BLI_assert_unreachable();
return;
}
int idx = CustomData_get_named_layer(cdata, CD_PROP_INT32, name);
if (idx < 0) {
BM_data_layer_add_named(idmap->bm, cdata, CD_PROP_INT32, name);
idx = CustomData_get_named_layer(cdata, CD_PROP_INT32, name);
}
if (!cdata->layers[idx].default_data) {
cdata->layers[idx].default_data = MEM_cnew<MIntProperty>("MIntProperty");
}
cdata->layers[idx].flag |= CD_FLAG_ELEM_NOINTERP | CD_FLAG_ELEM_NOCOPY;
int *default_data = static_cast<int *>(cdata->layers[idx].default_data);
*default_data = -1;
idmap->cd_id_off[type] = cdata->layers[idx].offset;
};
check_attr(BM_VERT);
check_attr(BM_EDGE);
check_attr(BM_LOOP);
check_attr(BM_FACE);
}
void BM_idmap_destroy(BMIdMap *idmap)
{
MEM_SAFE_FREE(idmap->map);
MEM_delete<BMIdMap>(idmap);
}
static void check_idx_map(BMIdMap *idmap)
{
if (idmap->free_idx_map && idmap->freelist.size() < FREELIST_HASHMAP_THRESHOLD_LOW) {
printf("%s: Deleting free_idx_map\n", __func__);
MEM_delete<BMIdMap::FreeIdxMap>(idmap->free_idx_map);
idmap->free_idx_map = nullptr;
}
else if (!idmap->free_idx_map && idmap->freelist.size() < FREELIST_HASHMAP_THRESHOLD_HIGH) {
printf("%s: Adding free_idx_map\n", __func__);
idmap->free_idx_map = MEM_new<BMIdMap::FreeIdxMap>("BMIdMap::FreeIdxMap");
for (int i : IndexRange(idmap->freelist.size())) {
idmap->free_idx_map->add(idmap->freelist[i], i);
}
}
}
void BM_idmap_assign(BMIdMap *idmap, BMElem *elem)
{
int id = -1;
while (idmap->freelist.size()) {
id = idmap->freelist.pop_last();
if (id == -1) {
continue;
}
if (idmap->free_idx_map) {
idmap->free_idx_map->remove(id);
}
break;
}
if (id == -1) {
id = idmap->maxid++;
}
idmap_grow_map(idmap, id);
idmap->map[id] = elem;
}
void BM_idmap_reassign(BMIdMap *idmap, BMElem *elem, int id)
{
if (idmap->free_idx_map) {
const int *val;
if ((val = idmap->free_idx_map->lookup_ptr(id))) {
idmap->freelist[*val] = -1;
idmap->free_idx_map->remove(id);
}
}
else {
for (int i : IndexRange(idmap->freelist.size())) {
if (idmap->freelist[i] == id) {
idmap->freelist[i] = -1;
}
}
}
idmap_grow_map(idmap, id);
idmap->map[id] = elem;
check_idx_map(idmap);
}
void BM_idmap_release(BMIdMap *idmap, BMElem *elem)
{
int id = BM_ELEM_CD_GET_INT(elem, idmap->cd_id_off[(int)elem->head.htype]);
if (id == -1) {
printf("%s: unassigned id!\n", __func__);
return;
}
idmap->map[id] = nullptr;
idmap->freelist.append(id);
if (idmap->free_idx_map) {
idmap->free_idx_map->add(id, idmap->freelist.size() - 1);
}
check_idx_map(idmap);
}
void BM_idmap_check_assign(BMIdMap *idmap, BMElem *elem)
{
int id = BM_ELEM_CD_GET_INT(elem, idmap->cd_id_off[(int)elem->head.htype]);
if (id == -1) {
BM_idmap_assign(idmap, elem);
}
}

View File

@ -0,0 +1,64 @@
#include "BLI_compiler_attrs.h"
#include "BLI_compiler_compat.h"
#include "BLI_sys_types.h"
#include "bmesh.h"
#ifndef WITH_BM_ID_FREELIST
# define WITH_BM_ID_FREELIST
#endif
#ifdef __cplusplus
# include "BLI_map.hh"
# include "BLI_vector.hh"
#endif
typedef struct BMIdMap {
int flag;
uint maxid;
int cd_id_off[15];
BMesh *bm;
BMElem **map;
int map_size;
#ifdef __cplusplus
blender::Vector<int> freelist;
using FreeIdxMap = blender::Map<int, int>;
/* maps ids to their position within the freelist
only used if freelist is bigger then a certain size,
see FREELIST_HASHMAP_THRESHOLD_HIGH in bmesh_construct.c.*/
FreeIdxMap *free_idx_map;
#endif
} BMIdMap;
#ifdef __cplusplus
extern "C" {
#endif
BMIdMap *BM_idmap_new(BMesh *bm);
void BM_idmap_check_attributes(BMIdMap *idmap);
void BM_idmap_check_ids(BMIdMap *idmap);
void BM_idmap_destroy(BMIdMap *idmap);
void BM_idmap_assign(BMIdMap *idmap, BMElem *elem);
void BM_idmap_reassign(BMIdMap *idmap, BMElem *elem);
void BM_idmap_release(BMIdMap *idmap, BMElem *elem);
void BM_idmap_check_assign(BMIdMap *idmap, BMElem *elem);
BLI_INLINE int BM_idmap_get_id(BMIdMap *map, BMElem *elem)
{
return BM_ELEM_CD_GET_INT(elem, map->cd_id_off[(int)elem->head.htype]);
}
BLI_INLINE BMElem *BM_idmap_lookup(BMIdMap *map, int elem)
{
return elem >= 0 ? map->map[elem] : NULL;
}
#ifdef __cplusplus
}
#endif

View File

@ -46,6 +46,7 @@ typedef struct CustomDataLayer {
* automatically.
*/
const struct AnonymousAttributeID *anonymous_id;
void *default_data;
} CustomDataLayer;
#define MAX_CUSTOMDATA_LAYER_NAME 64