sculpt-dev: part one of new id system for dyntopo
This commit is contained in:
parent
8a4d2eb670
commit
e19d6d2f18
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -46,6 +46,7 @@ typedef struct CustomDataLayer {
|
|||
* automatically.
|
||||
*/
|
||||
const struct AnonymousAttributeID *anonymous_id;
|
||||
void *default_data;
|
||||
} CustomDataLayer;
|
||||
|
||||
#define MAX_CUSTOMDATA_LAYER_NAME 64
|
||||
|
|
Loading…
Reference in New Issue